diff --git a/lib/AuditLogs.php b/lib/AuditLogs.php index 464e1ac0..c453d390 100644 --- a/lib/AuditLogs.php +++ b/lib/AuditLogs.php @@ -115,15 +115,110 @@ public function createExport($organizationId, $rangeStart, $rangeEnd, $actions = * @param string $auditLogExportId Unique identifier of the Audit Log Export * * @throws Exception\WorkOSException + * @throws \InvalidArgumentException * * @return Resource\AuditLogExport */ public function getExport($auditLogExportId) { + // Validate export ID parameter to prevent path traversal + if (!is_string($auditLogExportId) || !preg_match('/^[a-zA-Z0-9._-]+$/', $auditLogExportId)) { + throw new \InvalidArgumentException('Invalid export ID format. Export ID must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); + } + $getExportPath = "audit_logs/exports/{$auditLogExportId}"; $response = Client::request(Client::METHOD_GET, $getExportPath, null, null, true); return Resource\AuditLogExport::constructFromResponse($response); } + + /** + * Create an audit log action schema. + * + * @param string $action The action name for the schema + * @param array $schema Array containing the schema definition + * + * @throws Exception\WorkOSException + * @throws \InvalidArgumentException + * + * @return array The created schema response + */ + public function createSchema($action, $schema) + { + // Validate action parameter to prevent path traversal + if (!is_string($action) || !preg_match('/^[a-zA-Z0-9._-]+$/', $action)) { + throw new \InvalidArgumentException('Invalid action format. Action must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); + } + + $schemaPath = "audit_logs/actions/{$action}/schemas"; + + $response = Client::request(Client::METHOD_POST, $schemaPath, null, $schema, true); + + return $response; + } + + /** + * Check if an audit log action schema exists. + * + * @param string $action The action name to check + * + * @throws Exception\WorkOSException + * @throws \InvalidArgumentException + * + * @return bool True if schema exists, false if not found + */ + public function schemaExists($action) + { + // Validate action parameter to prevent path traversal + if (!is_string($action) || !preg_match('/^[a-zA-Z0-9._-]+$/', $action)) { + throw new \InvalidArgumentException('Invalid action format. Action must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); + } + + $schemaPath = "audit_logs/actions/{$action}/schemas"; + + try { + Client::request(Client::METHOD_GET, $schemaPath, null, null, true); + return true; + } catch (Exception\NotFoundException $e) { + return false; + } + } + + /** + * List all registered audit log actions. + * + * @param int $limit Maximum number of actions to return (default: 100) + * @param null|string $before Action ID to look before + * @param null|string $after Action ID to look after + * @param null|string $order The order in which to paginate records ("asc" or "desc") + * + * @throws Exception\WorkOSException + * + * @return array Array of registered actions + */ + public function listActions($limit = 100, $before = null, $after = null, $order = null) + { + $actionsPath = "audit_logs/actions"; + + $params = [ + "limit" => $limit + ]; + + if ($before !== null) { + $params["before"] = $before; + } + + if ($after !== null) { + $params["after"] = $after; + } + + if ($order !== null) { + $params["order"] = $order; + } + + $response = Client::request(Client::METHOD_GET, $actionsPath, null, $params, true); + + return $response; + } } diff --git a/tests/WorkOS/AuditLogsTest.php b/tests/WorkOS/AuditLogsTest.php index 757b4006..54127fc2 100644 --- a/tests/WorkOS/AuditLogsTest.php +++ b/tests/WorkOS/AuditLogsTest.php @@ -133,6 +133,136 @@ public function testGetExport() $this->assertSame($getExportFixture, $auditLogGetExport->toArray()); } + + public function testCreateSchema() + { + $path = "audit_logs/actions/document.updated/schemas"; + + $action = "document.updated"; + $schema = [ + "targets" => [ + [ + "type" => "document" + ], + [ + "type" => "user" + ] + ] + ]; + + $params = $schema; + + $result = $this->createSchemaResponseFixture(); + + $this->mockRequest( + Client::METHOD_POST, + $path, + null, + $params, + true, + $result + ); + + $response = $this->al->createSchema($action, $schema); + $schemaFixture = $this->createSchemaFixture(); + + $this->assertSame($schemaFixture, $response); + } + + public function testSchemaExists() + { + $path = "audit_logs/actions/document.updated/schemas"; + $action = "document.updated"; + + $result = $this->schemaExistsResponseFixture(); + + $this->mockRequest( + Client::METHOD_GET, + $path, + null, + null, + true, + $result + ); + + $exists = $this->al->schemaExists($action); + + $this->assertTrue($exists); + } + + public function testSchemaExistsNotFound() + { + $path = "audit_logs/actions/nonexistent.action/schemas"; + $action = "nonexistent.action"; + + $this->mockRequest( + Client::METHOD_GET, + $path, + null, + null, + true, + null, + null, + 404 + ); + + $exists = $this->al->schemaExists($action); + + $this->assertFalse($exists); + } + + public function testListActions() + { + $path = "audit_logs/actions"; + + $params = [ + "limit" => 100 + ]; + + $result = $this->listActionsResponseFixture(); + + $this->mockRequest( + Client::METHOD_GET, + $path, + null, + $params, + true, + $result + ); + + $response = $this->al->listActions(); + $actionsFixture = $this->listActionsFixture(); + + $this->assertSame($actionsFixture, $response); + } + + public function testListActionsWithPagination() + { + $path = "audit_logs/actions"; + + $params = [ + "limit" => 50, + "before" => "action_123", + "after" => "action_456", + "order" => "desc" + ]; + + $result = $this->listActionsResponseFixture(); + + $this->mockRequest( + Client::METHOD_GET, + $path, + null, + $params, + true, + $result + ); + + $response = $this->al->listActions(50, "action_123", "action_456", "desc"); + $actionsFixture = $this->listActionsFixture(); + + $this->assertSame($actionsFixture, $response); + } // Fixtures private function createEventFixture() @@ -196,4 +326,108 @@ private function getExportResponseFixture() "updated_at" => "2022-08-18T18:07:10.822Z", ]); } + + private function createSchemaFixture() + { + return [ + "object" => "audit_log_schema", + "id" => "schema_123", + "action" => "document.updated", + "targets" => [ + ["type" => "document"], + ["type" => "user"] + ], + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ]; + } + + private function createSchemaResponseFixture() + { + return json_encode([ + "object" => "audit_log_schema", + "id" => "schema_123", + "action" => "document.updated", + "targets" => [ + ["type" => "document"], + ["type" => "user"] + ], + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ]); + } + + private function schemaExistsResponseFixture() + { + return json_encode([ + "object" => "audit_log_schema", + "id" => "schema_123", + "action" => "document.updated", + "targets" => [ + ["type" => "document"] + ], + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ]); + } + + private function listActionsFixture() + { + return [ + "object" => "list", + "data" => [ + [ + "object" => "audit_log_action", + "id" => "action_123", + "name" => "document.updated", + "description" => "Document was updated", + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ], + [ + "object" => "audit_log_action", + "id" => "action_456", + "name" => "user.created", + "description" => "User was created", + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ] + ], + "list_metadata" => [ + "before" => null, + "after" => "action_456", + "limit" => 100 + ] + ]; + } + + private function listActionsResponseFixture() + { + return json_encode([ + "object" => "list", + "data" => [ + [ + "object" => "audit_log_action", + "id" => "action_123", + "name" => "document.updated", + "description" => "Document was updated", + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ], + [ + "object" => "audit_log_action", + "id" => "action_456", + "name" => "user.created", + "description" => "User was created", + "created_at" => "2022-08-18T18:07:10.822Z", + "updated_at" => "2022-08-18T18:07:10.822Z", + ] + ], + "list_metadata" => [ + "before" => null, + "after" => "action_456", + "limit" => 100 + ] + ]); + } }