diff --git a/cmd/attestors.go b/cmd/attestors.go new file mode 100644 index 00000000..91c4590e --- /dev/null +++ b/cmd/attestors.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/in-toto/go-witness/attestation" + "github.com/in-toto/witness/options" + "github.com/olekukonko/tablewriter" + "github.com/spf13/cobra" +) + +func AttestorsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "attestors", + Short: "List all available attestors", + Long: "Lists all the available attestors in Witness with supporting information", + SilenceErrors: true, + SilenceUsage: true, + DisableAutoGenTag: true, + RunE: func(cmd *cobra.Command, args []string) error { + return runAttestors(cmd.Context()) + }, + } + + return cmd +} + +func runAttestors(ctx context.Context) error { + items := [][]string{} + entries := attestation.RegistrationEntries() + for _, entry := range entries { + name := entry.Factory().Name() + + for _, a := range alwaysRunAttestors { + if name == a.Name() || name == "command-run" { + name = name + " (always run)" + } + } + + for _, a := range options.DefaultAttestors { + if name == a { + name = name + " (default)" + } + } + + runType := entry.Factory().RunType() + item := []string{name, entry.Factory().Type(), fmt.Sprintf("%v", runType)} + items = append(items, item) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Name", "Type", "RunType"}) + table.SetAutoMergeCells(false) + table.SetRowLine(false) + table.AppendBulk(items) + table.Render() + + return nil +} diff --git a/cmd/root.go b/cmd/root.go index b9ae47ed..81c15d51 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -44,6 +44,7 @@ func New() *cobra.Command { cmd.AddCommand(RunCmd()) cmd.AddCommand(CompletionCmd()) cmd.AddCommand(versionCmd()) + cmd.AddCommand(AttestorsCmd()) cobra.OnInitialize(func() { preRoot(cmd, ro, logger) }) return cmd } diff --git a/cmd/run.go b/cmd/run.go index 60a33a9e..0a51073f 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -33,6 +33,8 @@ import ( "github.com/spf13/cobra" ) +var alwaysRunAttestors = []attestation.Attestor{product.New(), material.New()} + func RunCmd() *cobra.Command { o := options.RunOptions{ AttestorOptSetters: make(map[string][]func(attestation.Attestor) (attestation.Attestor, error)), @@ -79,17 +81,22 @@ func runRun(ctx context.Context, ro options.RunOptions, args []string, signers . timestampers = append(timestampers, timestamp.NewTimestamper(timestamp.TimestampWithUrl(url))) } - attestors := []attestation.Attestor{product.New(), material.New()} + attestors := alwaysRunAttestors if len(args) > 0 { attestors = append(attestors, commandrun.New(commandrun.WithCommand(args), commandrun.WithTracing(ro.Tracing))) } for _, a := range ro.Attestations { + if a == "command-run" { + log.Warnf("'command-run' is a builtin attestor and cannot be called with --attestations flag") + continue + } + duplicate := false for _, att := range attestors { if a != att.Name() { } else { - log.Warnf("Attestator %s already declared, skipping", a) + log.Warnf("Attestor %s already declared, skipping", a) duplicate = true break } diff --git a/docs/commands.md b/docs/commands.md index 3be39524..cd1552e2 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -2,6 +2,35 @@ This is the reference for the Witness command line tool, generated by [Cobra](https://cobra.dev/). +## witness attestors + +List all available attestors + +### Synopsis + +Lists all the available attestors in Witness with supporting information + +``` +witness attestors [flags] +``` + +### Options + +``` + -h, --help help for attestors +``` + +### Options inherited from parent commands + +``` + -c, --config string Path to the witness config file (default ".witness.yaml") + -l, --log-level string Level of logging to output (debug, info, warn, error) (default "info") +``` + +### SEE ALSO + +* [witness](witness.md) - Collect and verify attestations about your build environments + ## witness run Runs the provided command and records attestations about the execution diff --git a/go.mod b/go.mod index 41981f84..5e725fab 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,11 @@ module github.com/in-toto/witness go 1.21 +toolchain go1.21.4 + require ( github.com/in-toto/go-witness v0.3.1 + github.com/olekukonko/tablewriter v0.0.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 @@ -91,6 +94,7 @@ require ( github.com/letsencrypt/boulder v0.0.0-20240226214708-a97e074b5a3e // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect diff --git a/go.sum b/go.sum index 33f09bf8..97e4f6eb 100644 --- a/go.sum +++ b/go.sum @@ -246,6 +246,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -257,6 +259,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/open-policy-agent/opa v0.61.0 h1:nhncQ2CAYtQTV/SMBhDDPsCpCQsUW+zO/1j+T5V7oZg= diff --git a/options/run.go b/options/run.go index 1b532c45..00f38ace 100644 --- a/options/run.go +++ b/options/run.go @@ -20,6 +20,8 @@ import ( "github.com/spf13/cobra" ) +var DefaultAttestors = []string{"environment", "git"} + type RunOptions struct { SignerOptions SignerOptions KMSSignerProviderOptions KMSSignerProviderOptions @@ -38,7 +40,7 @@ func (ro *RunOptions) AddFlags(cmd *cobra.Command) { ro.SignerOptions.AddFlags(cmd) ro.ArchivistaOptions.AddFlags(cmd) cmd.Flags().StringVarP(&ro.WorkingDir, "workingdir", "d", "", "Directory from which commands will run") - cmd.Flags().StringSliceVarP(&ro.Attestations, "attestations", "a", []string{"environment", "git"}, "Attestations to record ('product' and 'material' are always recorded)") + cmd.Flags().StringSliceVarP(&ro.Attestations, "attestations", "a", DefaultAttestors, "Attestations to record ('product' and 'material' are always recorded)") cmd.Flags().StringSliceVar(&ro.Hashes, "hashes", []string{"sha256"}, "Hashes selected for digest calculation. Defaults to SHA256") cmd.Flags().StringVarP(&ro.OutFilePath, "outfile", "o", "", "File to which to write signed data. Defaults to stdout") cmd.Flags().StringVarP(&ro.StepName, "step", "s", "", "Name of the step being run")