Skip to content

chore: audit test suite + retire legacy addTransaction (Issue #11)#14

Merged
toolpathguy merged 2 commits into
mainfrom
chore/audit-test-suite
Jun 16, 2026
Merged

chore: audit test suite + retire legacy addTransaction (Issue #11)#14
toolpathguy merged 2 commits into
mainfrom
chore/audit-test-suite

Conversation

@toolpathguy

@toolpathguy toolpathguy commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Fixes #11. Relates to #4.

Audits the test suite for tests that aren't protecting us (skipped, env-gated, legacy-path, or asserting hledger's own behavior), retires the legacy addTransaction write path, and makes CI actually run the suite with hledger installed.

Spec: .kiro/specs/audit-test-suite/ (design → requirements → tasks → outcome.md = the audit deliverable).

What changed

Retire the legacy write path

  • categories.post.ts now writes via appendTransaction (the direct journal writer), not addTransaction (hledger add over stdin). One write path now.
  • Deleted addTransaction from server/utils/hledger.ts.
  • The friendly fieldHasIllegalChars 400 stays; validateTransaction inside appendTransaction is the backstop, so the injection guard does not regress.

Clean the tests

  • Deleted F1 (asserts hledger engine behavior we don't own), F2 (legacy round-trip), and F4 — a non-skipped test coupled to addTransaction existing in source, missed by the original skip/gate sweep and caught during implementation (recorded in design.md as a tracked correction, with R3.6).
  • Kept F3 (the HLEDGER_TIMEOUT_MS=1 timeout-kill test) and its graceful if (!hledgerAvailable) return skip, plus the two module-invariant tests (hledger.ts performs no fs writes / does not import fs).
  • Repointed/removed the addTransaction test stubs.

CI runs the suite with hledger

  • Added a test job to .github/workflows/ci.yml: npm ci → install hledger → hledger --version (fail-loud gate) → npm run test. Install every run, no cache (ephemeral runners; a stale cache could reintroduce the silent skip). typecheck job untouched.

🔒 Bug the new CI job immediately caught (cross-platform path traversal)

  • The first CI run on Linux exposed a latent hole that Windows-only local runs structurally could not catch: safeJournalPath (server/utils/journalFiles.ts) used the platform basename to detect separators. On POSIX that is path.posix.basename, which treats \ as an ordinary filename char — so a\x.journal was rejected on Windows but accepted on Linux (the likely deployment OS).
  • Fix: detect separators with win32.basename (strict: /, \, and C: drive prefixes) so path-bearing names are rejected identically on every OS. The matching test's sanity helper had the same platform dependency and was switched to an explicit /[\\/]/ check; the load-bearing "must throw" assertion is unchanged.
  • This is exactly the class of silent gap the audit set out to remove — see outcome.md §1b.

Coverage

  • Added a non-default budget-base assign route test (R6.1). Scoping note: budget/transfer echoes fully-qualified envelope paths and has no base concept, so it's correctly out of scope.

Verification

  • npx vitest run — 40 files, all pass (local; hledger present → F3 ran).
  • npx nuxi typecheck — exit 0, no type errors.
  • No tooling config modified; no any/as added to production code.

Follow-ups (documented in outcome.md, not closed here)

  • Dedicated route tests for hidden-envelopes.get/post (incl. zero-balance-before-hide).
  • Confirm/add direct handler coverage for journal/create.post and journal/export.get.

🤖 Generated with Claude Code

toolpathguy and others added 2 commits June 16, 2026 15:52
Inventory gated/legacy tests, retire the legacy hledger-add write path, and
make CI actually run the suite with hledger available.

- Retire addTransaction: migrate categories.post.ts to appendTransaction (the
  direct journal writer) and delete the function. One write path now; the
  friendly control-char guard stays, with validateTransaction as backstop.
- Clean tests: delete F1 (engine-behavior assertion), F2 (legacy round-trip),
  and F4 (a non-skipped test coupled to addTransaction's existence, missed by
  the original skip/gate sweep). Keep F3 (timeout-kill) + its graceful skip and
  the two module-invariant tests. Repoint/remove the addTransaction stubs.
- CI: add a `test` job (npm ci -> install hledger -> hledger --version gate ->
  npm run test) so the hledger-gated test runs for real instead of no-op'ing.
  typecheck job untouched.
- Coverage: add a non-default budget-base assign route test (R6.1).
- Deliverable: outcome.md records F1-F4 verdicts, a path-coverage map, and
  follow-ups (hidden-envelopes + journal create/export route coverage).

Full suite (40 files) green; nuxi typecheck exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new CI test job (Issue #11) exposed a latent path-traversal hole that
Windows-only local runs could not catch. safeJournalPath used the platform
basename to detect separators; on POSIX that is path.posix.basename, which
treats `\` as a normal filename char — so `a\x.journal` was rejected on
Windows but accepted on Linux.

Use win32.basename (treats `/`, `\`, and `C:` drive prefixes as separators)
so path-bearing names are rejected identically on every OS. The test's sanity
helper had the same platform dependency; switched it to an explicit /[\/]/
check. The load-bearing "must throw" assertion is unchanged.

journalFiles.test.ts: 11/11 pass; full suite 40 files green; typecheck exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@toolpathguy toolpathguy merged commit 84248ee into main Jun 16, 2026
2 checks passed
@toolpathguy toolpathguy deleted the chore/audit-test-suite branch June 17, 2026 02:41
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.

chore: audit the test suite (skipped/gated tests, legacy paths, coverage gaps)

1 participant