Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,12 @@ jobs:
CI: "true"
run: cargo test --test integration_test -- --ignored --nocapture --test-threads=1

- name: Run replay-path tests (fresh vs cache vs replay)
env:
AUDITMYSITE_BROWSER: ${{ steps.setup-chrome.outputs.chrome-path }}
CI: "true"
run: cargo test --test replay_paths_test -- --ignored --nocapture --test-threads=1

# Schema/vulnerable-libs/easy-language detection-corpus tests
# (#553-#558; the WCAG corpus has its own job below): real Chrome, diffed against ground-truth fixtures.
# These are separate `#[ignore]`-gated test binaries and were never
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and verification for each change is in the

### Added

- **Replay:** `auditmysite replay <snapshot.json | cache directory | URL>` evaluates a stored snapshot without browser or network and reports it with `execution.environment.source: replay` and the verdict as exit code. `--session`, `--state-id` and `--storage-state` given to it are assertions about the stored measurement profile: a snapshot measured under another one is refused (`ReplayError::OtherMeasurement`, naming field, stored and asserted value) instead of being shown as the same measurement; `--dns-check`, `--check-ssr-content`, `--isolate-third-party-impact` and `--ai-transparency` are refused, because a replay shows the checks its run recorded. `--reuse-cache` answers through the same replay (`source: cache`); an unreadable, incomplete, version-mismatched or differently configured entry is a miss that prints its reason (`CacheMiss`), and the lossy reconstruction is no longer used for cache hits. `tests/replay_paths_test.rs` (Chrome, local fixture) checks that fresh run, cache hit and replay give one canonical model and that a single-page app whose content changes after a client-side navigation is explained by its measurement profile (`audit::profile_differences`).
- **Snapshot:** `snapshot.json` now holds the whole collected report, the document identity (requested/final URL, status, redirects), the run language and the versions it was written under (snapshot schema, fingerprint, collection contract, measurement profile, evaluation, decision contract, rule-set digest). `audit::replay` evaluates it without browser or network into the same model as the fresh run; `output::format_json_replay` exports it with `detail.module_detail: full`. Incomplete or version-mismatched snapshots are reported as such (`ReplayError`) and are a cache miss, never read under current semantics. Cache entries of earlier builds are not reused. Details: [Snapshot, replay and validation paths](https://github.com/casoon/auditmysite/blob/main/docs/OUTPUT_CONTRACT.md#snapshot-replay-and-validation-paths).
- **Validation:** `tests/validation_path_matrix.rs` checks that every fallible export entry refuses contradictory data and that unchecked `normalize()` calls in `cli`, `output` and `studio` do not grow.
- **Navigation:** `navigation.redirect_chain` lists the main document's redirects (URL and status, in order) next to `requested_url`, `final_url` and `redirect_count`.
Expand Down
3 changes: 2 additions & 1 deletion docs/OUTPUT_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ The cache entry's `snapshot.json` is the collected evidence, independent of any

- `versions` records the snapshot schema, the content fingerprint, the collection contract, the measurement-profile version, the evaluation version (normalization, scoring, decision derivation), the decision contract and a digest of the shared rule catalogue. A snapshot is replayed only when all of them equal the current values.
- `audit::replay(snapshot)` evaluates a snapshot without browser or network and returns the same `NormalizedReport` as the fresh run. Only `timestamp`, `duration_ms` and `execution.environment.source` (`replay`) may differ. `output::format_json_replay` exports it with `detail.module_detail: full`.
- A snapshot that lacks parts (`ReplayError::Incomplete`, naming them) or was written under other versions (`ReplayError::Incompatible`, naming field, stored and current value) is never evaluated under today's semantics. `load_artifacts` treats it as a cache miss.
- A snapshot that lacks parts (`ReplayError::Incomplete`, naming them) or was written under other versions (`ReplayError::Incompatible`, naming field, stored and current value) is never evaluated under today's semantics. `load_artifacts` treats it as a cache miss; `lookup_artifacts` and `cached_report` return the reason (`CacheMiss`: absent, unreadable, other configuration, not replayable), which the CLI prints.
- `--reuse-cache` answers through `replay_report_as(snapshot, "cache")`, `auditmysite replay <snapshot|directory|URL>` through `replay_report`. `SnapshotArtifact::check_measurement(&ExpectedProfile)` refuses a snapshot whose session policy, state id or storage-state digest differs from the asserted one (`ReplayError::OtherMeasurement`); `audit::profile_differences` names the differences between two profiles. A replay measures nothing, so the extra-check flags are refused for it (support matrix, mode `Replay`).
- `format_json_cached` works on a stored `NormalizedReport` alone and says so with `module_detail: not_restored`; an empty module block there never stands for restored data.
- Bump `SNAPSHOT_SCHEMA_VERSION` when the shape of the collected report changes in a way old data would survive deserialization, and `EVALUATION_VERSION` when a change moves a score, finding or verdict for unchanged input.

Expand Down
Loading
Loading