Skip to content

Secrets never block a task: take them out of the branch and push it - #54

Merged
danielehrhardt merged 1 commit into
mainfrom
fix/secret-push-autofix
Oct 4, 2026
Merged

danielehrhardt merged 1 commit into
mainfrom
fix/secret-push-autofix

Conversation

@danielehrhardt

Copy link
Copy Markdown
Contributor

Coding tasks landed in Blocked far too often with "The changes on contain a secret saved in the vault, so Godmode didn't push them". Now a secret never stops a push and never goes along: Godmode takes it out of the branch, pushes, and notifies.

Why it fired so often

  • The check scanned the whole git diff base...HEAD, so context lines, removed lines and file paths all counted.
  • It compared against every value the vault masks. That includes every env/header value of every custom MCP server (production, URLs, regions), so any branch touching a config file could trip it.

What counts now

  • Only what a push would publish adds: added lines, file names and commit messages of the commits that are neither on the base nor on the remote yet; .env/key files; and every version of a binary file (≤ 20 MB). Moved files count only for what changed.
  • Only values stored as a secret (a new pushSecrets subset; transcript redaction is unchanged):
    • passwords, 2FA secrets, API keys, tokens;
    • MCP env/header values whose name says secret (API_KEY, signingKey, SENTRY_DSN, SLACK_WEBHOOK_URL, Authorization) — not publishable/anon keys, not SORT_KEY=created_at;
    • bearer tokens and passwords inside URLs;
    • never a single plain word or number.

Instead of Blocked (removeSecrets in tasks/git.ts)

  • Text files: the secret is replaced with GODMODE_REMOVED_SECRET.
  • Left out of the push: secret-looking files, binaries holding a secret, and files that can't be rewritten safely. They stay in the worktree; a file the branch already had keeps the remote's version.
  • History: the unpushed commits become one commit on top of what the remote has, with the branch's own last commit as first parent. No pushed commit or message carries the secret, and nothing on the remote is rewritten.
  • Backup: the original tip stays local as refs/worktree/godmode/with-secrets/<sha> and is never pushed.
  • Concurrent turns: exactly the checked commit is pushed. If a turn stages or commits during the fix, this push is skipped and that turn's end pushes the branch.
  • Telling people: one warning names the changed files. The agent brief asks agents to read secrets from the environment. The PR title and body never carry a saved secret, even with redaction off.

SecretInBranch and its three catch sites (publish, keepWork, pushTaskBranch) are removed. Tasks already blocked with the old message push normally from the board, or when moved to Todo.

Trade-offs

  • Code that hard-coded a secret now holds the placeholder until someone wires an env variable. The warning says so.
  • A saved password that is one plain word or number (e.g. postgres) is no longer kept out of pushes. It is still masked.
  • When a fix triggers, the unpushed commits are squashed. Their subjects are kept in the new commit's body.

Tests

  • Results: bun test in packages/core passes 1056; the one failure (folder routes > list subfolders…) fails on main too. tsc --noEmit is clean.
  • New cases in tasks.test.ts / vault.test.ts:
    • committed .env file;
    • a secret added and then removed in a later commit;
    • a secret in a follow-up after a push;
    • a non-UTF-8 file and a read-only file;
    • binary files, including a secret only in an earlier version;
    • a merged base plus a renamed file;
    • pushing from the board;
    • plain settings and context/removed lines are not treated as secrets;
    • a turn staging or committing during the fix;
    • the name rules.
  • Guards checked: each new guard was removed once to confirm its test fails.
  • Review: an independent reviewer ran three rounds; every confirmed defect is fixed and the final round approved.

Coding tasks landed in Blocked far too often with "The changes on <branch>
contain a secret saved in the vault, so Godmode didn't push them". The check
compared the whole `git diff base...HEAD` (context lines, removed lines and
file paths included) with every value the vault masks, and that is every
value of every custom MCP server's env and headers — `production`, URLs,
regions. Any branch touching a config file could trip it.

What counts now
- Only what the commits a push would publish add (neither on the base nor
  on the remote yet): added lines, file names, commit messages, files that
  look like secrets (.env, keys) and every version of a binary file (read
  whole, up to 20 MB). Removed and surrounding lines don't count, a moved
  file adds only what changed.
- Only values stored as a secret (`pushSecrets`, a subset of the redaction
  list): passwords, 2FA secrets, API keys, tokens; of MCP env/header and
  messaging maps the values whose name says secret (API_KEY, signingKey,
  SENTRY_DSN, SLACK_WEBHOOK_URL, Authorization — not publishable/anon keys,
  not SORT_KEY=created_at), bearer tokens and URL passwords; never a single
  plain word or number. Redaction in transcripts and logs is unchanged.

What happens instead of Blocked (`removeSecrets`, tasks/git.ts)
- The secret is replaced with GODMODE_REMOVED_SECRET in text files; files
  that look like secrets, binaries holding one and files that can't be
  rewritten safely (not UTF-8, a link, not writable) are left out — they
  stay in the worktree, and one the branch already had keeps the remote's
  version.
- The unpushed commits become one commit on top of what the remote has (the
  branch's own last commit first), so no pushed commit or message carries
  the secret and nothing on the remote is rewritten. The branch as the agent
  left it stays in the worktree as refs/worktree/godmode/with-secrets/<sha>.
- Exactly the commit that was checked is pushed. A turn that stages or
  commits during the fix (or before a merge with someone else's push) makes
  Godmode skip this push; that turn's end pushes the branch.
- A warning names what was changed; the agent's brief asks it to read
  secrets from the environment; PR title and body never carry a saved
  secret, even with redaction off.

SecretInBranch and its three catch sites (publish, keepWork, pushTaskBranch)
are gone. Tasks already blocked with the old message push normally from the
board or when moved to Todo.
@danielehrhardt
danielehrhardt merged commit 7301ba8 into main Oct 4, 2026
5 of 6 checks passed
@danielehrhardt
danielehrhardt deleted the fix/secret-push-autofix branch October 4, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant