-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathDockerfile
More file actions
185 lines (174 loc) · 9.72 KB
/
Dockerfile
File metadata and controls
185 lines (174 loc) · 9.72 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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# BASE_IMAGE allows customization of the base Ubuntu image for closer parity
# with GitHub Actions runner environments. Options:
# - ubuntu:22.04 (default): Minimal image, smallest size (~200MB)
# - ghcr.io/catthehacker/ubuntu:runner-22.04: Closer to GitHub Actions runner (~2-5GB)
# - ghcr.io/catthehacker/ubuntu:full-22.04: Near-identical to GitHub Actions runner (~20GB compressed)
# Use --build-arg BASE_IMAGE=<image> to customize
# NOTE: ARG declared before first FROM is global and available in all FROM statements
ARG BASE_IMAGE=ubuntu:22.04
FROM ${BASE_IMAGE}
# Optionally switch to Azure apt mirror for faster package fetches in CI
# Only rewrite if azure.archive.ubuntu.com is resolvable (BuildKit DNS can fail)
# Falls back to default archive.ubuntu.com which is universally reachable
RUN if getent hosts azure.archive.ubuntu.com >/dev/null 2>&1; then \
echo "Using Azure apt mirror (DNS resolved successfully)"; \
if [ -f /etc/apt/sources.list ]; then \
sed -i 's|http://archive.ubuntu.com|http://azure.archive.ubuntu.com|g' /etc/apt/sources.list; \
sed -i 's|http://security.ubuntu.com|http://azure.archive.ubuntu.com|g' /etc/apt/sources.list; \
fi; \
if [ -d /etc/apt/sources.list.d ]; then \
find /etc/apt/sources.list.d -name '*.sources' -exec \
sed -i 's|http://archive.ubuntu.com|http://azure.archive.ubuntu.com|g' {} + 2>/dev/null || true; \
find /etc/apt/sources.list.d -name '*.sources' -exec \
sed -i 's|http://security.ubuntu.com|http://azure.archive.ubuntu.com|g' {} + 2>/dev/null || true; \
fi; \
else \
echo "Azure apt mirror not reachable, using default archive.ubuntu.com"; \
fi
# Install required packages and Node.js 22
# Note: Some packages may already exist in runner-like base images, apt handles this gracefully
# apt_update_retry: retries up to 3 times with backoff; if all fail, reverts to archive.ubuntu.com
RUN set -eux; \
apt_update_retry() { \
local i; for i in 1 2 3; do \
rm -rf /var/lib/apt/lists/* && apt-get update 2>&1 | tee /tmp/apt-update.log && \
if ! grep -q "Failed to fetch" /tmp/apt-update.log; then return 0; fi; \
echo "apt-get update attempt $i/3 had fetch failures, retrying in $((i*10))s..." >&2; sleep $((i*10)); \
done; \
echo "All apt-get update retries failed, falling back to archive.ubuntu.com..." >&2; \
if [ -f /etc/apt/sources.list ]; then \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' /etc/apt/sources.list; \
sed -i 's|http://security.ubuntu.com|http://archive.ubuntu.com|g' /etc/apt/sources.list 2>/dev/null || true; \
fi; \
if [ -d /etc/apt/sources.list.d ]; then \
find /etc/apt/sources.list.d -name '*.sources' -exec \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' {} + 2>/dev/null || true; \
fi; \
rm -rf /var/lib/apt/lists/* && apt-get update; \
}; \
PKGS="iptables curl ca-certificates git gh gnupg dnsutils net-tools netcat-openbsd gosu libcap2-bin"; \
apt_update_retry && \
( apt-get install -y --no-install-recommends $PKGS || \
(echo "apt-get install failed, retrying with fresh package index..." && \
apt_update_retry && \
apt-get install -y --no-install-recommends $PKGS) ) && \
# Prefer system binaries over runner toolcache (e.g., act images) for Node checks.
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH" && \
# Install Node.js 22 from NodeSource
# Check if Node.js 22 is already installed (common in runner images)
if ! command -v node >/dev/null 2>&1 || ! node --version | grep -qE '^v22\.'; then \
# Remove any existing nodejs packages first to avoid conflicts
apt-get remove -y nodejs npm || true && \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt-get install -y nodejs && \
# Verify Node.js 22 was installed correctly
node --version | grep -q "^v22\." || (echo "ERROR: Node.js 22 not installed correctly" && exit 1) && \
npx --version || (echo "ERROR: npx not found" && exit 1); \
fi && \
rm -rf /var/lib/apt/lists/*
# Install additional system packages for GitHub Actions runner parity
# These packages are commonly needed by workflows and avoid agents spending time installing them manually
# See: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
RUN set -eux; \
apt_update_retry() { \
local i; for i in 1 2 3; do \
rm -rf /var/lib/apt/lists/* && apt-get update 2>&1 | tee /tmp/apt-update.log && \
if ! grep -q "Failed to fetch" /tmp/apt-update.log; then return 0; fi; \
echo "apt-get update attempt $i/3 had fetch failures, retrying in $((i*10))s..." >&2; sleep $((i*10)); \
done; \
echo "All apt-get update retries failed, falling back to archive.ubuntu.com..." >&2; \
if [ -f /etc/apt/sources.list ]; then \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' /etc/apt/sources.list; \
fi; \
if [ -d /etc/apt/sources.list.d ]; then \
find /etc/apt/sources.list.d -name '*.sources' -exec \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' {} + 2>/dev/null || true; \
fi; \
rm -rf /var/lib/apt/lists/* && apt-get update; \
}; \
PARITY_PKGS="libgdiplus libev-dev libssl-dev php-intl php-gd"; \
apt_update_retry && \
( apt-get install -y --no-install-recommends $PARITY_PKGS || \
(echo "apt-get install failed, retrying with fresh package index..." && \
apt_update_retry && \
apt-get install -y --no-install-recommends $PARITY_PKGS) ) && \
rm -rf /var/lib/apt/lists/*
# Upgrade all packages to pick up security patches
# Addresses CVE-2023-44487 (HTTP/2 Rapid Reset) and other known vulnerabilities
# Retry logic handles transient mirror sync failures during apt-get update
RUN apt_update_retry() { \
local i; for i in 1 2 3; do \
rm -rf /var/lib/apt/lists/* && apt-get update 2>&1 | tee /tmp/apt-update.log && \
if ! grep -q "Failed to fetch" /tmp/apt-update.log; then return 0; fi; \
echo "apt-get update attempt $i/3 had fetch failures, retrying in $((i*10))s..." >&2; sleep $((i*10)); \
done; \
echo "All apt-get update retries failed, falling back to archive.ubuntu.com..." >&2; \
if [ -f /etc/apt/sources.list ]; then \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' /etc/apt/sources.list; \
fi; \
if [ -d /etc/apt/sources.list.d ]; then \
find /etc/apt/sources.list.d -name '*.sources' -exec \
sed -i 's|http://azure.archive.ubuntu.com|http://archive.ubuntu.com|g' {} + 2>/dev/null || true; \
fi; \
rm -rf /var/lib/apt/lists/* && apt-get update; \
}; \
apt_update_retry && \
apt-get upgrade -y && rm -rf /var/lib/apt/lists/* || \
(echo "apt-get upgrade failed, retrying with fresh package index..." && \
apt_update_retry && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*)
# Create non-root user with UID/GID matching host user
# This allows the user command to run with appropriate permissions
# and prevents file ownership issues with mounted volumes
ARG USER_UID=1000
ARG USER_GID=1000
RUN if ! getent group awfuser >/dev/null 2>&1; then \
if ! getent group ${USER_GID} >/dev/null 2>&1; then \
groupadd -g ${USER_GID} awfuser; \
else \
groupadd awfuser; \
fi; \
fi && \
if ! id -u awfuser >/dev/null 2>&1; then \
if ! getent passwd ${USER_UID} >/dev/null 2>&1; then \
useradd -u ${USER_UID} -g awfuser -m -s /bin/bash awfuser; \
else \
useradd -g awfuser -m -s /bin/bash awfuser; \
fi; \
fi && \
# Create directories for awfuser
mkdir -p /home/awfuser/.copilot/logs && \
chown -R awfuser:awfuser /home/awfuser
# Copy iptables setup script, PID logger, API proxy health check, Claude key helper,
# and gh CLI proxy wrapper (used when --enable-cli-proxy is active)
COPY setup-iptables.sh /usr/local/bin/setup-iptables.sh
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
COPY pid-logger.sh /usr/local/bin/pid-logger.sh
COPY api-proxy-health-check.sh /usr/local/bin/api-proxy-health-check.sh
COPY get-claude-key.sh /usr/local/bin/get-claude-key.sh
COPY gh-cli-proxy-wrapper.sh /usr/local/bin/gh-cli-proxy-wrapper.sh
RUN chmod +x /usr/local/bin/setup-iptables.sh /usr/local/bin/entrypoint.sh /usr/local/bin/pid-logger.sh /usr/local/bin/api-proxy-health-check.sh /usr/local/bin/get-claude-key.sh /usr/local/bin/gh-cli-proxy-wrapper.sh
# Copy pre-built one-shot-token library from rust-builder stage
# This prevents tokens from being read multiple times (e.g., by malicious code)
# Build flags: -fvisibility=hidden hides internal symbols, -s strips at link time
COPY one-shot-token/one-shot-token.c /tmp/one-shot-token.c
RUN set -eux; \
BUILD_PKGS="gcc libc6-dev binutils"; \
apt-get update && \
( apt-get install -y --no-install-recommends $BUILD_PKGS || \
(rm -rf /var/lib/apt/lists/* && apt-get update && \
apt-get install -y --no-install-recommends $BUILD_PKGS) ) && \
gcc -shared -fPIC -fvisibility=hidden -O2 -Wall -s \
-o /usr/local/lib/one-shot-token.so /tmp/one-shot-token.c -ldl -lpthread && \
strip --strip-unneeded /usr/local/lib/one-shot-token.so && \
rm /tmp/one-shot-token.c && \
apt-get remove -y $BUILD_PKGS && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*
# Install Docker stub script that shows helpful error message
# Docker-in-Docker support was removed in v0.9.1
COPY docker-stub.sh /usr/bin/docker
RUN chmod +x /usr/bin/docker
# Set working directory
WORKDIR /workspace
# Use entrypoint to setup iptables and run command
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]