From dd9cfaad58cd39798fecf585122dafdfc0ffc448 Mon Sep 17 00:00:00 2001 From: wind Date: Fri, 27 Feb 2026 20:06:19 +0100 Subject: [PATCH] feat: add Docker Hub build-and-push workflow and update compose/Dockerfile - Add .github/workflows/docker.yml: builds linux/amd64 + linux/arm64 images via docker/build-push-action, pushes to talesofthemoon/networkcrawler on merge to main and on semver tags; PR builds validate the image without pushing - Add GHA layer cache (type=gha) to keep multi-arch builds fast - Add peter-evans/dockerhub-description step to sync README to Hub on main merges - Update Dockerfile OCI labels to include Docker Hub URL and vendor - Update docker-compose.yml to pull talesofthemoon/networkcrawler:latest by default; local build block preserved (commented out) for development use - Update .env.example with Docker Hub secrets reference and IMAGE_TAG hint Unraid CA template updated locally (gitignored): Repository field now points to talesofthemoon/networkcrawler:latest with full CA metadata and TemplateURL. --- .env.example | 12 ++++ .github/workflows/docker.yml | 104 +++++++++++++++++++++++++++++++++++ docker/Dockerfile | 5 +- docker/docker-compose.yml | 17 ++++-- 4 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/docker.yml diff --git a/.env.example b/.env.example index efa6a5f..0a8734b 100644 --- a/.env.example +++ b/.env.example @@ -13,3 +13,15 @@ SCAN_INTERVAL_SECONDS=3600 # Logging verbosity: DEBUG | INFO | WARNING | ERROR LOG_LEVEL=INFO + +# ── Docker Hub publish (CI use only — set as GitHub Actions secrets) ───────── +# These are NOT used at runtime. They are only consumed by the +# .github/workflows/docker.yml build-and-push workflow. +# +# Required GitHub repository secrets (Settings → Secrets → Actions): +# DOCKERHUB_USERNAME talesofthemoon +# DOCKERHUB_TOKEN Docker Hub access token (Account Settings → Security → New Access Token) +# +# Optional: pin a specific image tag when pulling via docker compose +# IMAGE_TAG=latest + diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..8d8191e --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,104 @@ +name: Docker — Build & Push + +# Triggers: +# • Push to main → builds and pushes :latest + : +# • Version tag (v*) → builds and pushes :latest + : (e.g. v1.2.3 → 1.2.3) +# • Pull request against main → build-only (no push) for image validation +# +# Required GitHub repository secrets (Settings → Secrets → Actions): +# DOCKERHUB_USERNAME — your Docker Hub username (talesofthemoon) +# DOCKERHUB_TOKEN — Docker Hub access token (Account Settings → Security → New Access Token) + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + branches: [main] + +concurrency: + group: docker-${{ github.ref }} + cancel-in-progress: true + +env: + IMAGE: talesofthemoon/networkcrawler + +jobs: + build: + name: Build & Push + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write # kept for potential future GHCR mirror + + steps: + # ── Checkout ──────────────────────────────────────────────────────────── + - uses: actions/checkout@v4 + + # ── QEMU — multi-arch emulation (linux/amd64 + linux/arm64) ───────────── + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + # ── Buildx — multi-platform builder ───────────────────────────────────── + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # ── Authenticate to Docker Hub (skip on PR builds) ────────────────────── + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # ── Generate image tags and OCI labels ────────────────────────────────── + # Push events produce: + # main branch → :latest + : + # v1.2.3 tag → :latest + :1.2.3 + - name: Generate Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE }} + tags: | + # Always tag :latest on main / tag pushes + type=raw,value=latest,enable={{is_default_branch}} + # Short SHA for main-branch pushes (e.g. sha-abc1234) + type=sha,prefix=sha-,enable={{is_default_branch}} + # Semver tags: v1.2.3 → 1.2.3, 1.2, 1 + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + labels: | + org.opencontainers.image.title=NetworkCrawler + org.opencontainers.image.description=LAN security posture scanner for home lab operators + org.opencontainers.image.vendor=talesofthemoon + org.opencontainers.image.licenses=MIT + + # ── Build (and push on non-PR events) ─────────────────────────────────── + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: docker/Dockerfile + # Build both amd64 (x86 Unraid servers) and arm64 (Pi / ARM NAS) + platforms: linux/amd64,linux/arm64 + # Only push when this is NOT a pull_request event + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + # Layer caching via GitHub Actions cache backend + cache-from: type=gha + cache-to: type=gha,mode=max + + # ── Update Docker Hub repo description (main branch only) ─────────────── + - name: Update Docker Hub description + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: peter-evans/dockerhub-description@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: ${{ env.IMAGE }} + short-description: "LAN security posture scanner for home lab operators" + readme-filepath: ./README.md diff --git a/docker/Dockerfile b/docker/Dockerfile index 52d8b35..45a5c9b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -28,7 +28,10 @@ FROM python:3.11-slim AS production LABEL org.opencontainers.image.title="NetworkCrawler" \ org.opencontainers.image.description="LAN security posture scanner for home lab operators" \ - org.opencontainers.image.source="https://github.com/reloadfast/NetworkCrawler" + org.opencontainers.image.source="https://github.com/reloadfast/NetworkCrawler" \ + org.opencontainers.image.url="https://hub.docker.com/r/talesofthemoon/networkcrawler" \ + org.opencontainers.image.vendor="talesofthemoon" \ + org.opencontainers.image.licenses="MIT" # Install system-level scanning tools RUN apt-get update \ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b6d573d..8b40eb5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,15 +10,23 @@ version: "3.9" # │ cap_add: [NET_RAW] │ # │ Grants raw socket access for arp-scan and nmap without running as root. │ # │ The container still runs as uid 1000 (non-root, set in Dockerfile). │ +# │ │ +# │ IMAGE │ +# │ By default pulls talesofthemoon/networkcrawler:latest from Docker Hub. │ +# │ To build locally instead: │ +# │ docker compose -f docker/docker-compose.yml build │ +# │ or set IMAGE_TAG env var to a specific digest/sha tag. │ # └─────────────────────────────────────────────────────────────────────────────┘ services: networkcrawler: - build: - context: .. - dockerfile: docker/Dockerfile + image: talesofthemoon/networkcrawler:${IMAGE_TAG:-latest} container_name: networkcrawler - image: networkcrawler:latest + + # Uncomment the build block to build from source instead of pulling from Hub: + # build: + # context: .. + # dockerfile: docker/Dockerfile # Host networking — required for ARP visibility across the LAN subnet network_mode: host @@ -54,3 +62,4 @@ services: volumes: networkcrawler_data: driver: local +