fix(stage-1): audit High-severity backend correctness + CI unblocker
Closes 4 High-severity audit findings:
- describe_event broken for HTTP-async payloads: was reading source/op
JSON fields that HttpDispatchPayload doesn't carry, producing empty
source on DL rows. from_wire("") then fell back to Kv on replay, the
dispatcher tried to resolve a non-existent trigger, and replay no-op'd
silently. Now branches on OutboxSourceKind: HTTP rows emit
"<method> <path>" + source="http"; Invoke rows emit "invoke_async" +
source="invoke"; TriggerEvent payloads keep top-level field extraction.
- HTTP outbound Authorization leaked across cross-origin redirects.
Manual redirect loop (Policy::none) reused header_map on every hop
and only scrubbed Content-Type for POST->GET. Now compares
url::Url::origin() across hops and strips Authorization,
Proxy-Authorization, Cookie when origin changes — matching reqwest's
default policy.
- F-S-010 inbound email HMAC had no replay protection. Signature was
computed over body only with no timestamp or nonce, so captured POSTs
were replayable indefinitely. Adds X-Picloud-Timestamp header bound
into the HMAC input (signed string is ts || "." || body), 300s
tolerance window, and a process-local LRU keyed on
(ts, sha256(body)) with 600s TTL to catch within-window replays.
Breaking change: webhook senders must include the timestamp header.
- expected_schema.txt re-blessed for migrations 0036-0039 (the previous
snapshot stopped at 0035 so CI would have gone red on first run).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -371,6 +371,7 @@ indexes on app_user_invitations:
|
||||
app_user_invitations_pkey: public.app_user_invitations USING btree (id)
|
||||
app_user_invitations_token_hash_key: public.app_user_invitations USING btree (token_hash)
|
||||
idx_app_user_invitations_app_pending: public.app_user_invitations USING btree (app_id) WHERE (accepted_at IS NULL)
|
||||
idx_app_user_invitations_unique_pending: public.app_user_invitations USING btree (app_id, lower(email)) WHERE (accepted_at IS NULL)
|
||||
|
||||
indexes on app_user_password_resets:
|
||||
app_user_password_resets_pkey: public.app_user_password_resets USING btree (token_hash)
|
||||
@@ -396,7 +397,6 @@ indexes on apps:
|
||||
|
||||
indexes on cron_trigger_details:
|
||||
cron_trigger_details_pkey: public.cron_trigger_details USING btree (trigger_id)
|
||||
idx_cron_triggers_due: public.cron_trigger_details USING btree (last_fired_at)
|
||||
|
||||
indexes on dead_letter_trigger_details:
|
||||
dead_letter_trigger_details_pkey: public.dead_letter_trigger_details USING btree (trigger_id)
|
||||
@@ -482,6 +482,7 @@ indexes on topics:
|
||||
indexes on triggers:
|
||||
idx_triggers_app_kind_enabled: public.triggers USING btree (app_id, kind) WHERE (enabled = true)
|
||||
idx_triggers_app_pubsub_enabled: public.triggers USING btree (app_id, kind) WHERE ((enabled = true) AND (kind = 'pubsub'::text))
|
||||
idx_triggers_kind_enabled: public.triggers USING btree (kind) WHERE (enabled = true)
|
||||
triggers_pkey: public.triggers USING btree (id)
|
||||
|
||||
## constraints
|
||||
@@ -518,6 +519,7 @@ constraints on app_members:
|
||||
[PRIMARY KEY] app_members_pkey: PRIMARY KEY (app_id, user_id)
|
||||
|
||||
constraints on app_secrets:
|
||||
[CHECK] app_secrets_realtime_signing_key_pair: CHECK (((realtime_signing_key_encrypted IS NULL) = (realtime_signing_key_nonce IS NULL)))
|
||||
[FOREIGN KEY] app_secrets_app_id_fkey: FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE
|
||||
[PRIMARY KEY] app_secrets_pkey: PRIMARY KEY (app_id)
|
||||
|
||||
@@ -580,6 +582,7 @@ constraints on docs_trigger_details:
|
||||
[PRIMARY KEY] docs_trigger_details_pkey: PRIMARY KEY (trigger_id)
|
||||
|
||||
constraints on email_trigger_details:
|
||||
[CHECK] email_trigger_details_inbound_secret_pair: CHECK (((inbound_secret_encrypted IS NULL) = (inbound_secret_nonce IS NULL)))
|
||||
[FOREIGN KEY] email_trigger_details_trigger_id_fkey: FOREIGN KEY (trigger_id) REFERENCES triggers(id) ON DELETE CASCADE
|
||||
[PRIMARY KEY] email_trigger_details_pkey: PRIMARY KEY (trigger_id)
|
||||
|
||||
@@ -698,3 +701,7 @@ constraints on triggers:
|
||||
0033: topics auth mode session
|
||||
0034: queue messages
|
||||
0035: queue triggers
|
||||
0036: index triggers kind enabled
|
||||
0037: drop idx cron triggers due
|
||||
0038: email realtime secret check
|
||||
0039: app user invitations unique pending
|
||||
|
||||
Reference in New Issue
Block a user