doc/user/duo_agent_platform/flows/execution.md
{{< history >}}
{{< /history >}}
Flows use agents to execute tasks.
You can configure the environment where flows use CI/CD to execute. You can also choose to use your own runners, and specify variables in your jobs.
When flows execute in GitLab CI/CD:
By default, flows have network access to the GitLab instance only. For more information about network access rules, see how to configure a network policy. This separate environment protects from unintended consequences of running shell commands.
To prevent flows from running autonomously in the GitLab UI, you can turn off flow execution.
agent-config.ymlThe .gitlab/duo/agent-config.yml file controls how flows execute in CI/CD, including the
commands that run in setup_script. Because of how flows run, changes to this file affect more
than the user who commits them.
Flows run under the identity of the user who triggers them through composite identity.
Commands in setup_script execute with the triggering user's composite identity credentials,
not the credentials of the user who committed the configuration.
A user with write access to .gitlab/duo/agent-config.yml can influence what runs in another
user's runner environment. Modifications to this file affect the execution context of every
user who later triggers a flow in the project.
During setup_script execution, which runs outside Anthropic Sandbox Runtime (SRT),
the following sensitive variables are present in the environment:
GITLAB_OAUTH_TOKEN and GITLAB_TOKEN: The triggering user's OAuth token
through composite identity.DUO_WORKFLOW_GIT_HTTP_PASSWORD: The Git HTTP password.DUO_WORKFLOW_SERVICE_TOKEN: The service token.DUO_WORKFLOW_GIT_USER_EMAIL and DUO_WORKFLOW_GIT_USER_NAME: The triggering user's
email and name.For the full list of exposed variables, see flow execution variables.
To reduce the risk of unauthorized changes to the .gitlab/duo/agent-config.yml file:
Protect your default branch to prevent direct pushes.
Use Code Owners to require approval from specific
owners before changes to .gitlab/duo/agent-config.yml are merged.
For example, add the following to your CODEOWNERS file:
.gitlab/duo/agent-config.yml @your-group/security-reviewers
Configure approval rules that require review from trusted maintainers for merge requests that modify this file.
When a flow runs in CI/CD, the runner:
@gitlab/duo-cli package from the npm registry.The executor version is managed by GitLab and updated as part of regular releases.
[!note] The
@gitlab/duo-clinpm package is labeled "Experimental" for standalone CLI usage. When used within flows, the relevant capabilities are covered by the same support level as flows.
You can customize how flows are executed in CI/CD by creating an agent configuration file in your project.
[!note] You cannot use predefined CI/CD variables in this scenario. See the list of available variables.
.gitlab/duo/ folder if it doesn't exist.agent-config.yml.The configuration is applied when flows run in CI/CD for your project.
[!note] The configuration file is read only from the project's default branch. Files committed to other branches are ignored, even when a flow runs from those branches.
By default, all flows executed with CI/CD use a standard Docker image provided by GitLab.
This Docker image uses Anthropic Sandbox Runtime (srt)
to automatically include network protection.
You can change the Docker image and specify your own instead.
Your own image can be useful for complex projects that require specific dependencies or tools.
To use network protection in your image, add srt to your
Docker image with your preferred version:
# Install srt sandboxing with cache clearing and verification
ARG SANDBOX_RUNTIME_VERSION=0.0.20
RUN npm cache clean --force && \
npm install -g @anthropic-ai/sandbox-runtime@${SANDBOX_RUNTIME_VERSION} && \
test -s "$(npm root -g)/@anthropic-ai/sandbox-runtime/package.json" && \
srt --version
For more information about SRT and how to install it on a custom image, see remote execution environment sandbox.
To change the default Docker image, in the agent-config.yml file, add the following configuration:
image: YOUR_DOCKER_IMAGE
For example:
image: python:3.11-slim
Or for a Node.js project:
image: node:20-alpine
{{< history >}}
{{< /history >}}
GitLab also provides a hardened, minimal image variant based on Red Hat Universal Base Image (UBI) 9 Minimal. This image is designed for network-restricted, FedRAMP-style, or otherwise security-sensitive environments where a smaller attack surface, non-root execution, and a Red Hat UBI base are required.
The hardened image is published at:
registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image-hardened
It is built for both linux/amd64 and linux/arm64, and uses the same tag scheme as the default image:
:<short-sha> per build:<git-tag> per releasePrerequisites:
To use the hardened image, set it in your agent-config.yml:
image: registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image-hardened:<tag>
| Component | Version |
|---|---|
| Base image | Red Hat UBI 9 Minimal |
git | UBI 9 stock |
git-lfs | UBI 9 stock |
| Node.js | 20 (UBI 9 module stream) |
npm | Bundled with Node.js 20 |
@gitlab/duo-cli | Pre-installed |
glab (GitLab CLI) | Pre-installed |
| Runtime user | Non-root, UID 1001 (duo-runner) |
The image includes @gitlab/duo-cli and glab, so outbound access to registry.npmjs.org or registry.gitlab.com is not needed at flow execution time.
The hardened image runs as UID 1001 (duo-runner). The setup_script in your agent-config.yml
also runs as this non-root user, so it cannot install system packages with microdnf.
To add language runtimes or system packages:
Extend the image with your own FROM layer:
FROM registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image-hardened:<tag>
USER root
RUN microdnf install -y python3.12 python3.12-pip && microdnf clean all
USER 1001
Use setup_script for project dependencies that do not require root access. For example, pip install --user or npm install.
Use the hardened image when your environment requires:
Use the default image for general-purpose flows on connected environments that need multiple language runtimes out of the box.
If you use a custom Docker image, ensure that the following commands are available for the agent to function correctly:
gitnpm with a Node.js version compatible with @gitlab/duo-cli. For more information, see GitLab Duo CLI prerequisites.Most base images include these commands by default. However, minimal images (like alpine variants)
might require you to install them explicitly. If needed, you can install missing commands in the
setup script configuration.
[!note] In GitLab 18.9 and earlier, there is a known issue (587996) where flows might fail with newer versions of
gitin custom images. This issue is resolved in@gitlab/duo-cliversion 8.71.0.If you are on
@gitlab/duo-cliversion 8.71.0 or earlier, to avoid flows failing with newer Git versions, you can do either of the following:
- Use Git version
2.43.7or earlier in your custom image- Use
@gitlab/duo-cliversion 8.71.0.
Additionally, depending on the tool calls made by agents during flow execution, other common utilities might be required.
For example, if you use an Alpine-based image:
image: python:3.11-alpine
setup_script:
- apk add --update git nodejs npm
When you use a custom Docker image, the environment sandbox is only applied when Anthropic Sandbox Runtime (SRT) is included in your custom image. If SRT is not included, your flow can access any domain reachable from the runner and the full filesystem.
If you require network isolation with custom images, install SRT on your image and configure a network policy, or configure network-level controls on your runner (for example, firewall rules or network policies).
To reduce job startup time by approximately 15-20 seconds, include the
@gitlab/duo-cli npm package and the glab CLI in your custom image.
The hardened image pre-installs both tools.
You can define setup scripts that run before your flow executes. This is useful for installing dependencies, configuring environments, or performing any necessary initialization.
To add setup scripts, in the agent-config.yml file, add the following commands:
setup_script:
- apt-get update && apt-get install -y curl
- pip install -r requirements.txt
- echo "Setup complete"
These commands complete the following actions:
The user context for setup_script depends on the Docker image. The default
GitLab image runs as root. Custom images run as the user defined in the
image's USER directive. If your setup_script requires root access (for
example, to install system packages), ensure your custom image is configured
accordingly.
[!warning]
setup_scriptcommands run before SRT is applied and execute outside it. These commands have access to all environment variables in the flow, including the triggering user's OAuth token, service token, and identity details. For the security model and recommended protections, see security implications ofagent-config.yml.
In offline environments where runners cannot reach external
registries, you can prebuild a custom executor image that includes
@gitlab/duo-cli. When the GitLab Duo CLI is already in the image, the
flow startup skips the npm download step.
Prerequisites:
To configure flows for an offline environment:
On an online machine, build a custom image with the GitLab Duo CLI:
FROM registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image:v0.0.6
RUN npm install -g @gitlab/[email protected]
Alternatively, to avoid npm entirely, download the standalone binary from the GitLab package registry:
FROM registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image:v0.0.6
COPY duo-linux-x64 /usr/bin/duo
RUN chmod +x /usr/bin/duo
To download the standalone binary, run the following command:
curl --location "https://gitlab.com/api/v4/projects/46519181/packages/generic/duo-cli/8.86.0/duo-linux-x64" \
--output duo-linux-x64
Transfer the image to your offline environment. For example, with Docker, run the following commands:
# On an online machine
docker save my-duo-executor:latest -o duo-executor.tar
# Transfer `duo-executor.tar` to the offline environment
# On an offline machine
docker load -i duo-executor.tar
Push the image to your internal container registry.
Set the custom image registry:
registry.internal.example.com).In the top bar, select Search or go to and find your project.
To use the custom image, update the agent-config.yml file:
image: registry.internal.example.com/duo-executor:latest
To configure caching to speed up subsequent flow runs, configure the agent-config.yml file to
preserve files and directories between executions. Caching can be useful for dependency folders like node_modules or Python virtual environments.
To cache specific paths, add the following to your agent-config.yml file:
cache:
paths:
- node_modules/
- .npm/
You can use cache keys to create different caches for different scenarios. Cache keys help ensure that the cache is based on your project's state.
cache:
key: my-project-cache
paths:
- vendor/
- .bundle/
Create dynamic cache keys based on file contents (like lock files). When these files change, a new cache is created. This generates a SHA checksum of the specified files:
cache:
key:
files:
- package-lock.json
- yarn.lock
paths:
- node_modules/
Combine a prefix with the SHA computed for the cache key files:
cache:
key:
files:
- package-lock.json
prefix: $CI_JOB_NAME
paths:
- node_modules/
- .npm/
In this example, if the job name is test and the SHA checksum is abc123, the cache key becomes test-abc123.
paths field is required. A cache configuration without paths has no effect.prefix field.Here's an example agent-config.yml file that uses all available options:
# Custom Docker image
image: python:3.11
# Setup script to run before the flow
setup_script:
- apt-get update && apt-get install -y build-essential
- pip install --upgrade pip
- pip install -r requirements.txt
# Cache configuration
cache:
key:
files:
- requirements.txt
- Pipfile.lock
prefix: python-deps
paths:
- .cache/pip
- venv/
# Network configuration
network_policy:
include_recommended_allowed: true
allow_all_unix_sockets: true
allowed_domains:
- my-own-site.com
denied_domains:
- malicious.com
This configuration:
requirements.txt or Pipfile.lock changes, with a prefix of python-deps.Flows that use CI/CD are executed on runners. These runners must:
docker, docker-autoscaler, kubernetes, or others.
The shell executor is not supported.gitlab--duo tag, so the runner knows to pick up the correct jobs.duo_runner_restrictions feature flag.In addition, the following requirements apply to runners on GitLab Self-Managed:
duo-workflow-svc.runway.gitlab.net on port 443.registry.gitlab.com
or be able to access the Docker image you specified.For GitLab instances with self-signed certificates in the certificate chain, the GitLab Duo CLI requires additional configuration.
[!note] The runner's connection to the GitLab Duo Agent Platform Service is routed through the GitLab instance. Runners do not connect directly to
duo-workflow-svc.runway.gitlab.net. The firewall requirement forduo-workflow-svc.runway.gitlab.neton port443applies to the GitLab instance, not the runner. Your runner network configuration must allow outbound HTTPS traffic to the GitLab instance.
On GitLab.com, flows can use:
[!note] If your top-level group has IP address restrictions enabled, hosted runners cannot be used for flows. Hosted runners use dynamic IP addresses from cloud provider pools that cannot be added to your group's IP allowlist. Instead, configure your own group runner with the
gitlab--duotag at the top-level group level, and ensure its IP address is included in your group's allowlist.
Flows executed on runners can be secured with runtime sandboxing offering network and file system isolation. To benefit from sandboxing you must:
privileged = true in your runner configuration.Privileged mode is required for environment sandbox protection. This requirement applies when you use either the default GitLab-provided image or a custom image with SRT installed. If you use a custom Docker image without SRT, privileged mode is not required because the sandbox cannot be applied.
| Configuration | Privileged mode required | Sandbox active |
|---|---|---|
| Default image | Yes | Yes |
| Custom image with SRT | Yes | Yes |
| Custom image without SRT | No | No |
| Hardened UBI 9 Minimal image | No | No |