Upgrade LangChain4j to 1.15.1-TB1 and migrate GitHub Models to the
official OpenAI integration (OpenAiOfficialChatModel), enabling JSON
Schema (strict) structured output for GitHub Models and exposing JSON
Schema as a response format for Anthropic and Amazon Bedrock.
- Rename model capability flags to supportsSchemalessJsonOutput() and
supportsJsonSchemaOutput(), declared explicitly per provider
- Push response-format capability checks into TbResponseFormat and
simplify response-format handling in TbAiNode
- Remove obsolete manual JSON escaping for GitHub Models, which now
double-escaped requests under the official OpenAI SDK
- Drop the now-obsolete opennlp-tools version pin (the upgraded
LangChain4j fork ships opennlp-tools >= 2.5.9)
- Update the AI rule node UI to offer response formats per provider,
refresh available model lists, and migrate toggle options to @if
- Expand configurer tests to verify per-provider model configuration
- Provide a scoped Angular ErrorHandler on the dynamic component's
injector in HtmlContainerWidgetComponent so template-runtime
exceptions raised inside user-authored Angular templates flow
through handleWidgetException instead of crashing the global
Angular ErrorHandler.
- Add `ctx.invokeAction($event, actionName, additionalParams?)` to
WidgetActionsApi / WidgetComponent and a `WidgetDestroyCallback` +
ctx.registerDestroyCallback() API on WidgetContext (callbacks run
in registration order on destroy, errors per-callback are caught
so one bad cleanup doesn't break the rest).
- Surface widget actions on the HTML Container basic config: render
tb-widget-actions-panel with the new strokedPanel input below
the html-container settings, and register a default "JavaScript"
multi-action source on the html_container widget JSON.
- Expand the widget-completion docs for `registerDestroyCallback`
(when it fires, what to use it for, lifecycle semantics, exact
callback signature `() => void`) and for `invokeAction`'s
`additionalParams` arg (forwarded to the configured JS action
handler, common payload examples).
Netty 4.1.133.Final introduced a regression in MqttDecoder while fixing
CVE-2026-44248: when multiple MQTT packets are present in the same
cumulation buffer, the per-message size check used the total buffer size
instead of the current packet's declared remaining length. Valid in-limit
packets get rejected with TooLongFrameException("message length exceeds
65536: <small number>"). Fixed upstream by netty/netty#16787 and ported
to 4.1 as netty/netty@30f8f284db, released in 4.1.134.Final.
Exposes the dashboard entities-limit check as a reusable public method
so callers outside the validator can enforce the same limit without
duplicating the apiLimitService logic.
Two test layers covering the controller surface that the JVN PoC uses:
Java unit (Spring MockMvc):
RuleChainControllerTest#testScriptForbiddenForCustomer asserts a
customer JWT against POST /api/ruleChain/testScript returns 403,
locking in the existing @PreAuthorize('TENANT_ADMIN') guard.
Black-box (live docker-compose):
JsExecutorSandboxIsolationTest#testRuleChainScriptCannotReachHostProcess
posts the JVN exploit payload as a tenant admin and asserts the
response carries error='process is not defined'. End-to-end through
tb-node -> Kafka -> tb-js-executor with use_sandbox=true.
Registered the new org.thingsboard.server.msa.security package in
the connectivity TestNG suite so the black-box runner picks it up.
Added a thin TestRestClient.testRuleChainScript() helper.
Four test cases under describe('js-executor'):
- sandbox isolates args from host realm (JVN#16937365 — regression guard)
- sandbox passes string args through unchanged
- non-sandbox path does not isolate from host realm (documented contract)
- non-sandbox path passes string args through unchanged
Tests use Node's built-in node:test + node:assert (zero new devDependencies;
ts-node was already there). Two npm scripts:
test — spec output for local dev
test:ci — spec to stdout + Node's built-in junit reporter to
target/surefire-reports/TEST-js-executor.xml
Wired 'yarn test:ci' into the Maven 'test' phase via frontend-maven-plugin,
so 'mvn test -pl=msa/js-executor' produces JUnit XML that TeamCity's
Maven runner auto-discovers under the 'js-executor' suite name.
TEST_FAST.md picks up the same step.
tsconfig excludes test/ from the production pkg bundle.
The args array passed into the sandbox carried the host realm prototype
chain, so a script could reach the host Function constructor via
args.constructor.constructor and execute arbitrary code in the host
process (read files, run shell commands, dump env vars).
Construct args inside the sandbox context using vm.runInContext('[]'),
then populate with string primitives. The resulting array's prototype
chain belongs to the sandbox realm, so constructor traversal cannot
escape. Strings are primitives and safe to cross the realm boundary.
Affects use_sandbox=true path only. The use_sandbox=false path
(invokeFunction) is intentionally left as-is and explicitly marked as
dangerous-by-design — it compiles and runs user-supplied scripts in
the host realm via vm.compileFunction (parsingContext only isolates
parsing, not execution). It remains as a documented performance
trade-off for trusted, non-public clusters; a startup WARN is logged
when script.use_sandbox=false, and an operator-facing yaml comment
sits next to the setting in config/default.yml.
Reported by Hiroki Imai, LAC Co., Ltd.