Skip to content

Commit 79b52cd

Browse files
aepfliCopilot
andauthored
feat: add YAML flag configuration loading with schema validation (#7)
* feat: add YAML flag configuration loading with schema validation - Add serde_yaml dependency (non-WASM only) to Rust core and Python crate - Add src/yaml.rs with yaml_to_json() conversion helper - Add FlagEvaluator::update_state_from_yaml() in Rust (non-WASM only) - Add FlagEvaluator.updateStateFromYaml() in Java with SnakeYAML - Add update_state_from_yaml() in Python PyO3 bindings - Expose yaml module in lib.rs (non-WASM only) - Add Rust integration tests (yaml_tests module) - Add Java YamlLoadingTest - Add Python tests/test_yaml.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> * fix(yaml): address review comments and fix formatting - Extract static YAML_PARSER field in Java FlagEvaluator - Simplify exception handling in updateStateFromYaml - Use complete JSON equivalent in Java parity test - Extract update_caches_from_response helper in Python - Use complete JSON equivalent in Python parity test - Fix Rust formatting (cargo fmt) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> * feat(java): auto-detect JSON vs YAML in updateState Addresses review comment: consumers should not need to specify the string format. updateState now detects JSON (starts with '{') and treats everything else as YAML, converting via SnakeYAML before passing to the WASM boundary. updateStateFromYaml is kept for explicitness but delegates to updateState. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> * feat: move YAML conversion into WASM module serde_yaml 0.9 compiles to wasm32-unknown-unknown, so YAML conversion can be owned by the WASM module rather than each language binding. - Move serde_yaml from cfg-gated to regular [dependencies] - Remove #[cfg(not(target_family = "wasm"))] gate from yaml module - Remove cfg gate from FlagEvaluator::update_state_from_yaml - Expose update_state_from_yaml as a WASM export - update_state auto-detects JSON vs YAML ('{' prefix = JSON, else YAML) - Remove cfg gate from yaml_tests in integration_tests.rs - Remove SnakeYAML dependency from Java (no host-side conversion) - Simplify Java updateState to pass raw string directly to WASM - updateInstance now throws EvaluatorException on success=false - Remove serde_yaml from Python binding Cargo.toml - Python update_state_from_yaml delegates to inner.update_state_from_yaml Bindings are now format-agnostic: pass JSON or YAML, WASM handles both. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> * refactor: unified update_state API accepts JSON or YAML string The WASM module now owns YAML conversion — serde_yaml 0.9 compiles to wasm32-unknown-unknown so no host-side conversion is needed. - update_state WASM export auto-detects JSON (starts with '{') vs YAML - Remove update_state_from_yaml WASM export (redundant) - Java: remove SnakeYAML dependency, updateState passes raw string to WASM - Python: update_state accepts str (JSON or YAML), remove update_state_from_yaml - Update all Python tests to pass JSON strings instead of dicts - serde_yaml promoted to regular dependency (no cfg gates) - Add use pyo3::types::PyDict (not re-exported by pyo3::prelude in 0.22) - Serialize WASM unit tests with static mutex to prevent global-state races Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> * refactor: remove updateStateFromYaml convenience method The WASM module owns YAML/JSON detection via update_state. There is no need for a separate convenience method — updateState(String) accepts both formats transparently. Remove updateStateFromYaml from Java and update tests to call updateState directly. Clean up stale comment in Python bindings. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: handle new CompiledNode variants from datalogic-rs 4.0.18 datalogic-rs 4.0.18 added CompiledVar, CompiledExists, CompiledSplitRegex and CompiledStringConcat variants to CompiledNode. The walk_node_for_vars match was non-exhaustive. Add a wildcard arm that conservatively returns false (send full context) for any unknown variants. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(evaluator): handle CompiledVar/CompiledExists nodes and fix getrandom for WASM datalogic-rs 4.0.18 introduced dedicated CompiledVar and CompiledExists nodes replacing BuiltinOperator { opcode: Var/Exists }. Update walk_node_for_vars to extract variable paths from PathSegment slices so required_context_keys works correctly and optimization tests pass. Also replace the wasm_js getrandom feature (browser-only) with the unsupported cfg backend via .cargo/config.toml. This eliminates __wbg_getRandomValues imports that broke wasmtime, Chicory, and wazero runtimes. The evaluator never calls getrandom at runtime since murmurhash3 is fully deterministic. Regenerate flagd_evaluator.wasm with the clean WASM binary. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(evaluator): update CompiledNode variant matching for datalogic-rs fork Switch to tuple-variant syntax for CustomOperator, StructuredObject, CompiledExists, CompiledSplitRegex, CompiledThrow to match the refactored struct layout in the patched datalogic-rs fork. Use [patch.crates-io] with git URL pointing to fix/wasm-wasmbind-unconditional branch in aepfli/datalogic-rs, which removes the unconditional chrono/wasmbind dependency on wasm32 targets. This eliminates __wbg_* browser imports that break wasmtime, Chicory, and wazero. PR upstream: GoPlasmatic/datalogic-rs#48. Regenerate flagd_evaluator.wasm — binary is now clean of wasm-bindgen imports. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(wasm): use datalogic-rs 4.0.19, no wasm-bindgen imports Switch from git-patched fork to registry datalogic-rs 4.0.19 which fixed the WASM browser dependency issue properly: the 'wasm' feature (chrono/wasmbind) is now opt-in and disabled by default. Use getrandom_backend="unsupported" cfg flag since nothing in the evaluation path calls getrandom at runtime (ahash uses compile-time-rng, murmurhash3 is deterministic). This produces a fully clean WASM binary with zero __wbg_* imports. Update walk_node_for_vars to use 4.0.19's tuple-variant CompiledNode API (CustomOperator, StructuredObject, CompiledExists, CompiledSplitRegex, CompiledThrow). Result: flagd_evaluator.wasm has no wasm-bindgen imports at all — compatible with Chicory, wazero, Wasmtime, and any other non-browser WASM runtime. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(wasm): provide custom getrandom backend to prevent runtime panic ahash's default features include runtime-rng, which calls getrandom at startup to XOR a runtime-random value into the compile-time seed. With getrandom_backend="unsupported", this panicked (unreachable trap) on every update_state call across all language runtimes. Switch to getrandom_backend="custom" and define __getrandom_v03_custom to fill with zeros. This is safe: ahash already has a strong compile-time seed via const-random, and the evaluator has no cryptographic randomness requirements. Result: zero __wbg_* imports, no runtime panics. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: update Cargo.lock for getrandom 0.3 custom backend dep Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(dotnet): make wasm-bindgen imports optional in WasmRuntime The WASM binary no longer has __wbindgen_placeholder__ imports since switching to getrandom_backend="custom". WasmRuntime now only requires host::get_current_time_unix_seconds and gracefully skips registration of any wasm-bindgen functions that are absent from the module. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: update HOST_FUNCTIONS.md to reflect single import The WASM module now has only one import: host::get_current_time_unix_seconds. All wasm-bindgen imports (__wbindgen_placeholder__, __wbindgen_externref_xform__) were eliminated by switching to getrandom_backend="custom" and datalogic-rs without the wasm feature. Update docs and java/README.md accordingly. Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 63b7879 commit 79b52cd

18 files changed

Lines changed: 915 additions & 445 deletions

File tree

‎.cargo/config.toml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Cargo configuration for flagd-evaluator
22

33
# Disable SIMD for WASM target (Chicory doesn't support V128/SIMD128)
4+
# Use "custom" getrandom backend: ahash's runtime-rng feature calls getrandom to
5+
# augment its compile-time seed. We provide a stub that fills with zeros — safe for
6+
# HashMap seeding in a deterministic evaluator, and avoids pulling in wasm-bindgen.
47
[target.wasm32-unknown-unknown]
58
rustflags = [
6-
"-C", "target-feature=-simd128"
9+
"-C", "target-feature=-simd128",
10+
"--cfg", "getrandom_backend=\"custom\""
711
]

0 commit comments

Comments
 (0)