Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions cmd/cosign/cli/attest/attest_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,24 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error
}
}

if err := os.WriteFile(c.BundlePath, contents, 0600); err != nil {
return fmt.Errorf("create bundle file: %w", err)
// If BundlePath is "-", write to stdout with trailing newline
if c.BundlePath == "-" {
fmt.Fprintln(os.Stdout, string(contents))
} else {
if err := os.WriteFile(c.BundlePath, contents, 0600); err != nil {
return fmt.Errorf("create bundle file: %w", err)
}
fmt.Fprintln(os.Stderr, "Bundle wrote in the file ", c.BundlePath)
}
fmt.Fprintln(os.Stderr, "Bundle wrote in the file ", c.BundlePath)
}

if c.OutputSignature != "" {
if err := os.WriteFile(c.OutputSignature, bundleComponents.SignedPayload, 0600); err != nil {
return fmt.Errorf("create signature file: %w", err)
}
fmt.Fprintf(os.Stderr, "Signature written in %s\n", c.OutputSignature)
} else {
} else if c.BundlePath != "-" {
// Only output signature to stdout if bundle is not going to stdout
fmt.Fprintln(os.Stdout, string(bundleComponents.SignedPayload))
}

Expand Down
59 changes: 59 additions & 0 deletions cmd/cosign/cli/attest/attest_blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,62 @@ func TestStatementPath(t *testing.T) {
err := at.Exec(ctx, "")
assert.NoError(t, err)
}

// TestAttestBlobBundleStdout tests that the bundle is printed to stdout
// with a trailing newline when --bundle is set to "-"
func TestAttestBlobBundleStdout(t *testing.T) {
ctx := context.Background()
td := t.TempDir()

keys, _ := cosign.GenerateKeyPair(nil)
keyRef := writeFile(t, td, string(keys.PrivateBytes), "key.pem")

blob := []byte("foo")
blobPath := writeFile(t, td, string(blob), "foo.txt")
predicatePath := makeSLSA02PredicateFile(t, td)

// Capture stdout
oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

at := AttestBlobCommand{
KeyOpts: options.KeyOpts{
KeyRef: keyRef,
NewBundleFormat: true,
BundlePath: "-", // stdout
},
PredicatePath: predicatePath,
PredicateType: "slsaprovenance",
RekorEntryType: "dsse",
}

err := at.Exec(ctx, blobPath)
if err != nil {
t.Fatal(err)
}

// Restore stdout and read captured output
w.Close()
os.Stdout = oldStdout
var buf bytes.Buffer
_, _ = buf.ReadFrom(r)
output := buf.String()

// Verify output has trailing newline
if !strings.HasSuffix(output, "\n") {
t.Fatal("expected bundle output to have trailing newline")
}

// Verify output is valid JSON
outputWithoutNewline := strings.TrimSuffix(output, "\n")
var bundle interface{}
if err := json.Unmarshal([]byte(outputWithoutNewline), &bundle); err != nil {
t.Fatalf("bundle output is not valid JSON: %v", err)
}

// Verify bundle is non-empty
if len(outputWithoutNewline) == 0 {
t.Fatal("expected non-empty bundle output")
}
}
6 changes: 5 additions & 1 deletion cmd/cosign/cli/attest_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ func AttestBlob() *cobra.Command {
cosign attest-blob --predicate <FILE> --type <TYPE> --key hashivault://[KEY] <BLOB>
# supply attestation via stdin
echo <PAYLOAD> | cosign attest-blob --predicate - --yes`,
echo <PAYLOAD> | cosign attest-blob --predicate - --yes
# create a JSONL file with multiple attestations by outputting bundles to stdout
cosign attest-blob --key cosign.key --predicate <FILE1> --type <TYPE> --bundle=- <BLOB> >> attestations.jsonl
cosign attest-blob --key cosign.key --predicate <FILE2> --type <TYPE> --bundle=- <BLOB> >> attestations.jsonl`,

PersistentPreRun: options.BindViper,
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/options/attest_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) {
_ = cmd.MarkFlagFilename("key", certificateExts...)

cmd.Flags().StringVar(&o.BundlePath, "bundle", "",
"write everything required to verify the blob to a FILE")
"write everything required to verify the blob to a FILE (use \"-\" for stdout)")
_ = cmd.MarkFlagFilename("bundle", bundleExts...)

cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true,
Expand Down
5 changes: 5 additions & 0 deletions cmd/cosign/cli/signcommon/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,11 @@ func WriteNewBundleWithSigningConfig(ctx context.Context, ko options.KeyOpts, ce
}

if bundleOpts.BundlePath != "" {
// If bundleOpts.BundlePath is "-", write to stdout with trailing newline
if bundleOpts.BundlePath == "-" {
fmt.Fprintln(os.Stdout, string(bundle))
return nil
}
if err := os.WriteFile(bundleOpts.BundlePath, bundle, 0600); err != nil {
return fmt.Errorf("creating bundle file: %w", err)
}
Expand Down
6 changes: 5 additions & 1 deletion doc/cosign_attest-blob.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading