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
1 change: 1 addition & 0 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ workflows:
'.github/workflows/labels.yml': []
'.github/workflows/lock-sync-gate.yml': []
'.github/workflows/mirror.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'hyperpolymath/standards@84355587cb2a1f86e6882de83514a32db2646e7a'
'.github/workflows/push-email-notify.yml':
- 'hyperpolymath/smtp-notify-action@c1c9fa07992a02c1fd3d67a0dc1b08cccb852aef'
Expand Down
61 changes: 36 additions & 25 deletions .github/workflows/cargo-audit.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# Prevention workflow - audits Rust dependencies for vulnerabilities
# Prevention workflow - audits Rust dependencies for vulnerabilities.
#
# The audit steps are blocking and unchanged in meaning. What changed is what
# happens to the issue: previously every failing run created a duplicate whose
# whole body was "Run `cargo audit` locally for details", and nothing ever
# closed one. Now one issue carries the findings, the run that produced them and
# acceptance criteria, and the gate that opened it closes it again with a green
# run on the default branch (scripts/reconcile-audit-issue.sh).
name: Cargo Audit
on:
push:
Expand All @@ -20,37 +27,41 @@ jobs:
audit:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install cargo-audit
run: cargo install cargo-audit --version 0.22.2 --locked
- name: Run cargo audit
run: cargo audit --deny warnings
- name: Check for unmaintained crates
run: cargo audit --deny unmaintained
# Optional: Create issues for vulnerabilities
create-issue:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: audit
if: failure() && github.event_name != 'pull_request'
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Create vulnerability issue
- name: Install cargo-audit
run: cargo install cargo-audit --version 0.22.2 --locked
- name: Run cargo audit
id: audit
# Both audits run so the report shows unmaintained crates as well as
# advisories; the step still fails if either fails.
run: |
status=0
{
echo '--- cargo audit --deny warnings ---'
cargo audit --deny warnings 2>&1 || status=$?
echo '--- cargo audit --deny unmaintained ---'
cargo audit --deny unmaintained 2>&1 || status=$?
} | tee "$RUNNER_TEMP/cargo-audit.txt"
exit "$status"
- name: Reconcile the vulnerability issue
# Runs whatever the audit did, so a passing audit closes the issue it
# opened. Skipped on pull requests (including forks) and when the audit
# never ran, because an install failure is not a vulnerability finding.
if: always() && github.event_name != 'pull_request' && steps.audit.outcome != 'skipped'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUDIT_STATUS: ${{ steps.audit.outcome == 'success' && '0' || '1' }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
EXISTING=$(gh issue list --label "security,dependencies" --state open --json number -q '.[0].number')
if [ -z "$EXISTING" ]; then
gh issue create \
--title "Security: Dependency vulnerabilities detected" \
--body "cargo audit found vulnerabilities. Run \`cargo audit\` locally for details." \
--label "security,dependencies"
fi
bash scripts/reconcile-audit-issue.sh \
--status "$AUDIT_STATUS" \
--summary "$RUNNER_TEMP/cargo-audit.txt" \
--run "$RUN_URL" \
--event "${{ github.event_name }}" \
--repo "${{ github.repository }}"
40 changes: 40 additions & 0 deletions .github/workflows/mirror.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# Mirror to Git Forges.
#
# The fan-out itself lives in hyperpolymath/standards (mirror-reusable.yml),
# where each forge job is gated on a repository variable and skips itself when
# its key is absent. Two failure modes that gate cannot see are caught here
# first, by the preflight job below:
#
# * a forge enabled for this repository that META.a2ml does not declare, so
# the enabled set and the declared set disagree; and
# * a forge enabled but not actually configured — in particular the gitea leg,
# which reads `vars.GITEA_HOST` and fails inside ssh-keyscan (exit 1, no
# push attempted) when that variable is empty.
#
# The preflight reads variables only, never the forge keys: an empty key is
# handled by the reusable (skip plus notice), and no job here needs to hold one.
#
# On 2026-09-15 the mirror legs here went red in exactly that second shape:
# mirror-gitea exit 1 and mirror-disroot exit 128, with nothing in the run to
# say which configuration was missing. The preflight names it.
name: Mirror to Git Forges
on:
push:
Expand All @@ -9,6 +28,27 @@ permissions:
actions: read
contents: read
jobs:
mirror-preflight:
name: Mirror configuration
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
env:
CODEBERG_MIRROR_ENABLED: ${{ vars.CODEBERG_MIRROR_ENABLED }}
GITLAB_MIRROR_ENABLED: ${{ vars.GITLAB_MIRROR_ENABLED }}
BITBUCKET_MIRROR_ENABLED: ${{ vars.BITBUCKET_MIRROR_ENABLED }}
SOURCEHUT_MIRROR_ENABLED: ${{ vars.SOURCEHUT_MIRROR_ENABLED }}
RADICLE_MIRROR_ENABLED: ${{ vars.RADICLE_MIRROR_ENABLED }}
GITEA_MIRROR_ENABLED: ${{ vars.GITEA_MIRROR_ENABLED }}
GITEA_HOST: ${{ vars.GITEA_HOST }}
DISROOT_MIRROR_ENABLED: ${{ vars.DISROOT_MIRROR_ENABLED }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check the enabled mirror set against the declared one
run: bash scripts/check-mirror-config.sh
mirror:
uses: hyperpolymath/standards/.github/workflows/mirror-reusable.yml@84355587cb2a1f86e6882de83514a32db2646e7a
secrets: inherit
21 changes: 21 additions & 0 deletions .github/workflows/workflow-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ on:
pull_request:
push:
branches: [main, master]
schedule:
# Weekly, after the Monday cargo-audit run: a workflow can go red without a
# push (the ClusterFuzzLite batch is on a Sunday schedule), and a red that
# nobody pushes near would otherwise go unrecorded until the next commit.
- cron: '30 6 * * 1'
permissions:
contents: read
# Reading the run list is what lets the ledger verify recorded states against
# the latest runs on the default branch.
actions: read
jobs:
lint-workflows:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -44,3 +52,16 @@ jobs:
run: |
bash scripts/check-repository-health.sh
bash scripts/tests/repository-health-test.sh
- name: Verify the CI check ledger
# Offline structure always; the recorded states are verified against the
# latest runs on the default branch, where a green workflow that has
# gone red must not pass unnoticed (docs/CI-RED-DETERMINATIONS.adoc).
env:
GH_TOKEN: ${{ github.token }}
run: |
bash scripts/ci-check-ledger.sh --check
if [ '${{ github.event_name }}' = 'pull_request' ]; then
echo "pull request: recorded states are verified on the default branch"
else
bash scripts/ci-check-ledger.sh --verify
fi
22 changes: 21 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,33 @@ crg-badge:
secret-scan-trufflehog:
@command -v trufflehog >/dev/null && trufflehog filesystem . --only-verified || true

# Offline repository quality and lock regression controls (mikefarah yq v4 + jq).
# Offline repository quality, lock and CI-ledger controls (mikefarah yq v4 + jq).
ci-check:
bash scripts/check-lock-sync.sh
bash scripts/tests/check-lock-sync-test.sh
bash scripts/tests/actions-lock-update-test.sh
bash scripts/check-repository-health.sh
bash scripts/tests/repository-health-test.sh
bash scripts/ci-check-ledger.sh --check
bash scripts/tests/ci-check-ledger-test.sh
bash scripts/tests/reconcile-audit-issue-test.sh
bash scripts/tests/mirror-config-test.sh

# Recorded state and written determination for every workflow (offline).
ci-ledger-check:
bash scripts/ci-check-ledger.sh --check

# Refresh the ledger from the latest runs on the default branch. Human fields
# (determination, reason, owner_action, issue, review_by) are left alone: a new
# red has to be determined by hand, which is the point.
ci-ledger-write:
bash scripts/ci-check-ledger.sh --write

# Name each enabled-but-undeclared and enabled-but-unconfigured mirror. The
# mirror variables only exist in Actions, so locally this reports the declared
# set as switched off.
check-mirror-config:
bash scripts/check-mirror-config.sh

# Pin the security-audit tool and reject warnings/unmaintained crates.
audit:
Expand Down
6 changes: 4 additions & 2 deletions docs/AUDIT.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
Audit scope: CI quality, action-graph integrity, supply-chain controls,
community-health surfaces and RSR template applicability, 2026-10-14.

See link:STANDARDS-ALIGNMENT.adoc[authority revisions, findings, checks and gaps]
and link:CI-CD-REPAIR.adoc[the original multi-gate CI repair].
See link:STANDARDS-ALIGNMENT.adoc[authority revisions, findings, checks and gaps],
link:CI-CD-REPAIR.adoc[the original multi-gate CI repair] and
link:CI-RED-DETERMINATIONS.adoc[the recorded state and determination for every
workflow] (ledger: link:audits/ci-check-ledger.json[audits/ci-check-ledger.json]).
This is a maintainer/agent review, not an independent penetration test or
formal verification of the whole application. Do not infer release readiness
or legal certification from this file's presence.
9 changes: 9 additions & 0 deletions docs/CI-CD-REPAIR.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ not evidence that those repositories were changed or their CI became green.
the crates.io index; GitHub's locked build and security audit validate the
resulting graph.

== Follow-up: reds that had no determination

This repair made the workflows run again, which exposed checks that were already
red. The follow-up measured every workflow's state on the default branch, recorded
a determination for each non-green one, and wired the record into CI so a red
cannot go unrecorded again:
link:CI-RED-DETERMINATIONS.adoc[CI red-check determinations] and
link:audits/ci-check-ledger.json[the ledger] (triage issue #147).

== Preventing recurrence

`check-lock-sync.sh` reads YAML through mikefarah/yq v4 and compares structured
Expand Down
Loading
Loading