From 5de904de43a01342d02fa96848e2664781dd3405 Mon Sep 17 00:00:00 2001 From: Basil Zafar Date: Sat, 24 Oct 2026 11:50:09 +0530 Subject: [PATCH 1/2] fix(web): bundle fonts to avoid Google loader build failures --- .../src/app/fonts/IBM-Plex-Mono-LICENSE.txt | 93 ++++++++++++++++++ apps/web/src/app/fonts/README.md | 14 +++ apps/web/src/app/fonts/Rubik-LICENSE.txt | 93 ++++++++++++++++++ .../ibm-plex-mono-latin-400-normal.woff2 | Bin 0 -> 14708 bytes .../ibm-plex-mono-latin-500-normal.woff2 | Bin 0 -> 14888 bytes .../ibm-plex-mono-latin-600-normal.woff2 | Bin 0 -> 15620 bytes .../app/fonts/rubik-latin-wght-normal.woff2 | Bin 0 -> 35348 bytes apps/web/src/app/layout.tsx | 19 ++-- 8 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 apps/web/src/app/fonts/IBM-Plex-Mono-LICENSE.txt create mode 100644 apps/web/src/app/fonts/README.md create mode 100644 apps/web/src/app/fonts/Rubik-LICENSE.txt create mode 100644 apps/web/src/app/fonts/ibm-plex-mono-latin-400-normal.woff2 create mode 100644 apps/web/src/app/fonts/ibm-plex-mono-latin-500-normal.woff2 create mode 100644 apps/web/src/app/fonts/ibm-plex-mono-latin-600-normal.woff2 create mode 100644 apps/web/src/app/fonts/rubik-latin-wght-normal.woff2 diff --git a/apps/web/src/app/fonts/IBM-Plex-Mono-LICENSE.txt b/apps/web/src/app/fonts/IBM-Plex-Mono-LICENSE.txt new file mode 100644 index 0000000..83eac82 --- /dev/null +++ b/apps/web/src/app/fonts/IBM-Plex-Mono-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-ThinItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-ExtraLight.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-ExtraLightItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-Light.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-LightItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-Regular.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-Italic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-Medium.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-MediumItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-SemiBold.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-SemiBoldItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-Bold.ttf: Copyright 2017 IBM Corp. All rights reserved. IBMPlexMono-BoldItalic.ttf: Copyright 2017 IBM Corp. All rights reserved. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/web/src/app/fonts/README.md b/apps/web/src/app/fonts/README.md new file mode 100644 index 0000000..28ae9ec --- /dev/null +++ b/apps/web/src/app/fonts/README.md @@ -0,0 +1,14 @@ +# Bundled UI fonts + +The UI loads Latin Rubik (variable, weights 400–800) and IBM Plex Mono +(weights 400, 500, 600) through `next/font/local`. Builds do not fetch Google +Fonts CSS or font files. + +Unmodified WOFF2 files were extracted from these npm packages, with the archive +SHA-512 checked against the registry's `dist.integrity`: + +- `@fontsource-variable/rubik@5.3.0`: `files/rubik-latin-wght-normal.woff2` +- `@fontsource/ibm-plex-mono@5.3.0`: `files/ibm-plex-mono-latin-{400,500,600}-normal.woff2` + +Both fonts use the SIL Open Font License 1.1. Their copyright notices and +licenses are included beside the font files. Preserve these when updating fonts. diff --git a/apps/web/src/app/fonts/Rubik-LICENSE.txt b/apps/web/src/app/fonts/Rubik-LICENSE.txt new file mode 100644 index 0000000..b25d078 --- /dev/null +++ b/apps/web/src/app/fonts/Rubik-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2015 The Rubik Project Authors (https://github.com/googlefonts/rubik) Rubik-Italic[wght].ttf: Copyright 2015 The Rubik Project Authors (https://github.com/googlefonts/rubik) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/web/src/app/fonts/ibm-plex-mono-latin-400-normal.woff2 b/apps/web/src/app/fonts/ibm-plex-mono-latin-400-normal.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0804aaff92260b5359330f63e05b9ac25ccabeee GIT binary patch literal 14708 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 literal 0 HcmV?d00001 diff --git a/apps/web/src/app/fonts/rubik-latin-wght-normal.woff2 b/apps/web/src/app/fonts/rubik-latin-wght-normal.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..42fc52af04fdce1a7c9072ca2a5510295990fbc1 GIT binary patch literal 35348 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

~+M#_U(F~Vxu#37}2SEn%kv6;{t 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 Date: Sat, 24 Oct 2026 11:59:48 +0530 Subject: [PATCH 2/2] fix(deploy): build non-root Hosted images with data-only storage --- .dockerignore | 8 +++++- .github/workflows/ci.yml | 51 +++++++++++++++++++++++++++++++++++ Dockerfile | 48 +++++++++++++++++++++++++++++++++ SECURITY.md | 28 ++++++++++++++++++++ apps/web/next.config.ts | 1 + docker-compose.yml | 32 +++++++++++----------- docs/COLD_START.md | 57 ++++++++++++++++++++++++++++++++++++++-- railway.toml | 12 +++++---- 8 files changed, 212 insertions(+), 25 deletions(-) create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore index 3274faf..338b8d8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,10 @@ -# Nixpacks/Docker build context — do NOT ignore .mutiny (Docker cannot +# Docker build context — do NOT ignore .mutiny (Docker cannot # re-include files under an excluded parent dir). Sample adapter must ship. .env .env.* !.env.example +**/.env +**/.env.* __pycache__/ *.py[cod] *$py.class @@ -26,5 +28,9 @@ node_modules/ .worktrees/ .vscode/ .idea/ +.git/ +.codex/ +.agents/ +.uv-cache/ apps/web/node_modules/ apps/web/.next/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a912316..84f42b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,6 +140,57 @@ jobs: - name: Build run: npm run build + container-smoke: + name: container-smoke + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + MUTINY_API_TOKEN: container-ci-dummy-token + COMPOSE_PROJECT_NAME: mutiny-ci + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Build and start production images + run: docker compose up --build -d + + - name: Check readiness and container boundaries + run: | + set -euo pipefail + for attempt in $(seq 1 30); do + if curl --fail --silent http://127.0.0.1:8000/api/health >/dev/null && + curl --fail --silent http://127.0.0.1:3000 >/dev/null; then + break + fi + sleep 2 + done + curl --fail http://127.0.0.1:8000/api/health + curl --fail --silent http://127.0.0.1:3000 >/dev/null + # Same-origin proxy must reach the API and inject the runtime token. + curl --fail http://127.0.0.1:3000/api/campaigns + docker compose exec -T api sh -c 'test "$(id -u)" = 10001 && test -w /app/data && test ! -w /app/.venv && test ! -w /app/examples' + docker compose exec -T web sh -c 'test "$(id -u)" != 0' + # The named volume is the only API mount; web has no host mounts. + test "$(docker inspect --format '{{len .Mounts}}' "$(docker compose ps -q api)")" = 1 + test "$(docker inspect --format '{{(index .Mounts 0).Type}}' "$(docker compose ps -q api)")" = volume + test "$(docker inspect --format '{{len .Mounts}}' "$(docker compose ps -q web)")" = 0 + + - name: Confirm missing token fails before listen + run: | + set +e + timeout 15 docker compose run --rm --no-deps -e MUTINY_API_TOKEN= api + status=$? + test "$status" = 2 + + - name: Container logs + if: failure() + run: docker compose logs --no-color + + - name: Clean up test containers and data + if: always() + run: docker compose down -v + package-build: name: package-build runs-on: ubuntu-latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..db083e4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# syntax=docker/dockerfile:1 +FROM python:3.12-slim-bookworm AS api-build +COPY --from=ghcr.io/astral-sh/uv:0.12.23 /uv /usr/local/bin/uv +WORKDIR /app +ENV UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never +COPY pyproject.toml uv.lock ./ +COPY packages ./packages +COPY apps/api ./apps/api +COPY apps/demo_agent ./apps/demo_agent +RUN uv sync --locked --no-dev --no-editable --package mutiny-api + +FROM node:22-bookworm-slim AS web-build +WORKDIR /app +ENV NEXT_TELEMETRY_DISABLED=1 +COPY apps/web/package.json apps/web/package-lock.json ./ +RUN npm ci +COPY apps/web ./ +# Next.js rewrites are baked into the build. Never pass the API token here. +ARG MUTINY_API_URL=http://api:8000 +ENV MUTINY_API_URL=$MUTINY_API_URL +RUN npm run build + +FROM node:22-bookworm-slim AS web +WORKDIR /app +ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0 PORT=3000 +COPY --from=web-build --chown=node:node /app/.next/standalone ./ +COPY --from=web-build --chown=node:node /app/.next/static ./.next/static +USER node +EXPOSE 3000 +CMD ["node", "server.js"] + +# Keep API last: Railway builds this default target from the repository root. +FROM python:3.12-slim-bookworm AS api +WORKDIR /app +ENV PATH="/app/.venv/bin:$PATH" \ + PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 \ + MUTINY_DB_PATH=/app/data/mutiny.sqlite +RUN groupadd --gid 10001 mutiny && useradd --uid 10001 --gid mutiny --no-create-home mutiny \ + && mkdir /app/data && chown mutiny:mutiny /app/data +COPY --from=api-build /app/.venv /app/.venv +COPY examples ./examples +COPY config ./config +COPY scripts/ensure_sample_mutiny.py ./scripts/ensure_sample_mutiny.py +# Preserve the Railway sample-ensure behavior, but prepare files during build. +RUN python scripts/ensure_sample_mutiny.py +USER 10001:10001 +EXPOSE 8000 +CMD ["python", "-m", "mutiny_api", "--host", "0.0.0.0", "--port", "8000"] diff --git a/SECURITY.md b/SECURITY.md index 40e1216..50dfc69 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -129,6 +129,34 @@ mutiny db restore --from /secure/backups/mutiny-YYYYMMDD.sqlite --db /path/to/mu **Not provided:** automated off-site replication, PostgreSQL, or Web `POST /api/db/*` endpoints. +## Container deployment (MUT-012 / #63) + +Compose builds the API and production Next.js UI from the root Dockerfile. +Python dependencies are installed with `uv sync --locked` and JavaScript +dependencies with `npm ci` during image build. Restarts use the built virtual +environment / standalone server; no package installation occurs at startup. +Rebuild images to apply dependency or base-image updates. Lockfiles constrain +application dependencies; image tags and build tooling still require trusted +registries and a trusted build environment. + +The API runs as UID/GID 10001 and the UI as the image's `node` user. Source and +dependencies in the API image are root-owned. Compose mounts only the named +`mutiny-data` volume at `/app/data`, with no host checkout bind mount. Both host +ports bind to `127.0.0.1`. The API still listens on `0.0.0.0` inside its container +and requires `MUTINY_API_TOKEN` through `python -m mutiny_api` before listening. + +The UI proxies that shared operator token for its visitors. Keep it on a trusted +local machine: exposing port 3000 through a public proxy requires separate +access control. Non-root execution and restricted mounts reduce host exposure; +containers still share the host kernel and are not a sandbox for hostile agents. + +Railway builds the default API image and uses its installed Python environment. +Its startup keeps the existing sample-ensure check; customer execution remains +removed. Configure a persistent volume at `/app/data` writable by UID/GID 10001 +if durable storage is needed. New Docker named volumes inherit image directory +ownership; existing or externally provisioned volumes need permissions set by +the operator. See [COLD_START](./docs/COLD_START.md) for commands and backup notes. + ## Reporting a vulnerability Please **do not** open a public GitHub issue for security-sensitive reports. diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 83022ed..e10402a 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -3,6 +3,7 @@ import type { NextConfig } from "next"; const API = process.env.MUTINY_API_URL || "http://127.0.0.1:8000"; const nextConfig: NextConfig = { + output: "standalone", async rewrites() { return [ { diff --git a/docker-compose.yml b/docker-compose.yml index a82a2b3..7d1d7d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,12 @@ services: api: - image: python:3.12-slim - working_dir: /app + build: + context: . + target: api volumes: - # Bind-mount keeps MUTINY_DB_PATH (/app/data/...) on the host ./data/ - - .:/app - command: > - bash -lc "pip install -q uv && uv sync && - PYTHONPATH=apps/api/src:apps/demo_agent/src:packages/mutiny_core/src - uv run python -m mutiny_api --host 0.0.0.0 --port 8000" + - mutiny-data:/app/data ports: - - "8000:8000" + - "127.0.0.1:8000:8000" environment: # Honored by mutiny_api.db.resolve_db_path (M-PR4). - MUTINY_DB_PATH=/app/data/mutiny.sqlite @@ -18,18 +14,20 @@ services: # Set the same value on `web` so the Next rewrite can inject Authorization. - MUTINY_API_TOKEN=${MUTINY_API_TOKEN:?set MUTINY_API_TOKEN for non-loopback Hosted} web: - image: node:22-bookworm - working_dir: /app/apps/web - volumes: - - .:/app - command: bash -lc "npm install && npm run dev -- --hostname 0.0.0.0 --port 3000" + build: + context: . + target: web + args: + MUTINY_API_URL: http://api:8000 ports: - - "3000:3000" + - "127.0.0.1:3000:3000" depends_on: - api environment: - - WATCHPACK_POLLING=true # Same token as `api` so middleware can inject Authorization on rewrites. # Use the Docker service hostname — 127.0.0.1 is wrong inside this container. - MUTINY_API_TOKEN=${MUTINY_API_TOKEN:?set MUTINY_API_TOKEN for non-loopback Hosted} - - MUTINY_API_URL=http://api:8000 + # API destination is set at image build time above. + +volumes: + mutiny-data: diff --git a/docs/COLD_START.md b/docs/COLD_START.md index 50282b4..4169e7a 100644 --- a/docs/COLD_START.md +++ b/docs/COLD_START.md @@ -3,7 +3,7 @@ | Field | Value | |---|---| | **Status** | Canonical clean-machine bootstrap | -| **Last updated** | 2026-08-09 | +| **Last updated** | 2026-10-24 | | **Pin** | [`config/demo_pin.json`](../config/demo_pin.json) | Use this on a clean machine. Competitive claims stay frozen to [COMPETITOR_ANALYSIS.md](./COMPETITOR_ANALYSIS.md). @@ -86,7 +86,60 @@ Verify: - [ ] Open `http://127.0.0.1:3000` — safety banner visible - [ ] Narrative: sample/reference agent, not “this is the product” -**docker-compose:** use when you want containerized API + web (`docker compose up --build`). Prefer `scripts/dev.sh` for local iteration. Compose sets `MUTINY_DB_PATH=/app/data/mutiny.sqlite` (honored by the API). The bind mount `.:/app` keeps that file on the host under `./data/`; there is no separate named volume. Compose binds the API to `0.0.0.0`, so **`MUTINY_API_TOKEN` is required** (P0-1/P0-4) — unset/empty fails closed before listen. Set the same value on `api` and `web`. Compose also sets `MUTINY_API_URL=http://api:8000` on `web` so Next rewrites reach the API service (not `127.0.0.1`). +### Containerized local demo (MUT-012 / #63) + +Set `MUTINY_API_TOKEN` in your shell or an uncommitted `.env` file, then run: + +```bash +docker compose up --build -d +curl -f http://127.0.0.1:8000/api/health +# Open http://127.0.0.1:3000 +docker compose down +``` + +Both host ports publish only on `127.0.0.1`. The UI acts for its visitors using +the operator token, so keep it local or behind your own authenticated proxy. +Compose passes the same token to both services. The API's internal `0.0.0.0` +bind still fails closed without a token; the supported entrypoint remains +`python -m mutiny_api`. + +Dependencies are installed at image build (`uv sync --locked --no-dev +--no-editable --package mutiny-api`, `npm ci`, `npm run build`). Runtime uses +non-root users and the prebuilt Python environment / Next.js standalone server. +Rebuild after dependency or source changes; use `scripts/dev.sh` for hot reload. +The web image's API rewrite destination is a **build argument**, +`MUTINY_API_URL` (Compose: `http://api:8000`), because Next.js bakes rewrites into +its build. The token is runtime-only; never supply it as a build argument. + +Only a named `mutiny-data` volume is mounted at `/app/data`; neither container +mounts the host checkout. The database is `/app/data/mutiny.sqlite`, not the +host's `./data/mutiny.sqlite`. `docker compose down` retains the volume; +`docker compose down -v` deletes it. To back it up using the documented SQLite +backup API, stage the backup inside the volume and copy it out: + +```bash +docker compose exec api python -c "import sqlite3; source=sqlite3.connect('/app/data/mutiny.sqlite'); dest=sqlite3.connect('/app/data/backup.sqlite'); source.backup(dest); dest.close(); source.close()" +docker compose cp api:/app/data/backup.sqlite ./mutiny-backup.sqlite +``` + +Keep backups private. Existing host `./data/` databases are not migrated +automatically; back them up and restore deliberately before switching. An +existing volume or an optional data-only bind mount must be writable by API +UID/GID `10001:10001`; fresh named volumes inherit image directory ownership. + +### Railway API image + +`railway.toml` selects the root Dockerfile's final `api` stage. Build dependencies +are already installed; startup runs the existing sample-ensure check and then +`python -m mutiny_api`, expanding Railway's `PORT`. Set `MUTINY_API_TOKEN` in the +service environment. No `uv sync` or package manager runs at boot. The sample +files are prepared during image build, preserving the existing ensure behavior +(MUT-066 is separate). + +For persistence, attach a volume at `/app/data` with ownership allowing UID/GID +`10001:10001` to write it. Without a volume, database state is ephemeral across +replacement deployments. This change does not provide public UI authentication +or multi-tenant isolation; see [SECURITY.md](../SECURITY.md#container-deployment-mut-012--63). --- diff --git a/railway.toml b/railway.toml index 922bf05..14377a9 100644 --- a/railway.toml +++ b/railway.toml @@ -1,12 +1,14 @@ # Mutiny Hosted API — Railway deploy from monorepo root [build] -builder = "nixpacks" +builder = "DOCKERFILE" +dockerfilePath = "Dockerfile" +# The final Dockerfile stage is the API image. [deploy] # Non-loopback bind (0.0.0.0) requires MUTINY_API_TOKEN (P0-1/P0-4); # python -m mutiny_api fails closed before listen if missing/empty. -# Sample .mutiny may be stripped from the image (Docker cannot re-include under -# an excluded .mutiny/ parent). Always ensure adapter exists before listen. -startCommand = "uv sync && mkdir -p data && uv run python scripts/ensure_sample_mutiny.py && uv run python -m mutiny_api --host 0.0.0.0 --port ${PORT:-8000}" -restartPolicyType = "on_failure" +# Keep the existing sample-ensure step (MUT-066 is separate). The image already +# prepares these files at build time, so this is normally a read-only check. +startCommand = "sh -c 'python scripts/ensure_sample_mutiny.py && exec python -m mutiny_api --host 0.0.0.0 --port ${PORT:-8000}'" +restartPolicyType = "ON_FAILURE" restartPolicyMaxRetries = 10