-
Notifications
You must be signed in to change notification settings - Fork 438
335 lines (307 loc) · 14.4 KB
/
appsec.yml
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
name: AppSec Tests
on:
workflow_call: # allows to reuse this workflow
inputs:
ref:
description: 'The branch to run the workflow on'
required: true
type: string
workflow_dispatch: # manually
schedule: # nightly
- cron: "0 0 * * *"
pull_request: # on pull requests touching appsec files
paths:
- '.github/workflows/appsec.yml'
- 'internal/appsec/**'
- 'appsec/**'
- 'contrib/**/appsec.go'
- '**/go.mod'
merge_group:
push:
branches: release-v*
env:
DD_APPSEC_WAF_TIMEOUT: 1m
PACKAGES: >-
./appsec/...
./internal/appsec/...
SUBMODULES: >-
./contrib/database/sql
./contrib/gin-gonic/gin
./contrib/google.golang.org/grpc
./contrib/net/http
./contrib/gorilla/mux
./contrib/go-chi/chi
./contrib/go-chi/chi.v5
./contrib/labstack/echo.v4
./contrib/99designs/gqlgen
./contrib/graphql-go/graphql
./contrib/graph-gophers/graphql-go
concurrency:
# Automatically cancel previous runs if a new one is triggered to conserve resources.
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
permissions:
contents: read
jobs:
# Prepare the cache of Go modules to share it will the other jobs.
# This maximizes cache hits and minimizes the time spent downloading Go modules.
# Note 1: @actions/cache is very sensitive and it's easy to mess up. Things to know:
# - doing it after @actions/checkout is required for all the metadata to be available;
# - sharing the cache with windows requires backslashes to be used in the path;
# - sharing the cache between OSes requires the base path to be the same, so a relative one is used;
# - as of writing this doc, @actions/cache doest work inside docker containers, so had to design so
# containerized jobs around this problem, by restoring the cache in the runner and mounting it in the
# container ourselves.
# Note 2: a lot of time was spent on making caching work across macos, linux,
# windows and golang containers. So this is very sensitive and should be
# validated again in case of changes. To do so, you can click on the @actions/cache
# actions logs and look for the "Cache hit" or "Cache miss" messages.
go-mod-caching:
name: Prepare Go modules cache
runs-on: ubuntu-latest-16-cores
outputs:
key: ${{ steps.cfg.outputs.key }}
path: ${{ steps.cfg.outputs.path }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Compute cache configuration
id: cfg
run: |
echo "key=go-pkg-mod-${{ hashFiles('**/go.sum') }}" >> $GITHUB_OUTPUT
echo "path=go_pkg_mod_cache" >> $GITHUB_OUTPUT
- uses: actions/setup-go@v5
with:
cache: false
- name: Cache Go modules
id: cache
uses: actions/cache@v4
with:
path: ${{ steps.cfg.outputs.path }}
key: ${{ steps.cfg.outputs.key }}
enableCrossOsArchive: true
lookup-only: true
- name: Download Go modules
if: steps.cache.outputs.cache-hit != 'true'
env:
GOMODCACHE: ${{ github.workspace }}/${{ steps.cfg.outputs.path }}
run: go mod download -x
macos:
name: ${{ matrix.runs-on }} go${{ matrix.go-version }}
runs-on: ${{ matrix.runs-on }}
needs: go-mod-caching
strategy:
matrix:
runs-on: [ macos-12, macos-14 ] # oldest and newest macos runners available - macos-14 mainly is here to cover the fact it is an ARM machine
go-version: [ "1.23", "1.22" ]
fail-fast: true # saving some CI time - macos runners too long to get
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Restore Go modules cache
uses: actions/cache/restore@v4
with:
path: ${{ needs.go-mod-caching.outputs.path }}
key: ${{ needs.go-mod-caching.outputs.key }}
restore-keys: go-pkg-mod-
enableCrossOsArchive: true
fail-on-cache-miss: true
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: false # we manage the caching ourselves
# go test is being manually called multiple times here for the sake of reusing the runner.
# Waiting runners is unfortunately so long that we decided to do so for things only requiring recompilation or
# reruns under different settings.
- name: go test
shell: bash
env:
GOMODCACHE: ${{ github.workspace }}/${{ needs.go-mod-caching.outputs.path }}
run: |
set -euxo pipefail
cgocheck="GOEXPERIMENT=cgocheck2"
report_error=0
for cgo in "0" "1"; do
for appsec_enabled_env in "" "DD_APPSEC_ENABLED=true" "DD_APPSEC_ENABLED=false"; do
for cgocheck_env in "" "$cgocheck"; do
if ! env CGO_ENABLED=$cgo $appsec_enabled_env $cgocheck_env go test -v $PACKAGES; then
echo "Failed: env CGO_ENABLED=$cgo $appsec_enabled_env $cgocheck_env go test -v $PACKAGES"
fi
for submodule in $SUBMODULES; do
if [[ $cgocheck_env == "GOEXPERIMENT=cgocheck2" && $submodule == "./contrib/gin-gonic/gin" ]]; then
echo "Skipped: env CGO_ENABLED=$cgo $appsec_enabled_env $cgocheck_env go test -v . (submodule: $submodule, reason: gin-gonic/gin depends on leodido/go-urn that causes an internal compiler when GOEXPERIMENT=cgocheck2)"
continue
fi
cd $submodule
if ! env CGO_ENABLED=$cgo $appsec_enabled_env $cgocheck_env go test -v .; then
echo "Failed: env CGO_ENABLED=$cgo $appsec_enabled_env $cgocheck_env go test -v . (submodule: $submodule)"
report_error=1
fi
cd -
done
done
done
done
exit $report_error
# Tests cases were appsec end up being disabled at compilation time
disabled:
name: ${{ matrix.runs-on }} (AppSec disabled)
needs: go-mod-caching
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
runs-on: [ macos-latest, windows-latest, ubuntu-latest-16-cores ]
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Restore Go modules cache
uses: actions/cache/restore@v4
with:
path: ${{ needs.go-mod-caching.outputs.path }}
key: ${{ needs.go-mod-caching.outputs.key }}
restore-keys: go-pkg-mod-
enableCrossOsArchive: true
fail-on-cache-miss: true
- uses: actions/setup-go@v5
with:
go-version: stable
cache: false # we manage the caching ourselves
- run: go env -w GOMODCACHE=${{ github.workspace }}\${{ needs.go-mod-caching.outputs.path }}
if: runner.os == 'Windows'
- run: go env -w GOMODCACHE=${{ github.workspace }}/${{ needs.go-mod-caching.outputs.path }}
if: runner.os != 'Windows'
- name: go test
shell: bash
run: |
set -euxo pipefail
for appsec_enabled_env in "" "DD_APPSEC_ENABLED=true" "DD_APPSEC_ENABLED=false"; do
for go_tags in "" "-tags datadog.no_waf"; do
if ! env $appsec_enabled_env go test -v $go_tags $PACKAGES; then
echo "Failed: env $appsec_enabled_env go test -v $go_tags $PACKAGES"
fi
for submodule in $SUBMODULES; do
cd $submodule
if ! env $appsec_enabled_env go test -v $go_tags .; then
echo "Failed: env $appsec_enabled_env go test -v $go_tags . (submodule: $submodule)"
fi
cd -
done
done
done
# Same tests but on the official golang container for linux
golang-linux-container:
name: ${{ matrix.platform }} golang:${{ matrix.go-version }}-${{ matrix.distribution }}
# We use ARM runners when needed to avoid the performance hit of QEMU
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest-16-cores' || 'arm-4core-linux' }}
needs: go-mod-caching
strategy:
matrix:
go-version: [ "1.23", "1.22" ]
distribution: [ bookworm, bullseye, alpine ]
platform: [ linux/amd64, linux/arm64 ]
fail-fast: false
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Restore Go modules cache
uses: actions/cache/restore@v4
with:
path: ${{ needs.go-mod-caching.outputs.path }}
key: ${{ needs.go-mod-caching.outputs.key }}
restore-keys: go-pkg-mod-
enableCrossOsArchive: true
fail-on-cache-miss: true
# Docker is not present on early-access ARM runners
- name: Prepare ARM Runner
if: runner.arch == 'ARM64' || runner.arch == 'ARM'
run: |-
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg || echo "Not present: $pkg"; done
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
- name: Create container
env:
GOMODCACHE: ${{ github.workspace }}/${{ needs.go-mod-caching.outputs.path }}
run: |-
sudo docker run \
--rm \
-di \
--name test.runner \
-v "${GOMODCACHE}:${GOMODCACHE}" \
-e "GOMODCACHE=${GOMODCACHE}" \
-v "$PWD:$PWD" \
-w "$PWD" \
-e "DD_APPSEC_WAF_TIMEOUT=${{ env.DD_APPSEC_WAF_TIMEOUT }}" \
golang:${{ matrix.go-version }}-${{ matrix.distribution }}
- name: Install pre-requisites on Alpine
if: matrix.distribution == 'alpine'
run: sudo docker exec -i test.runner apk add gcc musl-dev libc6-compat bash
- name: Output go env
run: sudo docker exec -i test.runner go env
- name: NOCGO, undefined appsec state
run: |
sudo docker exec -i -e CGO_ENABLED=0 test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=0 test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=0 bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: NOCGO, appsec disabled
run: |
sudo docker exec -i -e CGO_ENABLED=0 -e DD_APPSEC_ENABLED=false test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=0 -e DD_APPSEC_ENABLED=false test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=0 DD_APPSEC_ENABLED=false bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: NOCGO, appsec enabled
run: |
sudo docker exec -i -e CGO_ENABLED=0 -e DD_APPSEC_ENABLED=true test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=0 -e DD_APPSEC_ENABLED=true test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=0 DD_APPSEC_ENABLED=true bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: CGO, undefined appsec state
run: |
sudo docker exec -i -e CGO_ENABLED=1 test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=1 test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=1 bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: CGO, appsec disabled
run: |
sudo docker exec -i -e CGO_ENABLED=1 -e DD_APPSEC_ENABLED=false test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=1 -e DD_APPSEC_ENABLED=false test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=1 DD_APPSEC_ENABLED=false bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: CGO, appsec enabled
run: |
sudo docker exec -i -e CGO_ENABLED=1 -e DD_APPSEC_ENABLED=true test.runner go test -v $PACKAGES
for submodule in $SUBMODULES; do
if ! sudo docker exec -i -e CGO_ENABLED=1 -e DD_APPSEC_ENABLED=true test.runner bash -c "cd $submodule && go test -v ."; then
echo "Failed: env CGO_ENABLED=1 DD_APPSEC_ENABLED=true bash -c \"cd $submodule && go test -v .\" (submodule: $submodule)"
fi
done
- name: Clean up
if: always()
run: sudo docker rm --force test.runner || echo "Could not remove container"
# TODO(darccio): revert to use main on release
test-app-smoke-tests:
name: Smoke Tests
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner == 'DataDog'
uses: DataDog/appsec-go-test-app/.github/workflows/[email protected]/AIT-3705/dd-trace-go.v2
with:
dd-trace-go-version: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || '' }}