-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContainerfile
More file actions
134 lines (115 loc) · 6.42 KB
/
Containerfile
File metadata and controls
134 lines (115 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# OpenClaw — Crunchtools Autonomous Agent
# General-purpose AI assistant with Signal integration, running under
# the crunchtools Autonomous Agent constitution profile.
#
# Build:
# podman build -t quay.io/crunchtools/openclaw .
#
# Run:
# podman run -d --name openclaw \
# --read-only --tmpfs /tmp:rw,nosuid \
# -p 127.0.0.1:18789:18789 \
# -v /srv/openclaw.crunchtools.com/data/openclaw:/app/.openclaw:Z \
# -v /srv/openclaw.crunchtools.com/signal/data:/app/.local/share/signal-cli:Z \
# -v /srv/openclaw.crunchtools.com/logs:/app/logs:Z \
# --env-file /srv/openclaw.crunchtools.com/config/env \
# quay.io/crunchtools/openclaw
# Stage 1: Install OpenClaw and dependencies
# Use UBI 10 Minimal as builder — Hummingbird lacks git which
# OpenClaw's npm dependencies require for installation
FROM registry.access.redhat.com/ubi10/ubi-minimal AS builder
RUN microdnf install -y nodejs npm git tar gzip && microdnf clean all
WORKDIR /build
# Install OpenClaw at a pinned version — update this on upgrades
# --legacy-peer-deps on the in-package overrides: re-resolving OpenClaw's dev
# tree otherwise fails on an upstream peer conflict (oxlint vs oxlint-tsgolint).
RUN npm install --global --prefix /build/install openclaw@2026.5.22 && \
cd /build/install/lib/node_modules/openclaw && \
npm install @hono/node-server@1.19.10 --save --legacy-peer-deps && \
npm install tar@7.5.11 --legacy-peer-deps && \
npm install fast-xml-parser@5.5.6 --legacy-peer-deps && \
npm install glob@10.5.0 --legacy-peer-deps && \
npm install minimatch@9.0.7 --legacy-peer-deps && \
find node_modules -mindepth 3 -path "*/@hono/node-server" -type d -exec rm -rf {} +
# Install mcporter — MCP server client, required for OpenClaw's mcporter skill
# NOT bundled as an OpenClaw dependency; must be installed separately
ARG MCPORTER_VERSION=0.7.3
RUN npm install --global --prefix /build/mcporter mcporter@${MCPORTER_VERSION}
# Install the clawphone Twilio SMS plugin as a BUNDLED OpenClaw extension
# (pinned). We bundle it into dist/extensions rather than `openclaw plugins
# install` at runtime because the runtime image is read-only + npm-stripped and
# ~/.openclaw is a bind-mounted volume — a runtime install neither persists nor
# survives a separately-built image (its registry is build-fingerprinted).
# Bundling also means OpenClaw's install-time "dangerous code" scanner does not
# apply: clawphone uses child_process.spawn to bridge inbound SMS to
# `openclaw agent` (reviewed safe — args array, no shell, hardcoded args).
# Re-vet on every version bump. Ships DISABLED; enable + configure in config.
ARG CLAWPHONE_VERSION=1.2.0
RUN npm install --prefix /build/cphone @ranacseruet/clawphone@${CLAWPHONE_VERSION} --legacy-peer-deps && \
mkdir -p /build/cphone-ext && \
cp -a /build/cphone/node_modules/@ranacseruet/clawphone/. /build/cphone-ext/ && \
cp -a /build/cphone/node_modules /build/cphone-ext/node_modules
# Download signal-cli native binary (GraalVM, no JVM required)
ARG SIGNAL_CLI_VERSION=0.14.0
RUN curl -sL "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux-native.tar.gz" \
-o /tmp/signal-cli.tar.gz && \
mkdir -p /build/signal-cli/bin && \
tar xf /tmp/signal-cli.tar.gz -C /build/signal-cli/bin && \
chmod +x /build/signal-cli/bin/signal-cli && \
rm /tmp/signal-cli.tar.gz
# Stage 2: Runtime image — minimal, no build tools
# Hummingbird images are immutable (/etc/passwd, /home are read-only)
# so we use /app as the working directory (same pattern as mcp-github)
FROM quay.io/hummingbird/nodejs:22
LABEL name="openclaw-crunchtools" \
version="1.0.0" \
summary="OpenClaw autonomous agent under crunchtools constitution" \
description="General-purpose AI assistant with Signal channel, MCP server governance, and behavioral circuit breakers" \
maintainer="crunchtools.com" \
io.k8s.display-name="OpenClaw CrunchTools" \
org.opencontainers.image.source="https://github.com/crunchtools/openclaw" \
org.opencontainers.image.description="OpenClaw autonomous agent — crunchtools deployment" \
org.opencontainers.image.licenses="MIT"
WORKDIR /app
# Copy installed OpenClaw from builder into /app
COPY --from=builder /build/install /app
# Bundle the clawphone Twilio SMS extension into OpenClaw's stock extensions
# directory. Ships DISABLED — enable + configure (Twilio creds, cloudflared
# tunnel URL, allowlist) via openclaw.json when the A2P campaign is live.
COPY --from=builder /build/cphone-ext /app/lib/node_modules/openclaw/dist/extensions/clawphone
# Copy signal-cli native binary
COPY --from=builder /build/signal-cli /app/signal-cli
# Copy mcporter
COPY --from=builder /build/mcporter /app/mcporter
# Remove npm/npx from the runtime — OpenClaw needs only the `node` runtime to
# run; npm is a build-time package manager. Takeda launches MCP servers over
# HTTP (no npx/stdio), and the image is read-only with deps baked in, so npm is
# never invoked at runtime. Dropping it eliminates the base image's bundled-npm
# CVEs (e.g. picomatch ReDoS) and shrinks the attack surface.
#
# Why strip rather than pick an npm-less base: npm ships inside the Node.js RPM
# in EVERY Hummingbird nodejs variant — confirmed via the catalog SBOM, the
# distroless `default` runtime still lists @npmcli/* as runtime packages. There
# is no npm-less Node runtime image to switch to, and the distroless runtime has
# no dnf to remove it cleanly, so stripping the npm dir + symlinks post-COPY is
# the correct (and only) way to get an npm-free Node runtime.
#
# Briefly switch to root to delete the root-owned base-image files, then
# restore the non-root runtime user (65532).
USER root
RUN rm -rf /usr/lib/node_modules_22/npm \
/usr/bin/npm /usr/bin/npx \
/usr/sbin/npm /usr/sbin/npx
USER 65532
ENV PATH="/app/bin:/app/mcporter/bin:/app/signal-cli/bin:${PATH}" \
NODE_ENV=production \
HOME=/app
EXPOSE 18789
# Health check — OpenClaw gateway health probe
HEALTHCHECK --interval=60s --timeout=10s --start-period=30s --retries=3 \
CMD openclaw health --json || exit 1
# Bind 0.0.0.0 inside container — host-side restriction is handled by
# podman's -p 127.0.0.1:18789:18789 (loopback-only on the host).
# Using --bind loopback here would bind to the container's own 127.0.0.1,
# which is unreachable through bridge networking's DNAT port mapping.
ENTRYPOINT ["openclaw", "gateway", "run", "--bind", "lan"]