Skip to content

pm-stack(aggregator): validateNewComment/validateNewAction accept ref keys parseRef rejects (GH_REF number unbounded) #4952

Closed

Description

@dezren39

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 by validateNewComment (:119) for a kind: "github" comment's githubRef, and by the store-load gate commentRecordProblem (:65).
  • pm-stack/aggregator/src/actions.ts:253 — the same GH_REF, used by validateNewAction for targetRef (:396) and for the request-status target derived from objectRef (: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 verbatim
  • githubCommentUrl({githubRef: that ref}) → throws ref number is not a safe integer: developing-today/code#99999999999999999999
  • validateNewAction({targetRef: that ref, …}) → ok: true; a request-status action with objectRef: "gh:developing-today/code#99999999999999999999" → ok: true, targetRef derived to the same unsafe key
  • Boundary: #9007199254740991 (MAX_SAFE_INTEGER) — validate true, parseRef ok; #9007199254740992 — validate true, parseRef throws
  • Controls: #123 — validate true, 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 RefKey out 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

  • validateNewComment rejects a githubRef whose number is not a safe integer (same rule as parseRef), and commentRecordProblem applies the same rule at store load.
  • validateNewAction rejects an unsafe-number targetRef, including the request-status target derived from objectRef.
  • The check is one shared rule (e.g. a parseRef-based isValidRef helper 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; #9007199254740991 and 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

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    on Nov 3, 2026
  2. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator (new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a, run 2026-11-03 08:05 CST
    • Found via: filed this run
    • Task: Filed this issue — aggregator GH_REF validators (comments githubRef, actions targetRef) accept ref keys parseRef rejects; verified by laptop bun probe at origin/main a8dbda7 (validate ok, githubCommentUrl throws, controls/boundary pass).
    • Expectation: effort s — one shared parseRef-based ref rule at both validators + the comments store-load gate, with regression tests; queued as a small_fix packet for repo-worker-code.
    • Links: evidence in the issue body; body file hidden_files/issue-aggregator-ghref-unsafe-number.md
  3. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    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

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  5. added a commit that references this issue on Nov 4, 2026
  6. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: done — fixed and merged (task 8066, repo-worker-code lane code-e)

    PR #5235 merged (merge commit 0b75366) — shared isValidRef in 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/pm-stackpm-stack (Pad/Grist) in developing-today/codekind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions