Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/push-trigger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }}
OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }}
OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
Comment on lines 45 to 48
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

🏁 Script executed:

# Read the push-trigger.yml file to understand the context around lines 45-48
cat -n .github/workflows/push-trigger.yml | head -60

Repository: inji/digital-credential-plugins

Length of output: 2618


🏁 Script executed:

# Find and read the maven-publish-to-nexus.yml workflow
find .github -name "*maven*publish*" -o -name "*nexus*" | head -10

Repository: inji/digital-credential-plugins

Length of output: 57


🏁 Script executed:

# Search for OSSRH_CENTRAL_URL and OSSRH_SNAPSHOT_URL references across the repo
rg "OSSRH_(CENTRAL|SNAPSHOT)_URL" --type yaml

Repository: inji/digital-credential-plugins

Length of output: 223


🏁 Script executed:

# Search for secrets definitions and environment variable references
rg "OSSRH_URL" --type yaml -B 2 -A 2

Repository: inji/digital-credential-plugins

Length of output: 223


🏁 Script executed:

# List all workflow files
find .github/workflows -name "*.yml" -o -name "*.yaml" | head -20

Repository: inji/digital-credential-plugins

Length of output: 109


🏁 Script executed:

# Search for OSSRH references without type filter
rg "OSSRH" .github/workflows/ -A 1 -B 1

Repository: inji/digital-credential-plugins

Length of output: 6216


🏁 Script executed:

# Search for snapshot or central URL references
rg "snapshot|central|CENTRAL" .github/workflows/ -i

Repository: inji/digital-credential-plugins

Length of output: 499


🏁 Script executed:

# Check if maven-publish-to-nexus is in this repo or if it's external
ls -la .github/workflows/ | grep -E "nexus|publish"

Repository: inji/digital-credential-plugins

Length of output: 57


🏁 Script executed:

cat -n .github/workflows/push-trigger.yml

Repository: inji/digital-credential-plugins

Length of output: 11372


🏁 Script executed:

# Search for any references to snapshot, staging, or release repositories
rg "snapshot|staging|release|repository" .github/ -i

Repository: inji/digital-credential-plugins

Length of output: 1373


All 5 publish_to_nexus_ jobs use the wrong repository URL for snapshot publishing.*

These jobs explicitly exclude release, prerelease, and publish events and run on branches like develop, 1.*, and MOSIP*—making them snapshot/development builds. Using OSSRH_CENTRAL_URL (Central Publishing) for snapshots is incorrect; snapshot artifacts should target a snapshot repository endpoint instead. This will either fail or publish to the wrong repository at runtime.

Change OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }} to OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }} in all 5 publish jobs (lines 47, 88, 129, 170, 211). Also verify that OSSRH_SNAPSHOT_URL is defined in repository or organization secrets.

🤖 Prompt for AI Agents
In @.github/workflows/push-trigger.yml around lines 45 - 48, The five
publish_to_nexus_* jobs in push-trigger.yml are using the central repository URL
for snapshot builds; update each job's OSSRH_URL assignment from ${{
secrets.OSSRH_CENTRAL_URL }} to ${{ secrets.OSSRH_SNAPSHOT_URL }} (for the jobs
named publish_to_nexus_* referenced around the OSSRH_USER/OSSRH_SECRET block) so
snapshot/development branches publish to the snapshot endpoint, and confirm
OSSRH_SNAPSHOT_URL is present in the repo/org secrets.

GPG_SECRET: ${{ secrets.GPG_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }}
OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }}
OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
GPG_SECRET: ${{ secrets.GPG_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }}
OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }}
OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
GPG_SECRET: ${{ secrets.GPG_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Expand Down Expand Up @@ -167,7 +167,7 @@ jobs:
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }}
OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }}
OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
GPG_SECRET: ${{ secrets.GPG_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Expand Down Expand Up @@ -208,7 +208,7 @@ jobs:
secrets:
OSSRH_USER: ${{ secrets.OSSRH_USER }}
OSSRH_SECRET: ${{ secrets.OSSRH_SECRET }}
OSSRH_URL: ${{ secrets.OSSRH_SNAPSHOT_URL }}
OSSRH_URL: ${{ secrets.OSSRH_CENTRAL_URL }}
OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
GPG_SECRET: ${{ secrets.GPG_SECRET }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Expand Down
38 changes: 13 additions & 25 deletions mock-certify-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<groupId>io.mosip.certify</groupId>
<artifactId>mock-certify-plugin</artifactId>
<version>0.4.0-SNAPSHOT</version>
<version>0.5.0</version>
<packaging>jar</packaging>

<name>mock-certify-integration-impl</name>
Expand Down Expand Up @@ -48,7 +48,7 @@
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
<maven-gpg-plugin.version>1.5</maven-gpg-plugin.version>
<maven-source-plugin>2.2.1</maven-source-plugin>
<nexus-staging-maven-plugin>6.1.0</nexus-staging-maven-plugin>
<central.publishing.maven.plugin.version>0.7.0</central.publishing.maven.plugin.version>
<git-commit-id-plugin.version>3.0.1</git-commit-id-plugin.version>
<maven.jacoco.version>0.8.11</maven.jacoco.version>
<maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
Expand All @@ -65,7 +65,7 @@
<dependency>
<groupId>io.mosip.certify</groupId>
<artifactId>certify-core</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -170,9 +170,9 @@

<repositories>
<repository>
<id>ossrh</id>
<name>CentralRepository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<id>ossrh-central</id>
<name>MavenCentralRepository</name>
<url>https://central.sonatype.com/repository/maven-snapshots</url>
<layout>default</layout>
<snapshots>
<enabled>true</enabled>
Expand Down Expand Up @@ -200,14 +200,13 @@
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
<url>https://central.sonatype.com/api/v1/publisher</url>
</repository>
</distributionManagement>

<build>
<plugins>
<!-- assembly-plugin -->
Expand Down Expand Up @@ -262,26 +261,15 @@
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.14</version>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central.publishing.maven.plugin.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
<publishingServerId>ossrh</publishingServerId>
<autoPublish>false</autoPublish>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class MDocMockVCIssuancePlugin implements VCIssuancePlugin {
@Autowired
private KeymanagerDBHelper dbHelper;

@Autowired
private MdocGenerator mdocGenerator;

@Value("${mosip.certify.cache.security.secretkey.reference-id}")
private String cacheSecretKeyRefId;

Expand Down Expand Up @@ -84,7 +87,7 @@ public VCResult<String> getVerifiableCredential(VCRequestDto vcRequestDto, Strin
VCResult<String> vcResult = new VCResult<>();
String mdocVc;
try {
mdocVc = new MdocGenerator().generate(mockDataForMsoMdoc(documentNumber),holderId, issuerKeyAndCertificate);
mdocVc = mdocGenerator.generate(mockDataForMsoMdoc(documentNumber),holderId, issuerKeyAndCertificate);
} catch (Exception e) {
log.error("Exception on mdoc creation", e);
throw new VCIExchangeException(ErrorConstants.VCI_EXCHANGE_FAILED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.android.identity.mdoc.util.MdocUtil;
import com.android.identity.util.Timestamp;
import io.mosip.certify.util.*;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.security.KeyPair;
Expand All @@ -20,6 +21,7 @@
import java.time.temporal.ChronoUnit;
import java.util.*;

@Component
public class MdocGenerator {

public static final String NAMESPACE = "org.iso.18013.5.1";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package io.mosip.certify.mock.integration.service;

import io.mosip.certify.api.dto.VCRequestDto;
import io.mosip.certify.api.dto.VCResult;
import io.mosip.certify.api.exception.VCIExchangeException;
import io.mosip.certify.constants.VCFormats;
import io.mosip.certify.core.exception.CertifyException;
import io.mosip.certify.mock.integration.mocks.MdocGenerator;
import io.mosip.esignet.core.dto.OIDCTransaction;
import io.mosip.kernel.core.keymanager.spi.KeyStore;
import io.mosip.kernel.keymanagerservice.entity.KeyAlias;
import io.mosip.kernel.keymanagerservice.helper.KeymanagerDBHelper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.test.util.ReflectionTestUtils;

import java.security.Key;
import java.time.LocalDateTime;
import java.util.*;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

@RunWith(org.mockito.junit.MockitoJUnitRunner.class)
public class MDocMockVCIssuancePluginTest {

@InjectMocks
private MDocMockVCIssuancePlugin plugin;

@Mock
private CacheManager cacheManager;
@Mock
private KeyStore keyStore;
@Mock
private KeymanagerDBHelper dbHelper;
@Mock
private Cache cache;
@Mock
private Key key;
@Mock
private MdocGenerator mdocGenerator;

@Before
public void setUp() {
ReflectionTestUtils.setField(plugin, "issuerKeyAndCertificate", "empty");
ReflectionTestUtils.setField(plugin, "cacheSecretKeyRefId", "refId");
ReflectionTestUtils.setField(plugin, "aesECBTransformation", "AES/ECB/PKCS5Padding");
ReflectionTestUtils.setField(plugin, "storeIndividualId", true);
ReflectionTestUtils.setField(plugin, "secureIndividualId", false);
}

@Test
public void testGetVerifiableCredential_Success() throws Exception {
VCRequestDto dto = mock(VCRequestDto.class);
when(dto.getFormat()).thenReturn(VCFormats.MSO_MDOC);

Map<String, Object> identityDetails = new HashMap<>();
identityDetails.put("accessTokenHash", "tokenHash");

OIDCTransaction transaction = mock(OIDCTransaction.class);
when(transaction.getIndividualId()).thenReturn("docNum");

when(cacheManager.getCache(anyString())).thenReturn(cache);
when(cache.get(anyString(), eq(OIDCTransaction.class))).thenReturn(transaction);

when(mdocGenerator.generate(anyMap(), anyString(), anyString())).thenReturn("mockedMdoc");

VCResult<String> result = plugin.getVerifiableCredential(dto, "holderId", identityDetails);

assertNotNull(result);
assertEquals(VCFormats.MSO_MDOC, result.getFormat());
assertEquals("mockedMdoc", result.getCredential());
}

@Test(expected = VCIExchangeException.class)
public void testGetVerifiableCredential_NotImplemented() throws Exception {
VCRequestDto dto = mock(VCRequestDto.class);

Map<String, Object> identityDetails = new HashMap<>();
identityDetails.put("accessTokenHash", "tokenHash");

plugin.getVerifiableCredential(dto, "holderId", identityDetails);
}
Comment on lines +79 to +87
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix potential NPE in the “not implemented” test.

dto.getFormat() is unstubbed, so getFormat().equals(...) will throw a NullPointerException instead of VCIExchangeException. Stub it to a non‑MSO_MDOC value to hit the intended branch.

🐛 Proposed fix
@@
     `@Test`(expected = VCIExchangeException.class)
     public void testGetVerifiableCredential_NotImplemented() throws Exception {
         VCRequestDto dto = mock(VCRequestDto.class);
+        when(dto.getFormat()).thenReturn(VCFormats.LDP_VC);
 
         Map<String, Object> identityDetails = new HashMap<>();
         identityDetails.put("accessTokenHash", "tokenHash");
 
         plugin.getVerifiableCredential(dto, "holderId", identityDetails);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test(expected = VCIExchangeException.class)
public void testGetVerifiableCredential_NotImplemented() throws Exception {
VCRequestDto dto = mock(VCRequestDto.class);
Map<String, Object> identityDetails = new HashMap<>();
identityDetails.put("accessTokenHash", "tokenHash");
plugin.getVerifiableCredential(dto, "holderId", identityDetails);
}
`@Test`(expected = VCIExchangeException.class)
public void testGetVerifiableCredential_NotImplemented() throws Exception {
VCRequestDto dto = mock(VCRequestDto.class);
when(dto.getFormat()).thenReturn(VCFormats.LDP_VC);
Map<String, Object> identityDetails = new HashMap<>();
identityDetails.put("accessTokenHash", "tokenHash");
plugin.getVerifiableCredential(dto, "holderId", identityDetails);
}
🤖 Prompt for AI Agents
In
`@mock-certify-plugin/src/test/java/io/mosip/certify/mock/integration/service/MDocMockVCIssuancePluginTest.java`
around lines 79 - 87, The test testGetVerifiableCredential_NotImplemented is
hitting a NullPointerException because dto.getFormat() is unstubbed; stub the
mock VCRequestDto (dto) so getFormat() returns a non-MS0_MDOC/other value (e.g.,
a simple string) before calling plugin.getVerifiableCredential(dto, "holderId",
identityDetails) so the code path throws VCIExchangeException as expected;
update the test to mock/stub dto.getFormat() accordingly (reference:
VCRequestDto, dto.getFormat(), testGetVerifiableCredential_NotImplemented,
plugin.getVerifiableCredential, VCIExchangeException).


@Test(expected = VCIExchangeException.class)
public void testGetVerifiableCredentialWithLinkedDataProof_NotImplemented() throws Exception {
VCRequestDto dto = mock(VCRequestDto.class);
plugin.getVerifiableCredentialWithLinkedDataProof(dto, "holderId", new HashMap<>());
}

@Test
public void testGetIndividualId_SecureFalse() {
OIDCTransaction transaction = mock(OIDCTransaction.class);
when(transaction.getIndividualId()).thenReturn("docNum");
ReflectionTestUtils.setField(plugin, "secureIndividualId", false);
ReflectionTestUtils.setField(plugin, "storeIndividualId", true);
String result = (String) ReflectionTestUtils.invokeMethod(plugin, "getIndividualId", transaction);
assertEquals("docNum", result);
}

@Test
public void testGetIndividualId_StoreFalse() {
OIDCTransaction transaction = mock(OIDCTransaction.class);
ReflectionTestUtils.setField(plugin, "storeIndividualId", false);
String result = (String) ReflectionTestUtils.invokeMethod(plugin, "getIndividualId", transaction);
assertNull(result);
}

@Test(expected = CertifyException.class)
public void testDecryptIndividualId_Exception() {
ReflectionTestUtils.setField(plugin, "aesECBTransformation", "invalid");
ReflectionTestUtils.invokeMethod(plugin, "decryptIndividualId", "invalid");
}

@Test(expected = CertifyException.class)
public void testGetSecretKeyFromHSM_NoAlias() {
when(dbHelper.getKeyAliases(anyString(), anyString(), any(LocalDateTime.class)))
.thenReturn(Collections.singletonMap("currentKeyAlias", new ArrayList<>()));
ReflectionTestUtils.invokeMethod(plugin, "getSecretKeyFromHSM");
}

@Test
public void testGetKeyAlias_Success() {
KeyAlias alias = mock(KeyAlias.class);
when(alias.getAlias()).thenReturn("alias");
List<KeyAlias> aliases = Collections.singletonList(alias);
Map<String, List<KeyAlias>> map = new HashMap<>();
map.put("currentKeyAlias", aliases);
when(dbHelper.getKeyAliases(anyString(), anyString(), any(LocalDateTime.class))).thenReturn(map);
String result = (String) ReflectionTestUtils.invokeMethod(plugin, "getKeyAlias", "appId", "refId");
assertEquals("alias", result);
}

@Test(expected = CertifyException.class)
public void testGetKeyAlias_NotUnique() {
List<KeyAlias> aliases = Arrays.asList(mock(KeyAlias.class), mock(KeyAlias.class));
Map<String, List<KeyAlias>> map = new HashMap<>();
map.put("currentKeyAlias", aliases);
when(dbHelper.getKeyAliases(anyString(), anyString(), any(LocalDateTime.class))).thenReturn(map);
ReflectionTestUtils.invokeMethod(plugin, "getKeyAlias", "appId", "refId");
}

@Test
public void testMockDataForMsoMdoc() {
String docNum = "12345";
@SuppressWarnings("unchecked")
Map<String, Object> data = (Map<String, Object>) ReflectionTestUtils.invokeMethod(plugin, "mockDataForMsoMdoc", docNum);
assertNotNull(data);
assertEquals("Agatha", data.get("family_name"));
assertEquals("Joseph", data.get("given_name"));
assertEquals("1994-11-06", data.get("birth_date"));
assertEquals("IN", data.get("issuing_country"));
assertEquals(docNum, data.get("document_number"));
assertTrue(data.get("driving_privileges") instanceof Map);
assertEquals("A", ((Map<?, ?>) data.get("driving_privileges")).get("vehicle_category_code"));
}

@Test
public void testGetUserInfoTransaction() {
String accessTokenHash = "tokenHash";
OIDCTransaction transaction = mock(OIDCTransaction.class);
when(cacheManager.getCache(anyString())).thenReturn(cache);
when(cache.get(eq(accessTokenHash), eq(OIDCTransaction.class))).thenReturn(transaction);

OIDCTransaction result = (OIDCTransaction) ReflectionTestUtils.invokeMethod(plugin, "getUserInfoTransaction", accessTokenHash);
assertNotNull(result);
assertEquals(transaction, result);
}
}
Loading
Loading