mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 10:32:40 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { DatabaseSync } = require('node:sqlite');
|
||||
const { test } = require('node:test');
|
||||
|
||||
const {
|
||||
LocalSqliteAdoptionError,
|
||||
inspectLegacyCrontabAdoptionDiagnostics,
|
||||
inspectLegacySqlitePath,
|
||||
issueReviewedLegacyCrontabAdoptionDecisionAuthorizationFile,
|
||||
verifyReviewedLegacyCrontabAdoptionDecisionAuthorizationFile,
|
||||
} = require('..');
|
||||
const {
|
||||
LegacyCrontabDecisionIssuerKeyringFileProvider,
|
||||
provisionLegacyCrontabDecisionIssuerKeyring,
|
||||
} = require('../dist/legacy-adoption/legacyCrontabDecisionIssuer');
|
||||
|
||||
const NOW_MS = 1_760_000_000_000;
|
||||
const DECISION_ID = '019a2b3c-4d5e-7f60-8123-456789abcdef';
|
||||
|
||||
function fixture(t) {
|
||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-issuer-'));
|
||||
fs.chmodSync(directory, 0o700);
|
||||
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
||||
const sourcePath = path.join(directory, 'database.sqlite');
|
||||
const source = new DatabaseSync(sourcePath);
|
||||
source.exec(`
|
||||
CREATE TABLE "Auths" (id INTEGER PRIMARY KEY, type TEXT, info TEXT);
|
||||
CREATE TABLE "Crontabs" (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
command TEXT NOT NULL,
|
||||
schedule TEXT
|
||||
);
|
||||
CREATE TABLE "Envs" (id INTEGER PRIMARY KEY, name TEXT, value TEXT);
|
||||
INSERT INTO "Crontabs" (id, name, command, schedule)
|
||||
VALUES (1, 'Reviewed task', 'task /scripts/reviewed.sh', '0 0 * * *');
|
||||
`);
|
||||
source.close();
|
||||
return {
|
||||
directory,
|
||||
sourcePath,
|
||||
authorizationPath: path.join(directory, 'decision.ndjson'),
|
||||
issuerKeyringPath: path.join(directory, 'decision-issuer.keyring'),
|
||||
};
|
||||
}
|
||||
|
||||
function review(value) {
|
||||
const plan = inspectLegacySqlitePath({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
});
|
||||
const page = inspectLegacyCrontabAdoptionDiagnostics({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
expectedPlanDigest: plan.planDigest,
|
||||
limit: 16,
|
||||
});
|
||||
assert.equal(page.diagnostics.length, 1);
|
||||
assert.equal(page.diagnostics[0].classification, 'lossless');
|
||||
return {
|
||||
plan,
|
||||
decisions: [
|
||||
{
|
||||
rowOrdinal: page.diagnostics[0].rowOrdinal,
|
||||
sourceDigest: page.diagnostics[0].sourceDigest,
|
||||
disposition: 'adopt',
|
||||
reason: 'reviewed_lossless',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function reviewer(assurance = 'local_console') {
|
||||
return Object.freeze({
|
||||
subject: Object.freeze({ type: 'user', id: 'local-owner' }),
|
||||
authenticationId: 'local-console:credential-v1',
|
||||
authenticatedAtMs: NOW_MS - 1_000,
|
||||
expiresAtMs: NOW_MS + 5 * 60 * 1_000,
|
||||
assurance,
|
||||
});
|
||||
}
|
||||
|
||||
test('issues one bounded authorization from an authenticated capability and dedicated keyring', async (t) => {
|
||||
const value = fixture(t);
|
||||
const { plan, decisions } = review(value);
|
||||
await provisionLegacyCrontabDecisionIssuerKeyring(value.issuerKeyringPath);
|
||||
let authenticationCalls = 0;
|
||||
let confirmationCalls = 0;
|
||||
const result =
|
||||
await issueReviewedLegacyCrontabAdoptionDecisionAuthorizationFile({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
expectedPlanDigest: plan.planDigest,
|
||||
decisionId: DECISION_ID,
|
||||
authorizationPath: value.authorizationPath,
|
||||
issuerKeyringPath: value.issuerKeyringPath,
|
||||
decisions,
|
||||
async authenticateReviewer() {
|
||||
authenticationCalls += 1;
|
||||
return reviewer();
|
||||
},
|
||||
confirmIssuerAuthority() {
|
||||
confirmationCalls += 1;
|
||||
},
|
||||
lifetimeMs: 2 * 60 * 1_000,
|
||||
clock: () => NOW_MS,
|
||||
});
|
||||
|
||||
assert.equal(authenticationCalls, 1);
|
||||
assert.equal(confirmationCalls, 4);
|
||||
assert.equal(result.receipt.reviewer.subject.id, 'local-owner');
|
||||
assert.equal(result.receipt.issuedAtMs, NOW_MS);
|
||||
assert.equal(result.receipt.expiresAtMs, NOW_MS + 2 * 60 * 1_000);
|
||||
assert.match(result.file.keyId, /^qladk-/);
|
||||
assert.equal(fs.statSync(value.authorizationPath).mode & 0o777, 0o600);
|
||||
|
||||
const verified =
|
||||
await verifyReviewedLegacyCrontabAdoptionDecisionAuthorizationFile({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
expectedPlanDigest: plan.planDigest,
|
||||
expectedDecisionId: DECISION_ID,
|
||||
authorizationPath: value.authorizationPath,
|
||||
keyProvider: new LegacyCrontabDecisionIssuerKeyringFileProvider(
|
||||
value.issuerKeyringPath,
|
||||
),
|
||||
observedAtMs: NOW_MS + 1_000,
|
||||
});
|
||||
assert.equal(verified.file.fileDigest, result.file.fileDigest);
|
||||
});
|
||||
|
||||
test('rejects a self-reported weak reviewer before reading any issuer key', async (t) => {
|
||||
const value = fixture(t);
|
||||
const { plan, decisions } = review(value);
|
||||
await assert.rejects(
|
||||
issueReviewedLegacyCrontabAdoptionDecisionAuthorizationFile({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
expectedPlanDigest: plan.planDigest,
|
||||
decisionId: DECISION_ID,
|
||||
authorizationPath: value.authorizationPath,
|
||||
issuerKeyringPath: value.issuerKeyringPath,
|
||||
decisions,
|
||||
authenticateReviewer: () => reviewer('single_factor'),
|
||||
confirmIssuerAuthority() {},
|
||||
clock: () => NOW_MS,
|
||||
}),
|
||||
LocalSqliteAdoptionError,
|
||||
);
|
||||
assert.equal(fs.existsSync(value.authorizationPath), false);
|
||||
});
|
||||
|
||||
test('rechecks issuer authority immediately before no-replace publication', async (t) => {
|
||||
const value = fixture(t);
|
||||
const { plan, decisions } = review(value);
|
||||
await provisionLegacyCrontabDecisionIssuerKeyring(value.issuerKeyringPath);
|
||||
let confirmationCalls = 0;
|
||||
await assert.rejects(
|
||||
issueReviewedLegacyCrontabAdoptionDecisionAuthorizationFile({
|
||||
sourcePath: value.sourcePath,
|
||||
profile: 'edge',
|
||||
legacyTimezone: 'UTC',
|
||||
expectedPlanDigest: plan.planDigest,
|
||||
decisionId: DECISION_ID,
|
||||
authorizationPath: value.authorizationPath,
|
||||
issuerKeyringPath: value.issuerKeyringPath,
|
||||
decisions,
|
||||
authenticateReviewer: () => reviewer(),
|
||||
confirmIssuerAuthority() {
|
||||
confirmationCalls += 1;
|
||||
if (confirmationCalls === 4) throw new Error('authority drift');
|
||||
},
|
||||
clock: () => NOW_MS,
|
||||
}),
|
||||
LocalSqliteAdoptionError,
|
||||
);
|
||||
assert.equal(confirmationCalls, 4);
|
||||
assert.equal(fs.existsSync(value.authorizationPath), false);
|
||||
assert.deepEqual(
|
||||
fs.readdirSync(value.directory).filter((entry) => entry.includes('.tmp')),
|
||||
[],
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user