Declaratively defining environment variables

Per the conversation in the topic about using pre-built binaries inside snaps, please note that for a some time now we support declaring environment variables to be exported inside the snap environment directly in snapcraft.yaml.

For example, at the top level:

environment:
    SOME_VAR_NAME: some value

and/or under each application:

apps:
    myapp:
        command: ...
        environment:
            SOME_VAR_NAME: some_value
5 Likes

I think what still needs to be released for this to be generally available is support for variable expansion, I was surprised to notice that most of my use of environment had this construct:

apps:
    vim:
        command: vim
        environment:
            VIM_RUNTIME_DIR: $SNAP/usr

Or something like that. Is that currently working on the released versions?

1 Like

It didn’t work when I tried it on version 2.28. Unfortunately, this means that it’s still not possible to set $PATH for example, without relisting all directories or using the wrapper scripts of old.

If that doesn’t work, let’s get it fixed.

@chipaca Can you put that somewhere in your ever-growing list of paper cuts?

1 Like

To add to this, we can’t use env vars (nor a lot of other potentially useful stuff, like quotes) in commands. I think it makes sense for things like daemons to not need a wrapper just to have a funky commandline; not sure about regular commands though.

2 Likes

We have some tricks up our sleeves in snapcraft, this is one of the reasons we use the wrapper (among others)

btw, cool snippeting forum!

EDIT: my statement is true only for environment, not for command. Sorry for this mixup.

This should work with 2.23.6 (which is in -updates). We have a test in test-snapd-tools that looks like this: name: test-snapd-tools environment: EXTRA_CACHE_DIR: $SNAP_USER_DATA/.cache and when I run it: $ test-snapd-tools.env |grep CACHE EXTRA_CACHE_DIR=/home/egon/snap/test-snapd-tools/x1/.cache/.cache Unless I misunderstand the topic this is what you need, right?

done.

So a follow up question, is there a way to have the environment entries affect command but not be exported? This will help a lot with classic confined snaps.

Do you mean interpolating the command but not exporting as a variable? Mixing these two options seems super confusing, and the benefit is unclear. Seems simpler and more straightforward to simply use a variable name which isn’t used by the command.

The use case is to be able to do something like:

LD_LIBRARY_PATH=$SNAP/usr/lib/x86_64-gnu-linux <command>

without having LD_LIBRARY_PATH leak into command.

1 Like

The thing that uses this environment variable is ld.so, which is the interpreter of the dynamically linked executable. Not exporting means the shell holds it just for its own use on interpolations, which means it won’t pass it over during the child fork, which means ld.so won’t find it.

Just to add one egg to to this basket, there’s a bug now that $PATH is incorrect. I suspect it has happened since we introduced better environment handling. Details are available here:

https://rocket.ubuntu.com/channel/snapcraft?msg=ahsLwYvntQT5aZSTX

1 Like

One quirk I found is that variables defined in snap.yaml environment: sections are interpolated for $SNAP* variables for apps, but not in the configure hook, they are set to the un-interpolated string.

An example snap that shows this problem is here:

https://code.launchpad.net/~bloodearnest/+git/snap-env-test

The configure hook variables are left un-interpolated, but the app ones are. Additionally, a stray newline is added to the variables value!?

I note that only $SNAP* variables are interpolated, which i assume is a security feature? I would be nice if other variables defined within the same environment: block could also be interpreted?

I am working around this hardcoding /var/snap//current instead of $SNAP_DATA in my environment: block, but I need to strip my env vars in the configure hook code :frowning_face:

2 Likes

This is something @pstolowski wants to know about, I suspect

@bloodearnest, @zyga-snapd I’ll look at why this isn’t working for configure hook. Thanks for reporting.

1 Like

Ok, at first I thought this is a bug and has an easy explanation - we do not do osutil.SubstituteEnv(..) for hooks in snap-exec. But I think it is actually by design and not an oversight (one could also say it’s a limitation): hooks are executed by snapd with euid=root (but are confined of course), so doing env var expansion for hooks would be a security issue.

@bloodearnest so, we don’t interpolate the variables from “environment:” section for hooks, but you can of course use $SNAP_DATA, $SNAP_COMMON etc. directly in hooks (no need for intermediate values in the yaml).

Hmm, wait, this makes no sense. We run daemons as root and we do expand their environment. Is this really by design?

@zyga-snapd I don’t know the original designs and I didn’t implement the hook machinery. All I can say is right now the env expansion happens in snap-exec and for some reason we don’t expand for hooks - fixing this is a one line change if that’s what we want.

I think @niemeyer and @mvo should review this. It certainly feels broken to me.