Skip to content

Conversation

@GOKULRAJ136
Copy link
Contributor

@GOKULRAJ136 GOKULRAJ136 commented Nov 14, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Improved public key certificate parsing and validation in the sync service
    • Enhanced sync response to include certificate issuance and expiry date information
    • Strengthened error handling for data synchronization failures

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Walkthrough

Refactors public key response parsing in SyncConfigDetailsServiceImpl from TypeReference-based deserialization to manual JsonNode parsing. Extracts certificate, issuedAt, and expiryAt fields, constructs X.509 certificate, computes PublicKey, converts to PEM format with 64-character line wrapping, and returns enhanced PublicKeyResponse with additional metadata.

Changes

Cohort / File(s) Change Summary
Public Key Response Parsing & Cryptographic Handling
admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncConfigDetailsServiceImpl.java
Replaces TypeReference-based JSON deserialization with manual JsonNode tree parsing. Adds extraction of certificate data and timestamp fields (issuedAt, expiryAt). Implements X.509 certificate building and PublicKey computation. Introduces convertToPEM helper method for PEM format conversion with BEGIN/END PUBLIC KEY delimiters and 64-character line wrapping. Adds constants BEGIN_KEY and END_KEY. Updates imports (JsonNode, ByteArrayInputStream, PublicKey, CertificateFactory, X509Certificate, OffsetDateTime). Uses DateUtils2 for UTC timestamps. Enhances error handling with SyncDataServiceException.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Service
    participant JsonParser as JSON Parser
    participant CertFactory as Certificate Factory
    participant PEMConverter as PEM Converter
    
    rect rgb(200, 220, 255)
    Note over Service: Old Flow (TypeReference)
    Client->>Service: getPublicKey()
    Service->>JsonParser: deserialize(response, TypeReference)
    JsonParser-->>Service: PublicKeyResponse
    Service-->>Client: return PublicKeyResponse
    end
    
    rect rgb(220, 240, 200)
    Note over Service: New Flow (Manual Parsing)
    Client->>Service: getPublicKey()
    Service->>JsonParser: parse as JsonNode
    JsonParser-->>Service: JsonNode tree
    Service->>Service: extract certificate, issuedAt, expiryAt
    Service->>CertFactory: buildX509Certificate()
    CertFactory-->>Service: X509Certificate
    Service->>Service: computePublicKey()
    Service->>PEMConverter: convertToPEM(publicKey)
    PEMConverter-->>Service: PEM formatted string (64-char wrapped)
    Service->>Service: buildPublicKeyResponse(enriched fields)
    Service-->>Client: return enhanced PublicKeyResponse
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • X.509 certificate construction and PublicKey computation correctness
  • PEM format conversion logic, specifically 64-character line wrapping implementation
  • Null safety checks for nested JsonNode field extraction (certificate, issuedAt, expiryAt)
  • OffsetDateTime to LocalDateTime conversion accuracy and timezone handling
  • Exception handling and mapping to SyncDataServiceException with SYNC_IO_EXCEPTION

Poem

🐰 From JSON trees to keys so grand,
Certificate parsing, oh so planned!
PEM lines wrapped at sixty-four,
Cryptographic magic, nothing more! 🔐✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extracting and refactoring public key data handling in the getPublicKey API method, which aligns with the core modifications in SyncConfigDetailsServiceImpl.java.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example:

"Create a concise high-level summary as a bullet-point list. Then include a Markdown table showing lines added and removed by each contributing author."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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 and usage tips.

@ase-101
Copy link
Contributor

ase-101 commented Nov 17, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e564f8 and 8579d20.

📒 Files selected for processing (1)
  • admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncConfigDetailsServiceImpl.java (6 hunks)
🔇 Additional comments (1)
admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncConfigDetailsServiceImpl.java (1)

68-72: PEM formatting helper and constants look correct

The BEGIN_KEY/END_KEY constants combined with convertToPEM(PublicKey) produce a standard PUBLIC KEY PEM with 64‑character line wrapping; the implementation is straightforward and appropriate.

Also applies to: 373-383

Comment on lines 245 to +270
try {
publicKeyResponseMapped = objectMapper.readValue(publicKeyResponseEntity.getBody(),
new TypeReference<ResponseWrapper<PublicKeyResponse<String>>>() {
});

publicKeyResponseMapped.getResponse().setProfile(environment.getActiveProfiles()[0]);
LOGGER.debug("Public key fetched successfully for applicationId: {}", applicationId);
return publicKeyResponseMapped.getResponse();
} catch (IOException | NullPointerException e) {
JsonNode root = objectMapper.readTree(publicKeyResponseEntity.getBody());
String certificatePem = root.path("response").path("certificate").asText();
String issuedAt = root.path("response").path("issuedAt").asText();
String expiryAt = root.path("response").path("expiryAt").asText();

CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream certStream = new ByteArrayInputStream(certificatePem.getBytes(StandardCharsets.UTF_8));
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(certStream);
PublicKey publicKey = certificate.getPublicKey();

String publicKeyPEM = convertToPEM(publicKey);

OffsetDateTime issued = OffsetDateTime.parse(issuedAt);
OffsetDateTime expiry = OffsetDateTime.parse(expiryAt);

PublicKeyResponse<String> response = new PublicKeyResponse<>();
response.setPublicKey(publicKeyPEM);
response.setLastSyncTime(DateUtils2.getUTCCurrentDateTimeString());
response.setIssuedAt(issued.toLocalDateTime());
response.setExpiryAt(expiry.toLocalDateTime());
response.setProfile(environment.getActiveProfiles()[0]);

return response;

} catch (Exception e) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Handle missing response fields and active profiles more defensively

The new parsing flow is directionally good, but a few robustness points are worth tightening:

  • environment.getActiveProfiles()[0] (Line 266) will throw ArrayIndexOutOfBoundsException if no active profiles are set (which is valid in Spring). Consider a safe fallback, e.g. checking length and defaulting to "default" or a configured value.
  • certificate, issuedAt, and expiryAt are taken via asText() (Lines 247–249), so missing/blank fields only surface later as generic parse errors (certificate factory or OffsetDateTime.parse). It would be clearer to explicitly validate these fields (null/empty/format) and throw a more specific exception (e.g. SyncInvalidArgumentException with details) before attempting parsing.
  • In the catch block (Lines 270–274) you log only e.getMessage(). Using LOGGER.error("Failed to parse public key response", e); would retain the stack trace and make production debugging easier.
  • Behavioural change: lastSyncTime and profile are now derived locally (DateUtils2.getUTCCurrentDateTimeString() and environment profile) instead of being taken from the upstream response. Please double‑check that this changed semantics is acceptable for existing consumers of getPublicKey.

Please verify these changes against existing registration‑client flows (especially ones relying on profile and lastSyncTime) and adjust the error handling as needed.


I need to verify the specific concerns in this review comment by examining the actual code. Let me gather detailed information from the repository.


---

🏁 Script executed:

```shell
#!/bin/bash
# Retrieve the full method implementation around lines 245-270
fd -e java "SyncConfigDetailsServiceImpl" --exec cat {} \; | head -400 | tail -160

Length of output: 7165


🏁 Script executed:

#!/bin/bash
# Search for getActiveProfiles usage in the codebase to understand safety patterns
rg -nC5 "getActiveProfiles" --type=java

Length of output: 5302


🏁 Script executed:

#!/bin/bash
# Look for the convertToPEM method and BEGIN_KEY/END_KEY constants
fd -e java "SyncConfigDetailsServiceImpl" --exec cat {} \; | grep -A 20 "convertToPEM\|BEGIN_KEY"

Length of output: 2077


🏁 Script executed:

#!/bin/bash
# Search for calls to getPublicKey to understand downstream consumers
rg -nP '\bgetPublicKey\s*\(' --type=java -C3

Length of output: 43012


Let me verify one more critical aspect—whether the behavioral change for profile and lastSyncTime represents a breaking change:


---

🏁 Script executed:

```shell
#!/bin/bash
# Check if profile was previously populated from response or if this is a new addition
rg -nC8 "setProfile|getProfile" --type=java admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/

Length of output: 2924


🏁 Script executed:

#!/bin/bash
# Inspect full getPublicKey method to see what was there before (context lines)
fd -e java "SyncConfigDetailsServiceImpl" --exec cat {} \; | grep -B50 "try {" | grep -A50 "getPublicKey"

Length of output: 6990


🏁 Script executed:

#!/bin/bash
# Check the test setup to confirm if profile was being set from response before
cat admin/kernel-syncdata-service/src/test/java/io/mosip/kernel/syncdata/test/service/SyncConfigDetailsServiceImplTest.java | grep -A 30 "public void getPublicKey"

Length of output: 4388


Add defensive null-check for getActiveProfiles() and improve error logging

Your implementation correctly extracts certificate details and derives the public key, but two issues need attention:

  1. Line 266: environment.getActiveProfiles()[0] lacks safety check. If no active profiles are set (valid in Spring), this throws ArrayIndexOutOfBoundsException. Other parts of the codebase use getActiveProfiles().length == 0 ? getDefaultProfiles() : getActiveProfiles() (see admin-service/AuditUtil.java:201). Apply the same pattern here or provide a fallback (e.g., "default").

  2. Line 271: Logging discards stack trace. Change LOGGER.error("Failed to parse public key response: {}", e.getMessage()) to LOGGER.error("Failed to parse public key response", e) to preserve the full stack trace for production debugging.

  3. lastSyncTime and profile derivation: These are now set locally instead of from the response. Note that SyncDataController line 136 overwrites lastSyncTime anyway, so the service-level value is not used; however, verify that clients have no other dependencies on the profile field being immutable or response-sourced.

🤖 Prompt for AI Agents
In
admin/kernel-syncdata-service/src/main/java/io/mosip/kernel/syncdata/service/impl/SyncConfigDetailsServiceImpl.java
around lines 245 to 270, add a defensive check for
environment.getActiveProfiles() before indexing [0] (use the pattern used in
admin-service/AuditUtil.java:201: use getActiveProfiles().length == 0 ?
getDefaultProfiles() : getActiveProfiles() or fall back to "default") and assign
profile from that safe value; change the error log inside the catch to
LOGGER.error("Failed to parse public key response", e) so the full stacktrace is
logged; also confirm whether lastSyncTime/profile should remain set here or left
for SyncDataController (update or document accordingly).

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