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
20 changes: 7 additions & 13 deletions src/sap_cloud_sdk/core/auditlog_ng/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ def __init__(
def send(
self,
event: Message,
event_type: Optional[str] = None,
format: str = "protobuf-binary",
) -> str:
"""Send an audit log event.
Expand Down Expand Up @@ -192,16 +191,11 @@ def send(

event_id = str(uuid.uuid4())

if event_type is None:
descriptor = getattr(event, "DESCRIPTOR", None)
descriptor_name = getattr(descriptor, "name", None)
if not isinstance(descriptor_name, str) or not descriptor_name:
raise ValueError(
"Could not determine event type from message descriptor"
)
event_type = descriptor_name

event_type = f"sap.als.AuditEvent.{event_type}.v2"
descriptor = getattr(event, "DESCRIPTOR", None)
descriptor_full_name = getattr(descriptor, "full_name", None)
if not isinstance(descriptor_full_name, str) or not descriptor_full_name:
raise ValueError("Could not determine event type from message descriptor")
event_type = descriptor_full_name

if format == "json":
mime_type = "application/json"
Expand All @@ -225,9 +219,9 @@ def send(

return event_id

def send_json(self, event: Message, event_type: Optional[str] = None) -> str:
def send_json(self, event: Message) -> str:
"""Send event in JSON format."""
return self.send(event, event_type, format="json")
return self.send(event, format="json")

def flush(self) -> None:
"""Flush pending events (for batch mode)."""
Expand Down
9 changes: 4 additions & 5 deletions src/sap_cloud_sdk/core/auditlog_ng/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,16 @@ event.object_id = "resource-001"
**Binary protobuf:**

```python
event_id = client.send(event, "DataAccess")
event_id = client.send(event)
print(f"Sent event with ID: {event_id}")
```

**JSON format:**

```python
event_id = client.send_json(event, "DataAccess")
event_id = client.send_json(event)
```

> The `event_type` argument is optional. If omitted, the client derives it from the protobuf descriptor name (e.g., `"sap.als.AuditEvent.DataAccess.v2"`).

### Step 5: Close the Client

Expand Down Expand Up @@ -177,7 +176,7 @@ class AgentAuditLogger:
event.object_type = "resource"
event.object_id = resource

event_id = self.client.send(event, "DataAccess")
event_id = self.client.send(event)
return event_id

def shutdown(self):
Expand Down Expand Up @@ -213,7 +212,7 @@ with create_client(
cert_file="/path/to/cert.pem",
key_file="/path/to/key.pem",
) as client:
event_id = client.send(event, "DataAccess")
event_id = client.send(event)
```

---
Expand Down
22 changes: 11 additions & 11 deletions tests/core/unit/auditlog_ng/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"namespace": "namespace-123",
"insecure": True,
}
defaults.update(overrides) # ty: ignore[invalid-argument-type]

Check warning on line 37 in tests/core/unit/auditlog_ng/unit/test_client.py

View workflow job for this annotation

GitHub Actions / Code Quality Checks

ty (unused-ignore-comment)

tests/core/unit/auditlog_ng/unit/test_client.py:37:33: unused-ignore-comment: Unused `ty: ignore` directive help: Remove the unused suppression comment
return AuditLogNGConfig(**defaults)


Expand Down Expand Up @@ -67,10 +67,10 @@
)


def _make_mock_event(tenant_id="tenant-123", descriptor_name="DataAccess"):
def _make_mock_event(tenant_id="tenant-123", descriptor_full_name="sap.auditlog.auditevent.v2.DataAccess"):
event = MagicMock()
event.common.tenant_id = tenant_id
event.DESCRIPTOR.name = descriptor_name
event.DESCRIPTOR.full_name = descriptor_full_name
event.SerializeToString.return_value = b"\x00\x01\x02"
return event

Expand Down Expand Up @@ -120,14 +120,14 @@
client, mock_logger, _, mock_validate, patcher, _ = _make_mocked_client()
try:
event = _make_mock_event()
event_id = client.send(event, "DataAccess")
event_id = client.send(event)

assert isinstance(event_id, str)
mock_validate.assert_called_once_with(event)
mock_logger.emit.assert_called_once()

_, kwargs = mock_logger.emit.call_args
assert kwargs["event_name"] == "sap.als.AuditEvent.DataAccess.v2"
assert kwargs["event_name"] == "sap.auditlog.auditevent.v2.DataAccess"
assert kwargs["body"] == b"\x00\x01\x02"
assert (
kwargs["attributes"]["sap.auditlogging.mime_type"]
Expand All @@ -142,7 +142,7 @@
client, mock_logger, _, mock_validate, patcher, _ = _make_mocked_client()
try:
event = _make_mock_event()
event_id = client.send_json(event, "DataAccess")
event_id = client.send_json(event)

assert isinstance(event_id, str)
mock_logger.emit.assert_called_once()
Expand All @@ -158,11 +158,11 @@
def test_send_uses_descriptor_name_when_event_type_missing(self):
client, mock_logger, _, _, patcher, _ = _make_mocked_client()
try:
event = _make_mock_event(descriptor_name="ConfigurationChange")
event = _make_mock_event(descriptor_full_name="sap.auditlog.auditevent.v2.ConfigurationChange")
client.send(event)

_, kwargs = mock_logger.emit.call_args
assert kwargs["event_name"] == "sap.als.AuditEvent.ConfigurationChange.v2"
assert kwargs["event_name"] == "sap.auditlog.auditevent.v2.ConfigurationChange"
finally:
patcher.stop()

Expand All @@ -172,13 +172,13 @@
client.close()

with pytest.raises(RuntimeError, match="Client is closed"):
client.send(_make_mock_event(), "DataAccess")
client.send(_make_mock_event())

def test_send_invalid_format_raises(self):
client, _, _, _, patcher, _ = _make_mocked_client()
try:
with pytest.raises(ValueError, match="format must be"):
client.send(_make_mock_event(), "DataAccess", format="xml")
client.send(_make_mock_event(), format="xml")
finally:
patcher.stop()

Expand All @@ -190,7 +190,7 @@
)
try:
with pytest.raises(ValidationError, match="Audit event validation failed"):
client.send(_make_mock_event(), "DataAccess")
client.send(_make_mock_event())

mock_logger.emit.assert_not_called()
finally:
Expand All @@ -202,7 +202,7 @@
event = _make_mock_event(tenant_id="bad tenant id")

with pytest.raises(ValueError):
client.send(event, "DataAccess")
client.send(event)

mock_logger.emit.assert_not_called()
finally:
Expand Down
Loading