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)
This commit is contained in:
Ysopwnable authored and GitHub committed 2026-10-08 02:26:29 +08:00
1 parent 76e7e510bb
commit 6a278a68dd
4 files changed
+91 -49

No files matched your search

+4 -14
View File
@@ -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 '
+12 -7
View File
@@ -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
+12 -8
View File
@@ -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.
@@ -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();