Public dry run dryrun-1714a9eedd5b
Source commit: 1714a9eedd5b1e30c6c9aceb7a999f2f695ba83c Public tree identity: sha256:e5daffad23fa7c7f1822adccd3c3b4ee0bc7f1a45e0d321eb9a6fb8282b269db
This commit is contained in:
commit
20c72e6066
102 changed files with 32054 additions and 0 deletions
176
scripts/hostile-input-contract-smoke.js
Normal file
176
scripts/hostile-input-contract-smoke.js
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const repo = path.resolve(__dirname, "..");
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(repo, relativePath), "utf8");
|
||||
}
|
||||
|
||||
function maybeRead(segments) {
|
||||
const fullPath = path.join(repo, ...segments);
|
||||
if (!fs.existsSync(fullPath)) return null;
|
||||
return fs.readFileSync(fullPath, "utf8");
|
||||
}
|
||||
|
||||
function expect(source, name, pattern) {
|
||||
assert.match(source, pattern, `missing hostile-input evidence: ${name}`);
|
||||
}
|
||||
|
||||
function expectGate(script, gateName) {
|
||||
assert(
|
||||
script.includes("node scripts/hostile-input-contract-smoke.js"),
|
||||
`${gateName} must run hostile-input-contract-smoke.js`
|
||||
);
|
||||
}
|
||||
|
||||
const coreSource = read("crates/disasmer-core/src/source.rs");
|
||||
const coreCapabilities = read("crates/disasmer-core/src/capability.rs");
|
||||
const coordinatorService = read("crates/disasmer-coordinator/src/service.rs");
|
||||
const artifactDownloadSmoke = read("scripts/artifact-download-smoke.js");
|
||||
const operatorPanelSmoke = read("scripts/operator-panel-smoke.js");
|
||||
const schedulerSmoke = read("scripts/scheduler-placement-smoke.js");
|
||||
const sourcePreparationSmoke = read("scripts/source-preparation-smoke.js");
|
||||
const publicAcceptance = read("scripts/acceptance-public.sh");
|
||||
const publicSplit = read("scripts/verify-public-split.sh");
|
||||
const privateAcceptance = read("scripts/acceptance-private.sh");
|
||||
|
||||
for (const [name, pattern] of [
|
||||
["source manifests validate shape", /pub fn validate_public_mvp\(&self\)[\s\S]*self\.validate_shape\(\)\?/],
|
||||
["source manifests reject invalid digests", /SourceManifestError::InvalidDigest/],
|
||||
["source manifests reject invalid custom providers", /SourceManifestError::InvalidProviderId/],
|
||||
["source manifests reject control characters", /DescriptionControlCharacter/],
|
||||
["source manifests reject coordinator checkout access", /CoordinatorCheckoutAccess/],
|
||||
["source manifests reject default source-byte upload", /CoordinatorReceivesSourceBytes/],
|
||||
]) {
|
||||
expect(coreSource, name, pattern);
|
||||
}
|
||||
|
||||
for (const [name, pattern] of [
|
||||
["capability reports validate public shape", /pub fn validate_public_report\(&self\)/],
|
||||
["capability reports validate architecture labels", /InvalidArchitecture/],
|
||||
["capability reports validate OS labels", /InvalidOsLabel/],
|
||||
["capability reports validate source providers", /InvalidSourceProvider/],
|
||||
["source provider ids reject path traversal", /valid_source_provider_id/],
|
||||
]) {
|
||||
expect(coreCapabilities, name, pattern);
|
||||
}
|
||||
|
||||
for (const [name, pattern] of [
|
||||
["coordinator task log tails are bounded", /MAX_TASK_LOG_TAIL_BYTES: usize = 256 \* 1024/],
|
||||
["coordinator validates reported stdout tails", /ReportTaskLog[\s\S]*validate_task_log_tail\("stdout_tail", &stdout_tail\)\?/],
|
||||
["coordinator validates completed task stdout tails", /TaskCompleted[\s\S]*validate_task_log_tail\("stdout_tail", &stdout_tail\)\?/],
|
||||
["coordinator rejects oversized log tail in unit coverage", /"x"\.repeat\(MAX_TASK_LOG_TAIL_BYTES \+ 1\)/],
|
||||
]) {
|
||||
expect(coordinatorService, name, pattern);
|
||||
}
|
||||
|
||||
for (const [name, pattern] of [
|
||||
["service rejects malformed node capability report", /fn service_rejects_malformed_node_capability_report\(\)/],
|
||||
["capability report rejection leaves descriptors empty", /assert!\(service\.node_descriptors\.is_empty\(\)\)/],
|
||||
["node capability report rejects cross-scope writes", /fn service_rejects_node_capability_report_outside_enrollment_scope\(\)/],
|
||||
["task completion rejects cross-scope writes", /task completion outside node scope|outside/],
|
||||
]) {
|
||||
expect(coordinatorService, name, pattern);
|
||||
}
|
||||
|
||||
for (const [name, source, patterns] of [
|
||||
[
|
||||
"artifact download smoke",
|
||||
artifactDownloadSmoke,
|
||||
[
|
||||
/const crossTenant = await send/,
|
||||
/const crossProject = await send/,
|
||||
/const guessed = await send/,
|
||||
/const crossActorOpen = await send/,
|
||||
/token is invalid/,
|
||||
/tenant mismatch/,
|
||||
/project mismatch/,
|
||||
],
|
||||
],
|
||||
[
|
||||
"operator panel smoke",
|
||||
operatorPanelSmoke,
|
||||
[
|
||||
/render_operator_panel/,
|
||||
/submit_panel_event/,
|
||||
/assert\(!JSON\.stringify\(panel\)\.includes\("<script"\)\)/,
|
||||
/assert\(!JSON\.stringify\(panel\)\.toLowerCase\(\)\.includes\("oauth"\)\)/,
|
||||
/rate limit/i,
|
||||
/exceeds download limit/,
|
||||
],
|
||||
],
|
||||
[
|
||||
"scheduler smoke",
|
||||
schedulerSmoke,
|
||||
[/const crossTenantReport = await send/, /report_node_capabilities/, /tenant\\\/project scope/],
|
||||
],
|
||||
[
|
||||
"source preparation smoke",
|
||||
sourcePreparationSmoke,
|
||||
[/const crossTenantCompletion = await send/, /complete_source_preparation/, /tenant\\\/project scope/i],
|
||||
],
|
||||
]) {
|
||||
for (const pattern of patterns) {
|
||||
expect(source, name, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
expectGate(publicAcceptance, "public acceptance");
|
||||
expectGate(publicSplit, "public split acceptance");
|
||||
expectGate(privateAcceptance, "private acceptance");
|
||||
|
||||
const hostedService = maybeRead([
|
||||
"private",
|
||||
"hosted-policy",
|
||||
"src",
|
||||
"bin",
|
||||
"disasmer-hosted-service.rs",
|
||||
]);
|
||||
const hostedSmoke = maybeRead([
|
||||
"private",
|
||||
"hosted-policy",
|
||||
"scripts",
|
||||
"hosted-community-smoke.js",
|
||||
]);
|
||||
|
||||
if (hostedService && hostedSmoke) {
|
||||
for (const [name, pattern] of [
|
||||
["hosted service turns malformed JSON into error responses", /serde_json::from_str::<HostedRequest>[\s\S]*HostedResponse::Error/],
|
||||
["tenant ids are validated", /fn tenant_id\(value: String\)[\s\S]*validate_identifier\("tenant", &value\)\?/],
|
||||
["project ids are validated", /fn project_id\(value: String\)[\s\S]*validate_identifier\("project", &value\)\?/],
|
||||
["user ids are validated", /fn user_id\(value: String\)[\s\S]*validate_identifier\("user", &value\)\?/],
|
||||
["node ids are validated", /fn node_id\(value: String\)[\s\S]*validate_identifier\("node", &value\)\?/],
|
||||
["process ids are validated", /fn process_id\(value: String\)[\s\S]*validate_identifier\("process", &value\)\?/],
|
||||
["task ids are validated", /fn task_id\(value: String\)[\s\S]*validate_identifier\("task", &value\)\?/],
|
||||
["artifact ids are validated", /fn artifact_id\(value: String\)[\s\S]*validate_identifier\("artifact", &value\)\?/],
|
||||
["identifiers reject empty and control/path characters", /fn validate_identifier[\s\S]*trim\(\)\.is_empty\(\)[\s\S]*ch\.is_control\(\) \|\| ch == '\/' \|\| ch == '\\\\'/],
|
||||
["OIDC and agent text fields are bounded", /fn validate_text[\s\S]*value\.len\(\) > max_bytes[\s\S]*contains unsupported characters/],
|
||||
["tokens are bounded", /fn validate_token[\s\S]*value\.len\(\) > max_bytes[\s\S]*contains unsupported characters/],
|
||||
["logs are bounded at service boundary", /fn validate_log[\s\S]*512 \* 1024/],
|
||||
["debug requests validate process and task before inspection", /HostedRequest::DebugProcess[\s\S]*process_id\(process\)\?[\s\S]*task_id\(task\)\?[\s\S]*debug_process/],
|
||||
["download requests validate artifact before action", /HostedRequest::DownloadAction[\s\S]*artifact_id\(artifact\)\?[\s\S]*download_action/],
|
||||
["log completion requests validate task and stdout before recording", /HostedRequest::RecordUserNodeTaskCompletion[\s\S]*task_id\(task\)\?[\s\S]*validate_log\("task stdout", &stdout\)\?[\s\S]*record_user_node_task_completion/],
|
||||
]) {
|
||||
expect(hostedService, name, pattern);
|
||||
}
|
||||
|
||||
for (const [name, pattern] of [
|
||||
["running service rejects malformed JSON", /sendRaw\(addr, "\{not-json"\)/],
|
||||
["running service rejects invalid tenant id", /tenant: " "/],
|
||||
["running service rejects invalid project id", /project: "project\\nbad"/],
|
||||
["running service rejects invalid task id", /task: "compile-linux\\nescape"/],
|
||||
["running service rejects oversized logs", /stdout: "x"\.repeat\(256 \* 1024 \+ 1\)/],
|
||||
["running service rejects cross-tenant debug", /const crossTenantDebug = await send/],
|
||||
["running service rejects cross-tenant metadata", /const crossTenantMetadata = await send/],
|
||||
["running service rejects cross-tenant download", /const crossTenantDownload = await send/],
|
||||
["foreign snapshots do not reveal objects", /foreignSnapshot[\s\S]*snapshot\.nodes, \[\][\s\S]*snapshot\.logs, \[\][\s\S]*snapshot\.artifacts, \[\]/],
|
||||
]) {
|
||||
expect(hostedSmoke, name, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Hostile input contract smoke passed");
|
||||
Loading…
Add table
Add a link
Reference in a new issue