Run CI and image publishing on the self-hosted GitLab
Ports ci.yml and publish.yml after the GitHub account was suspended and ghcr.io/coffey-labs/ihasvpn went dark with it. The deployment on Web_Host was still pulling that tag, and the only surviving copy was the image already on the host -- amd64 only. This rebuilds the multi-arch tag. The workflow built each platform on a native runner; there is one amd64 runner here, so arm64 goes through QEMU. Slower, and tag-driven for that reason, but shipping amd64 only is exactly what the suspension already cost us once. The Actions workflows stay in the tree as the reference.
This commit is contained in:
@@ -0,0 +1,99 @@
|
|||||||
|
# CI on the self-hosted GitLab, ported from .github/workflows/ci.yml and
|
||||||
|
# publish.yml when the GitHub account was suspended on 2026-09-20. The Actions
|
||||||
|
# files stay in the tree: they are the reference this was written from and work
|
||||||
|
# unchanged if the appeal succeeds.
|
||||||
|
#
|
||||||
|
# This one mattered more than most. ghcr.io/coffey-labs/ihasvpn went dark with
|
||||||
|
# the account while the deployment on Web_Host was still pulling from it, and
|
||||||
|
# the only surviving copy was the image already on that host -- amd64 only,
|
||||||
|
# because that is the platform it runs. The multi-arch tag is rebuilt here.
|
||||||
|
#
|
||||||
|
# Images are pinned by digest, with the tag in the trailing comment: the
|
||||||
|
# replacement for the workflow's SHA-pinned actions, since GitLab has no
|
||||||
|
# action allowlist.
|
||||||
|
|
||||||
|
stages: [build, check, publish]
|
||||||
|
|
||||||
|
variables:
|
||||||
|
IMAGE: $CI_REGISTRY_IMAGE
|
||||||
|
|
||||||
|
default:
|
||||||
|
interruptible: true
|
||||||
|
|
||||||
|
.on-change: &on-change
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||||
|
|
||||||
|
# The Go binary embeds the built web assets, so the frontend build comes first
|
||||||
|
# and hands its output to the Go job as an artifact.
|
||||||
|
web:
|
||||||
|
stage: build
|
||||||
|
image: node:26-bookworm-slim@sha256:582460f614631b59b824ac6020533b9bf339c7fdf3a6d7db31abb6b4065f0212 # 26-bookworm-slim
|
||||||
|
variables:
|
||||||
|
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm"
|
||||||
|
cache:
|
||||||
|
key:
|
||||||
|
files: [web/package-lock.json]
|
||||||
|
paths: [.npm/]
|
||||||
|
script:
|
||||||
|
- cd web
|
||||||
|
- npm ci --ignore-scripts --no-audit --no-fund
|
||||||
|
- npm run build
|
||||||
|
artifacts:
|
||||||
|
paths: [web/dist/]
|
||||||
|
expire_in: 1 week
|
||||||
|
<<: *on-change
|
||||||
|
|
||||||
|
go:
|
||||||
|
stage: check
|
||||||
|
image: golang:1.27-bookworm@sha256:69a7b9788769bec032d238959b61854e9ae87f57be9029ec04e9885fabf99195 # 1.27-bookworm
|
||||||
|
needs: [web]
|
||||||
|
cache:
|
||||||
|
key: go-mod
|
||||||
|
paths: [.gocache/]
|
||||||
|
variables:
|
||||||
|
GOPATH: "$CI_PROJECT_DIR/.gocache"
|
||||||
|
script:
|
||||||
|
- go vet ./...
|
||||||
|
- go test -count=1 ./...
|
||||||
|
# Left as `go run ...@latest`, as the workflow had it: a vulnerability
|
||||||
|
# check wants today's database, not a pinned copy of last month's.
|
||||||
|
- go run golang.org/x/vuln/cmd/govulncheck@latest ./...
|
||||||
|
<<: *on-change
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
stage: check
|
||||||
|
image: docker:28-cli@sha256:625d9431a9f54c5a2bc90f24f0e1c3d55b1349fd857dd85035f98c2c9acbdd4d # 28-cli
|
||||||
|
needs: [web]
|
||||||
|
script:
|
||||||
|
- docker build -t ihasvpn:ci-$CI_COMMIT_SHORT_SHA .
|
||||||
|
- docker image rm ihasvpn:ci-$CI_COMMIT_SHORT_SHA
|
||||||
|
<<: *on-change
|
||||||
|
|
||||||
|
# The workflow built each platform on its own native runner and joined the two
|
||||||
|
# digests into one tag. There is a single amd64 runner here, so arm64 goes
|
||||||
|
# through QEMU instead -- slower, but this is tag-driven and the alternative is
|
||||||
|
# shipping amd64 only, which is what the account suspension already cost us
|
||||||
|
# once. TrueNAS and Unraid users pull arm64.
|
||||||
|
publish:
|
||||||
|
stage: publish
|
||||||
|
image: docker:28-cli@sha256:625d9431a9f54c5a2bc90f24f0e1c3d55b1349fd857dd85035f98c2c9acbdd4d # 28-cli
|
||||||
|
needs: [web, go]
|
||||||
|
before_script:
|
||||||
|
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
|
||||||
|
- docker run --privileged --rm tonistiigi/binfmt --install arm64
|
||||||
|
- docker buildx create --use --name ci-builder --driver docker-container || docker buildx use ci-builder
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--build-arg IHASVPN_VERSION="$CI_COMMIT_TAG" \
|
||||||
|
--provenance=false --sbom=false \
|
||||||
|
--tag "$IMAGE:$CI_COMMIT_TAG" \
|
||||||
|
--tag "$IMAGE:latest" \
|
||||||
|
--push .
|
||||||
|
after_script:
|
||||||
|
- docker logout "$CI_REGISTRY" || true
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_TAG
|
||||||
Reference in New Issue
Block a user