Files
swarm-house/.github/workflows/release.yaml
T
eSlider 2787a361bd
CI & Release / Verify simulator (push) Successful in 7s
CI & Release / Trivy scan (push) Successful in 9s
CI & Release / Semantic Release (push) Successful in 3s
fix(ci): bump Trivy to 0.72.0, old release asset is gone
2026-07-08 13:55:52 +01:00

193 lines
7.1 KiB
YAML

# Swarm House - Gitea Actions
# verify: compile check, virtual-drone smoke flight, SQL gate tests (every push/PR)
# scan: Trivy vulnerability + misconfiguration scan
# release: semantic version bump (conventional commits), tag, Gitea release
# with a fleet release manifest + source bundle
name: CI & Release
on:
push:
branches: [main]
paths-ignore:
- 'docs/**'
- 'README.md'
- 'AGENTS.md'
pull_request:
branches: [main]
jobs:
verify:
name: Verify simulator
runs-on: ubuntu-latest
container: python:3.12-bookworm
steps:
- name: Checkout
run: |
git clone --depth=50 https://${{ gitea.actor }}:${{ gitea.token }}@git.produktor.io/${{ gitea.repository }}.git .
git checkout ${{ gitea.sha }}
- name: Install dependencies
run: pip install --quiet -r simulator/requirements.txt
- name: Compile check
run: python -m compileall -q simulator/virtual_drone simulator/monitoring simulator/explorer
- name: Smoke flight
working-directory: simulator
run: |
DRONE_ID=ci-01 FLIGHT_ID=ci-smoke DURATION_S=10 SPEEDUP=10 DATA_DIR=./data \
python -m virtual_drone.main
python - <<'EOF'
import duckdb
rows = duckdb.sql("""
SELECT count(*) FROM read_parquet(
'data/dataset=telemetry/**/*.parquet',
hive_partitioning=true, union_by_name=true)
""").fetchone()[0]
assert rows > 0, "smoke flight produced no telemetry"
print(f"smoke flight OK: {rows} telemetry rows")
EOF
- name: SQL gate tests
working-directory: simulator
run: |
python - <<'EOF'
import sys
sys.path.insert(0, "explorer")
from server import gate
assert gate("SELECT 1") is None
assert gate("WITH t AS (SELECT 1) SELECT * FROM t") is None
assert gate("DESCRIBE telemetry") is None
assert gate("DROP TABLE telemetry") is not None
assert gate("SELECT 1; SELECT 2") is not None
assert gate("INSTALL httpfs") is not None
assert gate("SET memory_limit='1GB'") is not None
assert gate("/* sneaky */ COPY t TO 'x'") is not None
assert gate("") is not None
print("SQL gate OK: reads pass, writes and config are rejected")
EOF
scan:
name: Trivy scan
runs-on: ubuntu-latest
container: python:3.12-bookworm
needs: verify
steps:
- name: Checkout
run: |
git clone --depth=1 https://${{ gitea.actor }}:${{ gitea.token }}@git.produktor.io/${{ gitea.repository }}.git .
git checkout ${{ gitea.sha }}
- name: Install Trivy
run: |
TRIVY_VER="0.72.0"
curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VER}/trivy_${TRIVY_VER}_Linux-64bit.tar.gz" \
| tar -xz -C /usr/local/bin trivy
trivy --version
- name: Dependency vulnerabilities
run: trivy fs --scanners vuln --severity HIGH,CRITICAL --exit-code 1 .
- name: Dockerfile and Compose misconfigurations
run: trivy config --severity HIGH,CRITICAL --exit-code 0 .
release:
name: Semantic Release
runs-on: ubuntu-latest
container: python:3.12-bookworm
needs: [verify, scan]
if: gitea.event_name == 'push'
permissions:
contents: write
steps:
- name: Checkout (full history for tags)
run: |
git clone https://${{ gitea.actor }}:${{ gitea.token }}@git.produktor.io/${{ gitea.repository }}.git .
git checkout ${{ gitea.sha }}
git fetch --tags
- name: Determine version bump (conventional commits)
id: version
run: |
LATEST_TAG=$(git tag -l 'v*' --sort=-v:refname | head -1)
[ -z "$LATEST_TAG" ] && LATEST_TAG="v0.0.0"
echo "Latest tag: $LATEST_TAG"
VER="${LATEST_TAG#v}"
MAJOR=$(echo "$VER" | cut -d. -f1)
MINOR=$(echo "$VER" | cut -d. -f2)
PATCH=$(echo "$VER" | cut -d. -f3)
MSG=$(git log -1 --format='%s%n%b' ${{ gitea.sha }})
echo "Commit: $(git log -1 --format='%s' ${{ gitea.sha }})"
if echo "$MSG" | grep -qE '^[a-z]+(\(.+\))?!:|BREAKING CHANGE'; then
MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0; BUMP="major"
elif echo "$MSG" | grep -qE '^feat(\(.+\))?:'; then
MINOR=$((MINOR + 1)); PATCH=0; BUMP="minor"
else
PATCH=$((PATCH + 1)); BUMP="patch"
fi
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
echo "Bump: $BUMP -> $NEW_TAG"
echo "new_tag=${NEW_TAG}" >> "$GITHUB_OUTPUT"
echo "bump_type=${BUMP}" >> "$GITHUB_OUTPUT"
- name: Build fleet release manifest and source bundle
run: |
TAG="${{ steps.version.outputs.new_tag }}"
mkdir -p .tmp
tar --exclude='.git' --exclude='.tmp' --exclude='simulator/data' \
--exclude='simulator/.venv' --exclude='prototype/node_modules' \
-czf ".tmp/swarm-house-${TAG}.tar.gz" .
cat > .tmp/manifest.yaml <<EOF
# Fleet release manifest (docs/11-cicd-delivery.md)
release: ${TAG}
commit: ${{ gitea.sha }}
built_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
artifacts:
- name: swarm-house-${TAG}.tar.gz
sha256: $(sha256sum ".tmp/swarm-house-${TAG}.tar.gz" | cut -d' ' -f1)
components:
simulator: python-3.12
explorer: python-3.12
prototype: vite-react
EOF
cat .tmp/manifest.yaml
- name: Create tag
run: |
git config user.name "Gitea Actions"
git config user.email "actions@git.produktor.io"
git tag -a "${{ steps.version.outputs.new_tag }}" \
-m "Release ${{ steps.version.outputs.new_tag }} (${{ steps.version.outputs.bump_type }})"
git push https://${{ gitea.actor }}:${{ gitea.token }}@git.produktor.io/${{ gitea.repository }}.git \
"${{ steps.version.outputs.new_tag }}"
- name: Create Gitea Release
run: |
TAG="${{ steps.version.outputs.new_tag }}"
BUMP="${{ steps.version.outputs.bump_type }}"
API="https://git.produktor.io/api/v1/repos/${{ gitea.repository }}/releases"
TOKEN="${{ gitea.token }}"
RELEASE=$(curl -sf -X POST "$API" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\":\"$TAG\",\"name\":\"Swarm House $TAG\",\"body\":\"**${BUMP}** release \`${TAG}\` — verified (smoke flight, SQL gate) and scanned (Trivy). Includes the fleet release manifest.\"}")
RELEASE_ID=$(echo "$RELEASE" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
echo "Created release ID: $RELEASE_ID"
for f in .tmp/*; do
FNAME=$(basename "$f")
curl -sf -X POST "$API/$RELEASE_ID/assets?name=$FNAME" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$f"
echo "Uploaded: $FNAME"
done