⚠️ Deprecation Notice
This repository is no longer maintained.
Please use the new/updated implementation at:
A package for viewing + editing sops files. It handles sops pin prompts, I wrote this particularly to handle pin-guarded age keys stored on yubikeys. It also handles age keys guarded by passphrases, plus can be extended to support any KMS that sops prompts for.
sops-file-demo.webm
- sops minimum version 3.10.2 (latest as of 5/20/25)
- needed for getsops/sops#1400
- env (for disabling pinentry)
- emacs minimum 29.1
Using straight.el:
(use-package sops-file
:straight
`(:host github :repo "ajarara/sops-file.el")
:after yaml-mode ;; yaml-mode is optional
:config
;; adds an auto-mode-alist entry and yaml-mode hooks if yaml-mode is installed
(sops-file-auto-mode 1)
;; for age-plugin-yubikey users with multiple yubikeys, if a card isn't detected from your
;; identity file sops will prompt you to insert it or skip it.
;; by default sops-file will skip these unavailable cards -- set this to nil to be prompted
(setq sops-file-skip-unavailable-smartcards nil))After we cut a version we'll be on melpa{-stable}.
Without any configuration, users can simply do M-x format-find-file, select the file, then select format sops-file. Users can also, when visiting a file literally, M-x format-decode-buffer and select sops-file as the format.
sops-file-auto-mode is a global minor mode that attaches a trigger to the yaml-mode mode hook (if yaml-mode is loaded) and also installs an entry into auto-mode-alist, so that regular M-x find-files apply the format (whether yaml-mode is installed or not).
Users are welcome to attach sops-file-entry-trigger to any major mode hook they like: if sops-file determines that this file is encrypted by sops, sops-file will attempt to apply the format encoding. On decyption failure we write to *sops-file-error*.
Users can also use this to create sops files for the first time, simply do M-x format-find-file on any path. Provided there is a creation_rule for that path, the contents will never hit disk decrypted.
Sops integrates with a diverse array of encryption providers: age, age-on-yubikeys, pgp, external KMS. sops-file.el mostly ferries prompts between the decryption process and the user, however some glue code is needed to support each encryption method. This is the primary place users should expect to write code against sops-file (if at all): when sops encounters a prompt it cannot handle, it will hang for a bit until it fails and spit out the prompt in a *sops-file-error*.
Look to the existing prompt-handlers, namely sops-file--prompt-handler-passphrase-identity -- the important thing is to advance point past the prompt.
Users shouldn't need to integrate with sops-file through writing non-prompt-handling code. The public API should be thought of as:
- the sops-file format registration (which happens on load)
sops-file-auto-modesops-file-entry-trigger(to be added to any relevant hooks)- defcustoms defined in the sops-file group
Before claiming a stable 1.0, we're going to wait for more users and bug reports. There are a couple features I know that need to be implemented for a comprehensive experience:
- confirmed, tested pgp support:
- looking at source pgp follows the same logic as age: lean on gpg-agent to request the passphrase (sops uses gpg-agent as well, if available). If no connection can be made, read it directly from stdin. Gpg has many more moving parts over age, so an isolated test is going to be more complex. But in theory it should work fine, with graphical pinentry or with no daemon (in my tests non-graphical pinentry doesn't work).
- tramp support: as of now, none known. I remember there are some caveats towards remote shell commands and having to mix in stderr/stdout, which could be difficult to handle here, given we rely on dedicated outputs for prompt handling and cleartext retrieval.
- support for external KMS providers (testing will be difficult)
What follows are things that I think would be useful, but would probably mean compromises to the complexity of the code as is or would be difficult to test. Your comments are welcome on these (or anything else related to this project for that matter), as issues.
often while testing this I would find-file into a sops file I'd expect to be decrypted, only to realize that I needed to toggle the mode. I would then toggle the mode and remember I have to revert the buffer for the hook to fire. I would prefer that this minor mode felt alive like all the other minor modes.
There are two major points against this:
- I bet most users toggle on the mode in their init file and don't toggle it interactively (if they do, they probably want to have it be disabled on one specific file in which case they should use find-file-literally).
- Applying the format to buffers not visible is a subpar experience when passphrases are prompted interactively: multiple passphrases, multiple files, we'd need to flit them in or something.
Simple, add the prompts to comint-password-prompt-regexp for similar behavior to allow for read-password during shell command invocations. This is eventually used by comint-output-filter-functions. This can probably be added unconditionally.
epa-file, sops.el, rot13