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 +