Cap the size of the workload job environment

<🤖>

What does this MR do and why?

Workload jobs fail in prepare_script with dumb-init: argument list too long when their environment is too big for execve(). Linux caps one NAME=VALUE string at 128 KiB (MAX_ARG_STRLEN) and the whole environment at ARG_MAX, and nothing in Rails enforced either.

  • Ci::Workloads::RunWorkloadService rejects a workload with a variable over 128 KiB (measured as NAME=VALUE\0, like the kernel). It returns an error naming the variable, creates no pipeline, and logs names and sizes only.
  • A total over 1 MiB is only logged as a warning, with the same names and sizes. ARG_MAX scales with the runner's stack rlimit, so the total reject waits until the logs show how many workloads go over.
  • Gitlab::DuoWorkflow::WorkspaceAgentsReader caps DUO_WORKFLOW_AGENTS at 112 KiB. The old limits allowed 640 KiB. Agents that don't fit are dropped whole, and later agents that still fit are kept.

This is a backstop. Per-payload budgets and the recommend_reviewers dual-emit are follow-ups on the issue.

References

Screenshots or screen recordings

Not applicable, no UI change.

How to set up and validate locally

Prerequisites: a GDK with the Duo Agent Platform, a registered Docker runner, and a project where a catalog flow can be triggered by mentioning its service account, for example the Developer flow. Go through each part on master, then on this branch.

1. Oversized job environment

In production this happens with a mention on a long discussion thread. To reproduce it without one, pad the environment locally.

  1. In ee/app/services/ai/duo_workflows/start_workflow_service.rb, add this line to the hash in base_variables, after DUO_WORKFLOW_GOAL:

    DUO_WORKFLOW_PAD: 'a' * 200.kilobytes,
  2. Run gdk restart rails-web rails-background-jobs.

  3. On an issue in the project, mention the flow's service account with a short request.

  • master: the agent says it started, and its session links to a pipeline. The job fails before cloning with exec /usr/bin/dumb-init: argument list too long.

  • This branch: the agent replies Failed to start the Duo workflow. Please try again., and Build > Pipelines shows no new pipeline. The log entry names the variable, with byte counts but no values:

    grep "exceeds the size limits" log/application_json.log | tail -1 | jq "{oversized_variables, variables_bytesize}"

To check the total threshold, replace the line with 20 variables that are each under 128 KiB, about 2.4 MiB in all, then restart and mention again:

**(1..20).to_h { |i| [:"DUO_WORKFLOW_PAD_#{i}", 'a' * 120.kilobytes] },
  • master: the same argument list too long failure, from the kernel's 2 MiB total limit.
  • This branch: the same argument list too long failure, since the total is only logged. log/application_json.log has Workload job environment is over the total size threshold with an empty oversized_variables and a variables_bytesize over 1048576.

Remove the line when done.

2. Workspace agents budget

  1. Enable the flag: echo 'Feature.enable(:dap_workspace_agents)' | gdk rails console.

  2. On the default branch, add four files under .agents/agents/ with Code > New file, named a.md, b.md, c.md and d.md. Give each one this content, using the file name as the description and sizing the body as listed:

    ---
    description: <file name>
    ---
    <body>
    File Body
    a.md about 63 KB: ruby -e 'print "x" * 63_000' | pbcopy
    b.md about 63 KB, same command
    c.md one line
    d.md about 10 KB: ruby -e 'print "x" * 10_000' | pbcopy
  3. Trigger the flow with a short mention in a new thread.

  • master: all four agents go into DUO_WORKFLOW_AGENTS, about 137 KB, and the job fails with argument list too long.
  • This branch: the session starts. log/application_json.log has Ignoring workspace agents over the total size budget with names: ["b"], so c and d, which come after it, are still sent.

To clean up, delete .agents/agents and disable the flag.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

  • No feature flag. The only reject is for a variable over MAX_ARG_STRLEN, which can't execute today on any runner.
  • Changelog: fixed without EE: true, since the change spans app/ and ee/. The Danger warning about it is a false positive.
  • The branch was pushed with ci.skip, so a full pipeline is needed before merge.

</🤖>

Edited by Andras Herczeg

Merge request reports

Loading
Loading