Skip to content

Commit 907bd59

Browse files
committed
enhance token management with engine-specific recommendations and optional tokens
1 parent 64f0bf0 commit 907bd59

File tree

1 file changed

+120
-9
lines changed

1 file changed

+120
-9
lines changed

pkg/cli/tokens_bootstrap.go

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,110 @@ type tokenSpec struct {
1313
Name string
1414
When string
1515
Description string
16+
Optional bool
17+
}
18+
19+
// getRecommendedTokensForEngine returns token specs based on the workflow engine
20+
func getRecommendedTokensForEngine(engine string) []tokenSpec {
21+
// Base tokens needed for most workflows
22+
tokens := []tokenSpec{
23+
{
24+
Name: "GH_AW_GITHUB_TOKEN",
25+
When: "Cross-repo Project Ops / remote GitHub tools",
26+
Description: "Fine-grained or classic PAT with contents/issues/pull-requests read+write on the repos gh-aw will touch.",
27+
Optional: false,
28+
},
29+
}
30+
31+
// Engine-specific tokens
32+
switch engine {
33+
case "copilot":
34+
tokens = append(tokens, tokenSpec{
35+
Name: "COPILOT_GITHUB_TOKEN",
36+
When: "Copilot workflows (CLI, engine, agent tasks, etc.)",
37+
Description: "PAT with Copilot Requests permission and repo access where Copilot workflows run.",
38+
Optional: false,
39+
})
40+
case "claude":
41+
tokens = append(tokens, tokenSpec{
42+
Name: "ANTHROPIC_API_KEY",
43+
When: "Claude engine workflows",
44+
Description: "API key from Anthropic Console for Claude API access.",
45+
Optional: false,
46+
})
47+
case "codex":
48+
tokens = append(tokens, tokenSpec{
49+
Name: "OPENAI_API_KEY",
50+
When: "Codex/OpenAI engine workflows",
51+
Description: "API key from OpenAI for Codex/GPT API access.",
52+
Optional: false,
53+
})
54+
}
55+
56+
// Optional tokens for advanced use cases
57+
tokens = append(tokens,
58+
tokenSpec{
59+
Name: "GH_AW_AGENT_TOKEN",
60+
When: "Assigning agents/bots to issues or pull requests",
61+
Description: "PAT for agent assignment with issues and pull-requests write on the repos where agents act.",
62+
Optional: true,
63+
},
64+
tokenSpec{
65+
Name: "GH_AW_GITHUB_MCP_SERVER_TOKEN",
66+
When: "Isolating MCP server permissions (advanced, optional)",
67+
Description: "Optional read-mostly token for the GitHub MCP server when you want different scopes than GH_AW_GITHUB_TOKEN.",
68+
Optional: true,
69+
},
70+
)
71+
72+
return tokens
1673
}
1774

1875
// recommendedTokenSpecs defines the core tokens we surface in tokens.md
76+
// This is kept for backward compatibility and default listing
1977
var recommendedTokenSpecs = []tokenSpec{
2078
{
2179
Name: "GH_AW_GITHUB_TOKEN",
2280
When: "Cross-repo Project Ops / remote GitHub tools",
2381
Description: "Fine-grained or classic PAT with contents/issues/pull-requests read+write on the repos gh-aw will touch.",
82+
Optional: false,
2483
},
2584
{
2685
Name: "COPILOT_GITHUB_TOKEN",
2786
When: "Copilot workflows (CLI, engine, agent tasks, etc.)",
2887
Description: "PAT with Copilot Requests permission and repo access where Copilot workflows run.",
88+
Optional: true,
89+
},
90+
{
91+
Name: "ANTHROPIC_API_KEY",
92+
When: "Claude engine workflows",
93+
Description: "API key from Anthropic Console for Claude API access.",
94+
Optional: true,
95+
},
96+
{
97+
Name: "OPENAI_API_KEY",
98+
When: "Codex/OpenAI engine workflows",
99+
Description: "API key from OpenAI for Codex/GPT API access.",
100+
Optional: true,
29101
},
30102
{
31103
Name: "GH_AW_AGENT_TOKEN",
32104
When: "Assigning agents/bots to issues or pull requests",
33105
Description: "PAT for agent assignment with issues and pull-requests write on the repos where agents act.",
106+
Optional: true,
34107
},
35108
{
36109
Name: "GH_AW_GITHUB_MCP_SERVER_TOKEN",
37110
When: "Isolating MCP server permissions (advanced, optional)",
38111
Description: "Optional read-mostly token for the GitHub MCP server when you want different scopes than GH_AW_GITHUB_TOKEN.",
112+
Optional: true,
39113
},
40114
}
41115

42116
// NewTokensBootstrapSubcommand creates the `tokens bootstrap` subcommand
43117
func NewTokensBootstrapSubcommand() *cobra.Command {
118+
var engineFlag string
119+
44120
cmd := &cobra.Command{
45121
Use: "bootstrap",
46122
Short: "Check and suggest setup for gh-aw GitHub token secrets",
@@ -55,24 +131,35 @@ available) and prints the exact secrets to add and suggested scopes.
55131
For full details, including precedence rules, see the GitHub Tokens
56132
reference in the documentation.`,
57133
RunE: func(cmd *cobra.Command, args []string) error {
58-
return runTokensBootstrap()
134+
return runTokensBootstrap(engineFlag)
59135
},
60136
}
61137

138+
cmd.Flags().StringVarP(&engineFlag, "engine", "e", "", "Check tokens for specific engine (copilot, claude, codex)")
139+
62140
return cmd
63141
}
64142

65-
func runTokensBootstrap() error {
143+
func runTokensBootstrap(engine string) error {
66144
repoSlug, err := GetCurrentRepoSlug()
67145
if err != nil {
68146
return fmt.Errorf("failed to detect current repository: %w", err)
69147
}
70148

71149
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Checking recommended gh-aw token secrets in %s...", repoSlug)))
72150

73-
missing := make([]tokenSpec, 0, len(recommendedTokenSpecs))
151+
// Get tokens based on engine or use all recommended tokens
152+
var tokensToCheck []tokenSpec
153+
if engine != "" {
154+
tokensToCheck = getRecommendedTokensForEngine(engine)
155+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Checking tokens for engine: %s", engine)))
156+
} else {
157+
tokensToCheck = recommendedTokenSpecs
158+
}
159+
160+
missing := make([]tokenSpec, 0, len(tokensToCheck))
74161

75-
for _, spec := range recommendedTokenSpecs {
162+
for _, spec := range tokensToCheck {
76163
exists, err := checkSecretExists(spec.Name)
77164
if err != nil {
78165
// If we hit a 403 or other error, surface a friendly message and abort
@@ -88,13 +175,37 @@ func runTokensBootstrap() error {
88175
return nil
89176
}
90177

91-
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Some recommended gh-aw token secrets are missing:"))
178+
// Separate required and optional missing secrets
179+
var requiredMissing, optionalMissing []tokenSpec
92180
for _, spec := range missing {
181+
if spec.Optional {
182+
optionalMissing = append(optionalMissing, spec)
183+
} else {
184+
requiredMissing = append(requiredMissing, spec)
185+
}
186+
}
187+
188+
if len(requiredMissing) > 0 {
189+
fmt.Fprintln(os.Stderr, console.FormatErrorMessage("Required gh-aw token secrets are missing:"))
190+
for _, spec := range requiredMissing {
191+
fmt.Fprintln(os.Stderr, "")
192+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Secret: %s", spec.Name)))
193+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("When needed: %s", spec.When)))
194+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Recommended scopes: %s", spec.Description)))
195+
fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("gh aw secret set %s --owner <owner> --repo <repo>", spec.Name)))
196+
}
197+
}
198+
199+
if len(optionalMissing) > 0 {
93200
fmt.Fprintln(os.Stderr, "")
94-
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Secret: %s", spec.Name)))
95-
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("When needed: %s", spec.When)))
96-
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Recommended scopes: %s", spec.Description)))
97-
fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("gh secret set %s -a actions", spec.Name)))
201+
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Optional gh-aw token secrets are missing:"))
202+
for _, spec := range optionalMissing {
203+
fmt.Fprintln(os.Stderr, "")
204+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Secret: %s (optional)", spec.Name)))
205+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("When needed: %s", spec.When)))
206+
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Recommended scopes: %s", spec.Description)))
207+
fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("gh aw secret set %s --owner <owner> --repo <repo>", spec.Name)))
208+
}
98209
}
99210

100211
fmt.Fprintln(os.Stderr, "")

0 commit comments

Comments
 (0)