diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..751f853 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,34 @@ + +## Summary + + + +## AI Provenance Declaration + + + +- [ ] AI generated or assisted with **code** in this PR +- [ ] AI generated or assisted with **tests** in this PR +- [ ] AI introduced or suggested **new dependencies** in this PR +- [ ] AI generated or assisted with **documentation** in this PR + +**AI tool(s)/model(s) used (if any):** + +**Human review performed on AI-generated parts (what/how):** + +## Dependency Changes + + + +- [ ] No new dependencies +- [ ] New dependencies validated (`sscsb deps check`) and approved + +## Merge Policy Reminder + +Merges to protected branches must be signed by an approved **human** hardware-backed +key. When AI involvement is declared above, the merge commit needs review +evidence (`Reviewed-by:` trailer). See `docs/signing.md`. diff --git a/.github/chainguard/sscsb-automation.sts.yaml b/.github/chainguard/sscsb-automation.sts.yaml new file mode 100644 index 0000000..7882c0c --- /dev/null +++ b/.github/chainguard/sscsb-automation.sts.yaml @@ -0,0 +1,26 @@ +# sscsb Octo STS trust policy — lives at .github/chainguard/sscsb-automation.sts.yaml +# in the repo that GRANTS access. Workflows in `subject_pattern` below can +# exchange their OIDC identity for a short-lived token with EXACTLY these +# permissions on THIS repo. No PAT, nothing stored, expires in ~1 hour. +# +# Docs: https://github.com/octo-sts/app +issuer: https://token.actions.githubusercontent.com + +# Which workflow identities may federate. GitHub's OIDC `sub` claim is +# ID-DECORATED — `repo:OWNER@/REPO@:ref:refs/heads/main` — +# so a pattern spelled from names alone never matches (Octo STS refuses with +# `subject "repo:OWNER@123/REPO@456:ref:…" did not match "repo:OWNER/REPO:ref:…"`). +# The `(@)?` groups accept both the bare and the decorated form; the ids +# are what survive a rename and what a re-created repository of the same name +# does NOT share, so pin them (sscsb fills them in from the GitHub API when +# `gh` is available; otherwise `[0-9]+` accepts any id until you replace it): +# gh api repos/grcengineering/grcengineering.github.io --jq .id → repo id +# gh api users/grcengineering --jq .id → owner id +# `.` in the repository name is escaped: this is a regular expression. +subject_pattern: 'repo:grcengineering(@155832502)?/grcengineering\.github\.io(@743624125)?:ref:refs/heads/main' + +permissions: + # Least privilege: grant only what the automation needs. + contents: read + # issues: write + # pull_requests: write diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5706725..e646732 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,32 +1,50 @@ -name: Deploy GRC Engineering MkDocs site +name: Deploy GRC Engineering MkDocs site on: push: branches: - - master + - master - main + +# Least privilege at the top level: nothing inherits write. The single job that +# genuinely needs to write takes a job-scoped grant below. permissions: - contents: write + contents: read + jobs: deploy: runs-on: ubuntu-latest + permissions: + # `mkdocs gh-deploy` pushes the built site to the gh-pages branch. + contents: write steps: - - uses: actions/checkout@v4 + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + # persist-credentials stays at its default (true) for this job ONLY: + # `mkdocs gh-deploy` pushes to the gh-pages branch over the origin remote + # and needs the checkout credential to do it. Every other workflow in this + # repo sets persist-credentials: false. + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Configure Git Credentials run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: 3.x - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v4 + - run: echo "cache_id=$(date --utc '+%V')" >> "$GITHUB_ENV" + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: key: mkdocs-material-${{ env.cache_id }} path: .cache restore-keys: | mkdocs-material- - - run: pip install mkdocs-material - - run: pip install "mkdocs-material[imaging]" - - run: pip install mkdocs-git-revision-date-localized-plugin - - run: pip install mkdocs-git-committers-plugin-2 - - run: mkdocs gh-deploy --force \ No newline at end of file + # Version-pinned: an unpinned `pip install` takes whatever the index serves + # at build time, so a compromised or yanked upstream release lands silently. + # Renovate (renovate.json5) proposes the bumps. + - run: pip install "mkdocs-material==9.7.7" + - run: pip install "mkdocs-material[imaging]==9.7.7" + - run: pip install "mkdocs-git-revision-date-localized-plugin==1.5.4" + - run: pip install "mkdocs-git-committers-plugin-2==2.5.0" + - run: mkdocs gh-deploy --force diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..c75c73f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,57 @@ +# sscsb: CodeQL — deep interprocedural analysis on PRs and the default branch. +# +# Languages for THIS repo. The sscsb template ships `actions` only and tells you +# to add your own, because CodeQL that does not read your source code is not +# analysing your source code: +# actions — the workflows in this directory +# javascript-typescript — docs/javascripts/tablesort.js and the nthpartyfinder +# design-system scripts (ds/node-graph.js, +# ds/site-header.js), plus the inline