Compare commits

...

1 Commits

Author SHA1 Message Date
infra-sre d1651fd101 fix(channels): log json.Unmarshal errors in List and Webhook handlers
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 31s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 24s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 41s
CI / Detect changes (pull_request) Successful in 1m20s
Harness Replays / detect-changes (pull_request) Successful in 26s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 33s
qa-review / approved (pull_request) Successful in 28s
security-review / approved (pull_request) Successful in 27s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m38s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m42s
gate-check-v3 / gate-check (pull_request) Successful in 1m4s
sop-checklist / all-items-acked (pull_request) Successful in 37s
sop-tier-check / tier-check (pull_request) Successful in 36s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 1m34s
audit-force-merge / audit (pull_request) Has been skipped
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m57s
Harness Replays / Harness Replays (pull_request) Successful in 14s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 20s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 27s
CI / Python Lint & Test (pull_request) Successful in 8m5s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 6m14s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6m48s
CI / Canvas (Next.js) (pull_request) Successful in 17m27s
CI / Canvas Deploy Reminder (pull_request) Successful in 8s
CI / Platform (Go) (pull_request) Successful in 18m40s
CI / all-required (pull_request) Successful in 18m33s
Fixes issue #1108 — silent data loss when DB JSONB contains corrupt data.

List handler: if json.Unmarshal fails on channel config or
allowed_users, log the error and fall back to zero values instead
of returning null to the client.

Webhook handler: same fix. Falls back to empty map/slice so the
DecryptSensitiveFields call still runs (logging any decryption
errors) rather than silently skipping webhook processing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 03:47:00 +00:00
+16 -4
View File
@@ -67,7 +67,10 @@ func (h *ChannelHandler) List(c *gin.Context) {
}
var config map[string]interface{}
json.Unmarshal(configJSON, &config)
if err := json.Unmarshal(configJSON, &config); err != nil {
log.Printf("Channels: list: unmarshal config for channel %s: %v", id, err)
config = map[string]interface{}{}
}
// #319: decrypt sensitive fields first so the mask operates on
// plaintext (first-4 / last-4 of the real token, not the ciphertext
// prefix). Decrypt errors are logged but non-fatal — List must keep
@@ -86,7 +89,10 @@ func (h *ChannelHandler) List(c *gin.Context) {
}
var allowed []string
json.Unmarshal(allowedJSON, &allowed)
if err := json.Unmarshal(allowedJSON, &allowed); err != nil {
log.Printf("Channels: list: unmarshal allowed_users for channel %s: %v", id, err)
allowed = []string{}
}
entry := map[string]interface{}{
"id": id,
@@ -496,8 +502,14 @@ func (h *ChannelHandler) Webhook(c *gin.Context) {
if err := rows.Scan(&row.ID, &row.WorkspaceID, &row.ChannelType, &configJSON, &row.Enabled, &allowedJSON); err != nil {
continue
}
json.Unmarshal(configJSON, &row.Config)
json.Unmarshal(allowedJSON, &row.AllowedUsers)
if err := json.Unmarshal(configJSON, &row.Config); err != nil {
log.Printf("Channels: webhook: unmarshal config for row %s: %v", row.ID, err)
row.Config = map[string]interface{}{}
}
if err := json.Unmarshal(allowedJSON, &row.AllowedUsers); err != nil {
log.Printf("Channels: webhook: unmarshal allowed_users for row %s: %v", row.ID, err)
row.AllowedUsers = nil
}
if err := channels.DecryptSensitiveFields(row.Config); err != nil {
log.Printf("Channels: decrypt webhook row %s: %v", row.ID, err)
continue