# 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`/`https` manifest 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 typed `evidence.sources` entries and the legacy `source_root` plus `evidence_dir` filesystem configuration. ## TDD and verification - RED: focused tests initially failed during collection because the adapter package did not exist. - GREEN: `15 passed` for 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:`: 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 `openat` semantics (`dir_fd`, `O_NOFOLLOW`, and `O_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: true` is required for trusted private deployments and local tests. - Every HTTP response is closed in a `finally` block, 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.