-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDockerfile
More file actions
167 lines (135 loc) · 5.63 KB
/
Dockerfile
File metadata and controls
167 lines (135 loc) · 5.63 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# Customize this to your heart's desire!
# Stage 1: Get Chrome/Chromium from chromedp/headless-shell
FROM docker.io/chromedp/headless-shell:stable AS chrome
# Stage 2: Main application image
FROM ubuntu:24.04
# Git configuration arguments
ARG GIT_USER_NAME="Container User"
ARG GIT_USER_EMAIL="user@example.com"
# Switch from dash to bash by default.
SHELL ["/bin/bash", "-euxo", "pipefail", "-c"]
RUN echo 'Acquire::Queue-Mode "access";' > /etc/apt/apt.conf.d/99parallel
# attempt to keep package installs lean
RUN printf '%s\n' \
'path-exclude=/usr/share/man/*' \
'path-exclude=/usr/share/doc/*' \
'path-exclude=/usr/share/doc-base/*' \
'path-exclude=/usr/share/info/*' \
'path-exclude=/usr/share/locale/*' \
'path-exclude=/usr/share/groff/*' \
'path-exclude=/usr/share/lintian/*' \
'path-exclude=/usr/share/zoneinfo/*' \
> /etc/dpkg/dpkg.cfg.d/01_nodoc
RUN apt-get update; \
apt-get install -y --no-install-recommends tmux \
ca-certificates wget \
git jq sqlite3 gh ripgrep fzf python3 curl vim lsof iproute2 less \
docker.io docker-compose-v2 docker-buildx \
make python3-pip python-is-python3 tree net-tools file build-essential \
pipx cargo psmisc bsdmainutils openssh-client sudo \
unzip util-linux xz-utils \
backblaze-b2 atop btop htop \
tini \
libglib2.0-0 libnss3 libx11-6 libxcomposite1 libxdamage1 \
libxext6 libxi6 libxrandr2 libgbm1 libgtk-3-0 \
fonts-noto-color-emoji fonts-symbola && \
fc-cache -f -v && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /usr/share/{doc,doc-base,info,lintian,man,groff,locale,zoneinfo}/*
# Create non-root user 'agent' and add to sudoers
RUN useradd -m -s /bin/bash agent && \
echo "agent ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Install Node.js 22 via nodeenv and install CLIs (claude, codex, happy) using that npm
RUN pipx install nodeenv && \
NODE_VER=$(curl -fsSL https://nodejs.org/dist/index.json | jq -r '[.[] | select(.version | startswith("v22."))][0].version' | sed 's/^v//') && \
echo "Installing Node.js ${NODE_VER} via nodeenv" && \
/root/.local/bin/nodeenv --node=${NODE_VER} /opt/node22
# Ensure nodeenv binaries are preferred and npm globals go into /opt/node22
ENV PATH="/opt/node22/bin:${PATH}"
ENV NPM_CONFIG_PREFIX="/opt/node22"
ENV NPM_CONFIG_UPDATE_NOTIFIER="false"
# Install CLI tools globally using nodeenv's npm and verify
RUN npm i -g @openai/codex happy-coder @google/gemini-cli && \
npm cache clean --force || true && \
command -v codex && command -v happy && command -v gemini
# Install Playwright MCP server
RUN npm i -g playwright @playwright/mcp && \
npm cache clean --force || true
# RUN claude mcp add playwright npx @playwright/mcp@latest
RUN playwright install chromium --with-deps --only-shell
# RUN codex mcp add playwright mcp-server-playwright --browser chromium
RUN echo '{"storage-driver":"vfs", "bridge":"none", "iptables":false, "ip-forward": false}' \
> /etc/docker/daemon.json
ENV GO_VERSION=1.25.5
ENV GOROOT=/usr/local/go
ENV GOPATH=/go
ENV PATH=$GOROOT/bin:$GOPATH/bin:$PATH
RUN ARCH=$(uname -m) && \
case $ARCH in \
x86_64) GOARCH=amd64 ;; \
aarch64) GOARCH=arm64 ;; \
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
esac && \
wget -O go.tar.gz "https://golang.org/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" && \
tar -C /usr/local -xzf go.tar.gz && \
rm go.tar.gz
# Create GOPATH directory
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 755 "$GOPATH"
# While these binaries install generally useful supporting packages,
# the specific versions are rarely what a user wants so there is no
# point polluting the base image module with them.
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
go install golang.org/x/tools/cmd/goimports@latest; \
go install golang.org/x/tools/gopls@latest; \
go install mvdan.cc/gofumpt@latest
# Build differing from source
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
git clone https://github.com/philz/differing.git /tmp/differing && \
true && cd /tmp/differing && \
make && \
cp differing $GOPATH/bin/ && \
rm -rf /tmp/differing
# Build tsproxy
COPY tsproxy /tmp/tsproxy
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
cd /tmp/tsproxy && \
go build -o $GOPATH/bin/tsproxy . && \
rm -rf /tmp/tsproxy
# Build headless
COPY headless /tmp/headless
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
cd /tmp/headless && \
go build -o $GOPATH/bin/headless ./cmd/headless && \
rm -rf /tmp/headless
# Build yatty
COPY yatty /tmp/yatty
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
cd /tmp/yatty && \
go build -o $GOPATH/bin/yatty . && \
rm -rf /tmp/yatty
# Copy the self-contained Chrome bundle from chromedp/headless-shell
COPY --from=chrome /headless-shell /headless-shell
ENV PATH="/headless-shell:${PATH}"
# Set ownership of key directories to agent user
RUN chown -R agent:agent /opt/node22 /go
# Switch to agent user
USER agent
# Install uv
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
# Configure git with build-time arguments
RUN git config --global user.name "${GIT_USER_NAME}" && git config --global user.email "${GIT_USER_EMAIL}"
# Install Claude Code native binary (as agent user so it goes to ~/.claude/bin)
RUN date && curl -fsSL https://claude.ai/install.sh | bash
RUN rm ~/.claude.json
ENV PATH="/home/agent/.claude/bin:${PATH}"
# Install subtrace
RUN curl -fsSL https://subtrace.dev/install.sh | sh
WORKDIR /home/agent
# Use tini as init system
# ENTRYPOINT ["/usr/bin/tini", "--"]