Skip to content

Harden runtime input validation (pre-existing, deferred from TS port #66) #67

Description

@KalebCole

Split out from the TypeScript port (#66), which was an annotation-only faithful translation — these are pre-existing behaviors present verbatim in the JS baseline (ad7be30), surfaced by CodeRabbit on the port diff. Fixing them changes runtime behavior, so they belong here, not in the port PR.

Findings (all confirmed present pre-port)

  1. src/lib/http.tsPARTIFUL_MAX_RETRIES NaN wedge. parseInt(process.env.PARTIFUL_MAX_RETRIES || '3', 10) — a non-numeric env value → NaN, attempt <= NaN is false on iteration 0, so no HTTP call is ever made and every command throws 'Request failed after retries'. Add Number.isFinite + floor guard.
  2. src/lib/http.tsRetry-After HTTP-date → NaN backoff. parseFloat on a date string yields NaN → setTimeout(…, NaN) fires immediately, discarding server backoff on 429s. Handle the HTTP-date form.
  3. src/lib/http.ts — no request timeout on the three fetch call sites (apiRequest, firestoreRequest, firestoreListDocuments). A stalled socket hangs the CLI forever. Add AbortSignal.timeout(...) (composes with withRetry). upload.ts already bounds its fetches.
  4. src/helpers/watch.ts--interval/--duration unvalidated. parseInt('x') → NaN → setTimeout(resolve, NaN) fires immediately, turning the poll loop into a request storm against Firestore; bad --duration exits instantly with a misleading 'Watch complete'. Add radix + positive-integer validation.
  5. src/lib/auth.ts — token refresh trusts response without resp.ok/id_token check. A non-{error}-shaped error body persists accessToken=undefined + tokenExpiry=Date.now() to auth.json and returns undefined, producing Authorization: Bearer undefined. Guard !resp.ok and missing id_token; lets getValidToken drop its ! assertions.

Recommended fix pattern

Centralize numeric-env parsing in one parsePositiveInt(value, fallback) helper, add a shared fetchWithTimeout, and tighten the auth refresh guard. All five are quick wins except the shared-timeout wiring.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions