mirror of
https://github.com/NixOS/nix.git
synced 2025-11-29 13:41:00 +01:00
Merge remote-tracking branch 'origin/master' into gdennis/git-filter-config
This commit is contained in:
commit
9bba7ac3e8
887 changed files with 34455 additions and 28681 deletions
11
tests/functional/build-cores.nix
Normal file
11
tests/functional/build-cores.nix
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
with import ./config.nix;
|
||||
|
||||
{
|
||||
# Test derivation that checks the NIX_BUILD_CORES environment variable
|
||||
testCores = mkDerivation {
|
||||
name = "test-build-cores";
|
||||
buildCommand = ''
|
||||
echo "$NIX_BUILD_CORES" > $out
|
||||
'';
|
||||
};
|
||||
}
|
||||
32
tests/functional/build-cores.sh
Executable file
32
tests/functional/build-cores.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source common.sh
|
||||
|
||||
clearStoreIfPossible
|
||||
|
||||
echo "Testing build-cores configuration behavior..."
|
||||
|
||||
# Test 1: When build-cores is set to a non-zero value, NIX_BUILD_CORES should have that value
|
||||
echo "Testing build-cores=4..."
|
||||
rm -f "$TEST_ROOT"/build-cores-output
|
||||
nix-build --cores 4 build-cores.nix -A testCores -o "$TEST_ROOT"/build-cores-output
|
||||
result=$(cat "$(readlink "$TEST_ROOT"/build-cores-output)")
|
||||
if [[ "$result" != "4" ]]; then
|
||||
echo "FAIL: Expected NIX_BUILD_CORES=4, got $result"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: build-cores=4 correctly sets NIX_BUILD_CORES=4"
|
||||
rm -f "$TEST_ROOT"/build-cores-output
|
||||
|
||||
# Test 2: When build-cores is set to 0, NIX_BUILD_CORES should be resolved to getDefaultCores()
|
||||
echo "Testing build-cores=0..."
|
||||
nix-build --cores 0 build-cores.nix -A testCores -o "$TEST_ROOT"/build-cores-output
|
||||
result=$(cat "$(readlink "$TEST_ROOT"/build-cores-output)")
|
||||
if [[ "$result" == "0" ]]; then
|
||||
echo "FAIL: NIX_BUILD_CORES should not be 0 when build-cores=0"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: build-cores=0 resolves to NIX_BUILD_CORES=$result (should be > 0)"
|
||||
rm -f "$TEST_ROOT"/build-cores-output
|
||||
|
||||
echo "All build-cores tests passed!"
|
||||
|
|
@ -5,9 +5,9 @@ configure_file(
|
|||
)
|
||||
|
||||
suites += {
|
||||
'name': 'ca',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'name' : 'ca',
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'build-cache.sh',
|
||||
'build-with-garbage-path.sh',
|
||||
'build.sh',
|
||||
|
|
@ -30,5 +30,5 @@ suites += {
|
|||
'substitute.sh',
|
||||
'why-depends.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ test_custom_build_dir() {
|
|||
nix-build check.nix -A failed --argstr checkBuildId "$checkBuildId" \
|
||||
--no-out-link --keep-failed --option build-dir "$TEST_ROOT/custom-build-dir" 2> "$TEST_ROOT/log" || status=$?
|
||||
[ "$status" = "100" ]
|
||||
[[ 1 == "$(count "$customBuildDir/nix-build-"*)" ]]
|
||||
local buildDir=("$customBuildDir/nix-build-"*)
|
||||
[[ 1 == "$(count "$customBuildDir/nix-"*)" ]]
|
||||
local buildDir=("$customBuildDir/nix-"*)
|
||||
if [[ "${#buildDir[@]}" -ne 1 ]]; then
|
||||
echo "expected one nix-build-* directory, got: ${buildDir[*]}" >&2
|
||||
echo "expected one nix-* directory, got: ${buildDir[*]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e ${buildDir[*]}/build ]]; then
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ expected=100
|
|||
if [[ -v NIX_DAEMON_PACKAGE ]]; then expected=1; fi # work around the daemon not returning a 100 status correctly
|
||||
|
||||
expectStderr "$expected" nix-build ./text-hashed-output.nix -A failingWrapper --no-out-link \
|
||||
| grepQuiet "build of '.*use-dynamic-drv-in-non-dynamic-drv-wrong.drv' failed"
|
||||
| grepQuiet "build of resolved derivation '.*use-dynamic-drv-in-non-dynamic-drv-wrong.drv' failed"
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ configure_file(
|
|||
)
|
||||
|
||||
suites += {
|
||||
'name': 'dyn-drv',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'name' : 'dyn-drv',
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'text-hashed-output.sh',
|
||||
'recursive-mod-json.sh',
|
||||
'build-built-drv.sh',
|
||||
|
|
@ -17,5 +17,5 @@ suites += {
|
|||
'old-daemon-error-hack.sh',
|
||||
'dep-built-drv-2.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,27 @@ rm -rf $TEST_HOME/.cache/nix
|
|||
path=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
||||
[[ $(cat $path/hello) = world ]]
|
||||
|
||||
# Fetch again. This should be cached.
|
||||
# NOTE: This has to be done before the test case below which tries to pack-refs
|
||||
# the reason being that the lookup on the cache uses the ref-file `/refs/heads/master`
|
||||
# which does not exist after packing.
|
||||
mv $repo ${repo}-tmp
|
||||
path2=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
||||
[[ $path = $path2 ]]
|
||||
|
||||
[[ $(nix eval --impure --expr "(builtins.fetchGit file://$repo).revCount") = 2 ]]
|
||||
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).rev") = $rev2 ]]
|
||||
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).shortRev") = ${rev2:0:7} ]]
|
||||
|
||||
# Fetching with a explicit hash should succeed.
|
||||
path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath")
|
||||
[[ $path = $path2 ]]
|
||||
|
||||
path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev1\"; }).outPath")
|
||||
[[ $(cat $path2/hello) = utrecht ]]
|
||||
|
||||
mv ${repo}-tmp $repo
|
||||
|
||||
# Fetch when the cache has packed-refs
|
||||
# Regression test of #8822
|
||||
git -C $TEST_HOME/.cache/nix/gitv3/*/ pack-refs --all
|
||||
|
|
@ -83,24 +104,6 @@ path2=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"
|
|||
# But without a hash, it fails.
|
||||
expectStderr 1 nix eval --expr 'builtins.fetchGit "file:///foo"' | grepQuiet "'fetchGit' doesn't fetch unlocked input"
|
||||
|
||||
# Fetch again. This should be cached.
|
||||
mv $repo ${repo}-tmp
|
||||
path2=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).outPath")
|
||||
[[ $path = $path2 ]]
|
||||
|
||||
[[ $(nix eval --impure --expr "(builtins.fetchGit file://$repo).revCount") = 2 ]]
|
||||
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).rev") = $rev2 ]]
|
||||
[[ $(nix eval --impure --raw --expr "(builtins.fetchGit file://$repo).shortRev") = ${rev2:0:7} ]]
|
||||
|
||||
# Fetching with a explicit hash should succeed.
|
||||
path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev2\"; }).outPath")
|
||||
[[ $path = $path2 ]]
|
||||
|
||||
path2=$(nix eval --refresh --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev1\"; }).outPath")
|
||||
[[ $(cat $path2/hello) = utrecht ]]
|
||||
|
||||
mv ${repo}-tmp $repo
|
||||
|
||||
# Using a clean working tree should produce the same result.
|
||||
path2=$(nix eval --impure --raw --expr "(builtins.fetchGit $repo).outPath")
|
||||
[[ $path = $path2 ]]
|
||||
|
|
@ -233,10 +236,10 @@ path9=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$rep
|
|||
# Specifying a ref without a rev shouldn't pick a cached rev for a different ref
|
||||
export _NIX_FORCE_HTTP=1
|
||||
rev_tag1_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag1\"; }).rev")
|
||||
rev_tag1=$(git -C $repo rev-parse refs/tags/tag1)
|
||||
rev_tag1=$(git -C $repo rev-parse refs/tags/tag1^{commit})
|
||||
[[ $rev_tag1_nix = $rev_tag1 ]]
|
||||
rev_tag2_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag2\"; }).rev")
|
||||
rev_tag2=$(git -C $repo rev-parse refs/tags/tag2)
|
||||
rev_tag2=$(git -C $repo rev-parse refs/tags/tag2^{commit})
|
||||
[[ $rev_tag2_nix = $rev_tag2 ]]
|
||||
unset _NIX_FORCE_HTTP
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ valid_ref 'foo./bar'
|
|||
valid_ref 'heads/foo@bar'
|
||||
valid_ref "$(printf 'heads/fu\303\237')"
|
||||
valid_ref 'foo-bar-baz'
|
||||
valid_ref 'branch#'
|
||||
valid_ref '$1'
|
||||
valid_ref 'foo.locke'
|
||||
|
||||
|
|
@ -97,6 +98,7 @@ invalid_ref 'heads/v@{ation'
|
|||
invalid_ref 'heads/foo\.ar' # should fail due to \
|
||||
invalid_ref 'heads/foo\bar' # should fail due to \
|
||||
invalid_ref "$(printf 'heads/foo\t')" # should fail because it has a TAB
|
||||
invalid_ref "$(printf 'heads/foo\37')"
|
||||
invalid_ref "$(printf 'heads/foo\177')"
|
||||
invalid_ref '@'
|
||||
|
||||
|
|
|
|||
|
|
@ -88,3 +88,8 @@ requireDaemonNewerThan "2.20"
|
|||
expected=100
|
||||
if [[ -v NIX_DAEMON_PACKAGE ]]; then expected=1; fi # work around the daemon not returning a 100 status correctly
|
||||
expectStderr $expected nix-build --expr '{ url }: builtins.derivation { name = "nix-cache-info"; system = "x86_64-linux"; builder = "builtin:fetchurl"; inherit url; outputHashMode = "flat"; }' --argstr url "file://$narxz" 2>&1 | grep 'must be a fixed-output or impure derivation'
|
||||
|
||||
requireDaemonNewerThan "2.32.0pre20250831"
|
||||
|
||||
expect 1 nix-build --expr 'import <nix/fetchurl.nix>' --argstr name 'name' --argstr url "file://authority.not.allowed/fetchurl.sh?a=1&a=2" --no-out-link |&
|
||||
grepQuiet "error: file:// URL 'file://authority.not.allowed/fetchurl.sh?a=1&a=2' has unexpected authority 'authority.not.allowed'"
|
||||
|
|
|
|||
|
|
@ -74,5 +74,10 @@ rec {
|
|||
nar-not-recursive = f2 "foo" ./fixed.builder2.sh "nar" "md5" "3670af73070fa14077ad74e0f5ea4e42";
|
||||
|
||||
# Experimental feature
|
||||
git = f2 "foo" ./fixed.builder2.sh "git" "sha1" "cd44baf36915d5dec8374232ea7e2057f3b4494e";
|
||||
|
||||
git-sha1 = f2 "foo" ./fixed.builder2.sh "git" "sha1" "cd44baf36915d5dec8374232ea7e2057f3b4494e";
|
||||
|
||||
git-sha256 =
|
||||
f2 "foo" ./fixed.builder2.sh "git" "sha256"
|
||||
"3c957653f90c34c0a8badf343b61393936cddf4a2ca93f64b21f02303ddedcc2";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,3 +135,35 @@ EOF
|
|||
|
||||
checkRes=$(nix flake check --all-systems $flakeDir 2>&1 && fail "nix flake check --all-systems should have failed" || true)
|
||||
echo "$checkRes" | grepQuiet "formatter.system-1"
|
||||
|
||||
# Test whether `nix flake check` builds checks.
|
||||
cat > $flakeDir/flake.nix <<EOF
|
||||
{
|
||||
outputs = { self }: {
|
||||
checks.$system.foo = with import ./config.nix; mkDerivation {
|
||||
name = "simple";
|
||||
buildCommand = "mkdir \$out";
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
cp "${config_nix}" "$flakeDir/"
|
||||
|
||||
expectStderr 0 nix flake check "$flakeDir" | grepQuiet 'running 1 flake check'
|
||||
|
||||
cat > $flakeDir/flake.nix <<EOF
|
||||
{
|
||||
outputs = { self }: {
|
||||
checks.$system.foo = with import ./config.nix; mkDerivation {
|
||||
name = "simple";
|
||||
buildCommand = "false";
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
# FIXME: error code 100 doesn't get propagated from the daemon.
|
||||
if !isTestOnNixOS && $NIX_REMOTE != daemon; then
|
||||
expectStderr 100 nix flake check "$flakeDir" | grepQuiet 'builder failed with exit code 1'
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -432,3 +432,71 @@ nix flake metadata "$flake2Dir" --reference-lock-file $TEST_ROOT/flake2-overridd
|
|||
|
||||
# reference-lock-file can only be used if allow-dirty is set.
|
||||
expectStderr 1 nix flake metadata "$flake2Dir" --no-allow-dirty --reference-lock-file $TEST_ROOT/flake2-overridden.lock
|
||||
|
||||
# After changing an input (flake2 from newFlake2Rev to prevFlake2Rev), we should have the transitive inputs locked by revision $prevFlake2Rev of flake2.
|
||||
prevFlake1Rev=$(nix flake metadata --json "$flake1Dir" | jq -r .revision)
|
||||
prevFlake2Rev=$(nix flake metadata --json "$flake2Dir" | jq -r .revision)
|
||||
|
||||
echo "# bla" >> "$flake1Dir/flake.nix"
|
||||
git -C "$flake1Dir" commit flake.nix -m 'bla'
|
||||
|
||||
nix flake update --flake "$flake2Dir"
|
||||
git -C "$flake2Dir" commit flake.lock -m 'bla'
|
||||
|
||||
newFlake1Rev=$(nix flake metadata --json "$flake1Dir" | jq -r .revision)
|
||||
newFlake2Rev=$(nix flake metadata --json "$flake2Dir" | jq -r .revision)
|
||||
|
||||
cat > "$flake3Dir/flake.nix" <<EOF
|
||||
{
|
||||
inputs.flake2.url = "flake:flake2/master/$newFlake2Rev";
|
||||
|
||||
outputs = { self, flake2 }: {
|
||||
};
|
||||
}
|
||||
EOF
|
||||
git -C "$flake3Dir" commit flake.nix -m 'bla'
|
||||
|
||||
rm "$flake3Dir/flake.lock"
|
||||
nix flake lock "$flake3Dir"
|
||||
[[ "$(nix flake metadata --json "$flake3Dir" | jq -r .locks.nodes.flake1.locked.rev)" = $newFlake1Rev ]]
|
||||
|
||||
cat > "$flake3Dir/flake.nix" <<EOF
|
||||
{
|
||||
inputs.flake2.url = "flake:flake2/master/$prevFlake2Rev";
|
||||
|
||||
outputs = { self, flake2 }: {
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
[[ "$(nix flake metadata --json "$flake3Dir" | jq -r .locks.nodes.flake1.locked.rev)" = $prevFlake1Rev ]]
|
||||
|
||||
baseDir=$TEST_ROOT/$RANDOM
|
||||
subdirFlakeDir1=$baseDir/foo1
|
||||
mkdir -p "$subdirFlakeDir1"
|
||||
|
||||
writeSimpleFlake "$baseDir"
|
||||
|
||||
cat > "$subdirFlakeDir1"/flake.nix <<EOF
|
||||
{
|
||||
outputs = inputs: {
|
||||
shouldBeOne = 1;
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
nix registry add --registry "$registry" flake2 "path:$baseDir?dir=foo1"
|
||||
[[ "$(nix eval --flake-registry "$registry" flake2#shouldBeOne)" = 1 ]]
|
||||
|
||||
subdirFlakeDir2=$baseDir/foo2
|
||||
mkdir -p "$subdirFlakeDir2"
|
||||
cat > "$subdirFlakeDir2"/flake.nix <<EOF
|
||||
{
|
||||
inputs.foo1.url = "path:$baseDir?dir=foo1";
|
||||
|
||||
outputs = inputs: { };
|
||||
}
|
||||
EOF
|
||||
|
||||
# Regression test for https://github.com/NixOS/nix/issues/13918
|
||||
[[ "$(nix eval --inputs-from "$subdirFlakeDir2" foo1#shouldBeOne)" = 1 ]]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
suites += {
|
||||
'name': 'flakes',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'name' : 'flakes',
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'flakes.sh',
|
||||
'develop.sh',
|
||||
'edit.sh',
|
||||
|
|
@ -35,5 +35,5 @@ suites += {
|
|||
'old-lockfiles.sh',
|
||||
'trace-ifd.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,13 @@ nix run -f shell-hello.nix env > $TEST_ROOT/actual-env
|
|||
# - we unset TMPDIR on macOS if it contains /var/folders. bad. https://github.com/NixOS/nix/issues/7731
|
||||
# - _ is set by bash and is expected to differ because it contains the original command
|
||||
# - __CF_USER_TEXT_ENCODING is set by macOS and is beyond our control
|
||||
# - __LLVM_PROFILE_RT_INIT_ONCE - implementation detail of LLVM source code coverage collection
|
||||
sed -i \
|
||||
-e 's/PATH=.*/PATH=.../' \
|
||||
-e 's/_=.*/_=.../' \
|
||||
-e '/^TMPDIR=\/var\/folders\/.*/d' \
|
||||
-e '/^__CF_USER_TEXT_ENCODING=.*$/d' \
|
||||
-e '/^__LLVM_PROFILE_RT_INIT_ONCE=.*$/d' \
|
||||
$TEST_ROOT/expected-env $TEST_ROOT/actual-env
|
||||
sort $TEST_ROOT/expected-env | uniq > $TEST_ROOT/expected-env.sorted
|
||||
# nix run appears to clear _. I don't understand why. Is this ok?
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# shellcheck shell=bash
|
||||
|
||||
source ../common.sh
|
||||
|
||||
TODO_NixOS # Need to enable git hashing feature and make sure test is ok for store we don't clear
|
||||
|
|
|
|||
|
|
@ -5,4 +5,8 @@ source common.sh
|
|||
# Store layer needs bugfix
|
||||
requireDaemonNewerThan "2.27pre20250122"
|
||||
|
||||
nix-build ../fixed.nix -A git --no-out-link
|
||||
nix-build ../fixed.nix -A git-sha1 --no-out-link
|
||||
|
||||
if isDaemonNewer "2.31pre20250724"; then
|
||||
nix-build ../fixed.nix -A git-sha256 --no-out-link
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
suites += {
|
||||
'name': 'git-hashing',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'simple.sh',
|
||||
'name' : 'git-hashing',
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'simple-sha1.sh',
|
||||
'simple-sha256.sh',
|
||||
'fixed.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
|
|
|||
96
tests/functional/git-hashing/simple-common.sh
Normal file
96
tests/functional/git-hashing/simple-common.sh
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# shellcheck shell=bash
|
||||
|
||||
source common.sh
|
||||
|
||||
# Assert is set
|
||||
[[ ${hashAlgo+x} ]]
|
||||
|
||||
repo="$TEST_ROOT/scratch"
|
||||
|
||||
initRepo () {
|
||||
git init "$repo" --object-format="$hashAlgo"
|
||||
|
||||
git -C "$repo" config user.email "you@example.com"
|
||||
git -C "$repo" config user.name "Your Name"
|
||||
}
|
||||
|
||||
# Compare Nix's and git's implementation of git hashing
|
||||
try () {
|
||||
local expected="$1"
|
||||
|
||||
local hash
|
||||
hash=$(nix hash path --mode git --format base16 --algo "$hashAlgo" "$TEST_ROOT/hash-path")
|
||||
[[ "$hash" == "$expected" ]]
|
||||
|
||||
git -C "$repo" rm -rf hash-path || true
|
||||
cp -r "$TEST_ROOT/hash-path" "$repo/hash-path"
|
||||
git -C "$repo" add hash-path
|
||||
git -C "$repo" commit -m "x"
|
||||
git -C "$repo" status
|
||||
local hash2
|
||||
hash2=$(git -C "$repo" rev-parse HEAD:hash-path)
|
||||
[[ "$hash2" = "$expected" ]]
|
||||
}
|
||||
|
||||
# Check Nix added object has matching git hash
|
||||
try2 () {
|
||||
local hashPath="$1"
|
||||
local expected="$2"
|
||||
|
||||
local path
|
||||
path=$(nix store add --mode git --hash-algo "$hashAlgo" "$repo/$hashPath")
|
||||
|
||||
git -C "$repo" add "$hashPath"
|
||||
git -C "$repo" commit -m "x"
|
||||
git -C "$repo" status
|
||||
local hashFromGit
|
||||
hashFromGit=$(git -C "$repo" rev-parse "HEAD:$hashPath")
|
||||
[[ "$hashFromGit" == "$expected" ]]
|
||||
|
||||
local caFromNix
|
||||
caFromNix=$(nix path-info --json "$path" | jq -r ".[] | .ca")
|
||||
[[ "fixed:git:$hashAlgo:$(nix hash convert --to nix32 "$hashAlgo:$hashFromGit")" = "$caFromNix" ]]
|
||||
}
|
||||
|
||||
test0 () {
|
||||
rm -rf "$TEST_ROOT/hash-path"
|
||||
echo "Hello World" > "$TEST_ROOT/hash-path"
|
||||
}
|
||||
|
||||
test1 () {
|
||||
rm -rf "$TEST_ROOT/hash-path"
|
||||
mkdir "$TEST_ROOT/hash-path"
|
||||
echo "Hello World" > "$TEST_ROOT/hash-path/hello"
|
||||
echo "Run Hello World" > "$TEST_ROOT/hash-path/executable"
|
||||
chmod +x "$TEST_ROOT/hash-path/executable"
|
||||
}
|
||||
|
||||
test2 () {
|
||||
rm -rf "$repo/dummy1"
|
||||
echo Hello World! > "$repo/dummy1"
|
||||
}
|
||||
|
||||
test3 () {
|
||||
rm -rf "$repo/dummy2"
|
||||
mkdir -p "$repo/dummy2"
|
||||
echo Hello World! > "$repo/dummy2/hello"
|
||||
}
|
||||
|
||||
test4 () {
|
||||
rm -rf "$repo/dummy3"
|
||||
mkdir -p "$repo/dummy3"
|
||||
mkdir -p "$repo/dummy3/dir"
|
||||
touch "$repo/dummy3/dir/file"
|
||||
echo Hello World! > "$repo/dummy3/dir/file"
|
||||
touch "$repo/dummy3/dir/executable"
|
||||
chmod +x "$repo/dummy3/dir/executable"
|
||||
echo Run Hello World! > "$repo/dummy3/dir/executable"
|
||||
}
|
||||
|
||||
test5 () {
|
||||
rm -rf "$repo/dummy4"
|
||||
mkdir -p "$repo/dummy4"
|
||||
mkdir -p "$repo/dummy4/dir"
|
||||
touch "$repo/dummy4/dir/file"
|
||||
ln -s './hello/world.txt' "$repo/dummy4/dir/symlink"
|
||||
}
|
||||
27
tests/functional/git-hashing/simple-sha1.sh
Executable file
27
tests/functional/git-hashing/simple-sha1.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
hashAlgo=sha1
|
||||
|
||||
source simple-common.sh
|
||||
|
||||
initRepo
|
||||
|
||||
# blob
|
||||
test0
|
||||
try "557db03de997c86a4a028e1ebd3a1ceb225be238"
|
||||
|
||||
# tree with children
|
||||
test1
|
||||
try "e5c0a11a556801a5c9dcf330ca9d7e2c572697f4"
|
||||
|
||||
test2
|
||||
try2 dummy1 "980a0d5f19a64b4b30a87d4206aade58726b60e3"
|
||||
|
||||
test3
|
||||
try2 dummy2 "8b8e43b937854f4083ea56777821abda2799e850"
|
||||
|
||||
test4
|
||||
try2 dummy3 "f227adfaf60d2778aabbf93df6dd061272d2dc85"
|
||||
|
||||
test5
|
||||
try2 dummy4 "06f3e789820fc488d602358f03e3a1cbf993bf33"
|
||||
29
tests/functional/git-hashing/simple-sha256.sh
Executable file
29
tests/functional/git-hashing/simple-sha256.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
hashAlgo=sha256
|
||||
|
||||
source simple-common.sh
|
||||
|
||||
requireDaemonNewerThan 2.31pre20250724
|
||||
|
||||
initRepo
|
||||
|
||||
# blob
|
||||
test0
|
||||
try "7c5c8610459154bdde4984be72c48fb5d9c1c4ac793a6b5976fe38fd1b0b1284"
|
||||
|
||||
# tree with children
|
||||
test1
|
||||
try "cd79952f42462467d0ea574b0283bb6eb77e15b2b86891e29f2b981650365474"
|
||||
|
||||
test2
|
||||
try2 dummy1 "f5b5cec05fb6f9302b507a48c1573e6f36075e954d97caa8667f784e9cdb0d13"
|
||||
|
||||
test3
|
||||
try2 dummy2 "399d851c74ceac2c2b61b53b13dcf5e88df3b6135c7df1f248a323c3c2f9aa78"
|
||||
|
||||
test4
|
||||
try2 dummy3 "d3ae8fc87e76b9b871bd06a58c925c5fb5f83b5393f9f58e4f6dba3f59470289"
|
||||
|
||||
test5
|
||||
try2 dummy4 "8c090dd057e8e01ffe1fec24a3133dfe52ba4eda822e67ee7fefc2af7c6a2906"
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source common.sh
|
||||
|
||||
repo="$TEST_ROOT/scratch"
|
||||
git init "$repo"
|
||||
|
||||
git -C "$repo" config user.email "you@example.com"
|
||||
git -C "$repo" config user.name "Your Name"
|
||||
|
||||
# Compare Nix's and git's implementation of git hashing
|
||||
try () {
|
||||
local hash=$(nix hash path --mode git --format base16 --algo sha1 $TEST_ROOT/hash-path)
|
||||
[[ "$hash" == "$1" ]]
|
||||
|
||||
git -C "$repo" rm -rf hash-path || true
|
||||
cp -r "$TEST_ROOT/hash-path" "$TEST_ROOT/scratch/hash-path"
|
||||
git -C "$repo" add hash-path
|
||||
git -C "$repo" commit -m "x"
|
||||
git -C "$repo" status
|
||||
local hash2=$(git -C "$TEST_ROOT/scratch" rev-parse HEAD:hash-path)
|
||||
[[ "$hash2" = "$1" ]]
|
||||
}
|
||||
|
||||
# blob
|
||||
rm -rf $TEST_ROOT/hash-path
|
||||
echo "Hello World" > $TEST_ROOT/hash-path
|
||||
try "557db03de997c86a4a028e1ebd3a1ceb225be238"
|
||||
|
||||
# tree with children
|
||||
rm -rf $TEST_ROOT/hash-path
|
||||
mkdir $TEST_ROOT/hash-path
|
||||
echo "Hello World" > $TEST_ROOT/hash-path/hello
|
||||
echo "Run Hello World" > $TEST_ROOT/hash-path/executable
|
||||
chmod +x $TEST_ROOT/hash-path/executable
|
||||
try "e5c0a11a556801a5c9dcf330ca9d7e2c572697f4"
|
||||
|
||||
# Check Nix added object has matching git hash
|
||||
try2 () {
|
||||
local hashPath="$1"
|
||||
local expected="$2"
|
||||
|
||||
local path=$(nix store add --mode git --hash-algo sha1 "$repo/$hashPath")
|
||||
|
||||
git -C "$repo" add "$hashPath"
|
||||
git -C "$repo" commit -m "x"
|
||||
git -C "$repo" status
|
||||
local hashFromGit=$(git -C "$repo" rev-parse "HEAD:$hashPath")
|
||||
[[ "$hashFromGit" == "$2" ]]
|
||||
|
||||
local caFromNix=$(nix path-info --json "$path" | jq -r ".[] | .ca")
|
||||
[[ "fixed:git:sha1:$(nix hash convert --to nix32 "sha1:$hashFromGit")" = "$caFromNix" ]]
|
||||
}
|
||||
|
||||
rm -rf "$repo/dummy1"
|
||||
echo Hello World! > "$repo/dummy1"
|
||||
try2 dummy1 "980a0d5f19a64b4b30a87d4206aade58726b60e3"
|
||||
|
||||
rm -rf "$repo/dummy2"
|
||||
mkdir -p "$repo/dummy2"
|
||||
echo Hello World! > "$repo/dummy2/hello"
|
||||
try2 dummy2 "8b8e43b937854f4083ea56777821abda2799e850"
|
||||
|
||||
rm -rf "$repo/dummy3"
|
||||
mkdir -p "$repo/dummy3"
|
||||
mkdir -p "$repo/dummy3/dir"
|
||||
touch "$repo/dummy3/dir/file"
|
||||
echo Hello World! > "$repo/dummy3/dir/file"
|
||||
touch "$repo/dummy3/dir/executable"
|
||||
chmod +x "$repo/dummy3/dir/executable"
|
||||
echo Run Hello World! > "$repo/dummy3/dir/executable"
|
||||
try2 dummy3 "f227adfaf60d2778aabbf93df6dd061272d2dc85"
|
||||
|
||||
rm -rf "$repo/dummy4"
|
||||
mkdir -p "$repo/dummy4"
|
||||
mkdir -p "$repo/dummy4/dir"
|
||||
touch "$repo/dummy4/dir/file"
|
||||
ln -s './hello/world.txt' "$repo/dummy4/dir/symlink"
|
||||
try2 dummy4 "06f3e789820fc488d602358f03e3a1cbf993bf33"
|
||||
6
tests/functional/git/meson.build
Normal file
6
tests/functional/git/meson.build
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
suites += {
|
||||
'name' : 'git',
|
||||
'deps' : [],
|
||||
'tests' : [ 'packed-refs-no-cache.sh' ],
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
81
tests/functional/git/packed-refs-no-cache.sh
Normal file
81
tests/functional/git/packed-refs-no-cache.sh
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Please see https://github.com/NixOS/nix/issues/13457
|
||||
# for a higher description of the purpose of the test.
|
||||
# tl;dr;fetchGit will utilize the git cache and avoid refetching when possible.
|
||||
# It relies on the presence of either the commit when rev is provided
|
||||
# or checks if the ref refs/heads/<ref_name> if ref is provided.
|
||||
#
|
||||
# Unfortunately, git can occasionally "pack references" which moves the references
|
||||
# from individual files to a single unifies file.
|
||||
# When this occurs, nix can no longer check for the presence of the ref to check
|
||||
# for the mtime and will refetch unnecessarily.
|
||||
|
||||
source ../common.sh
|
||||
|
||||
requireGit
|
||||
|
||||
clearStoreIfPossible
|
||||
|
||||
# Intentionally not in a canonical form
|
||||
# See https://github.com/NixOS/nix/issues/6195
|
||||
repo=$TEST_ROOT/./git
|
||||
|
||||
export _NIX_FORCE_HTTP=1
|
||||
|
||||
rm -rf "$repo" "${repo}-tmp" "$TEST_HOME/.cache/nix"
|
||||
|
||||
git init --initial-branch="master" "$repo"
|
||||
git -C "$repo" config user.email "nix-tests@example.com"
|
||||
git -C "$repo" config user.name "Nix Tests"
|
||||
|
||||
echo "hello world" > "$repo/hello_world"
|
||||
git -C "$repo" add hello_world
|
||||
git -C "$repo" commit -m 'My first commit.'
|
||||
|
||||
# We now do an eval
|
||||
nix eval --impure --raw --expr "builtins.fetchGit { url = file://$repo; }"
|
||||
|
||||
# test that our eval even worked by checking for the presence of the file
|
||||
[[ $(nix eval --impure --raw --expr "builtins.readFile ((builtins.fetchGit { url = file://$repo; }) + \"/hello_world\")") = 'hello world' ]]
|
||||
|
||||
# Validate that refs/heads/master exists
|
||||
shopt -s nullglob
|
||||
matches=("$TEST_HOME/.cache/nix/gitv3/*/refs/heads/master")
|
||||
shopt -u nullglob
|
||||
|
||||
if [[ ${#matches[@]} -eq 0 ]]; then
|
||||
echo "refs/heads/master does not exist."
|
||||
exit 1
|
||||
fi
|
||||
# pack refs
|
||||
git -C "$TEST_HOME"/.cache/nix/gitv3/*/ pack-refs --all
|
||||
|
||||
shopt -s nullglob
|
||||
matches=("$TEST_HOME"/.cache/nix/gitv3/*/refs/heads/master)
|
||||
shopt -u nullglob
|
||||
|
||||
# ensure refs/heads/master is now gone
|
||||
if [[ ${#matches[@]} -ne 0 ]]; then
|
||||
echo "refs/heads/master still exists after pack-refs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# create a new commit
|
||||
echo "hello again" > "$repo/hello_again"
|
||||
git -C "$repo" add hello_again
|
||||
git -C "$repo" commit -m 'Second commit.'
|
||||
|
||||
# re-eval — this should return the path to the cached version
|
||||
store_path=$(nix eval --tarball-ttl 3600 --impure --raw --expr "(builtins.fetchGit { url = file://$repo; }).outPath")
|
||||
echo "Fetched store path: $store_path"
|
||||
|
||||
# Validate that the new file is *not* there
|
||||
# FIXME: This is a broken test case and we should swap the assertion here.
|
||||
if [[ -e "$store_path/hello_again" ]]; then
|
||||
echo "ERROR: Cached fetchGit should not include the new commit."
|
||||
exit 0
|
||||
else
|
||||
echo "PASS: New commit was not fetched due to caching (as expected)."
|
||||
exit 1
|
||||
fi
|
||||
13
tests/functional/lang/eval-fail-fromTOML-overflow.err.exp
Normal file
13
tests/functional/lang/eval-fail-fromTOML-overflow.err.exp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error:
|
||||
… while calling the 'fromTOML' builtin
|
||||
at /pwd/lang/eval-fail-fromTOML-overflow.nix:1:1:
|
||||
1| builtins.fromTOML ''attr = 9223372036854775808''
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: while parsing TOML: [error] toml::parse_dec_integer: too large integer: current max digits = 2^63
|
||||
--> fromTOML
|
||||
|
|
||||
1 | attr = 9223372036854775808
|
||||
| ^-- must be < 2^63
|
||||
|
||||
1
tests/functional/lang/eval-fail-fromTOML-overflow.nix
Normal file
1
tests/functional/lang/eval-fail-fromTOML-overflow.nix
Normal file
|
|
@ -0,0 +1 @@
|
|||
builtins.fromTOML ''attr = 9223372036854775808''
|
||||
13
tests/functional/lang/eval-fail-fromTOML-underflow.err.exp
Normal file
13
tests/functional/lang/eval-fail-fromTOML-underflow.err.exp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error:
|
||||
… while calling the 'fromTOML' builtin
|
||||
at /pwd/lang/eval-fail-fromTOML-underflow.nix:1:1:
|
||||
1| builtins.fromTOML ''attr = -9223372036854775809''
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: while parsing TOML: [error] toml::parse_dec_integer: too large integer: current max digits = 2^63
|
||||
--> fromTOML
|
||||
|
|
||||
1 | attr = -9223372036854775809
|
||||
| ^-- must be < 2^63
|
||||
|
||||
1
tests/functional/lang/eval-fail-fromTOML-underflow.nix
Normal file
1
tests/functional/lang/eval-fail-fromTOML-underflow.nix
Normal file
|
|
@ -0,0 +1 @@
|
|||
builtins.fromTOML ''attr = -9223372036854775809''
|
||||
12
tests/functional/lang/eval-fail-missing-arg-import.err.exp
Normal file
12
tests/functional/lang/eval-fail-missing-arg-import.err.exp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
error:
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-missing-arg-import.nix:1:1:
|
||||
1| import ./non-eval-trivial-lambda-formals.nix { }
|
||||
| ^
|
||||
2|
|
||||
|
||||
error: function 'anonymous lambda' called without required argument 'a'
|
||||
at /pwd/lang/non-eval-trivial-lambda-formals.nix:1:1:
|
||||
1| { a }: a
|
||||
| ^
|
||||
2|
|
||||
1
tests/functional/lang/eval-fail-missing-arg-import.nix
Normal file
1
tests/functional/lang/eval-fail-missing-arg-import.nix
Normal file
|
|
@ -0,0 +1 @@
|
|||
import ./non-eval-trivial-lambda-formals.nix { }
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error:
|
||||
… from call site
|
||||
at /pwd/lang/eval-fail-undeclared-arg-import.nix:1:1:
|
||||
1| import ./non-eval-trivial-lambda-formals.nix {
|
||||
| ^
|
||||
2| a = "a";
|
||||
|
||||
error: function 'anonymous lambda' called with unexpected argument 'b'
|
||||
at /pwd/lang/non-eval-trivial-lambda-formals.nix:1:1:
|
||||
1| { a }: a
|
||||
| ^
|
||||
2|
|
||||
Did you mean a?
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import ./non-eval-trivial-lambda-formals.nix {
|
||||
a = "a";
|
||||
b = "b";
|
||||
}
|
||||
|
|
@ -2,16 +2,15 @@ with import ./lib.nix;
|
|||
|
||||
let
|
||||
|
||||
attrs =
|
||||
{
|
||||
y = "y";
|
||||
x = "x";
|
||||
foo = "foo";
|
||||
}
|
||||
// rec {
|
||||
x = "newx";
|
||||
bar = x;
|
||||
};
|
||||
attrs = {
|
||||
y = "y";
|
||||
x = "x";
|
||||
foo = "foo";
|
||||
}
|
||||
// rec {
|
||||
x = "newx";
|
||||
bar = x;
|
||||
};
|
||||
|
||||
names = builtins.attrNames attrs;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
let {
|
||||
as =
|
||||
{
|
||||
x = 123;
|
||||
y = 456;
|
||||
}
|
||||
// {
|
||||
z = 789;
|
||||
}
|
||||
// {
|
||||
z = 987;
|
||||
};
|
||||
as = {
|
||||
x = 123;
|
||||
y = 456;
|
||||
}
|
||||
// {
|
||||
z = 789;
|
||||
}
|
||||
// {
|
||||
z = 987;
|
||||
};
|
||||
|
||||
body =
|
||||
if as ? a then
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
let {
|
||||
as =
|
||||
{
|
||||
x = 123;
|
||||
y = 456;
|
||||
}
|
||||
// {
|
||||
z = 789;
|
||||
}
|
||||
// {
|
||||
z = 987;
|
||||
};
|
||||
as = {
|
||||
x = 123;
|
||||
y = 456;
|
||||
}
|
||||
// {
|
||||
z = 789;
|
||||
}
|
||||
// {
|
||||
z = 987;
|
||||
};
|
||||
|
||||
A = "a";
|
||||
Z = "z";
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{ "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bin1 = 214; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; dog = { "tater.man" = { type = { name = "pug"; }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; fruit = [ { name = "apple"; physical = { color = "red"; shape = "round"; }; variety = [ { name = "red delicious"; } { name = "granny smith"; } ]; } { name = "banana"; variety = [ { name = "plantain"; } ]; } ]; g = { h = { i = { }; }; }; hex1 = 3735928559; hex2 = 3735928559; hex3 = 3735928559; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { l = { }; }; }; key = "value"; key2 = "value"; ld1 = { _type = "timestamp"; value = "1979-05-27"; }; ldt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00"; }; ldt2 = { _type = "timestamp"; value = "1979-05-27T00:32:00.999999"; }; lt1 = { _type = "timestamp"; value = "07:32:00"; }; lt2 = { _type = "timestamp"; value = "00:32:00.999999"; }; name = "Orange"; oct1 = 342391; oct2 = 493; odt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; odt2 = { _type = "timestamp"; value = "1979-05-27T00:32:00-07:00"; }; odt3 = { _type = "timestamp"; value = "1979-05-27T00:32:00.999999-07:00"; }; odt4 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; physical = { color = "orange"; shape = "round"; }; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; "quoted \"value\"" = "value"; site = { "google.com" = true; }; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { animal = { type = { name = "pug"; }; }; name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; }
|
||||
{ "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bin1 = 214; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; dog = { "tater.man" = { type = { name = "pug"; }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; fruit = [ { name = "apple"; physical = { color = "red"; shape = "round"; }; variety = [ { name = "red delicious"; } { name = "granny smith"; } ]; } { name = "banana"; variety = [ { name = "plantain"; } ]; } ]; g = { h = { i = { }; }; }; hex1 = 3735928559; hex2 = 3735928559; hex3 = 3735928559; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { l = { }; }; }; key = "value"; key2 = "value"; ld1 = { _type = "timestamp"; value = "1979-05-27"; }; ldt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00"; }; ldt10 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456789"; }; ldt11 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456789"; }; ldt2 = { _type = "timestamp"; value = "1979-05-27T07:32:00.100"; }; ldt3 = { _type = "timestamp"; value = "1979-05-27T07:32:00.120"; }; ldt4 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123"; }; ldt5 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123400"; }; ldt6 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123450"; }; ldt7 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456"; }; ldt8 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456700"; }; ldt9 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456780"; }; lt1 = { _type = "timestamp"; value = "07:32:00"; }; lt10 = { _type = "timestamp"; value = "00:32:00.123456789"; }; lt11 = { _type = "timestamp"; value = "00:32:00.123456789"; }; lt2 = { _type = "timestamp"; value = "00:32:00.100"; }; lt3 = { _type = "timestamp"; value = "00:32:00.120"; }; lt4 = { _type = "timestamp"; value = "00:32:00.123"; }; lt5 = { _type = "timestamp"; value = "00:32:00.123400"; }; lt6 = { _type = "timestamp"; value = "00:32:00.123450"; }; lt7 = { _type = "timestamp"; value = "00:32:00.123456"; }; lt8 = { _type = "timestamp"; value = "00:32:00.123456700"; }; lt9 = { _type = "timestamp"; value = "00:32:00.123456780"; }; name = "Orange"; oct1 = 342391; oct2 = 493; odt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; odt10 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456Z"; }; odt11 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456700Z"; }; odt12 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456780Z"; }; odt13 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456789Z"; }; odt14 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456789Z"; }; odt2 = { _type = "timestamp"; value = "1979-05-27T00:32:00-07:00"; }; odt3 = { _type = "timestamp"; value = "1979-05-27T00:32:00.999999-07:00"; }; odt4 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; odt5 = { _type = "timestamp"; value = "1979-05-27T07:32:00.100Z"; }; odt6 = { _type = "timestamp"; value = "1979-05-27T07:32:00.120Z"; }; odt7 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123Z"; }; odt8 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123400Z"; }; odt9 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123450Z"; }; physical = { color = "orange"; shape = "round"; }; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; "quoted \"value\"" = "value"; site = { "google.com" = true; }; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { animal = { type = { name = "pug"; }; }; name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; }
|
||||
|
|
|
|||
|
|
@ -55,11 +55,53 @@ builtins.fromTOML ''
|
|||
odt2 = 1979-05-27T00:32:00-07:00
|
||||
odt3 = 1979-05-27T00:32:00.999999-07:00
|
||||
odt4 = 1979-05-27 07:32:00Z
|
||||
# milliseconds
|
||||
odt5 = 1979-05-27 07:32:00.1Z
|
||||
odt6 = 1979-05-27 07:32:00.12Z
|
||||
odt7 = 1979-05-27 07:32:00.123Z
|
||||
# microseconds
|
||||
odt8 = 1979-05-27t07:32:00.1234Z
|
||||
odt9 = 1979-05-27t07:32:00.12345Z
|
||||
odt10 = 1979-05-27t07:32:00.123456Z
|
||||
# nanoseconds
|
||||
odt11 = 1979-05-27 07:32:00.1234567Z
|
||||
odt12 = 1979-05-27 07:32:00.12345678Z
|
||||
odt13 = 1979-05-27 07:32:00.123456789Z
|
||||
# no more precision after nanoseconds
|
||||
odt14 = 1979-05-27t07:32:00.1234567891Z
|
||||
|
||||
ldt1 = 1979-05-27T07:32:00
|
||||
ldt2 = 1979-05-27T00:32:00.999999
|
||||
# milliseconds
|
||||
ldt2 = 1979-05-27T07:32:00.1
|
||||
ldt3 = 1979-05-27T07:32:00.12
|
||||
ldt4 = 1979-05-27T07:32:00.123
|
||||
# microseconds
|
||||
ldt5 = 1979-05-27t00:32:00.1234
|
||||
ldt6 = 1979-05-27t00:32:00.12345
|
||||
ldt7 = 1979-05-27t00:32:00.123456
|
||||
# nanoseconds
|
||||
ldt8 = 1979-05-27 00:32:00.1234567
|
||||
ldt9 = 1979-05-27 00:32:00.12345678
|
||||
ldt10 = 1979-05-27 00:32:00.123456789
|
||||
# no more precision after nanoseconds
|
||||
ldt11 = 1979-05-27t00:32:00.1234567891
|
||||
|
||||
ld1 = 1979-05-27
|
||||
lt1 = 07:32:00
|
||||
lt2 = 00:32:00.999999
|
||||
# milliseconds
|
||||
lt2 = 00:32:00.1
|
||||
lt3 = 00:32:00.12
|
||||
lt4 = 00:32:00.123
|
||||
# microseconds
|
||||
lt5 = 00:32:00.1234
|
||||
lt6 = 00:32:00.12345
|
||||
lt7 = 00:32:00.123456
|
||||
# nanoseconds
|
||||
lt8 = 00:32:00.1234567
|
||||
lt9 = 00:32:00.12345678
|
||||
lt10 = 00:32:00.123456789
|
||||
# no more precision after nanoseconds
|
||||
lt11 = 00:32:00.1234567891
|
||||
|
||||
arr1 = [ 1, 2, 3 ]
|
||||
arr2 = [ "red", "yellow", "green" ]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ let
|
|||
scopedImport = attrs: fn: scopedImport (overrides // attrs) fn;
|
||||
|
||||
builtins = builtins // overrides;
|
||||
} // import ./lib.nix;
|
||||
}
|
||||
// import ./lib.nix;
|
||||
|
||||
in
|
||||
scopedImport overrides ./imported.nix
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{ a }: a
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
suites += {
|
||||
'name': 'local-overlay-store',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'name' : 'local-overlay-store',
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'check-post-init.sh',
|
||||
'redundant-add.sh',
|
||||
'build.sh',
|
||||
|
|
@ -14,5 +14,5 @@ suites += {
|
|||
'optimise.sh',
|
||||
'stale-file-handle.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
project('nix-functional-tests',
|
||||
project(
|
||||
'nix-functional-tests',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
'cpp_std=c++23',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
|
|
@ -23,14 +24,16 @@ dot = find_program('dot', native : true, required : false)
|
|||
|
||||
nix_bin_dir = fs.parent(nix.full_path())
|
||||
|
||||
subdir('nix-meson-build-support/default-system-cpu')
|
||||
|
||||
test_confdata = {
|
||||
'bindir': nix_bin_dir,
|
||||
'coreutils': fs.parent(coreutils.full_path()),
|
||||
'dot': dot.found() ? dot.full_path() : '',
|
||||
'bash': bash.full_path(),
|
||||
'sandbox_shell': busybox.found() ? busybox.full_path() : '',
|
||||
'PACKAGE_VERSION': meson.project_version(),
|
||||
'system': host_machine.cpu_family() + '-' + host_machine.system(),
|
||||
'bindir' : nix_bin_dir,
|
||||
'coreutils' : fs.parent(coreutils.full_path()),
|
||||
'dot' : dot.found() ? dot.full_path() : '',
|
||||
'bash' : bash.full_path(),
|
||||
'sandbox_shell' : busybox.found() ? busybox.full_path() : '',
|
||||
'PACKAGE_VERSION' : meson.project_version(),
|
||||
'system' : nix_system_cpu + '-' + host_machine.system(),
|
||||
}
|
||||
|
||||
# Just configures `common/vars-and-functions.sh.in`.
|
||||
|
|
@ -46,8 +49,8 @@ configure_file(
|
|||
suites = [
|
||||
{
|
||||
'name' : 'main',
|
||||
'deps': [],
|
||||
'tests': [
|
||||
'deps' : [],
|
||||
'tests' : [
|
||||
'test-infra.sh',
|
||||
'gc.sh',
|
||||
'nix-collect-garbage-d.sh',
|
||||
|
|
@ -110,6 +113,8 @@ suites = [
|
|||
'impure-eval.sh',
|
||||
'pure-eval.sh',
|
||||
'eval.sh',
|
||||
'short-path-literals.sh',
|
||||
'no-url-literals.sh',
|
||||
'repl.sh',
|
||||
'binary-cache-build-remote.sh',
|
||||
'search.sh',
|
||||
|
|
@ -145,6 +150,7 @@ suites = [
|
|||
'placeholders.sh',
|
||||
'ssh-relay.sh',
|
||||
'build.sh',
|
||||
'build-cores.sh',
|
||||
'build-delete.sh',
|
||||
'output-normalization.sh',
|
||||
'selfref-gc.sh',
|
||||
|
|
@ -169,7 +175,7 @@ suites = [
|
|||
'help.sh',
|
||||
'symlinks.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -178,14 +184,14 @@ if nix_store.found()
|
|||
add_languages('cpp')
|
||||
subdir('test-libstoreconsumer')
|
||||
suites += {
|
||||
'name': 'libstoreconsumer',
|
||||
'deps': [
|
||||
'name' : 'libstoreconsumer',
|
||||
'deps' : [
|
||||
libstoreconsumer_tester,
|
||||
],
|
||||
'tests': [
|
||||
'tests' : [
|
||||
'test-libstoreconsumer.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
|
||||
endif
|
||||
|
|
@ -196,26 +202,39 @@ if nix_expr.found() and get_option('default_library') != 'static'
|
|||
add_languages('cpp')
|
||||
subdir('plugins')
|
||||
suites += {
|
||||
'name': 'plugins',
|
||||
'deps': [
|
||||
'name' : 'plugins',
|
||||
'deps' : [
|
||||
libplugintest,
|
||||
],
|
||||
'tests': [
|
||||
'tests' : [
|
||||
'plugins.sh',
|
||||
],
|
||||
'workdir': meson.current_source_dir(),
|
||||
'workdir' : meson.current_source_dir(),
|
||||
}
|
||||
endif
|
||||
|
||||
subdir('ca')
|
||||
subdir('dyn-drv')
|
||||
subdir('flakes')
|
||||
subdir('git')
|
||||
subdir('git-hashing')
|
||||
subdir('local-overlay-store')
|
||||
|
||||
foreach suite : suites
|
||||
workdir = suite['workdir']
|
||||
suite_name = suite['name']
|
||||
# This is workaround until [1] is resolved. When building in a devshell
|
||||
# as a subproject we want the tests to depend on the nix build target, so
|
||||
# that it gets automatically rebuilt.
|
||||
# However, when the functional test suite is built separately (via componentized
|
||||
# builds or in NixOS tests) we can't depend on the nix executable, since it's
|
||||
# an external program. The following is a simple heuristic that suffices for now.
|
||||
# [1]: https://github.com/mesonbuild/meson/issues/13877
|
||||
deps = suite['deps']
|
||||
if meson.is_subproject()
|
||||
nix_subproject = subproject('nix')
|
||||
deps += [ nix ] + nix_subproject.get_variable('nix_symlinks_targets')
|
||||
endif
|
||||
foreach script : suite['tests']
|
||||
# Turns, e.g., `tests/functional/flakes/show.sh` into a Meson test target called
|
||||
# `functional-flakes-show`.
|
||||
|
|
@ -224,27 +243,28 @@ foreach suite : suites
|
|||
test(
|
||||
name,
|
||||
bash,
|
||||
args: [
|
||||
args : [
|
||||
'-x',
|
||||
'-e',
|
||||
'-u',
|
||||
'-o', 'pipefail',
|
||||
'-o',
|
||||
'pipefail',
|
||||
script,
|
||||
],
|
||||
suite : suite_name,
|
||||
env : {
|
||||
'_NIX_TEST_SOURCE_DIR': meson.current_source_dir(),
|
||||
'_NIX_TEST_BUILD_DIR': meson.current_build_dir(),
|
||||
'TEST_NAME': suite_name / name,
|
||||
'NIX_REMOTE': '',
|
||||
'PS4': '+(${BASH_SOURCE[0]-$0}:$LINENO) ',
|
||||
'_NIX_TEST_SOURCE_DIR' : meson.current_source_dir(),
|
||||
'_NIX_TEST_BUILD_DIR' : meson.current_build_dir(),
|
||||
'TEST_NAME' : suite_name / name,
|
||||
'NIX_REMOTE' : '',
|
||||
'PS4' : '+(${BASH_SOURCE[0]-$0}:$LINENO) ',
|
||||
},
|
||||
# Some tests take 15+ seconds even on an otherwise idle machine;
|
||||
# on a loaded machine this can easily drive them to failure. Give
|
||||
# them more time than the default of 30 seconds.
|
||||
timeout : 300,
|
||||
# Used for target dependency/ordering tracking, not adding compiler flags or anything.
|
||||
depends : suite['deps'],
|
||||
depends : deps,
|
||||
workdir : workdir,
|
||||
)
|
||||
endforeach
|
||||
|
|
|
|||
|
|
@ -44,3 +44,7 @@ out="$(expectStderr 0 nix-instantiate --option foobar baz --expr '{}')"
|
|||
|
||||
out="$(expectStderr 0 nix-instantiate '{}' --option foobar baz --expr )"
|
||||
[[ "$(echo "$out" | grep foobar | wc -l)" = 1 ]]
|
||||
|
||||
if [[ $(uname) = Linux && $(uname -m) = i686 ]]; then
|
||||
[[ $(nix config show system) = i686-linux ]]
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -6,32 +6,31 @@ mkDerivation {
|
|||
name = "nested-sandboxing";
|
||||
busybox = builtins.getEnv "busybox";
|
||||
EXTRA_SANDBOX = builtins.getEnv "EXTRA_SANDBOX";
|
||||
buildCommand =
|
||||
''
|
||||
set -x
|
||||
set -eu -o pipefail
|
||||
''
|
||||
+ (
|
||||
if altitude == 0 then
|
||||
''
|
||||
echo Deep enough! > $out
|
||||
''
|
||||
else
|
||||
''
|
||||
cp -r ${../common} ./common
|
||||
cp ${../common.sh} ./common.sh
|
||||
cp ${../config.nix} ./config.nix
|
||||
cp -r ${./.} ./nested-sandboxing
|
||||
buildCommand = ''
|
||||
set -x
|
||||
set -eu -o pipefail
|
||||
''
|
||||
+ (
|
||||
if altitude == 0 then
|
||||
''
|
||||
echo Deep enough! > $out
|
||||
''
|
||||
else
|
||||
''
|
||||
cp -r ${../common} ./common
|
||||
cp ${../common.sh} ./common.sh
|
||||
cp ${../config.nix} ./config.nix
|
||||
cp -r ${./.} ./nested-sandboxing
|
||||
|
||||
export PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH
|
||||
export PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH
|
||||
|
||||
export _NIX_TEST_SOURCE_DIR=$PWD
|
||||
export _NIX_TEST_BUILD_DIR=$PWD
|
||||
export _NIX_TEST_SOURCE_DIR=$PWD
|
||||
export _NIX_TEST_BUILD_DIR=$PWD
|
||||
|
||||
source common.sh
|
||||
source ./nested-sandboxing/command.sh
|
||||
source common.sh
|
||||
source ./nested-sandboxing/command.sh
|
||||
|
||||
runNixBuild ${storeFun} ${toString altitude} >> $out
|
||||
''
|
||||
);
|
||||
runNixBuild ${storeFun} ${toString altitude} >> $out
|
||||
''
|
||||
);
|
||||
}
|
||||
|
|
|
|||
1
tests/functional/nix-meson-build-support
Symbolic link
1
tests/functional/nix-meson-build-support
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
||||
28
tests/functional/no-url-literals.sh
Normal file
28
tests/functional/no-url-literals.sh
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source common.sh
|
||||
|
||||
clearStoreIfPossible
|
||||
|
||||
# Test 1: By default, unquoted URLs are accepted
|
||||
nix eval --expr 'http://example.com' 2>&1 | grepQuietInverse "error: URL literals are disabled"
|
||||
|
||||
# Test 2: With the experimental feature enabled, unquoted URLs are rejected
|
||||
expect 1 nix eval --extra-experimental-features 'no-url-literals' --expr 'http://example.com' 2>&1 | grepQuiet "error: URL literals are disabled"
|
||||
|
||||
# Test 3: Quoted URLs are always accepted
|
||||
nix eval --extra-experimental-features 'no-url-literals' --expr '"http://example.com"' 2>&1 | grepQuietInverse "error: URL literals are disabled"
|
||||
|
||||
# Test 4: URLs with parameters (which must be quoted) are accepted
|
||||
nix eval --extra-experimental-features 'no-url-literals' --expr '"http://example.com?foo=bar"' 2>&1 | grepQuietInverse "error: URL literals are disabled"
|
||||
|
||||
# Test 5: The feature can be enabled via NIX_CONFIG
|
||||
expect 1 env NIX_CONFIG='extra-experimental-features = no-url-literals' nix eval --expr 'http://example.com' 2>&1 | grepQuiet "error: URL literals are disabled"
|
||||
|
||||
# Test 6: The feature can be enabled via CLI even if not set in config
|
||||
expect 1 env NIX_CONFIG='' nix eval --extra-experimental-features 'no-url-literals' --expr 'http://example.com' 2>&1 | grepQuiet "error: URL literals are disabled"
|
||||
|
||||
# Test 7: Evaluation still works for quoted URLs
|
||||
nix eval --raw --extra-experimental-features no-url-literals --expr '"http://example.com"' | grepQuiet "^http://example.com$"
|
||||
|
||||
echo "no-url-literals test passed!"
|
||||
|
|
@ -39,6 +39,7 @@ mkMesonDerivation (
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../nix-meson-build-support
|
||||
../../scripts/nix-profile.sh.in
|
||||
../../.version
|
||||
../../tests/functional
|
||||
|
|
@ -46,26 +47,25 @@ mkMesonDerivation (
|
|||
];
|
||||
|
||||
# Hack for sake of the dev shell
|
||||
passthru.externalNativeBuildInputs =
|
||||
[
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
passthru.externalNativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
|
||||
jq
|
||||
git
|
||||
mercurial
|
||||
unixtools.script
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||
# For various sandboxing tests that needs a statically-linked shell,
|
||||
# etc.
|
||||
busybox-sandbox-shell
|
||||
# For Overlay FS tests need `mount`, `umount`, and `unshare`.
|
||||
# For `script` command (ensuring a TTY)
|
||||
# TODO use `unixtools` to be precise over which executables instead?
|
||||
util-linux
|
||||
];
|
||||
jq
|
||||
git
|
||||
mercurial
|
||||
unixtools.script
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||
# For various sandboxing tests that needs a statically-linked shell,
|
||||
# etc.
|
||||
busybox-sandbox-shell
|
||||
# For Overlay FS tests need `mount`, `umount`, and `unshare`.
|
||||
# For `script` command (ensuring a TTY)
|
||||
# TODO use `unixtools` to be precise over which executables instead?
|
||||
util-linux
|
||||
];
|
||||
|
||||
nativeBuildInputs = finalAttrs.passthru.externalNativeBuildInputs ++ [
|
||||
nix-cli
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ libplugintest = shared_module(
|
|||
'plugintest.cc',
|
||||
dependencies : [
|
||||
dependency('nix-expr'),
|
||||
# hack for trailing newline
|
||||
],
|
||||
build_by_default : false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@ using namespace nix;
|
|||
|
||||
struct MySettings : Config
|
||||
{
|
||||
Setting<bool> settingSet{this, false, "setting-set",
|
||||
"Whether the plugin-defined setting was set"};
|
||||
Setting<bool> settingSet{this, false, "setting-set", "Whether the plugin-defined setting was set"};
|
||||
};
|
||||
|
||||
MySettings mySettings;
|
||||
|
||||
static GlobalConfig::Register rs(&mySettings);
|
||||
|
||||
static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
static void prim_anotherNull(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||
{
|
||||
if (mySettings.settingSet)
|
||||
v.mkNull();
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ chmod -R -w $TEST_ROOT/var
|
|||
|
||||
# Make sure we fail on add operations on the read-only store
|
||||
# This is only for adding files that are not *already* in the store
|
||||
expectStderr 1 nix-store --add eval.nix | grepQuiet "error: opening lock file '$(readlink -e $TEST_ROOT)/var/nix/db/big-lock'"
|
||||
# Should show enhanced error message with helpful context
|
||||
expectStderr 1 nix-store --add eval.nix | grepQuiet "This command may have been run as non-root in a single-user Nix installation"
|
||||
expectStderr 1 nix-store --store local?read-only=true --add eval.nix | grepQuiet "Permission denied"
|
||||
|
||||
# Test the same operations from before should again succeed
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ nix shell -f shell-hello.nix hello -c env > "$TEST_ROOT/actual-env"
|
|||
# - we unset TMPDIR on macOS if it contains /var/folders
|
||||
# - _ is set by bash and is expectedf to differ because it contains the original command
|
||||
# - __CF_USER_TEXT_ENCODING is set by macOS and is beyond our control
|
||||
# - __LLVM_PROFILE_RT_INIT_ONCE - implementation detail of LLVM source code coverage collection
|
||||
sed -i \
|
||||
-e 's/PATH=.*/PATH=.../' \
|
||||
-e 's/_=.*/_=.../' \
|
||||
-e '/^TMPDIR=\/var\/folders\/.*/d' \
|
||||
-e '/^__CF_USER_TEXT_ENCODING=.*$/d' \
|
||||
-e '/^__LLVM_PROFILE_RT_INIT_ONCE=.*$/d' \
|
||||
"$TEST_ROOT/expected-env" "$TEST_ROOT/actual-env"
|
||||
sort "$TEST_ROOT/expected-env" > "$TEST_ROOT/expected-env.sorted"
|
||||
sort "$TEST_ROOT/actual-env" > "$TEST_ROOT/actual-env.sorted"
|
||||
|
|
|
|||
55
tests/functional/short-path-literals.sh
Normal file
55
tests/functional/short-path-literals.sh
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source common.sh
|
||||
|
||||
clearStoreIfPossible
|
||||
|
||||
# Test 1: Without the setting (default), no warnings should be produced
|
||||
nix eval --expr 'test/subdir' 2>"$TEST_ROOT"/stderr
|
||||
grepQuietInverse < "$TEST_ROOT/stderr" -E "relative path|path literal" || fail "Should not produce warnings by default"
|
||||
|
||||
# Test 2: With the setting enabled, warnings should be produced for short path literals
|
||||
nix eval --warn-short-path-literals --expr 'test/subdir' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "relative path literal 'test/subdir' should be prefixed with '.' for clarity: './test/subdir'" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 3: Different short path literals should all produce warnings
|
||||
nix eval --warn-short-path-literals --expr 'foo/bar' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "relative path literal 'foo/bar' should be prefixed with '.' for clarity: './foo/bar'" "$TEST_ROOT/stderr"
|
||||
|
||||
nix eval --warn-short-path-literals --expr 'a/b/c/d' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "relative path literal 'a/b/c/d' should be prefixed with '.' for clarity: './a/b/c/d'" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 4: Paths starting with ./ should NOT produce warnings
|
||||
nix eval --warn-short-path-literals --expr './test/subdir' 2>"$TEST_ROOT"/stderr
|
||||
grepQuietInverse "relative path literal" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 5: Paths starting with ../ should NOT produce warnings
|
||||
nix eval --warn-short-path-literals --expr '../test/subdir' 2>"$TEST_ROOT"/stderr
|
||||
grepQuietInverse "relative path literal" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 6: Absolute paths should NOT produce warnings
|
||||
nix eval --warn-short-path-literals --expr '/absolute/path' 2>"$TEST_ROOT"/stderr
|
||||
grepQuietInverse "relative path literal" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 7: Test that the warning is at the correct position
|
||||
nix eval --warn-short-path-literals --expr 'foo/bar' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "at «string»:1:1:" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 8: Test that evaluation still works correctly despite the warning
|
||||
result=$(nix eval --warn-short-path-literals --expr 'test/subdir' 2>/dev/null)
|
||||
expected="$PWD/test/subdir"
|
||||
[[ "$result" == "$expected" ]] || fail "Evaluation result should be correct despite warning"
|
||||
|
||||
# Test 9: Test with nix-instantiate as well
|
||||
nix-instantiate --warn-short-path-literals --eval -E 'foo/bar' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "relative path literal 'foo/bar' should be prefixed" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 10: Test that the setting can be set via configuration
|
||||
NIX_CONFIG='warn-short-path-literals = true' nix eval --expr 'test/file' 2>"$TEST_ROOT"/stderr
|
||||
grepQuiet "relative path literal 'test/file' should be prefixed" "$TEST_ROOT/stderr"
|
||||
|
||||
# Test 11: Test that command line flag overrides config
|
||||
NIX_CONFIG='warn-short-path-literals = true' nix eval --no-warn-short-path-literals --expr 'test/file' 2>"$TEST_ROOT"/stderr
|
||||
grepQuietInverse "relative path literal" "$TEST_ROOT/stderr"
|
||||
|
||||
echo "short-path-literals test passed!"
|
||||
|
|
@ -2,12 +2,67 @@
|
|||
|
||||
source common.sh
|
||||
|
||||
# Different versions of the Nix daemon normalize or don't normalize
|
||||
# store URLs, plus NIX_REMOTE (per the test suite) might not be using on
|
||||
# store URL in normal form, so the easiest thing to do is normalize URLs
|
||||
# after the fact before comparing them for equality.
|
||||
normalize_nix_store_url () {
|
||||
local url="$1"
|
||||
case "$url" in
|
||||
'auto' )
|
||||
# Need to actually ask Nix in this case
|
||||
echo "$defaultStore"
|
||||
;;
|
||||
local | 'local://' )
|
||||
echo 'local'
|
||||
;;
|
||||
daemon | 'unix://' )
|
||||
echo 'daemon'
|
||||
;;
|
||||
'local://'* )
|
||||
# To not be captured by next pattern
|
||||
echo "$url"
|
||||
;;
|
||||
'local?'* )
|
||||
echo "local://${url#local}"
|
||||
;;
|
||||
'daemon?'* )
|
||||
echo "unix://${url#daemon}"
|
||||
;;
|
||||
* )
|
||||
echo "$url"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
STORE_INFO=$(nix store info 2>&1)
|
||||
LEGACY_STORE_INFO=$(nix store ping 2>&1) # alias to nix store info
|
||||
STORE_INFO_JSON=$(nix store info --json)
|
||||
|
||||
echo "$STORE_INFO" | grep "Store URL: ${NIX_REMOTE}"
|
||||
echo "$LEGACY_STORE_INFO" | grep "Store URL: ${NIX_REMOTE}"
|
||||
defaultStore="$(normalize_nix_store_url "$(echo "$STORE_INFO_JSON" | jq -r ".url")")"
|
||||
|
||||
# Test cases for `normalize_nix_store_url` itself
|
||||
|
||||
# Normalize local store
|
||||
[[ "$(normalize_nix_store_url "local://")" = "local" ]]
|
||||
[[ "$(normalize_nix_store_url "local")" = "local" ]]
|
||||
[[ "$(normalize_nix_store_url "local?foo=bar")" = "local://?foo=bar" ]]
|
||||
|
||||
# Normalize unix domain socket remote store
|
||||
[[ "$(normalize_nix_store_url "unix://")" = "daemon" ]]
|
||||
[[ "$(normalize_nix_store_url "daemon")" = "daemon" ]]
|
||||
[[ "$(normalize_nix_store_url "daemon?x=y")" = "unix://?x=y" ]]
|
||||
|
||||
# otherwise unchanged
|
||||
[[ "$(normalize_nix_store_url "https://site")" = "https://site" ]]
|
||||
|
||||
nixRemoteOrDefault=$(normalize_nix_store_url "${NIX_REMOTE:-"auto"}")
|
||||
|
||||
check_human_readable () {
|
||||
[[ "$(normalize_nix_store_url "$(echo "$1" | grep 'Store URL:' | sed 's^Store URL: ^^')")" = "${nixRemoteOrDefault}" ]]
|
||||
}
|
||||
check_human_readable "$STORE_INFO"
|
||||
check_human_readable "$LEGACY_STORE_INFO"
|
||||
|
||||
if [[ -v NIX_DAEMON_PACKAGE ]] && isDaemonNewer "2.7.0pre20220126"; then
|
||||
DAEMON_VERSION=$("$NIX_DAEMON_PACKAGE"/bin/nix daemon --version | cut -d' ' -f3)
|
||||
|
|
@ -21,4 +76,4 @@ expect 127 NIX_REMOTE=unix:"$PWD"/store nix store info || \
|
|||
|
||||
TODO_NixOS
|
||||
|
||||
[[ "$(echo "$STORE_INFO_JSON" | jq -r ".url")" == "${NIX_REMOTE:-local}" ]]
|
||||
[[ "$(normalize_nix_store_url "$(echo "$STORE_INFO_JSON" | jq -r ".url")")" == "${nixRemoteOrDefault}" ]]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
using namespace nix;
|
||||
|
||||
int main (int argc, char **argv)
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
try {
|
||||
if (argc != 2) {
|
||||
|
|
@ -21,12 +21,8 @@ int main (int argc, char **argv)
|
|||
|
||||
// build the derivation
|
||||
|
||||
std::vector<DerivedPath> paths {
|
||||
DerivedPath::Built {
|
||||
.drvPath = makeConstantStorePathRef(store->parseStorePath(drvPath)),
|
||||
.outputs = OutputsSpec::Names{"out"}
|
||||
}
|
||||
};
|
||||
std::vector<DerivedPath> paths{DerivedPath::Built{
|
||||
.drvPath = makeConstantStorePathRef(store->parseStorePath(drvPath)), .outputs = OutputsSpec::Names{"out"}}};
|
||||
|
||||
const auto results = store->buildPathsWithResults(paths, bmNormal, store);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ libstoreconsumer_tester = executable(
|
|||
'main.cc',
|
||||
dependencies : [
|
||||
dependency('nix-store'),
|
||||
# hack for trailing newline
|
||||
],
|
||||
build_by_default : false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
su --login mallory -c '
|
||||
nix-store --generate-binary-cache-key cache1.example.org sk1 pk1
|
||||
(! nix store sign --key-file sk1 ${pathFour} 2>&1)' | tee diag 1>&2
|
||||
grep -F "cannot open connection to remote store 'daemon'" diag
|
||||
grep -F "cannot open connection to remote store 'unix://'" diag
|
||||
""")
|
||||
|
||||
machine.succeed("""
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
|
|
@ -25,12 +26,12 @@ int main(int argc, char **argv) {
|
|||
// executed in, just busyloop here.
|
||||
int res = -1;
|
||||
while (res < 0) {
|
||||
res = connect(sock, (const struct sockaddr *)&data,
|
||||
offsetof(struct sockaddr_un, sun_path)
|
||||
+ strlen(argv[1])
|
||||
+ 1);
|
||||
if (res < 0 && errno != ECONNREFUSED) perror("connect");
|
||||
if (errno != ECONNREFUSED) break;
|
||||
res = connect(
|
||||
sock, (const struct sockaddr *) &data, offsetof(struct sockaddr_un, sun_path) + strlen(argv[1]) + 1);
|
||||
if (res < 0 && errno != ECONNREFUSED)
|
||||
perror("connect");
|
||||
if (errno != ECONNREFUSED)
|
||||
break;
|
||||
}
|
||||
|
||||
// Write our message header.
|
||||
|
|
@ -39,27 +40,28 @@ int main(int argc, char **argv) {
|
|||
msg.msg_controllen = 128;
|
||||
|
||||
// Write an SCM_RIGHTS message containing the output path.
|
||||
struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
|
||||
struct cmsghdr * hdr = CMSG_FIRSTHDR(&msg);
|
||||
hdr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
hdr->cmsg_level = SOL_SOCKET;
|
||||
hdr->cmsg_type = SCM_RIGHTS;
|
||||
int fd = open(getenv("out"), O_RDWR | O_CREAT, 0640);
|
||||
memcpy(CMSG_DATA(hdr), (void *)&fd, sizeof(int));
|
||||
memcpy(CMSG_DATA(hdr), (void *) &fd, sizeof(int));
|
||||
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(int));
|
||||
|
||||
// Write a single null byte too.
|
||||
msg.msg_iov = (struct iovec*) malloc(sizeof(struct iovec));
|
||||
msg.msg_iov[0].iov_base = (void*) "";
|
||||
msg.msg_iov = (struct iovec *) malloc(sizeof(struct iovec));
|
||||
msg.msg_iov[0].iov_base = (void *) "";
|
||||
msg.msg_iov[0].iov_len = 1;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
// Send it to the othher side of this connection.
|
||||
res = sendmsg(sock, &msg, 0);
|
||||
if (res < 0) perror("sendmsg");
|
||||
if (res < 0)
|
||||
perror("sendmsg");
|
||||
int buf;
|
||||
|
||||
// Wait for the server to close the socket, implying that it has
|
||||
// received the commmand.
|
||||
recv(sock, (void *)&buf, sizeof(int), 0);
|
||||
recv(sock, (void *) &buf, sizeof(int), 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
|
|
@ -18,21 +19,21 @@ int main(int argc, char **argv) {
|
|||
data.sun_family = AF_UNIX;
|
||||
data.sun_path[0] = 0;
|
||||
strncpy(data.sun_path + 1, argv[1], sizeof(data.sun_path) - 1);
|
||||
int res = bind(sock, (const struct sockaddr *)&data,
|
||||
offsetof(struct sockaddr_un, sun_path)
|
||||
+ strlen(argv[1])
|
||||
+ 1);
|
||||
if (res < 0) perror("bind");
|
||||
int res = bind(sock, (const struct sockaddr *) &data, offsetof(struct sockaddr_un, sun_path) + strlen(argv[1]) + 1);
|
||||
if (res < 0)
|
||||
perror("bind");
|
||||
|
||||
res = listen(sock, 1);
|
||||
if (res < 0) perror("listen");
|
||||
if (res < 0)
|
||||
perror("listen");
|
||||
|
||||
int smuggling_fd = -1;
|
||||
|
||||
// Accept the connection a first time to receive the file descriptor.
|
||||
fprintf(stderr, "%s\n", "Waiting for the first connection");
|
||||
int a = accept(sock, 0, 0);
|
||||
if (a < 0) perror("accept");
|
||||
if (a < 0)
|
||||
perror("accept");
|
||||
|
||||
struct msghdr msg = {0};
|
||||
msg.msg_control = malloc(128);
|
||||
|
|
@ -41,13 +42,12 @@ int main(int argc, char **argv) {
|
|||
// Receive the file descriptor as sent by the smuggler.
|
||||
recvmsg(a, &msg, 0);
|
||||
|
||||
struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
|
||||
struct cmsghdr * hdr = CMSG_FIRSTHDR(&msg);
|
||||
while (hdr) {
|
||||
if (hdr->cmsg_level == SOL_SOCKET
|
||||
&& hdr->cmsg_type == SCM_RIGHTS) {
|
||||
if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
|
||||
|
||||
// Grab the copy of the file descriptor.
|
||||
memcpy((void *)&smuggling_fd, CMSG_DATA(hdr), sizeof(int));
|
||||
memcpy((void *) &smuggling_fd, CMSG_DATA(hdr), sizeof(int));
|
||||
}
|
||||
|
||||
hdr = CMSG_NXTHDR(&msg, hdr);
|
||||
|
|
@ -58,11 +58,14 @@ int main(int argc, char **argv) {
|
|||
// Wait for a second connection, which will tell us that the build is
|
||||
// done
|
||||
a = accept(sock, 0, 0);
|
||||
if (a < 0) perror("accept");
|
||||
if (a < 0)
|
||||
perror("accept");
|
||||
fprintf(stderr, "%s\n", "Got a second connection, rewriting the file");
|
||||
// Write a new content to the file
|
||||
if (ftruncate(smuggling_fd, 0)) perror("ftruncate");
|
||||
if (ftruncate(smuggling_fd, 0))
|
||||
perror("ftruncate");
|
||||
const char * new_content = "Pwned\n";
|
||||
int written_bytes = write(smuggling_fd, new_content, strlen(new_content));
|
||||
if (written_bytes != strlen(new_content)) perror("write");
|
||||
if (written_bytes != strlen(new_content))
|
||||
perror("write");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
nixComponents,
|
||||
nixpkgs,
|
||||
nixpkgsFor,
|
||||
nixpkgs-23-11,
|
||||
}:
|
||||
|
||||
|
|
@ -19,27 +20,28 @@ let
|
|||
);
|
||||
|
||||
# https://nixos.org/manual/nixos/unstable/index.html#sec-calling-nixos-tests
|
||||
runNixOSTestFor =
|
||||
system: test:
|
||||
runNixOSTest =
|
||||
test:
|
||||
(nixos-lib.runTest {
|
||||
imports = [
|
||||
test
|
||||
];
|
||||
|
||||
hostPkgs = nixpkgsFor.${system}.native;
|
||||
hostPkgs = pkgs;
|
||||
defaults = {
|
||||
nixpkgs.pkgs = nixpkgsFor.${system}.native;
|
||||
nixpkgs.pkgs = pkgs;
|
||||
nix.checkAllErrors = false;
|
||||
# TODO: decide which packaging stage to use. `nix-cli` is efficient, but not the same as the user-facing `everything.nix` package (`default`). Perhaps a good compromise is `everything.nix` + `noTests` defined above?
|
||||
nix.package = nixpkgsFor.${system}.native.nixComponents2.nix-cli;
|
||||
nix.package = nixComponents.nix-cli;
|
||||
|
||||
# Evaluate VMs faster
|
||||
documentation.enable = false;
|
||||
# this links against nix and might break with our git version.
|
||||
system.tools.nixos-option.enable = false;
|
||||
};
|
||||
_module.args.nixComponents = nixComponents;
|
||||
_module.args.nixpkgs = nixpkgs;
|
||||
_module.args.system = system;
|
||||
_module.args.system = pkgs.system;
|
||||
})
|
||||
// {
|
||||
# allow running tests against older nix versions via `nix eval --apply`
|
||||
|
|
@ -47,13 +49,13 @@ let
|
|||
# nix build "$(nix eval --raw --impure .#hydraJobs.tests.fetch-git --apply 't: (t.forNix "2.19.2").drvPath')^*"
|
||||
forNix =
|
||||
nixVersion:
|
||||
runNixOSTestFor system {
|
||||
runNixOSTest {
|
||||
imports = [ test ];
|
||||
defaults.nixpkgs.overlays = [
|
||||
(curr: prev: {
|
||||
nix =
|
||||
let
|
||||
packages = (builtins.getFlake "nix/${nixVersion}").packages.${system};
|
||||
packages = (builtins.getFlake "nix/${nixVersion}").packages.${pkgs.system};
|
||||
in
|
||||
packages.nix-cli or packages.nix;
|
||||
})
|
||||
|
|
@ -77,7 +79,15 @@ let
|
|||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [ checkOverrideNixVersion ];
|
||||
nix.package = lib.mkForce pkgs.nixVersions.nix_2_3;
|
||||
nix.package = lib.mkForce (
|
||||
pkgs.nixVersions.nix_2_3.overrideAttrs (o: {
|
||||
meta = o.meta // {
|
||||
# This version shouldn't be used by end-users, but we run tests against
|
||||
# it to ensure we don't break protocol compatibility.
|
||||
knownVulnerabilities = [ ];
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
otherNixes.nix_2_13.setNixPackage =
|
||||
|
|
@ -88,6 +98,8 @@ let
|
|||
nixpkgs-23-11.legacyPackages.${pkgs.stdenv.hostPlatform.system}.nixVersions.nix_2_13.overrideAttrs
|
||||
(o: {
|
||||
meta = o.meta // {
|
||||
# This version shouldn't be used by end-users, but we run tests against
|
||||
# it to ensure we don't break protocol compatibility.
|
||||
knownVulnerabilities = [ ];
|
||||
};
|
||||
})
|
||||
|
|
@ -97,18 +109,18 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
authorization = runNixOSTestFor "x86_64-linux" ./authorization.nix;
|
||||
authorization = runNixOSTest ./authorization.nix;
|
||||
|
||||
remoteBuilds = runNixOSTestFor "x86_64-linux" ./remote-builds.nix;
|
||||
remoteBuilds = runNixOSTest ./remote-builds.nix;
|
||||
|
||||
remoteBuildsSshNg = runNixOSTestFor "x86_64-linux" ./remote-builds-ssh-ng.nix;
|
||||
remoteBuildsSshNg = runNixOSTest ./remote-builds-ssh-ng.nix;
|
||||
|
||||
}
|
||||
// lib.concatMapAttrs (
|
||||
nixVersion:
|
||||
{ setNixPackage, ... }:
|
||||
{
|
||||
"remoteBuilds_remote_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
"remoteBuilds_remote_${nixVersion}" = runNixOSTest {
|
||||
name = "remoteBuilds_remote_${nixVersion}";
|
||||
imports = [ ./remote-builds.nix ];
|
||||
builders.config =
|
||||
|
|
@ -118,7 +130,7 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
"remoteBuilds_local_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
"remoteBuilds_local_${nixVersion}" = runNixOSTest {
|
||||
name = "remoteBuilds_local_${nixVersion}";
|
||||
imports = [ ./remote-builds.nix ];
|
||||
nodes.client =
|
||||
|
|
@ -128,7 +140,7 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
"remoteBuildsSshNg_remote_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
"remoteBuildsSshNg_remote_${nixVersion}" = runNixOSTest {
|
||||
name = "remoteBuildsSshNg_remote_${nixVersion}";
|
||||
imports = [ ./remote-builds-ssh-ng.nix ];
|
||||
builders.config =
|
||||
|
|
@ -140,7 +152,7 @@ in
|
|||
|
||||
# FIXME: these tests don't work yet
|
||||
|
||||
# "remoteBuildsSshNg_local_${nixVersion}" = runNixOSTestFor "x86_64-linux" {
|
||||
# "remoteBuildsSshNg_local_${nixVersion}" = runNixOSTest {
|
||||
# name = "remoteBuildsSshNg_local_${nixVersion}";
|
||||
# imports = [ ./remote-builds-ssh-ng.nix ];
|
||||
# nodes.client = { lib, pkgs, ... }: {
|
||||
|
|
@ -151,49 +163,49 @@ in
|
|||
) otherNixes
|
||||
// {
|
||||
|
||||
nix-copy-closure = runNixOSTestFor "x86_64-linux" ./nix-copy-closure.nix;
|
||||
nix-copy-closure = runNixOSTest ./nix-copy-closure.nix;
|
||||
|
||||
nix-copy = runNixOSTestFor "x86_64-linux" ./nix-copy.nix;
|
||||
nix-copy = runNixOSTest ./nix-copy.nix;
|
||||
|
||||
nix-docker = runNixOSTestFor "x86_64-linux" ./nix-docker.nix;
|
||||
nix-docker = runNixOSTest ./nix-docker.nix;
|
||||
|
||||
nssPreload = runNixOSTestFor "x86_64-linux" ./nss-preload.nix;
|
||||
nssPreload = runNixOSTest ./nss-preload.nix;
|
||||
|
||||
githubFlakes = runNixOSTestFor "x86_64-linux" ./github-flakes.nix;
|
||||
githubFlakes = runNixOSTest ./github-flakes.nix;
|
||||
|
||||
gitSubmodules = runNixOSTestFor "x86_64-linux" ./git-submodules.nix;
|
||||
gitSubmodules = runNixOSTest ./git-submodules.nix;
|
||||
|
||||
sourcehutFlakes = runNixOSTestFor "x86_64-linux" ./sourcehut-flakes.nix;
|
||||
sourcehutFlakes = runNixOSTest ./sourcehut-flakes.nix;
|
||||
|
||||
tarballFlakes = runNixOSTestFor "x86_64-linux" ./tarball-flakes.nix;
|
||||
tarballFlakes = runNixOSTest ./tarball-flakes.nix;
|
||||
|
||||
containers = runNixOSTestFor "x86_64-linux" ./containers/containers.nix;
|
||||
containers = runNixOSTest ./containers/containers.nix;
|
||||
|
||||
setuid = lib.genAttrs [ "x86_64-linux" ] (system: runNixOSTestFor system ./setuid.nix);
|
||||
setuid = runNixOSTest ./setuid.nix;
|
||||
|
||||
fetch-git = runNixOSTestFor "x86_64-linux" ./fetch-git;
|
||||
fetch-git = runNixOSTest ./fetch-git;
|
||||
|
||||
ca-fd-leak = runNixOSTestFor "x86_64-linux" ./ca-fd-leak;
|
||||
ca-fd-leak = runNixOSTest ./ca-fd-leak;
|
||||
|
||||
gzip-content-encoding = runNixOSTestFor "x86_64-linux" ./gzip-content-encoding.nix;
|
||||
gzip-content-encoding = runNixOSTest ./gzip-content-encoding.nix;
|
||||
|
||||
functional_user = runNixOSTestFor "x86_64-linux" ./functional/as-user.nix;
|
||||
functional_user = runNixOSTest ./functional/as-user.nix;
|
||||
|
||||
functional_trusted = runNixOSTestFor "x86_64-linux" ./functional/as-trusted-user.nix;
|
||||
functional_trusted = runNixOSTest ./functional/as-trusted-user.nix;
|
||||
|
||||
functional_root = runNixOSTestFor "x86_64-linux" ./functional/as-root.nix;
|
||||
functional_root = runNixOSTest ./functional/as-root.nix;
|
||||
|
||||
functional_symlinked-home = runNixOSTestFor "x86_64-linux" ./functional/symlinked-home.nix;
|
||||
functional_symlinked-home = runNixOSTest ./functional/symlinked-home.nix;
|
||||
|
||||
user-sandboxing = runNixOSTestFor "x86_64-linux" ./user-sandboxing;
|
||||
user-sandboxing = runNixOSTest ./user-sandboxing;
|
||||
|
||||
s3-binary-cache-store = runNixOSTestFor "x86_64-linux" ./s3-binary-cache-store.nix;
|
||||
s3-binary-cache-store = runNixOSTest ./s3-binary-cache-store.nix;
|
||||
|
||||
fsync = runNixOSTestFor "x86_64-linux" ./fsync.nix;
|
||||
fsync = runNixOSTest ./fsync.nix;
|
||||
|
||||
cgroups = runNixOSTestFor "x86_64-linux" ./cgroups;
|
||||
cgroups = runNixOSTest ./cgroups;
|
||||
|
||||
fetchurl = runNixOSTestFor "x86_64-linux" ./fetchurl.nix;
|
||||
fetchurl = runNixOSTest ./fetchurl.nix;
|
||||
|
||||
chrootStore = runNixOSTestFor "x86_64-linux" ./chroot-store.nix;
|
||||
chrootStore = runNixOSTest ./chroot-store.nix;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,5 +224,25 @@
|
|||
""")
|
||||
|
||||
client.succeed(f"cmp {repo.path}/beeg {fetched_self_lfs}/beeg >&2")
|
||||
|
||||
|
||||
with subtest("Ensure fetching with SSH generates the same output"):
|
||||
client.succeed(f"{repo.git} push origin-ssh main >&2")
|
||||
client.succeed("rm -rf ~/.cache/nix") # Avoid using the cached output of the http fetch
|
||||
|
||||
fetchGit_ssh_expr = f"""
|
||||
builtins.fetchGit {{
|
||||
url = "{repo.remote_ssh}";
|
||||
rev = "{lfs_file_rev}";
|
||||
ref = "main";
|
||||
lfs = true;
|
||||
}}
|
||||
"""
|
||||
fetched_ssh = client.succeed(f"""
|
||||
nix eval --debug --impure --raw --expr '({fetchGit_ssh_expr}).outPath'
|
||||
""")
|
||||
|
||||
assert fetched_ssh == fetched_lfs, \
|
||||
f"fetching with ssh (store path {fetched_ssh}) yielded a different result than using http (store path {fetched_lfs})"
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,19 +49,15 @@ in
|
|||
self.name = name
|
||||
self.path = "/tmp/repos/" + name
|
||||
self.remote = "http://gitea:3000/test/" + name
|
||||
self.remote_ssh = "ssh://gitea/root/" + name
|
||||
self.remote_ssh = "ssh://gitea:3001/test/" + name
|
||||
self.git = f"git -C {self.path}"
|
||||
self.private = private
|
||||
self.create()
|
||||
|
||||
def create(self):
|
||||
# create ssh remote repo
|
||||
# create remote repo
|
||||
gitea.succeed(f"""
|
||||
git init --bare -b main /root/{self.name}
|
||||
""")
|
||||
# create http remote repo
|
||||
gitea.succeed(f"""
|
||||
curl --fail -X POST http://{gitea_admin}:{gitea_admin_password}@gitea:3000/api/v1/user/repos \
|
||||
curl --fail -X POST http://{gitea_user}:{gitea_password}@gitea:3000/api/v1/user/repos \
|
||||
-H 'Accept: application/json' -H 'Content-Type: application/json' \
|
||||
-d {shlex.quote( f'{{"name":"{self.name}", "default_branch": "main", "private": {boolToJSON(self.private)}}}' )}
|
||||
""")
|
||||
|
|
@ -70,7 +66,7 @@ in
|
|||
mkdir -p {self.path} \
|
||||
&& git init -b main {self.path} \
|
||||
&& {self.git} remote add origin {self.remote} \
|
||||
&& {self.git} remote add origin-ssh root@gitea:{self.name}
|
||||
&& {self.git} remote add origin-ssh {self.remote_ssh}
|
||||
""")
|
||||
'';
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,28 +35,20 @@ in
|
|||
server = {
|
||||
DOMAIN = "gitea";
|
||||
HTTP_PORT = 3000;
|
||||
SSH_PORT = 3001;
|
||||
START_SSH_SERVER = true;
|
||||
};
|
||||
log.LEVEL = "Info";
|
||||
database.LOG_SQL = false;
|
||||
};
|
||||
services.openssh.enable = true;
|
||||
networking.firewall.allowedTCPPorts = [ 3000 ];
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
3000
|
||||
3001
|
||||
];
|
||||
environment.systemPackages = [
|
||||
pkgs.git
|
||||
pkgs.gitea
|
||||
];
|
||||
|
||||
users.users.root.openssh.authorizedKeys.keys = [ clientPublicKey ];
|
||||
|
||||
# TODO: remove this after updating to nixos-23.11
|
||||
nixpkgs.pkgs = lib.mkForce (
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
config.permittedInsecurePackages = [
|
||||
"gitea-1.19.4"
|
||||
];
|
||||
}
|
||||
);
|
||||
};
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
|
|
@ -67,38 +59,33 @@ in
|
|||
];
|
||||
};
|
||||
};
|
||||
defaults =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
};
|
||||
|
||||
setupScript = ''
|
||||
import shlex
|
||||
|
||||
gitea.wait_for_unit("gitea.service")
|
||||
|
||||
gitea_admin = "test"
|
||||
gitea_admin_password = "test123test"
|
||||
gitea_user = "test"
|
||||
gitea_password = "test123test"
|
||||
|
||||
gitea.succeed(f"""
|
||||
gitea --version >&2
|
||||
su -l gitea -c 'GITEA_WORK_DIR=/var/lib/gitea gitea admin user create \
|
||||
--username {gitea_admin} --password {gitea_admin_password} --email test@client'
|
||||
--username {gitea_user} --password {gitea_password} --email test@client'
|
||||
""")
|
||||
|
||||
client.wait_for_unit("multi-user.target")
|
||||
gitea.wait_for_open_port(3000)
|
||||
gitea.wait_for_open_port(3001)
|
||||
|
||||
gitea_admin_token = gitea.succeed(f"""
|
||||
curl --fail -X POST http://{gitea_admin}:{gitea_admin_password}@gitea:3000/api/v1/users/test/tokens \
|
||||
gitea.succeed(f"""
|
||||
curl --fail -X POST http://{gitea_user}:{gitea_password}@gitea:3000/api/v1/user/keys \
|
||||
-H 'Accept: application/json' -H 'Content-Type: application/json' \
|
||||
-d {shlex.quote( '{"name":"token", "scopes":["all"]}' )} \
|
||||
| jq -r '.sha1'
|
||||
""").strip()
|
||||
-d {shlex.quote( '{"title":"key", "key":"${clientPublicKey}", "read_only": false}' )} >&2
|
||||
""")
|
||||
|
||||
client.succeed(f"""
|
||||
echo "http://{gitea_admin}:{gitea_admin_password}@gitea:3000" >~/.git-credentials-admin
|
||||
echo "http://{gitea_user}:{gitea_password}@gitea:3000" >~/.git-credentials-admin
|
||||
git config --global credential.helper 'store --file ~/.git-credentials-admin'
|
||||
git config --global user.email "test@client"
|
||||
git config --global user.name "Test User"
|
||||
|
|
@ -118,13 +105,7 @@ in
|
|||
echo "Host gitea" >>~/.ssh/config
|
||||
echo " StrictHostKeyChecking no" >>~/.ssh/config
|
||||
echo " UserKnownHostsFile /dev/null" >>~/.ssh/config
|
||||
echo " User root" >>~/.ssh/config
|
||||
echo " User gitea" >>~/.ssh/config
|
||||
""")
|
||||
|
||||
# ensure ssh from client to gitea works
|
||||
client.succeed("""
|
||||
ssh root@gitea true
|
||||
""")
|
||||
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ lib, ... }:
|
||||
{ lib, nixComponents, ... }:
|
||||
|
||||
let
|
||||
# FIXME (roberth) reference issue
|
||||
|
|
@ -49,11 +49,11 @@ in
|
|||
|
||||
cd ~
|
||||
|
||||
cp -r ${pkgs.nixComponents2.nix-functional-tests.src} nix
|
||||
cp -r ${nixComponents.nix-functional-tests.src} nix
|
||||
chmod -R +w nix
|
||||
|
||||
chmod u+w nix/.version
|
||||
echo ${pkgs.nixComponents2.version} > nix/.version
|
||||
echo ${nixComponents.version} > nix/.version
|
||||
|
||||
export isTestOnNixOS=1
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ let
|
|||
mkdir -p $out/archive
|
||||
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
cp -rd --preserve=ownership,timestamps ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
builtins.substring 12 2 nixpkgs.lastModifiedDate
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ let
|
|||
services.openssh.enable = true;
|
||||
virtualisation.writableStore = true;
|
||||
nix.settings.sandbox = true;
|
||||
services.openssh.ports = [
|
||||
22
|
||||
]
|
||||
++ lib.optional supportsCustomPort 2222;
|
||||
|
||||
# Regression test for use of PID namespaces when /proc has
|
||||
# filesystems mounted on top of it
|
||||
|
|
@ -42,6 +46,7 @@ let
|
|||
|
||||
supportsBadShell = lib.versionAtLeast config.nodes.client.nix.package.version "2.25pre";
|
||||
|
||||
supportsCustomPort = lib.versionAtLeast config.nodes.client.nix.package.version "2.31.0pre20250806";
|
||||
in
|
||||
|
||||
{
|
||||
|
|
@ -74,7 +79,7 @@ in
|
|||
nix.distributedBuilds = true;
|
||||
nix.buildMachines = [
|
||||
{
|
||||
hostName = "builder1";
|
||||
hostName = "builder1" + (lib.optionalString supportsCustomPort ":2222");
|
||||
sshUser = "root";
|
||||
sshKey = "/root/.ssh/id_ed25519";
|
||||
system = "i686-linux";
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ let
|
|||
|
||||
nixpkgs-repo = pkgs.runCommand "nixpkgs-flake" { } ''
|
||||
dir=NixOS-nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
cp -rd --preserve=ownership,timestamps ${nixpkgs} $dir
|
||||
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ let
|
|||
|
||||
set -x
|
||||
dir=nixpkgs-${nixpkgs.shortRev}
|
||||
cp -prd ${nixpkgs} $dir
|
||||
cp -rd --preserve=ownership,timestamps ${nixpkgs} $dir
|
||||
# Set the correct timestamp in the tarball.
|
||||
find $dir -print0 | xargs -0 touch -h -t ${builtins.substring 0 12 nixpkgs.lastModifiedDate}.${
|
||||
builtins.substring 12 2 nixpkgs.lastModifiedDate
|
||||
|
|
|
|||
|
|
@ -9,74 +9,74 @@
|
|||
|
||||
#define SYS_fchmodat2 452
|
||||
|
||||
int fchmodat2(int dirfd, const char *pathname, mode_t mode, int flags) {
|
||||
return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags);
|
||||
int fchmodat2(int dirfd, const char * pathname, mode_t mode, int flags)
|
||||
{
|
||||
return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc <= 1) {
|
||||
// stage 1: place the setuid-builder executable
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
if (argc <= 1) {
|
||||
// stage 1: place the setuid-builder executable
|
||||
|
||||
// make the build directory world-accessible first
|
||||
chmod(".", 0755);
|
||||
// make the build directory world-accessible first
|
||||
chmod(".", 0755);
|
||||
|
||||
if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||
perror("Setting the suid bit on attacker");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
} else {
|
||||
// stage 2: corrupt the victim derivation while it's building
|
||||
|
||||
// prevent the kill
|
||||
if (setresuid(-1, -1, getuid())) {
|
||||
perror("setresuid");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (fork() == 0) {
|
||||
|
||||
// wait for the victim to build
|
||||
int fd = inotify_init();
|
||||
inotify_add_watch(fd, argv[1], IN_CREATE);
|
||||
int dirfd = open(argv[1], O_DIRECTORY);
|
||||
if (dirfd < 0) {
|
||||
perror("opening the global build directory");
|
||||
exit(-1);
|
||||
}
|
||||
char buf[4096];
|
||||
fprintf(stderr, "Entering the inotify loop\n");
|
||||
for (;;) {
|
||||
ssize_t len = read(fd, buf, sizeof(buf));
|
||||
struct inotify_event *ev;
|
||||
for (char *pe = buf; pe < buf + len;
|
||||
pe += sizeof(struct inotify_event) + ev->len) {
|
||||
ev = (struct inotify_event *)pe;
|
||||
fprintf(stderr, "folder %s created\n", ev->name);
|
||||
// wait a bit to prevent racing against the creation
|
||||
sleep(1);
|
||||
int builddir = openat(dirfd, ev->name, O_DIRECTORY);
|
||||
if (builddir < 0) {
|
||||
perror("opening the build directory");
|
||||
continue;
|
||||
}
|
||||
int resultfile = openat(builddir, "build/result", O_WRONLY | O_TRUNC);
|
||||
if (resultfile < 0) {
|
||||
perror("opening the hijacked file");
|
||||
continue;
|
||||
}
|
||||
int writeres = write(resultfile, "bad\n", 4);
|
||||
if (writeres < 0) {
|
||||
perror("writing to the hijacked file");
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Hijacked the build for %s\n", ev->name);
|
||||
return 0;
|
||||
if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||
perror("Setting the suid bit on attacker");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// stage 2: corrupt the victim derivation while it's building
|
||||
|
||||
// prevent the kill
|
||||
if (setresuid(-1, -1, getuid())) {
|
||||
perror("setresuid");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (fork() == 0) {
|
||||
|
||||
// wait for the victim to build
|
||||
int fd = inotify_init();
|
||||
inotify_add_watch(fd, argv[1], IN_CREATE);
|
||||
int dirfd = open(argv[1], O_DIRECTORY);
|
||||
if (dirfd < 0) {
|
||||
perror("opening the global build directory");
|
||||
exit(-1);
|
||||
}
|
||||
char buf[4096];
|
||||
fprintf(stderr, "Entering the inotify loop\n");
|
||||
for (;;) {
|
||||
ssize_t len = read(fd, buf, sizeof(buf));
|
||||
struct inotify_event * ev;
|
||||
for (char * pe = buf; pe < buf + len; pe += sizeof(struct inotify_event) + ev->len) {
|
||||
ev = (struct inotify_event *) pe;
|
||||
fprintf(stderr, "folder %s created\n", ev->name);
|
||||
// wait a bit to prevent racing against the creation
|
||||
sleep(1);
|
||||
int builddir = openat(dirfd, ev->name, O_DIRECTORY);
|
||||
if (builddir < 0) {
|
||||
perror("opening the build directory");
|
||||
continue;
|
||||
}
|
||||
int resultfile = openat(builddir, "build/result", O_WRONLY | O_TRUNC);
|
||||
if (resultfile < 0) {
|
||||
perror("opening the hijacked file");
|
||||
continue;
|
||||
}
|
||||
int writeres = write(resultfile, "bad\n", 4);
|
||||
if (writeres < 0) {
|
||||
perror("writing to the hijacked file");
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Hijacked the build for %s\n", ev->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ in
|
|||
|
||||
# Wait for the build to be ready
|
||||
# This is OK because it runs as root, so we can access everything
|
||||
machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-build-open-build-dir.drv-*/build/syncPoint")
|
||||
dir = machine.succeed("ls -d /nix/var/nix/builds/nix-build-open-build-dir.drv-*").strip()
|
||||
machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-*/build/syncPoint")
|
||||
dir = machine.succeed("ls -d /nix/var/nix/builds/nix-*").strip()
|
||||
|
||||
# But Alice shouldn't be able to access the build directory
|
||||
machine.fail(f"su alice -c 'ls {dir}/build'")
|
||||
|
|
@ -125,8 +125,8 @@ in
|
|||
args = [ (builtins.storePath "${create-hello-world}") ];
|
||||
}' >&2 &
|
||||
""".strip())
|
||||
machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-build-innocent.drv-*/build/syncPoint")
|
||||
dir = machine.succeed("ls -d /nix/var/nix/builds/nix-build-innocent.drv-*").strip()
|
||||
machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-*/build/syncPoint")
|
||||
dir = machine.succeed("ls -d /nix/var/nix/builds/nix-*").strip()
|
||||
|
||||
# The build ran as `nixbld1` (which is the only build user on the
|
||||
# machine), but a process running as `nixbld1` outside the sandbox
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue