Skip to content

fix(sec): tighten parseIntOption + fix bundled import.meta.dir asset paths#206

Open
sroussey wants to merge 2 commits into
mainfrom
claude/wonderful-hypatia-j6vmqi
Open

fix(sec): tighten parseIntOption + fix bundled import.meta.dir asset paths#206
sroussey wants to merge 2 commits into
mainfrom
claude/wonderful-hypatia-j6vmqi

Conversation

@sroussey

Copy link
Copy Markdown
Contributor

Summary

parseIntOption silently accepts non-integers. The commander parser used parseInt(value, 10), which happily returned 123 for "123abc" and 1 for "1e5" — the CLI then handed a plausible-but-wrong CIK to downstream tasks, so sec query facts 123abc and sec query xbrl --cik 1e5 returned rows for a different issuer than the user asked about. The two known callsites (sec query facts <cik> and sec query xbrl --cik) had ad-hoc /^\d+$/ guards duct-taped on top; every other numeric option (year, limit, offset, sic, portal…) was still exposed. This tightens parseIntOption at the parser boundary — trim, require all-digit + Number.isSafeInteger, throw commander's InvalidArgumentError with the original value — and drops the redundant per-command guards. Every commander option using parseIntOption is now protected in one place.

Bundled asset paths broke on the packaged binary. import.meta.dir resolves to src/…/ in dev but to dist/…/ after bun build, so on the shipped sec binary the eval harness's mock_data/embarc-spac-unit-terms.csv and committed S-1 HTML weren't found at all (the build script never copied them into dist/), and — worse — the sec fetch fixtures / sec fetch s1-fixtures "gitignored cache" was silently writing back into the packaged binary's own directory. This introduces resolveAsset() for the dev-vs-dist candidate walk on read-only fixtures, adds a copy-assets build step that stages both fixture trees into dist/, and reroutes the two fetch tasks to SEC_FIXTURES_DIR ?? cwd — logging where output landed so the user can find it. realSections.ts also picks up a documented 4-tier resolution order (--dirSEC_S1_MOCK_DIR env → dist candidate → source candidate) and lists every candidate in its not-found error.

Verification

  • bun run build — clean; dist/eval/mock_data/embarc-spac-unit-terms.csv and dist/sec/html/mock_data/s1/*.htm present after build.
  • npx tsc --noEmit — clean (this repo has no types script; equivalent).
  • bun test src/cli/ — 273 pass, 0 fail (includes the new parseIntOption block: 3 accept cases + 9 reject cases, plus the pre-existing query.test.ts guards updated for the new error message).
  • bun test src/eval/ — 40 pass, 0 fail.
  • bun test src/util/ — 50 pass, 0 fail.
  • bun test src/task/fixtures/ — 14 pass, 0 fail.

Notes

  • Two commits, one per fix.
  • SEC_FIXTURES_DIR and SEC_S1_MOCK_DIR are documented under Environment Variables in CLAUDE.md, and .sec-fixtures/ is added to .gitignore so the default (cwd-relative) output stays untracked.
  • embarcUnitTermsReference.ts resolves its CSV lazily inside loadEmbarcUnitTermsReference() rather than at module-load time, so a missing asset doesn't crash import for code paths that don't need the eval reference.
  • Addresses the two HIGH-severity findings on parseIntOption argument validation and import.meta.dir asset-path resolution surfaced in review.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UC9LGu3iokhuhAB46yt1ee


Generated by Claude Code

claude added 2 commits July 19, 2026 08:21
parseInt silently accepted values like "123abc" (→ 123) and "1e5" (→ 1) and
handed a plausible-but-wrong CIK to downstream tasks, so queries returned rows
for a different issuer. The ad-hoc /^\d+$/ trims scattered above the query
tasks caught it for the ones I noticed, but the primary parser was still the
hole. Tightening parseIntOption to reject anything that isn't an all-digit,
safe-integer string closes it for every commander option in one place and
lets the query commands drop their bespoke guards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UC9LGu3iokhuhAB46yt1ee
…te-side cache paths

`import.meta.dir` in dev points at `src/…/`, but after `bun build` it points
at `dist/…/` — so:

  - the CSV / HTML fixtures the eval harness reads weren't in `dist/` at all
    (never copied by the build), and `sec eval unit-terms` / `sec eval s1`
    on the packaged binary failed to load them; and
  - `sec fetch fixtures` / `sec fetch s1-fixtures` were writing their
    "gitignored cache" into the packaged binary's directory instead of
    somewhere in the user's project.

`resolveAsset` centralizes the dev-vs-dist candidate walk for read-only
assets, the build now copies the fixture trees into `dist/`, and the two
fetch tasks resolve their output under `SEC_FIXTURES_DIR ?? cwd` and log
where they landed so the user can find them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UC9LGu3iokhuhAB46yt1ee
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants