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
5 changes: 5 additions & 0 deletions .changeset/patch-add-github-token-secret-validation.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions docs/src/content/docs/guides/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ Workflows use a hierarchical token precedence system that allows you to configur

This allows you to set a default token for the entire workflow while still allowing specific safe-outputs to use different tokens when needed.

:::tip[Automatic Secret Validation]
All `github-token` fields are automatically validated during compilation to ensure they use GitHub Actions secret expressions (e.g., `${{ secrets.CUSTOM_PAT }}`). This prevents accidental plaintext secret leakage in workflow files.

If you specify a plaintext token like `ghp_1234...` or use an environment variable like `${{ env.MY_TOKEN }}`, compilation will fail with a clear error message.
:::

#### Token Configuration Examples

**Top-level token for entire workflow:**
Expand Down
14 changes: 14 additions & 0 deletions docs/src/content/docs/reference/frontmatter.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ The `github-token:` field configures the default GitHub token for the entire wor
github-token: ${{ secrets.CUSTOM_PAT }}
```

:::caution[Secret Expression Required]
The `github-token` field **must** use a GitHub Actions secret expression (e.g., `${{ secrets.CUSTOM_PAT }}`). Plaintext tokens are rejected during compilation to prevent accidental secret leakage.

**Valid formats:**
- `${{ secrets.GITHUB_TOKEN }}`
- `${{ secrets.CUSTOM_PAT }}`
- `${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}`

**Invalid formats:**
- `ghp_1234567890...` (plaintext token)
- `${{ env.MY_TOKEN }}` (environment variable; not protected like secrets)
- `my-secret-token` (plaintext string)
:::

The token precedence hierarchy allows fine-grained control:

1. **Individual safe-output `github-token`** (highest priority) - e.g., `create-issue.github-token`
Expand Down
95 changes: 68 additions & 27 deletions pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,33 @@
{
"type": "string",
"description": "Single event name or '*' for all events. Use GitHub Actions event names: 'issues', 'issue_comment', 'pull_request_comment', 'pull_request', 'pull_request_review_comment', 'discussion', 'discussion_comment'.",
"enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"]
"enum": [
"*",
"issues",
"issue_comment",
"pull_request_comment",
"pull_request",
"pull_request_review_comment",
"discussion",
"discussion_comment"
]
},
{
"type": "array",
"description": "Array of event names where the command should be active. Use GitHub Actions event names.",
"items": {
"type": "string",
"description": "GitHub Actions event name.",
"enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"]
"enum": [
"*",
"issues",
"issue_comment",
"pull_request_comment",
"pull_request",
"pull_request_review_comment",
"discussion",
"discussion_comment"
]
}
}
]
Expand Down Expand Up @@ -1279,11 +1297,13 @@
"description": "The name of the environment configured in the repo"
},
"url": {
"type": "string",
"type": "string",
"description": "A deployment URL"
}
},
"required": ["name"],
"required": [
"name"
],
"additionalProperties": false
}
]
Expand Down Expand Up @@ -1349,7 +1369,9 @@
"description": "Additional Docker container options"
}
},
"required": ["image"],
"required": [
"image"
],
"additionalProperties": false
}
]
Expand Down Expand Up @@ -1417,7 +1439,9 @@
"description": "Additional Docker container options"
}
},
"required": ["image"],
"required": [
"image"
],
"additionalProperties": false
}
]
Expand Down Expand Up @@ -1458,7 +1482,9 @@
},
{
"type": "string",
"enum": ["disable"],
"enum": [
"disable"
],
"description": "Disable AWF firewall (triggers warning if allowed != *, error in strict mode if allowed is not * or engine does not support firewall)"
},
{
Expand Down Expand Up @@ -1585,7 +1611,10 @@
},
"mode": {
"type": "string",
"enum": ["local", "remote"],
"enum": [
"local",
"remote"
],
"description": "MCP server mode: 'local' (Docker-based, default) or 'remote' (hosted at api.githubcopilot.com)"
},
"version": {
Expand All @@ -1604,7 +1633,7 @@
"description": "Enable read-only mode to restrict GitHub MCP server to read-only operations only"
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "Optional custom GitHub token (e.g., '${{ secrets.CUSTOM_PAT }}'). For 'remote' type, defaults to GH_AW_GITHUB_TOKEN if not specified."
},
"toolset": {
Expand Down Expand Up @@ -2033,7 +2062,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository issue creation. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2072,7 +2101,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository agent task creation. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2124,7 +2153,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository discussion creation. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2163,7 +2192,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository comments. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
},
"discussion": {
Expand Down Expand Up @@ -2231,7 +2260,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository pull request creation. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2278,7 +2307,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository PR review comments. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2312,7 +2341,7 @@
"description": "Driver name for SARIF tool.driver.name field (default: 'GitHub Agentic Workflows Security Scanner')"
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2361,7 +2390,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository label addition. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2408,7 +2437,7 @@
"description": "Target repository in format 'owner/repo' for cross-repository issue updates. Takes precedence over trial target repo settings."
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2463,7 +2492,7 @@
"description": "Optional suffix to append to generated commit titles (e.g., ' [skip ci]' to prevent triggering CI on the commit)"
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand All @@ -2489,7 +2518,7 @@
"maximum": 100
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2545,7 +2574,7 @@
"maximum": 100
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for this specific output type. Overrides global github-token if specified."
}
},
Expand Down Expand Up @@ -2573,7 +2602,7 @@
"additionalProperties": false
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token to use for safe output jobs. Typically a secret reference like ${{ secrets.GITHUB_TOKEN }} or ${{ secrets.CUSTOM_PAT }}"
},
"max-patch-size": {
Expand Down Expand Up @@ -2672,7 +2701,7 @@
"$ref": "#/properties/permissions"
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token for this specific job"
},
"output": {
Expand Down Expand Up @@ -2744,14 +2773,14 @@
"additionalProperties": false
},
"roles": {
"description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (⚠️ security consideration).",
"description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (\u26a0\ufe0f security consideration).",
"oneOf": [
{
"type": "string",
"enum": [
"all"
],
"description": "Allow any authenticated user to trigger the workflow (⚠️ disables permission checking entirely - use with caution)"
"description": "Allow any authenticated user to trigger the workflow (\u26a0\ufe0f disables permission checking entirely - use with caution)"
},
{
"type": "array",
Expand Down Expand Up @@ -2880,7 +2909,7 @@
"additionalProperties": false
},
"github-token": {
"type": "string",
"$ref": "#/$defs/github_token",
"description": "GitHub token expression to use for all steps that require GitHub authentication. Typically a secret reference like ${{ secrets.GITHUB_TOKEN }} or ${{ secrets.CUSTOM_PAT }}. If not specified, defaults to ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}. This value can be overridden by safe-outputs github-token or individual safe-output github-token fields."
}
},
Expand Down Expand Up @@ -2943,7 +2972,9 @@
"description": "Whether to cancel in-progress runs of the same concurrency group. Defaults to false for agentic workflow runs."
}
},
"required": ["group"],
"required": [
"group"
],
"additionalProperties": false
}
],
Expand Down Expand Up @@ -3190,6 +3221,16 @@
"url"
],
"additionalProperties": false
},
"github_token": {
"type": "string",
"pattern": "^\\$\\{\\{\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*\\s*\\}\\}$",
"description": "GitHub token expression using secrets. Pattern details: `[A-Za-z_][A-Za-z0-9_]*` matches a valid secret name (starts with a letter or underscore, followed by letters, digits, or underscores). The full pattern matches expressions like `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`.",
"examples": [
"${{ secrets.GITHUB_TOKEN }}",
"${{ secrets.CUSTOM_PAT }}",
"${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}"
]
}
}
}
Loading
Loading