Support optional encrypted-at-rest secrets via SOPS (re #233) #236
Closed
nickorlabs wants to merge 1 commit from
nickorlabs/feat/sops-encrypted-secrets into main
pull from: nickorlabs/feat/sops-encrypted-secrets
merge into: sleepy:main
sleepy:main
sleepy:dev
sleepy:fix/effective-mode-undefined
sleepy:fix/async-generator-500
sleepy:refactor/split-small-routes-779
sleepy:refactor/split-session-routes-778
sleepy:refactor/split-llm-core-700
sleepy:refactor/split-chat-routes-724
sleepy:refactor/split-model-routes-701
sleepy:refactor/split-skills-routes-777
sleepy:refactor/split-document-routes-769
sleepy:refactor/split-ai-interaction-722
sleepy:refactor/split-cookbook-routes-775
sleepy:refactor/split-builtin-actions-723
sleepy:refactor/split-task-scheduler-774
sleepy:refactor/tool-execution-split-667
sleepy:fix/rag-health-coordinator-756
sleepy:fix/agent-core-missing-round-loop
sleepy:fix/rag-health-check-756
sleepy:fix/missing-readmes-782
sleepy:fix/search-files-split-772
sleepy:fix/dedup-search-impl-771
sleepy:fix/mcp-integrations-split-781
sleepy:fix/cookbook-helpers-split-785
sleepy:fix/search-cross-feature-776
sleepy:fix/graceful-llm-degradation-770
sleepy:fix/dedup-research-handler-773
sleepy:fix/cross-route-coupling-780
sleepy:fix/skills-typed-request-762
sleepy:fix/chat-stream-pydantic-731
sleepy:fix/chat-handler-imports-737
sleepy:fix/public-llm-exports-730
sleepy:fix/dedup-search-content-784
sleepy:fix/dedup-stream-parse-735
sleepy:fix/stream-error-boundary-734
sleepy:fix/typed-event-names-786
sleepy:fix/dedup-js-utilities-792
sleepy:fix/skills-index-lookup-761
sleepy:fix/xss-charname-innerhtml-788
sleepy:fix/coderunner-document-write-789
sleepy:fix/ai-interaction-thread-safety-729
sleepy:fix/client-side-api-key-regex-793
sleepy:fix/dead-loadingtext-796
sleepy:fix/active-streams-eviction-736
sleepy:fix/builtin-actions-sqlite-orm-732
sleepy:fix/llm-core-thread-safety-709
sleepy:fix/singleton-thread-safety-768
sleepy:fix/video-upload-multimodal-826
sleepy:fix/mic-button-audio-825
sleepy:fix/multimodal-capabilities-827
sleepy:fix/dedup-system-msg-717
sleepy:fix/service-dead-calls-750
sleepy:fix/db-session-context-manager-757
sleepy:fix/dedup-llmconfig-710
sleepy:fix/keyword-lists-764-v2
sleepy:fix/keyword-lists-764
sleepy:fix/llm-cache-ttl-708
sleepy:fix/validate-config-711
sleepy:fix/totp-constant-time-689
sleepy:fix/admin-tools-constant-681
sleepy:fix/dedup-truncate-670
sleepy:fix/threadsafe-extractions-audit-754
sleepy:fix/dedup-json-io-767
sleepy:fix/695-deduplicate-admin-check
sleepy:fix/upload-auth-dedup-765
sleepy:fix/705-deduplicate-network-constants
sleepy:fix/deduplicate-chunking-749
sleepy:fix/760-deduplicate-embed
sleepy:fix/dedup-validation-759
sleepy:fix/748-deduplicate-tokenization
sleepy:fix/add-readmes-728-742-782
sleepy:fix/key-file-permissions-706
sleepy:fix/embedding-retry-766
sleepy:fix/deterministic-doc-ids-753
sleepy:fix/search-facade-783
sleepy:fix/remove-dead-memory-746
sleepy:fix/remove-rag-manager-747
sleepy:fix/dead-docstring-763
sleepy:refactor/split-tool-schemas-666
sleepy:refactor/split-agent-loop-664
sleepy:refactor/split-tool-implementations-665
sleepy:fix/mark-stopped-500-663
sleepy:fix/streamingtts-scope-662
sleepy:fix/code-block-tool-parsing-661
No reviewers
Labels
Clear labels
area:chat
area:core
area:llm
area:routes
area:tools
bug
Something isn't working
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
refactor
wontfix
This will not be worked on
No labels
area:chat
area:core
area:llm
area:routes
area:tools
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
refactor
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
sleepy/odysseus!236
Loading…
Reference in a new issue
No description provided.
Delete branch "nickorlabs/feat/sops-encrypted-secrets"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Concrete code for #233. Adds opt-in SOPS support so true secrets (
OPENAI_API_KEY,ODYSSEUS_ADMIN_PASSWORD,SEARXNG_SECRET, MCP OAuth secrets, IMAP passwords) can be encrypted at rest instead of sitting plaintext in.env. Non-secret config (APP_PORT,LLM_HOST, etc.) stays in.envso structural diffs remain reviewable.The feature is only active when
/app/secrets.env.encis present at container start. Existing deployments are bit-for-bit identical.Diff overview (6 files, +123 / -0)
Dockerfiledpkg --print-architecturedocker/entrypoint.shsecrets.env.encexists, wrapgosuwithsops exec-env— secrets become env vars JIT, plaintext never touches the FS. Hard-fails if sops is missing or noSOPS_AGE_KEY[_FILE]set..sops.yamlsecrets.env.example.gitignore.envpattern: ignoresecrets.env, allowsecrets.env.exampleandsecrets.env.encSECURITY.mdsops -e→ compose mount workflowNaming
The codebase already has
routes/vault_routes.py(Bitwarden/Vaultwarden integration — runtime feature). To avoid collision I'm using "encrypted secrets at rest" / "SOPS" /secrets.env.encthroughout — never "vault."Backwards compatibility
secrets.env.enc→ entrypoint takes the existingexec gosu "$PUID:$PGID" "$@"path, byte-for-byte unchanged.python-dotenvflow.Test plan
docker build .succeeds on the modified Dockerfiledocker run odysseus-sops-test:local sh -c 'sops --version'→sops 3.13.1secrets.env.encpresent → entrypoint code path is unchanged (the new block is skipped by[ -f ... ])sops -e secrets.env > secrets.env.enc→ mount key into container →docker compose up→ verify env vars are populated and plaintext never appears on disk)Open for direction
I went with the design described in #233 (sops bundled in the image, age keys, opt-in via file presence). If you'd prefer any of:
ARGso non-users don't pull the binary…just say the word and I'll adjust or close. Self-contained PR; easy to drop.
Pull request closed