- New non-root user 'lore' (uid 10001) created early so --chown works on subsequent COPYs. The final USER directive means everything reachable from the MCP wire (pickle load, 36 tools including 12 mutators) runs as UID 10001, not root. - --chown=lore:lore on all COPY lines. - Removed the redundant .graph.pkl COPY (the file is bundled via the lore_engine_poc/ directory copy, but the explicit line was hiding that — restore the 'override at runtime' instruction in the README). - New test: test_docker_runs_as_non_root — execs 'id -u' inside the container and asserts the uid is non-zero. Co-Authored-By: Claude <noreply@anthropic.com>
48 lines
1.8 KiB
Docker
48 lines
1.8 KiB
Docker
# syntax=docker/dockerfile:1.6
|
|
# Lore Engine POC MCP server — Streamable HTTP transport (slice 11.4).
|
|
FROM python:3.12-slim
|
|
|
|
# Sane Python defaults
|
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
PYTHONUNBUFFERED=1 \
|
|
PIP_NO_CACHE_DIR=1 \
|
|
LORE_HTTP_HOST=0.0.0.0 \
|
|
LORE_HTTP_PORT=8765
|
|
|
|
# Create a non-root user early so subsequent --chown works and so the
|
|
# final USER directive doesn't need to chown retroactively.
|
|
RUN groupadd --system --gid 10001 lore \
|
|
&& useradd --system --uid 10001 --gid lore --no-create-home --home-dir /app lore
|
|
|
|
WORKDIR /app
|
|
|
|
# Layer 1: requirements (cache-friendly; rebuilds only when deps change)
|
|
COPY --chown=lore:lore requirements.txt ./
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
# Layer 2: source tree. The pre-built graph (165 KB) lives at
|
|
# lore_engine_poc/.graph.pkl and rides along in this layer. For larger
|
|
# codexes, override at run time with:
|
|
# docker run -v $PWD/data:/data -e LORE_GRAPH_PATH=/data/.graph.pkl
|
|
COPY --chown=lore:lore lore_engine_poc ./lore_engine_poc
|
|
COPY --chown=lore:lore scripts ./scripts
|
|
|
|
EXPOSE 8765
|
|
|
|
# Drop root. Anything reachable from the MCP wire (pickle load, 36
|
|
# tools including 12 mutators) now runs as UID 10001, not root.
|
|
USER lore
|
|
|
|
# Healthcheck: same JSON-RPC path an MCP client would use.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
|
CMD python -c "import json, urllib.request; \
|
|
req = urllib.request.Request('http://127.0.0.1:8765/mcp', \
|
|
method='POST', \
|
|
data=json.dumps({'jsonrpc':'2.0','id':1,'method':'initialize','params':{}}).encode(), \
|
|
headers={'Content-Type':'application/json','Accept':'application/json'}); \
|
|
r = json.loads(urllib.request.urlopen(req, timeout=3).read()); \
|
|
assert r['result']['protocolVersion'] == '2024-11-05'" \
|
|
|| exit 1
|
|
|
|
CMD ["python", "scripts/06_mcp_http_server.py", "--host", "0.0.0.0"]
|