Skip to content

feat: CLI-first container image + robust technique count; fixes red wheel job (roadmap #14) - #96

Merged
404SecNotFound merged 2 commits into
mainfrom
feat/pip-and-container
Sep 1, 2026
Merged

feat: CLI-first container image + robust technique count; fixes red wheel job (roadmap #14)#96
404SecNotFound merged 2 commits into
mainfrom
feat/pip-and-container

Conversation

@404SecNotFound

Copy link
Copy Markdown
Owner

Roadmap 2026-09 item 14, unblocked by the rank-2 OSS/CLI-first decision. The pip-installable CLI already exists (console_scripts + [web] optional extra); this adds the container half and hardens the build gate.

What's new

  • Dockerfile — a CLI-first image (python:3.12-slim, non-root runner, ENTRYPOINT ["replicant"]). The web UI is deliberately not installed, so a CLI-first evaluator does not build a React bundle to see one FortiGate line. replicant web in the image serves its build-it page.
  • .dockerignore — keeps everything but the package and its metadata out of the build context, including the in-tree backup git repos (replicant-backup-*/, replicant-rewrite/) and the checked-in webui_dist.
  • CI container job — builds the image and drives the CLI inside it (--version, all 24 techniques, a full run ... --to-file --no-send that produces a FortiGate CEF line, and an assertion the UI assets are absent). This is the positive control I cannot run locally (no Docker daemon on the dev Mac); a broken Dockerfile fails here.
  • README — documents pip install replicant / [web] and the container trial, noting the PyPI publish itself is a release step.

Also: fixes a red wheel job on main

The transferability-notes footer from item #5 made replicant list | grep -c 'REP-0' return 28, which turned the wheel job red on main (confirmed on the latest main run — I missed it relying on gh pr checks --watch exit codes). Both the wheel and container checks now count distinct technique ids (grep -oE 'REP-[0-9]{3}' | sort -u), which is what "24 techniques" means and is immune to the footer. This PR restores the gate.

No Python changed; suite unaffected. Decision record: docs/roadmap-2026-09.md.

)

The pip-installable CLI already exists (console_scripts + [web] optional extra);
this adds the container half and a robust build gate.

- Dockerfile: a CLI-first image (python:3.12-slim, non-root, ENTRYPOINT
  replicant). Web UI deliberately excluded so a CLI evaluator does not build a
  React bundle to see one FortiGate line. .dockerignore keeps everything but the
  package out of the build context, including the in-tree backup git repos and
  the checked-in webui_dist.
- CI 'container' job builds the image and drives the CLI inside it (the positive
  control the author cannot run locally: no Docker daemon on the dev Mac). A
  broken Dockerfile fails there rather than being merged on inspection.
- README documents 'pip install replicant' / '[web]' and the container trial,
  noting the PyPI publish itself is a release step.

Also fixes a regression this session introduced: the transferability-notes
footer (item #5) made 'replicant list | grep -c REP-0' return 28, turning the
wheel job red on main. Both the wheel and container checks now count DISTINCT
technique ids (grep -oE 'REP-[0-9]{3}' | sort -u), which is what '24 techniques'
means and is immune to the footer.
…rrect docs

From /code-review on PR #96, verified before fixing:

1. (main) The README's headline 'docker run -v ... run' example failed on native
   Linux: the non-root image (uid 10001) cannot write a host-owned bind mount.
   Now documents --user $(id -u):$(id -g), and a new CI step exercises exactly
   that bind-mounted run on the Linux runner (previously untested).
2/4. The Dockerfile/README claimed 'replicant web' serves its build-it page (it
   errors 'web dependencies missing', no fastapi) and called webui_dist
   'checked-in' (it is gitignored). Both corrected.
3. The 'no web assets' CI guard could never fail: webui_dist is gitignored and
   the job never built it, so the image lacked it regardless of .dockerignore.
   The container job now builds the frontend first (like the wheel job), so the
   guard actually tests the .dockerignore exclusion; deleting that line now fails
   it.

Finding 5 (the distinct-count one-liner duplicated across wheel and container
jobs) left as-is: both correct, a shared composite action would over-engineer a
one-liner.
@404SecNotFound
404SecNotFound merged commit 838852e into main Sep 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant