Repository navigation
Description
pm-stack(aggregator): validateNewComment / validateNewAction accept ref keys parseRef rejects — GH_REF number group is unbounded
Summary
Two POST boundary validators in the aggregator check GitHub refs with a local regex whose number group is an unbounded \d+:
pm-stack/aggregator/src/comments.ts:43—GH_REF, used byvalidateNewComment(:119) for akind: "github"comment'sgithubRef, and by the store-load gatecommentRecordProblem(:65).pm-stack/aggregator/src/actions.ts:253— the sameGH_REF, used byvalidateNewActionfortargetRef(:396) and for therequest-statustarget derived fromobjectRef(:469-470).
Both validators therefore accept refs like developing-today/code#99999999999999999999 and store them typed as RefKey. But a RefKey is only meaningful if the canonical parser accepts it: parseRef (src/model.ts:460-466) throws ref number is not a safe integer for any number above Number.MAX_SAFE_INTEGER — the rule established for #2485/#4284 and applied at the registry gate (isValidTaskRef, registry.ts) — and refUrl inherits the throw.
The comment module's own consumer proves the breakage in-repo: githubCommentUrl (src/comments.ts:482-485) returns refUrl(c.githubRef) for a stored comment, so a comment that passed validation and the store-load gate throws when its URL is derived, instead of rendering a link. Action targetRefs carrying the same shape are handed to downstream status-request consumers as valid RefKeys they cannot parse.
This is the validator-side sibling of #4890 (open): that issue covers refsInText manufacturing unsafe keys from text; this one covers the two boundary validators (and the comments store-load gate) accepting unsafe keys a client posts directly. The fix in one does not touch the other.
Evidence (verified this run, laptop bun probe at origin/main a8dbda7)
Probe imported validateNewComment, validateNewAction, githubCommentUrl, and parseRef from the laptop primary's aggregator sources:
validateNewComment({kind:"github", githubRef:"developing-today/code#99999999999999999999", …})→ok: true, ref stored verbatimgithubCommentUrl({githubRef: that ref})→ throwsref number is not a safe integer: developing-today/code#99999999999999999999validateNewAction({targetRef: that ref, …})→ok: true; arequest-statusaction withobjectRef: "gh:developing-today/code#99999999999999999999"→ok: true,targetRefderived to the same unsafe key- Boundary:
#9007199254740991(MAX_SAFE_INTEGER) — validatetrue,parseRefok;#9007199254740992— validatetrue,parseRefthrows - Controls:
#123— validatetrue,parseRef→{repo, number: 123},githubCommentUrl→https://github.com/developing-today/code/issues/123
Why it matters
- The boundary is the one place the aggregator's ingest contract (validate once, at the boundary) can keep an unparseable
RefKeyout of the durable stores; once stored, the comments store-load gate (commentRecordProblem, same regex) re-admits it on every load, so the poisoned record is permanent until hand-edited. - The failure surfaces far from the cause: a render/URL derivation throw (or a downstream consumer refusing the ref) for a comment/action that every validator said was fine.
- Two copies of the same flawed regex (comments.ts:43, actions.ts:253) guarantee the sites drift; the registry already solved this by routing through
parseRef(isValidTaskRef) — the validators should share that one rule.
Acceptance criteria
-
validateNewCommentrejects agithubRefwhose number is not a safe integer (same rule asparseRef), andcommentRecordProblemapplies the same rule at store load. -
validateNewActionrejects an unsafe-numbertargetRef, including therequest-statustarget derived fromobjectRef. - The check is one shared rule (e.g. a
parseRef-basedisValidRefhelper in model.ts, as registry.ts already uses), not a third copy of a patched regex. - Regression tests: oversized-number refs rejected at both validators and at the comments store-load gate;
#9007199254740991and ordinary refs (e.g.#123) still accepted; existing comments/actions tests stay green.
Distinct from: #4890 (refsInText builder emitting unsafe keys from session text), #2485/#4284 (registry gate hardening, already landed).
Activity
dezren39 commentedon Nov 3, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 4, 2026
agent-note:v1
state: picked up
task 8066 (queue repo-health-code-pilot, lane code-e) — small_fix, assigned direct. Revalidated fresh: issue #4952 OPEN, no hard-stop labels, no competing PR or branch. Implementing the shared parseRef-based ref check in the aggregator validators (comments + actions + store-load gate) with regression tests, on a laptop worktree.
— repo-worker-code lane code-e, 2026-11-04T01:30Z
Merge pull request #5235 from developing-today/queue/8066-4952-gh-ref…
dezren39 commentedon Nov 4, 2026
agent-note:v1
state: done — fixed and merged (task 8066, repo-worker-code lane code-e)
PR #5235 merged (merge commit 0b75366) — shared
isValidRefin model.ts (parseRef-based); validateNewComment, commentRecordProblem (store-load gate), validateNewAction (targetRef + derived request-status target), and registry isValidTaskRef all route through it; both local GH_REF regex copies deleted. Acceptance: oversized refs rejected at both validators and the load gate; #9007199254740991 and #123 accepted.Tests: full aggregator suite on laptop — 1513 pass / 0 fail, incl. new test/gh-ref-safe-integer-4952.test.ts. Codex review on PR #5235 completed with zero findings. tsc shows only the two pre-existing clean-main errors (verified by stash comparison).
— repo-worker-code lane code-e, 2026-11-04T01:40Z