fix(db): permite inicializacao da identidade sem roles operacionais
This commit is contained in:
1 parent
a4f0a2f649
commit
b410fa4559
3 files changed
+62
-3
No files matched your search
@@ -1,12 +1,15 @@
|
||||
import { adapterEnv } from "../src/config/env";
|
||||
import { buildPostgresOptions, databaseUrlFor, DatabaseGuardError } from "../src/infra/db/connection-policy";
|
||||
import { createPostgresDb } from "../src/infra/db/postgres";
|
||||
import { assertInitAuthorized, installProjectIdentity } from "../src/infra/db/project-identity";
|
||||
import { assertAdminTarget } from "../src/infra/db/target-guard";
|
||||
import { bootstrapScript, runScript } from "./_bootstrap";
|
||||
import { runScript } from "./_bootstrap";
|
||||
|
||||
/**
|
||||
* Grava `adaptador_guard.project_identity` uma única vez.
|
||||
* Exige ADAPTER_INIT_PROJECT_IDENTITY=1 e o destino administrativo já conferido.
|
||||
* Não chama o fail-fast da aplicação: nesta etapa os papéis web e worker ainda
|
||||
* não existem, e Redis, seed e a feature flag ficam fora desta operação.
|
||||
* Migrate, seed e deploy não chamam este script.
|
||||
*/
|
||||
try {
|
||||
@@ -17,7 +20,7 @@ try {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
bootstrapScript("init-project-identity");
|
||||
console.log(`[init-project-identity] ambiente=${adapterEnv()}`);
|
||||
|
||||
runScript("init-project-identity", async () => {
|
||||
const databaseUrl = databaseUrlFor("admin");
|
||||
|
||||
@@ -22,7 +22,7 @@ const env = {
|
||||
|
||||
let db: Db;
|
||||
|
||||
function roleUrl(role: "adaptador_web" | "adaptador_worker"): string {
|
||||
function roleUrl(role: string): string {
|
||||
const parsed = new URL(url as string);
|
||||
parsed.username = role;
|
||||
parsed.password = "";
|
||||
@@ -68,6 +68,58 @@ describe.skipIf(!enabled)("identidade no PostgreSQL 17", () => {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
it("grava a primeira identidade sem papéis web ou worker", async () => {
|
||||
await db.exec(`
|
||||
drop role if exists anon;
|
||||
drop role if exists authenticated;
|
||||
drop role if exists service_role;
|
||||
create role anon nologin nosuperuser nobypassrls;
|
||||
create role authenticated nologin nosuperuser nobypassrls;
|
||||
create role service_role nologin nosuperuser bypassrls;
|
||||
`);
|
||||
try {
|
||||
expect(await installProjectIdentity(db, REF)).toBe("criada");
|
||||
expect(await installProjectIdentity(db, REF)).toBe("inalterada");
|
||||
await expect(installProjectIdentity(db, OUTRO_REF)).rejects.toMatchObject({ code: "marcador_diverge" });
|
||||
const estado = await db.withService((query) =>
|
||||
query.query<{
|
||||
operacional: number;
|
||||
migrations: string | null;
|
||||
flags: string | null;
|
||||
anon_exec: boolean;
|
||||
service_exec: boolean;
|
||||
project_ref: string;
|
||||
}>(
|
||||
`select
|
||||
(select count(*)::int from pg_catalog.pg_roles where rolname in ('adaptador_web', 'adaptador_worker')) as operacional,
|
||||
to_regclass('public.schema_migrations')::text as migrations,
|
||||
to_regclass('public.workspace_module_flags')::text as flags,
|
||||
has_function_privilege('anon', 'adaptador_guard.adapter_project_identity()', 'execute') as anon_exec,
|
||||
has_function_privilege('service_role', 'adaptador_guard.adapter_project_identity()', 'execute') as service_exec,
|
||||
i.project_ref
|
||||
from adaptador_guard.project_identity i`,
|
||||
),
|
||||
);
|
||||
expect(estado[0]).toEqual({
|
||||
operacional: 0,
|
||||
migrations: null,
|
||||
flags: null,
|
||||
anon_exec: false,
|
||||
service_exec: false,
|
||||
project_ref: REF,
|
||||
});
|
||||
} finally {
|
||||
await revertProjectIdentity(db).catch(async () => {
|
||||
await db.exec(`drop schema if exists adaptador_guard cascade`).catch(() => undefined);
|
||||
});
|
||||
await db.exec(`
|
||||
drop role if exists anon;
|
||||
drop role if exists authenticated;
|
||||
drop role if exists service_role;
|
||||
`).catch(() => undefined);
|
||||
}
|
||||
});
|
||||
|
||||
it("não cria a identidade na migration e impede a web de alterá-la", async () => {
|
||||
await db.exec(`create schema adaptador_guard`);
|
||||
await expect(installProjectIdentity(db, REF)).rejects.toMatchObject({ code: "marcador_indisponivel" });
|
||||
|
||||
@@ -98,6 +98,10 @@ describe("barreira do banco de homologação", () => {
|
||||
const initScript = readFileSync(path.join(process.cwd(), "scripts/init-project-identity.ts"), "utf8");
|
||||
expect(initScript).not.toContain("console.log(databaseUrl");
|
||||
expect(initScript).not.toContain("console.log(process.env");
|
||||
expect(initScript).not.toContain("bootstrapScript");
|
||||
expect(initScript).not.toContain("exitOnInvalidConfig");
|
||||
expect(initScript).not.toMatch(/migrate\(/);
|
||||
expect(initScript).not.toMatch(/from ["'].*seed/);
|
||||
});
|
||||
|
||||
it("exige o host do Dashboard e recusa índice, região ou domínio diferentes", () => {
|
||||
|
||||
Reference in new issue
Block a user