-
Notifications
You must be signed in to change notification settings - Fork 0
318 lines (265 loc) · 11.7 KB
/
build-and-push.yml
File metadata and controls
318 lines (265 loc) · 11.7 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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
name: Build and Push Docker Image
on:
push:
branches:
- master
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
build:
runs-on: ${{ matrix.runs-on }}
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- platform: linux/amd64
runs-on: ubuntu-latest
- platform: linux/arm64
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Get current date for tagging
run: echo "DATE_TAG=$(date +'%Y%m%d')" >> $GITHUB_ENV
- name: Prepare platform pair
run: |
PLATFORM_PAIR=$(echo ${{ matrix.platform }} | tr '/' '-')
echo "PLATFORM_PAIR=$PLATFORM_PAIR" >> $GITHUB_ENV
- name: Set lowercase image name
run: |
echo "IMAGE_NAME=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=short
type=raw,value=${{ github.sha }}
type=raw,value=${{ env.DATE_TAG }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs: build
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Get current date for tagging
run: echo "DATE_TAG=$(date +'%Y%m%d')" >> $GITHUB_ENV
- name: Set lowercase image name
run: |
echo "IMAGE_NAME=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=short
type=raw,value=${{ github.sha }}
type=raw,value=${{ env.DATE_TAG }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
# Build the list of digests
digests=$(find . -type f | while read f; do
digest=$(basename "$f")
echo "${{ env.IMAGE_NAME }}@sha256:${digest}"
done)
# Create and push manifest with all tags
tags="${{ steps.meta.outputs.tags }}"
echo "$tags" | while read -r tag; do
docker buildx imagetools create -t "$tag" $digests
done
- name: Inspect image
run: |
TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1 | tr -d '\n')
docker buildx imagetools inspect "$TAG"
test:
name: Test Image
runs-on: ${{ matrix.runs-on }}
needs: merge
timeout-minutes: 15
permissions:
contents: read
packages: read
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runs-on: ubuntu-latest
- platform: linux/arm64
runs-on: ubuntu-24.04-arm
steps:
- name: Set lowercase image name
run: |
echo "IMAGE_NAME=ghcr.io/$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull image
run: docker pull ${{ env.IMAGE_NAME }}:${{ github.sha }}
- name: Start test container
run: docker run -d --name test-container ${{ env.IMAGE_NAME }}:${{ github.sha }} sleep 600
- name: Test default user is coder
timeout-minutes: 1
run: |
echo "Testing default user is 'coder'..."
USER=$(docker exec test-container whoami)
if [ "$USER" != "coder" ]; then
echo "::error::Default user is '$USER', expected 'coder'"
exit 1
fi
echo "✓ Default user is 'coder'"
- name: Test installed tools accessibility (VS Code terminal simulation)
timeout-minutes: 5
run: |
echo "Testing installed tools accessibility for coder user..."
echo "Using interactive shell (bash -i) to simulate VS Code terminal behavior"
# Test function with timeout
# Uses 'bash -i -c' to simulate VS Code terminal (interactive non-login shell)
# This ensures .bashrc is loaded, matching real VS Code terminal environment
test_tool() {
local tool=$1
local cmd=$2
local timeout_secs=10
if timeout $timeout_secs docker exec test-container bash -i -c "$cmd" > /dev/null 2>&1; then
echo " ✓ $tool is accessible"
return 0
else
echo " ✗ $tool is NOT accessible"
return 1
fi
}
FAILED_TOOLS=""
# Go tools
test_tool "go" "go version" || FAILED_TOOLS="$FAILED_TOOLS go"
test_tool "gopls" "gopls version" || FAILED_TOOLS="$FAILED_TOOLS gopls"
test_tool "dlv" "dlv version" || FAILED_TOOLS="$FAILED_TOOLS dlv"
test_tool "golangci-lint" "golangci-lint --version" || FAILED_TOOLS="$FAILED_TOOLS golangci-lint"
# Python tools
test_tool "python3" "python3 --version" || FAILED_TOOLS="$FAILED_TOOLS python3"
test_tool "pip" "pip --version" || FAILED_TOOLS="$FAILED_TOOLS pip"
test_tool "uv" "uv --version" || FAILED_TOOLS="$FAILED_TOOLS uv"
test_tool "conda" "conda --version" || FAILED_TOOLS="$FAILED_TOOLS conda"
# Node.js tools
test_tool "node" "node --version" || FAILED_TOOLS="$FAILED_TOOLS node"
test_tool "npm" "npm --version" || FAILED_TOOLS="$FAILED_TOOLS npm"
test_tool "pnpm" "pnpm --version" || FAILED_TOOLS="$FAILED_TOOLS pnpm"
test_tool "yarn" "yarn --version" || FAILED_TOOLS="$FAILED_TOOLS yarn"
# Java tools
test_tool "java" "java -version" || FAILED_TOOLS="$FAILED_TOOLS java"
test_tool "mvn" "mvn --version" || FAILED_TOOLS="$FAILED_TOOLS mvn"
# Ruby tools
test_tool "ruby" "ruby --version" || FAILED_TOOLS="$FAILED_TOOLS ruby"
test_tool "gem" "gem --version" || FAILED_TOOLS="$FAILED_TOOLS gem"
test_tool "rails" "rails --version" || FAILED_TOOLS="$FAILED_TOOLS rails"
# System tools
test_tool "git" "git --version" || FAILED_TOOLS="$FAILED_TOOLS git"
test_tool "curl" "curl --version" || FAILED_TOOLS="$FAILED_TOOLS curl"
test_tool "wget" "wget --version" || FAILED_TOOLS="$FAILED_TOOLS wget"
test_tool "vim" "vim --version | head -1" || FAILED_TOOLS="$FAILED_TOOLS vim"
test_tool "kubectl" "kubectl version --client --output=json" || FAILED_TOOLS="$FAILED_TOOLS kubectl"
test_tool "yq" "yq --version" || FAILED_TOOLS="$FAILED_TOOLS yq"
# Database and Middleware clients
test_tool "mysql" "mysql --version" || FAILED_TOOLS="$FAILED_TOOLS mysql"
test_tool "psql" "psql --version" || FAILED_TOOLS="$FAILED_TOOLS psql"
test_tool "redis-cli" "redis-cli --version" || FAILED_TOOLS="$FAILED_TOOLS redis-cli"
test_tool "docker" "docker --version" || FAILED_TOOLS="$FAILED_TOOLS docker"
test_tool "kafka-topics" "kafka-topics.sh --version" || FAILED_TOOLS="$FAILED_TOOLS kafka-topics"
if [ -n "$FAILED_TOOLS" ]; then
echo "::error::The following tools are not accessible:$FAILED_TOOLS"
exit 1
fi
echo "✓ All tools are accessible for coder user (VS Code terminal simulation)"
- name: Test sudo without password
timeout-minutes: 1
run: |
echo "Testing sudo works without password..."
docker exec test-container bash -c "sudo whoami" | grep -q "root" && echo "✓ sudo works without password" || { echo "::error::sudo requires password"; exit 1; }
- name: Test su command is blocked
timeout-minutes: 1
run: |
echo "Testing su command is blocked..."
SU_OUTPUT=$(docker exec test-container bash -c "sudo -n /usr/bin/su - root -c 'whoami'" 2>&1 || true)
echo "sudo su output: $SU_OUTPUT"
if echo "$SU_OUTPUT" | grep -q "^root$"; then
echo "::error::su command escalated to root; policy is broken"
exit 1
fi
if echo "$SU_OUTPUT" | grep -Eq "not allowed to execute|command not found|a password is required|password is required|authentication is required"; then
echo "✓ su command is properly blocked"
else
echo "::error::Unexpected sudo/su behavior: $SU_OUTPUT"
exit 1
fi
- name: Test mirror configurations
timeout-minutes: 2
run: |
echo "Testing mirror configurations..."
echo "Using interactive shell (bash -i) to simulate VS Code terminal behavior"
# Test Go proxy
docker exec test-container bash -i -c 'echo $GOPROXY | grep -q "goproxy.cn"' && echo " ✓ Go proxy configured" || echo " ⚠ Go proxy not using goproxy.cn"
# Test npm registry
docker exec test-container bash -i -c 'npm config get registry | grep -q "npmmirror"' && echo " ✓ npm registry configured" || echo " ⚠ npm registry not using npmmirror"
# Test gem sources
docker exec test-container bash -i -c 'gem sources | grep -q "ruby-china"' && echo " ✓ gem sources configured" || echo " ⚠ gem sources not using ruby-china"
echo "✓ Mirror configurations verified (VS Code terminal simulation)"
- name: Cleanup test container
if: always()
run: docker rm -f test-container 2>/dev/null || true