Skip to content

flatpak-context: Implement --env-expanded for in-sandbox env expansion#6336

Open
ryanabx wants to merge 1 commit into
flatpak:mainfrom
ryanabx:work/rbrue/env-expansion
Open

flatpak-context: Implement --env-expanded for in-sandbox env expansion#6336
ryanabx wants to merge 1 commit into
flatpak:mainfrom
ryanabx:work/rbrue/env-expansion

Conversation

@ryanabx

@ryanabx ryanabx commented Sep 28, 2025

Copy link
Copy Markdown
Contributor

Resolves: #1415
Resolves: #6333

When using --env-expanded=KEY=$OTHER_KEY, $OTHER_KEY will be
evaluated as the incoming $OTHER_KEY value into the bwrap environment.
This is useful for adding locations to the PATH, among other things.

This environment expansion is subject to some limitations.

  1. The environment expansion only expands existing environment
    variables. For example,

flatpak run --env-expanded=A=VALUE --env-expanded=B=$A

will result in A being VALUE and B being an empty string. This is to
avoid the unnecessary complexity of recursing environment variables and
the potential nondeterminism of resolving environment variables in
differing orders on each execution. If you need to expand B to equal
A, you can easily perform the expansion yourself prior to running the
flatpak run command.

  1. For backwards compatibility with existing overrides, command
    invocations, and build args, only environment variables in
    --env-expanded will be expanded.

  2. --env-expanded environment variables are applied after --env, to
    allow modifying things like XDG_DATA_DIRS for example.

  3. You may escape environment variable expansion in --env-expanded by
    using a leading backslash before your environment expansion.

i.e. --env-expanded=A=\$VALUE will set A to the literal $VALUE

Note: In most shell environments, you will already have to escape with a
leading backslash when entering in the values as arguments or else you
will expand the variable on the host.


I haven't done a lot of C and GLib programming before, so let me know if this is a sane implementation. It makes sense to me though. If the function needs to be moved above or below other functions in flatpak-bwrap, let me know.

Also, currently if an environment variable is not found in the bwrap environment, it will behave like a shell would, and just evaluate to nothing. Let me know if we want to change that.

I also modified the test-exports and test-override tests to have some coverage for --env-expanded.

@ryanabx

ryanabx commented Sep 28, 2025

Copy link
Copy Markdown
Contributor Author

I haven't tested whether this works with persistent overrides, so that's worth making sure that it works. I think it should just work fine though.

Confirmed working:

image

@Erick555

Erick555 commented Sep 29, 2025

Copy link
Copy Markdown
Contributor

Some issues were raised in previous attempt that may need to be addressed here as well, see #2555 (comment) and below.

@smcv smcv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What @Erick555 said. Before anyone spends time on reviewing the implementation, I think we'll need a summary of the design that explains how it addresses the concerns from previous attempts at this, and I would not want to merge this without approval from @alexlarsson.

@smcv smcv requested a review from alexlarsson September 29, 2025 11:56
@hfiguiere

hfiguiere commented Sep 29, 2025

Copy link
Copy Markdown
Collaborator

How would the compatibility work with older version of a flatpak? If a package maintainer put this in finish-args and the user use a flatpak version that doesn't understand it. Given how long some distro version that never update flatpak (because they are hostile to it) are being used, this is likely to be unusable.

@smcv

smcv commented Sep 29, 2025

Copy link
Copy Markdown
Collaborator

How would the compatibility work with older version of a flatpak?

That's another valid question.

Conversely, if a pre-existing app has a literal $ in its --env (which might seem unlikely, but I wouldn't be entirely surprised if there was a dual-architecture x86_64/i386 app like Steam with LD_PRELOAD=/usr/${LIB}/something.so or LD_PRELOAD=/app/${LIB}/something.so), what's the backward compatibility story there? Adding --env-expanded=... would likely be a more backward-compatible way to introduce the new feature.

@hfiguiere

Copy link
Copy Markdown
Collaborator

flatpak run --env=PATH=$PATH:$HOME/.local/bin org.my.app

The fact that this specific case doesn't work is good. Because it's not supposed to work. binaries in $HOME are not supposed to work inside the sandbox.

@smcv

smcv commented Sep 29, 2025

Copy link
Copy Markdown
Collaborator

If a package maintainer put this in finish-args and the user use a flatpak version that doesn't understand it

I do have an answer for that, which is the same as every other new sandboxing parameter: if this feature was added, then the app maintainer should either not use it until the necessary Flatpak version is ubiquitous (a timescale of years), or set their app's minimum version to a Flatpak that has this feature and accept that it will not be installable on oldLTS distros.

@hfiguiere

Copy link
Copy Markdown
Collaborator

or set their app's minimum version to a Flatpak that has this feature and accept that it will not be installable on oldLTS distros.

Which mean not on flathub. This totally defeat the whole purpose.

@ryanabx

ryanabx commented Sep 29, 2025

Copy link
Copy Markdown
Contributor Author

Some issues were raised in previous attempt that may need to be addressed here as well, see #2555 (comment) and below.

What @Erick555 said. Before anyone spends time on reviewing the implementation, I think we'll need a summary of the design that explains how it addresses the concerns from previous attempts at this, and I would not want to merge this without approval from @alexlarsson.

Ah, I didn't realize there was a previous implementation, and I probably should have checked to see if it had been attempted before 😅

From Alex in the other PR:

So, the proper way imho is to apply all the elements in the envp, in order, expanding only against things already in the envp (i.e. no recursive expansion). Then you have to pick some arbitrary order (alphabetical?) in order to make this reproducible. On top of that we need to handle $ in the value as an escaped $, and possibly add the expand-if-variable-set syntax.

And from @smcv:

How would the compatibility work with older version of a flatpak?

That's another valid question.

Conversely, if a pre-existing app has a literal $ in its --env (which might seem unlikely, but I wouldn't be entirely surprised if there was a dual-architecture x86_64/i386 app like Steam with LD_PRELOAD=/usr/${LIB}/something.so or LD_PRELOAD=/app/${LIB}/something.so), what's the backward compatibility story there? Adding --env-expanded=... would likely be a more backward-compatible way to introduce the new feature.

I agree that if we want to move forward with this, maybe we do want to separate this into a new flag --env-expanded, and apply expanded variables after everything else sets envp (--env flags being the one I know of)

I would also have to have a set order, alphabetical seems fine to me, as long as we document it. Handling escaped $ might be as simple as evaluating \$ to $.

Regular expansion is not expressive enough to allow PATH extension when the original variable was empty or unset. You need something like the bash ${variable:+value} syntax.

We start to get more in the weeds with stuff like this, but I see now why this feature doesn't exist yet in flatpak

@ryanabx

ryanabx commented Sep 29, 2025

Copy link
Copy Markdown
Contributor Author

or set their app's minimum version to a Flatpak that has this feature and accept that it will not be installable on oldLTS distros.

Which mean not on flathub. This totally defeat the whole purpose.

Actually, I envisioned this to be more useful for local overrides that a user might set, I hadn't even considered it being set in a flatpak manifest, but it makes sense that developers might want to do that.

@ryanabx ryanabx marked this pull request as draft September 30, 2025 02:56
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch 7 times, most recently from c40ad15 to 696da9f Compare October 5, 2025 06:29
Comment thread tests/test-override.sh Fixed
Comment thread tests/test-override.sh Fixed
Comment thread tests/test-override.sh Fixed
Comment thread tests/test-override.sh Fixed
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch 2 times, most recently from d98a447 to 12a0a57 Compare October 6, 2025 01:44
@ryanabx ryanabx marked this pull request as ready for review October 6, 2025 01:54
@ryanabx

ryanabx commented Oct 6, 2025

Copy link
Copy Markdown
Contributor Author

Should be ready for an initial review now. Decided to go with a new flag --env-expanded, which is evaluated after --env (therefore overriding it), and expansion of every --env-expanded value happens before applying them, to avoid any ordering issues. I also updated test-exports and test-override to cover some of --env-expanded.

I'll address what I ended up going with regarding #2555 (comment) :

We need some form of escapes to handle the case where you actually want a $ in the env value

I have not made any escapes for --env-expanded, but should be easy to implement if that's wanted. Since it's a new flag, it shouldn't negatively affect any existing usage of --env

Regular expansion is not expressive enough to allow PATH extension when the original variable was empty or unset. You need something like the bash ${variable:+value} syntax.
Now we're parsing like a mini language...

I don't have any special ${variable:+value} syntax, instead simply assuming that any usage of this expects either the value to be previously set or for that not to matter. For an empty PATH, this would mean that

--env-expanded=PATH='$PATH:/my/new/path`

would evaluate to

PATH=:/my/new/path

which I don't actually know what that will do 🤷

expansion is order sensitive, whereas the env handling doesn't really have a well defined order (i.e. its a hash table, not an array of settings in FlatpakContext). This means that something like A=foo:$B + B=bar can result in A being foo: or foo:bar, depending on the order of expansion.

This one was pretty easy. I just made expansion happen before applying all the expansions in envp. We also avoid the idea of recursive expansion, simplifying it even more.

Let me know your thoughts!

@ryanabx ryanabx changed the title flatpak-run: Implement app environment expansion in --env values flatpak-context: Implement --env-expanded for in-sandbox env expansion Oct 6, 2025
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch 2 times, most recently from af0a128 to ad4ab25 Compare October 14, 2025 19:54
@musjj

musjj commented Oct 14, 2025

Copy link
Copy Markdown

which I don't actually know what that will do 🤷

This is how it is specified in POSIX:

A zero-length prefix is a legacy feature that indicates the current working directory. It appears as two adjacent characters ( "::" ), as an initial preceding the rest of the list, or as a trailing following the rest of the list. A strictly conforming application shall use an actual pathname (such as .) to represent the current working directory in PATH.

I tested Bash and it seems conformant:

$ cat greet
#!/usr/bin/env bash
echo hello

$ greet
bash: greet: command not found

$ PATH=":$PATH"

$ greet
hello

I'm not sure how it works for other <colon>-separated variables, but I won't be surprised if it copies this behavior.

@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch from ad4ab25 to bce9fc0 Compare November 5, 2025 22:58
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch from bce9fc0 to 28c73a1 Compare November 26, 2025 16:18
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch from 28c73a1 to 67e8be8 Compare December 4, 2025 18:24
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch from 67e8be8 to 087cf0f Compare January 16, 2026 18:47
@ryanabx

ryanabx commented Jan 31, 2026

Copy link
Copy Markdown
Contributor Author

If anyone is interested in this patch, some testing would be nice. From what I recall, this worked on my VM test setup, but edge cases could be different. 🤷

Resolves: flatpak#1415
Resolves: flatpak#6333

When using `--env-expanded=KEY=$OTHER_KEY`, `$OTHER_KEY` will be
evaluated as the incoming `$OTHER_KEY` value into the bwrap environment.
This is useful for adding locations to the PATH, among other things.

This environment expansion is subject to some limitations.

1. The environment expansion only expands existing environment
variables. For example,

`flatpak run --env-expanded=A=VALUE --env-expanded=B=$A`

will result in A being `VALUE` and B being an empty string. This is to
avoid the unnecessary complexity of recursing environment variables and
the potential nondeterminism of resolving environment variables in
differing orders on each execution. If you need to expand B to equal
A, you can easily perform the expansion yourself prior to running the
`flatpak run` command.

2. For backwards compatibility with existing overrides, command
invocations, and build args, only environment variables in
`--env-expanded` will be expanded.

3. `--env-expanded` environment variables are applied after `--env`, to
allow modifying things like `XDG_DATA_DIRS` for example.

4. You may escape environment variable expansion in `--env-expanded` by
using a leading backslash before your environment expansion.

i.e. `--env-expanded=A=\$VALUE` will set A to the literal `$VALUE`

Note: In most shell environments, you will already have to escape with a
leading backslash when entering in the values as arguments or else you
will expand the variable on the host.
@ryanabx ryanabx force-pushed the work/rbrue/env-expansion branch from 087cf0f to 5c0623e Compare January 31, 2026 18:26
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.

Expand env vars passed to --env during run [Feature request]: Environment expansion in overrides

6 participants