This repository holds the Colvenna series website: the generated static pages (index.html, site.js, styles.css) and the brand assets. GitHub Pages publishes it from the root of main, at the domain in CNAME.
The site files are generated by the series index's site build and copied here in a pull request. A sync replaces the site files only. This repository's own files are not part of that build, and a sync keeps them: this README, .gitignore, .gitguardian.yaml, .pre-commit-config.yaml, scripts/ and .github/.
Nothing is made public before ggshield, GitGuardian's command-line scanner, finds 0 incidents in it with this repository's .gitguardian.yaml. The repository is public, so a push publishes its commits, and a merge into main publishes the website. The local hooks below are a best-effort check before a push, and CI scans each push again. A ruleset on main requires a pull request whose secret scan check passes and whose branch is up to date with main, and blocks force pushes and deletion. Before merging, a maintainer also runs the full scan. ggshield is installed from a hash-locked file:
python3 -m venv ~/.venvs/colvenna-ggshield
~/.venvs/colvenna-ggshield/bin/python -m pip install --require-hashes --only-binary=:all: \
-r scripts/ggshield-requirements.lock
export PATH="$HOME/.venvs/colvenna-ggshield/bin:$PATH" GITGUARDIAN_API_KEY=... # or: ggshield auth login-
Each pull request: the secret scan workflow scans the new commits of each push and pull request with the
GITGUARDIAN_API_KEYActions secret, which the repository owner sets. A manual run scans the whole history.- Pull requests from forks get no secrets, so for them the job only notes this. A maintainer scans such a change before merging it.
-
Before merging a site sync, a maintainer also runs the full scan on the sync's branch and records its summary in the pull request. Check the remaining API quota first with
ggshield quota, because a full scan uses part of it.scripts/ggshield-scan.sh <private directory> <sync branch>
It scans everything the public can fetch:
- an anonymous mirror clone (every branch, tag and
refs/pull/*), plus each pull-request head that a force push replaced and GitHub still serves. The website is the repository's content, so this covers it; - the GitHub text: issues, pull requests, comments, reviews, release notes and commit comments.
It uses the
.gitguardian.yamlof the given branch (mainby default), and refuses any ggshield version other than the one in the lock file. ggshield's default exclusions (for examplevendor/,node_modules/,*.mdxand*.sops) apply to every scan and cannot be turned off in 1.56.1, so any path in the history that they match makes the scan fail. It also scans the wiki when the wiki is enabled; an enabled wiki that cannot be cloned makes it fail. It exits 0 only when every scan is complete and finds 0 incidents; any file that ggshield skips, other than binary files, makes it fail.The reports in the directory contain the matched values, so keep the directory private. The summary has no values.
- an anonymous mirror clone (every branch, tag and
-
Each commit and each push (best effort):
pre-commit installenables the ggshield hooks. They use theggshieldonPATHand refuse any version other than the one in the lock file.- The pre-commit hook scans the staged changes.
- The pre-push hook scans the commits about to be published. It covers at most
max_commits_for_hookcommits of a push (1000, set in.gitguardian.yaml), and ggshield lets a push through with only a warning when it cannot work out the commit range. When one push updates several refs (git push --all, or several branches or tags), pre-commit hands ggshield only the first, so push them one at a time. - Without an API key, they stop with ggshield's error.
SKIP=ggshield,ggshield-pushorgit push --no-verifyskips them. The CI job and the full scan still apply.
-
A finding:
- A real credential is revoked or rotated first, then the history is reviewed. It is never ignored.
- Any other finding is added to
.gitguardian.yamlby its ignore SHA, with a name that gives the file and the reason. The addition is reviewed in its pull request. - No path or detector is ignored.
-
Deployment values: ggshield does not look for AWS account IDs, ARNs, endpoints or internal addresses, so before merging, a maintainer also searches what the full scan fetched:
- Each account that a deployment of yours used must appear 0 times.
- List the accounts named in ARNs, the AWS endpoint hosts and the private IPv4 addresses, and review each one.
Documentation examples, such as
123456789012, are expected:ACCOUNT=<your deployment account ID>; DIR=<private directory> content() { for git in "$DIR"/mirror.git "$DIR"/wiki.git; do if [ -d "$git" ]; then git -C "$git" log --all -p; fi; done grep -rhI '' "$DIR/github-text"; } content | grep -c "$ACCOUNT" # must be 0 content | grep -oE 'arn:aws[a-z-]*:[a-z0-9-]*:[a-z0-9-]*:[0-9]{12}:' | grep -oE '[0-9]{12}' | sort | uniq -c content | grep -oE '[a-z0-9.-]+\.(amazonaws\.com|cloudfront\.net|awsapps\.com)' | sort | uniq -c content | grep -oE '\b(10\.[0-9]+|172\.(1[6-9]|2[0-9]|3[01])|192\.168)\.[0-9]+\.[0-9]+\b' | sort | uniq -c
See LICENSE.