Skip to content
Draft
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
13 changes: 13 additions & 0 deletions spp_api_v2_simulation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ Dependencies
Changelog
=========

19.0.2.0.1
~~~~~~~~~~

- fix(security): build the API V2 FastAPI app from the current router
module. ``fastapi_endpoint.py`` still imported ``aggregation_router``
from the removed ``routers/aggregation`` module (renamed to
``routers/analytics``), so ``_get_fastapi_routers()`` raised
``ModuleNotFoundError`` during app construction — which FastAPI
dispatch performs, before endpoint OAuth/JWT checks, for a request to
the API root. An unauthenticated request could therefore take the
whole API V2 endpoint down. The import now targets
``routers/analytics`` (which still exports ``aggregation_router``).

19.0.2.0.0
~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion spp_api_v2_simulation/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"name": "OpenSPP Simulation API",
"category": "OpenSPP/Integration",
"version": "19.0.2.0.0",
"version": "19.0.2.0.1",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/OpenSPP2",
Expand Down
2 changes: 1 addition & 1 deletion spp_api_v2_simulation/models/fastapi_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _get_fastapi_routers(self) -> list[APIRouter]:
"""Add simulation and aggregation routers to API V2."""
routers = super()._get_fastapi_routers()
if self.app == "api_v2":
from ..routers.aggregation import aggregation_router
from ..routers.analytics import aggregation_router
from ..routers.comparison import comparison_router
from ..routers.run import run_router
from ..routers.scenario import scenario_router
Expand Down
11 changes: 11 additions & 0 deletions spp_api_v2_simulation/readme/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
### 19.0.2.0.1

- fix(security): build the API V2 FastAPI app from the current router module.
``fastapi_endpoint.py`` still imported ``aggregation_router`` from the removed
``routers/aggregation`` module (renamed to ``routers/analytics``), so
``_get_fastapi_routers()`` raised ``ModuleNotFoundError`` during app
construction — which FastAPI dispatch performs, before endpoint OAuth/JWT
checks, for a request to the API root. An unauthenticated request could
therefore take the whole API V2 endpoint down. The import now targets
``routers/analytics`` (which still exports ``aggregation_router``).

### 19.0.2.0.0

- Initial migration to OpenSPP2
1 change: 1 addition & 0 deletions spp_api_v2_simulation/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
from . import test_router_coverage
from . import test_scenario_update
from . import test_simulation_service
from . import test_fastapi_router_inclusion
33 changes: 33 additions & 0 deletions spp_api_v2_simulation/tests/test_fastapi_router_inclusion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Part of OpenSPP. See LICENSE file for full copyright and licensing details.
"""Building the API V2 FastAPI app must not abort on a stale router import.

``fastapi.endpoint._get_fastapi_routers()`` runs during app construction, which
FastAPI dispatch performs for a request to the API root *before* endpoint-level
OAuth/JWT checks. A broken import here (e.g. a router module renamed without
updating the importer) therefore turns into an unauthenticated failure that
takes the whole API V2 endpoint down. This test calls the router aggregation
for the api_v2 app and asserts the simulation ``/aggregation`` router is
included without raising.
"""

from odoo.tests import TransactionCase, tagged


@tagged("post_install", "-at_install")
class TestSimulationFastapiRouterInclusion(TransactionCase):
def test_api_v2_routers_build_and_include_aggregation(self):
endpoint = self.env["fastapi.endpoint"].search([("app", "=", "api_v2")], limit=1)
self.assertTrue(
endpoint,
"The api_v2 fastapi.endpoint record must exist (shipped by spp_api_v2)",
)

# Must not raise ModuleNotFoundError from a stale router import.
routers = endpoint._get_fastapi_routers()

prefixes = [getattr(r, "prefix", "") for r in routers]
self.assertIn(
"/aggregation",
prefixes,
"The simulation aggregation router must be included in the API V2 app",
)
Loading