diff --git a/server-tools/lake-lamp-authz/architecture-provision-broker.js b/server-tools/lake-lamp-authz/architecture-provision-broker.js index dab5059..ff65030 100644 --- a/server-tools/lake-lamp-authz/architecture-provision-broker.js +++ b/server-tools/lake-lamp-authz/architecture-provision-broker.js @@ -29,10 +29,7 @@ function validateManifest(manifest, resource) { const unit = String(manifest.module && manifest.module.unit || ""); if (!/^[A-Za-z0-9_.@-]+\.service$/.test(unit)) throw new Error("invalid_unit_name"); if (manifest.schema === "guanghu.existing-service-update-request/v1") return validateServiceUpdateManifest(manifest, unit); - if (manifest.status !== "ARCHITECTURE_PACKAGE_READY · INITIAL_PROVISION_PENDING") { - if (/^DEPLOYED(?:_| )/.test(String(manifest.status || ""))) throw new Error("manifest_already_finalized"); - throw new Error("manifest_not_pending"); - } + if (manifest.status !== "ARCHITECTURE_PACKAGE_READY · INITIAL_PROVISION_PENDING") throw new Error("manifest_not_pending"); if (!manifest.initial_provision || manifest.initial_provision.kind !== "new-architecture-unit") throw new Error("not_initial_architecture_unit"); if (!Array.isArray(manifest.source_paths) || manifest.source_paths.length < 1 || manifest.source_paths.length > 64 || manifest.source_paths.some(item => !safeRelative(item))) throw new Error("invalid_source_paths"); const unitMatches = manifest.source_paths.filter(item => path.basename(item) === unit); diff --git a/server-tools/lake-lamp-authz/architecture-provision-broker.test.js b/server-tools/lake-lamp-authz/architecture-provision-broker.test.js index a04b315..43299a7 100644 --- a/server-tools/lake-lamp-authz/architecture-provision-broker.test.js +++ b/server-tools/lake-lamp-authz/architecture-provision-broker.test.js @@ -35,22 +35,6 @@ test("architecture deployment defaults to the current Fifth Domain code channel" assert.doesNotMatch(source, /ARCHITECTURE_PROVISION_REPO_URL \|\| "https:\/\/guanghulab\.com\/fifth-domain\//); }); -test("a completed architecture manifest is distinguished from an invalid pending state", () => { - const completed = manifest(); - completed.status = "DEPLOYED_RUNNING_COMPANION · STAGE_B_BOUNDED_RESTART_PROVEN"; - assert.throws( - () => validateManifest(completed, { requestId, commit }), - /manifest_already_finalized/, - ); - - const invalid = manifest(); - invalid.status = "UNKNOWN"; - assert.throws( - () => validateManifest(invalid, { requestId, commit }), - /manifest_not_pending/, - ); -}); - test("unit requires non-root systemd hardening and release placeholder", () => { const unit = "[Service]\nUser=guanghu\nGroup=guanghu\nNoNewPrivileges=true\nPrivateTmp=true\nProtectSystem=strict\nProtectHome=true\nExecStart=/usr/bin/node __RELEASE_ROOT__/server.js\n"; assert.equal(validateUnit(unit), unit); diff --git a/server-tools/lake-lamp-authz/deployment-event-worker.js b/server-tools/lake-lamp-authz/deployment-event-worker.js index fdd05bd..8e34680 100644 --- a/server-tools/lake-lamp-authz/deployment-event-worker.js +++ b/server-tools/lake-lamp-authz/deployment-event-worker.js @@ -32,32 +32,10 @@ async function processOne(options = {}) { const checked = validateEvent(event, options.registry || loadRegistry(options.registryFile)); if (checked) throw new Error(checked); const result = await (options.provisionFn || provision)({ target: event.target, action: "provision-approved-architecture", resource: event.resource }, { repoUrl: options.registry ? options.registry[event.repo].repo_url : loadRegistry(options.registryFile)[event.repo].repo_url }); - const noDeploymentRequired = result.ok === false && result.error === "manifest_already_finalized"; - const completed = result.ok || noDeploymentRequired; - const receipt = { - schema: "guanghu.deployment-agent-receipt/v1", - event_id: event.event_id, - workorder_id: event.workorder_id, - repo: event.repo, - branch: event.branch, - commit_sha: event.commit_sha, - resource: event.resource, - result: result.ok - ? "DEPLOYED_AND_VERIFIED" - : noDeploymentRequired - ? "NO_DEPLOYMENT_REQUIRED" - : "FAILED_OR_ROLLED_BACK", - diagnostic_code: result.ok - ? "deployment_succeeded" - : noDeploymentRequired - ? "manifest_already_finalized" - : String(result.error || "deployment_failed"), - evidence: result, - recorded_at: new Date().toISOString(), - }; + const receipt = { schema: "guanghu.deployment-agent-receipt/v1", event_id: event.event_id, workorder_id: event.workorder_id, repo: event.repo, branch: event.branch, commit_sha: event.commit_sha, resource: event.resource, result: result.ok ? "DEPLOYED_AND_VERIFIED" : "FAILED_OR_ROLLED_BACK", diagnostic_code: result.ok ? "deployment_succeeded" : String(result.error || "deployment_failed"), evidence: result, recorded_at: new Date().toISOString() }; writeAtomic(path.join(receiptsDir, `${event.event_id}.json`), `${JSON.stringify(receipt, null, 2)}\n`); - fs.renameSync(processing, `${processing}.${completed ? "done" : "failed"}`); - return { ok: completed, state: receipt.result, receipt }; + fs.renameSync(processing, `${processing}.${result.ok ? "done" : "failed"}`); + return { ok: result.ok, state: receipt.result, receipt }; } catch (error) { const receipt = { schema: "guanghu.deployment-agent-receipt/v1", event_id: event && event.event_id || "", result: "REJECTED", diagnostic_code: String(error && error.message || "deployment_event_invalid").slice(0, 160), recorded_at: new Date().toISOString() }; writeAtomic(path.join(receiptsDir, `${path.basename(file, ".json")}.rejected.json`), `${JSON.stringify(receipt, null, 2)}\n`); diff --git a/server-tools/lake-lamp-authz/deployment-event-worker.test.js b/server-tools/lake-lamp-authz/deployment-event-worker.test.js index f1aa285..79834ee 100644 --- a/server-tools/lake-lamp-authz/deployment-event-worker.test.js +++ b/server-tools/lake-lamp-authz/deployment-event-worker.test.js @@ -14,34 +14,6 @@ test("resident deployment agent consumes only an explicit immutable event and wr assert.equal(JSON.parse(fs.readFileSync(path.join(receipts, "event-1.json"))).diagnostic_code, "deployment_succeeded"); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); -test("a finalized manifest produces a clean no-deployment receipt", async () => { - const root = fs.mkdtempSync(path.join(os.tmpdir(), "lake-lamp-deploy-noop-")); - const queue = path.join(root, "queue"), receipts = path.join(root, "receipts"), sha = "c".repeat(40); - fs.mkdirSync(queue); - fs.writeFileSync(path.join(queue, "event.json"), JSON.stringify({ - schema: "guanghu.deployment-event/v1", - event_id: "event-finalized", - state: "queued_for_resident_agent", - repo: "bingshuo/guanghu-ice-heart", - branch: "main", - commit_sha: sha, - workorder_id: "order-finalized", - resource: `GLS-FINALIZED-DEPLOY@${sha}`, - manifest: "deployment/requests/GLS-FINALIZED-DEPLOY.json", - })); - try { - const result = await processOne({ - queueDir: queue, - receiptsDir: receipts, - registry: { "bingshuo/guanghu-ice-heart": { repo_url: "https://example.invalid/code.git" } }, - provisionFn: async () => ({ ok: false, error: "manifest_already_finalized" }), - }); - assert.equal(result.ok, true); - assert.equal(result.state, "NO_DEPLOYMENT_REQUIRED"); - assert.equal(result.receipt.diagnostic_code, "manifest_already_finalized"); - assert.equal(fs.existsSync(path.join(queue, "event.json.processing.done")), true); - } finally { fs.rmSync(root, { recursive: true, force: true }); } -}); test("resident agent rechecks source ownership before deployment", async () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), "lake-lamp-source-policy-")); const queue = path.join(root, "queue"), receipts = path.join(root, "receipts"), sha = "b".repeat(40);