-
Notifications
You must be signed in to change notification settings - Fork 540
171 lines (154 loc) · 6.19 KB
/
Copy pathcontainer-ci.yml
File metadata and controls
171 lines (154 loc) · 6.19 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
name: container-ci
on:
push:
branches: [main]
paths:
- .dockerignore
- .github/workflows/container-ci.yml
- Dockerfile
- Dockerfile.dockerignore
- compose.yaml
- compose.apparmor.yaml
- docker/**
- sdk/typescript/**
pull_request:
paths:
- .dockerignore
- .github/workflows/container-ci.yml
- Dockerfile
- Dockerfile.dockerignore
- compose.yaml
- compose.apparmor.yaml
- docker/**
- sdk/typescript/**
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
container:
name: linux-amd64
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Verify customer build excludes secrets and scan data
shell: bash
run: |
set -euo pipefail
ignore_file=.dockerignore
if [[ -f Dockerfile.dockerignore ]]; then
ignore_file=Dockerfile.dockerignore
if ! cmp -s .dockerignore "$ignore_file"; then
echo "Dockerfile-specific ignore rules must match the approved customer baseline." >&2
exit 1
fi
fi
if grep -Fq '!' "$ignore_file"; then
echo "Customer Docker ignore rules must not re-include excluded files: $ignore_file" >&2
exit 1
fi
for pattern in \
'**/.env' \
'**/.env.*' \
'**/.npmrc' \
'**/node_modules' \
'**/*.csv' \
'**/repositories.csv' \
'**/results' \
'**/security-scans' \
'**/state'; do
if ! grep -Fxq -- "$pattern" "$ignore_file"; then
echo "Missing customer Docker build exclusion in $ignore_file: $pattern" >&2
exit 1
fi
done
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build customer container
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
env:
DOCKER_BUILD_RECORD_UPLOAD: "false"
with:
context: .
load: true
platforms: linux/amd64
push: false
tags: codex-security:ci
cache-from: type=gha,scope=codex-security-amd64
cache-to: ${{ github.event_name != 'pull_request' && 'type=gha,mode=max,scope=codex-security-amd64' || '' }}
- name: Verify bundled scanner
run: |
docker run --rm codex-security:ci --version
docker run --rm codex-security:ci bulk-scan --help
docker run --rm codex-security:ci info --json
- name: Validate hardened customer Compose configuration
env:
CODEX_SECURITY_IMAGE: codex-security:ci
run: |
mkdir -p results state
chmod 700 results state
printf 'id,repository,revision\n' > repositories.csv
CODEX_SECURITY_USER="$(id -u):$(id -g)"
export CODEX_SECURITY_USER
docker compose config --quiet
docker compose run --rm codex-security --version
- name: Validate optional AppArmor Compose configuration
env:
CODEX_SECURITY_IMAGE: codex-security:ci
run: docker compose -f compose.yaml -f compose.apparmor.yaml config --quiet
- name: Verify hardened Codex command sandbox
shell: bash
run: |
set -euo pipefail
command=(
docker run --rm
--cap-drop ALL
--security-opt no-new-privileges
--security-opt "seccomp=$GITHUB_WORKSPACE/docker/codex-security-seccomp.json"
--entrypoint node
codex-security:ci
/usr/local/lib/node_modules/@openai/codex-security/node_modules/@openai/codex/bin/codex.js
)
if output="$("${command[@]}" sandbox /usr/bin/true 2>&1)"; then
printf '%s\n' "$output"
elif grep -Eq 'bwrap: (Failed to make / slave: Permission denied|loopback: Failed RTM_NEW(ADDR|LINK): Operation not permitted|setting up uid map: Permission denied|No permissions to create a new namespace)' <<< "$output"; then
echo '::notice::This Docker host blocks nested Bubblewrap namespaces; verifying the supported Landlock fallback.'
"${command[@]}" sandbox --enable use_legacy_landlock /usr/bin/true
else
printf 'The hardened Codex sandbox failed unexpectedly:\n%s\n' "$output" >&2
exit 1
fi
- name: Reject interactive repository discovery
shell: bash
run: |
set -euo pipefail
if output="$(docker run --rm -t codex-security:ci bulk-scan 2>&1)"; then
echo "The customer container must require a repository CSV." >&2
exit 1
else
status=$?
fi
if [[ "$status" -ne 2 ]]; then
printf 'The customer container returned unexpected exit status %s:\n%s\n' "$status" "$output" >&2
exit 1
fi
expected='codex-security: bulk-scan requires a repository CSV; interactive discovery is not supported in this image.'
if [[ "${output//$'\r'/}" != "$expected" ]]; then
printf 'The customer container returned an unexpected repository discovery error:\n%s\n' "$output" >&2
exit 1
fi
- name: Verify host-scoped noninteractive Git credentials
shell: bash
run: |
set -euo pipefail
docker run --rm \
--entrypoint /bin/sh \
--env GH_TOKEN=SYNTHETIC_GITHUB_TOKEN \
codex-security:ci \
-ec 'actual="$(printf "protocol=https\nhost=github.com\n\n" | /usr/local/bin/codex-security-git-credential get)"; test "$actual" = "$(printf "username=x-access-token\npassword=SYNTHETIC_GITHUB_TOKEN")"; test -z "$(printf "protocol=https\nhost=untrusted.example\n\n" | /usr/local/bin/codex-security-git-credential get)"'