refactor(persistence): migrate fulfillment-store to canonical atomic-write util (DC-103) [glm-grade=A]
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

writeState() drops its private tmp+writeFileSync+rename copy (no fsync,
Date.now() tmp names, best-effort chmod) and delegates to
src/utils/atomic-write.js atomicWriteJSON (exclusive-create tmp, fsync,
rename, parent-dir fsync, 0600). A torn stripe-fulfillments.json could
previously make a webhook retry mint a SECOND valid license key for an
order that already has one. Both consumers (routes/billing.js,
scripts/stripe-license-bridge.js) JSON.parse only - trailing-newline
drop in the canonical serializer is harmless. Unused crypto require
removed. +2 DC-103 pins: full lifecycle 0600/complete/zero-leftovers,
and dual-instance interleaved writes (bridge+API file-IPC) with no tmp
collisions. 121 suites / 2776 tests green.

Judge: GLM-5.3 round-1 A (deleg_bd49a97b), URN urn:ump:layk7h326sqymcsh6tiusrs2sdbqdcx6ygvcuwwoxqn4rf7ycoua
This commit is contained in:
Hermes
2026-08-23 01:21:28 -07:00
parent 521b2f24a1
commit 6f8fac142f
2 changed files with 68 additions and 10 deletions
+6 -10
View File
@@ -10,8 +10,8 @@
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const platformPaths = require('../../platform-paths');
const { atomicWriteJSON } = require('../utils/atomic-write');
const DELIVERY_LEASE_MS = 5 * 60 * 1000;
@@ -44,15 +44,11 @@ function createFulfillmentStore(options = {}) {
function writeState(state) {
const dir = path.dirname(filePath);
fs.mkdirSync(dir, { recursive: true });
const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}`;
fs.writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n', { mode: 0o600 });
try {
fs.renameSync(tmp, filePath);
} catch (error) {
try { fs.unlinkSync(tmp); } catch (_) { /* best effort */ }
throw error;
}
try { fs.chmodSync(filePath, 0o600); } catch (_) { /* best effort */ }
// Canonical atomic-write (DC-099): fsync-before-rename + exclusive-create
// tmp + dir fsync. A crash mid-write can no longer leave a torn
// stripe-fulfillments.json — which would have forced the bridge to
// re-mint a duplicate license key on the next webhook retry.
atomicWriteJSON(filePath, state);
}
function mutate(mutator) {