-
Notifications
You must be signed in to change notification settings - Fork 2
115 lines (105 loc) · 5.32 KB
/
Copy pathci-compose-validate.yml
File metadata and controls
115 lines (105 loc) · 5.32 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
name: Validate Compose
# Shared Compose files can break either the reference or self-hosted stack, so
# render both configurations.
on:
workflow_call:
permissions:
contents: read
jobs:
validate:
name: "Render compose stacks"
timeout-minutes: 15
runs-on: ubuntu-latest
env:
COMPOSE_ENV_FILES: .env,release-lock.env
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Render the self-hosted stack
working-directory: docker/self-host
run: |
set -euo pipefail
# Render what the install guide produces: the installer's generated secrets plus the
# values step 2 asks the operator for. Hand-filling the generated ones here would hide a
# required variable the installer forgets, which is how one reached a release smoke test.
./setup.sh
sed -i \
-e 's|^APP_HOSTNAME=$|APP_HOSTNAME=hephaestus.example.com|' \
-e 's|^ACME_EMAIL=$|ACME_EMAIL=operator@example.com|' \
.env
while IFS= read -r image; do
name="HEPHAESTUS_IMAGE_${image^^}"
name=${name//-/_}
printf '%s=%s@sha256:%s\n' "$name" "example.invalid/${image}" "$(printf '0%.0s' {1..64})" >> release-lock.env
done < <(jq -r '.images[], .upstream[].name' ../../security/release-images.json)
printf 'IMAGE_TAG=0.0.0\nHEPHAESTUS_RELEASE=v0.0.0\nHEPHAESTUS_RELEASE_COMMIT=%s\n' \
"$(printf '0%.0s' {1..40})" >> release-lock.env
docker compose config > /dev/null
echo "Rendered services:"
docker compose config --services | sort
- name: Fail on unset variables
working-directory: docker/self-host
run: |
set -euo pipefail
# `config` warns rather than fails when .env omits a referenced variable.
if docker compose config 2>&1 >/dev/null | grep "variable is not set"; then
echo "::error::docker/self-host/.env.example is missing variables the stack references (see warnings above)"
exit 1
fi
- name: Assert the merged stack matches single-host intent
working-directory: docker/self-host
run: |
set -euo pipefail
services=$(docker compose config --services)
for unwanted in application-worker maintenance; do
grep -qx "$unwanted" <<< "$services" && {
echo "::error::'$unwanted' is a reference-deployment service and must not run on a single host"; exit 1; } || true
done
for required in application-server webhook-server postgres nats-server webapp reverse-proxy; do
grep -qx "$required" <<< "$services" || {
echo "::error::'$required' is missing from the self-hosted stack"; exit 1; }
done
# Some Compose releases accept `!override` without applying it.
rendered=$(docker compose config)
for required in \
'entrypoints.https.http.middlewares=security-headers@docker' \
'request-body-limit@docker' \
'providers.file.filename=/etc/traefik/dynamic.yml' \
'contentsecuritypolicy' \
'default-src' \
'stsseconds' \
'2592000' \
'maxrequestbodybytes' \
'26214400' \
'minversion' \
'versiontls12'; do
grep -Fiq "$required" <<< "$rendered" || {
echo "::error::runtime edge envelope is missing '$required'"; exit 1; }
done
edge_csp=$(sed -n 's/.*contentSecurityPolicy=\(.*\)"/\1/p' ../compose.proxy.yaml)
selfhost_csp=$(sed -n 's/.*contentSecurityPolicy=\(.*\)"/\1/p' compose.single-host.yaml)
nginx_csp=$(sed -n 's/add_header Content-Security-Policy "\(.*\)" always;/\1/p' ../../webapp/docker/security-headers.conf)
[ "$edge_csp" = "$nginx_csp" ] || {
echo "::error::Traefik and nginx Content-Security-Policy values differ"; exit 1; }
[ "$edge_csp" = "$selfhost_csp" ] || {
echo "::error::reference and single-host Content-Security-Policy values differ"; exit 1; }
grep -q "admin@tum.de" <<< "$rendered" && {
echo "::error::the maintainers' ACME email survived the override — Compose is too old to honour !override"; exit 1; } || true
published=$(docker compose config --format json \
| jq -r '.services["reverse-proxy"].ports[].published' | sort -n | tr '\n' ' ')
[ "$published" = "80 443 " ] || {
echo "::error::reverse-proxy publishes '$published', expected '80 443 ' — !override was ignored"; exit 1; }
- name: Set up the repository's Node.js and pnpm versions
uses: ./.github/actions/setup-node-pnpm
with:
install: "none"
- name: Render the preview stack and assert it stays sandboxed
run: pnpm run check:preview-stack
- name: Render the reference deployment
working-directory: docker
run: |
set -euo pipefail
# Values mirror what the deploy workflow supplies; only proves the files
# still render, not that they are correct for production.
docker compose \
-f compose.proxy.yaml -f compose.core.yaml -f compose.app.yaml \
--env-file self-host/.env --env-file self-host/release-lock.env config --quiet