procurement-ingest/lambdas/api
Adam Moussa cf8ca2eeb6
feat(api): custom domain procurement-api.seahaven.com (stacked on PR-2) (#140)
* feat(api): custom domain procurement-api.seahaven.com for the read API

Stacked on feat/shoc-wo-webhook. Gives the SHOC-facing read API a stable,
brandable endpoint instead of the opaque execute-api URL.

- procurement_api_stack.py: REGIONAL API Gateway DomainName (TLS 1.2) +
  empty base-path mapping to the prod stage, so callers hit
  https://procurement-api.seahaven.com/work-orders (no /prod segment). The
  ACM cert ARN is read from SSM (/procurement-api/custom-domain/certificate-arn)
  via value_for_string_parameter, because the seahaven.com zone is in the
  mgmt account (cross-account DNS) and the cert is issued out of band. Outputs
  expose the regional alias target + hosted-zone id for the mgmt A-record.
- scripts/setup_procurement_api_domain.sh: idempotent two-step runbook
  (cert: request + mgmt-zone validation + wait + SSM; alias: post-deploy
  A-record from stack outputs). Verifies both account identities.
- handler._base_url: omit the /{stage} segment for a custom-domain request
  (the base-path mapping serves the stage at the root) so the docs never
  advertise a broken server URL; execute-api hosts keep /{stage}.
- openapi.json: custom domain added as servers[0] (recommended), execute-api
  kept as the direct fallback + the per-request injection target.

No IAM/auth/policy change (same API id + resource policy), so the SigV4
surface and the mandatory cross-family gates are unaffected. 751 pytest,
ruff, cdk synth, redocly lint all green.

* fix(api): use .endswith('.amazonaws.com') instead of substring check for execute-api detection

The prior '.execute-api.' in domain substring check is fragile and
triggers CodeQL incomplete-sanitization warnings. All API Gateway default
domains end with .amazonaws.com, so a suffix check is more precise and
also silences the false-positive alert.

Refs: https://github.com/Sea-Haven-Industries/procurement-ingest/security/code-scanning/6
2026-07-24 18:41:10 -04:00
..
docs.html feat(api): Redocly lint gate + SHOC-themed /docs (Redoc theming, topbar, collapsible samples) (#130) 2026-07-24 18:04:30 +00:00
fonts.css feat(api): Redocly lint gate + SHOC-themed /docs (Redoc theming, topbar, collapsible samples) (#130) 2026-07-24 18:04:30 +00:00
handler.py feat(api): custom domain procurement-api.seahaven.com (stacked on PR-2) (#140) 2026-07-24 18:41:10 -04:00
openapi.json feat(api): custom domain procurement-api.seahaven.com (stacked on PR-2) (#140) 2026-07-24 18:41:10 -04:00
pagination.py feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00
po_repo.py feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00
redoc.standalone.js feat(api): swap /docs from Swagger UI to Redoc (vendored offline) (#129) 2026-07-24 12:00:22 -04:00
requirements.txt feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00
router.py feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00
serialization.py feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00
wo_repo.py feat(api): procurement-api read stack + OpenAPI docs (SHOC reconciliation path) (#127) 2026-07-23 19:32:20 -04:00