Creates missing system images from application/src/main/data/resources/images
during LTS patch startup, mirroring the upgrade-path loadSystemResources logic.
Existing system images in the DB are left untouched.
Several testSaveProtoDeviceProfileWithInvalidRpcRequestSchema* tests
intermittently fail with:
org.thingsboard.server.dao.exception.TenantNotFoundException: Tenant
with id <fresh-tenant-uuid> not found
when the tenant created in @Before has not yet been populated in the
tenant profile cache by the time the request hits the partition-lookup
path (DefaultTenantRoutingInfoService -> TbTenantProfileCache ->
TenantService#findTenantById). The underlying request is idempotent
(the schema is invalid so it is rejected with 400 regardless of
retries), so wrap the doPost + status assertion in Awaitility with
Mockito.reset inside the retry block: only the last attempt's
invocations are visible to the subsequent verify* assertions.
Applies to all testSaveDeviceProfileWithInvalidRpcRequestProtoSchema
callers, including the currently-muted
testSaveProtoDeviceProfileWithInvalidRpcRequestSchemaRequestIdDateType.
The test asserts exactly 2 UserCredentialsUpdateMsg after creating a new
tenant-admin user, but the user activation flow can emit either 2 or 3
depending on timing:
- activateUserCredentials publishes CREDENTIALS_UPDATED (msg #1)
- setUserCredentialsEnabled publishes CREDENTIALS_UPDATED (msg #2)
- the initial USER ADDED edge event is processed asynchronously in
UserEdgeProcessor and bundles an extra UserCredentialsUpdateMsg when
it finds userCredentials.isEnabled() == true (i.e. activation
already raced past the ADDED event)
When the race goes the second way we end up with 1 UserUpdateMsg plus
3 UserCredentialsUpdateMsg, which currently fails the hard-coded
assertEquals(2, ...) assertion.
Accept both 2 and 3 UserCredentialsUpdateMsg instead of asserting an
exact count, matching the reality of the asynchronous edge event
pipeline.
Await cached resource data to become available after save eviction
before asserting, and await null after deletion. Prevents Mockito
verifyNoMoreInteractions(resourceService) failure caused by racing
background cache-load invocations.
Backport of 99334ba7fe from master.
Relax version check to allow maintenance digit increases within the same
LTS family (e.g. 4.3.0 -> 4.3.1), not just patch digit increases.
Add LTS SQL schema patch execution from upgrade/lts/schema_update.sql,
running before views and widget updates so schema changes are in place
for dependent objects.
Replace the blocking semaphore guard with a non-blocking bounded FIFO queue
+ semaphore pattern:
- No semaphore/queue when maxParallelRequestsCount=0 (default): direct doHttpCall,
identical to the old behavior.
- When a concurrency limit is set, incoming messages are enqueued via non-blocking
offer(); a full queue triggers onFailure immediately.
- tryProcess() acquires one semaphore slot and dispatches the next valid queued task.
Stale tasks (batch deadline expired) are dropped and the slot reused in the same pass.
- doFinally hook releases the semaphore and calls tryProcess() exactly once after any
terminal signal (success, error, cancel), preventing double-release and permit leaks.
- publishOn(externalCallExecutor) moves callbacks off reactor-netty I/O threads.
System-level safety caps are wired through thingsboard.yml → ActorSystemContext →
TbContext → TbHttpClient, scoped to rule-engine services only via @TbRuleEngineComponent:
actors.rule.external.http_client.max_parallel_requests (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_MAX_PARALLEL_REQUESTS)
actors.rule.external.http_client.max_pending_requests (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_MAX_PENDING_REQUESTS)
actors.rule.external.http_client.pool_max_connections (ACTORS_RULE_EXTERNAL_HTTP_CLIENT_POOL_MAX_CONNECTIONS)
Backward compat: TB_RE_HTTP_CLIENT_POOL_MAX_CONNECTIONS still honored via yaml fallback.
Observability: five AtomicLong counters (dispatched, success, failure, droppedQueueFull,
droppedStale) with periodic WARN anomaly logging including semaphorePermits for leak detection.
No configuration changes or upgrade scripts required — docker image update is sufficient.
Rename RestApiCallNodeSettings to TbHttpClientSettings
The settings are about HTTP client transport concerns (connection pool,
concurrency, queue depth), not REST API Call node business logic.
The new name matches the consumer (TbHttpClient) and the YAML path
(actors.rule.external.http_client.*).
Remove <pkg.skip.bootjar>false</pkg.skip.bootjar> from all child
module <properties> blocks. The root POM already defaults it to false,
and child declarations block the skip-pkg profile override, so
-Dpkg.skip=true was never actually skipping spring-boot:repackage.
Also remove the unused surefire.version property (superseded by
maven-surefire-plugin.version).
Introduces four independent flags to skip individual packaging artifacts:
-Dpkg.skip.bootjar=true skip spring-boot repackage (*-boot.jar)
-Dpkg.skip.deb=true skip Gradle buildDeb + Maven attach-artifact
-Dpkg.skip.rpm=true skip Gradle buildRpm
-Dpkg.skip.zip=true skip maven-assembly-plugin Windows ZIP
Adds -Dpkg.skip=true as a single convenience flag that sets all four
at once. msa/pom.xml mirrors the skip-pkg profile to override its own
<pkg.deb.phase>package</pkg.deb.phase> property (child POM properties
have higher priority than parent profile properties in Maven).
msa/* docker modules used ${basedir}/../.. (non-canonical) for main.dir.
maven-enforcer-plugin 3.5.0's osIndependentNameMatch() compares
file.toURI() vs file.getCanonicalFile().toURI() — these differ when the
path contains '..', causing RequireFilesExist to report false-negative.
Fix: replace ${basedir}/../.. with ${maven.multiModuleProjectDirectory}.
Route DataAccessException and PersistenceException (including bare
ConstraintViolationException) to a unified handler that extracts the
constraint name and returns "Constraint violation: <name>" instead of
the raw PSQLException message. Other DB errors continue to return the
generic "Database error" response.
Adds DaoUtil.extractConstraintViolation helper and an integration test
that verifies no SQL details leak when an FK constraint is violated.
Keep both save-time validation (Oauth2ClientDataValidator) and runtime
re-validation as defense-in-depth: DNS records can change between config
save and OAuth2 login, creating a TOCTOU gap.
- Use kebab-case 'report-only' in web-ui configs to match thingsboard.yml
- Add log.warn for unrecognized X-Frame-Options values in customizer
- Replace @Configuration with @Component on HttpSecurityHeadersProperties
- Add comment explaining '!== false' vs truthiness pattern in server.ts
- Extract shared parseHostEntries() to deduplicate setAllowedHosts/setAdditionalBlockedHosts
- Add isHostnameAllowed() and propagate hostname allow-list check in resolver
- Move OAuth2 custom mapper URL SSRF validation to save-time (Oauth2ClientDataValidator)
- Remove runtime SSRF checks from CustomOAuth2ClientMapper and GithubOAuth2ClientMapper
(custom URL now validated at save; GitHub emailUrl is server config, not user input)
- Replace example.com with 8.8.8.8 in resolver test to avoid DNS dependency
Fix security issues from penetration test report:
- M2: Add configurable X-Frame-Options and CSP headers (disabled by default)
- L2: Add X-Content-Type-Options and Referrer-Policy headers (enabled by default)
- L3: Make CORS allowed-origin-patterns configurable via TB_CORS_* env vars
Root cause: ThingsboardSecurityConfiguration called .disable() on the entire
HeadersConfigurer, which removed ALL security headers including Cache-Control.
Fix uses defaultsDisabled() + selective header enablement via a new
HttpSecurityHeadersCustomizer component.
Both Spring Boot (tb-node) and Express.js (web-ui) share the same
SECURITY_HEADERS_* environment variables for consistent configuration
across monolith and microservice deployments.
Add SsrfSafeAddressResolverGroup that validates resolved IPs at Netty
connection time, eliminating the TOCTOU gap where DNS rebinding domains
resolve to safe IPs during validation but to private/metadata IPs at
connection time. Disable HTTP redirects in TbHttpClient to prevent
redirect-based SSRF bypass.
Add allow-list support (SSRF_ALLOWED_HOSTS) to SsrfProtectionValidator
so customers with IoT devices on private networks can whitelist specific
addresses or CIDR ranges while keeping SSRF protection enabled.
Add SSRF validation to MS Teams webhook, custom OAuth2 mapper, and
GitHub OAuth2 mapper endpoints. Log a warning when SSRF protection is
disabled.
Static fields RESOURCE_ID_3303_12_5700_TS_0/TS_1 in Lwm2mTestHelper are never
reset between test runs. On CI retries the await() at the start of the test
passes immediately (both timestamps are still > 0 from the previous run), so
the telemetry query uses stale timestamps and the second await() times out.
Fix: add @Before that resets both timestamps to 0 before each test method,
which was already correctly implied by the unused @Before import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Leshan's NotificationDataStore.toKey() can throw NPE when the server reference
is null during CoAP observe-relation cleanup on client shutdown (race condition).
This NPE was caught by the outer try-catch in startUpdating(), which prevented
leshanClient.start() from being called, leaving the simulated device stuck in
UPDATING state and causing the awaitility timeout in the OTA integration test.
Fix: wrap leshanClient.stop(false) in its own try-catch so that a Leshan
internal exception during stop does not abort the subsequent client restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Make setupSsl package-private so the test can call it directly, ensuring
tests exercise the real production code path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add RSA_4096 and EC_P256 alongside RSA_2048 and EC_P384
- Parameterize encrypted key tests (RSA-only, EC encrypted keys
are a pre-existing PemSslCredentials limitation)
- 14 test scenarios total
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add EC_P384 key type alongside RSA_2048
- Parameterize separateCertAndKeyFiles and combinedPemFile tests
- Write private keys in PKCS#8 format for EC compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>