Merge pull request #425 from pikasTech/fix/d601-ci-artifact-publish-65583b7
fix: 拆分 CI artifact publish 与 CD transaction
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
||||
resolveDevArtifactServices,
|
||||
serviceInventoryFromServices
|
||||
} from "./src/dev-artifact-services.mjs";
|
||||
import { requireDevCdTransactionForSideEffect } from "./src/dev-cd-transaction-guard.mjs";
|
||||
import { requireDevArtifactPublishIdentity } from "./src/dev-cd-transaction-guard.mjs";
|
||||
import { runDevBaseImagePreflight } from "./src/dev-base-image-preflight.mjs";
|
||||
import { probeRegistryCapabilities } from "./src/registry-capabilities.mjs";
|
||||
import { inspectCloudWebDistFreshness } from "../web/hwlab-cloud-web/scripts/dist-contract.mjs";
|
||||
@@ -1429,12 +1429,12 @@ async function main() {
|
||||
return;
|
||||
}
|
||||
if (args.mode === "publish") {
|
||||
const transactionGuard = requireDevCdTransactionForSideEffect({
|
||||
const identityGuard = requireDevArtifactPublishIdentity({
|
||||
script: "scripts/dev-artifact-publish.mjs",
|
||||
mode: "--publish"
|
||||
});
|
||||
if (transactionGuard) {
|
||||
console.log(JSON.stringify(transactionGuard, null, 2));
|
||||
if (identityGuard) {
|
||||
console.log(JSON.stringify(identityGuard, null, 2));
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1598,20 +1598,22 @@ test("live verify summarizes 16666 and 16667 health identity", async () => {
|
||||
assert.equal(result.endpoints.every((endpoint) => endpoint.commitMatches), true);
|
||||
});
|
||||
|
||||
test("legacy artifact publish CLI rejects side effects without transaction env", async () => {
|
||||
test("artifact publish CLI rejects side effects without CI or transaction identity", async () => {
|
||||
await assert.rejects(
|
||||
execFileAsync(process.execPath, ["scripts/dev-artifact-publish.mjs", "--publish", "--no-report"], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
HWLAB_CD_TRANSACTION_ID: ""
|
||||
HWLAB_CD_TRANSACTION_ID: "",
|
||||
HWLAB_CI_ARTIFACT_RUN_ID: ""
|
||||
}
|
||||
}),
|
||||
(error) => {
|
||||
assert.equal(error.code, 2);
|
||||
const payload = JSON.parse(error.stdout);
|
||||
assert.equal(payload.error, "cd-transaction-required");
|
||||
assert.equal(payload.error, "artifact-publish-identity-required");
|
||||
assert.equal(payload.script, "scripts/dev-artifact-publish.mjs");
|
||||
assert.equal(payload.cdLockRequired, false);
|
||||
assert.equal(payload.rolloutAttempted, false);
|
||||
assert.equal(payload.mutationAttempted, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,26 @@ const transactionEnvNames = [
|
||||
"HWLAB_CD_LOCK_NAME"
|
||||
];
|
||||
|
||||
const ciArtifactEnvNames = [
|
||||
"HWLAB_CI_ARTIFACT_RUN_ID",
|
||||
"GITHUB_RUN_ID",
|
||||
"CI_PIPELINE_ID",
|
||||
"BUILDKITE_BUILD_ID"
|
||||
];
|
||||
|
||||
const artifactPublishIdentityEnvNames = [
|
||||
...ciArtifactEnvNames,
|
||||
...transactionEnvNames
|
||||
];
|
||||
|
||||
export function hasDevCdTransactionEnv(env = process.env) {
|
||||
return typeof env.HWLAB_CD_TRANSACTION_ID === "string" && env.HWLAB_CD_TRANSACTION_ID.trim().length > 0;
|
||||
}
|
||||
|
||||
export function hasCiArtifactPublishEnv(env = process.env) {
|
||||
return ciArtifactEnvNames.some((name) => typeof env[name] === "string" && env[name].trim().length > 0);
|
||||
}
|
||||
|
||||
export function devCdTransactionGuardFailure({
|
||||
script,
|
||||
mode,
|
||||
@@ -32,7 +48,36 @@ export function devCdTransactionGuardFailure({
|
||||
};
|
||||
}
|
||||
|
||||
export function devArtifactPublishIdentityGuardFailure({
|
||||
script,
|
||||
mode,
|
||||
requiredEnv = "HWLAB_CI_ARTIFACT_RUN_ID or HWLAB_CD_TRANSACTION_ID"
|
||||
}) {
|
||||
return {
|
||||
ok: false,
|
||||
status: "blocked",
|
||||
error: "artifact-publish-identity-required",
|
||||
code: "artifact-publish-identity-required",
|
||||
script,
|
||||
mode,
|
||||
requiredEnv,
|
||||
acceptedEnv: artifactPublishIdentityEnvNames,
|
||||
entrypoint: `HWLAB_CI_ARTIFACT_RUN_ID=<run-id> node scripts/dev-artifact-publish.mjs --publish --report ${tempReportPath("dev-artifacts.json")}`,
|
||||
summary: `${script} ${mode} is a DEV artifact publish side-effect step and must run under CI artifact identity, or the legacy DEV CD transaction path.`,
|
||||
devOnly: true,
|
||||
prodTouched: false,
|
||||
cdLockRequired: false,
|
||||
rolloutAttempted: false,
|
||||
mutationAttempted: false
|
||||
};
|
||||
}
|
||||
|
||||
export function requireDevCdTransactionForSideEffect({ env = process.env, script, mode }) {
|
||||
if (hasDevCdTransactionEnv(env)) return null;
|
||||
return devCdTransactionGuardFailure({ script, mode });
|
||||
}
|
||||
|
||||
export function requireDevArtifactPublishIdentity({ env = process.env, script, mode }) {
|
||||
if (hasCiArtifactPublishEnv(env) || hasDevCdTransactionEnv(env)) return null;
|
||||
return devArtifactPublishIdentityGuardFailure({ script, mode });
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@ import {
|
||||
resolveDevKubeconfigSelection
|
||||
} from "./dev-deploy-apply.mjs";
|
||||
import {
|
||||
devArtifactPublishIdentityGuardFailure,
|
||||
devCdTransactionGuardFailure,
|
||||
hasCiArtifactPublishEnv,
|
||||
hasDevCdTransactionEnv,
|
||||
requireDevArtifactPublishIdentity,
|
||||
requireDevCdTransactionForSideEffect
|
||||
} from "./dev-cd-transaction-guard.mjs";
|
||||
|
||||
@@ -141,6 +144,43 @@ test("DEV CD transaction guard rejects direct legacy side-effect calls", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("DEV artifact publish guard allows CI identity without CD transaction", () => {
|
||||
assert.equal(hasCiArtifactPublishEnv({}), false);
|
||||
assert.equal(hasCiArtifactPublishEnv({ HWLAB_CI_ARTIFACT_RUN_ID: "ci-123" }), true);
|
||||
|
||||
const failure = requireDevArtifactPublishIdentity({
|
||||
env: {},
|
||||
script: "scripts/dev-artifact-publish.mjs",
|
||||
mode: "--publish"
|
||||
});
|
||||
assert.deepEqual(failure, devArtifactPublishIdentityGuardFailure({
|
||||
script: "scripts/dev-artifact-publish.mjs",
|
||||
mode: "--publish"
|
||||
}));
|
||||
assert.equal(failure.error, "artifact-publish-identity-required");
|
||||
assert.equal(failure.cdLockRequired, false);
|
||||
assert.equal(failure.rolloutAttempted, false);
|
||||
assert.equal(failure.mutationAttempted, false);
|
||||
assert.match(failure.entrypoint, /HWLAB_CI_ARTIFACT_RUN_ID=.*dev-artifact-publish\.mjs/u);
|
||||
|
||||
assert.equal(
|
||||
requireDevArtifactPublishIdentity({
|
||||
env: { HWLAB_CI_ARTIFACT_RUN_ID: "ci-123" },
|
||||
script: "scripts/dev-artifact-publish.mjs",
|
||||
mode: "--publish"
|
||||
}),
|
||||
null
|
||||
);
|
||||
assert.equal(
|
||||
requireDevArtifactPublishIdentity({
|
||||
env: { HWLAB_CD_TRANSACTION_ID: "tx-123" },
|
||||
script: "scripts/dev-artifact-publish.mjs",
|
||||
mode: "--publish"
|
||||
}),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
test("matching allowlisted suspended template Job image does not replace", () => {
|
||||
const image = "127.0.0.1:5000/hwlab/hwlab-cli:73b379f";
|
||||
const decision = decideDevTemplateJobReplacement({
|
||||
|
||||
Reference in New Issue
Block a user