feat(secrets): encrypt provider, gateway, and mcp secrets at rest - #77
Merged
Merged
Conversation
Provider API keys sat as plaintext in the providers.api_key column, gateways.json stored remote endpoint keys unencrypted, and mcp.json kept MCP server auth headers in the clear. All three were only protected by 0600 file permissions or the local sqlite file itself; the existing maskSecret helper hid values on display but never touched what was persisted. Add util/crypto.go with AES-256-GCM Encrypt/Decrypt helpers keyed by a new secret.key (generated the same way as mininaru.key, but kept separate from it since that file authenticates the daemon rather than protecting stored credentials). Decrypt passes unprefixed values through unchanged, so existing plaintext rows and config entries migrate in place the next time they're written rather than needing a separate migration step.
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.
What this changes
Provider API keys (
providers.api_key),gateways.jsonendpoint keys, andmcp.jsonserver auth headers were all stored as plaintext, protected only by 0600 file permissions or the local sqlite file.maskSecrethid them on display but never touched what was persisted. This adds AES-256-GCM encryption at rest for all three, keyed by a newsecret.keyfile kept separate frommininaru.key(which authenticates the daemon itself and is intentionally out of scope). Existing plaintext values are decrypted transparently on read and re-encrypted the next time they're saved, so no separate migration step is needed.How it was verified
make test-racepassesAdded
util/crypto_test.gocovering encrypt/decrypt round-trip, empty-string passthrough, and legacy-plaintext passthrough throughDecrypt. Also manually confirmed a provider's storedapi_keyisenc:v1:...ciphertext in the sqlite file and round-trips back to the original value throughProviderCreate/ProviderRead.Checklist
:=, onevarblock per function in first-use order witherrlast, callees before callers, andmainunconditionally last.gofiles carry the two-line SPDX headerGPL-3.0-only, matching the project