mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
5f00cb9771
## Summary Ports [ag-ui-protocol/ag-ui#1914](https://github.com/ag-ui-protocol/ag-ui/pull/1914) to CopilotKit — plus the two supporting guard files ag-ui already had: - **`.github/workflows/canary.yml`** — discoverable **`canary / publish`** `workflow_dispatch` orchestrator. Any maintainer can publish a prerelease of the branch they're on straight from the Actions tab. It is a thin orchestrator — it does **not** publish to npm itself: 1. Guards against `main` and non-branch refs. 2. Mints the devops-bot App token (app-id `1108748`, `DEVOPS_BOT_PRIVATE_KEY`) with scoped `contents:write` + `actions:write`. 3. Mirrors the dispatched ref to a unique `canary/<slug>-<run_id>-<attempt>` branch via the GitHub API (no checkout). 4. Dispatches **`publish-release.yml --ref canary/<slug> -f mode=prerelease …`**, locates the run, and waits (`gh run watch --exit-status` + explicit conclusion check). 5. Deletes the canary ref — status-gated (never yanks the ref under a still-running delegated run) with a fresh cleanup token (90-min job ceiling exceeds the 1h App-token TTL). - **`scripts/release/verify-release-scope-dropdowns.sh`** — drift guard: the hand-maintained `scope` dropdowns in `publish-release.yml` / `stable-release.yml` / `canary.yml` must exactly match `release.config.json`'s `.scopes` keys. Parsers fail loud and distinct on structural changes instead of silently passing. - **`.github/workflows/lint-release-workflows.yml`** — actionlint + shellcheck + the dropdown-sync job over the release pipelines. ### Why a separate orchestrator (and not a flag in publish-release.yml) - A GitHub Environment's deployment-branch policy is evaluated against the ref a run is **triggered on** — not branches created mid-run. The orchestrator exists to get the publish run *onto* a `canary/*` ref. - `publish-release.yml` holds the **single npm OIDC trusted-publisher binding**; a second publishing entry point would break OIDC for every `@copilotkit/*` package. The orchestrator never touches npm. - The cross-workflow dispatch uses the **App token, not `GITHUB_TOKEN`** — `GITHUB_TOKEN`-authenticated events never start new workflow runs. **Note:** the `npm` environment currently has *no* deployment-branch policy, so the orchestrator is a convenience wrapper today. Tightening the policy to `main` + `canary/*` + `release/publish/*` (matching ag-ui's security posture) is being applied as repo configuration alongside this PR — requires admin. This PR includes the prerequisite: `publish-commit.yml` (pkg-pr-new) is removed from the `npm` environment, since it runs on every PR and would be blocked by the policy (it publishes to pkg.pr.new, not npm, and uses no environment secrets). ## Testing done - Drift guard: positive run against all three real workflows; negative tests (scope removed → drift FAIL with diff; bogus scope → FAIL; `case "${SCOPE}"` quoting refactor → loud parser-degradation FAIL; whole case block deleted → loud zero-block FAIL; quoted arm `"angular")` → accepted; blank/comment lines inside `options:` → still parsed; prose comments mentioning case/SCOPE/in → no false positive). - `shellcheck` clean at all severities; `bash -n` on every workflow `run:` block; YAML parses. - 3 rounds of 7-agent code review converged to zero load-bearing findings. ## ⚠️ Still to verify before first real use - [ ] devops-bot App (id 1108748) has **Actions: write** — required for the in-workflow `gh workflow run`. Safe first test: dispatch once with `dry_run=true`. - [ ] First `dry_run=false` run clears the `npm` environment end-to-end via the App token once the deployment-branch policy is tightened. 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Post-merge follow-ups (maintainer action required) These need repo **admin** rights and must happen **in this order**: 1. **Merge this PR first.** `main`'s current `publish-commit.yml` (pkg-pr-new) still sits in the `npm` environment and runs on every PR touching `packages/**` — applying the branch policy before this PR lands would block every snapshot publish. This PR removes that environment association. 2. **Tighten the `npm` environment's deployment-branch policy** to `main` + `canary/*` + `release/publish/*` (matching ag-ui). With an admin-scoped token: ```bash gh api --method PUT repos/CopilotKit/CopilotKit/environments/npm \ -F "deployment_branch_policy[protected_branches]=false" \ -F "deployment_branch_policy[custom_branch_policies]=true" gh api --method POST repos/CopilotKit/CopilotKit/environments/npm/deployment-branch-policies -f name="main" -f type=branch gh api --method POST repos/CopilotKit/CopilotKit/environments/npm/deployment-branch-policies -f name="canary/*" -f type=branch gh api --method POST repos/CopilotKit/CopilotKit/environments/npm/deployment-branch-policies -f name="release/publish/*" -f type=branch ``` Or via UI: Settings → Environments → npm → Deployment branches and tags → "Selected branches and tags" → add the three patterns above. Why these three: `main` covers stable `workflow_dispatch` retries and `stable-release.yml`; `release/publish/*` covers the merged-release-PR runs (the run's head branch is the release PR branch); `canary/*` covers the orchestrator's delegated prerelease runs. After this, direct `mode=prerelease` dispatches from arbitrary feature branches stop working — the `canary / publish` orchestrator becomes the one-click path (by design). 3. **Verify the devops-bot App (id `1108748`) has `Actions: write`** (org/App settings). The orchestrator's `gh workflow run` dispatch 403s without it. Safe end-to-end test, after step 2: Actions tab → **canary / publish** → pick any feature branch, any scope, **`dry_run=true`** → confirm the delegated `release / publish` run is created, watched, and the `canary/*` ref is deleted afterward. 4. **First real canary** (`dry_run=false`) confirms the npm OIDC publish clears the environment gate end-to-end on a `canary/*` ref.