1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-29 06:21:14 +02:00

Warn if the computed tree hash differs from the one reported by GitHub

Ideally this would be a fatal error, but tree hashes won't be correct
for repos that use submodules. (But OTOH, the GitHub fetcher doesn't
support submodules anyway...)
This commit is contained in:
Eelco Dolstra 2023-02-03 16:23:12 +01:00
parent 7b1cda9ca2
commit 00b746d099

View file

@ -199,7 +199,13 @@ struct GitArchiveInputScheme : InputScheme
return headers; return headers;
} }
virtual Hash getRevFromRef(nix::ref<Store> store, const Input & input) const = 0; struct RefInfo
{
Hash rev;
std::optional<Hash> treeHash;
};
virtual RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const = 0;
virtual DownloadUrl getDownloadUrl(const Input & input) const = 0; virtual DownloadUrl getDownloadUrl(const Input & input) const = 0;
@ -207,8 +213,15 @@ struct GitArchiveInputScheme : InputScheme
{ {
if (!maybeGetStrAttr(input.attrs, "ref")) input.attrs.insert_or_assign("ref", "HEAD"); if (!maybeGetStrAttr(input.attrs, "ref")) input.attrs.insert_or_assign("ref", "HEAD");
std::optional<Hash> upstreamTreeHash;
auto rev = input.getRev(); auto rev = input.getRev();
if (!rev) rev = getRevFromRef(store, input); if (!rev) {
auto refInfo = getRevFromRef(store, input);
rev = refInfo.rev;
upstreamTreeHash = refInfo.treeHash;
debug("HEAD revision for '%s' is %s", input.to_string(), refInfo.rev.gitRev());
}
input.attrs.erase("ref"); input.attrs.erase("ref");
input.attrs.insert_or_assign("rev", rev->gitRev()); input.attrs.insert_or_assign("rev", rev->gitRev());
@ -243,6 +256,13 @@ struct GitArchiveInputScheme : InputScheme
cache->upsertFact(treeHashKey, tarballInfo.treeHash.gitRev()); cache->upsertFact(treeHashKey, tarballInfo.treeHash.gitRev());
cache->upsertFact(lastModifiedKey, std::to_string(tarballInfo.lastModified)); cache->upsertFact(lastModifiedKey, std::to_string(tarballInfo.lastModified));
if (upstreamTreeHash != tarballInfo.treeHash)
warn(
"Git tree hash mismatch for revision '%s' of '%s': "
"expected '%s', got '%s'. "
"This can happen if the Git repository uses submodules.",
rev->gitRev(), input.to_string(), upstreamTreeHash->gitRev(), tarballInfo.treeHash.gitRev());
return {std::move(input), tarballInfo}; return {std::move(input), tarballInfo};
} }
@ -297,7 +317,7 @@ struct GitHubInputScheme : GitArchiveInputScheme
} }
/* .commit.tree.sha, .commit.committer.date */ /* .commit.tree.sha, .commit.committer.date */
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
{ {
auto host = getHost(input); auto host = getHost(input);
auto url = fmt( auto url = fmt(
@ -312,9 +332,10 @@ struct GitHubInputScheme : GitArchiveInputScheme
readFile( readFile(
store->toRealPath( store->toRealPath(
downloadFile(store, url, "source", false, headers).storePath))); downloadFile(store, url, "source", false, headers).storePath)));
auto rev = Hash::parseAny(std::string { json["sha"] }, htSHA1); return RefInfo {
debug("HEAD revision for '%s' is %s", url, rev.gitRev()); .rev = Hash::parseAny(std::string { json["sha"] }, htSHA1),
return rev; .treeHash = Hash::parseAny(std::string { json["commit"]["tree"]["sha"] }, htSHA1)
};
} }
DownloadUrl getDownloadUrl(const Input & input) const override DownloadUrl getDownloadUrl(const Input & input) const override
@ -371,7 +392,7 @@ struct GitLabInputScheme : GitArchiveInputScheme
return std::make_pair(token.substr(0,fldsplit), token.substr(fldsplit+1)); return std::make_pair(token.substr(0,fldsplit), token.substr(fldsplit+1));
} }
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
{ {
auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com"); auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com");
// See rate limiting note below // See rate limiting note below
@ -384,9 +405,9 @@ struct GitLabInputScheme : GitArchiveInputScheme
readFile( readFile(
store->toRealPath( store->toRealPath(
downloadFile(store, url, "source", false, headers).storePath))); downloadFile(store, url, "source", false, headers).storePath)));
auto rev = Hash::parseAny(std::string(json[0]["id"]), htSHA1); return RefInfo {
debug("HEAD revision for '%s' is %s", url, rev.gitRev()); .rev = Hash::parseAny(std::string(json[0]["id"]), htSHA1)
return rev; };
} }
DownloadUrl getDownloadUrl(const Input & input) const override DownloadUrl getDownloadUrl(const Input & input) const override
@ -430,7 +451,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
// Once it is implemented, however, should work as expected. // Once it is implemented, however, should work as expected.
} }
Hash getRevFromRef(nix::ref<Store> store, const Input & input) const override RefInfo getRevFromRef(nix::ref<Store> store, const Input & input) const override
{ {
// TODO: In the future, when the sourcehut graphql API is implemented for mercurial // TODO: In the future, when the sourcehut graphql API is implemented for mercurial
// and with anonymous access, this method should use it instead. // and with anonymous access, this method should use it instead.
@ -476,9 +497,9 @@ struct SourceHutInputScheme : GitArchiveInputScheme
if (!id) if (!id)
throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref); throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref);
auto rev = Hash::parseAny(*id, htSHA1); return RefInfo {
debug("HEAD revision for '%s' is %s", fmt("%s/%s", base_url, ref), rev.gitRev()); .rev = Hash::parseAny(*id, htSHA1)
return rev; };
} }
DownloadUrl getDownloadUrl(const Input & input) const override DownloadUrl getDownloadUrl(const Input & input) const override