Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Heroku Review Apps #8

Merged
merged 1 commit into from
Nov 7, 2024
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
5 changes: 0 additions & 5 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----
Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,3 @@ black = "*"
autoflake = "*"
"zope.testing" = "*"
pytest-freezegun = "*"

[tool.pytest.ini_options]
junit_duration_report = "call"
4 changes: 4 additions & 0 deletions pyramid_cloudflare_access/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
28 changes: 24 additions & 4 deletions pyramid_cloudflare_access/tests/test_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Loading