Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.12.12
rev: v0.13.1
hooks:
# Run the linter.
- id: ruff-check
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ decrypted_data = tdf_reader.payload
with open("decrypted.txt", "wb") as f:
f.write(decrypted_data)

# Don't forget to close the SDK when done
sdk.close()
```

## Project Structure
Expand Down
10 changes: 5 additions & 5 deletions otdf-python-proto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ See [CONNECT_RPC.md](../docs/CONNECT_RPC.md) for additional information.
## Structure

- `proto-files/`: Contains the raw .proto files downloaded from the OpenTDF platform
- `generated/`: Contains the generated Python protobuf and Connect RPC client files
- `src/otdf_python_proto/`: Contains the generated Python protobuf and Connect RPC client files
- `scripts/`: Contains build scripts for generating protobuf and Connect RPC files
- `buf.yaml`: Buf configuration for proto validation and management
- `buf.gen.yaml`: Buf generation configuration for Connect RPC and protobuf
Expand All @@ -40,10 +40,10 @@ Or use the convenience script:
```

This generates:
- `generated/*_connect.py` - Connect RPC clients (preferred)
- `generated/*_pb2.py` - Standard protobuf classes
- `generated/*_pb2.pyi` - Type stubs for better IDE support
- `generated/legacy_grpc/*_pb2_grpc.py` - Legacy gRPC clients (backward compatibility)
- `src/otdf_python_proto/**/*_connect.py` - Connect RPC clients (preferred)
- `src/otdf_python_proto/**/*_pb2.py` - Standard protobuf classes
- `src/otdf_python_proto/**/*_pb2.pyi` - Type stubs for better IDE support
- `src/otdf_python_proto/legacy_grpc/**/*_pb2_grpc.py` - Legacy gRPC clients (backward compatibility)

### Legacy gRPC Generation

Expand Down
12 changes: 6 additions & 6 deletions otdf-python-proto/scripts/generate_connect_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ def copy_opentdf_proto_files(proto_gen_dir: Path) -> bool:
print(f" Copying {relative_path}...")

# Copy the file content
with open(proto_file) as src:
with proto_file.open() as src:
content = src.read()

with open(dest_path, "w") as dst:
with dest_path.open("w") as dst:
dst.write(content)

copied_files += 1
Expand Down Expand Up @@ -155,15 +155,15 @@ def run_buf_generate(proto_gen_dir: Path) -> bool:

# Update buf.gen.yaml with the correct path
buf_gen_path = proto_gen_dir / "buf.gen.yaml"
with open(buf_gen_path) as f:
with buf_gen_path.open() as f:
content = f.read()

# Replace the local plugin path
updated_content = content.replace(
"- local: protoc-gen-connect_python", f"- local: {connect_plugin_path}"
)

with open(buf_gen_path, "w") as f:
with buf_gen_path.open("w") as f:
f.write(updated_content)

# Run buf generate
Expand Down Expand Up @@ -221,7 +221,7 @@ def _fix_ignore_if_default_value(proto_files_dir):
# Iterate all .proto files in the directory
for proto_file in proto_files_dir.glob("**/*.proto"):
try:
with open(proto_file, "r") as file: # noqa: UP015
with proto_file.open("r") as file:
content = file.read()

# Replace the old enum value with the new one
Expand All @@ -230,7 +230,7 @@ def _fix_ignore_if_default_value(proto_files_dir):
)

# Write the updated content back to the file
with open(proto_file, "w") as file:
with proto_file.open("w") as file:
file.write(updated_content)

print(f"Updated {proto_file.name} to use IGNORE_IF_ZERO_VALUE")
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ lint.select = [
"I",
# Performance-related rules
"PERF", # Ruff's performance rules
"PTH", # pathlib (path handling)
# Additional useful rules
"UP", # pyupgrade (modern Python features)
"SIM", # flake8-simplify (simplifications)
Expand Down
18 changes: 9 additions & 9 deletions src/otdf_python/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def load_client_credentials(creds_file_path: str) -> tuple[str, str]:
"CRITICAL", f"Credentials file does not exist: {creds_file_path}"
)

with open(creds_path) as f:
with creds_path.open() as f:
creds = json.load(f)

client_id = creds.get("clientId")
Expand Down Expand Up @@ -223,13 +223,13 @@ def cmd_encrypt(args):

try:
# Read input file
with open(input_path, "rb") as input_file:
with input_path.open("rb") as input_file:
payload = input_file.read()

# Determine output
if args.output:
output_path = Path(args.output)
with open(output_path, "wb") as output_file:
with output_path.open("wb") as output_file:
try:
# Create appropriate config based on container type
container_type = getattr(args, "container_type", "tdf")
Expand All @@ -247,7 +247,7 @@ def cmd_encrypt(args):
logger.debug("Creating TDF")
config = create_tdf_config(sdk, args)
output_stream = BytesIO()
manifest, size, _ = sdk.create_tdf(
_manifest, size, _ = sdk.create_tdf(
BytesIO(payload), config, output_stream
)
output_file.write(output_stream.getvalue())
Expand All @@ -274,7 +274,7 @@ def cmd_encrypt(args):
logger.debug("Creating TDF")
config = create_tdf_config(sdk, args)
output_stream = BytesIO()
manifest, size, _ = sdk.create_tdf(
_manifest, size, _ = sdk.create_tdf(
BytesIO(payload), config, output_stream
)
output_file.write(output_stream.getvalue())
Expand All @@ -296,13 +296,13 @@ def cmd_decrypt(args):

try:
# Read encrypted file
with open(input_path, "rb") as input_file:
with input_path.open("rb") as input_file:
encrypted_data = input_file.read()

# Determine output
if args.output:
output_path = Path(args.output)
with open(output_path, "wb") as output_file:
with output_path.open("wb") as output_file:
try:
# Try to determine if it's a NanoTDF or regular TDF
# NanoTDFs have a specific header format, regular TDFs are ZIP files
Expand Down Expand Up @@ -359,7 +359,7 @@ def cmd_inspect(args):

try:
# Read encrypted file
with open(input_path, "rb") as input_file:
with input_path.open("rb") as input_file:
encrypted_data = input_file.read()

if encrypted_data.startswith(b"PK"):
Expand Down Expand Up @@ -400,7 +400,7 @@ def cmd_inspect(args):
except Exception as e:
# If we can't inspect due to auth issues, show what we can
logger.warning(f"Limited inspection due to: {e}")
with open(input_path, "rb") as input_file:
with input_path.open("rb") as input_file:
encrypted_data = input_file.read()

file_type = "TDF" if encrypted_data.startswith(b"PK") else "NanoTDF"
Expand Down
4 changes: 2 additions & 2 deletions src/otdf_python/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ def peek_length(buffer: bytes) -> int:
# MAGIC_NUMBER_AND_VERSION (3 bytes)
offset += 3
# ResourceLocator
kas_locator, kas_size = ResourceLocator.from_bytes_with_size(buffer[offset:])
_kas_locator, kas_size = ResourceLocator.from_bytes_with_size(buffer[offset:])
offset += kas_size
# ECC mode (1 byte)
ecc_mode = ECCMode(buffer[offset])
offset += 1
# Payload config (1 byte)
offset += 1
# PolicyInfo
policy_info, policy_size = PolicyInfo.from_bytes_with_size(
_policy_info, policy_size = PolicyInfo.from_bytes_with_size(
buffer[offset:], ecc_mode
)
offset += policy_size
Expand Down
2 changes: 1 addition & 1 deletion src/otdf_python/nanotdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def create_nano_tdf(
iv, ciphertext = self._encrypt_payload(payload, key)

# Wrap key if needed
wrapped_key, kas_public_key = self._wrap_key_if_needed(key, config)
wrapped_key, _kas_public_key = self._wrap_key_if_needed(key, config)

# Compose the complete NanoTDF: [IV][CIPHERTEXT][WRAPPED_KEY][WRAPPED_KEY_LEN]
if wrapped_key:
Expand Down
9 changes: 5 additions & 4 deletions src/otdf_python/sdk_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"""

import logging
import os
import ssl
from dataclasses import dataclass
from pathlib import Path
from typing import Any

import httpx
Expand Down Expand Up @@ -77,9 +77,10 @@ def ssl_context_from_directory(self, certs_dir_path: str) -> "SDKBuilder":
self.cert_paths = []

# Find all .pem and .crt files in the directory
for filename in os.listdir(certs_dir_path):
if filename.endswith(".pem") or filename.endswith(".crt"):
self.cert_paths.append(os.path.join(certs_dir_path, filename))
certs_path = Path(certs_dir_path)
for cert_file in certs_path.iterdir():
if cert_file.suffix in (".pem", ".crt"):
self.cert_paths.append(str(cert_file))

# Create SSL context with these certificates
if self.cert_paths:
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def temp_credentials_file():
with tempfile.TemporaryDirectory() as temp_dir:
creds_file = Path(temp_dir) / "creds.json"
creds_data = {"clientId": "opentdf", "clientSecret": "secret"}
with open(creds_file, "w") as f:
with creds_file.open("w") as f:
json.dump(creds_data, f)
yield creds_file

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_sample_file_contents(sample_input_files):
# Check text file has content
text_file = sample_input_files["text"]
assert text_file.exists(), f"Text file should exist: {text_file}"
with open(text_file) as f:
with text_file.open() as f:
content = f.read()
assert "Hello, World!" in content
assert len(content) > 0
Expand All @@ -66,7 +66,7 @@ def test_sample_file_contents(sample_input_files):
# Check attributes file has content
attr_file = sample_input_files["with_attributes"]
assert attr_file.exists(), f"Attributes file should exist: {attr_file}"
with open(attr_file) as f:
with attr_file.open() as f:
content = f.read()
assert "Classification: SECRET" in content

Expand Down
4 changes: 2 additions & 2 deletions tests/integration/otdfctl_to_python/test_cli_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_otdfctl_encrypt_python_decrypt(
# Create input file
input_file = temp_path / "input.txt"
input_content = "Hello, World! This is a test for otdfctl decrypt comparison."
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define TDF file created by otdfctl
Expand Down Expand Up @@ -115,7 +115,7 @@ def test_otdfctl_encrypt_otdfctl_decrypt(collect_server_logs, temp_credentials_f
input_content = (
"Hello, World! This is a test for otdfctl roundtrip encryption/decryption."
)
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define TDF file and decrypted output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_read_otdfctl_created_tdf_structure(
# Create input file
input_file = temp_path / "input.txt"
input_content = "Hello, World! This is test data for TDFReader integration."
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define output files
Expand All @@ -60,7 +60,7 @@ def test_read_otdfctl_created_tdf_structure(
assert otdfctl_output.stat().st_size > 0, "otdfctl created empty TDF file"

# Test that TDFReader can open and read the structure
with open(otdfctl_output, "rb") as f:
with otdfctl_output.open("rb") as f:
tdf_data = f.read()

# Initialize TDFReader
Expand Down Expand Up @@ -116,7 +116,7 @@ def test_read_otdfctl_tdf_with_attributes(
# Create input file
input_file = temp_path / "input.txt"
input_content = "This is input data for testing attributes."
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define output file
Expand All @@ -143,7 +143,7 @@ def test_read_otdfctl_tdf_with_attributes(
assert otdfctl_output.exists(), "otdfctl did not create TDF file"

# Test that TDFReader can read the file with attributes
with open(otdfctl_output, "rb") as f:
with otdfctl_output.open("rb") as f:
tdf_data = f.read()

reader = TDFReader(io.BytesIO(tdf_data))
Expand Down Expand Up @@ -209,10 +209,10 @@ def test_read_multiple_otdfctl_files(
# Create input file
input_file = temp_path / f"{test_case['name']}.txt"
if isinstance(test_case["content"], bytes):
with open(input_file, "wb") as f:
with input_file.open("wb") as f:
f.write(test_case["content"])
else:
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(test_case["content"])

# Define output file
Expand All @@ -235,7 +235,7 @@ def test_read_multiple_otdfctl_files(
)

# Test TDFReader on this file
with open(output_file, "rb") as f:
with output_file.open("rb") as f:
tdf_data = f.read()

reader = TDFReader(io.BytesIO(tdf_data))
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/test_cli_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_cli_decrypt_otdfctl_tdf(
# Create input file
input_file = temp_path / "input.txt"
input_content = "Hello, World! This is a test for decryption."
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define TDF file created by otdfctl
Expand Down Expand Up @@ -99,7 +99,7 @@ def test_otdfctl_decrypt_comparison(
# Create input file
input_file = temp_path / "input.txt"
input_content = "Hello, World! This is a test for otdfctl decrypt comparison."
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define TDF file created by otdfctl
Expand Down Expand Up @@ -183,7 +183,7 @@ def test_otdfctl_encrypt_decrypt_roundtrip(collect_server_logs, temp_credentials
input_content = (
"Hello, World! This is a test for otdfctl roundtrip encryption/decryption."
)
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define TDF file and decrypted output
Expand Down Expand Up @@ -258,7 +258,7 @@ def test_cli_encrypt_integration(
# Create input file
input_file = temp_path / "input.txt"
input_content = "Hello, World"
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(input_content)

# Define output files
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/test_cli_tdf_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
def _create_test_input_file(temp_path: Path, content: str) -> Path:
"""Create a test input file with the given content."""
input_file = temp_path / "input.txt"
with open(input_file, "w") as f:
with input_file.open("w") as f:
f.write(content)
return input_file

Expand Down Expand Up @@ -471,7 +471,7 @@ def test_different_content_types(
# Create input file
input_file = temp_path / filename
# Use binary mode for consistent handling of all content types
with open(input_file, "w", encoding="utf-8") as f:
with input_file.open("w", encoding="utf-8") as f:
f.write(content)

# Test with Python CLI
Expand Down Expand Up @@ -528,7 +528,7 @@ def test_different_content_types_empty(
# Create input file
input_file = temp_path / filename
# Use binary mode for consistent handling of all content types
with open(input_file, "w", encoding="utf-8") as f:
with input_file.open("w", encoding="utf-8") as f:
f.write(content)

# Test with Python CLI
Expand Down
Loading
Loading