Skip to content

fix(fetcher): guard HashStore.load against non-object stores (#238)#247

Merged
williamzujkowski merged 1 commit into
mainfrom
fix/hash-store-shape-guard-238
Jun 30, 2026
Merged

fix(fetcher): guard HashStore.load against non-object stores (#238)#247
williamzujkowski merged 1 commit into
mainfrom
fix/hash-store-shape-guard-238

Conversation

@williamzujkowski

Copy link
Copy Markdown
Collaborator

Summary

HashStore.load() did JSON.parse(raw) as HashRecord with no shape validation. A corrupt idempotency store silently breaks change detection:

  • a null payload → getHash/setHash throw on null[key]
  • an array [] payload → setHash sets a property that JSON.stringify([]) drops, silently losing the write
  • a primitive (42) → property assignment throws (strict mode)

Any of these either crashes the fetcher or makes it re-commit/skip content incorrectly.

Fix

After parsing, verify the value is a non-null plain object (not null, not an array); otherwise treat it as an empty store — the same safe degrade as the existing invalid-JSON path. (Distinct from the setHash write-rejection tracked under #233; this is the read/parse path.)

Tests

hash-store.test.ts (new): valid round-trip; degrades to empty (no throw, writes recover) for invalid JSON, null, [], and a primitive payload.

Fetcher package: lint, typecheck, 166 tests green.

Closes #238

load() did `JSON.parse(raw) as HashRecord` with no shape validation. A corrupt
idempotency store that parses to null made getHash/setHash throw (null[key]);
an array payload made setHash silently lose the write (the property is dropped
by JSON.stringify); a primitive threw on assignment. Any of these silently
breaks change detection — re-committing everything or skipping genuinely
changed content.

Validate that the parsed value is a non-null plain object (not null, not an
array); otherwise treat it as an empty store, matching the existing
invalid-JSON degrade path. Distinct from the setHash write-rejection tracked
separately — this is the read/parse path.

Adds hash-store.test.ts covering invalid-JSON, null, array, and primitive
payloads plus a valid round-trip.

Closes #238

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@williamzujkowski williamzujkowski requested a review from a team as a code owner June 30, 2026 01:50
@williamzujkowski williamzujkowski merged commit 75c727d into main Jun 30, 2026
3 checks passed
@williamzujkowski williamzujkowski deleted the fix/hash-store-shape-guard-238 branch June 30, 2026 02:02
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.

bug(fetcher): HashStore.load() has no object-shape guard; null/array hashes.json throws or silently loses writes

1 participant