Skip to content
Merged
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
6 changes: 2 additions & 4 deletions .github/check_entitlements.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
#!/bin/bash


# Derive additional environment variables
TOKEN_URL="${OIDC_OP_TOKEN_ENDPOINT}"
OTDF_HOST_AND_PORT="${OPENTDF_PLATFORM_HOST}"
OTDF_CLIENT="${OPENTDF_CLIENT_ID}"
OTDF_CLIENT_SECRET="${OPENTDF_CLIENT_SECRET}"

# Enable debug mode
DEBUG=1

echo "🔧 Environment Configuration:"
echo " TOKEN_URL: ${TOKEN_URL}"
echo " OTDF_HOST_AND_PORT: ${OTDF_HOST_AND_PORT}"
Expand All @@ -28,6 +24,8 @@ get_token() {

echo "🔐 Getting access token..."
BEARER=$( get_token | jq -r '.access_token' )
# NOTE: It's always okay to print this token, because it will
# only be valid / available in dummy / dev scenarios
[[ "${DEBUG:-}" == "1" ]] && echo "Got Access Token: ${BEARER}"
echo ""

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/platform-integration-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ jobs:
OIDC_TOKEN_ENDPOINT: "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token"
OPENTDF_KAS_URL: "http://localhost:8080/kas"
INSECURE_SKIP_VERIFY: "TRUE"
TEST_OPENTDF_ATTRIBUTE_1: "https://example.com/attr/attr1/value/value1"
TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value2"
TEST_OPENTDF_ATTRIBUTE_1: "https://example.net/attr/attr1/value/value1"
TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value1"
run: |
uv sync
# Skip the tests marked "integration"
Expand All @@ -180,8 +180,8 @@ jobs:
OIDC_OP_TOKEN_ENDPOINT: "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token"
OPENTDF_KAS_URL: "http://localhost:8080/kas"
INSECURE_SKIP_VERIFY: "TRUE"
TEST_OPENTDF_ATTRIBUTE_1: "https://example.com/attr/attr1/value/value1"
TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value2"
TEST_OPENTDF_ATTRIBUTE_1: "https://example.net/attr/attr1/value/value1"
TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value1"
run: |
# Run check_entitlements.sh
./.github/check_entitlements.sh
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# Edit at https://www.toptal.com/developers/gitignore?templates=python

platform/

tests/integration/test_data/v4.2.2/*tdf
tests/integration/test_data/v4.3.1/*tdf
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
55 changes: 30 additions & 25 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,34 @@ exclude: |
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks#
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
args: ["--ignore-words-list", "b-long, otdf_python", "--skip=go.sum,otdf_python/"]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
args:
[
"--ignore-words-list",
"b-long, otdf_python",
"--skip=uv.lock,otdf-python-proto/uv.lock",
]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.12.12
hooks:
# Run the linter.
- id: ruff
# Run the formatter.
- id: ruff-format
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v4.2.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg,post-rewrite]
args: [--verbose,--scopes="feat,fix,docs,style,test,chore,ci"]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.12.12
hooks:
# Run the linter.
- id: ruff-check
# Run the formatter.
- id: ruff-format
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v4.2.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
args: [--verbose, --scopes="feat, fix, docs, style, test, chore, ci"]
3 changes: 1 addition & 2 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
".": "0.3.2",
"otdf-python-proto": "0.3.2"
".": "0.3.2"
}
9 changes: 8 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
loaded by pytest when running tests.
"""

from pathlib import Path

import pytest

from tests.server_logs import log_server_logs_on_failure


@pytest.fixture(scope="session")
def project_root(request) -> Path:
return request.config.rootpath # Project root


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""
Expand Down Expand Up @@ -43,7 +51,6 @@ def pytest_runtest_makereport(item, call):
log_server_logs_on_failure(test_name)


# Optional: Add a fixture to manually collect logs
@pytest.fixture
def collect_server_logs():
"""
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ lint.select = [
"C4",
# McCabe complexity
"C90",
# isort
"I",
# Performance-related rules
"PERF", # Ruff's performance rules
# Additional useful rules
Expand Down
4 changes: 2 additions & 2 deletions src/otdf_python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
Provides both programmatic APIs and command-line interface for encryption and decryption.
"""

from .cli import main as cli_main
from .config import KASInfo, NanoTDFConfig, TDFConfig
from .sdk import SDK
from .sdk_builder import SDKBuilder
from .config import TDFConfig, NanoTDFConfig, KASInfo
from .cli import main as cli_main

__all__ = [
"SDK",
Expand Down
3 changes: 2 additions & 1 deletion src/otdf_python/aesgcm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

from cryptography.hazmat.primitives.ciphers.aead import AESGCM


class AesGcm:
GCM_NONCE_LENGTH = 12
Expand Down
5 changes: 2 additions & 3 deletions src/otdf_python/asym_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
Asymmetric encryption and decryption utilities for RSA keys in PEM format.
"""

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.x509 import load_pem_x509_certificate

from .sdk_exceptions import SDKException
Expand Down
8 changes: 4 additions & 4 deletions src/otdf_python/asym_decryption.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
import base64

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

from .sdk_exceptions import SDKException


Expand Down
10 changes: 5 additions & 5 deletions src/otdf_python/asym_encryption.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
import base64
import re

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.x509 import load_pem_x509_certificate

from .sdk_exceptions import SDKException


Expand Down
48 changes: 21 additions & 27 deletions src/otdf_python/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
"""

import argparse
import contextlib
import json
import logging
import sys
from dataclasses import asdict
from io import BytesIO
from pathlib import Path

from otdf_python.sdk_builder import SDKBuilder
from otdf_python.config import KASInfo, NanoTDFConfig, TDFConfig
from otdf_python.sdk import SDK
from otdf_python.config import TDFConfig, NanoTDFConfig, KASInfo
from otdf_python.tdf import TDFReaderConfig
from otdf_python.sdk_builder import SDKBuilder
from otdf_python.sdk_exceptions import SDKException
import contextlib

from otdf_python.tdf import TDFReaderConfig

# Version - get from project metadata
__version__ = "0.3.2"
Expand Down Expand Up @@ -355,27 +355,21 @@ def cmd_inspect(args):
# Validate input file
input_path = validate_file_exists(args.file)

# For inspection, we don't need full authentication
# Create a minimal SDK for reading metadata
# For inspection, try to create authenticated SDK, but allow unauthenticated inspection too
try:
builder = SDKBuilder()
if args.platform_url:
builder.set_platform_endpoint(args.platform_url)

# For inspection, we may not need authentication depending on the TDF
if args.client_id and args.client_secret:
builder.client_secret(args.client_id, args.client_secret)
elif args.auth:
auth_parts = args.auth.split(":")
if len(auth_parts) == 2:
builder.client_secret(auth_parts[0], auth_parts[1])

if args.plaintext:
builder.use_insecure_plaintext_connection(True)
if args.insecure:
builder.use_insecure_skip_verify(True)

sdk = builder.build()
try:
sdk = build_sdk(args)
except CLIError as auth_error:
# If authentication fails, create minimal SDK for basic inspection
logger.warning(f"Authentication failed, using minimal SDK: {auth_error}")
builder = SDKBuilder()
if args.platform_url:
builder.set_platform_endpoint(args.platform_url)
if hasattr(args, "plaintext") and args.plaintext:
builder.use_insecure_plaintext_connection(True)
if args.insecure:
builder.use_insecure_skip_verify(True)
sdk = builder.build()
Comment on lines +365 to +372
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This block of code for creating a minimal SDK duplicates logic from the build_sdk function, specifically setting the platform endpoint and security flags. This duplication can lead to maintenance issues if build_sdk is updated but this block is not. Consider refactoring to reduce duplication. For example, you could create a helper function that configures a SDKBuilder with common options from args, which both build_sdk and this fallback logic can use.


try:
# Read encrypted file
Expand All @@ -395,12 +389,12 @@ def cmd_inspect(args):
try:
data_attributes = [] # This would need to be implemented in the SDK
inspection_result = {
"manifest": manifest,
"manifest": asdict(manifest),
"dataAttributes": data_attributes,
}
except Exception as e:
logger.warning(f"Could not retrieve data attributes: {e}")
inspection_result = {"manifest": manifest}
inspection_result = {"manifest": asdict(manifest)}

print(json.dumps(inspection_result, indent=2, default=str))
else:
Expand Down
2 changes: 1 addition & 1 deletion src/otdf_python/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from dataclasses import dataclass, field
from enum import Enum
from urllib.parse import urlparse, urlunparse
from typing import Any
from urllib.parse import urlparse, urlunparse


class TDFFormat(Enum):
Expand Down
7 changes: 4 additions & 3 deletions src/otdf_python/crypto_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import hmac
import hashlib
from cryptography.hazmat.primitives.asymmetric import rsa, ec
from cryptography.hazmat.primitives import serialization
import hmac

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec, rsa


class CryptoUtils:
Expand Down
5 changes: 3 additions & 2 deletions src/otdf_python/dpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
DPoP (Demonstration of Proof-of-Possession) token generation utilities.
"""

import time
import hashlib
import base64
import hashlib
import time

import jwt

from .crypto_utils import CryptoUtils
Expand Down
10 changes: 5 additions & 5 deletions src/otdf_python/eckeypair.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.serialization import (
Encoding,
PublicFormat,
PrivateFormat,
NoEncryption,
PrivateFormat,
PublicFormat,
)
from cryptography.hazmat.backends import default_backend
from cryptography.exceptions import InvalidSignature


class ECKeyPair:
Expand Down
6 changes: 3 additions & 3 deletions src/otdf_python/header.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from otdf_python.resource_locator import ResourceLocator
from otdf_python.constants import MAGIC_NUMBER_AND_VERSION
from otdf_python.ecc_mode import ECCMode
from otdf_python.symmetric_and_payload_config import SymmetricAndPayloadConfig
from otdf_python.policy_info import PolicyInfo
from otdf_python.constants import MAGIC_NUMBER_AND_VERSION
from otdf_python.resource_locator import ResourceLocator
from otdf_python.symmetric_and_payload_config import SymmetricAndPayloadConfig


class Header:
Expand Down
Loading
Loading