Skip to content

Commit

Permalink
Attest: Add refs flag, improve help and command
Browse files Browse the repository at this point in the history
This commit adds a new --refs flag to the attest subcommand. This lets
the user define an image reference to attach the attestation to. The help
text is also improved.

This commit also adds the --file reusable flag to allow attestations to be
written to a file.

Finally, this commit reshuffles the attest subcommand to use the pattern
of reusable flags in use in other subcommmands.

Signed-off-by: Adolfo Garcia Veytia (puerco) <[email protected]>
  • Loading branch information
puerco committed Oct 8, 2023
1 parent a74ed39 commit f72ff68
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 44 deletions.
131 changes: 89 additions & 42 deletions internal/cmd/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,86 @@ import (
"context"
"errors"
"fmt"
"io"
"os"

"github.com/google/go-containerregistry/pkg/name"
"github.com/openvex/vexctl/pkg/ctl"
"github.com/spf13/cobra"
)

type attestOptions struct {
outFileOption
attach bool
sign bool
refs []string
}

func (o *attestOptions) AddFlags(cmd *cobra.Command) {
o.outFileOption.AddFlags(cmd)
cmd.PersistentFlags().BoolVarP(
&o.attach,
"attach",
"a",
false,
"attach the generated attestation to an image (implies --sign)",
)

cmd.PersistentFlags().BoolVarP(
&o.sign,
"sign",
"s",
false,
"sign the attestation with sigstore",
)

cmd.PersistentFlags().StringArrayVarP(
&o.refs,
"refs",
"r",
[]string{},
"list of image references to attach the attestation to",
)
}

// Validate checks if the options are sane
func (o *attestOptions) Validate() error {
var sErr error
for _, ref := range o.refs {
if _, err := name.ParseReference(ref); err != nil {
sErr = fmt.Errorf("parsing reference: %w", err)
break
}
}

if o.attach {
o.sign = true
}

return errors.Join(
sErr, o.outFileOption.Validate(),
)
}

func addAttest(parentCmd *cobra.Command) {
opts := attestOptions{}
generateCmd := &cobra.Command{
attestCmd := &cobra.Command{
Short: fmt.Sprintf("%s attest: generate a VEX attestation", appname),
Long: fmt.Sprintf(`%s attest: generate an VEX attestation
The attach subcommand lets users wrap OpenVEX documents in in-toto attestations.
Attestations generated by %s can be signed with sigstore and attached to container
images stored in an OCI registry.
Attestations generated by %s can be signed with sigstore and attached to
container images stored in an OCI registry.
In its simplest form, %s will create an attestation from an OpenVEX file and
write it to stdout:
%s attest data.vex.json
Without any more arguments, images defined as products in the VEX statements,
will be read by %s and transferred to the attestation's subjects when required.
Without any more arguments, container images and other products that have hashes
defined in their VEX statements, will be read by %s and transferred to
the attestation's subjects when required.
If the products are purls of type oci:, they will be converted to image
references as is customary in the sigstore tooling. For example:
Expand All @@ -48,11 +100,12 @@ It will be transferred to the attestation subjects as:
registry.k8s.io/kube-apiserver:v1.26.0
Any purls and image references not specifying a digest will trigger a network
lookup to read the image digest from the registry.
Any oci purls and image references not specifying a digest will trigger a
network lookup to read the image digest from the registry.
Please note that purls of types other than oci: and other strings which are not
valid image references will not be included in the resulting attestation.
valid image references will not be included in the resulting attestation unless
the product has hashes associated with it.
Signing Attestations
--------------------
Expand All @@ -62,35 +115,38 @@ credentials from the user or trying to get them from the environment:
%s attest --sign data.vex.json
When signing an attestation, the standard sigstore signing flow will be defined
When signing an attestation, the standard sigstore signing flow will be triggered
if credentials are not found in the environment. Refer to the sigstore
documentation for details.
Attaching Attestations
----------------------
The --attach flag will attach the attestation to the OCI registry of all attested
images. It will use the credentials in the user's environment to authenticate,
this means that if you can write to the registry, attaching should work.
The --attach flag will attach the resulting attestation to the OCI registry of
all subjects that parse as image references. If this behavior fails, try defining
--refs to specify which images to attach the attestation to.
--attach always implies --sign as sigstore does not support attaching unsigned
images.
%s will use the credentials from the user's environment to authenticate to the
registry, this means that if you can write to the registry, attaching should work.
Note: --attach always implies --sign as sigstore does not support attaching
unsigned attestations.
Specifying Images to Attest
---------------------------
If any further positional arguments are defined, they will be interpreted as
products/image references. %s will generate and attach (if applicable) the
attestation only for those images, skpping any other products found in the
VEX document.
attestation only for those images, not transferring other products in the
VEX document as in-toto subjects.
For example, the following invocation will only attest and attach vex.json
to user/test, even if the OpenVEX document has entries for other images:
to user/test, even if the OpenVEX document has product entries for other images:
%s attest --attach vex.json user/test
`, appname, appname, appname, appname, appname, appname, appname, appname),
`, appname, appname, appname, appname, appname, appname, appname, appname, appname),
Use: "attest",
SilenceUsage: false,
SilenceErrors: false,
Expand All @@ -99,16 +155,16 @@ to user/test, even if the OpenVEX document has entries for other images:
if len(args) == 0 {
return errors.New("not enough arguments")
}
cmd.SilenceUsage = true

if err := opts.Validate(); err != nil {
return fmt.Errorf("validating options: %w", err)
}

cmd.SilenceUsage = true
ctx := context.Background()

vexctl := ctl.New()
vexctl.Options.Sign = opts.sign
// Attaching always means signing
if opts.attach {
vexctl.Options.Sign = true
}

attestation, err := vexctl.Attest(args[0], args[1:])
if err != nil {
Expand All @@ -121,29 +177,20 @@ to user/test, even if the OpenVEX document has entries for other images:
}
}

if err := attestation.ToJSON(os.Stdout); err != nil {
var out io.Writer = os.Stdout
if opts.outFileOption.outFilePath != "" {
out, err = os.Create(opts.outFilePath)
if err != nil {
return fmt.Errorf("opening attestation file: %w", err)
}
}
if err := attestation.ToJSON(out); err != nil {
return fmt.Errorf("marshaling attestation to json")
}

return nil
},
}

generateCmd.PersistentFlags().BoolVarP(
&opts.attach,
"attach",
"a",
false,
"attach the generated attestation to an image (implies --sign)",
)

generateCmd.PersistentFlags().BoolVarP(
&opts.sign,
"sign",
"s",
false,
"sign the attestation with sigstore",
)

parentCmd.AddCommand(generateCmd)
opts.AddFlags(attestCmd)
parentCmd.AddCommand(attestCmd)
}
4 changes: 2 additions & 2 deletions pkg/ctl/ctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ func (vexctl *VexCtl) Attest(vexDataPath string, subjectStrings []string) (*atte
}

// Attach attaches an attestation to a list of images
func (vexctl *VexCtl) Attach(ctx context.Context, att *attestation.Attestation) (err error) {
if err := vexctl.impl.Attach(ctx, att); err != nil {
func (vexctl *VexCtl) Attach(ctx context.Context, att *attestation.Attestation, refs ...string) (err error) {
if err := vexctl.impl.Attach(ctx, att, refs...); err != nil {
return fmt.Errorf("attaching attestation: %w", err)
}

Expand Down

0 comments on commit f72ff68

Please sign in to comment.