Skip to content

Commit 64ef20a

Browse files
ci: harden workflows + resolve Hypatia findings at source (#178)
Adds codeql.yml (javascript-typescript + actions), secret-scanner.yml, and .github/dependabot.yml; pins the governance reusable to a SHA; adds timeout-minutes to the real-step jobs; grants scorecard's analysis job the documented caller permissions; and adds .hypatia-ignore for two verified false positives (agda_postulate on Smoke.agda comments; SVG-namespace http URL in build-banner.mjs). Advisory Hypatia scan after these changes: Critical 0. Remaining items are upstream rule limitations (hypatia/standards), addressed by a separate patch. No proofs/Agda/core files touched. All 21 checks green. https://claude.ai/code/session_01Jxr3Wy4ngpkbc2QwjEam82
1 parent 71ac8c8 commit 64ef20a

8 files changed

Lines changed: 154 additions & 2 deletions

File tree

.github/dependabot.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Dependabot configuration for echo-types.
3+
#
4+
# echo-types is an Agda proof repository with no language package
5+
# manifests (no Cargo.toml / package.json / mix.exs / requirements).
6+
# The relevant ecosystem is GitHub Actions — this keeps the SHA-pinned
7+
# reusable workflows and third-party actions current, and satisfies the
8+
# OSSF Scorecard "Dependency-Update-Tool" check.
9+
10+
version: 2
11+
updates:
12+
- package-ecosystem: "github-actions"
13+
directory: "/"
14+
schedule:
15+
interval: "weekly"
16+
groups:
17+
actions:
18+
patterns:
19+
- "*"

.github/workflows/agda.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ permissions: read-all
2727
jobs:
2828
check:
2929
runs-on: ubuntu-latest
30+
# Bound the job so a hung typecheck/clone cannot occupy a runner for
31+
# the 6-hour default. Generous upper bound — the warm suite is a few
32+
# minutes; a cold stdlib+suite build is well under this.
33+
timeout-minutes: 30
3034
steps:
3135
- name: Checkout
3236
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -148,6 +152,9 @@ jobs:
148152
# given the documented WSL git-object-corruption risk). Runs in
149153
# parallel with `check`; both must pass.
150154
runs-on: ubuntu-latest
155+
# Cold (--ignore-interfaces) build is the slowest path; still well
156+
# under this bound. Caps a runaway/hung job below the 6-hour default.
157+
timeout-minutes: 30
151158
steps:
152159
- name: Checkout
153160
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

.github/workflows/codeql.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
name: CodeQL Security Analysis
3+
4+
on:
5+
push:
6+
branches: [main, master]
7+
pull_request:
8+
branches: [main, master]
9+
schedule:
10+
- cron: '0 6 * * 1'
11+
12+
# Estate guardrail: cancel superseded runs so re-pushes / rebased PR
13+
# updates do not pile up queued runs against the shared account-wide
14+
# Actions concurrency pool. Applied only to read-only check workflows
15+
# (no publish/mutation), so cancelling a superseded run is always safe.
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
analyze:
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 30
27+
permissions:
28+
contents: read
29+
security-events: write
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
include:
34+
- language: javascript-typescript
35+
build-mode: none
36+
# Also analyse the GitHub Actions workflows themselves
37+
# (CodeQL `actions` language) — directly relevant given the
38+
# workflow-hardening in this PR, and closes the Hypatia
39+
# `codeql_missing_actions_language` finding.
40+
- language: actions
41+
build-mode: none
42+
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
46+
47+
- name: Initialize CodeQL
48+
uses: github/codeql-action/init@c6f931105cb2c34c8f901cc885ba1e2e259cf745 # v3
49+
with:
50+
languages: ${{ matrix.language }}
51+
build-mode: ${{ matrix.build-mode }}
52+
53+
- name: Perform CodeQL Analysis
54+
uses: github/codeql-action/analyze@c6f931105cb2c34c8f901cc885ba1e2e259cf745 # v3
55+
with:
56+
category: "/language:${{ matrix.language }}"

.github/workflows/governance.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,8 @@ permissions:
3030

3131
jobs:
3232
governance:
33-
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@main
33+
# Pinned to a SHA (not @main) per the estate supply-chain policy —
34+
# matches the sibling repos' pin (e.g. ochrance-framework). Bump
35+
# deliberately, never float: an unpinned reusable workflow is an
36+
# unpinned trust boundary. mirror.yml / scorecard.yml already pin.
37+
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613

.github/workflows/hypatia-scan.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ jobs:
4343
scan:
4444
name: Hypatia Neurosymbolic Analysis
4545
runs-on: ubuntu-latest
46+
# Bound the job: clone + Elixir build + scan is minutes, not hours.
47+
# Caps a hung clone/build below the 6-hour default.
48+
timeout-minutes: 20
4649

4750
steps:
4851
- name: Checkout repository

.github/workflows/scorecard.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ on:
88
push:
99
branches: [main]
1010

11-
permissions: read-all
11+
permissions:
12+
contents: read
1213

1314
jobs:
1415
analysis:
16+
# Caller-granted permissions per the scorecard-reusable contract
17+
# (its header documents: the caller MUST grant security-events:write
18+
# + id-token:write; contents:read lets it read the repo). Closes the
19+
# Hypatia `scorecard_wrapper_missing_job_permissions` finding.
20+
permissions:
21+
contents: read
22+
security-events: write
23+
id-token: write
1524
uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@e0caf11508a3989574713c78f5f444f2ce5e33ef
1625
secrets: inherit
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
name: Secret Scanner
3+
4+
on:
5+
pull_request:
6+
push:
7+
branches: [main]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
scan:
18+
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@3e4bd4c93911750727e2e4c66dff859e00079da0
19+
secrets: inherit

.hypatia-ignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
#
3+
# .hypatia-ignore — per-rule scanner exemptions for echo-types.
4+
#
5+
# Format (one entry per line; `#` for comments):
6+
# <rule_module>/<rule_type>:<path-fragment>
7+
# The path fragment is substring-matched against each finding's
8+
# repo-relative path. Consumed by the Hypatia scanner
9+
# (lib/hypatia/scanner_suppression.ex). Only content-pattern rule
10+
# modules (e.g. code_safety) are routed through this suppression path;
11+
# structural rules (workflow_audit / honest_completion / scorecard) are
12+
# not, and must be addressed by a real fix or an upstream rule change.
13+
#
14+
# Each entry below is a verified FALSE POSITIVE. Real findings are not
15+
# silenced here.
16+
17+
# ── code_safety/agda_postulate on Smoke.agda — FALSE POSITIVE ──────────────
18+
# The rule is a naive `\bpostulate\b` regex over raw file content that does
19+
# NOT strip comments. The only "postulate" tokens in Smoke.agda are in
20+
# COMMENTS documenting the suite's postulate-free discipline ("Zero
21+
# postulates", "never a postulate", "no funext"); there is no `postulate`
22+
# declaration. The repo's own guardrail tools/check-guardrails.sh strips
23+
# comments before checking and passes — it is the real gate (a genuine
24+
# postulate in Smoke.agda would fail it). The single real postulate in
25+
# proofs/agda (EchoImageFactorizationPropPostulated.agda) is isolated,
26+
# guardrail-exempt by design, and not imported by All.agda or Smoke.agda.
27+
# Upstream fix: agda_postulate should strip comments (see PR notes).
28+
code_safety/agda_postulate:proofs/agda/Smoke.agda
29+
30+
# ── code_safety/js_http_url_in_code on build-banner.mjs — FALSE POSITIVE ───
31+
# The flagged `http://` is the SVG XML namespace identifier
32+
# `xmlns="http://www.w3.org/2000/svg"` — a constant namespace URI that is
33+
# never dereferenced over the network. It MUST remain http:// (changing it
34+
# to https would be semantically wrong and break SVG handling). Not CWE-319.
35+
code_safety/js_http_url_in_code:tools/banner/build-banner.mjs

0 commit comments

Comments
 (0)