From 79b5a53dbcdf79e3655438090344970557981e77 Mon Sep 17 00:00:00 2001 From: Marcela Melara Date: Wed, 1 Nov 2023 16:40:49 -0700 Subject: [PATCH] Add JSON pretty printing to select scai-gen commands, mkdir -p the output directory on any file write Signed-off-by: Marcela Melara --- scai-gen/cmd/assert.go | 7 ++++++- scai-gen/cmd/rd.go | 22 ++++++++++++---------- scai-gen/cmd/report.go | 15 ++++++++++++++- scai-gen/cmd/root.go | 5 ++++- scai-gen/cmd/sigstore.go | 5 +++++ scai-gen/fileio/common.go | 17 +++++++++++++++++ scai-gen/fileio/dsse.go | 5 +++++ scai-gen/fileio/pb.go | 24 ++++++++++++++++++++++-- 8 files changed, 85 insertions(+), 15 deletions(-) create mode 100644 scai-gen/fileio/common.go diff --git a/scai-gen/cmd/assert.go b/scai-gen/cmd/assert.go index 4a4afb6..08f1a65 100644 --- a/scai-gen/cmd/assert.go +++ b/scai-gen/cmd/assert.go @@ -60,6 +60,11 @@ func init() { } func genAttrAssertion(_ *cobra.Command, args []string) error { + // want to make sure the AttributeAssertion is a JSON file + if !fileio.HasJSONExt(outFile) { + return fmt.Errorf("expected a .json extension for the generated SCAI AttributeAssertion file %s", outFile) + } + attribute := args[0] var target *ita.ResourceDescriptor @@ -101,5 +106,5 @@ func genAttrAssertion(_ *cobra.Command, args []string) error { return fmt.Errorf("invalid SCAI attribute assertion: %w", err) } - return fileio.WritePbToFile(aa, outFile) + return fileio.WritePbToFile(aa, outFile, false) } diff --git a/scai-gen/cmd/rd.go b/scai-gen/cmd/rd.go index 8252a1e..85aa909 100644 --- a/scai-gen/cmd/rd.go +++ b/scai-gen/cmd/rd.go @@ -75,14 +75,6 @@ func init() { "The URI of the resource", ) - rdFileCmd.Flags().BoolVarP( - &withContent, - "content", - "c", - false, - "Flag to include the content of the file", - ) - rdFileCmd.Flags().StringVarP( &downloadLocation, "download-location", @@ -165,6 +157,11 @@ func readAnnotations(filename string) (*structpb.Struct, error) { } func genRdFromFile(_ *cobra.Command, args []string) error { + // want to make sure the ResourceDescriptor is a JSON file + if !fileio.HasJSONExt(outFile) { + return fmt.Errorf("expected a .json extension for the generated ResourceDescriptor file %s", outFile) + } + filename := args[0] fileBytes, err := os.ReadFile(filename) if err != nil { @@ -203,10 +200,15 @@ func genRdFromFile(_ *cobra.Command, args []string) error { return fmt.Errorf("invalid resource descriptor: %w", err) } - return fileio.WritePbToFile(rd, outFile) + return fileio.WritePbToFile(rd, outFile, false) } func genRdForRemote(_ *cobra.Command, args []string) error { + // want to make sure the ResourceDescriptor is a JSON file + if !fileio.HasJSONExt(outFile) { + return fmt.Errorf("expected a .json extension for the generated ResourceDescriptor file %s", outFile) + } + remoteURI := args[0] digestSet := make(map[string]string) @@ -240,5 +242,5 @@ func genRdForRemote(_ *cobra.Command, args []string) error { return fmt.Errorf("invalid resource descriptor: %w", err) } - return fileio.WritePbToFile(rd, outFile) + return fileio.WritePbToFile(rd, outFile, false) } diff --git a/scai-gen/cmd/report.go b/scai-gen/cmd/report.go index 024f179..f05b27a 100644 --- a/scai-gen/cmd/report.go +++ b/scai-gen/cmd/report.go @@ -50,9 +50,22 @@ func init() { "", "The filename of the JSON-encoded producer resource descriptor", ) + + reportCmd.Flags().BoolVarP( + &prettyPrint, + "pretty-print", + "y", + false, + "Flag to JSON pretty-print the generated Report", + ) } func genAttrReport(_ *cobra.Command, args []string) error { + // want to make sure the Report is a JSON file + if !fileio.HasJSONExt(outFile) { + return fmt.Errorf("expected a .json extension for the generated in-toto Statement file %s", outFile) + } + attrAsserts := make([]*scai.AttributeAssertion, 0, len(args)) for _, attrAssertPath := range args { aa := &scai.AttributeAssertion{} @@ -117,5 +130,5 @@ func genAttrReport(_ *cobra.Command, args []string) error { return fmt.Errorf("invalid in-toto Statement: %w", err) } - return fileio.WritePbToFile(statement, outFile) + return fileio.WritePbToFile(statement, outFile, prettyPrint) } diff --git a/scai-gen/cmd/root.go b/scai-gen/cmd/root.go index 0b14aed..f606a75 100644 --- a/scai-gen/cmd/root.go +++ b/scai-gen/cmd/root.go @@ -12,7 +12,10 @@ var rootCmd = &cobra.Command{ Short: "A CLI tool for generating/checking SCAI metadata", } -var outFile string +var ( + outFile string + prettyPrint bool +) func init() { rootCmd.AddCommand(rdCmd) diff --git a/scai-gen/cmd/sigstore.go b/scai-gen/cmd/sigstore.go index 3a891a3..89a4f70 100644 --- a/scai-gen/cmd/sigstore.go +++ b/scai-gen/cmd/sigstore.go @@ -73,6 +73,11 @@ func getNewFulcioSigner(ctx context.Context) (*fulcio.Signer, error) { func signWithSigstore(cmd *cobra.Command, args []string) error { fmt.Println("EXPERIMENTAL FEATURE. DO NOT USE IN PRODUCTION.") + // want to make sure the DSSE is a JSON file + if !fileio.HasJSONExt(outFile) { + return fmt.Errorf("expected a .json extension for the generated DSSE file %s", outFile) + } + statementFile := args[0] statement := &ita.Statement{} err := fileio.ReadPbFromFile(statementFile, statement) diff --git a/scai-gen/fileio/common.go b/scai-gen/fileio/common.go new file mode 100644 index 0000000..9fa27de --- /dev/null +++ b/scai-gen/fileio/common.go @@ -0,0 +1,17 @@ +package fileio + +import ( + "os" + "path/filepath" + "strings" +) + +func HasJSONExt(filename string) bool { + return strings.HasSuffix(filename, ".json") +} + +func CreateOutDir(filename string) error { + outDir := filepath.Dir(filename) + + return os.MkdirAll(outDir, 0644) +} diff --git a/scai-gen/fileio/dsse.go b/scai-gen/fileio/dsse.go index c7d1a31..f1a59db 100644 --- a/scai-gen/fileio/dsse.go +++ b/scai-gen/fileio/dsse.go @@ -44,5 +44,10 @@ func ReadStatementFromDSSEFile(path string) (*ita.Statement, error) { } func WriteDSSEToFile(envBytes []byte, outFile string) error { + // ensure the out directory exists + if err := CreateOutDir(outFile); err != nil { + return fmt.Errorf("error creating output directory for file %s: %w", outFile, err) + } + return os.WriteFile(outFile, envBytes, 0644) //nolint:gosec } diff --git a/scai-gen/fileio/pb.go b/scai-gen/fileio/pb.go index 11b37b5..317f618 100644 --- a/scai-gen/fileio/pb.go +++ b/scai-gen/fileio/pb.go @@ -8,12 +8,32 @@ import ( "google.golang.org/protobuf/proto" ) -func WritePbToFile(pb proto.Message, outFile string) error { - pbBytes, err := protojson.Marshal(pb) +func WritePbToFile(pb proto.Message, outFile string, pretty bool) error { + var ( + pbBytes []byte + err error + ) + + if pretty { + opt := &protojson.MarshalOptions{ + Multiline: true, + Indent: " ", + EmitUnpopulated: false, + } + pbBytes, err = opt.Marshal(pb) + } else { + pbBytes, err = protojson.Marshal(pb) + } + if err != nil { return err } + // ensure the out directory exists + if err = CreateOutDir(outFile); err != nil { + return fmt.Errorf("error creating output directory for file %s: %w", outFile, err) + } + return os.WriteFile(outFile, pbBytes, 0644) //nolint:gosec }