BUG-1063:后台按列只读档案,授权前数据库拒绝读表,授权后通过。对话输入框下和报告标题下加上 AI 生成说明。状态板按已部署提交改措辞,不标 resolved。下载文件元数据没有做。 自测:tsc 退出码 0;lint 0 error;定向测试 51 通过;test:db 82 项里 13 项为 Windows 已知失败,无新增;隐私标记退出码 0。 Co-Authored-By: Grok (agent loop)
84 lines
3.5 KiB
TypeScript
84 lines
3.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { randomUUID } from "node:crypto";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import test from "node:test";
|
|
|
|
import { closeLocalPostgresDataPool, createLocalPostgresDataClient } from "../src/lib/db/local-postgres-client-core.ts";
|
|
import { loadReportWorkerProfile } from "../src/lib/personal-report-worker-subject.ts";
|
|
import { CHART_SUBJECT_SELECT } from "../src/lib/subject-birth.ts";
|
|
import { startPostgresFixture, type PostgresFixture } from "./helpers/postgres-fixture.ts";
|
|
|
|
// BUG-1063: the report worker reads another person's archive through
|
|
// service_role. Fictional rows only.
|
|
const runner = fileURLToPath(new URL("../scripts/db-migrate.mjs", import.meta.url));
|
|
const docker = spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], { stdio: "ignore" }).status === 0;
|
|
const SERVICE_URL_ROLE = ["service_runtime", "service-runtime-test-password"] as const;
|
|
|
|
function applyMigrations(fixture: PostgresFixture): void {
|
|
const result = spawnSync(process.execPath, [runner], {
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
SCHEMA_DATABASE_URL: fixture.connectionUrl("schema_owner", "schema-owner-test-password"),
|
|
},
|
|
});
|
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
}
|
|
|
|
test("service_role can read another person's chart profile for a report", {
|
|
skip: docker ? false : "docker unavailable",
|
|
}, async () => {
|
|
const fixture = startPostgresFixture();
|
|
const serviceUrl = fixture.connectionUrl(...SERVICE_URL_ROLE);
|
|
try {
|
|
applyMigrations(fixture);
|
|
const owner = randomUUID();
|
|
const subjectId = randomUUID();
|
|
fixture.psql(`insert into identity.users (id, name, email, email_verified, email_verified_at)
|
|
values ('${owner}', 'Fictional owner', '${owner}@example.invalid', true, now());`);
|
|
fixture.psql(`insert into public.chart_profiles (
|
|
id, user_id, role, profile, updated_at, name, birth_date, reported_birth_time,
|
|
birth_time_source, latitude, longitude, timezone_id, timezone_offset,
|
|
birth_place_label, ayanamsa, birth_time_status
|
|
) values (
|
|
'${subjectId}', '${owner}', 'other', '{"name":"虚构乙"}'::jsonb, now(),
|
|
'虚构乙', '1990-01-01', '08:00', 'family_exact', 22.3, 114.1,
|
|
'Asia/Shanghai', 8, '虚构港', 'lahiri', 'reported'
|
|
);`);
|
|
|
|
const admin = createLocalPostgresDataClient(serviceUrl, null, "service_role");
|
|
const probe = await admin
|
|
.from("chart_profiles")
|
|
.select(CHART_SUBJECT_SELECT)
|
|
.eq("id", subjectId)
|
|
.maybeSingle();
|
|
assert.equal(probe.error, null, probe.error?.message ?? "chart_profiles select failed");
|
|
|
|
const loaded = await loadReportWorkerProfile(admin, owner, subjectId) as { name?: string };
|
|
assert.equal(loaded.name, "虚构乙");
|
|
|
|
for (const column of CHART_SUBJECT_SELECT.split(",")) {
|
|
assert.equal(
|
|
fixture.psql(`select has_column_privilege('service_role', 'public.chart_profiles', '${column}', 'select')`),
|
|
"t",
|
|
column,
|
|
);
|
|
}
|
|
for (const privilege of ["insert", "update", "delete"]) {
|
|
assert.equal(
|
|
fixture.psql(`select has_table_privilege('service_role', 'public.chart_profiles', '${privilege}')`),
|
|
"f",
|
|
privilege,
|
|
);
|
|
}
|
|
assert.equal(
|
|
fixture.psql("select has_table_privilege('authenticated', 'public.chart_profiles', 'select')"),
|
|
"t",
|
|
);
|
|
} finally {
|
|
await closeLocalPostgresDataPool(serviceUrl);
|
|
fixture.stop();
|
|
}
|
|
});
|