3.0 KiB
2026-08-23 — snapshot integrity hardening
Plan status
- Root-cause fix for fail-open point-in-time metadata: complete.
- Raw payload and normalized snapshot binding: complete.
- Manifest/source metadata cross-checks: complete.
- Cached research report revalidation: complete.
- Trusted host/signing boundary: documented as local-only; multi-user deployment deferred.
Changed files
backend/app/vintages.py— canonical normalized hash, raw payload verification, manifest/source cross-checks, timezone-equivalent revision handling.backend/app/prices.py— canonical normalized hash, strict boolean point-in-time metadata, raw/manifest/source cross-checks.backend/app/research.py— validate selected snapshots before cached report lookup and derive the price gate from the verified snapshot source.backend/app/__init__.py— price health validates the latest snapshot before reporting availability.backend/tests/test_vintages.py— normalized payload tamper regression.backend/tests/test_research.py— manifest tamper and cached-ready replay regressions.
Root cause
The previous implementation trusted manifest metadata too early. A truthy string such as "false" could pass a boolean gate, and a ready report could be returned from cache before current snapshot bytes were revalidated. The previous vintage loader also checked identity but not raw/normalized content against the manifest.
Fix
All new persisted snapshots carry:
normalized_hash_algorithm: sha256-json-canonical-v1
normalized_snapshot_hash: SHA-256(sorted-key compact UTF-8 JSON, excluding only the hash field)
raw_payload_hash: SHA-256(raw provider payload)
Loads now verify raw files, normalized content, manifest metadata, strict boolean types, and snapshot identity before the research runner can return a cached result or run an event study.
Live evidence
BOT source restarted and replayable=true.
Price snapshot re-collected under the new schema; 9 symbols; point_in_time=false.
GET /api/v1/prices/health → HTTP 200, available=true, revised_vendor_history.
POST /api/v1/research/tourism/run → HTTP 200, blocked 1/12 releases.
Verification
PYTHONPATH=backend .venv/bin/python -W error -m unittest discover -s backend/tests -v
Ran 57 tests ... OK
npm run build
Vite build completed successfully.
npm audit --omit=dev --audit-level=high
found 0 vulnerabilities
python -m compileall -q backend
python /tmp/set50_platform_security_scan.py → {}
git diff --check
Boundary
Content hashes are a local artifact/corruption control. They are not a signature against a hostile operator who can rewrite the application, manifests, raw files and runtime environment. Add a trusted deployment signing key before multi-user or hostile-host deployment.
Independent review
passed: true
security_concerns: []
logic_errors: []
Non-blocking backlog: retain the canonicalization/hash-version contract, keep crash/partial-write coverage, and introduce signed manifests when the deployment threat model expands.