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 { buildPostgresOptions, databaseUrlFor, DatabaseGuardError } from "../src/infra/db/connection-policy";
|
||||||
import { createPostgresDb } from "../src/infra/db/postgres";
|
import { createPostgresDb } from "../src/infra/db/postgres";
|
||||||
import { assertInitAuthorized, installProjectIdentity } from "../src/infra/db/project-identity";
|
import { assertInitAuthorized, installProjectIdentity } from "../src/infra/db/project-identity";
|
||||||
import { assertAdminTarget } from "../src/infra/db/target-guard";
|
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.
|
* Grava `adaptador_guard.project_identity` uma única vez.
|
||||||
* Exige ADAPTER_INIT_PROJECT_IDENTITY=1 e o destino administrativo já conferido.
|
* 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.
|
* Migrate, seed e deploy não chamam este script.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
@@ -17,7 +20,7 @@ try {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrapScript("init-project-identity");
|
console.log(`[init-project-identity] ambiente=${adapterEnv()}`);
|
||||||
|
|
||||||
runScript("init-project-identity", async () => {
|
runScript("init-project-identity", async () => {
|
||||||
const databaseUrl = databaseUrlFor("admin");
|
const databaseUrl = databaseUrlFor("admin");
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const env = {
|
|||||||
|
|
||||||
let db: Db;
|
let db: Db;
|
||||||
|
|
||||||
function roleUrl(role: "adaptador_web" | "adaptador_worker"): string {
|
function roleUrl(role: string): string {
|
||||||
const parsed = new URL(url as string);
|
const parsed = new URL(url as string);
|
||||||
parsed.username = role;
|
parsed.username = role;
|
||||||
parsed.password = "";
|
parsed.password = "";
|
||||||
@@ -68,6 +68,58 @@ describe.skipIf(!enabled)("identidade no PostgreSQL 17", () => {
|
|||||||
await db.close();
|
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 () => {
|
it("não cria a identidade na migration e impede a web de alterá-la", async () => {
|
||||||
await db.exec(`create schema adaptador_guard`);
|
await db.exec(`create schema adaptador_guard`);
|
||||||
await expect(installProjectIdentity(db, REF)).rejects.toMatchObject({ code: "marcador_indisponivel" });
|
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");
|
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(databaseUrl");
|
||||||
expect(initScript).not.toContain("console.log(process.env");
|
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", () => {
|
it("exige o host do Dashboard e recusa índice, região ou domínio diferentes", () => {
|
||||||
|
|||||||
Reference in new issue
Block a user