Files
qinglong/scripts/ql3-worker-kubernetes-rollout-live-contract.cjs

2440 lines
89 KiB
JavaScript

#!/usr/bin/env node
'use strict';
const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const { createHash } = crypto;
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { createRequire } = require('node:module');
const { pathToFileURL } = require('node:url');
const { spawnSync } = require('node:child_process');
const { createMutualTlsPki } = require('./lib/ql3-live-pki.cjs');
const {
validateWorkerKubernetesRolloutLiveReport,
} = require('./ql3-worker-kubernetes-rollout-live-audit.cjs');
const {
remoteWorkerArchitectureForNodeRuntime,
remoteWorkerSupportTierForArchitecture,
} = require('../packages/ql3-runtime-core/dist/remote-execution/remoteWorkerCompatibility.js');
const ROOT = path.resolve(__dirname, '..');
const K3S_IMAGE = 'rancher/k3s:v1.34.3-k3s1';
const K3S_DIGEST =
'sha256:71abd3a56f57884c62732e0e0d87606052cb5f8555b7db7e8e33c04570b8175c';
const POSTGRES_IMAGE = 'postgres:18.4-bookworm';
const POSTGRES_DIGEST =
'sha256:1961f96e6029a02c3812d7cb329a3b03a3ac2bb067058dec17b0f5596aca9296';
const POSTGRES_DATABASE = 'ql3_contract';
const POSTGRES_SUPERUSER_PASSWORD = 'postgres';
const POSTGRES_ROLES = Object.freeze({
migration: Object.freeze({ user: 'ql3_migration', password: 'ql3_migration_test' }),
runtime: Object.freeze({ user: 'ql3_runtime', password: 'ql3_runtime_test' }),
admin: Object.freeze({ user: 'ql3_admin', password: 'ql3_admin_test' }),
automationManager: Object.freeze({
user: 'ql3_automation_manager',
password: 'ql3_automation_manager_test',
}),
approvalManager: Object.freeze({
user: 'ql3_approval_manager',
password: 'ql3_approval_manager_test',
}),
packageManager: Object.freeze({
user: 'ql3_package_manager',
password: 'ql3_package_manager_test',
}),
packageExecutor: Object.freeze({
user: 'ql3_package_executor',
password: 'ql3_package_executor_test',
}),
workerCredentialManager: Object.freeze({
user: 'ql3_worker_credential_manager',
password: 'ql3_worker_credential_manager_test',
}),
workerCredentialExecutor: Object.freeze({
user: 'ql3_worker_credential_executor',
password: 'ql3_worker_credential_executor_test',
}),
workerIngress: Object.freeze({
user: 'ql3_worker_ingress',
password: 'ql3_worker_ingress_test',
}),
});
const WORKER_CREDENTIAL_PEPPER = Buffer.alloc(32, 7).toString('base64url');
const EXECUTOR_NAMESPACE = 'ql3-worker-executor-live';
const EXECUTOR_SERVICE_ACCOUNT = 'ql3-worker-credential-executor-live';
const NAMESPACE = 'ql3-worker-rollout-live';
const STAGE_NAMESPACE = 'ql3-worker-rollout-stage-live';
const DELIVERY_SERVICE_ACCOUNT = 'ql3-worker-credential-admin';
const TOKEN_ISSUER_USER = 'ql3-worker-credential-operator-live';
const DEPLOYMENT = 'ql3-worker-live';
const TARGET_SECRET = 'ql3-worker-live-credential';
const WORKER_ID = 'ql3-worker-live';
const WORKER_INGRESS_SERVICE = 'ql3-worker-ingress';
const WORKER_IMAGE_BASE = 'ql3-worker-product-live';
const CONTROL_IMAGE_BASE = 'ql3-worker-control-live';
const FIXTURE = 'qinglong/worker-kubernetes-rollout-live-contract@v2';
const LIMITATIONS = Object.freeze([
'single-node K3s local-path PVC is not multi-node CSI detach/attach evidence',
'the product phase proves Session lifecycle but does not execute a Remote Run; the independent Worker PostgreSQL live gate owns Run execution evidence',
'forced Pod deletion is not physical node power loss',
'the live fixture uses deterministic local strong-User principals, not a production external IdP ceremony',
]);
const clusterRequire = createRequire(
path.join(ROOT, 'packages/ql3-cluster-admin/package.json'),
);
function run(binary, args, options = {}) {
if (!options.quiet) {
process.stderr.write(`+ ${path.basename(binary)} ${args.join(' ')}\n`);
}
const result = spawnSync(binary, args, {
cwd: ROOT,
env: options.env ?? process.env,
input: options.input,
encoding: 'utf8',
maxBuffer: 64 * 1024 * 1024,
stdio: options.capture
? ['pipe', 'pipe', 'pipe']
: [options.input === undefined ? 'inherit' : 'pipe', 'inherit', 'inherit'],
});
if (result.error) throw result.error;
if (result.status !== 0 && !options.allowFailure) {
throw new Error(
`${path.basename(binary)} failed with ${String(result.status)}: ` +
`${result.stderr || result.stdout || ''}`,
);
}
return {
status: result.status,
stdout: options.capture ? result.stdout.trim() : '',
stderr: options.capture ? result.stderr.trim() : '',
};
}
function sleep(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function waitFor(description, timeoutMs, inspect) {
const startedAt = Date.now();
let last = 'not observed';
while (Date.now() - startedAt < timeoutMs) {
try {
const value = await inspect();
if (value?.ready) return value.value;
if (value?.fact) last = value.fact;
} catch (error) {
last = error instanceof Error ? error.message : String(error);
}
await sleep(500);
}
throw new Error(`${description} timed out: ${last}`);
}
function sha256(value) {
return createHash('sha256').update(value, 'utf8').digest('hex');
}
function privateReportPath(argv) {
if (
argv.length !== 1 ||
!argv[0].startsWith('--report=') ||
!path.isAbsolute(argv[0].slice('--report='.length))
) {
throw new Error(
'usage: ql3-worker-kubernetes-rollout-live-contract ' +
'--report=/absolute/private-report.json',
);
}
const reportFile = argv[0].slice('--report='.length);
if (fs.existsSync(reportFile)) {
throw new Error('refusing to overwrite the Worker Kubernetes live report');
}
const parent = fs.lstatSync(path.dirname(reportFile));
if (!parent.isDirectory() || parent.isSymbolicLink()) {
throw new Error('Worker Kubernetes live report parent must be a real directory');
}
return reportFile;
}
function writePrivateReport(reportFile, report) {
const temporaryReport = path.join(
path.dirname(reportFile),
`.${path.basename(reportFile)}.${process.pid}.` +
`${crypto.randomBytes(6).toString('hex')}.tmp`,
);
let descriptor;
try {
descriptor = fs.openSync(temporaryReport, 'wx', 0o600);
fs.writeFileSync(descriptor, JSON.stringify(report, null, 2) + '\n');
fs.fsyncSync(descriptor);
fs.closeSync(descriptor);
descriptor = undefined;
fs.linkSync(temporaryReport, reportFile);
} finally {
if (descriptor !== undefined) fs.closeSync(descriptor);
fs.rmSync(temporaryReport, { force: true });
}
}
async function main(argv = process.argv.slice(2)) {
const reportFile = privateReportPath(argv);
if (process.env.QL3_WORKER_KUBERNETES_ROLLOUT_LIVE !== '1') {
throw new Error(
'Refusing to mutate Docker/Kubernetes without ' +
'QL3_WORKER_KUBERNETES_ROLLOUT_LIVE=1',
);
}
const docker = process.env.QL3_DOCKER_BIN || 'docker';
const kubectlBinary = process.env.QL3_KUBECTL_BIN || 'kubectl';
const container = `ql3-worker-rollout-live-${process.pid.toString(36)}`;
const postgresContainer =
`ql3-worker-rollout-postgres-live-${process.pid.toString(36)}`;
const temporary = fs.mkdtempSync(
path.join(os.tmpdir(), 'ql3-worker-rollout-live-'),
);
const kubeconfig = path.join(temporary, 'kubeconfig');
const imageArchive = path.join(temporary, 'actor-image.tar');
const adminImageArchive = path.join(temporary, 'admin-image.tar');
const adminImage = `ql3-worker-credential-executor-live:${process.pid.toString(36)}`;
const workerImageArchive = path.join(temporary, 'worker-image.tar');
const controlImageArchive = path.join(temporary, 'control-image.tar');
const imageSuffix = process.pid.toString(36);
const workerImage = `${WORKER_IMAGE_BASE}:${imageSuffix}`;
const controlImage = `${CONTROL_IMAGE_BASE}:${imageSuffix}`;
let created = false;
let postgresCreated = false;
let adminImageBuilt = false;
let workerImageBuilt = false;
let controlImageBuilt = false;
let migrationDatabase;
let managerDatabase;
let first;
let second;
try {
run(docker, ['version'], { capture: true, quiet: true });
const image = JSON.parse(run(docker, [
'image', 'inspect', K3S_IMAGE,
], { capture: true, quiet: true }).stdout)[0];
assert.ok(image.RepoDigests.includes(`rancher/k3s@${K3S_DIGEST}`));
assert.equal(
run(docker, ['inspect', container], {
capture: true,
quiet: true,
allowFailure: true,
}).status,
1,
'refusing to reuse an existing live-contract container',
);
run(docker, [
'run', '-d', '--privileged', '--name', container,
'-p', '127.0.0.1::6443',
K3S_IMAGE,
'server', '--disable=traefik', '--disable=servicelb',
'--write-kubeconfig-mode=600', '--tls-san=127.0.0.1',
]);
created = true;
await waitFor('K3s API readiness', 120_000, () => {
const result = run(docker, [
'exec', container, 'kubectl', 'get', '--raw=/readyz',
], { capture: true, quiet: true, allowFailure: true });
return result.status === 0 && result.stdout === 'ok'
? { ready: true, value: true }
: { ready: false, fact: result.stderr || result.stdout };
});
const port = run(docker, ['port', container, '6443/tcp'], {
capture: true,
quiet: true,
}).stdout;
assert.match(port, /^127\.0\.0\.1:\d+$/);
const k3sAddress = run(docker, [
'inspect', '--format',
'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}',
container,
], { capture: true, quiet: true }).stdout;
assert.match(k3sAddress, /^\d{1,3}(?:\.\d{1,3}){3}$/);
const config = run(docker, [
'exec', container, 'cat', '/etc/rancher/k3s/k3s.yaml',
], { capture: true, quiet: true }).stdout.replace(
'https://127.0.0.1:6443',
`https://${port}`,
);
fs.writeFileSync(kubeconfig, `${config}\n`, { mode: 0o600, flag: 'wx' });
run(docker, ['image', 'save', '--output', imageArchive, K3S_IMAGE]);
run(docker, ['cp', imageArchive, `${container}:/tmp/ql3-worker-actor.tar`]);
run(docker, [
'exec', container, 'ctr',
'--address', '/run/k3s/containerd/containerd.sock',
'--namespace', 'k8s.io', 'images', 'import',
'/tmp/ql3-worker-actor.tar',
]);
run(docker, [
'exec', container, 'rm', '-f', '/tmp/ql3-worker-actor.tar',
]);
fs.unlinkSync(imageArchive);
const sourceRevision = run('git', ['rev-parse', 'HEAD'], {
capture: true,
quiet: true,
}).stdout;
run(docker, [
'build',
'--file', 'deploy/containers/ql3-cluster-admin/Dockerfile',
'--tag', adminImage,
'--build-arg', `SOURCE_REVISION=${sourceRevision}`,
'.',
]);
adminImageBuilt = true;
run(docker, ['image', 'save', '--output', adminImageArchive, adminImage]);
run(docker, [
'cp', adminImageArchive,
`${container}:/tmp/ql3-worker-credential-executor.tar`,
]);
run(docker, [
'exec', container, 'ctr',
'--address', '/run/k3s/containerd/containerd.sock',
'--namespace', 'k8s.io', 'images', 'import',
'/tmp/ql3-worker-credential-executor.tar',
]);
run(docker, [
'exec', container, 'rm', '-f',
'/tmp/ql3-worker-credential-executor.tar',
]);
fs.unlinkSync(adminImageArchive);
for (const imageBuild of [
{
dockerfile: 'deploy/containers/ql3-worker/Dockerfile',
image: workerImage,
archive: workerImageArchive,
remote: '/tmp/ql3-worker-product.tar',
markBuilt() {
workerImageBuilt = true;
},
},
{
dockerfile: 'deploy/containers/ql3-cluster-control/Dockerfile',
image: controlImage,
archive: controlImageArchive,
remote: '/tmp/ql3-worker-control.tar',
markBuilt() {
controlImageBuilt = true;
},
},
]) {
run(docker, [
'build',
'--file', imageBuild.dockerfile,
'--tag', imageBuild.image,
'--build-arg', `SOURCE_REVISION=${sourceRevision}`,
'.',
]);
imageBuild.markBuilt();
run(docker, [
'image', 'save', '--output', imageBuild.archive, imageBuild.image,
]);
run(docker, ['cp', imageBuild.archive, `${container}:${imageBuild.remote}`]);
run(docker, [
'exec', container, 'ctr',
'--address', '/run/k3s/containerd/containerd.sock',
'--namespace', 'k8s.io', 'images', 'import', imageBuild.remote,
]);
run(docker, ['exec', container, 'rm', '-f', imageBuild.remote]);
fs.unlinkSync(imageBuild.archive);
}
const kubectl = (args, options = {}) => run(
kubectlBinary,
['--kubeconfig', kubeconfig, ...args],
options,
);
const kubectlJson = (args) => JSON.parse(kubectl([...args, '-o', 'json'], {
capture: true,
quiet: true,
}).stdout);
const apply = (body) => kubectl(['apply', '-f', '-'], {
input: `${JSON.stringify(body)}\n`,
quiet: true,
});
const create = (body) => kubectl(['create', '-f', '-'], {
input: `${JSON.stringify(body)}\n`,
quiet: true,
});
apply({ apiVersion: 'v1', kind: 'Namespace', metadata: { name: NAMESPACE } });
apply({
apiVersion: 'v1',
kind: 'Namespace',
metadata: { name: STAGE_NAMESPACE },
});
apply({
apiVersion: 'v1',
kind: 'Namespace',
metadata: { name: EXECUTOR_NAMESPACE },
});
apply({
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: {
name: DELIVERY_SERVICE_ACCOUNT,
namespace: STAGE_NAMESPACE,
},
automountServiceAccountToken: false,
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'Role',
metadata: {
name: 'ql3-worker-credential-stage-admin',
namespace: STAGE_NAMESPACE,
},
rules: [{
apiGroups: [''],
resources: ['secrets'],
verbs: ['get', 'list', 'create', 'delete'],
}],
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
name: 'ql3-worker-credential-stage-admin',
namespace: STAGE_NAMESPACE,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: 'ql3-worker-credential-stage-admin',
},
subjects: [{
kind: 'ServiceAccount',
name: DELIVERY_SERVICE_ACCOUNT,
namespace: STAGE_NAMESPACE,
}],
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'Role',
metadata: {
name: 'ql3-worker-credential-token-issuer',
namespace: STAGE_NAMESPACE,
},
rules: [{
apiGroups: [''],
resources: ['serviceaccounts/token'],
resourceNames: [DELIVERY_SERVICE_ACCOUNT],
verbs: ['create'],
}],
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
name: 'ql3-worker-credential-token-issuer',
namespace: STAGE_NAMESPACE,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: 'ql3-worker-credential-token-issuer',
},
subjects: [{
apiGroup: 'rbac.authorization.k8s.io',
kind: 'User',
name: TOKEN_ISSUER_USER,
}],
});
apply({
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: {
name: EXECUTOR_SERVICE_ACCOUNT,
namespace: EXECUTOR_NAMESPACE,
},
automountServiceAccountToken: false,
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
name: 'ql3-worker-credential-executor-token-issuer-live',
namespace: STAGE_NAMESPACE,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: 'ql3-worker-credential-token-issuer',
},
subjects: [{
kind: 'ServiceAccount',
name: EXECUTOR_SERVICE_ACCOUNT,
namespace: EXECUTOR_NAMESPACE,
}],
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'Role',
metadata: {
name: 'ql3-worker-credential-target-admin',
namespace: NAMESPACE,
},
rules: [
{
apiGroups: [''],
resources: ['secrets'],
resourceNames: [TARGET_SECRET],
verbs: ['get', 'update'],
},
{
apiGroups: ['apps'],
resources: ['deployments'],
resourceNames: [DEPLOYMENT],
verbs: ['get', 'update'],
},
],
});
apply({
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
name: 'ql3-worker-credential-target-admin',
namespace: NAMESPACE,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: 'ql3-worker-credential-target-admin',
},
subjects: [{
kind: 'ServiceAccount',
name: DELIVERY_SERVICE_ACCOUNT,
namespace: STAGE_NAMESPACE,
}],
});
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: { name: 'ql3-worker-live-identity', namespace: NAMESPACE },
type: 'Opaque',
stringData: {
'ca.crt': 'ca-generation-a',
'tls.key': 'key-generation-a',
'tls.crt': 'certificate-generation-a',
},
});
create({
apiVersion: 'v1',
kind: 'Secret',
metadata: {
name: TARGET_SECRET,
namespace: NAMESPACE,
labels: {
'app.kubernetes.io/managed-by': 'qinglong3',
'qinglong.io/worker-credential-target': 'prepared-v3',
},
},
type: 'Opaque',
data: {},
});
apply({
apiVersion: 'v1',
kind: 'PersistentVolumeClaim',
metadata: { name: 'ql3-worker-live-state', namespace: NAMESPACE },
spec: {
accessModes: ['ReadWriteOnce'],
resources: { requests: { storage: '64Mi' } },
},
});
apply({
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: DEPLOYMENT,
namespace: NAMESPACE,
labels: { 'app.kubernetes.io/component': 'worker' },
},
spec: {
replicas: 1,
strategy: { type: 'Recreate' },
selector: { matchLabels: { app: DEPLOYMENT } },
template: {
metadata: {
labels: {
app: DEPLOYMENT,
'app.kubernetes.io/component': 'worker',
},
annotations: {
'qinglong.io/worker-identity-generation': 'identity-a',
},
},
spec: {
automountServiceAccountToken: false,
terminationGracePeriodSeconds: 30,
securityContext: {
runAsNonRoot: true,
runAsUser: 65532,
runAsGroup: 65532,
fsGroup: 65532,
seccompProfile: { type: 'RuntimeDefault' },
},
initContainers: [{
name: 'materialize-worker-authority',
image: K3S_IMAGE,
imagePullPolicy: 'Never',
command: ['/bin/sh', '-ec'],
args: [
'umask 077; mkdir -p /authority/private /state/journal; ' +
'cp /projected/ca.crt /authority/private/ca.crt; ' +
'cp /projected/credential-token /authority/private/credential-token; ' +
'chmod 0400 /authority/private/ca.crt ' +
'/authority/private/credential-token',
],
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
volumeMounts: [
{ name: 'projected-authority', mountPath: '/projected', readOnly: true },
{ name: 'materialized-authority', mountPath: '/authority' },
{ name: 'worker-state', mountPath: '/state' },
],
}],
containers: [{
name: 'worker',
image: K3S_IMAGE,
imagePullPolicy: 'Never',
command: ['/bin/sh', '-ec'],
args: [
'credential_digest="$(sha256sum /authority/private/credential-token | cut -d" " -f1)"; ' +
'ca_digest="$(sha256sum /authority/private/ca.crt | cut -d" " -f1)"; ' +
'printf "start %s %s %s\\n" "$POD_UID" "$credential_digest" "$ca_digest" >> /state/journal/rollout.log; ' +
'sleep 86400',
],
env: [{
name: 'POD_UID',
valueFrom: { fieldRef: { fieldPath: 'metadata.uid' } },
}],
lifecycle: {
preStop: {
exec: {
command: ['/bin/sh', '-ec',
'printf "stop %s\\n" "$POD_UID" >> /state/journal/rollout.log'],
},
},
},
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
volumeMounts: [
{ name: 'materialized-authority', mountPath: '/authority', readOnly: true },
{ name: 'worker-state', mountPath: '/state' },
],
}],
volumes: [
{
name: 'projected-authority',
projected: {
defaultMode: 288,
sources: [
{
secret: {
name: 'ql3-worker-live-identity',
items: [{ key: 'ca.crt', path: 'ca.crt' }],
},
},
{
secret: {
name: TARGET_SECRET,
items: [{ key: 'credential-token', path: 'credential-token' }],
},
},
],
},
},
{ name: 'materialized-authority', emptyDir: { medium: 'Memory' } },
{
name: 'worker-state',
persistentVolumeClaim: { claimName: 'ql3-worker-live-state' },
},
],
},
},
},
});
const k8sEntry = clusterRequire.resolve('@kubernetes/client-node');
const k8s = await import(pathToFileURL(k8sEntry).href);
const kube = new k8s.KubeConfig();
kube.loadFromFile(kubeconfig);
const currentCluster = kube.getCurrentCluster();
const currentUser = kube.getCurrentUser();
assert.ok(currentCluster);
assert.ok(currentUser);
const issuerKube = new k8s.KubeConfig();
issuerKube.loadFromOptions({
clusters: [{ ...currentCluster, name: 'ql3-live-issuer' }],
users: [{
...currentUser,
name: 'ql3-live-issuer',
impersonateUser: TOKEN_ISSUER_USER,
}],
contexts: [{
name: 'ql3-live-issuer',
cluster: 'ql3-live-issuer',
user: 'ql3-live-issuer',
namespace: STAGE_NAMESPACE,
}],
currentContext: 'ql3-live-issuer',
});
const {
createWorkerCredentialKubernetesKubeConfigTokenRequestSession,
} = clusterRequire(
'@qinglong/cluster-admin/worker-credential-kubernetes-token-request',
);
const {
workerCredentialKubernetesDeploymentTargetDigest,
} = clusterRequire(
'@qinglong/cluster-admin/worker-credential-kubernetes-delivery',
);
const {
createClusterWorkerCredentialManagementService,
} = clusterRequire(
'@qinglong/cluster-admin/worker-credential-management',
);
const {
runClusterWorkerCredentialExecution,
} = clusterRequire(
'@qinglong/cluster-admin/worker-credential-management-executor',
);
const {
assertPostgresWorkerCredentialManagerSchemaReady,
createPostgresDatabaseOpener,
} = clusterRequire(
'@qinglong/cluster-postgres/worker-credential-manager',
);
const { runPostgresMigrations } = clusterRequire(
'@qinglong/cluster-postgres/migration',
);
const deliveryOptions = Object.freeze({
clusterIdentity: 'ql3-worker-rollout-live',
namespace: NAMESPACE,
stageNamespace: STAGE_NAMESPACE,
targetSecretName: TARGET_SECRET,
targetDeploymentName: DEPLOYMENT,
targetDataKey: 'credential-token',
});
const deliverySession =
createWorkerCredentialKubernetesKubeConfigTokenRequestSession(
issuerKube,
k8s,
{
serviceAccountName: DELIVERY_SERVICE_ACCOUNT,
identitySecretName: 'ql3-worker-live-identity',
delivery: deliveryOptions,
},
);
assert.equal(
run(docker, ['inspect', postgresContainer], {
capture: true,
quiet: true,
allowFailure: true,
}).status,
1,
'refusing to reuse an existing PostgreSQL live-contract container',
);
const postgresImage = JSON.parse(run(docker, [
'image', 'inspect', POSTGRES_IMAGE,
], { capture: true, quiet: true }).stdout)[0];
assert.ok(postgresImage.RepoDigests.includes(`postgres@${POSTGRES_DIGEST}`));
run(docker, [
'run', '-d', '--name', postgresContainer,
'-p', '127.0.0.1::5432',
'-e', `POSTGRES_DB=${POSTGRES_DATABASE}`,
'-e', 'POSTGRES_USER=postgres',
'-e', `POSTGRES_PASSWORD=${POSTGRES_SUPERUSER_PASSWORD}`,
POSTGRES_IMAGE,
]);
postgresCreated = true;
await waitFor('PostgreSQL readiness', 60_000, () => {
const result = run(docker, [
'exec', postgresContainer, 'pg_isready',
'-h', '127.0.0.1', '-U', 'postgres', '-d', POSTGRES_DATABASE,
], { capture: true, quiet: true, allowFailure: true });
return result.status === 0
? { ready: true, value: true }
: { ready: false, fact: result.stderr || result.stdout };
});
const postgresEndpoint = run(docker, [
'port', postgresContainer, '5432/tcp',
], { capture: true, quiet: true }).stdout;
assert.match(postgresEndpoint, /^127\.0\.0\.1:\d+$/);
const postgresPort = Number(postgresEndpoint.slice(postgresEndpoint.lastIndexOf(':') + 1));
const postgresAddress = run(docker, [
'inspect', '--format',
'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}',
postgresContainer,
], { capture: true, quiet: true }).stdout;
assert.match(postgresAddress, /^\d{1,3}(?:\.\d{1,3}){3}$/);
const databaseUrl = ({ user, password }) =>
`postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}` +
`@127.0.0.1:${postgresPort}/${POSTGRES_DATABASE}`;
const openDatabase = (role, credential, applicationName) =>
createPostgresDatabaseOpener({
role,
connection: {
connectionString: databaseUrl(credential),
tls: { mode: 'disable' },
},
pool: {
applicationName,
maxConnections: role === 'migration' ? 1 : 2,
connectionTimeoutMs: 2_000,
},
onPoolError() {},
});
const superuser = Object.freeze({
user: 'postgres',
password: POSTGRES_SUPERUSER_PASSWORD,
});
const bootstrapDatabase = await openDatabase(
'migration',
superuser,
'ql3-worker-rollout-bootstrap',
)();
try {
for (const credential of Object.values(POSTGRES_ROLES)) {
await bootstrapDatabase.pool.query(
`CREATE ROLE ${credential.user} LOGIN PASSWORD '${credential.password}'`,
);
}
await bootstrapDatabase.pool.query(
`ALTER DATABASE ${POSTGRES_DATABASE} OWNER TO ` +
POSTGRES_ROLES.migration.user,
);
} finally {
await bootstrapDatabase.close();
}
migrationDatabase = await openDatabase(
'migration',
POSTGRES_ROLES.migration,
'ql3-worker-rollout-migration',
)();
await runPostgresMigrations({ pool: migrationDatabase.pool });
const seededAtMs = Date.now();
await migrationDatabase.pool.query(
`INSERT INTO "ql3"."projects" (
id, name, slug, status, version, created_at_ms, updated_at_ms
) VALUES (
'cluster-authority', 'Cluster Authority', 'cluster-authority',
'active', 1, $1, $1
)`,
[seededAtMs],
);
for (const [subjectId, mutationId] of [
['operator-a', 'binding-operator-a-v1'],
['reviewer-b', 'binding-reviewer-b-v1'],
]) {
await migrationDatabase.pool.query(
`INSERT INTO "ql3"."project_role_bindings" (
project_id, subject_type, subject_id, version, state, role,
mutation_id, changed_by_type, changed_by_id, created_at_ms
) VALUES (
'cluster-authority', 'user', $1, 1, 'active', 'admin',
$2, 'user', 'owner-a', $3
)`,
[subjectId, mutationId, seededAtMs],
);
}
managerDatabase = await openDatabase(
'worker-credential-manager',
POSTGRES_ROLES.workerCredentialManager,
'ql3-worker-credential-manager-live',
)();
const managerReadiness =
await assertPostgresWorkerCredentialManagerSchemaReady(
managerDatabase.pool,
);
let managementNowMs = Date.now();
const management = createClusterWorkerCredentialManagementService({
pool: managerDatabase.pool,
now: () => managementNowMs,
});
const deploymentTargetDigest =
workerCredentialKubernetesDeploymentTargetDigest(deliveryOptions);
const openExecutorDatabase = openDatabase(
'worker-credential-executor',
POSTGRES_ROLES.workerCredentialExecutor,
'ql3-worker-credential-executor-live',
);
let tokenRequestEvidence;
let tokenRequestSessions = 0;
let authorizationRechecks = 0;
const approve = async ({
generation,
deliveryId,
credentialId,
previousCredentialId,
auditIds,
}) => {
const plannedAtMs = Date.now();
managementNowMs = plannedAtMs;
const requester = Object.freeze({
subject: Object.freeze({ type: 'user', id: 'operator-a' }),
authenticationId: `session-operator-a-${generation}`,
authenticatedAtMs: plannedAtMs - 100,
expiresAtMs: plannedAtMs + 30 * 60_000,
assurance: 'multi_factor',
});
const reviewer = Object.freeze({
subject: Object.freeze({ type: 'user', id: 'reviewer-b' }),
authenticationId: `session-reviewer-b-${generation}`,
authenticatedAtMs: plannedAtMs - 100,
expiresAtMs: plannedAtMs + 30 * 60_000,
assurance: 'hardware',
});
const actionRef = `worker-credential:ql3-worker-live:${generation}`;
const planned = await management.plan({
actionRef,
authorityProjectId: 'cluster-authority',
action: previousCredentialId === null ? 'issue' : 'rotate',
deliveryId,
workerId: 'ql3-worker-live',
credentialId,
previousCredentialId,
credentialNotBeforeAtMs: plannedAtMs,
credentialExpiresAtMs: plannedAtMs + 60 * 60_000,
deploymentTargetDigest,
deploymentGeneration: generation,
principal: requester,
});
managementNowMs = plannedAtMs + 1;
const proposed = await management.propose({
actionRef,
authorityProjectId: 'cluster-authority',
approvalRequestId: `approval-${generation}`,
approvalAuditEventId: auditIds.proposal,
principal: requester,
});
managementNowMs = plannedAtMs + 2;
const decided = await management.decide({
actionRef,
authorityProjectId: 'cluster-authority',
approvalRequestId: proposed.approvalRequest.id,
expectedVersion: 1,
decisionId: `decision-${generation}`,
auditEventId: auditIds.decision,
decision: 'approved',
reasonCode: 'reviewed',
principal: reviewer,
});
const executionNowMs = plannedAtMs + 3;
assert.equal(planned.status, 'created');
assert.equal(proposed.approvalStatus, 'created');
assert.equal(decided.status, 'decided');
assert.equal(decided.request.state, 'approved');
return Object.freeze({
planned,
proposed,
decided,
executionNowMs,
command: Object.freeze({
schemaVersion: 1,
actionRef,
approvalRequestId: proposed.approvalRequest.id,
consumptionId: `consumption-${generation}`,
dispatchId: `dispatch-${generation}`,
auditEventId: auditIds.consume,
}),
});
};
const approveAndExecute = async (parameters) => {
const approval = await approve(parameters);
const executionOptions = {
openDatabase: openExecutorDatabase,
tokenRequestSession: deliverySession,
workerCredentialPepper: WORKER_CREDENTIAL_PEPPER,
actionRef: approval.command.actionRef,
approvalRequestId: approval.command.approvalRequestId,
consumptionId: approval.command.consumptionId,
dispatchId: approval.command.dispatchId,
auditEventId: approval.command.auditEventId,
confirmAuthorization() {
authorizationRechecks += 1;
},
now: () => approval.executionNowMs,
};
const executed = await runClusterWorkerCredentialExecution(
executionOptions,
);
tokenRequestSessions += 1;
if (tokenRequestEvidence === undefined) {
tokenRequestEvidence = executed.tokenRequest;
} else {
assert.deepEqual(executed.tokenRequest, tokenRequestEvidence);
}
assert.equal(executed.execution.status, 'succeeded');
assert.equal(executed.result.status, 'published');
assert.ok(executed.result.delivery);
assert.equal(
executed.result.delivery.deploymentTargetDigest,
deploymentTargetDigest,
);
const replayed = await runClusterWorkerCredentialExecution(
executionOptions,
);
assert.equal(replayed.result.status, 'existing');
assert.equal(replayed.tokenRequest, null);
assert.deepEqual(replayed.execution, executed.execution);
assert.deepEqual(replayed.result.delivery, executed.result.delivery);
return Object.freeze({
candidate: executed.result.delivery,
publication: Object.freeze({
publicationDigest: executed.result.delivery.publicationDigest,
}),
planDigest: approval.planned.plan.planDigest,
approvalRequestId: approval.proposed.approvalRequest.id,
dispatchId: executed.approval.id,
executorDatabase: executed.database,
});
};
const currentPod = async (excludedUid = null) => waitFor(
'Worker replacement Pod',
120_000,
() => {
const pods = kubectlJson([
'-n', NAMESPACE, 'get', 'pods', '-l', `app=${DEPLOYMENT}`,
]).items.filter((pod) =>
pod.metadata.deletionTimestamp === undefined &&
pod.status.phase === 'Running' &&
pod.metadata.uid !== excludedUid);
return pods.length === 1
? { ready: true, value: pods[0] }
: { ready: false, fact: `${pods.length} running replacement Pods` };
},
);
const journal = (pod) => kubectl([
'-n', NAMESPACE, 'exec', pod.metadata.name, '-c', 'worker', '--',
'cat', '/state/journal/rollout.log',
], { capture: true, quiet: true }).stdout.split('\n').filter(Boolean);
const apiServiceAddress = kubectlJson([
'-n', 'default', 'get', 'service', 'kubernetes',
]).spec.clusterIP;
assert.match(apiServiceAddress, /^\d{1,3}(?:\.\d{1,3}){3}$/);
await waitFor('executor namespace root CA projection', 30_000, () => {
const result = kubectl([
'-n', EXECUTOR_NAMESPACE, 'get', 'configmap', 'kube-root-ca.crt',
], { capture: true, quiet: true, allowFailure: true });
return result.status === 0
? { ready: true, value: true }
: { ready: false, fact: result.stderr || result.stdout };
});
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: {
name: 'ql3-worker-credential-executor-pepper-live',
namespace: EXECUTOR_NAMESPACE,
},
type: 'Opaque',
stringData: {
'worker-credential-pepper': WORKER_CREDENTIAL_PEPPER,
},
});
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: {
name: 'ql3-worker-credential-executor-database-live',
namespace: EXECUTOR_NAMESPACE,
},
type: 'Opaque',
stringData: {
username: POSTGRES_ROLES.workerCredentialExecutor.user,
password: POSTGRES_ROLES.workerCredentialExecutor.password,
},
});
apply({
apiVersion: 'networking.k8s.io/v1',
kind: 'NetworkPolicy',
metadata: {
name: 'ql3-worker-credential-executor-live',
namespace: EXECUTOR_NAMESPACE,
},
spec: {
podSelector: {
matchLabels: {
app: 'ql3-worker-credential-executor-live',
},
},
policyTypes: ['Ingress', 'Egress'],
ingress: [],
egress: [
{
to: [{ ipBlock: { cidr: `${apiServiceAddress}/32` } }],
ports: [{ protocol: 'TCP', port: 443 }],
},
{
to: [{ ipBlock: { cidr: `${k3sAddress}/32` } }],
ports: [{ protocol: 'TCP', port: 6443 }],
},
{
to: [{ ipBlock: { cidr: `${postgresAddress}/32` } }],
ports: [{ protocol: 'TCP', port: 5432 }],
},
],
},
});
const runExecutorJob = async ({ jobName, command, expected }) => {
const commandConfigName = `${jobName}-command`;
create({
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: {
name: commandConfigName,
namespace: EXECUTOR_NAMESPACE,
},
immutable: true,
data: { 'command.json': JSON.stringify(command) },
});
create({
apiVersion: 'batch/v1',
kind: 'Job',
metadata: {
name: jobName,
namespace: EXECUTOR_NAMESPACE,
labels: {
app: 'ql3-worker-credential-executor-live',
'qinglong.io/execution-model': 'caller-driven',
},
},
spec: {
backoffLimit: 0,
activeDeadlineSeconds: 600,
ttlSecondsAfterFinished: 600,
template: {
metadata: {
labels: {
app: 'ql3-worker-credential-executor-live',
'qinglong.io/execution-model': 'caller-driven',
},
},
spec: {
serviceAccountName: EXECUTOR_SERVICE_ACCOUNT,
automountServiceAccountToken: false,
restartPolicy: 'Never',
securityContext: {
runAsNonRoot: true,
runAsUser: 10001,
runAsGroup: 10001,
fsGroup: 10001,
seccompProfile: { type: 'RuntimeDefault' },
},
containers: [{
name: 'executor',
image: adminImage,
imagePullPolicy: 'Never',
command: ['/bin/sh', '-c'],
args: [
'set +e\n' +
'output="$(node ' +
'/opt/qinglong/node_modules/@qinglong/cluster-admin/dist/' +
'worker-credential/workerCredentialExecutorCli.js 2>&1)"\n' +
'status=$?\n' +
'printf \'%s\\n\' "$output" > /dev/termination-log\n' +
'printf \'%s\\n\' "$output"\n' +
'exit "$status"',
],
terminationMessagePolicy: 'File',
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
env: [
{ name: 'QL3_PROFILE', value: 'cluster-admin' },
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_ENABLED',
value: 'true',
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_COMMAND_FILE',
value: '/var/run/qinglong3/command/command.json',
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_PEPPER_FILE',
value: '/var/run/secrets/qinglong3/executor/pepper',
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_CLUSTER_IDENTITY',
value: 'ql3-worker-rollout-live',
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_STAGE_NAMESPACE',
value: STAGE_NAMESPACE,
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_TARGET_NAMESPACE',
value: NAMESPACE,
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_TARGET_SECRET',
value: TARGET_SECRET,
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_TARGET_DEPLOYMENT',
value: DEPLOYMENT,
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_TARGET_DATA_KEY',
value: 'credential-token',
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_DELIVERY_SERVICE_ACCOUNT',
value: DELIVERY_SERVICE_ACCOUNT,
},
{
name: 'QL3_WORKER_CREDENTIAL_EXECUTOR_IDENTITY_SECRET',
value: 'ql3-worker-live-identity',
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_HOST',
value: postgresAddress,
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_PORT',
value: '5432',
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_DATABASE',
value: POSTGRES_DATABASE,
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_USER',
valueFrom: {
secretKeyRef: {
name: 'ql3-worker-credential-executor-database-live',
key: 'username',
},
},
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_PASSWORD',
valueFrom: {
secretKeyRef: {
name: 'ql3-worker-credential-executor-database-live',
key: 'password',
},
},
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_TLS_MODE',
value: 'disable',
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_ALLOW_INSECURE',
value: 'true',
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_APPLICATION_NAME',
value: 'ql3-worker-credential-executor-job-live',
},
{
name: 'QL3_POSTGRES_WORKER_CREDENTIAL_EXECUTOR_MAX_CONNECTIONS',
value: '1',
},
],
resources: {
requests: { cpu: '50m', memory: '64Mi' },
limits: { cpu: '500m', memory: '256Mi' },
},
volumeMounts: [
{ name: 'tmp', mountPath: '/tmp' },
{
name: 'kube-api-access',
mountPath: '/var/run/secrets/kubernetes.io/serviceaccount',
readOnly: true,
},
{
name: 'command',
mountPath: '/var/run/qinglong3/command',
readOnly: true,
},
{
name: 'pepper',
mountPath: '/var/run/secrets/qinglong3/executor',
readOnly: true,
},
],
}],
volumes: [
{ name: 'tmp', emptyDir: { medium: 'Memory', sizeLimit: '8Mi' } },
{
name: 'kube-api-access',
projected: {
defaultMode: 288,
sources: [
{
serviceAccountToken: {
path: 'token',
expirationSeconds: 600,
},
},
{
configMap: {
name: 'kube-root-ca.crt',
items: [{ key: 'ca.crt', path: 'ca.crt' }],
},
},
{
downwardAPI: {
items: [{
path: 'namespace',
fieldRef: {
apiVersion: 'v1',
fieldPath: 'metadata.namespace',
},
}],
},
},
],
},
},
{
name: 'command',
configMap: {
name: commandConfigName,
defaultMode: 292,
items: [{ key: 'command.json', path: 'command.json' }],
},
},
{
name: 'pepper',
secret: {
secretName: 'ql3-worker-credential-executor-pepper-live',
defaultMode: 288,
items: [{
key: 'worker-credential-pepper',
path: 'pepper',
}],
},
},
],
},
},
},
});
const completion = await waitFor(`${jobName} completion`, 120_000, () => {
const job = kubectlJson([
'-n', EXECUTOR_NAMESPACE, 'get', 'job', jobName,
]);
const completed = job.status.conditions?.some(
(condition) => condition.type === 'Complete' && condition.status === 'True',
);
const failed = job.status.conditions?.some(
(condition) => condition.type === 'Failed' && condition.status === 'True',
);
return completed || failed
? { ready: true, value: { job, failed } }
: {
ready: false,
fact: `active=${job.status.active ?? 0} failed=${job.status.failed ?? 0}`,
};
});
const pods = kubectlJson([
'-n', EXECUTOR_NAMESPACE, 'get', 'pods', '-l', `job-name=${jobName}`,
]).items;
assert.equal(pods.length, 1);
const executorPod = pods[0];
const terminated = executorPod.status.containerStatuses?.[0]
?.state?.terminated;
const terminationOutput = terminated?.message ?? '';
if (completion.failed) {
throw new Error(
`${jobName} failed (${terminated?.reason ?? 'unknown'}; ` +
`exit=${terminated?.exitCode ?? 'unknown'}): ` +
`${terminationOutput || 'no termination output'}`,
);
}
assert.equal(terminated?.exitCode, 0);
assert.equal(terminationOutput.includes(WORKER_CREDENTIAL_PEPPER), false);
assert.equal(
terminationOutput.includes(
POSTGRES_ROLES.workerCredentialExecutor.password,
),
false,
);
const output = JSON.parse(
terminationOutput.split('\n').filter(Boolean).at(-1),
);
assert.deepEqual(output, {
schemaVersion: 1,
component: 'qinglong3-worker-credential-executor',
event: 'execution_completed',
actionRef: command.actionRef,
dispatchId: command.dispatchId,
executionStatus: 'succeeded',
deliveryStatus: expected.deliveryStatus,
tokenRequestUsed: expected.tokenRequestUsed,
});
const tokenProjection = executorPod.spec.volumes
.find((volume) => volume.name === 'kube-api-access')
?.projected?.sources?.find((source) => source.serviceAccountToken)
?.serviceAccountToken;
assert.equal(executorPod.spec.serviceAccountName, EXECUTOR_SERVICE_ACCOUNT);
assert.equal(executorPod.spec.automountServiceAccountToken, false);
assert.equal(tokenProjection?.expirationSeconds, 600);
return Object.freeze({
jobName,
podUid: executorPod.metadata.uid,
image: executorPod.spec.containers[0].image,
output: Object.freeze(output),
projectedIssuerTokenSeconds: tokenProjection.expirationSeconds,
});
};
first = await approveAndExecute({
generation: 'generation-live_generation_1',
deliveryId: '323e4567-e89b-42d3-a456-426614174901',
credentialId: 'live_generation_1',
previousCredentialId: null,
auditIds: {
proposal: '423e4567-e89b-42d3-a456-426614174901',
decision: '423e4567-e89b-42d3-a456-426614174902',
consume: '423e4567-e89b-42d3-a456-426614174903',
},
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=120s',
], { capture: true, quiet: true });
const podA = await currentPod();
await waitFor('first PVC journal record', 30_000, () => {
const lines = journal(podA);
return lines.some((line) => line.startsWith(`start ${podA.metadata.uid} `))
? { ready: true, value: lines }
: { ready: false, fact: JSON.stringify(lines) };
});
second = await approveAndExecute({
generation: 'generation-live_generation_2',
deliveryId: '323e4567-e89b-42d3-a456-426614174902',
credentialId: 'live_generation_2',
previousCredentialId: 'live_generation_1',
auditIds: {
proposal: '523e4567-e89b-42d3-a456-426614174901',
decision: '523e4567-e89b-42d3-a456-426614174902',
consume: '523e4567-e89b-42d3-a456-426614174903',
},
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=120s',
], { capture: true, quiet: true });
const podB = await currentPod(podA.metadata.uid);
const afterCredentialRollout = await waitFor(
'credential rollout journal convergence',
30_000,
() => {
const lines = journal(podB);
const stopped = lines.indexOf(`stop ${podA.metadata.uid}`);
const started = lines.findIndex((line) =>
line.startsWith(`start ${podB.metadata.uid} `));
return stopped >= 0 && started > stopped
? { ready: true, value: lines }
: { ready: false, fact: JSON.stringify(lines) };
},
);
kubectl([
'-n', NAMESPACE, 'delete', 'pod', podB.metadata.name,
'--grace-period=0', '--force', '--wait=true',
], { capture: true, quiet: true });
const podAfterCrash = await currentPod(podB.metadata.uid);
const afterCrash = await waitFor('forced Pod replacement PVC recovery', 30_000, () => {
const lines = journal(podAfterCrash);
return lines.some((line) =>
line.startsWith(`start ${podAfterCrash.metadata.uid} `)) &&
lines.some((line) => line.startsWith(`start ${podA.metadata.uid} `))
? { ready: true, value: lines }
: { ready: false, fact: JSON.stringify(lines) };
});
const thirdApproval = await approve({
generation: 'generation-live_generation_3',
deliveryId: '323e4567-e89b-42d3-a456-426614174903',
credentialId: 'live_generation_3',
previousCredentialId: 'live_generation_2',
auditIds: {
proposal: '623e4567-e89b-42d3-a456-426614174901',
decision: '623e4567-e89b-42d3-a456-426614174902',
consume: '623e4567-e89b-42d3-a456-426614174903',
},
});
const executorJob = await runExecutorJob({
jobName: 'ql3-worker-credential-executor-live-3',
command: thirdApproval.command,
expected: { deliveryStatus: 'published', tokenRequestUsed: true },
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=120s',
], { capture: true, quiet: true });
const podAfterExecutorJob = await currentPod(podAfterCrash.metadata.uid);
const afterExecutorJobRollout = await waitFor(
'executor Job credential rollout journal convergence',
30_000,
() => {
const lines = journal(podAfterExecutorJob);
const stopped = lines.indexOf(`stop ${podAfterCrash.metadata.uid}`);
const started = lines.findIndex((line) =>
line.startsWith(`start ${podAfterExecutorJob.metadata.uid} `));
return stopped >= 0 && started > stopped
? { ready: true, value: lines }
: { ready: false, fact: JSON.stringify(lines) };
},
);
const executorReplayJob = await runExecutorJob({
jobName: 'ql3-worker-credential-executor-live-3-replay',
command: thirdApproval.command,
expected: { deliveryStatus: 'existing', tokenRequestUsed: false },
});
const targetAfterExecutorJob = kubectlJson([
'-n', NAMESPACE, 'get', 'secret', TARGET_SECRET,
]);
const deploymentAfterExecutorJob = kubectlJson([
'-n', NAMESPACE, 'get', 'deployment', DEPLOYMENT,
]);
const rolloutAnnotations =
deploymentAfterExecutorJob.spec.template.metadata.annotations;
const executorPublication = Object.freeze({
deliveryId: targetAfterExecutorJob.metadata.annotations[
'qinglong.io/worker-credential-delivery-id'
],
generation: targetAfterExecutorJob.metadata.annotations[
'qinglong.io/worker-credential-generation'
],
credentialId: rolloutAnnotations[
'qinglong.io/worker-credential-id'
],
publicationDigest: rolloutAnnotations[
'qinglong.io/worker-credential-publication-digest'
],
});
assert.equal(
rolloutAnnotations['qinglong.io/worker-credential-delivery-id'],
executorPublication.deliveryId,
);
assert.equal(
rolloutAnnotations['qinglong.io/worker-credential-generation'],
executorPublication.generation,
);
assert.deepEqual(executorPublication, {
deliveryId: '323e4567-e89b-42d3-a456-426614174903',
generation: 'generation-live_generation_3',
credentialId: 'live_generation_3',
publicationDigest: executorPublication.publicationDigest,
});
assert.match(executorPublication.publicationDigest, /^[a-f0-9]{64}$/);
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: { name: 'ql3-worker-live-identity', namespace: NAMESPACE },
type: 'Opaque',
stringData: {
'ca.crt': 'ca-generation-b',
'tls.key': 'key-generation-b',
'tls.crt': 'certificate-generation-b',
},
});
kubectl([
'-n', NAMESPACE, 'patch', 'deployment', DEPLOYMENT, '--type=merge',
'-p', JSON.stringify({
spec: { template: { metadata: { annotations: {
'qinglong.io/worker-identity-generation': 'identity-b',
} } } },
}),
], { capture: true, quiet: true });
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=120s',
], { capture: true, quiet: true });
const podAfterIdentity = await currentPod(podAfterExecutorJob.metadata.uid);
const finalJournal = await waitFor('identity rollout journal convergence', 30_000, () => {
const lines = journal(podAfterIdentity);
const expectedCaDigest = sha256('ca-generation-b');
return lines.some((line) =>
line.startsWith(`start ${podAfterIdentity.metadata.uid} `) &&
line.endsWith(` ${expectedCaDigest}`))
? { ready: true, value: lines }
: { ready: false, fact: JSON.stringify(lines) };
});
// The earlier bounded actor proves Kubernetes publication/PVC mechanics.
// This second phase deliberately replaces it with the production control
// and Worker images so Session reconciliation and drain are observed in
// the same real Deployment/PVC/credential authority.
const pkiDirectory = path.join(temporary, 'product-pki');
fs.mkdirSync(pkiDirectory, { mode: 0o700 });
const ingressServername =
`${WORKER_INGRESS_SERVICE}.${NAMESPACE}.svc`;
const pki = createMutualTlsPki({
directory: pkiDirectory,
servername: ingressServername,
label: 'QingLong Worker product live',
run,
crypto,
});
const pkiMaterial = pki.read();
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: { name: 'ql3-worker-ingress-tls-live', namespace: NAMESPACE },
type: 'Opaque',
stringData: {
'tls.key': pkiMaterial.serverKey,
'tls.crt': pkiMaterial.serverCertificate,
'client-ca.crt': pkiMaterial.ca,
},
});
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: { name: 'ql3-worker-live-identity', namespace: NAMESPACE },
type: 'Opaque',
stringData: {
'ca.crt': pkiMaterial.ca,
'tls.key': pkiMaterial.oldClientKey,
'tls.crt': pkiMaterial.oldClientCertificate,
},
});
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: {
name: 'ql3-worker-control-live-runtime',
namespace: NAMESPACE,
},
type: 'Opaque',
stringData: {
'api-credential-pepper-keyring.json': `${JSON.stringify({
schemaVersion: 1,
activePepperKeyId: 'legacy-v1',
keys: [{
pepperKeyId: 'legacy-v1',
pepper: Buffer.alloc(32, 29).toString('base64url'),
}],
})}\n`,
},
});
const workerArchitecture = remoteWorkerArchitectureForNodeRuntime(
process.arch, process.config.variables.arm_version,
);
apply({
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: { name: 'ql3-worker-product-config-live', namespace: NAMESPACE },
data: {
'worker-id': WORKER_ID,
'control-origin': `https://${ingressServername}:5801`,
'capabilities.json': `${JSON.stringify({
architecture: workerArchitecture,
operatingSystem: 'linux',
executors: ['remote-worker'],
protocolVersion: '1.0.0',
supportTier:
remoteWorkerSupportTierForArchitecture(workerArchitecture),
runtimes: [{ name: 'node', version: '24.18.0' }],
labels: { contract: 'kubernetes-product-live' },
capacity: { cpuCores: 1, memoryBytes: 256 * 1024 * 1024 },
features: [],
})}\n`,
},
});
apply({
apiVersion: 'v1',
kind: 'Service',
metadata: { name: WORKER_INGRESS_SERVICE, namespace: NAMESPACE },
spec: {
selector: { app: 'ql3-worker-control-live' },
ports: [
{ name: 'http', port: 5800, targetPort: 5800 },
{ name: 'worker-mtls', port: 5801, targetPort: 5801 },
],
},
});
const runtimeDatabaseUrl =
`postgresql://${POSTGRES_ROLES.runtime.user}:` +
`${POSTGRES_ROLES.runtime.password}@${postgresAddress}:5432/` +
POSTGRES_DATABASE;
const ingressDatabaseUrl =
`postgresql://${POSTGRES_ROLES.workerIngress.user}:` +
`${POSTGRES_ROLES.workerIngress.password}@${postgresAddress}:5432/` +
POSTGRES_DATABASE;
apply({
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: { name: 'ql3-worker-control-live', namespace: NAMESPACE },
spec: {
replicas: 1,
selector: { matchLabels: { app: 'ql3-worker-control-live' } },
template: {
metadata: { labels: { app: 'ql3-worker-control-live' } },
spec: {
automountServiceAccountToken: false,
securityContext: {
runAsNonRoot: true,
runAsUser: 65532,
runAsGroup: 65532,
fsGroup: 65532,
fsGroupChangePolicy: 'OnRootMismatch',
seccompProfile: { type: 'RuntimeDefault' },
},
containers: [{
name: 'control',
image: controlImage,
imagePullPolicy: 'Never',
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
env: [
{ name: 'QL_DEPLOYMENT_PROFILE', value: 'cluster-control' },
{ name: 'QL3_CLUSTER_CONTROL_ENABLED', value: 'true' },
{ name: 'QL3_CLUSTER_REPLICA_ID', value: 'worker-product-live-control' },
{ name: 'QL3_CLUSTER_HTTP_HOST', value: '0.0.0.0' },
{ name: 'QL3_CLUSTER_HTTP_PORT', value: '5800' },
{ name: 'QL3_POSTGRES_RUNTIME_URL', value: runtimeDatabaseUrl },
{ name: 'QL3_POSTGRES_TLS_MODE', value: 'disable' },
{ name: 'QL3_POSTGRES_ALLOW_INSECURE', value: 'true' },
{ name: 'QL3_POSTGRES_MAX_CONNECTIONS', value: '2' },
{
name: 'QL3_API_CREDENTIAL_PEPPER_KEYRING_FILE',
value: '/var/run/secrets/qinglong3/api-credential/keyring.json',
},
{ name: 'QL3_WORKER_INGRESS_ENABLED', value: 'true' },
{ name: 'QL3_WORKER_INGRESS_HOST', value: '0.0.0.0' },
{ name: 'QL3_WORKER_INGRESS_PORT', value: '5801' },
{ name: 'QL3_POSTGRES_WORKER_INGRESS_URL', value: ingressDatabaseUrl },
{ name: 'QL3_WORKER_INGRESS_POSTGRES_TLS_MODE', value: 'disable' },
{ name: 'QL3_WORKER_INGRESS_POSTGRES_ALLOW_INSECURE', value: 'true' },
{ name: 'QL3_WORKER_INGRESS_POSTGRES_MAX_CONNECTIONS', value: '2' },
{ name: 'QL3_WORKER_CREDENTIAL_PEPPER', value: WORKER_CREDENTIAL_PEPPER },
{ name: 'QL3_WORKER_ARTIFACT_S3_BUCKET', value: 'ql3-worker-product-live' },
{ name: 'QL3_WORKER_ARTIFACT_S3_REGION', value: 'us-east-1' },
{ name: 'AWS_ACCESS_KEY_ID', value: 'ql3-live-access' },
{ name: 'AWS_SECRET_ACCESS_KEY', value: 'ql3-live-secret' },
{
name: 'QL3_WORKER_INGRESS_TLS_PRIVATE_KEY_FILE',
value: '/tls/tls.key',
},
{
name: 'QL3_WORKER_INGRESS_TLS_CERTIFICATE_FILE',
value: '/tls/tls.crt',
},
{
name: 'QL3_WORKER_INGRESS_TLS_CLIENT_CA_FILE',
value: '/tls/client-ca.crt',
},
],
ports: [
{ name: 'http', containerPort: 5800 },
{ name: 'worker-mtls', containerPort: 5801 },
],
readinessProbe: {
httpGet: { path: '/readyz', port: 'http' },
periodSeconds: 2,
timeoutSeconds: 1,
failureThreshold: 20,
},
volumeMounts: [
{ name: 'tls', mountPath: '/tls', readOnly: true },
{
name: 'api-credential-keyring',
mountPath: '/var/run/secrets/qinglong3/api-credential',
readOnly: true,
},
],
}],
volumes: [
{
name: 'tls',
secret: {
secretName: 'ql3-worker-ingress-tls-live',
defaultMode: 288,
},
},
{
name: 'api-credential-keyring',
secret: {
secretName: 'ql3-worker-control-live-runtime',
defaultMode: 288,
items: [{
key: 'api-credential-pepper-keyring.json',
path: 'keyring.json',
}],
},
},
],
},
},
},
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status',
'deployment/ql3-worker-control-live', '--timeout=180s',
], { capture: true, quiet: true });
await migrationDatabase.pool.query(`
CREATE TABLE public.ql3_worker_session_live_observations (
observation_id bigserial PRIMARY KEY,
session_id varchar(36) NOT NULL,
generation integer NOT NULL,
status varchar(16) NOT NULL,
version integer NOT NULL,
observed_at timestamptz NOT NULL DEFAULT clock_timestamp()
);
CREATE FUNCTION public.ql3_capture_worker_session_live_observation()
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER
SET search_path = pg_catalog, public AS $capture$
BEGIN
IF NEW.worker_id = '${WORKER_ID}' THEN
INSERT INTO public.ql3_worker_session_live_observations (
session_id, generation, status, version
) VALUES (NEW.session_id, NEW.generation, NEW.status, NEW.version);
END IF;
RETURN NEW;
END;
$capture$;
CREATE TRIGGER ql3_capture_worker_session_live_observation
AFTER INSERT OR UPDATE ON "ql3"."worker_sessions"
FOR EACH ROW EXECUTE FUNCTION
public.ql3_capture_worker_session_live_observation();
`);
const session = async () => (await migrationDatabase.pool.query(
`SELECT session_id AS "sessionId", generation, status, version,
max_concurrent_runs AS "maxConcurrentRuns"
FROM "ql3"."worker_sessions" WHERE worker_id = $1`,
[WORKER_ID],
)).rows[0] ?? null;
const observations = async () => (await migrationDatabase.pool.query(
`SELECT session_id AS "sessionId", generation, status, version
FROM public.ql3_worker_session_live_observations
ORDER BY observation_id`,
)).rows;
const heartbeatAuditCount = async () => Number((
await migrationDatabase.pool.query(
`SELECT count(*)::integer AS count
FROM "ql3"."security_audit_events"
WHERE subject_type = 'worker' AND subject_id = $1
AND operation_id = 'worker.heartbeat'`,
[WORKER_ID],
)
).rows[0].count);
const waitForOnlineSession = async (excludedSessionId = null) =>
(await waitFor('production Worker online Session', 180_000, async () => {
const current = await session();
return current?.status === 'online' &&
current.sessionId !== excludedSessionId
? { ready: true, value: current }
: { ready: false, fact: JSON.stringify(current) };
}));
const waitForHeartbeatAudit = async (minimumCount) =>
waitFor('production Worker heartbeat audit', 30_000, async () => {
const current = await heartbeatAuditCount();
return current >= minimumCount
? { ready: true, value: current }
: { ready: false, fact: String(current) };
});
const productEvents = (pod) => {
const containerId = pod.status.containerStatuses
?.find((status) => status.name === 'worker')
?.containerID?.replace(/^containerd:\/\//, '');
assert.match(containerId ?? '', /^[a-f0-9]{64}$/);
return run(docker, [
'exec', container, 'crictl', 'logs', containerId,
], { capture: true, quiet: true }).stdout.split('\n').filter(Boolean)
.map((line) => JSON.parse(line));
};
const productAnnotations = {
...kubectlJson([
'-n', NAMESPACE, 'get', 'deployment', DEPLOYMENT,
]).spec.template.metadata.annotations,
'qinglong.io/worker-identity-generation': 'product-identity-a',
};
apply({
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: DEPLOYMENT,
namespace: NAMESPACE,
labels: { 'app.kubernetes.io/component': 'worker' },
},
spec: {
replicas: 1,
minReadySeconds: 0,
strategy: { type: 'Recreate' },
selector: { matchLabels: { app: DEPLOYMENT } },
template: {
metadata: {
labels: { app: DEPLOYMENT, 'app.kubernetes.io/component': 'worker' },
annotations: productAnnotations,
},
spec: {
automountServiceAccountToken: false,
terminationGracePeriodSeconds: 360,
securityContext: {
runAsNonRoot: true,
runAsUser: 65532,
runAsGroup: 65532,
fsGroup: 65532,
fsGroupChangePolicy: 'OnRootMismatch',
seccompProfile: { type: 'RuntimeDefault' },
},
initContainers: [{
name: 'materialize-worker-authority',
image: workerImage,
imagePullPolicy: 'Never',
command: ['/bin/sh', '-ec'],
args: [
'umask 077; mkdir -p /authority/private /state/journal ' +
'/state/logs /state/receipts /state/identity; ' +
'chmod 0700 /authority/private /state/journal /state/logs ' +
'/state/receipts /state/identity; ' +
'cp /projected/ca.crt /authority/private/ca.crt; ' +
'cp /projected/tls.key /authority/private/tls.key; ' +
'cp /projected/tls.crt /authority/private/tls.crt; ' +
'cp /projected/credential-token /authority/private/credential-token; ' +
'cp /projected/capabilities.json /authority/private/capabilities.json; ' +
'chmod 0400 /authority/private/*',
],
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
volumeMounts: [
{ name: 'projected-authority', mountPath: '/projected', readOnly: true },
{ name: 'materialized-authority', mountPath: '/authority' },
{ name: 'worker-state', mountPath: '/state' },
],
}],
containers: [{
name: 'worker',
image: workerImage,
imagePullPolicy: 'Never',
securityContext: {
allowPrivilegeEscalation: false,
readOnlyRootFilesystem: true,
capabilities: { drop: ['ALL'] },
},
env: [
{ name: 'QL_DEPLOYMENT_PROFILE', value: 'worker' },
{ name: 'QL3_WORKER_RUNTIME_ENABLED', value: 'true' },
{ name: 'QL3_WORKER_ID', value: WORKER_ID },
{
name: 'QL3_WORKER_CONTROL_ORIGIN',
value: `https://${ingressServername}:5801`,
},
{ name: 'QL3_WORKER_CAPACITY_PROFILE', value: 'edge' },
{ name: 'QL3_WORKER_CAPABILITIES_FILE', value: '/authority/private/capabilities.json' },
{ name: 'QL3_WORKER_JOURNAL_ROOT', value: '/state/journal' },
{ name: 'QL3_WORKER_LOG_ROOT', value: '/state/logs' },
{ name: 'QL3_WORKER_RECEIPT_ROOT', value: '/state/receipts' },
{ name: 'QL3_WORKER_CERTIFICATE_STORE_ROOT', value: '/state/identity' },
{ name: 'QL3_WORKER_TRUST_ANCHOR_FILE', value: '/authority/private/ca.crt' },
{ name: 'QL3_WORKER_CREDENTIAL_TOKEN_FILE', value: '/authority/private/credential-token' },
{ name: 'QL3_WORKER_IDENTITY_BOOTSTRAP_PRIVATE_KEY_FILE', value: '/authority/private/tls.key' },
{ name: 'QL3_WORKER_IDENTITY_BOOTSTRAP_CERTIFICATE_FILE', value: '/authority/private/tls.crt' },
{ name: 'QL3_WORKER_CADENCE_MS', value: '100' },
{ name: 'QL3_WORKER_HEARTBEAT_INTERVAL_MS', value: '5000' },
{ name: 'QL3_WORKER_SESSION_LEASE_DURATION_MS', value: '15000' },
{ name: 'QL3_WORKER_DRAIN_TIMEOUT_MS', value: '5000' },
{ name: 'QL3_WORKER_DRAIN_POLL_MS', value: '25' },
],
volumeMounts: [
{ name: 'materialized-authority', mountPath: '/authority', readOnly: true },
{ name: 'worker-state', mountPath: '/state' },
{ name: 'tmp', mountPath: '/tmp' },
],
}],
volumes: [
{
name: 'projected-authority',
projected: {
defaultMode: 288,
sources: [
{
secret: {
name: 'ql3-worker-live-identity',
items: [
{ key: 'ca.crt', path: 'ca.crt' },
{ key: 'tls.key', path: 'tls.key' },
{ key: 'tls.crt', path: 'tls.crt' },
],
},
},
{
secret: {
name: TARGET_SECRET,
items: [{ key: 'credential-token', path: 'credential-token' }],
},
},
{
configMap: {
name: 'ql3-worker-product-config-live',
items: [{ key: 'capabilities.json', path: 'capabilities.json' }],
},
},
],
},
},
{ name: 'materialized-authority', emptyDir: { medium: 'Memory', sizeLimit: '4Mi' } },
{ name: 'worker-state', persistentVolumeClaim: { claimName: 'ql3-worker-live-state' } },
{ name: 'tmp', emptyDir: { medium: 'Memory', sizeLimit: '16Mi' } },
],
},
},
},
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=240s',
], { capture: true, quiet: true });
const productPodA = await currentPod(podAfterIdentity.metadata.uid);
const productSessionA = await waitForOnlineSession();
await waitForHeartbeatAudit(1);
const productEventsA = productEvents(productPodA);
assert.equal(productEventsA.some((event) => event.event === 'active'), true);
const fourth = await approveAndExecute({
generation: 'generation-live_generation_4',
deliveryId: '323e4567-e89b-42d3-a456-426614174904',
credentialId: 'live_generation_4',
previousCredentialId: 'live_generation_3',
auditIds: {
proposal: '723e4567-e89b-42d3-a456-426614174901',
decision: '723e4567-e89b-42d3-a456-426614174902',
consume: '723e4567-e89b-42d3-a456-426614174903',
},
});
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=240s',
], { capture: true, quiet: true });
const productPodB = await currentPod(productPodA.metadata.uid);
const productSessionB = await waitForOnlineSession(productSessionA.sessionId);
await waitForHeartbeatAudit(2);
const productEventsB = productEvents(productPodB);
assert.equal(productEventsB.some((event) => event.event === 'active'), true);
apply({
apiVersion: 'v1',
kind: 'Secret',
metadata: { name: 'ql3-worker-live-identity', namespace: NAMESPACE },
type: 'Opaque',
stringData: {
'ca.crt': pkiMaterial.ca,
'tls.key': pkiMaterial.newClientKey,
'tls.crt': pkiMaterial.newClientCertificate,
},
});
kubectl([
'-n', NAMESPACE, 'patch', 'deployment', DEPLOYMENT, '--type=merge',
'-p', JSON.stringify({ spec: { template: { metadata: { annotations: {
'qinglong.io/worker-identity-generation': 'product-identity-b',
} } } } }),
], { capture: true, quiet: true });
kubectl([
'-n', NAMESPACE, 'rollout', 'status', `deployment/${DEPLOYMENT}`,
'--timeout=240s',
], { capture: true, quiet: true });
const productPodC = await currentPod(productPodB.metadata.uid);
const productSessionC = await waitForOnlineSession(productSessionB.sessionId);
await waitForHeartbeatAudit(3);
const productEventsC = productEvents(productPodC);
assert.equal(productEventsC.some((event) => event.event === 'active'), true);
const finalDrainStartedAt = Date.now();
kubectl([
'-n', NAMESPACE, 'scale', `deployment/${DEPLOYMENT}`, '--replicas=0',
], { capture: true, quiet: true });
const finalOffline = await waitFor(
'production Worker final offline Session',
30_000,
async () => {
const current = await session();
return current?.sessionId === productSessionC.sessionId &&
current.status === 'offline'
? { ready: true, value: current }
: { ready: false, fact: JSON.stringify(current) };
},
);
const productObservations = await observations();
for (const productSession of [
productSessionA,
productSessionB,
productSessionC,
]) {
const states = productObservations
.filter((entry) => entry.sessionId === productSession.sessionId)
.map((entry) => entry.status);
assert.equal(states.includes('online'), true);
assert.equal(states.includes('draining'), true);
assert.equal(states.includes('offline'), true);
}
assert.equal(productSessionA.generation < productSessionB.generation, true);
assert.equal(productSessionB.generation < productSessionC.generation, true);
assert.equal(finalOffline.status, 'offline');
const productDurability = (await migrationDatabase.pool.query(
`SELECT
count(*) FILTER (WHERE operation_id = 'worker.register')::integer
AS "registerAudits",
count(*) FILTER (WHERE operation_id = 'worker.transition')::integer
AS "transitionAudits",
count(*) FILTER (WHERE operation_id = 'worker.heartbeat')::integer
AS "heartbeatAudits",
NOT EXISTS (
SELECT 1 FROM "ql3"."worker_credentials"
WHERE to_jsonb(worker_credentials)::text LIKE '%ql3w_%'
) AS "credentialSecretsAbsent"
FROM "ql3"."security_audit_events"
WHERE subject_type = 'worker' AND subject_id = $1`,
[WORKER_ID],
)).rows[0];
assert.equal(productDurability.registerAudits >= 3, true);
assert.equal(productDurability.transitionAudits >= 6, true);
assert.equal(productDurability.heartbeatAudits >= 3, true);
assert.equal(productDurability.credentialSecretsAbsent, true);
const productionWorkerEvidence = Object.freeze({
workerImageId: JSON.parse(run(docker, [
'image', 'inspect', workerImage,
], { capture: true, quiet: true }).stdout)[0].Id,
controlImageId: JSON.parse(run(docker, [
'image', 'inspect', controlImage,
], { capture: true, quiet: true }).stdout)[0].Id,
podUids: [
productPodA.metadata.uid,
productPodB.metadata.uid,
productPodC.metadata.uid,
],
nodeNames: [
productPodA.spec.nodeName,
productPodB.spec.nodeName,
productPodC.spec.nodeName,
],
sessionIds: [
productSessionA.sessionId,
productSessionB.sessionId,
productSessionC.sessionId,
],
generations: [
productSessionA.generation,
productSessionB.generation,
productSessionC.generation,
],
observationCount: productObservations.length,
gracefulDrainElapsedMs: Date.now() - finalDrainStartedAt,
terminationGracePeriodSeconds: 360,
startupReconciliationBeforeOnline: true,
everySessionObservedOnlineDrainingOffline: true,
credentialRolloutCreatedFreshSession: true,
identityRolloutCreatedFreshSession: true,
pvcReusedAcrossProductSessions: true,
serviceAccountTokenMounted: false,
...productDurability,
fourthCredentialId: fourth.candidate.credentialId,
});
const finalDeployment = kubectlJson([
'-n', NAMESPACE, 'get', 'deployment', DEPLOYMENT,
]);
const finalPvc = kubectlJson([
'-n', NAMESPACE, 'get', 'pvc', 'ql3-worker-live-state',
]);
const finalTarget = kubectlJson([
'-n', NAMESPACE, 'get', 'secret', TARGET_SECRET,
]);
assert.equal(
finalTarget.metadata.labels['qinglong.io/worker-credential-target'],
'v3',
);
assert.equal(
productPodC.spec.volumes?.some((volume) =>
volume.projected?.sources?.some((source) =>
source.serviceAccountToken !== undefined)),
false,
);
const approvalExecutionFacts = (await migrationDatabase.pool.query(
`SELECT
(SELECT count(*)::integer
FROM "ql3"."worker_credential_management_plans") AS "plans",
(SELECT count(*)::integer
FROM "ql3"."approval_requests"
WHERE state = 'consumed' AND version = 3) AS "consumedApprovals",
(SELECT count(*)::integer
FROM "ql3"."approved_action_dispatches") AS "dispatches",
(SELECT count(*)::integer
FROM "ql3"."approved_action_executions"
WHERE status = 'succeeded') AS "succeededExecutions",
(SELECT count(*)::integer
FROM "ql3"."worker_credentials") AS "credentials",
(SELECT count(*)::integer
FROM "ql3"."worker_credential_deliveries"
WHERE state = 'published' AND version = 2) AS "publishedDeliveries",
(SELECT count(*)::integer
FROM "ql3"."security_audit_events"
WHERE operation_id IN (
'approval.request', 'approval.decide', 'approval.consume',
'worker_credential.issue'
)) AS "auditEvents"`,
)).rows[0];
assert.deepEqual(approvalExecutionFacts, {
plans: 4,
consumedApprovals: 4,
dispatches: 4,
succeededExecutions: 4,
credentials: 4,
publishedDeliveries: 4,
auditEvents: 16,
});
assert.equal(authorizationRechecks, 9);
assert.equal(managerReadiness.currentUser, 'ql3_worker_credential_manager');
assert.equal(
first.executorDatabase.currentUser,
'ql3_worker_credential_executor',
);
assert.equal(
second.executorDatabase.currentUser,
'ql3_worker_credential_executor',
);
const report = {
schemaVersion: 1,
fixture: FIXTURE,
observedAt: new Date().toISOString(),
sourceRevision,
kubernetes: {
distribution: 'k3s',
image: K3S_IMAGE,
imageDigest: K3S_DIGEST,
architecture: image.Architecture,
serverVersion: kubectlJson(['version']).serverVersion.gitVersion,
},
postgresql: {
image: POSTGRES_IMAGE,
imageDigest: POSTGRES_DIGEST,
imageId: postgresImage.Id,
architecture: postgresImage.Architecture,
contractVersion: managerReadiness.contractVersion,
migrationId: managerReadiness.migrationIds.at(-1),
managerRole: managerReadiness.currentUser,
executorRole: first.executorDatabase.currentUser,
},
approvalExecution: {
...approvalExecutionFacts,
planDigests: [
first.planDigest,
second.planDigest,
thirdApproval.planned.plan.planDigest,
fourth.planDigest,
],
approvalRequestIds: [
first.approvalRequestId,
second.approvalRequestId,
thirdApproval.proposed.approvalRequest.id,
fourth.approvalRequestId,
],
dispatchIds: [
first.dispatchId,
second.dispatchId,
thirdApproval.command.dispatchId,
fourth.dispatchId,
],
hostAuthorizationRechecks: authorizationRechecks,
tokenRequestAfterApprovalConsumption: true,
executionReplayWithoutTokenRequest: true,
tokenOrSecretPersistedInPlan: false,
},
credentialRollout: {
secretSeparatedFromTlsIdentity: true,
generations: [
first.candidate.deploymentGeneration,
second.candidate.deploymentGeneration,
executorPublication.generation,
fourth.candidate.deploymentGeneration,
],
publicationDigests: [
first.publication.publicationDigest,
second.publication.publicationDigest,
executorPublication.publicationDigest,
fourth.publication.publicationDigest,
],
recreateStoppedOldBeforeStartingNew:
afterCredentialRollout.indexOf(`stop ${podA.metadata.uid}`) <
afterCredentialRollout.findIndex((line) =>
line.startsWith(`start ${podB.metadata.uid} `)),
executorJobStoppedOldBeforeStartingNew:
afterExecutorJobRollout.indexOf(`stop ${podAfterCrash.metadata.uid}`) <
afterExecutorJobRollout.findIndex((line) =>
line.startsWith(`start ${podAfterExecutorJob.metadata.uid} `)),
},
callerDrivenExecutorJob: {
image: executorJob.image,
firstJobName: executorJob.jobName,
firstPodUid: executorJob.podUid,
firstOutput: executorJob.output,
replayJobName: executorReplayJob.jobName,
replayPodUid: executorReplayJob.podUid,
replayOutput: executorReplayJob.output,
backoffLimit: 0,
projectedIssuerTokenSeconds:
executorJob.projectedIssuerTokenSeconds,
apiServerEgressCidr: `${apiServiceAddress}/32`,
apiServerBackendEgressCidr: `${k3sAddress}/32`,
apiServerBackendPort: 6443,
postgresEgressCidr: `${postgresAddress}/32`,
},
rbac: {
tokenIssuerImpersonatedUser: TOKEN_ISSUER_USER,
tokenIssuerExactServiceAccountBound: true,
hostTokenRequestSessions: tokenRequestSessions,
executorJobTokenRequestSessions: 1,
shortLivedTokenRequestSeconds:
tokenRequestEvidence.tokenLifetimeSeconds,
issuerAllowedChecks: tokenRequestEvidence.issuerAllowedChecks,
issuerDeniedChecks: tokenRequestEvidence.issuerDeniedChecks,
serviceAccountAutomount: false,
workerPodServiceAccountTokenProjected: false,
separateStageNamespace: STAGE_NAMESPACE !== NAMESPACE,
allowedChecks: tokenRequestEvidence.allowedChecks,
deniedChecks: tokenRequestEvidence.deniedChecks,
tokenNeverReturnedBySession: true,
restrictedClientDisposedAfterEachOperation: true,
adapterUsedRestrictedToken: true,
},
recovery: {
pvcPhase: finalPvc.status.phase,
sameClaimAfterCredentialRollout: true,
sameClaimAfterForcedPodLoss: afterCrash.length >= 3,
oldPodUid: podA.metadata.uid,
rotatedPodUid: podB.metadata.uid,
crashReplacementPodUid: podAfterCrash.metadata.uid,
executorJobReplacementPodUid: podAfterExecutorJob.metadata.uid,
identityReplacementPodUid: podAfterIdentity.metadata.uid,
durableJournalRecords: finalJournal.length,
},
identityRollout: {
generation:
finalDeployment.spec.template.metadata.annotations[
'qinglong.io/worker-identity-generation'
],
caDigest: sha256(pkiMaterial.ca),
observedByReplacement: true,
},
productionWorker: productionWorkerEvidence,
gates: {
realKubernetesApi: true,
secretAndDeploymentResourceVersionCas: true,
recreateOrderingObserved: true,
pvcJournalSurvivedRolloutAndForcedPodLoss: true,
explicitIdentityGenerationRolloutObserved: true,
strongUserPlanApprovalAndDispatchPersisted: true,
managerExecutorDatabaseRolesSeparated: true,
approvalConsumedBeforeTokenRequest: true,
leastPrivilegeTokenIssuerRbac: true,
tokenRequestSessionDisposed: true,
restrictedCredentialDeliveryRbac: true,
realCallerDrivenExecutorJob: true,
executorJobExactReplayWithoutTokenRequest: true,
executorJobUsesProjectedShortLivedIssuerToken: true,
executorJobExactNetworkEgress: true,
productionWorkerImageInKubernetes: true,
productionWorkerIngressComposition: true,
productionSessionReplacement: true,
productionStartupReconciliation: true,
productionGracefulDrainToOffline: true,
passed: true,
},
limitations: [...LIMITATIONS],
};
const audit = validateWorkerKubernetesRolloutLiveReport(report);
assert.deepEqual(audit.findings, []);
writePrivateReport(reportFile, report);
process.stdout.write(
JSON.stringify({
schemaVersion: 1,
fixture: FIXTURE,
reportWritten: true,
passed: true,
}) + '\n',
);
} finally {
first = undefined;
second = undefined;
if (managerDatabase) {
await managerDatabase.close().catch(() => undefined);
}
if (migrationDatabase) {
await migrationDatabase.close().catch(() => undefined);
}
if (postgresCreated) {
run(docker, ['rm', '-f', '-v', postgresContainer], {
capture: true,
quiet: true,
allowFailure: true,
});
}
if (created) {
run(docker, ['rm', '-f', '-v', container], {
capture: true,
quiet: true,
allowFailure: true,
});
}
if (adminImageBuilt) {
run(docker, ['image', 'rm', '-f', adminImage], {
capture: true,
quiet: true,
allowFailure: true,
});
}
if (workerImageBuilt) {
run(docker, ['image', 'rm', '-f', workerImage], {
capture: true,
quiet: true,
allowFailure: true,
});
}
if (controlImageBuilt) {
run(docker, ['image', 'rm', '-f', controlImage], {
capture: true,
quiet: true,
allowFailure: true,
});
}
fs.rmSync(temporary, { recursive: true, force: true });
}
}
if (require.main === module) {
main().catch((error) => {
process.stderr.write(
`ql3 Worker Kubernetes rollout live contract failed: ${error.stack || error}\n`,
);
process.exitCode = 1;
});
}
module.exports = { writePrivateReport };