Skip to content
Open
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 docs/MIGRATION_AND_PARITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Primary Rust gates:
cargo fmt --manifest-path rust/Cargo.toml -- --check
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path rust/Cargo.toml --all-targets
bash scripts/ci/run-quality-indicators.sh
```

Legacy parity harness:
Expand Down
69 changes: 69 additions & 0 deletions docs/QUALITY_GATES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Quality gates

APW keeps PR checks cheap, but release and readiness work should include a
deeper quality signal when code changes affect credential handling, process
execution, or operator diagnostics.

## Fast checks

Run the normal local gate before opening a PR:

```bash
bash scripts/ci/run-fast-checks.sh
cargo fmt --manifest-path rust/Cargo.toml -- --check
cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path rust/Cargo.toml
```

## Mutation testing

Mutation testing is opt-in because it is intentionally slower than PR Fast CI.
Install `cargo-mutants`, then run:

```bash
APW_RUN_MUTATION=1 bash scripts/ci/run-quality-indicators.sh
```

The script writes mutation output under `rust/target/mutants` and keeps it out
of source control. When `APW_RUN_MUTATION=1` is set, missing `cargo-mutants`
is a hard failure rather than a silent skip.

## CRAP indicator

The CRAP indicator highlights functions whose estimated complexity is high
relative to test coverage:

```text
complexity^2 * (1 - coverage)^3 + complexity
```

Run the source-only hotspot report:

```bash
bash scripts/ci/run-quality-indicators.sh
```

For coverage-aware scores, install `cargo-llvm-cov` and run:

```bash
APW_RUN_COVERAGE=1 bash scripts/ci/run-quality-indicators.sh
```

Without LCOV coverage input, the script assumes 0% coverage and produces a
conservative hotspot list. That mode is useful for deciding where to add tests
before enabling coverage tooling on a runner. When `APW_RUN_COVERAGE=1` is
set, missing `cargo-llvm-cov` is a hard failure rather than a silent skip.
The source scanner recognizes ordinary Rust functions plus qualified forms such
as `async fn`, `const fn`, `unsafe fn`, and `extern "C" fn`, including
visibility-qualified declarations.

## Tooling regression tests

Fast checks run:

```bash
./scripts/test-quality-indicators.sh
```

This covers the CRAP self-test and verifies that explicitly requested mutation
or coverage runs fail closed when their required tools are unavailable.
6 changes: 6 additions & 0 deletions docs/SECURITY_POSTURE_AND_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,14 @@ cargo test --manifest-path rust/Cargo.toml --test legacy_parity
cargo test --manifest-path rust/Cargo.toml --test native_app_e2e
cargo build --manifest-path rust/Cargo.toml --release
./scripts/build-native-app.sh
bash scripts/ci/run-quality-indicators.sh
```

For high-risk changes, enable the deeper optional checks described in
[QUALITY_GATES.md](QUALITY_GATES.md): `APW_RUN_COVERAGE=1` adds LCOV-backed CRAP
scores when `cargo-llvm-cov` is installed, and `APW_RUN_MUTATION=1` runs
`cargo-mutants` when available.

## Security-focused regression coverage

The Rust test suite covers:
Expand Down
1 change: 1 addition & 0 deletions scripts/ci/run-fast-checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ while IFS= read -r -d '' script; do
done < <(find .github/scripts scripts -type f -name '*.sh' -print0)

./scripts/test-render-homebrew-formula.sh
./scripts/test-quality-indicators.sh
./scripts/test-extended-validation-config.sh

echo "APW fast checks passed."
47 changes: 47 additions & 0 deletions scripts/ci/run-quality-indicators.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"

echo "Running APW quality indicators..."

LCOV_PATH="${APW_LCOV_PATH:-}"

if [[ "${APW_RUN_COVERAGE:-0}" == "1" ]]; then
if command -v cargo-llvm-cov >/dev/null 2>&1; then
LCOV_PATH="${LCOV_PATH:-rust/target/apw-lcov.info}"
cargo llvm-cov \
--manifest-path rust/Cargo.toml \
--lcov \
--output-path "$LCOV_PATH"
else
echo "cargo-llvm-cov is required when APW_RUN_COVERAGE=1." >&2
echo "Install it or unset APW_RUN_COVERAGE to run the source-only CRAP report." >&2
exit 1
fi
fi

if [[ "${APW_RUN_MUTATION:-0}" == "1" ]]; then
if command -v cargo-mutants >/dev/null 2>&1; then
cargo mutants \
--manifest-path rust/Cargo.toml \
--output rust/target/mutants \
--timeout "${APW_MUTATION_TIMEOUT:-30}"
else
echo "cargo-mutants is required when APW_RUN_MUTATION=1." >&2
echo "Install it or unset APW_RUN_MUTATION to run CRAP indicators only." >&2
exit 1
fi
fi

CRAP_ARGS=(rust/src --limit "${APW_CRAP_LIMIT:-20}" --threshold "${APW_CRAP_THRESHOLD:-30}")
if [[ -n "$LCOV_PATH" && -f "$LCOV_PATH" ]]; then
CRAP_ARGS+=(--lcov "$LCOV_PATH")
else
echo "No LCOV file supplied; CRAP report uses conservative 0% coverage." >&2
fi

python3 scripts/quality/crap_indicator.py "${CRAP_ARGS[@]}"

echo "APW quality indicators passed."
Loading
Loading