diff --git a/src/services/remediation-plan.ts b/src/services/remediation-plan.ts index f5246b403c..f8d14d4333 100644 --- a/src/services/remediation-plan.ts +++ b/src/services/remediation-plan.ts @@ -34,8 +34,11 @@ export type RemediationPlanInput = { }>; }; -const FORBIDDEN_PATTERN = - /\b(reward\w*|wallet|hotkey|coldkey|mnemonic|farming|payout|ranking|raw[-_\s]?trust|trust[-_\s]?score|private[-_\s]?reviewability|reviewability|private[-_\s]?scoreability|scoreability|score\w*|token[-_\s]?gate|token[-_\s]?score|base[-_\s]?score|multiplier|eligibility)\b|\/Users\/|\/home\/|\/tmp\/|[A-Z]:[\\/]Users[\\/]/i; +// #8886: exported so its forbidden-term coverage (specifically the plural `rankings`, unreachable through the +// public builder because sanitizePublicComment rewrites the term before this secondary gate ever sees it) can +// be asserted directly, matching how the issue itself verified the gap. +export const FORBIDDEN_PATTERN = + /\b(reward\w*|wallet|hotkey|coldkey|mnemonic|farming|payout|rankings?|raw[-_\s]?trust|trust[-_\s]?score|private[-_\s]?reviewability|reviewability|private[-_\s]?scoreability|scoreability|score\w*|token[-_\s]?gate|token[-_\s]?score|base[-_\s]?score|multiplier|eligibility)\b|\/Users\/|\/home\/|\/tmp\/|[A-Z]:[\\/]Users[\\/]/i; const SOURCE_PRIORITY: Record = { account_state: 0, diff --git a/test/unit/remediation-plan.test.ts b/test/unit/remediation-plan.test.ts index 60a253301b..df22a0ffa5 100644 --- a/test/unit/remediation-plan.test.ts +++ b/test/unit/remediation-plan.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { buildRemediationPlan } from "../../src/services/remediation-plan"; +import { buildRemediationPlan, FORBIDDEN_PATTERN } from "../../src/services/remediation-plan"; const FORBIDDEN = /\b(wallet|hotkey|coldkey|mnemonic|farming|payout|raw[-_\s]?trust|score\w*|scoreability|token[-_\s]?score|base[-_\s]?score)\b/i; @@ -188,6 +188,15 @@ describe("buildRemediationPlan", () => { ]); }); + it("FORBIDDEN_PATTERN catches both the singular 'ranking' and the plural 'rankings' (#8886)", () => { + // The bare singular `ranking` could never match inside "rankings" (no word boundary between "g" and "s"), + // so the plural leaked past this secondary gate; `rankings?` fixes it while still matching the singular. + expect(FORBIDDEN_PATTERN.test("this shows the ranking of contributors")).toBe(true); + expect(FORBIDDEN_PATTERN.test("this shows the rankings of contributors")).toBe(true); + // A benign word that merely starts the same must still pass through untouched. + expect(FORBIDDEN_PATTERN.test("the rankboard is empty")).toBe(false); + }); + it("falls back to public-safe copy when every blocker string is fully redacted", () => { const plan = buildRemediationPlan({ login: "miner",