7baf230066
Accepted profiles were selecting a revoked rectification table and failing the report before the engine ran. Degrade to a null window when that optional read fails. Co-authored-by: Cursor <cursoragent@cursor.com>
187 lines
7.0 KiB
TypeScript
187 lines
7.0 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import test from "node:test";
|
|
|
|
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
|
|
|
|
const runnerPath = fileURLToPath(
|
|
new URL("../scripts/db-migrate.mjs", import.meta.url),
|
|
);
|
|
|
|
function dockerAvailable(): boolean {
|
|
return spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], {
|
|
encoding: "utf8",
|
|
stdio: "ignore",
|
|
}).status === 0;
|
|
}
|
|
|
|
const skipWithoutDocker = dockerAvailable() ? false : "docker unavailable on this host";
|
|
|
|
const ids = {
|
|
user: "a1111111-1111-4111-8111-111111111111",
|
|
otherUser: "a2222222-2222-4222-8222-222222222222",
|
|
session: "b1111111-1111-4111-8111-111111111111",
|
|
otherSession: "b2222222-2222-4222-8222-222222222222",
|
|
caseId: "c1111111-1111-4111-8111-111111111111",
|
|
otherCase: "c2222222-2222-4222-8222-222222222222",
|
|
legacyCase: "d1111111-1111-4111-8111-111111111111",
|
|
};
|
|
|
|
function sqlLiteral(value: string): string {
|
|
return `'${value.replaceAll("'", "''")}'`;
|
|
}
|
|
|
|
test("read_report_candidate_range is service_role-only, returns only the window, and stays empty without rows", { skip: skipWithoutDocker }, () => {
|
|
const fixture = startPostgresFixture();
|
|
const migrate = () =>
|
|
spawnSync(process.execPath, [runnerPath], {
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
SCHEMA_DATABASE_URL: fixture.connectionUrl(
|
|
"schema_owner",
|
|
"schema-owner-test-password",
|
|
),
|
|
},
|
|
});
|
|
const serviceSql = (statement: string) =>
|
|
fixture
|
|
.psqlAs(
|
|
"service_runtime",
|
|
"service-runtime-test-password",
|
|
`set role service_role; ${statement}`,
|
|
)
|
|
.replace(/^SET\n/, "");
|
|
|
|
try {
|
|
const first = migrate();
|
|
assert.equal(first.status, 0, `${first.stdout}${first.stderr}`);
|
|
assert.match(first.stdout, /applied 20260904010000_read_report_candidate_range\.sql/);
|
|
|
|
const second = migrate();
|
|
assert.equal(second.status, 0, `${second.stdout}${second.stderr}`);
|
|
assert.match(second.stdout, /already applied 20260904010000_read_report_candidate_range\.sql/);
|
|
|
|
assert.equal(
|
|
fixture.psql(`
|
|
select concat_ws(':',
|
|
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'SELECT'),
|
|
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'INSERT'),
|
|
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'UPDATE'),
|
|
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'DELETE'),
|
|
has_function_privilege('service_role', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE'),
|
|
has_function_privilege('anon', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE'),
|
|
has_function_privilege('authenticated', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE')
|
|
)
|
|
`),
|
|
"f:f:f:f:t:f:f",
|
|
);
|
|
|
|
const catalog = fixture.psql(`
|
|
select concat_ws(':',
|
|
pg_catalog.pg_get_userbyid(p.proowner),
|
|
p.prosecdef::text,
|
|
coalesce(array_to_string(p.proconfig, ','), ''),
|
|
p.provolatile::text
|
|
)
|
|
from pg_catalog.pg_proc p
|
|
join pg_catalog.pg_namespace n on n.oid = p.pronamespace
|
|
where n.nspname = 'public' and p.proname = 'read_report_candidate_range'
|
|
`);
|
|
assert.match(catalog, /^schema_owner:true:search_path="":s$/);
|
|
|
|
fixture.psqlAs(
|
|
"identity_runtime",
|
|
"identity-runtime-test-password",
|
|
`insert into identity.users (id, name, email, email_verified, email_verified_at)
|
|
values (${sqlLiteral(ids.user)}, 'Range User', 'range-user@example.com', true, now()),
|
|
(${sqlLiteral(ids.otherUser)}, 'Other User', 'range-other@example.com', true, now());`,
|
|
);
|
|
|
|
assert.equal(
|
|
serviceSql(`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) is null`),
|
|
"t",
|
|
);
|
|
|
|
fixture.psql(`
|
|
insert into public.chat_sessions (id, user_id, title, theme, session_type, messages)
|
|
values (
|
|
${sqlLiteral(ids.session)}, ${sqlLiteral(ids.user)}, '生时校正', 'general',
|
|
'birth_time_rectification', '[]'::jsonb
|
|
), (
|
|
${sqlLiteral(ids.otherSession)}, ${sqlLiteral(ids.otherUser)}, '生时校正', 'general',
|
|
'birth_time_rectification', '[]'::jsonb
|
|
);
|
|
insert into public.agentic_rectification_cases (
|
|
id, user_id, session_id, status, skill_name, skill_version,
|
|
skill_sha256, skill_source_commit, baseline_profile_fingerprint,
|
|
baseline_birth_snapshot, candidate_range
|
|
) values (
|
|
${sqlLiteral(ids.caseId)}, ${sqlLiteral(ids.user)}, ${sqlLiteral(ids.session)},
|
|
'candidate_accepted', 'jyotish-birth-time-rectification', '9.0.0',
|
|
${sqlLiteral("a".repeat(64))}, ${sqlLiteral("0".repeat(40))}, ${sqlLiteral("a".repeat(64))},
|
|
'{"birth_date":"1997-08-08"}'::jsonb,
|
|
'{"start_time":"10:00","end_time":"10:04","secret":"must-not-leak"}'::jsonb
|
|
), (
|
|
${sqlLiteral(ids.otherCase)}, ${sqlLiteral(ids.otherUser)}, ${sqlLiteral(ids.otherSession)},
|
|
'candidate_accepted', 'jyotish-birth-time-rectification', '9.0.0',
|
|
${sqlLiteral("b".repeat(64))}, ${sqlLiteral("1".repeat(40))}, ${sqlLiteral("b".repeat(64))},
|
|
'{"birth_date":"1997-08-08"}'::jsonb,
|
|
'{"start_time":"11:00","end_time":"11:20"}'::jsonb
|
|
);
|
|
`);
|
|
|
|
assert.throws(
|
|
() => serviceSql(`select candidate_range from public.agentic_rectification_cases limit 1`),
|
|
/permission denied for table agentic_rectification_cases/,
|
|
);
|
|
|
|
assert.equal(
|
|
serviceSql(
|
|
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) = '{"start_time":"10:00","end_time":"10:04"}'::jsonb`,
|
|
),
|
|
"t",
|
|
);
|
|
|
|
const keys = serviceSql(`
|
|
select array_to_string(array(
|
|
select jsonb_object_keys(public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid))
|
|
order by 1
|
|
), ',')
|
|
`);
|
|
assert.equal(keys, "end_time,start_time");
|
|
|
|
assert.equal(
|
|
serviceSql(
|
|
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) ? 'secret'`,
|
|
),
|
|
"f",
|
|
);
|
|
|
|
try {
|
|
fixture.psql(`
|
|
insert into public.birth_time_rectification_cases (
|
|
id, user_id, status, reported_date, source, candidate_start, candidate_end
|
|
) values (
|
|
${sqlLiteral(ids.legacyCase)}, ${sqlLiteral(ids.user)}, 'confirmed',
|
|
'1997-08-08', 'family_exact', '08:16', '08:20'
|
|
);
|
|
`);
|
|
assert.equal(
|
|
serviceSql(
|
|
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid) = '{"start_time":"08:16","end_time":"08:20"}'::jsonb`,
|
|
),
|
|
"t",
|
|
);
|
|
} catch (error) {
|
|
assert.ok(
|
|
false,
|
|
`legacy birth_time_rectification_cases seed failed: ${error instanceof Error ? error.message : error}`,
|
|
);
|
|
}
|
|
} finally {
|
|
fixture.stop();
|
|
}
|
|
});
|