From 946ba87f759b8b3430d419ec746becd61bf6ac00 Mon Sep 17 00:00:00 2001 From: sevenc Date: Fri, 28 Aug 2026 14:45:50 +0800 Subject: [PATCH 1/4] fix(cloud-functions): reject fractional request priorities --- .../configuration/JacksonConfiguration.java | 1 + ...onWithLlmInvocationConfigPriorityTest.java | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java index da6124797..ef8604e5f 100644 --- a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java +++ b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java @@ -54,6 +54,7 @@ public JsonMapper jsonMapper() { .changeDefaultPropertyInclusion(v -> v.withValueInclusion(JsonInclude.Include.NON_NULL)) .enable(StreamWriteFeature.STRICT_DUPLICATE_DETECTION) .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + .disable(DeserializationFeature.ACCEPT_FLOAT_AS_INT) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .enable(EnumFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE) .build(); diff --git a/src/control-plane-services/cloud-functions/nvcf-core/src/test/java/com/nvidia/nvcf/rest/function/management/FunctionWithLlmInvocationConfigPriorityTest.java b/src/control-plane-services/cloud-functions/nvcf-core/src/test/java/com/nvidia/nvcf/rest/function/management/FunctionWithLlmInvocationConfigPriorityTest.java index 113cbdd08..dd38d2aa8 100644 --- a/src/control-plane-services/cloud-functions/nvcf-core/src/test/java/com/nvidia/nvcf/rest/function/management/FunctionWithLlmInvocationConfigPriorityTest.java +++ b/src/control-plane-services/cloud-functions/nvcf-core/src/test/java/com/nvidia/nvcf/rest/function/management/FunctionWithLlmInvocationConfigPriorityTest.java @@ -386,6 +386,85 @@ void createWithDefaultPriorityAboveMaxIsRejected() { assertThat(response.getBody()).contains("defaultPriority"); } + @Test + void updateWithFractionalDefaultPriorityIsRejectedWithoutChangingPriority() { + var created = createLlmFunction(uniqueName("fractional-default"), priorityConfig(7L, null)); + var updateToken = MOCK_OAUTH2_TOKEN_SERVER.getJwt(TEST_CLIENT_SUBJECT, + List.of(SCOPE_UPDATE_FUNCTION), 100); + var updateEntity = RequestEntity.put(URI.create("/v2/nvcf/functions/" + created.id() + + "/versions/" + created.versionId())) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + updateToken) + .body(""" + { + "llmInvocationConfig": { + "priority": { + "defaultPriority": 1.5 + } + } + } + """); + + var updateResponse = testRestTemplate.exchange(updateEntity, String.class); + + assertThat(updateResponse.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + + var getToken = MOCK_OAUTH2_TOKEN_SERVER.getJwt(TEST_CLIENT_SUBJECT, + List.of(SCOPE_LIST_FUNCTIONS), 100); + var getEntity = RequestEntity.get(URI.create("/v2/nvcf/functions/" + created.id() + + "/versions/" + created.versionId())) + .header("Authorization", "Bearer " + getToken) + .build(); + var getResponse = testRestTemplate.exchange(getEntity, FunctionResponse.class); + + assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(getResponse.getBody()).isNotNull(); + assertThat(getResponse.getBody().function().llmInvocationConfig().priority().defaultPriority()) + .isEqualTo(7L); + } + + @Test + void updateWithFractionalPerAccountPriorityIsRejectedWithoutChangingPriority() { + var created = createLlmFunction( + uniqueName("fractional-per-account"), + priorityConfig(7L, Map.of(OVERRIDE_NCA_ID, 3L))); + var updateToken = MOCK_OAUTH2_TOKEN_SERVER.getJwt(TEST_CLIENT_SUBJECT, + List.of(SCOPE_UPDATE_FUNCTION), 100); + var updateEntity = RequestEntity.put(URI.create("/v2/nvcf/functions/" + created.id() + + "/versions/" + created.versionId())) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + updateToken) + .body(""" + { + "llmInvocationConfig": { + "priority": { + "defaultPriority": 7, + "perAccountPriority": { + "nca-override": 1.5 + } + } + } + } + """); + + var updateResponse = testRestTemplate.exchange(updateEntity, String.class); + + assertThat(updateResponse.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + + var getToken = MOCK_OAUTH2_TOKEN_SERVER.getJwt(TEST_CLIENT_SUBJECT, + List.of(SCOPE_LIST_FUNCTIONS), 100); + var getEntity = RequestEntity.get(URI.create("/v2/nvcf/functions/" + created.id() + + "/versions/" + created.versionId())) + .header("Authorization", "Bearer " + getToken) + .build(); + var getResponse = testRestTemplate.exchange(getEntity, FunctionResponse.class); + + assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(getResponse.getBody()).isNotNull(); + assertThat(getResponse.getBody().function().llmInvocationConfig().priority()) + .isEqualTo(new PriorityDto(7L, Map.of(OVERRIDE_NCA_ID, 3L))); + } + @Test void updateWithModelUpdatesAndLlmInvocationConfigAppliesBothToAllVersions() { var name = uniqueName("update-both"); From fe5298091263baa91bc6bbf0703ff16fe8436fe0 Mon Sep 17 00:00:00 2001 From: sevenc Date: Fri, 28 Aug 2026 15:18:57 +0800 Subject: [PATCH 2/4] fix(ci): upload generated CodeQL SARIF artifacts --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 28b94633b..1528138a7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -130,7 +130,7 @@ jobs: with: # The companion workflow parses this artifact as untrusted data only. name: codeql-pr-results-${{ matrix.language }} - path: results/${{ matrix.language }}.sarif + path: results/*.sarif if-no-files-found: error retention-days: 1 From 2d4023df701c65a2b18c2e36945491352f5cefa0 Mon Sep 17 00:00:00 2001 From: sevenc Date: Sat, 29 Aug 2026 09:05:16 +0800 Subject: [PATCH 3/4] fix(cloud-functions): scope integer validation to priority --- .../configuration/JacksonConfiguration.java | 1 - .../function/management/dto/PriorityDto.java | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java index ef8604e5f..da6124797 100644 --- a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java +++ b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/configuration/JacksonConfiguration.java @@ -54,7 +54,6 @@ public JsonMapper jsonMapper() { .changeDefaultPropertyInclusion(v -> v.withValueInclusion(JsonInclude.Include.NON_NULL)) .enable(StreamWriteFeature.STRICT_DUPLICATE_DETECTION) .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) - .disable(DeserializationFeature.ACCEPT_FLOAT_AS_INT) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .enable(EnumFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE) .build(); diff --git a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java index 0496c7ba7..7ea316527 100644 --- a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java +++ b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java @@ -31,6 +31,12 @@ import java.lang.annotation.Target; import java.util.Map; import org.springframework.util.CollectionUtils; +import tools.jackson.core.JsonParser; +import tools.jackson.core.JsonToken; +import tools.jackson.databind.DeserializationContext; +import tools.jackson.databind.annotation.JsonDeserialize; +import tools.jackson.databind.deser.std.StdScalarDeserializer; +import tools.jackson.databind.type.LogicalType; @PriorityDto.ValidPriority @Schema(types = {"object"}, @@ -40,6 +46,7 @@ public record PriorityDto( @Min(value = 0, message = "defaultPriority must be >= 0") @Max(value = MAX_PRIORITY, message = "defaultPriority must be <= " + MAX_PRIORITY) @Schema(description = "Default priority.") + @JsonDeserialize(using = PriorityValueDeserializer.class) Long defaultPriority, @Nullable @@ -47,6 +54,7 @@ public record PriorityDto( message = "Maximum number of perAccountPriority entries of " + MAX_PER_ACCOUNT_ENTRIES + " is exceeded.") @Schema(description = "Per-account priority overrides, keyed by account ID.") + @JsonDeserialize(contentUsing = PriorityValueDeserializer.class) Map { + public PriorityValueDeserializer() { + super(Long.class); + } + + @Override + public LogicalType logicalType() { + return LogicalType.Integer; + } + + @Override + public Long deserialize(JsonParser parser, DeserializationContext context) { + if (parser.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) { + return context.reportInputMismatch(Long.class, "priority must be an integer"); + } + return _parseLong(parser, context, Long.class); + } + } } From 5c3e7683b08a51f268f77755c62c4a70ffdd95bf Mon Sep 17 00:00:00 2001 From: sevenc Date: Sat, 29 Aug 2026 09:29:39 +0800 Subject: [PATCH 4/4] refactor(cloud-functions): extract priority validation message --- .../nvidia/nvcf/rest/function/management/dto/PriorityDto.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java index 7ea316527..d3cfbab87 100644 --- a/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java +++ b/src/control-plane-services/cloud-functions/nvcf-core/src/main/java/com/nvidia/nvcf/rest/function/management/dto/PriorityDto.java @@ -65,6 +65,8 @@ public record PriorityDto( static final int MAX_PER_ACCOUNT_ENTRIES = 64; private static final String MESG_DEFAULT_REQUIRED_WITH_OVERRIDES = "Invalid priority: 'defaultPriority' is required when 'perAccountPriority' has entries"; + private static final String MESG_PRIORITY_MUST_BE_INTEGER = + "priority must be an integer"; @Constraint(validatedBy = ValidPriorityValidator.class) @Target(ElementType.TYPE) @@ -111,7 +113,7 @@ public LogicalType logicalType() { @Override public Long deserialize(JsonParser parser, DeserializationContext context) { if (parser.hasToken(JsonToken.VALUE_NUMBER_FLOAT)) { - return context.reportInputMismatch(Long.class, "priority must be an integer"); + return context.reportInputMismatch(Long.class, MESG_PRIORITY_MUST_BE_INTEGER); } return _parseLong(parser, context, Long.class); }