Skip to content

2.12 - #1417

Merged
vinothrallapalli-eGov merged 22 commits into
maven-jdk21from
2.12
Aug 25, 2026
Merged

2.12#1417
vinothrallapalli-eGov merged 22 commits into
maven-jdk21from
2.12

Conversation

@vinothrallapalli-eGov

Copy link
Copy Markdown
Collaborator

No description provided.

Chakshu and others added 22 commits July 19, 2026 16:43
…ndpoint

Brand-new state-root tenants (e.g. created by MCP tenant_bootstrap) can
not be encrypted for until a key exists in eg_enc_symmetric_keys. The
existing key-generation paths don't cover this case:

- init() and rotateAll() discover tenants via MDMS search under
  STATE_LEVEL_TENANT_ID — a brand-new root is not under any existing
  root's tenant.tenants list, so it's missed.
- checkIfTenantExists() falls through to the same MDMS-driven generator,
  so the first encrypt for a new root throws "Tenant Id not found" 500.

This endpoint lets a provisioning caller (tenant_bootstrap, ansible
deploy, manual ops) explicitly provision a key for a tenantId, the same
way init() does, but for ONE tenant on demand.

Behavior:
  - POST /crypto/v1/_generatekey { "tenantId": "..." }
  - Returns 200 with { tenantId, created, keyId }
  - Idempotent: if tenant has an active key, returns existing keyId
    with created=false (no rotation, no duplicate insert)
  - Synchronized to prevent race on first-write
  - Refreshes KeyStore + KeyIdGenerator caches after generation

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit f5d272b)
…s and DTO projection

The localization service goes OOM when loaded with production-scale data
(~49K messages) because computeMessageList() loads ALL messages for a
locale+tenant regardless of the requested module, duplicating data 4-6x
in memory during tenant hierarchy merging.

Two optimizations:

1. Module-scoped query path (Option B): When a module parameter is
   present in the search request, only load messages for those modules
   from the database instead of loading all ~49K and filtering in-memory.
   Uses separate Redis cache keys that include the module name(s).
   This reduces loaded records from ~49K to ~5-8K for typical requests.

2. Native query DTO projection (Option C): Replace JPA entity queries
   with native SQL queries returning a lightweight 5-field interface
   projection (code, locale, module, message, tenantId). This bypasses
   the JPA persistence context, avoiding the overhead of loading full
   10-field entities with audit fields into Hibernate's first-level cache.

Together these reduce peak memory per request from ~88MB to ~8MB for
module-scoped requests, making the service stable at 256MB heap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 7f5a733)
…tionship search

Two bugs in boundary-relationships/_search caused incorrect results:

1. Controller used @ModelAttribute for search criteria, which reads from
   query params/form data — not the JSON POST body. This meant tenantId,
   hierarchyType, and all other filter fields were always null, so the
   query returned ALL boundary relationships across ALL tenants globally.
   Fix: introduce BoundaryRelationshipSearchRequest wrapper and use
   @RequestBody to properly deserialize the JSON body.

2. When isSearchForRootNode=true, the query builder appended
   "parent IS NULL" which returned only root-level nodes. The enricher
   (BoundaryRelationshipEnricher) needs ALL nodes for the tenant+hierarchy
   to build the full tree via getSeedBoundaryList(). With only root nodes,
   the response always had empty children arrays.
   Fix: remove the parent IS NULL clause so the enricher receives the
   complete node set for tree assembly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit cfe1923)
EncryptionDecryptionUtil and LocalizationUtil use a hardcoded
STATE_LEVEL_TENANT_ID property, preventing multi-state deployments
from using the correct encryption key or localization endpoint for
non-default state roots.

Add new overloaded methods that accept a tenantId parameter and use
MultiStateInstanceUtil.getStateLevelTenant() to dynamically derive
the state root. Original methods preserved for backward compatibility.

Related to PR #1043 (egov-workflow-v2 dynamic state tenant).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit c6f5438)
The `updateWithoutOtpValidation` and `partialUpdate` methods call
`requestInfo.getUserInfo().getId()` without null-checking `getUserInfo()`.
When the auth token doesn't resolve to a userInfo (e.g. cross-tenant
admin operations), this throws NullPointerException.

Additionally, `userRepository.update()` takes primitive `long` for userId,
so passing null Long causes unboxing NPE. Use 0L as the fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit ccc0e13)
…rload

The previous commit on this branch added an encryptObject overload that
accepts a tenantId and resolves the state root via MultiStateInstanceUtil,
but no call sites were updated to use it. With the legacy 3-arg method
still in place, every encrypt path silently fell back to the hardcoded
STATE_LEVEL_TENANT_ID env var. So flipping STATE_LEVEL_TENANT_ID between
deploys still produced key-version drift on encrypted columns and broke
logins (the freshly-generated ciphertext prefix mismatches the prefix on
existing DB rows; UserNotFoundException -> "Invalid login credentials").

Migrate the 6 UserService.java call sites:
  - encryptUserSearchCriteria (L154, L205): pass criteria.getTenantId()
  - createUser (L232):                      pass user.getTenantId()
  - updateWithoutOtpValidation (L367):      pass user.getTenantId()
  - partialUpdate (L418):                   pass user.getTenantId()
  - updatePassword (L492):                  pass user.getTenantId()

The new overload null-safe-falls-back to stateLevelTenantId, so paths
that genuinely lack a request tenant retain today behavior. For single-
state deployments (request tenant matches STATE_LEVEL_TENANT_ID),
getStateLevelTenant strips the city suffix to the state root - output
is identical to today's hardcoded path. No DB compatibility impact.

Validated on bomet (ke state): /user/oauth/token, /user/citizen/_create,
/user/profile/_update, /user/_search all 200 against pre-existing rows.

Refs egovernments/Citizen-Complaint-Resolution-System#622

(cherry picked from commit 884c5e6)
Fixes eGovStack/core-services#1674.

Root cause: the ProcessInstance API contract uses the historically
misspelled JSON key "assignes" (@JsonProperty). Clients that send the
correctly spelled "assignees" key (e.g. integration suites and UI
paths) have that field silently dropped during deserialization,
because Spring Boot's default ObjectMapper runs with
FAIL_ON_UNKNOWN_PROPERTIES disabled. The transition then proceeds with
assignes=null: WorkflowValidator has no assignee-presence check,
EnrichmentService.enrichUsers only enriches non-empty lists, and the
persister's eg_wf_assignee_v2 mapping (jsonPath
ProcessInstances.*.assignes.*) extracts zero rows and skips the INSERT
entirely while the eg_wf_processinstance_v2 INSERT in the same batch
succeeds. Result: the process instance exists but carries no assignee
rows, which surfaces as "assignees lost on ASSIGN" since /_search
returns the newest (assignee-less) instance per businessId.

Fix: add @JsonAlias("assignees") on the assignes field so
deserialization accepts both spellings. Serialization still emits
"assignes", so the persister jsonPaths, /process/_search responses and
all existing consumers are unchanged.

Tests: ProcessInstanceTest proves both spellings deserialize into
getAssignes() (including via the full ProcessInstanceRequest
transition payload) and that serialization keeps emitting "assignes".
The two alias tests fail without the one-line fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 43f925c)
Add build/maven-jdk21/ as a new Dockerfile variant alongside the
existing build/maven/ (JDK 17). Services on Spring Boot 3.x are
switched to the new Dockerfile; legacy services (Spring Boot 1.5/2.x)
remain on JDK 17 unchanged.

Why:
- JDK 17 has a cgroup v2 CPU detection bug (JDK-8281181) on
  kernel 6.8+ — the JVM sees all host CPUs instead of the
  container's CPU limit, spawning 50-60 threads instead of ~15.
- JDK 21 fixes this and auto-sizes heap/GC/threads from cgroup
  limits, eliminating the need for manual JVM tuning flags.
- JDK 21 runs Java 17 bytecode natively (no recompilation needed).

New files:
- build/maven-jdk21/Dockerfile: eclipse-temurin:21-jre-alpine runtime
  with CDS (Class Data Sharing) pre-dump for faster startup
- build/maven-jdk21/start.sh: no default -Xms/-Xmx, CDS loading

Updated: build-config.yml
- 26 Spring Boot 3.x services → build/maven-jdk21/Dockerfile
- 32 legacy/other services → unchanged (build/maven/Dockerfile)
- 1 service (egov-user) → unchanged (build/maven-java8/Dockerfile)

Validated on docker-compose local-setup (jar-swap approach):
- 12 services rebased, all healthy
- k6 load test: 100% success (104 transactions, 0 failures)
- Memory: ~24% RSS reduction, ~42% thread count reduction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 5c861ca)
egov-user is on Spring Boot 1.5 / JDK 8 and cannot be easily migrated
to Spring Boot 3.2. This new build variant compiles with JDK 8 but runs
on JDK 21, getting cgroup v2 fixes and memory improvements without a
framework migration.

The hybrid approach:
- Build stage: same JDK 8 Maven image (amazoncorretto-8)
- Patch stage: injects JAXB API + runtime jars (removed from JDK 11+)
- Runtime stage: eclipse-temurin:21-jre-alpine with CDS + --add-opens

Measured results (8 vCPU / 16 GB VM):
- Memory at idle: 461 MiB → 184 MiB (60% reduction)
- Memory under 300 VU load: OOM-killed → 286 MiB (56% of limit)
- Threads: 50+ → 34

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit affb45a)
Merges PR #1240 - adds JDK 21 base images with CDS pre-dumps for 26
Spring Boot 3.x services and a JDK 8→21 hybrid image for egov-user,
fixing cgroup v2 CPU detection bug (JDK-8281181) on kernel 6.8+.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 9f83afb)
…ening

egov-workflow-v2: BusinessServiceRepositoryTest was missing a @MockBean
for MultiStateInstanceUtil, causing Spring to fail context initialization
when trying to field-inject centralInstanceUtil into BusinessServiceRepository.

egov-url-shortening: UrlSorteningApplicationTest hard-coded Jackson's
internal deserialization feature bitfield (237020304) which changed to
473998480 in the jackson-databind version pulled by Spring Boot 3.4.5.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 983e8b2)
[2.12] egov-enc-service: idempotent POST /crypto/v1/_generatekey
[2.12] egov-localization: reduce memory (module-scoped queries + DTO projection)
[2.12] boundary-service: fix tenant filtering + tree assembly in relationship search
[2.12] egov-workflow-v2: persist assignees on self-loop ASSIGN transitions
…date-npe

[2.12] egov-user: prevent NPE in _updatenovalidate / profile _update
…-enc

[2.12] egov-user: tenant-aware encryption + localization overloads
[2.12][strategic] JDK 21 runtime migration (shared build layer)
Merge pull request #1410 from egovernments/master
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d8c63c03-fb39-4f4a-b10f-051864deccb7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@vinothrallapalli-eGov
vinothrallapalli-eGov merged commit 78ef26f into maven-jdk21 Aug 25, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants