Skip to content

feat(cli): Stage-1 KAS OAuth encrypt/decrypt for ztdf - #47

Merged
arkavo-com merged 2 commits into
mainfrom
feat/cli-kas-stage1
Jul 12, 2026
Merged

feat(cli): Stage-1 KAS OAuth encrypt/decrypt for ztdf#47
arkavo-com merged 2 commits into
mainfrom
feat/cli-kas-stage1

Conversation

@arkavo-com

@arkavo-com arkavo-com commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

OpenTDFKitCLI Stage-1 ztdf interop with go (no nano in Stage-1 matrix).

  • Encrypt: client_credentials + RSA PublicKey fetch + TDFEncryptor
  • Decrypt: ephemeral P-256 rewrap + unwrapKey(salt: Data()) (Standard TDF)
  • Legacy offline PEM/symmetric still available as shortcuts

Test plan

  • swift build -c release --product OpenTDFKitCLI
  • community-xtest swift job green (macos + colima)

Summary by Gitar

  • KAS Stage-1 integration:
    • Implemented getOAuthToken for client_credentials authentication to support modern KAS workflows.
    • Added fetchKASRSAPublicKey to dynamically retrieve RSA keys via ConnectRPC or REST endpoints.
  • Decryption enhancements:
    • Added support for ephemeral P-256 session key rewrap in decryptTDF.
    • Enabled XOR-based key reconstruction for TDF key shares.
  • Configuration & CLI updates:
    • Updated buildTDFConfiguration to support live KAS key fetching and OAuth integration.
    • Expanded xtest feature support in Commands.swift to reflect Stage-1 capabilities.

This will update automatically on new commits.

OpenTDFKitCLI ztdf path for community xtest interop with go:

- Encrypt: client_credentials + RSA PublicKey fetch + existing TDFEncryptor wrap
- Decrypt: ephemeral P-256 rewrap + unwrapKey(salt: empty) for Standard TDF
- supports: honest hexless/connectrpc; unknown features exit 2
Comment thread OpenTDFKitCLI/Commands.swift Outdated
Comment thread OpenTDFKitCLI/main.swift Outdated
Comment thread OpenTDFKitCLI/main.swift Outdated
- Use if-expression assignment for OAuth token URL (conditionalAssignment)
- Use try? when parsing KAS public-key JSON so raw PEM fallback is reachable
- Drop XT_WITH_TARGET_MODE from TDF specVersion (mode name, not schema version)
- Document supports exit codes (0/1/2) matching the xtest contract
- Wrap if statement bodies for SwiftFormat wrapIfStatementBodies
@gitar-bot

gitar-bot Bot commented Jul 12, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 3 resolved / 3 findings

Implements Stage-1 KAS OAuth and P-256 ephemeral decryption for ztdf interoperability, resolving previous JSON parsing errors, spec versioning issues, and exit-code contract inconsistencies. No open findings remain.

✅ 3 resolved
Bug: Raw-PEM KAS response unreachable due to throwing JSON parse

📄 OpenTDFKitCLI/Commands.swift:325-333
In fetchKASRSAPublicKey, the legacy REST branch parses the response with if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] (Commands.swift:325). Because this uses try (not try?), any non-JSON body causes JSONSerialization.jsonObject to throw and propagate out of the function, so the intended raw-PEM fallback on line 331 (if let pem = String(data: data, encoding: .utf8), pem.contains("BEGIN PUBLIC KEY")) is never reached. Any KAS deployment that returns a raw -----BEGIN PUBLIC KEY----- body with HTTP 200 (exactly the case the comment on line 330 anticipates) will fail public-key fetch instead of succeeding. Use try? so a JSON parse failure falls through to the raw-PEM check.

Bug: specVersion falls back to XT_WITH_TARGET_MODE (mode name, not version)

📄 OpenTDFKitCLI/main.swift:589
In buildTDFConfiguration, specVersion is set to env["TDF_SPEC_VERSION"] ?? env["XT_WITH_TARGET_MODE"] ?? "4.3.0" (main.swift:589). XT_WITH_TARGET_MODE is a target-mode identifier (e.g. "nano"/"zip"/"hexless" as read raw in Config.swift), not a TDF spec version string like "4.3.0". If that variable is present in the environment (likely under the xtest harness) it will be written directly into the manifest as the spec/schema version, producing a malformed manifest and breaking interop. The mimeType fallback to XT_WITH_MIME_TYPE on line 579 is appropriate, but a target-mode value should be mapped to a valid spec version rather than used verbatim.

Quality: supportsCommand default now returns 2, changing exit-code contract

📄 OpenTDFKitCLI/main.swift:762-763
The default branch of supportsCommand was changed from return 1 to return 2 // unknown feature (main.swift:762-763). Previously both "unsupported" and "unknown" features returned 1. If the xtest/community harness only distinguishes 0 (supported) vs non-zero (unsupported), this is harmless, but if it treats any exit code other than 0/1 as a hard error (crash/misconfiguration), unknown feature probes will now be reported as failures rather than "unsupported". Confirm the harness's interpretation of exit code 2 before relying on this distinction.

Was this helpful? React with 👍 / 👎 | Gitar

1 similar comment
@gitar-bot

gitar-bot Bot commented Jul 12, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 3 resolved / 3 findings

Implements Stage-1 KAS OAuth and P-256 ephemeral decryption for ztdf interoperability, resolving previous JSON parsing errors, spec versioning issues, and exit-code contract inconsistencies. No open findings remain.

✅ 3 resolved
Bug: Raw-PEM KAS response unreachable due to throwing JSON parse

📄 OpenTDFKitCLI/Commands.swift:325-333
In fetchKASRSAPublicKey, the legacy REST branch parses the response with if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] (Commands.swift:325). Because this uses try (not try?), any non-JSON body causes JSONSerialization.jsonObject to throw and propagate out of the function, so the intended raw-PEM fallback on line 331 (if let pem = String(data: data, encoding: .utf8), pem.contains("BEGIN PUBLIC KEY")) is never reached. Any KAS deployment that returns a raw -----BEGIN PUBLIC KEY----- body with HTTP 200 (exactly the case the comment on line 330 anticipates) will fail public-key fetch instead of succeeding. Use try? so a JSON parse failure falls through to the raw-PEM check.

Bug: specVersion falls back to XT_WITH_TARGET_MODE (mode name, not version)

📄 OpenTDFKitCLI/main.swift:589
In buildTDFConfiguration, specVersion is set to env["TDF_SPEC_VERSION"] ?? env["XT_WITH_TARGET_MODE"] ?? "4.3.0" (main.swift:589). XT_WITH_TARGET_MODE is a target-mode identifier (e.g. "nano"/"zip"/"hexless" as read raw in Config.swift), not a TDF spec version string like "4.3.0". If that variable is present in the environment (likely under the xtest harness) it will be written directly into the manifest as the spec/schema version, producing a malformed manifest and breaking interop. The mimeType fallback to XT_WITH_MIME_TYPE on line 579 is appropriate, but a target-mode value should be mapped to a valid spec version rather than used verbatim.

Quality: supportsCommand default now returns 2, changing exit-code contract

📄 OpenTDFKitCLI/main.swift:762-763
The default branch of supportsCommand was changed from return 1 to return 2 // unknown feature (main.swift:762-763). Previously both "unsupported" and "unknown" features returned 1. If the xtest/community harness only distinguishes 0 (supported) vs non-zero (unsupported), this is harmless, but if it treats any exit code other than 0/1 as a hard error (crash/misconfiguration), unknown feature probes will now be reported as failures rather than "unsupported". Confirm the harness's interpretation of exit code 2 before relying on this distinction.

Was this helpful? React with 👍 / 👎 | Gitar

@arkavo-com
arkavo-com merged commit 0fc4876 into main Jul 12, 2026
6 checks passed
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