Skip to content

ci(validation-ledger): green the check on v1.5.2 — cover creds kdbx-e… #293

ci(validation-ledger): green the check on v1.5.2 — cover creds kdbx-e…

ci(validation-ledger): green the check on v1.5.2 — cover creds kdbx-e… #293

Workflow file for this run

name: ci
on:
push:
branches: [main]
tags: ['v*']
pull_request:
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# Format + clippy — single-OS gate, cheapest.
lint:
name: fmt · clippy (deny warnings)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: format check
run: cargo fmt --all --check
- name: clippy (deny warnings — enforces CLAUDE.md "zero new warnings")
run: cargo clippy --workspace --all-targets -- -D warnings
# Build + test across every platform we ship a release binary for.
# A red build on any of these three blocks merge to main.
test:
name: build · test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: install libgssapi (linux) for gssapi feature build
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libkrb5-dev
- name: install libgssapi (macos) for gssapi feature build
if: runner.os == 'macOS'
run: |
brew install krb5
echo "LIBGSSAPI_PREFIX=$(brew --prefix krb5)" >> "$GITHUB_ENV"
echo "LIBGSSAPI_IMPL=mit" >> "$GITHUB_ENV"
- name: build
run: cargo build --workspace --release
- name: check supported feature variants
shell: bash
run: |
cargo check --workspace --locked --no-default-features
cargo test -p adhammer-collector --locked --no-default-features no_tls_feature_tests
cargo check -p adhammer --locked --no-default-features --features tls-native
cargo check -p adhammer --locked --features mssql,gssapi
cargo test -p adhammer --locked --features mssql rustls_provider_tests
cargo check -p adhammer-collector --locked --features experimental-gkdi
- name: test (unit + fuzz-lite parsers)
run: cargo test --workspace
# MSRV verification — declared in workspace.package.rust-version. If this
# breaks, either the code drifted past the claimed MSRV or the manifest is stale.
msrv:
name: MSRV verify (rust-version from Cargo.toml)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- name: read MSRV
id: msrv
run: |
version=$(grep '^rust-version' Cargo.toml | sed 's/.*"\(.*\)"/\1/')
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "MSRV=$version"
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master pinned
with:
toolchain: ${{ steps.msrv.outputs.version }}
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: build with pinned MSRV
run: cargo build --workspace --release
# Fuzz is slow — run it separately on a schedule so PR checks stay fast.
# Left on push/pull_request too, but continue-on-error so it never blocks merge.
# 1.4.9 WS-FUZZ-6 — added 6 targets (pac_credential_info, pac_parse_full,
# dpapi_blob, dpapi_masterkey, gpp_cpassword, gptmpl_parse) on top of the
# existing 2 (sddl_parse, hive_parse). Total 8.
fuzz:
name: cargo-fuzz (nightly, short)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@7c8d7d138f5c09cef361f8214cf96882cd029cdb # nightly pinned
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: install cargo-fuzz
run: cargo install cargo-fuzz --locked
- name: fuzz each target briefly
# pac_parse_full retired 2026-08-31 — see fuzz/Cargo.toml comment.
# Total 9 targets in scope (sddl_parse, hive_parse, pac_credential_info,
# dpapi_blob, dpapi_masterkey, gpp_cpassword, gptmpl_parse,
# ntlmssp_challenge, ntlmssp_type3).
# `|| true` per-target so we always upload every crash artifact,
# even when a later target also crashes. The overall job is
# continue-on-error so this stays truthful.
run: |
for t in sddl_parse hive_parse pac_credential_info \
dpapi_blob dpapi_masterkey gpp_cpassword gptmpl_parse \
ntlmssp_challenge ntlmssp_type3 \
sanitize_terminal scope_hostname dns_wire; do
cargo +nightly fuzz run "$t" -- -max_total_time=60 -rss_limit_mb=4096 || echo "FUZZ-CRASH: $t"
done
- name: upload fuzz crash artifacts (repro inputs)
if: always()
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 pinned
with:
name: fuzz-crashes
path: fuzz/artifacts/
if-no-files-found: ignore
retention-days: 30
# 1.4.9 WS-CI-HARDEN — verify every crate can be packaged in isolation.
# This catches release-day regressions (LICENSE-path bugs, missing metadata,
# circular internal deps) two weeks before a tag is cut, not on tag-cut day.
# --allow-dirty because CI runs against uncommitted state on PRs.
# 1.4.9 local-only manifest sanity: runs on every push. Catches manifest
# typos, missing crates in members, and misdeclared feature sets. Does
# NOT verify crates.io-resolvability (that is `package-check` below,
# gated to release cycles).
manifest-sanity:
name: cargo metadata (manifest sanity, local-only)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- name: cargo metadata (resolves workspace + all deps)
run: cargo metadata --format-version=1 --locked > /dev/null
# Registry-independent package inventory. `--list` exercises Cargo's
# include/exclude/readme/license packaging rules without pretending that
# unpublished same-version workspace dependencies already exist on crates.io.
package-inventory:
name: cargo package inventory (all 12 crates)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- name: cargo package --list per crate
run: |
set -e
for c in adhammer-core adhammer-secrets adhammer-ldap adhammer-graph \
adhammer-sysvol adhammer-kerberos adhammer-bloodhound \
adhammer-checks adhammer-collector adhammer-report \
adhammer-sdk adhammer; do
echo "=== cargo package -p $c --list ==="
cargo package -p "$c" --allow-dirty --no-verify --list > /dev/null
done
# Post-cascade registry resolution. This can only pass after the bottom-up
# crates.io waves have made each same-version internal dependency visible.
# It is manual by design and must not make a GitHub-binary-only tag red.
package-check:
name: crates.io post-cascade package check
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: cargo package --allow-dirty per crate
run: |
set -e
for c in adhammer-core adhammer-secrets adhammer-ldap adhammer-graph \
adhammer-sysvol adhammer-kerberos adhammer-bloodhound \
adhammer-checks adhammer-collector adhammer-report \
adhammer-sdk adhammer; do
echo "=== cargo package -p $c ==="
cargo package -p "$c" --allow-dirty --no-verify
done
# 1.5.0 WS-CASCADE-REHEARSAL — bottom-up `cargo publish --dry-run` for
# every publishable crate in DAG order. Reveals whether a real crates.io
# cascade would succeed WITHOUT publishing anything. INFORMATIONAL by
# design (continue-on-error: true): on dev branches with
# [patch.crates-io] present, the first crate reaching a patched dep
# fails-closed with a clear "no matching package found for adhammer-*
# 1.x.x" — that IS the correct signal that the cascade cannot proceed
# until patches are stripped and predecessor siblings published.
#
# Contract:
# - exit 0 = green (would ship)
# - exit 2 = expected fail-closed (patches present, patch-strip needed)
# - exit 1 = unknown failure (real cascade blocker)
cascade-rehearsal:
name: crates.io cascade rehearsal (informational)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 pinned
with:
python-version: "3.12"
- name: bash scripts/cascade_rehearsal.sh
run: bash scripts/cascade_rehearsal.sh
# 1.4.9 WS-CI-HARDEN — license + source + banned-crate policy from deny.toml.
# Non-blocking on `warn` (duplicate-versions), blocking on `deny` (unknown
# source, unlicensed crate). Ignore list for accepted advisories is in
# deny.toml with rationale.
cargo-deny:
name: cargo deny (licenses · sources · bans)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable pinned
- uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 pinned
- name: install cargo-deny
run: cargo install cargo-deny --locked
- name: cargo deny check
run: cargo deny check licenses sources bans advisories
# 1.4.9 Phase-1 gate — docs/VALIDATION.md is the source of truth for what the
# release supports. README / CHANGELOG / PLAN / VECTORS derive from it, not
# the other way around. This job fails when a public claim exceeds what the
# ledger records — "we support X" without a matching row is a bug.
validation-ledger:
name: docs/VALIDATION.md is authoritative
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.2.2 pinned
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 pinned
with:
python-version: "3.12"
- name: enforce ledger vs public surfaces
run: python3 scripts/check_validation_ledger.py
- name: enforce MSRV baseline (Cargo.toml vs docs/POLICY_MSRV.md)
run: python3 scripts/check_msrv_baseline.py
- name: validate receipt JSON shape against docs/receipts/schema.json
run: python3 scripts/validate_receipt.py
- name: verify live-receipt safety boundary
run: |
python3 -m unittest scripts/test_scrub_receipt.py
bash -n scripts/live_validation.sh .githooks/pre-commit
bash scripts/test_pre_commit_hook.sh