#127

fix(docker): build from source and verify tool downloads

DraftstevenAthompsonwants to merge intofrom

The published autumn27/artex image no longer exists (Docker Hub returns 404), while docker-compose.yml still pulled it from a namespace that could be reclaimed. This builds the image from source instead.

Changes:

  • multi-stage Dockerfile: frontend static export, Go binary with the embedded UI, pinned tools, runtime layer
  • tool downloads verified against the checksums published in each release: nuclei, httpx, subfinder, katana, ffuf, dalfox
  • sqlmap pinned to tag 1.9.9 and commit cceda39208b5aad478de2c3f731df4239d9881f6
  • Node 22.23.4 from the official tarball with SHASUMS256 verification; Playwright MCP/CLI/playwright pinned
  • docker-compose.yml builds artex:local; install.sh and update.sh build instead of pull
  • release workflow publishes to GHCR instead of Docker Hub
  • README and .env.example updated; the stale one-click-update note is removed from build.sh

Verification on the build machine (no Docker daemon available there), rebased on v0.4.0:

  • go build ./..., go vet ./...: pass
  • npm run build:static with Node 22: pass
  • GOOS=linux GOARCH=amd64 go build -tags embedui -trimpath -ldflags ... ./cmd/artex: pass; the resulting binary starts and prints usage
  • every tool archive downloaded and matched its published checksum; the sqlmap commit matched
  • hadolint Dockerfile: no errors (DL3008 and DL4006 warnings only)
  • compose and release workflow YAML parse; shell scripts pass bash -n

docker build itself was not executed because the machine has no container runtime. Keeping this as a draft until docker compose build has been run once on a Docker host or in CI.

Activity

5
BaaRai9d ago

Ran it on a Docker host so you can take the draft label off.

I checked out your branch on Kali (WSL2), Docker 28, and did:

  • cp .env.example .env with a real POSTGRES_PASSWORD (compose refuses to interpolate without it, even for a build only run)
  • docker compose build
  • docker compose up -d with the ports remapped so it did not collide with a local instance

Results:

  • build succeeded in about seven minutes, image artex:local at 4.56 GB
  • container healthy, GET /api/health returns 200 with {"ok":true,"service":"artex","version":"dev"}, and GET / serves the embedded UI
  • inside the image: bbot 3.0.2 with its module dependencies, the seven toolbox binaries (nuclei, httpx, subfinder, katana, ffuf, dalfox, sqlmap), sqlmap at /opt/sqlmap, and the ten skills copied
  • your premise checks out: hub.docker.com/v2/repositories/autumn27/artex/ returns 404 while docker-compose.yml still references that image

One small thing for the README: docker compose build needs a .env present because POSTGRES_PASSWORD uses the :? form, so anyone following the manual copy-paste path hits that before the build starts. install.sh already generates the file, so it is only that path that needs a line.

The blocker in your description is cleared from my side. Mark it ready when you want and I will review the diff properly, especially the release workflow switch to GHCR and the tool checksum verification.

BaaRaireviewed9d ago
BaaRai9d ago

Three things before this can land, all supply chain rather than style. The build itself is fine: it compiles and runs, the checksums you verify against each release's own sums file are correct, sqlmap's tag and commit assertion is right, and the Node tarball check works.

  1. Playwright's dependencies are unpinned and their install scripts run. The global install pins only the top level, there is no lockfile, so transitive dependencies resolve by range at build time with scripts enabled. That is the npm-worm shape. Fix: commit a package.json plus package-lock.json and install with npm ci --ignore-scripts (the browser download is already a separate playwright install step, so ignoring scripts should be safe).

  2. Base images are pinned by tag, not digest. node:22-bookworm-slim, golang:1.26-bookworm, debian:bookworm-slim, python:3.12-slim-bookworm and the docker/dockerfile:1 frontend are all mutable tags. Pin by digest.

  3. .dockerignore does not exclude .env, config.json, jwt.key or backups/, while the build stage does COPY . .. They do not reach the final image, but they land in the build-stage layer and the build cache. Also: the README says a multi-arch image is published to GHCR, which does not exist yet, and the GHCR job publishes latest on every tag with no provenance or signature.

bbot -y --install-all-deps is inherited from our own Dockerfile, so it is not something you introduced. We are tracking it as a known gap, no action needed from you unless you want to take it.

One more, minor: the docker job in the release workflow lost its opt-in gate and now publishes on every v* tag. If pre-release tags are ever used, they would overwrite latest.

BaaRai7d ago

@stevenAthompson thank you for this work, it is genuinely good. The multi-stage build from source is the right direction, the checksum-verified tool downloads (nuclei/httpx/subfinder/katana/ffuf/dalfox, Node against SHASUMS256, pinned sqlmap commit) are a real hardening win, and moving publishing to GHCR solves the broken image reference cleanly.

We did not want to hold up one urgent piece behind the rest. A fresh git clone of main cannot build the image today: the Dockerfile still copies the prebuilt dist/<arch>/artex, which is git-ignored, so docker compose up -d --build fails with /dist/amd64/artex: not found. The old autumn27/artex image is gone, so there is no pull fallback either. That blocks anyone installing from git right now.

Because this PR is still a draft and currently conflicting with main, we opened https://github.com/BaaRai/ARTEX/pull/147 to fix just the clean-clone build in your place. It is intentionally much smaller than your change: it builds the frontend and the Go binary from source in the image (reusing build.sh with the release flags) and nothing else.

To be clear, this does not close or replace #127, and we have not touched your branch. Once #147 lands you are very welcome to rebase #127 on the new main and keep everything we deliberately left out, the tool checksums, the GHCR publishing, and the sqlmap pinning. Those are still worth having. Thanks again.

BaaRai5d ago

Thanks for this. #147 already landed the build-from-source part, so this PR now conflicts with main. Could you rebase on main and keep only what is still unique here: checksum verification for the downloaded tools, the Node version, Playwright, and sqlmap? The GHCR publication should go in its own PR so it can be reviewed separately. Once rebased, mark it ready for review and I'll run CI.

This pull request is a draft

Merging is unavailable until it is marked ready for review.