feat: add L6 CLI web MVP gate entry
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { loadMvpGateSummary } from "../internal/mvp-gate/summary.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const outputPath = path.join(repoRoot, "web/hwlab-cloud-web/gate-summary.mjs");
|
||||
const summary = loadMvpGateSummary(repoRoot);
|
||||
const body = `// Generated from reports/dev-gate/dev-mvp-gate-report.json and fixtures/mvp/m5-e2e/dry-run-plan.json.
|
||||
// Run node scripts/export-web-gate-summary.mjs after changing those fixtures.
|
||||
export const gateSummary = ${JSON.stringify(summary, null, 2)};
|
||||
`;
|
||||
|
||||
fs.writeFileSync(outputPath, body);
|
||||
process.stdout.write(`wrote ${path.relative(repoRoot, outputPath)}\n`);
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from "node:assert/strict";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { loadMvpGateSummary } from "../internal/mvp-gate/summary.mjs";
|
||||
import { runCli } from "../tools/hwlab-cli/lib/cli.mjs";
|
||||
import { gateSummary } from "../web/hwlab-cloud-web/gate-summary.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
async function captureCli(args) {
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
const exitCode = await runCli(args, {
|
||||
cwd: repoRoot,
|
||||
stdout: {
|
||||
write(chunk) {
|
||||
stdout += chunk;
|
||||
}
|
||||
},
|
||||
stderr: {
|
||||
write(chunk) {
|
||||
stderr += chunk;
|
||||
}
|
||||
}
|
||||
});
|
||||
return { exitCode, stdout, stderr };
|
||||
}
|
||||
|
||||
const summary = loadMvpGateSummary(repoRoot);
|
||||
assert.equal(summary.endpoint, "http://74.48.78.17:6667");
|
||||
assert.deepEqual(
|
||||
summary.milestones.map((item) => item.id),
|
||||
["M0", "M1", "M2", "M3", "M4", "M5"]
|
||||
);
|
||||
|
||||
const dryRun = await captureCli(["test", "e2e", "--env", "dev", "--mvp"]);
|
||||
assert.equal(dryRun.exitCode, 0, dryRun.stderr);
|
||||
const dryRunJson = JSON.parse(dryRun.stdout);
|
||||
assert.equal(dryRunJson.mode, "dry-run");
|
||||
assert.equal(dryRunJson.environment, "dev");
|
||||
assert.equal(dryRunJson.endpoint, summary.endpoint);
|
||||
assert.equal(dryRunJson.contractStatus.artifacts.count, 13);
|
||||
assert.equal(dryRunJson.contractStatus.health.count, 14);
|
||||
assert.equal(dryRunJson.contractStatus.topology.gatewaySessions, 2);
|
||||
assert.equal(dryRunJson.contractStatus.topology.boxResources, 2);
|
||||
assert.equal(dryRunJson.contractStatus.topology.patchPanelStatusId, "pps_m5-0001");
|
||||
assert.equal(dryRunJson.contractStatus.agent.agentSessionId, "agt_m5-0001");
|
||||
assert.equal(dryRunJson.contractStatus.evidence.records.length, 2);
|
||||
assert.match(dryRunJson.statement, /no DEV\/PROD changes/);
|
||||
|
||||
const explicitDryRun = await captureCli(["test", "e2e", "--env", "dev", "--mvp", "--dry-run"]);
|
||||
assert.equal(explicitDryRun.exitCode, 0, explicitDryRun.stderr);
|
||||
assert.equal(JSON.parse(explicitDryRun.stdout).mode, "dry-run");
|
||||
|
||||
const liveBlocked = await captureCli([
|
||||
"test",
|
||||
"e2e",
|
||||
"--env",
|
||||
"dev",
|
||||
"--mvp",
|
||||
"--live",
|
||||
"--confirm-dev",
|
||||
"--confirmed-non-production"
|
||||
]);
|
||||
assert.equal(liveBlocked.exitCode, 2);
|
||||
const liveBlockedJson = JSON.parse(liveBlocked.stderr);
|
||||
assert.equal(liveBlockedJson.code, "BLOCKED");
|
||||
assert.equal(liveBlockedJson.blockers[0].type, "network_blocker");
|
||||
|
||||
assert.equal(gateSummary.endpoint, summary.endpoint);
|
||||
assert.equal(gateSummary.gateStatus, "blocked");
|
||||
assert.equal(gateSummary.artifactCount, 13);
|
||||
assert.equal(gateSummary.healthCount, 14);
|
||||
assert.equal(gateSummary.gatewaySessionCount, 2);
|
||||
assert.equal(gateSummary.boxResourceCount, 2);
|
||||
assert.equal(gateSummary.topology.patchPanel.serviceId, "hwlab-patch-panel");
|
||||
assert.equal(gateSummary.agent.agentServiceId, "hwlab-agent-mgr");
|
||||
assert.equal(gateSummary.agent.workerServiceId, "hwlab-agent-worker");
|
||||
assert.equal(gateSummary.evidenceRecords.length, 2);
|
||||
|
||||
console.log("L6 CLI/Web smoke passed: CLI and Web read the M0-M5 gate report");
|
||||
@@ -310,11 +310,19 @@ async function smokeCliDryRunFixture() {
|
||||
});
|
||||
|
||||
assert.equal(exitCode, 0, stderr);
|
||||
assert.match(stdout, /hwlab-cli test e2e --env dev --mvp --dry-run/);
|
||||
assert.match(stdout, /cloud-web\/cloud-api/);
|
||||
assert.match(stdout, /hardware trusted closed loop/);
|
||||
assert.match(stdout, /evidence_mvp-runtime-plan/);
|
||||
assert.match(stdout, /dry-run only: no DEV\/PROD changes were made/);
|
||||
const output = JSON.parse(stdout);
|
||||
assert.equal(output.command, "hwlab-cli test e2e --env dev --mvp --dry-run");
|
||||
assert.equal(output.mode, "dry-run");
|
||||
assert.equal(output.environment, "dev");
|
||||
assert.equal(output.endpoint, DEV_ENDPOINT);
|
||||
assert.equal(output.safety.allowNetwork, false);
|
||||
assert.equal(output.contractStatus.artifacts.services.includes("hwlab-cloud-web"), true);
|
||||
assert.equal(output.contractStatus.artifacts.services.includes("hwlab-cloud-api"), true);
|
||||
assert.equal(output.contractStatus.topology.gatewaySessions, 2);
|
||||
assert.equal(output.contractStatus.topology.boxResources, 2);
|
||||
assert.equal(output.contractStatus.agent.agentSessionId, "agt_m5-0001");
|
||||
assert.equal(output.contractStatus.evidence.records.length, 2);
|
||||
assert.match(output.statement, /no DEV\/PROD changes/);
|
||||
|
||||
logOk("CLI dry-run fixture parse");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user