docs: fix audit DB filename and document placeholder sentinel#9
Closed
8enji wants to merge 15 commits into
Closed
Conversation
IsSecretLike previously flagged any env var whose name matched the secret regex (key/secret/token/password/auth/credential/dsn) regardless of value, producing false-positive vaulting (LOG_LEVEL_AUTH=info, DB_PASSWORD_PROMPT=true) and false-positive run refusals. Now name-pattern matches must also clear len>=12 AND distinct>=6. Provider patterns, URL-with-password, and the length+entropy path are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
No behavior change. Adds the data shape needed by the upcoming basicCorrelator and the init flow's buildEnvFileCredentials basic branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pairs <prefix>USER(NAME)?<suffix> with <prefix>(PASSWORD|PASS)<suffix> using strict decoration matching. Password partner must clear a length+distinct value-shape floor (12/6) so fixture-style trivial values like DB_USER=test, DB_PASSWORD=test do not pair. Correlator is not yet registered in DetectAll — wired up next. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AWS triples are still claimed first; remaining candidates pass through the basic correlator. Integration test covers mixed input with both schemes plus a loose bearer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
basicCorrelator needs to see non-secret-shaped USER/USERNAME candidates that ScanEnviron drops via IsSecretLike. ScanEnvironForPairs keeps the denylist filter but omits the value-shape check, returning every plausibly-non-system env var for the correlator to pair against. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
processEnvFile now feeds every KV line into correlate.DetectAll (not just IsSecretLike-filtered) so USERNAME halves with non-secret-shaped values reach the basic correlator. Detected pairs become one basic-scheme credential (Username/UsernamePlaceholder fields set), and the .env file is rewritten with placeholders for both halves. The interactive prompt now groups basic pairs under a [basic] tag and counts them alongside any AWS triples. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
processShellEnv now uses the broader ScanEnvironForPairs pool for the correlator while keeping the existing IsSecretLike-filtered set for the loose-bearer path. Basic groups are vaulted as a single credential with Username + UsernamePlaceholder set; the interactive prompt labels them under [basic] and counts them in the header alongside AWS triples. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls the Basic-scheme decode out of tryRewriteBasic so the upcoming ClassifyBasicLeak diagnostic can reuse it. Behavior unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diagnostic helper for the leak handler: when both halves of a Basic header decode to placeholders belonging to two different credentials, returns a "how to fix" hint pointing at `veil add --scheme basic` or `veil init --force`. Returns "" otherwise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the leak guard fires on a Basic header whose two halves point to two different vault credentials, the 502 response now carries a targeted hint identifying the cred names and a `veil add --scheme basic` / `veil init --force` recipe. Header X-Veil-Error: basic_unpaired distinguishes this case for tooling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pins the runtime fail-closed behavior to the new value-shape gate: trivial-value name matches no longer trigger the unvaulted warning, real-shaped tokens still do. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gofmt prefers single spaces between aligned struct field types and between value-and-trailing-comment columns. Also replace empty backticks in basic.go's regex-explanation comment with prose so Go's doc-comment formatter doesn't smart-quote them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The hint suggested `veil add NAME --scheme basic --user X --value-stdin`, but `veil add` doesn't accept --scheme basic — basic is implied by setting --user. A user copying the hint verbatim would hit "unknown --scheme basic". Lead with `veil init --force` as the primary recipe (the basic-pair correlator picks them up automatically); demote `veil add` to a fallback with corrected syntax. The cred NAME passed to `veil add` is the password var (the existing canonical record), not the username var. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vault.Credential now persists UsernameVar (the source env-var name for the username half of a basic credential) so recoverPendingEnvRewrite can check the username line against c.Username, the same way it already checks the password line against c.Real. Before this fix, the divergence check only matched line.Key against c.Name (the password var). For a basic cred, the username var (e.g. GH_USERNAME) is never bound to a separate vault entry, so a user editing only the username between a crash and the re-run had their edit silently overwritten when recovery replayed the placeholder rewrite. UsernameVar is populated in both init flows (buildEnvFileCredentials and vaultShellBasicGroup); it's empty for manually-added basic creds (`veil add --user ...`) and non-basic schemes, which makes the new divergence check a no-op for those — matching the existing aws-scheme opt-out pattern. Regression test: TestRecoverPendingEnvRewriteDetectsBasicUsernameEdit asserts the recovery path surfaces an actionable error when only the username half has been edited. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CHANGELOG entries for v0.1.0 and v0.1.1 referenced `.veil/audit.db`, but the on-disk file has always been `.veil/audit.sqlite` (see internal/config/project.go:75). Correct both entries. Add a "What Veil does NOT protect against" bullet to THREAT_MODEL.md calling out that every Veil-generated placeholder embeds a literal `VEIL` substring as a fail-closed leak sentinel — an agent scanning for this substring can identify which inputs are placeholders, though it learns nothing about the real secret. This is consistent with the cooperative-but-curious model and the design tradeoff already documented in internal/placeholder/engine.go. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Merging locally instead. |
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.
Summary
Two small docs fixes from pre-launch E2E review:
.veil/audit.db, but the on-disk file has always been.veil/audit.sqlite(internal/config/project.go:75). Both entries corrected.docs/had no remainingaudit.dbreferences.VEILsubstring as a fail-closed leak sentinel (see internal/placeholder/engine.go —const Sentinel = "VEIL"). An agent that scans its inputs for this substring can identify which.env/ MCP-config values are placeholders, though it learns nothing about the real secret. Added a bullet todocs/THREAT_MODEL.md's "What Veil does NOT protect against" section calling this out as consistent with the cooperative-but-curious model.F16 (
--yesflag forveil list --revealon non-TTY) was investigated and found to already be wired in internal/cli/list.go:34 with a clearUsagestring — no change needed. Verified end-to-end below.Test plan
rg 'audit\.db' docs/returns no hitsrg 'audit\.db' --type mdreturns no hits (CHANGELOG clean)docs/THREAT_MODEL.mdreads cleanly (new bullet at line 19, list structure intact)veil list --helpshows:--yes bypass TTY safety check for --reveal (scripted use)veil list --reveal --yes | catprints the table without errorveil list --reveal | caterrors with "Pipe or redirect detected. Re-run with --yes to override."go build ./...cleango vet ./...clean🤖 Generated with Claude Code