Skip to content

Fix: ExecutionStore trusts persisted workspaceState data with zero validation (#19) - #20

Merged
thegoodengineer merged 1 commit into
thegoodengineer:mainfrom
Bhumika-1432006:issue/19-store-validates-persisted-data
Aug 14, 2026
Merged

Fix: ExecutionStore trusts persisted workspaceState data with zero validation (#19)#20
thegoodengineer merged 1 commit into
thegoodengineer:mainfrom
Bhumika-1432006:issue/19-store-validates-persisted-data

Conversation

@Bhumika-1432006

Copy link
Copy Markdown
Contributor

Fixes #19

Bug

ExecutionStore's constructor read context.workspaceState.get<Execution[]>(STORAGE_KEY, []) and trusted the result completely. Memento.get<T>() is a compile-time cast, not a runtime check — if the persisted value was ever anything other than a well-formed array of Execution objects (corrupted state, a Settings Sync merge conflict, a future version of TruthLog changing the shape and the user downgrading, etc.), every store method that assumes an array (add()'s findIndex/push/splice, treeProvider.getChildren()'s filter/slice) would throw a TypeError the moment the tree view rendered after activation — silently breaking the sidebar with no log line explaining why.

Fix

  • Added isExecution(value): value is Execution, a runtime shape check for a single record (validates id/command/output are strings, truncated is a boolean, startedAt is a number, and the optional fields cwd/exitCode/endedAt are either the right type or undefined).
  • Added a private loadPersisted() method that reads the raw value as unknown, and only accepts it if Array.isArray(raw) && raw.every(isExecution). Otherwise it resets to [] and calls an injected onWarning callback with a message explaining that history was reset because the persisted data was invalid.
  • ExecutionStore's constructor now takes an optional second parameter, onWarning?: (message: string) => void, mirroring the callback-injection pattern recorder.ts's createRecorder(callbacks) already uses elsewhere in this codebase (rather than importing extension.ts's private log() directly, which would create a dependency in the wrong direction and make the store harder to unit test). extension.ts now constructs it as new ExecutionStore(context, log), so a corrupt-history warning shows up in the TruthLog output channel exactly like the shell-integration-disabled warning does.

Design choice: if the top-level value isn't an array, or if any entry in it fails the shape check, the whole thing is treated as invalid and reset — I didn't try to filter out just the bad entries and keep the rest. This matches getMaxEntries()'s existing all-or-nothing validate-or-fallback style in the same file, and avoids the ambiguity of partial corruption (is a record missing one field still "trustworthy" for the rest of its fields?).

Testing

  • npm run compile passes cleanly with no errors.
  • Extended src/test/suite/storeOrdering.test.ts with a new describe('loading persisted history', ...) block covering:
    • a non-array string, null, and a non-array object → resets to [] and warns
    • a well-formed-looking array containing one malformed entry → resets to [] and warns
    • a corrupt load followed by store.add(...) → doesn't throw, and the store is fully usable afterward
    • a well-formed persisted array → loads normally, with no warning fired
  • Additionally sanity-checked the exact validation algorithm (isExecution + the array check) in a standalone plain-Node script against all five scenarios above, bypassing the blocked Electron host — all five behaved exactly as the new tests assert (reject/reject/reject/reject/accept).
  • Honest caveat, same as Fix: diagnostic notes silently dropped once output is already truncated (#15) #16 and Fix: endSub has no timeout on readDone, unlike closeSub (#17) #18: I could not run npm test (the Electron-hosted VS Code integration suite) in this environment — same Windows-sandbox limitation as those two PRs (Code.exe doesn't launch as a real GUI app here, matching why this repo's own CI only runs the integration suite on ubuntu-latest under xvfb). This PR's CI run will be the first real execution of the new test cases.

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.

ExecutionStore trusts persisted workspaceState data with zero validation on load

2 participants