Skip to content

feat(secrets): consume SOPS SDK payload - #167

Merged
altaywtf merged 5 commits into
mainfrom
feat/sops-secret-setup
Aug 2, 2026
Merged

feat(secrets): consume SOPS SDK payload#167
altaywtf merged 5 commits into
mainfrom
feat/sops-secret-setup

Conversation

@altaywtf

@altaywtf altaywtf commented Aug 2, 2026

Copy link
Copy Markdown
Member

Summary

  • replace provider-specific secret export with a generic SOPS ciphertext input
  • validate the exact SDK payload before writing ignored local env material
  • add deterministic secret-free renderer tests and update contributor guidance

Changed

  • PUTIO_SDK_TYPESCRIPT_SOPS_FILE is the only setup input
  • pnpm secrets:setup requires encrypted SOPS input, validates exact keys and formats, renders dotenv safely, and writes mode 0600
  • setup rejects plaintext, missing/extra keys, empty or quote-wrapped values, invalid numeric IDs, symlink output, and non-ignored output
  • active docs and examples no longer contain provider-specific setup language

Review aids

Input

PUTIO_SDK_TYPESCRIPT_SOPS_FILE=/path/to/typescript.sops.env

Output

ok wrote .env.local

The output is gitignored, mode 0600, and contains the existing nine-key live SDK contract. Secret values are never accepted as command arguments or written to logs.

Flow

flowchart LR
  A["Operator-supplied SOPS file"] --> B["Encrypted-status check"]
  B --> C["Owner-only temporary JSON"]
  C --> D["Exact semantic validation"]
  D --> E["Quoted dotenv rendering"]
  E --> F["Ignored .env.local at mode 0600"]
Loading

Risks

  • The wrapper intentionally fails when the ciphertext path or age identity is unavailable.
  • Existing secrets:setup and secrets:clean command names and .env.local consumer behavior are preserved.
  • CI, release, publishing, and GitHub secrets are unchanged.

Verification

  • pnpm run verify — 24 files / 142 tests, coverage, formatting, lint, build, route validation, and synthetic SOPS contract tests
  • real SOPS setup — nine validated variables loaded from the migrated ciphertext, mode and ignore checks passed, cleanup passed
  • pnpm test:live:fresh -- test/live/account.test.ts test/live/tunnel.test.ts — 2 files / 9 tests passed; fresh first-party token cleanup completed
  • publint passed; direct packed-tarball attw --profile esm-only passed
  • shellcheck scripts/secrets-setup.sh scripts/secrets-setup.test.sh
  • case-insensitive provider-name scan returned zero active-repo hits

Complexity

Moderate: one security-boundary shell wrapper, one synthetic contract test, and five documentation/config updates.


Summary by cubic

Switched pnpm secrets:setup to consume a SOPS-encrypted SDK payload instead of provider-specific exports, with stricter validation and safer .env.local rendering. This makes setup provider-agnostic and keeps secrets ignored and 0600.

  • New Features

    • pnpm secrets:setup reads PUTIO_SDK_TYPESCRIPT_SOPS_FILE, verifies exact keys and formats, and writes .env.local at mode 0600.
    • Fails closed on plaintext, missing/extra keys, empty or quote-wrapped values, invalid numeric IDs, symlinked input/output, or non-ignored/non-repo-relative output paths.
    • Added scripts/secrets-setup.test.sh and test:secrets; wired into verify. Docs and .env.example updated to SOPS-based setup.
  • Bug Fixes

    • Hardened input checks: require encrypted ciphertext via sops filestatus, reject symlinked ciphertext, and enforce repo-relative ignored output.
    • Hardened payload rendering: use delimiter fallback to avoid collisions; reject multiline, NUL/CR/LF, or otherwise unrenderable values. Made the .env.local mode check portable across Linux and macOS.

Written for commit d632bad. Summary will update on new commits.

Copilot AI review requested due to automatic review settings August 2, 2026 18:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The secrets wrapper should explicitly reject symlinked ciphertext inputs and use jq (already required) instead of a regex grep to validate the JSON filestatus encryption flag.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR updates the repository’s live-test secrets workflow to be provider-agnostic by consuming a maintainer-supplied SOPS ciphertext file, validating an exact SDK payload contract, and rendering a safe, ignored .env.local with strict permissions.

Changes:

  • Replaced the prior provider-specific secret export flow with a sops + jq-validated JSON payload that renders a quoted dotenv file at mode 0600.
  • Added a deterministic shell test (test:secrets) that exercises validation failures and output hardening, and wired it into pnpm run verify.
  • Updated contributor/testing docs and .env.example to document the new SOPS-based setup input (PUTIO_SDK_TYPESCRIPT_SOPS_FILE).
File summaries
File Description
scripts/secrets-setup.sh Implements SOPS ciphertext inspection/decrypt, contract validation, and safe .env.local rendering.
scripts/secrets-setup.test.sh Adds deterministic, secret-free integration tests for the setup wrapper and its failure modes.
package.json Adds test:secrets and runs it as part of verify.
docs/TESTING.md Updates live-test setup guidance to SOPS-based workflow.
CONTRIBUTING.md Updates contributor instructions for secrets setup prerequisites and env input.
AGENTS.md Updates agent routing notes to reference the SOPS ciphertext input.
.env.example Replaces provider-specific setup hints with SOPS ciphertext input hint.
Review details

Suppressed comments (1)

scripts/secrets-setup.sh:31

  • sops filestatus returns JSON, but the script uses a regex grep to detect encryption status. Since jq is already a required dependency here, parsing the JSON with jq -e is more robust and avoids false positives/formatting edge cases.
status="$(sops filestatus "$ciphertext" 2>/dev/null)" \
  || fail "SOPS could not inspect ciphertext input"
printf '%s\n' "$status" | grep -Eq '"encrypted"[[:space:]]*:[[:space:]]*true' \
  || fail "ciphertext input is not encrypted"
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread scripts/secrets-setup.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread package.json
Comment thread scripts/secrets-setup.sh Outdated
Comment thread scripts/secrets-setup.sh Outdated
Comment thread scripts/secrets-setup.test.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread scripts/secrets-render.mjs
Comment thread scripts/secrets-setup.test.sh Outdated
@altaywtf

altaywtf commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

Final verification

Input

  • Maintainer-supplied encrypted dotenv payload
  • Exact nine-variable SDK contract
  • Authorized local decryption path

Output

  • Validated, gitignored .env.local written with mode 0600
  • Quote and backslash values preserved exactly
  • Missing, extra, empty, malformed, quote-wrapped, multiline, NUL, plaintext, symlink, and unsafe-output cases rejected
  • Generated file removed by the cleanup command

Proof

  • pnpm run verify: passed, including 24 test files / 142 tests and the secret-free renderer contract
  • Fresh live acceptance: 2 files / 9 tests passed; temporary token lifecycle and reversible account mutation completed
  • Hosted SDK and Node, Bun, Chromium, Firefox, and WebKit compatibility checks: passed
  • Latest independent review: all reported issues addressed

@altaywtf
altaywtf merged commit 9db1adf into main Aug 2, 2026
10 checks passed
@altaywtf
altaywtf deleted the feat/sops-secret-setup branch August 2, 2026 19:23
putio-releaser Bot pushed a commit that referenced this pull request Aug 2, 2026
## [11.1.0](v11.0.2...v11.1.0) (2026-08-02)

### Features

* **secrets:** consume SOPS SDK payload ([#167](#167)) ([9db1adf](9db1adf))
@putio-releaser

putio-releaser Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 11.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants