⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
Four hand-written token-redaction patterns guard public-facing text in src/services/**, and every one of them misses something another one catches:
| Site |
Pattern |
Misses |
src/services/miner-dashboard-recommendations.ts:49 |
ghp_, github_pat_, gts_, orbenr_, orbsec_, glpat-, sk- |
gho_ ghu_ ghs_ ghr_, xox*- |
src/services/control-panel-roles.ts:304 |
same list |
gho_ ghu_ ghs_ ghr_, xox*- |
src/services/weekly-value-report.ts:414 |
same list + xox[baprs]- |
gho_ ghu_ ghs_ ghr_ |
src/services/score-breakdown.ts:15, src/services/agent-action-explanation-card.ts:15 |
github_pat_, gh[pousr]_ + path |
gts_ orbenr_ orbsec_ glpat- sk- xox*- |
The gh[pousr]_ class is the correct one for GitHub — it is what src/review/secret-patterns.ts:28 (/\bgh[pousr]_[A-Za-z0-9]{20,}\b/) and src/review/content-lane/registry-logic.ts:110 use. The three surfaces that only match ghp_ therefore pass ghs_... through verbatim — and ghs_ is the GitHub App installation access token this Worker itself mints on every pass via createInstallationToken. Input "token ghs_AAAAAAAAAAAAAAAAAAAAAAAA leaked" through sanitizePublicText (miner-dashboard-recommendations.ts:386-393) comes out unchanged; the same string with ghp_ comes out as "token private context leaked".
This is drift the files already know about in the adjacent line. miner-dashboard-recommendations.ts:46-47 says of the path pattern directly above: "Compose the roots from the canonical PUBLIC_LOCAL_PATH_INLINE in redaction.ts (so this surface cannot drift)" — while leaving the token pattern on line 49 a local literal. score-breakdown.ts:9-10 names miner-dashboard-recommendations.ts as following the same established pattern; it does not.
Requirements
- Add to
src/signals/redaction.ts (the module that already owns PUBLIC_LOCAL_PATH_INLINE / PUBLIC_LOCAL_PATH_SCRUB_PATTERN / PUBLIC_UNSAFE_PATTERN) a single exported source-of-truth:
export const PUBLIC_TOKEN_INLINE: string — the alternation of every prefix, being the union of all four current lists: gh[pousr]_, github_pat_, gts_, orbenr_, orbsec_, glpat-, sk-, xox[baprs]-.
export function publicTokenPattern(): RegExp — returns a fresh RegExp built from PUBLIC_TOKEN_INLINE with the g flag on each call, so no module-level /g object is ever shared across call sites.
- Rewrite all five sites to build their pattern from
PUBLIC_TOKEN_INLINE (composing with their own trailing character class / path alternation as they do today for the path root), removing every hand-written prefix literal: miner-dashboard-recommendations.ts:49, control-panel-roles.ts:304, weekly-value-report.ts:414, score-breakdown.ts:15, agent-action-explanation-card.ts:15.
- Each site keeps its own replacement string exactly as today (
"private context", "<redacted-token>") — this issue unifies what is matched, not what it is replaced with.
- After the change, the literal strings
ghp_ and gh[pousr]_ must not appear in any file under src/services/.
⚠️ Required pattern: PUBLIC_LOCAL_PATH_INLINE in src/signals/redaction.ts and the way miner-dashboard-recommendations.ts:46-48 already composes its LOCAL_PATH from it is the exact precedent — one exported inline root, composed per-surface. It does NOT satisfy this issue to fix only the ghs_ gap by editing three literals in place, leaving four divergent lists; to export a single shared module-level RegExp with the g flag (a shared stateful /g object would carry lastIndex across surfaces); or to change any site's replacement token or its surrounding forbidden-term checks.
Deliverables
All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example adding the shared constant and adopting it in two of the five sites — does not resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, on src/**. All six touched files are inside coverage.include. Because the change is a regex, coverage alone is insufficient: every prefix in PUBLIC_TOKEN_INLINE must be exercised at every call site via it.each, plus at least one non-token string per site asserting it is left unmodified.
Expected Outcome
A GitHub App installation token (ghs_), OAuth token (gho_), user token (ghu_), refresh token (ghr_) or Slack token cannot reach a public dashboard string, role summary, weekly report, score breakdown, or explanation card. One list of token prefixes exists, so adding a new provider's prefix updates every surface at once.
Links & Resources
src/signals/redaction.ts; src/services/miner-dashboard-recommendations.ts:44-49, :386-393; src/services/control-panel-roles.ts:301-310; src/services/weekly-value-report.ts:414; src/services/score-breakdown.ts:9-15; src/services/agent-action-explanation-card.ts:15; src/review/secret-patterns.ts:28.
Context
Four hand-written token-redaction patterns guard public-facing text in
src/services/**, and every one of them misses something another one catches:src/services/miner-dashboard-recommendations.ts:49ghp_,github_pat_,gts_,orbenr_,orbsec_,glpat-,sk-gho_ ghu_ ghs_ ghr_,xox*-src/services/control-panel-roles.ts:304gho_ ghu_ ghs_ ghr_,xox*-src/services/weekly-value-report.ts:414xox[baprs]-gho_ ghu_ ghs_ ghr_src/services/score-breakdown.ts:15,src/services/agent-action-explanation-card.ts:15github_pat_,gh[pousr]_+ pathgts_ orbenr_ orbsec_ glpat- sk- xox*-The
gh[pousr]_class is the correct one for GitHub — it is whatsrc/review/secret-patterns.ts:28(/\bgh[pousr]_[A-Za-z0-9]{20,}\b/) andsrc/review/content-lane/registry-logic.ts:110use. The three surfaces that only matchghp_therefore passghs_...through verbatim — andghs_is the GitHub App installation access token this Worker itself mints on every pass viacreateInstallationToken. Input"token ghs_AAAAAAAAAAAAAAAAAAAAAAAA leaked"throughsanitizePublicText(miner-dashboard-recommendations.ts:386-393) comes out unchanged; the same string withghp_comes out as"token private context leaked".This is drift the files already know about in the adjacent line.
miner-dashboard-recommendations.ts:46-47says of the path pattern directly above: "Compose the roots from the canonical PUBLIC_LOCAL_PATH_INLINE in redaction.ts (so this surface cannot drift)" — while leaving the token pattern on line 49 a local literal.score-breakdown.ts:9-10namesminer-dashboard-recommendations.tsas following the same established pattern; it does not.Requirements
src/signals/redaction.ts(the module that already ownsPUBLIC_LOCAL_PATH_INLINE/PUBLIC_LOCAL_PATH_SCRUB_PATTERN/PUBLIC_UNSAFE_PATTERN) a single exported source-of-truth:export const PUBLIC_TOKEN_INLINE: string— the alternation of every prefix, being the union of all four current lists:gh[pousr]_,github_pat_,gts_,orbenr_,orbsec_,glpat-,sk-,xox[baprs]-.export function publicTokenPattern(): RegExp— returns a freshRegExpbuilt fromPUBLIC_TOKEN_INLINEwith thegflag on each call, so no module-level/gobject is ever shared across call sites.PUBLIC_TOKEN_INLINE(composing with their own trailing character class / path alternation as they do today for the path root), removing every hand-written prefix literal:miner-dashboard-recommendations.ts:49,control-panel-roles.ts:304,weekly-value-report.ts:414,score-breakdown.ts:15,agent-action-explanation-card.ts:15."private context","<redacted-token>") — this issue unifies what is matched, not what it is replaced with.ghp_andgh[pousr]_must not appear in any file undersrc/services/.Deliverables
PUBLIC_TOKEN_INLINEandpublicTokenPattern()exist insrc/signals/redaction.tsand are the only place any token prefix literal appears undersrc/outsidesrc/review/secret-patterns.ts(grep-verifiable forghp_,gts_,orbenr_,orbsec_,glpat-,xox).sanitizePublicTextinminer-dashboard-recommendations.tsredacts aghs_-prefixed token — asserted as aREGRESSION:case naming the installation-token gap.sanitizeRoleText(control-panel-roles.ts) redactsghs_,gho_,ghu_,ghr_and anxoxb-token — oneit.eachover every prefix inPUBLIC_TOKEN_INLINE.weekly-value-report.ts,score-breakdown.tsandagent-action-explanation-card.tssanitizers each redact every prefix inPUBLIC_TOKEN_INLINE— oneit.eachper file.publicTokenPattern()returns a new object on each call and a repeated.replace()on the same input is idempotent (guards against a shared-lastIndexregression) — asserted in the redaction unit test.All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example adding the shared constant and adopting it in two of the five sites — does not resolve this issue.
Test Coverage Requirements
99%+ Codecov patch coverage, branch-counted, on
src/**. All six touched files are insidecoverage.include. Because the change is a regex, coverage alone is insufficient: every prefix inPUBLIC_TOKEN_INLINEmust be exercised at every call site viait.each, plus at least one non-token string per site asserting it is left unmodified.Expected Outcome
A GitHub App installation token (
ghs_), OAuth token (gho_), user token (ghu_), refresh token (ghr_) or Slack token cannot reach a public dashboard string, role summary, weekly report, score breakdown, or explanation card. One list of token prefixes exists, so adding a new provider's prefix updates every surface at once.Links & Resources
src/signals/redaction.ts;src/services/miner-dashboard-recommendations.ts:44-49,:386-393;src/services/control-panel-roles.ts:301-310;src/services/weekly-value-report.ts:414;src/services/score-breakdown.ts:9-15;src/services/agent-action-explanation-card.ts:15;src/review/secret-patterns.ts:28.