Skip to content

Scan for secrets with ggshield before anything is published (#4) - #5

Merged
amliuyong merged 6 commits into
mainfrom
codex/issue-4-ggshield
Nov 5, 2026
Merged

amliuyong merged 6 commits into
mainfrom
codex/issue-4-ggshield

Conversation

@amliuyong

@amliuyong amliuyong commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Closes #4. Nothing here goes public before ggshield (GitGuardian's CLI) finds 0 incidents in it with the repository's own configuration. Every commit pushed here is public, and a merge into main publishes the website.

Changes

  • .gitguardian.yaml: the backfill scan found nothing, so nothing is ignored. max_commits_for_hook is 1000.

  • scripts/ggshield-scan.sh, the full scan. It covers:

    • an anonymous mirror clone (every branch, tag and refs/pull/*, plus force-pushed-away PR heads GitHub still serves); the site is the repository's content, so this covers the site too;
    • the GitHub text: issues, PRs, comments, reviews, release notes, commit comments;
    • the wiki, when it is enabled.

    It fails closed:

    • when ggshield reports errors or "Scanning failed";
    • when ggshield skips a file that is not binary;
    • when a history path matches ggshield's default exclusions. Paths are listed unquoted, and the check uses ggshield's own matcher;
    • when the output directory is under such a path.

    It refuses any ggshield version other than the pinned one. Its summary records no values.

  • Hooks: scripts/ggshield-hook.sh runs the pre-commit and pre-push hooks. It uses only the ggshield version in scripts/ggshield-requirements.lock (hash-locked, Linux arm64).

  • .github/workflows/ggshield.yml runs ggshield secret scan ci on each push and PR, and a full-history scan when run manually.

    • After a force push, the replaced base is fetched by its SHA.
    • PRs from forks get a notice.
  • .gitignore keeps .cache_ggshield out of the repository; the file holds the latest findings.

  • README.md describes the repository and which files a site sync keeps (they are not part of the series site build). It also documents the rule:

    • the full scan before merging a sync;
    • the best-effort hooks and their limits;
    • the main ruleset (active): a PR whose secret scan check passes on an up-to-date branch, no force pushes, no deletion;
    • the deployment-value review commands.

Outside the diff, done for #4: the repository's wiki had no page and is now disabled.

Validation

  • shellcheck and actionlint: OK. Both hooks pass with the pinned ggshield and refuse a wrong version.
  • Full scan of this branch at 8071090, with the branch's own .gitguardian.yaml: VERDICT: CLEAN.
    • history: 16 commits and 5 refs/pull/*, 0 incidents;
    • GitHub text: 0 incidents;
    • no history path is excluded.
  • Review: Standards and Spec, six rounds; the last two found nothing on either axis.
  • CI ggshield job: it needs the GITGUARDIAN_API_KEY Actions secret, which the owner sets. Until then it fails at its last step with "secret is not set". The hash-locked install passes.

🤖 Generated with Claude Code

amliuyong and others added 6 commits November 4, 2026 12:39
Nothing is made public before ggshield finds 0 incidents with the
repository's own configuration:

- .gitguardian.yaml: the full scan of 2026-11-04 found nothing, so
  nothing is ignored.
- scripts/secret-scan.sh: the full scan of an anonymous mirror clone,
  including refs/pull/* and the force-pushed-away PR heads GitHub still
  serves. The website is the repository's content, so this covers it.
  The summary holds no values.
- The ggshield pre-commit hook is pinned to v1.56.1's commit.
- The secret scan workflow scans each push and pull request with the
  GITGUARDIAN_API_KEY secret, from a hash-locked install. Fork pull
  requests get a notice, and a manual run scans the whole history.
- README.md describes the repository, which files a site sync keeps,
  and the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These changes address the review of b089ef1.

- scripts/ggshield-scan.sh also scans the GitHub text: issues, pull
  requests, comments, reviews, release notes and commit comments. It
  records the API quota and gives a plain message when the branch is
  missing.
- It fails when ggshield reports errors or "Scanning failed", even on
  exit 0, and when ggshield skips any file that is not binary.
- A merge into main is the publication, so the README now has the full
  scan run before a site sync is merged.
- CI drops a push base that the checkout lacks (a new branch or a force
  push), so ggshield scans everything not on main instead of only the tip.
- The pre-commit hook runs the hash-locked ggshield from PATH.
- Names now match colvenna-isle's: ggshield-scan.sh,
  ggshield-requirements.lock and workflows/ggshield.yml.
- .gitignore keeps .cache_ggshield, which holds the latest findings, out
  of the repository.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These changes address the second review.

- scripts/ggshield-hook.sh pins the ggshield version for the pre-commit
  and pre-push stages. In a public repository a push is the publication,
  so the pre-push stage is the check before it.
- scripts/ggshield-scan.sh refuses a ggshield version other than the
  pinned one. It scans the wiki when the wiki is enabled, and fails when
  an enabled wiki cannot be cloned. The repository's wiki had no page and
  is now disabled. A failed pull-request listing now stops the script
  instead of dropping reviews silently.
- CI fetches a force-pushed-away base by its SHA, so only the new commits
  are scanned, including on main.
- The README now gives the timing of publication, says which files a sync
  keeps, and has concrete commands for the deployment-value check.
- The .gitguardian.yaml comment is re-wrapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

These changes address the third review.

- ggshield 1.56.1 always applies default exclusions (vendor/,
  node_modules/, .venv/, *.mdx, *.sops, ...) without reporting them. The
  full scan lists every path in a history that they match, using
  ggshield's own matcher, and fails on any.
- The wiki check reads has_wiki before testing it, so a failing gh call
  stops the script instead of skipping the wiki.
- .gitguardian.yaml raises max_commits_for_hook to 1000.
- The README calls the local hooks a best-effort check and names their
  limits. It says the pull-request check before a merge is a convention,
  since main has no rule to enforce it. It gives deployment-value
  commands that cover the GitHub text, ARN accounts and private IPv4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These changes address the fourth review.

- The full scan lists history paths unquoted (core.quotePath=false, -z),
  because git had quoted a non-ASCII path and it slipped past the
  default-exclusion check.
- It refuses an output directory under a path the default exclusions
  match, since ggshield would drop every file there without notice.
- The README names pre-commit's first-ref-only pre-push behaviour and
  lists AWS endpoint hosts for the deployment-value review. The content()
  helper no longer returns 1 when there is no wiki.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now has an active ruleset. It requires a pull request whose
'Scan for secrets with ggshield' check passes on a branch that is up to
date with main, and it blocks force pushes and deletion. The README had
called that check a convention.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@amliuyong
amliuyong merged commit ed48935 into main Nov 5, 2026
3 of 5 checks passed
@amliuyong
amliuyong deleted the codex/issue-4-ggshield branch November 5, 2026 01:38
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.

[安全] 仓库已公开:补做 ggshield 完整历史与制品扫描,并加上日常拦截

1 participant