From a4fe1e98943145080e8d2263107e7153b2cfb23c Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Thu, 13 Nov 2025 23:33:55 +0530 Subject: [PATCH 1/6] Basic implementation of sign, verify, attest commands Signed-off-by: Keerthan KK --- cmd/root.go | 6 +++ pkg/cmd/attest/attest.go | 22 ++++++++++ pkg/cmd/attest/cmd.go | 63 +++++++++++++++++++++++++++++ pkg/cmd/sign/cmd.go | 62 ++++++++++++++++++++++++++++ pkg/cmd/sign/sign.go | 21 ++++++++++ pkg/cmd/verify/cmd.go | 87 ++++++++++++++++++++++++++++++++++++++++ pkg/cmd/verify/verify.go | 22 ++++++++++ 7 files changed, 283 insertions(+) create mode 100644 pkg/cmd/attest/attest.go create mode 100644 pkg/cmd/attest/cmd.go create mode 100644 pkg/cmd/sign/cmd.go create mode 100644 pkg/cmd/sign/sign.go create mode 100644 pkg/cmd/verify/cmd.go create mode 100644 pkg/cmd/verify/verify.go diff --git a/cmd/root.go b/cmd/root.go index 33346a65d..9481d16f1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" + "github.com/kitops-ml/kitops/pkg/cmd/attest" "github.com/kitops-ml/kitops/pkg/cmd/dev" "github.com/kitops-ml/kitops/pkg/cmd/diff" "github.com/kitops-ml/kitops/pkg/cmd/info" @@ -37,8 +38,10 @@ import ( "github.com/kitops-ml/kitops/pkg/cmd/pull" "github.com/kitops-ml/kitops/pkg/cmd/push" "github.com/kitops-ml/kitops/pkg/cmd/remove" + "github.com/kitops-ml/kitops/pkg/cmd/sign" "github.com/kitops-ml/kitops/pkg/cmd/tag" "github.com/kitops-ml/kitops/pkg/cmd/unpack" + "github.com/kitops-ml/kitops/pkg/cmd/verify" "github.com/kitops-ml/kitops/pkg/cmd/version" "github.com/kitops-ml/kitops/pkg/lib/constants" "github.com/kitops-ml/kitops/pkg/lib/filesystem/cache" @@ -167,6 +170,9 @@ func addSubcommands(rootCmd *cobra.Command) { rootCmd.AddCommand(diff.DiffCommand()) rootCmd.AddCommand(kitimport.ImportCommand()) rootCmd.AddCommand(kitcache.CacheCommand()) + rootCmd.AddCommand(sign.SignCommand()) + rootCmd.AddCommand(attest.AttestCommand()) + rootCmd.AddCommand(verify.VerifyCommand()) } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/pkg/cmd/attest/attest.go b/pkg/cmd/attest/attest.go new file mode 100644 index 000000000..ba11c781c --- /dev/null +++ b/pkg/cmd/attest/attest.go @@ -0,0 +1,22 @@ +package attest + +import ( + "context" + "fmt" + "os" + "os/exec" +) + +func RunAttest(context context.Context, options *attestOptions) any { + cmd := exec.CommandContext(context, "cosign", options.cosignArgs...) + + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + + err := cmd.Run() + if err != nil { + return fmt.Errorf("attestation failed %s", err) + } + return nil +} diff --git a/pkg/cmd/attest/cmd.go b/pkg/cmd/attest/cmd.go new file mode 100644 index 000000000..327dd0269 --- /dev/null +++ b/pkg/cmd/attest/cmd.go @@ -0,0 +1,63 @@ +package attest + +import ( + "context" + "fmt" + + "github.com/kitops-ml/kitops/pkg/lib/completion" + "github.com/kitops-ml/kitops/pkg/lib/constants" + "github.com/kitops-ml/kitops/pkg/output" + "github.com/spf13/cobra" +) + +type attestOptions struct { + configHome string + cosignArgs []string +} + +func (opts *attestOptions) complete(ctx context.Context, args []string) error { + configHome, ok := ctx.Value(constants.ConfigKey{}).(string) + if !ok { + return fmt.Errorf("default config path not set on command context") + } + opts.configHome = configHome + //opts.cosignArgs = append(args, "verify") + //cosignArgs := + opts.cosignArgs = append([]string{"attest"}, args...) + fmt.Println(opts.cosignArgs) + return nil +} + +func AttestCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "attest", + Short: "", + Long: "", + Example: "", + RunE: runCommand(&attestOptions{}), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return completion.GetLocalModelKitsCompletion(cmd.Context(), toComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + }, + DisableFlagParsing: true, + } + + return cmd +} + +func runCommand(opts *attestOptions) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if err := opts.complete(cmd.Context(), args); err != nil { + return output.Fatalf("Invalid arguments: %s", err) + } + + err := RunAttest(cmd.Context(), opts) + if err != nil { + return output.Fatalf("Failed to attest: %s", err) + } + output.Infof("Attestation successful") + return nil + } +} diff --git a/pkg/cmd/sign/cmd.go b/pkg/cmd/sign/cmd.go new file mode 100644 index 000000000..23cde21f4 --- /dev/null +++ b/pkg/cmd/sign/cmd.go @@ -0,0 +1,62 @@ +package sign + +import ( + "context" + "fmt" + + "github.com/kitops-ml/kitops/pkg/lib/completion" + "github.com/kitops-ml/kitops/pkg/lib/constants" + "github.com/kitops-ml/kitops/pkg/output" + "github.com/spf13/cobra" +) + +type signOptions struct { + configHome string + cosignArgs []string +} + +func SignCommand() *cobra.Command { + + cmd := &cobra.Command{ + Use: "sign", + Short: "", + Long: "", + Example: "", + RunE: runCommand(&signOptions{}), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return completion.GetLocalModelKitsCompletion(cmd.Context(), toComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + }, + DisableFlagParsing: true, + } + + return cmd +} + +func (opts *signOptions) complete(ctx context.Context, args []string) error { + configHome, ok := ctx.Value(constants.ConfigKey{}).(string) + if !ok { + return fmt.Errorf("default config path not set on command context") + } + opts.configHome = configHome + opts.cosignArgs = append([]string{"sign"}, args...) + fmt.Println(opts.cosignArgs) + return nil +} + +func runCommand(opts *signOptions) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + if err := opts.complete(cmd.Context(), args); err != nil { + return output.Fatalf("Invalid arguments: %s", err) + } + + err := RunSign(cmd.Context(), opts) + if err != nil { + return output.Fatalf("Failed to sign: %s", err) + } + output.Infof("Modelkit signed") + return nil + } +} diff --git a/pkg/cmd/sign/sign.go b/pkg/cmd/sign/sign.go new file mode 100644 index 000000000..c48026295 --- /dev/null +++ b/pkg/cmd/sign/sign.go @@ -0,0 +1,21 @@ +package sign + +import ( + "context" + "fmt" + "os/exec" +) + +func RunSign(ctx context.Context, options *signOptions) error { + cmd := exec.CommandContext(ctx, "cosign", options.cosignArgs...) + + cmd.Stdin = nil + cmd.Stderr = nil + cmd.Stderr = nil + + err := cmd.Run() + if err != nil { + return fmt.Errorf("signing failed %s", err) + } + return nil +} diff --git a/pkg/cmd/verify/cmd.go b/pkg/cmd/verify/cmd.go new file mode 100644 index 000000000..7421dbacd --- /dev/null +++ b/pkg/cmd/verify/cmd.go @@ -0,0 +1,87 @@ +package verify + +import ( + "context" + "fmt" + + "github.com/kitops-ml/kitops/pkg/lib/completion" + "github.com/kitops-ml/kitops/pkg/lib/constants" + "github.com/kitops-ml/kitops/pkg/output" + "github.com/spf13/cobra" +) + +type verifyOptions struct { + configHome string + cosignArgs []string +} + +func (opts *verifyOptions) complete(ctx context.Context, args []string) error { + configHome, ok := ctx.Value(constants.ConfigKey{}).(string) + if !ok { + return fmt.Errorf("default config path not set on command context") + } + opts.configHome = configHome + opts.cosignArgs = args + + return nil +} + +func VerifyCommand() *cobra.Command { + var verifySign, verifyAttestation bool + + cmd := &cobra.Command{ + Use: "verify", + Short: "", + Long: "", + Example: "", + RunE: runCommand([]verifyOptions{}, verifySign, verifyAttestation), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return completion.GetLocalModelKitsCompletion(cmd.Context(), toComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + }, + } + + cmd.Flags().BoolVar(&verifySign, "verifysign", false, "If only modelkit signature needs to be verified") + cmd.Flags().BoolVar(&verifyAttestation, "verifyattestation", false, "If only attestation needs to be verified") + return cmd +} + +func runCommand(opts []verifyOptions, verifySign, verifyAttestation bool) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + commands := []string{"verify", "verify-attestation"} + + if verifySign { + opts = append(opts, verifyOptions{}) + args = append([]string{commands[0]}, args...) + if err := opts[0].complete(cmd.Context(), args); err != nil { + return output.Fatalf("Invalid arguments: %s", err) + } + } else if verifyAttestation { + opts = append(opts, verifyOptions{}) + args = append([]string{commands[1]}, args...) + if err := opts[0].complete(cmd.Context(), args); err != nil { + return output.Fatalf("Invalid arguments: %s", err) + } + } else { + for i := range 2 { + opts = append(opts, verifyOptions{}) + args = append([]string{commands[i]}, args...) + if err := opts[i].complete(cmd.Context(), args); err != nil { + return output.Fatalf("Invalid arguments: %s", err) + } + } + + } + + for i := range len(opts) { + err := RunVerify(cmd.Context(), opts[i]) + if err != nil { + return output.Fatalf("Failed to %s: %s", commands[i], err) + } + } + output.Infof("Modelkit signed") + return nil + } +} diff --git a/pkg/cmd/verify/verify.go b/pkg/cmd/verify/verify.go new file mode 100644 index 000000000..69373e19e --- /dev/null +++ b/pkg/cmd/verify/verify.go @@ -0,0 +1,22 @@ +package verify + +import ( + "context" + "fmt" + "os" + "os/exec" +) + +func RunVerify(context context.Context, options verifyOptions) error { + cmd := exec.CommandContext(context, "cosign", options.cosignArgs...) + + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + + err := cmd.Run() + if err != nil { + return fmt.Errorf("%s failed %s", options.cosignArgs[0], err) + } + return nil +} From 2f791e5c630d4a7200a25c1fb0ecc9637abc1d49 Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Fri, 14 Nov 2025 20:06:36 +0530 Subject: [PATCH 2/6] Fixed logic for verify command, also included support for command specific flags Signed-off-by: Keerthan KK --- pkg/cmd/sign/sign.go | 7 ++++--- pkg/cmd/verify/cmd.go | 41 ++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/sign/sign.go b/pkg/cmd/sign/sign.go index c48026295..0a7ffc649 100644 --- a/pkg/cmd/sign/sign.go +++ b/pkg/cmd/sign/sign.go @@ -3,15 +3,16 @@ package sign import ( "context" "fmt" + "os" "os/exec" ) func RunSign(ctx context.Context, options *signOptions) error { cmd := exec.CommandContext(ctx, "cosign", options.cosignArgs...) - cmd.Stdin = nil - cmd.Stderr = nil - cmd.Stderr = nil + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout err := cmd.Run() if err != nil { diff --git a/pkg/cmd/verify/cmd.go b/pkg/cmd/verify/cmd.go index 7421dbacd..c49df4486 100644 --- a/pkg/cmd/verify/cmd.go +++ b/pkg/cmd/verify/cmd.go @@ -3,6 +3,7 @@ package verify import ( "context" "fmt" + "strings" "github.com/kitops-ml/kitops/pkg/lib/completion" "github.com/kitops-ml/kitops/pkg/lib/constants" @@ -27,52 +28,46 @@ func (opts *verifyOptions) complete(ctx context.Context, args []string) error { } func VerifyCommand() *cobra.Command { - var verifySign, verifyAttestation bool cmd := &cobra.Command{ Use: "verify", Short: "", Long: "", Example: "", - RunE: runCommand([]verifyOptions{}, verifySign, verifyAttestation), + RunE: runCommand([]verifyOptions{}), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) >= 1 { return nil, cobra.ShellCompDirectiveNoFileComp } return completion.GetLocalModelKitsCompletion(cmd.Context(), toComplete), cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace }, + DisableFlagParsing: true, } - cmd.Flags().BoolVar(&verifySign, "verifysign", false, "If only modelkit signature needs to be verified") - cmd.Flags().BoolVar(&verifyAttestation, "verifyattestation", false, "If only attestation needs to be verified") return cmd } -func runCommand(opts []verifyOptions, verifySign, verifyAttestation bool) func(cmd *cobra.Command, args []string) error { +func runCommand(opts []verifyOptions) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { commands := []string{"verify", "verify-attestation"} - - if verifySign { - opts = append(opts, verifyOptions{}) - args = append([]string{commands[0]}, args...) - if err := opts[0].complete(cmd.Context(), args); err != nil { - return output.Fatalf("Invalid arguments: %s", err) + argsnew := [][]string{{}, {}} + for _, val := range args { + if val, ok := strings.CutPrefix(val, "--verify."); ok { + argsnew[0] = append(argsnew[0], "--"+val) + } else if val, ok := strings.CutPrefix(val, "--verify-attestation."); ok { + argsnew[1] = append(argsnew[1], "--"+val) + } else { + argsnew[0] = append(argsnew[0], val) + argsnew[1] = append(argsnew[1], val) } - } else if verifyAttestation { + } + + for i := range 2 { opts = append(opts, verifyOptions{}) - args = append([]string{commands[1]}, args...) - if err := opts[0].complete(cmd.Context(), args); err != nil { + argsnew[i] = append([]string{commands[i]}, argsnew[i]...) + if err := opts[i].complete(cmd.Context(), argsnew[i]); err != nil { return output.Fatalf("Invalid arguments: %s", err) } - } else { - for i := range 2 { - opts = append(opts, verifyOptions{}) - args = append([]string{commands[i]}, args...) - if err := opts[i].complete(cmd.Context(), args); err != nil { - return output.Fatalf("Invalid arguments: %s", err) - } - } - } for i := range len(opts) { From 2453a3a7b93571b76804645081266bd293de20cc Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Fri, 14 Nov 2025 21:38:56 +0530 Subject: [PATCH 3/6] Removed print statements, updated descriptions of commands. Signed-off-by: Keerthan KK --- pkg/cmd/attest/cmd.go | 15 ++++++++------- pkg/cmd/sign/cmd.go | 13 ++++++++----- pkg/cmd/verify/cmd.go | 12 ++++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/pkg/cmd/attest/cmd.go b/pkg/cmd/attest/cmd.go index 327dd0269..103da3d5e 100644 --- a/pkg/cmd/attest/cmd.go +++ b/pkg/cmd/attest/cmd.go @@ -10,6 +10,11 @@ import ( "github.com/spf13/cobra" ) +const ( + shortDesc = "Attest the supplied container image. Use the same flags as cosign." + example = `kit attest --predicate PREDICATE_FILE --key cosign.key --tlog-upload=false IMAGE_URI` +) + type attestOptions struct { configHome string cosignArgs []string @@ -21,19 +26,15 @@ func (opts *attestOptions) complete(ctx context.Context, args []string) error { return fmt.Errorf("default config path not set on command context") } opts.configHome = configHome - //opts.cosignArgs = append(args, "verify") - //cosignArgs := opts.cosignArgs = append([]string{"attest"}, args...) - fmt.Println(opts.cosignArgs) return nil } func AttestCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "attest", - Short: "", - Long: "", - Example: "", + Use: "attest [FLAGS]", + Short: shortDesc, + Example: example, RunE: runCommand(&attestOptions{}), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) >= 1 { diff --git a/pkg/cmd/sign/cmd.go b/pkg/cmd/sign/cmd.go index 23cde21f4..70fefd0d4 100644 --- a/pkg/cmd/sign/cmd.go +++ b/pkg/cmd/sign/cmd.go @@ -10,6 +10,11 @@ import ( "github.com/spf13/cobra" ) +const ( + shortDesc = "Sign the supplied container image. Use the same flags as cosign." + example = `kit sign --key cosign.key --tlog-upload=false myimage:latest` +) + type signOptions struct { configHome string cosignArgs []string @@ -18,10 +23,9 @@ type signOptions struct { func SignCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "sign", - Short: "", - Long: "", - Example: "", + Use: "sign [flags]", + Short: shortDesc, + Example: example, RunE: runCommand(&signOptions{}), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) >= 1 { @@ -42,7 +46,6 @@ func (opts *signOptions) complete(ctx context.Context, args []string) error { } opts.configHome = configHome opts.cosignArgs = append([]string{"sign"}, args...) - fmt.Println(opts.cosignArgs) return nil } diff --git a/pkg/cmd/verify/cmd.go b/pkg/cmd/verify/cmd.go index c49df4486..571d96abc 100644 --- a/pkg/cmd/verify/cmd.go +++ b/pkg/cmd/verify/cmd.go @@ -11,6 +11,11 @@ import ( "github.com/spf13/cobra" ) +const ( + shortDesc = "Verify the ModelKit signature and attestation. Runs both verify and verify-attestation. Use --verify.* and --verify-attestation.* for flags specific to each step." + example = `kit verify --key cosign.pub --verify.insecure-ignore-tlog=true DIGEST` +) + type verifyOptions struct { configHome string cosignArgs []string @@ -30,10 +35,9 @@ func (opts *verifyOptions) complete(ctx context.Context, args []string) error { func VerifyCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "verify", - Short: "", - Long: "", - Example: "", + Use: "verify [FLAGS]", + Short: shortDesc, + Example: example, RunE: runCommand([]verifyOptions{}), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) >= 1 { From 8777354739d63ef31350689646db74dde4b2e9c2 Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Fri, 14 Nov 2025 21:54:08 +0530 Subject: [PATCH 4/6] Added license to all new files Signed-off-by: Keerthan KK --- pkg/cmd/attest/attest.go | 16 ++++++++++++++++ pkg/cmd/attest/cmd.go | 16 ++++++++++++++++ pkg/cmd/sign/cmd.go | 16 ++++++++++++++++ pkg/cmd/sign/sign.go | 16 ++++++++++++++++ pkg/cmd/verify/cmd.go | 16 ++++++++++++++++ pkg/cmd/verify/verify.go | 16 ++++++++++++++++ 6 files changed, 96 insertions(+) diff --git a/pkg/cmd/attest/attest.go b/pkg/cmd/attest/attest.go index ba11c781c..7db418b1c 100644 --- a/pkg/cmd/attest/attest.go +++ b/pkg/cmd/attest/attest.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package attest import ( diff --git a/pkg/cmd/attest/cmd.go b/pkg/cmd/attest/cmd.go index 103da3d5e..dfed80f14 100644 --- a/pkg/cmd/attest/cmd.go +++ b/pkg/cmd/attest/cmd.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package attest import ( diff --git a/pkg/cmd/sign/cmd.go b/pkg/cmd/sign/cmd.go index 70fefd0d4..2bdb5f236 100644 --- a/pkg/cmd/sign/cmd.go +++ b/pkg/cmd/sign/cmd.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package sign import ( diff --git a/pkg/cmd/sign/sign.go b/pkg/cmd/sign/sign.go index 0a7ffc649..891473568 100644 --- a/pkg/cmd/sign/sign.go +++ b/pkg/cmd/sign/sign.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package sign import ( diff --git a/pkg/cmd/verify/cmd.go b/pkg/cmd/verify/cmd.go index 571d96abc..346c7fb88 100644 --- a/pkg/cmd/verify/cmd.go +++ b/pkg/cmd/verify/cmd.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package verify import ( diff --git a/pkg/cmd/verify/verify.go b/pkg/cmd/verify/verify.go index 69373e19e..90ff7277c 100644 --- a/pkg/cmd/verify/verify.go +++ b/pkg/cmd/verify/verify.go @@ -1,3 +1,19 @@ +// Copyright 2025 The KitOps Authors. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + package verify import ( From 344ae1dab7668ba197356e9d19785187a4779243 Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Fri, 14 Nov 2025 22:14:06 +0530 Subject: [PATCH 5/6] Moved appending cosign flag to args to runCommand Signed-off-by: Keerthan KK --- pkg/cmd/attest/cmd.go | 3 ++- pkg/cmd/sign/cmd.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/attest/cmd.go b/pkg/cmd/attest/cmd.go index dfed80f14..577a4a789 100644 --- a/pkg/cmd/attest/cmd.go +++ b/pkg/cmd/attest/cmd.go @@ -42,7 +42,7 @@ func (opts *attestOptions) complete(ctx context.Context, args []string) error { return fmt.Errorf("default config path not set on command context") } opts.configHome = configHome - opts.cosignArgs = append([]string{"attest"}, args...) + opts.cosignArgs = args return nil } @@ -66,6 +66,7 @@ func AttestCommand() *cobra.Command { func runCommand(opts *attestOptions) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + args = append([]string{"attest"}, args...) if err := opts.complete(cmd.Context(), args); err != nil { return output.Fatalf("Invalid arguments: %s", err) } diff --git a/pkg/cmd/sign/cmd.go b/pkg/cmd/sign/cmd.go index 2bdb5f236..23907add9 100644 --- a/pkg/cmd/sign/cmd.go +++ b/pkg/cmd/sign/cmd.go @@ -61,12 +61,13 @@ func (opts *signOptions) complete(ctx context.Context, args []string) error { return fmt.Errorf("default config path not set on command context") } opts.configHome = configHome - opts.cosignArgs = append([]string{"sign"}, args...) + opts.cosignArgs = args return nil } func runCommand(opts *signOptions) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + args = append([]string{"sign"}, args...) if err := opts.complete(cmd.Context(), args); err != nil { return output.Fatalf("Invalid arguments: %s", err) } From 0848136bcf9ee8270c5a30708f7fc94832590096 Mon Sep 17 00:00:00 2001 From: Keerthan KK Date: Sun, 28 Dec 2025 17:17:30 +0530 Subject: [PATCH 6/6] Updated error handling and converted opts to local scope for runverify Signed-off-by: Keerthan KK --- pkg/cmd/attest/attest.go | 11 ++++++++--- pkg/cmd/attest/cmd.go | 6 +++--- pkg/cmd/sign/cmd.go | 4 ++-- pkg/cmd/sign/sign.go | 10 ++++++++-- pkg/cmd/verify/cmd.go | 14 ++++++++------ pkg/cmd/verify/verify.go | 9 +++++++-- 6 files changed, 36 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/attest/attest.go b/pkg/cmd/attest/attest.go index 7db418b1c..18aa2fc26 100644 --- a/pkg/cmd/attest/attest.go +++ b/pkg/cmd/attest/attest.go @@ -23,16 +23,21 @@ import ( "os/exec" ) -func RunAttest(context context.Context, options *attestOptions) any { +func RunAttest(context context.Context, options *attestOptions) error { + _, err := exec.LookPath("cosign") + if err != nil { + fmt.Println() + return fmt.Errorf("cosign not found, please install cosign") + } cmd := exec.CommandContext(context, "cosign", options.cosignArgs...) cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout - err := cmd.Run() + err = cmd.Run() if err != nil { - return fmt.Errorf("attestation failed %s", err) + return fmt.Errorf("attestation failed: %w", err) } return nil } diff --git a/pkg/cmd/attest/cmd.go b/pkg/cmd/attest/cmd.go index 577a4a789..0cbca849c 100644 --- a/pkg/cmd/attest/cmd.go +++ b/pkg/cmd/attest/cmd.go @@ -48,7 +48,7 @@ func (opts *attestOptions) complete(ctx context.Context, args []string) error { func AttestCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "attest [FLAGS]", + Use: "attest [flags]", Short: shortDesc, Example: example, RunE: runCommand(&attestOptions{}), @@ -68,12 +68,12 @@ func runCommand(opts *attestOptions) func(cmd *cobra.Command, args []string) err return func(cmd *cobra.Command, args []string) error { args = append([]string{"attest"}, args...) if err := opts.complete(cmd.Context(), args); err != nil { - return output.Fatalf("Invalid arguments: %s", err) + return output.Fatalf("Invalid arguments: %w", err) } err := RunAttest(cmd.Context(), opts) if err != nil { - return output.Fatalf("Failed to attest: %s", err) + return output.Fatalf("Failed to attest: %w", err) } output.Infof("Attestation successful") return nil diff --git a/pkg/cmd/sign/cmd.go b/pkg/cmd/sign/cmd.go index 23907add9..ba87c2fe2 100644 --- a/pkg/cmd/sign/cmd.go +++ b/pkg/cmd/sign/cmd.go @@ -69,12 +69,12 @@ func runCommand(opts *signOptions) func(cmd *cobra.Command, args []string) error return func(cmd *cobra.Command, args []string) error { args = append([]string{"sign"}, args...) if err := opts.complete(cmd.Context(), args); err != nil { - return output.Fatalf("Invalid arguments: %s", err) + return output.Fatalf("Invalid arguments: %w", err) } err := RunSign(cmd.Context(), opts) if err != nil { - return output.Fatalf("Failed to sign: %s", err) + return output.Fatalf("Failed to sign: %w", err) } output.Infof("Modelkit signed") return nil diff --git a/pkg/cmd/sign/sign.go b/pkg/cmd/sign/sign.go index 891473568..4c3f63589 100644 --- a/pkg/cmd/sign/sign.go +++ b/pkg/cmd/sign/sign.go @@ -24,15 +24,21 @@ import ( ) func RunSign(ctx context.Context, options *signOptions) error { + _, err := exec.LookPath("cosign") + if err != nil { + fmt.Println() + return fmt.Errorf("cosign not found, please install cosign") + } + cmd := exec.CommandContext(ctx, "cosign", options.cosignArgs...) cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout - err := cmd.Run() + err = cmd.Run() if err != nil { - return fmt.Errorf("signing failed %s", err) + return fmt.Errorf("signing failed: %w", err) } return nil } diff --git a/pkg/cmd/verify/cmd.go b/pkg/cmd/verify/cmd.go index 346c7fb88..ab10988b5 100644 --- a/pkg/cmd/verify/cmd.go +++ b/pkg/cmd/verify/cmd.go @@ -51,10 +51,10 @@ func (opts *verifyOptions) complete(ctx context.Context, args []string) error { func VerifyCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "verify [FLAGS]", + Use: "verify [flags]", Short: shortDesc, Example: example, - RunE: runCommand([]verifyOptions{}), + RunE: runCommand(), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) >= 1 { return nil, cobra.ShellCompDirectiveNoFileComp @@ -67,7 +67,7 @@ func VerifyCommand() *cobra.Command { return cmd } -func runCommand(opts []verifyOptions) func(cmd *cobra.Command, args []string) error { +func runCommand() func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { commands := []string{"verify", "verify-attestation"} argsnew := [][]string{{}, {}} @@ -82,21 +82,23 @@ func runCommand(opts []verifyOptions) func(cmd *cobra.Command, args []string) er } } + opts := make([]verifyOptions, 2) + for i := range 2 { opts = append(opts, verifyOptions{}) argsnew[i] = append([]string{commands[i]}, argsnew[i]...) if err := opts[i].complete(cmd.Context(), argsnew[i]); err != nil { - return output.Fatalf("Invalid arguments: %s", err) + return output.Fatalf("Invalid arguments: %w", err) } } for i := range len(opts) { err := RunVerify(cmd.Context(), opts[i]) if err != nil { - return output.Fatalf("Failed to %s: %s", commands[i], err) + return output.Fatalf("Failed to %s: %w", commands[i], err) } } - output.Infof("Modelkit signed") + output.Infof("Verification successful") return nil } } diff --git a/pkg/cmd/verify/verify.go b/pkg/cmd/verify/verify.go index 90ff7277c..aa29ade8b 100644 --- a/pkg/cmd/verify/verify.go +++ b/pkg/cmd/verify/verify.go @@ -24,15 +24,20 @@ import ( ) func RunVerify(context context.Context, options verifyOptions) error { + _, err := exec.LookPath("cosign") + if err != nil { + fmt.Println() + return fmt.Errorf("cosign not found, please install cosign") + } cmd := exec.CommandContext(context, "cosign", options.cosignArgs...) cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout - err := cmd.Run() + err = cmd.Run() if err != nil { - return fmt.Errorf("%s failed %s", options.cosignArgs[0], err) + return fmt.Errorf("%s failed: %w", options.cosignArgs[0], err) } return nil }