Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions xtest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ uv sync --extra dev
pytest
```

### Running xtests against a platform feature branch (CI)

To validate platform changes against the xtest suite without merging:

1. Go to the **Actions** tab in [opentdf/tests](https://github.com/opentdf/tests/actions)
2. Find the **xtest** workflow
3. Click the **"Run workflow"** dropdown on the right
4. Set **"Use workflow from"** to the xtest branch you want to run (e.g. `main`, or a companion xtest branch)
5. Set **"platform ref branch"** to the HEAD commit SHA of your platform feature branch
6. Click **Run workflow**

This builds the platform from your commit and runs the full xtest suite against it. Use this to validate SDK or KAS changes before merging.

#### Run TDF Tests

```shell
Expand Down
7 changes: 7 additions & 0 deletions xtest/sdk/go/cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ if [ "$1" == "supports" ]; then
"${cmd[@]}" --version --json | jq -re .sdk_version | awk -F. '{ if ($1 > 0 || ($1 == 0 && $2 > 3) || ($1 == 0 && $2 == 3 && $3 >= 18)) exit 0; else exit 1; }'
exit $?
;;
tamper-error-split)
# KAS 400 split: generic "bad request" = tamper, descriptive = misconfiguration
# Introduced in go sdk 0.14.0
set -o pipefail
"${cmd[@]}" --version --json | jq -re .sdk_version | awk -F. '{ if ($1 > 0 || ($1 == 0 && $2 >= 14)) exit 0; else exit 1; }'
exit $?
;;
*)
echo "Unknown feature: $2"
exit 2
Expand Down
3 changes: 3 additions & 0 deletions xtest/tdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
"mechanism-ec-curves-384-521",
"ns_grants",
"obligations",
# KAS 400 errors are split: generic "bad request" = tamper (ErrTampered),
# descriptive messages = misconfiguration (ErrKASRequestError).
"tamper-error-split",
]

container_version = Literal["4.2.2", "4.3.0"]
Expand Down
36 changes: 22 additions & 14 deletions xtest/test_tdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,30 +565,38 @@ def assert_tamper_error(
)


def assert_kas_request_error(
def assert_policy_tamper_error(
exc: subprocess.CalledProcessError, decrypt_sdk: tdfs.SDK
) -> None:
Comment thread
dmihalcik-virtru marked this conversation as resolved.
"""Assert that a KAS request error was returned.
"""Assert that a policy binding tamper error was returned.

Used for policy binding failures where KAS rejects the request (400).
Accepts both the new error classification (KAS request error) and the
legacy classification (tamper) for backward compatibility with older
SDK versions.
Policy binding failures (unbound or altered policy) are integrity
failures. KAS intentionally returns a generic "bad request" to avoid
leaking information about secret key computations, and the SDK
classifies this as a tamper error.
"""
if decrypt_sdk.supports("tamper-error-split"):
# SDK distinguishes tamper from misconfiguration — assert tamper specifically
assert re.search(b"tamper", exc.output, re.IGNORECASE), (
f"Expected tamper error, got: [{exc.output}]"
)
assert not re.search(b"KAS request error", exc.output, re.IGNORECASE), (
f"Policy binding failure must not be classified as KAS request error: [{exc.output}]"
)
Comment on lines +578 to +585
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Broaden the strict-mode negative match for request-error classification tokens.

This currently forbids only KAS request error. If output contains KASRequestError/ErrKASRequestError, the test can pass despite wrong classification.

Proposed patch
-        assert not re.search(b"KAS request error", exc.output, re.IGNORECASE), (
+        forbidden = b"|".join(
+            re.escape(p)
+            for p in [b"KAS request error", b"KASRequestError", b"ErrKASRequestError"]
+        )
+        assert not re.search(forbidden, exc.output, re.IGNORECASE), (
             f"Policy binding failure must not be classified as KAS request error: [{exc.output}]"
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xtest/test_tdfs.py` around lines 578 - 585, The negative assertion that
checks exc.output for "KAS request error" is too narrow; update the check in the
block gated by decrypt_sdk.supports("tamper-error-split") to reject any KAS
request-error variants (e.g., "KAS request error", "KASRequestError",
"ErrKASRequestError") by using a case-insensitive regex that matches these
variants against exc.output (still using re.search) so the test fails for any of
those tokens rather than only the exact phrase.

return

# Older SDKs: accept any plausible error output
expected_patterns = [
# New classification: KAS request error
b"KAS request error",
b"rewrap request 400",
b"tamper",
b"bad request",
b"InvalidArgument",
# Legacy classification: tamper (older SDK versions)
b"tamper",
b"rewrap request 400",
b"InvalidFileError",
b"could not find policy in rewrap response",
]
pattern = b"|".join(re.escape(p) for p in expected_patterns)
assert re.search(pattern, exc.output, re.IGNORECASE), (
f"Expected KAS request or tamper error, got: [{exc.output}]"
f"Expected policy tamper error, got: [{exc.output}]"
)


Expand Down Expand Up @@ -628,7 +636,7 @@ def test_tdf_with_unbound_policy(
decrypt_sdk.decrypt(b_file, rt_file, "ztdf", expect_error=True)
assert False, "decrypt succeeded unexpectedly"
except subprocess.CalledProcessError as exc:
assert_kas_request_error(exc, decrypt_sdk)
assert_policy_tamper_error(exc, decrypt_sdk)
Comment thread
dmihalcik-virtru marked this conversation as resolved.

# Verify rewrap failure was logged (policy binding mismatch)
# FIXME: Audit logs are not present on failed bindings
Expand Down Expand Up @@ -669,7 +677,7 @@ def test_tdf_with_altered_policy_binding(
decrypt_sdk.decrypt(b_file, rt_file, "ztdf", expect_error=True)
assert False, "decrypt succeeded unexpectedly"
except subprocess.CalledProcessError as exc:
assert_kas_request_error(exc, decrypt_sdk)
assert_policy_tamper_error(exc, decrypt_sdk)
Comment thread
dmihalcik-virtru marked this conversation as resolved.

# Verify rewrap failure was logged (policy binding mismatch)
# FIXME: Audit logs are not present on failed bindings
Expand Down
Loading