Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
7b7a688
Implement request API
Thanhphan1147 Mar 17, 2026
00a3ea7
update model validation before save and add unit tests
Thanhphan1147 Mar 17, 2026
77622dd
Merge branch 'main' into haprox-route-policy-requests-api
Thanhphan1147 Mar 17, 2026
bc11a1f
use environment variables for secret key
Thanhphan1147 Mar 17, 2026
6f1499d
Merge branch 'haprox-route-policy-requests-api' of github.com:canonic…
Thanhphan1147 Mar 17, 2026
6e98d08
ruff format
Thanhphan1147 Mar 17, 2026
f073454
add secret key for testing
Thanhphan1147 Mar 17, 2026
4842e4a
remove port attribute from test
Thanhphan1147 Mar 17, 2026
5b667c0
add requirements.txt for testing
Thanhphan1147 Mar 17, 2026
e719d33
reintroduce port field
Thanhphan1147 Mar 17, 2026
597eb66
Add change artifact
Thanhphan1147 Mar 17, 2026
6f51301
run lint with uv
Thanhphan1147 Mar 17, 2026
7f245ea
add unit testing
Thanhphan1147 Mar 17, 2026
6254485
remove custom test
Thanhphan1147 Mar 17, 2026
ad50aa3
update migration
Thanhphan1147 Mar 17, 2026
3640143
Wrap creation under `transaction.atomic`
Thanhphan1147 Mar 18, 2026
adbf18f
Potential fix for pull request finding
Thanhphan1147 Mar 18, 2026
daef5d3
remove unused code
Thanhphan1147 Mar 18, 2026
78e5dc0
minor fixes to settings
Thanhphan1147 Mar 18, 2026
cd93076
Potential fix for pull request finding
Thanhphan1147 Mar 18, 2026
f93e9cb
use django serializer
Thanhphan1147 Mar 18, 2026
4a92e21
update gitignore
Thanhphan1147 Mar 18, 2026
7b1c9ca
Merge branch 'haprox-route-policy-requests-api' of github.com:canonic…
Thanhphan1147 Mar 18, 2026
22e4aef
update view to use django rest
Thanhphan1147 Mar 19, 2026
266e20e
remove python-version
Thanhphan1147 Mar 19, 2026
d5db748
update gitignore
Thanhphan1147 Mar 19, 2026
34ca372
add missing license headers
Thanhphan1147 Mar 19, 2026
3ea5d0e
Add rules engine
Thanhphan1147 Mar 17, 2026
16833e4
update migration
Thanhphan1147 Mar 17, 2026
efe9beb
update view
Thanhphan1147 Mar 17, 2026
593518e
fix lint
Thanhphan1147 Mar 17, 2026
f23afe1
remove extra tests
Thanhphan1147 Mar 17, 2026
6955b92
add validation and update tests
Thanhphan1147 Mar 18, 2026
ff23fa0
update view
Thanhphan1147 Mar 18, 2026
314a687
remove to_dict
Thanhphan1147 Mar 19, 2026
a10a032
use serializer for get
Thanhphan1147 Mar 19, 2026
c4b297f
use serializer
Thanhphan1147 Mar 19, 2026
4f09fbc
remove unused tests
Thanhphan1147 Mar 19, 2026
ad1c42c
use filter for delete query
Thanhphan1147 Mar 19, 2026
fb9e143
update tests and move validation to serializer class
Thanhphan1147 Mar 19, 2026
b05c12a
Apply suggestion from @github-actions[bot]
Thanhphan1147 Mar 19, 2026
10a2708
Update haproxy-route-policy/policy/migrations/0001_initial.py
Thanhphan1147 Mar 19, 2026
571e469
Revert "Update haproxy-route-policy/policy/migrations/0001_initial.py"
Thanhphan1147 Mar 19, 2026
a22bedd
ignore migration files for license header
Thanhphan1147 Mar 19, 2026
7d3d20b
remove license header from generated files
Thanhphan1147 Mar 19, 2026
e41031c
Merge branch 'haprox-route-policy-requests-api' into haproxy-route-po…
Thanhphan1147 Mar 19, 2026
00c094e
add change artifact
Thanhphan1147 Mar 19, 2026
cd7c49a
add envlist to tox commands
Thanhphan1147 Mar 19, 2026
503a313
update envlist
Thanhphan1147 Mar 19, 2026
fc25b19
Merge branch 'haprox-route-policy-requests-api' into haproxy-route-po…
Thanhphan1147 Mar 19, 2026
a2d1ea2
convert pk to uuid for requests
Thanhphan1147 Mar 19, 2026
a9ceb87
Merge branch 'haprox-route-policy-requests-api' into haproxy-route-po…
Thanhphan1147 Mar 19, 2026
988ba70
Add guard against mal-formed uuid and parameter. Add logging configs,…
Thanhphan1147 Mar 19, 2026
9a246aa
add validators for port and paths
Thanhphan1147 Mar 19, 2026
35a286f
add tests for validators
Thanhphan1147 Mar 19, 2026
a42d4c3
add note for migration
Thanhphan1147 Mar 19, 2026
324114e
Merge remote-tracking branch 'origin/haprox-route-policy-requests-api…
Thanhphan1147 Mar 19, 2026
ee86d7d
ruff format
Thanhphan1147 Mar 19, 2026
9101175
remove unused imports
Thanhphan1147 Mar 19, 2026
69872ec
add static tests
Thanhphan1147 Mar 20, 2026
fee2543
Merge remote-tracking branch 'origin/main' into haproxy-route-policy-…
Thanhphan1147 Mar 20, 2026
b700245
guard rules API against pk
Thanhphan1147 Mar 20, 2026
931b5b1
Merge branch 'main' into haproxy-route-policy-rules-api
alithethird Mar 23, 2026
e3d7215
update view, middle wares and tests
Thanhphan1147 Mar 23, 2026
04f29ca
Merge branch 'haproxy-route-policy-rules-api' of github.com:canonical…
Thanhphan1147 Mar 23, 2026
b4717a4
Merge branch 'main' into haproxy-route-policy-rules-api
Thanhphan1147 Mar 23, 2026
6c1db27
refactor tests by parametrizing
Thanhphan1147 Mar 23, 2026
92fddb4
Merge branch 'haproxy-route-policy-rules-api' of github.com:canonical…
Thanhphan1147 Mar 23, 2026
ea6afe4
group tests by parameterizing
Thanhphan1147 Mar 23, 2026
7ec072c
refactor Rule model to rename attribute from "value" to "parameters"
Thanhphan1147 Mar 23, 2026
9a3d61a
update test name
Thanhphan1147 Mar 23, 2026
6b75a0a
update naming
Thanhphan1147 Mar 23, 2026
5e94907
Add coverage-report as part of unit test suite
Thanhphan1147 Mar 25, 2026
1910db5
update env list
Thanhphan1147 Mar 25, 2026
6a3b4b7
implement rule evaluation
Thanhphan1147 Mar 19, 2026
c564054
add change artifact
Thanhphan1147 Mar 19, 2026
92e6810
update imports
Thanhphan1147 Mar 19, 2026
ed16de9
update naming
Thanhphan1147 Mar 23, 2026
d3b5e6d
update rules matching logic
Thanhphan1147 Mar 25, 2026
ec6d312
update tests
Thanhphan1147 Mar 25, 2026
93ce0f4
save request using serializer with the correct instace
Thanhphan1147 Mar 26, 2026
7172da3
Merge remote-tracking branch 'origin/main' into haproxy-route-policy-…
Thanhphan1147 Mar 26, 2026
3e3a0a9
group tests
Thanhphan1147 Mar 26, 2026
60cc53f
update formatting
Thanhphan1147 Mar 26, 2026
195fa28
Add authentication configuration for django-restframework and adapt t…
Thanhphan1147 Mar 26, 2026
75663fa
add change artifact
Thanhphan1147 Mar 26, 2026
7d62e12
Add token urls
Thanhphan1147 Mar 26, 2026
2a0d45c
Merge branch 'main' into haproxy_route_policy_add_authentication
Thanhphan1147 Mar 30, 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
20 changes: 20 additions & 0 deletions docs/release-notes/artifacts/pr0412.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version_schema: 2

changes:
- title: Added authentication to haproxy-route-policy REST API
author: tphan025
type: minor
description: >
Configured Django REST Framework with JWT and session-based authentication
as default authentication classes, requiring all API endpoints to be accessed
by authenticated users. Added test_settings_authenticated.py for auth-enabled
tests, a dedicated unit-auth tox environment, and integration tests verifying
that unauthenticated requests are rejected and authenticated requests succeed.
Added djangorestframework-simplejwt as a dependency.
urls:
pr:
- https://github.com/canonical/haproxy-operator/pull/412
related_doc:
related_issue:
visibility: public
highlight: false
12 changes: 12 additions & 0 deletions haproxy-route-policy/haproxy_route_policy/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# django rest framework options
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
}

env_log_level = os.getenv("DJANGO_LOG_LEVEL", "INFO").upper()
if env_log_level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
env_log_level = "INFO"
Expand Down
7 changes: 7 additions & 0 deletions haproxy-route-policy/haproxy_route_policy/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@
"NAME": ":memory:",
}
}

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.AllowAny",
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2026 Canonical Ltd.
# See LICENSE file for licensing details.

"""Django settings for running tests with SQLite in an authenticated setup."""

from haproxy_route_policy.settings import * # noqa: F401, F403

# Mock secret key for testing.
SECRET_KEY = "test-secret-key"

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:",
}
}
8 changes: 8 additions & 0 deletions haproxy-route-policy/haproxy_route_policy/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,18 @@

from django.contrib import admin
from django.urls import include, path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)

from policy import urls as policy_urls

urlpatterns = [
path("admin/", admin.site.urls),
path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("api/token/verify/", TokenVerifyView.as_view(), name="token_verify"),
path("", include(policy_urls)),
]
85 changes: 85 additions & 0 deletions haproxy-route-policy/policy/tests/test_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2026 Canonical Ltd.
# See LICENSE file for licensing details.

"""Authentication tests."""

from django.test import TestCase, tag
from rest_framework.test import APIClient
from django.contrib.auth.models import User


@tag("auth")
class TestAuthenticationRequired(TestCase):
"""Tests that endpoints require authentication."""

def setUp(self):
self.client = APIClient()

def test_list_requests_unauthenticated(self):
"""GET /api/v1/requests returns 401/403 without auth."""
response = self.client.get("/api/v1/requests")
self.assertIn(response.status_code, [401, 403])

def test_create_requests_unauthenticated(self):
"""POST /api/v1/requests returns 401/403 without auth."""
response = self.client.post("/api/v1/requests", [], format="json")
self.assertIn(response.status_code, [401, 403])

def test_list_rules_unauthenticated(self):
"""GET /api/v1/rules returns 401/403 without auth."""
response = self.client.get("/api/v1/rules")
self.assertIn(response.status_code, [401, 403])


@tag("auth")
class TestAuthenticated(TestCase):
"""Tests endpoints as an authenticated user."""

def setUp(self):
self.user = User.objects.create_user("admin", "admin@example.com", "admin")
self.client = APIClient()
# Add nosec to ignore bandit warning as this is for testing.
self.client.login(username="admin", password="admin") # nosec

def test_create_requests_authenticated(self):
"""POST /api/v1/requests returns 201 with auth."""
payload = [
{
"relation_id": 1,
"hostname_acls": ["example.com"],
"backend_name": "backend-1",
"paths": ["/api"],
"port": 443,
},
{
"relation_id": 2,
"backend_name": "backend-2",
"port": 443,
},
]
response = self.client.post("/api/v1/requests", data=payload, format="json")
self.assertEqual(response.status_code, 201)

def test_create_rules_authenticated(self):
"""POST /api/v1/rules returns 201 with auth."""
payload = {
"name": "Test Rule",
"action": "allow",
"kind": "hostname_and_path_match",
"parameters": {
"hostnames": ["example.com"],
"paths": ["/api"],
},
}
response = self.client.post("/api/v1/rules", data=payload, format="json")
self.assertEqual(response.status_code, 201)

def test_list_requests_authenticated(self):
"""GET /api/v1/requests returns 200 with auth."""
response = self.client.get("/api/v1/requests")
self.assertEqual(response.status_code, 200)

def test_list_rules_authenticated(self):
"""GET /api/v1/rules returns 200 with auth."""
response = self.client.get("/api/v1/rules")
self.assertEqual(response.status_code, 200)
4 changes: 4 additions & 0 deletions haproxy-route-policy/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ requires-python = ">=3.12"
dependencies = [
"django>=6.0.3",
"djangorestframework>=3.16.1",
"djangorestframework-simplejwt>=5.5.1",
"validators>=0.35.0",
"whitenoise>=6.12.0",
]

[dependency-groups]
auth = [
"djangorestframework-simplejwt>=5.5.1",
]
coverage-report = [
"coverage[toml]>=7.13.5",
]
Expand Down
20 changes: 19 additions & 1 deletion haproxy-route-policy/tox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ skipsdist = true
skip_missing_interpreters = true
requires = ["tox>=4.21"]
no_package = true
envlist = ["lint", "unit", "static", "coverage-report"]
envlist = ["lint", "unit", "unit-auth", "static", "coverage-report"]

[env_run_base]
passenv = ["PYTHONPATH"]
Expand All @@ -26,11 +26,29 @@ commands = [
"test",
"policy",
"--settings=haproxy_route_policy.test_settings",
"--exclude-tag=auth",
"-v2",
],
]
dependency_groups = ["unit"]


[env.unit_auth]
description = "Run auth unit tests"
commands = [
[
"coverage",
"run",
"manage.py",
"test",
"policy",
"--settings=haproxy_route_policy.test_settings_authenticated",
"--tag=auth",
"-v2",
],
]
dependency_groups = ["unit", "auth"]

[env.lint]
description = "Check code against coding style standards"
commands = [
Expand Down
29 changes: 29 additions & 0 deletions haproxy-route-policy/uv.lock

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

Loading