Commit e14b3f1
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
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
48 | 49 | | |
0 commit comments