Skip to content

Commit e14b3f1

Browse files
authored
feat(spec): OpenAPI spec sync script + upstream snapshot (#47)
* feat(spec): add OpenAPI spec sync script and upstream snapshot The local OpenAPI spec at `docs/statuspro-openapi.yaml` is a fork — we evolve it locally to add params/endpoints not yet declared upstream (e.g. the `page` query parameter for `GET /orders` added in #27). Without a way to track what's diverged, local additions silently rot when upstream renames or removes fields. Adds `scripts/sync_openapi_spec.py` (registered as `poe sync-openapi-spec`) that: 1. Fetches the canonical upstream spec from `https://orderstatuspro.com/api/openapi.json` (configurable via `STATUSPRO_OPENAPI_URL`) 2. Normalizes the JSON to YAML with deterministic ordering — top-level keys follow OpenAPI convention (openapi, info, servers, security, tags, paths, components), nested keys sort alphabetically, list ordering is preserved (positionally meaningful in OpenAPI). 3. Writes to `docs/statuspro-openapi.upstream.yaml` with an auto- generated banner explaining its provenance. Workflow: - Run `uv run poe sync-openapi-spec` periodically (or via CI) to refresh the upstream snapshot. - `git diff` between commits of the synced file shows what changed upstream between sync points. - Reconcile interesting deltas into the local fork by hand; the script intentionally does NOT auto-merge — that's a human judgment call (e.g. "did upstream rename a parameter we already added?"). The script is dependency-free beyond stdlib + PyYAML (already in our dev deps). Includes the first synced snapshot. Structural diff against the local fork shows exactly one local addition: the `page` parameter on `GET /orders` from #27. All paths (9), schemas (20), and other params match upstream exactly. Addresses #29. * fix(spec): exclude auto-generated upstream snapshot from yamllint `docs/statuspro-openapi.upstream.yaml` is auto-generated by `scripts/sync_openapi_spec.py` (PyYAML's default block style) and uses indentation that yamllint flags but is otherwise valid YAML. The local fork is already excluded for the same reason; extend the ignore to the synced upstream view. * fix(spec): validate URL scheme before fetching to satisfy SAST GitHub Advanced Security (Semgrep `dynamic-urllib-use-detected`) flagged the urllib call because the URL is configurable via `STATUSPRO_OPENAPI_URL` and urllib accepts `file://` schemes — a misconfigured env var could read local files. Validate the URL scheme up front (must be http or https) and raise ValueError otherwise. The default URL is unchanged. * refactor(spec): switch sync script from urllib to httpx + Copilot fixes Switches the HTTP fetch from stdlib urllib to httpx (already a project dependency for the API client). This: - Matches the rest of the project's HTTP idiom - Eliminates the recurring Semgrep `dynamic-urllib-use-detected` flag that fires on the urllib pattern even with scheme validation in front - Uses one less stdlib module (urllib.parse retained for the scheme validation; urllib.error and urllib.request are gone) The scheme allow-list is kept as defense-in-depth — httpx itself rejects non-HTTP URLs but the explicit check documents the contract. Plus three Copilot-flagged fixes: 1. Module docstring now mentions `STATUSPRO_OPENAPI_OUTPUT` (the output path env var) alongside `STATUSPRO_OPENAPI_URL`. 2. YAML fallback parsing is wrapped in try/except so a non-JSON, non-YAML upstream response produces a clean error message rather than a stack trace. 3. `Path.write_text` now passes `encoding="utf-8"` explicitly to match the rest of the repo's file-write convention.
1 parent d09d418 commit e14b3f1

4 files changed

Lines changed: 1086 additions & 0 deletions

File tree

.yamllint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,5 @@ ignore: |
4545
*.egg-info/
4646
statuspro_public_api_client/generated/
4747
docs/statuspro-openapi.yaml
48+
docs/statuspro-openapi.upstream.yaml
4849
pnpm-lock.yaml

0 commit comments

Comments
 (0)