From 3a9d442b88a330be6458865c910356661fec726c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20=C3=81lvarez=20=C3=81lvarez?= Date: Tue, 15 Jul 2025 13:25:53 +0200 Subject: [PATCH 1/8] Fix NPE in AppSecConfigServiceImpl (#9172) (cherry picked from commit 9a188f8669cab5d4a4065d3cc98c482ac8517206) --- .../config/AppSecConfigServiceImpl.java | 33 +++++----- .../appsec/config/MergedAsmFeatures.java | 5 ++ ...ppSecConfigServiceImplSpecification.groovy | 61 +++++++++++++++++++ 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java index 51e5f07187b..880b6c45528 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/AppSecConfigServiceImpl.java @@ -75,8 +75,7 @@ public class AppSecConfigServiceImpl implements AppSecConfigService { private final ConfigurationPoller configurationPoller; private WafBuilder wafBuilder; - private MergedAsmFeatures mergedAsmFeatures; - private volatile boolean initialized; + private final MergedAsmFeatures mergedAsmFeatures = new MergedAsmFeatures(); private final ConcurrentHashMap subconfigListeners = new ConcurrentHashMap<>(); @@ -173,9 +172,7 @@ private class AppSecConfigChangesListener implements ProductListener { @Override public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollingRateHinter) throws IOException { - if (!initialized) { - throw new IllegalStateException(); - } + maybeInitializeDefaultConfig(); if (content == null) { try { @@ -219,8 +216,8 @@ public void accept(ConfigKey configKey, byte[] content, PollingRateHinter pollin } defaultConfigActivated = false; } - super.accept(configKey, content, pollingRateHinter); usedDDWafConfigKeys.add(configKey.toString()); + super.accept(configKey, content, pollingRateHinter); } @Override @@ -282,13 +279,7 @@ private void subscribeAsmFeatures() { Product.ASM_FEATURES, AppSecFeaturesDeserializer.INSTANCE, (configKey, newConfig, hinter) -> { - if (!hasUserWafConfig && !defaultConfigActivated) { - // features activated in runtime - init(); - } - if (!initialized) { - throw new IllegalStateException(); - } + maybeInitializeDefaultConfig(); if (newConfig == null) { mergedAsmFeatures.removeConfig(configKey); } else { @@ -305,10 +296,7 @@ private void subscribeAsmFeatures() { private void distributeSubConfigurations( String key, AppSecModuleConfigurer.Reconfiguration reconfiguration) { - if (usedDDWafConfigKeys.isEmpty() && !defaultConfigActivated && !hasUserWafConfig) { - // no config left in the WAF builder, add the default config - init(); - } + maybeInitializeDefaultConfig(); for (Map.Entry entry : subconfigListeners.entrySet()) { SubconfigListener listener = entry.getValue(); try { @@ -320,6 +308,13 @@ private void distributeSubConfigurations( } } + private void maybeInitializeDefaultConfig() { + if (usedDDWafConfigKeys.isEmpty() && !hasUserWafConfig && !defaultConfigActivated) { + // no config left in the WAF builder, add the default config + init(); + } + } + @Override public void init() { Map wafConfig; @@ -341,8 +336,8 @@ public void init() { } else { hasUserWafConfig = true; } - this.mergedAsmFeatures = new MergedAsmFeatures(); - this.initialized = true; + this.mergedAsmFeatures.clear(); + this.usedDDWafConfigKeys.clear(); if (wafConfig.isEmpty()) { throw new IllegalStateException("Expected default waf config to be available"); diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/MergedAsmFeatures.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/MergedAsmFeatures.java index 87ea4af0dbe..070c6056b1e 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/MergedAsmFeatures.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/config/MergedAsmFeatures.java @@ -49,4 +49,9 @@ private void mergeAutoUserInstrum( } target.autoUserInstrum = newValue; } + + public void clear() { + mergedData = null; + configs.clear(); + } } diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy index bf034235805..07fcae0da20 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/config/AppSecConfigServiceImplSpecification.groovy @@ -759,6 +759,67 @@ class AppSecConfigServiceImplSpecification extends DDSpecification { p.toFile().delete() } + // https://github.com/DataDog/dd-trace-java/issues/9159 + void 'test initialization issues while applying remote config'() { + setup: + final key = new ParsedConfigKey('Test', '1234', 1, 'ASM_DD', 'ID') + final service = new AppSecConfigServiceImpl(config, poller, reconf) + config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE + + when: + service.maybeSubscribeConfigPolling() + + then: + 1 * poller.addListener(Product.ASM_DD, _) >> { + listeners.savedWafDataChangesListener = it[1] + } + + when: + listeners.savedWafDataChangesListener.accept(key, '''{"rules_override": [{"rules_target": [{"rule_id": "foo"}], "enabled": false}]}'''.getBytes(), NOOP) + + then: + noExceptionThrown() + } + + void 'config keys are added and removed to the set when receiving ASM_DD payloads'() { + setup: + final key = new ParsedConfigKey('Test', '1234', 1, 'ASM_DD', 'ID') + final service = new AppSecConfigServiceImpl(config, poller, reconf) + config.getAppSecActivation() >> ProductActivation.ENABLED_INACTIVE + + when: + service.maybeSubscribeConfigPolling() + + then: + 1 * poller.addListener(Product.ASM_DD, _) >> { + listeners.savedWafDataChangesListener = it[1] + } + 1 * poller.addListener(Product.ASM_FEATURES, _, _) >> { + listeners.savedFeaturesDeserializer = it[1] + listeners.savedFeaturesListener = it[2] + } + + when: + listeners.savedFeaturesListener.accept('asm_features conf', + listeners.savedFeaturesDeserializer.deserialize('{"asm":{"enabled": true}}'.bytes), + NOOP) + + then: + service.usedDDWafConfigKeys.empty + + when: + listeners.savedWafDataChangesListener.accept(key, '''{"rules_override": [{"rules_target": [{"rule_id": "foo"}], "enabled": false}]}'''.getBytes(), NOOP) + + then: + service.usedDDWafConfigKeys.toList() == [key.toString()] + + when: + listeners.savedWafDataChangesListener.remove(key, NOOP) + + then: + service.usedDDWafConfigKeys.empty + } + private static AppSecFeatures autoUserInstrum(String mode) { return new AppSecFeatures().tap { features -> features.autoUserInstrum = new AppSecFeatures.AutoUserInstrum().tap { instrum -> From f7e20c74fc18cb5142e97f3451a2385f92392b9b Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 15 Jul 2025 15:27:17 +0200 Subject: [PATCH 2/8] Avoid race conditions and multiple agent discovery feature states (#9175) --- .../ddagent/SharedCommunicationObjects.java | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java index 894a9809e44..b17a94a9d05 100644 --- a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java +++ b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java @@ -30,7 +30,7 @@ public class SharedCommunicationObjects { public OkHttpClient okHttpClient; public HttpUrl agentUrl; public Monitoring monitoring; - private DDAgentFeaturesDiscovery featuresDiscovery; + private volatile DDAgentFeaturesDiscovery featuresDiscovery; private ConfigurationPoller configurationPoller; public SharedCommunicationObjects() { @@ -139,28 +139,34 @@ public void setFeaturesDiscovery(DDAgentFeaturesDiscovery featuresDiscovery) { } public DDAgentFeaturesDiscovery featuresDiscovery(Config config) { - if (featuresDiscovery == null) { - createRemaining(config); - featuresDiscovery = - new DDAgentFeaturesDiscovery( - okHttpClient, - monitoring, - agentUrl, - config.isTraceAgentV05Enabled(), - config.isTracerMetricsEnabled()); - - if (paused) { - // defer remote discovery until remote I/O is allowed - } else { - if (AGENT_THREAD_GROUP.equals(Thread.currentThread().getThreadGroup())) { - featuresDiscovery.discover(); // safe to run on same thread - } else { - // avoid performing blocking I/O operation on application thread - AgentTaskScheduler.INSTANCE.execute(featuresDiscovery::discover); + DDAgentFeaturesDiscovery ret = featuresDiscovery; + if (ret == null) { + synchronized (this) { + if (featuresDiscovery == null) { + createRemaining(config); + ret = + new DDAgentFeaturesDiscovery( + okHttpClient, + monitoring, + agentUrl, + config.isTraceAgentV05Enabled(), + config.isTracerMetricsEnabled()); + + if (paused) { + // defer remote discovery until remote I/O is allowed + } else { + if (AGENT_THREAD_GROUP.equals(Thread.currentThread().getThreadGroup())) { + ret.discover(); // safe to run on same thread + } else { + // avoid performing blocking I/O operation on application thread + AgentTaskScheduler.INSTANCE.execute(ret::discover); + } + } + featuresDiscovery = ret; } } } - return featuresDiscovery; + return ret; } private static final class FixedConfigUrlSupplier implements Supplier { From ce41a215983ce8e477f2a8046cd65e25bda66d84 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 15 Jul 2025 17:43:58 +0200 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=8D=92=20Avoid=20race=20conditions=20?= =?UTF-8?q?on=20feature=20discovery=20during=20Writer=20creation=20(#9177)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: avoid race conditions on feature discovery (cherry picked from commit ff2c775d8c44dbd393f2d609f02086edc1c83115) * commit suggestion Co-authored-by: Nikita Tkachenko <121111529+nikita-tkachenko-datadog@users.noreply.github.com> (cherry picked from commit a304e949af555867e5fbad62684fef1a7ebeaaa4) * fix: spotless and issue with groovy mocking (cherry picked from commit 4e880c76b9e23a4c2db71789f867252ebeedab2c) --------- Co-authored-by: Nikita Tkachenko <121111529+nikita-tkachenko-datadog@users.noreply.github.com> --- .../ddagent/SharedCommunicationObjects.java | 2 +- .../trace/common/writer/WriterFactory.java | 3 + .../java/datadog/trace/core/CoreTracer.java | 14 +++-- .../common/writer/WriterFactoryTest.groovy | 59 ++++++++++++++++--- 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java index b17a94a9d05..b855731bc08 100644 --- a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java +++ b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java @@ -159,7 +159,7 @@ public DDAgentFeaturesDiscovery featuresDiscovery(Config config) { ret.discover(); // safe to run on same thread } else { // avoid performing blocking I/O operation on application thread - AgentTaskScheduler.INSTANCE.execute(ret::discover); + AgentTaskScheduler.INSTANCE.execute(ret::discoverIfOutdated); } } featuresDiscovery = ret; diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java index baa55d5dbf1..a3244fc3768 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java @@ -86,6 +86,7 @@ public static Writer createWriter( // The AgentWriter doesn't support the CI Visibility protocol. If CI Visibility is // enabled, check if we can use the IntakeWriter instead. if (DD_AGENT_WRITER_TYPE.equals(configuredType) && (config.isCiVisibilityEnabled())) { + featuresDiscovery.discoverIfOutdated(); if (featuresDiscovery.supportsEvpProxy() || config.isCiVisibilityAgentlessEnabled()) { configuredType = DD_INTAKE_WRITER_TYPE; } else { @@ -94,6 +95,7 @@ public static Writer createWriter( } } if (DD_AGENT_WRITER_TYPE.equals(configuredType) && (config.isLlmObsEnabled())) { + featuresDiscovery.discoverIfOutdated(); if (featuresDiscovery.supportsEvpProxy() || config.isLlmObsAgentlessEnabled()) { configuredType = DD_INTAKE_WRITER_TYPE; } else { @@ -186,6 +188,7 @@ private static RemoteApi createDDIntakeRemoteApi( SharedCommunicationObjects commObjects, DDAgentFeaturesDiscovery featuresDiscovery, TrackType trackType) { + featuresDiscovery.discoverIfOutdated(); boolean evpProxySupported = featuresDiscovery.supportsEvpProxy(); boolean useProxyApi = (evpProxySupported && TrackType.LLMOBS == trackType && !config.isLlmObsAgentlessEnabled()) diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 28ba0832e30..498c8a9c27d 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -669,9 +669,16 @@ private CoreTracer( this.writer = writer; } + DDAgentFeaturesDiscovery featuresDiscovery = + sharedCommunicationObjects.featuresDiscovery(config); + + if (config.isCiVisibilityEnabled()) { + // ensure updated discovery and sync if the another discovery currently being done + featuresDiscovery.discoverIfOutdated(); + } + if (config.isCiVisibilityEnabled() - && (config.isCiVisibilityAgentlessEnabled() - || sharedCommunicationObjects.featuresDiscovery(config).supportsEvpProxy())) { + && (config.isCiVisibilityAgentlessEnabled() || featuresDiscovery.supportsEvpProxy())) { pendingTraceBuffer = PendingTraceBuffer.discarding(); traceCollectorFactory = new StreamingTraceCollector.Factory(this, this.timeSource, healthMetrics); @@ -732,8 +739,7 @@ private CoreTracer( if (config.isCiVisibilityAgentlessEnabled()) { addTraceInterceptor(DDIntakeTraceInterceptor.INSTANCE); } else { - DDAgentFeaturesDiscovery featuresDiscovery = - sharedCommunicationObjects.featuresDiscovery(config); + featuresDiscovery.discoverIfOutdated(); if (!featuresDiscovery.supportsEvpProxy()) { // CI Test Cycle protocol is not available addTraceInterceptor(CiVisibilityApmProtocolInterceptor.INSTANCE); diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy index e3d9ce9c427..926ec81907a 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy @@ -1,5 +1,7 @@ package datadog.trace.common.writer +import static datadog.trace.api.config.TracerConfig.PRIORITIZATION_TYPE + import datadog.communication.ddagent.DDAgentFeaturesDiscovery import datadog.communication.ddagent.SharedCommunicationObjects import datadog.trace.api.Config @@ -10,10 +12,16 @@ import datadog.trace.common.writer.ddintake.DDEvpProxyApi import datadog.trace.common.writer.ddintake.DDIntakeApi import datadog.trace.core.monitor.HealthMetrics import datadog.trace.test.util.DDSpecification - +import groovy.json.JsonBuilder import java.util.stream.Collectors - -import static datadog.trace.api.config.TracerConfig.PRIORITIZATION_TYPE +import okhttp3.Call +import okhttp3.HttpUrl +import okhttp3.MediaType +import okhttp3.OkHttpClient +import okhttp3.Protocol +import okhttp3.Request +import okhttp3.Response +import okhttp3.ResponseBody class WriterFactoryTest extends DDSpecification { @@ -27,19 +35,30 @@ class WriterFactoryTest extends DDSpecification { config.isCiVisibilityEnabled() >> true config.isCiVisibilityCodeCoverageEnabled() >> false - def agentFeaturesDiscovery = Mock(DDAgentFeaturesDiscovery) - agentFeaturesDiscovery.getEvpProxyEndpoint() >> DDAgentFeaturesDiscovery.V2_EVP_PROXY_ENDPOINT - agentFeaturesDiscovery.supportsContentEncodingHeadersWithEvpProxy() >> evpProxySupportsCompression + // Mock agent info response + def response = buildHttpResponse(hasEvpProxy, evpProxySupportsCompression, HttpUrl.parse(config.agentUrl + "/info")) + + // Mock HTTP client that simulates delayed response for async feature discovery + def mockCall = Mock(Call) + def mockHttpClient = Mock(OkHttpClient) + mockCall.execute() >> { + // Add a delay + sleep(400) + return response + } + mockHttpClient.newCall(_ as Request) >> mockCall + // Create SharedCommunicationObjects with mocked HTTP client def sharedComm = new SharedCommunicationObjects() - sharedComm.setFeaturesDiscovery(agentFeaturesDiscovery) + sharedComm.okHttpClient = mockHttpClient + sharedComm.agentUrl = HttpUrl.parse(config.agentUrl) sharedComm.createRemaining(config) def sampler = Mock(Sampler) when: - agentFeaturesDiscovery.supportsEvpProxy() >> hasEvpProxy config.ciVisibilityAgentlessEnabled >> isCiVisibilityAgentlessEnabled + def writer = WriterFactory.createWriter(config, sharedComm, sampler, null, HealthMetrics.NO_OP, configuredType) def apis @@ -77,4 +96,28 @@ class WriterFactoryTest extends DDSpecification { "not-found" | false | false | true | DDIntakeWriter | [DDIntakeApi] | true "not-found" | false | false | false | DDAgentWriter | [DDAgentApi] | false } + + Response buildHttpResponse(boolean hasEvpProxy, boolean evpProxySupportsCompression, HttpUrl agentUrl) { + def endpoints = [] + if (hasEvpProxy && evpProxySupportsCompression) { + endpoints = [DDAgentFeaturesDiscovery.V4_EVP_PROXY_ENDPOINT] + } else if (hasEvpProxy) { + endpoints = [DDAgentFeaturesDiscovery.V2_EVP_PROXY_ENDPOINT] + } else { + endpoints = [DDAgentFeaturesDiscovery.V4_ENDPOINT] + } + + def response = [ + "version" : "7.40.0", + "endpoints" : endpoints, + ] + + def builder = new Response.Builder() + .code(200) + .message("OK") + .protocol(Protocol.HTTP_1_1) + .request(new Request.Builder().url(agentUrl.resolve("/info")).build()) + .body(ResponseBody.create(MediaType.parse("application/json"), new JsonBuilder(response).toString())) + return builder.build() + } } From dcad7a15ca337f4b75704f834443373d5d1977fb Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Wed, 16 Jul 2025 16:03:47 -0400 Subject: [PATCH 4/8] Add octo-sts policy (cherry picked from commit 7ae2a667a0b968e16367fee4123a3796f9fa911d) --- .github/chainguard/dd-trace-java.release.sts.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/chainguard/dd-trace-java.release.sts.yaml diff --git a/.github/chainguard/dd-trace-java.release.sts.yaml b/.github/chainguard/dd-trace-java.release.sts.yaml new file mode 100644 index 00000000000..a0f33f91054 --- /dev/null +++ b/.github/chainguard/dd-trace-java.release.sts.yaml @@ -0,0 +1,14 @@ +issuer: https://gitlab.ddbuild.io + +subject: repo:DataDog/dd-trace-java:ref:refs/heads/* ????? + +claim_pattern: + project_path: "DataDog/dd-trace-rb" + ref: "master" + ref_type: "branch" + ref_path: "refs/heads/master" + +permissions: + contents: + - read + - write From 753f8a1bd38da6ec54e8c295aec67996403871c4 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Wed, 16 Jul 2025 16:08:45 -0400 Subject: [PATCH 5/8] Add workflow and debugging (cherry picked from commit 3feedd7254031b0c82602572543770dbb1196a6f) --- .gitlab-ci.yml | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 47662f1b163..8fc2b0571a5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -797,6 +797,35 @@ deploy_to_sonatype: - 'workspace/dd-trace-api/build/libs/*.jar' - 'workspace/dd-trace-ot/build/libs/*.jar' +get_github_token: + stage: publish + image: registry.ddbuild.io/images/dd-octo-sts-ci-base:v68058725-73f34e7-2025.06-1 + tags: [ "arch:amd64" ] + + id_tokens: + DDOCTOSTS_ID_TOKEN: + aud: dd-octo-sts + + rules: + - if: '$POPULATE_CACHE' + when: never + - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' + when: on_success + + script: + - dd-octo-sts version + - dd-octo-sts debug --scope DataDog/dd-trace-java --policy dd-trace-java.release + - dd-octo-sts token --scope DataDog/dd-trace-java --policy dd-trace-java.release > github-token.txt + # DEBUG + - echo "Token file exists:" $(test -f github-token.txt && echo "YES" || echo "NO") + - echo "Token file size:" $(wc -c < github-token.txt) "bytes" + - echo "Token preview:" $(head -c 10 github-token.txt)... + + artifacts: + paths: + - github-token.txt + expire_in: 1 hour # tokens generated by dd-octo-sts only last for 1 hour + deploy_artifacts_to_github: stage: publish image: registry.ddbuild.io/github-cli:v27480869-eafb11d-2.43.0 @@ -811,16 +840,21 @@ deploy_artifacts_to_github: - job: deploy_to_sonatype # The deploy_to_sonatype job is not run for release candidate versions optional: true + - job: get_github_token + script: - - aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.gh_release_token --with-decryption --query "Parameter.Value" --out text > github-token.txt + # - aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.gh_release_token --with-decryption --query "Parameter.Value" --out text > github-token.txt + # Debug token reception + - echo "Token file exists:" $(test -f github-token.txt && echo "YES" || echo "NO") + - echo "Token file size:" $(wc -c < github-token.txt) "bytes" - gh auth login --with-token < github-token.txt - gh auth status # Maybe helpful to have this output in logs? - - export VERSION=${CI_COMMIT_TAG##v} # remove "v" from front of tag to get version - - cp workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar workspace/dd-java-agent/build/libs/dd-java-agent.jar # we upload two filenames - - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent.jar - - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar - - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-api/build/libs/dd-trace-api-${VERSION}.jar - - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-ot/build/libs/dd-trace-ot-${VERSION}.jar + # - export VERSION=${CI_COMMIT_TAG##v} # remove "v" from front of tag to get version + # - cp workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar workspace/dd-java-agent/build/libs/dd-java-agent.jar # we upload two filenames + # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent.jar + # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar + # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-api/build/libs/dd-trace-api-${VERSION}.jar + # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-ot/build/libs/dd-trace-ot-${VERSION}.jar retry: max: 2 when: always From 119e3f29909338d6b9eeeb760a75c73d7a001fb2 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Wed, 16 Jul 2025 16:11:18 -0400 Subject: [PATCH 6/8] Fix policy (cherry picked from commit 59d79267bad02d06c421cb5400bae3341c03fb97) --- .github/chainguard/dd-trace-java.release.sts.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/chainguard/dd-trace-java.release.sts.yaml b/.github/chainguard/dd-trace-java.release.sts.yaml index a0f33f91054..eba7c24fed9 100644 --- a/.github/chainguard/dd-trace-java.release.sts.yaml +++ b/.github/chainguard/dd-trace-java.release.sts.yaml @@ -1,14 +1,12 @@ issuer: https://gitlab.ddbuild.io -subject: repo:DataDog/dd-trace-java:ref:refs/heads/* ????? +subject: repo:DataDog/dd-trace-java:ref:refs/heads/master claim_pattern: - project_path: "DataDog/dd-trace-rb" + project_path: "DataDog/dd-trace-java" ref: "master" ref_type: "branch" ref_path: "refs/heads/master" permissions: - contents: - - read - - write + contents: "read,write" From de8e6c07f4e31a33336b593aee7f9b20e6835f55 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Wed, 16 Jul 2025 16:24:02 -0400 Subject: [PATCH 7/8] Run jobs in CI for now (cherry picked from commit 1bb367d772873854416fba80d9b0ec8f166142fa) --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fc2b0571a5..858b5c2fcdf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -809,8 +809,8 @@ get_github_token: rules: - if: '$POPULATE_CACHE' when: never - - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' - when: on_success + # - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' + # when: on_success script: - dd-octo-sts version From dfe64c5bf02518213db6230cc8945c7e37120008 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Tue, 22 Jul 2025 13:34:04 -0400 Subject: [PATCH 8/8] fix cherry pick --- .gitlab-ci.yml | 108 +++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 858b5c2fcdf..beb8cf875e6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,10 +25,10 @@ variables: BUILD_JOB_NAME: "build" DEPENDENCY_CACHE_POLICY: pull BUILD_CACHE_POLICY: pull - GRADLE_VERSION: "8.5" # must match gradle-wrapper.properties + GRADLE_VERSION: "8.14.3" # must match gradle-wrapper.properties MAVEN_REPOSITORY_PROXY: "http://artifactual.artifactual.all-clusters.local-dc.fabric.dog:8081/repository/maven-central/" GRADLE_PLUGIN_PROXY: "http://artifactual.artifactual.all-clusters.local-dc.fabric.dog:8081/repository/gradle-plugin-portal-proxy/" - BUILDER_IMAGE_VERSION_PREFIX: "v25.06-" # use either an empty string (e.g. "") for latest images or a version followed by a hyphen (e.g. "v25.05-") + BUILDER_IMAGE_VERSION_PREFIX: "v25.07-" # use either an empty string (e.g. "") for latest images or a version followed by a hyphen (e.g. "v25.05-") REPO_NOTIFICATION_CHANNEL: "#apm-java-escalations" DEFAULT_TEST_JVMS: /^(8|11|17|21|stable)$/ PROFILE_TESTS: @@ -137,9 +137,12 @@ default: KUBERNETES_MEMORY_REQUEST: 8Gi KUBERNETES_MEMORY_LIMIT: 8Gi CACHE_TYPE: lib #default + FF_USE_FASTZIP: "true" + CACHE_COMPRESSION_LEVEL: "slowest" + RUNTIME_AVAILABLE_PROCESSORS_OVERRIDE: 4 # Runtime.getRuntime().availableProcessors() returns incorrect or very high values in Kubernetes cache: - - key: '$CI_SERVER_VERSION-$CACHE_TYPE' # Dependencies cache. Reset the cache every time gitlab is upgraded. ~Every couple months + - key: dependency-$CACHE_TYPE # Dependencies cache paths: # Cached dependencies and wrappers for gradle - .gradle/wrapper @@ -148,8 +151,8 @@ default: policy: $DEPENDENCY_CACHE_POLICY unprotect: true fallback_keys: # Use fallback keys because all cache types are not populated. See note under: populate_dep_cache - - '$CI_SERVER_VERSION-base' - - '$CI_SERVER_VERSION-lib' + - 'dependency-base' + - 'dependency-lib' - key: $CI_PIPELINE_ID-$CACHE_TYPE # Incremental build cache. Shared by all jobs in the pipeline of the same type paths: - .gradle/caches/$GRADLE_VERSION @@ -188,6 +191,7 @@ default: after_script: - *cgroup_info +# TODO: Add a pre-release check to see if the dd-octo-sts token is working. # Checks and fail early if central credentials are incorrect, indeed, when a new token is generated # on the central publisher protal, it invalidates the old one. This checks prevents going further. # See https://datadoghq.atlassian.net/wiki/x/Oog5OgE @@ -200,11 +204,11 @@ pre-release-checks: allow_failure: false script: - | - SONATYPE_USERNAME=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_username --with-decryption --query "Parameter.Value" --out text) - SONATYPE_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_password --with-decryption --query "Parameter.Value" --out text) + MAVEN_CENTRAL_USERNAME=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_username --with-decryption --query "Parameter.Value" --out text) + MAVEN_CENTRAL_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_password --with-decryption --query "Parameter.Value" --out text) # See https://central.sonatype.org/publish/publish-portal-api/ # 15e0cbbb-deff-421e-9e02-296a24d0cada is deployment, any deployment id listed in central work, the idea is to check whether the token can authenticate - curl --request POST --include --fail https://central.sonatype.com/api/v1/publisher/status?id=15e0cbbb-deff-421e-9e02-296a24d0cada --header "Authorization: Bearer $(printf "$SONATYPE_USERNAME:$SONATYPE_PASSWORD" | base64)" + curl --request POST --include --fail https://central.sonatype.com/api/v1/publisher/status?id=15e0cbbb-deff-421e-9e02-296a24d0cada --header "Authorization: Bearer $(printf "$MAVEN_CENTRAL_USERNAME:$MAVEN_CENTRAL_PASSWORD" | base64)" if [ $? -ne 0 ]; then echo "Failed to authenticate against central. Check credentials, see https://datadoghq.atlassian.net/wiki/x/Oog5OgE" exit 1 @@ -768,8 +772,8 @@ deploy_to_di_backend:manual: UPSTREAM_COMMIT_AUTHOR: $CI_COMMIT_AUTHOR UPSTREAM_COMMIT_SHORT_SHA: $CI_COMMIT_SHORT_SHA -# If the deploy_to_sonatype job is re-run, re-trigger the deploy_artifacts_to_github job as well so that the artifacts match. -deploy_to_sonatype: +# If the deploy_to_maven_central job is re-run, re-trigger the deploy_artifacts_to_github job as well so that the artifacts match. +deploy_to_maven_central: extends: .gradle_build stage: publish needs: [ build ] @@ -786,8 +790,8 @@ deploy_to_sonatype: - when: manual allow_failure: true script: - - export SONATYPE_USERNAME=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_username --with-decryption --query "Parameter.Value" --out text) - - export SONATYPE_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_password --with-decryption --query "Parameter.Value" --out text) + - export MAVEN_CENTRAL_USERNAME=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_username --with-decryption --query "Parameter.Value" --out text) + - export MAVEN_CENTRAL_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.central_password --with-decryption --query "Parameter.Value" --out text) - export GPG_PRIVATE_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_private_key --with-decryption --query "Parameter.Value" --out text) - export GPG_PASSWORD=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.signing.gpg_passphrase --with-decryption --query "Parameter.Value" --out text) - ./gradlew -PbuildInfo.build.number=$CI_JOB_ID publishToSonatype closeSonatypeStagingRepository -PskipTests $GRADLE_ARGS @@ -797,64 +801,70 @@ deploy_to_sonatype: - 'workspace/dd-trace-api/build/libs/*.jar' - 'workspace/dd-trace-ot/build/libs/*.jar' -get_github_token: +deploy_artifacts_to_github: stage: publish - image: registry.ddbuild.io/images/dd-octo-sts-ci-base:v68058725-73f34e7-2025.06-1 + image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1 tags: [ "arch:amd64" ] - id_tokens: DDOCTOSTS_ID_TOKEN: aud: dd-octo-sts - rules: - if: '$POPULATE_CACHE' when: never - # - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' - # when: on_success - - script: + - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' + when: on_success + # Requires the deploy_to_maven_central job to have run first (the UP-TO-DATE gradle check across jobs is broken) + # This will deploy the artifacts built from the publishToSonatype task to the GitHub release + needs: + - job: deploy_to_maven_central + # The deploy_to_maven_central job is not run for release candidate versions + optional: true + before_script: + # Get token - dd-octo-sts version - - dd-octo-sts debug --scope DataDog/dd-trace-java --policy dd-trace-java.release - - dd-octo-sts token --scope DataDog/dd-trace-java --policy dd-trace-java.release > github-token.txt - # DEBUG - - echo "Token file exists:" $(test -f github-token.txt && echo "YES" || echo "NO") - - echo "Token file size:" $(wc -c < github-token.txt) "bytes" - - echo "Token preview:" $(head -c 10 github-token.txt)... - - artifacts: - paths: - - github-token.txt - expire_in: 1 hour # tokens generated by dd-octo-sts only last for 1 hour + - dd-octo-sts debug --scope DataDog/dd-trace-java --policy self.gitlab.release + - dd-octo-sts token --scope DataDog/dd-trace-java --policy self.gitlab.release > github-token.txt + script: + - gh auth login --with-token < github-token.txt + - gh auth status # Maybe helpful to have this output in logs? + - export VERSION=${CI_COMMIT_TAG##v} # remove "v" from front of tag to get version + - cp workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar workspace/dd-java-agent/build/libs/dd-java-agent.jar # we upload two filenames + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-api/build/libs/dd-trace-api-${VERSION}.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-ot/build/libs/dd-trace-ot-${VERSION}.jar + after_script: + - dd-octo-sts revoke -t $(cat github-token.txt) + retry: + max: 2 + when: always -deploy_artifacts_to_github: +# This is the original job that uses the AWS SSM token retrieval method. Allow manual triggering in case the dd-octo-sts token is not working. +# TODO: Remove this job once the dd-octo-sts token is provably working. +deploy_artifacts_to_github_old: stage: publish image: registry.ddbuild.io/github-cli:v27480869-eafb11d-2.43.0 rules: - if: '$POPULATE_CACHE' when: never - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/' - when: on_success - # Requires the deploy_to_sonatype job to have run first (the UP-TO-DATE gradle check across jobs is broken) + when: manual + # Requires the deploy_to_maven_central job to have run first (the UP-TO-DATE gradle check across jobs is broken) # This will deploy the artifacts built from the publishToSonatype task to the GitHub release needs: - - job: deploy_to_sonatype - # The deploy_to_sonatype job is not run for release candidate versions + - job: deploy_to_maven_central + # The deploy_to_maven_central job is not run for release candidate versions optional: true - - job: get_github_token - script: - # - aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.gh_release_token --with-decryption --query "Parameter.Value" --out text > github-token.txt - # Debug token reception - - echo "Token file exists:" $(test -f github-token.txt && echo "YES" || echo "NO") - - echo "Token file size:" $(wc -c < github-token.txt) "bytes" + - aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.gh_release_token --with-decryption --query "Parameter.Value" --out text > github-token.txt - gh auth login --with-token < github-token.txt - gh auth status # Maybe helpful to have this output in logs? - # - export VERSION=${CI_COMMIT_TAG##v} # remove "v" from front of tag to get version - # - cp workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar workspace/dd-java-agent/build/libs/dd-java-agent.jar # we upload two filenames - # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent.jar - # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar - # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-api/build/libs/dd-trace-api-${VERSION}.jar - # - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-ot/build/libs/dd-trace-ot-${VERSION}.jar + - export VERSION=${CI_COMMIT_TAG##v} # remove "v" from front of tag to get version + - cp workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar workspace/dd-java-agent/build/libs/dd-java-agent.jar # we upload two filenames + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-java-agent/build/libs/dd-java-agent-${VERSION}.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-api/build/libs/dd-trace-api-${VERSION}.jar + - gh release upload --clobber --repo DataDog/dd-trace-java $CI_COMMIT_TAG workspace/dd-trace-ot/build/libs/dd-trace-ot-${VERSION}.jar retry: max: 2 when: always @@ -871,7 +881,7 @@ package-oci: configure_system_tests: variables: - SYSTEM_TESTS_SCENARIOS_GROUPS: "simple_onboarding,simple_onboarding_profiling,docker-ssi,lib-injection" + SYSTEM_TESTS_SCENARIOS_GROUPS: "simple_onboarding,simple_onboarding_profiling,simple_onboarding_appsec,docker-ssi,lib-injection" create_key: stage: generate-signing-key