about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/cli/src/tvix_store_io.rs2
-rw-r--r--tvix/store-go/pathinfo.go28
-rw-r--r--tvix/store-go/pathinfo.pb.go79
-rw-r--r--tvix/store-go/pathinfo_test.go4
-rw-r--r--tvix/store-go/rpc_pathinfo.pb.go11
-rw-r--r--tvix/store-go/rpc_pathinfo_grpc.pb.go14
-rw-r--r--tvix/store/protos/pathinfo.proto7
-rw-r--r--tvix/store/src/bin/tvix-store.rs2
-rw-r--r--tvix/store/src/proto/mod.rs23
-rw-r--r--tvix/store/src/proto/tests/pathinfo.rs10
-rw-r--r--tvix/store/src/tests/fixtures.rs2
11 files changed, 92 insertions, 90 deletions
diff --git a/tvix/cli/src/tvix_store_io.rs b/tvix/cli/src/tvix_store_io.rs
index e73076c4821a..a774b1619e34 100644
--- a/tvix/cli/src/tvix_store_io.rs
+++ b/tvix/cli/src/tvix_store_io.rs
@@ -343,10 +343,10 @@ async fn import_path_with_pathinfo(
             nar_sha256: nar_sha256.to_vec().into(),
             signatures: vec![],
             reference_names: vec![],
+            deriver: None,
             // TODO: narinfo for talosctl.src contains `CA: fixed:r:sha256:1x13j5hy75221bf6kz7cpgld9vgic6bqx07w5xjs4pxnksj6lxb6`
             // do we need this anywhere?
         }),
-        deriver: None,
     };
 
     // put into [PathInfoService], and return the [PathInfo] that we get
diff --git a/tvix/store-go/pathinfo.go b/tvix/store-go/pathinfo.go
index 8c0b94f200c1..d0384c4fe25c 100644
--- a/tvix/store-go/pathinfo.go
+++ b/tvix/store-go/pathinfo.go
@@ -49,6 +49,20 @@ func (p *PathInfo) Validate() (*storepath.StorePath, error) {
 				)
 			}
 		}
+
+		// If the Deriver field is populated, ensure it parses to a StorePath.
+		// We can't check for it to *not* end with .drv, as the .drv files produced by
+		// recursive Nix end with multiple .drv suffixes, and only one is popped when
+		// converting to this field.
+		if deriver := narInfo.GetDeriver(); deriver != nil {
+			deriverStorePath := storepath.StorePath{
+				Name:   string(deriver.GetName()),
+				Digest: deriver.GetDigest(),
+			}
+			if err := deriverStorePath.Validate(); err != nil {
+				return nil, fmt.Errorf("invalid deriver field: %w", err)
+			}
+		}
 	}
 
 	// ensure there is a (root) node present
@@ -81,19 +95,5 @@ func (p *PathInfo) Validate() (*storepath.StorePath, error) {
 		return nil, fmt.Errorf("unable to parse root node name %s as StorePath: %w", rootNodeName, err)
 	}
 
-	// If the Deriver field is populated, ensure it parses to a StorePath.
-	// We can't check for it to *not* end with .drv, as the .drv files produced by
-	// recursive Nix end with multiple .drv suffixes, and only one is popped when
-	// converting to this field.
-	if p.Deriver != nil {
-		deriverStorePath := storepath.StorePath{
-			Name:   string(p.Deriver.GetName()),
-			Digest: p.Deriver.GetDigest(),
-		}
-		if err := deriverStorePath.Validate(); err != nil {
-			return nil, fmt.Errorf("invalid deriver field: %w", err)
-		}
-	}
-
 	return storePath, nil
 }
diff --git a/tvix/store-go/pathinfo.pb.go b/tvix/store-go/pathinfo.pb.go
index cdd6129f7d56..cd4b14d7ae3f 100644
--- a/tvix/store-go/pathinfo.pb.go
+++ b/tvix/store-go/pathinfo.pb.go
@@ -10,7 +10,7 @@
 package storev1
 
 import (
-	protos "code.tvl.fyi/tvix/castore-go"
+	castore_go "code.tvl.fyi/tvix/castore-go"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -32,16 +32,13 @@ type PathInfo struct {
 	unknownFields protoimpl.UnknownFields
 
 	// The path can be a directory, file or symlink.
-	Node *protos.Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Node *castore_go.Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
 	// List of references (output path hashes)
 	// This really is the raw *bytes*, after decoding nixbase32, and not a
 	// base32-encoded string.
 	References [][]byte `protobuf:"bytes,2,rep,name=references,proto3" json:"references,omitempty"`
 	// see below.
 	Narinfo *NARInfo `protobuf:"bytes,3,opt,name=narinfo,proto3" json:"narinfo,omitempty"`
-	// The StorePath of the .drv file producing this output.
-	// The .drv suffix is omitted in its `name` field.
-	Deriver *StorePath `protobuf:"bytes,4,opt,name=deriver,proto3" json:"deriver,omitempty"`
 }
 
 func (x *PathInfo) Reset() {
@@ -76,7 +73,7 @@ func (*PathInfo) Descriptor() ([]byte, []int) {
 	return file_tvix_store_protos_pathinfo_proto_rawDescGZIP(), []int{0}
 }
 
-func (x *PathInfo) GetNode() *protos.Node {
+func (x *PathInfo) GetNode() *castore_go.Node {
 	if x != nil {
 		return x.Node
 	}
@@ -97,13 +94,6 @@ func (x *PathInfo) GetNarinfo() *NARInfo {
 	return nil
 }
 
-func (x *PathInfo) GetDeriver() *StorePath {
-	if x != nil {
-		return x.Deriver
-	}
-	return nil
-}
-
 // Represents a path in the Nix store (a direct child of STORE_DIR).
 // It is commonly formatted by a nixbase32-encoding the digest, and
 // concatenating the name, separated by a `-`.
@@ -190,6 +180,9 @@ type NARInfo struct {
 	// all references (like PathInfo.references), but their whole (base)names,
 	// so we need to keep them somewhere.
 	ReferenceNames []string `protobuf:"bytes,4,rep,name=reference_names,json=referenceNames,proto3" json:"reference_names,omitempty"`
+	// The StorePath of the .drv file producing this output.
+	// The .drv suffix is omitted in its `name` field.
+	Deriver *StorePath `protobuf:"bytes,5,opt,name=deriver,proto3" json:"deriver,omitempty"`
 }
 
 func (x *NARInfo) Reset() {
@@ -252,6 +245,13 @@ func (x *NARInfo) GetReferenceNames() []string {
 	return nil
 }
 
+func (x *NARInfo) GetDeriver() *StorePath {
+	if x != nil {
+		return x.Deriver
+	}
+	return nil
+}
+
 // This represents a (parsed) signature line in a .narinfo file.
 type NARInfo_Signature struct {
 	state         protoimpl.MessageState
@@ -316,7 +316,7 @@ var file_tvix_store_protos_pathinfo_proto_rawDesc = []byte{
 	0x74, 0x6f, 0x12, 0x0d, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
 	0x31, 0x1a, 0x21, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbb, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66,
 	0x6f, 0x12, 0x29, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
 	0x15, 0x2e, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x63, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
 	0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a,
@@ -324,32 +324,31 @@ var file_tvix_store_protos_pathinfo_proto_rawDesc = []byte{
 	0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x07,
 	0x6e, 0x61, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
 	0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x41,
-	0x52, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6e, 0x61, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x32,
-	0x0a, 0x07, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x18, 0x2e, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e,
-	0x53, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x07, 0x64, 0x65, 0x72, 0x69, 0x76,
-	0x65, 0x72, 0x22, 0x37, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12,
-	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
-	0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0xe3, 0x01, 0x0a, 0x07,
-	0x4e, 0x41, 0x52, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x61, 0x72, 0x5f, 0x73,
-	0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6e, 0x61, 0x72, 0x53, 0x69,
-	0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x61, 0x72, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6e, 0x61, 0x72, 0x53, 0x68, 0x61, 0x32, 0x35,
-	0x36, 0x12, 0x40, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18,
-	0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f,
-	0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x41, 0x52, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69,
-	0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
-	0x72, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65,
-	0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x1a, 0x33, 0x0a, 0x09,
+	0x52, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6e, 0x61, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x37,
+	0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x97, 0x02, 0x0a, 0x07, 0x4e, 0x41, 0x52, 0x49,
+	0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x61, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6e, 0x61, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d,
+	0x0a, 0x0a, 0x6e, 0x61, 0x72, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x0c, 0x52, 0x09, 0x6e, 0x61, 0x72, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x12, 0x40, 0x0a,
+	0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x20, 0x2e, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
+	0x31, 0x2e, 0x4e, 0x41, 0x52, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
+	0x75, 0x72, 0x65, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12,
+	0x27, 0x0a, 0x0f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+	0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
+	0x6e, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x64, 0x65, 0x72, 0x69,
+	0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x76, 0x69, 0x78,
+	0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x50,
+	0x61, 0x74, 0x68, 0x52, 0x07, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x72, 0x1a, 0x33, 0x0a, 0x09,
 	0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
 	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
 	0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
-	0x61, 0x42, 0x28, 0x5a, 0x26, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79,
-	0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x73, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x61, 0x42, 0x24, 0x5a, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79,
+	0x69, 0x2f, 0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67, 0x6f, 0x3b,
+	0x73, 0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -370,13 +369,13 @@ var file_tvix_store_protos_pathinfo_proto_goTypes = []interface{}{
 	(*StorePath)(nil),         // 1: tvix.store.v1.StorePath
 	(*NARInfo)(nil),           // 2: tvix.store.v1.NARInfo
 	(*NARInfo_Signature)(nil), // 3: tvix.store.v1.NARInfo.Signature
-	(*protos.Node)(nil),       // 4: tvix.castore.v1.Node
+	(*castore_go.Node)(nil),   // 4: tvix.castore.v1.Node
 }
 var file_tvix_store_protos_pathinfo_proto_depIdxs = []int32{
 	4, // 0: tvix.store.v1.PathInfo.node:type_name -> tvix.castore.v1.Node
 	2, // 1: tvix.store.v1.PathInfo.narinfo:type_name -> tvix.store.v1.NARInfo
-	1, // 2: tvix.store.v1.PathInfo.deriver:type_name -> tvix.store.v1.StorePath
-	3, // 3: tvix.store.v1.NARInfo.signatures:type_name -> tvix.store.v1.NARInfo.Signature
+	3, // 2: tvix.store.v1.NARInfo.signatures:type_name -> tvix.store.v1.NARInfo.Signature
+	1, // 3: tvix.store.v1.NARInfo.deriver:type_name -> tvix.store.v1.StorePath
 	4, // [4:4] is the sub-list for method output_type
 	4, // [4:4] is the sub-list for method input_type
 	4, // [4:4] is the sub-list for extension type_name
diff --git a/tvix/store-go/pathinfo_test.go b/tvix/store-go/pathinfo_test.go
index ff68171a251e..e248f52c8d26 100644
--- a/tvix/store-go/pathinfo_test.go
+++ b/tvix/store-go/pathinfo_test.go
@@ -125,7 +125,7 @@ func TestValidate(t *testing.T) {
 		pi := genPathInfoSymlink()
 
 		// add the Deriver Field.
-		pi.Deriver = &storev1pb.StorePath{
+		pi.Narinfo.Deriver = &storev1pb.StorePath{
 			Digest: exampleStorePathDigest,
 			Name:   "foo",
 		}
@@ -138,7 +138,7 @@ func TestValidate(t *testing.T) {
 		pi := genPathInfoSymlink()
 
 		// add the Deriver Field, with a broken digest
-		pi.Deriver = &storev1pb.StorePath{
+		pi.Narinfo.Deriver = &storev1pb.StorePath{
 			Digest: []byte{},
 			Name:   "foo2",
 		}
diff --git a/tvix/store-go/rpc_pathinfo.pb.go b/tvix/store-go/rpc_pathinfo.pb.go
index 8698c79215c3..80e0289588bc 100644
--- a/tvix/store-go/rpc_pathinfo.pb.go
+++ b/tvix/store-go/rpc_pathinfo.pb.go
@@ -10,7 +10,7 @@
 package storev1
 
 import (
-	protos "code.tvl.fyi/tvix/castore-go"
+	castore_go "code.tvl.fyi/tvix/castore-go"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -238,10 +238,9 @@ var file_tvix_store_protos_rpc_pathinfo_proto_rawDesc = []byte{
 	0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71,
 	0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x76, 0x69, 0x78, 0x2e, 0x73, 0x74, 0x6f, 0x72,
 	0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x30, 0x01, 0x42,
-	0x28, 0x5a, 0x26, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f,
-	0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x73, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x33,
+	0x24, 0x5a, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x74, 0x76, 0x6c, 0x2e, 0x66, 0x79, 0x69, 0x2f,
+	0x74, 0x76, 0x69, 0x78, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x67, 0x6f, 0x3b, 0x73, 0x74,
+	0x6f, 0x72, 0x65, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -262,7 +261,7 @@ var file_tvix_store_protos_rpc_pathinfo_proto_goTypes = []interface{}{
 	(*ListPathInfoRequest)(nil),  // 1: tvix.store.v1.ListPathInfoRequest
 	(*CalculateNARResponse)(nil), // 2: tvix.store.v1.CalculateNARResponse
 	(*PathInfo)(nil),             // 3: tvix.store.v1.PathInfo
-	(*protos.Node)(nil),          // 4: tvix.castore.v1.Node
+	(*castore_go.Node)(nil),      // 4: tvix.castore.v1.Node
 }
 var file_tvix_store_protos_rpc_pathinfo_proto_depIdxs = []int32{
 	0, // 0: tvix.store.v1.PathInfoService.Get:input_type -> tvix.store.v1.GetPathInfoRequest
diff --git a/tvix/store-go/rpc_pathinfo_grpc.pb.go b/tvix/store-go/rpc_pathinfo_grpc.pb.go
index 8f026f36bab5..4096211c1bb2 100644
--- a/tvix/store-go/rpc_pathinfo_grpc.pb.go
+++ b/tvix/store-go/rpc_pathinfo_grpc.pb.go
@@ -10,7 +10,7 @@
 package storev1
 
 import (
-	protos "code.tvl.fyi/tvix/castore-go"
+	castore_go "code.tvl.fyi/tvix/castore-go"
 	context "context"
 	grpc "google.golang.org/grpc"
 	codes "google.golang.org/grpc/codes"
@@ -61,7 +61,7 @@ type PathInfoServiceClient interface {
 	//
 	// It can also be used to calculate arbitrary NAR hashes of output paths,
 	// in case a legacy Nix Binary Cache frontend is provided.
-	CalculateNAR(ctx context.Context, in *protos.Node, opts ...grpc.CallOption) (*CalculateNARResponse, error)
+	CalculateNAR(ctx context.Context, in *castore_go.Node, opts ...grpc.CallOption) (*CalculateNARResponse, error)
 	// Return a stream of PathInfo messages matching the criteria specified in
 	// ListPathInfoRequest.
 	List(ctx context.Context, in *ListPathInfoRequest, opts ...grpc.CallOption) (PathInfoService_ListClient, error)
@@ -93,7 +93,7 @@ func (c *pathInfoServiceClient) Put(ctx context.Context, in *PathInfo, opts ...g
 	return out, nil
 }
 
-func (c *pathInfoServiceClient) CalculateNAR(ctx context.Context, in *protos.Node, opts ...grpc.CallOption) (*CalculateNARResponse, error) {
+func (c *pathInfoServiceClient) CalculateNAR(ctx context.Context, in *castore_go.Node, opts ...grpc.CallOption) (*CalculateNARResponse, error) {
 	out := new(CalculateNARResponse)
 	err := c.cc.Invoke(ctx, PathInfoService_CalculateNAR_FullMethodName, in, out, opts...)
 	if err != nil {
@@ -166,7 +166,7 @@ type PathInfoServiceServer interface {
 	//
 	// It can also be used to calculate arbitrary NAR hashes of output paths,
 	// in case a legacy Nix Binary Cache frontend is provided.
-	CalculateNAR(context.Context, *protos.Node) (*CalculateNARResponse, error)
+	CalculateNAR(context.Context, *castore_go.Node) (*CalculateNARResponse, error)
 	// Return a stream of PathInfo messages matching the criteria specified in
 	// ListPathInfoRequest.
 	List(*ListPathInfoRequest, PathInfoService_ListServer) error
@@ -183,7 +183,7 @@ func (UnimplementedPathInfoServiceServer) Get(context.Context, *GetPathInfoReque
 func (UnimplementedPathInfoServiceServer) Put(context.Context, *PathInfo) (*PathInfo, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method Put not implemented")
 }
-func (UnimplementedPathInfoServiceServer) CalculateNAR(context.Context, *protos.Node) (*CalculateNARResponse, error) {
+func (UnimplementedPathInfoServiceServer) CalculateNAR(context.Context, *castore_go.Node) (*CalculateNARResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CalculateNAR not implemented")
 }
 func (UnimplementedPathInfoServiceServer) List(*ListPathInfoRequest, PathInfoService_ListServer) error {
@@ -239,7 +239,7 @@ func _PathInfoService_Put_Handler(srv interface{}, ctx context.Context, dec func
 }
 
 func _PathInfoService_CalculateNAR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(protos.Node)
+	in := new(castore_go.Node)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -251,7 +251,7 @@ func _PathInfoService_CalculateNAR_Handler(srv interface{}, ctx context.Context,
 		FullMethod: PathInfoService_CalculateNAR_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(PathInfoServiceServer).CalculateNAR(ctx, req.(*protos.Node))
+		return srv.(PathInfoServiceServer).CalculateNAR(ctx, req.(*castore_go.Node))
 	}
 	return interceptor(ctx, in, info, handler)
 }
diff --git a/tvix/store/protos/pathinfo.proto b/tvix/store/protos/pathinfo.proto
index 316201226884..abddf31acd2b 100644
--- a/tvix/store/protos/pathinfo.proto
+++ b/tvix/store/protos/pathinfo.proto
@@ -21,10 +21,6 @@ message PathInfo {
 
     // see below.
     NARInfo narinfo = 3;
-
-    // The StorePath of the .drv file producing this output.
-    // The .drv suffix is omitted in its `name` field.
-    StorePath deriver = 4;
 }
 
 // Represents a path in the Nix store (a direct child of STORE_DIR).
@@ -70,4 +66,7 @@ message NARInfo {
     // so we need to keep them somewhere.
     repeated string reference_names = 4;
 
+    // The StorePath of the .drv file producing this output.
+    // The .drv suffix is omitted in its `name` field.
+    StorePath deriver = 5;
 }
diff --git a/tvix/store/src/bin/tvix-store.rs b/tvix/store/src/bin/tvix-store.rs
index db19c532f380..891b10da6955 100644
--- a/tvix/store/src/bin/tvix-store.rs
+++ b/tvix/store/src/bin/tvix-store.rs
@@ -302,8 +302,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
                                 nar_sha256: nar_sha256.to_vec().into(),
                                 signatures: vec![],
                                 reference_names: vec![],
+                                deriver: None,
                             }),
-                            deriver: None,
                         };
 
                         // put into [PathInfoService], and return the PathInfo that we get back
diff --git a/tvix/store/src/proto/mod.rs b/tvix/store/src/proto/mod.rs
index a982d71f8886..4b5bf4f59479 100644
--- a/tvix/store/src/proto/mod.rs
+++ b/tvix/store/src/proto/mod.rs
@@ -140,6 +140,19 @@ impl PathInfo {
                         );
                     }
                 }
+
+                // If the Deriver field is populated, ensure it parses to a
+                // [store_path::StorePath].
+                // We can't check for it to *not* end with .drv, as the .drv files produced by
+                // recursive Nix end with multiple .drv suffixes, and only one is popped when
+                // converting to this field.
+                if let Some(deriver) = &narinfo.deriver {
+                    store_path::StorePath::from_name_and_digest(
+                        deriver.name.clone(),
+                        &deriver.digest,
+                    )
+                    .map_err(ValidatePathInfoError::InvalidDeriverField)?;
+                }
             }
         }
 
@@ -156,16 +169,6 @@ impl PathInfo {
             }
         };
 
-        // If the Deriver field is populated, ensure it parses to a
-        // [store_path::StorePath].
-        // We can't check for it to *not* end with .drv, as the .drv files produced by
-        // recursive Nix end with multiple .drv suffixes, and only one is popped when
-        // converting to this field.
-        if let Some(deriver) = &self.deriver {
-            store_path::StorePath::from_name_and_digest(deriver.name.clone(), &deriver.digest)
-                .map_err(ValidatePathInfoError::InvalidDeriverField)?;
-        }
-
         // return the root nix path
         Ok(root_nix_path)
     }
diff --git a/tvix/store/src/proto/tests/pathinfo.rs b/tvix/store/src/proto/tests/pathinfo.rs
index 03094ed734ce..392d5d8127b4 100644
--- a/tvix/store/src/proto/tests/pathinfo.rs
+++ b/tvix/store/src/proto/tests/pathinfo.rs
@@ -266,10 +266,11 @@ fn validate_symlink_target_null_byte_invalid() {
 /// Create a PathInfo with a correct deriver field and ensure it succeeds.
 #[test]
 fn validate_valid_deriver() {
-    let mut path_info = PATH_INFO_WITHOUT_NARINFO.clone();
+    let mut path_info = PATH_INFO_WITH_NARINFO.clone();
 
     // add a valid deriver
-    path_info.deriver = Some(crate::proto::StorePath {
+    let narinfo = path_info.narinfo.as_mut().unwrap();
+    narinfo.deriver = Some(crate::proto::StorePath {
         name: "foo".to_string(),
         digest: DUMMY_OUTPUT_HASH.clone(),
     });
@@ -280,10 +281,11 @@ fn validate_valid_deriver() {
 /// Create a PathInfo with a broken deriver field and ensure it fails.
 #[test]
 fn validate_invalid_deriver() {
-    let mut path_info = PATH_INFO_WITHOUT_NARINFO.clone();
+    let mut path_info = PATH_INFO_WITH_NARINFO.clone();
 
     // add a broken deriver (invalid digest)
-    path_info.deriver = Some(crate::proto::StorePath {
+    let narinfo = path_info.narinfo.as_mut().unwrap();
+    narinfo.deriver = Some(crate::proto::StorePath {
         name: "foo".to_string(),
         digest: vec![].into(),
     });
diff --git a/tvix/store/src/tests/fixtures.rs b/tvix/store/src/tests/fixtures.rs
index 5290581688e6..95e77e3ba7b2 100644
--- a/tvix/store/src/tests/fixtures.rs
+++ b/tvix/store/src/tests/fixtures.rs
@@ -109,7 +109,6 @@ lazy_static! {
         }),
         references: vec![DUMMY_OUTPUT_HASH.clone()],
         narinfo: None,
-        deriver: None,
     };
 
     /// A PathInfo message with .narinfo populated.
@@ -121,6 +120,7 @@ lazy_static! {
             nar_sha256: DUMMY_DIGEST.clone().into(),
             signatures: vec![],
             reference_names: vec![DUMMY_NAME.to_string()],
+            deriver: None,
         }),
       ..PATH_INFO_WITHOUT_NARINFO.clone()
     };