3.8 KiB
Evidence Task 2 Report
Status
Implemented filesystem and explicit-manifest HTTP Evidence source adapters, typed source configuration with legacy compatibility, and factory construction.
Delivered behavior
- Filesystem discovery is deterministic and rooted at a strict canonical directory.
- Symlink/path escapes are rejected before content is exposed.
- Discovery hashing and acquisition reads enforce a configurable byte limit.
- Filesystem fingerprints are content SHA-256 values; stable IDs derive from relative paths.
- HTTP accepts only explicit
http/httpsmanifest entries and keeps transport URLs private. - HTTP provenance strips query strings/fragments, while config and adapter representations hide signed or secret-bearing transport URLs.
- HTTP acquisition uses separate connect/read timeouts, streaming byte limits, bounded redirects, private redirect rejection, and safe transient/permanent error classification.
- HTTP fingerprints prefer a deterministic ETag digest, then Last-Modified, then content SHA-256.
build_evidence_sources(cfg)supports both typedevidence.sourcesentries and the legacysource_rootplusevidence_dirfilesystem configuration.
TDD and verification
- RED: focused tests initially failed during collection because the adapter package did not exist.
- GREEN:
15 passedfor filesystem, HTTP, and resource-config tests. - Full harness:
548 passed, 5 deselected. - Changed-file Ruff: clean.
- Repository-wide Ruff remains non-clean due to 34 pre-existing findings in unrelated test files; no unrelated lint files were modified.
Notes
The approved SourceObject namespace grammar does not permit raw quoted ETags such as
etag:"abc". The adapter therefore uses etag:<sha256-of-opaque-etag>: it preserves ETag-based
change identity without weakening the canonical contract or exposing validator contents.
Review hardening follow-up
Four review findings were closed in a separate follow-up commit:
- Filesystem access now anchors a persistent descriptor at the canonical root and walks each
component with
openatsemantics (dir_fd,O_NOFOLLOW, andO_DIRECTORY). The regular-file check, bounded read, metadata, and hash all use the opened descriptor. Acquisition reopens by the same path-safe mechanism and rejects a changed fingerprint. Deterministic tests swap both a leaf and an ancestor to symlinks at open time. - HTTP network policy defaults to public hosts only. Initial URLs and every redirect reject
userinfo, mixed public/private IPv4/IPv6 answers fail closed, and the connected peer must be a
public member of the previously validated DNS answer set before any body bytes are consumed.
Explicit
allow_private_hosts: trueis required for trusted private deployments and local tests. - Every HTTP response is closed in a
finallyblock, including redirects, status failures, policy failures, oversized bodies, and mid-stream exceptions. - ETag and Last-Modified values remain adapter-internal. Repeated discovery and acquisition send
conditional headers; a 304 reuses only previously verified cached bytes and identity. The LRU
content cache has an explicit byte bound (
max_cache_bytes). Validators are not forwarded across redirect origins.
Conditional cache binding correction
The conditional cache now binds bytes and validators to both the canonical provenance key and the exact final effective representation URL. Redirect traversal recomputes request headers per hop: validators are sent only when that exact URL matches the cached final URL, never merely because a redirect retains an origin. A same-origin path change therefore downloads and replaces the body. The adapter accepts 304 only when the exact request carried a bound ETag or Last-Modified validator; unsolicited and cross-origin 304 responses are permanent protocol errors.