From 02c447ee8dbc482717d5d54b180ad2e2face9480 Mon Sep 17 00:00:00 2001 From: Tristan Vuong <85768771+tristanvuong2021@users.noreply.github.com> Date: Wed, 7 Feb 2024 13:43:57 -0800 Subject: [PATCH] Cache Certificates in Metrics Service (#1440) --- MODULE.bazel | 3 +- MODULE.bazel.lock | 176 +++++++++--------- maven_install.json | 12 +- src/main/k8s/reporting_v2.cue | 3 + .../reporting/v2/InProcessReportingServer.kt | 2 + .../common/job/ReportSchedulingJobExecutor.kt | 2 + .../common/server/V2AlphaPublicApiServer.kt | 10 + .../reporting/service/api/v2alpha/BUILD.bazel | 2 + .../service/api/v2alpha/MetricsService.kt | 172 ++++++++++------- .../service/api/v2alpha/MetricsServiceTest.kt | 83 +++++++++ 10 files changed, 300 insertions(+), 165 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 4e4ecb16561..79a3a85b1fc 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -122,7 +122,7 @@ bazel_dep( ) bazel_dep( name = "common-jvm", - version = "0.74.1", + version = "0.75.0", repo_name = "wfa_common_jvm", ) bazel_dep( @@ -199,6 +199,7 @@ maven.artifact( ) maven.install( artifacts = [ + "com.github.ben-manes.caffeine:caffeine:3.1.8", "com.google.cloud:google-cloud-security-private-ca:2.3.1", "com.google.crypto.tink:tink-awskms:1.9.1", "com.google.crypto.tink:tink-gcpkms:1.9.0", diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 90220b039cc..f1f0a31b6f5 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,6 +1,6 @@ { "lockFileVersion": 3, - "moduleFileHash": "0dc7e904607ab9e9f8907fc88414130e3dabc639026536b2e3d746570b898781", + "moduleFileHash": "e12530f2f47c1a303f3a4953bc52aee56a20704ae76b3330e84c28e167ea8820", "flags": { "cmdRegistries": [ "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main", @@ -78,6 +78,7 @@ "tagName": "install", "attributeValues": { "artifacts": [ + "com.github.ben-manes.caffeine:caffeine:3.1.8", "com.google.cloud:google-cloud-security-private-ca:2.3.1", "com.google.crypto.tink:tink-awskms:1.9.1", "com.google.crypto.tink:tink-gcpkms:1.9.0", @@ -119,7 +120,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 228, + "line": 229, "column": 20 }, "imports": { @@ -138,7 +139,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 229, + "line": 230, "column": 23 } } @@ -152,7 +153,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 237, + "line": 238, "column": 24 }, "imports": { @@ -174,7 +175,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 238, + "line": 239, "column": 15 } }, @@ -188,7 +189,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 243, + "line": 244, "column": 15 } }, @@ -202,7 +203,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 248, + "line": 249, "column": 15 } }, @@ -216,7 +217,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 253, + "line": 254, "column": 15 } }, @@ -230,7 +231,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 258, + "line": 259, "column": 15 } } @@ -244,7 +245,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 272, + "line": 273, "column": 23 }, "imports": {}, @@ -259,7 +260,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 273, + "line": 274, "column": 17 } } @@ -294,7 +295,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 282, + "line": 283, "column": 13 } }, @@ -309,7 +310,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 289, + "line": 290, "column": 13 } }, @@ -324,7 +325,7 @@ "devDependency": false, "location": { "file": "@@//:MODULE.bazel", - "line": 296, + "line": 297, "column": 13 } } @@ -356,7 +357,7 @@ "wfa_rules_kotlin_jvm": "rules_kotlin_jvm@0.2.0", "wfa_rules_swig": "rules_swig@0.1.0", "wfa_rules_cue": "rules_cue@0.4.0", - "wfa_common_jvm": "common-jvm@0.74.1", + "wfa_common_jvm": "common-jvm@0.75.0", "wfa_common_cpp": "common-cpp@0.12.0", "wfa_measurement_proto": "cross-media-measurement-api@0.57.0", "wfa_consent_signaling_client": "consent-signaling-client@0.20.0", @@ -1994,10 +1995,10 @@ } } }, - "common-jvm@0.74.1": { + "common-jvm@0.75.0": { "name": "common-jvm", - "version": "0.74.1", - "key": "common-jvm@0.74.1", + "version": "0.75.0", + "key": "common-jvm@0.75.0", "repoName": "wfa_common_jvm", "executionPlatformsToRegister": [], "toolchainsToRegister": [], @@ -2005,9 +2006,9 @@ { "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", "extensionName": "maven", - "usingModule": "common-jvm@0.74.1", + "usingModule": "common-jvm@0.75.0", "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 82, "column": 22 }, @@ -2026,7 +2027,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 83, "column": 15 } @@ -2041,7 +2042,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 89, "column": 15 } @@ -2056,7 +2057,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 95, "column": 15 } @@ -2071,7 +2072,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 101, "column": 15 } @@ -2086,7 +2087,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 107, "column": 15 } @@ -2101,7 +2102,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 113, "column": 15 } @@ -2116,7 +2117,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 119, "column": 15 } @@ -2131,7 +2132,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 125, "column": 15 } @@ -2146,7 +2147,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 131, "column": 15 } @@ -2161,7 +2162,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 137, "column": 15 } @@ -2176,7 +2177,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 143, "column": 15 } @@ -2191,7 +2192,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 149, "column": 15 } @@ -2208,7 +2209,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 155, "column": 15 } @@ -2223,7 +2224,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 163, "column": 15 } @@ -2260,6 +2261,7 @@ "org.reactivestreams:reactive-streams:1.0.4", "io.projectreactor:reactor-core:3.4.19", "com.google.crypto.tink:tink:1.12.0", + "com.github.ben-manes.caffeine:caffeine:3.1.8", "software.amazon.awssdk:auth:2.17.258", "software.amazon.awssdk:regions:2.17.258", "software.amazon.awssdk:s3:2.17.258", @@ -2297,7 +2299,7 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 170, "column": 14 } @@ -2309,10 +2311,10 @@ { "extensionBzlFile": "@rules_oci//oci:extensions.bzl", "extensionName": "oci", - "usingModule": "common-jvm@0.74.1", + "usingModule": "common-jvm@0.75.0", "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", - "line": 252, + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", + "line": 253, "column": 20 }, "imports": { @@ -2330,8 +2332,8 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", - "line": 253, + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", + "line": 254, "column": 9 } }, @@ -2344,8 +2346,8 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", - "line": 259, + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", + "line": 260, "column": 9 } } @@ -2356,9 +2358,9 @@ { "extensionBzlFile": "//:MODULE.bazel", "extensionName": "_repo_rules", - "usingModule": "common-jvm@0.74.1", + "usingModule": "common-jvm@0.75.0", "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", "line": 0, "column": 0 }, @@ -2380,8 +2382,8 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", - "line": 273, + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", + "line": 274, "column": 13 } }, @@ -2396,8 +2398,8 @@ }, "devDependency": false, "location": { - "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/MODULE.bazel", - "line": 280, + "file": "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/MODULE.bazel", + "line": 281, "column": 13 } } @@ -2426,14 +2428,14 @@ "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_archive", "attributes": { - "name": "common-jvm~0.74.1", + "name": "common-jvm~0.75.0", "urls": [ - "https://github.com/world-federation-of-advertisers/common-jvm/archive/refs/tags/v0.74.1.tar.gz" + "https://github.com/world-federation-of-advertisers/common-jvm/archive/refs/tags/v0.75.0.tar.gz" ], - "integrity": "sha256-cjRLKHfHlmMinrtMGMOrmzvBF52+p9Xw+Rq+fdJ8QGs=", - "strip_prefix": "common-jvm-0.74.1", + "integrity": "sha256-EACOR/g1d7lfA/H4Cw5uHRjZIS7rDYJ7x/Y3ncYYkDE=", + "strip_prefix": "common-jvm-0.75.0", "remote_patches": { - "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.74.1/patches/module_dot_bazel.patch": "sha256-e31JNiVE989lO3tJ0mZFrb22R17wKG5Dzarj5NoH3/4=" + "https://raw.githubusercontent.com/world-federation-of-advertisers/bazel-registry/main/modules/common-jvm/0.75.0/patches/module_dot_bazel.patch": "sha256-9D1J6GnwOWeimJCF1WiYtlcFAGRbUpJlKCYZ+VaULkQ=" }, "remote_patch_strip": 0 } @@ -2573,7 +2575,7 @@ "deps": { "wfa_rules_kotlin_jvm": "rules_kotlin_jvm@0.2.0", "wfa_measurement_proto": "cross-media-measurement-api@0.57.0", - "wfa_common_jvm": "common-jvm@0.74.1", + "wfa_common_jvm": "common-jvm@0.75.0", "bazel_tools": "bazel_tools@_", "local_config_platform": "local_config_platform@_" }, @@ -135949,7 +135951,7 @@ "recordedRepoMappingEntries": [] } }, - "@@common-jvm~0.74.1//:MODULE.bazel%_repo_rules": { + "@@common-jvm~0.75.0//:MODULE.bazel%_repo_rules": { "general": { "bzlTransitiveDigest": "nSp+oEsTv5DYy1r8s+aEwKWUHoJDhXelRNB5mFkZmdU=", "accumulatedFileDigests": {}, @@ -135964,18 +135966,18 @@ "urls": [ "https://github.com/grpc/grpc-proto/archive/08911e9d585cbda3a55eb1dcc4b99c89aebccff8.zip" ], - "name": "common-jvm~0.74.1~_repo_rules~io_grpc_grpc_proto" + "name": "common-jvm~0.75.0~_repo_rules~io_grpc_grpc_proto" } }, "com_google_highwayhash": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_archive", "attributes": { - "build_file": "@@common-jvm~0.74.1//build/com_google_highwayhash:BUILD.external", + "build_file": "@@common-jvm~0.75.0//build/com_google_highwayhash:BUILD.external", "sha256": "1e4e32f6198facbac7a35b04fa4c1acb5e6d9bb13f983c60903da9cbbbd9f5b5", "strip_prefix": "highwayhash-a7f68e2f95fac08b24327d74747521cf634d5aff", "url": "https://github.com/google/highwayhash/archive/a7f68e2f95fac08b24327d74747521cf634d5aff.tar.gz", - "name": "common-jvm~0.74.1~_repo_rules~com_google_highwayhash" + "name": "common-jvm~0.75.0~_repo_rules~com_google_highwayhash" } } }, @@ -138548,7 +138550,7 @@ "general": { "bzlTransitiveDigest": "vOkppYc6wE/3x4HnEmuAd/USfcKbaNTBbUEl7bKmhsY=", "accumulatedFileDigests": { - "@@//:maven_install.json": "1786291500b969bf25543446f7e0d3c009c2200bf44baae7defc9f3303185613", + "@@//:maven_install.json": "54917d3c6dfcd47e2e1e7f32481ba6a8eb07cef43411957dafc4514a9312beba", "@@rules_jvm_external~6.0//:rules_jvm_external_deps_install.json": "cafb5d2d8119391eb2b322ce3840d3352ea82d496bdb8cbd4b6779ec4d044dda" }, "envVariables": {}, @@ -138900,6 +138902,19 @@ "downloaded_file_path": "v1/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar" } }, + "com_github_ben_manes_caffeine_caffeine_3_1_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~6.0~maven~com_github_ben_manes_caffeine_caffeine_3_1_8", + "sha256": "7dd15f9df1be238ffaa367ce6f556737a88031de4294dad18eef57c474ddf1d3", + "urls": [ + "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8.jar", + "https://maven.google.com/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8.jar" + ], + "downloaded_file_path": "v1/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8.jar" + } + }, "com_google_truth_extensions_truth_proto_extension_jar_sources_1_1_2": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -142244,19 +142259,6 @@ "downloaded_file_path": "v1/org/springframework/boot/spring-boot-autoconfigure/2.3.12.RELEASE/spring-boot-autoconfigure-2.3.12.RELEASE.jar" } }, - "com_github_ben_manes_caffeine_caffeine_2_9_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~6.0~maven~com_github_ben_manes_caffeine_caffeine_2_9_3", - "sha256": "1e0a7bbef1dd791653143f3f05d0e489934bf5481e58a87c9e619cd46b68729b", - "urls": [ - "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3.jar", - "https://maven.google.com/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3.jar" - ], - "downloaded_file_path": "v1/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3.jar" - } - }, "com_ongres_scram_common_2_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -144008,6 +144010,19 @@ "downloaded_file_path": "v1/org/threeten/threeten-extra/1.7.2/threeten-extra-1.7.2.jar" } }, + "com_github_ben_manes_caffeine_caffeine_jar_sources_3_1_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~6.0~maven~com_github_ben_manes_caffeine_caffeine_jar_sources_3_1_8", + "sha256": "7c8237f5d8f23654e7091056316a3730636b7a0f2e6fce450e2bd522090d6b7f", + "urls": [ + "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8-sources.jar", + "https://maven.google.com/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8-sources.jar" + ], + "downloaded_file_path": "v1/com/github/ben-manes/caffeine/caffeine/3.1.8/caffeine-3.1.8-sources.jar" + } + }, "org_springframework_boot_spring_boot_autoconfigure_jar_sources_2_3_12_RELEASE": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -146632,19 +146647,6 @@ "downloaded_file_path": "v1/io/opencensus/opencensus-contrib-grpc-metrics/0.31.1/opencensus-contrib-grpc-metrics-0.31.1.jar" } }, - "com_github_ben_manes_caffeine_caffeine_jar_sources_2_9_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~6.0~maven~com_github_ben_manes_caffeine_caffeine_jar_sources_2_9_3", - "sha256": "9c70fa3874ad26bca1e071b7eb69a96d37f6d544eda743b4b00ea050f377b0d0", - "urls": [ - "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3-sources.jar", - "https://maven.google.com/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3-sources.jar" - ], - "downloaded_file_path": "v1/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3-sources.jar" - } - }, "org_eclipse_jetty_jetty_servlets_9_4_42_v20210604": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -148034,6 +148036,7 @@ "artifacts": [ "{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-runners-google-cloud-dataflow-java\", \"version\": \"2.40.0\", \"exclusions\": [{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-sdks-java-io-kafka\" }] }", "{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-sdks-java-io-google-cloud-platform\", \"version\": \"2.40.0\", \"exclusions\": [{ \"group\": \"io.netty\", \"artifact\": \"netty-tcnative-boringssl-static\" }] }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"3.1.8\" }", "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-security-private-ca\", \"version\": \"2.3.1\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink-awskms\", \"version\": \"1.9.1\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink-gcpkms\", \"version\": \"1.9.0\" }", @@ -148117,6 +148120,7 @@ "{ \"group\": \"org.reactivestreams\", \"artifact\": \"reactive-streams\", \"version\": \"1.0.4\" }", "{ \"group\": \"io.projectreactor\", \"artifact\": \"reactor-core\", \"version\": \"3.4.19\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink\", \"version\": \"1.12.0\" }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"3.1.8\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"auth\", \"version\": \"2.17.258\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"regions\", \"version\": \"2.17.258\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.17.258\" }", @@ -150062,6 +150066,7 @@ "artifacts": [ "{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-runners-google-cloud-dataflow-java\", \"version\": \"2.40.0\", \"exclusions\": [{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-sdks-java-io-kafka\" }] }", "{ \"group\": \"org.apache.beam\", \"artifact\": \"beam-sdks-java-io-google-cloud-platform\", \"version\": \"2.40.0\", \"exclusions\": [{ \"group\": \"io.netty\", \"artifact\": \"netty-tcnative-boringssl-static\" }] }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"3.1.8\" }", "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-security-private-ca\", \"version\": \"2.3.1\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink-awskms\", \"version\": \"1.9.1\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink-gcpkms\", \"version\": \"1.9.0\" }", @@ -150145,6 +150150,7 @@ "{ \"group\": \"org.reactivestreams\", \"artifact\": \"reactive-streams\", \"version\": \"1.0.4\" }", "{ \"group\": \"io.projectreactor\", \"artifact\": \"reactor-core\", \"version\": \"3.4.19\" }", "{ \"group\": \"com.google.crypto.tink\", \"artifact\": \"tink\", \"version\": \"1.12.0\" }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"3.1.8\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"auth\", \"version\": \"2.17.258\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"regions\", \"version\": \"2.17.258\" }", "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.17.258\" }", diff --git a/maven_install.json b/maven_install.json index 9bace422cb4..cdb997e154f 100755 --- a/maven_install.json +++ b/maven_install.json @@ -1,7 +1,7 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": -854047605, - "__RESOLVED_ARTIFACTS_HASH": 236716798, + "__INPUT_ARTIFACTS_HASH": -551144757, + "__RESOLVED_ARTIFACTS_HASH": 185108218, "conflict_resolution": { "com.google.code.gson:gson:2.8.9": "com.google.code.gson:gson:2.10.1", "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.23.0", @@ -174,10 +174,10 @@ }, "com.github.ben-manes.caffeine:caffeine": { "shasums": { - "jar": "1e0a7bbef1dd791653143f3f05d0e489934bf5481e58a87c9e619cd46b68729b", - "sources": "9c70fa3874ad26bca1e071b7eb69a96d37f6d544eda743b4b00ea050f377b0d0" + "jar": "7dd15f9df1be238ffaa367ce6f556737a88031de4294dad18eef57c474ddf1d3", + "sources": "7c8237f5d8f23654e7091056316a3730636b7a0f2e6fce450e2bd522090d6b7f" }, - "version": "2.9.3" + "version": "3.1.8" }, "com.github.docker-java:docker-java-api": { "shasums": { @@ -6026,8 +6026,6 @@ "com.flipkart.zjsonpatch" ], "com.github.ben-manes.caffeine:caffeine": [ - "com.github.benmanes.caffeine", - "com.github.benmanes.caffeine.base", "com.github.benmanes.caffeine.cache", "com.github.benmanes.caffeine.cache.stats" ], diff --git a/src/main/k8s/reporting_v2.cue b/src/main/k8s/reporting_v2.cue index 5927eb4818d..9abca010015 100644 --- a/src/main/k8s/reporting_v2.cue +++ b/src/main/k8s/reporting_v2.cue @@ -20,6 +20,8 @@ package k8s _reportSchedulingCronSchedule: string | *"30 6 * * *" // Daily at 6:30 AM + _certificateCacheExpirationDuration: string | *"60m" + _postgresConfig: #PostgresConfig _internalApiTarget: #GrpcTarget & { @@ -122,6 +124,7 @@ package k8s "--port=8443", "--health-port=8080", "--event-group-metadata-descriptor-cache-duration=1h", + "--certificate-cache-expiration-duration=\(_certificateCacheExpirationDuration)", ] + _tlsArgs + _internalApiTarget.args + _kingdomApiTarget.args spec: template: spec: { diff --git a/src/main/kotlin/org/wfanet/measurement/integration/common/reporting/v2/InProcessReportingServer.kt b/src/main/kotlin/org/wfanet/measurement/integration/common/reporting/v2/InProcessReportingServer.kt index 0d1fd80c315..129eaa8fe54 100644 --- a/src/main/kotlin/org/wfanet/measurement/integration/common/reporting/v2/InProcessReportingServer.kt +++ b/src/main/kotlin/org/wfanet/measurement/integration/common/reporting/v2/InProcessReportingServer.kt @@ -219,7 +219,9 @@ class InProcessReportingServer( SecureRandom(), signingPrivateKeyDir, trustedCertificates, + Duration.ofMinutes(60), Dispatchers.IO, + Dispatchers.Default, ) .withMetadataPrincipalIdentities(measurementConsumerConfigs), ReportingSetsService(internalReportingSetsClient) diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/job/ReportSchedulingJobExecutor.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/job/ReportSchedulingJobExecutor.kt index 970413f5973..f7402017f1e 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/job/ReportSchedulingJobExecutor.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/job/ReportSchedulingJobExecutor.kt @@ -122,7 +122,9 @@ private fun run( SecureRandom(), v2AlphaFlags.signingPrivateKeyStoreDir, commonServerFlags.tlsFlags.signingCerts.trustedCertificates, + Duration.ofMinutes(60), Dispatchers.IO, + Dispatchers.Default, ) val inProcessMetricsServerName = InProcessServerBuilder.generateName() diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/server/V2AlphaPublicApiServer.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/server/V2AlphaPublicApiServer.kt index 88215cffa51..acf7f1ae2b7 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/server/V2AlphaPublicApiServer.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/common/server/V2AlphaPublicApiServer.kt @@ -186,7 +186,9 @@ private fun run( SecureRandom(), v2AlphaFlags.signingPrivateKeyStoreDir, commonServerFlags.tlsFlags.signingCerts.trustedCertificates, + v2AlphaPublicServerFlags.certificateCacheExpirationDuration, Dispatchers.IO, + Dispatchers.Default, ) val inProcessExecutorService: ExecutorService = @@ -269,4 +271,12 @@ private class V2AlphaPublicServerFlags { ) lateinit var authorityKeyIdentifierToPrincipalMapFile: File private set + + @CommandLine.Option( + names = ["--certificate-cache-expiration-duration"], + description = ["Duration to mark cache entries as expired in format 1d1h1m1s1ms1ns"], + required = true, + ) + lateinit var certificateCacheExpirationDuration: Duration + private set } diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/BUILD.bazel b/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/BUILD.bazel index a646cdb463c..22d6343b537 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/BUILD.bazel +++ b/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/BUILD.bazel @@ -205,7 +205,9 @@ kt_jvm_library( "//src/main/proto/wfa/measurement/reporting/v2alpha:metrics_service_kt_jvm_grpc_proto", "//src/main/proto/wfa/measurement/reporting/v2alpha:page_token_kt_jvm_proto", "//src/main/proto/wfa/measurement/reporting/v2alpha:reporting_sets_service_kt_jvm_grpc_proto", + "@wfa_common_jvm//imports/java/com/github/benmanes/caffeine", "@wfa_common_jvm//imports/java/com/google/protobuf/util", + "@wfa_common_jvm//imports/kotlin/kotlinx/coroutines:core", "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/common", "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/common/crypto:security_provider", "@wfa_common_jvm//src/main/kotlin/org/wfanet/measurement/common/grpc", diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsService.kt b/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsService.kt index cd73b086976..8c76fdf5467 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsService.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsService.kt @@ -16,14 +16,16 @@ package org.wfanet.measurement.reporting.service.api.v2alpha +import com.github.benmanes.caffeine.cache.Caffeine import com.google.protobuf.Any as ProtoAny import com.google.protobuf.ByteString -import com.google.protobuf.Duration +import com.google.protobuf.Duration as ProtoDuration import com.google.protobuf.duration import com.google.protobuf.kotlin.unpack import com.google.protobuf.util.Durations import io.grpc.Status import io.grpc.StatusException +import io.grpc.StatusRuntimeException import java.io.File import java.lang.IllegalStateException import java.security.PrivateKey @@ -31,13 +33,17 @@ import java.security.SecureRandom import java.security.SignatureException import java.security.cert.CertPathValidatorException import java.security.cert.X509Certificate +import java.time.Duration import java.util.concurrent.TimeUnit +import kotlin.coroutines.ContinuationInterceptor import kotlin.coroutines.CoroutineContext import kotlin.math.max import kotlin.math.min import kotlin.math.sqrt +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.coroutineScope @@ -47,6 +53,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withContext import org.jetbrains.annotations.BlockingExecutor +import org.jetbrains.annotations.NonBlockingExecutor import org.wfanet.measurement.api.v2alpha.BatchCreateMeasurementsResponse import org.wfanet.measurement.api.v2alpha.BatchGetMeasurementsResponse import org.wfanet.measurement.api.v2alpha.Certificate @@ -80,6 +87,7 @@ import org.wfanet.measurement.api.v2alpha.measurementSpec import org.wfanet.measurement.api.v2alpha.requisitionSpec import org.wfanet.measurement.api.v2alpha.unpack import org.wfanet.measurement.api.withAuthenticationKey +import org.wfanet.measurement.common.LoadingCache import org.wfanet.measurement.common.base64UrlDecode import org.wfanet.measurement.common.base64UrlEncode import org.wfanet.measurement.common.crypto.Hashing @@ -215,7 +223,9 @@ class MetricsService( secureRandom: SecureRandom, signingPrivateKeyDir: File, trustedCertificates: Map, - coroutineContext: @BlockingExecutor CoroutineContext = Dispatchers.IO, + certificateCacheExpirationDuration: Duration = Duration.ofMinutes(60), + keyReaderContext: @BlockingExecutor CoroutineContext = Dispatchers.IO, + cacheLoaderContext: @NonBlockingExecutor CoroutineContext = Dispatchers.Default, ) : MetricsCoroutineImplBase() { private data class DataProviderInfo( @@ -236,7 +246,9 @@ class MetricsService( secureRandom, signingPrivateKeyDir, trustedCertificates, - coroutineContext, + certificateCacheExpirationDuration, + keyReaderContext, + cacheLoaderContext, ) private class MeasurementSupplier( @@ -250,8 +262,27 @@ class MetricsService( private val secureRandom: SecureRandom, private val signingPrivateKeyDir: File, private val trustedCertificates: Map, - private val coroutineContext: @BlockingExecutor CoroutineContext = Dispatchers.IO, + certificateCacheExpirationDuration: Duration, + private val keyReaderContext: @BlockingExecutor CoroutineContext = Dispatchers.IO, + cacheLoaderContext: @NonBlockingExecutor CoroutineContext = Dispatchers.Default, ) { + private data class ResourceNameApiAuthenticationKey( + val name: String, + val apiAuthenticationKey: String, + ) + + private val certificateCache: LoadingCache = + LoadingCache( + Caffeine.newBuilder() + .expireAfterWrite(certificateCacheExpirationDuration) + .executor( + (cacheLoaderContext[ContinuationInterceptor] as CoroutineDispatcher).asExecutor() + ) + .buildAsync() + ) { key -> + getCertificate(name = key.name, apiAuthenticationKey = key.apiAuthenticationKey) + } + /** * Creates CMM public [Measurement]s and [InternalMeasurement]s from a list of [InternalMetric]. */ @@ -300,6 +331,8 @@ class MetricsService( val dataProviderInfoMap: Map = buildDataProviderInfoMap(principal.config.apiKey, dataProviderNames) + val measurementConsumerSigningKey = getMeasurementConsumerSigningKey(principal) + val cmmsCreateMeasurementRequests: List = internalMetricsList.flatMap { internalMetric -> internalMetric.weightedMeasurementsList @@ -312,6 +345,7 @@ class MetricsService( measurementConsumer, principal, dataProviderInfoMap, + measurementConsumerSigningKey, ) } } @@ -405,18 +439,17 @@ class MetricsService( } /** Builds a CMMS [CreateMeasurementRequest]. */ - private suspend fun buildCreateMeasurementRequest( + private fun buildCreateMeasurementRequest( internalMeasurement: InternalMeasurement, metricSpec: InternalMetricSpec, internalPrimitiveReportingSetMap: Map, measurementConsumer: MeasurementConsumer, principal: MeasurementConsumerPrincipal, dataProviderInfoMap: Map, + measurementConsumerSigningKey: SigningKeyHandle, ): CreateMeasurementRequest { val eventGroupEntriesByDataProvider = groupEventGroupEntriesByDataProvider(internalMeasurement, internalPrimitiveReportingSetMap) - - val measurementConsumerSigningKey = getMeasurementConsumerSigningKey(principal) val packedMeasurementEncryptionPublicKey = measurementConsumer.publicKey.message return createMeasurementRequest { @@ -454,7 +487,7 @@ class MetricsService( ): SigningKeyHandle { // TODO: Factor this out to a separate class similar to EncryptionKeyPairStore. val signingPrivateKeyDer: ByteString = - withContext(coroutineContext) { + withContext(keyReaderContext) { signingPrivateKeyDir.resolve(principal.config.signingPrivateKeyPath).readByteString() } val measurementConsumerCertificate: X509Certificate = @@ -533,23 +566,14 @@ class MetricsService( .asRuntimeException() } - val certificate: Certificate = - try { - certificatesStub - .withAuthenticationKey(apiAuthenticationKey) - .getCertificate(getCertificateRequest { name = dataProvider.certificate }) - } catch (e: StatusException) { - throw when (e.status.code) { - Status.Code.NOT_FOUND -> - Status.NOT_FOUND.withDescription("${dataProvider.certificate} not found.") - else -> - Status.UNKNOWN.withDescription( - "Unable to retrieve Certificate ${dataProvider.certificate}." - ) - } - .withCause(e) - .asRuntimeException() - } + val certificate = + certificateCache.getValue( + ResourceNameApiAuthenticationKey( + name = dataProvider.certificate, + apiAuthenticationKey = apiAuthenticationKey, + ) + ) + if ( certificate.revocationState != Certificate.RevocationState.REVOCATION_STATE_UNSPECIFIED @@ -731,28 +755,15 @@ class MetricsService( private suspend fun getSigningCertificateDer( principal: MeasurementConsumerPrincipal ): ByteString { - // TODO: Replace this with caching certificates or having them stored alongside the private - // key. - return try { - certificatesStub - .withAuthenticationKey(principal.config.apiKey) - .getCertificate(getCertificateRequest { name = principal.config.signingCertificateName }) - .x509Der - } catch (e: StatusException) { - throw when (e.status.code) { - Status.Code.NOT_FOUND -> - Status.NOT_FOUND.withDescription( - "${principal.config.signingCertificateName} not found." - ) - else -> - Status.UNKNOWN.withDescription( - "Unable to retrieve the signing certificate " + - "[${principal.config.signingCertificateName}] for the measurement consumer." - ) - } - .withCause(e) - .asRuntimeException() - } + val certificate = + certificateCache.getValue( + ResourceNameApiAuthenticationKey( + name = principal.config.signingCertificateName, + apiAuthenticationKey = principal.config.apiKey, + ) + ) + + return certificate.x509Der } /** @@ -992,31 +1003,24 @@ class MetricsService( encryptionPrivateKeyHandle: PrivateKeyHandle, apiAuthenticationKey: String, ): Measurement.Result { - // TODO: Cache the certificate val certificate = - try { - certificatesStub - .withAuthenticationKey(apiAuthenticationKey) - .getCertificate(getCertificateRequest { name = measurementResultOutput.certificate }) - } catch (e: StatusException) { - throw when (e.status.code) { - Status.Code.NOT_FOUND -> - Status.NOT_FOUND.withDescription( - "${measurementResultOutput.certificate} not found." - ) - else -> - Status.UNKNOWN.withDescription( - "Unable to retrieve the certificate " + - "[${measurementResultOutput.certificate}] for the measurement consumer." - ) - } - .withCause(e) - .asRuntimeException() - } + certificateCache.getValue( + ResourceNameApiAuthenticationKey( + name = measurementResultOutput.certificate, + apiAuthenticationKey = apiAuthenticationKey, + ) + ) val signedResult = decryptResult(measurementResultOutput.encryptedResult, encryptionPrivateKeyHandle) + if (certificate.revocationState != Certificate.RevocationState.REVOCATION_STATE_UNSPECIFIED) { + throw Status.FAILED_PRECONDITION.withDescription( + "${certificate.name} revocation state is ${certificate.revocationState}" + ) + .asRuntimeException() + } + val x509Certificate: X509Certificate = readCertificate(certificate.x509Der) val trustedIssuer: X509Certificate = checkNotNull(trustedCertificates[checkNotNull(x509Certificate.authorityKeyIdentifier)]) { @@ -1033,6 +1037,30 @@ class MetricsService( } return signedResult.unpack() } + + /** + * Returns the [Certificate] from the CMMS system. + * + * @param[name] resource name of the [Certificate] + * @param[apiAuthenticationKey] API key to act as the [MeasurementConsumer] client + * @throws [StatusRuntimeException] with [Status.FAILED_PRECONDITION] when retrieving the + * [Certificate] fails. + */ + private suspend fun getCertificate(name: String, apiAuthenticationKey: String): Certificate { + return try { + certificatesStub + .withAuthenticationKey(apiAuthenticationKey) + .getCertificate(getCertificateRequest { this.name = name }) + } catch (e: StatusException) { + throw when (e.status.code) { + Status.Code.NOT_FOUND -> + Status.FAILED_PRECONDITION.withDescription("Certificate $name not found.") + else -> Status.UNKNOWN.withDescription("Unable to retrieve Certificate $name.") + } + .withCause(e) + .asRuntimeException() + } + } } override suspend fun getMetric(request: GetMetricRequest): Metric { @@ -1728,7 +1756,7 @@ private fun calculateWatchDurationResult( } } return watchDurationResult { - val watchDuration: Duration = + val watchDuration: ProtoDuration = weightedMeasurements .map { weightedMeasurement -> aggregateResults(weightedMeasurement.measurement.details.resultsList) @@ -1791,8 +1819,8 @@ private fun calculatePopulationResult( return populationCountResult { value = populationResult.population.value } } -/** Converts [Duration] format to [Double] second. */ -private fun Duration.toDoubleSecond(): Double { +/** Converts [ProtoDuration] format to [Double] second. */ +private fun ProtoDuration.toDoubleSecond(): Double { val source = this return source.seconds + (source.nanos.toDouble() / NANOS_PER_SECOND) } @@ -2470,7 +2498,7 @@ fun buildStatsMethodology(reachResult: InternalMeasurement.Result.Reach): Method } } -private operator fun Duration.times(weight: Int): Duration { +private operator fun ProtoDuration.times(weight: Int): ProtoDuration { val source = this return duration { val weightedTotalNanos: Long = @@ -2480,7 +2508,7 @@ private operator fun Duration.times(weight: Int): Duration { } } -private operator fun Duration.plus(other: Duration): Duration { +private operator fun ProtoDuration.plus(other: ProtoDuration): ProtoDuration { return Durations.add(this, other) } diff --git a/src/test/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsServiceTest.kt b/src/test/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsServiceTest.kt index e219795d383..65177023a46 100644 --- a/src/test/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsServiceTest.kt +++ b/src/test/kotlin/org/wfanet/measurement/reporting/service/api/v2alpha/MetricsServiceTest.kt @@ -3957,6 +3957,49 @@ class MetricsServiceTest { assertThat(exception).hasMessageThat().contains("dataProviders/") } + @Test + fun `createMetric throws UNKNOWN when getCertificate throws UNKNOWN`() = runBlocking { + whenever(certificatesMock.getCertificate(any())) + .thenThrow(StatusRuntimeException(Status.UNKNOWN)) + + val request = createMetricRequest { + parent = MEASUREMENT_CONSUMERS.values.first().name + metric = REQUESTING_INCREMENTAL_REACH_METRIC + metricId = "metric-id" + } + + val exception = + assertFailsWith { + withMeasurementConsumerPrincipal(MEASUREMENT_CONSUMERS.values.first().name, CONFIG) { + runBlocking { service.createMetric(request) } + } + } + assertThat(exception.status.code).isEqualTo(Status.Code.UNKNOWN) + assertThat(exception).hasMessageThat().contains("certificates/") + } + + @Test + fun `createMetric throws FAILED_PRECONDITION when getCertificate throws NOT_FOUND`() = + runBlocking { + whenever(certificatesMock.getCertificate(any())) + .thenThrow(StatusRuntimeException(Status.NOT_FOUND)) + + val request = createMetricRequest { + parent = MEASUREMENT_CONSUMERS.values.first().name + metric = REQUESTING_INCREMENTAL_REACH_METRIC + metricId = "metric-id" + } + + val exception = + assertFailsWith { + withMeasurementConsumerPrincipal(MEASUREMENT_CONSUMERS.values.first().name, CONFIG) { + runBlocking { service.createMetric(request) } + } + } + assertThat(exception.status.code).isEqualTo(Status.Code.FAILED_PRECONDITION) + assertThat(exception).hasMessageThat().contains("certificates/") + } + @Test fun `batchCreateMetrics creates CMMS measurements`() = runBlocking { val request = batchCreateMetricsRequest { @@ -5481,6 +5524,46 @@ class MetricsServiceTest { ) } + @Test + fun `getMetric throws FAILED_PRECONDITION when measurements SUCCEEDED but EDP cert is revoked`() = + runBlocking { + whenever(measurementsMock.batchGetMeasurements(any())).thenAnswer { + val batchGetMeasurementsRequest = it.arguments[0] as BatchGetMeasurementsRequest + val measurementsMap = + mapOf( + SUCCEEDED_UNION_ALL_REACH_MEASUREMENT.name to SUCCEEDED_UNION_ALL_REACH_MEASUREMENT, + SUCCEEDED_UNION_ALL_BUT_LAST_PUBLISHER_REACH_MEASUREMENT.name to + SUCCEEDED_UNION_ALL_BUT_LAST_PUBLISHER_REACH_MEASUREMENT, + PENDING_SINGLE_PUBLISHER_IMPRESSION_MEASUREMENT.name to + PENDING_SINGLE_PUBLISHER_IMPRESSION_MEASUREMENT, + ) + batchGetMeasurementsResponse { + measurements += + batchGetMeasurementsRequest.namesList.map { name -> measurementsMap.getValue(name) } + } + } + + val dataProvider = DATA_PROVIDERS.values.first() + whenever(certificatesMock.getCertificate(any())) + .thenReturn( + certificate { + name = dataProvider.certificate + x509Der = DATA_PROVIDER_SIGNING_KEY.certificate.encoded.toByteString() + revocationState = Certificate.RevocationState.REVOKED + } + ) + val request = getMetricRequest { name = PENDING_CROSS_PUBLISHER_WATCH_DURATION_METRIC.name } + + val exception = + assertFailsWith { + withMeasurementConsumerPrincipal(MEASUREMENT_CONSUMERS.values.first().name, CONFIG) { + runBlocking { service.getMetric(request) } + } + } + + assertThat(exception).hasMessageThat().ignoringCase().contains("revoked") + } + @Test fun `getMetric throw StatusRuntimeException when variance type in custom methodology is unspecified`() = runBlocking {