Skip to content

Upgrade libddwaf native bindings #5792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open

Conversation

CarlesDD
Copy link
Contributor

@CarlesDD CarlesDD commented May 30, 2025

What does this PR do?

Introduces changes to use the latest version of native appsec which contains the libddwaf changes up to version 1.24.1.

This new libddwaf brings a new interface for instance creation as well as instance configuration management, moving the logic of merging configurations received by RC to libddwaf.

Also, diagnostics have been updated and should now be propagated by RC and telemetry.

Additional Notes

APPSEC-55565
RFC-1025

Copy link

github-actions bot commented May 30, 2025

Overall package size

Self size: 9.58 MB
Deduped: 104.06 MB
No deduping: 104.58 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | @datadog/libdatadog | 0.5.1 | 29.73 MB | 29.73 MB | | @datadog/native-appsec | 9.0.0 | 19.6 MB | 19.61 MB | | @datadog/pprof | 5.8.0 | 12.55 MB | 12.92 MB | | @datadog/native-iast-taint-tracking | 4.0.0 | 11.72 MB | 11.73 MB | | @opentelemetry/core | 1.30.1 | 908.66 kB | 7.16 MB | | protobufjs | 7.5.3 | 2.95 MB | 5.6 MB | | @datadog/wasm-js-rewriter | 4.0.1 | 2.85 MB | 3.58 MB | | @datadog/native-metrics | 3.1.1 | 1.02 MB | 1.43 MB | | @opentelemetry/api | 1.8.0 | 1.21 MB | 1.21 MB | | import-in-the-middle | 1.14.0 | 120.58 kB | 842.2 kB | | source-map | 0.7.4 | 226 kB | 226 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | lru-cache | 7.18.3 | 133.92 kB | 133.92 kB | | pprof-format | 2.1.0 | 111.69 kB | 111.69 kB | | @datadog/sketches-js | 2.1.1 | 109.9 kB | 109.9 kB | | lodash.sortby | 4.7.0 | 75.76 kB | 75.76 kB | | ignore | 5.3.2 | 53.63 kB | 53.63 kB | | istanbul-lib-coverage | 3.2.2 | 34.37 kB | 34.37 kB | | rfdc | 1.4.1 | 27.15 kB | 27.15 kB | | @isaacs/ttlcache | 1.4.1 | 25.2 kB | 25.2 kB | | dc-polyfill | 0.1.9 | 25.11 kB | 25.11 kB | | tlhunter-sorted-set | 0.1.0 | 24.94 kB | 24.94 kB | | shell-quote | 1.8.2 | 23.54 kB | 23.54 kB | | limiter | 1.1.5 | 23.17 kB | 23.17 kB | | retry | 0.13.1 | 18.85 kB | 18.85 kB | | semifies | 1.0.0 | 15.84 kB | 15.84 kB | | jest-docblock | 29.7.0 | 8.99 kB | 12.76 kB | | crypto-randomuuid | 1.0.0 | 11.18 kB | 11.18 kB | | ttl-set | 1.0.0 | 4.61 kB | 9.69 kB | | mutexify | 1.4.0 | 5.71 kB | 8.74 kB | | path-to-regexp | 0.1.12 | 6.6 kB | 6.6 kB | | koalas | 1.0.2 | 6.47 kB | 6.47 kB | | module-details-from-path | 1.0.4 | 3.96 kB | 3.96 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

Copy link

codecov bot commented May 30, 2025

Codecov Report

Attention: Patch coverage is 95.45455% with 4 lines in your changes missing coverage. Please review.

Project coverage is 79.15%. Comparing base (569c46d) to head (079af0e).

Files with missing lines Patch % Lines
packages/dd-trace/src/appsec/reporter.js 88.23% 2 Missing ⚠️
packages/dd-trace/src/appsec/waf/waf_manager.js 88.23% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #5792   +/-   ##
=======================================
  Coverage   79.15%   79.15%           
=======================================
  Files         522      522           
  Lines       24010    23973   -37     
=======================================
- Hits        19005    18976   -29     
+ Misses       5005     4997    -8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@datadog-datadog-prod-us1
Copy link

datadog-datadog-prod-us1 bot commented May 30, 2025

Datadog Report

Branch report: ccapell/new-waf-builder
Commit report: d5eb034
Test service: dd-trace-js-integration-tests

✅ 0 Failed, 1257 Passed, 0 Skipped, 25m 36.12s Total Time

@pr-commenter
Copy link

pr-commenter bot commented May 30, 2025

Benchmarks

Benchmark execution time: 2025-06-02 13:38:41

Comparing candidate commit 079af0e in PR branch ccapell/new-waf-builder with baseline commit 569c46d in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1273 metrics, 50 unstable metrics.

@CarlesDD CarlesDD marked this pull request as ready for review May 30, 2025 08:57
@CarlesDD CarlesDD requested review from a team as code owners May 30, 2025 08:57
Copy link
Collaborator

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell anything about the domain logic in this case, I just had a brief look at the overall code and left a few questions and suggestions :)

Comment on lines 250 to 258
telemetryLogCh.publish({
message: diagnostics[configKey].error,
level: 'ERROR',
tags: {
log_type: `rc::${product.toLowerCase()}::diagnostic`,
appsec_config_key: configKey,
rc_config_id: rcConfigId
}
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would abstract this in a small helper with the rule of three

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New helper has been implemented to publish these diagnostics log messages.

for (const item of toUnapply) {
const { product, id } = item
if (!['ASM_DD', 'ASM_DATA', 'ASM'].includes(item.product)) continue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now this array is created in each loop iteration. Maybe move it outside of the method and make it a set so that there is only a single lookup happening per iteration? :)

Suggested change
if (!['ASM_DD', 'ASM_DATA', 'ASM'].includes(item.product)) continue
if (PRODUCTS.has(item.product)) continue

The same applies in other places.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion has been applied.

} catch (e) {
wafUpdatedSuccess = false
item.apply_state = ERROR
item.apply_error = e.toString()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional to only care about the error type and message? Calling .toString() is pretty bad for Node.js errors such that the stack and other properties are all lost. In case the error should be inspected, I would just use util.inspect(error).

The same for other spots.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (file?.custom_rules?.length) {
newCustomRules.set(id, file.custom_rules)
wafUpdatedSuccess = false
item.apply_error = JSON.stringify(extractErrors(updateResult.diagnostics))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The errors are handled very differently depending on where it happens while the overall logical seems to almost be identical. Should they not be handled all the same? :)

copy.data = data
}
return copy
return Object.keys(result).length > 0 ? result : null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of checking for results keys, I would just use a boolean that I set to true in case the loop happened to match something, since calling Object.keys() is quite expensive to just get that information.

In general, is the object really arbitrary that we have to loop over it completely in an unknown way?

Copy link
Contributor Author

@CarlesDD CarlesDD Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion's been applied.

Regarding the arbitrariness of the objetc, no, the object is not really arbitrary, it has a defined schema (at least, for this version of libddwaf).

@CarlesDD CarlesDD force-pushed the ccapell/new-waf-builder branch from c570c22 to 9872b5d Compare June 1, 2025 09:38
if (this.ddwaf.diagnostics.ruleset_version) {
this.rulesVersion = this.ddwaf.diagnostics.ruleset_version
}
const success = this.ddwaf.createOrUpdateConfig(rules, path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createOrUpdateConfig could throw an error, I think we need a try/catch block

this.ddwaf.createOrUpdateConfig(this.defaultRules, DEFAULT_WAF_CONFIG_PATH)
}

return { success, diagnostics }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we need to update this.rulesVersion = this.ddwaf.diagnostics.ruleset_version here too

wafUpdatedSuccess = false
item.apply_state = ERROR
item.apply_error = e.toString()
Reporter.reportWafConfigError(waf.wafManager.ddwafVersion, waf.wafManager.rulesVersion)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that we gonna report probably a wrong rulesVersion if remove fails no?

@CarlesDD CarlesDD force-pushed the ccapell/new-waf-builder branch from 9872b5d to 079af0e Compare June 2, 2025 13:29
@@ -225,6 +242,54 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}, success
incrementWafInitMetric(wafVersion, rulesVersion, success)
}

function logWafDiagnosticMessage (product, rcConfigId, configKey, message, level) {
telemetryLogCh.publish({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These logs are sent via telemetry, but aren't shown in the output if the logs are enabled, is the expected behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RFC only establishes the propagation of diagnostics by telemetry and RC. Specifically it states that:

Note that aside from through telemetry logs, none of the diagnostics presented here should be logged to a regular logger using a level above debug, as it will inevitably result in customer complaints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants