feat(ql3): add cluster tool result key authority

This commit is contained in:
whyour
2026-08-15 00:40:56 +08:00
parent 93690dd921
commit aae96390cc
10 changed files with 829 additions and 91 deletions
@@ -1,7 +1,4 @@
// Remote Execution owns mounted Secret resolution for authenticated delivery.
import { constants } from 'node:fs';
import { lstat, open, realpath } from 'node:fs/promises';
import { isAbsolute, join, normalize, parse, relative } from 'node:path';
import {
MAX_REMOTE_SECRET_DELIVERY_TOTAL_VALUE_BYTES,
MAX_REMOTE_SECRET_VALUE_BYTES,
@@ -12,7 +9,7 @@ import {
} from '@qinglong/runtime-core/remote-secret-delivery';
import { secretProjectionFileName } from '@qinglong/runtime-core/secret-projection';
const MAX_SECRET_ROOT_BYTES = 4096;
import { PrivateProjectedFileReader } from '../security/privateProjectedFile';
export interface ClusterMountedSecretProviderOptions {
/**
@@ -38,20 +35,6 @@ export class ClusterMountedSecretProviderError extends Error {
}
}
function rootDirectory(value: string): string {
if (
typeof value !== 'string' ||
!isAbsolute(value) ||
parse(value).root === value ||
normalize(value) !== value ||
value.includes('\0') ||
Buffer.byteLength(value, 'utf8') > MAX_SECRET_ROOT_BYTES
) {
throw new ClusterMountedSecretProviderError('invalid_configuration');
}
return value;
}
/**
* Kubernetes Secret keys cannot contain a SecretRef directly. This stable,
* non-reversible name also prevents Project/name input from becoming a path.
@@ -66,72 +49,6 @@ export function clusterMountedSecretFileName(secretRef: string): string {
}
}
function remainsBelow(root: string, candidate: string): boolean {
const suffix = relative(root, candidate);
return (
suffix.length > 0 &&
!isAbsolute(suffix) &&
suffix !== '..' &&
!suffix.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)
);
}
async function resolvedRoot(path: string): Promise<string> {
try {
const configured = await lstat(path);
if (!configured.isDirectory() || configured.isSymbolicLink()) {
throw new Error('root is not a direct directory');
}
return await realpath(path);
} catch (error) {
throw new ClusterMountedSecretProviderError('root_unavailable', {
cause: error,
});
}
}
async function readMaterial(root: string, secretRef: string): Promise<Buffer> {
const candidate = join(root, clusterMountedSecretFileName(secretRef));
let handle;
try {
const target = await realpath(candidate);
if (!remainsBelow(root, target)) {
throw new Error('material escaped its root');
}
handle = await open(
target,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
const stat = await handle.stat();
if (
!stat.isFile() ||
stat.nlink !== 1 ||
stat.size < 0 ||
stat.size > MAX_REMOTE_SECRET_VALUE_BYTES ||
(stat.mode & 0o111) !== 0 ||
(stat.mode & 0o027) !== 0
) {
throw new Error('material metadata is unsafe');
}
const bytes = await handle.readFile();
if (
bytes.byteLength !== stat.size ||
bytes.byteLength > MAX_REMOTE_SECRET_VALUE_BYTES ||
(await realpath(candidate)) !== target
) {
bytes.fill(0);
throw new Error('material changed while reading');
}
return bytes;
} catch (error) {
throw new ClusterMountedSecretProviderError('material_unavailable', {
cause: error,
});
} finally {
await handle?.close().catch(() => undefined);
}
}
function secretValue(bytes: Buffer): string {
try {
const value = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
@@ -155,17 +72,34 @@ function secretValue(bytes: Buffer): string {
export class ClusterMountedSecretProvider
implements RemoteWorkerSecretValueProvider
{
private readonly rootDirectory: string;
private readonly reader: PrivateProjectedFileReader;
constructor(options: ClusterMountedSecretProviderOptions) {
if (!options || typeof options !== 'object' || Array.isArray(options)) {
throw new ClusterMountedSecretProviderError('invalid_configuration');
}
this.rootDirectory = rootDirectory(options.rootDirectory);
try {
this.reader = new PrivateProjectedFileReader({
rootDirectory: options.rootDirectory,
minimumBytes: 0,
maximumBytes: MAX_REMOTE_SECRET_VALUE_BYTES,
access: 'private_material',
});
} catch (error) {
throw new ClusterMountedSecretProviderError('invalid_configuration', {
cause: error,
});
}
}
async verify(): Promise<void> {
await resolvedRoot(this.rootDirectory);
try {
await this.reader.verify();
} catch (error) {
throw new ClusterMountedSecretProviderError('root_unavailable', {
cause: error,
});
}
}
async resolve(
@@ -179,13 +113,19 @@ export class ClusterMountedSecretProvider
cause: error,
});
}
const root = await resolvedRoot(this.rootDirectory);
const buffers: Buffer[] = [];
try {
const values = [];
let totalBytes = 0;
for (const secretRef of normalized.secretRefs) {
const bytes = await readMaterial(root, secretRef);
const bytes = await this.reader
.read(clusterMountedSecretFileName(secretRef))
.catch((error) => {
throw new ClusterMountedSecretProviderError(
'material_unavailable',
{ cause: error },
);
});
buffers.push(bytes);
totalBytes += bytes.byteLength;
if (totalBytes > MAX_REMOTE_SECRET_DELIVERY_TOTAL_VALUE_BYTES) {