From 8cf18f80907e49140cd0088e624c4dfbffd89db3 Mon Sep 17 00:00:00 2001 From: Philippe Parage <69145356+pparage@users.noreply.github.com> Date: Thu, 6 Aug 2026 13:29:26 +0200 Subject: [PATCH] ci: fail when the committed openapi.json is out of date (#117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing regenerated or verified the spec that bootstraps the Kong gateway config, so it rotted silently — by #115 it had drifted back to the pre-v1 API, 84 paths with zero /v1. No test reads the file: the smoke tests and the healthcheck all hit the live /docs/openapi.json, and routes_golden.json covers registered routes, not the artifact. Generation is deterministic and independent of the env vars it needs (verified: byte-identical output from a different cwd with bogus paths), so this is safe as a hard gate. Confirmed it fails on a stale spec. Also makes the README recipe runnable — it died at import time without those vars, which is part of why regenerating was easy to skip. --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ README.md | 8 +++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 987377d..6493bab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,3 +26,23 @@ jobs: # since tests/overlay/conftest.py deliberately fails rather than skips # when the vectors are missing and CI is set. - run: pytest --tb=short -q --ignore=tests/overlay + + # The committed spec bootstraps the Kong gateway config, but nothing + # regenerated or verified it — it had rotted back to the pre-v1 API + # (84 paths, zero /v1) before #115. Generation is deterministic and + # independent of these paths; they only satisfy import-time reads. + - name: OpenAPI drift check + env: + PROJECT_ROOT_DIR: ${{ github.workspace }} + API_BACKEND_WWWAPP_PLAYBOOKS_DIR: ${{ github.workspace }} + API_BACKEND_PUBLIC_PLAYBOOKS_DIR: ${{ github.workspace }} + API_BACKEND_INVENTORY_DIR: ${{ github.workspace }}/inventory + PYTHONPATH: ${{ github.workspace }} + run: | + python -c " + import json + from app.main import create_app + print(json.dumps(create_app().openapi(), indent=2)) + " > /tmp/openapi.check.json + diff -u openapi.json /tmp/openapi.check.json \ + || { echo "::error::openapi.json is out of date — regenerate it (see README) and commit"; exit 1; } diff --git a/README.md b/README.md index f79edd8..11de1c3 100644 --- a/README.md +++ b/README.md @@ -139,9 +139,13 @@ VAULT_PASSWORD_FILE=/run/secrets/vault_pass docker compose up ### OpenAPI spec -The committed `openapi.json` at the repository root reflects the current API surface. It is used to bootstrap the Kong API gateway configuration. To regenerate it after adding or modifying routes: +The committed `openapi.json` at the repository root reflects the current API surface. It is used to bootstrap the Kong API gateway configuration, and **CI fails if it is out of date** — regenerate and commit it whenever you add or modify a route: ```bash +PROJECT_ROOT_DIR=$PWD \ +API_BACKEND_WWWAPP_PLAYBOOKS_DIR=$PWD \ +API_BACKEND_PUBLIC_PLAYBOOKS_DIR=$PWD \ +API_BACKEND_INVENTORY_DIR=$PWD/inventory \ PYTHONPATH=. python -c " import json from app.main import create_app @@ -149,6 +153,8 @@ print(json.dumps(create_app().openapi(), indent=2)) " > openapi.json ``` +The environment variables are only there to satisfy import-time reads — several route modules resolve paths at module scope, so the command dies without them. The generated document does not depend on their values. + --- ## Configuration