mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-23 03:18:09 +08:00
feat(ql3): close public local release pair
This commit is contained in:
@@ -22,11 +22,13 @@ import {
|
||||
} from '../foundation/files';
|
||||
import { deploymentPaths } from '../foundation/render';
|
||||
|
||||
const SELECTION_SCHEMA = 'qinglong/local-compose-image-selection@v2';
|
||||
const SELECTION_SCHEMA = 'qinglong/local-compose-image-selection@v3';
|
||||
const CATALOG_SCHEMA = 'qinglong/release-catalog-consumption-ceremony@v1';
|
||||
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
||||
const IMAGE_PATTERN =
|
||||
/^ghcr\.io\/([a-z0-9](?:[a-z0-9-]{0,38}))\/qinglong3-local-application@sha256:[0-9a-f]{64}$/;
|
||||
const OPERATOR_IMAGE_PATTERN =
|
||||
/^ghcr\.io\/([a-z0-9](?:[a-z0-9-]{0,38}))\/qinglong3-local-operator@sha256:[0-9a-f]{64}$/;
|
||||
const VERSION_PATTERN = /^3\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
||||
const SOURCE_REVISION_PATTERN = /^[a-f0-9]{40}$/;
|
||||
const SOURCE_REPOSITORY_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
||||
@@ -63,6 +65,7 @@ function selectionContents(selection: Readonly<ComposeImageSelection>): string {
|
||||
` catalog_manifest_digest: ${selection.catalogManifestDigest}`,
|
||||
` catalog_consumption_report_digest: ${selection.catalogConsumptionReportDigest}`,
|
||||
` catalog_discovery_tag_authority: ${selection.catalogDiscoveryTagAuthority}`,
|
||||
` operator_image: ${selection.operatorImage}`,
|
||||
` allow_root_service: ${selection.allowRootService}`,
|
||||
'services:',
|
||||
' qinglong3:',
|
||||
@@ -94,7 +97,7 @@ function parseSelection(
|
||||
label: string,
|
||||
): Readonly<ComposeImageSelection> {
|
||||
const match =
|
||||
/^x-qinglong-image-selection:\n schema: qinglong\/local-compose-image-selection@v2\n generation: (0|[1-9][0-9]{0,5})\n previous_generation: (0|[1-9][0-9]{0,5})\n rollback_target_generation: (0|[1-9][0-9]{0,5})\n mutation_id: ([0-9a-f-]+)\n changed_at_ms: ([0-9]+)\n release_selection_digest: (sha256:[a-f0-9]{64})\n release_set_digest: (sha256:[a-f0-9]{64})\n release_version: ([^\n]+)\n release_source_revision: ([a-f0-9]{40})\n release_source_ref: ([^\n]+)\n release_scope: (local|all)\n catalog_schema: qinglong\/release-catalog-consumption-ceremony@v1\n catalog_source_repository: ([^\n]+)\n catalog_workflow_identity: ([^\n]+)\n catalog_immutable_reference: ([^\n]+)\n catalog_manifest_digest: (sha256:[a-f0-9]{64})\n catalog_consumption_report_digest: (sha256:[a-f0-9]{64})\n catalog_discovery_tag_authority: none\n allow_root_service: (true|false)\nservices:\n qinglong3:\n image: ([^\n]+)\n labels:\n io\.qinglong\.deployment\.generation: "([0-9]+)"\n io\.qinglong\.deployment\.mutation: "([0-9a-f-]+)"\n io\.qinglong\.release\.selection: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.set: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.catalog-manifest: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.catalog-report: "(sha256:[a-f0-9]{64})"\n$/.exec(
|
||||
/^x-qinglong-image-selection:\n schema: qinglong\/local-compose-image-selection@v3\n generation: (0|[1-9][0-9]{0,5})\n previous_generation: (0|[1-9][0-9]{0,5})\n rollback_target_generation: (0|[1-9][0-9]{0,5})\n mutation_id: ([0-9a-f-]+)\n changed_at_ms: ([0-9]+)\n release_selection_digest: (sha256:[a-f0-9]{64})\n release_set_digest: (sha256:[a-f0-9]{64})\n release_version: ([^\n]+)\n release_source_revision: ([a-f0-9]{40})\n release_source_ref: ([^\n]+)\n release_scope: (local|all)\n catalog_schema: qinglong\/release-catalog-consumption-ceremony@v1\n catalog_source_repository: ([^\n]+)\n catalog_workflow_identity: ([^\n]+)\n catalog_immutable_reference: ([^\n]+)\n catalog_manifest_digest: (sha256:[a-f0-9]{64})\n catalog_consumption_report_digest: (sha256:[a-f0-9]{64})\n catalog_discovery_tag_authority: none\n operator_image: ([^\n]+)\n allow_root_service: (true|false)\nservices:\n qinglong3:\n image: ([^\n]+)\n labels:\n io\.qinglong\.deployment\.generation: "([0-9]+)"\n io\.qinglong\.deployment\.mutation: "([0-9a-f-]+)"\n io\.qinglong\.release\.selection: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.set: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.catalog-manifest: "(sha256:[a-f0-9]{64})"\n io\.qinglong\.release\.catalog-report: "(sha256:[a-f0-9]{64})"\n$/.exec(
|
||||
contents,
|
||||
);
|
||||
if (!match) {
|
||||
@@ -122,15 +125,17 @@ function parseSelection(
|
||||
const catalogImmutableReference = match[14]!;
|
||||
const catalogManifestDigest = match[15]!;
|
||||
const catalogConsumptionReportDigest = match[16]!;
|
||||
const allowRootService = match[17] === 'true';
|
||||
const image = match[18]!;
|
||||
const labelGeneration = Number(match[19]);
|
||||
const labelMutationId = match[20];
|
||||
const labelSelectionDigest = match[21];
|
||||
const labelReleaseSetDigest = match[22];
|
||||
const labelCatalogManifestDigest = match[23];
|
||||
const labelCatalogReportDigest = match[24];
|
||||
const operatorImage = match[17]!;
|
||||
const allowRootService = match[18] === 'true';
|
||||
const image = match[19]!;
|
||||
const labelGeneration = Number(match[20]);
|
||||
const labelMutationId = match[21];
|
||||
const labelSelectionDigest = match[22];
|
||||
const labelReleaseSetDigest = match[23];
|
||||
const labelCatalogManifestDigest = match[24];
|
||||
const labelCatalogReportDigest = match[25];
|
||||
const imageMatch = IMAGE_PATTERN.exec(image);
|
||||
const operatorImageMatch = OPERATOR_IMAGE_PATTERN.exec(operatorImage);
|
||||
if (
|
||||
generation < 1 ||
|
||||
previousGeneration !== generation - 1 ||
|
||||
@@ -150,6 +155,8 @@ function parseSelection(
|
||||
!DIGEST_PATTERN.test(catalogManifestDigest) ||
|
||||
!DIGEST_PATTERN.test(catalogConsumptionReportDigest) ||
|
||||
!imageMatch ||
|
||||
!operatorImageMatch ||
|
||||
operatorImageMatch[1] !== imageMatch[1] ||
|
||||
catalogImmutableReference !==
|
||||
`ghcr.io/${imageMatch?.[1]}/qinglong3-release-catalog@${catalogManifestDigest}` ||
|
||||
labelGeneration !== generation ||
|
||||
@@ -168,6 +175,7 @@ function parseSelection(
|
||||
mutationId,
|
||||
changedAtMs,
|
||||
image,
|
||||
operatorImage,
|
||||
allowRootService,
|
||||
selectionDigest,
|
||||
releaseSetDigest,
|
||||
@@ -235,6 +243,7 @@ function releaseAuthorityFromSelection(
|
||||
): Readonly<LocalComposeReleaseAuthority> {
|
||||
return Object.freeze({
|
||||
image: selection.image,
|
||||
operatorImage: selection.operatorImage,
|
||||
allowRootService: selection.allowRootService,
|
||||
selectionDigest: selection.selectionDigest,
|
||||
releaseSetDigest: selection.releaseSetDigest,
|
||||
|
||||
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const MAX_SELECTION_BYTES = 64 * 1024;
|
||||
const LOCAL_SELECTION_SCHEMA = 'qinglong/local-compose-release-image@v2';
|
||||
const LOCAL_SELECTION_SCHEMA = 'qinglong/local-compose-release-image@v3';
|
||||
const CATALOG_SCHEMA = 'qinglong/release-catalog-consumption-ceremony@v1';
|
||||
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
||||
const VERSION_PATTERN = /^3\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
||||
@@ -11,6 +11,8 @@ const SOURCE_REVISION_PATTERN = /^[a-f0-9]{40}$/;
|
||||
const SOURCE_REPOSITORY_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
||||
const IMAGE_PATTERN =
|
||||
/^ghcr\.io\/([a-z0-9](?:[a-z0-9-]{0,38}))\/qinglong3-local-application@(sha256:[a-f0-9]{64})$/;
|
||||
const OPERATOR_IMAGE_PATTERN =
|
||||
/^ghcr\.io\/([a-z0-9](?:[a-z0-9-]{0,38}))\/qinglong3-local-operator@(sha256:[a-f0-9]{64})$/;
|
||||
|
||||
export interface LocalComposeReleaseSelectionInput {
|
||||
readonly path: string;
|
||||
@@ -19,6 +21,7 @@ export interface LocalComposeReleaseSelectionInput {
|
||||
|
||||
export interface LocalComposeReleaseAuthority {
|
||||
readonly image: string;
|
||||
readonly operatorImage: string;
|
||||
readonly allowRootService: boolean;
|
||||
readonly selectionDigest: string;
|
||||
readonly releaseSetDigest: string;
|
||||
@@ -171,6 +174,7 @@ export function resolveLocalComposeReleaseSelection(
|
||||
'schemaVersion',
|
||||
'selectionDigest',
|
||||
'service',
|
||||
'operator',
|
||||
'verification',
|
||||
],
|
||||
'release selection',
|
||||
@@ -195,6 +199,7 @@ export function resolveLocalComposeReleaseSelection(
|
||||
'catalog',
|
||||
);
|
||||
exactKeys(value.service, ['allowRootService', 'image', 'kind'], 'service');
|
||||
exactKeys(value.operator, ['image', 'kind', 'network'], 'operator');
|
||||
exactKeys(
|
||||
value.verification,
|
||||
[
|
||||
@@ -210,9 +215,13 @@ export function resolveLocalComposeReleaseSelection(
|
||||
const release = value.release;
|
||||
const catalog = value.catalog;
|
||||
const service = value.service;
|
||||
const operator = value.operator;
|
||||
const verification = value.verification;
|
||||
const image = typeof service.image === 'string' ? service.image : '';
|
||||
const imageMatch = IMAGE_PATTERN.exec(image);
|
||||
const operatorImage =
|
||||
typeof operator.image === 'string' ? operator.image : '';
|
||||
const operatorImageMatch = OPERATOR_IMAGE_PATTERN.exec(operatorImage);
|
||||
const { selectionDigest, ...unsigned } = value;
|
||||
const calculatedDigest = digest(JSON.stringify(unsigned));
|
||||
if (
|
||||
@@ -239,10 +248,14 @@ export function resolveLocalComposeReleaseSelection(
|
||||
catalog.releaseSetDigest !== value.releaseSetDigest ||
|
||||
catalog.discoveryTagAuthority !== 'none' ||
|
||||
!imageMatch ||
|
||||
!operatorImageMatch ||
|
||||
operatorImageMatch[1] !== imageMatch[1] ||
|
||||
catalog.immutableReference !==
|
||||
`ghcr.io/${imageMatch[1]}/qinglong3-release-catalog@${catalog.manifestDigest}` ||
|
||||
service.kind !== 'compose' ||
|
||||
service.allowRootService !== allowRootService ||
|
||||
operator.kind !== 'short-lived' ||
|
||||
operator.network !== 'none-by-default' ||
|
||||
verification.releaseSet !==
|
||||
'standalone_structure_identity_and_self_digest' ||
|
||||
verification.sourceRecordsReplayed !== false ||
|
||||
@@ -262,6 +275,7 @@ export function resolveLocalComposeReleaseSelection(
|
||||
expectedSelectionDigest: input.expectedSelectionDigest,
|
||||
authority: Object.freeze({
|
||||
image,
|
||||
operatorImage,
|
||||
allowRootService,
|
||||
selectionDigest,
|
||||
releaseSetDigest: value.releaseSetDigest,
|
||||
|
||||
Reference in New Issue
Block a user