diff --git a/pkg/cmd/build/cancel.go b/pkg/cmd/build/cancel.go index 8d4d8de..8290d69 100644 --- a/pkg/cmd/build/cancel.go +++ b/pkg/cmd/build/cancel.go @@ -8,6 +8,7 @@ import ( buildResolver "github.com/buildkite/cli/v3/internal/build/resolver" "github.com/buildkite/cli/v3/internal/io" pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" + "github.com/buildkite/cli/v3/internal/scopes" "github.com/buildkite/cli/v3/internal/util" "github.com/buildkite/cli/v3/pkg/cmd/factory" "github.com/buildkite/go-buildkite/v4" @@ -28,6 +29,23 @@ func NewCmdBuildCancel(f *factory.Factory) *cobra.Command { Long: heredoc.Doc(` Cancel the given build. `), + PreRunE: func(cmd *cobra.Command, args []string) error { + // Get the command's required and optional scopes + cmdScopes := scopes.GetCommandScopes(cmd) + + // Get the token scopes from the factory + tokenScopes := f.Config.GetTokenScopes() + if len(tokenScopes) == 0 { + return fmt.Errorf("no scopes found in token. Please ensure you're using a token with appropriate scopes") + } + + // Validate the scopes + if err := scopes.ValidateScopes(cmdScopes, tokenScopes); err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { pipelineRes := pipelineResolver.NewAggregateResolver( pipelineResolver.ResolveFromFlag(pipeline, f.Config), @@ -57,6 +75,10 @@ func NewCmdBuildCancel(f *factory.Factory) *cobra.Command { }, } + cmd.Annotations = map[string]string{ + "requiredScopes": string(scopes.WriteBuilds), + } + cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the build in a web browser after it has been cancelled.") cmd.Flags().StringVarP(&pipeline, "pipeline", "p", "", "The pipeline to cancel a build on. This can be a {pipeline slug} or in the format {org slug}/{pipeline slug}.\n"+ "If omitted, it will be resolved using the current directory.", diff --git a/pkg/cmd/build/download.go b/pkg/cmd/build/download.go index 24f8cb9..8eed309 100644 --- a/pkg/cmd/build/download.go +++ b/pkg/cmd/build/download.go @@ -11,6 +11,7 @@ import ( buildResolver "github.com/buildkite/cli/v3/internal/build/resolver" "github.com/buildkite/cli/v3/internal/build/resolver/options" pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" + "github.com/buildkite/cli/v3/internal/scopes" "github.com/buildkite/cli/v3/pkg/cmd/factory" "github.com/charmbracelet/huh/spinner" "github.com/spf13/cobra" @@ -26,6 +27,23 @@ func NewCmdBuildDownload(f *factory.Factory) *cobra.Command { Short: "Download resources for a build", Long: "Download allows you to download resources for a build.", Args: cobra.MaximumNArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + // Get the command's required and optional scopes + cmdScopes := scopes.GetCommandScopes(cmd) + + // Get the token scopes from the factory + tokenScopes := f.Config.GetTokenScopes() + if len(tokenScopes) == 0 { + return fmt.Errorf("no scopes found in token. Please ensure you're using a token with appropriate scopes") + } + + // Validate the scopes + if err := scopes.ValidateScopes(cmdScopes, tokenScopes); err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { // we find the pipeline based on the following rules: // 1. an explicit flag is passed @@ -83,6 +101,10 @@ func NewCmdBuildDownload(f *factory.Factory) *cobra.Command { }, } + cmd.Annotations = map[string]string{ + "requiredScopes": fmt.Sprint(string(scopes.ReadBuilds), string(scopes.ReadArtifacts), string(scopes.ReadBuildLogs)), + } + cmd.Flags().BoolVarP(&mine, "mine", "m", false, "Filter builds to only my user.") cmd.Flags().StringVarP(&branch, "branch", "b", "", "Filter builds to this branch.") cmd.Flags().StringVarP(&user, "user", "u", "", "Filter builds to this user. You can use name or email.") diff --git a/pkg/cmd/build/rebuild.go b/pkg/cmd/build/rebuild.go index 2b7fc2d..2eff406 100644 --- a/pkg/cmd/build/rebuild.go +++ b/pkg/cmd/build/rebuild.go @@ -8,6 +8,7 @@ import ( buildResolver "github.com/buildkite/cli/v3/internal/build/resolver" "github.com/buildkite/cli/v3/internal/build/resolver/options" pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" + "github.com/buildkite/cli/v3/internal/scopes" "github.com/buildkite/cli/v3/internal/util" "github.com/buildkite/cli/v3/pkg/cmd/factory" "github.com/buildkite/go-buildkite/v4" @@ -28,6 +29,23 @@ func NewCmdBuildRebuild(f *factory.Factory) *cobra.Command { Rebuild a build. The web URL to the build will be printed to stdout. `), + PreRunE: func(cmd *cobra.Command, args []string) error { + // Get the command's required and optional scopes + cmdScopes := scopes.GetCommandScopes(cmd) + + // Get the token scopes from the factory + tokenScopes := f.Config.GetTokenScopes() + if len(tokenScopes) == 0 { + return fmt.Errorf("no scopes found in token. Please ensure you're using a token with appropriate scopes") + } + + // Validate the scopes + if err := scopes.ValidateScopes(cmdScopes, tokenScopes); err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { // we find the pipeline based on the following rules: // 1. an explicit flag is passed @@ -72,6 +90,10 @@ func NewCmdBuildRebuild(f *factory.Factory) *cobra.Command { }, } + cmd.Annotations = map[string]string{ + "requiredScopes": string(scopes.WriteBuilds), + } + cmd.Flags().BoolVarP(&mine, "mine", "m", false, "Filter build to only my user.") cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the build in a web browser after it has been created.") cmd.Flags().StringVarP(&branch, "branch", "b", "", "Filter builds to this branch.") diff --git a/pkg/cmd/build/view.go b/pkg/cmd/build/view.go index 7054fd3..061e5d9 100644 --- a/pkg/cmd/build/view.go +++ b/pkg/cmd/build/view.go @@ -12,6 +12,7 @@ import ( "github.com/buildkite/cli/v3/internal/build/resolver/options" "github.com/buildkite/cli/v3/internal/job" pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" + "github.com/buildkite/cli/v3/internal/scopes" "github.com/buildkite/cli/v3/pkg/cmd/factory" "github.com/buildkite/go-buildkite/v4" "github.com/charmbracelet/huh/spinner" @@ -53,6 +54,23 @@ func NewCmdBuildView(f *factory.Factory) *cobra.Command { # to view most recent build by greg on the deploy-pipeline $ bk build view -p deploy-pipeline -u "greg" `), + PreRunE: func(cmd *cobra.Command, args []string) error { + // Get the command's required and optional scopes + cmdScopes := scopes.GetCommandScopes(cmd) + + // Get the token scopes from the factory + tokenScopes := f.Config.GetTokenScopes() + if len(tokenScopes) == 0 { + return fmt.Errorf("no scopes found in token. Please ensure you're using a token with appropriate scopes") + } + + // Validate the scopes + if err := scopes.ValidateScopes(cmdScopes, tokenScopes); err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { var err error // we find the pipeline based on the following rules: @@ -189,6 +207,10 @@ func NewCmdBuildView(f *factory.Factory) *cobra.Command { }, } + cmd.Annotations = map[string]string{ + "requiredScopes": string(scopes.ReadBuilds), + } + cmd.Flags().BoolVarP(&mine, "mine", "m", false, "Filter builds to only my user.") cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the build in a web browser.") cmd.Flags().StringVarP(&branch, "branch", "b", "", "Filter builds to this branch.") diff --git a/pkg/cmd/build/watch.go b/pkg/cmd/build/watch.go index 4adf859..4944618 100644 --- a/pkg/cmd/build/watch.go +++ b/pkg/cmd/build/watch.go @@ -10,6 +10,7 @@ import ( "github.com/buildkite/cli/v3/internal/build/resolver/options" "github.com/buildkite/cli/v3/internal/job" pipelineResolver "github.com/buildkite/cli/v3/internal/pipeline/resolver" + "github.com/buildkite/cli/v3/internal/scopes" "github.com/buildkite/cli/v3/pkg/cmd/factory" "github.com/buildkite/go-buildkite/v4" "github.com/charmbracelet/lipgloss" @@ -45,6 +46,23 @@ func NewCmdBuildWatch(f *factory.Factory) *cobra.Command { # Set a custom polling interval (in seconds) $ bk build watch --interval 5 `), + PreRunE: func(cmd *cobra.Command, args []string) error { + // Get the command's required and optional scopes + cmdScopes := scopes.GetCommandScopes(cmd) + + // Get the token scopes from the factory + tokenScopes := f.Config.GetTokenScopes() + if len(tokenScopes) == 0 { + return fmt.Errorf("no scopes found in token. Please ensure you're using a token with appropriate scopes") + } + + // Validate the scopes + if err := scopes.ValidateScopes(cmdScopes, tokenScopes); err != nil { + return err + } + + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { pipelineRes := pipelineResolver.NewAggregateResolver( pipelineResolver.ResolveFromFlag(pipeline, f.Config), @@ -96,6 +114,10 @@ func NewCmdBuildWatch(f *factory.Factory) *cobra.Command { }, } + cmd.Annotations = map[string]string{ + "requiredeScopes": string(scopes.ReadBuilds), + } + cmd.Flags().StringVarP(&pipeline, "pipeline", "p", "", "The pipeline to watch. This can be a {pipeline slug} or in the format {org slug}/{pipeline slug}.") cmd.Flags().StringVarP(&branch, "branch", "b", "", "The branch to watch builds for.") cmd.Flags().IntVar(&intervalSeconds, "interval", 1, "Polling interval in seconds")