strconv.Atoi accepts "0" and negative values, and the delivery worker treats a
non-positive WebhookID as a fan out to every subscriber of the event. So a
malformed target value sent the conversation payload to unintended webhooks.
Reject it in the action and drop it in TriggerWebhook as well.
An automation rule that listens on an event and then writes the same field
re-fires its own event, so the rule matches again and loops forever. Status
already returned early on a no-op write, but priority and user assignment did
not, so those two could spin a worker doing a DB write per lap. Add the same
unchanged-value guard to both.
Suppression while the engine applies actions was a plain flag in a sync.Map,
so with more than one worker on the same conversation the first one to finish
deleted the key while the other was still applying actions. Make it a refcount
so each worker releases only its own claim.
The starts with operator is only implemented by the automation evaluator, not
the SQL filter builder, so give automation text fields their own operator list
instead of adding it to the shared one.
Also switch the notify action to its own recipients field type, fix the snooze
duration hint since the backend only takes Go duration units, trim and
lowercase notify recipient entries, and treat a missing previous value as no
match rather than an empty string.
handleAiPromptSelected now captures the conversation uuid and bails if it changed while the completion was in flight, and uses convertTextToHtml with a null guard, matching handleGenerateReply. This stops a generated prompt from landing in the wrong conversation's draft or crashing on an empty response.
Add ssrf.NewTransport that clones http.DefaultTransport (keeping proxy and connection-pool defaults) and applies the dial guard, then use it for the OIDC, AI, OpenAI, and webhook clients. The bare transports were dropping HTTP_PROXY handling and pool defaults.
Move the webhook SSRF guard into a shared internal/ssrf package and wire it
into every place the server fetches an admin-set URL: webhooks, OIDC discovery,
the AI provider base URL, and custom AI tool calls. Add a global [ssrf] config
block, off by default with an allowed_cidrs bypass, so single-tenant self-hosters
keep reaching internal hosts while multi-tenant or hosted deploys can turn it on.
The old [webhook] allowed_hosts key is still read for backward compat and folds
into the guard.
- reload app settings when notification settings are changed to trigger admin banner prompting user to restart app
- remove unncessary dummy password check before retaining passwords as an empty password check is enough.
- Update all SQL queries to add missing columns
- Update the create conversation API to allow setting the initiator of a conversation. For example, we might want to use this API to create a conversation on behalf of a customer, with the first message coming from the customer instead of the agent. This param allows this.
- Minor refactors and clean up
- Tidy go.mod
- Rename structs to reflect purpose
- Create focus structs for scanning JSON payloads for clarity.