From 6a278a68dd4fa69b9153697ecb7bba7de4c55c32 Mon Sep 17 00:00:00 2001 From: Ysopwnable <161784452+N0zoM1z0@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:26:29 +0800 Subject: [PATCH] fix(release): support default credentials and record 5.0.0 boundary (#1012) fix(release): support built-in credentials and refresh release boundary GitHub now creates approval-required PR workflows for GITHUB_TOKEN-authored opened/synchronize/reopened events. Restore optional custom credentials and cover prepare/publish without a separate secret. Record the verified 5.0.0 checkpoint, public 133-tool catalog and package update in the installation guide. Assisted-by: Sakuya (gensokyo-skills:sakuya-checkpointed-execution) --- .github/workflows/release.yml | 18 +--- docs/installation.md | 19 +++-- docs/releasing.md | 20 +++-- .../filesystem/releaseWorkflow.test.ts | 83 ++++++++++++++----- 4 files changed, 91 insertions(+), 49 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6be8836ab0..b1f0f00334 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,16 +32,6 @@ jobs: release_created: ${{ steps.release.outputs.release_created }} sha: ${{ steps.release.outputs.sha }} steps: - - name: Require a CI-capable release token - shell: bash - env: - RELEASE_PLEASE_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} - run: | - if [[ -z "${RELEASE_PLEASE_TOKEN}" ]]; then - echo "RELEASE_PLEASE_TOKEN is required. Pull requests and catalog commits created with GITHUB_TOKEN do not start workflow runs, so the normalized release head would have no CI result to approve." >&2 - exit 1 - fi - - name: Validate release selection shell: bash env: @@ -97,9 +87,9 @@ jobs: - uses: googleapis/release-please-action@v4 id: release with: - # A dedicated credential lets release-PR updates trigger CI. - # GITHUB_TOKEN-authored pull requests do not start workflow runs. - token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + # A dedicated credential starts PR CI automatically; the built-in + # token creates approval-required PR runs for maintainers to approve. + token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }} target-branch: ${{ inputs.release_branch }} skip-github-release: ${{ inputs.phase == 'prepare' }} skip-github-pull-request: ${{ inputs.phase == 'publish' }} @@ -148,7 +138,7 @@ jobs: shell: bash env: # Use the same identity for the follow-up commit so it also triggers CI. - GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} + GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }} RELEASE_PR_JSON: ${{ steps.release.outputs.pr }} run: | release_pr_branch="$(node --input-type=module -e ' diff --git a/docs/installation.md b/docs/installation.md index fcbed20a3a..86f008d110 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -68,13 +68,18 @@ selects the npm release, and persistent MCP registrations are pinned to the version that performed setup. Installing newer instructions does not update a running server or its registration. -The release checked on **2026-10-06** was **4.1.0** (125 MCP tools). That artifact -includes main's Windows native control bundle, Android/JADX and firmware -tools, Ghidra function annotation workflow, and retained application-Evidence -references. -Main's catalog describes the current code; a source build or a subsequent -release containing later changes is required for anything newer. Package startup alone does not verify a -provider's real platform workflow. +The release checked on **2026-10-07** was **5.0.0** (133 MCP tools), published +from the fixed checkpoint +[`b33236ec`](https://github.com/morluto/rea/releases/tag/rea-agents-5.0.0). +The public CLI, MCP catalog and target-free session, and isolated update from +4.1.0 to 5.0.0 were verified through npm. The artifact includes Windows native +controls, Android/JADX and firmware tools, Ghidra function annotations, and +retained application-Evidence references. + +Main's catalog describes the current code. A source build or a subsequent +release containing changes after this checkpoint is required for newer +functionality. Package startup alone does not verify a provider's real +platform workflow. To check the published version, run `npm view rea-agents dist-tags.latest`. Use the connected server's actual tool list and advertised input schemas for diff --git a/docs/releasing.md b/docs/releasing.md index 2a28ee39a3..b42189f458 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -35,14 +35,18 @@ gh workflow run release.yml --ref main \ ``` Release Please targets that branch and prepares its version, changelog, and -registry metadata. Preparation requires the `RELEASE_PLEASE_TOKEN` repository -secret. That credential opens the release pull request and pushes the catalog -normalization commit, so both start CI on the exact normalized head. The -default `GITHUB_TOKEN` cannot do that: events it authors do not start -workflow runs, and there is then no blocked run to approve. The existing -generation step normalizes the product catalog. Preparation cannot create a -GitHub release or publish a package. Record the final bot PR head after -normalization and wait for that head's CI. +registry metadata. The workflow uses an optional `RELEASE_PLEASE_TOKEN` +repository secret and otherwise uses the built-in `GITHUB_TOKEN`. A dedicated +GitHub App or personal access token can start PR CI automatically. With the +built-in token, `opened`, `synchronize`, and `reopened` PR events create runs +that require a maintainer with write access to approve them. See +[GitHub's workflow trigger documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow). + +The generation step normalizes the product catalog. Preparation cannot create +a GitHub release or publish a package. Record the final bot PR head after +normalization, then approve that head's blocked runs from the PR page. Updates +to the bot branch can create new approval-required runs; approval of an older +head does not verify the normalized candidate. Wait for the final head's CI. Review the candidate's version, notes, generated metadata, and package contents. Wait for the candidate's CI and relevant real-provider checks. diff --git a/tests/boundary/filesystem/releaseWorkflow.test.ts b/tests/boundary/filesystem/releaseWorkflow.test.ts index 905b0541cf..dcacdde579 100644 --- a/tests/boundary/filesystem/releaseWorkflow.test.ts +++ b/tests/boundary/filesystem/releaseWorkflow.test.ts @@ -1,10 +1,13 @@ import { execFile } from "node:child_process"; -import { readFile } from "node:fs/promises"; +import { readFile, writeFile } from "node:fs/promises"; +import { delimiter, join } from "node:path"; import { promisify } from "node:util"; import { expect, it } from "vitest"; import { parse } from "yaml"; import { z } from "zod"; +import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; + const execFileAsync = promisify(execFile); const stepSchema = z.object({ name: z.string().optional(), @@ -58,7 +61,7 @@ it("requires explicit release preparation or publication instead of main pushes" step.uses?.startsWith("googleapis/release-please-action@"), ); expect(release?.with).toMatchObject({ - token: "${{ secrets.RELEASE_PLEASE_TOKEN }}", + token: "${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}", "target-branch": "${{ inputs.release_branch }}", "skip-github-release": "${{ inputs.phase == 'prepare' }}", "skip-github-pull-request": "${{ inputs.phase == 'publish' }}", @@ -67,28 +70,68 @@ it("requires explicit release preparation or publication instead of main pushes" (step) => step.name === "Commit canonical release catalog", ); expect(catalogCommit?.env?.GH_TOKEN).toBe( - "${{ secrets.RELEASE_PLEASE_TOKEN }}", + "${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}", ); }); -it("stops preparation when the CI-capable release token is missing", async () => { - const workflow = await readReleaseWorkflow(); - const command = z - .string() - .parse( - workflow.jobs["release-please"].steps.find( - (step) => step.name === "Require a CI-capable release token", - )?.run, +it.skipIf(process.platform === "win32").each([ + { phase: "prepare", customToken: "" }, + { phase: "publish", customToken: "" }, + { phase: "prepare", customToken: "fixture-custom-token" }, + { phase: "publish", customToken: "fixture-custom-token" }, +])( + "accepts $phase with optional custom credentials: $customToken", + async ({ phase, customToken }) => { + const workflow = await readReleaseWorkflow(); + const steps = workflow.jobs["release-please"].steps; + const actionIndex = steps.findIndex((step) => + step.uses?.startsWith("googleapis/release-please-action@"), ); - await expect( - execFileAsync("bash", ["-e", "-o", "pipefail", "-c", command], { - env: { ...process.env, RELEASE_PLEASE_TOKEN: "" }, - }), - ).rejects.toMatchObject({ - code: 1, - stderr: expect.stringMatching(/RELEASE_PLEASE_TOKEN/u), - }); -}); + expect(actionIndex).toBeGreaterThanOrEqual(0); + const commands = steps + .slice(0, actionIndex) + .filter( + (step) => + step.if === undefined || + (phase === "publish" && step.if === "inputs.phase == 'publish'"), + ) + .map((step) => z.string().parse(step.run)); + const directory = await createTestTempDirectory("rea-release-credential-"); + const output = join(directory, "github-output"); + await writeFile( + join(directory, "gh"), + '#!/bin/sh\nprintf "%s\\n" "$GITHUB_SHA"\n', + { mode: 0o755 }, + ); + await expect( + execFileAsync( + "bash", + ["-e", "-o", "pipefail", "-c", commands.join("\n")], + { + env: { + ...process.env, + PATH: `${directory}${delimiter}${process.env.PATH ?? ""}`, + RELEASE_PLEASE_TOKEN: customToken, + GH_TOKEN: customToken || "fixture-built-in-token", + RELEASE_PHASE: phase, + RELEASE_BRANCH: "release/5.0.0", + GITHUB_REF: + phase === "prepare" + ? "refs/heads/main" + : "refs/heads/release/5.0.0", + GITHUB_REPOSITORY: "fixture/fixture", + GITHUB_SHA: "1111111111111111111111111111111111111111", + BRANCH_SHA: "1111111111111111111111111111111111111111", + GITHUB_OUTPUT: output, + }, + }, + ), + ).resolves.toMatchObject({ stderr: "" }); + expect(await readFile(output, "utf8")).toBe( + "sha=1111111111111111111111111111111111111111\n", + ); + }, +); it("binds npm and MCP publication to the same immutable release SHA", async () => { const workflow = await readReleaseWorkflow();