Commit Graph
2 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5 a372d5aa0f fix(mattermost): check the Agents service against the contract, not for identity
The convergence check compared the stored service element to the declared one with
jsonb equality, and the deploy failed on "The Agents plugin still stores a service or
bot that differs from the deployed gateway contract".

The sequence is write via SQL, cycle the plugin, read back. Cycling is exactly when
the plugin rewrites that structure, and it owns it. Any field it adds of its own makes
byte-identical equality impossible, permanently, while the contract itself holds.

Containment says what the task means. Its own name asks whether the stored config
still matches the gateway contract, not whether it is the same object: the deployed
keys must be present with the deployed values, and what the plugin keeps besides is
its business.

Only that one condition changes. The bot check, the legacy-bot check, the FROM clause
and the per-active-row semantics stay as they were -- a first attempt restructured the
whole query into CTEs, which would have aggregated across active rows instead of
evaluating each, and reported converged as soon as any one of them matched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 16:03:53 +02:00
kevinveenbirkenbachandClaude Opus 5 268c3082cb refactor(mattermost): take the Jinja out of the AI gateway SQL
The four SQL bodies behind the Agents integration were Jinja templates read
through lookup('template'), which meant the raw query: parameter and a
"# nocheck: database-query-raw" on all five call sites in
tasks/utils/ai_gateway.yml.

They now use the mechanism the database_query module already offers: static
.sql files under files/sql/, reached by query_file:, with the values supplied
as named_args and %(name)s placeholders. All five suppressions are gone.

Same move as 4e9d4b53db made for odoo, for the reason that commit gives: an
interpolation straight into SQL carries an injection surface that a bound
parameter does not. Postgres dollar-quoting was doing that job here; the
module's own escaping does it now, doubling single quotes per the _ENGINES
postgres entry.

The | to_json filters did not disappear, they moved to the call site.
MATTERMOST_LITELLM_SERVICE and MATTERMOST_LITELLM_BOT are dicts, and the
module raises TypeError on those, so pre-serialising is what it asks for.

set_ai/ became update/ai/ to match the select/ and update/ verbs the role's
existing files/sql already uses.

The api key inside MATTERMOST_LITELLM_SERVICE is now a named_args value, which
the module adds to no_log_values; as part of the query string it was not.

Verified statically only: the database-query-raw lint passes, the task file
still parses to the same 11 tasks in the same order, every placeholder has a
matching named_args entry, and no reference to the old paths survives. Nothing
ran against a database, and the adversarial review of this change had not
finished when it was committed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 13:46:05 +02:00