diff --git a/CHANGELOG.md b/CHANGELOG.md index e6fa6a2..1507af3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to `utopia-php/audit` are documented in this file. +## 2.7.0 + +### ClickHouse adapter — SDK columns + +The ClickHouse adapter now stores two additional optional columns capturing the +SDK that produced an audit event: + +#### Added + +- `Log::getSdk()` and `Log::getSdkVersion()` getters for ClickHouse-backed log reads. + +#### ClickHouse schema changes + +- Column `sdk` `LowCardinality(Nullable(String))` — SDK name (e.g. `web`, `flutter`, + `console`, `cli`); low-cardinality, optional. +- Column `sdkVersion` `Nullable(String)` — SDK version (e.g. `14.0.0`); high-cardinality, + optional. +- Index `_key_sdk` — bloom-filter index on the `sdk` column. + +Both columns are optional (`required = false`) so `createBatch()` never throws when a +caller omits them. Newly created tables include the columns automatically via `setup()`. +`setup()` only issues `CREATE TABLE IF NOT EXISTS`, so **existing** tables do not gain the +columns automatically — apply them with an `ALTER TABLE ... ADD COLUMN IF NOT EXISTS` +migration. + ## 2.4.0 ### ClickHouse adapter — actor terminology diff --git a/src/Audit/Adapter/ClickHouse.php b/src/Audit/Adapter/ClickHouse.php index 1524a5d..3d9134a 100644 --- a/src/Audit/Adapter/ClickHouse.php +++ b/src/Audit/Adapter/ClickHouse.php @@ -31,6 +31,7 @@ class ClickHouse extends SQL 'actorType', 'resourceType', 'country', + 'sdk', ]; /** @@ -536,6 +537,28 @@ public function getAttributes(): array 'array' => false, 'filters' => [], ], + [ + '$id' => 'sdk', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'sdkVersion', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ]; } @@ -609,6 +632,13 @@ public function getIndexes(): array 'lengths' => [], 'orders' => [], ], + [ + '$id' => '_key_sdk', + 'type' => Database::INDEX_KEY, + 'attributes' => ['sdk'], + 'lengths' => [], + 'orders' => [], + ], ]; } diff --git a/src/Audit/Log.php b/src/Audit/Log.php index 3188ee7..74febc9 100644 --- a/src/Audit/Log.php +++ b/src/Audit/Log.php @@ -101,6 +101,33 @@ public function getResource(): string return is_string($resource) ? $resource : ''; } + /** + * Get the SDK name associated with this log entry. + * + * Optional column: returns null when the SDK was never recorded, mirroring + * the other nullable actor columns (getActorId/getActorInternalId). + * + * @return string|null + */ + public function getSdk(): ?string + { + $sdk = $this->getAttribute('sdk'); + return is_string($sdk) ? $sdk : null; + } + + /** + * Get the SDK version associated with this log entry. + * + * Optional column: returns null when the SDK version was never recorded. + * + * @return string|null + */ + public function getSdkVersion(): ?string + { + $sdkVersion = $this->getAttribute('sdkVersion'); + return is_string($sdkVersion) ? $sdkVersion : null; + } + /** * Get the user agent string. * diff --git a/tests/Audit/Adapter/ClickHouseTest.php b/tests/Audit/Adapter/ClickHouseTest.php index c3c6a40..5b56173 100644 --- a/tests/Audit/Adapter/ClickHouseTest.php +++ b/tests/Audit/Adapter/ClickHouseTest.php @@ -535,7 +535,9 @@ public function testClickHouseAdapterAttributes(): void 'projectInternalId', 'teamId', 'teamInternalId', - 'hostname' + 'hostname', + 'sdk', + 'sdkVersion' ]; foreach ($expectedAttributes as $expected) { @@ -565,7 +567,8 @@ public function testClickHouseAdapterIndexes(): void '_key_actor_internal_id', '_key_actor_type', '_key_country', - '_key_hostname' + '_key_hostname', + '_key_sdk' ]; foreach ($expectedClickHouseIndexes as $expected) {