Fail flows when a required execution sandbox is unavailable

What does this MR do and why?

Part of Allow Sandbox failure to be configured as blocking (#607753 - closed) • Charlie Linacre • 19.6 • Needs attention (MR 2 of 4: backend and enforcement).

Add require_sandbox to instance and namespace A... (!260145 - merged) • Charlie Linacre • 19.5 (merged) added a require_sandbox boolean column (default false) to ai_settings (instance) and namespace_ai_settings (top-level group). This MR makes the setting do something.

Today, when a flow runs on GitLab Runner and the SRT execution environment sandbox is missing or can't start, the job prints a warning and runs the agent without network and file system isolation. Security-conscious customers need a way to stop that.

With require_sandbox on, the SRT wrapper in ee/lib/gitlab/duo_workflow/sandbox.rb now prints an error and exits 1 instead of running the command. This happens in both cases:

  • srt is not installed.
  • srt is found, but its pre-check fails.

With the setting off, the command still runs without the sandbox, as before. The only change is the warning text: both warnings now end with "running command directly without sandbox". Before, the can't create sandbox warning ended with "running command directly". The two doc pages that quote that warning (environment_sandbox.md and flows/execution/_index.md) are updated to match.

The nono sandbox path (behind the duo_workflow_nono_sandbox flag) already fails closed and is unchanged.

Where the setting is read from:

  • On GitLab.com, it is read from the top-level group only.
  • On Self-Managed and Dedicated, it is read from the instance only.
  • This is done in Sandbox#parent_settings.
  • It is never read from a project's agent-config.yml, so a project can't opt out.
  • There is no cascading to subgroups. This was decided on the issue.

What else changes:

  • GraphQL: new requireSandbox argument on the DuoSettingsUpdate mutation and new field on DuoSettings. It uses the same permission checks as the other sandbox network settings. It is not marked as an experiment because it is not behind a feature flag.
  • REST: new require_sandbox attribute in ai_settings_attributes for the groups API, and in the group ai_settings response.
  • UI data: the value is passed to the admin and group settings pages (presenter and settings helper). The UI itself comes in a follow-up MR. In the group helper, the sandbox keys moved into a sandbox_settings_data method. Adding the new key pushed duo_workflow_settings_data over the Metrics/AbcSize limit.
  • Audit: instance changes are audited by Ai::DuoSettings::ChangesAuditor (ai_setting_updated). Top-level group changes are audited by Namespaces::AiNamespaceSettingChangesAuditor with a new require_sandbox_updated event type.

There is no feature flag. The setting is off by default and does nothing until an admin or group owner turns it on.

Notes for reviewers:

  • Like the sibling network settings, the groups API also accepts the value on subgroups and on Self-Managed groups, where it has no effect. The UI MR will only show it where it applies.
  • Like the sibling settings, a REST null for the boolean is not rejected by Grape.
  • Both are consistent with existing behavior and out of scope here.

Follow-ups:

  • MR 3: frontend (settings UI).
  • MR 4: user docs.

References

How to set up and validate locally

On a Self-Managed GDK:

  1. In the Rails console, turn the setting on for the instance:

    Ai::Setting.for_organization(Organizations::Organization.first).update!(require_sandbox: true)
  2. Run a flow on GitLab Runner with a Docker image that does not have srt installed (or a runner where the sandbox can't start).

  3. Check the job log. It shows Error: srt is not installed or not in PATH, refusing to run because the sandbox is required, and the job fails.

  4. Turn the setting off (require_sandbox: false) and run the flow again. The job logs Warning: srt is not installed or not in PATH, running command directly without sandbox and runs without the sandbox.

  5. Optionally, toggle it with GraphQL, and check the admin audit events for an ai_setting_updated event:

    mutation {
      duoSettingsUpdate(input: { requireSandbox: true }) {
        duoSettings {
          requireSandbox
        }
        errors
      }
    }

Testing notes

Tested Fail flows when a required execution sandbox is... (!262117 - merged) • Charlie Linacre • 19.6 locally on GDK (Self-Managed, instance setting, Docker runner): with require_sandbox on, flows fail instead of running unsandboxed. With it off, behavior is unchanged apart from the new warning wording.

Test notes

Environment: GDK at commit 1310e50d6373, Self-Managed (instance-level setting), local Docker runner in privileged mode, default flow image. On this runner the SRT pre-check fails, so jobs take the "SRT found but can't create sandbox" path.

1. Generated job script, all four cases. Ran the script produced by Gitlab::DuoWorkflow::Sandbox#wrap_command under bash.

require_sandbox srt Exit Command ran
off not installed 0 Yes, with Warning: srt is not installed or not in PATH, running command directly without sandbox
off pre-check fails 0 Yes, with Warning: SRT found but can't create sandbox (insufficient privileges), running command directly without sandbox
on not installed 1 No: Error: srt is not installed or not in PATH, refusing to run because the sandbox is required
on pre-check fails 1 No: Error: SRT found but can't create sandbox (insufficient privileges), refusing to run because the sandbox is required

2. GraphQL, as an instance admin.

  • duoSettings { requireSandbox } returns false by default.
  • duoSettingsUpdate(input: { requireSandbox: true }) sets it, with no errors.
  • requireSandbox: null is rejected with "requireSandbox can't be null".

3. Audit events. Each change creates an ai_setting_updated instance audit event with change: require_sandbox and the old and new values.

4. Real flow on the runner. Ran the same flow on an issue in a test project twice.

  • Setting on: the session failed to start. The workload job logged Error: SRT found but can't create sandbox (insufficient privileges), refusing to run because the sandbox is required and failed with exit code 1. The agent never ran.
  • Setting off: the job logged Warning: SRT found but can't create sandbox (insufficient privileges), running command directly without sandbox. The flow ran normally.

Not tested manually: the GitLab.com path (top-level group setting through the groups API and the group audit event). The specs in the MR cover both.

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.

🤖 Generated with Claude Code

Edited by SAM FIGUEROA

Merge request reports

Loading
Loading