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
30 changes: 14 additions & 16 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,26 @@ CLI flags and environment variables override config values for one run. Legacy `

GitHub issue notifications are optional. Patchlane keeps one issue per failure event, updates it on repeated failures, assigns configured users individually, and closes it after a successful run when `closeOnRecovery` is enabled. The generated App tokens request `issues: write` only when they handle an enabled GitHub issue event. Notification API errors are warnings and do not replace the sync, CI, or promotion result.

## GitHub App authentication
## Workflow authentication

The generated workflows require:
Patchlane automation needs a token that can push repository contents, update workflow files, and start the downstream workflows triggered by those pushes. Enable issue access when GitHub issue notifications are configured. The built-in `GITHUB_TOKEN` is not suitable because GitHub deliberately suppresses most workflow events caused by it; increasing its workflow permissions does not change that behavior.

The generated workflows use `actions/create-github-app-token` with:

- repository variable `PATCHLANE_APP_CLIENT_ID`
- repository secret `PATCHLANE_APP_PRIVATE_KEY`

The App installation must grant Contents read/write and Workflows write. Enable Issues read/write when GitHub issue notifications are configured. Patchlane requests these permissions explicitly when creating each short-lived token, passes the token to checkout and `gh` as `GH_TOKEN`, and leaves the built-in `GITHUB_TOKEN` read-only.
The App installation must grant Contents read/write and Workflows write, plus Issues read/write when notifications are enabled. Generated jobs request the required least-privilege permissions explicitly, pass the token to checkout and `gh` as `GH_TOKEN`, and leave the built-in `GITHUB_TOKEN` read-only.

Adapted workflows may use another authentication source selected by the maintainer:

- an action step that exposes a token output;
- a `run` step that writes a token output to `GITHUB_OUTPUT`; or
- an Actions secret containing a suitable GitHub App or user token.

Adapted workflows may instead use a composite action that creates the App token and exposes it as `outputs.token`. Checkout and every `patchlane sync`, `promote`, or `notify` step in a job must consume the same `${{ steps.<id>.outputs.token }}` expression. No wrapper details belong in `.patchlane.yml`. Doctor validates this token flow but cannot inspect the wrapper's internal permission requests or credentials; use `verify-auth` for runtime validation. Generated workflows continue to use `actions/create-github-app-token` directly with the standard credentials and explicit least-privilege permissions.
For a step output, checkout must use an expression in the form `${{ steps.<id>.outputs.<name> }}`. For a stored token, it must use `${{ secrets.<name> }}`. Every `patchlane sync`, `promote`, or `notify` step in that job must receive the exact same expression as `GH_TOKEN`. Compound expressions, environment indirection, `github.token`, and `secrets.GITHUB_TOKEN` are not accepted. Authentication implementation details do not belong in `.patchlane.yml`.

A GitHub App or user token is required for pushes that must start another workflow. GitHub deliberately suppresses most workflow events caused by the built-in `GITHUB_TOKEN`; increasing its workflow permissions does not change that behavior. See [Manual setup](manual-setup.md) for App creation and repository configuration.
Doctor strictly checks credentials and requested permissions when `actions/create-github-app-token` is used directly. For other sources it validates only the token data flow because it cannot determine statically how the token is minted or which capabilities it has. Confirm custom authentication with the first workflow-driven published sync, including its downstream CI run and promotion. See [Manual setup](manual-setup.md) for the generated GitHub App setup.

## Commands

Expand All @@ -85,17 +93,7 @@ npx patchlane doctor
npx patchlane doctor --json
```

Doctor checks source resolution, remote patch refs, patch bases, composed workflow configuration and policy, CI triggers, App-token wiring, permissions, and bootstrap state without changing repository state. For GitHub origins it also attempts to inspect Actions enablement. When a job uses `actions/create-github-app-token` directly, Doctor additionally inspects the names—not values—of the expected repository variable and secret and strictly validates the action's credential and permission inputs. These direct-provider metadata checks are skipped for wrapper-only workflows. Insufficient metadata access is reported as a warning.

### Verify workflow authentication

After the generated workflows are present on the base branch, run:

```bash
npx patchlane verify-auth
```

This dispatches `sync-upstream.yml` with `no_push=true`, finds the newly created run, and waits for it to finish. A successful run validates the uploaded App key, installation, requested permissions, API access, authenticated checkout, and Patchlane rebuild without changing a branch. Use `--timeout <seconds>` and `--poll-interval <seconds>` to override the 60-second discovery timeout and 2-second polling interval. The equivalent environment variables are `PATCHLANE_AUTH_TIMEOUT_SECONDS` and `PATCHLANE_AUTH_POLL_INTERVAL_SECONDS`.
Doctor checks source resolution, remote patch refs, patch bases, composed workflow configuration and policy, CI triggers, authentication-token wiring, permissions, and bootstrap state without changing repository state. For GitHub origins it also attempts to inspect Actions enablement. When a job uses `actions/create-github-app-token` directly, Doctor additionally inspects the names—not values—of the expected repository variable and secret and strictly validates the action's credential and permission inputs. These standard credential metadata checks are skipped when all jobs use custom token sources. Insufficient metadata access is reported as a warning.

GitHub operations resolve the fork from the configured `origin` push URL, independently of `gh repo set-default`. Use `--origin-remote-name <name>` for a differently named push remote or `--repository <owner/repo>` to override repository detection.

Expand Down
12 changes: 3 additions & 9 deletions docs/manual-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ This walkthrough configures an existing GitHub fork. You need Node.js 22+, `git`

Already using an earlier Patchlane version? Follow the [migration guide](migrations.md) instead.

## 1. Configure GitHub App authentication
## 1. Configure the generated GitHub App authentication

Patchlane must push as a GitHub App so pushes to `sync/integration` and the promoted base branch trigger their configured workflows. GitHub suppresses most workflow events caused by the built-in `GITHUB_TOKEN`, so granting that token `contents: write` is not sufficient.
Patchlane's generated workflows push as a GitHub App so pushes to `sync/integration` and the promoted base branch trigger their configured workflows. GitHub suppresses most workflow events caused by the built-in `GITHUB_TOKEN`, so granting that token `contents: write` is not sufficient. Adapted workflows may use another token source that satisfies the contract in [Workflow authentication](configuration.md#workflow-authentication).

Create or reuse a GitHub App, install it on the fork, and grant these repository permissions:

Expand Down Expand Up @@ -125,13 +125,7 @@ Then publish, wait for CI, and promote the exact successful SHA:
npx patchlane bootstrap --wait
```

After this succeeds, run the post-bootstrap authentication check:

```bash
npx patchlane verify-auth
```

This dispatches the sync workflow with `no_push=true`, waits for it, and fails if the App credentials, installation, requested permissions, API access, checkout, or rebuild are invalid. It does not change any branches. After it succeeds, scheduled syncs and automatic promotions are active.
After bootstrap, scheduled syncs and automatic promotions are active. On the first workflow-driven sync that publishes a new integration SHA, confirm that authentication succeeds, CI runs as a `push` for that SHA, and promotion updates the base branch.

## Adding product patches

Expand Down
22 changes: 11 additions & 11 deletions docs/migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,29 @@ allowedWorkflows:

Use `allowedWorkflows: []` when the composed tree should contain only Patchlane's generated workflows. Add patches that delete unwanted upstream workflows rather than allowing them merely because they currently exist.

### 3. Configure GitHub App authentication
### 3. Choose workflow authentication

Create or reuse a GitHub App installed on the fork with Contents read/write and Workflows write. Add Issues read/write when issue notifications are enabled. Configure its credentials using the standard names:
Inspect the existing workflows and choose how the fork should authenticate before replacing or adapting them. The token must be able to push repository contents, update workflow files, and start downstream workflows. Enable issue access when GitHub issue notifications are configured. Do not use `github.token` or `secrets.GITHUB_TOKEN`: pushes made by the built-in `GITHUB_TOKEN` do not start the required downstream workflow runs.

The generated 0.5.1 workflows use `actions/create-github-app-token`. For this default, create or reuse a GitHub App installed on the fork with Contents read/write and Workflows write, plus Issues read/write when notifications are enabled. Configure its credentials using the standard names:

```bash
FORK=OWNER/REPOSITORY
gh variable set PATCHLANE_APP_CLIENT_ID --repo "$FORK" --body "YOUR_APP_CLIENT_ID"
gh secret set PATCHLANE_APP_PRIVATE_KEY --repo "$FORK" < /path/to/app-private-key.pem
```

Replace both generated workflow files with the 0.5 templates. Do not merely pass `github.token` as `GH_TOKEN`: that fixes API authentication, but pushes made by the built-in `GITHUB_TOKEN` do not start the required downstream workflow runs.
Alternatively, preserve an established authentication source or use another source selected by the maintainer. Patchlane accepts a token exposed by an action or `run` step as `${{ steps.<id>.outputs.<name> }}`, or a suitable App or user token stored as `${{ secrets.<name> }}`. Checkout and every Patchlane command in the job must use the exact same expression. Keep the selected source's existing inputs and secret names; do not request a client ID or duplicate private-key secret unless that source requires them.

Update both workflow files to the 0.5.1 structure without overwriting the selected authentication implementation. Doctor validates custom token wiring but cannot inspect how the token is created or which capabilities it has. Confirm the selected authentication with the first workflow-driven published sync, including the downstream CI run and promotion.

### 4. Validate before rollout

After pushing the updated patch refs, validate with Patchlane 0.5:

```bash
npx patchlane@0.5.0 doctor
npx patchlane@0.5.0 sync --dry-run
npx patchlane@0.5.1 doctor
npx patchlane@0.5.1 sync --dry-run
```

Doctor should identify every unexpected or missing workflow by filename. The dry run validates the actual output after all configured patches are replayed without changing the local or remote sync branch.
Expand All @@ -71,14 +75,10 @@ Doctor should identify every unexpected or missing workflow by filename. The dry
Update the pinned Patchlane version in the sync and promotion workflows as part of the same configuration patch. From that patch branch, use the new client for the first policy-enforced rebuild and promotion:

```bash
npx patchlane@0.5.0 bootstrap --wait
npx patchlane@0.5.1 bootstrap --wait
```

This validates the allowlist before publishing `sync/integration`, waits for CI on the exact published SHA, revalidates that SHA, and then promotes it. Confirm afterward that the generated base contains the intended workflow set and that scheduled syncs use the new Patchlane version. Then validate the uploaded App credentials with a no-push workflow run:

```bash
npx patchlane@0.5.0 verify-auth
```
This validates the allowlist before publishing `sync/integration`, waits for CI on the exact published SHA, revalidates that SHA, and then promotes it. Confirm afterward that the generated base contains the intended workflow set and that scheduled syncs use the new Patchlane version. On the first workflow-driven sync that publishes a new integration SHA, confirm that authentication succeeds, CI runs as a `push` for that SHA, and promotion updates the base branch.

### 6. Optionally enable maintainer notifications

Expand Down
6 changes: 0 additions & 6 deletions examples/sync-upstream.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
name: Sync Upstream Integration
run-name: ${{ inputs.verification_id && format('Verify Patchlane authentication ({0})', inputs.verification_id) || 'Sync Upstream Integration' }}

on:
schedule:
Expand All @@ -21,11 +20,6 @@ on:
type: string
required: false
default: ''
verification_id:
description: Correlate a Patchlane authentication check run.
type: string
required: false
default: ''

permissions:
contents: read
Expand Down
Loading