Restrict Duo Agent Platform job logs to Developer and above
What does this MR do and why?
Duo Agent Platform (DAP) flows run as CI jobs in pipelines with source duo_workflow. The executor prints the flow's final message to the job log. On public projects with public pipelines, anyone can read that log, including anonymous users. It can contain content the flow posted as an internal note, such as Duo Security Review findings. The agent session page already requires the Developer role.
This MR adds a duo_workflow_job condition to Ci::BuildPolicy. It prevents :read_build_trace for those jobs unless the user has the Developer-level _read_developer_job_artifact permission. It uses that permission instead of update_build, because archived projects lose update_build. The policy is checked on every read, so logs of jobs that already ran are covered too.
What this covers:
- The job page log, the
traceandrawendpoints, and/-/jobs/:id/artifacts/download?file_type=trace. - REST
GET /projects/:id/jobs/:job_id/trace. - GraphQL
CiJob.trace. - The MCP
get_joblog. - Duo Troubleshoot job (
troubleshoot_job_with_aidepends on:read_build_trace).
Impact
- Anonymous users, Guests, Planners, Reporters and Security Managers can no longer read logs of DAP jobs. They still see the job, its status and the pipeline.
- Jobs from other pipeline sources are unchanged.
- Custom flow triggers also run with source
duo_workflow, so their logs are restricted too. - Restricted users see the existing "The current user is not authorized to access the job log." alert, the same as debug-mode jobs.
Out of scope (follow-ups)
- Restricting artifacts of DAP jobs. This needs changes in
Ci::BuildPolicyandCi::JobArtifactPolicy, so it is a follow-up MR. !260132 - Hiding the "View raw" button for users who can't read the log. ()
References
- Issue: https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/work_items/3010
- Eligible for fix-in-public: https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/work_items/3010#note_3955526169
- Earlier flow-config approach that did not fix it: gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!7243 (closed)
Screenshots or screen recordings
How to set up and validate locally
-
Pick a project in GDK and make it public with public pipelines. In a Rails console:
project = Project.find_by_full_path('<namespace>/<project>') project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC, public_builds: true) -
Create a
duo_workflowjob with a log (no runner needed):definition = Ci::Workloads::WorkloadDefinition.new do |d| d.image = 'alpine' d.commands = ['echo hello'] end workload = Ci::Workloads::RunWorkloadService.new( project: project, current_user: User.find_by_username('root'), source: :duo_workflow, workload_definition: definition ).execute.payload build = workload.pipeline.builds.first build.trace.set("Pretend internal note content\n") build.success! puts Gitlab::Routing.url_helpers.project_job_url(project, build) -
Open that URL in a private window (signed out). The job page loads, but the log area shows "The current user is not authorized to access the job log." Opening
<job URL>/rawreturns 403. -
Sign in as a Reporter of the project. Same result. With a Reporter personal access token,
curl --header "PRIVATE-TOKEN: <token>" "<gdk url>/api/v4/projects/<project id>/jobs/<job id>/trace"returns 403. -
Sign in as a Developer (or use a Developer token). The log is visible and the API returns it.
-
Control: open any job from a normal (push) pipeline in the same project while signed out. Its log is still visible.
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.







