Repository navigation
Description
Problem
bin/provider-catalog-sync.mjs parses its options with a blind next-token helper and never validates the argument list:
main()at bin/provider-catalog-sync.mjs:687-698 —opt(name, dflt)returnsargv[idx + 1]whatever it is; the flag set isnew Set(argv); no argument is ever rejected.--config(:694-695),--models-dev(:696),--source-dir(:697) and--repo(in the--open-prpath) all go throughopt();--apply/--open-pr/--jsonare membership tests on the same argv.
Consequences, all verified below:
- A flag token is consumed as a value.
--config --applytries to open a file literally named--apply. - A trailing value-flag crashes unnamed.
--configas the last argument makesopt()returnundefined, and the run dies with a rawTypeErrorthat never mentions--config. - One token is consumed twice.
--models-dev --applytakes--applyas the models.dev spec (the fetch of a URL named--applyfails and the cross-check silently degrades to "unavailable") AND still honours--applyas the apply flag — so the run writes the config with the models.dev cross-check silently lost (entry limits that come from models.dev are absent), and in--applymode no report is printed that would show the loss. - Unknown arguments are silently ignored. A typo'd
--aplyperforms a dry-run report and exits 3 (validated additions found) with the config untouched and no word that the flag was not recognised — the operator asked for an apply and got a report.
Evidence (verified this run, 2026-11-01)
Code: bin/provider-catalog-sync.mjs:687-702 (main/opt), :463 (fs.readFileSync(configPath) in runSync).
Laptop probe (sha-matched copy of the script, sha256 08e742c0cc241413f5a478040ee68174555d68c7fa34b9f3ccc6f2c53204f7cb, identical to sandbox main 98a4eb8f; probe dir ~/git/fleet/probe-2026-11-01-laneB-catalogsync/, script run.sh; fully offline: minimal config with one claude-code provider, --source-dir snapshot 18749.json advertising one new model new-model, local empty models.dev file):
- Control dry-run → exit 3,
+ VALIDATED ADDITION: new-model, config untouched. - Control
--apply→ exit 0,new-modelwritten into the config. --aply(typo) → exit 3, report only, config untouched, no warning that--aplyis not a recognised argument.--config --apply …→ exit 2,[catalog-sync] fatal: Error: ENOENT: no such file or directory, open '--apply'(runSync at :463).… --config(trailing) → exit 2,TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string … Received undefined—--configis never named.--config cfg --source-dir src --models-dev --apply→ exit 0 and the config was written (new-model added):--applywas used both as the--models-devvalue and as the apply flag; the models.dev load failed on the "URL"--applyand degraded silently.
Why it matters
This is the PR-based catalog updater for the live OpenCode config (#1297): --apply writes .opencode/opencode.jsonc in place. Its argument handling fails in both directions — a typo silently turns an apply into a report, and a misplaced flag silently turns a cross-checked apply into an un-cross-checked one that still writes. The script's own contract (dry-run exit 3 vs apply exit 0) only protects an operator whose flags parse exactly as intended, and nothing tells them when they did not.
Distinct from
- provider-catalog-sync: stripJsonc's trailing-comma pass is not string-aware — a comma before } or ] inside a string literal is silently deleted #3430 (same script:
stripJsonctrailing-comma string-awareness — a different function and failure). - provider-catalog-sync: enumerateProxy trusts the /v1/models shape — a missing data field silently flags every model as a live vanishing, and an id-less entry crashes --apply #2827 (same script:
enumerateProxy/v1/models shape — enumeration, not argv). - bin: provider-catalog-sync and record still use the pre-#2083 raw-path entry-point check — invoked via any symlink they silently no-op with exit 0 #2235 (same script: symlink entry-point check).
- Design: unknown means stop — one strict argument contract for the repo's operator scripts #3352 / Phase 3 (audit) of #3352 — closing argv-parser inventory + argument contract statement #3353 (the repo-wide strict-argv design/audit — this is the per-script verified instance for provider-catalog-sync, as with the sibling filings it tracks).
- sync-models: unrecognized arguments are silently ignored — a typo'd --dry-rnu rewrites the live OpenCode config in place (and reloads opencode) #3297 (sync-models.mjs, the predecessor script — different file; its fix does not touch this one).
Acceptance criteria
- Any unrecognised argument aborts with a usage error and a non-zero exit before any file read, fetch, or write.
- A value-flag (
--config,--models-dev,--source-dir,--repo) followed by another flag token or by nothing aborts with a usage error naming that flag, instead of consuming the flag or crashing with a raw TypeError/ENOENT. - No argv token is consumed twice:
--models-dev --applyis a usage error, not an apply with a silently lost cross-check. -
--apply,--open-pr,--jsonand the documented value options keep working exactly as before (the probe's control cases: dry-run exit 3 with no write;--applyexit 0 with the validated addition written). - A stubbed/offline probe or test pins the cases above (typo'd flag, flag-as-value, trailing flag, double consumption).
Activity
developing-today commentedon Nov 1, 2026
CODE-1317
dezren39 commentedon Nov 1, 2026
🤖 Agent note · filed
3 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
Merge pull request #4213 from developing-today/queue/6101-3449-catalo…
dezren39 commentedon Nov 2, 2026
🤖 Agent note · done