Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
8 changes: 1 addition & 7 deletions .github/workflows/test-claude.lock.yml

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

8 changes: 1 addition & 7 deletions .github/workflows/test-claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ You are a code review assistant powered by Claude. Your task is to analyze the c

3. **Generate Summary Report**
Create a detailed comment on the pull request with the following sections:

#### 🤖 Claude PR Summary

**Branch:** `${{ github.head_ref }}`
**Files Changed:** [number] files
**Analysis Time:** [current timestamp from get_current_time]

#### 📋 Change Overview
- Brief description of what this PR accomplishes
Expand Down Expand Up @@ -80,7 +74,7 @@ You are a code review assistant powered by Claude. Your task is to analyze the c
- Reference to documentation updates needed

---
*Generated by Claude AI on ${{ github.event.pull_request.created_at }}*
*Generated by Claude AI*

### Instructions

Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/test-codex.lock.yml

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

8 changes: 1 addition & 7 deletions .github/workflows/test-codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ You are a code review assistant powered by Codex. Your task is to analyze the ch

3. **Generate Summary Report**
Create a detailed comment on the pull request with the following sections:

#### 🤖 Codex PR Summary

**Branch:** `${{ github.head_ref }}`
**Files Changed:** [number] files
**Analysis Time:** [current timestamp from get_current_time]

#### 📋 Change Overview
- Brief description of what this PR accomplishes
Expand Down Expand Up @@ -80,7 +74,7 @@ You are a code review assistant powered by Codex. Your task is to analyze the ch
- Reference to documentation updates needed

---
*Generated by Codex AI on ${{ github.event.pull_request.created_at }}*
*Generated by Codex AI*

### Instructions

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/weekly-research.lock.yml

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

2 changes: 1 addition & 1 deletion .github/workflows/weekly-research.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tools:

## Job Description

Do a deep research investigation in ${{ env.GITHUB_REPOSITORY }} repository, and the related industry in general.
Do a deep research investigation in ${{ github.repository }} repository, and the related industry in general.

- Read selections of the latest code, issues and PRs for this repo.
- Read latest trends and news from the software industry news source on the Web.
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Complete documentation for creating and managing agentic workflows with GitHub A

## Getting Started

- **[Workflow Structure](workflow-structure.md)** - Directory layout and file organization
- **[Workflow Structure](workflow-structure.md)** - Directory layout, file organization, and expression security
- **[Commands](commands.md)** - CLI commands for workflow management
- **[Include Directives](include-directives.md)** - Modularizing workflows with includes

Expand Down
85 changes: 85 additions & 0 deletions docs/workflow-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,91 @@ When a new issue is opened, analyze the issue content and:
The issue details are: "${{ needs.task.outputs.text }}"
```

## Expression Security

For security reasons, agentic workflows restrict which GitHub Actions expressions can be used in **markdown content**. This prevents potential security vulnerabilities from unauthorized access to secrets or environment variables.

> **Note**: These restrictions apply only to expressions in the markdown content portion of workflows. The YAML frontmatter can still use secrets and environment variables as needed for workflow configuration (e.g., `env:` and authentication).

### Allowed Expressions

The following GitHub Actions context expressions are permitted in workflow markdown:
#### GitHub Context Expressions

- `${{ github.event.after }}` - The SHA of the most recent commit on the ref after the push
- `${{ github.event.before }}` - The SHA of the most recent commit on the ref before the push
- `${{ github.event.check_run.id }}` - The ID of the check run that triggered the workflow
- `${{ github.event.check_suite.id }}` - The ID of the check suite that triggered the workflow
- `${{ github.event.comment.id }}` - The ID of the comment that triggered the workflow
- `${{ github.event.deployment.id }}` - The ID of the deployment that triggered the workflow
- `${{ github.event.deployment_status.id }}` - The ID of the deployment status that triggered the workflow
- `${{ github.event.head_commit.id }}` - The ID of the head commit for the push event
- `${{ github.event.installation.id }}` - The ID of the GitHub App installation
- `${{ github.event.issue.number }}` - The number of the issue that triggered the workflow
- `${{ github.event.label.id }}` - The ID of the label that triggered the workflow
- `${{ github.event.milestone.id }}` - The ID of the milestone that triggered the workflow
- `${{ github.event.organization.id }}` - The ID of the organization that triggered the workflow
- `${{ github.event.page.id }}` - The ID of the page build that triggered the workflow
- `${{ github.event.project.id }}` - The ID of the project that triggered the workflow
- `${{ github.event.project_card.id }}` - The ID of the project card that triggered the workflow
- `${{ github.event.project_column.id }}` - The ID of the project column that triggered the workflow
- `${{ github.event.pull_request.number }}` - The number of the pull request that triggered the workflow
- `${{ github.event.release.assets[0].id }}` - The ID of the first asset in a release
- `${{ github.event.release.id }}` - The ID of the release that triggered the workflow
- `${{ github.event.repository.id }}` - The ID of the repository that triggered the workflow
- `${{ github.event.review.id }}` - The ID of the pull request review that triggered the workflow
- `${{ github.event.review_comment.id }}` - The ID of the review comment that triggered the workflow
- `${{ github.event.sender.id }}` - The ID of the user who triggered the workflow
- `${{ github.event.workflow_run.id }}` - The ID of the workflow run that triggered the current workflow
- `${{ github.actor }}` - The username of the user who triggered the workflow
- `${{ github.owner }}` - The owner of the repository (user or organization name)
- `${{ github.repository }}` - The owner and repository name (e.g., `octocat/Hello-World`)
- `${{ github.run_id }}` - A unique number for each workflow run within a repository
- `${{ github.run_number }}` - A unique number for each run of a particular workflow in a repository
- `${{ github.workflow }}` - The name of the workflow

#### Special Pattern Expressions
- `${{ needs.* }}` - Any outputs from previous jobs (e.g., `${{ needs.task.outputs.text }}`)
- `${{ steps.* }}` - Any outputs from previous steps in the same job

### Prohibited Expressions

All other expressions are dissallowed.

### Security Rationale

This restriction prevents:
- **Secret leakage**: Prevents accidentally exposing secrets in AI prompts or logs
- **Environment variable exposure**: Protects sensitive configuration from being accessed
- **Code injection**: Prevents complex expressions that could execute unintended code
- **Expression injection**: Prevents malicious expressions from being injected into AI prompts
- **Prompt hijacking**: Stops unauthorized modification of workflow instructions through expression values
- **Cross-prompt information attacks (XPIA)**: Blocks attempts to leak information between different workflow executions

### Validation

Expression safety is validated during compilation with `gh aw compile`. If unauthorized expressions are found, you'll see an error like:

```
error: unauthorized expressions: [secrets.TOKEN, env.MY_VAR].
allowed: [github.repository, github.actor, github.workflow, ...]
```

### Example Valid Usage

```markdown
# Valid expressions
Repository: ${{ github.repository }}
Triggered by: ${{ github.actor }}
Issue number: ${{ github.event.issue.number }}
Previous output: ${{ needs.task.outputs.text }}

# Invalid expressions (will cause compilation error)
Token: ${{ secrets.GITHUB_TOKEN }}
Environment: ${{ env.MY_VAR }}
Complex: ${{ toJson(github.workflow) }}
```

## Generated Files

When you run `gh aw compile`, the system:
Expand Down
70 changes: 52 additions & 18 deletions pkg/cli/templates/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,30 +161,64 @@ on:

## GitHub Context Expression Interpolation

Use GitHub Actions context expressions throughout the workflow content:

### Common Context Variables
Use GitHub Actions context expressions throughout the workflow content. **Note: For security reasons, only specific expressions are allowed.**

### Allowed Context Variables
- **`${{ github.event.after }}`** - SHA of the most recent commit after the push
- **`${{ github.event.before }}`** - SHA of the most recent commit before the push
- **`${{ github.event.check_run.id }}`** - ID of the check run
- **`${{ github.event.check_suite.id }}`** - ID of the check suite
- **`${{ github.event.comment.id }}`** - ID of the comment
- **`${{ github.event.deployment.id }}`** - ID of the deployment
- **`${{ github.event.deployment_status.id }}`** - ID of the deployment status
- **`${{ github.event.head_commit.id }}`** - ID of the head commit
- **`${{ github.event.installation.id }}`** - ID of the GitHub App installation
- **`${{ github.event.issue.number }}`** - Issue number
- **`${{ github.event.issue.title }}`** - Issue title
- **`${{ github.event.issue.body }}`** - Issue body content
- **`${{ github.event.comment.body }}`** - Comment content
- **`${{ github.repository }}`** - Repository name (owner/repo)
- **`${{ github.actor }}`** - User who triggered the workflow
- **`${{ github.run_id }}`** - Workflow run ID
- **`${{ github.workflow }}`** - Workflow name
- **`${{ github.ref }}`** - Git reference
- **`${{ github.sha }}`** - Commit SHA

### Environment Variables
- **`${{ env.GITHUB_REPOSITORY }}`** - Repository name
- **`${{ secrets.GITHUB_TOKEN }}`** - GitHub token
- **Custom variables**: `${{ env.CUSTOM_VAR }}`
- **`${{ github.event.label.id }}`** - ID of the label
- **`${{ github.event.milestone.id }}`** - ID of the milestone
- **`${{ github.event.organization.id }}`** - ID of the organization
- **`${{ github.event.page.id }}`** - ID of the GitHub Pages page
- **`${{ github.event.project.id }}`** - ID of the project
- **`${{ github.event.project_card.id }}`** - ID of the project card
- **`${{ github.event.project_column.id }}`** - ID of the project column
- **`${{ github.event.pull_request.number }}`** - Pull request number
- **`${{ github.event.release.assets[0].id }}`** - ID of the first release asset
- **`${{ github.event.release.id }}`** - ID of the release
- **`${{ github.event.repository.id }}`** - ID of the repository
- **`${{ github.event.review.id }}`** - ID of the review
- **`${{ github.event.review_comment.id }}`** - ID of the review comment
- **`${{ github.event.sender.id }}`** - ID of the user who triggered the event
- **`${{ github.event.workflow_run.id }}`** - ID of the workflow run
- **`${{ github.actor }}`** - Username of the person who initiated the workflow
- **`${{ github.owner }}`** - Owner of the repository
- **`${{ github.repository }}`** - Repository name in "owner/name" format
- **`${{ github.run_id }}`** - Unique ID of the workflow run
- **`${{ github.run_number }}`** - Number of the workflow run
- **`${{ github.workflow }}`** - Name of the workflow

#### Special Pattern Expressions
- **`${{ needs.* }}`** - Any outputs from previous jobs (e.g., `${{ needs.task.outputs.text }}`)
- **`${{ steps.* }}`** - Any outputs from previous steps (e.g., `${{ steps.my-step.outputs.result }}`)

All other expressions are dissallowed.

### Security Validation

Expression safety is automatically validated during compilation. If unauthorized expressions are found, compilation will fail with an error listing the prohibited expressions.

### Example Usage
```markdown
# Valid expressions
Analyze issue #${{ github.event.issue.number }} in repository ${{ github.repository }}.

The issue was created by ${{ github.actor }} with title: "${{ github.event.issue.title }}"

Using output from previous task: "${{ needs.task.outputs.text }}"

# Invalid expressions (will cause compilation errors)
# Token: ${{ secrets.GITHUB_TOKEN }}
# Environment: ${{ env.MY_VAR }}
# Complex: ${{ toJson(github.workflow) }}
```

## Tool Configuration
Expand Down Expand Up @@ -342,7 +376,7 @@ timeout_minutes: 15

# Weekly Research

Research latest developments in ${{ env.GITHUB_REPOSITORY }}:
Research latest developments in ${{ github.repository }}:
- Review recent commits and issues
- Search for industry trends
- Create summary issue
Expand Down
36 changes: 36 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,39 @@ package constants

// CLIExtensionPrefix is the prefix used in user-facing output to refer to the CLI extension
const CLIExtensionPrefix = "gh aw"

// AllowedExpressions contains the GitHub Actions expressions that can be used in workflow markdown content
// see https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#github-context
var AllowedExpressions = []string{
"github.event.after",
"github.event.before",
"github.event.check_run.id",
"github.event.check_suite.id",
"github.event.comment.id",
"github.event.deployment.id",
"github.event.deployment_status.id",
"github.event.head_commit.id",
"github.event.installation.id",
"github.event.issue.number",
"github.event.label.id",
"github.event.milestone.id",
"github.event.organization.id",
"github.event.page.id",
"github.event.project.id",
"github.event.project_card.id",
"github.event.project_column.id",
"github.event.pull_request.number",
"github.event.release.assets[0].id",
"github.event.release.id",
"github.event.repository.id",
"github.event.review.id",
"github.event.review_comment.id",
"github.event.sender.id",
"github.event.workflow_run.id",
"github.actor",
"github.owner",
"github.repository",
"github.run_id",
"github.run_number",
"github.workflow",
} // needs., steps. already allowed
Loading