Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 0 additions & 3 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,3 @@ GOOGLE_ANALYTICS=foo

REDIS_HOST=redis
REDIS_PORT=6379

# Required for https redirects to correctly work behind a reverse proxy / load balancer
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8,172.16.0.0/12
3 changes: 3 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999

# Trusted proxy used by functional tests exercising forwarded client IPs.
SYMFONY_TRUSTED_PROXIES=192.0.2.0/24
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
9 changes: 6 additions & 3 deletions .github/workflows/build-containers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@ jobs:
if: ${{ github.ref == 'refs/heads/master' }}
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4

- name: Login to DockerHub
uses: docker/login-action@v4
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/cleanup-repo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ jobs:
cleanup-repository:
runs-on: ubuntu-latest

permissions:
contents: write
issues: write
pull-requests: write

steps:

# Mark issues and PRs with no activity as stale after a while, and close them after a while longer
- uses: actions/stale@v10
- uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10
with:
stale-issue-message: 'Marking issue as stale'
stale-pr-message: 'Marking PR as stale'
Expand All @@ -26,7 +31,7 @@ jobs:

# Delete old, abandoned branches
# See what constitutes an abandoned branch here: https://github.com/phpdocker-io/github-actions-delete-abandoned-branches
- uses: phpdocker-io/github-actions-delete-abandoned-branches@v1
- uses: phpdocker-io/github-actions-delete-abandoned-branches@d8e3635360bd492315571df30f15f55c98a28434 # v1
with:
github_token: ${{ github.token }}
last_commit_age_days: 30
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ jobs:
tests:
timeout-minutes: 10
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(make composer-cache-dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v5
- uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
Expand Down
82 changes: 72 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,39 @@ HOSTS_LOCATION=bin/hosts
SITE_HOST=phpdocker.local
PHP_RUN=docker compose run -e XDEBUG_MODE=coverage --rm php-fpm

# Integrity data for the binaries downloaded below. Upstream publishes no checksum
# for the mkcert v1.4.3 release assets (the GitHub release API reports
# "digest": null for each of them), so these SHA-256 values were computed locally
# from the assets downloaded over HTTPS from the official release URLs on
# 2026-09-25. The windows-amd64.exe value is independently corroborated by the
# mkcert 1.4.3 Chocolatey package (tools/mkcert.exe, published 2020-11-26), which
# contains the same bytes. hosts is fetched from the commit the 3.6.4 tag points at
# (9a929dc70fa11bfe6dc5b0f1d53aea442395edd3) and was hashed on 2026-09-25. If an
# asset is ever republished, update its URL and its hash in the same commit.
MKCERT_SHA256_linux-amd64=c2b0746528588d2a5dabe7c4394a848909da07e23ca3f2393375e9baa3931649
MKCERT_SHA256_darwin-amd64=0b5bd40ea69ec34c567707249938bcd0502d2c3efc0137143a076a2b80d5e882
MKCERT_SHA256_linux-arm=b982ade61b6781f17afc210914116d8078af3ebb631facd28a944033018d41d2
MKCERT_SHA256_linux-arm64=43c4e3b9e7e6466d397b3d6e221788f83b5b91f826f1040240dbaddfc101ce33
MKCERT_SHA256_windows-amd64.exe=9dc25f7d1ae0be93db81aa42f3abfd62d13725dfd48969c9fe94b6af57e5573c
HOSTS_COMMIT=9a929dc70fa11bfe6dc5b0f1d53aea442395edd3
HOSTS_SHA256=eee51960ec8dd30e00090779ba79f11410396e69ac7812b0ad99f5b597c8c36e

# sha256sum on Linux, shasum on macOS
SHA256_CMD=$(shell command -v sha256sum >/dev/null 2>&1 && echo sha256sum || echo 'shasum -a 256')

INFECTION_THREADS?=8
BUILD_TAG?:=$(shell date +'%Y-%m-%d-%H-%M-%S')-$(shell git rev-parse --short HEAD)

# linux-amd64, darwin-amd64, linux-arm
# linux-amd64, darwin-amd64, linux-arm, linux-arm64
# On windows, override with windows-amd64.exe
ifndef BINARY_SUFFIX
BINARY_SUFFIX:=$(shell [[ "`uname -s`" == "Linux" ]] && echo linux || echo darwin)-amd64
endif

# Resolved from BINARY_SUFFIX; an unsupported suffix yields an empty value, which
# fails verification instead of skipping it.
MKCERT_SHA256=$(MKCERT_SHA256_$(BINARY_SUFFIX))

ifndef BUILD_TAG
BUILD_TAG:=$(shell date +'%Y-%m-%d-%H-%M-%S')-$(shell git rev-parse --short HEAD)
endif
Expand Down Expand Up @@ -85,19 +109,57 @@ composer-update:
$(PHP_RUN) composer update --no-scripts
make composer-install

install-mkcert:
@echo "Installing mkcert for OS type ${BINARY_SUFFIX}"
@if [[ ! -f '$(MKCERT_LOCATION)' ]]; then curl -sL 'https://github.com/FiloSottile/mkcert/releases/download/$(MKCERT_VERSION)/mkcert-$(MKCERT_VERSION)-$(BINARY_SUFFIX)' -o $(MKCERT_LOCATION); chmod +x $(MKCERT_LOCATION); fi;
install-mkcert: verify-mkcert
bin/mkcert -install

create-certs:
download-mkcert:
@echo "Installing mkcert for OS type ${BINARY_SUFFIX}"
@if [[ ! -f '$(MKCERT_LOCATION)' ]]; then \
curl -fsSL --retry 3 -o '$(MKCERT_LOCATION).tmp' 'https://github.com/FiloSottile/mkcert/releases/download/$(MKCERT_VERSION)/mkcert-$(MKCERT_VERSION)-$(BINARY_SUFFIX)' || { rm -f '$(MKCERT_LOCATION).tmp'; exit 1; }; \
mv '$(MKCERT_LOCATION).tmp' '$(MKCERT_LOCATION)'; \
fi

verify-mkcert: download-mkcert
@if [[ ! -f '$(MKCERT_LOCATION)' ]]; then \
echo "Missing $(MKCERT_LOCATION); refusing to run it"; \
exit 1; \
fi; \
if [[ -z '$(MKCERT_SHA256)' ]]; then \
echo "No pinned SHA-256 for BINARY_SUFFIX '$(BINARY_SUFFIX)'; refusing to run $(MKCERT_LOCATION)"; \
exit 1; \
fi; \
actual="$$($(SHA256_CMD) '$(MKCERT_LOCATION)' | awk '{print $$1}')"; \
if [[ "$$actual" != '$(MKCERT_SHA256)' ]]; then \
echo "SHA-256 mismatch for $(MKCERT_LOCATION): expected '$(MKCERT_SHA256)', got '$$actual'"; \
exit 1; \
fi
chmod +x $(MKCERT_LOCATION)

create-certs: verify-mkcert
bin/mkcert -cert-file=infrastructure/local/localhost.pem -key-file=infrastructure/local/localhost-key.pem $(SITE_HOST)

install-hosts:
@echo "Installing hosts script"
@if [[ ! -f '$(HOSTS_LOCATION)' ]]; then curl -sL 'https://raw.githubusercontent.com/xwmx/hosts/$(HOSTS_VERSION)/hosts' -o $(HOSTS_LOCATION); chmod +x $(HOSTS_LOCATION); fi;

clean-hosts:
install-hosts: verify-hosts

download-hosts:
@echo "Installing hosts script ($(HOSTS_VERSION))"
@if [[ ! -f '$(HOSTS_LOCATION)' ]]; then \
curl -fsSL --retry 3 -o '$(HOSTS_LOCATION).tmp' 'https://raw.githubusercontent.com/xwmx/hosts/$(HOSTS_COMMIT)/hosts' || { rm -f '$(HOSTS_LOCATION).tmp'; exit 1; }; \
mv '$(HOSTS_LOCATION).tmp' '$(HOSTS_LOCATION)'; \
fi

verify-hosts: download-hosts
@if [[ ! -f '$(HOSTS_LOCATION)' ]]; then \
echo "Missing $(HOSTS_LOCATION); refusing to run it"; \
exit 1; \
fi; \
actual="$$($(SHA256_CMD) '$(HOSTS_LOCATION)' | awk '{print $$1}')"; \
if [[ "$$actual" != '$(HOSTS_SHA256)' ]]; then \
echo "SHA-256 mismatch for $(HOSTS_LOCATION): expected '$(HOSTS_SHA256)', got '$$actual'"; \
exit 1; \
fi
chmod +x $(HOSTS_LOCATION)

clean-hosts: verify-hosts
sudo bin/hosts remove --force *$(SITE_HOST) > /dev/null 2>&1 || exit 0

init-hosts: clean-hosts
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
"symfony/dotenv": "^8.0",
"symfony/flex": "^2.4",
"symfony/form": "^8.0",
"symfony/framework-bundle": "^8.0",
"symfony/framework-bundle": "^8.1",
"symfony/mime": "^8.0",
"symfony/monolog-bundle": "^4.0",
"symfony/rate-limiter": "^8.0",
"symfony/runtime": "^8.0",
"symfony/security-csrf": "^8.0",
"symfony/twig-bundle": "^8.0",
Expand Down
78 changes: 76 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions config/packages/cache.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
framework:
cache:
app: cache.adapter.apcu
default_redis_provider: 'redis://%env(REDIS_HOST)%:%env(REDIS_PORT)%'
pools:
rate_limiter.cache:
adapter: cache.adapter.redis

when@test:
framework:
cache:
pools:
rate_limiter.cache:
adapter: cache.adapter.filesystem
8 changes: 8 additions & 0 deletions config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ framework:
cookie_secure: auto
cookie_samesite: strict

# Only these forwarded headers are honoured, and only when the request
# arrives from a proxy listed in SYMFONY_TRUSTED_PROXIES (Symfony's default
# env var, left unset here so no proxy is trusted by default).
trusted_headers:
- x-forwarded-for
- x-forwarded-proto
- x-forwarded-port

#esi: true
#fragments: true
php_errors:
Expand Down
13 changes: 13 additions & 0 deletions config/packages/rate_limiter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
framework:
rate_limiter:
generator:
policy: 'fixed_window'
limit: 30
interval: '1 minute'
cache_pool: 'rate_limiter.cache'

when@test:
framework:
rate_limiter:
generator:
limit: 3
Loading
Loading