Skip to content

Bump docker/build-push-action from 6 to 7 #133

Bump docker/build-push-action from 6 to 7

Bump docker/build-push-action from 6 to 7 #133

Workflow file for this run

name: ci
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
on:
pull_request:
push:
branches:
- master
tags:
- "v*"
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:
jobs:
resolve-nexttrace-release:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.resolve.outputs.tag }}
steps:
- name: Resolve latest NTrace-core release
id: resolve
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
tag="$(curl -fsSL \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/nxtrace/NTrace-core/releases/latest | python3 -c 'import json, sys; print(json.load(sys.stdin)["tag_name"])')"
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
python-check:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.14"]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install dependencies
run: python -m pip install -r requirements.txt
- name: Run unit tests
run: python -m unittest discover -s tests -p "test_*.py"
- name: Compile Python modules
run: python -m py_compile app.py nexttrace_mtr.py
frontend-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: "20"
- name: Check browser scripts
run: |
node --check assets/js/main.js
node --check assets/js/mtr-agg.js
node --check assets/js/settingsmenu.js
node --check assets/js/ui-state.js
node --check tests/browser-harness.cjs
node --check tests/browser-controls.check.cjs
- name: Run frontend tests
run: |
node --test tests/*.test.cjs
node tests/browser-controls.check.cjs
security-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
cache: pip
- name: Install dependencies
run: python -m pip install -r requirements.txt pip-audit
- name: Audit Python dependencies
run: pip-audit -r requirements.txt
- name: Verify baseline hardening
run: |
python - <<'PY'
from pathlib import Path
required_snippets = {
"app.py": [
"NTWA_SECRET_KEY",
"NTWA_TRUSTED_HOSTS",
"SESSION_COOKIE_HTTPONLY",
"/healthz",
],
"Dockerfile": [
"FROM python:3.14-slim",
"HEALTHCHECK",
],
"requirements.txt": [
"gevent==26.4.0",
"gunicorn",
],
"nginx.conf": [
"Content-Security-Policy",
"X-Content-Type-Options",
"Referrer-Policy",
"X-Frame-Options",
"server_tokens off",
],
".github/workflows/docker-image.yml": [
"pull_request:",
"schedule:",
"python-wheel-check",
"docker-buildx-check",
"docker-smoke",
],
}
missing = []
for path, snippets in required_snippets.items():
content = Path(path).read_text()
for snippet in snippets:
if snippet not in content:
missing.append(f"{path} missing {snippet!r}")
if missing:
raise SystemExit("\n".join(missing))
PY
python-wheel-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
cache: pip
- name: Verify cp314 linux wheels
run: |
set -euo pipefail
common_args=(
--only-binary=:all:
--python-version 3.14
--implementation cp
--abi cp314
-r requirements.txt
)
python -m pip download "${common_args[@]}" \
--dest /tmp/ntwa-wheels-amd64 \
--platform manylinux_2_28_x86_64 \
--platform manylinux_2_27_x86_64 \
--platform manylinux_2_24_x86_64 \
--platform manylinux2014_x86_64
python -m pip download "${common_args[@]}" \
--dest /tmp/ntwa-wheels-arm64 \
--platform manylinux_2_28_aarch64 \
--platform manylinux_2_27_aarch64 \
--platform manylinux_2_24_aarch64 \
--platform manylinux2014_aarch64
docker-smoke:
runs-on: ubuntu-latest
needs:
- resolve-nexttrace-release
- python-check
- frontend-check
- security-check
- python-wheel-check
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Build smoke image
run: docker build --build-arg NEXTTRACE_RELEASE_TAG="${{ needs.resolve-nexttrace-release.outputs.tag }}" -t nexttraceweb:smoke .
- name: Start container
run: |
cid="$(docker run -d -p 30080:30080 nexttraceweb:smoke)"
echo "CONTAINER_ID=${cid}" >> "$GITHUB_ENV"
- name: Wait for healthz
run: |
for _ in $(seq 1 60); do
if curl -fsS http://127.0.0.1:30080/healthz >/dev/null; then
exit 0
fi
sleep 2
done
docker logs "$CONTAINER_ID"
exit 1
- name: Verify Socket.IO websocket upgrade
run: |
python - <<'PY'
import base64
import os
import socket
key = base64.b64encode(os.urandom(16)).decode("ascii")
request = "\r\n".join([
"GET /socket.io/?EIO=4&transport=websocket HTTP/1.1",
"Host: 127.0.0.1:30080",
"Upgrade: websocket",
"Connection: Upgrade",
f"Sec-WebSocket-Key: {key}",
"Sec-WebSocket-Version: 13",
"\r\n",
]).encode("ascii")
with socket.create_connection(("127.0.0.1", 30080), timeout=5) as sock:
sock.sendall(request)
response = sock.recv(1024).decode("iso-8859-1")
status_line = response.split("\r\n", 1)[0]
if " 101 " not in status_line:
raise SystemExit(response)
PY
- name: Verify container exits when gunicorn dies
run: |
gunicorn_pid="$(docker exec "$CONTAINER_ID" pgrep -f 'gunicorn.*app:app' | head -n1)"
docker exec "$CONTAINER_ID" kill -TERM "$gunicorn_pid"
timeout 20s docker wait "$CONTAINER_ID"
- name: Dump logs on failure
if: failure()
run: docker logs "$CONTAINER_ID"
- name: Cleanup container
if: always()
run: docker rm -f "$CONTAINER_ID" >/dev/null 2>&1 || true
docker-buildx-check:
runs-on: ubuntu-latest
needs:
- resolve-nexttrace-release
- python-check
- frontend-check
- security-check
- python-wheel-check
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build multi-arch image
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
push: false
build-args: |
NEXTTRACE_RELEASE_TAG=${{ needs.resolve-nexttrace-release.outputs.tag }}
publish:
runs-on: ubuntu-latest
needs:
- resolve-nexttrace-release
- python-check
- frontend-check
- security-check
- docker-smoke
- docker-buildx-check
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to DockerHub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Compute image tags
id: meta
run: |
short_sha="${GITHUB_SHA::7}"
tags="tsosc/nexttraceweb:sha-${short_sha}"
if [[ "${GITHUB_REF}" == "refs/heads/master" ]]; then
tags="${tags},tsosc/nexttraceweb:latest"
fi
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
tags="${tags},tsosc/nexttraceweb:${GITHUB_REF_NAME}"
fi
echo "tags=${tags}" >> "$GITHUB_OUTPUT"
- name: Build and push image
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
NEXTTRACE_RELEASE_TAG=${{ needs.resolve-nexttrace-release.outputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max