Release / Plan (reuse the published image?) (push) Successful in 3s
CI / Docker image (build and smoke test) (push) Skipped
CI / Format and clippy (push) Successful in 4m32s
CI / Dependency audit (push) Successful in 11s
CI / Tests (Linux) (push) Successful in 9m15s
Release / ci (push) Successful in 9m18s
Release / Build image (arm64) (push) Failing after 7m7s
Release / Build image (amd64) (push) Failing after 13m53s
Release / Publish tags (push) Skipped
Release / Gitea release (push) Skipped
Acaua is a collective SOC daemon consuming only Zeek log files, not a single-user tool needing local hardware like its siblings. Drop the Tauri desktop shell, installers and self-update entirely; the server and its web dashboard ship as a container, updated by pulling a new image tag. Link against the official prebuilt libduckdb instead of compiling it from source via the bundled feature, cutting image build time from 15+ minutes to about 3. Fix a real bug found along the way: as PID 1 in a container, the daemon ignored SIGTERM and was always killed after the stop timeout; it now shuts down gracefully. Also corrects the Pillar 1 beaconing score: the period estimate had a harmonic alias (a perfectly periodic 4h series resolved to 600s), and the old score formula flagged pure random traffic as suspicious (p95 = 0.839 on Poisson noise). The new formula was validated against 300 samples per scenario. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
164 lines
7.0 KiB
YAML
164 lines
7.0 KiB
YAML
name: Release
|
|
|
|
# Publishes the multi-arch Acauã image (linux/amd64 + linux/arm64) to the Gitea
|
|
# container registry. A merge into main publishes `edge`; a v* tag re-points the
|
|
# image already built for the same inputs to X.Y.Z, X.Y and latest (no rebuild)
|
|
# and creates the Gitea Release. Needs the secret REGISTRY_TOKEN (Gitea token
|
|
# with write:package) visible to this repository.
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: release-${{ gitea.ref }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
REGISTRY: git.lucasrguerra.dev.br
|
|
|
|
jobs:
|
|
# The image is built only from these paths, so their tree hashes identify it.
|
|
# When inputs-<hash> already exists (docs-only merge, workflow change, or a tag
|
|
# on a commit main already published), nothing is built or tested again.
|
|
plan:
|
|
name: Plan (reuse the published image?)
|
|
runs-on: linux-arm64
|
|
outputs:
|
|
inputs: ${{ steps.plan.outputs.inputs }}
|
|
reuse: ${{ steps.plan.outputs.reuse }}
|
|
image: ${{ steps.plan.outputs.image }}
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- id: plan
|
|
env:
|
|
REPO: ${{ gitea.repository }}
|
|
run: |
|
|
inputs=$(git rev-parse HEAD:Dockerfile HEAD:.dockerignore HEAD:Cargo.toml HEAD:Cargo.lock \
|
|
HEAD:crates HEAD:apps/gui/ui HEAD:logo.png HEAD:scripts/fetch-libduckdb.sh | sha256sum | cut -c1-16)
|
|
ns="${REPO,,}"
|
|
token=$(curl -fsS "https://$REGISTRY/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
|
|
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
|
|
-H "Authorization: Bearer $token" \
|
|
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json' \
|
|
"https://$REGISTRY/v2/$ns/manifests/inputs-$inputs")
|
|
echo "inputs-$inputs -> HTTP $code"
|
|
reuse=false; [ "$code" = 200 ] && reuse=true
|
|
echo "inputs=$inputs" >> "$GITHUB_OUTPUT"
|
|
echo "reuse=$reuse" >> "$GITHUB_OUTPUT"
|
|
echo "image=$REGISTRY/$ns" >> "$GITHUB_OUTPUT"
|
|
|
|
ci:
|
|
needs: plan
|
|
if: ${{ needs.plan.outputs.reuse != 'true' }}
|
|
uses: ./.gitea/workflows/ci.yml
|
|
|
|
# Each architecture is built on a native runner (no QEMU) and pushed under a
|
|
# per-architecture tag; publish joins them into one manifest list.
|
|
build:
|
|
name: Build image (${{ matrix.arch }})
|
|
needs: [plan, ci]
|
|
if: ${{ needs.plan.outputs.reuse != 'true' }}
|
|
runs-on: ${{ matrix.runner }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- { arch: amd64, platform: linux/amd64, runner: linux-amd64 }
|
|
- { arch: arm64, platform: linux/arm64, runner: linux-arm64 }
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- uses: docker/setup-buildx-action@v4
|
|
- uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ gitea.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Build and push (per architecture)
|
|
uses: docker/build-push-action@v7
|
|
with:
|
|
context: .
|
|
platforms: ${{ matrix.platform }}
|
|
push: true
|
|
tags: ${{ needs.plan.outputs.image }}:build-${{ gitea.sha }}-${{ matrix.arch }}
|
|
cache-from: type=registry,ref=${{ needs.plan.outputs.image }}:buildcache-${{ matrix.arch }}
|
|
cache-to: type=registry,ref=${{ needs.plan.outputs.image }}:buildcache-${{ matrix.arch }},mode=max
|
|
# Runs the image that was just pushed, on its own architecture.
|
|
- name: Smoke test
|
|
run: scripts/smoke-image.sh "${{ needs.plan.outputs.image }}:build-${{ gitea.sha }}-${{ matrix.arch }}"
|
|
|
|
publish:
|
|
name: Publish tags
|
|
needs: [plan, build]
|
|
# build is skipped, not successful, when the image is reused.
|
|
if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.build.result == 'success' || needs.plan.outputs.reuse == 'true') }}
|
|
runs-on: linux-arm64
|
|
steps:
|
|
- uses: docker/setup-buildx-action@v4
|
|
- uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ gitea.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Tags
|
|
id: meta
|
|
uses: docker/metadata-action@v6
|
|
with:
|
|
images: ${{ needs.plan.outputs.image }}
|
|
flavor: latest=false
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest,enable=${{ startsWith(gitea.ref, 'refs/tags/v') && !contains(gitea.ref_name, '-') }}
|
|
type=raw,value=edge,enable=${{ gitea.ref == 'refs/heads/main' }}
|
|
type=sha,format=long
|
|
- name: Apply tags
|
|
run: |
|
|
image='${{ needs.plan.outputs.image }}'
|
|
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
|
|
inputs='${{ needs.plan.outputs.inputs }}'
|
|
if [ '${{ needs.plan.outputs.reuse }}' = true ]; then
|
|
docker buildx imagetools create $tags "$image:inputs-$inputs"
|
|
else
|
|
docker buildx imagetools create $tags -t "$image:inputs-$inputs" \
|
|
"$image:build-${{ gitea.sha }}-amd64" "$image:build-${{ gitea.sha }}-arm64"
|
|
fi
|
|
- name: Check architectures
|
|
run: |
|
|
docker buildx imagetools inspect "${{ needs.plan.outputs.image }}:inputs-${{ needs.plan.outputs.inputs }}" \
|
|
--format '{{json .Manifest}}' \
|
|
| jq -r '.manifests[] | select(.platform.os == "linux") | "\(.platform.os)/\(.platform.architecture)"' \
|
|
| tee platforms.txt
|
|
grep -qx linux/amd64 platforms.txt && grep -qx linux/arm64 platforms.txt
|
|
- name: Summary
|
|
run: |
|
|
{ echo "### Acauã image published (linux/amd64, linux/arm64)"; echo; echo '```'
|
|
echo "${{ steps.meta.outputs.tags }}"; echo '```'; } >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
gitea-release:
|
|
name: Gitea release
|
|
needs: [plan, publish]
|
|
if: ${{ !cancelled() && needs.publish.result == 'success' && startsWith(gitea.ref, 'refs/tags/v') }}
|
|
runs-on: linux-arm64
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 0
|
|
- name: Release
|
|
env:
|
|
TAG: ${{ gitea.ref_name }}
|
|
TOKEN: ${{ gitea.token }}
|
|
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
|
IMAGE: ${{ needs.plan.outputs.image }}
|
|
run: |
|
|
if curl -fsS -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" >/dev/null 2>&1; then
|
|
echo "release $TAG already exists"; exit 0
|
|
fi
|
|
{ scripts/release-notes.sh "$TAG"; echo; echo '```bash'; echo "docker pull $IMAGE:${TAG#v}"; echo '```'; } > notes.md
|
|
pre=false; case "$TAG" in *-*) pre=true ;; esac
|
|
jq -n --arg tag "$TAG" --arg name "Acauã ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
|
|
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
|
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
|
-H 'Content-Type: application/json' -d @release.json >/dev/null
|