Files
dsh/upstream/.github/workflows/docker.yaml
T

332 lines
14 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Publish Container Images
on:
workflow_run:
workflows:
- Publish Supported Platform Target
types:
- completed
workflow_dispatch:
inputs:
source_commit:
description: Source commit to build
required: true
default: main
type: string
channel_commit:
description: release-channel ref to search for the matching signed target
required: false
default: release-channel
type: string
concurrency:
group: production-container-images
cancel-in-progress: false
env:
DOCKERHUB_IMAGE: szcq/deepseek-harness
GHCR_IMAGE: ghcr.io/${{ github.repository }}
jobs:
build:
name: Verify, test, and publish images
if: >-
(github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main') ||
github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 90
environment: production-image
permissions:
contents: read
packages: write
steps:
- name: Checkout reviewed source
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || inputs.source_commit }}
path: source
- name: Checkout signed channel history
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.channel_commit || 'release-channel' }}
fetch-depth: 0
path: channel
- name: Resolve immutable signed channel state
id: channel
run: |
source_commit="$(git -C source rev-parse HEAD)"
channel_commit=
while IFS= read -r candidate; do
candidate_source="$(git -C channel show "${candidate}:channel.json" | jq -er .sourceCommit)"
if test "$candidate_source" = "$source_commit"; then
channel_commit="$candidate"
break
fi
done < <(git -C channel log --format=%H -- channel.json)
if test -z "$channel_commit"; then
echo "No signed release-channel target matches source commit $source_commit" >&2
exit 1
fi
git -C channel checkout --detach "$channel_commit"
{
printf 'commit=%s\n' "$channel_commit"
printf 'source_commit=%s\n' "$source_commit"
} >> "$GITHUB_OUTPUT"
# shellcheck disable=SC2016
printf 'Using signed channel commit `%s` for source commit `%s`.\n' \
"$channel_commit" "$source_commit" >> "$GITHUB_STEP_SUMMARY"
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: |
source/container/control-plane/services/management/package-lock.json
source/container/environment/resources/plugins/platform-management/package/package-lock.json
- name: Install Management runtime dependencies
working-directory: source
run: |
npm ci --omit=dev --ignore-scripts --no-audit --no-fund --prefix container/control-plane/services/management
npm ci --omit=dev --ignore-scripts --no-audit --no-fund --legacy-peer-deps --prefix container/environment/resources/plugins/platform-management/package
- name: Verify gateway and Compose configuration
working-directory: source
run: |
npm test --prefix container/control-plane/services/gateway
npm test --prefix container/platform
node container/test/compose-config.mjs
sh -n container/test/container-smoke.sh
sh -n container/test/devtools-smoke.sh
- name: Verify signed Supported Target
id: signed-target
working-directory: source
env:
RECOVERY_ROOT_PUBLIC_KEY: ${{ secrets.DSH_RECOVERY_ROOT_PUBLIC_KEY }}
run: |
test -n "$RECOVERY_ROOT_PUBLIC_KEY"
source_commit="$(git rev-parse HEAD)"
test "$(jq -er .sourceCommit ../channel/channel.json)" = "$source_commit"
sequence="$(jq -er .targetSequence ../channel/stable.json)"
test "$(jq -er .targetSequence ../channel/channel.json)" = "$sequence"
release_dir="../channel/targets/$sequence"
test -d "$release_dir"
for name in stable.json stable.sig.json keyring.json keyring.sig.json; do
cmp "../channel/$name" "$release_dir/$name"
done
image_input=container/platform/image-input
mkdir -p "$image_input/release"
cp -a "$release_dir/." "$image_input/release/"
printf '%s\n' "$RECOVERY_ROOT_PUBLIC_KEY" > "$image_input/recovery-root.spki.base64"
cp release/supported-target.json "$image_input/supported-target.json"
cp container/environment/definition.json "$image_input/environment-definition.json"
version="$(jq -er '.latestSupportedDsh' release/supported-target.json)"
npm_input="$RUNNER_TEMP/image-npm-input"
mkdir -p "$npm_input"
npm pack "@deepseek-ai/dsh@${version}" --pack-destination "$npm_input" >/dev/null
tarball="$(find "$npm_input" -maxdepth 1 -type f -name '*.tgz' -print -quit)"
test -n "$tarball"
cp "$tarball" "$image_input/dsh.tgz"
verified="$(node container/platform/tools/verify-image-release.mjs \
"$image_input/release" "$image_input/recovery-root.spki.base64" "$image_input/dsh.tgz" \
"$image_input/supported-target.json" "$image_input/environment-definition.json")"
test "$(jq -er .dshVersion <<<"$verified")" = "$version"
test "$(jq -er .targetSequence <<<"$verified")" = "$sequence"
environment_version="$(jq -er .environmentVersion <<<"$verified")"
test "$environment_version" = "$(jq -er .version container/environment/definition.json)"
{
printf 'version=%s\n' "$version"
printf 'environment_version=%s\n' "$environment_version"
printf 'sequence=%s\n' "$sequence"
} >> "$GITHUB_OUTPUT"
cp "$image_input/recovery-root.spki.base64" container/platform/seed/trust/recovery-root.spki.base64
cp "$release_dir/keyring.json" container/platform/seed/trust/keyring.json
cp "$release_dir/keyring.sig.json" container/platform/seed/trust/keyring.sig.json
rm container/platform/seed/trust/DEVELOPMENT_FIXTURE
test ! -e container/platform/seed/trust/DEVELOPMENT_FIXTURE
printf 'Building signed DSH %s with Environment %s (sequence %s).\n' \
"$version" "$environment_version" "$sequence" >> "$GITHUB_STEP_SUMMARY"
- name: Generate registry tags
id: tags
env:
DSH_VERSION: ${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION: ${{ steps.signed-target.outputs.environment_version }}
run: |
[[ "$ENVIRONMENT_VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
{
echo 'standard<<EOF'
echo "${DOCKERHUB_IMAGE}:${DSH_VERSION}"
echo "${GHCR_IMAGE}:latest"
echo "${GHCR_IMAGE}:${ENVIRONMENT_VERSION}"
echo "${GHCR_IMAGE}:${major}.${minor}"
echo "${GHCR_IMAGE}:${major}"
echo "${GHCR_IMAGE}:dsh-${DSH_VERSION}"
echo 'EOF'
echo 'devtools<<EOF'
echo "${DOCKERHUB_IMAGE}:${DSH_VERSION}-devtools"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build standard smoke-test image
uses: docker/build-push-action@v7
with:
context: ./source
file: ./source/Dockerfile
platforms: linux/amd64
load: true
provenance: false
build-args: |
SIGNED_IMAGE_INPUT=true
DSH_VERSION=${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION=${{ steps.signed-target.outputs.environment_version }}
TARGET_SEQUENCE=${{ steps.signed-target.outputs.sequence }}
PLATFORM_REVISION=${{ steps.channel.outputs.source_commit }}
tags: dsh-gateway-smoke:${{ github.run_id }}
cache-from: type=gha,scope=standard
cache-to: type=gha,mode=max,scope=standard
- name: Run standard container smoke checks
working-directory: source
run: container/test/container-smoke.sh "dsh-gateway-smoke:${{ github.run_id }}"
- name: Build devtools smoke-test image
uses: docker/build-push-action@v7
with:
context: ./source
file: ./source/Dockerfile
platforms: linux/amd64
load: true
provenance: false
build-args: |
SIGNED_IMAGE_INPUT=true
DSH_VERSION=${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION=${{ steps.signed-target.outputs.environment_version }}
TARGET_SEQUENCE=${{ steps.signed-target.outputs.sequence }}
PLATFORM_REVISION=${{ steps.channel.outputs.source_commit }}
INSTALL_DEVTOOLS=true
tags: dsh-gateway-devtools-smoke:${{ github.run_id }}
cache-from: type=gha,scope=devtools
cache-to: type=gha,mode=max,scope=devtools
- name: Run devtools smoke checks
working-directory: source
run: container/test/devtools-smoke.sh "dsh-gateway-devtools-smoke:${{ github.run_id }}"
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: szcq
password: ${{ secrets.DOCKER_TOKEN }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Push versioned devtools image to Docker Hub
uses: docker/build-push-action@v7
with:
context: ./source
file: ./source/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
provenance: false
build-args: |
SIGNED_IMAGE_INPUT=true
DSH_VERSION=${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION=${{ steps.signed-target.outputs.environment_version }}
TARGET_SEQUENCE=${{ steps.signed-target.outputs.sequence }}
PLATFORM_REVISION=${{ steps.channel.outputs.source_commit }}
INSTALL_DEVTOOLS=true
tags: ${{ steps.tags.outputs.devtools }}
cache-from: type=gha,scope=devtools
cache-to: type=gha,mode=max,scope=devtools
- name: Push versioned standard image to Docker Hub and GHCR
uses: docker/build-push-action@v7
with:
context: ./source
file: ./source/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
provenance: false
build-args: |
SIGNED_IMAGE_INPUT=true
DSH_VERSION=${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION=${{ steps.signed-target.outputs.environment_version }}
TARGET_SEQUENCE=${{ steps.signed-target.outputs.sequence }}
PLATFORM_REVISION=${{ steps.channel.outputs.source_commit }}
tags: ${{ steps.tags.outputs.standard }}
cache-from: type=gha,scope=standard
cache-to: type=gha,mode=max,scope=standard
- name: Promote Docker Hub rolling tags
env:
DSH_VERSION: ${{ steps.signed-target.outputs.version }}
run: |
docker buildx imagetools create \
--tag "${DOCKERHUB_IMAGE}:latest-devtools" \
"${DOCKERHUB_IMAGE}:${DSH_VERSION}-devtools"
docker buildx imagetools create \
--tag "${DOCKERHUB_IMAGE}:latest" \
"${DOCKERHUB_IMAGE}:${DSH_VERSION}"
- name: Verify published registry manifests
env:
DSH_VERSION: ${{ steps.signed-target.outputs.version }}
ENVIRONMENT_VERSION: ${{ steps.signed-target.outputs.environment_version }}
run: |
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${DSH_VERSION}"
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${DSH_VERSION}-devtools"
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:latest"
docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:latest-devtools"
docker buildx imagetools inspect "${GHCR_IMAGE}:${ENVIRONMENT_VERSION}"
docker buildx imagetools inspect "${GHCR_IMAGE}:dsh-${DSH_VERSION}"
outputs:
dsh_version: ${{ steps.signed-target.outputs.version }}
environment_version: ${{ steps.signed-target.outputs.environment_version }}
sequence: ${{ steps.signed-target.outputs.sequence }}
notify-result:
name: Notify container image publication result
needs: build
if: >-
always() &&
(needs.build.result == 'success' || needs.build.result == 'failure')
uses: yjrszcq/github-workflows/.github/workflows/gotify-notify.yml@c4c7fe9e17854cd4962913ac2792513eab0be988
with:
title: >-
${{
needs.build.result == 'success' &&
format('DSH {0} 镜像已发布', needs.build.outputs.dsh_version) ||
'DSH 镜像发布失败'
}}
message: >-
${{
needs.build.result == 'success' &&
format('DSH {0} 与 Environment {1} 的标准镜像已同步到 Docker Hub 和 GHCR,Devtools 镜像已发布到 Docker Hub;签名目标序列为 {2}。', needs.build.outputs.dsh_version, needs.build.outputs.environment_version, needs.build.outputs.sequence) ||
format('Docker Hub 或 GHCR 镜像的构建、测试、推送或验证失败。请查看 GitHub Actions:{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id)
}}
priority: ${{ needs.build.result == 'failure' && 8 || 7 }}
secrets:
gotify_url: ${{ secrets.GOTIFY_URL }}
gotify_token: ${{ secrets.GOTIFY_TOKEN }}