Skip to content

Commit 7b66f64

Browse files
authored
refactor!: remove implicit audit logging from ObjectStore (#33)
1 parent 7a3c9b9 commit 7b66f64

File tree

6 files changed

+31
-175
lines changed

6 files changed

+31
-175
lines changed

.github/workflows/sync.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ jobs:
4646
echo "External repository **main** branch has been successfully mirrored to internal." >> $GITHUB_STEP_SUMMARY
4747
echo "- **External**: https://github.com/SAP/cloud-sdk-python" >> $GITHUB_STEP_SUMMARY
4848
echo "- **Branch**: main" >> $GITHUB_STEP_SUMMARY
49-
echo "- **Time**: $(date -u)" >> $GITHUB_STEP_SUMMARY
49+
echo "- **Time**: $(date -u)" >> $GITHUB_STEP_SUMMARY

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "sap-cloud-sdk"
3-
version = "0.3.2"
3+
version = "0.4.0"
44
description = "SAP Cloud SDK for Python"
55
readme = "README.md"
66
license = "Apache-2.0"

src/sap_cloud_sdk/aicore/user-guide.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,9 @@ try:
235235
temperature=0.7,
236236
max_tokens=100
237237
)
238-
238+
239239
print(f"Response: {response.choices[0].message.content}")
240-
240+
241241
except Exception as e:
242242
print(f"AI Core request failed: {e}")
243243
```
@@ -370,4 +370,4 @@ set_aicore_config()
370370
- The `set_aicore_config()` function sets environment variables that persist for the lifetime of the Python process
371371
- If you need to switch between multiple AI Core instances at runtime, call `set_aicore_config()` with different instance names
372372
- The function is safe to call multiple times; subsequent calls will overwrite the environment variables
373-
- Resource group defaults to "default" if not specified in secrets or environment variables
373+
- Resource group defaults to "default" if not specified in secrets or environment variables

src/sap_cloud_sdk/objectstore/_s3.py

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import io
44
import os
5-
import logging
65
from datetime import datetime
76
from http.client import HTTPResponse
87
from typing import BinaryIO, List, cast
@@ -19,16 +18,6 @@
1918
ListObjectsError,
2019
)
2120
from sap_cloud_sdk.objectstore._models import ObjectStoreBindingData, ObjectMetadata
22-
from sap_cloud_sdk.core.auditlog import (
23-
create_client as create_auditlog_client,
24-
DataAccessEvent,
25-
DataModificationEvent,
26-
DataDeletionEvent,
27-
DataAccessAttribute,
28-
ChangeAttribute,
29-
DeletedAttribute,
30-
Tenant,
31-
)
3221
from sap_cloud_sdk.objectstore.utils import _normalize_host
3322

3423
# Validation error message constants
@@ -64,10 +53,6 @@ def __init__(
6453
self._creds_config = creds_config
6554
self._disable_ssl = disable_ssl
6655
self._minio_client = self._create_minio_client()
67-
# Pass Module.OBJECTSTORE as source when creating auditlog client
68-
self._audit_client = create_auditlog_client(
69-
_telemetry_source=Module.OBJECTSTORE
70-
)
7156

7257
def _create_minio_client(self) -> Minio:
7358
"""Create MinIO client with proper configuration."""
@@ -82,46 +67,6 @@ def _create_minio_client(self) -> Minio:
8267
except Exception as e:
8368
raise ClientCreationError(f"Failed to create MinIO client: {e}") from e
8469

85-
def _build_data_access_event(
86-
self, object_name: str, success: bool
87-
) -> DataAccessEvent:
88-
"""Build a data access audit event for read operations."""
89-
return DataAccessEvent(
90-
object_type="s3-object",
91-
object_id={"bucket": self._creds_config.bucket, "key": object_name},
92-
subject_type="application",
93-
subject_id={"type": "automation"},
94-
subject_role="app-foundation-sdk-python",
95-
attributes=[DataAccessAttribute(name=object_name, successful=success)],
96-
user="app-foundation-sdk-python",
97-
tenant=Tenant.PROVIDER,
98-
)
99-
100-
def _build_data_modification_event(self, object_name: str) -> DataModificationEvent:
101-
return DataModificationEvent(
102-
object_type="s3-object",
103-
object_id={"bucket": self._creds_config.bucket, "key": object_name},
104-
subject_type="application",
105-
subject_id={"type": "automation"},
106-
subject_role="app-foundation-sdk-python",
107-
attributes=[ChangeAttribute(name=object_name, new="", old="")],
108-
user="app-foundation-sdk-python",
109-
tenant=Tenant.PROVIDER,
110-
)
111-
112-
def _build_data_deletion_event(self, object_name: str) -> DataDeletionEvent:
113-
"""Build a data deletion audit event for delete operations."""
114-
return DataDeletionEvent(
115-
object_type="s3-object",
116-
object_id={"bucket": self._creds_config.bucket, "key": object_name},
117-
subject_type="application",
118-
subject_id={"type": "automation"},
119-
subject_role="app-foundation-sdk-python",
120-
attributes=[DeletedAttribute(name=object_name, old="")],
121-
user="app-foundation-sdk-python",
122-
tenant=Tenant.PROVIDER,
123-
)
124-
12570
@record_metrics(Module.OBJECTSTORE, Operation.OBJECTSTORE_PUT_OBJECT_FROM_BYTES)
12671
def put_object_from_bytes(self, name: str, data: bytes, content_type: str) -> None:
12772
"""Upload an object from bytes.
@@ -150,12 +95,6 @@ def put_object_from_bytes(self, name: str, data: bytes, content_type: str) -> No
15095
length=len(data),
15196
content_type=content_type,
15297
)
153-
154-
try:
155-
self._audit_client.log(self._build_data_modification_event(name))
156-
except Exception as e:
157-
logging.error(f"audit log failed for PutObjectFromBytes operation: {e}")
158-
15998
except S3Error as e:
16099
raise ObjectOperationError(
161100
f"Failed to upload object '{name}': {e.code} - {e.message}"
@@ -196,12 +135,6 @@ def put_object(
196135
length=size,
197136
content_type=content_type,
198137
)
199-
200-
try:
201-
self._audit_client.log(self._build_data_modification_event(name))
202-
except Exception as e:
203-
logging.error(f"audit log failed for PutObject operation: {e}")
204-
205138
except S3Error as e:
206139
raise ObjectOperationError(
207140
f"Failed to upload object '{name}': {e.code} - {e.message}"
@@ -238,7 +171,6 @@ def put_object_from_file(
238171

239172
file_size = os.path.getsize(file_path)
240173

241-
# Single file operation - no content reading for audit
242174
with open(file_path, "rb") as file_stream:
243175
self._minio_client.put_object(
244176
bucket_name=self._creds_config.bucket,
@@ -247,12 +179,6 @@ def put_object_from_file(
247179
length=file_size,
248180
content_type=content_type,
249181
)
250-
251-
try:
252-
self._audit_client.log(self._build_data_modification_event(name))
253-
except Exception as e:
254-
logging.error(f"audit log failed for PutObjectFromFile operation: {e}")
255-
256182
except S3Error as e:
257183
raise ObjectOperationError(
258184
f"Failed to upload object '{name}': {e.code} - {e.message}"
@@ -278,7 +204,6 @@ def get_object(self, name: str) -> HTTPResponse:
278204
if not name:
279205
raise ValueError(EMPTY_NAME_ERROR)
280206

281-
get_err = None
282207
try:
283208
response = cast(
284209
HTTPResponse,
@@ -288,25 +213,15 @@ def get_object(self, name: str) -> HTTPResponse:
288213
)
289214
return response
290215
except S3Error as e:
291-
get_err = e
292216
if e.code == "NoSuchKey":
293217
raise ObjectNotFoundError(f"Object '{name}' not found") from e
294218
raise ObjectOperationError(
295219
f"Failed to download object '{name}': {e.code} - {e.message}"
296220
) from e
297221
except Exception as e:
298-
get_err = e
299222
raise ObjectOperationError(
300223
f"Failed to download object '{name}': {e}"
301224
) from e
302-
finally:
303-
# Log audit event
304-
try:
305-
self._audit_client.log(
306-
self._build_data_access_event(name, get_err is None)
307-
)
308-
except Exception as e:
309-
logging.error(f"audit log failed for GetObject operation: {e}")
310225

311226
@record_metrics(Module.OBJECTSTORE, Operation.OBJECTSTORE_DELETE_OBJECT)
312227
def delete_object(self, name: str) -> None:
@@ -326,22 +241,12 @@ def delete_object(self, name: str) -> None:
326241
self._minio_client.remove_object(
327242
bucket_name=self._creds_config.bucket, object_name=name
328243
)
329-
330-
try:
331-
self._audit_client.log(self._build_data_deletion_event(name))
332-
except Exception as e:
333-
logging.error(f"audit log failed for DeleteObject operation: {e}")
334-
335244
except S3Error as e:
336245
if e.code != "NoSuchKey":
337246
raise ObjectOperationError(
338247
f"Failed to delete object '{name}': {e.code} - {e.message}"
339248
) from e
340249
# For NoSuchKey, we still consider it successful (idempotent delete)
341-
try:
342-
self._audit_client.log(self._build_data_deletion_event(name))
343-
except Exception as audit_e:
344-
logging.error(f"audit log failed for DeleteObject operation: {audit_e}")
345250
except Exception as e:
346251
raise ObjectOperationError(f"Failed to delete object '{name}': {e}") from e
347252

@@ -362,7 +267,6 @@ def list_objects(self, prefix: str) -> List[ObjectMetadata]:
362267
if not isinstance(prefix, str):
363268
raise ValueError(INVALID_PREFIX_TYPE_ERROR)
364269

365-
list_err = None
366270
result = []
367271
try:
368272
objects = self._minio_client.list_objects(
@@ -382,25 +286,13 @@ def list_objects(self, prefix: str) -> List[ObjectMetadata]:
382286

383287
return result
384288
except S3Error as e:
385-
list_err = e
386289
raise ListObjectsError(
387290
f"Failed to list objects with prefix '{prefix}': {e.code} - {e.message}"
388291
) from e
389292
except Exception as e:
390-
list_err = e
391293
raise ListObjectsError(
392294
f"Failed to list objects with prefix '{prefix}': {e}"
393295
) from e
394-
finally:
395-
if prefix is None or prefix.strip() == "":
396-
# Audit log name can't be empty
397-
prefix = "/"
398-
try:
399-
self._audit_client.log(
400-
self._build_data_access_event(prefix, list_err is None)
401-
)
402-
except Exception as e:
403-
logging.error(f"audit log failed for ListObjects operation: {e}")
404296

405297
@record_metrics(Module.OBJECTSTORE, Operation.OBJECTSTORE_HEAD_OBJECT)
406298
def head_object(self, name: str) -> ObjectMetadata:
@@ -420,7 +312,6 @@ def head_object(self, name: str) -> ObjectMetadata:
420312
if not name:
421313
raise ValueError(EMPTY_NAME_ERROR)
422314

423-
head_err = None
424315
try:
425316
stat: minio.datatypes.Object = self._minio_client.stat_object(
426317
bucket_name=self._creds_config.bucket, object_name=name
@@ -435,24 +326,15 @@ def head_object(self, name: str) -> ObjectMetadata:
435326
owner=None, # stat_object doesn't provide owner
436327
)
437328
except S3Error as e:
438-
head_err = e
439329
if e.code == "NoSuchKey":
440330
raise ObjectNotFoundError(f"Object '{name}' not found") from e
441331
raise ObjectOperationError(
442332
f"Failed to get metadata for object '{name}': {e.code} - {e.message}"
443333
) from e
444334
except Exception as e:
445-
head_err = e
446335
raise ObjectOperationError(
447336
f"Failed to get metadata for object '{name}': {e}"
448337
) from e
449-
finally:
450-
try:
451-
self._audit_client.log(
452-
self._build_data_access_event(name, head_err is None)
453-
)
454-
except Exception as e:
455-
logging.error(f"audit log failed for HeadObject operation: {e}")
456338

457339
@record_metrics(Module.OBJECTSTORE, Operation.OBJECTSTORE_OBJECT_EXISTS)
458340
def object_exists(self, name: str) -> bool:

0 commit comments

Comments
 (0)