#!/usr/bin/env node const assert = require("assert"); const cp = require("child_process"); const net = require("net"); const path = require("path"); const repo = path.resolve(__dirname, ".."); const project = path.join(repo, "examples/launch-build-demo"); function runDisasmer(args) { return new Promise((resolve) => { const child = cp.spawn( "cargo", ["run", "-q", "-p", "disasmer-cli", "--bin", "disasmer", "--", ...args], { cwd: repo, stdio: ["ignore", "pipe", "pipe"], } ); let stdout = ""; let stderr = ""; child.stdout.setEncoding("utf8"); child.stderr.setEncoding("utf8"); child.stdout.on("data", (chunk) => { stdout += chunk; }); child.stderr.on("data", (chunk) => { stderr += chunk; }); child.on("close", (code, signal) => { resolve({ code, signal, stdout, stderr }); }); }); } async function runWithOneCoordinatorResponse(buildArgs, response) { let request = ""; const server = net.createServer((socket) => { socket.setEncoding("utf8"); socket.on("data", (chunk) => { request += chunk; if (!request.includes("\n")) return; socket.write(JSON.stringify(response) + "\n"); socket.end(); server.close(); }); }); const address = await new Promise((resolve) => { server.listen(0, "127.0.0.1", () => resolve(server.address())); }); const coordinator = `http://${address.address}:${address.port}`; const result = await runDisasmer(buildArgs(coordinator)); return { request, result }; } async function main() { const nonInteractive = await runDisasmer([ "run", "build", "--project", project, "--non-interactive", "--json", ]); assert.strictEqual(nonInteractive.signal, null, nonInteractive.stderr); assert.strictEqual(nonInteractive.code, 20, nonInteractive.stderr); assert.doesNotMatch(nonInteractive.stderr, /Opening Disasmer browser login/); const nonInteractiveReport = JSON.parse(nonInteractive.stdout); assert.strictEqual(nonInteractiveReport.status, "authentication_required"); assert.strictEqual(nonInteractiveReport.non_interactive, true); assert.strictEqual(nonInteractiveReport.browser_opened, false); assert.strictEqual(nonInteractiveReport.machine_error.category, "authentication"); assert.strictEqual(nonInteractiveReport.machine_error.stable_exit_code, 20); assert.strictEqual( nonInteractiveReport.machine_error.process_exit_code_applied, true ); assert( nonInteractiveReport.machine_error.next_actions.includes( "pass --local to run against local services" ) ); let request = ""; const server = net.createServer((socket) => { socket.setEncoding("utf8"); socket.on("data", (chunk) => { request += chunk; if (!request.includes("\n")) return; socket.write( JSON.stringify({ type: "error", message: "quota unavailable: resource limit exceeded for api_calls", }) + "\n" ); socket.end(); server.close(); }); }); const address = await new Promise((resolve) => { server.listen(0, "127.0.0.1", () => resolve(server.address())); }); const coordinator = `http://${address.address}:${address.port}`; const result = await runDisasmer([ "run", "build", "--project", project, "--coordinator", coordinator, "--json", ]); assert.strictEqual(result.signal, null, result.stderr); assert.strictEqual(result.code, 22, result.stderr); assert.match(request, /"type":"start_process"/); const report = JSON.parse(result.stdout); assert.strictEqual(report.status, "coordinator_rejected"); assert.strictEqual(report.run_start.machine_error.category, "quota"); assert.strictEqual(report.run_start.machine_error.resource_category, "api_calls"); assert.strictEqual(report.run_start.machine_error.community_tier_language, true); assert.strictEqual( report.run_start.machine_error.community_tier_label, "community tier" ); assert.doesNotMatch(result.stdout, new RegExp(["free", "tier"].join(" "), "i")); assert.strictEqual( report.run_start.machine_error.private_abuse_heuristics_exposed, false ); assert.strictEqual(report.run_start.machine_error.stable_exit_code, 22); assert.strictEqual( report.run_start.machine_error.process_exit_code_applied, true ); assert( report.run_start.machine_error.next_actions.includes("disasmer quota status") ); const artifactDownload = await runWithOneCoordinatorResponse( (coordinator) => [ "artifact", "download", "app.txt", "--coordinator", coordinator, "--json", ], { type: "artifact_download_denied", message: "artifact download unauthorized for project", } ); assert.strictEqual(artifactDownload.result.signal, null, artifactDownload.result.stderr); assert.strictEqual(artifactDownload.result.code, 21, artifactDownload.result.stderr); assert.match(artifactDownload.request, /"type":"create_artifact_download_link"/); const artifactDownloadReport = JSON.parse(artifactDownload.result.stdout); assert.strictEqual( artifactDownloadReport.download_session.machine_error.category, "authorization" ); assert.strictEqual( artifactDownloadReport.download_session.machine_error.process_exit_code_applied, true ); const artifactExport = await runWithOneCoordinatorResponse( (coordinator) => [ "artifact", "export", "app.txt", "--to", path.join(project, "target", "blocked-artifact.txt"), "--coordinator", coordinator, "--json", ], { type: "artifact_export_unavailable", message: "direct connectivity unavailable for artifact export", } ); assert.strictEqual(artifactExport.result.signal, null, artifactExport.result.stderr); assert.strictEqual(artifactExport.result.code, 25, artifactExport.result.stderr); assert.match(artifactExport.request, /"type":"export_artifact_to_node"/); const artifactExportReport = JSON.parse(artifactExport.result.stdout); assert.strictEqual( artifactExportReport.export_plan.machine_error.category, "connectivity" ); assert.strictEqual( artifactExportReport.export_plan.machine_error.process_exit_code_applied, true ); const confirmation = await runDisasmer([ "process", "cancel", "--coordinator", "127.0.0.1:9", "--json", ]); assert.strictEqual(confirmation.signal, null, confirmation.stderr); assert.strictEqual(confirmation.code, 23, confirmation.stderr); const confirmationReport = JSON.parse(confirmation.stdout); assert.strictEqual(confirmationReport.status, "confirmation_required"); assert.strictEqual(confirmationReport.coordinator_request_sent, false); assert.strictEqual(confirmationReport.machine_error.category, "policy"); assert.strictEqual( confirmationReport.machine_error.process_exit_code_applied, true ); assert( confirmationReport.next_actions.some((action) => action.includes("--yes")) ); } main() .then(() => { console.log("CLI error exit smoke passed"); }) .catch((error) => { console.error(error); process.exit(1); });