Files
qinglong/packages/ql3-ai/test/modelInvocationMigration.test.cjs
T

1027 lines
35 KiB
JavaScript

const assert = require('node:assert/strict');
const test = require('node:test');
const { DatabaseSync } = require('node:sqlite');
const {
LOCAL_PLUGIN_PACKAGE_PROMPT_ADMISSION_MIGRATION_ID,
LOCAL_PLUGIN_PACKAGE_PROMPT_FINALIZATION_MIGRATION_ID,
LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_ARTIFACT_MIGRATION_ID,
LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_RETIREMENT_MIGRATION_ID,
LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_TOMBSTONE_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_FEATURE_ACTIVATION_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE,
LOCAL_MODEL_INVOCATION_MIGRATION_PLAN_DIGEST,
LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
LOCAL_MODEL_PROVIDER_CREDENTIAL_CATALOG_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_QUOTA_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_PRICING_MIGRATION_ID,
LOCAL_MODEL_INVOCATION_USAGE_MIGRATION_ID,
LOCAL_MODEL_PRICE_CATALOG_AUTHORIZATION_MIGRATION_ID,
LOCAL_MODEL_PRICE_CATALOG_MIGRATION_ID,
POSTGRES_COPILOT_FAILURE_DIAGNOSIS_ADMISSION_MIGRATION_ID,
POSTGRES_MODEL_INVOCATION_MIGRATION_ID,
POSTGRES_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE,
POSTGRES_MODEL_INVOCATION_MIGRATION_STREAM_ID,
POSTGRES_MODEL_INVOCATION_SCHEMA,
POSTGRES_MODEL_PROVIDER_CREDENTIAL_CATALOG_MIGRATION_ID,
POSTGRES_MODEL_PROVIDER_CREDENTIAL_MANAGEMENT_MIGRATION_ID,
POSTGRES_MODEL_PROVIDER_CREDENTIAL_MANAGEMENT_IDENTITY_MIGRATION_ID,
POSTGRES_MODEL_PROVIDER_CREDENTIAL_TEST_CONNECTION_MIGRATION_ID,
POSTGRES_MODEL_INVOCATION_QUOTA_MIGRATION_ID,
POSTGRES_MODEL_INVOCATION_PRICING_MIGRATION_ID,
POSTGRES_MODEL_INVOCATION_USAGE_MIGRATION_ID,
POSTGRES_MODEL_PRICE_CATALOG_AUTHORIZATION_MIGRATION_ID,
POSTGRES_MODEL_PRICE_CATALOG_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_ADMISSION_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_FINALIZATION_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_ARTIFACT_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_RETIREMENT_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_ROTATION_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_PRODUCT_AUTHORIZATION_MIGRATION_ID,
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_TOMBSTONE_MIGRATION_ID,
LocalModelInvocationFeatureNotReadyError,
assertLocalModelInvocationFeatureReady,
localModelInvocationMigrationDefinition,
migrateLocalModelInvocationFeature,
postgresModelInvocationMigrationDefinition,
} = require('@qinglong/ai/model-invocation-migration');
function createMainSqliteContract(client) {
client.exec(`
CREATE TABLE "QingLong3SchemaMigrations" (
migration_id TEXT PRIMARY KEY,
stream_id TEXT NOT NULL,
dialect TEXT NOT NULL,
checksum TEXT NOT NULL,
applied_at_ms INTEGER NOT NULL
);
CREATE TABLE "Runs" (id TEXT PRIMARY KEY);
CREATE TABLE "RunEvents" (id TEXT PRIMARY KEY);
CREATE TABLE "StepRuns" (
id TEXT PRIMARY KEY,
run_id TEXT NOT NULL,
UNIQUE (run_id, id)
);
CREATE TABLE "StepRunMutations" (mutation_id TEXT PRIMARY KEY);
`);
}
function localFeatureTables(client) {
return client
.prepare(
`SELECT name FROM sqlite_schema
WHERE type = 'table' AND
(name LIKE 'ModelInvocation%' OR name LIKE 'ModelPriceCatalog%')
ORDER BY name`,
)
.all()
.map((row) => row.name);
}
test('SQLite AI schema is an explicit independent feature migration', async () => {
const client = new DatabaseSync(':memory:');
client.exec('PRAGMA foreign_keys = ON');
createMainSqliteContract(client);
assert.deepEqual(localFeatureTables(client), []);
await migrateLocalModelInvocationFeature(client);
await migrateLocalModelInvocationFeature(client);
assert.deepEqual(localFeatureTables(client), [
'ModelInvocationCompletions',
'ModelInvocationFeatureHead',
'ModelInvocationFeatureTransitions',
'ModelInvocationPriceQuotes',
'ModelInvocationPriceSettlements',
'ModelInvocationPromptAdmissions',
'ModelInvocationPromptFinalizations',
'ModelInvocationPromptOutputArtifactTombstones',
'ModelInvocationPromptOutputArtifacts',
'ModelInvocationPromptOutputKeyRetirementCompletions',
'ModelInvocationPromptOutputKeyRetirementPreparations',
'ModelInvocationProviderCredentialAudits',
'ModelInvocationProviderCredentialBindings',
'ModelInvocationProviderCredentialTransitions',
'ModelInvocationQuotaReservations',
'ModelInvocationQuotaSettlements',
'ModelInvocationResolutions',
'ModelInvocationStarts',
'ModelInvocationUsageLedger',
'ModelPriceCatalogAuthorizations',
'ModelPriceCatalogHeads',
'ModelPriceCatalogPublications',
]);
const history = client
.prepare(
`SELECT migration_id, stream_id, checksum
FROM "${LOCAL_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE}"
ORDER BY migration_id`,
)
.all();
assert.deepEqual(
history.map(({ migration_id, stream_id }) => ({
migration_id,
stream_id,
})),
[
{
migration_id: LOCAL_MODEL_INVOCATION_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_INVOCATION_USAGE_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_INVOCATION_QUOTA_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_INVOCATION_PRICING_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_PRICE_CATALOG_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_PRICE_CATALOG_AUTHORIZATION_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_INVOCATION_FEATURE_ACTIVATION_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_PLUGIN_PACKAGE_PROMPT_ADMISSION_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_PLUGIN_PACKAGE_PROMPT_FINALIZATION_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_ARTIFACT_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_TOMBSTONE_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id:
LOCAL_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_RETIREMENT_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
{
migration_id: LOCAL_MODEL_PROVIDER_CREDENTIAL_CATALOG_MIGRATION_ID,
stream_id: LOCAL_MODEL_INVOCATION_MIGRATION_STREAM_ID,
},
],
);
assert.equal(
history[0].checksum,
localModelInvocationMigrationDefinition.migrations[0].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[0].checksum,
'258e3fd9a250d53d7d0574c3c05b3f91c40c53b20a60b68a931babfc58a0451a',
);
assert.equal(
history[1].checksum,
localModelInvocationMigrationDefinition.migrations[1].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[1].checksum,
'37e5c9bbf3f459ff036a032fc564dfd8cd78325234c9d7916bfff886b1018da5',
);
assert.equal(
history[2].checksum,
localModelInvocationMigrationDefinition.migrations[2].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[2].checksum,
'fa734aac1a3f5affaf69f4fbe53a2c6ca628255ecdcde14c08b87b49d8162012',
);
assert.equal(
history[3].checksum,
localModelInvocationMigrationDefinition.migrations[3].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[3].checksum,
'572e37d2f44df43a50b51a07c1b4b0bb87fbb22e9cafbd3421ec7ab250036951',
);
assert.equal(
history[4].checksum,
localModelInvocationMigrationDefinition.migrations[4].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[4].checksum,
'20d5c288dfab65ac7ea75a96b7302f9d59cd1bfdf06af28f3868261f6e2e3013',
);
assert.equal(
history[5].checksum,
localModelInvocationMigrationDefinition.migrations[5].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[5].checksum,
'3ee48d1468569c9dc1fa9f04031a48a220161762d48eeac4cd924e2dcd7abd21',
);
assert.equal(
history[6].checksum,
localModelInvocationMigrationDefinition.migrations[6].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[6].checksum,
'2454987c61a48dc5286a883d755c709000e6fd630025373cb276723001bdcc6c',
);
assert.equal(
history[7].checksum,
localModelInvocationMigrationDefinition.migrations[7].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[7].checksum,
'7f0b675231a79a5917dab1b7088ac8c393afef448e35309ca2e3a691af45bc79',
);
assert.equal(
history[8].checksum,
localModelInvocationMigrationDefinition.migrations[8].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[8].checksum,
'bd4c6f9f72a16f7a0e8f6d7afc702c7fe1293e7fc6f60bc31f5604b30bbdd0b6',
);
assert.equal(
history[9].checksum,
localModelInvocationMigrationDefinition.migrations[9].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[9].checksum,
'79bf3edcccf273046cb8b8ab60a7a0da881efd4e641009fa3c5833013cb7a75b',
);
assert.equal(
history[10].checksum,
localModelInvocationMigrationDefinition.migrations[10].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[10].checksum,
'4283d738e3eeb99fce30d011fd7d090577aa897581ee83e691ae021eff3f369e',
);
assert.equal(
history[11].checksum,
localModelInvocationMigrationDefinition.migrations[11].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[11].checksum,
'213d255cc40c536bbdc5fa41691839e0eb8e869db5a53ed93df50295ca8d5fc5',
);
assert.equal(
history[12].checksum,
localModelInvocationMigrationDefinition.migrations[12].checksum,
);
assert.equal(
localModelInvocationMigrationDefinition.migrations[12].checksum,
'ca9bcb4370d747884a34fdeae5079fdd7ccdaadd5ba9f66dba2faab09cfa3abb',
);
assert.equal(
LOCAL_MODEL_INVOCATION_MIGRATION_PLAN_DIGEST,
'2720c6e45f82adbb03641d1c19e8ff7e1875a763a0b53d4910a46ca308800aa0',
);
assert.deepEqual(
client
.prepare(
`SELECT migration_id FROM "QingLong3SchemaMigrations"
ORDER BY migration_id`,
)
.all(),
[],
);
assert.equal(
client.prepare('PRAGMA integrity_check').get().integrity_check,
'ok',
);
client.close();
});
test('SQLite AI feature readiness is read-only and rejects partial or drifted schema', async () => {
const client = new DatabaseSync(':memory:');
client.exec('PRAGMA foreign_keys = ON');
createMainSqliteContract(client);
assert.throws(
() => assertLocalModelInvocationFeatureReady(client),
LocalModelInvocationFeatureNotReadyError,
);
await migrateLocalModelInvocationFeature(client);
assert.doesNotThrow(() => assertLocalModelInvocationFeatureReady(client));
client
.prepare(
`UPDATE "${LOCAL_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE}"
SET checksum = ?
WHERE migration_id = ?`,
)
.run('f'.repeat(64), LOCAL_MODEL_PRICE_CATALOG_AUTHORIZATION_MIGRATION_ID);
assert.throws(
() => assertLocalModelInvocationFeatureReady(client),
LocalModelInvocationFeatureNotReadyError,
);
assert.equal(
client
.prepare(
`SELECT count(*) AS count
FROM "${LOCAL_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE}"`,
)
.get().count,
13,
);
client.close();
});
test('SQLite AI migration refuses to create a parallel baseline', async () => {
const client = new DatabaseSync(':memory:');
await assert.rejects(
migrateLocalModelInvocationFeature(client),
/requires the main SQLite migration stream/,
);
assert.deepEqual(localFeatureTables(client), []);
client.close();
});
test('PostgreSQL AI schema is an independent reviewed feature stream', async () => {
assert.equal(
POSTGRES_MODEL_INVOCATION_MIGRATION_STREAM_ID,
'ql3-ai-model-invocation-postgresql',
);
assert.equal(
POSTGRES_MODEL_INVOCATION_MIGRATION_ID,
'pg-9001-ai-model-invocations',
);
assert.equal(
POSTGRES_MODEL_INVOCATION_USAGE_MIGRATION_ID,
'pg-9002-ai-model-usage-ledger',
);
assert.equal(
POSTGRES_MODEL_INVOCATION_QUOTA_MIGRATION_ID,
'pg-9003-ai-model-usage-quota',
);
assert.equal(
POSTGRES_MODEL_INVOCATION_PRICING_MIGRATION_ID,
'pg-9004-ai-model-pricing-snapshots',
);
assert.equal(
POSTGRES_MODEL_PRICE_CATALOG_MIGRATION_ID,
'pg-9005-ai-model-price-catalog',
);
assert.equal(
POSTGRES_MODEL_PRICE_CATALOG_AUTHORIZATION_MIGRATION_ID,
'pg-9006-ai-model-price-catalog-authorizations',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_ADMISSION_MIGRATION_ID,
'pg-9007-ai-plugin-package-prompt-admissions',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_FINALIZATION_MIGRATION_ID,
'pg-9008-ai-plugin-package-prompt-finalizations',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_ARTIFACT_MIGRATION_ID,
'pg-9009-ai-plugin-package-prompt-output-artifacts',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_TOMBSTONE_MIGRATION_ID,
'pg-9010-ai-plugin-package-prompt-output-tombstones',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_RETIREMENT_MIGRATION_ID,
'pg-9011-ai-plugin-package-prompt-output-key-retirements',
);
assert.equal(
POSTGRES_MODEL_PROVIDER_CREDENTIAL_CATALOG_MIGRATION_ID,
'pg-9012-ai-model-provider-credential-catalog',
);
assert.equal(
POSTGRES_MODEL_PROVIDER_CREDENTIAL_MANAGEMENT_MIGRATION_ID,
'pg-9013-ai-model-provider-credential-management-boundary',
);
assert.equal(
POSTGRES_MODEL_PROVIDER_CREDENTIAL_MANAGEMENT_IDENTITY_MIGRATION_ID,
'pg-9014-ai-model-provider-credential-management-identity-ledger',
);
assert.equal(
POSTGRES_MODEL_PROVIDER_CREDENTIAL_TEST_CONNECTION_MIGRATION_ID,
'pg-9015-ai-model-provider-credential-test-connection',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_OUTPUT_KEY_ROTATION_MIGRATION_ID,
'pg-9016-ai-plugin-package-prompt-output-key-rotation',
);
assert.equal(
POSTGRES_PLUGIN_PACKAGE_PROMPT_PRODUCT_AUTHORIZATION_MIGRATION_ID,
'pg-9017-ai-plugin-package-prompt-product-authorization',
);
assert.equal(
POSTGRES_COPILOT_FAILURE_DIAGNOSIS_ADMISSION_MIGRATION_ID,
'pg-9018-ai-copilot-failure-diagnosis-admissions',
);
assert.equal(
POSTGRES_MODEL_INVOCATION_MIGRATION_HISTORY_TABLE,
'ai_schema_migrations',
);
assert.equal(POSTGRES_MODEL_INVOCATION_SCHEMA, 'ql3_ai');
assert.equal(
postgresModelInvocationMigrationDefinition.migrationIdScheme,
'postgres-prefixed',
);
assert.match(
postgresModelInvocationMigrationDefinition.migrations[0].checksum,
/^[0-9a-f]{64}$/,
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[0].checksum,
'69f72286fba2988ba372f006eb894a7f8b89f4b1acd9da68dc1cdafc3ca96ea7',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[1].checksum,
'95ad6f46163b0bbc2583dddf492f91f767a00554683186f244d3f6a22a2ad00c',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[2].checksum,
'13ea1a904eb799bcae1b474d76b164a70748bdcca8e1e6ded9952921a291a855',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[3].checksum,
'd38b12c2640fdd9fe21dc43a4743fb3480c988fa0a87e210fd81074d87569d2f',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[4].checksum,
'7db1a80fab1aa3dee3a4c4bcae5add53758418504f63f4b7d253b090506d7864',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[5].checksum,
'486d46115e28e90604a47231fe95e3b1687649c063d93bf7ce267783f2a7165f',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[6].checksum,
'1ed94eae2225b26e89e8c5d34e265e143e8150ff1811f5d8ae1fda52a6603db0',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[7].checksum,
'8dfd02e8e4947acb03516795ae37ef7aae5ee52a25b1fe3cd1a8640782c5b235',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[8].checksum,
'cb4156b109694c2b3aaf60a870179da04e10b47dbddfc92db3a7c4a58dfd1c2d',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[9].checksum,
'8972237fa41c80d131c32b380f617e8c7720687980e9accfb08f8fb19b7d8b5f',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[10].checksum,
'843ea53460f6580801cb12428d35c5571fd36bbee64e7801d2c3f98ea39d8392',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[11].checksum,
'4c83f5dda3c922aefd77c58760881f926e63e33628120f2fe6c71a53b30a1248',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[12].checksum,
'c02a4c6b2953cc331580b6287283d33739c30c2e189d011f392c13ecea497224',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[13].checksum,
'02098fad764199bc5a7750483d050be5e5acdbcecd05c0975c3fe4e5be03c782',
);
assert.match(
postgresModelInvocationMigrationDefinition.migrations[14].checksum,
/^[0-9a-f]{64}$/,
);
assert.match(
postgresModelInvocationMigrationDefinition.migrations[16].checksum,
/^[0-9a-f]{64}$/,
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations[17].checksum,
'cd0837c68ecc6c2bce58d048308d0239397b6347b4483f02372f966c05ae7ad6',
);
assert.equal(
postgresModelInvocationMigrationDefinition.migrations.length,
18,
);
const diagnosisAdmissionStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[17].up({
async query(statement) {
diagnosisAdmissionStatements.push(statement);
return { rows: [] };
},
});
const diagnosisAdmissionSql = diagnosisAdmissionStatements.join('\n');
assert.match(
diagnosisAdmissionSql,
/CREATE TABLE "ql3_ai"\."copilot_failure_diagnosis_admissions"/,
);
assert.match(
diagnosisAdmissionSql,
/CREATE FUNCTION[\s\S]*copilot_failure_diagnosis_admission_source_snapshot/,
);
assert.match(diagnosisAdmissionSql, /SECURITY DEFINER/);
assert.match(diagnosisAdmissionSql, /FOR SHARE OF project, binding/);
assert.match(
diagnosisAdmissionSql,
/FOR SHARE OF source_run, source_attempt/,
);
assert.match(diagnosisAdmissionSql, /TO ql3_runtime/);
assert.doesNotMatch(diagnosisAdmissionSql, /GRANT[^;]*(?:UPDATE|DELETE)/);
const retirementStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[10].up({
async query(statement) {
retirementStatements.push(statement);
return { rows: [] };
},
});
const retirementSql = retirementStatements.join('\n');
assert.match(
retirementSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_key_retirement_preparations"/,
);
assert.match(
retirementSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_key_retirement_completions"/,
);
assert.match(retirementSql, /TO ql3_runtime/);
assert.match(retirementSql, /TO ql3_ai_maintenance/);
const credentialStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[11].up({
async query(statement) {
credentialStatements.push(statement);
return { rows: [] };
},
});
const credentialSql = credentialStatements.join('\n');
assert.match(
credentialSql,
/CREATE TABLE "ql3_ai"\."model_provider_credential_bindings"/,
);
assert.match(
credentialSql,
/CREATE TABLE "ql3_ai"\."model_provider_credential_transitions"/,
);
assert.match(
credentialSql,
/CREATE TABLE "ql3_ai"\."model_provider_credential_audits"/,
);
assert.match(credentialSql, /TO ql3_runtime/);
assert.match(credentialSql, /TO ql3_ai_maintenance/);
const credentialManagementStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[12].up({
async query(statement) {
credentialManagementStatements.push(statement);
return { rows: [] };
},
});
const credentialManagementSql = credentialManagementStatements.join('\n');
assert.match(
credentialManagementSql,
/GRANT CONNECT ON DATABASE %I TO ql3_ai_credential_manager/,
);
assert.match(
credentialManagementSql,
/GRANT SELECT ON TABLE[\s\S]*"ql3"\."projects"[\s\S]*"ql3"\."project_role_bindings"[\s\S]*"ql3"\."security_audit_events"[\s\S]*TO ql3_ai_credential_manager/,
);
assert.match(
credentialManagementSql,
/GRANT INSERT ON TABLE "ql3"\."security_audit_events"[\s\S]*TO ql3_ai_credential_manager/,
);
assert.match(
credentialManagementSql,
/GRANT INSERT ON TABLE[\s\S]*model_provider_credential_bindings[\s\S]*model_provider_credential_transitions[\s\S]*TO ql3_ai_credential_manager/,
);
assert.doesNotMatch(
credentialManagementSql,
/GRANT[^;]*(?:model_invocation_prompt_output|ql3_ai_maintenance)/,
);
assert.match(
credentialManagementSql,
/REVOKE ALL ON TABLE[\s\S]*model_provider_credential_bindings[\s\S]*model_provider_credential_transitions[\s\S]*model_provider_credential_audits[\s\S]*FROM ql3_ai_maintenance/,
);
const credentialIdentityStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[13].up({
async query(statement) {
credentialIdentityStatements.push(statement);
return { rows: [] };
},
});
const credentialIdentitySql = credentialIdentityStatements.join('\n');
assert.match(
credentialIdentitySql,
/CREATE TABLE "ql3_ai"\."model_provider_credential_management_identity_keyset_ledger"/,
);
assert.match(
credentialIdentitySql,
/GRANT SELECT, INSERT, UPDATE[\s\S]*TO ql3_ai_credential_manager/,
);
assert.match(credentialIdentitySql, /FROM PUBLIC, ql3_ai_maintenance/);
assert.doesNotMatch(credentialIdentitySql, /GRANT[^;]*DELETE/);
const credentialTestStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[14].up({
async query(statement) {
credentialTestStatements.push(statement);
return { rows: [] };
},
});
const credentialTestSql = credentialTestStatements.join('\n');
for (const table of [
'model_provider_credential_test_plans',
'model_provider_credential_test_quota_buckets',
'model_provider_credential_test_executions',
'model_provider_credential_test_results',
]) {
assert.match(
credentialTestSql,
new RegExp(`CREATE TABLE "ql3_ai"\\."${table}"`),
);
}
assert.match(
credentialTestSql,
/GRANT CONNECT ON DATABASE %I TO ql3_ai_credential_tester/,
);
assert.match(
credentialTestSql,
/GRANT SELECT, INSERT, UPDATE ON TABLE[\s\S]*model_provider_credential_test_quota_buckets[\s\S]*TO ql3_ai_credential_manager/,
);
assert.match(
credentialTestSql,
/GRANT INSERT ON TABLE[\s\S]*model_provider_credential_test_executions[\s\S]*model_provider_credential_test_results[\s\S]*TO ql3_ai_credential_tester/,
);
for (const statement of credentialTestStatements.filter((value) =>
value.includes('TO ql3_ai_credential_tester'),
)) {
assert.doesNotMatch(statement, /GRANT[\s\S]*(?:UPDATE|DELETE)/);
}
const rotationStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[15].up({
async query(statement) {
rotationStatements.push(statement);
return { rows: [] };
},
});
const rotationSql = rotationStatements.join('\n');
assert.match(
rotationSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_key_rotation_preparations"/,
);
assert.match(
rotationSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_key_rotation_completions"/,
);
assert.match(
rotationSql,
/UNIQUE \(expected_secret_uid, expected_catalog_digest\)/,
);
assert.match(rotationSql, /TO ql3_ai_maintenance/);
assert.doesNotMatch(rotationSql, /GRANT[^;]*TO ql3_runtime/);
assert.doesNotMatch(rotationSql, /GRANT[^;]*(?:UPDATE|DELETE)/);
const productAuthorizationStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[16].up({
async query(statement) {
productAuthorizationStatements.push(statement);
return { rows: [] };
},
});
const productAuthorizationSql = productAuthorizationStatements.join('\n');
assert.match(
productAuthorizationSql,
/CREATE FUNCTION[\s\S]*plugin_package_prompt_authorize_admission/,
);
assert.match(productAuthorizationSql, /SECURITY DEFINER/);
assert.match(productAuthorizationSql, /TO ql3_runtime/);
assert.doesNotMatch(productAuthorizationSql, /GRANT[^;]*TO ql3_admin/);
const statements = [];
await postgresModelInvocationMigrationDefinition.migrations[0].up({
async query(statement) {
statements.push(statement);
return { rows: [] };
},
});
const sql = statements.join('\n');
assert.match(sql, /CREATE TABLE "ql3_ai"\."model_invocation_starts"/);
assert.match(sql, /CREATE TABLE "ql3_ai"\."model_invocation_completions"/);
assert.match(sql, /CREATE TABLE "ql3_ai"\."model_invocation_resolutions"/);
assert.match(
sql,
/FOREIGN KEY \(mutation_id\)[\s\S]*"ql3"\."step_run_mutations"/,
);
assert.match(sql, /FOREIGN KEY \(run_event_id\)[\s\S]*"ql3"\."run_events"/);
assert.match(
sql,
/REVOKE ALL ON TABLE[\s\S]*model_invocation_starts[\s\S]*FROM PUBLIC/,
);
assert.match(
sql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_resolutions[\s\S]*TO ql3_runtime/,
);
assert.doesNotMatch(sql, /model_invocation_(?:starts|completions)_step_uidx/);
assert.match(sql, /model_invocation_starts_step_history_idx/);
assert.match(sql, /model_invocation_completions_step_history_idx/);
assert.doesNotMatch(sql, /TO ql3_admin/);
assert.doesNotMatch(sql, /TO ql3_worker_ingress/);
const usageStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[1].up({
async query(statement) {
usageStatements.push(statement);
return { rows: [] };
},
});
const usageSql = usageStatements.join('\n');
assert.match(
usageSql,
/CREATE TABLE "ql3_ai"\."model_invocation_usage_ledger"/,
);
assert.match(
usageSql,
/FOREIGN KEY \(invocation_id, completion_digest\)[\s\S]*model_invocation_completions/,
);
assert.match(
usageSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_usage_ledger[\s\S]*TO ql3_runtime/,
);
assert.deepEqual(
usageStatements.filter((statement) => statement.startsWith('GRANT ')),
[
`GRANT SELECT, INSERT ON TABLE
"ql3_ai"."model_invocation_usage_ledger"
TO ql3_runtime`,
],
);
assert.doesNotMatch(usageSql, /TO ql3_admin|TO ql3_worker_ingress/);
const quotaStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[2].up({
async query(statement) {
quotaStatements.push(statement);
return { rows: [] };
},
});
const quotaSql = quotaStatements.join('\n');
assert.match(
quotaSql,
/CREATE TABLE "ql3_ai"\."model_invocation_quota_reservations"/,
);
assert.match(
quotaSql,
/CREATE TABLE "ql3_ai"\."model_invocation_quota_settlements"/,
);
assert.match(
quotaSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_quota_reservations[\s\S]*model_invocation_quota_settlements[\s\S]*TO ql3_runtime/,
);
assert.deepEqual(
quotaStatements.filter((statement) =>
/^(?:UPDATE|DELETE)\b/.test(statement),
),
[],
);
assert.doesNotMatch(quotaSql, /TO ql3_admin|TO ql3_worker_ingress/);
const pricingStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[3].up({
async query(statement) {
pricingStatements.push(statement);
return { rows: [] };
},
});
const pricingSql = pricingStatements.join('\n');
assert.match(
pricingSql,
/CREATE TABLE "ql3_ai"\."model_invocation_price_quotes"/,
);
assert.match(
pricingSql,
/CREATE TABLE "ql3_ai"\."model_invocation_price_settlements"/,
);
assert.match(
pricingSql,
/FOREIGN KEY \(invocation_id, quote_digest\)[\s\S]*model_invocation_price_quotes/,
);
assert.match(
pricingSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_price_quotes[\s\S]*model_invocation_price_settlements[\s\S]*TO ql3_runtime/,
);
assert.deepEqual(
pricingStatements.filter((statement) =>
/^(?:UPDATE|DELETE)\b/.test(statement),
),
[],
);
assert.doesNotMatch(pricingSql, /TO ql3_admin|TO ql3_worker_ingress/);
const catalogStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[4].up({
async query(statement) {
catalogStatements.push(statement);
return { rows: [] };
},
});
const catalogSql = catalogStatements.join('\n');
assert.match(
catalogSql,
/CREATE TABLE "ql3_ai"\."model_price_catalog_publications"/,
);
assert.match(
catalogSql,
/CREATE TABLE "ql3_ai"\."model_price_catalog_heads"/,
);
assert.match(
catalogSql,
/GRANT SELECT ON TABLE[\s\S]*model_price_catalog_publications[\s\S]*model_price_catalog_heads[\s\S]*TO ql3_runtime/,
);
assert.match(
catalogSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_price_catalog_publications[\s\S]*model_price_catalog_heads[\s\S]*TO ql3_admin/,
);
assert.doesNotMatch(
catalogSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*TO ql3_runtime/,
);
assert.doesNotMatch(
catalogSql,
/TO ql3_package_manager|TO ql3_package_executor|TO ql3_worker_ingress/,
);
assert.deepEqual(
catalogStatements.filter((statement) =>
/^(?:UPDATE|DELETE)\b/.test(statement),
),
[],
);
const authorizationStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[5].up({
async query(statement) {
authorizationStatements.push(statement);
return { rows: [] };
},
});
const authorizationSql = authorizationStatements.join('\n');
assert.match(
authorizationSql,
/CREATE TABLE "ql3_ai"\."model_price_catalog_authorizations"/,
);
assert.match(
authorizationSql,
/FOREIGN KEY \(publication_digest\)[\s\S]*model_price_catalog_publications/,
);
assert.match(
authorizationSql,
/FOREIGN KEY \(head_digest\)[\s\S]*model_price_catalog_heads/,
);
assert.match(
authorizationSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_price_catalog_authorizations[\s\S]*TO ql3_admin/,
);
assert.doesNotMatch(authorizationSql, /TO ql3_runtime/);
assert.deepEqual(
authorizationStatements.filter((statement) =>
/^(?:UPDATE|DELETE)\b/.test(statement),
),
[],
);
const promptAdmissionStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[6].up({
async query(statement) {
promptAdmissionStatements.push(statement);
return { rows: [] };
},
});
const promptAdmissionSql = promptAdmissionStatements.join('\n');
assert.match(
promptAdmissionSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_admissions"/,
);
assert.match(
promptAdmissionSql,
/REFERENCES "ql3"\."plugin_package_automation_publications"/,
);
assert.match(
promptAdmissionSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_prompt_admissions[\s\S]*TO ql3_runtime/,
);
assert.match(
promptAdmissionSql,
/CREATE FUNCTION[\s\S]*"ql3_ai"\."plugin_package_prompt_admission_snapshot"/,
);
assert.match(promptAdmissionSql, /plugin_package_automation_start_allowed/);
assert.match(
promptAdmissionSql,
/GRANT EXECUTE ON FUNCTION[\s\S]*plugin_package_prompt_admission_snapshot[\s\S]*TO ql3_runtime/,
);
assert.doesNotMatch(
promptAdmissionSql,
/TO ql3_admin|TO ql3_package_manager|TO ql3_worker_ingress/,
);
const promptFinalizationStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[7].up({
async query(statement) {
promptFinalizationStatements.push(statement);
return { rows: [] };
},
});
const promptFinalizationSql = promptFinalizationStatements.join('\n');
assert.match(
promptFinalizationSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_finalizations"/,
);
assert.match(
promptFinalizationSql,
/FOREIGN KEY \(event_id\)[\s\S]*REFERENCES "ql3"\."run_events"/,
);
assert.match(
promptFinalizationSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_prompt_finalizations[\s\S]*TO ql3_runtime/,
);
assert.doesNotMatch(
`${promptAdmissionSql}\n${promptFinalizationSql}`,
/GRANT (?:UPDATE|DELETE)|TO ql3_admin|TO ql3_worker_ingress/,
);
const promptOutputArtifactStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[8].up({
async query(statement) {
promptOutputArtifactStatements.push(statement);
return { rows: [] };
},
});
const promptOutputArtifactSql = promptOutputArtifactStatements.join('\n');
assert.match(
promptOutputArtifactSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_artifacts"/,
);
assert.match(
promptOutputArtifactSql,
/FOREIGN KEY \(invocation_id\)[\s\S]*model_invocation_prompt_admissions/,
);
assert.match(
promptOutputArtifactSql,
/FOREIGN KEY \(invocation_id\)[\s\S]*model_invocation_starts/,
);
assert.match(
promptOutputArtifactSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_prompt_output_artifacts[\s\S]*TO ql3_runtime/,
);
assert.doesNotMatch(
promptOutputArtifactSql,
/GRANT (?:UPDATE|DELETE)|TO ql3_admin|TO ql3_package_manager|TO ql3_package_executor|TO ql3_worker_ingress/,
);
const promptOutputTombstoneStatements = [];
await postgresModelInvocationMigrationDefinition.migrations[9].up({
async query(statement) {
promptOutputTombstoneStatements.push(statement);
return { rows: [] };
},
});
const promptOutputTombstoneSql = promptOutputTombstoneStatements.join('\n');
assert.match(
promptOutputTombstoneSql,
/CREATE TABLE "ql3_ai"\."model_invocation_prompt_output_artifact_tombstones"/,
);
assert.match(
promptOutputTombstoneSql,
/GRANT CONNECT ON DATABASE %I TO ql3_ai_maintenance/,
);
assert.match(
promptOutputTombstoneSql,
/FOREIGN KEY \(invocation_id\)[\s\S]*model_invocation_prompt_admissions/,
);
assert.match(
promptOutputTombstoneSql,
/GRANT SELECT ON TABLE[\s\S]*model_invocation_prompt_output_artifact_tombstones[\s\S]*TO ql3_runtime/,
);
assert.match(
promptOutputTombstoneSql,
/GRANT SELECT, DELETE ON TABLE[\s\S]*model_invocation_prompt_output_artifacts[\s\S]*TO ql3_ai_maintenance/,
);
assert.match(
promptOutputTombstoneSql,
/GRANT SELECT, INSERT ON TABLE[\s\S]*model_invocation_prompt_output_artifact_tombstones[\s\S]*TO ql3_ai_maintenance/,
);
assert.doesNotMatch(
promptOutputTombstoneSql,
/GRANT (?:UPDATE|DELETE)[\s\S]*model_invocation_prompt_output_artifact_tombstones|TO ql3_admin|TO ql3_package_manager|TO ql3_package_executor|TO ql3_worker_ingress/,
);
});