From a51251b00019b0d259934674517b2d0bc58a87ee Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 22 Sep 2026 00:06:49 +0000 Subject: [PATCH] fix(api): fail Redocly on missing 4xx and 2xx/3xx (DEV-289) Promote operation-4xx-response and the 2xx-or-3xx success rule to error. Replace unused health and roster 400s with 403, matching portal health. Form-status keeps its real 400 for invalid week. Co-authored-by: Adam Moussa --- .redocly.yaml | 7 +++++-- openapi.yaml | 4 ++-- tests/test_openapi_contract.py | 10 ++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.redocly.yaml b/.redocly.yaml index b1ea20b..473f95c 100644 --- a/.redocly.yaml +++ b/.redocly.yaml @@ -1,15 +1,18 @@ # Same Redocly recommended ruleset as internal-portal (DEV-223 / DEV-289). -# Login-style redirects succeed with 302. Recommended only counts 2XX. +# Recommended operation-2xx-response does not count 302. Login-style redirects +# succeed with 302, so that rule is replaced by operation-2xx-or-3xx-response +# at error. operation-4xx-response is promoted to error so missing 4xx fails CI. extends: - recommended rules: operation-2xx-response: off + operation-4xx-response: error rule/operation-2xx-or-3xx-response: subject: type: Responses message: Operation must define a 2XX or 3XX response. - severity: warn + severity: error assertions: requireAny: - "200" diff --git a/openapi.yaml b/openapi.yaml index 968bd26..36af0b5 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -46,7 +46,7 @@ paths: application/json: schema: $ref: "#/components/schemas/Health" - "400": + "403": $ref: "#/components/responses/StringError" /api/menu/{week}: @@ -264,7 +264,7 @@ paths: application/json: schema: $ref: "#/components/schemas/FormRoster" - "400": + "403": $ref: "#/components/responses/StringError" /api/publish/settings: diff --git a/tests/test_openapi_contract.py b/tests/test_openapi_contract.py index a876099..d64fb41 100644 --- a/tests/test_openapi_contract.py +++ b/tests/test_openapi_contract.py @@ -13,7 +13,17 @@ def test_openapi_uses_redocly_recommended(): assert "extends:" in redocly assert "- recommended" in redocly assert "operation-2xx-response: off" in redocly + assert "operation-4xx-response: error" in redocly assert "rule/operation-2xx-or-3xx-response" in redocly + assert "severity: error" in redocly + health = spec.split("/api/health:", 1)[1].split("\n /", 1)[0] + assert '"403":' in health + assert '"400":' not in health + roster = spec.split("/api/roster:", 1)[1].split("\n /", 1)[0] + assert '"403":' in roster + assert '"400":' not in roster + form_status = spec.split("/api/form-status/{week}:", 1)[1].split("\n /", 1)[0] + assert '"400":' in form_status assert "root: openapi.yaml" in redocly assert '"openapi:lint"' in package assert '"@redocly/cli": "2.52.1"' in package