mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 18:08:20 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const SELECTION_DIRECTORY =
|
||||
'deploy/kubernetes/ql3-cluster/operators/cert-manager';
|
||||
const BARMAN_LOCK =
|
||||
'deploy/kubernetes/ql3-cluster/operators/barman-cloud/plugin-lock.json';
|
||||
const RELEASE_BLOCKERS = Object.freeze([
|
||||
'live-cert-manager-api-and-plugin-mtls-rotation-evidence',
|
||||
]);
|
||||
const RELEASE_MANIFEST_SHA256 =
|
||||
'7ee74ba06845213e96d8ceaff3d20dd51e682765c1418eddda4e8780ba082261';
|
||||
const IMAGES = Object.freeze([
|
||||
Object.freeze({
|
||||
name: 'controller',
|
||||
manifestReference: 'quay.io/jetstack/cert-manager-controller:v1.20.3',
|
||||
image:
|
||||
'quay.io/jetstack/cert-manager-controller:v1.20.3@sha256:6c13d61e0348a5bc3477f8ea9a928624300b30d19b1c72a7d2b90372fc713db4',
|
||||
platforms: Object.freeze({
|
||||
'linux/amd64':
|
||||
'sha256:1e4af57beb469cc3bb0fb48b9201caea2723819b9ffd3c3ea98568f55b4dd38b',
|
||||
'linux/arm64':
|
||||
'sha256:af62a025ae4f8fd03209b5e0760868296bad5a9370aab0c91ad3b5476bcb282d',
|
||||
}),
|
||||
}),
|
||||
Object.freeze({
|
||||
name: 'cainjector',
|
||||
manifestReference: 'quay.io/jetstack/cert-manager-cainjector:v1.20.3',
|
||||
image:
|
||||
'quay.io/jetstack/cert-manager-cainjector:v1.20.3@sha256:06ad347fe0dc2eb84cc355c26f6752e05e87dceb6447f5cd29b963dd66dfd8bd',
|
||||
platforms: Object.freeze({
|
||||
'linux/amd64':
|
||||
'sha256:a2b12d27950d1603d2c8168c3ccd95d07b93ce6ec4b530316196a31db592a9c0',
|
||||
'linux/arm64':
|
||||
'sha256:3c052c134ad1b93122b957f4d214aaa9d85a37b5ff15acc5b4d86f50e3ed822e',
|
||||
}),
|
||||
}),
|
||||
Object.freeze({
|
||||
name: 'webhook',
|
||||
manifestReference: 'quay.io/jetstack/cert-manager-webhook:v1.20.3',
|
||||
image:
|
||||
'quay.io/jetstack/cert-manager-webhook:v1.20.3@sha256:a61e817632cebed3bb59a189327e786fa3fdd7597167d994a1848d98fd55848f',
|
||||
platforms: Object.freeze({
|
||||
'linux/amd64':
|
||||
'sha256:953a97df613f7da7eda8ce4b1c8d8e6b50963db0800fab595d040db6eb5cb060',
|
||||
'linux/arm64':
|
||||
'sha256:7c510875e038f79f7fba707b5f86d8736777a4dfefcd42179b08844ee75e685b',
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
|
||||
function finding(code, detail) {
|
||||
return Object.freeze({ code, detail });
|
||||
}
|
||||
|
||||
function exactJson(actual, expected) {
|
||||
return JSON.stringify(actual) === JSON.stringify(expected);
|
||||
}
|
||||
|
||||
function auditCertManagerSelection(options = {}) {
|
||||
const root = path.resolve(options.root ?? path.join(__dirname, '..'));
|
||||
const readFile = options.readFile ?? fs.readFileSync;
|
||||
const readDirectory = options.readDirectory ?? fs.readdirSync;
|
||||
const findings = [];
|
||||
|
||||
try {
|
||||
const directory = path.join(root, SELECTION_DIRECTORY);
|
||||
const entries = [...readDirectory(directory)].sort();
|
||||
if (!exactJson(entries, ['selection-lock.json'])) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_INSTALLER_UNVERIFIED',
|
||||
'the selection directory must remain a lock-only input; installers are fetched and digest verified at deployment time',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const selection = JSON.parse(
|
||||
readFile(path.join(directory, 'selection-lock.json'), 'utf8'),
|
||||
);
|
||||
if (
|
||||
selection?.schemaVersion !== 1 ||
|
||||
selection?.observedAt !== '2026-08-03' ||
|
||||
selection?.certManager?.version !== '1.20.3' ||
|
||||
selection?.certManager?.releaseManifest !==
|
||||
'https://github.com/cert-manager/cert-manager/releases/download/v1.20.3/cert-manager.yaml' ||
|
||||
selection?.certManager?.status !== 'supply-chain-verified'
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_SELECTION',
|
||||
'cert-manager must remain fixed to the reviewed v1.20.3 selection until a new Kubernetes compatibility review',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (
|
||||
selection?.compatibility?.reviewedKubernetes !== '1.32.8' ||
|
||||
selection?.compatibility?.supportedKubernetesMin !== '1.32' ||
|
||||
selection?.compatibility?.supportedKubernetesMax !== '1.35' ||
|
||||
selection?.compatibility?.newerMinorRejected !==
|
||||
'1.21.0 requires Kubernetes 1.33 or newer'
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_KUBERNETES_COMPATIBILITY',
|
||||
'the certificate controller selection must stay compatible with the locked Kubernetes 1.32.8 live gate',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (
|
||||
selection?.certManager?.releaseManifestSha256 !==
|
||||
RELEASE_MANIFEST_SHA256 ||
|
||||
!exactJson(selection?.certManager?.images, IMAGES) ||
|
||||
selection?.releaseReady !== false ||
|
||||
!exactJson(selection?.releaseBlockers, RELEASE_BLOCKERS)
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_PREMATURE_RELEASE',
|
||||
'the exact release SHA and OCI platform digests must stay locked while live API and rotation evidence remains an explicit release blocker',
|
||||
),
|
||||
);
|
||||
}
|
||||
if (
|
||||
selection?.scope?.profile !== 'cluster-only' ||
|
||||
selection?.scope?.installNamespace !== 'cert-manager' ||
|
||||
selection?.scope?.consumerNamespace !== 'cnpg-system' ||
|
||||
selection?.scope?.requiredBy !== 'barman-cloud.cloudnative-pg.io@0.13.0'
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_SCOPE',
|
||||
'cert-manager must remain cluster-only and separate from the Barman plugin namespace',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const pluginTls = selection?.pluginTls;
|
||||
const certificates = pluginTls?.certificates;
|
||||
if (
|
||||
!exactJson(pluginTls?.issuer, {
|
||||
apiVersion: 'cert-manager.io/v1',
|
||||
kind: 'Issuer',
|
||||
name: 'selfsigned-issuer',
|
||||
namespace: 'cnpg-system',
|
||||
type: 'SelfSigned',
|
||||
}) ||
|
||||
!exactJson(certificates, [
|
||||
{
|
||||
name: 'barman-cloud-client',
|
||||
secretName: 'barman-cloud-client-tls',
|
||||
commonName: 'barman-cloud-client',
|
||||
usages: ['client auth'],
|
||||
duration: '2160h',
|
||||
renewBefore: '360h',
|
||||
},
|
||||
{
|
||||
name: 'barman-cloud-server',
|
||||
secretName: 'barman-cloud-server-tls',
|
||||
commonName: 'barman-cloud',
|
||||
dnsNames: ['barman-cloud'],
|
||||
usages: ['server auth'],
|
||||
duration: '2160h',
|
||||
renewBefore: '360h',
|
||||
},
|
||||
])
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_PLUGIN_TLS',
|
||||
'the Barman client/server certificate identities, usages and rotation window must match the reviewed release contract',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const barman = JSON.parse(readFile(path.join(root, BARMAN_LOCK), 'utf8'));
|
||||
if (
|
||||
!exactJson(barman?.certificateAuthority, {
|
||||
mode: 'cert-manager',
|
||||
version: '1.20.3',
|
||||
selectionLock:
|
||||
'deploy/kubernetes/ql3-cluster/operators/cert-manager/selection-lock.json',
|
||||
releaseManifestUses: 'cert-manager.io/v1',
|
||||
requiredSecrets: ['barman-cloud-client-tls', 'barman-cloud-server-tls'],
|
||||
status: 'supply-chain-verified',
|
||||
})
|
||||
) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_BARMAN_BINDING',
|
||||
'the Barman candidate must bind the exact supply-chain-verified certificate authority without claiming live readiness',
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
findings.push(
|
||||
finding(
|
||||
'QL3_CERT_MANAGER_SELECTION_AUDIT_UNAVAILABLE',
|
||||
error instanceof Error ? error.message : 'unknown audit failure',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
schemaVersion: 1,
|
||||
certManagerVersion: '1.20.3',
|
||||
kubernetesVersion: '1.32.8',
|
||||
releaseReady: false,
|
||||
releaseBlockers: RELEASE_BLOCKERS,
|
||||
findings: Object.freeze(findings),
|
||||
compatible: findings.length === 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
const report = auditCertManagerSelection();
|
||||
process.stdout.write(`${JSON.stringify(report)}\n`);
|
||||
if (!report.compatible) process.exitCode = 1;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
auditCertManagerSelection,
|
||||
};
|
||||
Reference in New Issue
Block a user