Source commit: 1714a9eedd5b1e30c6c9aceb7a999f2f695ba83c Public tree identity: sha256:e5daffad23fa7c7f1822adccd3c3b4ee0bc7f1a45e0d321eb9a6fb8282b269db
182 lines
5.6 KiB
JavaScript
182 lines
5.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
|
|
const repo = path.resolve(__dirname, "..");
|
|
|
|
function walk(relativePath, files = []) {
|
|
const fullPath = path.join(repo, relativePath);
|
|
if (!fs.existsSync(fullPath)) return files;
|
|
const stat = fs.statSync(fullPath);
|
|
if (stat.isDirectory()) {
|
|
const base = path.basename(relativePath);
|
|
if (["target", "node_modules", ".git"].includes(base)) return files;
|
|
for (const entry of fs.readdirSync(fullPath)) {
|
|
walk(path.join(relativePath, entry), files);
|
|
}
|
|
return files;
|
|
}
|
|
files.push(relativePath);
|
|
return files;
|
|
}
|
|
|
|
function read(relativePath) {
|
|
return fs.readFileSync(path.join(repo, relativePath), "utf8");
|
|
}
|
|
|
|
function copyPublicTree(sourceRoot, destinationRoot, relativePath = ".") {
|
|
const skippedDirectories = new Set([
|
|
".git",
|
|
"target",
|
|
"node_modules",
|
|
"private",
|
|
"experiments",
|
|
]);
|
|
const parts = relativePath.split(path.sep).filter(Boolean);
|
|
if (parts.some((part) => skippedDirectories.has(part))) {
|
|
return;
|
|
}
|
|
|
|
const source = path.join(sourceRoot, relativePath);
|
|
const destination = path.join(destinationRoot, relativePath);
|
|
const stat = fs.statSync(source);
|
|
if (stat.isDirectory()) {
|
|
fs.mkdirSync(destination, { recursive: true });
|
|
for (const entry of fs.readdirSync(source)) {
|
|
copyPublicTree(sourceRoot, destinationRoot, path.join(relativePath, entry));
|
|
}
|
|
return;
|
|
}
|
|
|
|
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
fs.copyFileSync(source, destination);
|
|
}
|
|
|
|
function assertPublicSplitTreeIsCoherent() {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "disasmer-public-split-"));
|
|
try {
|
|
copyPublicTree(repo, tmp);
|
|
|
|
for (const forbidden of ["private", "experiments"]) {
|
|
assert(
|
|
!fs.existsSync(path.join(tmp, forbidden)),
|
|
`${forbidden} must be absent from the public split tree`
|
|
);
|
|
}
|
|
|
|
const workspaceToml = fs.readFileSync(path.join(tmp, "Cargo.toml"), "utf8");
|
|
const membersBlock = workspaceToml.match(/members\s*=\s*\[([\s\S]*?)\]/);
|
|
assert(membersBlock, "public workspace must define members");
|
|
const members = [...membersBlock[1].matchAll(/"([^"]+)"/g)].map(
|
|
(match) => match[1]
|
|
);
|
|
assert(members.length > 0, "public workspace must list members");
|
|
for (const member of members) {
|
|
assert(
|
|
!member.startsWith("private/") && !member.startsWith("experiments/"),
|
|
`public workspace member must not point at filtered source: ${member}`
|
|
);
|
|
assert(
|
|
fs.existsSync(path.join(tmp, member, "Cargo.toml")),
|
|
`public workspace member is missing after split: ${member}`
|
|
);
|
|
}
|
|
|
|
for (const required of [
|
|
"scripts/acceptance-public.sh",
|
|
"scripts/verify-public-split.sh",
|
|
"scripts/public-private-boundary-smoke.js",
|
|
"scripts/public-local-demo-matrix-smoke.js",
|
|
"vscode-extension/package.json",
|
|
"examples/launch-build-demo/Cargo.toml",
|
|
]) {
|
|
assert(
|
|
fs.existsSync(path.join(tmp, required)),
|
|
`public split tree is missing ${required}`
|
|
);
|
|
}
|
|
} finally {
|
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
function publicSourceFiles() {
|
|
return [
|
|
...walk("crates"),
|
|
...walk("examples"),
|
|
...walk("scripts"),
|
|
...walk("vscode-extension"),
|
|
"Cargo.toml",
|
|
].filter((file) => {
|
|
if (file === "scripts/acceptance-private.sh") return false;
|
|
if (file === "scripts/acceptance-evidence-contract-smoke.js") return false;
|
|
if (file === "scripts/acceptance-environment-contract-smoke.js") return false;
|
|
if (file === "scripts/docs-smoke.js") return false;
|
|
if (file === "scripts/public-private-boundary-smoke.js") return false;
|
|
if (file === "scripts/release-blocker-smoke.js") return false;
|
|
return /\.(rs|toml|js|json|sh)$/.test(file);
|
|
});
|
|
}
|
|
|
|
const forbiddenPublicPatterns = [
|
|
/\bdisasmer[_-]hosted[_-]policy\b/,
|
|
/private\/hosted-policy/,
|
|
/path\s*=\s*["'][^"']*private\//,
|
|
/include!\s*\([^)]*private\//,
|
|
/mod\s+private_hosted/,
|
|
];
|
|
|
|
for (const file of publicSourceFiles()) {
|
|
const content = read(file);
|
|
for (const pattern of forbiddenPublicPatterns) {
|
|
assert(
|
|
!pattern.test(content),
|
|
`public source ${file} must not reference private hosted code via ${pattern}`
|
|
);
|
|
}
|
|
}
|
|
|
|
const workspace = read("Cargo.toml");
|
|
assert(
|
|
!/members\s*=\s*\[[\s\S]*private\//.test(workspace),
|
|
"public workspace members must not include private hosted crates"
|
|
);
|
|
assertPublicSplitTreeIsCoherent();
|
|
|
|
const privateHostedRoot = path.join(repo, "private", "hosted-policy");
|
|
if (fs.existsSync(privateHostedRoot)) {
|
|
const privateCargo = read("private/hosted-policy/Cargo.toml");
|
|
assert.match(privateCargo, /name\s*=\s*"disasmer-hosted-policy"/);
|
|
assert.match(privateCargo, /disasmer-core\s*=\s*\{/);
|
|
assert.match(privateCargo, /disasmer-coordinator\s*=\s*\{/);
|
|
|
|
const privateLib = read("private/hosted-policy/src/lib.rs");
|
|
for (const required of [
|
|
"AuthentikOidcConfig",
|
|
"CommunityTierPolicy",
|
|
"AdminControls",
|
|
"preflight_zero_capability_hosted_wasm",
|
|
"impl CapabilityPolicy for CommunityTierPolicy",
|
|
"AuthContext",
|
|
]) {
|
|
assert(
|
|
privateLib.includes(required),
|
|
`private hosted policy is missing ${required}`
|
|
);
|
|
}
|
|
|
|
const privateFiles = walk("private").filter((file) => !file.includes("/target/"));
|
|
const privateNodeRuntimeFiles = privateFiles.filter((file) =>
|
|
/(^|\/)(disasmer-node|node-runtime)(\/|$)/.test(file)
|
|
);
|
|
assert.deepStrictEqual(
|
|
privateNodeRuntimeFiles,
|
|
[],
|
|
"hosted mode must not carry a forked private node runtime"
|
|
);
|
|
}
|
|
|
|
console.log("Public/private boundary smoke passed");
|