From 604e107325ace8ce27d35313175667d6da62a37c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 19:16:52 +0200 Subject: [PATCH 1/7] Fix running hydraJobs in CI The `nix flake show --json` output format changed, so this jq query was returning an empty list. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d5cbfc34e2..161b805a836 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -134,8 +134,8 @@ jobs: nix build -L --keep-going --timeout 600 \ $(nix flake show --json \ | jq -r ' - .hydraJobs.tests - | with_entries(select(.value.type == "derivation")) + .inventory.hydraJobs.output.children.tests.children + | with_entries(select(.value | has("derivation"))) | keys[] | "${{ inputs.flake }}#hydraJobs.tests." + .') } From 258d02d9c4d95f5797978ea8417f604f9c7d3652 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 19:18:46 +0200 Subject: [PATCH 2/7] Run VM tests for one variant only --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 668323ed082..c102f36d4e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: runner_for_virt: UbuntuLatest32Cores128G runner_small: ubuntu-latest run_tests: true - run_vm_tests: true + run_vm_tests: false run_regression_tests: true upload_artifacts: false From 933ad82496daef8ccd004c62b9d5b03bea2a557a Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Wed, 10 Jun 2026 03:19:06 +0300 Subject: [PATCH 3/7] Revert "fetchTarball: Remove custom substitution code" This reverts commit 3ec0993179e653ee62ed410264d8d7bf5694bca3. This actually broke fetchersSubstitute test, since we want to be able to substitute builtins.fetchurl too, which is only handled by the tarball fetcher. See: https://hydra.nixos.org/build/331423127 --- src/libexpr/primops/fetchTree.cc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 1562544f0c0..1205e0b3c50 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -427,17 +427,38 @@ static void fetch( .atPos(pos) .debugThrow(); + // early exit if pinned and already in the store + if (expectedHash && expectedHash->algo == HashAlgorithm::SHA256) { + auto expectedPath = state.store->makeFixedOutputPath( + name, + FixedOutputInfo{ + .method = unpack ? FileIngestionMethod::NixArchive : FileIngestionMethod::Flat, + .hash = *expectedHash, + .references = {}}); + + // Try to get the path from the local store or substituters + try { + state.store->ensurePath(expectedPath); + debug("using substituted/cached path '%s' for '%s'", state.store->printStorePath(expectedPath), *url); + state.allowAndSetStorePathString(expectedPath, v); + return; + } catch (Error & e) { + debug( + "substitution of '%s' failed, will try to download: %s", + state.store->printStorePath(expectedPath), + e.what()); + // Fall through to download + } + } + if (unpack) { auto attrs = fetchers::Attrs{ {"type", "tarball"}, {"url", *url}, {"name", name}, }; - if (expectedHash) { + if (expectedHash) attrs.emplace("narHash", expectedHash->to_string(HashFormat::SRI, true)); - // Mark as final to allow the tree to be substituted. - attrs.emplace("__final", Explicit{true}); - } auto input = fetchers::Input::fromAttrs(state.fetchSettings, std::move(attrs)); auto cachedInput = state.inputCache->getAccessor(state.fetchSettings, *state.store, input, fetchers::UseRegistries::No); From ced7241842b558e86307ed1fe6a3980ea6812016 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 21:29:16 +0200 Subject: [PATCH 4/7] tests/nixos/s3-binary-cache-store.nix: Fix bad merge --- tests/nixos/s3-binary-cache-store.nix | 94 --------------------------- 1 file changed, 94 deletions(-) diff --git a/tests/nixos/s3-binary-cache-store.nix b/tests/nixos/s3-binary-cache-store.nix index 54ca0322859..d63ef4ca77b 100644 --- a/tests/nixos/s3-binary-cache-store.nix +++ b/tests/nixos/s3-binary-cache-store.nix @@ -953,100 +953,6 @@ in ) verify_packages_in_store(client, PKGS['A']) - @setup_s3( - populate_bucket=[PKGS['A']], - profiles={ - "valid": {"access_key": ACCESS_KEY, "secret_key": SECRET_KEY}, - "invalid": {"access_key": "INVALIDKEY", "secret_key": "INVALIDSECRET"}, - } - ) - def test_profile_credentials(bucket): - """Test that profile-based credentials work without environment variables""" - print("\n=== Testing Profile-Based Credentials ===") - - store_url = make_s3_url(bucket, profile="valid") - - # Verify store info works with profile credentials (no env vars) - client.succeed(f"HOME=/root nix store info --store '{store_url}' >&2") - - # Verify we can copy from the store using profile - verify_packages_in_store(client, PKGS['A'], should_exist=False) - client.succeed(f"HOME=/root nix copy --no-check-sigs --from '{store_url}' {PKGS['A']}") - verify_packages_in_store(client, PKGS['A']) - - # Clean up the package we just copied so we can test invalid profile - client.succeed(f"nix store delete --ignore-liveness {PKGS['A']}") - verify_packages_in_store(client, PKGS['A'], should_exist=False) - - # Verify invalid profile fails when trying to copy - invalid_url = make_s3_url(bucket, profile="invalid") - client.fail(f"HOME=/root nix copy --no-check-sigs --from '{invalid_url}' {PKGS['A']} 2>&1") - - @setup_s3( - populate_bucket=[PKGS['A']], - profiles={ - "wrong": {"access_key": "WRONGKEY", "secret_key": "WRONGSECRET"}, - } - ) - def test_env_vars_precedence(bucket): - """Test that environment variables take precedence over profile credentials""" - print("\n=== Testing Environment Variables Precedence ===") - - # Use profile with wrong credentials, but provide correct creds via env vars - store_url = make_s3_url(bucket, profile="wrong") - - # Ensure package is not in client store - verify_packages_in_store(client, PKGS['A'], should_exist=False) - - # This should succeed because env vars (correct) override profile (wrong) - output = client.succeed( - f"HOME=/root {ENV_WITH_CREDS} nix copy --no-check-sigs --debug --from '{store_url}' {PKGS['A']} 2>&1" - ) - - # Verify the credential chain shows Environment provider was added - if "Added AWS Environment Credential Provider" not in output: - print("Debug output:") - print(output) - raise Exception("Expected Environment provider to be added to chain") - - # Clean up the package so we can test again without env vars - client.succeed(f"nix store delete --ignore-liveness {PKGS['A']}") - verify_packages_in_store(client, PKGS['A'], should_exist=False) - - # Without env vars, same URL should fail (proving profile creds are actually wrong) - client.fail(f"HOME=/root nix copy --no-check-sigs --from '{store_url}' {PKGS['A']} 2>&1") - - @setup_s3( - populate_bucket=[PKGS['A']], - profiles={ - "testprofile": {"access_key": ACCESS_KEY, "secret_key": SECRET_KEY}, - } - ) - def test_credential_provider_chain(bucket): - """Test that debug logging shows which providers are added to the chain""" - print("\n=== Testing Credential Provider Chain Logging ===") - - store_url = make_s3_url(bucket, profile="testprofile") - - output = client.succeed( - f"HOME=/root nix store info --debug --store '{store_url}' 2>&1" - ) - - # For a named profile, we expect to see these providers in the chain - expected_providers = ["Environment", "Profile", "IMDS"] - for provider in expected_providers: - msg = f"Added AWS {provider} Credential Provider to chain for profile 'testprofile'" - if msg not in output: - print("Debug output:") - print(output) - raise Exception(f"Expected to find: {msg}") - - # SSO should be skipped (no SSO config for this profile) - if "Skipped AWS SSO Credential Provider for profile 'testprofile'" not in output: - print("Debug output:") - print(output) - raise Exception("Expected SSO provider to be skipped") - # ============================================================================ # Main Test Execution # ============================================================================ From b638394f022431739a284eba9fd7be2ac9e63fc4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 21:29:29 +0200 Subject: [PATCH 5/7] Ensure that tests in not empty --- .github/workflows/build.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 161b805a836..ab4a76ea5fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,14 +130,20 @@ jobs: - uses: DeterminateSystems/determinate-nix-action@main - uses: DeterminateSystems/flakehub-cache-action@main - run: | + tests=$(nix flake show --json \ + | jq -r ' + .inventory.hydraJobs.output.children.tests.children + | with_entries(select(.value | has("derivation"))) + | keys[] + | "${{ inputs.flake }}#hydraJobs.tests." + .') + + if [ -z "$tests" ]; then + echo "error: no tests found in hydraJobs.tests" + exit 1 + fi + cmd() { - nix build -L --keep-going --timeout 600 \ - $(nix flake show --json \ - | jq -r ' - .inventory.hydraJobs.output.children.tests.children - | with_entries(select(.value | has("derivation"))) - | keys[] - | "${{ inputs.flake }}#hydraJobs.tests." + .') + nix build -L --keep-going --timeout 600 $tests } if ! cmd; then From 8397d69c22517db4dc1a807b4914c25e0865ea69 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 21:41:22 +0200 Subject: [PATCH 6/7] Remove upgrade-nix tests Determinate Nix remove `nix upgrade-nix`. --- tests/nixos/default.nix | 17 ------ tests/nixos/upgrade-nix.nix | 104 ------------------------------------ 2 files changed, 121 deletions(-) delete mode 100644 tests/nixos/upgrade-nix.nix diff --git a/tests/nixos/default.nix b/tests/nixos/default.nix index f06ad1c3093..c30e872bc1d 100644 --- a/tests/nixos/default.nix +++ b/tests/nixos/default.nix @@ -205,21 +205,4 @@ in fetchersSubstitute = runNixOSTest ./fetchers-substitute.nix; chrootStore = runNixOSTest ./chroot-store.nix; - - upgrade-nix = runNixOSTest { - imports = [ ./upgrade-nix.nix ]; - upgrade-nix.oldNix = nixComponents.nix-cli; - }; - - upgrade-nix_fromStable = runNixOSTest { - imports = [ ./upgrade-nix.nix ]; - name = lib.mkForce "upgrade-nix-from-stable"; - upgrade-nix.oldNix = pkgs.nixVersions.stable; - }; - - upgrade-nix_fromLatest = runNixOSTest { - imports = [ ./upgrade-nix.nix ]; - name = lib.mkForce "upgrade-nix-from-latest"; - upgrade-nix.oldNix = pkgs.nixVersions.latest; - }; } diff --git a/tests/nixos/upgrade-nix.nix b/tests/nixos/upgrade-nix.nix deleted file mode 100644 index 947fa453312..00000000000 --- a/tests/nixos/upgrade-nix.nix +++ /dev/null @@ -1,104 +0,0 @@ -# This installs an older Nix into a nix-env profile, and then runs `nix upgrade-nix` -# pointing at a local fallback-paths file containing the locally built nix. -# -# This is based on nixpkgs' nixosTests.nix-upgrade test. -# See https://github.com/NixOS/nixpkgs/blob/e3469a82fbd496d9c8e6192bbaf7cf056c6449ff/nixos/tests/nix/upgrade.nix. - -{ - config, - lib, - nixComponents, - system, - ... -}: -let - pkgs = config.nodes.machine.nixpkgs.pkgs; - - newNix = nixComponents.nix-cli; - oldNix = config.upgrade-nix.oldNix; - - fallback-paths = pkgs.writeTextDir "fallback-paths.nix" '' - { - ${system} = "${newNix}"; - } - ''; -in -{ - options.upgrade-nix.oldNix = lib.mkOption { - type = lib.types.package; - default = newNix; - description = "The Nix package to install before upgrading."; - }; - - config = { - name = "upgrade-nix"; - - nodes.machine = - { lib, ... }: - { - virtualisation.writableStore = true; - nix.settings.substituters = lib.mkForce [ ]; - nix.settings.hashed-mirrors = null; - nix.settings.connect-timeout = 1; - nix.extraOptions = "experimental-features = nix-command"; - environment.localBinInPath = true; - system.extraDependencies = [ - fallback-paths - newNix - oldNix - ]; - users.users.alice = { - isNormalUser = true; - packages = [ newNix ]; - }; - }; - - testScript = /* py */ '' - machine.start() - machine.wait_for_unit("multi-user.target") - - with subtest("nix-current"): - # Create a profile to pretend we are on non-NixOS - - print(machine.succeed("nix --version")) - machine.succeed("nix-env -i ${oldNix} -p /root/.local") - result = machine.succeed("/root/.local/bin/nix --version") - print(f"installed: {result}") - - with subtest("nix-upgrade"): - machine.succeed( - "nix upgrade-nix" - " --nix-store-paths-url file://${fallback-paths}/fallback-paths.nix" - " --profile /root/.local" - ) - result = machine.succeed("/root/.local/bin/nix --version") - print(f"after upgrade: {result}") - assert "${newNix.version}" in result, \ - f"expected ${newNix.version} in: {result}" - - with subtest("nix-build-with-mismatched-daemon"): - # The daemon is still running oldNix; verify the new client works. - machine.succeed( - "runuser -u alice -- nix build" - " --expr 'derivation { name = \"test\"; system = \"${system}\";" - " builder = \"/bin/sh\"; args = [\"-c\" \"echo test > $out\"]; }'" - " --print-out-paths" - ) - - with subtest("nix-upgrade-auto-detect"): - # Without passing in --profile, getProfileDir auto-detects the profile - # by finding nix-env in PATH and resolving the symlink chain back - # to the store. - machine.succeed("nix-env -i ${oldNix} -p /root/.local") - machine.succeed( - "PATH=/root/.local/bin:$PATH" - " ${newNix}/bin/nix upgrade-nix" - " --nix-store-paths-url file://${fallback-paths}/fallback-paths.nix" - ) - result = machine.succeed("/root/.local/bin/nix --version") - print(f"after auto-detect upgrade: {result}") - assert "${newNix.version}" in result, \ - f"expected ${newNix.version} in: {result}" - ''; - }; -} From fa8e4066539c4823627333efc4bb03f6116490e4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Jun 2026 22:25:11 +0200 Subject: [PATCH 7/7] Use default kernel --- tests/nixos/user-sandboxing/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/nixos/user-sandboxing/default.nix b/tests/nixos/user-sandboxing/default.nix index d6899140ad0..4305bee1090 100644 --- a/tests/nixos/user-sandboxing/default.nix +++ b/tests/nixos/user-sandboxing/default.nix @@ -75,7 +75,6 @@ in create-hello-world pkgs.socat ]; - boot.kernelPackages = pkgs.linuxPackages_latest; users.users.alice = { isNormalUser = true; };