From 448ed806f069feece441393acea3f0d4f8748056 Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 11 May 2026 08:00:15 -0400 Subject: [PATCH 1/4] initiate upload verify md5 match --- .../score/server/metadata/MetadataFile.java | 23 +++++++++++++++++++ .../server/metadata/MetadataService.java | 17 ++++++++++++++ .../server/repository/s3/S3UploadService.java | 19 ++++++++++++--- 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java diff --git a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java new file mode 100644 index 00000000..24c28b32 --- /dev/null +++ b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java @@ -0,0 +1,23 @@ +package bio.overture.score.server.metadata; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class MetadataFile { + private String objectId; + private String studyId; + private String analysisId; + private String fileName; + private String fileSize; + private String fileType; + private String fileMd5sum; + private String fileAccess; +} diff --git a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java index 803a3e6f..196741b1 100644 --- a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java +++ b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java @@ -62,6 +62,23 @@ public MetadataEntity getEntity(@NonNull String id) { } } + public MetadataFile getFile(@NonNull String studyId, @NonNull String id) { + log.debug("using " + metadataUrl + " for MetaData server"); + try { + return restTemplate + .getForEntity(metadataUrl + "/studies/" + studyId + "/files/" + id, MetadataFile.class) + .getBody(); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == NOT_FOUND) { + throw new IdNotFoundException(format("File %s is not registered on the server.", id)); + } + + log.error("Unexpected response code {} while getting ID {}", e.getStatusCode(), id); + + throw e; + } + } + public String getAnalysisStateForMetadata(@NonNull MetadataEntity metadataEntity) { val studyId = getStudyId(metadataEntity); val analysisId = getAnalysisId(metadataEntity); diff --git a/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java b/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java index 7cbad788..b7d4a4f5 100644 --- a/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java +++ b/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java @@ -86,7 +86,7 @@ public class S3UploadService implements UploadService { public ObjectSpecification initiateUpload( String objectId, long fileSize, String md5, boolean overwrite) { // First ensure that the system is aware of the requested object - checkRegistered(objectId); + checkRegistered(objectId, md5); val objectKey = ObjectKeys.getObjectKey(dataDir, objectId); log.debug("Initiating upload for object key: {}, overwrite: {}", objectKey, overwrite); @@ -142,7 +142,9 @@ public ObjectSpecification initiateUpload( return spec; } catch (AmazonServiceException e) { log.error("Multipart Upload Initialization failure", e); - if (e.getErrorCode().equals("KMS.DisabledException")) { + if (e.getErrorCode().equals("BadDigest")) { + throw new NotRetryableException(e); + } else if (e.getErrorCode().equals("KMS.DisabledException")) { throw new InternalUnrecoverableError(e); } @@ -432,7 +434,7 @@ public void deletePart(String objectId, String uploadId, int partNumber) { stateStore.deletePart(objectId, uploadId, partNumber); } - void checkRegistered(String objectId) { + void checkRegistered(String objectId, String md5) { val entity = metadataClient.getEntity(objectId); if (!entity.getId().equals(objectId)) { val message = @@ -444,6 +446,17 @@ void checkRegistered(String objectId) { throw new InternalUnrecoverableError(message); } + val registeredFile = metadataClient.getFile(entity.getProjectCode(), objectId); + if (!registeredFile.getFileMd5sum().equals(md5)) { + val message = + String.format( + "Critical Error: checked for objectId %s with md5 %s and metadata server returned md5 %s as match", + objectId, md5, registeredFile.getFileMd5sum()); + + log.error(message); // Log to audit log file + throw new InternalUnrecoverableError(message); + } + if (!useLegacyMode) { checkUnpublishedAnalysisState(entity); } From 435ca1399ff884139bf6b04eb8fd98d5b90e9c0f Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 11 May 2026 18:05:30 -0400 Subject: [PATCH 2/4] local checksum debug log --- .../overture/score/client/storage/ScoreStorageService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java b/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java index d0a6793d..44453e0e 100644 --- a/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java +++ b/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java @@ -259,6 +259,12 @@ public void finalizeUploadPart( partNumber); retry.execute( ctx -> { + log.debug( + "Local checksum {} for part {}", + disableChecksum + ? "disabled" + : (md5.equals(etag) ? "validation passed" : "validation failed"), + partNumber); if (disableChecksum || md5.equals(etag)) { serviceTemplate.exchange( endpoint From 360517bcedaa8e6c6e206905cc0d8209efec066c Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 11 May 2026 18:09:52 -0400 Subject: [PATCH 3/4] update aws sdk minor version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 622e4dff..2e9ee84d 100644 --- a/pom.xml +++ b/pom.xml @@ -260,7 +260,7 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S 2021.0.8 - 1.11.219 + 1.12.797 8.6.6 From e470e7ffed4e8e41e486fda574a98998236271da Mon Sep 17 00:00:00 2001 From: Leonardo Rivera Date: Mon, 11 May 2026 18:31:21 -0400 Subject: [PATCH 4/4] fix broken make tests --- Makefile | 13 +++++++------ docker-compose.yml | 1 - .../keycloak-init/data_import/myrealm-users-0.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 6019b1ed..4e11286d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ DEMO_MODE := 0 FORCE := 0 # Required System files -DOCKER_COMPOSE_EXE := $(shell which docker-compose) +DOCKER_COMPOSE_EXE := $(shell which docker) compose CURL_EXE := $(shell which curl) MVN_EXE := $(shell which mvn) @@ -38,6 +38,7 @@ RETRY_CMD := $(DOCKER_DIR)/retry-command.sh # Commands DOCKER_COMPOSE_CMD := echo "*********** DEMO_MODE = $(DEMO_MODE) **************" \ && echo "*********** FORCE = $(FORCE) **************" \ + && echo "*********** Docker file = $(DOCKERFILE_NAME) **************" \ && MY_UID=$(MY_UID) MY_GID=$(MY_GID) DOCKERFILE_NAME=$(DOCKERFILE_NAME) $(DOCKER_COMPOSE_EXE) -f $(ROOT_DIR)/docker-compose.yml SCORE_CLIENT_CMD := $(DOCKER_COMPOSE_CMD) run --rm -u $(THIS_USER) score-client bin/score-client SCORE_CLIENT_TEST := $(DOCKER_COMPOSE_CMD) run --rm -u $(THIS_USER) score-client /data/run_tests.sh @@ -77,17 +78,17 @@ _ping_song_server: _setup-object-storage: @echo $(YELLOW)$(INFO_HEADER) "Setting up bucket score.data and heliograph" $(END) - @if $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \ + @if $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \ echo $(YELLOW)$(INFO_HEADER) "Bucket already exists. Skipping creation..." $(END); \ else \ - $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 mb s3://score.data; \ + $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 mb s3://score.data; \ fi - @$(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 cp /score-data/heliograph s3://score.data/data/heliograph + @$(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 cp /score-data/heliograph s3://score.data/data/heliograph _destroy-object-storage: @echo $(YELLOW)$(INFO_HEADER) "Removing bucket score.data" $(END) - @if $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \ - $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 rb s3://score.data --force; \ + @if $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \ + $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 rb s3://score.data --force; \ else \ echo $(YELLOW)$(INFO_HEADER) "Bucket does not exist. Skipping..." $(END); \ fi diff --git a/docker-compose.yml b/docker-compose.yml index cde27bd5..73ee5b5b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.7' services: keycloak-server: image: docker.io/bitnami/keycloak:22 diff --git a/docker/keycloak-init/data_import/myrealm-users-0.json b/docker/keycloak-init/data_import/myrealm-users-0.json index 01eb8bfd..7f2d2668 100644 --- a/docker/keycloak-init/data_import/myrealm-users-0.json +++ b/docker/keycloak-init/data_import/myrealm-users-0.json @@ -8,7 +8,7 @@ "totp" : false, "emailVerified" : false, "attributes" : { - "api-keys" : [ "{\"name\":\"4978D340EDFA11ABF4A6B282C762676DCFAAEF55496631A6474D55C17CB96DCB\",\"scope\":[\"song.READ\",\"score.WRITE\",\"score.READ\",\"song.WRITE\"],\"expiryDate\":1746499545473,\"issueDate\":1714963545473,\"isRevoked\":false,\"description\":\"write and read\"}" ] + "api-keys" : [ "{\"name\":\"4978D340EDFA11ABF4A6B282C762676DCFAAEF55496631A6474D55C17CB96DCB\",\"scope\":[\"song.READ\",\"score.WRITE\",\"score.READ\",\"song.WRITE\"],\"expiryDate\":1904308934000,\"issueDate\":1714963545473,\"isRevoked\":false,\"description\":\"write and read\"}" ] }, "credentials" : [ { "id" : "b2152773-6246-4f74-bddd-6440e99dc860",