Add SSH keys and config to credential sharing - #139
Merged
Conversation
Private keys have lived as plaintext-on-disk files guarded only by a passphrase. This puts them in the same end-to-end-encrypted vaults as .env secrets, and adds an agent path so a machine can use a key without ever writing one to its disk. - `ssh` provider: ~/.ssh as a value bag. Files are picked by sniffing contents (PRIVATE KEY blocks, ssh-*/ecdsa-*/sk-* public keys) plus config, config.d/* and allowed_signers. known_hosts and authorized_keys are host-specific and access-granting, so they need an explicit --include. - Each file is one secret carrying a JSON envelope of path, mode and body. The engine only hands write() the secrets that CHANGED, so a separate manifest secret would be absent whenever a key's contents change but the file list doesn't — self-describing values keep every restore total. - `logicsrc secrets ssh push|pull|list|agent`, addressed by PERSON not project: the vault is ssh--<username>, which teams vaults reads as project ssh, env <username>. One teammate's keys never land in another's restore; sharing stays a deliberate teams grant. - Both directions hold back anything that would overwrite a file that already differs, and say what they skipped. --force opts in. A restore onto a machine with its own keys is otherwise a way to lose them. - Restores chmod each file back to its recorded mode; writeFileSync's mode applies only on create, so an existing world-readable key would otherwise stay world-readable. The adapter declares delete:false. - push warns about passphrase-less private keys before they go up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ThreatCrush Security Scan72 finding(s) HIGH/CRITICAL: 8 | MEDIUM: 40 | LOW: 24
…and 22 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
Commander's usage line shows only the first alias, so `logicsrc secrets` — the spelling people actually type — was invisible in its own help. The examples carry it, alongside the flows worth copying: link/up/down, the ssh backup round trip, and a plan → dry-run → approve sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ralyodio
marked this pull request as ready for review
August 13, 2026 23:47
The marketing-drift contract failed the build because `ssh` shipped in the provider registry with no entry in MARKETING_PROOF -- which is the test working: it exists so a provider cannot ship while the pages people actually land on still describe the tool without it. The proof regex is `/~\/\.ssh|SSH key/` rather than a bare `/SSH/` on purpose. The provider grid renders every registry `name`, and this one is "Local SSH directory", so `/SSH/` would already be satisfied by the generated grid and the provider could ship with no copy written about it at all -- passing the test while failing its intent. Requiring the path or the phrase means a human wrote a sentence. That sentence is the new block in the credential-sharing band: ~/.ssh is a directory of files whose permission bits are load-bearing, not a set of KEY=VALUE lines, which is the part that makes this provider different from the other six. README already named ~/.ssh keys, so it needed no change. apps/logicsrc-web: 75/75 contract tests pass (was 74 passed, 1 failed). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stores SSH key pairs and
~/.ssh/configin the same end-to-end-encrypted team vaults as.envsecrets, plus an agent path that uses a key without writing it to disk — the trade Proton Pass makes with its SSH agent.Surface
Key material is addressed by person, not project: the vault is
ssh--<username>, whichteams vaultslists as projectssh, env<username>. One teammate's keys never land in another's restore, and sharing stays a deliberateteams grant.Design notes
sshprovider rather than bespoke CLI code, so diff, dry-run, approval, rollback and audit come from the existing engine.logicsrc secrets inspect --provider ssh --path ~/.sshandplan --from ssh --to sshwork too.PRIVATE KEYblocks,ssh-*/ecdsa-*/sk-*public keys, plusconfig,config.d/*,allowed_signers.known_hostsandauthorized_keysare host-specific and access-granting, so they need--include.write()the secrets that changed, so a separate manifest secret would be missing whenever a key's contents change but the file list doesn't — self-describing values keep every restore total.--forceopts in. A restore onto a machine that has its own keys is otherwise a way to lose them.chmodeach file back to its recorded mode (writeFileSync's mode applies only on create, so an existing world-readable key would stay world-readable) and create the directory0700. The adapter declaresdelete: false.pushwarns about passphrase-less private keys before they go up.Verification
credential-sharing68,cli54).secrets plan/sync --from ssh --to sshbetween two directories restored byte-identical files at0600/0644,ssh-keygen -ystill derives the public key, andknown_hosts/authorized_keyswere correctly left behind.🤖 Generated with Claude Code