fix: convert astrolabe int provisioned_at to ISO before ProvisioningStatus

Round-4 review (real bug): get_background_sync_status now returns provisioned_at
as Unix seconds (the wire/pact value), but ProvisioningStatus.provisioned_at is
str | None (ISO). Constructing it for a provisioned user raised a Pydantic
ValidationError — a path that was unreachable before the has_access fix.

Convert int -> ISO at the oauth_tools boundary (mirroring the existing
refresh_token branch), keeping the model schema and the int-asserting contract
pact/unit tests intact. Add a regression test that drives the full
_get_provisioning_status round-trip with an integer timestamp.

Also surface dropped provider-state params in the verifier's _dispatch_state
no-op branch (round-4 nit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-10 21:36:27 +02:00
co-authored by Claude Opus 4.8
parent c474f62190
commit 69c40a0479
3 changed files with 48 additions and 2 deletions
+7 -1
View File
@@ -118,7 +118,13 @@ async def _get_provisioning_status(ctx: Context, user_id: str) -> ProvisioningSt
" get_provisioning_status: app password FOUND for user_id=%s",
user_id,
)
provisioned_at_str = status.get("provisioned_at")
# Astrolabe returns provisioned_at as Unix seconds (see the
# contract pact); convert to the ISO string the model expects.
provisioned_at_str = None
provisioned_at_raw = status.get("provisioned_at")
if provisioned_at_raw:
dt = datetime.fromtimestamp(provisioned_at_raw, tz=timezone.utc)
provisioned_at_str = dt.isoformat()
return ProvisioningStatus(
is_provisioned=True,
provisioned_at=provisioned_at_str,