fix: make the pre-push key scan usable from worktrees and on macOS - #2
Merged
Conversation
The optional EVM key scan could not run at all in two common setups. Both
fail closed, so nothing was exposed — but a hook that cannot be installed or
cannot pass is a hook developers route around with --no-verify, which is the
outcome this is meant to prevent.
Git worktrees
-------------
Git exports GIT_DIR into hook processes. In a linked worktree that value is an
absolute path, so `git -C "$shared_dir" ...` still resolves against the pushing
repository: the hook read the *repo's* HEAD, origin and status instead of the
pinned policy checkout's, and refused with "Vana scanner checkout is at
<repo HEAD>, expected <policy SHA>". In a normal checkout GIT_DIR is the
relative ".git", which happens to resolve correctly under -C, which is why this
only bites worktrees.
Adds a `shared_git` helper that scrubs the inherited repository environment
(GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY,
GIT_ALTERNATE_OBJECT_DIRECTORIES, GIT_COMMON_DIR) and routes every command that
must target the policy checkout through it, in both hooks/pre-push and
scripts/install-pre-push.sh. Commands that scan the pushing repository keep the
inherited environment, which is what they want.
macOS checksum verification
---------------------------
macOS ships its own /sbin/sha256sum ("sha256sum (Darwin) 1.0"). It rejects the
GNU long options used in install-gitleaks.sh, so `command -v sha256sum`
succeeded, the GNU branch was taken, and the download check failed for every
download regardless of authenticity — the `shasum` fallback was never reachable
on the one platform that needed it. Prefer `shasum -a 256`, which accepts
--check/--status on both platforms, and keep sha256sum for minimal images that
ship coreutils but no perl.
Verified on macOS with a stock PATH (no Homebrew coreutils):
- install-pre-push.sh prepare now completes; previously it died on
`usage: sha256sum [-bctwz]`
- the hook runs from a linked worktree with GIT_DIR set and exits 0 on a
clean range; previously it refused before scanning
- detection is unchanged: the same hook still exits 1 and reports
"Potential EVM private key detected" on a range containing one
- `shasum -a 256 --check --status` was checked to exit 0 on a matching
digest and 1 on a mismatch, so the verification is still real
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tnunamak
pushed a commit
to vana-com/vana-sdk
that referenced
this pull request
Aug 18, 2026
…ixed policy Addresses both review findings on this PR. The hardcoded scrub list omitted GIT_CONFIG_GLOBAL, so the origin check was satisfiable from the caller's environment: a policy cache whose real origin is attacker-controlled passes validation when the caller supplies a global config naming vana-com/.github. Verified against this branch on git 2.53.0 — the check returned the spoofed URL, and returns the real (attacker) URL once the variable is scrubbed. The origin check runs before the SHA check, so the spoof is reachable rather than masked by a stale-cache refusal. Deriving the list from `git rev-parse --local-env-vars` also covers the repository-local variables the hardcoded set missed (GIT_SHALLOW_FILE, GIT_GRAFT_FILE, GIT_REPLACE_REF_BASE, GIT_IMPLICIT_WORK_TREE) plus GIT_CONFIG_PARAMETERS/GIT_CONFIG_COUNT. The GIT_CONFIG_* file overrides are not in that list, so they are added explicitly; a hardcoded fallback covers older git. Bumps CENTRAL_POLICY_SHA to vana-com/.github@9990452 (the merge of vana-com/.github#2), which is what makes this end-to-end: until the pinned policy contained the same fix, prepare and run failed one layer later. Verified against the real merged policy from a linked worktree with GIT_DIR set: prepare succeeds, a clean range exits 0, a range containing a key in a secret-shaped declaration is still detected and exits 1, and a cache with a spoofed origin is refused. Assisted-by: AI
tnunamak
added a commit
to vana-com/vana-smart-contracts
that referenced
this pull request
Aug 18, 2026
…igin check (#71) * ci(hooks): resolve the policy cache from a worktree and harden the origin check Applies the fix already merged in vana-com/.github#2 and vana-com/vana-sdk#189. Git exports an absolute GIT_DIR into hook processes from a linked worktree, so a bare `git -C "$policy_dir"` read the pushing repo's remote/HEAD/status and refused a valid policy cache. Routes every policy-targeting command through a `policy_git` helper that scrubs the inherited repository environment, derived from `git rev-parse --local-env-vars` plus the GIT_CONFIG_* file overrides — without GIT_CONFIG_GLOBAL the origin check is satisfiable from the caller's environment against an attacker-controlled cache. Bumps CENTRAL_POLICY_SHA to vana-com/.github@9990452 so the fix is end-to-end. Assisted-by: AI * ci: pin the key-scan workflow to the fixed policy The reusable workflow file is byte-identical between 5f1b4b1 and 9990452, so CI behavior is unchanged — but the workflow calls install-gitleaks.sh, which 9990452 fixes for macOS (Darwin ships its own /sbin/sha256sum that rejects the GNU long options, so the download checksum failed for every download). Keeps the CI pin and the bootstrap pin on the same reviewed policy commit. Assisted-by: AI --------- Co-authored-by: tnunamak <everyone@appears.blue>
tnunamak
added a commit
to vana-com/vana
that referenced
this pull request
Aug 18, 2026
…igin check (#24) The EVM key-scan bootstrap cannot pass from a git worktree, and its policy-cache origin check is satisfiable from the caller's environment. Both are fixed in the central policy (vana-com/.github#2) and in vana-sdk (vana-com/vana-sdk#189, merged); this applies the same fix here. ## Worktree bug Git exports `GIT_DIR` into hook processes. In a linked worktree that value is an **absolute** path, so `git -C "$policy_dir" ...` still resolves against the pushing repository and reports ITS remote, HEAD and status instead of the policy cache's. Validation then rejects a perfectly good cache: ``` Refusing unexpected policy-cache origin: ~/.local/share/vana-secret-scan/policy/<sha> ``` In a normal checkout `GIT_DIR` is the relative `.git`, which happens to resolve correctly under `-C` — which is why this only bites worktrees. A hook that cannot pass is a hook developers route around with `--no-verify`, which is the outcome this policy exists to prevent. ## Origin check hardening The scrub list is derived from `git rev-parse --local-env-vars` rather than hardcoded. Beyond the directory variables that fix the worktree bug, that covers the repository-local variables (`GIT_SHALLOW_FILE`, `GIT_GRAFT_FILE`, `GIT_REPLACE_REF_BASE`, `GIT_IMPLICIT_WORK_TREE`) and `GIT_CONFIG_PARAMETERS`/`GIT_CONFIG_COUNT`, which `git -c foo=bar push` exports into hooks. `GIT_CONFIG_GLOBAL` is **not** in that list, so it is added explicitly. Without it, a caller can point `remote.origin.url` at `vana-com/.github` from its own environment and satisfy the origin check against a cache whose real origin is attacker-controlled. Verified on git 2.53.0: with the directory-only scrub the check returned the spoofed URL; with `GIT_CONFIG_GLOBAL` scrubbed it returns the real (attacker) URL and refuses. The `git rev-parse --show-toplevel` that discovers the pushing repo deliberately keeps the inherited environment — that is exactly what it wants. ## Policy SHA bump `CENTRAL_POLICY_SHA` moves to `9990452` (the merge of vana-com/.github#2). This is what makes the fix end-to-end: until the pinned policy contained the same fix, `install`/`status` would fail one layer later in the central scripts. ## Verification Against the real merged policy, from a linked worktree with `GIT_DIR` set the way git sets it for hooks: - **before**: `Refusing unexpected policy-cache origin`, nothing scanned - **after**: validation passes and the policy cache is fetched at the pinned SHA - **spoof test**: with the cache's origin set to `https://github.com/attacker/evil.git` and `GIT_CONFIG_GLOBAL` claiming `vana-com/.github`, this branch refuses at the origin check - **detection unchanged**: verified in vana-sdk against the same policy — a range containing a key in a secret-shaped declaration still exits 1 with `Potential EVM private key detected` This file is byte-identical across the five remaining repos, so the same patch applies to each. Assisted-by: AI --------- Co-authored-by: tnunamak <everyone@appears.blue>
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.
The optional EVM key scan could not run at all in two common setups. Both fail closed, so nothing was exposed — but a hook that cannot be installed, or cannot pass, is a hook developers route around with
--no-verify. That is the outcome this policy exists to prevent.1. Git worktrees
Git exports
GIT_DIRinto hook processes. In a linked worktree that value is an absolute path, sogit -C "$shared_dir" ...still resolves against the pushing repository: the hook read the repo's HEAD, origin and status instead of the pinned policy checkout's, and refused withVana scanner checkout is at <repo HEAD>, expected <policy SHA>. In a normal checkoutGIT_DIRis the relative.git, which happens to resolve correctly under-C— which is why this only bites worktrees.Adds a
shared_githelper that scrubs the inherited repository environment and routes every command that must target the policy checkout through it, in bothhooks/pre-pushandscripts/install-pre-push.sh. Commands that scan the pushing repository keep the inherited environment, which is what they want.The scrub list is taken from
git rev-parse --local-env-varsrather than hardcoded, plus theGIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM/GIT_CONFIG_NOSYSTEMoverrides that are not in that list, with a hardcoded fallback for a git too old to answer.Why the config vars matter.
git -c remote.origin.url=... pushexportsGIT_CONFIG_PARAMETERSinto hooks. Scrubbing only the directory variables fixes the worktree bug but makes the origin integrity check satisfiable from the caller's environment rather than the checkout's real config. That is not reachable onmaintoday — theGIT_DIRbug masks it by failing at the SHA check first — so it is a hole this fix would have opened had it stopped at the directory variables. Verified both ways, see below.2. macOS checksum verification
macOS ships its own
/sbin/sha256sum(sha256sum (Darwin) 1.0). It rejects the GNU long options used ininstall-gitleaks.sh, socommand -v sha256sumsucceeded, the GNU branch was taken, and the download check failed for every download regardless of authenticity — theshasumfallback was never reachable on the one platform that needed it.install-pre-push.sh preparetherefore died onusage: sha256sum [-bctwz]and the hook could never be installed.Prefers
shasum -a 256, which accepts--check/--statuson both platforms, keepingsha256sumfor minimal images that ship coreutils but no perl.Note
verify-gitleaks.shis deliberately untouched: its plainsha256sum "$file"produces byte-identical<hash> <path>output on Darwin and GNU, so there is no bug there.Verification
On macOS with a stock
PATH(no Homebrew coreutils), against a scratch policy cache:install-pre-push.sh preparecompletes; previously it died on thesha256sumusage errorGIT_DIRset and exits 0 on a clean range; previously it refused before scanning anythingPotential EVM private key detectedon a range containing oneshasum -a 256 --check --statuswas checked to exit 0 on a matching digest and 1 on a mismatch, so verification is still realhttps://github.com/attacker/evil.gitandGIT_CONFIG_PARAMETERS/GIT_CONFIG_COUNTset to claimvana-com/.github, this branch refuses at the origin check. A directory-variables-only scrub accepted it and proceeded.Downstream
vana-sdkpins this repo by SHA (CENTRAL_POLICY_SHAin.github/scripts/install-evm-key-scan-hook.sh) and has the sameGIT_DIRbug in its own bootstrap — fixed in vana-com/vana-sdk#189. That PR needs its pinned SHA bumped to this merge commit before the fix takes effect end to end.🤖 Generated with Claude Code