-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial api scoping checks * never use optional
- Loading branch information
Showing
3 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package config | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"sync" | ||
) | ||
|
||
type AccessToken struct { | ||
UUID string `json:"uuid"` | ||
Scopes []string `json:"scopes"` | ||
ClientID string `json:"client_id"` | ||
} | ||
|
||
var ( | ||
tokenInfo *AccessToken | ||
tokenInfoOnce sync.Once | ||
) | ||
|
||
// GetTokenScopes fetches and returns the scopes associated with the current API token | ||
func (c *Config) GetTokenScopes() []string { | ||
var err error | ||
tokenInfoOnce.Do(func() { | ||
tokenInfo, err = c.fetchTokenInfo(context.Background()) | ||
}) | ||
|
||
if err != nil { | ||
// Log the error but don't expose it to the caller | ||
// as this is called in the middle of command execution | ||
log.Printf("Error fetching token info: %v", err) | ||
return nil | ||
} | ||
|
||
if tokenInfo == nil { | ||
return nil | ||
} | ||
|
||
return tokenInfo.Scopes | ||
} | ||
|
||
// fetchTokenInfo retrieves the token information from the Buildkite API | ||
func (c *Config) fetchTokenInfo(ctx context.Context) (*AccessToken, error) { | ||
req, err := http.NewRequestWithContext( | ||
ctx, | ||
"GET", | ||
fmt.Sprintf("%s/v2/access-token", c.RESTAPIEndpoint()), | ||
nil, | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("creating request: %w", err) | ||
} | ||
|
||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.APIToken())) | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
return nil, fmt.Errorf("fetching token info: %w", err) | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
body, _ := io.ReadAll(resp.Body) | ||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body)) | ||
} | ||
|
||
var token AccessToken | ||
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil { | ||
return nil, fmt.Errorf("decoding response: %w", err) | ||
} | ||
|
||
return &token, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package scopes | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
type Scope string | ||
|
||
const ( | ||
// Agent scopes | ||
ReadAgents Scope = "read_agents" | ||
WriteAgents Scope = "write_agents" | ||
|
||
// Cluster scopes | ||
ReadClusters Scope = "read_clusters" | ||
WriteClusters Scope = "write_clusters" | ||
|
||
// Team scopes | ||
ReadTeams Scope = "read_teams" | ||
WriteTeams Scope = "write_teams" | ||
|
||
// Artifact scopes | ||
ReadArtifacts Scope = "read_artifacts" | ||
WriteArtifacts Scope = "write_artifacts" | ||
|
||
// Build scopes | ||
ReadBuilds Scope = "read_builds" | ||
WriteBuilds Scope = "write_builds" | ||
|
||
// Build logs and environment scopes | ||
ReadJobEnv Scope = "read_job_env" | ||
ReadBuildLogs Scope = "read_build_logs" | ||
WriteBuildLogs Scope = "write_build_logs" | ||
|
||
// Organization scopes | ||
ReadOrganizations Scope = "read_organizations" | ||
|
||
// Pipeline scopes | ||
ReadPipelines Scope = "read_pipelines" | ||
WritePipelines Scope = "write_pipelines" | ||
|
||
// Pipeline template scopes | ||
ReadPipelineTemplates Scope = "read_pipeline_templates" | ||
WritePipelineTemplates Scope = "write_pipeline_templates" | ||
|
||
// Rule scopes | ||
ReadRules Scope = "read_rules" | ||
WriteRules Scope = "write_rules" | ||
|
||
// User scopes | ||
ReadUser Scope = "read_user" | ||
|
||
// Test suite scopes | ||
ReadSuites Scope = "read_suites" | ||
WriteSuites Scope = "write_suites" | ||
|
||
// Test plan scopes | ||
ReadTestPlan Scope = "read_test_plan" | ||
WriteTestPlan Scope = "write_test_plan" | ||
|
||
// Registry scopes | ||
ReadRegistries Scope = "read_registries" | ||
WriteRegistries Scope = "write_registries" | ||
DeleteRegistries Scope = "delete_registries" | ||
|
||
// Package scopes | ||
ReadPackages Scope = "read_packages" | ||
WritePackages Scope = "write_packages" | ||
DeletePackages Scope = "delete_packages" | ||
|
||
// GraphQL scope | ||
GraphQL Scope = "graphql" | ||
) | ||
|
||
type CommandScopes struct { | ||
Required []Scope | ||
} | ||
|
||
func GetCommandScopes(cmd *cobra.Command) CommandScopes { | ||
required := []Scope{} | ||
|
||
if reqScopes, ok := cmd.Annotations["requiredScopes"]; ok { | ||
for _, scope := range strings.Split(reqScopes, ",") { | ||
required = append(required, Scope(strings.TrimSpace(scope))) | ||
} | ||
} | ||
|
||
return CommandScopes{ | ||
Required: required, | ||
} | ||
} | ||
|
||
func ValidateScopes(cmdScopes CommandScopes, tokenScopes []string) error { | ||
missingRequired := []string{} | ||
|
||
for _, requiredScope := range cmdScopes.Required { | ||
found := false | ||
for _, tokenScope := range tokenScopes { | ||
if string(requiredScope) == tokenScope { | ||
found = true | ||
break | ||
} | ||
} | ||
if !found { | ||
missingRequired = append(missingRequired, string(requiredScope)) | ||
} | ||
} | ||
|
||
if len(missingRequired) > 0 { | ||
return fmt.Errorf("missing required scopes: %s", strings.Join(missingRequired, ", ")) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters