Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/actions/test-docker-image/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Test Docker image
description: Verify a loaded image with its built-in healthcheck and real image inference

inputs:
image:
description: Locally loaded Docker image to verify
required: true

outputs:
image-id:
description: Immutable ID of the image used by the verified container
value: ${{ steps.image.outputs.id }}

runs:
using: composite
steps:
# The host only runs the HTTP checker. The server and model stay inside Docker.
- uses: pnpm/action-setup@v6.1.0
- uses: actions/setup-node@v7.1.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
shell: bash
- name: Resolve immutable image
id: image
shell: bash
env:
TEST_IMAGE: ${{ inputs.image }}
run: |
image_id=$(timeout --signal=KILL 60s docker image inspect "$TEST_IMAGE" --format '{{.Id}}')
[[ "$image_id" =~ ^sha256:[0-9a-f]{64}$ ]]
echo "id=$image_id" >> "$GITHUB_OUTPUT"
- name: Start built image
shell: bash
env:
TESTED_IMAGE_ID: ${{ steps.image.outputs.id }}
SENSITIVE_DETECTOR_API_KEY: docker-e2e-test-key
run: |
timeout --signal=KILL 60s docker create --name sensitive-detector-e2e \
--publish 127.0.0.1::3009 \
--mount "type=bind,source=$GITHUB_WORKSPACE/config.docker.mjs,target=/config/config.mjs,readonly" \
--env SENSITIVE_DETECTOR_API_KEY \
"$TESTED_IMAGE_ID"
timeout --signal=KILL 60s docker start sensitive-detector-e2e
- name: Check health, authentication and image predictions
shell: bash
env:
SENSITIVE_DETECTOR_API_KEY: docker-e2e-test-key
run: pnpm test:e2e:docker sensitive-detector-e2e
- name: Container diagnostics
if: failure()
shell: bash
run: |
timeout --signal=KILL 60s docker logs sensitive-detector-e2e || true
timeout --signal=KILL 60s docker inspect sensitive-detector-e2e || true
- name: Remove test container
if: always()
shell: bash
run: timeout --signal=KILL 60s docker rm --force sensitive-detector-e2e
32 changes: 4 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,8 @@ jobs:
runner: ubuntu-24.04-arm
env:
TEST_IMAGE: sensitive-detector:e2e
TEST_CONTAINER: sensitive-detector-e2e
SENSITIVE_DETECTOR_API_KEY: docker-e2e-test-key
steps:
- uses: actions/checkout@v7.0.1
# The host only runs the HTTP checker. Build the server inside Docker.
- uses: pnpm/action-setup@v6.1.0
- uses: actions/setup-node@v7.1.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: docker/setup-buildx-action@v4
- name: Build and load image
uses: docker/build-push-action@v7
Expand All @@ -70,22 +61,7 @@ jobs:
tags: ${{ env.TEST_IMAGE }}
cache-from: type=gha,scope=docker-e2e-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=docker-e2e-${{ matrix.arch }}
- name: Start built image
run: |
timeout --signal=KILL 60s docker create --name "$TEST_CONTAINER" \
--publish 127.0.0.1::3009 \
--mount "type=bind,source=$GITHUB_WORKSPACE/config.docker.mjs,target=/config/config.mjs,readonly" \
--env SENSITIVE_DETECTOR_API_KEY \
"$TEST_IMAGE"
timeout --signal=KILL 60s docker start "$TEST_CONTAINER"
- name: Check health, authentication and image predictions
run: pnpm test:e2e:docker "$TEST_CONTAINER"
- name: Container diagnostics
if: failure()
run: |
timeout --signal=KILL 60s docker logs "$TEST_CONTAINER" || true
timeout --signal=KILL 60s docker inspect "$TEST_CONTAINER" || true
- name: Remove test container
if: always()
run: |
timeout --signal=KILL 60s docker rm --force "$TEST_CONTAINER"
- name: Verify built image
uses: ./.github/actions/test-docker-image
with:
image: ${{ env.TEST_IMAGE }}
65 changes: 47 additions & 18 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@ env:
jobs:
# see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
build:
name: Build
runs-on: ubuntu-latest
name: Build, verify and push (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
env:
TEST_IMAGE: sensitive-detector:release-test
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
include:
- arch: amd64
platform: linux/amd64
runner: ubuntu-24.04
- arch: arm64
platform: linux/arm64
runner: ubuntu-24.04-arm
if: github.repository == 'misskey-dev/sensitive-detector'
steps:
- name: Prepare
Expand All @@ -34,6 +41,8 @@ jobs:
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v7.0.1
with:
ref: ${{ github.sha }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Docker meta
Expand All @@ -42,28 +51,48 @@ jobs:
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: ${{ env.TAGS }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
id: build
- name: Build and load image
uses: docker/build-push-action@v7
with:
context: .
push: true
load: true
push: false
tags: ${{ env.TEST_IMAGE }}
platforms: ${{ matrix.platform }}
provenance: false
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=docker-release-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=docker-release-${{ matrix.arch }}
- name: Verify built image
id: verify
uses: ./.github/actions/test-docker-image
with:
image: ${{ env.TEST_IMAGE }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Push the verified ID directly: a second build could produce a different image.
- name: Push verified image
id: push
env:
TESTED_IMAGE_ID: ${{ steps.verify.outputs.image-id }}
run: |
publish_ref="$REGISTRY_IMAGE:build-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$PLATFORM_PAIR"
timeout --signal=KILL 60s docker tag "$TESTED_IMAGE_ID" "$publish_ref"
timeout --signal=KILL 600s docker push "$publish_ref"
repo_digest=$(timeout --signal=KILL 60s docker image inspect "$publish_ref" --format '{{json .RepoDigests}}' |
jq -er --arg prefix "$REGISTRY_IMAGE@" \
'map(select(startswith($prefix))) | unique | if length == 1 then .[0] else error("expected one registry digest") end')
digest="${repo_digest#*@}"
[[ "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]
echo "digest=$digest" >> "$GITHUB_OUTPUT"
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
digest="${{ steps.push.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ CIの `Docker (amd64)` / `Docker (arm64)` ジョブは、それぞれ `ubuntu-24
各HTTP通信は本文を含め最大60秒。失敗時はログ・状態を出力し、終了時はコンテナを削除する。
PR、mainへのpush、手動実行が対象で、レジストリへのログイン・pushは行わない。

リリース時も同じDocker検証actionを実行し、成功したコンテナが使用したimage IDを
再ビルドせずGHCRにpushする。amd64・arm64の両方が成功してから、従来のsemverタグの
manifestを公開する。manifestへの受け渡し用に、実行ID・再実行番号・architectureを含む
`build-<run-id>-<attempt>-linux-<arch>`補助タグもGHCRに保持する。

Dockerの検証はローカルでも実行できる(Node.js 22以上、GNU `timeout` と `pnpm install` が必要)。
検証コマンドは既存コンテナを確認するため、呼び出し側で削除を行う。

Expand Down
67 changes: 0 additions & 67 deletions docs/superpowers/plans/2026-11-06-docker-ci.md

This file was deleted.

49 changes: 0 additions & 49 deletions docs/superpowers/plans/2026-11-06-server-e2e.md

This file was deleted.

Loading