Skip to content

feat(stores): route audit-cache through AuditCacheStore protocol (feature 035) - #413

Merged
Marc-cn merged 1 commit into
darnitdevorg:mainfrom
mlieberman85:035-audit-cache-store-migration
Sep 6, 2026
Merged

Marc-cn merged 1 commit into
darnitdevorg:mainfrom
mlieberman85:035-audit-cache-store-migration

Conversation

@mlieberman85

Copy link
Copy Markdown
Contributor

Summary

Close the wiring gap where tools/audit.py::run_sieve_audit called core.audit_cache.write_audit_cache directly, ignoring feature 033's execution_context.stores.cache bundle. Operators setting [stores.cache] backend / root in .baseline.toml now see the audit-cache actually redirect.

Changes

  • core/audit_cache.py rewritten as thin wrapper over AuditCacheStore. Public API keeps positional signatures (backward compat) plus two new kwargs (store, cache_key) for driver-side calls. TTL / git-HEAD / working-tree-dirty staleness enforcement stays in the wrapper, not the store.
  • tools/audit.py picks cache_key by whether stores_config.cache is set: "audit-cache" for default-store (root already encodes repo identity) or sha256(abspath(repo))[:16] for a configured store (per-repo isolation under a shared root).
  • stores/selection.py default cache_root moved from <repo>/.darnit/audit-cache/ to <tempdir>/darnit/<sha256(abspath(repo))[:16]> so bundle.cache's default backend produces the same byte-for-byte on-disk path as the pre-feature wrapper.

Documented behavior changes

  • write_audit_cache is best-effort per feature 033 FR-011 (log and continue; previously raised on tempfile failure).
  • invalidate_audit_cache writes an expired envelope (timestamp 1970-01-01T00:00:00Z) rather than deleting the file. The AuditCacheStore Protocol has no delete(key) method; the surface stays unchanged.

Test plan

  • 11 new driver-level integration tests at tests/darnit/test_audit_cache_store_wiring.py (configured-store routing, zero-config invariance, staleness through a configured store, shared-root non-collision, fault injection, backward-compat call form).
  • Two existing tests updated for behavior change: no-raise on write failure, invalidate leaves expired envelope.
  • Two zero-config path-shape tests updated to expect the new default cache_root (tempdir/hash instead of repo/.darnit/audit-cache).
  • End-to-end: darnit audit with [stores.cache] backend = "local-fs" root = "/tmp/qs-cache" writes /tmp/qs-cache/<hash>.json and does NOT create a fallback under the tempdir.
  • Full framework test suite: 1900 passed, 6 skipped, 0 failed.

Follow-up (out of scope)

  • packages/darnit-baseline/src/darnit_baseline/remediation/orchestrator.py calls read_audit_cache(local_path) positionally, so it always reads from the backward-compat default store. To honor configured [stores.cache] on the remediate side too, that consumer needs its own driver-style call refactor. Explicitly listed as out-of-scope in specs/035-audit-cache-store-migration/spec.md.

Spec

Full spec, plan, and tasks live at specs/035-audit-cache-store-migration/.

@mlieberman85
mlieberman85 force-pushed the 035-audit-cache-store-migration branch from 670dec5 to 2bc52ad Compare September 5, 2026 17:01
…ture 035)

Close the wiring gap where tools/audit.py::run_sieve_audit called
core.audit_cache.write_audit_cache directly, ignoring feature 033's
execution_context.stores.cache bundle. Operators setting [stores.cache]
backend/root in .baseline.toml now see the audit-cache actually redirect.

Core changes:
- core/audit_cache.py rewritten as thin wrapper over AuditCacheStore.
  Public API keeps positional signatures (backward compat) plus two new
  kwargs (store, cache_key) for driver-side calls. TTL / git-HEAD /
  working-tree-dirty staleness enforcement stays in the wrapper, not
  the store.
- tools/audit.py picks cache_key by whether stores_config.cache is set:
  "audit-cache" for the default-store case (root already encodes repo
  identity), sha256(abspath(repo))[:16] for the configured-store case
  (per-repo isolation under a shared root).
- stores/selection.py default cache_root moved from <repo>/.darnit/
  audit-cache/ to <tempdir>/darnit/<sha256(abspath(repo))[:16]> so
  bundle.cache's default backend produces the same byte-for-byte
  on-disk path as the pre-feature audit_cache wrapper.

Behavior changes documented in the spec:
- write_audit_cache is best-effort per feature 033 FR-011 (log and
  continue; previously raised on tempfile failure).
- invalidate_audit_cache writes an expired envelope (timestamp
  1970-01-01T00:00:00Z) rather than deleting the file. The
  AuditCacheStore protocol has no delete(key) method; the surface stays
  unchanged.

Tests:
- 11 new driver-level integration tests at tests/darnit/
  test_audit_cache_store_wiring.py cover configured-store routing,
  zero-config invariance, staleness through a configured store, shared
  -root non-collision, fault injection, and backward-compat call form.
- Two existing tests updated for behavior change: no-raise on write
  failure, invalidate leaves an expired envelope.
- Two zero-config path-shape tests updated to expect the new default
  cache_root shape (tempdir/hash instead of repo/.darnit/audit-cache).

Verified end-to-end: darnit audit with [stores.cache] backend="local-fs"
root="/tmp/qs-cache" writes /tmp/qs-cache/<hash>.json and does NOT
create a fallback file under the system tempdir.

Full framework test suite: 1900 passed, 6 skipped, 0 failed.
@mlieberman85
mlieberman85 force-pushed the 035-audit-cache-store-migration branch from 2bc52ad to 33999f9 Compare September 5, 2026 17:27
@Marc-cn

Marc-cn commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

The wiring works end to end with this in .baseline.toml:

[stores.cache]
backend = "local-fs"
root = "/tmp/qs-cache"

the cache lands at /tmp/qs-cache/<hash>.json and nothing is written to the fallback tempdir. Zero-config writes to /tmp/darnit/<hash>/audit-cache.json as before, and the audited repo stays clean.

tests/darnit/test_audit_cache_store_wiring.py 11/11.
lgtm

@Marc-cn
Marc-cn merged commit a1d4493 into darnitdevorg:main Sep 6, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants