TASK-3909cbf6-10c6-44ce-b82e-5bfb62cf34c8 harden artifact target guard

This commit is contained in:
thePR0M3TH3AN committed 2026-10-01 05:45:12 -04:00
1 parent 014bdb4f97
commit 0fdfcb3b68
4 files changed
+92 -24

No files matched your search

+3 -3
View File
@@ -2541,11 +2541,11 @@ test_integrity_note:
- id: SCN-dashboard-artifacts
given: "The dashboard test runs without an artifact environment, with an external runner directory, or with a repository/worktree target"
when: "It chooses the screenshot output boundary before the browser or screenshot writer starts"
then: "The default is a retained fresh external directory with provenance and hashes; explicit external output is honored; repository and symlink-resolved worktree targets fail before protected bytes change"
then: "The default is a retained fresh external directory with provenance and hashes; explicit external output is honored; repository, temporary-root, pre-existing and symlink-resolved targets fail before protected bytes change"
observable_outcomes:
- "Printed artifact directory, provenance, relative names, byte counts and SHA-256 hashes"
- "Refusal code for direct and symlink-resolved tracked-worktree destinations"
- "Unchanged tracked baseline bytes after refusal"
- "Refusal code for direct, temporary-root, existing-file and symlink-resolved tracked-worktree destinations"
- "Unchanged tracked baseline and external user bytes after refusal"
determinism_controls:
- "Disposable Git worktrees and temporary directories"
- "Fixed fixture bytes and SHA-256 assertions; no browser, network, sleep or retry is needed for the boundary scenarios"
+48 -11
View File
@@ -1,12 +1,12 @@
import { execFileSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import { existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
import { existsSync, lstatSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, relative, resolve } from 'node:path';
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
function isWithin(path, root) {
const difference = relative(root, path);
return difference === '' || (!difference.startsWith('..') && !difference.includes('/../'));
return difference === '' || (!isAbsolute(difference) && difference !== '..' && !difference.startsWith(`..${sep}`));
}
function existingAncestor(path) {
@@ -36,6 +36,28 @@ function refusal(target, protectedRoot) {
return error;
}
function targetExists(target) {
try {
lstatSync(target);
return true;
} catch (error) {
if (error.code === 'ENOENT') return false;
throw error;
}
}
function resolvePhysicalDirectory(directory) {
const requested = resolve(directory);
const ancestor = existingAncestor(requested);
return { requested, resolved: resolve(realpathSync(ancestor), relative(ancestor, requested)) };
}
function assertExternalDirectory({ requested, resolved }, repositoryRoot) {
for (const protectedRoot of trackedWorktreeRoots(repositoryRoot)) {
if (isWithin(resolved, protectedRoot)) throw refusal(requested, protectedRoot);
}
}
export function createDashboardArtifactDirectory({
environment = process.env,
repositoryRoot,
@@ -44,18 +66,33 @@ export function createDashboardArtifactDirectory({
if (!repositoryRoot) throw new Error('repositoryRoot is required for dashboard artifact isolation');
const requestedDirectory = environment.TORCH_CHECK_ARTIFACT_DIR;
if (!requestedDirectory) {
const directory = mkdtempSync(join(temporaryRoot, 'torch-dashboard-artifacts-'));
const temporary = resolvePhysicalDirectory(temporaryRoot);
assertExternalDirectory(temporary, repositoryRoot);
const directory = mkdtempSync(join(temporary.resolved, 'torch-dashboard-artifacts-'));
return { directory, provenance: 'standalone-temporary', requestedDirectory: null };
}
const requested = resolve(requestedDirectory);
const ancestor = existingAncestor(requested);
const resolved = resolve(realpathSync(ancestor), relative(ancestor, requested));
for (const protectedRoot of trackedWorktreeRoots(repositoryRoot)) {
if (isWithin(resolved, protectedRoot)) throw refusal(requested, protectedRoot);
const output = resolvePhysicalDirectory(requestedDirectory);
assertExternalDirectory(output, repositoryRoot);
mkdirSync(output.resolved, { recursive: true });
return { directory: output.resolved, provenance: 'TORCH_CHECK_ARTIFACT_DIR', requestedDirectory: output.requested };
}
export function prepareDashboardArtifactTargets(artifacts, names) {
if (new Set(names).size !== names.length || names.some((name) => name !== basename(name))) {
throw new Error('Dashboard screenshot names must be unique plain filenames');
}
mkdirSync(resolved, { recursive: true });
return { directory: resolved, provenance: 'TORCH_CHECK_ARTIFACT_DIR', requestedDirectory: requested };
const paths = {};
for (const name of names) {
const target = join(artifacts.directory, name);
if (targetExists(target)) {
const error = new Error(`DASHBOARD_ARTIFACT_TARGET_EXISTS: refusing to replace ${target}`);
error.code = 'DASHBOARD_ARTIFACT_TARGET_EXISTS';
throw error;
}
paths[name] = target;
}
return Object.freeze(paths);
}
function artifactFiles(directory, prefix = '') {
+11 -4
View File
@@ -1,17 +1,24 @@
import assert from 'node:assert/strict';
import { once } from 'node:events';
import { chromium } from '@playwright/test';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createConsoleServer } from '../src/console/server.mjs';
import { createDashboardArtifactDirectory, describeDashboardArtifacts } from './dashboard-artifacts.mjs';
import { createDashboardArtifactDirectory, describeDashboardArtifacts, prepareDashboardArtifactTargets } from './dashboard-artifacts.mjs';
const screenshotNames = [
'torch-dashboard-operation-outcomes.png', 'torch-dashboard-activity-review.png',
'torch-dashboard-check-evidence.png', 'torch-dashboard-owner-briefing-desktop.png',
'torch-dashboard-pilot-conclusion.png', 'torch-dashboard-pilot-review.png',
'torch-dashboard-manager-wakes.png', 'torch-dashboard-demo-desktop.png',
'torch-dashboard-demo-mobile.png', 'torch-dashboard-owner-briefing-mobile.png',
'torch-dashboard-live-refresh.png',
];
const artifacts = createDashboardArtifactDirectory({
repositoryRoot: fileURLToPath(new URL('..', import.meta.url)),
});
const screenshotDirectory = artifacts.directory;
const screenshotPaths = prepareDashboardArtifactTargets(artifacts, screenshotNames);
function screenshotPath(name) {
return join(screenshotDirectory, name);
return screenshotPaths[name];
}
const server = createConsoleServer();
+30 -6
View File
@@ -4,7 +4,7 @@ import { existsSync, mkdtempSync, mkdirSync, readFileSync, symlinkSync, writeFil
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import test from 'node:test';
import { createDashboardArtifactDirectory, describeDashboardArtifacts } from '../../scripts/dashboard-artifacts.mjs';
import { createDashboardArtifactDirectory, describeDashboardArtifacts, prepareDashboardArtifactTargets } from '../../scripts/dashboard-artifacts.mjs';
function repositoryFixture() {
const root = mkdtempSync(join(tmpdir(), 'torch-dashboard-artifact-fixture-'));
@@ -24,7 +24,8 @@ test('SCN-dashboard-artifacts: standalone execution retains fresh external scree
assert.equal(artifacts.provenance, 'standalone-temporary');
assert.equal(artifacts.requestedDirectory, null);
assert.equal(artifacts.directory.startsWith(resolve(repositoryRoot)), false);
writeFileSync(join(artifacts.directory, 'captured.png'), 'standalone screenshot');
const targets = prepareDashboardArtifactTargets(artifacts, ['captured.png']);
writeFileSync(targets['captured.png'], 'standalone screenshot');
assert.deepEqual(describeDashboardArtifacts(artifacts).files, [{
path: 'captured.png', bytes: 21,
sha256: '6921ad2c105108a005db4282443624252c392392d85bcb4ca2625c6af488f57c',
@@ -39,20 +40,25 @@ test('SCN-dashboard-artifacts: an explicit external runner directory receives ha
});
assert.equal(artifacts.provenance, 'TORCH_CHECK_ARTIFACT_DIR');
assert.equal(artifacts.directory, resolve(output));
writeFileSync(join(artifacts.directory, 'captured.png'), 'runner screenshot');
const targets = prepareDashboardArtifactTargets(artifacts, ['captured.png']);
writeFileSync(targets['captured.png'], 'runner screenshot');
assert.deepEqual(describeDashboardArtifacts(artifacts).files, [{
path: 'captured.png', bytes: 17,
sha256: '382d6e41938a7a8cc7767e9b519ddbef25e5048fc6fa9fe02faf31bab4148e2b',
}]);
});
test('SCN-dashboard-artifacts: repository and symlinked-worktree targets fail before changing preserved baseline bytes', () => {
test('SCN-dashboard-artifacts: repository, temporary-root, pre-existing and symlink targets fail before changing preserved bytes', () => {
const repositoryRoot = repositoryFixture();
const baseline = join(repositoryRoot, 'reports', 'design-system', 'baseline.png');
const before = readFileSync(baseline);
const direct = join(repositoryRoot, 'reports', 'design-system');
for (const direct of [join(repositoryRoot, 'reports', 'design-system'), join(repositoryRoot, '..captures')]) {
assert.throws(() => createDashboardArtifactDirectory({
environment: { TORCH_CHECK_ARTIFACT_DIR: direct }, repositoryRoot,
}), (error) => error.code === 'DASHBOARD_ARTIFACT_DIRECTORY_FORBIDDEN');
}
assert.throws(() => createDashboardArtifactDirectory({
environment: { TORCH_CHECK_ARTIFACT_DIR: direct }, repositoryRoot,
environment: {}, repositoryRoot, temporaryRoot: join(repositoryRoot, 'unsafe-tmp'),
}), (error) => error.code === 'DASHBOARD_ARTIFACT_DIRECTORY_FORBIDDEN');
assert.deepEqual(readFileSync(baseline), before);
@@ -65,4 +71,22 @@ test('SCN-dashboard-artifacts: repository and symlinked-worktree targets fail be
}), (error) => error.code === 'DASHBOARD_ARTIFACT_DIRECTORY_FORBIDDEN');
assert.deepEqual(readFileSync(baseline), before);
assert.equal(existsSync(join(linkedWorktree, 'reports', 'design-system', 'torch-dashboard-demo-desktop.png')), false);
const output = mkdtempSync(join(tmpdir(), 'torch-dashboard-existing-output-'));
const expected = join(output, 'torch-dashboard-demo-desktop.png');
writeFileSync(expected, 'existing user evidence');
const external = createDashboardArtifactDirectory({ environment: { TORCH_CHECK_ARTIFACT_DIR: output }, repositoryRoot });
assert.throws(() => prepareDashboardArtifactTargets(external, ['torch-dashboard-demo-desktop.png']),
(error) => error.code === 'DASHBOARD_ARTIFACT_TARGET_EXISTS');
assert.equal(readFileSync(expected, 'utf8'), 'existing user evidence');
const linkedOutput = mkdtempSync(join(tmpdir(), 'torch-dashboard-linked-output-'));
const linkedExpected = join(linkedOutput, 'torch-dashboard-demo-desktop.png');
symlinkSync(baseline, linkedExpected);
const linkedExternal = createDashboardArtifactDirectory({
environment: { TORCH_CHECK_ARTIFACT_DIR: linkedOutput }, repositoryRoot,
});
assert.throws(() => prepareDashboardArtifactTargets(linkedExternal, ['torch-dashboard-demo-desktop.png']),
(error) => error.code === 'DASHBOARD_ARTIFACT_TARGET_EXISTS');
assert.deepEqual(readFileSync(baseline), before);
});