Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1465 attestation with private key #1502

Merged
merged 4 commits into from
Jan 26, 2023
Merged
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
11 changes: 8 additions & 3 deletions cmd/syft/cli/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const (
attestHelp = attestExample + attestSchemeHelp
)

//nolint:dupl
func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions) *cobra.Command {
func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po *options.PackagesOptions, ao *options.AttestOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "attest --output [FORMAT] <IMAGE>",
Short: "Generate an SBOM as an attestation for the given [SOURCE] container image",
Expand Down Expand Up @@ -50,11 +49,17 @@ func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions, po
},
}

// syft attest is an enhancment of the packages command, so it should have the same flags
// syft attest is an enhancement of the packages command, so it should have the same flags
err := po.AddFlags(cmd, v)
if err != nil {
log.Fatal(err)
}

// syft attest has its own options not included as part of the packages command
err = ao.AddFlags(cmd, v)
if err != nil {
log.Fatal(err)
}

return cmd
}
12 changes: 11 additions & 1 deletion cmd/syft/cli/attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func buildSBOM(app *config.Application, si source.Input, writer sbom.Writer, err
return sBytes, nil
}

//nolint:funlen
func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-chan error {
errs := make(chan error)
go func() {
Expand Down Expand Up @@ -131,9 +132,18 @@ func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-
}

args := []string{"attest", si.UserInput, "--type", "custom", "--predicate", f.Name()}
if app.Attest.Key != "" {
args = append(args, "--key", app.Attest.Key)
}

execCmd := exec.Command(cmd, args...)
execCmd.Env = os.Environ()
execCmd.Env = append(execCmd.Env, "COSIGN_EXPERIMENTAL=1")
if app.Attest.Key != "" {
execCmd.Env = append(execCmd.Env, fmt.Sprintf("COSIGN_PASSWORD=%s", app.Attest.Password))
} else {
// no key provided, use cosign's keyless mode
execCmd.Env = append(execCmd.Env, "COSIGN_EXPERIMENTAL=1")
}

// bus adapter for ui to hook into stdout via an os pipe
r, w, err := os.Pipe()
Expand Down
3 changes: 2 additions & 1 deletion cmd/syft/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ func New() (*cobra.Command, error) {
// we also need the command to have information about the `root` options because of this alias
ro := &options.RootOptions{}
po := &options.PackagesOptions{}
ao := &options.AttestOptions{}
packagesCmd := Packages(v, app, ro, po)

// root options are also passed to the attestCmd so that a user provided config location can be discovered
poweruserCmd := PowerUser(v, app, ro)
convertCmd := Convert(v, app, ro, po)
attestCmd := Attest(v, app, ro, po)
attestCmd := Attest(v, app, ro, po, ao)

// rootCmd is currently an alias for the packages command
rootCmd := &cobra.Command{
Expand Down
25 changes: 25 additions & 0 deletions cmd/syft/cli/options/attest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package options

import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

type AttestOptions struct {
Key string
}

var _ Interface = (*AttestOptions)(nil)

func (o AttestOptions) AddFlags(cmd *cobra.Command, v *viper.Viper) error {
cmd.Flags().StringVarP(&o.Key, "key", "k", "", "the key to use for the attestation")
return bindAttestConfigOptions(cmd.Flags(), v)
}

func bindAttestConfigOptions(flags *pflag.FlagSet, v *viper.Viper) error {
if err := v.BindPFlag("attest.key", flags.Lookup("key")); err != nil {
return err
}
return nil
}
1 change: 1 addition & 0 deletions internal/config/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Application struct {
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
FileContents fileContents `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
Expand Down
13 changes: 13 additions & 0 deletions internal/config/attest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package config

import "github.com/spf13/viper"

type attest struct {
Key string `yaml:"key" json:"key" mapstructure:"key"`
Password string `yaml:"password" json:"password" mapstructure:"password"`
}

func (cfg attest) loadDefaultValues(v *viper.Viper) {
v.SetDefault("attest.key", "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is already set because of the v.BindPFlag("attest.key", flags.Lookup("key")) earlier

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I removed it and didn't see any change. I would like to keep this though as the default that is called even if v.BindPFlag("attest.key", flags.Lookup("key")) is not invoked during another command.

I don't think v.BindPFlag("attest.key", flags.Lookup("key")) is called during other non attest command executions and having the config set explicit defaults overall seems cleaner than implicitly blank strings if nothing is called.

v.SetDefault("attest.password", "")
}
3 changes: 3 additions & 0 deletions ui/event_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ func AttestationStartedHandler(ctx context.Context, fr *frame.Frame, event party
text := s.Text()
if strings.Contains(text, "tlog entry created with index") {
tlogEntry = text
} else {
// no tlog entry create so user used personal PKI
tlogEntry = "signed attestation using provided key"
}
_, err = line.Write([]byte(fmt.Sprintf(" %s %s", auxInfoFormat.Sprintf("░░"), text)))
if err != nil {
Expand Down