Repository navigation
Description
aggregator(collect-github-billing): --year/--month/--user values are never validated — NaN, month 13, month 0, fractional and flag-token values go straight into the billing API URL, and the failure is blamed on the gh token scope
Evidence (verified this run, main f1eac95)
pm-stack/aggregator/scripts/collect-github-billing.ts:
:42-45—argValue(flag)returnsprocess.argv[i + 1]unchecked: a flag token is accepted as the previous flag's value, and a trailing flag yieldsundefined.:72-74—year/monthareNumber(argValue(...))with no integer/range check;useris the raw string. All three are interpolated straight into the API path at:52(users/${user}/settings/billing/usage?year=${year}&month=${month}).:58-61— on anyghfailure the script's error says a 404 "usually means the scope, not a missing user", so a self-inflicted bad URL is reported as a token-scope problem.
Probe (laptop, ~/git/fleet/probe-2026-11-01-laneB-ghbilling/; real script + src/, sha256 of the script 5f8d8100… matched to main; gh stubbed to log its argv and return {"usageItems":[]}):
| Invocation | API call issued | Result |
|---|---|---|
--year 2026 --month 10 --print (control) |
users/dezren39/settings/billing/usage?year=2026&month=10 |
exit 0, correct |
--month banana |
…?year=2026&month=NaN |
exit 0, prints 2026-NaN |
--month 13 |
…&month=13 |
exit 0 |
--month 0 |
…&month=0 |
exit 0 |
--year 2026.5 --month 2.5 |
…?year=2026.5&month=2.5 |
exit 0 |
--month --print |
…&month=NaN (the flag token is consumed as the value, and --print still takes effect) |
exit 0 |
--user --print |
users/--print/settings/billing/usage?… |
exit 0 |
--print --user (trailing) |
user silently falls back to the default dezren39 |
exit 0 |
Against the real endpoint every malformed case 404s, and the script then misreports it as a missing user scope on the gh token — the exact misdiagnosis the error text at :58-61 was written to prevent, pointed the wrong way.
Why it matters
This is the daily GitHub billing collector (#1051): its records feed the usage snapshot store. A typo'd month in a manual or scheduled invocation either fails with a misleading scope error (sending the operator to re-auth gh instead of fixing the argument) or, for a trailing flag, silently collects a different month/user than the one named. Every sibling script that validates its period args locally fails fast with a usage error; this one validates nothing.
Acceptance criteria
--yearmust be an integer in a sane range (e.g. 2000–2100) and--monthan integer 1–12; anything else (non-numeric, fractional, out of range) exits non-zero with a usage error naming the bad value, before anyghcall.- A value-taking flag that is last, or whose next token is another flag, is a usage error — never silently replaced by the default and never consumed as a value.
--usermust be a non-empty, non-flag value.- The
gh-failure error keeps its scope hint only for calls whose arguments passed validation. - Tests pin: the control case,
banana,13,0,2.5, flag-as-value, and trailing-flag cases.
Distinct from #2493 (billing items never validated — response side; this is the request/CLI side) and from the per-script flag-token filings for other scripts (#3295, #3330, #3333, #3415 — different files). Family: #3352/#3353 argument-contract inventory.
Activity
developing-today commentedon Nov 1, 2026
CODE-1307
dezren39 commentedon Nov 1, 2026
🤖 Agent note · filed
21 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · parked
testcheck is QUEUED (fleet runner backlog) and the Codex review is still running with no findings posted yet.Merge pull request #4205 from developing-today/queue/6077-3419-billin…
dezren39 commentedon Nov 2, 2026
🤖 Agent note · done
testcheck was still QUEUED at merge time (fleet runner backlog) — merged under Drew's standing merge authority (PRs do not wait for CI when the change itself is verified), with CI on main as the backstop.