Files
Hermes Agent ffaff66505 deps: REA 6.8.0 (+ Node 24.22.1), and the admissions that moved with it
Upstream: https://github.com/morluto/rea/releases/tag/rea-agents-6.8.0
Check:    make check-updates  ->  0 actionable / 6 pending / 0 unknown
Harness:  scripts/verify-all-engines.sh  121/0/3 · 109/0/8 · 102/0/7 · 94/0/11

REA 6.8.0 changes two things this image has to follow:

- engines.node is now ^22.23.4 || ^24.22.1 || >=26.12.1, so the 24.22.0
  runtime that 6.7.0 accepted is *refused*. NODE_VERSION moves to 24.22.1
  in the same commit, in the Dockerfile and in the compose default.
- the bundled skill is v49 with 229 MCP tools (was v42 / 207), read from the
  shipped dist/mcp-catalog.json rather than the release notes.

No engine admission moved: GhidraReleasePolicy.ts is byte-identical
(12.1.4, Java 21) and Hopper is still the vendor feed's 6.6.0 demo, so the
engine pins are untouched and the harness re-proved both providers.

Two checks had to change shape, and both got stricter:

- binwalk/unblob left CapabilityInventory's remediation prose for structured
  defineToolRequirement() entries in
  src/contracts/firmware/firmwareToolRequirements.ts. scrape_rea now reads
  those first and falls back to the prose, so both rows keep showing the
  admitted value instead of printing `ok` with nothing verified.
- extract-artifact lost its second positional (REA picks the destination and
  reports output_root). The harness now asserts containment_verified,
  coverage complete, cleanup verified, non-empty created artifacts, and that
  the reported files exist under the reported root - one check more per
  image than the exit-status check it replaces.

Docs regenerated for this run: docs/verify-engines.txt,
docs/verify-summary.txt, the size table (make sizes), and the skill/tool
counts in README, HERMES-MCP, IMAGES, ARCHITECTURE and UPDATES.
2026-10-25 10:02:32 +00:00

157 lines
5.6 KiB
Makefile

# Build and run helpers for the rea-agent images.
#
# Four images, one engine each - select with ENGINE=all|ghidra|hopper|ida:
#
# make build ENGINE=ghidra make up ENGINE=hopper make verify ENGINE=ida
# make build-ghidra make up-hopper make verify-ghidra
#
# Everything Docker-side uses the HOST path to this project directory when a
# Docker socket is bind-mounted into the caller (e.g. Hermes running in Docker
# with DooD): volume/context sources resolve on the host daemon, not inside the
# caller's container. scripts/build.sh does that translation.
SHELL := /bin/bash
ENGINE ?= all
DOCKER ?= docker
COMPOSE ?= $(DOCKER) compose
TAG_SUFFIX ?= 6.8.0-linux-amd64
# engine -> compose service / profile (the image name comes from
# scripts/image-name.sh, which also honours the REA_*_IMAGE names in .env, so a
# local build tags exactly what `docker compose pull` would fetch)
engine_service = $(if $(filter all,$(1)),rea-agent,rea-$(1))
IMAGE := $(shell scripts/image-name.sh $(ENGINE))
SERVICE := $(call engine_service,$(ENGINE))
PROFILE := $(if $(filter all,$(ENGINE)),,--profile $(ENGINE))
COMPOSE_ENGINE = $(COMPOSE) -f docker-compose.yml
.DEFAULT_GOAL := help
.PHONY: help
help: ## show this help
@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
@echo
@echo " ENGINE=$(ENGINE) -> image $(IMAGE), service $(SERVICE)"
@echo " images: all=rea-agent (Ghidra+Hopper) | ghidra | hopper | ida (bring your own IDA)"
.PHONY: env
env: ## create .env from .env.example when missing
@test -f .env || (cp .env.example .env && echo "created .env - review it, then 'make build'")
.PHONY: build
build: env ## build the image for $(ENGINE)
scripts/build.sh --engine $(ENGINE)
.PHONY: build-ghidra build-hopper build-ida
build-ghidra: ## build the Ghidra-only image
scripts/build.sh --engine ghidra
build-hopper: ## build the Hopper-only image
scripts/build.sh --engine hopper
build-ida: ## build the engine-less IDA image (bring your own IDA)
scripts/build.sh --engine ida
.PHONY: build-all
build-all: ## build all four images
scripts/build-all.sh
.PHONY: up
up: ## start the long-lived container for $(ENGINE)
$(COMPOSE_ENGINE) $(PROFILE) up -d $(SERVICE)
.PHONY: up-ghidra up-hopper up-ida
up-ghidra: ## start the Ghidra-only container
$(COMPOSE_ENGINE) --profile ghidra up -d rea-ghidra
up-hopper: ## start the Hopper-only container
$(COMPOSE_ENGINE) --profile hopper up -d rea-hopper
up-ida: ## start the IDA container (needs your own IDA install/licence)
$(COMPOSE_ENGINE) --profile ida up -d rea-ida
.PHONY: down
down: ## stop every compose service of this project
$(COMPOSE) down
.PHONY: shell
shell: ## interactive shell in the running $(ENGINE) container
$(COMPOSE) exec $(SERVICE) bash
.PHONY: doctor
doctor: ## REA readiness report from inside the $(ENGINE) container
$(COMPOSE) exec $(SERVICE) rea doctor --json
.PHONY: providers
providers: ## list analysis providers and their capabilities
$(COMPOSE) exec $(SERVICE) rea providers --json
.PHONY: verify
verify: ## full in-container verification for $(ENGINE)
scripts/verify.sh --image $(IMAGE)
.PHONY: verify-quick
verify-quick: ## fast verification (tool presence + static + MCP handshake)
scripts/verify.sh --image $(IMAGE) --quick
.PHONY: verify-ghidra verify-hopper verify-ida
verify-ghidra: ## full verification of the Ghidra-only image
scripts/verify.sh --engine ghidra --only tools,analysis,static,clients,mcp
verify-hopper: ## full verification of the Hopper-only image
scripts/verify.sh --engine hopper --only tools,analysis,static,clients,mcp
verify-ida: ## verification of the engine-less IDA image
scripts/verify.sh --engine ida --only tools,static,clients,mcp
.PHONY: pull
pull: ## pull the published image for $(ENGINE) from GHCR (no local build)
$(DOCKER) pull $(IMAGE)
.PHONY: pull-all
pull-all: ## pull all four published images from GHCR
@for e in all ghidra hopper ida; do \
img="$$( scripts/image-name.sh $$e )"; \
echo "== pulling $$img"; \
$(DOCKER) pull "$$img" || exit 1; \
done
.PHONY: mcp-stdio
mcp-stdio: ## speak MCP over stdio the way Hermes does
$(DOCKER) exec -i $(SERVICE) rea mcp
.PHONY: http-up
http-up: ## start the Streamable HTTP bridge for $(ENGINE)
REA_IMAGE=$(IMAGE) REA_ENGINE=$(ENGINE) $(COMPOSE_ENGINE) $(PROFILE) -f compose.http.yml up -d rea-mcp-http
.PHONY: ida-up
ida-up: ## start the IDA overlay (needs your own IDA install/licence)
$(COMPOSE_ENGINE) -f compose.ida.yml --profile ida up -d rea-ida
.PHONY: test-host
test-host: ## run the harness in a throwaway container against ./work
$(DOCKER) run --rm -it --shm-size=1g \
--user "$$(id -u):$$(id -g)" \
-v $(PWD)/work:/work -v $(PWD)/config:/etc/rea:ro $(IMAGE) \
/opt/rea/verify/verify-all.sh
.PHONY: check-updates
check-updates: ## are the pins still current? (upstream + what REA admits)
scripts/check-updates.py $(ARGS)
.PHONY: check-updates-json
check-updates-json: ## the same check as JSON (for scripts)
scripts/check-updates.py --json --no-fail
.PHONY: sizes
sizes: ## report the size of every engine image
@for e in all ghidra hopper ida; do \
img="$$( scripts/image-name.sh $$e )"; \
bytes="$$( $(DOCKER) image inspect "$$img" --format '{{.Size}}' 2>/dev/null || echo '' )"; \
if [ -n "$$bytes" ]; then \
human="$$(awk -v b="$$bytes" 'BEGIN{printf "%.2f GB", b/1024/1024/1024}')"; \
printf ' %-52s %s (%s bytes)\n' "$$img" "$$human" "$$bytes"; \
else \
printf ' %-52s %s\n' "$$img" "not built/pulled"; \
fi; \
done
.PHONY: clean
clean: ## remove build output, not the images
rm -rf work/verify-reports work/tmp