From 18d7e0d2d74ba1b5f1325d11584bd5095a48fa2e Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2026 21:20:05 +0100 Subject: [PATCH] Recognise declared Pro server artifacts during issue intake The published native Pro archive and paid registry image currently become missing-version reports, unlike the Community server artifact. Accept those server naming shapes without mining unknown fields, link destinations, signatures or companion binaries. Exercise the actual silent label consumer and preserve Community-owned state and the live-read fence. Contract-Neutral: Silent issue version classification and registered regression controls only; no Pulse runtime, rendered product surface, subsystem contract, dependency, access or public-contact change. Change-source: pulse-maintainer --- .github/scripts/issue-version-triage.cjs | 8 +-- .github/scripts/issue-version-triage.test.cjs | 54 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/.github/scripts/issue-version-triage.cjs b/.github/scripts/issue-version-triage.cjs index 5b5397e045..c0af496d91 100644 --- a/.github/scripts/issue-version-triage.cjs +++ b/.github/scripts/issue-version-triage.cjs @@ -165,12 +165,12 @@ function normalizeLegacyVersionValue(value) { const visible = text.trim().replace(/^[`*_]+/, ""); // Failed-install forms explicitly accept an attempted server archive. Its // packaging suffix is not part of the release version. Recognise only the - // server archive names; companion binaries and signatures cannot establish - // the attempted server executable's version. + // Community and Pro server archive names; companion binaries and signatures + // cannot establish the attempted server executable's version. const filename = visible.match(/^pulse-[^\s`*_]+/i)?.[0]; if (filename && /\.(?:tar\.gz|tgz|zip|exe|sha256|sig|sshsig)(?:\.|$)/i.test(filename)) { const archive = filename.match( - /^pulse-v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\.(?:tar\.gz|tgz)$/i + /^pulse-(?:pro-)?v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\.(?:tar\.gz|tgz)$/i ); return archive ? normalizeVersion(archive[1].replace( /-linux-(?:386|amd64|arm64|armv6|armv7)$/i, "" @@ -178,7 +178,7 @@ function normalizeLegacyVersionValue(value) { } // Keep an explicitly shared server/agent version (as in #1788), without // mining a sentence such as "unknown; agent version 6.5.0" for a number. - return /^(?:v?\d+\.\d+\.\d+\b|(?:pulse|server(?:[ \t]*\+[ \t]*pulse-agent)?)[ \t]+v?\d+\.\d+\.\d+\b|(?:[a-z0-9._/-]+\/)?pulse:|pulse[-_])/i.test(visible) + return /^(?:v?\d+\.\d+\.\d+\b|(?:pulse|server(?:[ \t]*\+[ \t]*pulse-agent)?)[ \t]+v?\d+\.\d+\.\d+\b|(?:[a-z0-9._/-]+\/)?pulse(?:-pro)?:|pulse[-_])/i.test(visible) ? normalizeVersion(visible) : null; } diff --git a/.github/scripts/issue-version-triage.test.cjs b/.github/scripts/issue-version-triage.test.cjs index 0037a420f9..1c2e5f032b 100644 --- a/.github/scripts/issue-version-triage.test.cjs +++ b/.github/scripts/issue-version-triage.test.cjs @@ -1821,6 +1821,60 @@ test("non-server artifacts cannot supply an attempted server version", () => { } }); +test("Pro server artifacts retain their declared version without borrowing agent evidence", () => { + const { extractPulseVersion } = triage.internals; + for (const version of ["6.5.0", "6.6.0-beta.3", "6.6.0-rc.6"]) { + for (const artifact of [ + `pulse-pro-v${version}-linux-amd64.tar.gz`, + `pulse-pro-v${version}-linux-arm64.tar.gz`, + `license.pulserelay.pro/pulse-pro:${version}`, + ]) { + for (const value of [artifact, `**\`${artifact}\`**`, `[${artifact}](https://example.invalid/6.4.5)`]) { + for (const field of ["### Pulse version\n", "Pulse version: ", "- **Pulse version**: "]) { + for (const newline of ["\n", "\r\n"]) { + const body = `${field}${value}\n\n### Agent version\n6.4.5`.replaceAll("\n", newline); + assert.equal(extractPulseVersion("Upgrade from v6.4.5", body), version, body); + } + } + } + } + } + for (const value of [ + "pulse-pro-agent-v6.6.0-rc.6-linux-amd64.tar.gz", + "pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz.sshsig", + "pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz.sha256", + "pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz.sig", + "unknown; downloaded pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz", + "[unknown](https://example.invalid/pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz)", + ]) { + assert.equal(extractPulseVersion("Upgrade from v6.4.5", + `### Pulse version\n${value}\n### Agent version\n6.4.5`), null, value); + } +}); + +for (const value of [ + "pulse-pro-v6.6.0-rc.6-linux-amd64.tar.gz", + "pulse-pro-v6.6.0-rc.6-linux-arm64.tar.gz", + "license.pulserelay.pro/pulse-pro:6.6.0-rc.6", +]) { + test(`Pro server intake updates only silent version metadata: ${value}`, async () => { + const { github, calls } = createGithub(); + const issue = { number: 2923, title: "Failed install", labels: [ + "bug", "affects-6.4.5", "needs-version-info", "needs-human", "release-blocker", + "needs-decomposition", "needs-retest-on-latest", + ].map(name => ({ name })), + body: `### Pulse version\n${value}\n### Agent version\n6.4.5` }; + await syncLabels({ github, context: createContext({ issue }), core: createCore() }); + assert.deepEqual(calls.addLabels.map(call => call.labels), [["affects-6.6.0-rc.6"]]); + assert.deepEqual(calls.removeLabel.map(call => call.name), ["affects-6.4.5", "needs-version-info"]); + assert.deepEqual(calls.createLabel.map(call => call.name), ["affects-6.6.0-rc.6"]); + assert.deepEqual(calls.createComment, []); + assert.deepEqual(calls.getLatestRelease, []); + assert.deepEqual(calls.paginate, []); + assert.equal(calls.getIssue.length, 2); + }); +} + test("archive recognition neither borrows a later filename nor shortens bare prereleases", () => { const { extractPulseVersion } = triage.internals; assert.equal(extractPulseVersion("Upgrade from v6.4.5",