Skip to content

fix: inherit config.json env vars in exec processes#3439

Merged
saku3 merged 7 commits intoyouki-dev:mainfrom
KevinKickass:fix/exec-inherit-env
Mar 11, 2026
Merged

fix: inherit config.json env vars in exec processes#3439
saku3 merged 7 commits intoyouki-dev:mainfrom
KevinKickass:fix/exec-inherit-env

Conversation

@KevinKickass
Copy link
Copy Markdown
Contributor

Closes #3428

Problem

youki exec does not inherit environment variables from the container's config.json process.env. Only variables passed via --env on the CLI (plus PATH from the spec) are available to the exec process. This differs from runc, crun, and runsc, which all inherit the full process.env.

Reproduction:

youki spec  # add AAA=bbb to process.env
youki run yy
youki exec yy sh -c "echo $AAA"  # prints nothing (expected: bbb)

Root cause

In crates/libcontainer/src/container/tenant_builder.rs, the function get_path_from_spec() only extracted the PATH variable from the spec's env. This single value was passed to get_environment(), which built the exec env from CLI --env args + that one PATH fallback. All other spec env vars were silently dropped.

Changes

crates/libcontainer/src/container/tenant_builder.rs (only file changed):

  1. Replaced get_path_from_spec() with get_env_from_spec() — returns all env vars from the container spec instead of just PATH. The old function was only used in one place, so nothing else is affected.

  2. Rewrote get_environment() — now takes the full spec env as a baseline. CLI --env overrides by variable name (matching by the key before =). This means:

    • Spec env vars are inherited (matches runc/crun/runsc behavior)
    • --env FOO=bar on exec still overrides FOO from the spec
    • New vars via --env are appended as before
  3. Added 5 unit tests for get_environment():

    • env_inherits_spec_vars — spec vars are passed through
    • cli_env_overrides_spec — CLI --env takes precedence by name
    • cli_env_adds_new_vars — new CLI vars are appended
    • empty_spec_env_uses_cli_only — no spec env, CLI only
    • no_env_at_all — empty in, empty out

Backward compatibility

Fully backward compatible. The --env flag still works exactly as before (overrides by name). The only difference is that spec env vars are now inherited as the baseline, which is what users expect from the OCI runtime spec and how every other runtime handles it.

@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from 5efb350 to be3c32c Compare March 1, 2026 16:02
@saku3 saku3 added the kind/bug label Mar 1, 2026
@stepancheg stepancheg mentioned this pull request Mar 2, 2026
13 tasks
Copy link
Copy Markdown
Contributor

@nayuta723 nayuta723 left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! The implementation looks solid. I’ve left a few comments mainly around simplification and avoiding unnecessary allocations.

Comment thread crates/libcontainer/src/container/tenant_builder.rs Outdated
Comment thread crates/libcontainer/src/container/tenant_builder.rs Outdated
Comment thread crates/libcontainer/src/container/tenant_builder.rs Outdated
@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from b1e5100 to bc4bddc Compare March 2, 2026 20:08
Previously, youki exec only used env vars passed via --env on the CLI,
plus PATH from the container spec. All other spec env vars were silently
dropped. This differs from runc, crun, and runsc, which inherit the full
process.env from config.json.

Now the spec's env vars are used as a baseline, with CLI --env overriding
by variable name. This matches the behavior of other OCI runtimes.

Closes youki-dev#3428

Signed-off-by: KevinKickass <k@ppload.eu>
@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from b7ed342 to 46857df Compare March 2, 2026 20:14
Comment thread crates/libcontainer/src/container/tenant_builder.rs Outdated
@saku3
Copy link
Copy Markdown
Member

saku3 commented Mar 3, 2026

Could you please make sure the CI passes?

Also, it would be great if we could add an e2e test for this.

Ref: https://github.com/youki-dev/youki/tree/main/tests/contest/contest

KevinKickass and others added 4 commits March 3, 2026 13:51
Add contest e2e tests for exec environment variable handling:
- spec env inheritance, CLI override, CLI addition, process.json

Merge duplicate test modules (mod test + mod tests) in
tenant_builder.rs into a single mod tests block and fix
rustfmt chain formatting.

Signed-off-by: KevinKickass <k@ppload.eu>
Matches the pattern used in other contest tests (e.g., mount_test.rs).
Without this check, start_container would fail silently if the
container creation step had issues.

Signed-off-by: KevinKickass <k@ppload.eu>
@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from d549311 to 863c24a Compare March 9, 2026 13:29
Copy link
Copy Markdown
Member

@saku3 saku3 left a comment

Choose a reason for hiding this comment

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

Thank you for the update.
I left a comment, so could you please take a look?

self.get_process(process)?
} else {
let original_path_env = get_path_from_spec(spec);
// Inherit spec env vars for exec processes (matches runc/crun/runsc).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

// Use the spec's process env as the baseline for exec.

is enough. The same point is already described in get_environment(), so if the behavior changes later, having it in both places would hurt maintainability.

env_exists = true;
}
format!("{k}={v}")
/// Builds the environment for an exec process. The spec's env vars are
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/// Builds the environment for an exec process. The spec's env vars are
/// Builds the environment for an exec process.
/// The spec's env vars are used as the baseline, and env vars provided to the
/// builder, such as those from the CLI, override entries with the same key.
/// This follows runc's behavior.
/// See <https://github.com/youki-dev/youki/issues/3428>.

I checked the behavior of crun and runsc as well.

That said, mentioning them in the comment would make us implicitly responsible for keeping that comparison accurate, and there may still be subtle behavioral differences.
Since youki primarily aims for compatibility with runc, I think it would be better to mention only runc here.

}

#[test]
fn cli_env_overrides_spec() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When I think of this as a unit test for TenantContainerBuilder, it is not clear that this is specifically about the CLI.

How about the following name instead?

builder_env_overrides_spec

}

#[test]
fn cli_env_adds_new_vars() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Similarly, how about:

builder_env_adds_new_vars

SpecBuilder::default()
.process(
ProcessBuilder::default()
.args(vec!["sleep".to_string(), "10000".to_string()])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
.args(vec!["sleep".to_string(), "10000".to_string()])
.args(vec!["sleep".to_string(), "1000".to_string()])

}

/// Helper: run exec with --env flags via the CLI.
fn exec_with_env<P: AsRef<Path>>(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be better to consolidate this into the existing exec_container helper, but that does not need to be done right now.

}

#[test]
fn empty_spec_env_uses_cli_only() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
fn empty_spec_env_uses_cli_only() {
fn empty_spec_env_uses_builder_env_only() {

@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from 675aaa1 to 9e5f5a9 Compare March 10, 2026 17:21
- Shorten inline comment per review suggestion
- Update get_environment docstring to mention only runc
- Rename unit tests: cli_env_* -> builder_env_*
- Reduce sleep from 10000 to 1000 in exec_env tests
- Use full PATH in exec_env test specs so sleep is found
  in the busybox rootfs (/bin/sleep)
- Add env parameter to exec_container helper instead of
  duplicating the logic in a separate function

Signed-off-by: KevinKickass <k@ppload.eu>
@KevinKickass KevinKickass force-pushed the fix/exec-inherit-env branch from 9e5f5a9 to 3eccc4e Compare March 10, 2026 17:44
@KevinKickass
Copy link
Copy Markdown
Contributor Author

Thanks for taking the time to review this so thoroughly — really good catches all around.

Pushed the updates:

  • Shortened the inline comment and updated the docstring to reference only runc
  • Renamed the unit tests from cli_env_* to builder_env_*
  • Reduced sleep from 10000 to 1000
  • Fixed the exec_env integration tests — they were using PATH=/usr/bin which doesn't include /bin where sleep lives in the busybox rootfs. Switched to the full default PATH.
  • Consolidated exec_with_env into the existing exec_container helper by adding an env parameter directly, and updated all callers

@saku3
Copy link
Copy Markdown
Member

saku3 commented Mar 11, 2026

Thank you for the update.
Could you please fix the CI issue?

Running cargo fmt should resolve it.

Signed-off-by: KevinKickass <k@ppload.eu>
Copy link
Copy Markdown
Member

@saku3 saku3 left a comment

Choose a reason for hiding this comment

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

LGTM
Thanks.

Copy link
Copy Markdown
Contributor

@nayuta723 nayuta723 left a comment

Choose a reason for hiding this comment

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

LGTM!

@saku3 saku3 merged commit 76b913d into youki-dev:main Mar 11, 2026
28 checks passed
@github-actions github-actions Bot mentioned this pull request Mar 11, 2026
sat0ken pushed a commit to sat0ken/youki that referenced this pull request Mar 17, 2026
* fix: inherit spec env vars in exec process

Previously, youki exec only used env vars passed via --env on the CLI,
plus PATH from the container spec. All other spec env vars were silently
dropped. This differs from runc, crun, and runsc, which inherit the full
process.env from config.json.

Now the spec's env vars are used as a baseline, with CLI --env overriding
by variable name. This matches the behavior of other OCI runtimes.

Closes youki-dev#3428

Signed-off-by: KevinKickass <k@ppload.eu>

* test: add e2e tests for exec --env and merge test modules

Add contest e2e tests for exec environment variable handling:
- spec env inheritance, CLI override, CLI addition, process.json

Merge duplicate test modules (mod test + mod tests) in
tenant_builder.rs into a single mod tests block and fix
rustfmt chain formatting.

Signed-off-by: KevinKickass <k@ppload.eu>

* fix: add check_container_created before start in exec_env tests

Matches the pattern used in other contest tests (e.g., mount_test.rs).
Without this check, start_container would fail silently if the
container creation step had issues.

Signed-off-by: KevinKickass <k@ppload.eu>

* fix: address review feedback and fix exec_env test PATH

- Shorten inline comment per review suggestion
- Update get_environment docstring to mention only runc
- Rename unit tests: cli_env_* -> builder_env_*
- Reduce sleep from 10000 to 1000 in exec_env tests
- Use full PATH in exec_env test specs so sleep is found
  in the busybox rootfs (/bin/sleep)
- Add env parameter to exec_container helper instead of
  duplicating the logic in a separate function

Signed-off-by: KevinKickass <k@ppload.eu>

* style: cargo fmt

Signed-off-by: KevinKickass <k@ppload.eu>

---------

Signed-off-by: KevinKickass <k@ppload.eu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: config.json env is not inherited into processes spawned with exec

3 participants