Skip to content
Merged
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
14 changes: 11 additions & 3 deletions .github/pmd-ruleset.xml
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="Custom Ruleset"
<ruleset name="Custom Ruleset"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0
https://pmd.github.io/pmd-7.0.0/pmd-7.0.0.xsd">
https://pmd.github.io/pmd-7.17.0/pmd-7.17.0.xsd">

<description>Custom ruleset including exclusions</description>

<rule ref="category/java/codestyle.xml/MethodNamingConventions">
<properties>
<!-- This regex allows underscores in JUnit 5 test method names -->
<property name="junit5TestPattern" value="^[a-z][a-zA-Z0-9_]*$"/>
</properties>
</rule>
<rule ref="category/java/bestpractices.xml">
<exclude name="GuardLogStatement"/>
<exclude name="UnitTestAssertionsShouldIncludeMessage"/>
<exclude name="UnitTestContainsTooManyAsserts"/>
<exclude name="PreserveStackTrace"/>
<exclude name="ImplicitFunctionalInterface"/>
</rule>
<rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/>
<exclude name="CallSuperInConstructor"/>
<exclude name="LongVariable"/>
<exclude name="ShortVariable"/>
<exclude name="TooManyStaticImports"/>
</rule>
<rule ref="category/java/errorprone.xml">
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/code-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ jobs:
with:
rulesets: '.github/pmd-ruleset.xml'
sourcePath: 'src/main/java'
analyzeModifiedFilesOnly: false

- name: Fail build if there are violations
if: steps.pmd.outputs.violations != 0
run: exit 1
if: always()
run: |
VIOLATIONS="${{ steps.pmd.outputs.violations }}"
if [ -n "$VIOLATIONS" ] && [ "$VIOLATIONS" != "0" ]; then
echo "PMD found $VIOLATIONS violations"
exit 1
fi
17 changes: 1 addition & 16 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ repositories {

apply {
from("gradle/docker.gradle")
from("gradle/pmd.gradle")
}

/* ------------ Java toolchain ------------ */
Expand Down Expand Up @@ -226,22 +227,6 @@ gitProperties {
dateFormatTimeZone = "UTC"
}

/* ------------ PMD ------------ */
pmd {
ruleSets = []
ruleSetFiles = files(".github/pmd-ruleset.xml")
ignoreFailures = false
}
tasks.withType(Pmd).configureEach {
reports { xml.required.set(true); html.required.set(true) }
if (name.toLowerCase().contains("test") || name.toLowerCase().contains("integration")) {
enabled = false
}
}
tasks.named("pmdMain").configure {
onlyIf { Boolean.getBoolean("runPmd") || System.getenv("RUN_PMD")?.toBoolean() == true }
}

/* ------------ SBOM ------------ */
tasks.cyclonedxDirectBom {
includeConfigs = ["runtimeClasspath"]
Expand Down
29 changes: 29 additions & 0 deletions gradle/pmd.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apply plugin: 'pmd'

pmd {
ruleSets = []
ruleSetFiles = files(".github/pmd-ruleset.xml")
ignoreFailures = false
}

tasks.named("pmdMain").configure {
onlyIf { gradle.startParameter.taskNames.contains(name) }
}

tasks.named("pmdTest").configure {
enabled = false
}

tasks.withType(Pmd) {
reports {
xml.required.set(true)
html.required.set(true)
}
}

tasks.withType(Checkstyle).configureEach {
def generatedDir = file("${layout.buildDirectory.get().asFile.absolutePath}/generated/src/main/java").canonicalPath
source = source.filter { file ->
!file.canonicalPath.startsWith(generatedDir)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class ActuatorHttpLiveTest {
class ActuatorHttpLiveTest {

private final String baseUrl = System.getProperty("app.baseUrl", "http://localhost:8082/casedocumentknowledge-service");
private final RestTemplate http = new RestTemplate();

@Test
void health_is_up() {
ResponseEntity<String> res = http.exchange(
final ResponseEntity<String> res = http.exchange(
baseUrl + "/actuator/health", HttpMethod.GET,
new HttpEntity<>(new HttpHeaders()),
String.class
Expand All @@ -29,9 +29,9 @@ void health_is_up() {

@Test
void prometheus_is_exposed() {
HttpHeaders h = new HttpHeaders();
final HttpHeaders h = new HttpHeaders();
h.setAccept(java.util.List.of(MediaType.TEXT_PLAIN));
ResponseEntity<String> res = http.exchange(
final ResponseEntity<String> res = http.exchange(
baseUrl + "/actuator/prometheus", HttpMethod.GET,
new HttpEntity<>(h),
String.class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import static java.util.UUID.fromString;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static uk.gov.hmcts.cp.cdk.testsupport.TestConstants.CJSCPPUID;
import static uk.gov.hmcts.cp.cdk.testsupport.TestConstants.USER_WITH_PERMISSIONS;
import static uk.gov.hmcts.cp.cdk.util.UtilConstants.CJSCPPUID;
import static uk.gov.hmcts.cp.cdk.util.UtilConstants.USER_WITH_PERMISSIONS;

import uk.gov.hmcts.cp.cdk.testsupport.AbstractHttpLiveTest;
import uk.gov.hmcts.cp.cdk.util.BrokerUtil;
Expand Down Expand Up @@ -35,10 +35,14 @@
* - GET /answers/{caseId}/{queryId}/with-llm (latest with LLM payload)
* - GET /queries?caseId={caseId}&at={isoInstant} (as-of queries view for a case)
*/
public class AnswersHttpLiveTest extends AbstractHttpLiveTest {

public final MediaType VND_TYPE_JSON = MediaType.valueOf("application/vnd.casedocumentknowledge-service.answers+json");
public final MediaType VND_TYPE_JSON_QUERIES = MediaType.valueOf("application/vnd.casedocumentknowledge-service.queries+json");
class AnswersHttpLiveTest extends AbstractHttpLiveTest {

public static final MediaType VND_TYPE_JSON = MediaType.valueOf("application/vnd.casedocumentknowledge-service.answers+json");
public static final MediaType VND_TYPE_JSON_QUERIES = MediaType.valueOf("application/vnd.casedocumentknowledge-service.queries+json");
public static final String ANSWERS = "/answers/";
public static final String CONTENT = "content";
public static final String METADATA = "_metadata";
public static final String NAME = "name";
private UUID caseId;
private UUID queryId;

Expand Down Expand Up @@ -163,7 +167,7 @@ void get_latest_answer_without_version_param() throws Exception {
headers.setAccept(List.of(VND_TYPE_JSON));

final ResponseEntity<String> response = http.exchange(
baseUrl + "/answers/" + caseId + "/" + queryId,
baseUrl + ANSWERS + caseId + "/" + queryId,
HttpMethod.GET,
new HttpEntity<>(headers),
String.class
Expand All @@ -175,25 +179,25 @@ void get_latest_answer_without_version_param() throws Exception {
// This endpoint typically omits LLM input:
assertThat(response.getBody()).doesNotContain("llmInput");

String auditRequest = brokerUtil.getMessageMatching(json ->
json.has("content")
final String auditRequest = brokerUtil.getMessageMatching(json ->
json.has(CONTENT)
&& "casedocumentknowledge-service".equals(json.get("origin").asText())
&& "casedocumentknowledge-service-api".equals(json.get("component").asText())
&& caseId.equals(fromString(json.get("content").get("caseId").asText()))
&& queryId.equals(fromString(json.get("content").get("queryId").asText()))
&& "application/vnd.casedocumentknowledge-service.answers+json".equals(json.get("content").get("_metadata").get("name").asText())
&& "audit.events.audit-recorded".equals(json.get("_metadata").get("name").asText())
&& caseId.equals(fromString(json.get(CONTENT).get("caseId").asText()))
&& queryId.equals(fromString(json.get(CONTENT).get("queryId").asText()))
&& "application/vnd.casedocumentknowledge-service.answers+json".equals(json.get(CONTENT).get(METADATA).get(NAME).asText())
&& "audit.events.audit-recorded".equals(json.get(METADATA).get(NAME).asText())
);
assertNotNull(auditRequest);

String auditResponse = brokerUtil.getMessageMatching(json ->
json.has("content")
final String auditResponse = brokerUtil.getMessageMatching(json ->
json.has(CONTENT)
&& "casedocumentknowledge-service".equals(json.get("origin").asText())
&& "casedocumentknowledge-service-api".equals(json.get("component").asText())
&& "Answer v2".equals(json.get("content").get("answer").asText())
&& !json.get("content").has("llmInput")
&& "application/vnd.casedocumentknowledge-service.answers+json".equals(json.get("content").get("_metadata").get("name").asText())
&& "audit.events.audit-recorded".equals(json.get("_metadata").get("name").asText())
&& "Answer v2".equals(json.get(CONTENT).get("answer").asText())
&& !json.get(CONTENT).has("llmInput")
&& "application/vnd.casedocumentknowledge-service.answers+json".equals(json.get(CONTENT).get(METADATA).get(NAME).asText())
&& "audit.events.audit-recorded".equals(json.get(METADATA).get(NAME).asText())
);
assertNotNull(auditResponse);
}
Expand All @@ -202,7 +206,7 @@ void get_latest_answer_without_version_param() throws Exception {
@Test
void get_latest_answer_not_found() throws Exception {

try (BrokerUtil brokerUtil = new BrokerUtil()) {
try (BrokerUtil ignored = new BrokerUtil()) {

final HttpHeaders headers = new HttpHeaders();
headers.setAccept(List.of(VND_TYPE_JSON));
Expand All @@ -211,7 +215,7 @@ void get_latest_answer_not_found() throws Exception {

try {
http.exchange(
baseUrl + "/answers/" + caseId + "/" + nonExistentQueryId,
baseUrl + ANSWERS + caseId + "/" + nonExistentQueryId,
HttpMethod.GET,
new HttpEntity<>(headers),
String.class
Expand All @@ -233,7 +237,7 @@ void get_specific_answer_version() {
headers.setAccept(List.of(VND_TYPE_JSON));

final ResponseEntity<String> response = http.exchange(
baseUrl + "/answers/" + caseId + "/" + queryId + "?version=1",
baseUrl + ANSWERS + caseId + "/" + queryId + "?version=1",
HttpMethod.GET,
new HttpEntity<>(headers),
String.class
Expand All @@ -255,7 +259,7 @@ void cors_preflight_allows_get_answers_version() {

final HttpEntity<Void> req = new HttpEntity<>(headers);

final String url = baseUrl + "/answers/" + caseId + "/" + queryId + "?version=1";
final String url = baseUrl + ANSWERS+ caseId + "/" + queryId + "?version=1";

final ResponseEntity<Void> resp = http.exchange(
url,
Expand All @@ -272,7 +276,7 @@ void get_answer_with_llm_latest() {
headers.setAccept(List.of(VND_TYPE_JSON));
headers.set(CJSCPPUID, USER_WITH_PERMISSIONS);
final ResponseEntity<String> response = http.exchange(
baseUrl + "/answers/" + caseId + "/" + queryId + "/with-llm",
baseUrl + ANSWERS + caseId + "/" + queryId + "/with-llm",
HttpMethod.GET,
new HttpEntity<>(headers),
String.class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,27 @@
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.azure.storage.blob.sas.BlobSasPermission;
import com.azure.storage.blob.sas.BlobServiceSasSignatureValues;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public final class AzureSasUtil {

private static final Logger LOGGER =
LoggerFactory.getLogger(AzureSasUtil.class);

private AzureSasUtil() {
}

public static void main(String[] args) {
System.out.println(sasUrlFromEnv("idpc-ai", // container

LOGGER.info(sasUrlFromEnv("idpc-ai",
"hello.pdf", // blob
120));
}

private AzureSasUtil() {
}

public static String sasUrlFromEnv(final String container, final String blobName, final int minutes) {
String conn = "";
final String conn = "";

if (conn == null || conn.isBlank()) {
throw new IllegalStateException("Missing env: CP_CDK_AZURE_STORAGE_CONNECTION_STRING");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package uk.gov.hmcts.cp.cdk.http;

import static org.assertj.core.api.Assertions.assertThat;
import static uk.gov.hmcts.cp.cdk.testsupport.TestConstants.CJSCPPUID;
import static uk.gov.hmcts.cp.cdk.testsupport.TestConstants.USER_WITH_PERMISSIONS;
import static uk.gov.hmcts.cp.cdk.util.UtilConstants.CJSCPPUID;
import static uk.gov.hmcts.cp.cdk.util.UtilConstants.USER_WITH_PERMISSIONS;

import uk.gov.hmcts.cp.cdk.testsupport.AbstractHttpLiveTest;

Expand All @@ -20,15 +20,15 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

public class DocumentHttpLiveTest extends AbstractHttpLiveTest {
public final MediaType VND_TYPE_MATERIAL = MediaType.valueOf("application/vnd.casedocumentknowledge-service.document-content+json");
private UUID queryId;
class DocumentHttpLiveTest extends AbstractHttpLiveTest {
public static final MediaType VND_TYPE_MATERIAL = MediaType.valueOf("application/vnd.casedocumentknowledge-service.document-content+json");


@Test
void getMaterialContentUrl_returns_expected_url() throws Exception {
void materialContentUrl_returnsExpectedUrl() throws Exception {

UUID docId = UUID.randomUUID();
UUID materialId = UUID.randomUUID();
final UUID docId = UUID.randomUUID();
final UUID materialId = UUID.randomUUID();

try (Connection c = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPass);
PreparedStatement ps = c.prepareStatement(
Expand All @@ -45,12 +45,12 @@ void getMaterialContentUrl_returns_expected_url() throws Exception {
ps.executeUpdate();
}

HttpHeaders headers = new HttpHeaders();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(VND_TYPE_MATERIAL);
headers.set(CJSCPPUID, USER_WITH_PERMISSIONS); // add required header

// --- Act: perform GET request to the endpoint ---
ResponseEntity<String> res = http.exchange(
final ResponseEntity<String> res = http.exchange(
baseUrl + "/document/" + docId + "/content",
HttpMethod.GET,
new HttpEntity<>(headers),
Expand Down
Loading
Loading