Skip to content

Commit a25c290

Browse files
committed
refactor(cli): simplify archive-explode output and routing
Drop the redundant explode bool from shouldExplode (derivable from the returned ArchiveFormat) and branch on the format at the call site. Reuse output.EncodeOutput for the multi-material result instead of a hand-rolled format switch, adding []*AttestationStatusMaterial to the tabulated-data union so the slice renders as a single JSON array. Assisted-by: Claude Code Signed-off-by: Javier Rodriguez <javier@chainloop.dev> Chainloop-Trace-Sessions: da72e107-14e9-4da1-add0-28004f542628, ef6d3cdb-5a23-445c-b39a-510b659023e4
1 parent 8d2a365 commit a25c290

4 files changed

Lines changed: 25 additions & 36 deletions

File tree

app/cli/cmd/attestation_add.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,22 +150,17 @@ func newAttestationAddCmd() *cobra.Command {
150150
return err
151151
}
152152

153-
// The explode path can return several materials. Render JSON as a
154-
// single array so the output stays a parseable document; only the
155-
// table renderer is emitted per material.
156-
switch flagOutputFormat {
157-
case output.FormatJSON:
158-
return output.EncodeJSON(resp)
159-
case output.FormatTable:
160-
for _, m := range resp {
153+
// The explode path can return several materials. EncodeOutput
154+
// renders the whole slice as a single JSON array (a parseable
155+
// document) and the table renderer per material.
156+
return output.EncodeOutput(flagOutputFormat, resp, func(mats []*action.AttestationStatusMaterial) error {
157+
for _, m := range mats {
161158
if err := displayMaterialInfo(m, policies[m.Name]); err != nil {
162159
return err
163160
}
164161
}
165162
return nil
166-
default:
167-
return output.ErrOutputFormatNotImplemented
168-
}
163+
})
169164
},
170165
)
171166
},

app/cli/cmd/output/output.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type tabulatedData interface {
5656
*action.APITokenItem |
5757
[]*action.APITokenItem |
5858
*action.AttestationStatusMaterial |
59+
[]*action.AttestationStatusMaterial |
5960
*action.ListMembershipResult |
6061
*action.PolicyLintResult
6162
}

app/cli/pkg/action/attestation_add.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,11 @@ func (action *AttestationAdd) Run(ctx context.Context, attestationID, materialNa
153153
addOpts := runtimeInputAddOpts(runtimeInputs)
154154

155155
// Explode path: --kind set, value is a (non-archive-native) archive.
156-
format, explode, err := shouldExplode(materialType, materialValue)
156+
format, err := shouldExplode(materialType, materialValue)
157157
if err != nil {
158158
return nil, fmt.Errorf("detecting archive: %w", err)
159159
}
160-
if explode {
160+
if format != materials.ArchiveNone {
161161
if len(policyInputFiles) > 0 {
162162
action.Logger.Warn().Msg("--policy-input-from-file is ignored when expanding an archive; evidence cross-links are not recorded for exploded materials")
163163
}
@@ -226,15 +226,11 @@ func (action *AttestationAdd) Run(ctx context.Context, attestationID, materialNa
226226
// shouldExplode decides whether an att-add should explode the value into many
227227
// materials: only when --kind is set, the value is a supported archive, and the
228228
// kind is not archive-native (e.g. ZAP_DAST_ZIP, which is recorded whole).
229-
func shouldExplode(materialType, value string) (materials.ArchiveFormat, bool, error) {
229+
func shouldExplode(materialType, value string) (materials.ArchiveFormat, error) {
230230
if materialType == "" || materials.IsArchiveNativeKind(materialType) {
231-
return materials.ArchiveNone, false, nil
231+
return materials.ArchiveNone, nil
232232
}
233-
format, err := materials.DetectArchive(value)
234-
if err != nil {
235-
return materials.ArchiveNone, false, err
236-
}
237-
return format, format != materials.ArchiveNone, nil
233+
return materials.DetectArchive(value)
238234
}
239235

240236
// runtimeInputAddOpts wraps the runtime inputs as crafter add options, or

app/cli/pkg/action/attestation_add_routing_test.go

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,26 @@ func TestShouldExplode(t *testing.T) {
5353
require.NoError(t, os.WriteFile(plainPath, []byte("not an archive"), 0600))
5454

5555
tests := []struct {
56-
name string
57-
kind string
58-
value string
59-
wantExplode bool
60-
wantFormat materials.ArchiveFormat
56+
name string
57+
kind string
58+
value string
59+
wantFormat materials.ArchiveFormat
6160
}{
62-
{"kind + archive", "SBOM_CYCLONEDX_JSON", zipPath, true, materials.ArchiveZip},
63-
{"archive-native kind", "ZAP_DAST_ZIP", zipPath, false, materials.ArchiveNone},
64-
{"no kind", "", zipPath, false, materials.ArchiveNone},
65-
{"kind + non-archive", "ARTIFACT", plainPath, false, materials.ArchiveNone},
61+
// A non-ArchiveNone format means the value will be exploded.
62+
{"kind + archive", "SBOM_CYCLONEDX_JSON", zipPath, materials.ArchiveZip},
63+
{"archive-native kind", "ZAP_DAST_ZIP", zipPath, materials.ArchiveNone},
64+
{"no kind", "", zipPath, materials.ArchiveNone},
65+
{"kind + non-archive", "ARTIFACT", plainPath, materials.ArchiveNone},
6666
// Non-file values must never return an error — STRING and CONTAINER_IMAGE
6767
// carry values that are not file paths at all.
68-
{"kind STRING non-file value", "STRING", "hello world", false, materials.ArchiveNone},
69-
{"kind CONTAINER_IMAGE non-file value", "CONTAINER_IMAGE", "registry.example.com/app:v1", false, materials.ArchiveNone},
68+
{"kind STRING non-file value", "STRING", "hello world", materials.ArchiveNone},
69+
{"kind CONTAINER_IMAGE non-file value", "CONTAINER_IMAGE", "registry.example.com/app:v1", materials.ArchiveNone},
7070
}
7171
for _, tc := range tests {
7272
t.Run(tc.name, func(t *testing.T) {
73-
format, explode, err := shouldExplode(tc.kind, tc.value)
73+
format, err := shouldExplode(tc.kind, tc.value)
7474
require.NoError(t, err)
75-
assert.Equal(t, tc.wantExplode, explode)
76-
if explode {
77-
assert.Equal(t, tc.wantFormat, format)
78-
}
75+
assert.Equal(t, tc.wantFormat, format)
7976
})
8077
}
8178
}

0 commit comments

Comments
 (0)