Repository navigation
feat(openfeature): protect flagevaluation PII - #20354
gh-worker-dd-mergequeue-cf854d[bot] merged 13 commits into
Conversation
Environment: Datadog workspace Co-authored-by: vickie.fridge <vickie.fridge@datadoghq.com>
🎉 All green!🧪 All tests passed 🔗 Commit SHA: a65eeb1 | Docs | View more details | Give us feedback! |
Circular import analysis
|
Codeowners resolved asResolved from the full PR diff against No remaining files require a CODEOWNERS review. |
Dependency direction analysis
|
BenchmarksBenchmark execution time: 2026-09-22 18:12:06 Comparing candidate commit a65eeb1 in PR branch Found 2 performance improvements and 1 performance regressions! Performance is the same for 588 metrics, 10 unstable metrics, 7 known flaky benchmarks, 17 flaky benchmarks without significant changes.
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
11986ea to
70967e9
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3da0dd9626
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
aarsilv
left a comment
There was a problem hiding this comment.
Thanks for taking this on!
I pointed my "aaron-in-the-loop" agentic review skill at this. No blockers, mostly cleanups and testing gaps.
It did also find that when protecting against PII, an empty targeting key does different stuff here than in Go, Java, and Ruby. We'll probably want to align on a behavior and conform. (my vote would be keep it as the empty string, but the hash of the empty string could be defensible too)
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
# Conflicts: # benchmarks/openfeature_flagevaluation/scenario.py
Note to self: system-tests — latest main mergePASS for the candidate — both selections passed on their first run. No unexpected candidate regression or SDK iteration indicated by these results. 2026-09-21,
System-tests: docker buildx build --load --platform linux/arm64/v8 \
--build-context system_tests_base_python_flask_poc=docker-image://ffl2964/flask-poc-base:arm64 \
-f utils/build/docker/python/flask-poc.Dockerfile \
--label system-tests-library=python \
--label system-tests-weblog-variant=flask-poc -t system_tests/weblog .
./run.sh FEATURE_FLAGGING_AND_EXPERIMENTATION --library python \
-F tests/ffe/test_flag_eval_evp.py -k Test_FFE_EVP_Flagevaluation
./run.sh FEATURE_FLAGGING_AND_EXPERIMENTATION --library python \
-F tests/ffe/test_flag_eval_evp.pyThe second command runs the full FFE scenario: dynamic evaluation, exposures, flag-evaluation events, and OTel evaluation metrics.
Main's two repeatable failures are the expected absent/false-consent hashing assertions: it still emits the raw targeting key. Its additional focused degradation failure was “Expected degraded EVP flagevaluation buckets”; degradation passed in the full run and an isolated Candidate coverage confirms protected absent/false consent, full-data opt-in, bounded context, runtime defaults, counts, load/burst aggregation, cardinality/degradation, exposures, and OTel metrics. Its installed writer SHA-256 is Evidence: remote |
Note to self: ffe-dogfooding — latest main mergePASS — no regression found in the shared request matrix; no SDK iteration indicated by this run. 2026-09-21,
Harness: DD_TRACE_PY_PATH=<exact-SDK-clone> docker compose \
-f docker-compose.yml -f local/docker-compose.python.yml \
up -d --no-build app-python
python3 /tmp/ffl2964_dogfood_runner.pyThe updated harness images were built first. Reset mock intake before each identical 18-request matrix: five flag types with three subjects each, plus oversized attribute-count, long-field, and deeply nested-context cases.
All 18 logged evaluation results match, including values, reasons, variants, and error codes/messages. The intentionally invalid nested context produces the same Live Remote Configuration enables full data, so this run proves full-data parity; the companion system-tests run covers absent/false consent and hashing. Supplemental installed-wheel provider → hook → queue → aggregation → serialized-byte checks passed for the candidate in all four consent/tier combinations. The error-only PII canary is absent, the wire error is Evidence: remote |
|
/code blockers |
|
View all feedbacks in Devflow UI.
Checking merge blockers for #20354...
Detected 1 merge blocker(s) to address: 🟠 Pending
|
brettlangdon
left a comment
There was a problem hiding this comment.
might be worth setting the codeowner on benchmarks/openfeature_flagevaluation to FFE
should this be a fix instead of a feat? "don't send PII anymore" sounds more like a bug fix than a feature?
not a blocker, just how it reads to me.
Thanks @brettlangdon! I will fold this into my next PR!
Fair, it's kindof borderline since new functionality also. I think I'll leave it as-is for now |
## Description Assign `benchmarks/openfeature_flagevaluation/` to the Feature Flagging and Experimentation SDK team. This overrides the broader APM Core Python benchmark owner so review requests follow the benchmark's product ownership. ## Testing - Verified the CODEOWNERS diff applies cleanly with `git diff --check`. ## Risks None. This changes reviewer routing only. ## Additional Notes Follow-up from #20354 (review).
## Description Assign `benchmarks/openfeature_flagevaluation/` to the Feature Flagging and Experimentation SDK team. This overrides the broader APM Core Python benchmark owner so review requests follow the benchmark's product ownership. ## Testing - Verified the CODEOWNERS diff applies cleanly with `git diff --check`. ## Risks None. This changes reviewer routing only. ## Additional Notes Follow-up from #20354 (review).
## Description Implements protected-by-default OpenFeature `flagevaluation` telemetry. - Hash valid non-empty targeting keys as `sha256_<lowercase hex>` over exact UTF-8 bytes. Preserve explicit empty strings; omit missing or invalid keys without dropping evaluation counts. - Omit evaluation context by default. Only exact root `observeFullEvaluationData: true` permits raw valid targeting keys and a bounded immutable context snapshot. - Emit only approved OpenFeature error codes in **both** privacy modes. Full-data consent never permits raw evaluator/exception text. - Bind consent to the configuration used for the evaluation; carry it through private metadata, queueing, aggregation, and serialization. Full-tier identity includes consent; degraded identity excludes it and always omits key/context. Both tiers retain defensive AND-folds. - Preserve asynchronous bounded delivery, existing OTel metrics/exposures, `DoLog` independence, the kill switch, and the span helper's bare digest format. - Count invalid-key omissions separately from dropped rows and caught hook failures. Telemetry-sink failures cannot interrupt delivery. Supersedes the stale implementation in #19554 and builds on #19881. Context: [FFL-2964](https://datadoghq.atlassian.net/browse/FFL-2964), [FFL-2529](https://datadoghq.atlassian.net/browse/FFL-2529), [approved PII RFC](https://docs.google.com/document/d/19VIf4B9p-zsAL2uWSvdzil59DZlGjQm4yudAMwJBqLs/edit), [shared implementation guidance](DataDog/ffe-codegen-tools#9). ## Testing Validation refreshed on 2026-09-18 for `1bfd2eab9d36c935999c261bbade7c37a5f4f9cc`. - OpenFeature: **848 passed, 2 skipped** in each CPython 3.11 dependency selection (pinned 0.8 and latest). - Six isolated fault-injection checks detect bypassed context guards, queue aliasing, missing full-tier folding, unsafe serializer errors, and missing hook error-code forwarding. - Full mypy: **1,139 source files passed**. Targeted style, spelling, security, error-log, suitespec, and SLO ownership checks passed. The broad `scripts/lint checks` entrypoint hit generated cache files in its Cython scan; source-scoped checks were run separately. - Exact ARM64 wheels compared with main `63de8eb2d675e2ebe8428f058b01249674ab5079`: dogfooding **18/18 HTTP 200 and 18 evaluations on both sides**, no corrupt rows. Installed candidate writer checksum matches source. - Installed-wheel error-only canaries: candidate passes both consent modes and both tiers, preserving default counts; main leaks the canary in all four cases. - System tests: candidate **11 focused passed; 46 full passed, 2 skipped, 4 existing XPASS**. Main full has the two expected privacy failures. Its initial focused degradation failure passed in the full run and isolated rerun; candidate passed first try. - All ten benchmark means meet SLOs. Protected enqueue/aggregation measure **18.27/12.20 µs**, with **24/16 µs** thresholds. Legacy full-data scenarios retain their original work and limits. Full aggregate-typical is **28.75 vs 27.65 µs (+3.96%)**, close to its unchanged 29 µs limit; do not interpret protected improvements as same-mode optimization. - Five review lenses plus an adversarial pass and a read-only Codex sweep completed. The SRE finding about telemetry failure losing a flush was fixed and rechecked. No remaining actionable local findings. See the latest two **Note to self** comments for harness commits, wheel hashes, commands, and first-run/retry counts. New remote CI must finish independently of this local evidence. ## Risks / Additional Notes This intentionally changes the default wire shape. Deterministic unsalted hashes preserve cross-SDK subject joins but remain susceptible to dictionary attacks for low-entropy keys. Protected mode does not read/copy context attributes; hashing remains in the background worker. `flagevaluation.targeting_key.omitted{reason:invalid}` counts rejected inputs that reach aggregation, not transmitted rows or dropped evaluations. `flagevaluation.hook.errors` counts caught hook failures separately from writer-owned drops. All 16 review threads have replies. Three contract/design discussions remain open for acknowledgement: code-only errors in full mode, retaining the degraded defensive fold, and the approved `__dd_` metadata prefix. Empty-string preservation already matches the approved amendment and remains unchanged. [FFL-2964]: https://datadoghq.atlassian.net/browse/FFL-2964?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ Co-authored-by: vickie.fridge <vickie.fridge@datadoghq.com>
Description
Implements protected-by-default OpenFeature
flagevaluationtelemetry.sha256_<lowercase hex>over exact UTF-8 bytes. Preserve explicit empty strings; omit missing or invalid keys without dropping evaluation counts.observeFullEvaluationData: truepermits raw valid targeting keys and a bounded immutable context snapshot.DoLogindependence, the kill switch, and the span helper's bare digest format.Supersedes the stale implementation in #19554 and builds on #19881.
Context: FFL-2964, FFL-2529, approved PII RFC, shared implementation guidance.
Testing
Validation refreshed on 2026-09-18 for
1bfd2eab9d36c935999c261bbade7c37a5f4f9cc.scripts/lint checksentrypoint hit generated cache files in its Cython scan; source-scoped checks were run separately.63de8eb2d675e2ebe8428f058b01249674ab5079: dogfooding 18/18 HTTP 200 and 18 evaluations on both sides, no corrupt rows. Installed candidate writer checksum matches source.See the latest two Note to self comments for harness commits, wheel hashes, commands, and first-run/retry counts. New remote CI must finish independently of this local evidence.
Risks / Additional Notes
This intentionally changes the default wire shape. Deterministic unsalted hashes preserve cross-SDK subject joins but remain susceptible to dictionary attacks for low-entropy keys.
Protected mode does not read/copy context attributes; hashing remains in the background worker.
flagevaluation.targeting_key.omitted{reason:invalid}counts rejected inputs that reach aggregation, not transmitted rows or dropped evaluations.flagevaluation.hook.errorscounts caught hook failures separately from writer-owned drops.All 16 review threads have replies. Three contract/design discussions remain open for acknowledgement: code-only errors in full mode, retaining the degraded defensive fold, and the approved
__dd_metadata prefix. Empty-string preservation already matches the approved amendment and remains unchanged.