[roller-configurator] Extend Jiri support

Some Jiri rollers perform operations that require access to the full
checkout, which in turn requires configuring the roller with a Jiri
manifest to tell it what to check out.

Allow projects to configure the Jiri manifest to use for roller
checkouts with a new top-level `default_checkout_jiri_manifest` field in
rollers.textproto.

Bug: 42051371
Change-Id: I8663bd5721b7fb89d5d8ea69b2909c3aff3d976b
Reviewed-on: https://fuchsia-review.googlesource.com/c/infra/infra/+/964154
Reviewed-by: Carver Forbes <carverforbes@google.com>
Fuchsia-Auto-Submit: Oliver Newman <olivernewman@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/cmd/roller-configurator/proto/resolvers.go b/cmd/roller-configurator/proto/resolvers.go
index 078aef8..07395a0 100644
--- a/cmd/roller-configurator/proto/resolvers.go
+++ b/cmd/roller-configurator/proto/resolvers.go
@@ -8,12 +8,19 @@
 	"context"
 )
 
-func (s *GitSubmodule) Resolve(ctx context.Context, repoRoot string) (map[string]any, error) {
+// ResolveParams represents additional parameters that get passed into each
+// roller type's `Resolve` function.
+type ResolveParams struct {
+	RepoRoot                    string
+	DefaultCheckoutJiriManifest string
+}
+
+func (s *GitSubmodule) Resolve(ctx context.Context, params ResolveParams) (map[string]any, error) {
 	res, err := ProtoToMap(s)
 	if err != nil {
 		return nil, err
 	}
-	res["remote"], err = s.url(ctx, repoRoot)
+	res["remote"], err = s.url(ctx, params.RepoRoot)
 	if err != nil {
 		return nil, err
 	}
@@ -21,7 +28,7 @@
 	return res, nil
 }
 
-func (c *CIPDEnsureFile) Resolve(ctx context.Context, repoRoot string) (map[string]any, error) {
+func (c *CIPDEnsureFile) Resolve(ctx context.Context, params ResolveParams) (map[string]any, error) {
 	res, err := ProtoToMap(c)
 	if err != nil {
 		return nil, err
@@ -30,8 +37,8 @@
 	return res, nil
 }
 
-func (p *JiriProject) Resolve(ctx context.Context, repoRoot string) (map[string]any, error) {
-	me, err := p.manifestEntry(repoRoot)
+func (p *JiriProject) Resolve(ctx context.Context, params ResolveParams) (map[string]any, error) {
+	me, err := p.manifestEntry(params.RepoRoot)
 	if err != nil {
 		return nil, err
 	}
@@ -41,11 +48,12 @@
 	}
 	res["remote"] = me.Remote
 	res["remote_branch"] = me.RemoteBranch
+	res["checkout_manifest"] = params.DefaultCheckoutJiriManifest
 	res["type"] = "jiri_project"
 	return res, nil
 }
 
-func (p *JiriPackages) Resolve(ctx context.Context, repoRoot string) (map[string]any, error) {
+func (p *JiriPackages) Resolve(ctx context.Context, params ResolveParams) (map[string]any, error) {
 	if p.Ref == "" {
 		p.Ref = "latest"
 	}
@@ -53,6 +61,7 @@
 	if err != nil {
 		return nil, err
 	}
+	res["checkout_manifest"] = params.DefaultCheckoutJiriManifest
 	res["type"] = "jiri_packages"
 	return res, nil
 }
diff --git a/cmd/roller-configurator/proto/rollers_cfg.pb.go b/cmd/roller-configurator/proto/rollers_cfg.pb.go
index 2c505ad..462c475 100644
--- a/cmd/roller-configurator/proto/rollers_cfg.pb.go
+++ b/cmd/roller-configurator/proto/rollers_cfg.pb.go
@@ -30,6 +30,10 @@
 	unknownFields protoimpl.UnknownFields
 
 	Rollers []*Roller `protobuf:"bytes,1,rep,name=rollers,proto3" json:"rollers,omitempty"`
+	// Path to the manifest that defines the checkout to use when rolling Jiri
+	// projects/packages, since some Jiri roller operations require access to the
+	// whole Jiri checkout and not just the repository containing the manifests.
+	DefaultCheckoutJiriManifest string `protobuf:"bytes,2,opt,name=default_checkout_jiri_manifest,json=defaultCheckoutJiriManifest,proto3" json:"default_checkout_jiri_manifest,omitempty"`
 }
 
 func (x *Config) Reset() {
@@ -71,6 +75,13 @@
 	return nil
 }
 
+func (x *Config) GetDefaultCheckoutJiriManifest() string {
+	if x != nil {
+		return x.DefaultCheckoutJiriManifest
+	}
+	return ""
+}
+
 type Roller struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -93,8 +104,12 @@
 	// For supported syntax see:
 	// https://chromium.googlesource.com/infra/luci/luci-go/+/refs/heads/main/lucicfg/doc/README.md#schedules-doc
 	Schedule string `protobuf:"bytes,5,opt,name=schedule,proto3" json:"schedule,omitempty"`
+	// Email of the owner of the roller.
+	OwnerEmail string `protobuf:"bytes,6,opt,name=owner_email,json=ownerEmail,proto3" json:"owner_email,omitempty"`
 	// Emails to alert when the roller fails.
-	NotifyEmails []string `protobuf:"bytes,6,rep,name=notify_emails,json=notifyEmails,proto3" json:"notify_emails,omitempty"`
+	NotifyEmails []string `protobuf:"bytes,7,rep,name=notify_emails,json=notifyEmails,proto3" json:"notify_emails,omitempty"`
+	// Whether the roller should bypass presubmit checks.
+	ForceSubmit bool `protobuf:"varint,8,opt,name=force_submit,json=forceSubmit,proto3" json:"force_submit,omitempty"`
 }
 
 func (x *Roller) Reset() {
@@ -171,6 +186,13 @@
 	return ""
 }
 
+func (x *Roller) GetOwnerEmail() string {
+	if x != nil {
+		return x.OwnerEmail
+	}
+	return ""
+}
+
 func (x *Roller) GetNotifyEmails() []string {
 	if x != nil {
 		return x.NotifyEmails
@@ -178,6 +200,13 @@
 	return nil
 }
 
+func (x *Roller) GetForceSubmit() bool {
+	if x != nil {
+		return x.ForceSubmit
+	}
+	return false
+}
+
 type isRoller_ToRoll interface {
 	isRoller_ToRoll()
 }
@@ -488,51 +517,60 @@
 
 var file_rollers_cfg_proto_rawDesc = []byte{
 	0x0a, 0x11, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x5f, 0x63, 0x66, 0x67, 0x2e, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x22, 0x2b, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x21, 0x0a,
+	0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x21, 0x0a,
 	0x07, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x07,
 	0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x07, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73,
-	0x22, 0xa9, 0x02, 0x0a, 0x06, 0x52, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x09, 0x73,
-	0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d,
-	0x2e, 0x47, 0x69, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x48, 0x00, 0x52,
-	0x09, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x3b, 0x0a, 0x10, 0x63, 0x69,
-	0x70, 0x64, 0x5f, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x43, 0x49, 0x50, 0x44, 0x45, 0x6e, 0x73, 0x75, 0x72,
-	0x65, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x69, 0x70, 0x64, 0x45, 0x6e, 0x73,
-	0x75, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x0c, 0x6a, 0x69, 0x72, 0x69, 0x5f,
-	0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
-	0x4a, 0x69, 0x72, 0x69, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6a,
-	0x69, 0x72, 0x69, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x6a, 0x69,
-	0x72, 0x69, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x0d, 0x2e, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73,
-	0x48, 0x00, 0x52, 0x0c, 0x6a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73,
-	0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d,
-	0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x06, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c,
-	0x73, 0x42, 0x09, 0x0a, 0x07, 0x74, 0x6f, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x22, 0x22, 0x0a, 0x0c,
-	0x47, 0x69, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
-	0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68,
-	0x22, 0x36, 0x0a, 0x0e, 0x43, 0x49, 0x50, 0x44, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x46, 0x69,
-	0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x22, 0x43, 0x0a, 0x0b, 0x4a, 0x69, 0x72, 0x69,
-	0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66,
-	0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66,
-	0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x92, 0x01,
-	0x0a, 0x0c, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x34,
-	0x0a, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x16, 0x2e, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73,
-	0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66,
-	0x65, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x1a, 0x3a, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65,
-	0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
-	0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
-	0x65, 0x73, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x6f, 0x2e, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61,
-	0x2e, 0x64, 0x65, 0x76, 0x2f, 0x69, 0x6e, 0x66, 0x72, 0x61, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x72,
-	0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
-	0x6f, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x12, 0x43, 0x0a, 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63,
+	0x6b, 0x6f, 0x75, 0x74, 0x5f, 0x6a, 0x69, 0x72, 0x69, 0x5f, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65,
+	0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
+	0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x6f, 0x75, 0x74, 0x4a, 0x69, 0x72, 0x69, 0x4d, 0x61, 0x6e,
+	0x69, 0x66, 0x65, 0x73, 0x74, 0x22, 0xed, 0x02, 0x0a, 0x06, 0x52, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
+	0x12, 0x2d, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x47, 0x69, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x48, 0x00, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12,
+	0x3b, 0x0a, 0x10, 0x63, 0x69, 0x70, 0x64, 0x5f, 0x65, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x5f, 0x66,
+	0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x43, 0x49, 0x50, 0x44,
+	0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x69,
+	0x70, 0x64, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x31, 0x0a, 0x0c,
+	0x6a, 0x69, 0x72, 0x69, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+	0x48, 0x00, 0x52, 0x0b, 0x6a, 0x69, 0x72, 0x69, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12,
+	0x34, 0x0a, 0x0d, 0x6a, 0x69, 0x72, 0x69, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63,
+	0x6b, 0x61, 0x67, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x6a, 0x69, 0x72, 0x69, 0x50, 0x61, 0x63,
+	0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+	0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+	0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c,
+	0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61,
+	0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x65, 0x6d, 0x61,
+	0x69, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+	0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65,
+	0x5f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x66,
+	0x6f, 0x72, 0x63, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x74, 0x6f,
+	0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x22, 0x22, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x53, 0x75, 0x62, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x36, 0x0a, 0x0e, 0x43, 0x49, 0x50,
+	0x44, 0x45, 0x6e, 0x73, 0x75, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70,
+	0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12,
+	0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65,
+	0x66, 0x22, 0x43, 0x0a, 0x0b, 0x4a, 0x69, 0x72, 0x69, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+	0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07,
+	0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70,
+	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x92, 0x01, 0x0a, 0x0c, 0x4a, 0x69, 0x72, 0x69, 0x50,
+	0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66,
+	0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x4a, 0x69, 0x72,
+	0x69, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65,
+	0x73, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a,
+	0x03, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x1a,
+	0x3a, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70,
+	0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12,
+	0x1a, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x42, 0x34, 0x5a, 0x32, 0x67,
+	0x6f, 0x2e, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x69, 0x6e,
+	0x66, 0x72, 0x61, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2d, 0x63,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/cmd/roller-configurator/proto/rollers_cfg.proto b/cmd/roller-configurator/proto/rollers_cfg.proto
index 24e9672..3332899 100644
--- a/cmd/roller-configurator/proto/rollers_cfg.proto
+++ b/cmd/roller-configurator/proto/rollers_cfg.proto
@@ -8,6 +8,11 @@
 
 message Config {
   repeated Roller rollers = 1;
+
+  // Path to the manifest that defines the checkout to use when rolling Jiri
+  // projects/packages, since some Jiri roller operations require access to the
+  // whole Jiri checkout and not just the repository containing the manifests.
+  string default_checkout_jiri_manifest = 2;
 }
 
 message Roller {
@@ -28,8 +33,14 @@
   // https://chromium.googlesource.com/infra/luci/luci-go/+/refs/heads/main/lucicfg/doc/README.md#schedules-doc
   string schedule = 5;
 
+  // Email of the owner of the roller.
+  string owner_email = 6;
+
   // Emails to alert when the roller fails.
-  repeated string notify_emails = 6;
+  repeated string notify_emails = 7;
+
+  // Whether the roller should bypass presubmit checks.
+  bool force_submit = 8;
 
   // TODO(olivernewman): owner, justification issue URL, pause status
 }
diff --git a/cmd/roller-configurator/resolve.go b/cmd/roller-configurator/resolve.go
index 1932405..a87e5b9 100644
--- a/cmd/roller-configurator/resolve.go
+++ b/cmd/roller-configurator/resolve.go
@@ -72,7 +72,7 @@
 		}
 
 		var toResolve interface {
-			Resolve(ctx context.Context, repoRoot string) (map[string]any, error)
+			Resolve(ctx context.Context, params proto.ResolveParams) (map[string]any, error)
 		}
 		switch field.Name() { // TODO(olivernewman): Deduplicate this logic with validate.go.
 		case "submodule":
@@ -92,7 +92,10 @@
 			return err
 		}
 		delete(resolved, string(field.Name()))
-		addl, err := toResolve.Resolve(ctx, repoRoot)
+		addl, err := toResolve.Resolve(ctx, proto.ResolveParams{
+			RepoRoot:                    repoRoot,
+			DefaultCheckoutJiriManifest: config.DefaultCheckoutJiriManifest,
+		})
 		if err != nil {
 			return err
 		}
diff --git a/cmd/roller-configurator/resolve_test.go b/cmd/roller-configurator/resolve_test.go
index 68ed827..51fb1d0 100644
--- a/cmd/roller-configurator/resolve_test.go
+++ b/cmd/roller-configurator/resolve_test.go
@@ -67,7 +67,9 @@
 					"path": "path/to/submodule",
 					"remote": "https://example.com/lib",
 					"schedule": "* * * * *",
-					"notify_emails": []
+					"force_submit": false,
+					"notify_emails": [],
+					"owner_email": ""
 				}
 			]`,
 		},
@@ -80,7 +82,9 @@
 						project: "foo-project"
 					}
 				}
-			]`,
+			]
+			default_checkout_jiri_manifest: "manifest"
+			`,
 			want: `[
 				{
 					"type": "jiri_project",
@@ -88,8 +92,11 @@
 					"project": "foo-project",
 					"remote": "https://example.com/jiri-project",
 					"remote_branch": "",
+					"checkout_manifest": "manifest",
 					"schedule": "",
-					"notify_emails": []
+					"force_submit": false,
+					"notify_emails": [],
+					"owner_email": ""
 				}
 			]`,
 		},
@@ -121,7 +128,9 @@
 						]
 					}
 				}
-			]`,
+			]
+			default_checkout_jiri_manifest: "manifest"
+			`,
 			want: `[
 				{
 					"type": "jiri_packages",
@@ -134,7 +143,10 @@
 						}
 					],
 					"ref": "foo",
+					"checkout_manifest": "manifest",
 					"schedule": "",
+					"force_submit": false,
+					"owner_email": "",
 					"notify_emails": []
 				},
 				{
@@ -148,7 +160,10 @@
 						}
 					],
 					"ref": "latest",
+					"checkout_manifest": "manifest",
 					"schedule": "",
+					"force_submit": false,
+					"owner_email": "",
 					"notify_emails": []
 				}
 			]`,
diff --git a/cmd/roller-configurator/validate.go b/cmd/roller-configurator/validate.go
index 2bd7fb3..7c2779e 100644
--- a/cmd/roller-configurator/validate.go
+++ b/cmd/roller-configurator/validate.go
@@ -56,6 +56,7 @@
 }
 
 func validate(ctx context.Context, repoRoot string, config *proto.Config) error {
+	var hasJiriEntities bool
 	for i, roller := range config.GetRollers() {
 		toRollDesc := roller.ProtoReflect().Descriptor().Oneofs().ByName("to_roll")
 		field := roller.ProtoReflect().WhichOneof(toRollDesc)
@@ -73,8 +74,10 @@
 			toValidate = roller.GetCipdEnsureFile()
 		case "jiri_project":
 			toValidate = roller.GetJiriProject()
+			hasJiriEntities = true
 		case "jiri_packages":
 			toValidate = roller.GetJiriPackages()
+			hasJiriEntities = true
 		default:
 			log.Panicf("unknown to_roll type: %q", field.Name())
 		}
@@ -95,6 +98,11 @@
 			}
 		}
 	}
+	if hasJiriEntities && config.GetDefaultCheckoutJiriManifest() == "" {
+		return fmt.Errorf("default_checkout_jiri_manifest is required to enable jiri rollers")
+	} else if !hasJiriEntities && config.GetDefaultCheckoutJiriManifest() != "" {
+		return fmt.Errorf("default_checkout_jiri_manifest need not be set")
+	}
 	return nil
 }
 
diff --git a/cmd/roller-configurator/validate_test.go b/cmd/roller-configurator/validate_test.go
index b827581..b098856 100644
--- a/cmd/roller-configurator/validate_test.go
+++ b/cmd/roller-configurator/validate_test.go
@@ -94,6 +94,7 @@
 						},
 					},
 				},
+				DefaultCheckoutJiriManifest: "manifest",
 			},
 			files: filesWithJiriManifest,
 		},
@@ -115,6 +116,7 @@
 						}},
 					},
 				},
+				DefaultCheckoutJiriManifest: "manifest",
 			},
 			files: filesWithJiriManifest,
 		},
@@ -145,6 +147,14 @@
 		files  map[string]string
 	}{
 		{
+			name: "unnecessary default_checkout_jiri_manifest",
+			config: &proto.Config{
+				// Shouldn't be set unless `Rollers` contains any Jiri rollers.
+				DefaultCheckoutJiriManifest: "manifest",
+			},
+			err: "default_checkout_jiri_manifest need not be set",
+		},
+		{
 			name: "no entity to roll",
 			config: &proto.Config{
 				Rollers: []*proto.Roller{
@@ -350,6 +360,43 @@
 			files: filesWithJiriManifest,
 			err:   `no package "bad-package1" in manifest "path/to/jiri_manifest"`,
 		},
+		{
+			name: "jiri project roller with no default checkout manifest",
+			config: &proto.Config{
+				Rollers: []*proto.Roller{
+					{
+						ToRoll: &proto.Roller_JiriProject{JiriProject: &proto.JiriProject{
+							Manifest: "path/to/jiri_manifest",
+							Project:  "foo-project",
+						}},
+					},
+				},
+			},
+			files: filesWithJiriManifest,
+			err:   `default_checkout_jiri_manifest is required to enable jiri rollers`,
+		},
+		{
+			name: "jiri package roller with no default checkout manifest",
+			config: &proto.Config{
+				Rollers: []*proto.Roller{
+					{
+						ToRoll: &proto.Roller_JiriPackages{JiriPackages: &proto.JiriPackages{
+							Manifests: []*proto.JiriPackages_Manifest{
+								{
+									Path: "path/to/jiri_manifest",
+									Packages: []string{
+										"package1",
+										"package2",
+									},
+								},
+							},
+						}},
+					},
+				},
+			},
+			files: filesWithJiriManifest,
+			err:   `default_checkout_jiri_manifest is required to enable jiri rollers`,
+		},
 	}
 
 	for _, tc := range testCases {