Skip to content

Commit d05b090

Browse files
Merge branch 'sezen.leblay/upgrade-libddwaf-java-1.23' into sezen.leblay/APPSEC-57893-appsec-enabled-metric
2 parents af32b13 + 8212f64 commit d05b090

File tree

42 files changed

+5823
-2105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5823
-2105
lines changed

.github/workflows/analyze-changes.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
${{ runner.os }}-gradle-
4141
4242
- name: Initialize CodeQL
43-
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
43+
uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
4444
with:
4545
languages: 'java'
4646
build-mode: 'manual'
@@ -57,7 +57,7 @@ jobs:
5757
--build-cache --parallel --stacktrace --no-daemon --max-workers=4
5858
5959
- name: Perform CodeQL Analysis and upload results to GitHub Security tab
60-
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
60+
uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
6161

6262
trivy:
6363
name: Analyze changes with Trivy
@@ -109,7 +109,7 @@ jobs:
109109
ls -laR "./workspace/.trivy"
110110
111111
- name: Run Trivy security scanner
112-
uses: aquasecurity/trivy-action@6c175e9c4083a92bbca2f9724c8a5e33bc2d97a5 # v0.30.0
112+
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0.31.0
113113
with:
114114
scan-type: rootfs
115115
scan-ref: './workspace/.trivy/'
@@ -122,7 +122,7 @@ jobs:
122122
TRIVY_JAVA_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-java-db,public.ecr.aws/aquasecurity/trivy-java-db
123123

124124
- name: Upload Trivy scan results to GitHub Security tab
125-
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
125+
uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
126126
if: always()
127127
with:
128128
sarif_file: 'trivy-results.sarif'

.github/workflows/check-ci-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
runs-on: ubuntu-latest
2424
steps:
2525
- name: Run Ensure CI Success
26-
uses: DataDog/ensure-ci-success@727e7fe39ae2e1ce7ea336ec85a7369ab0731754
26+
uses: DataDog/ensure-ci-success@4a4b720e881d965254a9de2a4f14d1ec0c3d0d7c
2727
with:
2828
initial-delay-seconds: "500"
2929
max-retries: "60"

.gitlab-ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ default:
9595
- ONE_INDEXED_NODE_INDEX=${CI_NODE_INDEX:-1}; export NORMALIZED_NODE_INDEX=$((ONE_INDEXED_NODE_INDEX - 1))
9696
- echo "NORMALIZED_NODE_TOTAL=${NORMALIZED_NODE_TOTAL}, NORMALIZED_NODE_INDEX=$NORMALIZED_NODE_INDEX"
9797

98+
.cgroup_info: &cgroup_info
99+
- source .gitlab/gitlab-utils.sh
100+
- gitlab_section_start "cgroup-info" "cgroup info"
101+
- .gitlab/cgroup-info.sh
102+
- gitlab_section_end "cgroup-info"
103+
98104
.gradle_build: &gradle_build
99105
image: ghcr.io/datadog/dd-trace-java-docker-build:${BUILDER_IMAGE_VERSION_PREFIX}base
100106
stage: build
@@ -140,6 +146,8 @@ default:
140146
- mv .gradle-copy .gradle
141147
- ls -la
142148
- gitlab_section_end "gradle-dance"
149+
after_script:
150+
- *cgroup_info
143151

144152
build:
145153
extends: .gradle_build
@@ -275,6 +283,7 @@ test_published_artifacts:
275283
- export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xmx1G -Xms1G -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'"
276284
- ./gradlew check --info $GRADLE_ARGS
277285
after_script:
286+
- *cgroup_info
278287
- source .gitlab/gitlab-utils.sh
279288
- gitlab_section_start "collect-reports" "Collecting reports"
280289
- .circleci/collect_reports.sh
@@ -293,6 +302,7 @@ test_published_artifacts:
293302
script:
294303
- ./gradlew $GRADLE_TARGET -PskipTests -PrunBuildSrcTests -PskipSpotless -PtaskPartitionCount=$NORMALIZED_NODE_TOTAL -PtaskPartition=$NORMALIZED_NODE_INDEX $GRADLE_ARGS
295304
after_script:
305+
- *cgroup_info
296306
- source .gitlab/gitlab-utils.sh
297307
- gitlab_section_start "collect-reports" "Collecting reports"
298308
- .circleci/collect_reports.sh --destination ./check_reports --move
@@ -353,6 +363,7 @@ muzzle:
353363
- split --number=l/$NORMALIZED_NODE_TOTAL --suffix-length=1 --numeric-suffixes sortedMuzzleTasks muzzleSplit
354364
- ./gradlew `cat muzzleSplit${NORMALIZED_NODE_INDEX} | xargs` $GRADLE_ARGS
355365
after_script:
366+
- *cgroup_info
356367
- source .gitlab/gitlab-utils.sh
357368
- gitlab_section_start "collect-reports" "Collecting reports"
358369
- .circleci/collect_reports.sh
@@ -373,6 +384,7 @@ muzzle-dep-report:
373384
- export SKIP_BUILDSCAN="true"
374385
- ./gradlew generateMuzzleReport muzzleInstrumentationReport $GRADLE_ARGS
375386
after_script:
387+
- *cgroup_info
376388
- .circleci/collect_muzzle_deps.sh
377389
artifacts:
378390
when: always
@@ -432,6 +444,7 @@ muzzle-dep-report:
432444
after_script:
433445
- *restore_pretest_env
434446
- *set_datadog_api_keys
447+
- *cgroup_info
435448
- source .gitlab/gitlab-utils.sh
436449
- gitlab_section_start "collect-reports" "Collecting reports"
437450
- .circleci/collect_reports.sh

.gitlab/cgroup-info.sh

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env bash
2+
3+
print_metric() {
4+
local label="$1"
5+
local raw_value="$2"
6+
local trimmed_value
7+
8+
# Use read -rd '' to trim leading/trailing IFS whitespace (space, tab, newline)
9+
read -rd '' trimmed_value <<< "$raw_value" || :
10+
11+
# Check if trimmed_value contains a newline character for formatting
12+
if [[ "$trimmed_value" == *$'\n'* ]]; then
13+
local indent=" "
14+
# Using a more robust way to handle potential leading/trailing newlines in raw_value for printf
15+
printf "%-35s :\n" "$label"
16+
printf "%s\n" "$indent${trimmed_value//$'\n'/$'\n'$indent}" # Indent and print the value on new lines
17+
else
18+
printf "%-35s : %s\n" "$label" "$trimmed_value"
19+
fi
20+
}
21+
22+
cat_file() {
23+
cat "$1" 2>/dev/null || echo 'not found'
24+
}
25+
26+
# Show cgroup memory usage
27+
print_metric "RAM memory" "$( (grep MemTotal /proc/meminfo | tr -s ' ' | cut -d ' ' -f 2) 2>/dev/null || echo 'not found')"
28+
29+
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
30+
# cgroup v2
31+
print_metric "cgroup v2 memory.peak" "$(cat_file /sys/fs/cgroup/memory.peak)"
32+
print_metric "cgroup v2 memory.max" "$(cat_file /sys/fs/cgroup/memory.max)"
33+
print_metric "cgroup v2 memory.high" "$(cat_file /sys/fs/cgroup/memory.high)"
34+
print_metric "cgroup v2 memory.current" "$(cat_file /sys/fs/cgroup/memory.current)"
35+
if [ -f /sys/fs/cgroup/memory.pressure ]; then
36+
print_metric "cgroup v2 memory.pressure" "$(cat_file /sys/fs/cgroup/memory.pressure)"
37+
fi
38+
if [ -f /sys/fs/cgroup/memory.events ]; then
39+
print_metric "cgroup v2 memory.events oom" "$( (grep -E '^oom\\s' /sys/fs/cgroup/memory.events | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
40+
print_metric "cgroup v2 memory.events oom_kill" "$( (grep -E '^oom_kill\\s' /sys/fs/cgroup/memory.events | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
41+
print_metric "cgroup v2 memory.events high" "$( (grep -E '^high\\s' /sys/fs/cgroup/memory.events | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
42+
fi
43+
44+
# CPU metrics
45+
print_metric "cgroup v2 cpu.max" "$(cat_file /sys/fs/cgroup/cpu.max)"
46+
print_metric "cgroup v2 cpu.nr_throttled" "$( (grep -E "^nr_throttled[[:space:]]+" /sys/fs/cgroup/cpu.stat | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
47+
print_metric "cgroup v2 cpu.throttled_usec" "$( (grep -E "^throttled_usec[[:space:]]+" /sys/fs/cgroup/cpu.stat | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
48+
print_metric "cgroup v2 cpu.usage_usec" "$( (grep -E "^usage_usec[[:space:]]+" /sys/fs/cgroup/cpu.stat | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
49+
if [ -f /sys/fs/cgroup/cpu.pressure ]; then # cpu.pressure might not exist on older kernels/setups
50+
print_metric "cgroup v2 cpu.pressure" "$(cat_file /sys/fs/cgroup/cpu.pressure)"
51+
fi
52+
53+
elif [ -d "/sys/fs/cgroup/memory" ]; then # Assuming if memory cgroup v1 exists, cpu might too
54+
# cgroup v1
55+
# Note: In cgroup v1, memory stats are typically found under /sys/fs/cgroup/memory/
56+
# The specific path might vary if inside a nested cgroup.
57+
# This script assumes it's running in a context where /sys/fs/cgroup/memory/ points to the relevant cgroup.
58+
print_metric "cgroup v1 memory.usage_in_bytes" "$(cat_file /sys/fs/cgroup/memory/memory.usage_in_bytes)"
59+
print_metric "cgroup v1 memory.limit_in_bytes" "$(cat_file /sys/fs/cgroup/memory/memory.limit_in_bytes)"
60+
print_metric "cgroup v1 memory.failcnt" "$(cat_file /sys/fs/cgroup/memory/memory.failcnt)"
61+
print_metric "cgroup v1 memory.max_usage_in_bytes" "$(cat_file /sys/fs/cgroup/memory/memory.max_usage_in_bytes)"
62+
63+
# Throttling stats from /sys/fs/cgroup/cpu/cpu.stat
64+
if [ -f /sys/fs/cgroup/cpu/cpu.stat ]; then
65+
print_metric "cgroup v1 cpu.nr_throttled" "$( (grep -E "^nr_throttled[[:space:]]+" /sys/fs/cgroup/cpu/cpu.stat | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
66+
print_metric "cgroup v1 cpu.throttled_time_ns" "$( (grep -E "^throttled_time[[:space:]]+" /sys/fs/cgroup/cpu/cpu.stat | cut -d' ' -f2) 2>/dev/null || echo 'not found')"
67+
else
68+
# Print not found for these specific metrics if cpu.stat is missing, to avoid ambiguity
69+
print_metric "cgroup v1 cpu.nr_throttled" "not found (cpu.stat)"
70+
print_metric "cgroup v1 cpu.throttled_time_ns" "not found (cpu.stat)"
71+
fi
72+
# CPU Quota settings from /sys/fs/cgroup/cpu/
73+
print_metric "cgroup v1 cpu.cfs_period_us" "$(cat_file /sys/fs/cgroup/cpu/cpu.cfs_period_us)"
74+
print_metric "cgroup v1 cpu.cfs_quota_us" "$(cat_file /sys/fs/cgroup/cpu/cpu.cfs_quota_us)"
75+
# CPU usage from /sys/fs/cgroup/cpuacct/ (usually same hierarchy as cpu)
76+
print_metric "cgroup v1 cpuacct.usage_ns" "$(cat_file /sys/fs/cgroup/cpuacct/cpuacct.usage)"
77+
print_metric "cgroup v1 cpuacct.usage_user_ns" "$(cat_file /sys/fs/cgroup/cpuacct/cpuacct.usage_user)"
78+
print_metric "cgroup v1 cpuacct.usage_sys_ns" "$(cat_file /sys/fs/cgroup/cpuacct/cpuacct.usage_sys)"
79+
80+
else
81+
printf "cgroup memory paths not found. Neither cgroup v2 controller file nor cgroup v1 memory directory detected.\n"
82+
fi
83+

benchmark/load/petclinic/benchmark.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@
3030
"JAVA_OPTS": "-javaagent:${TRACER} -Ddd.appsec.enabled=true"
3131
}
3232
},
33-
"appsec_no_iast": {
34-
"env": {
35-
"VARIANT": "appsec_no_iast",
36-
"JAVA_OPTS": "-javaagent:${TRACER} -Ddd.appsec.enabled=true -Ddd.iast.enabled=false"
37-
}
38-
},
3933
"iast": {
4034
"env": {
4135
"VARIANT": "iast",

benchmark/startup/petclinic/benchmark.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@
2424
"JAVA_OPTS": "-Ddd.appsec.enabled=true"
2525
}
2626
},
27-
"appsec_no_iast": {
28-
"env": {
29-
"VARIANT": "appsec",
30-
"JAVA_OPTS": "-Ddd.appsec.enabled=true -Ddd.iast.enabled=false"
31-
}
32-
},
3327
"iast": {
3428
"env": {
3529
"VARIANT": "iast",

dd-java-agent/appsec/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies {
1515
implementation project(':internal-api')
1616
implementation project(':communication')
1717
implementation project(':telemetry')
18-
implementation group: 'io.sqreen', name: 'libsqreen', version: '13.0.1'
18+
implementation group: 'io.sqreen', name: 'libsqreen', version: '14.0.0'
1919
implementation libs.moshi
2020

2121
testImplementation libs.bytebuddy
@@ -70,6 +70,7 @@ ext {
7070
'com.datadog.appsec.config.MergedAsmData.InvalidAsmDataException',
7171
'com.datadog.appsec.ddwaf.WafInitialization',
7272
'com.datadog.appsec.ddwaf.WAFModule.WAFDataCallback',
73+
'com.datadog.appsec.config.AppSecModuleConfigurer.Reconfiguration',
7374
'com.datadog.appsec.report.*',
7475
'com.datadog.appsec.config.AppSecConfigServiceImpl.SubscribeFleetServiceRunnable.1',
7576
'com.datadog.appsec.util.StandardizedLogging',
@@ -81,6 +82,7 @@ ext {
8182
'com.datadog.appsec.config.AppSecFeatures.Asm',
8283
'com.datadog.appsec.config.AppSecFeatures.ApiSecurity',
8384
'com.datadog.appsec.config.AppSecFeatures.AutoUserInstrum',
85+
'com.datadog.appsec.AppSecModule.AppSecModuleActivationException',
8486
'com.datadog.appsec.event.ReplaceableEventProducerService',
8587
'com.datadog.appsec.api.security.ApiSecuritySampler.NoOp',
8688
]

dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/WafBenchmark.java

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@
33
import static java.util.concurrent.TimeUnit.MICROSECONDS;
44
import static java.util.concurrent.TimeUnit.SECONDS;
55

6-
import com.datadog.appsec.config.AppSecConfig;
7-
import com.datadog.appsec.config.AppSecConfigDeserializer;
86
import com.datadog.appsec.event.data.KnownAddresses;
97
import com.datadog.ddwaf.Waf;
8+
import com.datadog.ddwaf.WafBuilder;
109
import com.datadog.ddwaf.WafContext;
1110
import com.datadog.ddwaf.WafHandle;
1211
import com.datadog.ddwaf.WafMetrics;
1312
import com.datadog.ddwaf.exception.AbstractWafException;
13+
import com.squareup.moshi.JsonAdapter;
14+
import com.squareup.moshi.Moshi;
15+
import com.squareup.moshi.Types;
1416
import java.io.IOException;
1517
import java.io.InputStream;
1618
import java.util.ArrayList;
1719
import java.util.Collections;
1820
import java.util.HashMap;
1921
import java.util.List;
2022
import java.util.Map;
23+
import okio.Okio;
2124
import org.openjdk.jmh.annotations.Benchmark;
2225
import org.openjdk.jmh.annotations.BenchmarkMode;
2326
import org.openjdk.jmh.annotations.Fork;
@@ -38,45 +41,49 @@
3841
@OutputTimeUnit(MICROSECONDS)
3942
@Fork(value = 3)
4043
public class WafBenchmark {
44+
private static final JsonAdapter<Map<String, Object>> ADAPTER =
45+
new Moshi.Builder()
46+
.build()
47+
.adapter(Types.newParameterizedType(Map.class, String.class, Object.class));
4148

4249
static {
4350
BenchmarkUtil.disableLogging();
4451
BenchmarkUtil.initializeWaf();
4552
}
4653

47-
WafHandle ctx;
54+
WafBuilder wafBuilder;
55+
WafHandle wafHandle;
56+
WafContext wafContext;
4857
Map<String, Object> wafData = new HashMap<>();
4958
Waf.Limits limits = new Waf.Limits(50, 500, 1000, 5000000, 5000000);
5059

5160
@Benchmark
5261
public void withMetrics() throws Exception {
53-
WafMetrics metricsCollector = ctx.createMetrics();
54-
WafContext add = ctx.openContext();
62+
WafMetrics metricsCollector = new WafMetrics();
63+
wafContext = new WafContext(wafHandle);
5564
try {
56-
add.run(wafData, limits, metricsCollector);
65+
wafContext.run(wafData, limits, metricsCollector);
5766
} finally {
58-
add.close();
67+
wafContext.close();
5968
}
6069
}
6170

6271
@Benchmark
6372
public void withoutMetrics() throws Exception {
64-
WafContext add = ctx.openContext();
73+
wafContext = new WafContext(wafHandle);
6574
try {
66-
add.run(wafData, limits, null);
75+
wafContext.run(wafData, limits, null);
6776
} finally {
68-
add.close();
77+
wafContext.close();
6978
}
7079
}
7180

7281
@Setup(Level.Trial)
7382
public void setUp() throws AbstractWafException, IOException {
83+
wafBuilder = new WafBuilder();
7484
InputStream stream = getClass().getClassLoader().getResourceAsStream("test_multi_config.json");
75-
Map<String, AppSecConfig> cfg =
76-
Collections.singletonMap("waf", AppSecConfigDeserializer.INSTANCE.deserialize(stream));
77-
AppSecConfig waf = cfg.get("waf");
78-
ctx = Waf.createHandle("waf", waf.getRawConfig());
79-
85+
wafBuilder.addOrUpdateConfig("waf", ADAPTER.fromJson(Okio.buffer(Okio.source(stream))));
86+
wafHandle = wafBuilder.buildWafHandleInstance();
8087
wafData.put(KnownAddresses.REQUEST_METHOD.getKey(), "POST");
8188
wafData.put(
8289
KnownAddresses.REQUEST_URI_RAW.getKey(), "/foo/bar?foo=bar&foo=xpto&foo=%3cscript%3e");
@@ -112,6 +119,14 @@ public void setUp() throws AbstractWafException, IOException {
112119

113120
@TearDown(Level.Trial)
114121
public void teardown() {
115-
ctx.close();
122+
if (wafHandle != null && wafHandle.isOnline()) {
123+
wafHandle.close();
124+
}
125+
if (wafContext != null && wafContext.isOnline()) {
126+
wafContext.close();
127+
}
128+
if (wafBuilder != null && wafBuilder.isOnline()) {
129+
wafBuilder.close();
130+
}
116131
}
117132
}

dd-java-agent/appsec/src/main/java/com/datadog/appsec/AppSecModule.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@
33
import com.datadog.appsec.config.AppSecModuleConfigurer;
44
import com.datadog.appsec.event.DataListener;
55
import com.datadog.appsec.event.data.Address;
6+
import com.datadog.ddwaf.WafBuilder;
67
import java.util.Collection;
78

89
public interface AppSecModule {
910
void config(AppSecModuleConfigurer appSecConfigService) throws AppSecModuleActivationException;
1011

12+
void setWafBuilder(WafBuilder wafBuilder);
13+
14+
void setRuleVersion(String rulesetVersion);
15+
1116
String getName();
1217

1318
String getInfo();
1419

1520
Collection<DataSubscription> getDataSubscriptions();
1621

22+
boolean isWafBuilderSet();
23+
1724
abstract class DataSubscription implements DataListener {
1825
private final Collection<Address<?>> subscribedAddresses;
1926
private final Priority priority;

0 commit comments

Comments
 (0)