diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml index d98229d..ba45f4d 100644 --- a/.gitea/workflows/docker.yml +++ b/.gitea/workflows/docker.yml @@ -31,3 +31,34 @@ jobs: - name: Build and run container smoke test run: ./tests/container-smoke.sh + + - name: Log in to Gitea Container Registry + if: gitea.event_name != 'pull_request' + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: printf '%s' "$REGISTRY_TOKEN" | docker login git.ipao.vip --username "${{ gitea.actor }}" --password-stdin + + - name: Publish tested image + if: gitea.event_name != 'pull_request' + env: + IMAGE_NAME: git.ipao.vip/rogee/mohomo-docker + SHA_TAG: sha-${{ gitea.sha }} + run: | + docker tag mohomo-docker:smoke "$IMAGE_NAME:latest" + docker tag mohomo-docker:smoke "$IMAGE_NAME:$SHA_TAG" + docker push "$IMAGE_NAME:latest" + docker push "$IMAGE_NAME:$SHA_TAG" + + - name: Link package to repository + if: gitea.event_name != 'pull_request' + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + package_api=https://git.ipao.vip/api/v1/packages/rogee/container/mohomo-docker + linked_repo="$(curl --fail --silent --show-error --header "Authorization: token $REGISTRY_TOKEN" "$package_api/-/latest" | jq -r '.repository.full_name // empty')" + if [ "$linked_repo" != rogee/mohomo-docker ]; then + curl --fail --silent --show-error --request POST \ + --header "Authorization: token $REGISTRY_TOKEN" \ + "$package_api/-/link/mohomo-docker" + fi + test "$(curl --fail --silent --show-error --header "Authorization: token $REGISTRY_TOKEN" "$package_api/-/latest" | jq -r '.repository.full_name // empty')" = rogee/mohomo-docker diff --git a/README.md b/README.md index 6bafb0b..693302b 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,14 @@ The image pins and SHA-256 verifies Mihomo `v1.19.30`, MetaCubeXD `v1.273.0`, an The container runs as an unprivileged user with all capabilities dropped, a read-only root filesystem, and only `/data` writable. Do not publish a derivative image without respecting the upstream Mihomo, MetaCubeXD, and ACL4SSR licenses. +## CI image publishing + +GitHub Actions publishes to `ghcr.io/`. Gitea Actions publishes the same tested image to `git.ipao.vip/rogee/mohomo-docker` with `latest` and `sha-` tags. The workflows are independent and do not share registry credentials or provider contexts. + +Before enabling Gitea publishing, add a repository Actions secret named `REGISTRY_TOKEN`. It must be a Gitea token whose owner can push packages for `rogee` and link the resulting container package to `rogee/mohomo-docker`. Keep the token out of files and logs, and rotate it in Gitea without changing the workflow. + +Gitea publishes only after tests and the container smoke test pass on a `main` push or manual workflow dispatch. Pull requests run those validations but skip secret use, registry login, image push, and package linking. A failed link check leaves the pushed image intact; fix the token permissions and rerun the workflow to retry the idempotent link step. + ## Local acceptance ```sh diff --git a/tests/workflow-contract.sh b/tests/workflow-contract.sh index d0dd315..a26c7f2 100755 --- a/tests/workflow-contract.sh +++ b/tests/workflow-contract.sh @@ -19,6 +19,12 @@ for workflow in "$github_workflow" "$gitea_workflow"; do grep -F ' workflow_dispatch:' "$workflow" >/dev/null done +gitea_trigger_count=$(awk '/^on:/ { in_on = 1; next } in_on && /^[^ ]/ { exit } in_on && /^ [a-z_]+:/ { count++ } END { print count + 0 }' "$gitea_workflow") +if [ "$gitea_trigger_count" -ne 3 ] || [ "$(grep -Fc ' - main' "$gitea_workflow")" -ne 2 ]; then + echo "Gitea workflow must only run for main pushes, main pull requests, and manual dispatches" >&2 + exit 1 +fi + grep -F 'packages: write' "$github_workflow" >/dev/null # Match the GitHub expression literally. # shellcheck disable=SC2016 @@ -33,11 +39,32 @@ grep -F 'push: ${{ github.event_name != '\''pull_request'\'' }}' "$github_workfl grep -F 'run: ./scripts/test.sh' "$gitea_workflow" >/dev/null grep -F 'run: ./tests/container-smoke.sh' "$gitea_workflow" >/dev/null +grep -F 'git.ipao.vip/rogee/mohomo-docker' "$gitea_workflow" >/dev/null +# Match Gitea expressions literally. +# shellcheck disable=SC2016 +grep -F '${{ secrets.REGISTRY_TOKEN }}' "$gitea_workflow" >/dev/null +# shellcheck disable=SC2016 +grep -F 'sha-${{ gitea.sha }}' "$gitea_workflow" >/dev/null +grep -F 'docker login git.ipao.vip' "$gitea_workflow" >/dev/null +grep -F 'docker push "$IMAGE_NAME:latest"' "$gitea_workflow" >/dev/null +grep -F 'api/v1/packages/rogee/container/mohomo-docker' "$gitea_workflow" >/dev/null +grep -F '/link/mohomo-docker' "$gitea_workflow" >/dev/null + +publish_condition="if: gitea.event_name != 'pull_request'" +if [ "$(grep -Fc "$publish_condition" "$gitea_workflow")" -ne 3 ]; then + echo "every Gitea publishing step must be disabled for pull requests" >&2 + exit 1 +fi if grep -Ei 'ghcr\.io|github\.|GITHUB_TOKEN|packages: write|docker/(login|build-push)-action' "$gitea_workflow" >/dev/null; then echo "Gitea workflow must not depend on GitHub publishing" >&2 exit 1 fi +if grep -Ei 'gitea\.|REGISTRY_TOKEN|git\.ipao\.vip' "$github_workflow" >/dev/null; then + echo "GitHub workflow must not depend on Gitea publishing" >&2 + exit 1 +fi + if grep -Ei 'arm64|setup-qemu' "$github_workflow" >/dev/null; then echo "workflow must build linux/amd64 only and must not configure QEMU" >&2 exit 1