feat(cli): accept an archive of dranzer reports as one material - #3310
Conversation
AI Session Analysis
|
| Status | Policy | Material | Messages |
|---|---|---|---|
| ✅ Passed | ai-config-ai-agents-allowed |
ai-coding-session-2b0a76 |
- |
| ✅ Passed | ai-config-no-dangerous-commands |
ai-coding-session-2b0a76 |
- |
| ✅ Passed | ai-config-no-secrets |
ai-coding-session-2b0a76 |
- |
| ✅ Passed | ai-config-mcp-servers-allowed |
ai-coding-session-2b0a76 |
- |
Powered by Chainloop and Chainloop Trace
There was a problem hiding this comment.
All reported issues were addressed across 21 files
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
A single dranzer run emits one report per test mode (-b, -p, -s, -t), so the evidence arrives as a bundle rather than a single file. CERTCC_DRANZER now accepts either a single report or a zip/tar.gz of them, following the RADAMSA_CRASHES precedent: the archive is recorded whole under the contract's declared material name, with the report count as an annotation. Recording the archive alone is not enough, because the policy engine reads dranzer content: parsing archive bytes as text yields an empty report, which makes the ActiveX policy skip rather than evaluate and reads as a clean run. The projection therefore aggregates the archive's entries, summing every counter and unioning objects and findings, and keeps a per-report breakdown alongside. The aggregate is promoted to the top level so existing policies reading tool, summary and findings are unaffected. Craft time and evaluation time share both predicates -- what counts as an archive and what counts as a report -- because a disagreement would accept a material whose projection then silently skips. Container detection is by content on both sides for the same reason: a zip carrying a prepended stub still opens, since its central directory is at the end, but no longer starts with the zip magic, so detecting by filename at craft time would accept what the projection cannot read. Archive container detection and walking move to a new archiveio leaf package so the projection can share the entry-count, size and traversal guards with the crafters without an import cycle. Those guards are also corrected: the size cap reported its error alongside a full buffer, which io.ReadFull discards, so a stream read in exact block sizes -- every tar header -- passed the limit unreported; and entries skipped as directories or symlinks counted against neither limit, letting a directory-only tar.gz decompress unmeasured. LooksLikeDranzer now judges only what the parser extracted rather than the presence of a phrase in the raw text. The CSV companion that ships beside real reports quotes both the per-object banner and an error line inside its columns, so a substring match accepted a file that yields no version, objects, findings or counters -- which would then skip policy evaluation. Genuine reports put those lines on their own line where the anchored patterns match them, and a parsed counter counts even when zero, so a run that found no COM objects is still recognized. Container detection fills its peek buffer instead of trusting a single read, since the tar marker sits at offset 257 and a short read would misdetect a valid tar as a plain file, and it now surfaces read failures rather than reporting them as "not an archive". Refs PFM-6467 Assisted-by: Claude Code Signed-off-by: Javier Rodriguez <javier@chainloop.dev> Chainloop-Trace-Sessions: 2b0a76d9-abe5-44af-919a-419aca149653
31c2512 to
b8a3ffa
Compare
|
Both findings addressed in b8a3ffa.
Short header read / swallowed read errors — valid. The tar marker sits at offset 257, so a single Both are covered by tests that failed before the fix. End-to-end behaviour against a real dranzer bundle is unchanged. |
Resolves the archive.go conflict against upstream's archiveio refactor (chainloop-dev#3310/chainloop-dev#3301): keep upstream's archiveio-backed primitives and re-apply the AllocateNamed allocator and NormalizeArchivePath helper on top. Regenerated the workflowcontract proto artifacts so the additive match_mode field coexists with the upstream protovalidate bump. Assisted-by: Claude Code Signed-off-by: Javier Rodriguez <javier@chainloop.dev>
Summary
A single CERT/CC dranzer run emits one plain-text report per test mode (
-b,-p,-s,-t), so the evidence arrives as an archive rather than a single file.CERTCC_DRANZERnow accepts either a single report or a zip/tar.gz holding several, following theRADAMSA_CRASHESprecedent: the archive is recorded whole as one material under the contract's declared material name, with the number of reports it holds recorded as an annotation.Because the policy engine reads dranzer content, recording the archive is not sufficient on its own — parsing archive bytes as text yields an empty report, which makes a policy skip rather than evaluate. The policy-input projection therefore aggregates the archive's entries, summing the run counters and unioning the per-object and finding data, and carries a per-report breakdown alongside so a policy can be precise about which mode reported what. The aggregate is promoted to the top level of the projection, so policies that read
tool,summaryandfindingsbehave the same whether the material was a single report or a bundle.Archive container detection and walking move into a new
archiveioleaf package, so the crafters and the policy-input projections share one implementation of the entry-count, uncompressed-size and path-traversal guards rather than each carrying their own. Two gaps in those guards are closed as part of the move: the size cap reported its error alongside a full buffer, whichio.ReadFulldiscards, so a stream read in exact block sizes passed the limit unreported; and entries skipped as directories or symlinks counted against neither limit.The dranzer fingerprint no longer falls back to searching the raw text for a per-object banner. The CSV companion file that ships beside real reports quotes that banner inside one of its columns, so the fallback accepted a file carrying no version, objects, findings or counters — which would then skip policy evaluation rather than being rejected. Genuine reports carry the banner on its own line and are unaffected.
Refs PFM-6467
AI assistance
This change was produced with assistance from Claude Code, disclosed via the
Assisted-bytrailer on the commit.