mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:32:44 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
const {
|
||||
ProjectPolicyUnavailableError,
|
||||
ProjectRoleBindingMutationConflictError,
|
||||
ProjectRoleBindingVersionConflictError,
|
||||
} = require('@qinglong/runtime-core/project-policy');
|
||||
const {
|
||||
PostgresProjectPolicyRepository,
|
||||
} = require('../dist/security/projectPolicyRepository');
|
||||
|
||||
const BINDING = Object.freeze({
|
||||
projectId: 'default',
|
||||
subject: Object.freeze({ type: 'user', id: 'usr_primary' }),
|
||||
version: 1,
|
||||
state: 'active',
|
||||
role: 'owner',
|
||||
mutationId: 'grant-owner-1',
|
||||
changedBy: Object.freeze({ type: 'system', id: 'bootstrap' }),
|
||||
createdAtMs: 1,
|
||||
});
|
||||
|
||||
function bindingRow(overrides = {}) {
|
||||
return {
|
||||
projectId: 'default',
|
||||
subjectType: 'user',
|
||||
subjectId: 'usr_primary',
|
||||
version: 1,
|
||||
state: 'active',
|
||||
role: 'owner',
|
||||
mutationId: 'grant-owner-1',
|
||||
changedByType: 'system',
|
||||
changedById: 'bootstrap',
|
||||
createdAtMs: '1',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function snapshotRow(overrides = {}) {
|
||||
return {
|
||||
projectId: 'default',
|
||||
projectName: 'Default',
|
||||
projectSlug: 'default',
|
||||
projectStatus: 'active',
|
||||
projectVersion: 1,
|
||||
projectCreatedAtMs: '0',
|
||||
projectUpdatedAtMs: '0',
|
||||
bindingProjectId: 'default',
|
||||
bindingSubjectType: 'user',
|
||||
bindingSubjectId: 'usr_primary',
|
||||
bindingVersion: 1,
|
||||
bindingState: 'active',
|
||||
bindingRole: 'owner',
|
||||
bindingMutationId: 'grant-owner-1',
|
||||
bindingChangedByType: 'system',
|
||||
bindingChangedById: 'bootstrap',
|
||||
bindingCreatedAtMs: '1',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('resolves one normalized Project and latest RoleBinding snapshot', async () => {
|
||||
const queries = [];
|
||||
const repository = new PostgresProjectPolicyRepository({
|
||||
async query(text, values) {
|
||||
queries.push({ text, values });
|
||||
return { rows: [snapshotRow()] };
|
||||
},
|
||||
async connect() {
|
||||
throw new Error('not used');
|
||||
},
|
||||
});
|
||||
assert.deepEqual(
|
||||
await repository.resolve('default', { type: 'user', id: 'usr_primary' }),
|
||||
{
|
||||
project: {
|
||||
id: 'default',
|
||||
name: 'Default',
|
||||
slug: 'default',
|
||||
status: 'active',
|
||||
version: 1,
|
||||
createdAtMs: 0,
|
||||
updatedAtMs: 0,
|
||||
},
|
||||
binding: BINDING,
|
||||
},
|
||||
);
|
||||
assert.deepEqual(queries[0].values, ['default', 'user', 'usr_primary']);
|
||||
assert.match(queries[0].text, /LEFT JOIN LATERAL/);
|
||||
assert.match(queries[0].text, /ORDER BY candidate\.version DESC/);
|
||||
await assert.rejects(
|
||||
repository.resolve('x'.repeat(129), {
|
||||
type: 'user',
|
||||
id: 'usr_primary',
|
||||
}),
|
||||
);
|
||||
assert.equal(queries.length, 1);
|
||||
});
|
||||
|
||||
function appendPool(options = {}) {
|
||||
const events = [];
|
||||
let connection = 0;
|
||||
return {
|
||||
events,
|
||||
pool: {
|
||||
async query() {
|
||||
throw new Error('not used');
|
||||
},
|
||||
async connect() {
|
||||
connection += 1;
|
||||
let inserted = false;
|
||||
return {
|
||||
async query(text) {
|
||||
events.push(text.split('\n', 1)[0]);
|
||||
if (text.startsWith('SELECT id FROM'))
|
||||
return { rows: [{ id: 'default' }] };
|
||||
if (text.includes('mutation_id = $2')) {
|
||||
return {
|
||||
rows: options.replay ? [bindingRow(options.replay)] : [],
|
||||
};
|
||||
}
|
||||
if (text.startsWith('SELECT version FROM')) {
|
||||
return {
|
||||
rows:
|
||||
options.currentVersion === undefined
|
||||
? []
|
||||
: [{ version: options.currentVersion }],
|
||||
};
|
||||
}
|
||||
if (text.startsWith('INSERT INTO')) {
|
||||
if (options.retryOnce && connection === 1 && !inserted) {
|
||||
inserted = true;
|
||||
throw Object.assign(new Error('serialization'), {
|
||||
code: '40001',
|
||||
});
|
||||
}
|
||||
return { rows: [], rowCount: 1 };
|
||||
}
|
||||
return { rows: [] };
|
||||
},
|
||||
release() {
|
||||
events.push(`release:${connection}`);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('appends under a serializable Project lock and replays exactly', async () => {
|
||||
const insertedFixture = appendPool();
|
||||
const inserted = await new PostgresProjectPolicyRepository(
|
||||
insertedFixture.pool,
|
||||
).append({ expectedCurrentVersion: 0, binding: BINDING });
|
||||
assert.deepEqual(inserted, { status: 'inserted', binding: BINDING });
|
||||
assert.equal(
|
||||
insertedFixture.events.some((event) =>
|
||||
event.startsWith('BEGIN ISOLATION LEVEL SERIALIZABLE'),
|
||||
),
|
||||
true,
|
||||
);
|
||||
assert.ok(
|
||||
insertedFixture.events.findIndex((event) => event.startsWith('SELECT id')) <
|
||||
insertedFixture.events.findIndex((event) => event.startsWith('INSERT')),
|
||||
);
|
||||
assert.ok(insertedFixture.events.includes('COMMIT'));
|
||||
|
||||
const replayFixture = appendPool({ replay: {} });
|
||||
const replay = await new PostgresProjectPolicyRepository(
|
||||
replayFixture.pool,
|
||||
).append({ expectedCurrentVersion: 0, binding: BINDING });
|
||||
assert.deepEqual(replay, { status: 'existing', binding: BINDING });
|
||||
assert.equal(
|
||||
replayFixture.events.some((event) => event.startsWith('INSERT')),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('rejects stale versions and conflicting mutation replay', async () => {
|
||||
await assert.rejects(
|
||||
new PostgresProjectPolicyRepository(
|
||||
appendPool({ currentVersion: 1 }).pool,
|
||||
).append({ expectedCurrentVersion: 0, binding: BINDING }),
|
||||
ProjectRoleBindingVersionConflictError,
|
||||
);
|
||||
await assert.rejects(
|
||||
new PostgresProjectPolicyRepository(
|
||||
appendPool({ replay: { role: 'viewer' } }).pool,
|
||||
).append({ expectedCurrentVersion: 0, binding: BINDING }),
|
||||
ProjectRoleBindingMutationConflictError,
|
||||
);
|
||||
});
|
||||
|
||||
test('retries serialization failures but fails closed on corrupt rows', async () => {
|
||||
const retryFixture = appendPool({ retryOnce: true });
|
||||
assert.equal(
|
||||
(
|
||||
await new PostgresProjectPolicyRepository(retryFixture.pool).append({
|
||||
expectedCurrentVersion: 0,
|
||||
binding: BINDING,
|
||||
})
|
||||
).status,
|
||||
'inserted',
|
||||
);
|
||||
assert.equal(
|
||||
retryFixture.events.filter((event) => event.startsWith('release:')).length,
|
||||
2,
|
||||
);
|
||||
|
||||
const repository = new PostgresProjectPolicyRepository({
|
||||
async query() {
|
||||
return { rows: [snapshotRow({ projectVersion: 'not-a-number' })] };
|
||||
},
|
||||
async connect() {
|
||||
throw new Error('not used');
|
||||
},
|
||||
});
|
||||
await assert.rejects(
|
||||
repository.resolve('default', { type: 'user', id: 'usr_primary' }),
|
||||
ProjectPolicyUnavailableError,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user