修复(08-08-production-deployment-execution): 校验候选 Compose 构建标识
这个提交包含在:
@@ -128,6 +128,8 @@ describe("deployment safety contract", () => {
|
||||
expect(preflight).toContain("CANDIDATE_MIGRATIONS_CSV");
|
||||
expect(preflight).toContain("PRISMA_STATUS_OUTPUT_MISSING");
|
||||
expect(preflight).toContain("PRISMA_STATUS_OUTPUT_UNREADABLE");
|
||||
expect(preflight).toContain("CANDIDATE_COMMIT_MISSING");
|
||||
expect(preflight).not.toContain("rev-parse");
|
||||
expect(preflight).toContain("redacted datasource line");
|
||||
expect(preflight).toContain("PRODUCTION_PREFLIGHT_REPORT_NOT_FRESH");
|
||||
expect(preflight.lastIndexOf("printStableRemoteSummary(stdout)")).toBeLessThan(
|
||||
@@ -140,6 +142,7 @@ describe("deployment safety contract", () => {
|
||||
expect(remote).toContain("PROD_MIGRATION_STATUS_UNKNOWN_PENDING");
|
||||
expect(remote).toContain("logged_failure");
|
||||
expect(remote).toContain("PROD_DATABASE_URL_HOST_NON_PRODUCTION_IDENTITY");
|
||||
expect(remote).toContain("PROD_TARGET_BUILD_SHA_MISMATCH");
|
||||
expect(remote).toContain('FROM "_prisma_migrations"');
|
||||
expect(remote).toContain("rollbackWindow=OPEN");
|
||||
expect(remote).not.toMatch(/\b(prisma migrate reset|prisma db push|prisma migrate resolve)\b/);
|
||||
@@ -337,6 +340,8 @@ describe("deployment safety contract", () => {
|
||||
expect(sshCommand).not.toContain("hyb_oa");
|
||||
expect(sshCommand).toContain("EXPECTED_PRODUCTION_ORIGIN_SHA256");
|
||||
expect(sshCommand).toContain("EXPECTED_PRODUCTION_DB_NAME_SHA256");
|
||||
expect(sshCommand).toContain(`BUILD_SHA='${candidateCommit}'`);
|
||||
expect(sshCommand).toContain(`VITE_BUILD_SHA='${candidateCommit.slice(0, 12)}'`);
|
||||
});
|
||||
|
||||
it("bootstraps only an exact historical identity and a unique refresh probe", async () => {
|
||||
@@ -494,7 +499,8 @@ describe("deployment safety contract", () => {
|
||||
await chmod(path.join(fakeBin, "docker"), 0o700);
|
||||
|
||||
const hash = (value) => createHash("sha256").update(value, "utf8").digest("hex");
|
||||
const runRemote = (mode, expectedPending = "") => execFileAsync("bash", [PRODUCTION_PREFLIGHT_REMOTE], {
|
||||
const buildSha = "a".repeat(40);
|
||||
const runRemote = (mode, expectedPending = "", buildOverrides = {}) => execFileAsync("bash", [PRODUCTION_PREFLIGHT_REMOTE], {
|
||||
cwd: remoteDir,
|
||||
env: {
|
||||
...process.env,
|
||||
@@ -508,8 +514,11 @@ describe("deployment safety contract", () => {
|
||||
STORAGE_HOST_DIR: storageDir,
|
||||
EXPECTED_PRODUCTION_ORIGIN_SHA256: hash("https://oa.example.com"),
|
||||
EXPECTED_PRODUCTION_DB_NAME_SHA256: hash("production_db"),
|
||||
BUILD_SHA: buildSha,
|
||||
VITE_BUILD_SHA: buildSha.slice(0, 12),
|
||||
CANDIDATE_MIGRATIONS_CSV: "20260807193000_contract_registry_termination_workspace,20260807193001_followup_migration",
|
||||
EXPECTED_PENDING_MIGRATIONS_CSV: expectedPending,
|
||||
...buildOverrides,
|
||||
},
|
||||
});
|
||||
const result = await runRemote("happy");
|
||||
@@ -524,6 +533,15 @@ describe("deployment safety contract", () => {
|
||||
await expect(runRemote("logs")).rejects.toMatchObject({
|
||||
stderr: expect.stringContaining("PROD_MIGRATION_FAILED_OR_ROLLED_BACK"),
|
||||
});
|
||||
await expect(runRemote("happy", "", { BUILD_SHA: "a".repeat(39) })).rejects.toMatchObject({
|
||||
stderr: expect.stringContaining("PROD_TARGET_BUILD_SHA_INVALID"),
|
||||
});
|
||||
await expect(runRemote("happy", "", { VITE_BUILD_SHA: "a".repeat(7) })).rejects.toMatchObject({
|
||||
stderr: expect.stringContaining("PROD_TARGET_VITE_BUILD_SHA_INVALID"),
|
||||
});
|
||||
await expect(runRemote("happy", "", { VITE_BUILD_SHA: "b".repeat(12) })).rejects.toMatchObject({
|
||||
stderr: expect.stringContaining("PROD_TARGET_BUILD_SHA_MISMATCH"),
|
||||
});
|
||||
});
|
||||
|
||||
it("aggregates preflight checks and keeps the root helper self-contained", async () => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户