feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,306 @@
// PostgreSQL anti-rollback ledger shared by bounded Cluster management authorities.
import type { PostgresClient, PostgresPool } from '@qinglong/runtime-core';
export type ClusterManagementIdentityAuthority =
| 'plugin-package-management'
| 'worker-credential-management'
| 'automation-management'
| 'approval-management';
const DIGEST_PATTERN = /^[A-Za-z0-9_-]{43}$/;
const KEY_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
const CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
type Row = Record<string, unknown>;
export interface PluginPackageIdentityKeysetLedgerSnapshot {
readonly schemaVersion: 1;
readonly generation: number;
readonly digest: string;
readonly issuer: string;
readonly audience: string;
readonly activeKeyIds: readonly string[];
readonly revokedKeyIds: readonly string[];
}
export interface PluginPackageIdentityKeysetLedgerPort {
observe(
snapshot: Readonly<PluginPackageIdentityKeysetLedgerSnapshot>,
): Promise<void>;
}
export class PostgresPluginPackageIdentityKeysetLedgerConflictError extends Error {
readonly code = 'POSTGRES_PLUGIN_PACKAGE_IDENTITY_KEYSET_LEDGER_CONFLICT';
constructor() {
super('PostgreSQL Plugin Package identity keyset ledger conflicts');
this.name = 'PostgresPluginPackageIdentityKeysetLedgerConflictError';
}
}
export class PostgresPluginPackageIdentityKeysetLedgerUnavailableError extends Error {
readonly code = 'POSTGRES_PLUGIN_PACKAGE_IDENTITY_KEYSET_LEDGER_UNAVAILABLE';
constructor(options?: ErrorOptions) {
super(
'PostgreSQL Plugin Package identity keyset ledger is unavailable',
options,
);
this.name = 'PostgresPluginPackageIdentityKeysetLedgerUnavailableError';
}
}
function reviewedKeyIds(
value: readonly string[],
minimum: number,
maximum: number,
): readonly string[] {
if (
!Array.isArray(value) ||
value.length < minimum ||
value.length > maximum
) {
throw new TypeError(
'PostgreSQL Plugin Package identity key ids are invalid',
);
}
const seen = new Set<string>();
for (const keyId of value) {
if (
typeof keyId !== 'string' ||
!KEY_ID_PATTERN.test(keyId) ||
seen.has(keyId)
) {
throw new TypeError(
'PostgreSQL Plugin Package identity key ids are invalid',
);
}
seen.add(keyId);
}
return Object.freeze([...value].sort());
}
function reviewedSnapshot(
value: Readonly<PluginPackageIdentityKeysetLedgerSnapshot>,
): Readonly<PluginPackageIdentityKeysetLedgerSnapshot> {
if (
!value ||
typeof value !== 'object' ||
Array.isArray(value) ||
Object.keys(value).length !== 7 ||
Object.keys(value).some(
(key) =>
![
'schemaVersion',
'generation',
'digest',
'issuer',
'audience',
'activeKeyIds',
'revokedKeyIds',
].includes(key),
) ||
value.schemaVersion !== 1 ||
!Number.isSafeInteger(value.generation) ||
value.generation < 1 ||
typeof value.digest !== 'string' ||
!DIGEST_PATTERN.test(value.digest) ||
typeof value.issuer !== 'string' ||
value.issuer.length < 1 ||
value.issuer.length > 512 ||
CONTROL_PATTERN.test(value.issuer) ||
typeof value.audience !== 'string' ||
value.audience.length < 1 ||
value.audience.length > 256 ||
CONTROL_PATTERN.test(value.audience)
) {
throw new TypeError(
'PostgreSQL Plugin Package identity keyset snapshot is invalid',
);
}
const activeKeyIds = reviewedKeyIds(value.activeKeyIds, 1, 8);
const revokedKeyIds = reviewedKeyIds(value.revokedKeyIds, 0, 64);
if (activeKeyIds.some((keyId) => revokedKeyIds.includes(keyId))) {
throw new TypeError(
'PostgreSQL Plugin Package identity keyset snapshot is invalid',
);
}
return Object.freeze({ ...value, activeKeyIds, revokedKeyIds });
}
function integer(row: Row, name: string): number {
const value = Number(row[name]);
if (!Number.isSafeInteger(value) || value < 1) {
throw new Error(`invalid ${name}`);
}
return value;
}
function text(row: Row, name: string): string {
const value = row[name];
if (typeof value !== 'string') throw new Error(`invalid ${name}`);
return value;
}
function textArray(row: Row, name: string): readonly string[] {
const value = row[name];
if (
!Array.isArray(value) ||
value.some((candidate) => typeof candidate !== 'string')
) {
throw new Error(`invalid ${name}`);
}
return value;
}
function sameArray(left: readonly string[], right: readonly string[]): boolean {
return (
left.length === right.length &&
left.every((value, index) => value === right[index])
);
}
function includesAll(
candidate: readonly string[],
required: readonly string[],
): boolean {
const values = new Set(candidate);
return required.every((value) => values.has(value));
}
async function rollback(client: PostgresClient): Promise<void> {
await client.query('ROLLBACK').catch(() => undefined);
}
export class PostgresPluginPackageIdentityKeysetLedgerRepository
implements PluginPackageIdentityKeysetLedgerPort
{
readonly #authority: ClusterManagementIdentityAuthority;
constructor(
private readonly pool: PostgresPool,
authority: ClusterManagementIdentityAuthority = 'plugin-package-management',
) {
if (!pool || typeof pool.connect !== 'function') {
throw new TypeError(
'PostgreSQL Plugin Package identity keyset ledger pool is invalid',
);
}
if (
authority !== 'plugin-package-management' &&
authority !== 'worker-credential-management' &&
authority !== 'automation-management' &&
authority !== 'approval-management'
) {
throw new TypeError(
'PostgreSQL management identity keyset authority is invalid',
);
}
this.#authority = authority;
}
async observe(
value: Readonly<PluginPackageIdentityKeysetLedgerSnapshot>,
): Promise<void> {
const candidate = reviewedSnapshot(value);
let client: PostgresClient;
try {
client = await this.pool.connect();
} catch (error) {
throw new PostgresPluginPackageIdentityKeysetLedgerUnavailableError({
cause: error,
});
}
try {
await client.query('BEGIN');
await client.query(
`INSERT INTO "ql3"."plugin_package_identity_keyset_ledger" (
authority, generation, digest, issuer, audience,
active_key_ids, revoked_key_ids, updated_at_ms
)
VALUES (
$1, $2, $3, $4, $5, $6::jsonb, $7::jsonb,
floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint
)
ON CONFLICT (authority) DO NOTHING`,
[
this.#authority,
candidate.generation,
candidate.digest,
candidate.issuer,
candidate.audience,
JSON.stringify(candidate.activeKeyIds),
JSON.stringify(candidate.revokedKeyIds),
],
);
const selected = await client.query<Row>(
`SELECT generation, digest, issuer, audience,
active_key_ids AS "activeKeyIds",
revoked_key_ids AS "revokedKeyIds"
FROM "ql3"."plugin_package_identity_keyset_ledger"
WHERE authority = $1
FOR UPDATE`,
[this.#authority],
);
if (selected.rows.length !== 1) throw new Error('ledger row is missing');
const current = selected.rows[0]!;
const generation = integer(current, 'generation');
const digest = text(current, 'digest');
const issuer = text(current, 'issuer');
const audience = text(current, 'audience');
const activeKeyIds = textArray(current, 'activeKeyIds');
const revokedKeyIds = textArray(current, 'revokedKeyIds');
const exact =
generation === candidate.generation &&
digest === candidate.digest &&
issuer === candidate.issuer &&
audience === candidate.audience &&
sameArray(activeKeyIds, candidate.activeKeyIds) &&
sameArray(revokedKeyIds, candidate.revokedKeyIds);
if (!exact) {
const retained = [
...candidate.activeKeyIds,
...candidate.revokedKeyIds,
];
if (
candidate.generation <= generation ||
candidate.issuer !== issuer ||
candidate.audience !== audience ||
!includesAll(candidate.revokedKeyIds, revokedKeyIds) ||
!includesAll(retained, activeKeyIds)
) {
throw new PostgresPluginPackageIdentityKeysetLedgerConflictError();
}
await client.query(
`UPDATE "ql3"."plugin_package_identity_keyset_ledger"
SET generation = $2,
digest = $3,
active_key_ids = $4::jsonb,
revoked_key_ids = $5::jsonb,
updated_at_ms =
floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint
WHERE authority = $1`,
[
this.#authority,
candidate.generation,
candidate.digest,
JSON.stringify(candidate.activeKeyIds),
JSON.stringify(candidate.revokedKeyIds),
],
);
}
await client.query('COMMIT');
} catch (error) {
await rollback(client);
if (
error instanceof PostgresPluginPackageIdentityKeysetLedgerConflictError
) {
throw error;
}
throw new PostgresPluginPackageIdentityKeysetLedgerUnavailableError({
cause: error,
});
} finally {
client.release();
}
}
}
@@ -0,0 +1,321 @@
// PostgreSQL distributed quota authority for authenticated management operations.
import type { PostgresPool } from '@qinglong/runtime-core';
import {
PLUGIN_PACKAGE_MANAGEMENT_QUOTA_OPERATIONS,
PluginPackageManagementQuotaExceededError,
PluginPackageManagementUnavailableError,
type ConsumePluginPackageManagementQuotaCommand,
type PluginPackageManagementQuotaOperation,
type PluginPackageManagementQuotaPort,
type PluginPackageManagementQuotaResult,
} from '@qinglong/runtime-core/plugin-package-management';
import {
postgresRequiredBoolean,
postgresRequiredInteger,
} from '../repository/definitionRepositorySupport';
const DEFAULT_WINDOW_MS = 60_000;
const DEFAULT_LIMITS = Object.freeze({
'plugin-package.propose': 30,
'plugin-package.decide': 60,
'plugin-package.inspect': 600,
});
const PROJECT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
const IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,254}$/;
type Row = Record<string, unknown>;
export interface PostgresPluginPackageManagementQuotaOptions {
readonly windowMs?: number;
readonly limits?: Partial<
Readonly<Record<PluginPackageManagementQuotaOperation, number>>
>;
}
function unavailable(cause?: unknown): PluginPackageManagementUnavailableError {
return new PluginPackageManagementUnavailableError({
cause: cause instanceof Error ? cause : undefined,
});
}
function integer(
value: number | undefined,
fallback: number,
minimum: number,
maximum: number,
label: string,
): number {
const candidate = value ?? fallback;
if (
!Number.isSafeInteger(candidate) ||
candidate < minimum ||
candidate > maximum
) {
throw new TypeError(`PostgreSQL Package management ${label} is invalid`);
}
return candidate;
}
function reviewedOptions(
value: PostgresPluginPackageManagementQuotaOptions | undefined,
): Readonly<{
windowMs: number;
limits: Readonly<Record<PluginPackageManagementQuotaOperation, number>>;
}> {
if (
value !== undefined &&
(!value ||
typeof value !== 'object' ||
Array.isArray(value) ||
Object.keys(value).some((key) => key !== 'windowMs' && key !== 'limits'))
) {
throw new TypeError(
'PostgreSQL Package management quota options are invalid',
);
}
const limits = value?.limits;
if (
limits !== undefined &&
(!limits ||
typeof limits !== 'object' ||
Array.isArray(limits) ||
Object.keys(limits).some(
(key) =>
!PLUGIN_PACKAGE_MANAGEMENT_QUOTA_OPERATIONS.includes(
key as PluginPackageManagementQuotaOperation,
),
))
) {
throw new TypeError(
'PostgreSQL Package management quota limits are invalid',
);
}
return Object.freeze({
windowMs: integer(
value?.windowMs,
DEFAULT_WINDOW_MS,
1_000,
5 * 60_000,
'quota window',
),
limits: Object.freeze({
'plugin-package.propose': integer(
limits?.['plugin-package.propose'],
DEFAULT_LIMITS['plugin-package.propose'],
1,
1_000,
'proposal quota',
),
'plugin-package.decide': integer(
limits?.['plugin-package.decide'],
DEFAULT_LIMITS['plugin-package.decide'],
1,
1_000,
'decision quota',
),
'plugin-package.inspect': integer(
limits?.['plugin-package.inspect'],
DEFAULT_LIMITS['plugin-package.inspect'],
1,
1_000,
'inspection quota',
),
}),
});
}
function validateCommand(
command: ConsumePluginPackageManagementQuotaCommand,
): Readonly<ConsumePluginPackageManagementQuotaCommand> {
if (
!command ||
typeof command !== 'object' ||
Array.isArray(command) ||
Object.keys(command).some(
(key) =>
!['projectId', 'subject', 'operation', 'idempotencyKey'].includes(key),
) ||
Object.keys(command).length !== 4 ||
typeof command.projectId !== 'string' ||
!PROJECT_PATTERN.test(command.projectId) ||
!command.subject ||
typeof command.subject !== 'object' ||
Array.isArray(command.subject) ||
Object.keys(command.subject).length !== 2 ||
command.subject.type !== 'user' ||
typeof command.subject.id !== 'string' ||
command.subject.id.length < 1 ||
command.subject.id.length > 255 ||
/[\u0000-\u001f\u007f]/.test(command.subject.id) ||
!PLUGIN_PACKAGE_MANAGEMENT_QUOTA_OPERATIONS.includes(command.operation) ||
typeof command.idempotencyKey !== 'string' ||
!IDENTIFIER_PATTERN.test(command.idempotencyKey)
) {
throw new TypeError(
'PostgreSQL Package management quota command is invalid',
);
}
return command;
}
export class PostgresPluginPackageManagementQuotaRepository
implements PluginPackageManagementQuotaPort
{
readonly #windowMs: number;
readonly #limits: Readonly<
Record<PluginPackageManagementQuotaOperation, number>
>;
constructor(
private readonly pool: PostgresPool,
options?: PostgresPluginPackageManagementQuotaOptions,
) {
if (!pool || typeof pool.query !== 'function') {
throw new TypeError(
'PostgreSQL Package management quota pool is invalid',
);
}
const reviewed = reviewedOptions(options);
this.#windowMs = reviewed.windowMs;
this.#limits = reviewed.limits;
}
async consume(
commandValue: ConsumePluginPackageManagementQuotaCommand,
): Promise<Readonly<PluginPackageManagementQuotaResult>> {
const command = validateCommand(commandValue);
const limit = this.#limits[command.operation];
let result;
try {
result = await this.pool.query<Row>(
`
WITH database_clock AS (
SELECT floor(
extract(epoch FROM clock_timestamp()) * 1000
)::bigint AS now_ms
)
INSERT INTO "ql3"."plugin_package_management_quota_buckets" (
project_id, subject_type, subject_id, operation,
window_started_at_ms, consumed_count, receipt_ids, updated_at_ms
)
SELECT
$1, $2, $3, $4,
(now_ms / $6::bigint) * $6::bigint,
1,
jsonb_build_array($5::text),
now_ms
FROM database_clock
ON CONFLICT (project_id, subject_type, subject_id, operation)
DO UPDATE SET
window_started_at_ms = CASE
WHEN "plugin_package_management_quota_buckets".window_started_at_ms
+ $6::bigint <= EXCLUDED.updated_at_ms
THEN (EXCLUDED.updated_at_ms / $6::bigint) * $6::bigint
ELSE "plugin_package_management_quota_buckets".window_started_at_ms
END,
consumed_count = CASE
WHEN "plugin_package_management_quota_buckets".window_started_at_ms
+ $6::bigint <= EXCLUDED.updated_at_ms
THEN 1
WHEN "plugin_package_management_quota_buckets".receipt_ids ? $5::text
THEN "plugin_package_management_quota_buckets".consumed_count
ELSE "plugin_package_management_quota_buckets".consumed_count + 1
END,
receipt_ids = CASE
WHEN "plugin_package_management_quota_buckets".window_started_at_ms
+ $6::bigint <= EXCLUDED.updated_at_ms
THEN jsonb_build_array($5::text)
WHEN "plugin_package_management_quota_buckets".receipt_ids ? $5::text
THEN "plugin_package_management_quota_buckets".receipt_ids
ELSE "plugin_package_management_quota_buckets".receipt_ids
|| jsonb_build_array($5::text)
END,
updated_at_ms = EXCLUDED.updated_at_ms
WHERE
"plugin_package_management_quota_buckets".window_started_at_ms
+ $6::bigint <= EXCLUDED.updated_at_ms
OR "plugin_package_management_quota_buckets".receipt_ids ? $5::text
OR "plugin_package_management_quota_buckets".consumed_count < $7::integer
RETURNING
true AS admitted,
consumed_count AS "consumedCount",
window_started_at_ms + $6::bigint AS "resetAtMs",
updated_at_ms AS "observedAtMs"
`.trim(),
[
command.projectId,
command.subject.type,
command.subject.id,
command.operation,
command.idempotencyKey,
this.#windowMs,
limit,
],
);
} catch (error) {
throw unavailable(error);
}
if (result.rows.length === 0) {
try {
result = await this.pool.query<Row>(
`
WITH database_clock AS (
SELECT floor(
extract(epoch FROM clock_timestamp()) * 1000
)::bigint AS now_ms
)
SELECT
false AS admitted,
buckets.consumed_count AS "consumedCount",
buckets.window_started_at_ms + $5::bigint AS "resetAtMs",
database_clock.now_ms AS "observedAtMs"
FROM "ql3"."plugin_package_management_quota_buckets" AS buckets
CROSS JOIN database_clock
WHERE buckets.project_id = $1
AND buckets.subject_type = $2
AND buckets.subject_id = $3
AND buckets.operation = $4
LIMIT 2
`.trim(),
[
command.projectId,
command.subject.type,
command.subject.id,
command.operation,
this.#windowMs,
],
);
} catch (error) {
throw unavailable(error);
}
}
if (result.rows.length !== 1) throw unavailable();
const row = result.rows[0]!;
const admitted = postgresRequiredBoolean(row.admitted, unavailable);
const consumedCount = postgresRequiredInteger(
row.consumedCount,
unavailable,
);
const resetAtMs = postgresRequiredInteger(row.resetAtMs, unavailable);
const observedAtMs = postgresRequiredInteger(row.observedAtMs, unavailable);
if (
consumedCount < 1 ||
consumedCount > limit ||
resetAtMs <= observedAtMs ||
resetAtMs > observedAtMs + this.#windowMs
) {
throw unavailable();
}
if (!admitted) {
throw new PluginPackageManagementQuotaExceededError(
Math.max(1, resetAtMs - observedAtMs),
);
}
return Object.freeze({
remaining: limit - consumedCount,
resetAtMs,
observedAtMs,
});
}
}