Files
qinglong/packages/ql3-cluster-admin/test/promptOutputKeyRetirementProcess.test.cjs

230 lines
6.5 KiB
JavaScript

const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
pluginPackagePromptOutputKeyRetirementAbsenceProof,
} = require('@qinglong/ai/plugin-package-prompt-output-key-retirement');
const {
ClusterPromptOutputKeyRetirementProcessConfigError,
runClusterPromptOutputKeyRetirementProcess,
} = require('../dist/prompt-output/key-management/promptOutputKeyRetirementProcess');
function preparationRow(value) {
return {
keyId: value.keyId,
retirementId: value.retirementId,
requestId: value.requestId,
mutationId: value.mutationId,
catalogDigest: value.catalogDigest,
materialProof: value.materialProof,
preparedAtMs: String(value.preparedAtMs),
preparationDigest: value.preparationDigest,
preparationJson: value,
};
}
function completionRow(value) {
return {
keyId: value.keyId,
retirementId: value.retirementId,
requestId: value.requestId,
mutationId: value.mutationId,
preparationDigest: value.preparationDigest,
retiredCatalogDigest: value.retiredCatalogDigest,
absenceProof: value.absenceProof,
completedAtMs: String(value.completedAtMs),
completionDigest: value.completionDigest,
completionJson: value,
};
}
function databaseHarness() {
let preparation = null;
let completion = null;
let closeCount = 0;
const statements = [];
const query = async (sql, values = []) => {
statements.push({ sql, values });
if (sql.includes('current_user AS "currentUser"')) {
return {
rows: [
{
currentUser: 'ql3_ai_maintenance',
maintenanceAuthority: true,
schemaAuthority: true,
artifactDeleteOnly: true,
tombstoneAppendOnly: true,
keyRetirementAppendOnly: true,
keyRotationAppendOnly: true,
terminalEvidenceReadOnly: true,
},
],
rowCount: 1,
};
}
if (sql.includes('key_retirement_preparations') && sql.includes('SELECT')) {
return {
rows:
preparation && preparation.keyId === values[0]
? [preparationRow(preparation)]
: [],
rowCount: preparation ? 1 : 0,
};
}
if (sql.includes('key_retirement_completions') && sql.includes('SELECT')) {
return {
rows:
completion && completion.keyId === values[0]
? [completionRow(completion)]
: [],
rowCount: completion ? 1 : 0,
};
}
if (sql.includes('count(*)::text AS count')) {
return { rows: [{ count: '0' }], rowCount: 1 };
}
if (
sql.includes('INSERT INTO') &&
sql.includes('key_retirement_preparations')
) {
preparation = JSON.parse(values[8]);
return { rows: [], rowCount: 1 };
}
if (
sql.includes('INSERT INTO') &&
sql.includes('key_retirement_completions')
) {
completion = JSON.parse(values[9]);
return { rows: [], rowCount: 1 };
}
if (
sql.startsWith('BEGIN') ||
sql.startsWith('SET LOCAL') ||
sql.startsWith('SELECT pg_advisory_xact_lock') ||
sql === 'COMMIT' ||
sql === 'ROLLBACK'
) {
return { rows: [], rowCount: 0 };
}
throw new Error(`unexpected query: ${sql}`);
};
const client = { query, release() {} };
const pool = {
query,
async connect() {
return client;
},
};
return {
statements,
get closeCount() {
return closeCount;
},
async openDatabase() {
return {
pool,
async close() {
closeCount += 1;
},
};
},
};
}
test('retires one inactive Cluster key through maintenance PostgreSQL and injected material authority', async () => {
const database = databaseHarness();
const keyId = 'cluster-key-old';
const initialCatalogDigest = '1'.repeat(64);
const materialProof = '2'.repeat(64);
const retiredCatalogDigest = '3'.repeat(64);
let retiredPreparation = null;
const materials = {
async inspect() {
if (retiredPreparation) {
return {
state: 'absent',
keyId,
catalogDigest: retiredCatalogDigest,
absenceProof: pluginPackagePromptOutputKeyRetirementAbsenceProof(
retiredPreparation,
retiredCatalogDigest,
),
};
}
return {
state: 'inactive',
keyId,
catalogDigest: initialCatalogDigest,
materialProof,
};
},
async retire({ preparation }) {
retiredPreparation = preparation;
return this.inspect(keyId);
},
};
const options = {
database: { connection: { host: 'postgres.example.test' } },
request: {
keyId,
retirementId: 'retirement-1',
requestId: 'request-1',
mutationId: 'mutation-1',
},
materials,
openDatabase: database.openDatabase,
};
const completed = await runClusterPromptOutputKeyRetirementProcess(options);
assert.equal(completed.status, 'completed');
assert.equal(completed.keyId, keyId);
assert.equal(completed.readiness.keyRetirementAppendOnly, true);
assert.equal(completed.readiness.keyRotationAppendOnly, true);
assert.match(completed.preparationDigest, /^[0-9a-f]{64}$/);
assert.match(completed.completionDigest, /^[0-9a-f]{64}$/);
const replay = await runClusterPromptOutputKeyRetirementProcess(options);
assert.equal(replay.status, 'existing');
assert.equal(replay.preparationDigest, completed.preparationDigest);
assert.equal(replay.completionDigest, completed.completionDigest);
assert.equal(database.closeCount, 2);
assert.equal(
database.statements.filter(
({ sql }) =>
sql.includes('INSERT INTO') &&
sql.includes('key_retirement_preparations'),
).length,
1,
);
assert.equal(
database.statements.filter(
({ sql }) =>
sql.includes('INSERT INTO') &&
sql.includes('key_retirement_completions'),
).length,
1,
);
});
test('rejects an invalid retirement request before opening PostgreSQL', async () => {
let opened = false;
await assert.rejects(
runClusterPromptOutputKeyRetirementProcess({
database: { connection: { host: 'postgres.example.test' } },
request: {
keyId: '../invalid',
retirementId: 'retirement-1',
requestId: 'request-1',
mutationId: 'mutation-1',
},
materials: { async inspect() {}, async retire() {} },
async openDatabase() {
opened = true;
throw new Error('must not open');
},
}),
ClusterPromptOutputKeyRetirementProcessConfigError,
);
assert.equal(opened, false);
});