Skip to content

Commit 5344a4b

Browse files
authored
Forward native runner credentials and publication policy (#121)
1 parent 3a89775 commit 5344a4b

7 files changed

Lines changed: 94 additions & 24 deletions

.github/workflows/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Docs Agent Workflows
22

3-
`maintain-docs.yml` is the consumer-facing reusable workflow for scheduled upkeep. Consumer repositories pass product-level inputs such as `audience`, `base_ref`, `docs_branch`, `writable_paths`, `verification_commands`, `drift_checks`, `prompt`, and `run_agent`.
3+
`maintain-docs.yml` is the consumer-facing reusable workflow for scheduled upkeep. Consumer repositories pass product-level inputs such as `audience`, `base_ref`, `docs_branch`, `writable_paths`, `verification_commands`, `drift_checks`, `prompt`, `run_agent`, and `dry_run`.
44

55
The consumer workflow supports separate lanes for technical docs, user docs, and live skills maintenance. Use `audience: skills` with skills/package writable paths instead of broad docs paths.
66

@@ -10,7 +10,7 @@ When verification commands or drift checks are needed, pass them through the reu
1010

1111
The reusable workflow declares the expected typed review artifacts for Docs Agent runs: transcript, change summary, verification report, drift report, and workspace publication links. `maintain-docs.yml` writes those declarations into the portable recipe and exposes the declaration objects through `declared_artifacts_json`.
1212

13-
The target repository must pass `ACCESS_TOKEN` and `EXTERNAL_PACKAGE_SOURCE_POLICY`. `ACCESS_TOKEN` authorizes target-repository publication. The policy is a separate v1 JSON secret that authorizes only the selected public standalone Docs Agent package; it is forwarded to WP Codebox as a secret and never serialized into the task descriptor. Same-organization callers can use `secrets: inherit` with both secrets; cross-organization callers map each secret explicitly.
13+
The target repository grants `contents: write`, `pull-requests: write`, and `issues: write`. Docs Agent forwards the caller-scoped `${{ github.token }}` to WP Codebox for same-repository publication, so consumers do not configure `ACCESS_TOKEN`. `OPENAI_API_KEY` is an optional workflow secret and is required only for a live OpenAI run; skipped and dry-run calls do not require it. `EXTERNAL_PACKAGE_SOURCE_POLICY` remains a separate required v1 JSON secret that authorizes only the selected public standalone Docs Agent package. Both secrets are forwarded to WP Codebox without serialization into the task descriptor.
1414

1515
## Docs Agent Runner Recipe
1616

.github/workflows/maintain-docs.yml

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ name: Maintain Docs
3939
description: Run the prepared Docs Agent task through the generic Codebox agent-task workflow.
4040
type: boolean
4141
default: true
42+
dry_run:
43+
description: Validate the prepared Docs Agent task without starting a live agent run.
44+
type: boolean
45+
default: false
4246
secrets:
43-
ACCESS_TOKEN:
44-
description: GitHub token authorized to read, push, and open pull requests in the calling repository.
45-
required: true
47+
OPENAI_API_KEY:
48+
description: Optional OpenAI credential used for live Docs Agent runs.
49+
required: false
4650
EXTERNAL_PACKAGE_SOURCE_POLICY:
4751
description: Version 1 JSON policy authorizing Docs Agent standalone native packages.
4852
required: true
@@ -65,6 +69,9 @@ name: Maintain Docs
6569
credential_mode:
6670
description: Normalized native runner credential mode.
6771
value: ${{ jobs.run-agent.outputs.credential_mode }}
72+
success_requires_pr:
73+
description: Whether the selected lane requires a published pull request for success.
74+
value: ${{ jobs.prepare.outputs.success_requires_pr }}
6875

6976
jobs:
7077
prepare:
@@ -81,6 +88,7 @@ jobs:
8188
runner_workspace: ${{ steps.config.outputs.runner_workspace }}
8289
expected_artifacts: ${{ steps.config.outputs.expected_artifacts }}
8390
output_projections: ${{ steps.config.outputs.output_projections }}
91+
success_requires_pr: ${{ steps.config.outputs.success_requires_pr }}
8492
steps:
8593
- name: Resolve Docs Agent settings
8694
id: config
@@ -91,6 +99,9 @@ jobs:
9199
INPUT_DRIFT_CHECKS: ${{ inputs.drift_checks }}
92100
INPUT_PROMPT: ${{ inputs.prompt }}
93101
INPUT_WRITABLE_PATHS: ${{ inputs.writable_paths }}
102+
RUN_AGENT: ${{ inputs.run_agent }}
103+
DRY_RUN: ${{ inputs.dry_run }}
104+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
94105
DOCS_AGENT_REVISION: ${{ github.job_workflow_sha }}
95106
INPUT_DOCS_BRANCH: ${{ inputs.docs_branch }}
96107
INPUT_BASE_REF: ${{ inputs.base_ref }}
@@ -105,30 +116,35 @@ jobs:
105116
package_path="bundles/technical-docs-agent/native/technical-docs-bootstrap-agent.agent.json"
106117
agent_slug="technical-docs-bootstrap-agent"
107118
package_digest="sha256-bytes-v1:9050c9b4364a5a91b057fd51ff5f667efc320f9d6776160ab3e7cf4fd5e4f0e6"
119+
success_requires_pr=true
108120
default_prompt="Bootstrap source-grounded developer documentation that helps developers understand, use, and extend the code in the repository."
109121
;;
110122
technical:maintenance)
111123
package_path="bundles/technical-docs-agent/native/technical-docs-maintenance-agent.agent.json"
112124
agent_slug="technical-docs-maintenance-agent"
113125
package_digest="sha256-bytes-v1:6057aad4eb7c5f0320ccfbce9da93a5fa1d3fc521478b5571ed81c28129325aa"
126+
success_requires_pr=false
114127
default_prompt="Maintain source-grounded developer documentation that helps developers understand, use, and extend the code in the repository."
115128
;;
116129
user:bootstrap)
117130
package_path="bundles/user-docs-agent/native/user-docs-bootstrap-agent.agent.json"
118131
agent_slug="user-docs-bootstrap-agent"
119132
package_digest="sha256-bytes-v1:ee558a73f2a393c1912d62f7f40dbdd4bc31ac0168c3c248316b3430258c55cd"
133+
success_requires_pr=true
120134
default_prompt="Bootstrap source-grounded product documentation for onboarding, setup, common tasks, expected outcomes, permissions, compatibility, troubleshooting, and FAQs."
121135
;;
122136
user:maintenance)
123137
package_path="bundles/user-docs-agent/native/user-docs-maintenance-agent.agent.json"
124138
agent_slug="user-docs-maintenance-agent"
125139
package_digest="sha256-bytes-v1:e2248f014c1409a8d4c5cb303ea37c0b24ae05babd02d40c6032160daf60d4c4"
140+
success_requires_pr=false
126141
default_prompt="Maintain source-grounded product documentation for onboarding, setup, common tasks, expected outcomes, permissions, compatibility, troubleshooting, and FAQs."
127142
;;
128143
skills:maintenance)
129144
package_path="bundles/skills-agent/native/skills-maintenance-agent.agent.json"
130145
agent_slug="skills-maintenance-agent"
131146
package_digest="sha256-bytes-v1:c643f8bd31864cdd607f9025a000694a65a3fdf91532e4311fbac541e708a2b2"
147+
success_requires_pr=false
132148
default_prompt="Maintain live agent skill instructions and generated packaged skill outputs."
133149
;;
134150
*)
@@ -137,6 +153,11 @@ jobs:
137153
;;
138154
esac
139155
156+
if [ "$RUN_AGENT" = true ] && [ "$DRY_RUN" != true ] && [ -z "$OPENAI_API_KEY" ]; then
157+
printf 'OPENAI_API_KEY is required when run_agent=true for the openai provider. Set run_agent=false or dry_run=true for an explicit non-live path.\n' >&2
158+
exit 1
159+
fi
160+
140161
verification_commands="$(printf '%s' "$INPUT_VERIFICATION_COMMANDS" | jq -c 'if type == "array" then . else error("verification_commands must be an array") end')"
141162
drift_checks="$(printf '%s' "$INPUT_DRIFT_CHECKS" | jq -c 'if type == "array" then . else error("drift_checks must be an array") end')"
142163
if ! printf '%s' "$DOCS_AGENT_REVISION" | grep -Eq '^[0-9a-fA-F]{40}$'; then
@@ -176,10 +197,11 @@ jobs:
176197
--arg writablePaths "$INPUT_WRITABLE_PATHS" \
177198
--arg baseRef "$INPUT_BASE_REF" \
178199
--arg docsBranch "$INPUT_DOCS_BRANCH" \
200+
--argjson successRequiresPr "$success_requires_pr" \
179201
--argjson verificationCommands "$verification_commands" \
180202
--argjson driftChecks "$drift_checks" \
181203
--argjson artifactDeclarations "$artifact_declarations" \
182-
'{schema:"docs-agent/runner-recipe/v1",targetRepository:$targetRepository,prompt:$prompt,docsAgent:{externalPackageSource:{repository:$repository,revision:$revision,path:$packagePath,digest:$packageDigest},agentSlug:$agentSlug},runner:{verificationCommands:$verificationCommands,driftChecks:$driftChecks,writablePaths:$writablePaths,baseRef:$baseRef,docsBranch:$docsBranch},artifacts:{expected:($artifactDeclarations|map(.name)),declarations:$artifactDeclarations}}')"
204+
'{schema:"docs-agent/runner-recipe/v1",targetRepository:$targetRepository,prompt:$prompt,docsAgent:{externalPackageSource:{repository:$repository,revision:$revision,path:$packagePath,digest:$packageDigest},agentSlug:$agentSlug},runner:{verificationCommands:$verificationCommands,driftChecks:$driftChecks,writablePaths:$writablePaths,baseRef:$baseRef,docsBranch:$docsBranch,successRequiresPr:$successRequiresPr},artifacts:{expected:($artifactDeclarations|map(.name)),declarations:$artifactDeclarations}}')"
183205
external_package_source="$(jq -cn --arg repository "Automattic/docs-agent" --arg revision "$DOCS_AGENT_REVISION" --arg path "$package_path" --arg digest "$package_digest" '{repository:$repository,revision:$revision,path:$path,digest:$digest}')"
184206
185207
runner_workspace="$(jq -cn \
@@ -200,11 +222,16 @@ jobs:
200222
printf 'runner_workspace<<EOF\n%s\nEOF\n' "$runner_workspace"
201223
printf 'expected_artifacts<<EOF\n%s\nEOF\n' "$expected_artifacts"
202224
printf 'output_projections<<EOF\n%s\nEOF\n' "$output_projections"
225+
printf 'success_requires_pr=%s\n' "$success_requires_pr"
203226
} >> "$GITHUB_OUTPUT"
204227
205228
run-agent:
206229
name: Run Docs Agent
207230
needs: prepare
231+
permissions:
232+
contents: write
233+
pull-requests: write
234+
issues: write
208235
uses: Automattic/wp-codebox/.github/workflows/run-agent-task.yml@54c2f9a7bc3cd1fe20055d496c83efcfb99afb41
209236
with:
210237
external_package_source: ${{ needs.prepare.outputs.external_package_source }}
@@ -217,7 +244,7 @@ jobs:
217244
runner_workspace: ${{ needs.prepare.outputs.runner_workspace }}
218245
verification_commands: ${{ needs.prepare.outputs.verification_commands }}
219246
drift_checks: ${{ needs.prepare.outputs.drift_checks }}
220-
success_requires_pr: false
247+
success_requires_pr: ${{ needs.prepare.outputs.success_requires_pr == 'true' }}
221248
access_token_repos: ${{ github.repository }}
222249
require_access_token: true
223250
allowed_repos: '["${{ github.repository }}"]'
@@ -226,6 +253,8 @@ jobs:
226253
output_projections: ${{ needs.prepare.outputs.output_projections }}
227254
callback_data: ${{ needs.prepare.outputs.recipe_json }}
228255
run_agent: ${{ inputs.run_agent }}
256+
dry_run: ${{ inputs.dry_run }}
229257
secrets:
230-
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
258+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
259+
ACCESS_TOKEN: ${{ github.token }}
231260
EXTERNAL_PACKAGE_SOURCE_POLICY: ${{ secrets.EXTERNAL_PACKAGE_SOURCE_POLICY }}

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ jobs:
3838
docs_branch: docs-agent/my-repo-docs
3939
writable_paths: README.md,docs/**
4040
secrets:
41-
ACCESS_TOKEN: ${{ secrets.DOCS_AGENT_ACCESS_TOKEN }}
41+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
4242
EXTERNAL_PACKAGE_SOURCE_POLICY: ${{ secrets.DOCS_AGENT_EXTERNAL_PACKAGE_SOURCE_POLICY }}
4343
```
4444
45-
`ACCESS_TOKEN` is required because the native runner checks out the target repository and may publish the Docs Agent branch and pull request. Docs Agent sets the target to the calling repository, so its normal consumer run is same-repository and the token must write that repository. Configure `DOCS_AGENT_ACCESS_TOKEN` with that access. `EXTERNAL_PACKAGE_SOURCE_POLICY` is a separate required secret: WP Codebox uses it only to authorize fetching the standalone Docs Agent package selected by the lane. A same-organization caller may instead use `secrets: inherit` when it defines both secrets. For a cross-organization call, map each secret explicitly as shown above.
45+
Docs Agent targets the calling repository and forwards its scoped `${{ github.token }}` to WP Codebox for checkout and publication. The consumer must grant `contents: write`, `pull-requests: write`, and `issues: write`; no `ACCESS_TOKEN` secret is required for this same-repository contract. `OPENAI_API_KEY` is optional in the reusable workflow schema but required for a live `run_agent: true` OpenAI run. `EXTERNAL_PACKAGE_SOURCE_POLICY` is a separate required secret: WP Codebox uses it only to authorize fetching the standalone Docs Agent package selected by the lane. Map both secrets explicitly, including for cross-organization calls.
4646

4747
Configure `DOCS_AGENT_EXTERNAL_PACKAGE_SOURCE_POLICY` with this exact v1 JSON value:
4848

4949
```json
5050
{"version":1,"repositories":{"automattic/docs-agent":["bundles/technical-docs-agent/native/technical-docs-bootstrap-agent.agent.json","bundles/technical-docs-agent/native/technical-docs-maintenance-agent.agent.json","bundles/user-docs-agent/native/user-docs-bootstrap-agent.agent.json","bundles/user-docs-agent/native/user-docs-maintenance-agent.agent.json","bundles/skills-agent/native/skills-maintenance-agent.agent.json"]}}
5151
```
5252

53-
The policy authorizes only public `Automattic/docs-agent` package bytes. It does not grant target-repository publication access; keep `ACCESS_TOKEN` separate.
53+
The policy authorizes only public `Automattic/docs-agent` package bytes. It does not grant target-repository publication access.
5454

5555
For repositories that run their own preflight detection, pass `run_agent: false` when no docs work is needed. The workflow records a deterministic skipped run instead of booting the agent runtime.
5656

@@ -74,7 +74,7 @@ jobs:
7474
writable_paths: README.md,docs/**
7575
run_agent: ${{ needs.detect.outputs.should_run == 'true' }}
7676
secrets:
77-
ACCESS_TOKEN: ${{ secrets.DOCS_AGENT_ACCESS_TOKEN }}
77+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
7878
EXTERNAL_PACKAGE_SOURCE_POLICY: ${{ secrets.DOCS_AGENT_EXTERNAL_PACKAGE_SOURCE_POLICY }}
7979
```
8080

@@ -85,13 +85,15 @@ The consumer API is product-level. Consumer repositories configure the documenta
8585
| Input | Default | Description |
8686
| --- | --- | --- |
8787
| `audience` | `technical` | `technical` for developer/operator docs, `user` for non-technical product docs, or `skills` for live skill upkeep. |
88+
| `run_kind` | `maintenance` | `bootstrap` establishes initial documentation and requires publication; `maintenance` permits a no-change result. |
8889
| `base_ref` | `main` | Base branch or ref for the maintenance PR. |
8990
| `docs_branch` | `docs-agent/docs-upkeep` | Stable branch reused for the canonical Docs Agent PR. |
9091
| `writable_paths` | `README.md,docs/**` | Comma-separated allowlist of paths Docs Agent may edit. |
9192
| `verification_commands` | `[]` | JSON array of canonical runner verification commands executed in the target workspace. |
9293
| `drift_checks` | `[]` | JSON array of canonical runner drift checks executed after verification. |
9394
| `prompt` | empty | Optional additional maintenance instruction. |
9495
| `run_agent` | `true` | Set `false` to skip after deterministic preflight says docs are current. |
96+
| `dry_run` | `false` | Set `true` to validate the prepared task without starting a live agent run. |
9597

9698
`verification_commands` and `drift_checks` are executable runner inputs. Docs Agent keeps the target repository as the only writable PR boundary; the reusable runner executes the selected native agent task.
9799

@@ -120,7 +122,7 @@ Docs Agent opens or updates one canonical PR for the configured branch.
120122
- If the selected surface is current, the run succeeds with no changes.
121123
- If maintenance is needed, changes are written only under `writable_paths`.
122124
- If the canonical PR is already open, later runs reuse the same `docs_branch` and PR instead of creating duplicates.
123-
- `job_status`, `transcript_summary`, `credential_mode`, and bounded `projected_outputs_json` are exposed as reusable workflow outputs. A `run_agent: false` call returns `job_status: skipped`; it still requires the documented `ACCESS_TOKEN` mapping because the reusable workflow contract requires that secret. `projected_outputs_json` includes the runner publication URL when one exists; typed artifact declarations are exposed as `declared_artifacts_json` for review/debugging. Raw engine data is retained in runner artifacts rather than exposed as a workflow output.
125+
- `job_status`, `transcript_summary`, `credential_mode`, `success_requires_pr`, and bounded `projected_outputs_json` are exposed as reusable workflow outputs. A `run_agent: false` call returns `job_status: skipped`; a `dry_run: true` call validates without starting a model run. `OPENAI_API_KEY` is only required for a live OpenAI run and is never included in recipes, workflow outputs, or artifacts. Bootstrap lanes require a published pull request for success and expose its URL through `projected_outputs_json`; maintenance lanes allow a no-change result. Typed artifact declarations are exposed as `declared_artifacts_json` for review/debugging. Raw engine data is retained in runner artifacts rather than exposed as a workflow output.
124126

125127
## Quality Bar
126128

@@ -213,6 +215,9 @@ For skills PRs, also confirm the live instructions match current upstream tool b
213215
php tests/validate-docs-agent-bundle.php
214216
php tests/validate-external-native-package-sources.php
215217
php tests/repair-docs-links-smoke.php
218+
WP_CODEBOX_DIR=/path/to/wp-codebox php tests/validate-wp-codebox-run-agent-task-contract.php
219+
actionlint -config-file .github/actionlint.yaml .github/workflows/*.yml
220+
git diff --check
216221
```
217222

218223
The native import test uses the maintained Agents API pure-PHP smoke harness; clone `Automattic/agents-api` and run:

examples/consumer-workflow.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ jobs:
3030
writable_paths: README.md,docs/**
3131
prompt: ${{ github.event_name == 'workflow_dispatch' && inputs.prompt || '' }}
3232
run_agent: ${{ github.event_name != 'workflow_dispatch' || inputs.run_agent }}
33-
secrets: inherit
33+
secrets:
34+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
35+
EXTERNAL_PACKAGE_SOURCE_POLICY: ${{ secrets.DOCS_AGENT_EXTERNAL_PACKAGE_SOURCE_POLICY }}

0 commit comments

Comments
 (0)