Skip to content

feat(httpclient): forward cagent install UUID on gateway-bound requests#2653

Merged
dgageot merged 2 commits intodocker:mainfrom
dgageot:board/c99857e5dc51e9c4
May 6, 2026
Merged

feat(httpclient): forward cagent install UUID on gateway-bound requests#2653
dgageot merged 2 commits intodocker:mainfrom
dgageot:board/c99857e5dc51e9c4

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented May 6, 2026

Today the models gateway has stable per-session attribution (X-Cagent-Session-Id, #2631) and per-request metadata (model, provider, runtime), but no way to tie a stream of sessions back to a single cagent install. That gap rules out per-install rate limiting, install-level analytics, and basic abuse signals on the gateway side.

Cagent already maintains exactly that identifier: the persistent UUID stored in $configDir/user-uuid and reported as the user_uuid telemetry property. This change extracts that loader into a small pkg/userid package and forwards the value as X-Cagent-Id on gateway-bound requests — the same gating as X-Cagent-Session-Id (only set when X-Cagent-Forward is present), so direct provider calls and unrelated outbound HTTP never carry it.

pkg/telemetry now delegates to userid.Get instead of carrying its own copy of the file/IO logic, so the user_uuid event property and the X-Cagent-Id header are guaranteed to be the same string. userid.Get validates the on-disk value with uuid.Parse and regenerates if the file is missing, empty, or corrupted, so a hand-edited file can never propagate a malformed identifier to the gateway. Gateways that don't care can ignore the header, same pattern as #1751 (X-Cagent-Model-Name) and #2631.

@dgageot dgageot requested a review from a team as a code owner May 6, 2026 07:40
Copy link
Copy Markdown

@docker-agent docker-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

Comment thread pkg/userid/userid.go Outdated
}

func save(file, id string) error {
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Config directory created world-readable (0o755) while UUID file is protected (0o600)

save creates the config directory with 0o755, letting any local user enumerate it and see that the user-uuid file exists — even though they cannot read its contents (protected by 0o600).

Because the UUID is a persistent per-install identifier forwarded as X-Cagent-Id on every gateway request, directory-level enumeration on a shared/multi-user host is a mild privacy leak: it reveals that this tool is installed and (via ls -la) the file's modification time.

Suggested fix: use 0o700 for the directory, consistent with the intent of 0o600 on the file:

if err := os.MkdirAll(filepath.Dir(file), 0o700); err != nil {

gtardif
gtardif previously approved these changes May 6, 2026
The save helper created the config directory with 0o755, letting

any local user enumerate it and observe that the user-uuid file

exists (and its mtime via ls -la), even though they cannot read

its 0o600-protected contents.

Since the UUID is a persistent per-install identifier forwarded as

X-Cagent-Id on every gateway request, directory-level enumeration

on a shared/multi-user host is a mild privacy leak. Use 0o700 on

the directory to match the 0o600 protection on the file itself,

consistent with other sensitive paths in the codebase (sandbox

tokens, sqlite stores, log files).

Assisted-By: docker-agent
@dgageot dgageot merged commit 3d58819 into docker:main May 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants