fix(authz): require email approval for native layout signing

This commit is contained in:
冰朔 2026-08-03 00:00:04 +08:00
commit a385249819
5 changed files with 92 additions and 1 deletions

View file

@ -789,6 +789,61 @@ test("GHDR controller transport endpoints expose jobs and public authority witho
});
});
test("GHDR layout signing refuses a Guanghu Router approval in place of email approval", async () => {
const now = Math.floor(Date.now() / 1000);
const plan = {
schema: "guanghu.ghdr-signed-layout-plan/v1",
payload: {
node_id: "GH-CVM-MAIN-PROD-01",
provider: "tencent_cloud",
region: "ap-guangzhou",
target_probe_sha256: "11".repeat(32),
system_disk: "/dev/vda",
disk_sectors: 104857600,
logical_sector_bytes: 512,
disk_identity_sha256: "22".repeat(32),
recovery_evidence_sha256: "55".repeat(32),
first_partition_lba: 2048,
generation: 1,
operation: "install_native_ab",
issued_at_unix: now,
expires_at_unix: now + 300,
slots: [
{ name: "A", lba_start: 34, sector_count: 29, image_sha256: "33".repeat(32) },
{ name: "B", lba_start: 73, sector_count: 29, image_sha256: "44".repeat(32) },
],
},
signatures: [],
};
const digest = crypto.createHash("sha256").update(JSON.stringify(plan.payload)).digest("hex");
const resource = `GH-CVM-MAIN-PROD-01:${digest}:1`;
await withServer(async ({ base }) => {
const response = await fetch(`${base}/api/ghdr/sign-layout`, {
method: "POST",
headers: {
authorization: "Bearer router-approved-session",
"content-type": "application/json",
},
body: JSON.stringify({
persona_id: "ICE-GL-ZY001",
target: "GH-CVM-MAIN-PROD-01",
scope: "native-recovery",
resource,
plan,
}),
});
assert.equal(response.status, 403);
assert.equal((await response.json()).error, "ghdr_email_approval_required");
}, {
manager: {
verifySession: () => ({
ok: true,
session: { approvalChannel: "guanghu_router" },
}),
},
});
});
test("deployment is dispatched only by an explicit approved second signal", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "lake-lamp-deploy-dispatch-"));
const mapsDir = path.join(dir, "maps"); fs.mkdirSync(mapsDir);