Skip to content

feat: expand audit logging - #1130

Merged
oleksandr-nc merged 1 commit into
mainfrom
feat/admin-audit-logging
Nov 12, 2026
Merged

oleksandr-nc merged 1 commit into
mainfrom
feat/admin-audit-logging

Conversation

@GhassenKefi

@GhassenKefi GhassenKefi commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Nextcloud 36 asks every app to write its administrative and security relevant actions to the admin audit log, each with a stable operation id. AppAPI wrote nothing: installing, updating or removing ExApps, changing deploy daemons or AppAPI settings, and failed ExApp authentication left no trace in audit.log.

Changes

  • ExApps (app_api.ex_app.*): registered, updated, enabled, disabled, unregistered and data deleted, written where the change is stored, so occ, the web interface and the OCS API are each covered once. Installs, updates and the test deploy started in the web interface run occ in a separate process without a user, so the web request also writes install_requested, update_requested or uninstall_requested as the administrator, with the names of the environment variables and the mounts.
  • Deploy daemons (app_api.daemon.*, app_api.daemon_registry.*): registered, updated with the names of the changed settings, unregistered, registry mapping added and removed. A change of the default daemon is an app_api.admin_config.updated entry.
  • AppAPI settings (app_api.admin_config.updated): one entry per changed key, the value only for the known AppAPI settings.
  • Failed authentication: AppAPI requests for an unknown ExApp or with a wrong secret, HaRP requests with a missing or wrong shared key (now throttled like the other AppAPI checks), and Talk bot messages with a wrong signature.
  • The entries never contain secrets. Values sent by a client or an ExApp stay out of the messages, and {placeholders} in all other values are escaped, as the logger interpolates them in the message.
  • With --rm-data, a Kubernetes ExApp whose deployment is already gone now has its volume removed too.
  • nextcloud/ocp is bumped for the operation parameter; an unused method that still referenced the removed OCP\IServerContainer is dropped.

The operations are listed in lib/AuditLog/Operation.php and documented in nextcloud/documentation#16039.

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI (N/A)

@GhassenKefi GhassenKefi added this to the Nextcloud 36 milestone Oct 19, 2026
@GhassenKefi GhassenKefi self-assigned this Oct 19, 2026
@GhassenKefi GhassenKefi added enhancement New feature or request 3. to review labels Oct 19, 2026
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review
Walkthrough

The change adds audit operation identifiers and an AuditLogger. It records selected configuration, daemon, ExApp lifecycle, authentication, and data-deletion events, with tests for event contents and logging conditions. Kubernetes removal now sends a data-removal request when the deployment is absent and data removal is requested. The change also removes ExApp TaskProcessing provider registration.

Merge Risk: Low · up to 219f5

The audit logging changes are mostly sound. Before merging, fix the registry-removal endpoint so a non-matching mapping returns a JSON error instead of a 500. Two smaller issues, unregistration audit ordering and enable rollback, are bounded and can follow up.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title "feat: expand audit logging" matches the main change. The PR adds audit log entries for AppAPI ExApp lifecycle actions, deploy daemon and registry changes, AppAPI settings, and failed authen…
Description check Passed The description explains the purpose (Nextcloud 36 audit log requirement) and lists the changes: ExApp lifecycle events, deploy daemon and registry changes, AppAPI settings, failed authentication, sec…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "feat: expand audit logging" matches the main change. The PR adds audit log entries for AppAPI ExApp lifecycle actions, deploy daemon and registry changes, AppAPI settings, and failed authentication. The title is short and specific enough for a reader scanning history. It omits the specific scope (AppAPI, admin audit log), but that is an acceptable level of detail.

Full details: Description check

Explanation

The description explains the purpose (Nextcloud 36 audit log requirement) and lists the changes: ExApp lifecycle events, deploy daemon and registry changes, AppAPI settings, failed authentication, secret handling, the Kubernetes volume removal fix, and the nextcloud/ocp bump. It matches the changeset closely.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cff23f7f-ef6d-4d59-a3d8-bd265278c6f2
📥 Commits

Reviewing files that changed from the base of the PR and between 38a8a35 and 853c618.

📒 Files selected for processing: 19
  • lib/AuditLog/AuditLogger.php
  • lib/AuditLog/Operation.php
  • lib/Command/ExApp/Unregister.php
  • lib/Controller/ConfigController.php
  • lib/Controller/DaemonConfigController.php
  • lib/Controller/ExAppsPageController.php
  • lib/Service/AppAPIService.php
  • lib/Service/DaemonConfigService.php
  • lib/Service/ExAppService.php
  • tests/php/AuditLog/AuditLoggerTest.php
  • tests/php/AuditLog/OperationTest.php
  • tests/php/Command/ExApp/UnregisterTest.php
  • tests/php/Controller/ConfigControllerTest.php
  • tests/php/Controller/DaemonConfigControllerTest.php
  • tests/php/Controller/ExAppsPageControllerTest.php
  • tests/php/Service/AppAPIServiceTest.php
  • tests/php/Service/DaemonConfigServiceTest.php
  • tests/php/Service/ExAppServiceAuditLogTest.php
  • tests/php/Service/ExAppServiceGetAppInfoTest.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Comment thread lib/AuditLog/AuditLogger.php Resolved
@GhassenKefi
GhassenKefi force-pushed the feat/admin-audit-logging branch from 853c618 to c02350b Compare October 20, 2026 15:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b6037887-7eb4-4096-8f3e-1432c885e56c
📥 Commits

Reviewing files that changed from the base of the PR and between 853c618 and c02350b.

📒 Files selected for processing: 3
  • lib/AuditLog/AuditLogger.php
  • tests/php/AuditLog/AuditEvents.php
  • tests/php/AuditLog/AuditLoggerTest.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Comment thread lib/AuditLog/AuditLogger.php Resolved
Comment thread tests/php/AuditLog/AuditEvents.php Resolved
@susnux susnux changed the title Feat/admin audit logging feat: expand audit logging Oct 27, 2026
@GhassenKefi

Copy link
Copy Markdown
Contributor Author

@oleksandr-nc please review and merge this PR.

@oleksandr-nc

Copy link
Copy Markdown
Contributor

@GhassenKefi this PR requires some small adjustments. I will take over from here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · Emit ExAppUnregistered after cleanup succeeds. · ExAppService.php:141

lib/Service/ExAppService.php:141
Minor · Data Integrity & Integration · Quick win

Emit ExAppUnregistered after cleanup succeeds.

The audit entry is written after the ExApp row is deleted but before removeExAppRoutes() and the cache removal run. Two failure cases follow:

  • If route removal fails, the audit log still records a successful unregistration, but the method returns false.
  • If an audit listener throws, the exception can leave unregisterExApp() before route removal and cache invalidation. The ExApp row is already deleted at that point.

Move the audit call after the cleanup steps and gate it on the final result. A throwing listener then no longer skips route removal or cache invalidation. The exception still reaches the caller after cleanup finishes. A failed route removal produces no success entry; the existing error log records that case.

Suggested fix

 		$r = $this->exAppMapper->deleteExApp($appId);
 		if ($r !== 1) {
 			$this->logger->error(sprintf('Error while unregistering %s ExApp from the database.', $appId));
-		} else {
-			$this->auditLogger->log(Operation::ExAppUnregistered, 'ExApp %s was unregistered', [
-				'appId' => $appId,
-			]);
 		}
 		$rmRoutes = $this->removeExAppRoutes($exApp);
 		if ($rmRoutes === null) {
 			$this->logger->error(sprintf('Error while unregistering %s ExApp routes from the database.', $appId));
 		}
 		$this->cache?->remove('/ex_apps');
-		return $r === 1 && $rmRoutes !== null;
+		$unregistered = $r === 1 && $rmRoutes !== null;
+		if ($unregistered) {
+			$this->auditLogger->log(Operation::ExAppUnregistered, 'ExApp %s was unregistered', [
+				'appId' => $appId,
+			]);
+		}
+		return $unregistered;
Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: dc69a60e-646f-4c2f-a524-2e4ccdf606ee
Commits

Reviewing files that changed from the base of the PR and between c02350b and d856a75.

Files ignored due to path filters: 1

  • composer.lock is excluded by !**/*.lock
Files selected for processing: 25

  • CHANGELOG.md
  • lib/AuditLog/AuditLogger.php
  • lib/AuditLog/Operation.php
  • lib/Command/Daemon/RegisterDaemon.php
  • lib/Controller/DaemonConfigController.php
  • lib/Controller/ExAppsPageController.php
  • lib/Controller/HarpController.php
  • lib/Controller/TalkBotController.php
  • lib/DeployActions/AIODockerActions.php
  • lib/DeployActions/KubernetesActions.php
  • lib/Service/AppAPIService.php
  • lib/Service/DaemonConfigService.php
  • lib/Service/ExAppService.php
  • lib/Service/ProvidersAI/TaskProcessingService.php
  • tests/php/AuditLog/AuditLoggerTest.php
  • tests/php/Command/ExApp/UnregisterTest.php
  • tests/php/Controller/DaemonConfigControllerTest.php
  • tests/php/Controller/ExAppsPageControllerTest.php
  • tests/php/Controller/HarpControllerTest.php
  • tests/php/Controller/TalkBotControllerAuditLogTest.php
  • tests/php/Controller/TalkBotControllerTest.php
  • tests/php/DeployActions/KubernetesActionsTest.php
  • tests/php/Service/AppAPIServiceTest.php
  • tests/php/Service/DaemonConfigServiceTest.php
  • tests/php/Service/ExAppServiceAuditLogTest.php
Files with no reviewable changes: 1

  • lib/Service/ProvidersAI/TaskProcessingService.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Comment thread lib/Service/AppAPIService.php Resolved
Comment thread lib/Service/DaemonConfigService.php Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c1e77785-2bfb-4f19-b951-fb56a3276b66
Commits

Reviewing files that changed from the base of the PR and between d856a75 and bfcb389.

Files selected for processing: 3

  • lib/Service/DaemonConfigService.php
  • lib/Service/ExAppService.php
  • tests/php/Service/DaemonConfigServiceTest.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

Comment thread lib/Service/DaemonConfigService.php Resolved
Signed-off-by: Ghassen kefi <ghassen.kefi.dev@gmail.com>
Co-authored-by: Oleksandr Piskun <oleksandr2088@icloud.com>
Signed-off-by: Oleksandr Piskun <oleksandr2088@icloud.com>
@oleksandr-nc
oleksandr-nc force-pushed the feat/admin-audit-logging branch from 3a35d64 to 219f511 Compare November 12, 2026 10:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · Return a controller error when registry removal fails. · DaemonConfigService.php:370-371

lib/Service/DaemonConfigService.php:370-371
Minor · Stability & Availability · Quick win

Return a controller error when registry removal fails.

removeDockerRegistry() returns an error array when it removes no mapping. removeDaemonDockerRegistry() handles only null, so it calls jsonSerialize() on that array. PHP throws an Error, and the request fails with a 500 instead of a JSON error response.

A JSON body with boolean from and to values can reach this path. The loose in_array check accepts it when the stored mapping has non-empty string endpoints. The strict filter then removes nothing. Before this change, the same request succeeded as a no-op. A mapping that does not exist already triggers the same crash.

Suggested fix

-		$daemonConfig = $this->daemonConfigService->removeDockerRegistry($daemonConfig, $registryMap);
-		if ($daemonConfig === null) {
+		$result = $this->daemonConfigService->removeDockerRegistry($daemonConfig, $registryMap);
+		if (is_array($result)) {
+			return new JSONResponse($result, Http::STATUS_NOT_FOUND);
+		}
+		if ($result === null) {
 			return new JSONResponse(['error' => $this->l10n->t('Error removing Docker registry')], Http::STATUS_INTERNAL_SERVER_ERROR);
 		}
-		return new JSONResponse($daemonConfig->jsonSerialize(), Http::STATUS_OK);
+		return new JSONResponse($result->jsonSerialize(), Http::STATUS_OK);

Add a controller test that sends ['from' => true, 'to' => true] against a stored string mapping and expects a 404 response. No controller test covers this method.

Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1c5b55c1-0955-4fe8-a6de-ed7aef6aa7d8
Commits

Reviewing files that changed from the base of the PR and between bfcb389 and 219f511.

Files ignored due to path filters: 1

  • composer.lock is excluded by !**/*.lock
Files selected for processing: 3

  • CHANGELOG.md
  • lib/Service/DaemonConfigService.php
  • tests/php/Service/DaemonConfigServiceTest.php
Files skipped from review as they are similar to previous changes: 1

  • CHANGELOG.md

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

@oleksandr-nc
oleksandr-nc merged commit 5a6036c into main Nov 12, 2026
54 checks passed
@oleksandr-nc
oleksandr-nc deleted the feat/admin-audit-logging branch November 12, 2026 10:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants