otherwise / scripts /verify-release.mjs
citispire
Release named states, saved scenarios and causal study handouts
1af6033
Raw History Blame Contribute Delete
2.47 kB
import fs from 'node:fs';
import path from 'node:path';
import assert from 'node:assert/strict';
const root = path.resolve('dist/client'),
hosting = JSON.parse(fs.readFileSync('.openai/hosting.json', 'utf8'));
assert.equal(hosting.static.directory, 'dist/client');
assert.equal(hosting.d1, null);
assert.equal(hosting.r2, null);
const files = [];
function visit(dir) {
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
const p = path.join(dir, e.name);
assert.ok(!e.isSymbolicLink(), 'No symlinks in public output');
if (e.isDirectory()) visit(p);
else files.push(p);
}
}
visit(root);
assert.ok(fs.existsSync(path.join(root, 'index.html')));
const html = fs.readFileSync(path.join(root, 'index.html'), 'utf8');
for (const phrase of [
'OTHERWISE',
'Compare what you observe',
'The assumed world',
'Probability under the edited model',
'84%',
'Keep the question behind the number',
])
assert.ok(html.includes(phrase), 'Missing product text: ' + phrase);
for (const p of files) {
const relative = path.relative(root, p).replaceAll('\\', '/');
assert.ok(
!/(^|\/)(server|node_modules|\.git|\.wrangler|\.env)/.test(relative),
relative,
);
assert.ok(!relative.endsWith('.map'), 'No source maps in public release');
if (/\.(html|js|json|css|txt)$/.test(p)) {
const content = fs.readFileSync(p, 'utf8');
assert.ok(
!/sk-(?:proj-)?[A-Za-z0-9_-]{24,}|ghp_[A-Za-z0-9]{20,}|hf_[A-Za-z0-9]{20,}/.test(
content,
),
'Recognized credential pattern in ' + relative,
);
assert.ok(
!/__sites_local_auth|local_seedy|seedy@sites\.test/.test(content),
'Development auth marker in public output',
);
}
}
for (const match of html.matchAll(
/(?:src|href)="(\/(?:assets|_next)\/[^"?#]+)"/g,
)) {
assert.ok(
fs.existsSync(path.join(root, decodeURIComponent(match[1]))),
'Missing referenced public asset: ' + match[1],
);
}
const allScripts = files
.filter((f) => f.endsWith('.js'))
.map((f) => fs.readFileSync(f, 'utf8'))
.join('\n');
for (const name of [
'read_otherwise_experiment',
'configure_otherwise_query',
'replace_otherwise_experiment',
])
assert.ok(allScripts.includes(name), 'Missing browser control');
console.log(
'Static release check passed: ' +
files.length +
' public files; real product content/assets and browser controls present; no checked secrets, server directories, local-auth markers or source maps.',
);