name: ci
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "0 6 * * 1"
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- run: cargo fmt --all -- --check
- run: cargo clippy --all-targets -- -D warnings
- run: shellcheck verify.sh tests/*.sh
conformance:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- run: cargo test
- run: make conformance
action:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- id: bare
uses: ./
- name: nothing covered, and the step succeeded
run: |
set -eu
[ "${{ steps.bare.outputs.gates }}" = "[]" ] || {
echo "expected [], got: ${{ steps.bare.outputs.gates }}"; exit 1; }
[ -z "${{ steps.bare.outputs.covered }}" ] || {
echo "expected empty covered"; exit 1; }
- name: sign this exact tree
run: |
set -eu
# `git notes add` writes an object and needs a committer identity;
# a bare runner has none.
git config user.email ci@example.org
git config user.name CI
# Drop origin first. The verifier force-fetches refs/notes/amont-attest
# before reading it, which would replace the note minted below with
# whatever the remote holds — and this repository really does carry
# one, written by amont when this branch was pushed from a Mac. That
# is correct behaviour (CI wants the remote's note, not a local one)
# and it is precisely what makes a locally-seeded fixture unusable
# here. Without a remote the fetch fails harmlessly, as it does in
# any repository that has never pushed an attestation.
git remote remove origin
ssh-keygen -q -t ed25519 -N '' -C ci@example.org -f /tmp/k
printf '%s namespaces="amont-attest" %s\n' ci@example.org "$(cat /tmp/k.pub)" \
> .github/ci-signers
tree=$(git rev-parse 'HEAD^{tree}')
printf 'amont-attest-v2\ntree %s\ngates pre-push-cargo-test pre-push-clippy\nplatform x86_64-linux\namont ci\n' \
"$tree" > /tmp/p
ssh-keygen -Y sign -n amont-attest -f /tmp/k /tmp/p
git notes --ref amont-attest add \
-m "$(printf '%s\n\n%s' "$(cat /tmp/p)" "$(cat /tmp/p.sig)")" "$tree"
- id: signed
uses: ./
with:
signers: .github/ci-signers
- name: the attestation is reported, exactly
run: |
set -eu
got='${{ steps.signed.outputs.gates }}'
want='["pre-push-cargo-test","pre-push-clippy"]'
[ "$got" = "$want" ] || { echo "want $want, got $got"; exit 1; }
- name: a covered gate is skipped
if: ${{ contains(fromJSON(steps.signed.outputs.gates), 'pre-push-cargo-test') }}
run: echo "correctly identified as covered"
- name: an uncovered gate still runs
if: ${{ !contains(fromJSON(steps.signed.outputs.gates), 'pre-push-audit-rust') }}
run: echo "correctly identified as NOT covered"
- name: re-sign with only a prefix-colliding gate
run: |
set -eu
tree=$(git rev-parse 'HEAD^{tree}')
printf 'amont-attest-v2\ntree %s\ngates pre-push-cargo-test-slow\nplatform x86_64-linux\namont ci\n' \
"$tree" > /tmp/p2
ssh-keygen -Y sign -n amont-attest -f /tmp/k /tmp/p2
git notes --ref amont-attest add -f \
-m "$(printf '%s\n\n%s' "$(cat /tmp/p2)" "$(cat /tmp/p2.sig)")" "$tree"
- id: collide
uses: ./
with:
signers: .github/ci-signers
- name: a merely-prefix-matching gate does NOT count as covered
run: |
set -eu
[ '${{ steps.collide.outputs.gates }}' = '["pre-push-cargo-test-slow"]' ] || exit 1
# the legacy string form WOULD have matched — that is the defect:
case '${{ steps.collide.outputs.covered }}' in
*pre-push-cargo-test*) echo "substring match, as expected of the old form" ;;
esac
- name: and the array form correctly says it is not covered
if: ${{ !contains(fromJSON(steps.collide.outputs.gates), 'pre-push-cargo-test') }}
run: echo "the real suite would still run — correct"
msrv:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- run: |
v=$(awk -F'"' '/^rust-version/ {print $2}' Cargo.toml)
rustup toolchain install "$v" --profile minimal
cargo "+$v" check --locked