Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into lazy-trees
Browse files Browse the repository at this point in the history
  • Loading branch information
edolstra committed Nov 20, 2024
2 parents 9ed105a + 32becc8 commit 2ab5278
Show file tree
Hide file tree
Showing 22 changed files with 295 additions and 63 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ jobs:
- run: exec bash -c "nix-channel --update && nix-env -iA nixpkgs.hello && hello"

docker_push_image:
needs: [check_secrets, tests]
needs: [check_secrets, tests, vm_tests]
permissions:
contents: read
packages: write
Expand Down Expand Up @@ -194,7 +194,13 @@ jobs:
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- run: nix build -L .#hydraJobs.tests.githubFlakes .#hydraJobs.tests.tarballFlakes .#hydraJobs.tests.functional_user
- run: |
nix build -L \
.#hydraJobs.tests.functional_user \
.#hydraJobs.tests.githubFlakes \
.#hydraJobs.tests.nix-docker \
.#hydraJobs.tests.tarballFlakes \
;
flake_regressions:
needs: vm_tests
Expand Down
18 changes: 18 additions & 0 deletions doc/manual/source/installation/installing-docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,21 @@ $ nix build ./\#hydraJobs.dockerImage.x86_64-linux
$ docker load -i ./result/image.tar.gz
$ docker run -ti nix:2.5pre20211105
```

# Docker image with non-root Nix

If you would like to run Nix in a container under a user other than `root`,
you can build an image with a non-root single-user installation of Nix
by specifying the `uid`, `gid`, `uname`, and `gname` arguments to `docker.nix`:

```console
$ nix build --file docker.nix \
--arg uid 1000 \
--arg gid 1000 \
--argstr uname user \
--argstr gname user \
--argstr name nix-user \
--out-link nix-user.tar.gz
$ docker load -i nix-user.tar.gz
$ docker run -ti nix-user
```
50 changes: 35 additions & 15 deletions docker.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
, maxLayers ? 100
, nixConf ? {}
, flake-registry ? null
, uid ? 0
, gid ? 0
, uname ? "root"
, gname ? "root"
}:
let
defaultPkgs = with pkgs; [
Expand Down Expand Up @@ -50,6 +54,15 @@ let
description = "Unprivileged account (don't use!)";
};

} // lib.optionalAttrs (uid != 0) {
"${uname}" = {
uid = uid;
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/home/${uname}";
gid = gid;
groups = [ "${gname}" ];
description = "Nix user";
};
} // lib.listToAttrs (
map
(
Expand All @@ -70,6 +83,8 @@ let
root.gid = 0;
nixbld.gid = 30000;
nobody.gid = 65534;
} // lib.optionalAttrs (gid != 0) {
"${gname}".gid = gid;
};

userToPasswd = (
Expand Down Expand Up @@ -150,6 +165,8 @@ let
in
"${n} = ${vStr}") (defaultNixConf // nixConf))) + "\n";

userHome = if uid == 0 then "/root" else "/home/${uname}";

baseSystem =
let
nixpkgs = pkgs.path;
Expand Down Expand Up @@ -237,26 +254,26 @@ let
mkdir -p $out/etc/nix
cat $nixConfContentsPath > $out/etc/nix/nix.conf
mkdir -p $out/root
mkdir -p $out/nix/var/nix/profiles/per-user/root
mkdir -p $out${userHome}
mkdir -p $out/nix/var/nix/profiles/per-user/${uname}
ln -s ${profile} $out/nix/var/nix/profiles/default-1-link
ln -s $out/nix/var/nix/profiles/default-1-link $out/nix/var/nix/profiles/default
ln -s /nix/var/nix/profiles/default $out/root/.nix-profile
ln -s /nix/var/nix/profiles/default $out${userHome}/.nix-profile
ln -s ${channel} $out/nix/var/nix/profiles/per-user/root/channels-1-link
ln -s $out/nix/var/nix/profiles/per-user/root/channels-1-link $out/nix/var/nix/profiles/per-user/root/channels
ln -s ${channel} $out/nix/var/nix/profiles/per-user/${uname}/channels-1-link
ln -s $out/nix/var/nix/profiles/per-user/${uname}/channels-1-link $out/nix/var/nix/profiles/per-user/${uname}/channels
mkdir -p $out/root/.nix-defexpr
ln -s $out/nix/var/nix/profiles/per-user/root/channels $out/root/.nix-defexpr/channels
echo "${channelURL} ${channelName}" > $out/root/.nix-channels
mkdir -p $out${userHome}/.nix-defexpr
ln -s $out/nix/var/nix/profiles/per-user/${uname}/channels $out${userHome}/.nix-defexpr/channels
echo "${channelURL} ${channelName}" > $out${userHome}/.nix-channels
mkdir -p $out/bin $out/usr/bin
ln -s ${pkgs.coreutils}/bin/env $out/usr/bin/env
ln -s ${pkgs.bashInteractive}/bin/bash $out/bin/sh
'' + (lib.optionalString (flake-registry-path != null) ''
nixCacheDir="/root/.cache/nix"
nixCacheDir="${userHome}/.cache/nix"
mkdir -p $out$nixCacheDir
globalFlakeRegistryPath="$nixCacheDir/flake-registry.json"
ln -s ${flake-registry-path} $out$globalFlakeRegistryPath
Expand All @@ -268,7 +285,7 @@ let
in
pkgs.dockerTools.buildLayeredImageWithNixDb {

inherit name tag maxLayers;
inherit name tag maxLayers uid gid uname gname;

contents = [ baseSystem ];

Expand All @@ -279,25 +296,28 @@ pkgs.dockerTools.buildLayeredImageWithNixDb {
fakeRootCommands = ''
chmod 1777 tmp
chmod 1777 var/tmp
chown -R ${toString uid}:${toString gid} .${userHome}
chown -R ${toString uid}:${toString gid} nix
'';

config = {
Cmd = [ "/root/.nix-profile/bin/bash" ];
Cmd = [ "${userHome}/.nix-profile/bin/bash" ];
User = "${toString uid}:${toString gid}";
Env = [
"USER=root"
"USER=${uname}"
"PATH=${lib.concatStringsSep ":" [
"/root/.nix-profile/bin"
"${userHome}/.nix-profile/bin"
"/nix/var/nix/profiles/default/bin"
"/nix/var/nix/profiles/default/sbin"
]}"
"MANPATH=${lib.concatStringsSep ":" [
"/root/.nix-profile/share/man"
"${userHome}/.nix-profile/share/man"
"/nix/var/nix/profiles/default/share/man"
]}"
"SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
"GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
"NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
"NIX_PATH=/nix/var/nix/profiles/per-user/root/channels:/root/.nix-defexpr/channels"
"NIX_PATH=/nix/var/nix/profiles/per-user/${uname}/channels:${userHome}/.nix-defexpr/channels"
];
};

Expand Down
3 changes: 3 additions & 0 deletions packaging/dependencies.nix
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ let
pkgs.buildPackages.meson
pkgs.buildPackages.ninja
] ++ prevAttrs.nativeBuildInputs or [];
mesonCheckFlags = prevAttrs.mesonCheckFlags or [] ++ [
"--print-errorlogs"
];
};

mesonBuildLayer = finalAttrs: prevAttrs:
Expand Down
4 changes: 2 additions & 2 deletions src/libcmd/common-eval-args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ EvalSettings evalSettings {
{
{
"flake",
[](ref<Store> store, std::string_view rest) {
[](EvalState & state, std::string_view rest) {
experimentalFeatureSettings.require(Xp::Flakes);
// FIXME `parseFlakeRef` should take a `std::string_view`.
auto flakeRef = parseFlakeRef(fetchSettings, std::string { rest }, {}, true, false);
debug("fetching flake search path element '%s''", rest);
auto [accessor, _] = flakeRef.resolve(store).lazyFetch(store);
auto [accessor, _] = flakeRef.resolve(state.store).lazyFetch(state.store);
return SourcePath(accessor);
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr-c/nix_api_expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, nix_val
if (context)
context->last_err_code = NIX_OK;
try {
state->state.callFunction(fn->value, nargs, (nix::Value * *)args, value->value, nix::noPos);
state->state.callFunction(fn->value, {(nix::Value * *) args, nargs}, value->value, nix::noPos);
state->state.forceValue(value->value, nix::noPos);
}
NIXC_CATCH_ERRS
Expand Down
6 changes: 6 additions & 0 deletions src/libexpr-test-support/tests/libexpr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ namespace nix {
return v;
}

Value * maybeThunk(std::string input, bool forceValue = true) {
Expr * e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
assert(e);
return e->maybeThunk(state, state.baseEnv);
}

Symbol createSymbol(const char * value) {
return state.symbols.create(value);
}
Expand Down
25 changes: 24 additions & 1 deletion src/libexpr-tests/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,27 @@ TEST(nix_isAllowedURI, non_scheme_colon) {
ASSERT_FALSE(isAllowedURI("https://foo/bar:baz", allowed));
}

} // namespace nix
class EvalStateTest : public LibExprTest {};

TEST_F(EvalStateTest, getBuiltins_ok) {
auto evaled = maybeThunk("builtins");
auto & builtins = state.getBuiltins();
ASSERT_TRUE(builtins.type() == nAttrs);
ASSERT_EQ(evaled, &builtins);
}

TEST_F(EvalStateTest, getBuiltin_ok) {
auto & builtin = state.getBuiltin("toString");
ASSERT_TRUE(builtin.type() == nFunction);
// FIXME
// auto evaled = maybeThunk("builtins.toString");
// ASSERT_EQ(evaled, &builtin);
auto & builtin2 = state.getBuiltin("true");
ASSERT_EQ(state.forceBool(builtin2, noPos, "in unit test"), true);
}

TEST_F(EvalStateTest, getBuiltin_fail) {
ASSERT_THROW(state.getBuiltin("nonexistent"), EvalError);
}

} // namespace nix
4 changes: 2 additions & 2 deletions src/libexpr/eval-settings.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace nix {

class Store;
class EvalState;

struct EvalSettings : Config
{
Expand All @@ -20,7 +20,7 @@ struct EvalSettings : Config
* The return value is (a) whether the entry was valid, and, if so,
* what does it map to.
*/
using LookupPathHook = std::optional<SourcePath>(ref<Store> store, std::string_view);
using LookupPathHook = std::optional<SourcePath>(EvalState & state, std::string_view);

/**
* Map from "scheme" to a `LookupPathHook`.
Expand Down
Loading

0 comments on commit 2ab5278

Please sign in to comment.