-
Notifications
You must be signed in to change notification settings - Fork 1
128 lines (118 loc) · 6.07 KB
/
Copy pathci.yml
File metadata and controls
128 lines (118 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# Least-privilege GITHUB_TOKEN, SHA-pinned actions, and the gates that run on every pull
# request: SAST, secret scan, workflow SAST, and `make verify` (lockfile drift, lint,
# format, types, tests, SCA, the HTML-conformance and WCAG checks over the built pages in
# two engines, WCAG 2.2 Reflow at a 320px viewport, and the determinism check). CodeQL
# runs from codeql.yml.
#
# These gates report. As of 2026-08-15 they block nothing. `main` carries no ruleset and
# no branch protection: `gh api repos/ChelseaKR/perimeter/rulesets` returns `[]`,
# `branches/main` returns `"protected": false`, and `branches/main/protection` 404s. So
# `main` can be force-pushed, deleted, or pushed to with every check on this page red.
# This header used to open by calling these gates merge-blocking, which was the opposite
# of what the server enforces, and a reader who opened the file to check the posture was
# told the wrong thing. The profile that would make the sentence true is committed at
# `.github/rulesets/main.json`; applying it is a live repository setting and the owner's
# call. Edit this paragraph when the ruleset goes on, not before.
#
# Every action is pinned to the full 40-char commit SHA of its tag, resolved
# 2026-08-07 via `gh api repos/OWNER/REPO/commits/TAG`. Actions stay
# `@<sha> # vX.Y.Z` so the version stays readable next to the pin.
#
# CI never touches the network for data. `data/raw/` is not in the repo, so the
# test suite runs entirely against committed fixtures.
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
version: ">=0.11.0"
python-version: "3.12"
# `make verify` includes `make pages`, which runs html-validate and axe-core over
# the pages built from committed fixtures, then the same axe rule sets and the
# WCAG 2.2 Reflow spec again in Chromium. Nothing is served and nothing is
# deployed: every checker reads files off disk, the browser included, as file://
# URLs. `make browser-sync` fetches the browser binary, which is the only thing
# this job takes off the network beyond its packages.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
cache: npm
# `make verify` ends in `make determinism`: two builds into two directories,
# compared by tools/determinism.sh. That check used to be four lines inlined here,
# and it could not fail. `find` on a missing directory exits 1, but under the
# default `bash -e` shell without `pipefail` a pipeline reports its last command's
# status, so the step stayed green; and with no files to hash both sides came out
# identical, so an empty build passed. The script refuses an empty or missing tree,
# and tests/test_determinism_gate.py runs it against trees that should fail it.
- name: make verify (byte-for-byte the local target)
run: make verify
secret-scan:
runs-on: ubuntu-latest
permissions:
contents: read
# The action lists the PR's commits to scope its scan to them, which needs
# pull-requests:read. Read only: it does not write to the PR, see below.
pull-requests: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
# Comments off so the job needs nothing beyond contents:read. With them on the
# action asks for pull-requests:write to annotate the PR, and a least-privilege
# token gets a 403 instead. Findings still fail the job and appear in the log.
- uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_ENABLE_COMMENTS: "false"
GITLEAKS_ENABLE_UPLOAD_ARTIFACT: "false"
sast:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
- run: uvx --from semgrep==1.168.0 semgrep scan --error --metrics off --config p/python --config p/javascript --config p/security-audit .
# CICD-19. Nothing in this repository looked at the workflows themselves until now:
# `verify` runs `make verify`, which never reads them, gitleaks scans for secrets, and
# semgrep's p/python, p/javascript and p/security-audit rule sets carry no GitHub
# Actions rules. pages.yml only triggers on push to main, so the five open dependabot
# PRs that change nothing but pages.yml went green against three checks, none of which
# read the file they changed. This job and codeql.yml are what close that.
zizmor:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
# Online mode, on purpose. zizmor defaults to offline and, in that mode, silently
# drops the audits that need the API: whether a pinned SHA is still reachable from
# its tag, and whether a `uses:` resolves upstream at all. A gate that quietly runs
# a subset of itself is the failure mode this repository is trying not to have.
# GITHUB_TOKEN's contents:read is the whole permission it needs.
- name: workflow static analysis (zizmor, online)
run: uvx --from zizmor==1.29.0 zizmor --format=plain .github/workflows/
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}