How encrypted files work across the deployment lifecycle
CoB projects sometimes need to ship files that contain secrets — API keys, credentials, certificates. These files cannot be committed to the repository in plaintext, but they still need to reach the server as part of a normal deployment. The .enc mechanism solves this by keeping an encrypted copy in the repository and decrypting it on the server at deploy time.
The day-to-day steps are in How to add, update and remove encrypted files; this page explains what happens underneath.
The two forms of a secret file
Every encrypted file exists in two forms:
- The
.encfile — the encrypted version, committed to the repository. For example,recordm/services/com.cultofbits.web.integration.properties.enc. This file is safe to store in version control. - The decrypted file — the plaintext version, produced on the server by
cob-decrypt. It sits next to the.encfile in the server's live directory (e.g./etc/recordm/services/com.cultofbits.web.integration.properties) but is never part of the repository.
The decrypted file is a derived artefact. It is owned by the server, not the repository, and cob-cli treats it accordingly across all commands.
On deploy
When cob-cli deploy runs, rsync copies the .enc file to the server's live directory alongside all other project files. Once the transfer is complete, cob-cli calls cob-decrypt over SSH for each .enc file that was transferred:
sudo -u cob-secrets /usr/local/bin/cob-decrypt '<server file path>'cob-decrypt reads the .enc file and writes the decrypted version next to it, without the .enc extension. From that point on, the application on the server reads the decrypted file as it would any ordinary config file.
Decryption only happens for .enc files that were actually transferred in that deploy, not for every .enc file in the project.
On test
cob-cli test continuously syncs local files to the server. The decrypted file on the server is protected from being deleted by this sync — even if the local repository has no decrypted counterpart (which it never does), rsync is instructed to preserve the server's decrypted file. This means secrets remain available on the server throughout a test session without needing to re-deploy.
If a .enc file is removed from the local repository during a test session, cob-cli also removes the corresponding decrypted file from the server, keeping the two forms in sync. It does so even when a cleartext file with the same name was added at the same time — see When a file stops being encrypted.
On updateFromServer
When cob-cli updateFromServer --code compares the server's live files against the local repository, decrypted files are excluded from the diff. A file like /etc/recordm/services/com.cultofbits.web.integration.properties will never appear as a change to pull back locally, because its source of truth is the .enc file, not the decrypted copy on the server.
When a file stops being encrypted
The mechanism also runs in reverse. When a file no longer contains secrets, the .enc is replaced in the repository by the developer with a plain file with the same name minus the extension, and the next deploy brings the server in line:
- rsync runs with
--delete, so the.encfile disappears from the live directory. - The decrypted sibling is protected from rsync only while a local
.encexists. With the.encgone, rsync compares it against the committed cleartext like any other file. - rsync writes a fresh file owned by the deployer, with the same permissions as every other project file. This happens even when the committed cleartext is identical to the decrypted copy: deployers cannot read decrypted files, so rsync cannot checksum the server copy and transfers the committed one again.
DANGER
The test path is not symmetric. A test session that sees a .enc file disappear removes the decrypted sibling from the server without checking whether a cleartext file with that name now exists locally, and the end-of-session restore makes the same assumption. For this reason the conversion back to cleartext is done with a deploy, never inside a test session.
Why decryption happens on the server
Decrypting on the server rather than locally and uploading the plaintext keeps the secret out of most developers' hands. A developer can encrypt a new secret file and commit it without ever holding the decryption key — only the server's cob-secrets user and the developers explicitly trusted with the age key can decrypt it. The plaintext is never present on an untrusted developer's machine, never travels over the network, and is never accessible through normal cob-cli operations. The repository holds only the encrypted form, and the decrypted form on the server is owned and managed exclusively by cob-decrypt.
Summary
| Repository | Server live directory | |
|---|---|---|
.enc file | ✓ committed | ✓ deployed by rsync |
| Decrypted file | — never present | ✓ produced by cob-decrypt |
| File converted back to cleartext | ✓ committed | ✓ deployed by rsync, like any other file |
