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/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 new file mode 100644 index 00000000..b8ac5d63 --- /dev/null +++ b/xtest/scenarios/pure-mlkem.yaml @@ -0,0 +1,75 @@ +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 + 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 + 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 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 + (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. 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" }, 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):