fix: separate Fifth Domain source deployment identities
This commit is contained in:
parent
711cd232ca
commit
83589aa2c2
27 changed files with 620 additions and 73 deletions
|
|
@ -60,6 +60,7 @@ function createApp(options = {}) {
|
|||
});
|
||||
const repoGrantDir = options.repoGrantDir || process.env.LAKE_LAMP_REPO_GRANT_DIR || "/var/lib/guanghu/repo-authorizations";
|
||||
const deploymentQueueDir = options.deploymentQueueDir || process.env.LAKE_LAMP_DEPLOYMENT_EVENT_DIR || "/var/lib/guanghu/deployment-events";
|
||||
const deploymentRegistryFile = options.deploymentRegistryFile || process.env.LAKE_LAMP_DEPLOYMENT_REPOSITORIES || "/etc/guanghu/lake-lamp/deployment-repositories.json";
|
||||
const executeAction = options.executeAction || executeRegisteredAction;
|
||||
// Creating a powerless request must never become harder than the human mail
|
||||
// handoff. Keep at least three attempts per network each hour.
|
||||
|
|
@ -81,6 +82,10 @@ function createApp(options = {}) {
|
|||
manager.failApprovalEmail(handoffToken);
|
||||
return { ok: false, reason: "no_registered_approver" };
|
||||
}
|
||||
if (!manager.bindApprover(handoffToken, approver.id)) {
|
||||
manager.failApprovalEmail(handoffToken);
|
||||
return { ok: false, reason: "approver_binding_failed" };
|
||||
}
|
||||
const approvalUrl = `${publicBaseUrl}/approve/${issued.approvalToken}`;
|
||||
const emailSent = await sendEmail({
|
||||
to: approver.email,
|
||||
|
|
@ -325,7 +330,23 @@ function createApp(options = {}) {
|
|||
if (!verified.ok) return json(res, 403, failure(verified.reason));
|
||||
const map = mapGate.read(target);
|
||||
if (!mapGate.verify(token, target, map.hash).ok) return json(res, 423, failure("map_ack_required", "先读取并确认导航图。", { required_action: "read-navigation-map" }));
|
||||
const queued = enqueueDeploymentEvent({ schema: "guanghu.deployment-intent/v1", repo, branch, commit_sha: commit, resource, manifest, workorder_id: verified.session.workorderId }, { repo, branch, commit_sha: commit }, deploymentQueueDir);
|
||||
const deploymentRepositories = options.deploymentRepositories || loadDeploymentRepositories(deploymentRegistryFile);
|
||||
const queued = enqueueDeploymentEvent({
|
||||
schema: "guanghu.deployment-intent/v1",
|
||||
repo,
|
||||
branch,
|
||||
commit_sha: commit,
|
||||
resource,
|
||||
manifest,
|
||||
workorder_id: verified.session.workorderId,
|
||||
deployment_source: body.deployment_source || null,
|
||||
}, { repo, branch, commit_sha: commit }, deploymentQueueDir, {
|
||||
authorizer_id: verified.session.authorizerId,
|
||||
persona_id: verified.session.persona.pid,
|
||||
execution_runtime_id: String(body.execution_runtime_id || ""),
|
||||
target,
|
||||
registry: deploymentRepositories,
|
||||
});
|
||||
const operationReceipt = receipt({ state: queued.state === "queued_for_resident_agent" ? "queued" : "blocked", diagnostic_code: queued.diagnostic_code || "deployment_event_queued", workorder_id: verified.session.workorderId, target, action: "dispatch-approved-deployment", evidence: { repo, branch, commit_sha: commit, event_id: queued.event_id || "" }, next_step: queued.state === "queued_for_resident_agent" ? "常驻部署 Agent 将读取该事件并回写部署、健康检查或回滚回执。" : "修正部署绑定信息后重新申请或派发,不要让服务器自行扫描提交。" });
|
||||
manager.recordReceipt(token, operationReceipt);
|
||||
return json(res, queued.state === "queued_for_resident_agent" ? 202 : 400, { ok: queued.state === "queued_for_resident_agent", deployment: queued, receipt: operationReceipt });
|
||||
|
|
@ -339,6 +360,12 @@ function createApp(options = {}) {
|
|||
});
|
||||
}
|
||||
|
||||
function loadDeploymentRepositories(file) {
|
||||
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
if (!parsed || !parsed.repos || typeof parsed.repos !== "object") throw new Error("invalid_deployment_repository_registry");
|
||||
return parsed.repos;
|
||||
}
|
||||
|
||||
function approvalPage(order, token) {
|
||||
return document("小湖灯授权请求", `
|
||||
<p class="eyebrow">LAKE LAMP SECURITY PROTOCOL</p>
|
||||
|
|
@ -416,7 +443,7 @@ function safeEqual(left, right) { const a = Buffer.from(String(left)); const b =
|
|||
function sha256(value) { return crypto.createHash("sha256").update(String(value)).digest("hex"); }
|
||||
function splitCsv(value) { return value.split(",").map(item => item.trim()).filter(Boolean); }
|
||||
function loadApprovers(file, ownerEmail) {
|
||||
if (!file) return ownerEmail ? [{ id: "sovereign-owner", email: ownerEmail, default: true, persona_ids: [], targets: ["*"], scopes: ["*"] }] : [];
|
||||
if (!file) return ownerEmail ? [{ id: "ICE-GL∞", email: ownerEmail, default: true, persona_ids: [], targets: ["*"], scopes: ["*"] }] : [];
|
||||
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
if (!parsed || !Array.isArray(parsed.approvers)) throw new Error("invalid approver registry");
|
||||
return parsed.approvers.filter(item => item && validEmail(item.email)).map(item => ({
|
||||
|
|
|
|||
Loading…
Reference in a new issue