Skip to content

feat(security): fail-closed secret-scan gate for the public docs site#50

Merged
JacobPEvans-personal merged 3 commits into
mainfrom
feat/secret-scan-gate
Jun 2, 2026
Merged

feat(security): fail-closed secret-scan gate for the public docs site#50
JacobPEvans-personal merged 3 commits into
mainfrom
feat/secret-scan-gate

Conversation

@JacobPEvans-personal
Copy link
Copy Markdown
Member

@JacobPEvans-personal JacobPEvans-personal commented May 31, 2026

Secret-scan gate for the public docs site

What

Adds a fail-closed gitleaks gate so no
sensitive value can reach docs.jacobpevans.com, and mirrors the change into the
docs themselves.

  • .github/workflows/secret-scan.yml — runs on PRs (incl. drafts) and push to
    main. No script: two declarative steps — select the ruleset via shell
    parameter expansion, then scan with the official gitleaks OSS Docker image
    (ghcr.io/gitleaks/gitleaks:v8.30.1). The gitleaks GitHub Action requires a
    paid license for org accounts; the image does not.
  • .gitleaks.toml.example — the public-safe generic baseline (built-in
    credential rules + placeholder allowlist + .git skip). It is a template /
    fork fallback, not the active config.
  • security/scrubbed-values.mdx — documents the gate (the implementation of
    golden law 1).
  • automation/scheduled-routines/claude-code-routines.mdx — registers the new
    Docs Sync routine (six → seven).

Two-layer design (list stays private)

The full org-specific ruleset lives only in the private docs-starlight repo
and reaches CI as the encrypted GITLEAKS_PRIVATE_CONFIG secret, run with
--redact (patterns and matches never appear in public logs). When the secret is
absent (fork PRs), the workflow falls back to the committed
.gitleaks.toml.example via ${GITLEAKS_PRIVATE_CONFIG:-$(cat …)} — so forks
still get credential detection, and full org-specific coverage runs on push to
main.

Validation

  • CI green: the Docker image pulls and runs, gitleaks reports no leaks found
    on the docs tree (using the example fallback, since the secret isn't set yet).
  • The full ruleset was validated against fixtures (in docs-starlight#17): flags a
    dirty fixture, passes clean content, no false positives on CLAUDE.local.md,
    svc.cluster.local, 192.168.0.x, example.com.

⚠️ Before enabling the full ruleset

Running the full ruleset against the existing docs surfaces 3 pre-existing
visicore references
(in observability/overview.mdx and a .claude/ skill).
The GITLEAKS_PRIVATE_CONFIG secret is therefore not set yet — doing so would
make the gate fail-closed on existing content. Decide: strip the refs, allowlist
visicore as intentionally public, or adjust the client-terms rule. Until then,
the gate runs the safe generic baseline (this PR is green on it).

Operator setup (after the decision above)

gh secret set GITLEAKS_PRIVATE_CONFIG --repo dryvist/docs \
  < security/gitleaks-public-docs.toml   # from the docs-starlight checkout

Then make Secret Scan a required check on main.

Related

  • dryvist/docs-starlight#17 (merged) — the private ruleset this consumes.
  • dryvist/docs-starlight#18.git scan-skip follow-up.
  • dryvist/claude-code-routines#36 (merged) — the Docs Sync routine.

🤖 Generated with Claude Code

Adds a gitleaks secret-scan gate so no sensitive value can reach
docs.jacobpevans.com:
- scripts/secret-scan.sh installs pinned, checksum-verified gitleaks and scans
  the committed tree (git archive HEAD), fail-closed.
- .github/workflows/secret-scan.yml runs it on PRs (incl. drafts) + push to main.
- .gitleaks.toml is the public-safe generic baseline (credential rules +
  placeholder allowlist). The org-specific ruleset stays private in docs-starlight
  and reaches CI as the redacted GITLEAKS_PRIVATE_CONFIG secret; fork PRs fall back
  to the baseline.

Mirrors the change into the docs: documents the gate in security/scrubbed-values.mdx
and registers the new Docs Sync routine in
automation/scheduled-routines/claude-code-routines.mdx.

The gitleaks Action requires a license for org accounts, so the Apache-2.0 binary
is installed directly instead.

Assisted-by: Claude:claude-opus-4-8
…cript

Replaces scripts/secret-scan.sh with two declarative workflow steps: select the
ruleset (private secret, else committed example) via shell parameter expansion,
then scan with the official gitleaks OSS Docker image — no GitHub Action license
(required for org accounts) and no custom install logic.

- Renames .gitleaks.toml -> .gitleaks.toml.example: it is a template + fork
  fallback, not the active config. The active ruleset is injected from the
  GITLEAKS_PRIVATE_CONFIG secret.
- Adds a .git path allowlist so VCS metadata is not scanned.

Validated: config parses; a planted .git secret is ignored; the gate still flags
the pre-existing client-term references in the docs tree.

Assisted-by: Claude:claude-opus-4-8
Switches the gate from the raw gitleaks Docker image to gitleaks-action@v2, now
that the dryvist org provides GITLEAKS_LICENSE_KEY. The ruleset is injected from
the org-wide GITLEAKS_PRIVATE_CONFIG secret (never committed — the sensitive list
stays private), materialized to a config file at run time.

The action runs gitleaks with --redact; PR comments, SARIF artifact, and job
summary are disabled so the rule taxonomy / file locations are not exposed on
this public repo. Removes the now-unused .gitleaks.toml.example. Updates the
security doc to match.

Assisted-by: Claude:claude-opus-4-8
@JacobPEvans-personal JacobPEvans-personal merged commit 49dce01 into main Jun 2, 2026
3 checks passed
@JacobPEvans-personal JacobPEvans-personal deleted the feat/secret-scan-gate branch June 2, 2026 00:55
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