Skip to content

chore(ci): harden api-sync coverage (enum, nested-object, delivery manifest) - #70

Merged
ericviana merged 1 commit into
mainfrom
eric/api-sync-hardening
Aug 4, 2026
Merged

ericviana merged 1 commit into
mainfrom
eric/api-sync-hardening

Conversation

@ericviana

Copy link
Copy Markdown
Member

Summary

Three infra hardenings to .api-sync, no user-visible SDK change:

  1. Enum coverage check (blocking). sync.py --check now walks every mapped schema for enum-constrained properties in any shape the spec uses (bare enum, array items.enum, or either wrapped in anyOf/oneOf) and fails if the locator has no enums map entry and no recorded .api-sync/unmodeled.json exclusion. Only 17 shared enums were mapped before this; running the new check against the real spec surfaced ~194 enum-constrained properties that were invisible to the patcher, most already backed by existing SDK Literals (AccountClass, Country, BusinessIndustry, Network, TransactionStatus, ...) that simply had never been registered. 92 of those got wired into spec-map.json's enums list; wiring them surfaced 4 additional real membership drifts (missing values on BusinessIndustry, LimitIncreaseRequestSupportingDocumentType, Currency, ManualExecutionStatus) plus one bad-fit case (CustomerOut.kyc_type is a discriminated union with per-variant singleton Literals, not one shared enum) -- all recorded as honest, attributed unmodeled.json entries rather than silently patched, since fixing them is real SDK behavior change out of scope for an infra PR. The remaining 101 gaps are properties genuinely typed as bare str today (mostly the tracking_* sub-object family shared across every payin/payout response and webhook schema) -- also recorded, each with a reason and owner.

  2. Nested-object coverage check (blocking). Recursively enumerates inline object and array-item-object shapes under every mapped schema's mapped path; each must have its own map entry or a recorded omission. Found 18 such shapes (offramp_wallets, owners, tracking_bridge_swap/tracking_paymaster/tracking_transaction_monitoring, limit, us, etc.) that are already modeled by real SDK TypedDicts but were never registered as specPath map entries -- recorded as nested_object exclusions naming the existing TypedDict, pending a human pass to wire the actual specPath.

  3. Delivery manifest verification. The api-sync workflow now fetches .api-sync/delivery.json alongside spec-current.json from the api-sync-data branch and verifies it before running the patcher: fails loudly if either file is missing, if sha256sum(spec-current.json) doesn't match the manifest's spec_sha256, or if the triggering repository_dispatch payload's spec_sha256 is non-empty and stale against what's currently on that branch.

Also reviewed .github/workflows/pipeline-alert.yml per request: it already passes all four injection-safety criteria (event fields via env:, jq -n --arg for payload construction, quoted webhook URL, missing SLACK_WEBHOOK_URL exits non-zero). No changes needed there.

Two new unmodeled.json kinds added: enum_coverage (schema + property [+ optional path]) and nested_object (schema + path), both validated by load_unmodeled() the same way property/enum already are.

Test plan

  • New unit tests for find_enum_locator, reconcile_enum_coverage, reconcile_nested_coverage, and the two new unmodeled.json kinds (233 tests total, all passing)
  • python3 .api-sync/sync.py --check passes clean (exit 0) against the real spec-snapshot
  • python3 .api-sync/sync.py --validate-map and --coverage unaffected
  • check_contract.py, pytest, pyright, mypy, ruff all pass

Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs

.api-sync/sync.py --check now walks every mapped schema for
enum-constrained properties (bare enum, items.enum, and anyOf/oneOf
wrapped forms) and for inline object/array-item shapes, and fails if
either lacks a spec-map.json entry or a recorded unmodeled.json
exclusion. Only ~17 shared enums were previously mapped while domain
Literals already in the SDK (AccountClass, Country, BusinessIndustry,
etc.) were invisible to the patcher; this makes every such gap
mechanically visible instead of silently unchecked.

Also wires the api-sync workflow to verify the delivery manifest
(.api-sync/delivery.json) committed alongside spec-current.json on the
api-sync-data branch before running the patcher: fails loudly if
either file is missing, if the spec's sha256 does not match the
manifest, or if the triggering repository_dispatch payload's
spec_sha256 is stale against what is currently on that branch.

Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs
@ericviana
ericviana merged commit 868557f into main Aug 4, 2026
1 check was pending
@ericviana
ericviana deleted the eric/api-sync-hardening branch August 4, 2026 12:50
@BernardoSM

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants