From 3d8082718260487d8067248c8b7dcaf7add0ba24 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. Drop unused 400s on health and CORS OPTIONS. Health documents 403 like the portal. CORS stays in Flask and is not part of the employee contract. Co-authored-by: Adam Moussa --- .redocly.yaml | 7 +++++-- openapi.yaml | 12 +----------- tests/infra/test_hcp_contract.py | 6 ++++++ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.redocly.yaml b/.redocly.yaml index 0914f58..17d1df1 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 d26e979..aa4adac 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -44,7 +44,7 @@ paths: application/json: schema: $ref: "#/components/schemas/Health" - "400": + "403": $ref: "#/components/responses/PortalError" /roster: @@ -118,16 +118,6 @@ paths: $ref: "#/components/responses/PortalError" "503": $ref: "#/components/responses/PortalError" - options: - operationId: optionsShifts - tags: [Shifts] - summary: CORS preflight - security: [] - responses: - "204": - description: Empty preflight - "400": - $ref: "#/components/responses/PortalError" /api/shifts/pick: post: diff --git a/tests/infra/test_hcp_contract.py b/tests/infra/test_hcp_contract.py index 8688ffd..1e69e9d 100644 --- a/tests/infra/test_hcp_contract.py +++ b/tests/infra/test_hcp_contract.py @@ -131,7 +131,13 @@ 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 + assert "optionsShifts" not in spec + health = spec.split("/api/health:", 1)[1].split("\n /", 1)[0] + assert '"403":' in health + assert '"400":' not in health assert 'root: openapi.yaml' in redocly assert '"openapi:lint"' in package assert '"@redocly/cli": "2.52.1"' in package