4.4 KiB
4.4 KiB
Implementation Plan: Job 871 — follow-up tweaks
1. Architectural Reconnaissance
- The previous implementation introduced a
RestoreServicethat takes aConfigServiceconstructor parameter but does not retain it onthis. InternallystageArchive()callsresolveSystemStagingDir(this.requireConfig()), whererequireConfig()returns the parameter via a cast(this as any).configService. This works but is a hack — the parameter should simply be retained as a class field. - The previous
DangerZoneService.wipeChallenges()snapshots<UPLOAD_DIR>/challengesto a side directory, transactionally deletes the DB rows, and then removes the snapshot. It currently never actually deletes the live<UPLOAD_DIR>/challengesdirectory on success, so the filesystem files persist even though the DB rows are gone. The user wants the live directory physically removed after the DB commit succeeds, with the snapshot retained as the rollback source until the disk delete is complete so that a disk-delete failure can be restored from it.
2. Impacted Files
- To Modify:
backend/src/modules/admin/system/restore.service.ts— retainConfigServiceon the instance and stop using therequireConfig()shim; use it directly instageArchive().backend/src/modules/admin/system/danger-zone.service.ts— inwipeChallenges(), after the DB transaction commits, physically remove the live<UPLOAD_DIR>/challengesdirectory, and only after that succeeds remove the snapshot; on any failure after the snapshot was created, copy the snapshot back into place so a disk-delete failure can be reversed.
3. Proposed Changes
restore.service.tscleanup:- Convert the constructor's
config: ConfigServiceparameter intoprivate readonly configService: ConfigServiceso it is stored on the instance. - At the top of the constructor body, capture each derived value (
uploadDir,databasePath,stageTtlMs,restoreUploadLimit) fromconfigServiceonce. - Remove the private
requireConfig()shim method entirely. - In
stageArchive(), change the call toresolveSystemStagingDir(this.configService).
- Convert the constructor's
danger-zone.service.tsphysical delete:- In
wipeChallenges(), after thedataSource.transaction(...)block returns successfully (we already have the row counts incounts), add:FilesystemTransactionService.rmSafe(challengesDir)to physically remove the live<UPLOAD_DIR>/challengesdirectory and its contents. - If that rm succeeds, then
rmSafethestagingBackupsnapshot. - If the rm of
challengesDiritself throws, retain the snapshot so the catch branch can restore from it (keepstaged = true), rethrow the error to enter the catch branch, and from the existing catch branch copystagingBackupback intochallengesDirexactly as before. Update the in-method narrative so that order of operations matches: stage → db commit → live rm → snapshot rm. - Do not change the DB ordering: the transaction must commit before any filesystem delete so a DB failure does not leave a partial filesystem state.
- In
4. Test Strategy
- Target Unit Test File:
- Existing
tests/backend/admin-system-danger.spec.tsalready verifies that afterwipe-challengesthechallengetable is empty. Extend it with one assertion: after a successful wipe, the live<UPLOAD_DIR>/challengesdirectory is also physically empty/absent. - Existing
tests/backend/admin-system-backup.spec.tsandtests/backend/admin-system-restore-validation.spec.tsalready validateBackupServiceandRestoreService.stageArchive()behavior; no behavioral changes are expected from the constructor cleanup sincestageArchive()still resolves the same staging directory. Re-run those tests after the edit to confirm no regressions. - No new frontend tests are required — these are strictly backend concerns.
- Existing
- Mocking Strategy: Reuse the existing per-suite isolated temp upload directories (
mkdtempSync(path.join(os.tmpdir(), 'hipctf-…'))) and assert against the live path withfs.existsSync/fs.readdirSync. No new mocking infrastructure is needed; the danger-zone logic now relies on the same primitives (fs + SQLite transaction) the existing tests already exercise. - Verification: Run
npm testto confirm bothadmin-system-danger.spec.tsand the related system suites stay green; also runnpx --workspace backend tsc -p tsconfig.build.json --noEmitto confirm therequireConfig()removal does not break the build.