Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/src/content/docs/reference/cross-repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ If only a the current repository, you can use `checkout:` to override default ch

```yaml wrap
checkout:
fetch-depth: 0 # Full git history
github-token: ${{ secrets.MY_TOKEN }} # Custom authentication
fetch-depth: 0 # Full git history
token: ${{ secrets.MY_TOKEN }} # Custom authentication
```

You can also use `checkout:` to check out additional repositories alongside the main repository:
Expand All @@ -37,7 +37,7 @@ checkout:
- repository: owner/other-repo
path: ./libs/other
ref: main
github-token: ${{ secrets.CROSS_REPO_PAT }}
token: ${{ secrets.CROSS_REPO_PAT }}
```

### Checkout Configuration Options
Expand All @@ -47,7 +47,7 @@ checkout:
| `repository` | string | Repository in `owner/repo` format. Defaults to the current repository. |
| `ref` | string | Branch, tag, or SHA to checkout. Defaults to the triggering ref. |
| `path` | string | Path within `GITHUB_WORKSPACE` to place the checkout. Defaults to workspace root. |
| `github-token` | string | Token for authentication. Use `${{ secrets.MY_TOKEN }}` syntax. |
| `token` | string | Token for authentication. Use `${{ secrets.MY_TOKEN }}` syntax. |
| `fetch-depth` | integer | Commits to fetch. `0` = full history, `1` = shallow clone (default). |
| `sparse-checkout` | string | Newline-separated patterns for sparse checkout (e.g., `.github/\nsrc/`). |
| `submodules` | string/bool | Submodule handling: `"recursive"`, `"true"`, or `"false"`. |
Expand All @@ -74,7 +74,7 @@ When a workflow running from a central repository targets a different repository
checkout:
- repository: org/target-repo
path: ./target
github-token: ${{ secrets.CROSS_REPO_PAT }}
token: ${{ secrets.CROSS_REPO_PAT }}
current: true # agent's primary target
```

Expand Down Expand Up @@ -150,7 +150,7 @@ checkout:
- repository: org/shared-libs
path: ./libs/shared
ref: main
github-token: ${{ secrets.LIBS_PAT }}
token: ${{ secrets.LIBS_PAT }}
- repository: org/config-repo
path: ./config
sparse-checkout: |
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/frontmatter.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ Configure how `actions/checkout` is invoked in the agent job. Override default c
# Single repository with custom settings
checkout:
fetch-depth: 0
github-token: ${{ secrets.MY_TOKEN }}
token: ${{ secrets.MY_TOKEN }}
```

```yaml wrap
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7894,7 +7894,7 @@
"type": "boolean",
"description": "Whether to download Git LFS objects. Defaults to false."
},
"github-token": {
"token": {
"type": "string",
"description": "GitHub token for authentication. Use ${{ secrets.MY_TOKEN }} to reference a secret. Credentials are always removed after checkout (persist-credentials: false is enforced).",
"examples": ["${{ secrets.MY_PAT }}", "${{ secrets.GITHUB_TOKEN }}"]
Expand Down
25 changes: 10 additions & 15 deletions pkg/workflow/checkout_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var checkoutManagerLog = logger.New("workflow:checkout_manager")
//
// checkout:
// fetch-depth: 0
// github-token: ${{ secrets.MY_TOKEN }}
// token: ${{ secrets.MY_TOKEN }}
//
// Or multiple checkouts:
//
Expand All @@ -36,13 +36,10 @@ type CheckoutConfig struct {
// Path within GITHUB_WORKSPACE to place the checkout. Defaults to the workspace root.
Path string `json:"path,omitempty"`

// GitHubToken overrides the default GITHUB_TOKEN for authentication.
// Token overrides the default GITHUB_TOKEN for authentication.
// Use ${{ secrets.MY_TOKEN }} to reference a repository secret.
//
// Frontmatter key: "github-token" (user-facing name used here and in the schema)
// Generated YAML key: "token" (the actual input name for actions/checkout)
// The compiler maps frontmatter "github-token" → lock.yml "token" during step generation.
GitHubToken string `json:"github-token,omitempty"`
// Matches the "token" input of actions/checkout.
Token string `json:"token,omitempty"`

// FetchDepth controls the number of commits to fetch.
// 0 fetches all history (full clone). 1 is a shallow clone (default).
Expand Down Expand Up @@ -138,8 +135,8 @@ func (cm *CheckoutManager) add(cfg *CheckoutConfig) {
if cfg.Ref != "" && entry.ref == "" {
entry.ref = cfg.Ref // first-seen ref wins
}
if cfg.GitHubToken != "" && entry.token == "" {
entry.token = cfg.GitHubToken // first-seen token wins
if cfg.Token != "" && entry.token == "" {
entry.token = cfg.Token // first-seen token wins
}
if cfg.SparseCheckout != "" {
entry.sparsePatterns = mergeSparsePatterns(entry.sparsePatterns, cfg.SparseCheckout)
Expand All @@ -158,7 +155,7 @@ func (cm *CheckoutManager) add(cfg *CheckoutConfig) {
entry := &resolvedCheckout{
key: key,
ref: cfg.Ref,
token: cfg.GitHubToken,
token: cfg.Token,
fetchDepth: cfg.FetchDepth,
submodules: cfg.Submodules,
lfs: cfg.LFS,
Expand Down Expand Up @@ -257,7 +254,6 @@ func (cm *CheckoutManager) GenerateDefaultCheckoutStep(
fmt.Fprintf(&sb, " ref: %s\n", override.ref)
}
if override.token != "" {
// actions/checkout input is "token", not "github-token"
fmt.Fprintf(&sb, " token: %s\n", override.token)
}
if override.fetchDepth != nil {
Expand Down Expand Up @@ -301,7 +297,6 @@ func generateCheckoutStepLines(entry *resolvedCheckout, getActionPin func(string
fmt.Fprintf(&sb, " path: %s\n", entry.key.path)
}
if entry.token != "" {
// actions/checkout input is "token", not "github-token"
fmt.Fprintf(&sb, " token: %s\n", entry.token)
}
if entry.fetchDepth != nil {
Expand Down Expand Up @@ -480,12 +475,12 @@ func checkoutConfigFromMap(m map[string]any) (*CheckoutConfig, error) {
cfg.Path = s
}

if v, ok := m["github-token"]; ok {
if v, ok := m["token"]; ok {
s, ok := v.(string)
if !ok {
return nil, errors.New("checkout.github-token must be a string")
return nil, errors.New("checkout.token must be a string")
}
cfg.GitHubToken = s
cfg.Token = s
}

if v, ok := m["fetch-depth"]; ok {
Expand Down
22 changes: 16 additions & 6 deletions pkg/workflow/checkout_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestNewCheckoutManager(t *testing.T) {

t.Run("custom token on default checkout", func(t *testing.T) {
cm := NewCheckoutManager([]*CheckoutConfig{
{GitHubToken: "${{ secrets.MY_TOKEN }}"},
{Token: "${{ secrets.MY_TOKEN }}"},
})
override := cm.GetDefaultCheckoutOverride()
require.NotNil(t, override, "should have default override")
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestGenerateDefaultCheckoutStep(t *testing.T) {

t.Run("user token is included in default checkout", func(t *testing.T) {
cm := NewCheckoutManager([]*CheckoutConfig{
{GitHubToken: "${{ secrets.MY_TOKEN }}"},
{Token: "${{ secrets.MY_TOKEN }}"},
})
lines := cm.GenerateDefaultCheckoutStep(false, "", getPin)
combined := strings.Join(lines, "")
Expand Down Expand Up @@ -161,7 +161,7 @@ func TestGenerateDefaultCheckoutStep(t *testing.T) {

t.Run("trial mode overrides user config", func(t *testing.T) {
cm := NewCheckoutManager([]*CheckoutConfig{
{GitHubToken: "${{ secrets.MY_TOKEN }}"},
{Token: "${{ secrets.MY_TOKEN }}"},
})
lines := cm.GenerateDefaultCheckoutStep(true, "owner/trial-repo", getPin)
combined := strings.Join(lines, "")
Expand Down Expand Up @@ -224,6 +224,16 @@ func TestGenerateAdditionalCheckoutSteps(t *testing.T) {
combined := strings.Join(lines, "")
assert.Contains(t, combined, "submodules: recursive", "should include submodules option")
})

t.Run("additional checkout emits token not github-token", func(t *testing.T) {
cm := NewCheckoutManager([]*CheckoutConfig{
{Path: "./libs", Repository: "owner/libs", Token: "${{ secrets.MY_TOKEN }}"},
})
lines := cm.GenerateAdditionalCheckoutSteps(getPin)
combined := strings.Join(lines, "")
assert.Contains(t, combined, "token: ${{ secrets.MY_TOKEN }}", "actions/checkout input must be 'token'")
assert.NotContains(t, combined, "github-token:", "must not emit 'github-token' as actions/checkout input")
})
}

// TestParseCheckoutConfigs verifies parsing of raw frontmatter values.
Expand All @@ -236,13 +246,13 @@ func TestParseCheckoutConfigs(t *testing.T) {

t.Run("single object", func(t *testing.T) {
raw := map[string]any{
"fetch-depth": float64(0),
"github-token": "${{ secrets.MY_TOKEN }}",
"fetch-depth": float64(0),
"token": "${{ secrets.MY_TOKEN }}",
}
configs, err := ParseCheckoutConfigs(raw)
require.NoError(t, err, "single object should parse without error")
require.Len(t, configs, 1, "should produce one config")
assert.Equal(t, "${{ secrets.MY_TOKEN }}", configs[0].GitHubToken, "token should be set")
assert.Equal(t, "${{ secrets.MY_TOKEN }}", configs[0].Token, "token should be set")
require.NotNil(t, configs[0].FetchDepth, "fetch-depth should be set")
assert.Equal(t, 0, *configs[0].FetchDepth, "fetch-depth should be 0")
})
Expand Down
14 changes: 7 additions & 7 deletions pkg/workflow/trial_mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ This is a test workflow for trial mode compilation.
t.Error("Expected safe_outputs job in normal mode")
}

// Checkout should not include github-token in normal mode
// Check specifically that the checkout step doesn't have a token parameter
// Checkout should not include an implicit/default token in normal mode when the workflow doesn't configure one
// Check specifically that the generated checkout step doesn't include a token parameter unless explicitly configured in the workflow
lines := strings.Split(lockContent, "\n")
for i, line := range lines {
if strings.Contains(line, "actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd") {
Expand All @@ -85,7 +85,7 @@ This is a test workflow for trial mode compilation.
// Found "with:" section, check for token
for k := j + 1; k < len(lines) && k < j+5; k++ {
if strings.Contains(lines[k], "token:") {
t.Error("Did not expect github-token in checkout step in normal mode")
t.Error("Did not expect token in checkout step in normal mode")
break
}
// If we hit another step or section, stop checking
Expand Down Expand Up @@ -133,7 +133,7 @@ This is a test workflow for trial mode compilation.
t.Error("Expected safe_outputs job in trial mode")
}

// Checkout in agent job should include github-token in trial mode
// Checkout in agent job should include token in trial mode
// Extract the agent job section first
agentJobStart := strings.Index(lockContent, "agent:")
if agentJobStart == -1 {
Expand Down Expand Up @@ -205,7 +205,7 @@ This is a test workflow for trial mode compilation.
}
}
if !foundCheckoutToken {
t.Error("Expected github-token in checkout step in trial mode")
t.Error("Expected token in checkout step in trial mode")
}

// Should still include the main workflow job
Expand Down Expand Up @@ -318,10 +318,10 @@ This is a test workflow for trial mode compilation.
t.Error("Expected jobs section to be present in trial mode")
}

// In trial mode, checkout should always include github-token
// In trial mode, checkout should always include token (as "token:" input for actions/checkout)
if strings.Contains(lockContent, "uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd") {
if !strings.Contains(lockContent, "token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}") {
t.Error("Expected github-token in checkout step in trial mode")
t.Error("Expected token in checkout step in trial mode")
}
}
})
Expand Down
Loading