aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/fetchers/fetchers.cc4
-rw-r--r--src/libstore/fetchers/fetchers.hh2
-rw-r--r--src/libstore/fetchers/tarball.cc91
-rw-r--r--tests/flakes.sh14
4 files changed, 110 insertions, 1 deletions
diff --git a/src/libstore/fetchers/fetchers.cc b/src/libstore/fetchers/fetchers.cc
index 7f82d5af0..efc18dbb8 100644
--- a/src/libstore/fetchers/fetchers.cc
+++ b/src/libstore/fetchers/fetchers.cc
@@ -39,6 +39,10 @@ std::pair<Tree, std::shared_ptr<const Input>> Input::fetchTree(ref<Store> store)
if (input->narHash)
assert(input->narHash == tree.narHash);
+ if (narHash && narHash != input->narHash)
+ throw Error("NAR hash mismatch in input '%s', expected '%s', got '%s'",
+ to_string(), narHash->to_string(SRI), input->narHash->to_string(SRI));
+
return {std::move(tree), input};
}
diff --git a/src/libstore/fetchers/fetchers.hh b/src/libstore/fetchers/fetchers.hh
index 1f3be8c2b..ccc1683ba 100644
--- a/src/libstore/fetchers/fetchers.hh
+++ b/src/libstore/fetchers/fetchers.hh
@@ -25,7 +25,7 @@ struct Tree
struct Input : std::enable_shared_from_this<Input>
{
std::string type;
- std::optional<Hash> narHash;
+ std::optional<Hash> narHash; // FIXME: implement
virtual ~Input() { }
diff --git a/src/libstore/fetchers/tarball.cc b/src/libstore/fetchers/tarball.cc
new file mode 100644
index 000000000..e82066089
--- /dev/null
+++ b/src/libstore/fetchers/tarball.cc
@@ -0,0 +1,91 @@
+#include "fetchers.hh"
+#include "download.hh"
+#include "globals.hh"
+#include "parse.hh"
+#include "store-api.hh"
+
+namespace nix::fetchers {
+
+struct TarballInput : Input
+{
+ ParsedURL url;
+ std::optional<Hash> hash;
+
+ bool operator ==(const Input & other) const override
+ {
+ auto other2 = dynamic_cast<const TarballInput *>(&other);
+ return
+ other2
+ && to_string() == other2->to_string()
+ && hash == other2->hash;
+ }
+
+ bool isImmutable() const override
+ {
+ return (bool) hash;
+ }
+
+ std::string to_string() const override
+ {
+ auto url2(url);
+ if (narHash)
+ url2.query.insert_or_assign("narHash", narHash->to_string(SRI));
+ return url2.to_string();
+ }
+
+ std::pair<Tree, std::shared_ptr<const Input>> fetchTreeInternal(nix::ref<Store> store) const override
+ {
+ CachedDownloadRequest request(url.to_string());
+ request.unpack = true;
+ request.getLastModified = true;
+ request.name = "source";
+
+ auto res = getDownloader()->downloadCached(store, request);
+
+ auto input = std::make_shared<TarballInput>(*this);
+
+ auto storePath = store->parseStorePath(res.storePath);
+
+ input->narHash = store->queryPathInfo(storePath)->narHash;
+
+ return {
+ Tree {
+ .actualPath = res.path,
+ .storePath = std::move(storePath),
+ .lastModified = *res.lastModified
+ },
+ input
+ };
+ }
+};
+
+struct TarballInputScheme : InputScheme
+{
+ std::unique_ptr<Input> inputFromURL(const ParsedURL & url) override
+ {
+ if (url.scheme != "file" && url.scheme != "http" && url.scheme != "https") return nullptr;
+
+ if (!hasSuffix(url.path, ".zip")
+ && !hasSuffix(url.path, ".tar")
+ && !hasSuffix(url.path, ".tar.gz")
+ && !hasSuffix(url.path, ".tar.xz")
+ && !hasSuffix(url.path, ".tar.bz2"))
+ return nullptr;
+
+ auto input = std::make_unique<TarballInput>();
+ input->type = "tarball";
+ input->url = url;
+
+ auto narHash = url.query.find("narHash");
+ if (narHash != url.query.end()) {
+ // FIXME: require SRI hash.
+ input->narHash = Hash(narHash->second);
+ }
+
+ return input;
+ }
+};
+
+static auto r1 = OnStartup([] { registerInputScheme(std::make_unique<TarballInputScheme>()); });
+
+}
diff --git a/tests/flakes.sh b/tests/flakes.sh
index 5b844a784..41f123883 100644
--- a/tests/flakes.sh
+++ b/tests/flakes.sh
@@ -573,3 +573,17 @@ nix flake info --flake-registry $registry --json hg+file://$flake5Dir
[[ $(nix flake info --flake-registry $registry --json hg+file://$flake5Dir | jq -e -r .revCount) = 1 ]]
nix build -o $TEST_ROOT/result hg+file://$flake5Dir --no-registries --no-allow-dirty
+
+# Test tarball flakes
+tar cfz $TEST_ROOT/flake.tar.gz -C $TEST_ROOT flake5
+
+nix build -o $TEST_ROOT/result file://$TEST_ROOT/flake.tar.gz
+
+# Building with a tarball URL containing a SRI hash should also work.
+url=$(nix flake info --json file://$TEST_ROOT/flake.tar.gz | jq -r .url)
+[[ $url =~ sha256- ]]
+
+nix build -o $TEST_ROOT/result $url
+
+# Building with an incorrect SRI hash should fail.
+nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch'