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
36 changes: 36 additions & 0 deletions docs/src/content/docs/reference/checkout.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ checkout:
| `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. |
| `github-app` | object | GitHub App credentials (`client-id` or `app-id` (deprecated), `private-key`, optional `owner`, `repositories`). Mutually exclusive with `github-token`. `app` is a deprecated alias for the field name. Run `gh aw fix` to auto-migrate `app-id` to `client-id`. |
| `safe-output-github-app` | object | Optional per-checkout GitHub App credentials used exclusively for safe_outputs git operations on this checkout target (`client-id` or `app-id` (deprecated), `private-key`, optional `owner`, `repositories`). Does not change agent/activation checkout auth. See [Cross-Organization safe_outputs Authentication](#cross-organization-safe_outputs-authentication-safe-output-github-app) for cross-org usage. |
| `fetch-depth` | integer | Commits to fetch. `0` = full history, `1` = shallow clone (default). |
| `fetch` | string \| string[] | Additional Git refs to fetch after checkout. See [Fetching Additional Refs](#fetching-additional-refs). |
| `sparse-checkout` | string | Newline-separated patterns for sparse checkout (e.g., `.github/\nsrc/`). |
Expand Down Expand Up @@ -153,6 +154,40 @@ checkout:
force-clean-git-credentials: true
```

## Cross-Organization safe_outputs Authentication (`safe-output-github-app`)

By default, the safe_outputs job uses `GITHUB_TOKEN` to check out repositories — `safe-outputs.github-app` and `safe-outputs.github-token` are **not** used for checkout and only govern PR/push API operations. This design prevents cross-org token confusion when the safe-outputs app is scoped to a target organization that differs from the workflow repository's organization.

For workflows that target a different organization, use `safe-output-github-app` on the relevant checkout entry to supply a checkout token for the safe_outputs job:

```yaml wrap
checkout:
- repository: OrgB/target-repo
github-app:
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: OrgB
safe-output-github-app:
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: OrgB
current: true

safe-outputs:
github-app:
client-id: ${{ vars.APP_CLIENT_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: OrgB
create-pull-request:
target-repo: OrgB/target-repo
```

In this configuration:
- The agent job checks out `OrgB/target-repo` using the app token scoped to `OrgB`.
- The safe_outputs job checks out `OrgB/target-repo` using the `safe-output-github-app` token.
- The safe_outputs job checks out the **workflow repository** using `GITHUB_TOKEN` (the default), not the `OrgB`-scoped app token — avoiding the cross-org authentication failure.
- `safe-outputs.github-app` is used only for PR creation and push operations, not for checkout.

## Checkout Merging

Multiple `checkout:` configurations can target the same path and repository. This is useful for monorepos where different parts of the repository must be merged into the same workspace directory with different settings (e.g., sparse checkout for some paths, full checkout for others).
Expand All @@ -171,3 +206,4 @@ When multiple `checkout:` entries target the same repository and path, their con
- [Cross-Repository Operations](/gh-aw/reference/cross-repository/) - Reading and writing across multiple repositories
- [Authentication Reference](/gh-aw/reference/auth/) - PAT and GitHub App setup
- [Multi-Repository Examples](/gh-aw/examples/multi-repo/) - Complete working examples
- [Checkout Behavior Specification](/gh-aw/specs/checkout-behavior-specification/) - Formal checkout semantics across activation, agent, and safe_outputs jobs
290 changes: 290 additions & 0 deletions docs/src/content/docs/specs/checkout-behavior-specification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
---
title: Checkout Behavior Specification
description: Formal specification of checkout behavior across activation, agent, and safe_outputs jobs in gh-aw workflows
sidebar:
order: 1365
---

# Checkout Behavior Specification

**Version**: 1.0.0
**Status**: Working Draft
**Publication Date**: 2026-07-08
**Editor**: GitHub Agentic Workflows Team
**This Version**: [checkout-behavior-specification](/gh-aw/specs/checkout-behavior-specification/)
**Latest Published Version**: This document

---

## Abstract

This specification defines normative checkout behavior in GitHub Agentic Workflows (`gh-aw`) for activation, agent, and `safe_outputs` jobs. It specifies credential and token precedence, `github-token` and `github-app` resolution, trial mode behavior, side-repo targeting, sparse/shallow/fetch semantics, symlink handling during sparse activation checkout, submodule cleanup semantics, and checkout-manifest behavior used by safe output handlers.

## Status of This Document

This is a working draft and may change. It describes behavior mined from the current implementation in `pkg/workflow/` and `actions/setup/js/`.

## Table of Contents

1. [Introduction](#1-introduction)
2. [Conformance](#2-conformance)
3. [Checkout Model](#3-checkout-model)
4. [Authentication and Token Resolution](#4-authentication-and-token-resolution)
5. [Sparse, Shallow, Fetch, Symlink, and Submodule Behavior](#5-sparse-shallow-fetch-symlink-and-submodule-behavior)
6. [Trial Mode and Side-Repo Behavior](#6-trial-mode-and-side-repo-behavior)
7. [Compliance Testing](#7-compliance-testing)
8. [References](#8-references)
9. [Change Log](#9-change-log)

---

## 1. Introduction

### 1.1 Purpose

This document defines exactly how checkout is compiled and executed for:

- Activation job sparse checkouts
- Agent job checkouts
- `safe_outputs` job PR/push checkouts

### 1.2 Scope

This specification covers:

- `checkout:` parsing and merge behavior
- `actions/checkout` step generation
- Checkout credential persistence/cleanup behavior
- Token and GitHub App precedence across checkout and `safe_outputs`
- Sparse/shallow/fetch mechanics
- Symlink handling for activation sparse checkout
- Submodule credential cleanup behavior
- Trial mode and side-repo derivation behavior
- Checkout-manifest generation requirements for safe_outputs handler lookup

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot also handle checkout manifest generation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f4562a1: added normative checkout-manifest generation requirements, including safe-outputs auth metadata handling and no persisted resolved tokens.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section 3.4 (Checkout Manifest) was added in f4562a1 and is in the current spec — see lines 111–118 of checkout-behavior-specification.md. It covers the compiler requirement to emit a manifest step, manifest-path safety (absolute/out-of-workspace rejection), and the requirement to include safe_outputs auth metadata without persisting resolved token values.

---

## 2. Conformance

### 2.1 Requirements Notation

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).

### 2.2 Conformance Classes

- **C1 (Compiler conformance)**: emits checkout YAML conforming to Sections 3–6.
- **C2 (Runtime conformance)**: JS/sh handlers honor manifest safety, fetch behavior, and credential boundaries in Sections 4–6.

---

## 3. Checkout Model

### 3.1 Checkout Entry Parsing

`checkout:` MUST accept either a single object or an array of objects.
Each entry MAY define: `repository`, `ref`, `path`, `github-token` (or legacy `token`), `github-app` (or deprecated alias `app`), `safe-output-github-app`, `fetch-depth`, `fetch`, `sparse-checkout`, `submodules`, `lfs`, `current`, `wiki`, and `force-clean-git-credentials`.

`github-token` and `github-app` MUST be mutually exclusive per entry.

`safe-output-github-app` applies only to safe_outputs git auth/token resolution. It MUST NOT change agent/activation checkout authentication behavior.

### 3.2 Entry Merge Rules

Entries with the same `(repository, path, wiki)` key MUST merge with these rules:

- `fetch-depth`: deepest wins (`0` wins over all)
- `ref`: first non-empty wins
- auth (`github-token` vs `github-app`): first auth wins
- safe_outputs auth (`safe-output-github-app`): first non-empty wins
- sparse patterns: union
- fetch refs: union
- `lfs`: OR
- `submodules`: first non-empty wins
- `force-clean-git-credentials`: OR

### 3.3 Job-specific Checkout Generation

- **Activation job** MUST use sparse checkout for `.github` and `.agents`, with `persist-credentials: false`.
- **Agent job** MUST generate default checkout plus additional checkouts from `CheckoutManager`, with `persist-credentials: false` by default.
- **safe_outputs job** MUST reuse the same checkout generators but set keep-credentials mode for push/fetch use and inject a `Configure Git credentials` step.

### 3.4 Checkout Manifest

For non-default cross-repo checkouts, the compiler MUST emit a checkout manifest step.
Runtime lookup (`find_repo_checkout`) MUST prefer manifest paths and MUST reject manifest paths that are absolute or escape workspace roots.

Checkout-manifest generation MUST include enough per-checkout auth metadata to resolve default branches and safe_outputs repo targeting without relying on implicit defaults.
The manifest (or manifest-construction env) MUST NOT persist resolved token values to disk.

---

## 4. Authentication and Token Resolution

### 4.1 Checkout Entry Auth

For each checkout step, token resolution MUST be:

1. Entry `github-app` minted token (with fallback behavior if `ignore-if-missing: true`)
2. Entry `github-token`
3. Default token fallback when required by context

Top-level `github-app` fallback MUST be applied to checkout entries only when that entry has neither `github-app` nor `github-token`.

### 4.2 Activation Job Token

Activation token precedence MUST be:

1. `on.github-app` minted token; when `ignore-if-missing: true`, this resolves to `steps.activation-app-token.outputs.token || secrets.GITHUB_TOKEN`
2. `on.github-token`
3. `secrets.GITHUB_TOKEN`

### 4.3 safe_outputs PR Checkout Token

`safe-outputs.github-app` and `safe-outputs.github-token` MUST NOT be used as checkout tokens in the safe_outputs job. They govern safe_outputs operations (PR creation, push) only. Using a safe_outputs-scoped app token for checkout is unsafe when that token is scoped to a target organization that differs from the workflow repository's organization.

`resolvePRCheckoutToken` precedence MUST be:

1. Checkout target `safe-output-github-app` minted token (with fallback chain when `ignore-if-missing: true`)
2. `${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}`

When safe_outputs checkout retention is enabled, checkouts without explicit entry tokens MUST persist the resolved PR checkout token so local git credentials match push/fetch token usage.

### 4.4 Credential Lifecycle Boundary

- Agent job checkouts MUST remove persisted credentials by default (`persist-credentials: false`).
- safe_outputs PR checkout path MUST retain credentials (`persist-credentials: true`) and run explicit git remote credential configuration for root and sub-repo checkouts.
- Agent guidance MUST state that authenticated `git fetch/pull/push` is unavailable after checkout unless refs were already fetched.

### 4.5 Credential-less Safe-outputs MCP Context

`generate_git_patch` and `generate_git_bundle` in the safe-outputs MCP server context MUST fail softly when required refs are unavailable and private-repo fetch cannot authenticate, with actionable error text directing users to add refs via `checkout.fetch`.

---

## 5. Sparse, Shallow, Fetch, Symlink, and Submodule Behavior

### 5.1 Shallow and Additional Fetch

- Default shallow behavior MUST be `fetch-depth: 1` when unset.
- Additional `fetch:` refs MUST emit a follow-up `git fetch` step per checkout entry.
- Follow-up fetch MUST mirror effective depth (omit `--depth` only when effective depth is `0`).
- Follow-up fetch MUST inject credentials via command-level `http.extraheader` and MUST NOT persist credentials to git config.

### 5.2 Sparse Checkout and Partial-clone Repair

When sparse checkout is configured, compiler-generated checkout steps MUST emit:

- `filter: 'blob:limit=1073741824'`
- a post-checkout step clearing:
- `remote.origin.promisor`
- `remote.origin.partialclonefilter`

This avoids blobless partial-clone behavior that would require later authenticated lazy fetches in agent contexts.

### 5.3 Activation Symlink Handling

Activation sparse checkout path expansion MUST detect symlinks for known `.github` subpaths and include resolved in-repo targets.
Resolved targets escaping repository root MUST be rejected.

### 5.4 Submodules and Credential Cleanup

`submodules` MUST accept string or boolean and compile to string form accepted by `actions/checkout`.
When `force-clean-git-credentials: true` is set (and keep-credentials-for-push is not enabled), checkout MUST keep credentials long enough for checkout internals and then run cleanup that removes credential sections/headers from:

- `.git/config`
- `.git/modules/**/config`

---

## 6. Trial Mode and Side-Repo Behavior

### 6.1 Trial Mode Checkout

In trial mode, default checkout generation MUST:

- Override repository to `trialLogicalRepoSlug` when provided
- Emit token via default GitHub token chain (`getEffectiveGitHubToken("")`)
- Keep additional fetch-step behavior aligned with non-trial mode

For safe-output environment variables, trial mode SHOULD set `GH_AW_TARGET_REPO_SLUG` to the logical trial repo when no explicit target repo is configured.

### 6.2 Side-Repo Target Derivation

Side-repo maintenance target detection MUST use checkout entries marked `current: true` with static repository slugs.
Expression-based repositories MUST be excluded.
Auth selection for repeated targets MUST preserve first-seen auth, except that empty auth MAY be upgraded by a later non-empty auth.

Effective side-repo token precedence MUST be:

1. side-repo target checkout `github-token`
2. side-repo target checkout `github-app` minted token reference
3. `${{ secrets.GH_AW_GITHUB_TOKEN }}`

---

## 7. Compliance Testing

### 7.1 Required Tests

- **T-CHK-001**: `checkout.github-token` and `checkout.github-app` mutual exclusivity validation
- **T-CHK-002**: Merge behavior by `(repository,path,wiki)` key
- **T-CHK-003**: Agent job emits `persist-credentials: false` by default
- **T-CHK-004**: safe_outputs PR checkout path retains credentials and configures git remotes
- **T-CHK-005**: Sparse checkout emits blob-limit filter and partial-clone reset step
- **T-CHK-006**: Additional `fetch:` emits depth-mirrored fetch with `http.extraheader`
- **T-CHK-007**: Manifest path resolution rejects absolute/out-of-workspace paths
- **T-CHK-008**: Trial mode repository/token override behavior
- **T-CHK-009**: Side-repo target extraction and auth precedence
- **T-CHK-010**: `force-clean-git-credentials` cleanup covers `.git/modules/**/config`
- **T-CHK-011**: `checkout.safe-output-github-app` is the sole supported safe_outputs auth override per checkout entry
- **T-CHK-012**: safe_outputs checkout token MUST NOT use `safe-outputs.github-app` or `safe-outputs.github-token`; only `safe-output-github-app` (per entry) or `GITHUB_TOKEN` are permitted
- **T-CHK-013**: Checkout-manifest generation includes safe_outputs auth metadata without persisting resolved tokens

### 7.2 Compliance Checklist

| Requirement | Test ID | Level | Status |
|---|---|---|---|
| Checkout parse + merge semantics | T-CHK-001, T-CHK-002 | C1 | Required |
| Agent vs safe_outputs credential lifecycle | T-CHK-003, T-CHK-004 | C1/C2 | Required |
| Sparse/shallow/fetch semantics | T-CHK-005, T-CHK-006 | C1 | Required |
| Manifest path safety | T-CHK-007 | C2 | Required |
| Trial and side-repo behavior | T-CHK-008, T-CHK-009 | C1 | Required |
| Submodule cleanup behavior | T-CHK-010 | C1/C2 | Required |
| Checkout-level safe_outputs auth field | T-CHK-011, T-CHK-012 | C1/C2 | Required |
| Checkout-manifest generation requirements | T-CHK-013 | C1/C2 | Required |

---

## 8. References

### Normative References

- [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)
- `pkg/workflow/checkout_manager.go`
- `pkg/workflow/checkout_config_parser.go`
- `pkg/workflow/checkout_step_generator.go`
- `pkg/workflow/compiler_yaml_main_job.go`
- `pkg/workflow/compiler_safe_outputs_steps.go`
- `pkg/workflow/safe_outputs_app_config.go`
- `pkg/workflow/github_token.go`
- `actions/setup/js/generate_git_patch.cjs`
- `actions/setup/js/generate_git_bundle.cjs`
- `actions/setup/js/find_repo_checkout.cjs`
- `actions/setup/sh/configure_git_credentials.sh`
- `actions/setup/sh/clean_git_credentials.sh`

### Informative References

- `/gh-aw/reference/checkout/`
- `/gh-aw/reference/safe-outputs-pull-requests/`
- `/gh-aw/docs/sparseness.md`

---

## 9. Change Log

### Version 1.0.0 (Working Draft)

- Initial specification for checkout behavior in activation, agent, and safe_outputs jobs
- Added normative credential precedence and lifecycle requirements
- Added sparse/shallow/fetch, symlink, submodule, trial mode, and side-repo requirements