name: CI
on:
pull_request:
merge_group: {}
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
pull-requests: read
env:
CARGO_INCREMENTAL: "0"
RUSTFLAGS: "-D warnings"
jobs:
changes:
name: Detect changes
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
rust: ${{ steps.filter.outputs.rust || 'true' }}
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d id: filter
if: github.event_name == 'pull_request'
with:
filters: |
rust:
- 'src/**'
- 'crates/**'
- 'tests/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rustfmt.toml'
- 'rust-toolchain.toml'
- '.gitignore'
- 'deny.toml'
- '.github/workflows/**'
- '.github/zizmor.yml'
- 'factory/scripts/deny-check.sh'
- 'Makefile'
- 'AGENTS.md'
- 'README.md'
- 'factory/BLINE_CONSUMER.md'
- 'fuzz/**'
lint:
name: Lint
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
env:
CARGO_TARGET_DIR: target/ci-lint
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: "1.85"
components: rustfmt, clippy
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc with:
tool: cargo-deny@0.20.2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
save-if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch' }}
- run: cargo fmt --check
- run: cargo clippy --locked --workspace --all-targets -- -D warnings
- run: bash factory/scripts/deny-check.sh
test:
name: Test
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
env:
CARGO_TARGET_DIR: target/ci-test
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: "1.85"
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc with:
tool: cargo-nextest@0.9.143
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
save-if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch' }}
- run: cargo nextest run --locked --workspace
- run: cargo test --locked --workspace --doc
fuzz-smoke:
name: Fuzz smoke
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
env:
RUSTUP_TOOLCHAIN: nightly
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: nightly
targets: x86_64-unknown-linux-gnu
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc with:
tool: cargo-fuzz@0.13.2
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
workspaces: |
.
fuzz
shared-key: fuzz
cache-on-failure: true
save-if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch' }}
- run: cargo fuzz run parse_skill --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
- run: cargo fuzz run xml_catalog --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
- run: cargo fuzz run list_format --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
- run: cargo fuzz run catalog_format --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
- run: cargo fuzz run vendor_token --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
- run: cargo fuzz run sanitize_error_token --target x86_64-unknown-linux-gnu -- -max_total_time=5
env:
RUSTFLAGS: ""
test-windows:
name: Test (Windows)
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: windows-latest
timeout-minutes: 25
env:
CARGO_TARGET_DIR: target/ci-test
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: "1.85"
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc with:
tool: cargo-nextest@0.9.143
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
save-if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch' }}
- run: cargo nextest run --locked --workspace
- run: cargo test --locked --workspace --doc
test-macos:
name: Test (macOS)
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: macos-latest
timeout-minutes: 25
env:
CARGO_TARGET_DIR: target/ci-test
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 with:
toolchain: "1.85"
- uses: taiki-e/install-action@b6ff580856c41316412a0b9b60540fbc6f8c82cc with:
tool: cargo-nextest@0.9.143
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 with:
save-if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'workflow_dispatch' }}
- run: cargo nextest run --locked --workspace
- run: cargo test --locked --workspace --doc
workflows:
name: Workflows
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
persist-credentials: false
- uses: rhysd/actionlint@914e7df21a07ef503a81201c76d2b11c789d3fca - name: zizmor
run: |
python3 -m pip install --user 'zizmor==1.29.0'
"$HOME/.local/bin/zizmor" --min-severity=high .github/workflows
- run: bash factory/scripts/write-ledger.sh --self-test
gitleaks:
name: Gitleaks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with:
fetch-depth: 0
persist-credentials: false
- name: Install gitleaks
run: |
VER=8.30.1
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${VER}/gitleaks_${VER}_linux_x64.tar.gz" \
| tar xz -C /usr/local/bin gitleaks
- run: gitleaks detect --source . --exit-code 1
ci:
name: CI
if: always()
needs: [changes, lint, test, fuzz-smoke, test-windows, test-macos, workflows, gitleaks]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c with:
egress-policy: audit
- name: Check job results
run: |
for r in "${{ needs.changes.result }}" "${{ needs.lint.result }}" \
"${{ needs.test.result }}" \
"${{ needs.fuzz-smoke.result }}" \
"${{ needs.test-windows.result }}" "${{ needs.test-macos.result }}" \
"${{ needs.workflows.result }}" "${{ needs.gitleaks.result }}"; do
if [ "$r" = "failure" ] || [ "$r" = "cancelled" ]; then
echo "::error::needed job $r"
exit 1
fi
done