完善 readiness、发布追溯与敏感治理(07-15-production-trust-closeout-cleanup)
这个提交包含在:
@@ -0,0 +1,87 @@
|
||||
const fp = require("fastify-plugin");
|
||||
|
||||
const { buildApp } = require("../../src/app");
|
||||
|
||||
const startJobs = vi.fn(async () => ({ driver: "disabled" }));
|
||||
|
||||
function createPrismaPlugin(prisma) {
|
||||
return fp(async (app) => {
|
||||
app.decorate("prisma", prisma);
|
||||
}, { name: "test-prisma" });
|
||||
}
|
||||
|
||||
async function buildHealthApp({ buildSha, queryRaw = vi.fn().mockResolvedValue([{ ok: 1 }]) }) {
|
||||
vi.stubEnv("NODE_ENV", "test");
|
||||
vi.stubEnv("JWT_SECRET", "test-secret");
|
||||
vi.stubEnv("DATABASE_URL", "");
|
||||
vi.stubEnv("BUILD_SHA", buildSha);
|
||||
vi.stubEnv("JOBS_ENABLED", "false");
|
||||
vi.stubEnv("METRICS_ENABLED", "false");
|
||||
|
||||
const prisma = {
|
||||
$queryRaw: queryRaw,
|
||||
employee: {
|
||||
findUnique: vi.fn(),
|
||||
},
|
||||
};
|
||||
const app = await buildApp({
|
||||
prismaPlugin: createPrismaPlugin(prisma),
|
||||
startJobs,
|
||||
});
|
||||
return { app, queryRaw };
|
||||
}
|
||||
|
||||
describe("app build provenance endpoints", () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("returns the same redacted build SHA from health and readiness", async () => {
|
||||
const { app } = await buildHealthApp({
|
||||
buildSha: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
|
||||
});
|
||||
|
||||
try {
|
||||
const health = await app.inject({ method: "GET", url: "/health" });
|
||||
const ready = await app.inject({ method: "GET", url: "/ready" });
|
||||
|
||||
expect(health.statusCode).toBe(200);
|
||||
expect(ready.statusCode).toBe(200);
|
||||
expect(health.json().data).toEqual({ ok: true, buildSha: "abcdef123456" });
|
||||
expect(ready.json().data).toEqual({ ok: true, buildSha: "abcdef123456" });
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
}, 20_000);
|
||||
|
||||
it("uses a non-identifying marker when no valid build SHA is supplied", async () => {
|
||||
const { app } = await buildHealthApp({ buildSha: "local-working-tree" });
|
||||
|
||||
try {
|
||||
const health = await app.inject({ method: "GET", url: "/health" });
|
||||
expect(health.json().data.buildSha).toBe("unknown");
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
}, 20_000);
|
||||
|
||||
it("keeps the build marker visible when readiness fails", async () => {
|
||||
const queryRaw = vi.fn().mockRejectedValueOnce(new Error("database unavailable"));
|
||||
const { app } = await buildHealthApp({
|
||||
buildSha: "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
|
||||
queryRaw,
|
||||
});
|
||||
|
||||
try {
|
||||
const ready = await app.inject({ method: "GET", url: "/ready" });
|
||||
expect(ready.statusCode).toBe(503);
|
||||
expect(ready.json().error.details).toEqual({
|
||||
db: "unreachable",
|
||||
buildSha: "abcdef123456",
|
||||
});
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
}, 20_000);
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户