Skip to content

Add rawsetenv message type for provider plugins#13742

Open
rajyan wants to merge 1 commit into
docker:mainfrom
rajyan:13727-rawsetenv
Open

Add rawsetenv message type for provider plugins#13742
rajyan wants to merge 1 commit into
docker:mainfrom
rajyan:13727-rawsetenv

Conversation

@rajyan

@rajyan rajyan commented Apr 16, 2026

Copy link
Copy Markdown

What I did

Added a new rawsetenv message type to the provider plugin protocol. This allows providers to inject environment variables into dependent services without the automatic service name prefix.

Currently, setenv always prefixes variables with the service name (e.g., URL becomes DATABASE_URL). This works well for connection strings, but some applications require exact variable names that cannot be altered. There is no way to inject these as-is today.

With this change, providers can choose per-variable whether to use the prefixed (setenv) or unprefixed (rawsetenv) behavior:

{"type": "setenv", "message": "URL=https://example.com"}
{"type": "rawsetenv", "message": "SECRET_KEY=xxx"}

Changes

  • pkg/compose/plugins.go — Add RawSetEnvType constant and pluginVariables struct to separate prefixed/raw variables
  • docs/extension.md — Document rawsetenv in the protocol specification
  • docs/examples/provider.go — Add rawsetenv usage to the example provider
  • pkg/e2e/providers_test.go — Test for single-provider rawsetenv and multi-provider rawsetenv
  • pkg/e2e/fixtures/providers/rawsetenv.yaml — Test fixture

Related issue

resolves #13727

Providers can now send rawsetenv messages to inject environment
variables into dependent services without the automatic service name
prefix. This enables use cases where applications require exact
variable names that cannot be altered.

Closes docker#13727

Signed-off-by: Yohta Kimura <38206553+rajyan@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rajyan rajyan force-pushed the 13727-rawsetenv branch from 3ab9b49 to 101a41c Compare June 3, 2026 12:43
@phillias

Copy link
Copy Markdown

this patch worked for my issue with mariadb requiring MYSQL_ROOT_PASSWORD with no override, not LOCKET_MYSQL_ROOT_PASSWORD as the compose provider was passing.

@glours glours left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Few things to address before we can merge.
Also we need to add a sibling fixture to pkg/e2e/fixtures/providers/rawsetenv.yaml that sets environment: { CLOUD_REGION: user-value } on the test service, and assert that the resulting value matches the documented behavior (skipped write, warning, or overwrite, depending on which resolution is chosen).

Comment thread pkg/compose/plugins.go
}

variables, err := s.executePlugin(cmd, command, service)
vars, err := s.executePlugin(cmd, command, service)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why this rename?

Comment thread pkg/compose/plugins.go
s.Environment[prefix+key] = &val
}
for key, val := range vars.raw {
s.Environment[key] = &val

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rawsetenv silently overwrites user-defined env vars

If a user sets environment: { CLOUD_REGION: eu-west-1 } and a provider emits rawsetenv CLOUD_REGION=us-east-1, the user value is silently clobbered. setenv was immune thanks to the prefix.
Please either skip writes when the key already exists, or we need to document this precedence explicitly.

@ndeloof what is you preference here? I'm in favor of the overwrite + warning message in logs, and you?

Comment thread docs/extension.md
Comment on lines +108 to +111
This is useful when injecting secrets or configuration values that must match exact variable names expected by
applications or frameworks. Unlike `setenv`, which avoids collisions through automatic prefixing, `rawsetenv` keys
are the provider's responsibility to keep unique. If multiple providers emit the same `rawsetenv` key, the last one
to run will overwrite previous values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

executor.go runs plan nodes concurrently via errgroup. Two providers without a mutual dependency run in parallel; mux serializes the writes but not their order. The doc says "the last one to run will overwrite previous values", literally true, but readers will assume declaration order wins.
Either tighten the doc, or detect cross-provider rawsetenv collisions and fail.

Comment thread pkg/e2e/providers_test.go
env := getEnv(res.Combined(), false)
assert.Check(t, slices.Contains(env, "PROVIDER1_URL=https://magic.cloud/provider1"), env)
assert.Check(t, slices.Contains(env, "PROVIDER2_URL=https://magic.cloud/provider2"), env)
assert.Check(t, slices.Contains(env, "CLOUD_REGION=us-east-1"), env)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

both providers emit the same CLOUD_REGION value, so the conflict path is never exercised. Please add a test where a rawsetenv key collides with a user-defined env var

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.

Provider services: cannot inject environment variables without service name prefix

3 participants