feat: wire age review actions to Keycast account suspension (#79)#80
Conversation
460ee67 to
afa450f
Compare
Standalone Keycast admin API client for account suspension.
Three functions: suspendUser, unsuspendUser, banUser. Never throws --
returns KeycastResult { success, status?, error? }. Gracefully
degrades when not configured. Validates pubkey format before URL
interpolation. Handles SecretStoreSecret bindings.
11 unit tests covering success, 4xx, 5xx, network error, missing
config, empty token from unprovisioned SecretStoreSecret, and pubkey
validation.
handleUpdateAgeReviewCase: suspend on restricted_*, unsuspend on cleared, ban on denied_closed (reason: age_review_denied). checkAgeReviewDeadlines cron: ban on auto-close (reason: age_review_expired). All calls are fire-and-forget side effects wrapped in try/catch -- never block primary operations. AgeReviewEnv extends both BulkModerateEnv and KeycastEnv. KEYCAST_URL and KEYCAST_SERVICE_TOKEN added to Env interface. 7 integration tests covering all three transitions, graceful degradation on failure/throw, and cron path assertion.
KEYCAST_URL var and KEYCAST_SERVICE_TOKEN Secrets Store binding added to all three environments (prod, staging, test). Inert until the secret is provisioned in the shared store. ZENDESK_FIELD_AGE_REVIEW_DEADLINE set to 16123853180303 in all three configs (folded from PR #77, already deployed).
0c1f4c6 to
516cf15
Compare
|
Follow-up cleanup is pushed in aa989a1. What changed:
Validation run locally:
GitHub checks are green on the updated SHA. |
NotThatKindOfDrLiz
left a comment
There was a problem hiding this comment.
Final pass looks clean. The unsafe test wrangler file is removed, the Keycast/account-status transitions are now gated correctly, and the new regression coverage closes the previously unsafe clear-path behavior. Local validation and GitHub checks are green on aa989a1.
dcadenas
left a comment
There was a problem hiding this comment.
The Keycast account state must be fixed before merge. Clearing an age review case can currently leave the account suspended after the case moves through review or follow-up states.
| const enteredRestrictedState = requestedState !== undefined | ||
| && isAccountRestrictedAgeReviewState(requestedState) | ||
| && !isAccountRestrictedAgeReviewState(existing.state); | ||
| const clearedRestrictedState = requestedState === 'cleared' |
There was a problem hiding this comment.
Make the clear transition unsuspend accounts that already passed through a restricted age-review state, not only accounts whose immediately previous state is restricted.
A normal path is restricted_pending_* -> submitted_for_review or needs_follow_up -> cleared, and the middle transition intentionally leaves Keycast suspended.
With the current clearedRestrictedState check, the final clear skips unsuspendUser and leaves the account suspended after the case is cleared.
Add a regression test for restricted_pending_* -> submitted_for_review -> cleared, and cover needs_follow_up if that path can also follow a suspension.
There was a problem hiding this comment.
Fixed in b4b9f3e. Replaced clearedRestrictedState (which required the immediately prior state to be restricted) with an unconditional check on requestedState === 'cleared'. Both unsuspendUser and un-age-restrict-all are idempotent, so they fire on every clear regardless of prior state.
Added regression tests for restricted_pending_* → submitted_for_review → cleared and needs_follow_up → cleared.
Clearing a case that passed through intermediate states (submitted_for_review, needs_follow_up) after restriction skipped the Keycast unsuspend and bulk un-age-restrict calls because the check required the immediately prior state to be restricted. Both calls are idempotent, so fire them on every clear regardless of prior state. Adds regression tests for submitted_for_review → cleared and needs_follow_up → cleared paths.
dcadenas
left a comment
There was a problem hiding this comment.
✅ Keycast age actions land cleanly.
Summary
keycast-client.tsmodule withsuspendUser,unsuspendUser,banUserfunctions calling Keycast'sPUT /admin/users/:pubkey/statusendpointKEYCAST_URLto staging and production wrangler configs (KEYCAST_SERVICE_TOKENadded separately viawrangler secret)Closes #79
Prerequisites
KEYCAST_SERVICE_TOKENmust be set on staging/production viawrangler secret putbefore Keycast calls fire (calls silently return "not configured" until then)Test plan
KEYCAST_SERVICE_TOKENset, confirm age review transitions still work