Admin Control To Disable External Agents

What does this MR do and why?

This MR introduces a setting to control the availability of AI catalog external agents at the instance or top-level group level. When external agents are disabled, they become inaccessible to users.

A few things to note:

  • The setting defaults to true, so there is no impact on existing external agents.
  • There is no UI for this setting yet, so it cannot be toggled from the frontend. See the verification section below for testing instructions.
  • This MR includes both database and policy changes. I've decided to keep them together in a single MR, rather than splitting them out as we did for custom flows and agents.

For reference, here's how we handled similar implementations for custom flows and agents:

Cascading Settings

To implement cascading settings, we can use the add_cascading_namespace_setting helper method in the migration. By default, this would add 2 columns (duo_external_agents_enabled and lock_duo_external_agents_enabled) to both namespace_settings and application_settings.

However, the application_settings table is already becoming quite wide with many columns. To avoid adding more columns there, we can leverage the existing duo_settings JSONB column and store these new settings as keys within it.

That said, for namespace_settings, we still need to add these as individual columns to take advantage of the cascading_attr helper.

DB changes for Cascading Settings

Added 2 new columns to the namespace_settings table:

  • duo_external_agents_enabled
  • lock_duo_external_agents_enabled

Added 2 new keys to the existing duo_settings JSONB column in application_settings:

  • duo_external_agents_enabled
  • lock_duo_external_agents_enabled

References

#594615 (closed)

How to set up and validate locally

Prerequisites

TOKEN="<personal-access-token-of-owner-user-of-TLG>"
BASE_URL="http://gdk.test:3000"

Step 1: Check TLG Setting

Verify the default state in Rails console:

top_level_group = Group.find_by_full_path('gitlab-duo') # Namespace setting
top_level_group.namespace_settings.duo_external_agents_enabled # => true (default)

cs = Gitlab::CurrentSettings.current_application_settings # Instance setting
cs.duo_external_agents_enabled # => true (default)

Step 2: Disable External Agents via API

curl --request PUT \
    --header "PRIVATE-TOKEN: $TOKEN" \
    --header "Content-Type: application/json" \
    --data '{ "duo_external_agents_availability": false }' \
    "$BASE_URL/api/v4/groups/gitlab-duo"

Verify the cascade in Rails console:

top_level_group.reload.namespace_settings.reload.duo_external_agents_enabled # => false

Check the audit log at GitLab Duo > Secure > Audit Events to confirm the change was recorded. Re-enabling the setting will trigger an additional audit event.

Screenshot

image

Step 3: Verify External Agents Are Disabled

Navigate to Automate > Agents:

  • Enabled tab: External agents should not appear here
  • Managed tab: External agents created in the project are still visible
  • External agent details page: Users cannot perform actions on disabled agents (only report the agent).
  • Known issue: The "Enable" and "New Agent" buttons remain visible but non-functional (error on click). Frontend changes needed to hide these buttons
Screenshots

BEFORE:

image


AFTER:

image


ONLY REPORT ACTION:

image

Step 4: Verify External Agents Can Not be Triggered

Trigging it will not work

Screenshot_2026-04-29_at_6.12.21_PM

NOTE: Currently error is just being return and note is not being created so we can't see that. This is existing issue and there is MR which fix this.

Step 5: Disable External Agents at Instance Level

Disable the instance-level setting via API:

Note: For below you need to use admin user's PAT.

curl --request PUT \
    --header "PRIVATE-TOKEN: $A_TOKEN" \
    --header "Content-Type: application/json" \
    --data '{ "duo_external_agents_availability": false }' \
    "$BASE_URL/api/v4/application/settings"

Restart the Rails console to ensure the application changes are fully loaded:

cs = Gitlab::CurrentSettings.current_application_settings
cs.duo_external_agents_enabled # => false

Verify the change in the audit log at Admin > Monitor > Audit Events.

Screenshot

image

Step 6: Verify Cascade Lock Behavior

Once the instance-level setting is disabled, group-level settings cannot be changed. Attempting to enable the setting at the group level will return an error:

curl --request PUT \
    --header "PRIVATE-TOKEN: $TOKEN" \
    --header "Content-Type: application/json" \
    --data '{ "duo_external_agents_availability": true }' \
    "$BASE_URL/api/v4/groups/gitlab-duo"

RESPONSE:

{"message":{"namespace_settings.duo_external_agents_enabled":["cannot be changed because it is locked by an ancestor"]}}

Important: Even if external agents are enabled at the top-level group, they will not be accessible if disabled at the instance level. The instance-level setting takes precedence and locks all descendant namespaces.

Testing Notes

  • Use an owner or maintainer account for testing
  • Do not test with the root user``

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #594615 (closed)

Edited by Jaydip Pansuriya

Merge request reports

Loading