From c6373a1f38a7a855038cabc30e7e49ed2e1d7488 Mon Sep 17 00:00:00 2001 From: Dave Mihalcik Date: Fri, 29 May 2026 12:05:38 -0400 Subject: [PATCH 1/3] feat(xtest): Adds pure mlkem test scenarios --- xtest/conftest.py | 9 +++++---- xtest/tdfs.py | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/xtest/conftest.py b/xtest/conftest.py index eb2a4be9..e4abd289 100644 --- a/xtest/conftest.py +++ b/xtest/conftest.py @@ -173,12 +173,13 @@ def pytest_configure(config: pytest.Config) -> None: # If the user passed --sdks-encrypt / --sdks-decrypt explicitly, their # tokens win and we skip the resolution step entirely. need_resolve = ( - (not config.getoption("--sdks-encrypt") and scenario.sdks.encrypt) - or (not config.getoption("--sdks-decrypt") and scenario.sdks.decrypt) - ) + not config.getoption("--sdks-encrypt") and scenario.sdks.encrypt + ) or (not config.getoption("--sdks-decrypt") and scenario.sdks.decrypt) if need_resolve: try: - tokens = scenario_to_pytest_sdks(scenario, installed_json_for(scenario_path)) + tokens = scenario_to_pytest_sdks( + scenario, installed_json_for(scenario_path) + ) except FileNotFoundError as e: raise pytest.UsageError(str(e)) from e if not config.getoption("--sdks-encrypt") and tokens["encrypt"]: diff --git a/xtest/tdfs.py b/xtest/tdfs.py index f07f4595..f19b02c8 100644 --- a/xtest/tdfs.py +++ b/xtest/tdfs.py @@ -220,6 +220,11 @@ def __init__(self, **kwargs: dict[str, Any]): if any(a.startswith("mlkem:") for a in algs): self.features.add("mechanism-mlkem") + # Pure ML-KEM (non-hybrid) added by platform PR #3537. Tentatively v0.17.0; + # bump when the release target is finalized. + if self.semver >= (0, 17, 0): + self.features.add("mechanism-mlkem") + print(f"PLATFORM_VERSION '{v}' supports [{', '.join(self.features)}]") def skip_if_unsupported(self, *features: feature_type): From 924db4fd23ffb9fcbc818cc71ab57bdfca3220ff Mon Sep 17 00:00:00 2001 From: Dave Mihalcik Date: Fri, 29 May 2026 12:06:53 -0400 Subject: [PATCH 2/3] fixup: adds scneario file --- xtest/scenarios/pure-mlkem.yaml | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 xtest/scenarios/pure-mlkem.yaml diff --git a/xtest/scenarios/pure-mlkem.yaml b/xtest/scenarios/pure-mlkem.yaml new file mode 100644 index 00000000..c95c8f62 --- /dev/null +++ b/xtest/scenarios/pure-mlkem.yaml @@ -0,0 +1,66 @@ +apiVersion: opentdf.io/v1alpha1 +kind: Scenario +metadata: + id: pure-mlkem + name: pure-mlkem + title: "Pure ML-KEM (mlkem:768 / mlkem:1024) — platform PR #3537" + created: "2026-05-29" +instance: + apiVersion: opentdf.io/v1alpha1 + kind: Instance + metadata: + name: pure-mlkem + platform: + source: + ref: pr:3537 + ports: + base: 8080 + kas: + alpha: { source: { ref: "pr:3537" }, mode: standard } + beta: { source: { ref: "pr:3537" }, mode: standard } + gamma: { source: { ref: "pr:3537" }, mode: standard } + delta: { source: { ref: "pr:3537" }, mode: standard } + km1: { source: { ref: "pr:3537" }, mode: key_management } + km2: { source: { ref: "pr:3537" }, mode: key_management } +sdks: + encrypt: + - sdk: go + version: refs--pull--3537--head + decrypt: + - sdk: go + version: refs--pull--3537--head +suite: + targets: + - test_pqc.py::test_mlkem_768_roundtrip + - test_pqc.py::test_mlkem_1024_roundtrip + containers: + - ztdf +expected: | + Platform built from PR #3537 accepts mlkem:768 and mlkem:1024 managed-key + registrations on km1 (kids m1 / m2). Encrypt with go@pr:3537 produces a + single KAO of type "mlkem-wrapped" whose wrappedKey exceeds the raw + ML-KEM ciphertext (>1088 / >1568 bytes). Decrypt with go@pr:3537 succeeds + and round-trips the plaintext. +actual: | + Both test_mlkem_768_roundtrip and test_mlkem_1024_roundtrip PASS end-to-end + with go@refs--pull--3537--head encrypt + decrypt against PR #3537 platform + (head 08ab3a0a, "refactor(ocrypto): encode pure ML-KEM keys as SPKI/PKCS#8 + with NIST OIDs"). Observed: KAS Registry accepts algorithm enum 20/21, + emits SPKI/PKCS#8 PEMs of the expected sizes (mlkem:768 ≥ 1184B encap key, + mlkem:1024 ≥ 1568B). The KAO `type` field is "wrapped" (the existing + generic type), NOT "mlkem-wrapped" as some PR notes hint — algorithm is + disambiguated via key registry / kid, not a new KAO type. Test assertion + was relaxed to accept either; revisit if the PR later adds a distinct type. + + Decrypt with non-PR clients (Java, JS, older Go) not yet observed — those + SDKs aren't installed in this scenario. Add them to sdks.decrypt and rerun + to answer the "can older clients decrypt mlkem?" question empirically. + + Setup notes (one-time per PR worktree): + 1. Symlinked xtest/platform and xtest/sdk/go/dist → DSPX-3302-02-platform-installer + worktree (uv-tool-installed otdf-sdk-mgr/otdf-local anchor to that worktree). + 2. Seeded PR worktree with kas-*.pem + keys/ + opentdf.yaml from main + (PR source tree ships templates but not generated keys; init-temp-keys.sh + would generate them properly). + 3. Set PLATFORM_VERSION=0.17.0 (override; PR build reports version "0.9.0") + and OTDFCTL_HEADS='["refs--pull--3537--head"]' for the test invocation. From 8be00f940bf2d9ae2ed4ba6f58c77aea4df6f921 Mon Sep 17 00:00:00 2001 From: Dave Mihalcik Date: Tue, 2 Jun 2026 13:40:04 -0400 Subject: [PATCH 3/3] feat(scenario): enable KAS preview features configuration Scenario YAML files can now configure KAS preview settings via the features dict, avoiding manual edits to generated opentdf.yaml files that don't persist through service restarts. - Documents KasPin.features field with open-ended description for forward compatibility with new platform preview settings - Updates pure-mlkem scenario to enable hybrid_tdf_enabled for ML-KEM - Adds FEATURES.md guide with examples and precedence rules - Regenerates JSON schemas from Pydantic models Co-Authored-By: Claude Sonnet 4.5 --- xtest/scenarios/FEATURES.md | 185 ++++++++++++++++++++++++++++++ xtest/scenarios/pure-mlkem.yaml | 21 +++- xtest/schema/instance.schema.json | 2 + xtest/schema/scenario.schema.json | 2 + 4 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 xtest/scenarios/FEATURES.md diff --git a/xtest/scenarios/FEATURES.md b/xtest/scenarios/FEATURES.md new file mode 100644 index 00000000..b06bf228 --- /dev/null +++ b/xtest/scenarios/FEATURES.md @@ -0,0 +1,185 @@ +# KAS Preview Features in Scenario Files + +This guide documents how to configure KAS preview settings via the `features` dict in scenario YAML files. + +## Overview + +The `features` dict in a `KasPin` allows scenario authors to enable platform preview settings for specific KAS instances. Features are written to the generated `opentdf.yaml` as `services.kas.preview.: `. + +**Important:** Available preview settings depend on the platform version and may include experimental features in PRs. This guide provides common examples but is not exhaustive. + +## Basic Usage + +```yaml +instance: + kas: + km1: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true # Enable ML-KEM wrapping +``` + +## Precedence Rules + +Features are applied in order (last wins): + +1. **Template defaults** — from `opentdf-kas-mode.yaml` shipped with the platform +2. **Mode-based auto-enables** — e.g., `key_management` mode sets `ec_tdf_enabled: true` +3. **User features** — specified in scenario YAML (override previous layers) + +This allows you to override mode defaults when needed for testing. + +## Common Preview Settings + +These examples represent common settings as of 2026-06. Check your platform version's documentation for the complete list. + +### `ec_tdf_enabled` + +Enables elliptic-curve wrapping for TDF encryption. + +- **Auto-enabled:** `key_management` mode +- **When to use:** Testing EC wrapping on standard KAS instances +- **Example:** + ```yaml + kas: + alpha: + source: { ref: "v0.15.0" } + mode: standard + features: + ec_tdf_enabled: true + ``` + +### `hybrid_tdf_enabled` + +Enables hybrid post-quantum wrapping (ML-KEM). + +- **Auto-enabled:** Never (requires explicit opt-in) +- **When to use:** Testing ML-KEM encryption scenarios +- **Example:** + ```yaml + kas: + km1: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true # Required for mlkem:768 / mlkem:1024 + ``` + +### `key_management` + +Enables the managed key registry and key provisioning APIs. + +- **Auto-enabled:** `key_management` mode +- **When to use:** Rarely needed explicitly (mode handles it) +- **Example (disabling on key_management KAS for testing):** + ```yaml + kas: + km1: + mode: key_management + features: + key_management: false # Override mode default + ``` + +## Example Scenarios + +### ML-KEM Encryption Testing + +```yaml +instance: + kas: + km1: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true # Accept ML-KEM wrapped KAOs + km2: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true +``` + +### EC Wrapping on Standard KAS + +```yaml +instance: + kas: + alpha: + source: { ref: "v0.15.0" } + mode: standard + features: + ec_tdf_enabled: true # Enable EC without key management +``` + +### Disabling Mode Auto-Enables + +```yaml +instance: + kas: + km1: + mode: key_management + features: + ec_tdf_enabled: false # Override mode's auto-enable for testing +``` + +## Experimental Features in PRs + +Platform PRs may introduce experimental preview settings not listed here. Use the same syntax: + +```yaml +kas: + alpha: + source: { ref: "pr:9999" } + mode: standard + features: + experimental_new_feature: true +``` + +The scenario framework applies all features without validation, making it forward-compatible with new settings. + +## Instance-Level Features + +The `Instance.features` dict is reserved for future use. Currently, only per-KAS features are supported: + +```yaml +instance: + features: {} # Reserved, not implemented + kas: + km1: + features: + hybrid_tdf_enabled: true # Use this instead +``` + +## Verification + +After running `otdf-local instance init` and `otdf-local up`, verify the generated config: + +```bash +grep -A 5 "preview:" instances//kas/km1/opentdf.yaml +``` + +Expected output for a `key_management` KAS with `hybrid_tdf_enabled: true`: + +```yaml +preview: + ec_tdf_enabled: true + hybrid_tdf_enabled: true + key_management: true +``` + +## Troubleshooting + +### Feature not appearing in config + +1. Check the scenario YAML syntax (YAML indentation matters) +2. Verify `otdf-local instance init` ran without errors +3. Check if the feature exists in your platform version + +### Feature value overridden + +Remember precedence: user features override mode defaults. If a mode auto-enables a feature and you don't want it, explicitly set it to `false`. + +### Unknown feature + +Platform versions vary in which preview settings they support. Experimental PRs may have settings not in stable releases. The framework applies all features without validation for forward compatibility. diff --git a/xtest/scenarios/pure-mlkem.yaml b/xtest/scenarios/pure-mlkem.yaml index c95c8f62..b8ac5d63 100644 --- a/xtest/scenarios/pure-mlkem.yaml +++ b/xtest/scenarios/pure-mlkem.yaml @@ -20,8 +20,16 @@ instance: beta: { source: { ref: "pr:3537" }, mode: standard } gamma: { source: { ref: "pr:3537" }, mode: standard } delta: { source: { ref: "pr:3537" }, mode: standard } - km1: { source: { ref: "pr:3537" }, mode: key_management } - km2: { source: { ref: "pr:3537" }, mode: key_management } + km1: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true # Required for ML-KEM wrapping + km2: + source: { ref: "pr:3537" } + mode: key_management + features: + hybrid_tdf_enabled: true # Required for ML-KEM wrapping sdks: encrypt: - sdk: go @@ -37,10 +45,11 @@ suite: - ztdf expected: | Platform built from PR #3537 accepts mlkem:768 and mlkem:1024 managed-key - registrations on km1 (kids m1 / m2). Encrypt with go@pr:3537 produces a - single KAO of type "mlkem-wrapped" whose wrappedKey exceeds the raw - ML-KEM ciphertext (>1088 / >1568 bytes). Decrypt with go@pr:3537 succeeds - and round-trips the plaintext. + registrations on km1 and km2 (kids m1 / m2). KAS instances km1 and km2 have + `hybrid_tdf_enabled: true` in their preview settings to accept ML-KEM wrapped + KAOs. Encrypt with go@pr:3537 produces a single KAO whose wrappedKey exceeds + the raw ML-KEM ciphertext (>1088 / >1568 bytes). Decrypt with go@pr:3537 + succeeds and round-trips the plaintext. actual: | Both test_mlkem_768_roundtrip and test_mlkem_1024_roundtrip PASS end-to-end with go@refs--pull--3537--head encrypt + decrypt against PR #3537 platform diff --git a/xtest/schema/instance.schema.json b/xtest/schema/instance.schema.json index cdf172db..54b57bc7 100644 --- a/xtest/schema/instance.schema.json +++ b/xtest/schema/instance.schema.json @@ -53,6 +53,7 @@ "additionalProperties": { "type": "boolean" }, + "description": "KAS preview settings to enable. Keys are preview setting names (without the 'services.kas.preview.' prefix); values are booleans. Available settings depend on the platform version and may include experimental features in PRs. User-specified features override mode-based defaults.", "title": "Features", "type": "object" }, @@ -224,6 +225,7 @@ "additionalProperties": { "type": "boolean" }, + "description": "Reserved for future use. Instance-level feature defaults are not currently implemented. Use per-KAS features in the kas dict instead.", "title": "Features", "type": "object" }, diff --git a/xtest/schema/scenario.schema.json b/xtest/schema/scenario.schema.json index 426e11c5..4d1b6528 100644 --- a/xtest/schema/scenario.schema.json +++ b/xtest/schema/scenario.schema.json @@ -47,6 +47,7 @@ "additionalProperties": { "type": "boolean" }, + "description": "Reserved for future use. Instance-level feature defaults are not currently implemented. Use per-KAS features in the kas dict instead.", "title": "Features", "type": "object" }, @@ -102,6 +103,7 @@ "additionalProperties": { "type": "boolean" }, + "description": "KAS preview settings to enable. Keys are preview setting names (without the 'services.kas.preview.' prefix); values are booleans. Available settings depend on the platform version and may include experimental features in PRs. User-specified features override mode-based defaults.", "title": "Features", "type": "object" },