Skip to content

Commit 07f57c5

Browse files
authored
feat(cli): output format to export PAE-encoded payload (#971)
Signed-off-by: Jose I. Paris <[email protected]>
1 parent 584f4aa commit 07f57c5

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

app/cli/cmd/workflow_workflow_run_describe.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,25 @@ import (
1919
"context"
2020
"errors"
2121
"fmt"
22+
"io"
2223
"os"
2324
"time"
2425

2526
"github.com/chainloop-dev/chainloop/app/cli/internal/action"
2627
"github.com/jedib0t/go-pretty/v6/table"
2728
"github.com/jedib0t/go-pretty/v6/text"
2829
"github.com/muesli/reflow/wrap"
30+
"github.com/secure-systems-lab/go-securesystemslib/dsse"
2931
"github.com/spf13/cobra"
3032
)
3133

3234
const formatStatement = "statement"
3335
const formatAttestation = "attestation"
3436

37+
// outputs the payload in PAE encoding, so that it matches the signature in the attestation,
38+
// and it's easily verifiable by external tools
39+
const formatPayloadPAE = "payload-pae"
40+
3541
func newWorkflowWorkflowRunDescribeCmd() *cobra.Command {
3642
var runID, attestationDigest, publicKey string
3743
var verifyAttestation bool
@@ -58,7 +64,7 @@ func newWorkflowWorkflowRunDescribeCmd() *cobra.Command {
5864
return err
5965
}
6066

61-
return encodeAttestationOutput(res)
67+
return encodeAttestationOutput(res, os.Stdout)
6268
},
6369
}
6470

@@ -73,7 +79,7 @@ func newWorkflowWorkflowRunDescribeCmd() *cobra.Command {
7379
}
7480

7581
// Override default output flag
76-
cmd.InheritedFlags().StringVarP(&flagOutputFormat, "output", "o", "table", "output format, valid options are table, json, attestation or statement")
82+
cmd.InheritedFlags().StringVarP(&flagOutputFormat, "output", "o", "table", "output format, valid options are table, json, attestation, statement or payload-pae")
7783

7884
return cmd
7985
}
@@ -193,7 +199,7 @@ func predicateV1Table(att *action.WorkflowRunAttestationItem) {
193199
}
194200
}
195201

196-
func encodeAttestationOutput(run *action.WorkflowRunItemFull) error {
202+
func encodeAttestationOutput(run *action.WorkflowRunItemFull, writer io.Writer) error {
197203
// Try to encode as a table or json
198204
err := encodeOutput(run, workflowRunDescribeTableOutput)
199205
// It was correctly encoded, we are done
@@ -217,7 +223,18 @@ func encodeAttestationOutput(run *action.WorkflowRunItemFull) error {
217223
return encodeJSON(run.Attestation.Statement())
218224
case formatAttestation:
219225
return encodeJSON(run.Attestation.Envelope)
226+
case formatPayloadPAE:
227+
return encodePAE(run, writer)
220228
default:
221229
return ErrOutputFormatNotImplemented
222230
}
223231
}
232+
233+
func encodePAE(run *action.WorkflowRunItemFull, writer io.Writer) error {
234+
payload, err := run.Attestation.Envelope.DecodeB64Payload()
235+
if err != nil {
236+
return fmt.Errorf("could not decode attestation payload: %w", err)
237+
}
238+
_, err = fmt.Fprint(writer, string(dsse.PAE(run.Attestation.Envelope.PayloadType, payload)))
239+
return err
240+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// Copyright 2024 The Chainloop Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package cmd
17+
18+
import (
19+
"bytes"
20+
"encoding/base64"
21+
"testing"
22+
23+
"github.com/chainloop-dev/chainloop/app/cli/internal/action"
24+
"github.com/secure-systems-lab/go-securesystemslib/dsse"
25+
"github.com/stretchr/testify/suite"
26+
)
27+
28+
type workflowRunDescribeSuite struct {
29+
suite.Suite
30+
31+
run *action.WorkflowRunItemFull
32+
}
33+
34+
func TestSuite(t *testing.T) {
35+
suite.Run(t, new(workflowRunDescribeSuite))
36+
}
37+
38+
func (s *workflowRunDescribeSuite) SetupTest() {
39+
s.run = &action.WorkflowRunItemFull{
40+
Attestation: &action.WorkflowRunAttestationItem{
41+
Envelope: &dsse.Envelope{
42+
PayloadType: "application/vnd.in-toto+json",
43+
Payload: base64.StdEncoding.EncodeToString([]byte("hello")),
44+
Signatures: nil,
45+
},
46+
},
47+
}
48+
}
49+
50+
func (s *workflowRunDescribeSuite) TestOutputTypePayload() {
51+
flagOutputFormat = formatPayloadPAE
52+
expected := "DSSEv1 28 application/vnd.in-toto+json 5 hello"
53+
54+
buf := new(bytes.Buffer)
55+
err := encodeAttestationOutput(s.run, buf)
56+
s.NoError(err)
57+
58+
s.Require().NoError(err)
59+
s.Equal(expected, buf.String())
60+
}

0 commit comments

Comments
 (0)