Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
eabf8b3
nginx: semgrep
Feb 17, 2026
0251262
no-git-ignore
Feb 17, 2026
25498c7
touch
Feb 17, 2026
63ca528
disable gixy for faster tests
Feb 17, 2026
ab194dd
heredoc
Feb 17, 2026
7a16880
try with a rule
Feb 17, 2026
573b7bd
try escape
Feb 17, 2026
bc28bde
debg
Feb 17, 2026
7c62c33
generic lang
Feb 17, 2026
d65fd88
add some paths
Feb 17, 2026
d720de2
apt-get
Feb 17, 2026
ecba8e9
increase timeout
Feb 17, 2026
dad8258
add community ruleset
Feb 17, 2026
fa7458e
more haders, case insensitve
Feb 17, 2026
536461b
try excelude
Feb 17, 2026
3171cde
tabs
Feb 17, 2026
66485ab
v
Feb 17, 2026
1f0090f
make ERROR
Feb 17, 2026
24320c9
exluce
Feb 17, 2026
e9f2829
ellips?
Feb 17, 2026
3f288bd
fix paths
Feb 17, 2026
3bb524a
clude all
Feb 17, 2026
7e3ea15
cli include
Feb 17, 2026
1b84968
specific files
Feb 17, 2026
40b9c21
fix a violation; streamline the testing
Feb 17, 2026
a346d04
reintro install steps
Feb 17, 2026
f710102
reduce timeout again
Feb 17, 2026
279ce39
remove todo
Feb 17, 2026
2e6f34b
remove comment
Feb 17, 2026
27671d5
run on all files
Feb 17, 2026
9401cef
fiail on error?
Feb 17, 2026
e1c8ca4
refactor
Feb 17, 2026
8f2f8ed
add loads of always
Feb 17, 2026
7d4b7c5
X-Frame-Options
Feb 17, 2026
52f61e7
X-Content-Type-Options
Feb 17, 2026
1f8796a
fiail on ly onerr
Feb 17, 2026
05693c9
Revert "X-Content-Type-Options"
Feb 17, 2026
c5abe61
Revert "Revert "X-Content-Type-Options""
Feb 17, 2026
14ae294
ci: revet change
Feb 17, 2026
d7ccb76
tidy up gixy comments
Feb 17, 2026
2f07f17
dockerignore: include /test/ dir
Feb 17, 2026
8b5eba0
gnore test more
Feb 17, 2026
53b86af
revert dockerignore change
Feb 17, 2026
87ccb6e
Merge branch 'next' into always-headers
alxndrsn Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
- run: cd test/nginx && npm run lint
- run: cd test/nginx && ./setup-tests.sh
- run: cd test/nginx && npm run test:nginx
- run: cd test/nginx && ./gixy.sh
- run: cd test/nginx && ./lint-config.sh

- if: always()
run: cd test/nginx && docker compose -f nginx.test.docker-compose.yml logs --no-log-prefix nginx-ssl-selfsign
Expand Down
4 changes: 2 additions & 2 deletions files/nginx/common-headers.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ add_header Vary $cache_header_vary;

add_header Referrer-Policy same-origin;
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options nosniff always;
10 changes: 5 additions & 5 deletions files/nginx/odk.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ server {

server_tokens off;

add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src https://translate.google.com https://translate.googleapis.com; img-src https://translate.google.com; report-uri /csp-report";
add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src https://translate.google.com https://translate.googleapis.com; img-src https://translate.google.com; report-uri /csp-report" always;
include /usr/share/odk/nginx/common-headers.conf;

client_max_body_size 100m;
Expand Down Expand Up @@ -160,7 +160,7 @@ server {
# Google Maps API: https://developers.google.com/maps/documentation/javascript/content-security-policy
# Use 'none' per directive instead of falling back to default-src to make CSP violation reports more specific
proxy_hide_header Content-Security-Policy-Report-Only;
add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src 'self' blob: https://maps.googleapis.com/ https://maps.google.com/ https://maps.gstatic.com/mapfiles/ https://fonts.gstatic.com/ https://fonts.googleapis.com/ https://translate.google.com https://translate.googleapis.com; font-src 'self' https://fonts.gstatic.com/; frame-src 'none'; img-src data: blob: jr: 'self' https://maps.google.com/maps/ https://maps.gstatic.com/mapfiles/ https://maps.googleapis.com/maps/ https://tile.openstreetmap.org/ https://translate.google.com; manifest-src 'none'; media-src blob: jr: 'self'; object-src 'none'; script-src 'unsafe-inline' 'self' https://maps.googleapis.com/maps/api/js/ https://maps.google.com/maps/ https://maps.google.com/maps-api-v3/api/js/; style-src 'unsafe-inline' 'self' https://fonts.googleapis.com/css; style-src-attr 'unsafe-inline'; report-uri /csp-report";
add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src 'self' blob: https://maps.googleapis.com/ https://maps.google.com/ https://maps.gstatic.com/mapfiles/ https://fonts.gstatic.com/ https://fonts.googleapis.com/ https://translate.google.com https://translate.googleapis.com; font-src 'self' https://fonts.gstatic.com/; frame-src 'none'; img-src data: blob: jr: 'self' https://maps.google.com/maps/ https://maps.gstatic.com/mapfiles/ https://maps.googleapis.com/maps/ https://tile.openstreetmap.org/ https://translate.google.com; manifest-src 'none'; media-src blob: jr: 'self'; object-src 'none'; script-src 'unsafe-inline' 'self' https://maps.googleapis.com/maps/api/js/ https://maps.google.com/maps/ https://maps.google.com/maps-api-v3/api/js/; style-src 'unsafe-inline' 'self' https://fonts.googleapis.com/css; style-src-attr 'unsafe-inline'; report-uri /csp-report" always;

include /usr/share/odk/nginx/common-headers.conf;
}
Expand All @@ -173,7 +173,7 @@ server {

location ~ ^/v\d {
proxy_hide_header Content-Security-Policy-Report-Only;
add_header Content-Security-Policy-Report-Only "default-src 'none'; report-uri /csp-report";
add_header Content-Security-Policy-Report-Only "default-src 'none'; report-uri /csp-report" always;

include /usr/share/odk/nginx/common-headers.conf;
include /usr/share/odk/nginx/backend.conf;
Expand All @@ -183,7 +183,7 @@ server {
root /usr/share/nginx/html;
try_files /blank.html =404;

add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src https://translate.google.com https://translate.googleapis.com; img-src https://translate.google.com; report-uri /csp-report";
add_header Content-Security-Policy-Report-Only "default-src 'none'; connect-src https://translate.google.com https://translate.googleapis.com; img-src https://translate.google.com; report-uri /csp-report" always;
include /usr/share/odk/nginx/common-headers.conf;
}
location = /blank.html {
Expand All @@ -194,7 +194,7 @@ server {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;

add_header Content-Security-Policy-Report-Only "$central_frontend_csp";
add_header Content-Security-Policy-Report-Only "$central_frontend_csp" always;

include /usr/share/odk/nginx/common-headers.conf;
}
Expand Down
31 changes: 0 additions & 31 deletions test/nginx/gixy.sh

This file was deleted.

62 changes: 62 additions & 0 deletions test/nginx/lint-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash -eu
set -o pipefail
shopt -s inherit_errexit

log() { echo >&2 "[$(basename "$0")] $*"; }

docker_compose() {
docker compose --file nginx.test.docker-compose.yml "$@"
}

lint_service() {
local service="$1"
log "$service: checking config..."
docker_compose exec "$service" bash -euc '
echo "[lint-config] installing python..."
apt update
apt install -y python3-venv
python3 -m venv .venv
. .venv/bin/activate

echo "[lint-config] installing semgrep..."
pip install semgrep
cat >.semgrep.yml <<EOF
rules:
- id: nginx-add-header-missing-always
languages: [generic]
message: "Security headers should include \`always\` param to ensure they are sent with error responses (4xx, 5xx)."
severity: ERROR
patterns:
- pattern-regex: "\\\\badd_header\\\\s+(Strict-Transport-Security|X-Content-Type-Options|X-Frame-Options|Content-Security-Policy|Content-Security-Policy-Report-Only)\\\\s+.*"
- pattern-not-regex: "(?i)add_header\\\\s+.*\\\\balways\\\\b\\\\s*;"
EOF
echo "[lint-config] running semgrep..."
semgrep scan --verbose \
--error \
--severity ERROR \
--metrics=off \
--disable-version-check \
--no-git-ignore \
--config p/nginx \
--config .semgrep.yml \
-- \
/etc/nginx/conf.d/odk.conf \
/usr/share/odk/nginx/

# gixy-ng is a maintained fork of gixy: https://github.com/dvershinin/gixy
# For version updates, see: https://pypi.org/project/gixy-ng/#history
echo "[lint-config] installing gixy..."
pip install gixy-ng==0.2.12
echo "[lint-config] running gixy..."
gixy -lll

echo "[lint-config] All completed OK."
'

log "$service: config looks OK."
}

lint_service nginx-ssl-selfsign
lint_service nginx-ssl-upstream

log "Completed OK."