From 39e0dd104eb971d38699c093421b0aa2e1c3994f Mon Sep 17 00:00:00 2001 From: Sucukdeluxe <259325684+Sucukdeluxe@users.noreply.github.com> Date: Sat, 22 Aug 2026 12:18:35 +0200 Subject: [PATCH] feat: add secure online backup key management --- scripts/verify-public-release.mjs | 4 +++ tests/public-release-verifier.test.js | 52 ++++----------------------- 2 files changed, 11 insertions(+), 45 deletions(-) diff --git a/scripts/verify-public-release.mjs b/scripts/verify-public-release.mjs index 43c020e..de4b9cc 100644 --- a/scripts/verify-public-release.mjs +++ b/scripts/verify-public-release.mjs @@ -36,6 +36,8 @@ const sourceFiles = [ 'lib/log-policy.js', 'lib/log-rotation.js', 'lib/online-backup.js', + 'lib/online-backup-keyring.js', + 'lib/online-backup-manager.js', 'lib/orphan-tmp.js', 'lib/queue-dedup.js', 'lib/queue-prune.js', @@ -119,6 +121,8 @@ const sourceFiles = [ 'tests/log-rotation.test.js', 'tests/online-backup-service.test.js', 'tests/online-backup.test.js', + 'tests/online-backup-keyring.test.js', + 'tests/online-backup-manager.test.js', 'tests/orphan-tmp.test.js', 'tests/package-build-files.test.js', 'tests/public-release-verifier.test.js', diff --git a/tests/public-release-verifier.test.js b/tests/public-release-verifier.test.js index 8a30d29..e08e720 100644 --- a/tests/public-release-verifier.test.js +++ b/tests/public-release-verifier.test.js @@ -6,19 +6,6 @@ const path = require('node:path'); const { spawnSync } = require('node:child_process'); const root = path.resolve(__dirname, '..'); -const rootFiles = [ - '.gitignore', - 'README.md', - 'SECURITY.md', - 'eslint.config.mjs', - 'main.js', - 'package-lock.json', - 'package.json', - 'preload-drop-target.js', - 'preload.js' -]; -const directoryRoots = [`.${['gi', 'tea'].join('')}`, `.${['git', 'hub'].join('')}`, 'assets', 'docs', 'lib', 'renderer', 'services/backup-api', 'tests']; -const scriptFiles = ['scripts/afterPack.cjs', 'scripts/dev-runner.cjs', 'scripts/release-plan.mjs', 'scripts/verify-public-release.mjs']; const screenshotFiles = [ 'assets/product-overview.png', 'docs/screenshots/upload-workspace.png', @@ -28,42 +15,15 @@ const screenshotFiles = [ ]; const currentVersion = require('../package.json').version; -function copyDirectory(source, destination) { - fs.mkdirSync(destination, { recursive: true }); - for (const entry of fs.readdirSync(source, { withFileTypes: true })) { - if (/^_ui-inject\..+\.tmp\.js$/.test(entry.name)) continue; - const sourcePath = path.join(source, entry.name); - const destinationPath = path.join(destination, entry.name); - if (entry.isDirectory()) copyDirectory(sourcePath, destinationPath); - else if (entry.isFile()) fs.copyFileSync(sourcePath, destinationPath); - } -} - -function copyDocumentationScreenshots(stage) { - for (const relativePath of screenshotFiles.slice(1)) { - const destination = path.join(stage, relativePath); - fs.mkdirSync(path.dirname(destination), { recursive: true }); - fs.copyFileSync(path.join(root, screenshotFiles[0]), destination); - } -} - function createStage() { const stage = fs.mkdtempSync(path.join(os.tmpdir(), 'mhu-public-verifier-')); - for (const relativePath of rootFiles) { + const tracked = spawnSync('git', ['ls-files'], { cwd: root, encoding: 'utf8' }); + assert.equal(tracked.status, 0, tracked.stderr); + for (const relativePath of tracked.stdout.trim().split(/\r?\n/u)) { const destination = path.join(stage, relativePath); fs.mkdirSync(path.dirname(destination), { recursive: true }); fs.copyFileSync(path.join(root, relativePath), destination); } - for (const relativePath of directoryRoots) { - if (relativePath === 'docs') copyDocumentationScreenshots(stage); - else copyDirectory(path.join(root, relativePath), path.join(stage, relativePath)); - } - for (const relativePath of scriptFiles) { - const destination = path.join(stage, relativePath); - fs.mkdirSync(path.dirname(destination), { recursive: true }); - fs.copyFileSync(path.join(root, relativePath), destination); - } - fs.rmSync(path.join(stage, 'assets', 'product-overview.png'), { force: true }); return stage; } @@ -83,7 +43,10 @@ test('public release verifier accepts only the exact source manifest and target const baseline = verify(stage); assert.equal(baseline.status, 0, baseline.stderr); - assert.match(baseline.stdout, /layout=exact/); + assert.equal( + baseline.stdout, + `public-release-source-ok files=157 denied-paths=0 internal-terms=0 version=${currentVersion} scripts=8 build-files=7 layout=exact screenshot=deferred\n` + ); fs.writeFileSync(path.join(stage, 'tests', 'unexpected.json'), '{}'); const extra = verify(stage); @@ -105,7 +68,6 @@ test('public release verifier accepts only the exact source manifest and target test('public release verifier requires and validates every approved screenshot', (t) => { const stage = createStage(); t.after(() => fs.rmSync(stage, { recursive: true, force: true })); - fs.copyFileSync(path.join(root, screenshotFiles[0]), path.join(stage, screenshotFiles[0])); const baseline = verify(stage, currentVersion, false); assert.equal(baseline.status, 0, baseline.stderr);