fix: 收敛 PaC 自动交付提示
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
// Responsibility: expose the YAML-owned sentinel internal publish capability without claiming provenance.
|
||||
import { rootPath } from "./config";
|
||||
import type { CicdDeliveryAuthority } from "./cicd-delivery-authority";
|
||||
import type { WebProbeSentinelOptions } from "./hwlab-node-web-sentinel-cicd-shared";
|
||||
import { readYamlRecord } from "./platform-infra-ops-library";
|
||||
import { materializeYamlComposition } from "./yaml-composition";
|
||||
|
||||
const configPath = "config/platform-infra/pipelines-as-code.yaml";
|
||||
const configRef = `${configPath}#capabilities.sentinelInternalPublish`;
|
||||
|
||||
export interface SentinelPacInternalPublishCapability {
|
||||
readonly enabled: boolean;
|
||||
readonly admissionProvenance: "unavailable";
|
||||
readonly trackingIssue: string;
|
||||
readonly configRef: string;
|
||||
readonly valuesPrinted: false;
|
||||
}
|
||||
|
||||
export type SentinelPacInternalPublishAuthorization = {
|
||||
readonly allowed: false;
|
||||
readonly mode: "sentinel-pac-internal-publish-blocked";
|
||||
readonly reason:
|
||||
| "operator-entrypoint"
|
||||
| "delivery-authority-not-pac"
|
||||
| "capability-disabled"
|
||||
| "admission-provenance-unavailable";
|
||||
readonly capability: SentinelPacInternalPublishCapability;
|
||||
readonly valuesPrinted: false;
|
||||
};
|
||||
|
||||
export function readSentinelPacInternalPublishCapability(): SentinelPacInternalPublishCapability {
|
||||
const raw = readYamlRecord<Record<string, unknown>>(rootPath(...configPath.split("/")), "platform-infra-pipelines-as-code");
|
||||
const composed = materializeYamlComposition(raw, { label: configPath }).value;
|
||||
const capabilities = record(composed.capabilities, `${configPath}#capabilities`);
|
||||
const capability = record(capabilities.sentinelInternalPublish, configRef);
|
||||
const enabled = booleanField(capability.enabled, `${configRef}.enabled`);
|
||||
const admissionProvenance = stringField(capability.admissionProvenance, `${configRef}.admissionProvenance`);
|
||||
if (admissionProvenance !== "unavailable") {
|
||||
throw new Error(`${configRef}.admissionProvenance must remain unavailable until the admission contract is implemented`);
|
||||
}
|
||||
const trackingIssue = stringField(capability.trackingIssue, `${configRef}.trackingIssue`);
|
||||
if (!/^https:\/\/github\.com\/pikasTech\/unidesk\/issues\/\d+$/u.test(trackingIssue)) {
|
||||
throw new Error(`${configRef}.trackingIssue must reference the owning GitHub issue`);
|
||||
}
|
||||
return {
|
||||
enabled,
|
||||
admissionProvenance,
|
||||
trackingIssue,
|
||||
configRef,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function authorizeSentinelPacInternalPublish(
|
||||
options: WebProbeSentinelOptions,
|
||||
authority: CicdDeliveryAuthority,
|
||||
capability = readSentinelPacInternalPublishCapability(),
|
||||
): SentinelPacInternalPublishAuthorization {
|
||||
if (options.kind !== "publish" || options.internalExecution !== "pac-controller") {
|
||||
return denied("operator-entrypoint", capability);
|
||||
}
|
||||
if (authority.kind !== "pac-pr-merge") return denied("delivery-authority-not-pac", capability);
|
||||
if (!capability.enabled) return denied("capability-disabled", capability);
|
||||
return denied("admission-provenance-unavailable", capability);
|
||||
}
|
||||
|
||||
function denied(
|
||||
reason: SentinelPacInternalPublishAuthorization["reason"],
|
||||
capability: SentinelPacInternalPublishCapability,
|
||||
): SentinelPacInternalPublishAuthorization {
|
||||
return {
|
||||
allowed: false,
|
||||
mode: "sentinel-pac-internal-publish-blocked",
|
||||
reason,
|
||||
capability,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function record(value: unknown, path: string): Record<string, unknown> {
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be an object`);
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function booleanField(value: unknown, path: string): boolean {
|
||||
if (typeof value !== "boolean") throw new Error(`${path} must be a boolean`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function stringField(value: unknown, path: string): string {
|
||||
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path} must be a non-empty string`);
|
||||
return value.trim();
|
||||
}
|
||||
Reference in New Issue
Block a user