From 140632039550f0a5f123c7c36fbc6eb15f074551 Mon Sep 17 00:00:00 2001 From: Neyts Zupan Date: Thu, 7 Nov 2024 16:32:31 +0000 Subject: [PATCH] Add support for Heroku Review Apps Also fix failing tests. --- .github/workflows/python-app.yml | 5 ---- Makefile | 2 +- README.rst | 1 + pyproject.toml | 3 -- pyramid_cloudflare_access/__init__.py | 4 +++ .../tests/test_access.py | 28 ++++++++++++++++--- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index fe61704..b717156 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -34,8 +34,3 @@ jobs: - name: Test run: poetry run make unit - - - name: Upload to BlueRacer - run: bash <(curl -s https://app.blueracer.io/upload) - env: - BLUERACER_TOKEN: ${{ secrets.BLUERACER_TOKEN }} diff --git a/Makefile b/Makefile index 7bd72ea..5c41e98 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ ifeq ($(full_suite),"false") endif full_suite_args = "" ifeq ($(full_suite),"true") - full_suite_args = --junitxml junit.xml --durations 10 --cov=pyramid_cloudflare_access --cov-branch --cov-report html --cov-report xml:cov.xml --cov-report term-missing --cov-fail-under=100 + full_suite_args = --cov=pyramid_cloudflare_access --cov-branch --cov-report html --cov-report xml:cov.xml --cov-report term-missing --cov-fail-under=100 endif .PHONY: unit diff --git a/README.rst b/README.rst index 308b773..50c2bfa 100644 --- a/README.rst +++ b/README.rst @@ -23,6 +23,7 @@ Compatibility pyramid_cloudflare_access runs with pyramid>=1.7 and python>=3.6. Other versions might also work. +Heroku Review Apps deployed on `*.herokuapp.com` subdomains automatically skip the cloudflare access check as their domains are dynamic and as such can't be configured in Cloudflare dashboard in advance. Usage ----- diff --git a/pyproject.toml b/pyproject.toml index 7a55047..242a837 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,3 @@ black = "*" autoflake = "*" "zope.testing" = "*" pytest-freezegun = "*" - -[tool.pytest.ini_options] -junit_duration_report = "call" diff --git a/pyramid_cloudflare_access/__init__.py b/pyramid_cloudflare_access/__init__.py index 708d6ec..f037b80 100644 --- a/pyramid_cloudflare_access/__init__.py +++ b/pyramid_cloudflare_access/__init__.py @@ -60,6 +60,10 @@ def authenticated_request(self, request: Request) -> bool: def __call__(self, request: Request): + # Support for Heroku Review apps + if "herokuapp.com" in request.headers.get("Host", ""): + return self.handler(request) + if not self.authenticated_request(request): raise exc.HTTPForbidden() diff --git a/pyramid_cloudflare_access/tests/test_access.py b/pyramid_cloudflare_access/tests/test_access.py index 96be860..2febd7a 100644 --- a/pyramid_cloudflare_access/tests/test_access.py +++ b/pyramid_cloudflare_access/tests/test_access.py @@ -40,7 +40,7 @@ sample_audience = "https://expenses-api" -@pytest.mark.freeze_time("2017-05-21") +@pytest.mark.freeze_time("2019-10-25 12:36:00") def test_happy_path(mocker) -> None: """Test that JWT token is parsed and authorized.""" @@ -53,7 +53,7 @@ def test_happy_path(mocker) -> None: request.cookies = {"CF_Authorization": sample_token} request.registry.settings = { "pyramid_cloudflare_access.policy_audience": sample_audience, - "pyramid_cloudflare_access.team": "auth0", + "pyramid_cloudflare_access.team": "https://foo.cloudflareaccess.com", } CloudflareAccess(tween_handler, request.registry)(request) @@ -71,7 +71,7 @@ def test_missing_cookie(mocker) -> None: request = testing.DummyRequest() request.registry.settings = { "pyramid_cloudflare_access.policy_audience": sample_audience, - "pyramid_cloudflare_access.team": "auth0", + "pyramid_cloudflare_access.team": "https://foo.cloudflareaccess.com", } with pytest.raises(HTTPBadRequest): CloudflareAccess(tween_handler, request.registry)(request) @@ -89,7 +89,27 @@ def test_auth_failed(mocker) -> None: request.cookies = {"CF_Authorization": sample_token} request.registry.settings = { "pyramid_cloudflare_access.policy_audience": sample_audience, - "pyramid_cloudflare_access.team": "auth0", + "pyramid_cloudflare_access.team": "https://foo.cloudflareaccess.com", } with pytest.raises(HTTPForbidden): CloudflareAccess(tween_handler, request.registry)(request) + +def test_herokuapp(mocker) -> None: + """Test that Cloudflare Access is skipped for Heroku-hosted apps. + + This is to support Review Apps that have dynamic *.herokuapp.com hostname, + that cannot be configured as a domain for Cloudflare Access application + in Cloudflare dashboard. + """ + tween_handler = mocker.Mock() + + request = testing.DummyRequest() + request.cookies = {} + request.registry.settings = { + "pyramid_cloudflare_access.policy_audience": sample_audience, + "pyramid_cloudflare_access.team": "https://foo.cloudflareaccess.com", + } + request.headers['Host'] = "foo.herokuapp.com" + + CloudflareAccess(tween_handler, request.registry)(request) + tween_handler.assert_called_with(request)