fix(db): trust verified Supabase root CA for deployed TLS
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
60f15a3576
commit
af559ca455
3 files changed
+105
-8
No files matched your search
@@ -1,3 +1,8 @@
|
||||
import { X509Certificate } from "node:crypto";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import tls from "node:tls";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
AUTHORIZED_HML_PROJECT,
|
||||
@@ -13,6 +18,7 @@ import {
|
||||
import { readFileSync, readdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { assertInitAuthorized, projectIdentityDefinitionSql, projectIdentityRevertSql } from "@/infra/db/project-identity";
|
||||
import { SUPABASE_ROOT_CA_2021 } from "@/infra/db/supabase-root-ca";
|
||||
import { assertAdminTarget, evaluateAdminIdentity, evaluateProjectIdentity, evaluateRuntimeRole, type AdminAttestation } from "@/infra/db/target-guard";
|
||||
import type { Db } from "@/infra/db/types";
|
||||
|
||||
@@ -167,16 +173,73 @@ describe("barreira do banco de homologação", () => {
|
||||
expect(resolvePoolMax("web", env)).toBe(2);
|
||||
expect(resolvePoolMax("worker", env)).toBe(2);
|
||||
expect(resolvePoolMax("admin", env)).toBe(1);
|
||||
const root = new X509Certificate(SUPABASE_ROOT_CA_2021);
|
||||
expect(root.ca).toBe(true);
|
||||
expect(root.fingerprint256).toBe("80:70:25:AD:50:D4:ED:21:9D:2C:9C:7D:29:9C:00:4F:82:4E:B0:0C:F7:F6:5A:FE:F6:07:D0:7B:72:E6:CA:FA");
|
||||
expect(root.subject).toContain("CN=Supabase Root 2021 CA");
|
||||
expect(SUPABASE_ROOT_CA_2021).not.toContain("PRIVATE KEY");
|
||||
const deployed = buildPostgresOptions(adminUrl(), "admin", env);
|
||||
const production = buildPostgresOptions(adminUrl(), "admin", { ...env, ADAPTER_ENV: "production" });
|
||||
for (const options of [deployed, production]) {
|
||||
expect(options.ssl).toEqual({ rejectUnauthorized: true });
|
||||
expect(options.ssl).toEqual({ rejectUnauthorized: true, ca: SUPABASE_ROOT_CA_2021 });
|
||||
expect(options).not.toHaveProperty("connection");
|
||||
expect(JSON.stringify(options)).not.toContain("family");
|
||||
expect(JSON.stringify(options)).not.toContain("rejectUnauthorized\":false");
|
||||
}
|
||||
const local = buildPostgresOptions("postgres://adaptador:local@127.0.0.1:5432/adaptador", "local", {
|
||||
ADAPTER_ENV: "development",
|
||||
});
|
||||
expect(local).not.toHaveProperty("connection");
|
||||
expect(local.ssl).toBeUndefined();
|
||||
});
|
||||
|
||||
it("a CA pública não libera outro destino nem aceita certificado divergente", async () => {
|
||||
expect(() =>
|
||||
buildPostgresOptions(adminUrl(`postgres.${REF}`, "verify-full", "aws-0-us-west-2.pooler.supabase.com"), "admin", env),
|
||||
).toThrow(/destino_incompativel/);
|
||||
expect(() => assertInitAuthorized({ ADAPTER_ENV: "staging", ADAPTER_DB_PROJECT_REF: REF })).toThrow(/init_nao_autorizada/);
|
||||
const options = buildPostgresOptions(adminUrl(), "admin", env);
|
||||
expect(options.ssl).not.toHaveProperty("checkServerIdentity");
|
||||
expect(options.ssl).not.toHaveProperty("servername");
|
||||
expect(options.ssl?.rejectUnauthorized).toBe(true);
|
||||
|
||||
const dir = mkdtempSync(path.join(tmpdir(), "ca-divergente-"));
|
||||
const keyPath = path.join(dir, "key.pem");
|
||||
const certPath = path.join(dir, "cert.pem");
|
||||
try {
|
||||
execFileSync(
|
||||
"openssl",
|
||||
["req", "-x509", "-newkey", "ec", "-pkeyopt", "ec_paramgen_curve:prime256v1", "-keyout", keyPath, "-out", certPath, "-days", "1", "-nodes", "-subj", "/CN=divergente.example"],
|
||||
{ stdio: "ignore" },
|
||||
);
|
||||
const server = tls.createServer({ key: readFileSync(keyPath), cert: readFileSync(certPath) }, (socket) => socket.end());
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const address = server.address();
|
||||
if (!address || typeof address === "string") throw new Error("porta_local_ausente");
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const socket = tls.connect({
|
||||
host: "127.0.0.1",
|
||||
port: address.port,
|
||||
servername: "divergente.example",
|
||||
rejectUnauthorized: true,
|
||||
ca: SUPABASE_ROOT_CA_2021,
|
||||
});
|
||||
socket.once("secureConnect", () => {
|
||||
socket.end();
|
||||
reject(new Error("certificado_divergente_aceito"));
|
||||
});
|
||||
socket.once("error", (error: NodeJS.ErrnoException) => {
|
||||
expect(error.code).toMatch(/SELF_SIGNED_CERT_IN_CHAIN|DEPTH_ZERO_SELF_SIGNED_CERT|UNABLE_TO_VERIFY_LEAF_SIGNATURE/);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
expect(buildPostgresOptions("postgres://adaptador:local@127.0.0.1:5432/adaptador", "local", { ADAPTER_ENV: "development" })).not.toHaveProperty(
|
||||
"connection",
|
||||
);
|
||||
});
|
||||
|
||||
it("recusa a credencial administrativa na web e BYPASSRLS no worker", () => {
|
||||
|
||||
Reference in new issue
Block a user