Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/rulesets/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,30 @@ POSTed is the protection equivalent of a check that cannot fail.
Conversely, do not infer that the estate is protected because a ruleset exists.
A ruleset with `enforcement: disabled` is inert, and a `pull_request` rule with
`allowed_merge_methods: []` can never be satisfied at all.

== Live snapshot and drift check (ultraplan Phase 0.5, #416)

`live/` holds one JSON file per ruleset that GitHub actually enforces on
hyperpolymath/echidna, keyed by ruleset `id`. Volatile fields (timestamps,
`node_id`, `_links`) are removed so that diffs show only real changes.

The top-level `*.json` files in this directory are historical payloads from
before the snapshot existed. Some no longer match what is enforced (for example
`base.json` names contexts that no live ruleset requires). Do not apply them
without first checking `live/`.

Check for drift against live state (needs repository administration read):

[source,bash]
----
GH_TOKEN=<token-with-admin-read> python3 scripts/ci/check-ruleset-drift.py
----

Exit 0 means no drift, 1 means drift, 2 means the rulesets could not be read.
After an intentional change in the GitHub UI, regenerate the snapshot with
`--write` and commit the diff. Do not regenerate it to silence an unexpected
change.

Not yet automated: the check does not run in CI. The default Actions token
probably cannot read rulesets, so a dedicated read-only secret is needed first.
That secret is an owner action. Until it exists, run the check by hand.
23 changes: 23 additions & 0 deletions .github/rulesets/live/Branch-Floor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"bypass_actors": [],
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
}
},
"enforcement": "active",
"id": 23869567,
"name": "Branch-Floor",
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
}
],
"target": "branch"
}
43 changes: 43 additions & 0 deletions .github/rulesets/live/Immutable-Tags.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
},
{
"actor_id": 2538504,
"actor_type": "Integration",
"bypass_mode": "always"
}
],
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~ALL"
]
}
},
"enforcement": "active",
"id": 18111018,
"name": "Immutable-Tags",
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "update"
},
{
"type": "creation"
},
{
"type": "required_signatures"
}
],
"target": "tag"
}
20 changes: 20 additions & 0 deletions .github/rulesets/live/Require-Signed-Commits.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bypass_actors": [],
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
}
},
"enforcement": "disabled",
"id": 23852649,
"name": "Require-Signed-Commits",
"rules": [
{
"type": "required_signatures"
}
],
"target": "branch"
}
36 changes: 36 additions & 0 deletions .github/rulesets/live/Secret-Scan-Floor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
],
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
}
},
"enforcement": "active",
"id": 24309043,
"name": "Secret-Scan-Floor",
"rules": [
{
"parameters": {
"do_not_enforce_on_create": false,
"required_status_checks": [
{
"context": "scan / gitleaks",
"integration_id": 15368
}
],
"strict_required_status_checks_policy": false
},
"type": "required_status_checks"
}
],
"target": "branch"
}
64 changes: 64 additions & 0 deletions .github/rulesets/live/echidna-proof-stack-branch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
],
"conditions": {
"ref_name": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
}
},
"enforcement": "active",
"id": 22415566,
"name": "echidna-proof-stack-branch",
"rules": [
{
"parameters": {
"do_not_enforce_on_create": false,
"required_status_checks": [
{
"context": "scan / gitleaks",
"integration_id": 15368
},
{
"context": "scan / rust-secrets",
"integration_id": 15368
},
{
"context": "scan / shell-secrets",
"integration_id": 15368
},
{
"context": "rust-ci / Cargo check + clippy + fmt",
"integration_id": 15368
},
{
"context": "rust-ci / Cargo test",
"integration_id": 15368
},
{
"context": "rust-ci / Cargo audit (security)",
"integration_id": 15368
},
{
"context": "rust-ci / llvm-cov line coverage",
"integration_id": 15368
},
{
"context": "CodeQL",
"integration_id": 57789
}
],
"strict_required_status_checks_policy": false
},
"type": "required_status_checks"
}
],
"target": "branch"
}
2 changes: 1 addition & 1 deletion .github/workflows/boj-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
run: |
# Send a secure trigger to boj-server to build this repository
curl -X POST "http://boj-server.local:7700/cartridges/ssg-mcp/invoke" -H "Content-Type: application/json" -d "{\"repo\": \"${{ github.repository }}\", \"branch\": \"${{ github.ref_name }}\", \"engine\": \"casket\\"}"}
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
permissions:
contents: read
4 changes: 2 additions & 2 deletions .github/workflows/chapel-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 30
needs: zig-ffi
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
steps:
- uses: actions/checkout@v7.0.1

Expand Down Expand Up @@ -183,7 +183,7 @@ jobs:
runs-on: ubuntu-22.04
timeout-minutes: 30
needs: [chapel-build, zig-ffi]
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
steps:
- uses: actions/checkout@v7.0.1

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/container-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
if: >-
github.event_name == 'schedule' ||
(github.event_name == 'push' && contains(github.event.head_commit.modified, '.containerization/'))
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
strategy:
fail-fast: false
matrix:
Expand All @@ -132,10 +132,10 @@
# deliberate future optimisation, not required for correctness.
include:
- prover: tamarin
image: echidna:tamarin

Check warning on line 135 in .github/workflows/container-ci.yml

View workflow job for this annotation

GitHub Actions / Hypatia neurosymbolic scan

[hypatia] workflow .github/workflows/container-ci.yml:135 pins container `echidna:tamarin` by tag — tag is mutable; pin by sha256 digest instead
version_check: "tamarin-prover --version"
- prover: proverif
image: echidna:proverif

Check warning on line 138 in .github/workflows/container-ci.yml

View workflow job for this annotation

GitHub Actions / Hypatia neurosymbolic scan

[hypatia] workflow .github/workflows/container-ci.yml:138 pins container `echidna:proverif` by tag — tag is mutable; pin by sha256 digest instead
version_check: "proverif -help 2>&1 | head -1"
- prover: metamath
image: echidna:metamath
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/live-provers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ jobs:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
timeout-minutes: 20
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
Expand Down Expand Up @@ -180,7 +180,7 @@ jobs:
- name: Cache Cargo
uses: Swatinem/rust-cache@v2.9.2
- name: Provision ${{ matrix.backend }} (best-effort via apt / upstream release)
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
run: |
set -euo pipefail
sudo apt-get update -qq || sudo apt-get update -qq --fix-missing
Expand Down Expand Up @@ -306,7 +306,7 @@ jobs:
if: github.event_name == 'schedule' && github.event.schedule == '0 5 * * 0' || (github.event_name == 'workflow_dispatch' && (inputs.tier == '3' || inputs.tier == 'all'))
runs-on: ubuntu-latest
timeout-minutes: 20
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
strategy:
fail-fast: false
matrix:
Expand All @@ -330,7 +330,7 @@ jobs:
- name: Cache Cargo
uses: Swatinem/rust-cache@v2.9.2
- name: Provision ${{ matrix.backend }} (best-effort)
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
run: |
set -euo pipefail
sudo apt-get update -qq || sudo apt-get update -qq --fix-missing
Expand Down Expand Up @@ -423,7 +423,7 @@ jobs:
if: github.event_name == 'schedule' && github.event.schedule == '0 6 1 */3 *' || (github.event_name == 'workflow_dispatch' && (inputs.tier == '4' || inputs.tier == 'all'))
runs-on: ubuntu-latest
timeout-minutes: 20
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
Expand All @@ -443,7 +443,7 @@ jobs:
if: github.event_name == 'schedule' && github.event.schedule == '0 6 1 */3 *' || (github.event_name == 'workflow_dispatch' && (inputs.tier == '4' || inputs.tier == 'all'))
runs-on: ubuntu-latest
timeout-minutes: 20
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
strategy:
fail-fast: false
matrix:
Expand All @@ -460,7 +460,7 @@ jobs:
- name: Cache Cargo
uses: Swatinem/rust-cache@v2.9.2
- name: Provision ${{ matrix.backend }} (best-effort, CUDA/OpenCL required)
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
run: |
case "${{ matrix.backend }}" in
gpuverify)
Expand All @@ -473,5 +473,5 @@ jobs:
;;
esac
- name: Run live version check (SKIP if binary absent)
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
run: cargo test --test live_prover_suite --features live-provers -- --nocapture live_${{ matrix.backend }}_version
4 changes: 2 additions & 2 deletions .github/workflows/static-analysis-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,14 @@ jobs:
fetch-depth: 0
- name: Setup Elixir for Hypatia scanner
id: beam
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
uses: erlef/setup-beam@v1.24.1
with:
elixir-version: '1.19.4'
otp-version: '28.3'
- name: Clone and build Hypatia
id: build
continue-on-error: true
continue-on-error: true # allow-fail: issue=#416 expires=2026-11-30
env:
# Pinned to the hypatia commit standards@5751b97e vets as its default.
# When the standards callers move to that ref, the governance baseline
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/workflow-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
# banner before it), permissions, migration exemptions and risk routing.
run: bash scripts/ci/test-issue-regressions.sh

# Ultraplan Phase 2.3 (tracking issue #416): every continue-on-error unit
# needs an owner issue and an unexpired date on the same line.
- name: Allow-fail units have an owner and an unexpired date
run: python3 scripts/ci/check-allow-fail-expiry.py

- name: Verify immutable action lockfile with the authoritative tool
env:
GH_TOKEN: ${{ github.token }}
Expand Down
Loading
Loading