feat(cli): explode archive materials in chainloop att add
Merged
JA
3mo ago+1263+1263+0123456789012345678901234567890123456789-30-30-01234567890123456789
Summary
chainloop attestation add --kind <KIND> --value <archive> now unpacks a .zip, .tar, .tar.gz, or .tgz for the kinds that have a meaningful "bundle of the same kind" archive form and records each contained regular file as its own material of the given kind, instead of requiring one att add invocation per file.
Behavior
- Explosion applies only to an allowlist of kinds:
SBOM_CYCLONEDX_JSON,SBOM_SPDX_JSON, andSARIF. For one of these, when the value resolves to a supported archive, each contained regular file is added as an individual material of that kind. - Every other kind (e.g.
ARTIFACT,EVIDENCE,ZAP_DAST_ZIP) records the archive whole, so a customer can still provide a regular zip as a single material. - Per-entry material names are sequential and 0-indexed:
material-0,material-1, … with no--name, or<name>-0,<name>-1, … when--nameis provided (used as the prefix, sanitized to DNS-1123). Names already present in the attestation are skipped. The recorded artifact filename preserves the original entry basename. - Annotations passed via
--annotationare applied to every extracted material. - The operation is atomic: either all qualifying entries are added or none.
- Extraction is guarded against zip bombs and path traversal:
--max-extract-entries(default 10000) and--max-extract-size(default 1GiB) are enforced while streaming, and directory, symlink, absolute, and path-traversal entries are skipped or rejected.
For non-explodable kinds, non-archive values, and no --kind, behavior is unchanged. There are no server-side, contract, or gRPC changes.
Assumptions and scope
- Explosion is limited to the SBOM/SARIF allowlist above; it is intentionally conservative so a regular zip provided for any other kind is never expanded. New kinds can be added to the allowlist as they gain a bundle form.
- Every extracted file is recorded under the same
--kind; archives mixing material types are not split by type. - Nested archives are not recursed — an archive contained inside the archive is treated as a regular file.
--policy-input-from-fileis ignored on the explode path (a warning is logged); policy inputs and evidence cross-links are not recorded for exploded materials.- Zero-length entries are skipped and produce no material.
- Only stdlib-supported formats are handled (
.zip,.tar,.tar.gz,.tgz); bzip2/xz are not supported in this iteration.
AI disclosure
This contribution was assisted by Claude Code.