Skip to content

Audit cleanup: dw.json atomicity, output discipline, timer leaks, ANSI palette#411

Draft
clavery wants to merge 3 commits into
mainfrom
chore/audit-cleanup-waves
Draft

Audit cleanup: dw.json atomicity, output discipline, timer leaks, ANSI palette#411
clavery wants to merge 3 commits into
mainfrom
chore/audit-cleanup-waves

Conversation

@clavery

@clavery clavery commented May 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Outcomes from a multi-package code review across b2c-cli, b2c-tooling-sdk, b2c-dx-mcp, mrt-utilities, and b2c-vs-extension. Fixes correctness and consistency issues; no new features. The branch was rebased against current main (63 commits) and the audit findings were re-verified against that newer codebase — items that became obsolete were dropped and a handful of new issues main introduced were folded in.

Driven by a four-wave plan (HIGH risk first → focused refactors → MEDIUM cleanup → LOW polish), then re-evaluated post-merge.

What changed

Concurrency / data integrity (SDK)

  • dw.json mutations (addInstance, removeInstance, setActiveInstance) now serialize through a per-path async lock. saveDwJson writes via tmp-file + atomic rename with orphan cleanup.
  • stateful-store.setStoredSession removes an exists-then-mkdir TOCTOU; orphan tmp file is cleaned up if rename fails.

Resource cleanup (SDK)

  • code deploy/download progress intervals run inside a withProgress helper that always tears down on exception.
  • jobs/run.ts JobAlreadyRunning detection no longer silently swallows text() failure — falls through to normal error path with a debug log.
  • code/download.ts replaces Map.get(name)! non-null assertions with explicit guards.

Diagnostic preservation on HTTP error paths (SDK)

  • code/deploy.ts unzip and both code/download.ts zip-fetch sites wrap await response.text() in try/catch so a body-read failure no longer masks the HTTP status that triggered the throw. Same fix applied to the OAuth client_credentials path. Mirrors the wave-1 fix in jobs/run.ts:135-141.

Silent error surfaces (SDK)

  • operations/mrt/bundle.ts loadServerConfig now rethrows with cause when config.server.js exists but fails to import (syntax/runtime error). Previously any failure collapsed to "no config" and built the bundle with default ssrOnly/ssrShared/ssrParameters.
  • scaffold/registry.ts loadScaffold logs a warn for non-ENOENT manifest read errors. ENOENT still silently skipped.

Output discipline (CLI)

  • 9 sandbox commands now route output through this.log so --json mode and test stdout silencing work as documented.
  • no-console ESLint rule scoped to src/commands/** to prevent regression. Prophet IDE template exempt (it serializes JS source for an external runtime).

Shared CLI palette (SDK + CLI)

Public-API hygiene (CLI)

  • Dropped formatApiError re-export aliases in utils/slas/client.ts and utils/scapi/schemas.ts; 7 call sites now import getApiErrorMessage from the SDK directly.
  • Removed redundant alias-passthrough test.

DRY (CLI)

  • The 6 newly-added ecdn detail commands (firewall:get/create/update, rate-limit:get/create/update) now use the SDK's printFieldsBlock helper, matching the BM/AM detail commands that landed in the same wave. Eliminates two divergent labelWidth values across the families and an ad-hoc countingExpression null-skip.

Other

  • mrt-utilities proxy onError guards res.headersSent before writeHead so it doesn't mask the original error when upstream begins streaming before erroring.
  • Trimmed a duplicated docstring paragraph in mrt-utilities/ssr-proxying.ts.

What was deliberately not changed

The audit also flagged a number of issues that, on inspection of the source, were either false positives or contractually-correct behavior. All re-checked adversarially after the merge from main — every dismissal still holds:

  • OAuth token cache "race" — PENDING_TOKEN_REQUESTS singleflight is already in place; residual check-then-delete in getCachedOAuthToken is single-thread safe.
  • MCP registry.ts duplicate-tool registration — registeredToolNames Set already dedupes both toolset and --tools paths.
  • MCP waitForHalt "lost wakeup" — waiter is pushed synchronously inside the Promise executor; no interleaving possible.
  • VS-extension realm polling "race" — guards block stacked timers, single-threaded JS rules out callback interleaving.
  • mrt tail-logs heartbeat orphaning — open/error/close listeners attached synchronously; close always clears the heartbeat.
  • MCP logs_watch_poll vs logs_watch_stop race — adversarially traced; microtask ordering rules out the race.
  • Several "brittle test" findings actually verify legitimate contracts (auth-token literal output, fixture-data assertions, ANSI code presence).
  • pollUntil extraction — deferred. waitForJob and waitForSandbox have distinct error types and stage-specific logging; net DRY gain is small relative to regression risk on well-tested polling paths.
  • Test infrastructure overhaul (over-mocked CLI command tests) — deferred to a focused effort.

Dropped during merge reconciliation

  • VS-extension renderTemplate ordering bug (${pageName}Data placeholder) and the diff-with-instance stub re-tagging — main removed the entire Page Designer Assistant feature in feat(vs-extension): remove Page Designer Assistant webview #467 (commit ce0c0b5c), deleting webview.html, _app.pageId.tsx, and 140 lines from extension.ts including the renderTemplate function and the diff command. The audit's edits no longer apply.

Changeset

Included: .changeset/wave-review-cleanup.md — patch bumps for @salesforce/b2c-tooling-sdk, @salesforce/b2c-cli, and @salesforce/mrt-utilities. (b2c-vs-extension dropped because the only fix targeting it is now obsolete.)

Test plan

  • pnpm run lint:agent — clean across all packages
  • pnpm run typecheck:agent — clean
  • pnpm run test:agent — SDK 1744 / CLI 1284 / MCP 775 / MRT-utilities 534 / mrt-welcome-app 24 / mrt-reference-app 206 passing
  • Manual: b2c sandbox ips, b2c sandbox usage <id>, b2c sandbox settings <id> — verify human output and --json modes both work
  • Manual: b2c setup auth and a subsequent stateful-auth command — confirm session file round-trips
  • Manual: parallel b2c setup auth invocations against the same dw.json — confirm no entries are lost (the dw.json serializer is in-process; multi-process remains best-effort but writes themselves are atomic via rename)
  • Manual: b2c code deploy against a sandbox — confirm progress messages still appear at the expected cadence
  • Manual: b2c ecdn firewall get, b2c ecdn rate-limit get — confirm new printFieldsBlock rendering matches BM/AM commands (note: separator instead of blank line between title and fields)
  • Manual: b2c debug repl against a debug session — confirm REPL ANSI styling intact after palette migration

clavery added 3 commits May 8, 2026 10:28
…I palette

Outcomes from a multi-package code review (CLI, SDK, MCP, mrt-utilities,
vs-extension). Fixes correctness and consistency issues; no new features.

Concurrency / data integrity (SDK)
- dw.json mutations (addInstance/removeInstance/setActiveInstance) now
  serialize through a per-path async lock, and saveDwJson writes via
  tmp-file + atomic rename with orphan cleanup.
- stateful-store.setStoredSession drops an exists-then-mkdir TOCTOU and
  cleans up orphan tmp on rename failure.

Resource cleanup (SDK)
- code deploy/download progress intervals run inside a withProgress helper
  that always tears down on exception.
- jobs/run.ts JobAlreadyRunning detection no longer silently swallows a
  text() failure; an unreadable body falls through to the normal error
  path with a debug log.
- code/download.ts replaces non-null assertions on Map.get() with explicit
  guards.

Output discipline (CLI)
- 9 sandbox commands now route output through this.log; bare console.* in
  src/commands/** is now banned by ESLint (the Prophet IDE template script
  is exempt because it serializes JS source for an external runtime).

Shared CLI palette (SDK + CLI)
- New @salesforce/b2c-tooling-sdk/cli ANSI palette (LEVEL_COLORS,
  colorLevel, colorDim, colorHighlight); utils/logs/format.ts and
  utils/mrt-logs/format.ts now consume it instead of redefining.

Public-API hygiene (CLI)
- Dropped formatApiError re-export aliases in slas/client and
  scapi/schemas; 7 call sites now import getApiErrorMessage from the SDK
  directly. Removed redundant alias-passthrough test.

Other
- mrt-utilities configure-proxying onError guards res.headersSent before
  writeHead to avoid masking the original error.
- vs-extension renderTemplate fixes a latent ordering bug where
  ${pageName}Data placeholders were left orphaned after the broader
  ${pageName} replacement ran.
- Trimmed a duplicated docstring in mrt-utilities ssr-proxying and
  re-tagged the diff-with-instance comment in vs-extension as an
  intentional stub rather than a stale TODO.

Verification
- pnpm run lint:agent: clean across all packages
- pnpm run typecheck:agent: clean
- pnpm run test:agent: SDK 1722 / CLI 1215 / MCP 720 / MRT 516 passing
…aves

# Conflicts:
#	packages/b2c-cli/test/utils/scapi/schemas.test.ts
#	packages/b2c-vs-extension/src/code-sync/cartridge-commands.ts
#	packages/b2c-vs-extension/src/extension.ts
…ilent errors, ecdn DRY

Outcomes from re-running the audit against post-merge code (63 commits from
main since the wave-1 baseline). Extends a few existing themes and folds in
new findings discovered in code main introduced.

ANSI palette (broaden)
- @salesforce/b2c-tooling-sdk/cli ANSI now also exports standalone
  RED/GREEN/YELLOW/CYAN/MAGENTA/GRAY hues.
- src/utils/debug/repl.ts (script-debugger REPL, PR #395) replaces its
  module-level literal-ESC palette with the shared ANSI export.
- src/commands/cap/pull.ts and src/commands/cap/tasks.ts (PR #370)
  destructure the same hues from ANSI inside their non-JSON render paths
  instead of redeclaring literal-ESC consts inline.

Diagnostic preservation on body-stream rejection
- code/deploy.ts unzip and code/download.ts (both single- and full-version
  zip paths) wrap `await response.text()` in try/catch so a body-read
  failure no longer masks the HTTP status that triggered the throw.
- auth/oauth.ts client_credentials path applies the same guard;
  particularly valuable since users already struggle to debug auth.

Surface silent errors
- operations/mrt/bundle.ts loadServerConfig now rethrows with `cause` when
  config.server.js exists but fails to import (syntax/runtime error).
  Previously any failure collapsed to the same "no config" branch and the
  bundle was built with default ssrOnly/ssrShared/ssrParameters.
- scaffold/registry.ts loadScaffold logs a warn for non-ENOENT manifest
  read errors instead of dropping every failure silently. ENOENT keeps
  the existing silent-skip behaviour.

ecdn detail commands
- firewall:get/create/update and rate-limit:get/create/update consume
  the SDK's printFieldsBlock helper, matching the bm/am detail commands
  that landed in the same wave. Eliminates two divergent labelWidth
  values and a manual countingExpression null-skip.

Verification
- pnpm run lint:agent: clean
- pnpm run typecheck:agent: clean
- pnpm run test:agent: SDK 1744 / CLI 1284 / MCP 775 / MRT-utilities 534 /
  mrt-welcome-app 24 / mrt-reference-app 206 passing
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.

1 participant