diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..dc545c1 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,163 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * 1" + +jobs: + build-and-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Build Docker image + run: docker build -t socat-proxy:ci . + + - name: Smoke test (syntax check) + run: docker run --rm --entrypoint sh socat-proxy:ci -n /entrypoint.sh + + - name: Run unit tests + run: | + docker build --target test -t socat-proxy:test . + docker run --rm socat-proxy:test bats /app/tests/entrypoint.bats + + - name: Lint entrypoint.sh with shellcheck + run: docker build --target lint -t socat-proxy:lint . + + - name: Scan with Trivy (critical - blocking) + run: | + docker run --rm \ + -e DOCKER_HOST=tcp://dockerhost:2375 \ + --add-host=dockerhost:host-gateway \ + aquasec/trivy:0.74.0 image --exit-code 1 --severity CRITICAL socat-proxy:ci + + - name: Scan with Trivy (high - informative) + run: | + docker run --rm \ + -e DOCKER_HOST=tcp://dockerhost:2375 \ + --add-host=dockerhost:host-gateway \ + aquasec/trivy:0.74.0 image --exit-code 0 --severity HIGH socat-proxy:ci + + - name: Publish tagged image + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: | + BEFORE="${{ github.event.before }}" + if [ -n "$BEFORE" ] && [ "$BEFORE" != "0000000000000000000000000000000000000000" ] && git cat-file -e "$BEFORE" 2>/dev/null; then + CHANGED=$(git diff --name-only "$BEFORE" "${{ github.sha }}") + else + CHANGED=$(git diff --name-only HEAD~1 HEAD) + fi + echo "Changed files:" + echo "$CHANGED" + + if ! echo "$CHANGED" | grep -qE '^(Dockerfile|entrypoint\.sh|VERSION)$'; then + echo "No container-relevant file changed, skipping publish." + exit 0 + fi + + if echo "$CHANGED" | grep -qE '^VERSION$'; then + echo "VERSION was manually edited in this push, using it as-is." + else + echo "VERSION untouched but container files changed, auto-bumping the build number (Z)." + OLD_VERSION=$(tr -d '[:space:]' < VERSION) + IFS='.' read -r MAJOR MINOR PATCH <<< "$OLD_VERSION" + NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" + echo "$NEW_VERSION" > VERSION + + git config user.name "socat-proxy-ci" + git config user.email "ci@git.djeex.fr" + git add VERSION + git commit -m "Bump build version to $NEW_VERSION [skip ci]" + + # Belt and suspenders: actions/checkout can leave its own ephemeral + # credential injected as an extraheader, which would silently override + # the URL-embedded token below. persist-credentials:false on checkout + # should already prevent this, but strip it here too just in case. + git config --unset-all http.https://git.djeex.fr/.extraheader || true + + git push "https://Djeex:${{ secrets.CI_PUSH_TOKEN }}@git.djeex.fr/Djeex/socat-proxy.git" HEAD:main + fi + + VERSION=$(tr -d '[:space:]' < VERSION) + IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION" + MINOR_TAG="${MAJOR}.${MINOR}" + + IMAGE=git.djeex.fr/djeex/socat-proxy + echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.djeex.fr -u Djeex --password-stdin + + # Retag the already-built, already-scanned image — never rebuild for publish, + # so what ships is byte-for-byte what Trivy just scanned. + docker tag socat-proxy:ci "$IMAGE:latest" + docker tag socat-proxy:ci "$IMAGE:$MINOR_TAG" + docker tag socat-proxy:ci "$IMAGE:$VERSION" + docker push "$IMAGE:latest" + docker push "$IMAGE:$MINOR_TAG" + docker push "$IMAGE:$VERSION" + + TRIGGER_MSG=$(git log -1 --format=%s "${{ github.sha }}") + PR_NUM=$(echo "$TRIGGER_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || true) + + CATEGORY="🔧 Maintenance" + CHANGE_TITLE="$TRIGGER_MSG" + + if [ -n "$PR_NUM" ]; then + PR_JSON=$(curl -s -H "Authorization: token ${{ secrets.CI_PUSH_TOKEN }}" \ + "https://git.djeex.fr/api/v1/repos/Djeex/socat-proxy/pulls/$PR_NUM") + PR_TITLE=$(echo "$PR_JSON" | jq -r '.title // empty' 2>/dev/null || true) + LABELS=$(echo "$PR_JSON" | jq -r '.labels[]?.name' 2>/dev/null || true) + + if [ -n "$PR_TITLE" ]; then + CHANGE_TITLE="$PR_TITLE" + fi + + if echo "$LABELS" | grep -qx 'bug'; then + CATEGORY="⚠️ Hotfix" + elif echo "$LABELS" | grep -qx 'major'; then + CATEGORY="💥 Breaking change" + elif echo "$LABELS" | grep -qx 'minor'; then + CATEGORY="✨ Update" + fi + fi + + CHANGED_LIST=$(echo "$CHANGED" | sed 's/^/- /') + + REPO_URL="https://git.djeex.fr/Djeex/socat-proxy" + SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) + SOURCE_LINE="[${SHORT_SHA}](${REPO_URL}/commit/${{ github.sha }})" + if [ -n "$PR_NUM" ]; then + SOURCE_LINE="[#${PR_NUM}](${REPO_URL}/pulls/${PR_NUM}) · ${SOURCE_LINE}" + fi + + BODY=$(cat <