mirror of
https://github.com/marcoallegretti/karapace.git
synced 2026-03-26 21:43:09 +00:00
doctor command correctly reports missing prerequisites on the GitHub Actions runner. Allow it to fail since the smoke test only verifies the binary was built correctly and can execute.
561 lines
20 KiB
YAML
561 lines
20 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
RUSTFLAGS: >-
|
|
-D warnings
|
|
--remap-path-prefix /home/runner/work=src
|
|
--remap-path-prefix /home/runner/.cargo/registry/src=crate
|
|
--remap-path-prefix /home/runner/.rustup=rustup
|
|
RUST_TOOLCHAIN: "1.93"
|
|
SOURCE_DATE_EPOCH: "0"
|
|
CARGO_INCREMENTAL: "0"
|
|
|
|
jobs:
|
|
fmt:
|
|
name: Format
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
components: rustfmt
|
|
- run: cargo fmt --all --check
|
|
|
|
clippy:
|
|
name: Clippy
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
components: clippy
|
|
- uses: Swatinem/rust-cache@v2
|
|
- run: cargo clippy --workspace --all-targets -- -D warnings
|
|
|
|
test:
|
|
name: Test (${{ matrix.os }})
|
|
runs-on: ${{ matrix.runner }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: ubuntu
|
|
runner: ubuntu-latest
|
|
- os: fedora
|
|
runner: ubuntu-latest
|
|
container: fedora:latest
|
|
container: ${{ matrix.container || '' }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Install build deps (Fedora)
|
|
if: matrix.os == 'fedora'
|
|
run: dnf install -y gcc make curl
|
|
- name: Install Rust (container)
|
|
if: matrix.container != ''
|
|
run: |
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }} --profile minimal
|
|
. "$HOME/.cargo/env"
|
|
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
if: matrix.container == ''
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
- run: cargo test --workspace
|
|
|
|
e2e:
|
|
name: E2E Tests
|
|
runs-on: ubuntu-latest
|
|
needs: [test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
- name: Install prerequisites
|
|
run: |
|
|
sudo apt-get update -qq
|
|
sudo apt-get install -y -qq fuse-overlayfs curl crun
|
|
sudo sysctl -w kernel.unprivileged_userns_clone=1 || true
|
|
- name: Verify prerequisites
|
|
run: |
|
|
echo "--- Prerequisite verification ---"
|
|
unshare --version
|
|
fuse-overlayfs --version || echo "fuse-overlayfs: $(which fuse-overlayfs)"
|
|
curl --version | head -1
|
|
crun --version | head -1
|
|
echo "User namespace test:"
|
|
if ! unshare --user --map-root-user --fork true; then
|
|
echo "SKIP: user namespaces not available on this runner"
|
|
echo "SKIP_E2E=true" >> $GITHUB_ENV
|
|
else
|
|
echo "OK"
|
|
fi
|
|
echo "--- All prerequisites verified ---"
|
|
- name: Run E2E tests
|
|
if: env.SKIP_E2E != 'true'
|
|
run: cargo test --test e2e -- --ignored --test-threads=1
|
|
- name: Check for mount leaks
|
|
if: always()
|
|
run: |
|
|
if grep -q fuse-overlayfs /proc/mounts; then
|
|
echo "FATAL: stale fuse-overlayfs mounts detected"
|
|
grep fuse-overlayfs /proc/mounts
|
|
exit 1
|
|
fi
|
|
|
|
enospc:
|
|
name: ENOSPC Tests
|
|
runs-on: ubuntu-latest
|
|
needs: [test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
- name: Run ENOSPC tests (requires sudo for tmpfs)
|
|
run: sudo -E "$(which cargo)" test --test enospc -- --ignored --test-threads=1
|
|
|
|
e2e-resolve:
|
|
name: E2E Resolver (${{ matrix.os }})
|
|
runs-on: ubuntu-latest
|
|
needs: [test]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: ubuntu
|
|
container: ubuntu:24.04
|
|
setup: "apt-get update -qq && apt-get install -y -qq build-essential curl fuse-overlayfs crun"
|
|
- os: fedora
|
|
container: fedora:latest
|
|
setup: "dnf install -y gcc make curl fuse-overlayfs fuse3 crun"
|
|
# opensuse dropped: OCI container shell PATH issue (sh not in exec PATH)
|
|
container: ${{ matrix.container }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Install prerequisites
|
|
run: ${{ matrix.setup }}
|
|
- name: Install Rust
|
|
run: |
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${{ env.RUST_TOOLCHAIN }} --profile minimal
|
|
. "$HOME/.cargo/env"
|
|
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
|
- uses: Swatinem/rust-cache@v2
|
|
- name: Enable user namespaces
|
|
run: sysctl -w kernel.unprivileged_userns_clone=1 || true
|
|
- name: Verify prerequisites
|
|
run: |
|
|
echo "--- Prerequisite verification (${{ matrix.os }}) ---"
|
|
which unshare && unshare --version || true
|
|
which fuse-overlayfs && (fuse-overlayfs --version || true)
|
|
curl --version | head -1
|
|
if ! unshare --user --map-root-user --fork true; then
|
|
echo "SKIP: user namespaces not available in this container"
|
|
echo "SKIP_E2E=true" >> $GITHUB_ENV
|
|
else
|
|
echo "Namespaces: OK"
|
|
fi
|
|
echo "--- All prerequisites verified ---"
|
|
- name: Run resolver E2E tests
|
|
if: env.SKIP_E2E != 'true'
|
|
run: cargo test --test e2e e2e_resolve -- --ignored --test-threads=1
|
|
|
|
build-release:
|
|
name: Release Build (${{ matrix.target }})
|
|
runs-on: ubuntu-latest
|
|
needs: [fmt, clippy, test]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: x86_64-unknown-linux-gnu
|
|
artifact: karapace-linux-x86_64-gnu
|
|
- target: x86_64-unknown-linux-musl
|
|
artifact: karapace-linux-x86_64-musl
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
targets: ${{ matrix.target }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
key: ${{ matrix.target }}
|
|
- name: Install musl-tools
|
|
if: contains(matrix.target, 'musl')
|
|
run: sudo apt-get update -qq && sudo apt-get install -y -qq musl-tools
|
|
- name: Clean before release build
|
|
run: cargo clean
|
|
- run: cargo build --release --workspace --target ${{ matrix.target }}
|
|
- name: Install cargo-cyclonedx
|
|
run: cargo install cargo-cyclonedx@0.5.7 --locked
|
|
- name: Generate SBOM
|
|
run: |
|
|
cargo cyclonedx --manifest-path crates/karapace-cli/Cargo.toml --format json --override-filename karapace_bom
|
|
mv crates/karapace-cli/karapace_bom.json .
|
|
- name: Compute and verify checksums
|
|
run: |
|
|
cd target/${{ matrix.target }}/release
|
|
sha256sum karapace karapace-dbus > SHA256SUMS
|
|
sha256sum -c SHA256SUMS
|
|
echo "SHA256 checksum verification: OK"
|
|
- name: Validate SBOM is valid JSON with components
|
|
run: |
|
|
python3 -c "
|
|
import json
|
|
with open('karapace_bom.json') as f:
|
|
bom = json.load(f)
|
|
assert 'components' in bom, 'SBOM missing components key'
|
|
assert len(bom['components']) > 0, 'SBOM has zero components'
|
|
n = len(bom['components'])
|
|
print(f'SBOM valid: {n} components')
|
|
"
|
|
- name: Verify static linking (musl only)
|
|
if: contains(matrix.target, 'musl')
|
|
run: |
|
|
set -euo pipefail
|
|
for bin in karapace karapace-dbus; do
|
|
LDD_OUT=$(ldd target/${{ matrix.target }}/release/$bin 2>&1 || true)
|
|
if echo "$LDD_OUT" | grep -qE 'not a dynamic executable|statically linked'; then
|
|
echo "PASS: $bin is statically linked"
|
|
else
|
|
echo "FAIL: $bin is NOT statically linked"
|
|
echo "$LDD_OUT"
|
|
exit 1
|
|
fi
|
|
done
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ matrix.artifact }}
|
|
path: |
|
|
target/${{ matrix.target }}/release/karapace
|
|
target/${{ matrix.target }}/release/karapace-dbus
|
|
target/${{ matrix.target }}/release/SHA256SUMS
|
|
|
|
smoke-test:
|
|
name: Smoke Test Release (${{ matrix.target }})
|
|
runs-on: ubuntu-latest
|
|
needs: [build-release]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: x86_64-unknown-linux-gnu
|
|
artifact: karapace-linux-x86_64-gnu
|
|
- target: x86_64-unknown-linux-musl
|
|
artifact: karapace-linux-x86_64-musl
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: ${{ matrix.artifact }}
|
|
path: bin
|
|
- name: Verify binary
|
|
run: |
|
|
chmod +x bin/karapace
|
|
bin/karapace --version
|
|
bin/karapace doctor || true # doctor may report missing prereqs on runner
|
|
bin/karapace migrate
|
|
|
|
reproducibility-check:
|
|
name: Reproducibility Check (same-run)
|
|
runs-on: ubuntu-latest
|
|
needs: [fmt, clippy, test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- name: Build A
|
|
run: cargo build --release -p karapace-cli -p karapace-dbus
|
|
- name: Record hashes A
|
|
run: |
|
|
sha256sum target/release/karapace target/release/karapace-dbus > /tmp/hashes-a.txt
|
|
cat /tmp/hashes-a.txt
|
|
- name: Clean and rebuild B
|
|
run: |
|
|
cargo clean
|
|
cargo build --release -p karapace-cli -p karapace-dbus
|
|
- name: Record hashes B
|
|
run: |
|
|
sha256sum target/release/karapace target/release/karapace-dbus > /tmp/hashes-b.txt
|
|
cat /tmp/hashes-b.txt
|
|
- name: Compare A vs B
|
|
run: |
|
|
set -euo pipefail
|
|
echo "=== Build A ==="
|
|
cat /tmp/hashes-a.txt
|
|
echo "=== Build B ==="
|
|
cat /tmp/hashes-b.txt
|
|
HASH_A_CLI=$(awk '/karapace$/{print $1}' /tmp/hashes-a.txt)
|
|
HASH_B_CLI=$(awk '/karapace$/{print $1}' /tmp/hashes-b.txt)
|
|
HASH_A_DBUS=$(awk '/karapace-dbus$/{print $1}' /tmp/hashes-a.txt)
|
|
HASH_B_DBUS=$(awk '/karapace-dbus$/{print $1}' /tmp/hashes-b.txt)
|
|
if [ "$HASH_A_CLI" != "$HASH_B_CLI" ]; then
|
|
echo "FATAL: karapace binary not reproducible"
|
|
echo " A: $HASH_A_CLI"
|
|
echo " B: $HASH_B_CLI"
|
|
exit 1
|
|
fi
|
|
if [ "$HASH_A_DBUS" != "$HASH_B_DBUS" ]; then
|
|
echo "FATAL: karapace-dbus binary not reproducible"
|
|
echo " A: $HASH_A_DBUS"
|
|
echo " B: $HASH_B_DBUS"
|
|
exit 1
|
|
fi
|
|
echo "Reproducibility check PASSED: both binaries byte-identical across builds"
|
|
|
|
cross-run-reproducibility:
|
|
name: Cross-Run Reproducibility (${{ matrix.label }})
|
|
runs-on: ${{ matrix.runner }}
|
|
needs: [fmt, clippy, test]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- label: ubuntu-latest
|
|
runner: ubuntu-latest
|
|
- label: ubuntu-22.04
|
|
runner: ubuntu-22.04
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- name: Build release
|
|
run: cargo build --release -p karapace-cli -p karapace-dbus
|
|
- name: Compute hashes
|
|
run: |
|
|
sha256sum target/release/karapace target/release/karapace-dbus > hashes.txt
|
|
cat hashes.txt
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: repro-hashes-${{ matrix.label }}
|
|
path: hashes.txt
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: repro-binary-${{ matrix.label }}
|
|
path: |
|
|
target/release/karapace
|
|
target/release/karapace-dbus
|
|
|
|
verify-cross-reproducibility:
|
|
name: Verify Cross-Run Reproducibility
|
|
runs-on: ubuntu-latest
|
|
needs: [cross-run-reproducibility]
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-hashes-ubuntu-latest
|
|
path: build-latest
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-hashes-ubuntu-22.04
|
|
path: build-2204
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-binary-ubuntu-latest
|
|
path: bin-latest
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-binary-ubuntu-22.04
|
|
path: bin-2204
|
|
- name: Compare cross-run hashes
|
|
run: |
|
|
set -euo pipefail
|
|
echo "=== ubuntu-latest ==="
|
|
cat build-latest/hashes.txt
|
|
echo "=== ubuntu-22.04 ==="
|
|
cat build-2204/hashes.txt
|
|
if diff -u build-latest/hashes.txt build-2204/hashes.txt; then
|
|
echo "Cross-run reproducibility PASSED: builds are byte-identical"
|
|
else
|
|
echo "WARNING: Cross-run builds differ — generating diffoscope report"
|
|
sudo apt-get update -qq && sudo apt-get install -y -qq diffoscope
|
|
diffoscope bin-latest/target/release/karapace bin-2204/target/release/karapace \
|
|
--text /tmp/diffoscope-karapace.txt || true
|
|
diffoscope bin-latest/target/release/karapace-dbus bin-2204/target/release/karapace-dbus \
|
|
--text /tmp/diffoscope-dbus.txt || true
|
|
echo "=== Diffoscope report (karapace) ==="
|
|
cat /tmp/diffoscope-karapace.txt 2>/dev/null || echo "(empty)"
|
|
echo "=== Diffoscope report (karapace-dbus) ==="
|
|
cat /tmp/diffoscope-dbus.txt 2>/dev/null || echo "(empty)"
|
|
echo "WARNING: Cross-run gnu builds differ (expected: different OS linker versions)"
|
|
echo "NOTE: Same-run reproducibility is verified separately"
|
|
fi
|
|
|
|
reproducibility-check-musl:
|
|
name: Reproducibility Check (musl, same-run)
|
|
runs-on: ubuntu-latest
|
|
needs: [fmt, clippy, test]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
targets: x86_64-unknown-linux-musl
|
|
- name: Install musl-tools
|
|
run: sudo apt-get update -qq && sudo apt-get install -y -qq musl-tools
|
|
- name: Build A (musl)
|
|
run: |
|
|
cargo clean
|
|
cargo build --release -p karapace-cli -p karapace-dbus --target x86_64-unknown-linux-musl
|
|
- name: Record hashes A
|
|
run: |
|
|
sha256sum target/x86_64-unknown-linux-musl/release/karapace target/x86_64-unknown-linux-musl/release/karapace-dbus > /tmp/hashes-a.txt
|
|
cat /tmp/hashes-a.txt
|
|
- name: Clean and rebuild B
|
|
run: |
|
|
cargo clean
|
|
cargo build --release -p karapace-cli -p karapace-dbus --target x86_64-unknown-linux-musl
|
|
- name: Record hashes B
|
|
run: |
|
|
sha256sum target/x86_64-unknown-linux-musl/release/karapace target/x86_64-unknown-linux-musl/release/karapace-dbus > /tmp/hashes-b.txt
|
|
cat /tmp/hashes-b.txt
|
|
- name: Compare A vs B
|
|
run: |
|
|
set -euo pipefail
|
|
echo "=== Build A (musl) ==="
|
|
cat /tmp/hashes-a.txt
|
|
echo "=== Build B (musl) ==="
|
|
cat /tmp/hashes-b.txt
|
|
HASH_A_CLI=$(awk '/karapace$/{print $1}' /tmp/hashes-a.txt)
|
|
HASH_B_CLI=$(awk '/karapace$/{print $1}' /tmp/hashes-b.txt)
|
|
HASH_A_DBUS=$(awk '/karapace-dbus$/{print $1}' /tmp/hashes-a.txt)
|
|
HASH_B_DBUS=$(awk '/karapace-dbus$/{print $1}' /tmp/hashes-b.txt)
|
|
if [ "$HASH_A_CLI" != "$HASH_B_CLI" ]; then
|
|
echo "FATAL: karapace musl binary not reproducible"
|
|
echo " A: $HASH_A_CLI"
|
|
echo " B: $HASH_B_CLI"
|
|
exit 1
|
|
fi
|
|
if [ "$HASH_A_DBUS" != "$HASH_B_DBUS" ]; then
|
|
echo "FATAL: karapace-dbus musl binary not reproducible"
|
|
echo " A: $HASH_A_DBUS"
|
|
echo " B: $HASH_B_DBUS"
|
|
exit 1
|
|
fi
|
|
echo "Musl reproducibility check PASSED: both binaries byte-identical across builds"
|
|
|
|
cross-run-reproducibility-musl:
|
|
name: Cross-Run Reproducibility musl (${{ matrix.label }})
|
|
runs-on: ${{ matrix.runner }}
|
|
needs: [fmt, clippy, test]
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- label: ubuntu-latest
|
|
runner: ubuntu-latest
|
|
- label: ubuntu-22.04
|
|
runner: ubuntu-22.04
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
targets: x86_64-unknown-linux-musl
|
|
- name: Install musl-tools
|
|
run: sudo apt-get update -qq && sudo apt-get install -y -qq musl-tools
|
|
- name: Build release (musl)
|
|
run: |
|
|
cargo clean
|
|
cargo build --release -p karapace-cli -p karapace-dbus --target x86_64-unknown-linux-musl
|
|
- name: Compute hashes
|
|
run: |
|
|
sha256sum target/x86_64-unknown-linux-musl/release/karapace target/x86_64-unknown-linux-musl/release/karapace-dbus > hashes.txt
|
|
cat hashes.txt
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: repro-musl-hashes-${{ matrix.label }}
|
|
path: hashes.txt
|
|
|
|
verify-cross-reproducibility-musl:
|
|
name: Verify Cross-Run Reproducibility (musl)
|
|
runs-on: ubuntu-latest
|
|
needs: [cross-run-reproducibility-musl]
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-musl-hashes-ubuntu-latest
|
|
path: build-latest
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: repro-musl-hashes-ubuntu-22.04
|
|
path: build-2204
|
|
- name: Compare musl cross-run hashes
|
|
run: |
|
|
set -euo pipefail
|
|
echo "=== ubuntu-latest (musl) ==="
|
|
cat build-latest/hashes.txt
|
|
echo "=== ubuntu-22.04 (musl) ==="
|
|
cat build-2204/hashes.txt
|
|
if diff -u build-latest/hashes.txt build-2204/hashes.txt; then
|
|
echo "Musl cross-run reproducibility PASSED: builds are byte-identical"
|
|
else
|
|
echo "WARNING: Musl cross-run builds differ (different musl-tools versions across runners)"
|
|
echo "NOTE: Same-run reproducibility is verified separately"
|
|
fi
|
|
|
|
lockfile-check:
|
|
name: Lockfile Integrity
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
|
- name: Verify Cargo.lock is up-to-date
|
|
run: |
|
|
cargo check --workspace --locked
|
|
echo "Cargo.lock integrity: OK (lockfile consistent with Cargo.toml)"
|
|
|
|
cargo-deny:
|
|
name: Dependency Policy (cargo-deny)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: EmbarkStudios/cargo-deny-action@v2
|
|
with:
|
|
command: check
|
|
arguments: --all-features
|
|
|
|
ci-contract:
|
|
name: CI Contract
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: Verify all required jobs exist
|
|
run: |
|
|
set -euo pipefail
|
|
REQUIRED_JOBS="fmt clippy test e2e enospc e2e-resolve build-release smoke-test ci-contract reproducibility-check reproducibility-check-musl cross-run-reproducibility verify-cross-reproducibility cross-run-reproducibility-musl verify-cross-reproducibility-musl lockfile-check cargo-deny"
|
|
MISSING=""
|
|
for job in $REQUIRED_JOBS; do
|
|
if ! grep -qE "^ ${job}:" .github/workflows/ci.yml; then
|
|
MISSING="$MISSING $job"
|
|
fi
|
|
done
|
|
if [ -n "$MISSING" ]; then
|
|
echo "FATAL: Missing required CI jobs:$MISSING"
|
|
echo "See CI_CONTRACT.md for the full list of required jobs."
|
|
exit 1
|
|
fi
|
|
echo "All required CI jobs present: $REQUIRED_JOBS"
|
|
- name: Verify CI_CONTRACT.md exists
|
|
run: |
|
|
if [ ! -f CI_CONTRACT.md ]; then
|
|
echo "FATAL: CI_CONTRACT.md missing"
|
|
exit 1
|
|
fi
|
|
echo "CI_CONTRACT.md present"
|