mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 19:35:28 -06:00
fix(release): restore frozen validation startup (#110210)
* fix(release): restore frozen validation startup Adapt the no-write validation portion ofb597a8d364(#103834) for the 6.x extended-stable workflow set. Remove validation-owned image publisher jobs instead of granting write permissions; Docker publication remains out of scope. * fix(release): allow canonical extended-stable checks Restore the openclaw-release-checks.yml portion ofc7810fc697(#99352) that authorizes the canonical extended-stable/YYYY.M.33 workflow branch.
This commit is contained in:
@@ -52,17 +52,17 @@ function step(workflowJob: WorkflowJob, name: string): WorkflowStep {
|
||||
}
|
||||
|
||||
describe("install smoke no-push root image transport", () => {
|
||||
it("keeps registry transport as the default and validates the selected mode", () => {
|
||||
it("defaults every caller to artifact-only transport", () => {
|
||||
const workflow = readWorkflow(INSTALL_SMOKE);
|
||||
const dispatchInput = workflow.on?.workflow_dispatch?.inputs?.root_image_transport;
|
||||
const callInput = workflow.on?.workflow_call?.inputs?.root_image_transport;
|
||||
expect(dispatchInput).toMatchObject({
|
||||
default: "registry",
|
||||
options: ["registry", "no-push-artifact"],
|
||||
default: "no-push-artifact",
|
||||
options: ["no-push-artifact"],
|
||||
type: "choice",
|
||||
});
|
||||
expect(callInput).toMatchObject({
|
||||
default: "registry",
|
||||
default: "no-push-artifact",
|
||||
type: "string",
|
||||
});
|
||||
expect(workflow.permissions).toMatchObject({
|
||||
@@ -205,41 +205,18 @@ describe("install smoke no-push root image transport", () => {
|
||||
path: "${{ steps.image_artifact.outputs.artifact_path }}",
|
||||
});
|
||||
|
||||
const registryPublisher = job(workflow, "push_root_dockerfile_image");
|
||||
expect(registryPublisher.permissions).toEqual({
|
||||
contents: "read",
|
||||
packages: "write",
|
||||
});
|
||||
expect(registryPublisher.if).toBe(
|
||||
"needs.preflight.outputs.root_image_transport == 'registry' && needs.root_dockerfile_image.outputs.image_exists != 'true'",
|
||||
);
|
||||
expect(step(registryPublisher, "Checkout CLI").with).toMatchObject({
|
||||
ref: "${{ needs.preflight.outputs.target_sha }}",
|
||||
"persist-credentials": false,
|
||||
});
|
||||
expect(step(registryPublisher, "Log in to GHCR").if).toBeUndefined();
|
||||
const registryBuild = step(registryPublisher, "Build and push root Dockerfile smoke image");
|
||||
expect(registryBuild.run).toContain("--push");
|
||||
expect(registryBuild.run).not.toContain("--load");
|
||||
|
||||
const writeScopedJobs = Object.entries(workflow.jobs)
|
||||
.filter(([, candidate]) => candidate.permissions?.packages === "write")
|
||||
.map(([name]) => name);
|
||||
expect(writeScopedJobs).toEqual(["push_root_dockerfile_image"]);
|
||||
expect(writeScopedJobs).toEqual([]);
|
||||
expect(workflow.jobs.push_root_dockerfile_image).toBeUndefined();
|
||||
|
||||
const ready = job(workflow, "root_dockerfile_image_ready");
|
||||
expect(ready.needs).toEqual([
|
||||
"preflight",
|
||||
"root_dockerfile_image",
|
||||
"push_root_dockerfile_image",
|
||||
]);
|
||||
expect(ready.needs).toEqual(["preflight", "root_dockerfile_image"]);
|
||||
expect(ready.if).toContain("always()");
|
||||
const verify = step(ready, "Verify root Dockerfile image preparation");
|
||||
expect(verify.run).toContain('if [[ "$PREPARE_RESULT" != "success" ]]');
|
||||
expect(verify.run).toContain(
|
||||
'if [[ "$ROOT_IMAGE_TRANSPORT" == "registry" && "$IMAGE_EXISTS" != "true" ]]',
|
||||
);
|
||||
expect(verify.run).toContain('elif [[ "$PUSH_RESULT" != "skipped" ]]');
|
||||
expect(verify.run).not.toContain("PUSH_RESULT");
|
||||
});
|
||||
|
||||
it("verifies and loads the artifact in every consumer without registry fallback", () => {
|
||||
|
||||
@@ -650,6 +650,9 @@ describe("package acceptance workflow", () => {
|
||||
);
|
||||
expect(workflow).toContain("| Child | Result | Minutes | Head SHA | Run |");
|
||||
expect(releaseChecksWorkflow).toContain("refs/heads/release-ci/[0-9a-f]{12}-[0-9]+");
|
||||
expect(releaseChecksWorkflow).toContain(
|
||||
"refs/heads/extended-stable/[0-9]{4}\\.([1-9]|1[0-2])\\.33",
|
||||
);
|
||||
expect(releaseChecksWorkflow).toContain(
|
||||
"source: ${{ (needs.resolve_target.outputs.package_acceptance_package_spec != '' || needs.resolve_target.outputs.release_package_spec != '') && 'npm' || 'artifact' }}",
|
||||
);
|
||||
|
||||
@@ -273,12 +273,12 @@ describe("release validation no-push transport", () => {
|
||||
const registryAcceptance = job(packageAcceptance, "docker_acceptance_registry");
|
||||
expect(packageAcceptance.permissions?.packages).toBe("read");
|
||||
expect(packageAcceptance.on?.workflow_dispatch?.inputs?.shared_image_policy).toMatchObject({
|
||||
default: "allow-push",
|
||||
options: ["allow-push", "existing-only", "no-push-artifact"],
|
||||
default: "no-push-artifact",
|
||||
options: ["existing-only", "no-push-artifact"],
|
||||
type: "choice",
|
||||
});
|
||||
expect(packageAcceptance.on?.workflow_call?.inputs?.shared_image_policy).toMatchObject({
|
||||
default: "allow-push",
|
||||
default: "no-push-artifact",
|
||||
type: "string",
|
||||
});
|
||||
expect(standardAcceptance.with?.shared_image_policy).toBe("${{ inputs.shared_image_policy }}");
|
||||
@@ -298,8 +298,8 @@ describe("release validation no-push transport", () => {
|
||||
});
|
||||
expect(standardAcceptance.if).toContain("shared_image_policy == 'no-push-artifact'");
|
||||
expectReadOnlyPackagePermission(standardAcceptance);
|
||||
expect(registryAcceptance.if).toContain("shared_image_policy != 'no-push-artifact'");
|
||||
expect(registryAcceptance.permissions?.packages).toBe("write");
|
||||
expect(registryAcceptance.if).toContain("shared_image_policy == 'existing-only'");
|
||||
expectReadOnlyPackagePermission(registryAcceptance);
|
||||
|
||||
const pluginDocker = job(pluginPrerelease, "plugin-prerelease-docker-suite");
|
||||
expectReadOnlyPackagePermission(pluginDocker);
|
||||
@@ -322,10 +322,10 @@ describe("release validation no-push transport", () => {
|
||||
const dispatchPolicy = workflow.on?.workflow_dispatch?.inputs?.shared_image_policy;
|
||||
const callPolicy = workflow.on?.workflow_call?.inputs?.shared_image_policy;
|
||||
expect(dispatchPolicy).toMatchObject({
|
||||
default: "allow-push",
|
||||
options: ["allow-push", "existing-only", "no-push-artifact"],
|
||||
default: "no-push-artifact",
|
||||
options: ["existing-only", "no-push-artifact"],
|
||||
});
|
||||
expect(callPolicy).toMatchObject({ default: "allow-push", type: "string" });
|
||||
expect(callPolicy).toMatchObject({ default: "no-push-artifact", type: "string" });
|
||||
|
||||
const validation = job(workflow, "validate_selected_ref");
|
||||
expect(validation.outputs?.workflow_repository).toBe(
|
||||
@@ -354,28 +354,18 @@ describe("release validation no-push transport", () => {
|
||||
|
||||
const dockerProducer = job(workflow, "prepare_docker_e2e_image");
|
||||
const liveProducer = job(workflow, "prepare_live_test_image");
|
||||
const dockerPublisher = job(workflow, "push_docker_e2e_images");
|
||||
const livePublisher = job(workflow, "push_live_test_image");
|
||||
expect(workflow.permissions?.actions).toBe("read");
|
||||
expect(workflow.permissions?.packages).toBe("read");
|
||||
expectReadOnlyPackagePermission(dockerProducer);
|
||||
expectReadOnlyPackagePermission(liveProducer);
|
||||
expect(dockerPublisher.permissions?.packages).toBe("write");
|
||||
expect(livePublisher.permissions?.packages).toBe("write");
|
||||
expect(dockerPublisher.if).toContain("shared_image_policy == 'allow-push'");
|
||||
expect(livePublisher.if).toContain("shared_image_policy == 'allow-push'");
|
||||
expect(workflow.jobs?.push_docker_e2e_images).toBeUndefined();
|
||||
expect(workflow.jobs?.push_live_test_image).toBeUndefined();
|
||||
expect(job(workflow, "docker_e2e_image_ready").permissions?.packages).toBeUndefined();
|
||||
expect(job(workflow, "live_test_image_ready").permissions?.packages).toBeUndefined();
|
||||
const packageWriters = Object.entries(workflow.jobs ?? {}).filter(
|
||||
([, workflowJob]) => workflowJob.permissions?.packages === "write",
|
||||
);
|
||||
expect(packageWriters.map(([name]) => name).sort()).toEqual([
|
||||
"push_docker_e2e_images",
|
||||
"push_live_test_image",
|
||||
]);
|
||||
for (const [, workflowJob] of packageWriters) {
|
||||
expect(workflowJob.if).toContain("shared_image_policy == 'allow-push'");
|
||||
}
|
||||
expect(packageWriters).toEqual([]);
|
||||
const validateSelectedRef = step(
|
||||
job(workflow, "validate_selected_ref"),
|
||||
"Validate selected ref",
|
||||
@@ -557,13 +547,13 @@ describe("release validation no-push transport", () => {
|
||||
push: false,
|
||||
});
|
||||
const dockerLoginCondition = step(dockerProducer, "Log in to GHCR").if;
|
||||
expect(dockerLoginCondition).toContain("shared_image_policy == 'allow-push'");
|
||||
expect(dockerLoginCondition).toContain("shared_image_policy == 'existing-only'");
|
||||
expect(dockerLoginCondition).not.toContain("allow-push");
|
||||
expect(step(liveProducer, "Log in to GHCR").if).toContain(
|
||||
"shared_image_policy != 'no-push-artifact'",
|
||||
);
|
||||
expect(step(dockerProducer, "Check existing shared Docker E2E images").if).toContain(
|
||||
"shared_image_policy == 'allow-push'",
|
||||
"shared_image_policy == 'existing-only'",
|
||||
);
|
||||
expect(step(liveProducer, "Check existing shared live-test image").if).toContain(
|
||||
"shared_image_policy != 'no-push-artifact'",
|
||||
@@ -574,19 +564,7 @@ describe("release validation no-push transport", () => {
|
||||
.filter((candidate) => candidate.run?.includes("--push"))
|
||||
.map((candidate) => ({ candidate, jobName })),
|
||||
);
|
||||
expect(shellPushSteps.map(({ candidate }) => candidate.name).sort()).toEqual([
|
||||
"Build and push bare Docker E2E image",
|
||||
"Build and push functional Docker E2E image",
|
||||
]);
|
||||
for (const { jobName } of shellPushSteps) {
|
||||
expect(jobName).toBe("push_docker_e2e_images");
|
||||
}
|
||||
expect(step(livePublisher, "Build and push shared live-test image").with?.push).toBe(true);
|
||||
expect(step(dockerPublisher, "Download OpenClaw Docker E2E package").with).toMatchObject({
|
||||
"artifact-ids": "${{ needs.prepare_docker_e2e_image.outputs.package_artifact_id }}",
|
||||
"github-token": "${{ github.token }}",
|
||||
"run-id": "${{ needs.prepare_docker_e2e_image.outputs.package_artifact_run_id }}",
|
||||
});
|
||||
expect(shellPushSteps).toEqual([]);
|
||||
|
||||
for (const name of [
|
||||
"validate_docker_e2e",
|
||||
|
||||
Reference in New Issue
Block a user