diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d5cbfc34e25..ab4a76ea5fa0 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 ' - .hydraJobs.tests - | with_entries(select(.value.type == "derivation")) - | keys[] - | "${{ inputs.flake }}#hydraJobs.tests." + .') + nix build -L --keep-going --timeout 600 $tests } if ! cmd; then diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 668323ed0824..c102f36d4e1a 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 diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 1562544f0c08..1205e0b3c50d 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); diff --git a/tests/nixos/default.nix b/tests/nixos/default.nix index f06ad1c30937..c30e872bc1d0 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/s3-binary-cache-store.nix b/tests/nixos/s3-binary-cache-store.nix index 54ca03228597..d63ef4ca77bf 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 # ============================================================================ diff --git a/tests/nixos/upgrade-nix.nix b/tests/nixos/upgrade-nix.nix deleted file mode 100644 index 947fa4533121..000000000000 --- 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}" - ''; - }; -} diff --git a/tests/nixos/user-sandboxing/default.nix b/tests/nixos/user-sandboxing/default.nix index d6899140ad01..4305bee10902 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; };