mirror of
https://github.com/openclaw/openclaw.git
synced 2026-11-01 04:58:23 +00:00
* chore: refresh all dependencies with seven-day cutoff Select compatible releases published by 2026-10-08T06:25:51Z across npm, native apps, CI actions, containers and downloaded tools. Align lockfiles, hashes, license labels and consumer fixtures; preserve documented compatibility holds and runtime floors. * test: align remaining dependency refresh fixtures Align the Linux native-hook pressure proof with the audited Codex 0.161.0 binary. Use the existing real-Gateway fixture for Telegram conversation-binding proof instead of unrelated package-install preparation; preserve every authority and transport assertion. Original CI failures and focused proof limitations remain recorded in the PR. * fix(whatsapp): name reply plan declaration contracts Preserve the existing six-field reply plan and branded dispatch parameter through named public SDK type references. This avoids TS4058 while emitting the package-local declaration boundary; runtime behavior is unchanged. * fix: align dependency fixtures with current lifecycle owners Await automatic plugin retirement instead of polling, retain exact Codex prompt ordering, and align the newly added UI media dependency with the already eligible 1.61.3 resolution. The complete prior dependency candidate and this incremental repair have independent scoped-clean review. * test: retire obsolete Matrix preview and simplify Telegram fixture Keep the existing message-content privacy regression and all Telegram provider failure, continuation, and visible-settlement assertions. Use the established real-Gateway fixture instead of unrelated packaged-install preparation; do not raise test or compiler timeouts. * fix: avoid native hook priority inversion and palette hover leakage Keep synchronous Codex policy relays at inherited process priority instead of nice 10. The 20-way two-core pressure failure lost nineteen hook completions at the unchanged ten-second deadline; preserve the complete stress, denial, retry and output assertions for exact-head CI. Move the browser pointer off the select before checking its idle palette. Scheduled main reports the identical hover color failure. Independent P2 review is clean; local browser replay stalls in the pre-existing menu-opening phase, and Linux stress execution remains assigned to CI. * fix: preserve sealed worker and browser lifecycle contracts Retain native-disabled fs-safe behavior in sealed bundles and fail closed on a native batch request instead of emitting a missing native helper URL. Preserve the nonnative permission path and reject upstream transform drift. Use controlled native animations for the WebKit closing lease, require abort in active Talk close, and scope video failure text to the alert surface. Independent P2 review is clean. Original worker archive case passes (39.390s; 283.23s total); original Talk and video cases pass (1.876s and 1.485s; 55.96s total), excluding unrelated cases. WebKit proof belongs to CI because its matching browser is unavailable locally. * test: wait for side-turn and favicon startup signals
439 lines
21 KiB
YAML
439 lines
21 KiB
YAML
name: Docker Release
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
runner_group:
|
|
description: Optional dedicated release runner group; empty retains the current labels
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
tag:
|
|
description: Immutable stable, extended-stable, or beta release tag
|
|
required: true
|
|
type: string
|
|
release_sha:
|
|
description: Full immutable commit SHA resolved from tag
|
|
required: true
|
|
type: string
|
|
image_tag_suffix:
|
|
description: Optional dated rebuild suffix for version-identified image tags
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
focused_release_evidence_run_id:
|
|
description: Optional immutable authorized beta focused evidence producer run
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
focused_release_evidence_run_attempt:
|
|
description: Exact previously verified focused evidence producer attempt
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
focused_release_evidence_workflow_full_ref:
|
|
description: Exact previously verified focused evidence producer tag
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
focused_release_evidence_workflow_sha:
|
|
description: Exact previously verified focused evidence producer SHA
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
full_release_validation_run_id:
|
|
description: Exact Full Release Validation parent authorizing prepared bytes
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
full_release_validation_run_attempt:
|
|
description: Exact qualification parent attempt
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
prepared_run_id:
|
|
description: Exact prepared Docker producer run; omitted to prepare in this publication
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
prepared_run_attempt:
|
|
description: Exact prepared Docker producer attempt
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
prepared_artifact_name:
|
|
description: Immutable prepared Docker manifest artifact name
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
prepared_manifest_sha256:
|
|
description: SHA256 of the prepared Docker manifest bytes
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
outputs:
|
|
version:
|
|
description: Resolved Docker release version without the v prefix
|
|
value: ${{ jobs.validate_release_identity.outputs.version }}
|
|
include_browser:
|
|
description: Whether the tagged release includes browser images
|
|
value: ${{ jobs.validate_release_identity.outputs.include_browser }}
|
|
vcr_source_digests:
|
|
description: Newline-delimited verified immutable GHCR source digests
|
|
value: ${{ jobs.publish.outputs.vcr_source_digests }}
|
|
secrets:
|
|
DOCKERHUB_USERNAME:
|
|
required: true
|
|
DOCKERHUB_TOKEN:
|
|
required: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
|
|
jobs:
|
|
validate_release_identity:
|
|
runs-on: ${{ inputs.runner_group != '' && fromJSON(format('{{"group":{0},"labels":{1}}}', toJSON(inputs.runner_group), toJSON('ubuntu-24.04'))) || ('ubuntu-24.04') }}
|
|
outputs:
|
|
version: ${{ steps.identity.outputs.version }}
|
|
include_browser: ${{ steps.identity.outputs.include_browser }}
|
|
steps:
|
|
- name: Validate immutable tag and SHA inputs
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
RELEASE_SHA: ${{ inputs.release_sha }}
|
|
IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }}
|
|
PREPARED_RUN_ID: ${{ inputs.prepared_run_id }}
|
|
PREPARED_RUN_ATTEMPT: ${{ inputs.prepared_run_attempt }}
|
|
PREPARED_ARTIFACT_NAME: ${{ inputs.prepared_artifact_name }}
|
|
PREPARED_MANIFEST_SHA256: ${{ inputs.prepared_manifest_sha256 }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -n "${IMAGE_TAG_SUFFIX}" && ! "${IMAGE_TAG_SUFFIX}" =~ ^-r[0-9]{8}$ ]]; then
|
|
echo "Invalid Docker image tag suffix: ${IMAGE_TAG_SUFFIX}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! "${RELEASE_TAG}" =~ ^v[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-(beta\.)?[1-9][0-9]*)?$ || ! "${RELEASE_SHA}" =~ ^[a-f0-9]{40}$ ]]; then
|
|
echo "Docker publication requires an immutable stable, extended-stable, or beta tag and full SHA." >&2
|
|
exit 1
|
|
fi
|
|
if [[ -n "${PREPARED_RUN_ID}${PREPARED_RUN_ATTEMPT}${PREPARED_ARTIFACT_NAME}${PREPARED_MANIFEST_SHA256}" ]]; then
|
|
if [[ ! "${PREPARED_RUN_ID}" =~ ^[1-9][0-9]*$ || ! "${PREPARED_RUN_ATTEMPT}" =~ ^[1-9][0-9]*$ || ! "${PREPARED_MANIFEST_SHA256}" =~ ^[a-f0-9]{64}$ || "${PREPARED_ARTIFACT_NAME}" != "docker-release-${RELEASE_SHA}-${PREPARED_RUN_ATTEMPT}" ]]; then
|
|
echo "Prepared Docker evidence requires the complete exact producer and manifest tuple." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
- name: Checkout immutable release tag
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag }}
|
|
path: release-source
|
|
fetch-depth: 1
|
|
sparse-checkout: |
|
|
package.json
|
|
Dockerfile
|
|
sparse-checkout-cone-mode: false
|
|
persist-credentials: false
|
|
- name: Checkout trusted Docker tooling
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ github.workflow_sha }}
|
|
path: workflow-source
|
|
fetch-depth: 1
|
|
sparse-checkout: scripts
|
|
persist-credentials: false
|
|
- name: Setup supported Node runtime
|
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
|
with:
|
|
node-version: "24.21.0"
|
|
package-manager-cache: false
|
|
|
|
- name: Verify tag, SHA, and package identity agree
|
|
id: identity
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
RELEASE_SHA: ${{ inputs.release_sha }}
|
|
IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }}
|
|
run: |
|
|
set -euo pipefail
|
|
test "$(git -C release-source rev-parse "refs/tags/${RELEASE_TAG}^{commit}")" = "${RELEASE_SHA}"
|
|
test "$(git -C release-source rev-parse HEAD)" = "${RELEASE_SHA}"
|
|
node --input-type=module <<'NODE'
|
|
import { appendFileSync, readFileSync } from 'node:fs';
|
|
import { validateDockerReleaseIdentity } from './workflow-source/scripts/docker-release-artifacts.mjs';
|
|
const env = process.env;
|
|
const policy = validateDockerReleaseIdentity({ tag: env.RELEASE_TAG, sourceSha: env.RELEASE_SHA, imageTagSuffix: env.IMAGE_TAG_SUFFIX, packageVersion: JSON.parse(readFileSync('release-source/package.json', 'utf8')).version });
|
|
const includeBrowser = /^ARG OPENCLAW_INSTALL_BROWSER/m.test(readFileSync('release-source/Dockerfile', 'utf8'));
|
|
appendFileSync(env.GITHUB_OUTPUT, `version=${policy.version}\ninclude_browser=${includeBrowser}\n`);
|
|
NODE
|
|
|
|
prepare:
|
|
name: Prepare immutable Docker images
|
|
needs: validate_release_identity
|
|
if: ${{ inputs.prepared_run_id == '' }}
|
|
uses: ./.github/workflows/docker-release-prepare.yml
|
|
with:
|
|
tag: ${{ inputs.tag }}
|
|
release_sha: ${{ inputs.release_sha }}
|
|
image_tag_suffix: ${{ inputs.image_tag_suffix }}
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
|
|
approve:
|
|
name: Approve Docker images for ${{ inputs.tag }}${{ inputs.image_tag_suffix }}
|
|
needs: [validate_release_identity, prepare]
|
|
if: ${{ !cancelled() && needs.validate_release_identity.result == 'success' && (needs.prepare.result == 'success' || needs.prepare.result == 'skipped') }}
|
|
# An approval wait must not hold the global registry writer lock.
|
|
# Docker Hub credentials remain required workflow_call secrets for publish.
|
|
runs-on: ubuntu-24.04
|
|
environment: docker-release
|
|
permissions: {}
|
|
steps:
|
|
- name: Record Docker publication approval
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
RELEASE_SHA: ${{ inputs.release_sha }}
|
|
IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }}
|
|
PREPARED_MANIFEST_SHA256: ${{ inputs.prepared_manifest_sha256 || needs.prepare.outputs.prepared_manifest_sha256 }}
|
|
run: |
|
|
echo "Approved Docker images for ${RELEASE_TAG}${IMAGE_TAG_SUFFIX}"
|
|
echo "Release SHA: ${RELEASE_SHA}"
|
|
echo "Prepared manifest SHA256: ${PREPARED_MANIFEST_SHA256}"
|
|
|
|
publish:
|
|
name: Publish prepared Docker images
|
|
needs: [validate_release_identity, prepare, approve]
|
|
if: ${{ !cancelled() && needs.validate_release_identity.result == 'success' && (needs.prepare.result == 'success' || needs.prepare.result == 'skipped') && needs.approve.result == 'success' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 45
|
|
# The global lock covers every registry mutation and the alias read/write
|
|
# checks. Preparation never queues behind a previous release's promotion.
|
|
concurrency:
|
|
group: docker-release-publish
|
|
cancel-in-progress: false
|
|
queue: max
|
|
permissions:
|
|
actions: read
|
|
attestations: read
|
|
contents: read
|
|
packages: write
|
|
outputs:
|
|
vcr_source_digests: ${{ steps.promote.outputs.vcr_source_digests }}
|
|
env:
|
|
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
RELEASE_TAG: ${{ inputs.tag }}
|
|
RELEASE_SHA: ${{ inputs.release_sha }}
|
|
IMAGE_TAG_SUFFIX: ${{ inputs.image_tag_suffix }}
|
|
INCLUDE_BROWSER: ${{ needs.validate_release_identity.outputs.include_browser }}
|
|
PREPARED_RUN_ID: ${{ inputs.prepared_run_id || needs.prepare.outputs.prepared_run_id }}
|
|
PREPARED_RUN_ATTEMPT: ${{ inputs.prepared_run_attempt || needs.prepare.outputs.prepared_run_attempt }}
|
|
PREPARED_ARTIFACT_NAME: ${{ inputs.prepared_artifact_name || needs.prepare.outputs.prepared_artifact_name }}
|
|
PREPARED_MANIFEST_SHA256: ${{ inputs.prepared_manifest_sha256 || needs.prepare.outputs.prepared_manifest_sha256 }}
|
|
steps:
|
|
- name: Checkout immutable release source after approval
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag }}
|
|
path: release-source
|
|
fetch-depth: 1
|
|
filter: blob:none
|
|
sparse-checkout: |
|
|
package.json
|
|
Dockerfile
|
|
sparse-checkout-cone-mode: false
|
|
persist-credentials: false
|
|
- name: Fetch focused release history
|
|
if: ${{ inputs.focused_release_evidence_run_id != '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
# Historical focused evidence reconstructs candidate trees and ancestry.
|
|
git -C release-source fetch --no-tags --filter=blob:none --unshallow origin \
|
|
"refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
|
|
- name: Checkout trusted Docker tooling
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ github.workflow_sha }}
|
|
path: workflow-source
|
|
fetch-depth: 1
|
|
sparse-checkout: scripts
|
|
persist-credentials: false
|
|
- name: Revalidate immutable source after approval
|
|
run: |
|
|
set -euo pipefail
|
|
test "$(git -C release-source rev-parse "refs/tags/${RELEASE_TAG}^{commit}")" = "${RELEASE_SHA}"
|
|
test "$(git -C release-source rev-parse HEAD)" = "${RELEASE_SHA}"
|
|
- name: Revalidate focused evidence producer after Docker approval
|
|
if: ${{ inputs.focused_release_evidence_run_id != '' }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
FOCUSED_RELEASE_EVIDENCE_RUN_ID: ${{ inputs.focused_release_evidence_run_id }}
|
|
FOCUSED_RELEASE_EVIDENCE_RUN_ATTEMPT: ${{ inputs.focused_release_evidence_run_attempt }}
|
|
PRODUCER_WORKFLOW_FULL_REF: ${{ inputs.focused_release_evidence_workflow_full_ref }}
|
|
PRODUCER_WORKFLOW_SHA: ${{ inputs.focused_release_evidence_workflow_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ ! "${FOCUSED_RELEASE_EVIDENCE_RUN_ID}" =~ ^[1-9][0-9]*$ ||
|
|
! "${FOCUSED_RELEASE_EVIDENCE_RUN_ATTEMPT}" =~ ^[1-9][0-9]*$ ||
|
|
! "${PRODUCER_WORKFLOW_SHA}" =~ ^[a-f0-9]{40}$ ||
|
|
! "${PRODUCER_WORKFLOW_FULL_REF}" =~ ^refs/tags/release-publish/([a-f0-9]{12})-[1-9][0-9]*$ ||
|
|
"${PRODUCER_WORKFLOW_SHA:0:12}" != "${BASH_REMATCH[1]}" ]]; then
|
|
echo "Focused evidence producer identity is missing or invalid after Docker approval." >&2
|
|
exit 1
|
|
fi
|
|
producer_ref="${PRODUCER_WORKFLOW_FULL_REF#refs/tags/}"
|
|
run_json="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${FOCUSED_RELEASE_EVIDENCE_RUN_ID}")"
|
|
if ! jq -e \
|
|
--arg run_id "${FOCUSED_RELEASE_EVIDENCE_RUN_ID}" \
|
|
--arg attempt "${FOCUSED_RELEASE_EVIDENCE_RUN_ATTEMPT}" \
|
|
--arg producer_ref "${producer_ref}" \
|
|
--arg producer_sha "${PRODUCER_WORKFLOW_SHA}" \
|
|
'.id == ($run_id | tonumber) and .run_attempt == ($attempt | tonumber) and
|
|
.name == "Authorized Beta Focused Validation" and
|
|
.path == ".github/workflows/authorized-beta-focused-validation.yml" and
|
|
.event == "workflow_dispatch" and .status == "completed" and .conclusion == "success" and
|
|
.head_branch == $producer_ref and .head_sha == $producer_sha' \
|
|
<<<"${run_json}" >/dev/null; then
|
|
echo "Focused evidence producer changed after Docker approval." >&2
|
|
exit 1
|
|
fi
|
|
remote_producer_sha="$(
|
|
gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${producer_ref}" \
|
|
--jq '.object | select(.type == "commit") | .sha'
|
|
)"
|
|
if [[ "${remote_producer_sha}" != "${PRODUCER_WORKFLOW_SHA}" ]]; then
|
|
echo "Focused evidence producer tag is missing, moved, or annotated after Docker approval." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Download focused release evidence after Docker approval
|
|
if: ${{ inputs.focused_release_evidence_run_id != '' }}
|
|
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
with:
|
|
name: authorized-beta-focused-v1-${{ inputs.focused_release_evidence_run_id }}-${{ inputs.focused_release_evidence_run_attempt }}
|
|
path: ${{ runner.temp }}/authorized-beta-focused-evidence
|
|
repository: ${{ github.repository }}
|
|
run-id: ${{ inputs.focused_release_evidence_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Setup supported Node runtime
|
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
|
with:
|
|
node-version: "24.21.0"
|
|
package-manager-cache: false
|
|
|
|
- name: Verify focused release evidence after Docker approval
|
|
if: ${{ inputs.focused_release_evidence_run_id != '' }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
FOCUSED_RELEASE_EVIDENCE_RUN_ID: ${{ inputs.focused_release_evidence_run_id }}
|
|
FOCUSED_RELEASE_EVIDENCE_RUN_ATTEMPT: ${{ inputs.focused_release_evidence_run_attempt }}
|
|
PRODUCER_WORKFLOW_FULL_REF: ${{ inputs.focused_release_evidence_workflow_full_ref }}
|
|
PRODUCER_WORKFLOW_SHA: ${{ inputs.focused_release_evidence_workflow_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
evidence="${RUNNER_TEMP}/authorized-beta-focused-evidence/evidence.json"
|
|
gh attestation verify "${evidence}" \
|
|
--repo "${GITHUB_REPOSITORY}" \
|
|
--signer-workflow "${GITHUB_REPOSITORY}/.github/workflows/authorized-beta-focused-validation.yml" \
|
|
--signer-digest "${PRODUCER_WORKFLOW_SHA}" \
|
|
--source-digest "${PRODUCER_WORKFLOW_SHA}" \
|
|
--source-ref "${PRODUCER_WORKFLOW_FULL_REF}" \
|
|
--deny-self-hosted-runners
|
|
node workflow-source/scripts/verify-authorized-beta-focused-candidate.mjs \
|
|
--repository-root release-source \
|
|
--validator workflow-source/scripts/validate-authorized-beta-focused-evidence.mts \
|
|
--policy workflow-source/scripts/authorized-beta-focused-policy.json \
|
|
--artifact "${evidence}" \
|
|
--producer-run-id "${FOCUSED_RELEASE_EVIDENCE_RUN_ID}" \
|
|
--producer-run-attempt "${FOCUSED_RELEASE_EVIDENCE_RUN_ATTEMPT}" \
|
|
--producer-workflow-full-ref "${PRODUCER_WORKFLOW_FULL_REF}" \
|
|
--producer-workflow-sha "${PRODUCER_WORKFLOW_SHA}"
|
|
|
|
- name: Download immutable full release qualification
|
|
if: ${{ inputs.full_release_validation_run_id != '' }}
|
|
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
with:
|
|
name: full-release-validation-${{ inputs.full_release_validation_run_id }}-${{ inputs.full_release_validation_run_attempt }}
|
|
path: ${{ runner.temp }}/docker-qualification
|
|
repository: ${{ github.repository }}
|
|
run-id: ${{ inputs.full_release_validation_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Download prepared Docker manifest
|
|
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
with:
|
|
name: ${{ env.PREPARED_ARTIFACT_NAME }}
|
|
path: ${{ runner.temp }}/docker-release
|
|
repository: ${{ github.repository }}
|
|
run-id: ${{ env.PREPARED_RUN_ID }}
|
|
github-token: ${{ github.token }}
|
|
- name: Verify exact prepared producer and payload identities
|
|
id: prepared
|
|
run: |
|
|
set -euo pipefail
|
|
qualification_args=()
|
|
if [[ -n "${FULL_RELEASE_VALIDATION_RUN_ID}" ]]; then
|
|
qualification_args+=(--full-release-manifest "${RUNNER_TEMP}/docker-qualification/full-release-validation-manifest.json")
|
|
fi
|
|
node workflow-source/scripts/docker-release-artifacts.mjs verify "${qualification_args[@]}" \
|
|
--manifest "${RUNNER_TEMP}/docker-release/manifest.json" \
|
|
--manifest-sha256 "${PREPARED_MANIFEST_SHA256}" \
|
|
--artifact-name "${PREPARED_ARTIFACT_NAME}" \
|
|
--run-id "${PREPARED_RUN_ID}" --run-attempt "${PREPARED_RUN_ATTEMPT}"
|
|
- name: Download immutable OCI payloads
|
|
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
with:
|
|
artifact-ids: ${{ steps.prepared.outputs.artifact_ids }}
|
|
path: ${{ runner.temp }}/docker-release/payloads
|
|
repository: ${{ github.repository }}
|
|
run-id: ${{ env.PREPARED_RUN_ID }}
|
|
github-token: ${{ github.token }}
|
|
- name: Install reviewed OCI transport
|
|
run: |
|
|
set -euo pipefail
|
|
sudo apt-get update
|
|
sudo apt-get install --no-install-recommends -y skopeo
|
|
skopeo --version | grep -Fx 'skopeo version 1.13.3'
|
|
dpkg-query --show --showformat='${Package} ${Version}\n' skopeo
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
- name: Validate Docker Hub publish credentials
|
|
env:
|
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then
|
|
echo "Docker Hub publishing requires DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets." >&2
|
|
exit 1
|
|
fi
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.repository_owner }}
|
|
password: ${{ github.token }}
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
registry: docker.io
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
- name: Copy exact OCI digests, verify attestations, and promote aliases
|
|
id: promote
|
|
run: |
|
|
set -euo pipefail
|
|
qualification_args=()
|
|
if [[ -n "${FULL_RELEASE_VALIDATION_RUN_ID}" ]]; then
|
|
qualification_args+=(--full-release-manifest "${RUNNER_TEMP}/docker-qualification/full-release-validation-manifest.json")
|
|
fi
|
|
node workflow-source/scripts/docker-release-artifacts.mjs publish "${qualification_args[@]}" \
|
|
--manifest "${RUNNER_TEMP}/docker-release/manifest.json" \
|
|
--manifest-sha256 "${PREPARED_MANIFEST_SHA256}" \
|
|
--artifact-name "${PREPARED_ARTIFACT_NAME}" \
|
|
--run-id "${PREPARED_RUN_ID}" --run-attempt "${PREPARED_RUN_ATTEMPT}" \
|
|
--directory "${RUNNER_TEMP}/docker-release/payloads"
|