From 4e8d70ad79a2505d9d21f7649ac5b4e6746b4253 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:36:02 +1000 Subject: [PATCH 1/8] ensure container will have dependencies packages and related dependencies required so that bbot can operate normally --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 58feef49..69946f5d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM ghcr.io/astral-sh/uv:python3.11-trixie -RUN apt-get -y update && apt-get -y install curl jq +RUN apt-get -y update && apt-get -y install curl jq python3-pip pipx openssl tcpdump WORKDIR /app COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-install-project From cde873f6208ff9819ea924cacb4c8b395a29195b Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:33:24 +1000 Subject: [PATCH 2/8] add redis cluster support --- README.md | 5 ++++- bbot_server/message_queue/redis.py | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7e6c3b63..b4c7a0a0 100644 --- a/README.md +++ b/README.md @@ -194,9 +194,12 @@ export BBOT_SERVER_EVENT_STORE__URI="mongodb://localhost:27017/bbot_server" export BBOT_SERVER_ASSET_STORE__URI="mongodb://localhost:27017/bbot_server" export BBOT_SERVER_USER_STORE__URI="mongodb://localhost:27017/bbot_server" -# Message Queue URI +# Message Queue URI (standalone Redis) export BBOT_SERVER_MESSAGE_QUEUE__URI="redis://localhost:6379/0" +# Message Queue URI (Redis Cluster - use redis+cluster:// scheme) +export BBOT_SERVER_MESSAGE_QUEUE__URI="redis+cluster://your-redis-cluster-entrypoint:6379/0" + # Agent configuration export BBOT_SERVER_AGENT__BASE_PRESET='{"modules": ["nmap"]}' diff --git a/bbot_server/message_queue/redis.py b/bbot_server/message_queue/redis.py index 7fd6a615..afd2b799 100644 --- a/bbot_server/message_queue/redis.py +++ b/bbot_server/message_queue/redis.py @@ -4,7 +4,7 @@ from contextlib import suppress import redis.asyncio as redis -from taskiq_redis import RedisStreamBroker +from taskiq_redis import RedisStreamBroker, RedisStreamClusterBroker from .base import BaseMessageQueue from bbot_server.utils.misc import smart_encode @@ -29,6 +29,9 @@ class RedisMessageQueue(BaseMessageQueue): - bbot:stream:{subject}: for persistent, tailable streams - e.g. events, activities - bbot:work:{subject}: for one-time messages, e.g. tasks + Redis Cluster mode is enabled by using the redis+cluster:// URI scheme, e.g.: + redis+cluster://172.16.255.33:6379/0 + docker run --rm -p 127.0.0.1:6379:6379 redis To monitor Redis: @@ -41,13 +44,21 @@ class RedisMessageQueue(BaseMessageQueue): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._active_subscriptions = [] + self._cluster_mode = self.uri.startswith("redis+cluster://") + + def _broker_uri(self): + """Normalise the URI to redis:// for libraries that don't understand redis+cluster://.""" + return self.uri.replace("redis+cluster://", "redis://", 1) async def setup(self): - self.log.debug(f"Setting up Redis message queue at {self.uri}") + self.log.debug(f"Setting up Redis message queue at {self.uri} (cluster={self._cluster_mode})") while True: try: - self.redis = redis.from_url(self.uri) + if self._cluster_mode: + self.redis = redis.RedisCluster.from_url(self._broker_uri()) + else: + self.redis = redis.from_url(self.uri) await self.redis.ping() break except Exception as e: @@ -55,6 +66,8 @@ async def setup(self): await asyncio.sleep(1) async def make_taskiq_broker(self): + if self._cluster_mode: + return RedisStreamClusterBroker(self._broker_uri()) return RedisStreamBroker(self.uri) async def get(self, subject: str, timeout=None): From 93ef786116a9f67443c7ea686c67e833d6c1e787 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:49:13 +1000 Subject: [PATCH 3/8] Enhances containerization with dedicated build and compose files Introduces a `build.sh` script for multi-platform Docker image builds and optional registry pushes. Refactors the `Dockerfile` to consolidate `RUN` commands into a single layer, reducing image size and layers. Adds Docker Compose files `compose-server.yml` and `compose-agent.yml` to show how to run bbot-server in a more modular, closer to production ready, environment with the ability to scale out/up the number of available bbot agents that can run scans. The `compose-server.yml` externalizes database and message queue dependencies, leveraging environment variables for connection URIs and improving architectural flexibility. It also adds Traefik and autoupdate label examples for better integration with existing infrastructure. The new `compose-agent.yml` provides a template for running `bbot` agents, offering explicit ID configuration and server connectivity options. Improves `.gitignore` --- .gitignore | 10 ++++++++- Dockerfile | 22 ++++++++++++++------ build.sh | 27 ++++++++++++++++++++++++ compose-agent.yml | 22 ++++++++++++++++++++ compose-server.yml | 52 ++++++++++++++++++++++++++++++++++++++++++++++ compose.yml | 2 ++ 6 files changed, 128 insertions(+), 7 deletions(-) create mode 100755 build.sh create mode 100644 compose-agent.yml create mode 100644 compose-server.yml diff --git a/.gitignore b/.gitignore index b3a4b970..ecc99911 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +# container environment variables +.env + +# cached python stuff __pycache__/ + +# ?? textual/ -mongodb \ No newline at end of file + +# mongodb content +mongodb diff --git a/Dockerfile b/Dockerfile index 69946f5d..824593bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,23 @@ FROM ghcr.io/astral-sh/uv:python3.11-trixie -RUN apt-get -y update && apt-get -y install curl jq python3-pip pipx openssl tcpdump + WORKDIR /app -COPY pyproject.toml uv.lock ./ -RUN uv sync --frozen --no-install-project + COPY . . -RUN cp bbot_server/defaults_docker.yml bbot_server/defaults.yml -RUN uv sync --frozen -RUN useradd -u 1000 -m bbot && chown -R bbot:bbot /app + +# run as much as possible in one layer to minimise the number of layers in, and susequent size of, the final image +RUN apt-get -y update && \ + apt-get -y install curl jq python3-pip pipx openssl tcpdump && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* && \ + uv sync --frozen --no-install-project && \ + cp bbot_server/defaults_docker.yml bbot_server/defaults.yml && \ + uv sync --frozen && \ + useradd -u 1000 -m bbot && chown -R bbot:bbot /app + USER bbot + ENV PATH="/app/.venv/bin:$PATH" + EXPOSE 8807 + CMD ["uv", "run", "bbctl", "server", "start", "--api-only"] diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..bf85af37 --- /dev/null +++ b/build.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# defaults +IMAGE_NAME=${IMAGE_NAME:-blacklanternsecurity/bbot-server} +TAG=${TAG:-latest} +PLATFORMS=${PLATFORMS:-linux/amd64,linux/arm64} +REGISTRY_TAG=${REGISTRY_TAG:-latest} + +# store any custom build environment variables in the .env file... +# this allows you to build and store you own images, for whatever platforms you need, in whatever registry you want/need to... +test -f .env || { + echo "Error: .env file not found" + exit 1 +} + +source .env + +docker buildx create --use --name multi-builder +docker buildx build --platform "${PLATFORMS}" -t "${IMAGE_NAME}:${TAG}" --load . + +# only try to push the image to the registry if $REGISTRY_IMAGE_NAME has been set... +if [ "${REGISTRY_IMAGE_NAME}x" != "x" ]; then + docker tag "${IMAGE_NAME}:${TAG}" "${REGISTRY_IMAGE_NAME}:${REGISTRY_TAG}" + docker push "${REGISTRY_IMAGE_NAME}:${REGISTRY_TAG}" +fi + +# EOF diff --git a/compose-agent.yml b/compose-agent.yml new file mode 100644 index 00000000..9dd9ea08 --- /dev/null +++ b/compose-agent.yml @@ -0,0 +1,22 @@ +--- +services: + agent: + image: ${IMAGE_NAME:-blacklanternsecurity/bbot-server}:${TAG:-latest} + user: root + # use the following to utilise an explicit agent ID + # NOTE: --name has no effect, but bbctl presently requires that it is provided. + command: ["bbctl", "agent", "start", "--id", "${BBOT_AGENT_ID:-CHANGE_ME}", "--name", "${BBOT_AGENT_NAME:-Example Agent}"] + # use the following to auto-create the agent as "Docker Default Agent" + #entrypoint: ["bash", "/app/bbot_server/default_agent.sh"] + restart: always + environment: + - BBOT_SERVER_URL=${BBOT_SERVER_URL:-http://server:8807/v1/} + - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} + - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} + - BBOT_SERVER_API_KEY=${BBOT_SERVER_API_KEY:-CHANGE_ME} + # redirect python/certifi to use custom CA bundle if necessary + #- SSL_CERT_FILE=${SSL_CERT_FILE:-/etc/ssl/certs/ca-certificates.crt} + volumes: + # inject custom CA bundle if necessary + #- /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:/etc/ssl/certs/ca-certificates.crt:ro + - ~/.bbot:/root/.bbot diff --git a/compose-server.yml b/compose-server.yml new file mode 100644 index 00000000..900cd282 --- /dev/null +++ b/compose-server.yml @@ -0,0 +1,52 @@ +--- +networks: + network: + name: ${NETWORK:-systemd-traefik} + external: true + +x-bbot-server-base: &bbot-server-base + build: + context: . + restart: always + image: ${IMAGE_NAME:-blacklanternsecurity/bbot-server}:${TAG:-latest} + networks: + network: + volumes: + - "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/home/bbot/.config/bbot_server/config.yml" + environment: + - BBOT_SERVER_URL=${BBOT_SERVER_URL:-http://server:8807/v1/} + - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} + - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} + - BBOT_SERVER_API_KEY=${BBOT_SERVER_API_KEY:-CHANGE_ME} + - BBOT_SERVER_EVENT_STORE__URI=${BBOT_SERVER_EVENT_STORE__URI:-mongodb://CHANGE_ME:CHANGE_ME@mongodb:27017/bbot} + - BBOT_SERVER_ASSET_STORE__URI=${BBOT_SERVER_ASSET_STORE__URI:-mongodb://CHANGE_ME:CHANGE_ME@mongodb:27017/bbot} + - BBOT_SERVER_USER_STORE__URI=${BBOT_SERVER_USER_STORE__URI:-mongodb://CHANGE_ME:CHANGE_ME@mongodb:27017/bbot} + - BBOT_SERVER_MESSAGE_QUEUE__URI=${BBOT_SERVER_MESSAGE_QUEUE__URI:-redis://redis:6379/0} + +services: + server: + <<: *bbot-server-base + ports: + - "${BBOT_LISTEN_ADDRESS:-0.0.0.0}:${BBOT_PORT:-8807}:8807" + command: ["bbctl", "server", "start", "--api-only", "--listen", "0.0.0.0"] + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8807/v1/docs"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.http.routers.bbot_server.rule=Host(`bbot-server.example`)" + - "traefik.http.services.bbot_server.loadbalancer.server.port=8807" + - "io.containers.autoupdate=registry" + + worker: + <<: *bbot-server-base + command: ["bbctl", "server", "start", "--worker-only"] + labels: + - "traefik.enable=false" + - "io.containers.autoupdate=registry" + depends_on: + server: + condition: service_healthy diff --git a/compose.yml b/compose.yml index f998eb7f..0a8ddaa4 100644 --- a/compose.yml +++ b/compose.yml @@ -1,6 +1,7 @@ x-bbot-server-base: &bbot-server-base build: context: . + image: ${IMAGE_NAME:-blacklanternsecurity/bbot-server}:${TAG:-latest} restart: unless-stopped volumes: - "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/home/bbot/.config/bbot_server/config.yml" @@ -21,6 +22,7 @@ services: start_period: 30s environment: - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} + - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} depends_on: - mongodb - redis From 1cddd0abbb9e289e783e51014f00c9f430876699 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sat, 28 Mar 2026 02:14:26 +1000 Subject: [PATCH 4/8] Refines multi-agent scan dispatch logic Improves scan agent assignment by ensuring agents are removed from the ready pool after successfully dispatching a scan. Prevents scans from getting stuck by clearing the assigned agent when the `start_scan` command is rejected or if the pinned agent is offline/not ready. Adds a guard to re-fetch agent status if no ready agents remain during dispatch. --- bbot_server/modules/scans/scans_api.py | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/bbot_server/modules/scans/scans_api.py b/bbot_server/modules/scans/scans_api.py index 371f715b..2070e8c5 100644 --- a/bbot_server/modules/scans/scans_api.py +++ b/bbot_server/modules/scans/scans_api.py @@ -191,13 +191,11 @@ async def cancel_scan(self, id: str, force: bool = False): async def start_scans_loop(self): try: while True: - # get all queued scans queued_scans = await self.get_queued_scans() if not queued_scans: await self.sleep(1) continue self.log.info(f"Found {len(queued_scans):,} queued scans") - # get all alive agents ready_agents = {str(agent.id): agent for agent in await self.get_online_agents(status="READY")} if not ready_agents: self.log.warning("No agents are currently ready") @@ -205,7 +203,9 @@ async def start_scans_loop(self): continue self.log.info(f"Found {len(ready_agents):,} ready agents") for scan in queued_scans: - # find a suitable agent for the scan + if not ready_agents: + break + if scan.agent_id is None: selected_agent = random.choice(list(ready_agents.values())) else: @@ -213,22 +213,23 @@ async def start_scans_loop(self): selected_agent = ready_agents[str(scan.agent_id)] except KeyError: self.log.warning(f"Agent {scan.agent_id} was selected for a scan, but it is not online") - # check if agent doesn't exist anymore. if so, we'll clear it from the scan. try: - selected_agent = await self.root.get_agent(str(scan.agent_id)) + await self.root.get_agent(str(scan.agent_id)) + self.log.info( + f"Agent {scan.agent_id} exists but is not ready. " + "Clearing agent from scan so it can be re-assigned" + ) except self.BBOTServerNotFoundError: - self.log.warning(f"Scan's agent no longer exists. Clearing agent from scan") - await self.collection.update_one({"id": str(scan.id)}, {"$set": {"agent_id": None}}) - continue + self.log.warning("Scan's agent no longer exists. Clearing agent from scan") + await self.collection.update_one({"id": str(scan.id)}, {"$set": {"agent_id": None}}) + continue self.log.info(f"Selected agent: {selected_agent.name}") - # assign the agent to the scan await self.collection.update_one( {"id": str(scan.id)}, {"$set": {"agent_id": str(selected_agent.id)}} ) - # merge target and preset scan_preset = dict(scan.preset.preset) scan_preset["scan_name"] = scan.name scan_preset["target"] = scan.target.target @@ -240,7 +241,6 @@ async def start_scans_loop(self): config["scope"] = scope_config scan_preset["config"] = config - # send the scan to the agent scan_start_response = await self.execute_agent_command( str(selected_agent.id), "start_scan", scan_id=scan.id, preset=scan_preset ) @@ -258,6 +258,12 @@ async def start_scans_loop(self): "error": scan_start_response.error, }, ) + await self.collection.update_one( + {"id": str(scan.id)}, {"$set": {"agent_id": None}} + ) + ready_agents.pop(str(selected_agent.id), None) + if not ready_agents: + break await self.sleep(1) continue @@ -266,8 +272,10 @@ async def start_scans_loop(self): description=f"Scan [[COLOR]{scan.name}[/COLOR]] sent to agent [[bold]{selected_agent.name}[/bold]]", detail={"scan_id": scan.id, "agent_id": str(selected_agent.id)}, ) - # make the scan as sent await self.collection.update_one({"id": str(scan.id)}, {"$set": {"status": "SENT_TO_AGENT"}}) + ready_agents.pop(str(selected_agent.id), None) + if not ready_agents: + break except Exception as e: self.log.error(f"Error in scans loop: {e}") From bcadc00204e9ddbd356d23dc5434f91a3f8cc0da Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sat, 28 Mar 2026 02:29:40 +1000 Subject: [PATCH 5/8] Improves Docker Compose clarity and code formatting Refactors the scan error handling update operation for conciseness. Clarifies comments in the Docker Compose file regarding the injection of custom CA bundles, providing better guidance for future configuration. --- bbot_server/modules/scans/scans_api.py | 4 +--- compose-server.yml | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bbot_server/modules/scans/scans_api.py b/bbot_server/modules/scans/scans_api.py index 2070e8c5..07d6e8a8 100644 --- a/bbot_server/modules/scans/scans_api.py +++ b/bbot_server/modules/scans/scans_api.py @@ -258,9 +258,7 @@ async def start_scans_loop(self): "error": scan_start_response.error, }, ) - await self.collection.update_one( - {"id": str(scan.id)}, {"$set": {"agent_id": None}} - ) + await self.collection.update_one({"id": str(scan.id)}, {"$set": {"agent_id": None}}) ready_agents.pop(str(selected_agent.id), None) if not ready_agents: break diff --git a/compose-server.yml b/compose-server.yml index 900cd282..10807cf8 100644 --- a/compose-server.yml +++ b/compose-server.yml @@ -13,6 +13,8 @@ x-bbot-server-base: &bbot-server-base network: volumes: - "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/home/bbot/.config/bbot_server/config.yml" + # inject custom CA bundle if necessary + #- /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:/etc/ssl/certs/ca-certificates.crt:ro environment: - BBOT_SERVER_URL=${BBOT_SERVER_URL:-http://server:8807/v1/} - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} @@ -22,6 +24,8 @@ x-bbot-server-base: &bbot-server-base - BBOT_SERVER_ASSET_STORE__URI=${BBOT_SERVER_ASSET_STORE__URI:-mongodb://CHANGE_ME:CHANGE_ME@mongodb:27017/bbot} - BBOT_SERVER_USER_STORE__URI=${BBOT_SERVER_USER_STORE__URI:-mongodb://CHANGE_ME:CHANGE_ME@mongodb:27017/bbot} - BBOT_SERVER_MESSAGE_QUEUE__URI=${BBOT_SERVER_MESSAGE_QUEUE__URI:-redis://redis:6379/0} + # redirect python/certifi to use custom CA bundle if necessary + #- SSL_CERT_FILE=${SSL_CERT_FILE:-/etc/ssl/certs/ca-certificates.crt} services: server: From 2f60bd98ed8904439b3600e97ee6f3336f420c18 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sat, 28 Mar 2026 10:48:49 +1000 Subject: [PATCH 6/8] Add full stack compose option for dev Runs a default agent alongside everything else --- compose-dev.yml | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 compose-dev.yml diff --git a/compose-dev.yml b/compose-dev.yml new file mode 100644 index 00000000..1ba6fd24 --- /dev/null +++ b/compose-dev.yml @@ -0,0 +1,67 @@ +x-bbot-server-base: &bbot-server-base + build: + context: . + image: ${IMAGE_NAME:-blacklanternsecurity/bbot-server}:${TAG:-latest} + restart: unless-stopped + volumes: + - "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/home/bbot/.config/bbot_server/config.yml" + - ./bbot_server:/app/bbot_server + - ./bbot_server/defaults_docker.yml:/app/bbot_server/defaults.yml + +x-bbot-agent-base: &bbot-agent-base + build: + context: . + image: ${IMAGE_NAME:-blacklanternsecurity/bbot-server}:${TAG:-latest} + user: root + command: ["bbctl", "agent", "start"] + entrypoint: ["bash", "/app/bbot_server/default_agent.sh"] + restart: unless-stopped + environment: + - BBOT_SERVER_URL=${BBOT_SERVER_URL:-http://server:8807/v1/} + - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} + - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} + - BBOT_SERVER_API_KEY=${BBOT_SERVER_API_KEY:-} + volumes: + - ~/.bbot:/root/.bbot + +services: + server: + <<: *bbot-server-base + ports: + - "${BBOT_LISTEN_ADDRESS:-127.0.0.1}:${BBOT_PORT:-8807}:8807" + command: ["bbctl", "server", "start", "--api-only", "--listen", "0.0.0.0", "--reload"] + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8807/v1/docs"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + environment: + - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} + - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} + depends_on: + - mongodb + - redis + + worker: + <<: *bbot-server-base + command: ["bbctl", "server", "start", "--worker-only"] + depends_on: + server: + condition: service_healthy + + agent: + <<: *bbot-agent-base + depends_on: + server: + condition: service_healthy + + mongodb: + image: mongo:latest + restart: unless-stopped + volumes: + - ./mongodb:/data/db + + redis: + image: redis:latest + restart: unless-stopped From 4d4f66fa07a6eb25c4adcc082ae0dd2c0c2132d1 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sun, 29 Mar 2026 00:59:30 +1000 Subject: [PATCH 7/8] revert and improve Dockerfile Ensure sudo available so agent instances of containers can install necessary dependencies etc --- Dockerfile | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 824593bc..03155ea3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,13 +6,16 @@ COPY . . # run as much as possible in one layer to minimise the number of layers in, and susequent size of, the final image RUN apt-get -y update && \ - apt-get -y install curl jq python3-pip pipx openssl tcpdump && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* && \ - uv sync --frozen --no-install-project && \ - cp bbot_server/defaults_docker.yml bbot_server/defaults.yml && \ - uv sync --frozen && \ - useradd -u 1000 -m bbot && chown -R bbot:bbot /app + apt-get -y install --no-install-recommends \ + # ensure sudo is available to install dependencies for containers operating as non-root agents + sudo curl jq \ + && uv sync --frozen --no-install-project \ + && cp bbot_server/defaults_docker.yml bbot_server/defaults.yml \ + && uv sync --frozen \ + && useradd -u 1000 -m bbot \ + # ensure bbot user can run sudo without a password in order to install dependencies for containers operating as non-root agents + && echo "bbot ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/bbot \ + && chown -R bbot:bbot /app USER bbot From 97b65a4647ca15c6fe629d54ee1263e179fada52 Mon Sep 17 00:00:00 2001 From: Colin Stubbs <3059577+colin-stubbs@users.noreply.github.com> Date: Sun, 29 Mar 2026 01:03:21 +1000 Subject: [PATCH 8/8] agent needs matching API key --- compose-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/compose-dev.yml b/compose-dev.yml index 1ba6fd24..feeb5729 100644 --- a/compose-dev.yml +++ b/compose-dev.yml @@ -37,6 +37,7 @@ services: retries: 3 start_period: 30s environment: + - BBOT_SERVER_API_KEY=${BBOT_SERVER_API_KEY:-CHANGE_ME} - BBOT_SERVER_AUTH_ENABLED=${BBOT_SERVER_AUTH_ENABLED:-true} - BBOT_SERVER_AUTH_HEADER=${BBOT_SERVER_AUTH_HEADER:-X-API-Key} depends_on: