Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a44951692c |
@@ -1,64 +0,0 @@
|
||||
name: Docker image (Gitea)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test and build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: false
|
||||
|
||||
- name: Run tests
|
||||
run: ./scripts/test.sh
|
||||
|
||||
- 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
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Docker image (GitHub)
|
||||
name: Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -44,14 +44,14 @@ docker compose ps
|
||||
|
||||
On a fresh volume, bootstrap downloads, normalizes, generates, and validates a candidate with the packaged Mihomo binary before starting Mihomo. This is the cold-start update; a failure exits nonzero without starting an empty configuration.
|
||||
|
||||
On restart, bootstrap validates and starts the cached `last-good` slot, waits for the controller, and then immediately attempts an update. After startup processing finishes—including the cold-start update on a fresh volume or the immediate update on a restart—the hourly timer starts. The first scheduled update therefore runs one hour after that processing completes. Each candidate is written to the inactive generation, validated, and atomically selected before Mihomo reloads it through the native `PUT /configs` API.
|
||||
On restart, bootstrap validates and starts the cached `last-good` slot, waits for the controller, and then immediately attempts an update. Later updates run hourly from container start. Each candidate is written to the inactive generation, validated, and atomically selected before Mihomo reloads it through the native `PUT /configs` API.
|
||||
|
||||
Download, HTTP, YAML, generation, or Mihomo validation failures reject the candidate and keep the running `last-good`. A reload failure restores the prior pointer and reloads the prior configuration. A storage failure, or failure to persist/reload that rollback, stops Mihomo instead of claiming an unsafe recovery; Compose's restart policy then retries startup from whatever valid `last-good` remains.
|
||||
|
||||
Trigger the same update path immediately for tests or operations:
|
||||
|
||||
```sh
|
||||
docker compose kill --signal HUP mihomo
|
||||
docker kill --signal HUP mohomo-docker
|
||||
```
|
||||
|
||||
The `bootstrap candidate` subcommand remains available for an isolated one-shot candidate pipeline check; a running service should use `SIGHUP` so the result is hot-reloaded.
|
||||
@@ -82,14 +82,6 @@ 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/<github.repository>`. Gitea Actions publishes the same tested image to `git.ipao.vip/rogee/mohomo-docker` with `latest` and `sha-<full-commit>` 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
|
||||
|
||||
+14
-60
@@ -1,78 +1,32 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
github_workflow=.github/workflows/docker.yml
|
||||
gitea_workflow=.gitea/workflows/docker.yml
|
||||
|
||||
test -f "$github_workflow" || {
|
||||
echo "missing GHCR workflow: $github_workflow" >&2
|
||||
exit 1
|
||||
}
|
||||
test -f "$gitea_workflow" || {
|
||||
echo "missing Gitea workflow: $gitea_workflow" >&2
|
||||
workflow=.github/workflows/docker.yml
|
||||
test -f "$workflow" || {
|
||||
echo "missing GHCR workflow: $workflow" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
for workflow in "$github_workflow" "$gitea_workflow"; do
|
||||
grep -F ' push:' "$workflow" >/dev/null
|
||||
grep -F ' pull_request:' "$workflow" >/dev/null
|
||||
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
|
||||
grep -F 'packages: write' "$workflow" >/dev/null
|
||||
# Match the GitHub expression literally.
|
||||
# shellcheck disable=SC2016
|
||||
grep -F 'ghcr.io/${{ github.repository }}' "$github_workflow" >/dev/null
|
||||
grep -F 'platforms: linux/amd64' "$github_workflow" >/dev/null
|
||||
grep -F 'needs: test' "$github_workflow" >/dev/null
|
||||
grep -F 'run: ./tests/container-smoke.sh' "$github_workflow" >/dev/null
|
||||
grep -F 'cache-to: type=gha,mode=max,ignore-error=true' "$github_workflow" >/dev/null
|
||||
grep -F 'ghcr.io/${{ github.repository }}' "$workflow" >/dev/null
|
||||
grep -F 'platforms: linux/amd64' "$workflow" >/dev/null
|
||||
grep -F 'needs: test' "$workflow" >/dev/null
|
||||
grep -F 'run: ./tests/container-smoke.sh' "$workflow" >/dev/null
|
||||
grep -F 'cache-to: type=gha,mode=max,ignore-error=true' "$workflow" >/dev/null
|
||||
# Match the GitHub expression literally.
|
||||
# shellcheck disable=SC2016
|
||||
grep -F 'push: ${{ github.event_name != '\''pull_request'\'' }}' "$github_workflow" >/dev/null
|
||||
grep -F 'push: ${{ github.event_name != '\''pull_request'\'' }}' "$workflow" >/dev/null
|
||||
|
||||
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
|
||||
if grep -Ei 'arm64|setup-qemu' "$workflow" >/dev/null; then
|
||||
echo "workflow must build linux/amd64 only and must not configure QEMU" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
uses_count=$(grep -Ehc '^[[:space:]]+uses:' "$github_workflow" "$gitea_workflow" | awk '{ total += $1 } END { print total }')
|
||||
pinned_count=$(grep -Ehc '^[[:space:]]+uses: [^ ]+@[0-9a-f]{40}([[:space:]]|$)' "$github_workflow" "$gitea_workflow" | awk '{ total += $1 } END { print total }')
|
||||
uses_count=$(grep -Ec '^[[:space:]]+uses:' "$workflow")
|
||||
pinned_count=$(grep -Ec '^[[:space:]]+uses: [^ ]+@[0-9a-f]{40}([[:space:]]|$)' "$workflow")
|
||||
if [ "$uses_count" -eq 0 ] || [ "$uses_count" -ne "$pinned_count" ]; then
|
||||
echo "every action must be pinned to a full commit SHA" >&2
|
||||
echo "every GitHub Action must be pinned to a full commit SHA" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user