Skip to content

feat(browser): add opt-in response verification and trusted cache admission - #436

Draft
leoromanovsky wants to merge 6 commits into
leo.romanovsky/response-signing-verifier-20261027from
leo.romanovsky/response-signing-browser-20261027
Draft

leoromanovsky wants to merge 6 commits into
leo.romanovsky/response-signing-verifier-20261027from
leo.romanovsky/response-signing-browser-20261027

Conversation

@leoromanovsky

@leoromanovsky leoromanovsky commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

Customers need optional response verification that can roll out safely as SDKs become available. Applications can observe signatures without disrupting otherwise-valid flag delivery, then require verified responses when ready. Authentication, transport failures and context changes must keep their ordinary behavior.

Changes

Build on verifier #435 with responseSigning modes off (default), observe and required, plus DatadogProvider.responseSigningVersion = 1 for capability checks. Observe accepts otherwise-valid unsigned or unverifiable responses with bounded diagnostics. Required rejects them without an unsigned retry. No production root is bundled; public roots must be configured explicitly.

flowchart LR
  Fetch[One assignment fetch] --> HTTP[HTTP and redirect checks]
  HTTP --> Verify[Exact-byte v1 verification]
  Verify --> Parse[JSON and opt-out validation]
  Parse --> Admission[Abort and context admission]
  Admission --> Observe[Observe: ordinary cache and separate verified fallback]
  Admission --> Required[Required: verified memory only]
Loading

Required evaluations recheck the original proof expiry and full context. Bootstrap and persisted data never become trusted required-mode state. Observe preserves ordinary persistence in a full-scope namespace, with a one-time cold start, and keeps verified fallback separate. Cancellation and context changes prevent late responses from replacing current assignments. Disabling server signing cannot weaken a client's explicit required policy.

Public protocol v1 covers the request headers, transcript and persistent namespace; X.509 v3 encoding is unchanged. Each signed response includes its full leaf/intermediate chain, allowing rotation under an unchanged root without another fetch. Signed responses are currently buffered JSON. When signing preparation succeeds, observe and required requests send X-stream: false; off mode retains ordinary transport selection. Custom proxies must forward this header and permit it in CORS preflights. Existing unsigned streaming remains available; signed NDJSON checkpoints for early critical flags are not implemented here.

The prototype CDN comparison added about 34 KiB gzip overall, including off mode; the ASN.1 parser is included in the bundle. This size comparison has not been rerun for v1. An optional parser entrypoint is a possible follow-up. Production roots and browser deployment validation remain release prerequisites. The implementation and tests were AI-assisted.

Test instructions

At 7dd920263a4719ed35bdcd1ce5a449204f8749dc, all 656 browser tests across 32 suites pass. Typecheck and CommonJS/ESM/bundle builds pass. Coverage includes the buffered transport override in observe/required modes, unchanged default-off headers, real cryptography, one fetch, protocol cache isolation, required expiry/restart, observe persistence, HTTP/redirect failures, and context changes. The verifier and integration now consume fixture commit b57eac6711204a906f0b24e127124a03314e35a9 from main.

The unit suite uses jsdom and Node WebCrypto. The added header assertions failed in observe and required modes before the fix. No staging or fleet rollout is claimed.

Tested commit Validation Result
DataDog/openfeature-js-client@7dd920263a4719ed35bdcd1ce5a449204f8749dc Manual browser integration: buffered transport, CORS preflight, and public v1 proof verification; Chromium with a synthetic HTTPS endpoint and test root 3 modes passed; one assignment request per mode. Off omitted the override; observe and required sent it and verified the proof. Test TLS certificate validation was bypassed; staging TLS and customer proxies remain unvalidated

Checklist

  • Updated Documentation
  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change — provider/transport integration runs locally; v1 browser deployment validation remains pending.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

OpenFeature Browser Provider Bundle Sizes

Measured from the Vite production output after installing packed @datadog/flagging-core and @datadog/openfeature-browser tarballs.

Both scenarios initialize an OpenFeature provider, evaluate a boolean flag, change context, and evaluate again. Telemetry is disabled for DatadogProvider; no tracking hooks are registered for DatadogCoreProvider. DatadogProvider fetches precomputed assignments for each context; DatadogCoreProvider receives rules from fetchRulesConfiguration once and evaluates locally.

Sizes include OpenFeature and the same small scenario harness. Configuration responses are supplied by Playwright and are not bundled. These are complete scenario JS sizes, not configuration payload sizes or isolated provider/Protobuf costs; the difference between rows is not a decoder-only delta.

Scenario HTML JS Assets Raw JS Gzip JS Protobuf Markers
DatadogProvider (precomputed fetching) provider.html 18 233.6 KiB 71.0 KiB no
DatadogCoreProvider + fetchRulesConfiguration core-provider.html 15 300.4 KiB 86.9 KiB yes

Dependency checks passed: no Protobuf markers in default/precomputed scenarios; markers present in rules-based scenarios.

OpenFeature Browser Tracking Hook Bundle Sizes

Synthetic entrypoints import and call tracking hook factories from the packed @datadog/openfeature-browser/rules-based ESM package. Deltas are measured against the no-hook baseline from the same Vite production build.

Scenario HTML JS Assets Raw JS Raw Δ Gzip JS Gzip Δ
tracking hook baseline tracking-baseline.html 6 2.7 KiB 0 B 1.6 KiB 0 B
exposure logging hook tracking-exposure.html 13 199.1 KiB +196.5 KiB 59.4 KiB +57.8 KiB
evaluation logging hook tracking-evaluation.html 13 195.5 KiB +192.8 KiB 58.1 KiB +56.5 KiB
RUM tracking hook tracking-rum.html 9 6.7 KiB +4.1 KiB 3.6 KiB +2.0 KiB
all tracking hooks tracking-all.html 16 203.5 KiB +200.8 KiB 61.5 KiB +59.9 KiB

OpenFeature Node Server Bundle Sizes

Independent Webpack production builds of the installed core and Node SDK tarballs, targeting Node 18 with ESM (module export condition). Node built-ins remain external. OpenFeature, dd-trace, and configuration fixtures are not bundled.

Scenario Raw JS Gzip JS Protobuf Modules
Node provider only 39.3 KiB 12.5 KiB no
SSR helpers only (fetch client rules + serialize) 80.8 KiB 23.4 KiB yes
Node provider + SSR helpers 119.0 KiB 34.7 KiB yes

Adding SSR helpers to the provider adds 79.7 KiB raw / 22.2 KiB gzip in this build. This includes fetching, parsing, and serialization, not just the decoder. SSR helpers fetch rules for the browser, not for configuring that provider (which uses its existing JSON API).

These are bundler sizes, not npm install sizes, unbundled Node require/import costs, payload sizes, or latency. Gzip compares compressed artifacts. The browser scenarios include OpenFeature and a different harness, so their sizes are not directly comparable.

Dependency checks passed: no Protobuf runtime or generated schema modules in the provider-only bundle; present in both SSR bundles (checked using Webpack module statistics).

This report shows current PR artifact sizes only; it does not compare against the base branch.

…ider

Merge the v1 verifier and shared fixtures without rewriting the draft stack.
Use v1 request negotiation, runtime detection and isolated cache identity.
Preserve opt-in behavior and a single assignment fetch without fallback retry.
Merge the verifier fixture refresh into the integration stack.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant