From 404c7851ddb1f6a9a8d886870f66cd4ad251dfbd Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Thu, 29 Oct 2026 13:40:15 +0000 Subject: [PATCH 01/16] Remove the unused public MintActorCertificate API (#3427) `Control.MintActorCertificate` has no consumers: the feature that needed it was scoped out of GA. This removes the public RPC, its request/response types, signing code, validation, authorization rule, and docs, so a future consumer can define the API it needs. Actor JWT minting and the worker certificates used by atunnel remain in place. The internal `atelet.WorkerSupport.MintActorCertificate` is still used and forwards to `WorkerService.MintWorkerActorCertificate`. Fixes #3425 Breaking change: calls to the removed public RPC return `UNIMPLEMENTED`. Code referencing its generated client method or message types must remove those references before upgrading.
Certificate path retained for atunnel ```mermaid flowchart LR atunnel["atunnel"] -->|MintActorCertificate| atelet["atelet.WorkerSupport"] atelet -->|MintWorkerActorCertificate| worker["ateapi.WorkerService"] worker -->|Sign worker-for-actor certificate| ca["Actor identity CA pool"] ```
AI use: Prepared with Codex. - [x] Focused tests pass (see validation above) - [x] Docs updated --------- Signed-off-by: Eitan Yarmush --- api/ateapi/v1/ateapi.pb.go | 1062 +++++++---------- api/ateapi/v1/ateapi.proto | 43 - api/ateapi/v1/ateapi_grpc.pb.go | 50 - cmd/ateapi/internal/apivalidation/actor.go | 6 - .../internal/apivalidation/actor_test.go | 43 - .../apivalidation/zz_generated.validation.go | 104 -- cmd/ateapi/internal/authz/authz_util.go | 1 - cmd/ateapi/internal/authz/interceptor_test.go | 7 +- cmd/ateapi/internal/authz/model.fga | 1 - cmd/ateapi/internal/authz/model_test.fga.yaml | 6 - cmd/ateapi/internal/authz/registry.go | 3 - cmd/ateapi/internal/authz/registry_test.go | 12 - .../internal/controlapi/access_policy_test.go | 2 +- cmd/ateapi/internal/controlapi/actor.go | 90 -- cmd/ateapi/internal/controlapi/actor_test.go | 108 -- .../controlapi/functionaltest/common_test.go | 14 - cmd/ateapi/internal/controlapi/service.go | 4 - cmd/ateapi/main.go | 1 - docs/guides/authorization.md | 4 +- docs/reference/api-guide.md | 9 +- internal/proto/ateletpb/atelet.pb.go | 2 +- internal/proto/ateletpb/atelet.proto | 2 +- 22 files changed, 470 insertions(+), 1104 deletions(-) diff --git a/api/ateapi/v1/ateapi.pb.go b/api/ateapi/v1/ateapi.pb.go index 44de8a372c..aadebff8c9 100644 --- a/api/ateapi/v1/ateapi.pb.go +++ b/api/ateapi/v1/ateapi.pb.go @@ -5943,131 +5943,6 @@ func (x *MintActorJwtResponse) GetExpireTime() *timestamppb.Timestamp { return nil } -// Request message for MintActorCertificate. -type MintActorCertificateRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - // The actor for which the certificate should be issued. - // - // Must be a valid actor that currently exists according to the actor store. - // - // +k8s:required - Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` - // The UID of the actor --- used to guard against deletion and recreation of - // an actor with the same name. - // - // +k8s:required - // +k8s:format=k8s-uuid - ActorUid string `protobuf:"bytes,2,opt,name=actor_uid,json=actorUid,proto3" json:"actor_uid,omitempty"` - // Request contains DER encoded bytes of a x509 certificate signing request. - // The signer will ignore the contents of the CSR except to extract the - // subject public key. - // - // +k8s:required - // +k8s:maxBytes=16384 - CertificateSigningRequest []byte `protobuf:"bytes,3,opt,name=certificate_signing_request,json=certificateSigningRequest,proto3" json:"certificate_signing_request,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *MintActorCertificateRequest) Reset() { - *x = MintActorCertificateRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[78] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *MintActorCertificateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MintActorCertificateRequest) ProtoMessage() {} - -func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[78] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. -func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{78} -} - -func (x *MintActorCertificateRequest) GetActor() *ObjectRef { - if x != nil { - return x.Actor - } - return nil -} - -func (x *MintActorCertificateRequest) GetActorUid() string { - if x != nil { - return x.ActorUid - } - return "" -} - -func (x *MintActorCertificateRequest) GetCertificateSigningRequest() []byte { - if x != nil { - return x.CertificateSigningRequest - } - return nil -} - -// Response message for MintActorCertificate. -type MintActorCertificateResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Response contains a list of DER encoded certificates. The first entry is the - // leaf certificate, and any remaining entries are intermediates in - // leaf-to-root order. - ActorCertificates [][]byte `protobuf:"bytes,1,rep,name=actor_certificates,json=actorCertificates,proto3" json:"actor_certificates,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *MintActorCertificateResponse) Reset() { - *x = MintActorCertificateResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[79] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *MintActorCertificateResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MintActorCertificateResponse) ProtoMessage() {} - -func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[79] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. -func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{79} -} - -func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { - if x != nil { - return x.ActorCertificates - } - return nil -} - type ListTagsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The atespace to list tags from. Empty lists across all atespaces. @@ -6085,7 +5960,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[80] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6097,7 +5972,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[80] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6110,7 +5985,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{80} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{78} } func (x *ListTagsRequest) GetAtespace() string { @@ -6137,7 +6012,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[81] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6149,7 +6024,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[81] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6162,7 +6037,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{81} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{79} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -6207,7 +6082,7 @@ type CreateTagRequest struct { func (x *CreateTagRequest) Reset() { *x = CreateTagRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[82] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6219,7 +6094,7 @@ func (x *CreateTagRequest) String() string { func (*CreateTagRequest) ProtoMessage() {} func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[82] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6232,7 +6107,7 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{82} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{80} } func (x *CreateTagRequest) GetTag() *Tag { @@ -6262,7 +6137,7 @@ type UpdateTagRequest struct { func (x *UpdateTagRequest) Reset() { *x = UpdateTagRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[83] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6274,7 +6149,7 @@ func (x *UpdateTagRequest) String() string { func (*UpdateTagRequest) ProtoMessage() {} func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[83] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6287,7 +6162,7 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{83} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{81} } func (x *UpdateTagRequest) GetTag() *Tag { @@ -6312,7 +6187,7 @@ type DeleteTagRequest struct { func (x *DeleteTagRequest) Reset() { *x = DeleteTagRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[84] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6324,7 +6199,7 @@ func (x *DeleteTagRequest) String() string { func (*DeleteTagRequest) ProtoMessage() {} func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[84] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6337,7 +6212,7 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{84} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{82} } func (x *DeleteTagRequest) GetTag() *ObjectRef { @@ -6376,7 +6251,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[85] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6388,7 +6263,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[85] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6401,7 +6276,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{85} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{83} } func (x *DeleteOptions) GetVersion() int64 { @@ -6440,7 +6315,7 @@ type ListOptions struct { func (x *ListOptions) Reset() { *x = ListOptions{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[86] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6452,7 +6327,7 @@ func (x *ListOptions) String() string { func (*ListOptions) ProtoMessage() {} func (x *ListOptions) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[86] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6465,7 +6340,7 @@ func (x *ListOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use ListOptions.ProtoReflect.Descriptor instead. func (*ListOptions) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{86} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListOptions) GetPageSize() int32 { @@ -6501,7 +6376,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[87] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6513,7 +6388,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[87] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6526,7 +6401,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{87} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{85} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -6556,7 +6431,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[88] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6568,7 +6443,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[88] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6581,7 +6456,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{88} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{86} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -6610,7 +6485,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[89] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6622,7 +6497,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[89] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6635,7 +6510,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{89} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{87} } func (x *ListWorkersRequest) GetOptions() *ListOptions { @@ -6657,7 +6532,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[90] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6669,7 +6544,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[90] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6682,7 +6557,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{90} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{88} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -6712,7 +6587,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[91] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6724,7 +6599,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[91] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6737,7 +6612,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{91} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{89} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -6759,7 +6634,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[92] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6771,7 +6646,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[92] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6784,7 +6659,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{92} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{90} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -6819,7 +6694,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[93] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6831,7 +6706,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[93] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6844,7 +6719,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{93} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{91} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -6871,7 +6746,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[94] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6883,7 +6758,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[94] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6896,7 +6771,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{94} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{92} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -6926,7 +6801,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[95] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6938,7 +6813,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[95] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6951,7 +6826,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{95} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{93} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -6972,7 +6847,7 @@ type DrainWorkerResponse struct { func (x *DrainWorkerResponse) Reset() { *x = DrainWorkerResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[96] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6984,7 +6859,7 @@ func (x *DrainWorkerResponse) String() string { func (*DrainWorkerResponse) ProtoMessage() {} func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[96] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6997,7 +6872,7 @@ func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerResponse.ProtoReflect.Descriptor instead. func (*DrainWorkerResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{96} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{94} } func (x *DrainWorkerResponse) GetWorker() *Worker { @@ -7021,7 +6896,7 @@ type MarkWorkerAvailableRequest struct { func (x *MarkWorkerAvailableRequest) Reset() { *x = MarkWorkerAvailableRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[97] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7033,7 +6908,7 @@ func (x *MarkWorkerAvailableRequest) String() string { func (*MarkWorkerAvailableRequest) ProtoMessage() {} func (x *MarkWorkerAvailableRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[97] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7046,7 +6921,7 @@ func (x *MarkWorkerAvailableRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkWorkerAvailableRequest.ProtoReflect.Descriptor instead. func (*MarkWorkerAvailableRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{97} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{95} } func (x *MarkWorkerAvailableRequest) GetWorker() *ObjectRef { @@ -7067,7 +6942,7 @@ type MarkWorkerAvailableResponse struct { func (x *MarkWorkerAvailableResponse) Reset() { *x = MarkWorkerAvailableResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[98] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7079,7 +6954,7 @@ func (x *MarkWorkerAvailableResponse) String() string { func (*MarkWorkerAvailableResponse) ProtoMessage() {} func (x *MarkWorkerAvailableResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[98] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7092,7 +6967,7 @@ func (x *MarkWorkerAvailableResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkWorkerAvailableResponse.ProtoReflect.Descriptor instead. func (*MarkWorkerAvailableResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{98} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{96} } func (x *MarkWorkerAvailableResponse) GetWorker() *Worker { @@ -7116,7 +6991,7 @@ type MarkWorkerUnavailableRequest struct { func (x *MarkWorkerUnavailableRequest) Reset() { *x = MarkWorkerUnavailableRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[99] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7128,7 +7003,7 @@ func (x *MarkWorkerUnavailableRequest) String() string { func (*MarkWorkerUnavailableRequest) ProtoMessage() {} func (x *MarkWorkerUnavailableRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[99] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7141,7 +7016,7 @@ func (x *MarkWorkerUnavailableRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkWorkerUnavailableRequest.ProtoReflect.Descriptor instead. func (*MarkWorkerUnavailableRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{99} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{97} } func (x *MarkWorkerUnavailableRequest) GetWorker() *ObjectRef { @@ -7162,7 +7037,7 @@ type MarkWorkerUnavailableResponse struct { func (x *MarkWorkerUnavailableResponse) Reset() { *x = MarkWorkerUnavailableResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[100] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7174,7 +7049,7 @@ func (x *MarkWorkerUnavailableResponse) String() string { func (*MarkWorkerUnavailableResponse) ProtoMessage() {} func (x *MarkWorkerUnavailableResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[100] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7187,7 +7062,7 @@ func (x *MarkWorkerUnavailableResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkWorkerUnavailableResponse.ProtoReflect.Descriptor instead. func (*MarkWorkerUnavailableResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{100} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{98} } func (x *MarkWorkerUnavailableResponse) GetWorker() *Worker { @@ -7216,7 +7091,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[101] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7228,7 +7103,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[101] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7241,7 +7116,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{101} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{99} } func (x *ListActorsRequest) GetAtespace() string { @@ -7270,7 +7145,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[102] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7282,7 +7157,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[102] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7295,7 +7170,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{102} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{100} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -7383,7 +7258,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[103] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7395,7 +7270,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[103] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7408,7 +7283,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{103} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{101} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -7550,7 +7425,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[104] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7562,7 +7437,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[104] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7575,7 +7450,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{104} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{102} } func (x *WorkerStatus) GetState() WorkerState { @@ -7663,7 +7538,7 @@ type WorkerSandboxClass struct { func (x *WorkerSandboxClass) Reset() { *x = WorkerSandboxClass{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[105] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7675,7 +7550,7 @@ func (x *WorkerSandboxClass) String() string { func (*WorkerSandboxClass) ProtoMessage() {} func (x *WorkerSandboxClass) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[105] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7688,7 +7563,7 @@ func (x *WorkerSandboxClass) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerSandboxClass.ProtoReflect.Descriptor instead. func (*WorkerSandboxClass) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{105} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{103} } func (x *WorkerSandboxClass) GetSandboxClass() string { @@ -7739,7 +7614,7 @@ type WorkerSandboxRuntime struct { func (x *WorkerSandboxRuntime) Reset() { *x = WorkerSandboxRuntime{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[106] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7751,7 +7626,7 @@ func (x *WorkerSandboxRuntime) String() string { func (*WorkerSandboxRuntime) ProtoMessage() {} func (x *WorkerSandboxRuntime) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[106] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7764,7 +7639,7 @@ func (x *WorkerSandboxRuntime) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerSandboxRuntime.ProtoReflect.Descriptor instead. func (*WorkerSandboxRuntime) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{106} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{104} } func (x *WorkerSandboxRuntime) GetVersion() *VersionedSandboxCompat { @@ -7805,7 +7680,7 @@ type RuntimeOverhead struct { func (x *RuntimeOverhead) Reset() { *x = RuntimeOverhead{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[107] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7817,7 +7692,7 @@ func (x *RuntimeOverhead) String() string { func (*RuntimeOverhead) ProtoMessage() {} func (x *RuntimeOverhead) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[107] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7830,7 +7705,7 @@ func (x *RuntimeOverhead) ProtoReflect() protoreflect.Message { // Deprecated: Use RuntimeOverhead.ProtoReflect.Descriptor instead. func (*RuntimeOverhead) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{107} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{105} } func (x *RuntimeOverhead) GetMemoryBytes() int64 { @@ -7869,7 +7744,7 @@ type ActorSandboxRuntime struct { func (x *ActorSandboxRuntime) Reset() { *x = ActorSandboxRuntime{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[108] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7881,7 +7756,7 @@ func (x *ActorSandboxRuntime) String() string { func (*ActorSandboxRuntime) ProtoMessage() {} func (x *ActorSandboxRuntime) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[108] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7894,7 +7769,7 @@ func (x *ActorSandboxRuntime) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorSandboxRuntime.ProtoReflect.Descriptor instead. func (*ActorSandboxRuntime) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{108} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{106} } func (x *ActorSandboxRuntime) GetSandboxClass() string { @@ -7945,7 +7820,7 @@ type VersionedSandboxCompat struct { func (x *VersionedSandboxCompat) Reset() { *x = VersionedSandboxCompat{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[109] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7957,7 +7832,7 @@ func (x *VersionedSandboxCompat) String() string { func (*VersionedSandboxCompat) ProtoMessage() {} func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[109] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7970,7 +7845,7 @@ func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionedSandboxCompat.ProtoReflect.Descriptor instead. func (*VersionedSandboxCompat) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{109} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{107} } func (x *VersionedSandboxCompat) GetSchemaVersion() string { @@ -8006,7 +7881,7 @@ type AttributeEntry struct { func (x *AttributeEntry) Reset() { *x = AttributeEntry{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[110] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8018,7 +7893,7 @@ func (x *AttributeEntry) String() string { func (*AttributeEntry) ProtoMessage() {} func (x *AttributeEntry) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[110] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8031,7 +7906,7 @@ func (x *AttributeEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributeEntry.ProtoReflect.Descriptor instead. func (*AttributeEntry) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{110} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{108} } func (x *AttributeEntry) GetKey() string { @@ -8078,7 +7953,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[111] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8090,7 +7965,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[111] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8103,7 +7978,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{111} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{109} } func (x *WorkerResources) GetCpuMillicores() int64 { @@ -8159,7 +8034,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[112] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8171,7 +8046,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[112] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8184,7 +8059,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{112} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{110} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -8229,7 +8104,7 @@ type AcquireWorkerEpochRequest struct { func (x *AcquireWorkerEpochRequest) Reset() { *x = AcquireWorkerEpochRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[113] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8241,7 +8116,7 @@ func (x *AcquireWorkerEpochRequest) String() string { func (*AcquireWorkerEpochRequest) ProtoMessage() {} func (x *AcquireWorkerEpochRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[113] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8254,7 +8129,7 @@ func (x *AcquireWorkerEpochRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AcquireWorkerEpochRequest.ProtoReflect.Descriptor instead. func (*AcquireWorkerEpochRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{113} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{111} } func (x *AcquireWorkerEpochRequest) GetWorker() *ObjectRef { @@ -8274,7 +8149,7 @@ type AcquireWorkerEpochResponse struct { func (x *AcquireWorkerEpochResponse) Reset() { *x = AcquireWorkerEpochResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[114] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8286,7 +8161,7 @@ func (x *AcquireWorkerEpochResponse) String() string { func (*AcquireWorkerEpochResponse) ProtoMessage() {} func (x *AcquireWorkerEpochResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[114] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8299,7 +8174,7 @@ func (x *AcquireWorkerEpochResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AcquireWorkerEpochResponse.ProtoReflect.Descriptor instead. func (*AcquireWorkerEpochResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{114} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{112} } func (x *AcquireWorkerEpochResponse) GetEpoch() int64 { @@ -8342,7 +8217,7 @@ type RegisterWorkerRequest struct { func (x *RegisterWorkerRequest) Reset() { *x = RegisterWorkerRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[115] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8354,7 +8229,7 @@ func (x *RegisterWorkerRequest) String() string { func (*RegisterWorkerRequest) ProtoMessage() {} func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[115] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8367,7 +8242,7 @@ func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerRequest.ProtoReflect.Descriptor instead. func (*RegisterWorkerRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{115} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{113} } func (x *RegisterWorkerRequest) GetWorker() *ObjectRef { @@ -8408,7 +8283,7 @@ type RegisterWorkerResponse struct { func (x *RegisterWorkerResponse) Reset() { *x = RegisterWorkerResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[116] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8420,7 +8295,7 @@ func (x *RegisterWorkerResponse) String() string { func (*RegisterWorkerResponse) ProtoMessage() {} func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[116] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8433,7 +8308,7 @@ func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerResponse.ProtoReflect.Descriptor instead. func (*RegisterWorkerResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{116} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{114} } func (x *RegisterWorkerResponse) GetWorker() *Worker { @@ -8473,7 +8348,7 @@ type SetWorkerSandboxRuntimesRequest struct { func (x *SetWorkerSandboxRuntimesRequest) Reset() { *x = SetWorkerSandboxRuntimesRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[117] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8485,7 +8360,7 @@ func (x *SetWorkerSandboxRuntimesRequest) String() string { func (*SetWorkerSandboxRuntimesRequest) ProtoMessage() {} func (x *SetWorkerSandboxRuntimesRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[117] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8498,7 +8373,7 @@ func (x *SetWorkerSandboxRuntimesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerSandboxRuntimesRequest.ProtoReflect.Descriptor instead. func (*SetWorkerSandboxRuntimesRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{117} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{115} } func (x *SetWorkerSandboxRuntimesRequest) GetWorker() *ObjectRef { @@ -8532,7 +8407,7 @@ type SetWorkerSandboxRuntimesResponse struct { func (x *SetWorkerSandboxRuntimesResponse) Reset() { *x = SetWorkerSandboxRuntimesResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[118] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8544,7 +8419,7 @@ func (x *SetWorkerSandboxRuntimesResponse) String() string { func (*SetWorkerSandboxRuntimesResponse) ProtoMessage() {} func (x *SetWorkerSandboxRuntimesResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[118] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8557,7 +8432,7 @@ func (x *SetWorkerSandboxRuntimesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerSandboxRuntimesResponse.ProtoReflect.Descriptor instead. func (*SetWorkerSandboxRuntimesResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{118} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{116} } func (x *SetWorkerSandboxRuntimesResponse) GetWorker() *Worker { @@ -8604,7 +8479,7 @@ type MintWorkerActorCertificateRequest struct { func (x *MintWorkerActorCertificateRequest) Reset() { *x = MintWorkerActorCertificateRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[119] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8616,7 +8491,7 @@ func (x *MintWorkerActorCertificateRequest) String() string { func (*MintWorkerActorCertificateRequest) ProtoMessage() {} func (x *MintWorkerActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[119] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8629,7 +8504,7 @@ func (x *MintWorkerActorCertificateRequest) ProtoReflect() protoreflect.Message // Deprecated: Use MintWorkerActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintWorkerActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{119} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{117} } func (x *MintWorkerActorCertificateRequest) GetActor() *ObjectRef { @@ -8673,7 +8548,7 @@ type MintWorkerActorCertificateResponse struct { func (x *MintWorkerActorCertificateResponse) Reset() { *x = MintWorkerActorCertificateResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[120] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8685,7 +8560,7 @@ func (x *MintWorkerActorCertificateResponse) String() string { func (*MintWorkerActorCertificateResponse) ProtoMessage() {} func (x *MintWorkerActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[120] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8698,7 +8573,7 @@ func (x *MintWorkerActorCertificateResponse) ProtoReflect() protoreflect.Message // Deprecated: Use MintWorkerActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintWorkerActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{120} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{118} } func (x *MintWorkerActorCertificateResponse) GetActorCertificates() [][]byte { @@ -8739,7 +8614,7 @@ type MintWorkerActorJwtRequest struct { func (x *MintWorkerActorJwtRequest) Reset() { *x = MintWorkerActorJwtRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[121] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8751,7 +8626,7 @@ func (x *MintWorkerActorJwtRequest) String() string { func (*MintWorkerActorJwtRequest) ProtoMessage() {} func (x *MintWorkerActorJwtRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[121] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8764,7 +8639,7 @@ func (x *MintWorkerActorJwtRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintWorkerActorJwtRequest.ProtoReflect.Descriptor instead. func (*MintWorkerActorJwtRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{121} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{119} } func (x *MintWorkerActorJwtRequest) GetActor() *ObjectRef { @@ -8812,7 +8687,7 @@ type MintWorkerActorJwtResponse struct { func (x *MintWorkerActorJwtResponse) Reset() { *x = MintWorkerActorJwtResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[122] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8824,7 +8699,7 @@ func (x *MintWorkerActorJwtResponse) String() string { func (*MintWorkerActorJwtResponse) ProtoMessage() {} func (x *MintWorkerActorJwtResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[122] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8837,7 +8712,7 @@ func (x *MintWorkerActorJwtResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintWorkerActorJwtResponse.ProtoReflect.Descriptor instead. func (*MintWorkerActorJwtResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{122} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{120} } func (x *MintWorkerActorJwtResponse) GetActorJwt() string { @@ -8885,7 +8760,7 @@ type RequestActorSuspendRequest struct { func (x *RequestActorSuspendRequest) Reset() { *x = RequestActorSuspendRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[123] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8897,7 +8772,7 @@ func (x *RequestActorSuspendRequest) String() string { func (*RequestActorSuspendRequest) ProtoMessage() {} func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[123] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8910,7 +8785,7 @@ func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendRequest.ProtoReflect.Descriptor instead. func (*RequestActorSuspendRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{123} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{121} } func (x *RequestActorSuspendRequest) GetWorker() *ObjectRef { @@ -8944,7 +8819,7 @@ type RequestActorSuspendResponse struct { func (x *RequestActorSuspendResponse) Reset() { *x = RequestActorSuspendResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[124] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8956,7 +8831,7 @@ func (x *RequestActorSuspendResponse) String() string { func (*RequestActorSuspendResponse) ProtoMessage() {} func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[124] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8969,7 +8844,7 @@ func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendResponse.ProtoReflect.Descriptor instead. func (*RequestActorSuspendResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{124} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{122} } func (x *RequestActorSuspendResponse) GetActor() *Actor { @@ -9009,7 +8884,7 @@ type ReportActorCrashedRequest struct { func (x *ReportActorCrashedRequest) Reset() { *x = ReportActorCrashedRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[125] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9021,7 +8896,7 @@ func (x *ReportActorCrashedRequest) String() string { func (*ReportActorCrashedRequest) ProtoMessage() {} func (x *ReportActorCrashedRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[125] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9034,7 +8909,7 @@ func (x *ReportActorCrashedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportActorCrashedRequest.ProtoReflect.Descriptor instead. func (*ReportActorCrashedRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{125} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{123} } func (x *ReportActorCrashedRequest) GetWorker() *ObjectRef { @@ -9075,7 +8950,7 @@ type ReportActorCrashedResponse struct { func (x *ReportActorCrashedResponse) Reset() { *x = ReportActorCrashedResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[126] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9087,7 +8962,7 @@ func (x *ReportActorCrashedResponse) String() string { func (*ReportActorCrashedResponse) ProtoMessage() {} func (x *ReportActorCrashedResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[126] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9100,7 +8975,7 @@ func (x *ReportActorCrashedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportActorCrashedResponse.ProtoReflect.Descriptor instead. func (*ReportActorCrashedResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{126} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{124} } func (x *ReportActorCrashedResponse) GetActor() *Actor { @@ -9131,7 +9006,7 @@ type ReportActorSnapshotStateRequest struct { func (x *ReportActorSnapshotStateRequest) Reset() { *x = ReportActorSnapshotStateRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[127] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9143,7 +9018,7 @@ func (x *ReportActorSnapshotStateRequest) String() string { func (*ReportActorSnapshotStateRequest) ProtoMessage() {} func (x *ReportActorSnapshotStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[127] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9156,7 +9031,7 @@ func (x *ReportActorSnapshotStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportActorSnapshotStateRequest.ProtoReflect.Descriptor instead. func (*ReportActorSnapshotStateRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{127} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{125} } func (x *ReportActorSnapshotStateRequest) GetActor() *ObjectRef { @@ -9188,7 +9063,7 @@ type ReportActorSnapshotStateResponse struct { func (x *ReportActorSnapshotStateResponse) Reset() { *x = ReportActorSnapshotStateResponse{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[128] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9200,7 +9075,7 @@ func (x *ReportActorSnapshotStateResponse) String() string { func (*ReportActorSnapshotStateResponse) ProtoMessage() {} func (x *ReportActorSnapshotStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[128] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9213,7 +9088,7 @@ func (x *ReportActorSnapshotStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportActorSnapshotStateResponse.ProtoReflect.Descriptor instead. func (*ReportActorSnapshotStateResponse) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{128} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{126} } // ActorSnapshotState is what atelet holds for one Actor on its node. It @@ -9247,7 +9122,7 @@ type ActorSnapshotState struct { func (x *ActorSnapshotState) Reset() { *x = ActorSnapshotState{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[129] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9259,7 +9134,7 @@ func (x *ActorSnapshotState) String() string { func (*ActorSnapshotState) ProtoMessage() {} func (x *ActorSnapshotState) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[129] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9272,7 +9147,7 @@ func (x *ActorSnapshotState) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorSnapshotState.ProtoReflect.Descriptor instead. func (*ActorSnapshotState) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{129} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{127} } func (x *ActorSnapshotState) GetLatestLocal() *SnapshotReport { @@ -9344,7 +9219,7 @@ type SnapshotReport struct { func (x *SnapshotReport) Reset() { *x = SnapshotReport{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[130] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9356,7 +9231,7 @@ func (x *SnapshotReport) String() string { func (*SnapshotReport) ProtoMessage() {} func (x *SnapshotReport) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[130] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9369,7 +9244,7 @@ func (x *SnapshotReport) ProtoReflect() protoreflect.Message { // Deprecated: Use SnapshotReport.ProtoReflect.Descriptor instead. func (*SnapshotReport) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{130} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{128} } func (x *SnapshotReport) GetUuid() string { @@ -9439,7 +9314,7 @@ type AccessPolicy struct { func (x *AccessPolicy) Reset() { *x = AccessPolicy{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[131] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9451,7 +9326,7 @@ func (x *AccessPolicy) String() string { func (*AccessPolicy) ProtoMessage() {} func (x *AccessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[131] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9464,7 +9339,7 @@ func (x *AccessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use AccessPolicy.ProtoReflect.Descriptor instead. func (*AccessPolicy) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{131} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{129} } func (x *AccessPolicy) GetMetadata() *ResourceMetadata { @@ -9506,7 +9381,7 @@ type Binding struct { func (x *Binding) Reset() { *x = Binding{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[132] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9518,7 +9393,7 @@ func (x *Binding) String() string { func (*Binding) ProtoMessage() {} func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[132] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9531,7 +9406,7 @@ func (x *Binding) ProtoReflect() protoreflect.Message { // Deprecated: Use Binding.ProtoReflect.Descriptor instead. func (*Binding) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{132} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{130} } func (x *Binding) GetRole() string { @@ -9563,7 +9438,7 @@ type GetGlobalAccessPolicyRequest struct { func (x *GetGlobalAccessPolicyRequest) Reset() { *x = GetGlobalAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[133] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9575,7 +9450,7 @@ func (x *GetGlobalAccessPolicyRequest) String() string { func (*GetGlobalAccessPolicyRequest) ProtoMessage() {} func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[133] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9588,7 +9463,7 @@ func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{133} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{131} } func (x *GetGlobalAccessPolicyRequest) GetName() string { @@ -9612,7 +9487,7 @@ type CreateGlobalAccessPolicyRequest struct { func (x *CreateGlobalAccessPolicyRequest) Reset() { *x = CreateGlobalAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[134] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9624,7 +9499,7 @@ func (x *CreateGlobalAccessPolicyRequest) String() string { func (*CreateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[134] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9637,7 +9512,7 @@ func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{134} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{132} } func (x *CreateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -9661,7 +9536,7 @@ type UpdateGlobalAccessPolicyRequest struct { func (x *UpdateGlobalAccessPolicyRequest) Reset() { *x = UpdateGlobalAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[135] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9673,7 +9548,7 @@ func (x *UpdateGlobalAccessPolicyRequest) String() string { func (*UpdateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[135] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9686,7 +9561,7 @@ func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{135} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{133} } func (x *UpdateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -9716,7 +9591,7 @@ type GetAtespaceAccessPolicyRequest struct { func (x *GetAtespaceAccessPolicyRequest) Reset() { *x = GetAtespaceAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[136] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9728,7 +9603,7 @@ func (x *GetAtespaceAccessPolicyRequest) String() string { func (*GetAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[136] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9741,7 +9616,7 @@ func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{136} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{134} } func (x *GetAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9777,7 +9652,7 @@ type CreateAtespaceAccessPolicyRequest struct { func (x *CreateAtespaceAccessPolicyRequest) Reset() { *x = CreateAtespaceAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[137] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9789,7 +9664,7 @@ func (x *CreateAtespaceAccessPolicyRequest) String() string { func (*CreateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[137] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9802,7 +9677,7 @@ func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{137} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{135} } func (x *CreateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9838,7 +9713,7 @@ type UpdateAtespaceAccessPolicyRequest struct { func (x *UpdateAtespaceAccessPolicyRequest) Reset() { *x = UpdateAtespaceAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[138] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9850,7 +9725,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) String() string { func (*UpdateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[138] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9863,7 +9738,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{138} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{136} } func (x *UpdateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9904,7 +9779,7 @@ type DeleteAtespaceAccessPolicyRequest struct { func (x *DeleteAtespaceAccessPolicyRequest) Reset() { *x = DeleteAtespaceAccessPolicyRequest{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[139] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9916,7 +9791,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) String() string { func (*DeleteAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[139] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9929,7 +9804,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeleteAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{139} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{137} } func (x *DeleteAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9975,7 +9850,7 @@ type ResourceAnnotation struct { func (x *ResourceAnnotation) Reset() { *x = ResourceAnnotation{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[140] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9987,7 +9862,7 @@ func (x *ResourceAnnotation) String() string { func (*ResourceAnnotation) ProtoMessage() {} func (x *ResourceAnnotation) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[140] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10000,7 +9875,7 @@ func (x *ResourceAnnotation) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceAnnotation.ProtoReflect.Descriptor instead. func (*ResourceAnnotation) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{140} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{138} } func (x *ResourceAnnotation) GetParents() []string { @@ -10043,7 +9918,7 @@ type MethodAnnotation struct { func (x *MethodAnnotation) Reset() { *x = MethodAnnotation{} - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[141] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10055,7 +9930,7 @@ func (x *MethodAnnotation) String() string { func (*MethodAnnotation) ProtoMessage() {} func (x *MethodAnnotation) ProtoReflect() protoreflect.Message { - mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[141] + mi := &file_api_ateapi_v1_ateapi_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10068,7 +9943,7 @@ func (x *MethodAnnotation) ProtoReflect() protoreflect.Message { // Deprecated: Use MethodAnnotation.ProtoReflect.Descriptor instead. func (*MethodAnnotation) Descriptor() ([]byte, []int) { - return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{141} + return file_api_ateapi_v1_ateapi_proto_rawDescGZIP(), []int{139} } func (x *MethodAnnotation) GetResource() string { @@ -10400,13 +10275,7 @@ const file_api_ateapi_v1_ateapi_proto_rawDesc = "" + "\x14MintActorJwtResponse\x12 \n" + "\tactor_jwt\x18\x01 \x01(\tB\x03\x80\x01\x01R\bactorJwt\x12;\n" + "\vexpire_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\n" + - "expireTime\"\xb0\x01\n" + - "\x1bMintActorCertificateRequest\x124\n" + - "\x05actor\x18\x01 \x01(\v2\x1e.substrate.ateapi.v1.ObjectRefR\x05actor\x12\x1b\n" + - "\tactor_uid\x18\x02 \x01(\tR\bactorUid\x12>\n" + - "\x1bcertificate_signing_request\x18\x03 \x01(\fR\x19certificateSigningRequest\"M\n" + - "\x1cMintActorCertificateResponse\x12-\n" + - "\x12actor_certificates\x18\x01 \x03(\fR\x11actorCertificates\"i\n" + + "expireTime\"i\n" + "\x0fListTagsRequest\x12\x1a\n" + "\batespace\x18\x01 \x01(\tR\batespace\x12:\n" + "\aoptions\x18\x02 \x01(\v2 .substrate.ateapi.v1.ListOptionsR\aoptions\"h\n" + @@ -10666,7 +10535,7 @@ const file_api_ateapi_v1_ateapi_proto_rawDesc = "" + "\x05Scope\x12\x15\n" + "\x11SCOPE_UNSPECIFIED\x10\x00\x12\x12\n" + "\x0eSCOPE_ATESPACE\x10\x01\x12\x10\n" + - "\fSCOPE_GLOBAL\x10\x022\xd5'\n" + + "\fSCOPE_GLOBAL\x10\x022\xca&\n" + "\aControl\x12Y\n" + "\bGetActor\x12$.substrate.ateapi.v1.GetActorRequest\x1a\x1a.substrate.ateapi.v1.Actor\"\v\x82\xb5\x18\a\n" + "\x05Actor\x12_\n" + @@ -10691,8 +10560,6 @@ const file_api_ateapi_v1_ateapi_proto_rawDesc = "" + "\x17DeleteActorEgressPolicy\x123.substrate.ateapi.v1.DeleteActorEgressPolicyRequest\x1a!.substrate.ateapi.v1.EgressPolicy\"\x12\x82\xb5\x18\x0e\n" + "\fEgressPolicy\x12p\n" + "\fMintActorJwt\x12(.substrate.ateapi.v1.MintActorJwtRequest\x1a).substrate.ateapi.v1.MintActorJwtResponse\"\v\x82\xb5\x18\a\n" + - "\x05Actor\x12\x88\x01\n" + - "\x14MintActorCertificate\x120.substrate.ateapi.v1.MintActorCertificateRequest\x1a1.substrate.ateapi.v1.MintActorCertificateResponse\"\v\x82\xb5\x18\a\n" + "\x05Actor\x12W\n" + "\tCreateTag\x12%.substrate.ateapi.v1.CreateTagRequest\x1a\x18.substrate.ateapi.v1.Tag\"\t\x82\xb5\x18\x05\n" + "\x03Tag\x12Q\n" + @@ -10784,7 +10651,7 @@ func file_api_ateapi_v1_ateapi_proto_rawDescGZIP() []byte { } var file_api_ateapi_v1_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_api_ateapi_v1_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 145) +var file_api_ateapi_v1_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 143) var file_api_ateapi_v1_ateapi_proto_goTypes = []any{ (SnapshotOwner)(0), // 0: substrate.ateapi.v1.SnapshotOwner (SnapshotStorageState)(0), // 1: substrate.ateapi.v1.SnapshotStorageState @@ -10874,76 +10741,74 @@ var file_api_ateapi_v1_ateapi_proto_goTypes = []any{ (*GetTagRequest)(nil), // 85: substrate.ateapi.v1.GetTagRequest (*MintActorJwtRequest)(nil), // 86: substrate.ateapi.v1.MintActorJwtRequest (*MintActorJwtResponse)(nil), // 87: substrate.ateapi.v1.MintActorJwtResponse - (*MintActorCertificateRequest)(nil), // 88: substrate.ateapi.v1.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 89: substrate.ateapi.v1.MintActorCertificateResponse - (*ListTagsRequest)(nil), // 90: substrate.ateapi.v1.ListTagsRequest - (*ListTagsResponse)(nil), // 91: substrate.ateapi.v1.ListTagsResponse - (*CreateTagRequest)(nil), // 92: substrate.ateapi.v1.CreateTagRequest - (*UpdateTagRequest)(nil), // 93: substrate.ateapi.v1.UpdateTagRequest - (*DeleteTagRequest)(nil), // 94: substrate.ateapi.v1.DeleteTagRequest - (*DeleteOptions)(nil), // 95: substrate.ateapi.v1.DeleteOptions - (*ListOptions)(nil), // 96: substrate.ateapi.v1.ListOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 97: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 98: substrate.ateapi.v1.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 99: substrate.ateapi.v1.ListWorkersRequest - (*ListWorkersResponse)(nil), // 100: substrate.ateapi.v1.ListWorkersResponse - (*GetWorkerRequest)(nil), // 101: substrate.ateapi.v1.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 102: substrate.ateapi.v1.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 103: substrate.ateapi.v1.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 104: substrate.ateapi.v1.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 105: substrate.ateapi.v1.DrainWorkerRequest - (*DrainWorkerResponse)(nil), // 106: substrate.ateapi.v1.DrainWorkerResponse - (*MarkWorkerAvailableRequest)(nil), // 107: substrate.ateapi.v1.MarkWorkerAvailableRequest - (*MarkWorkerAvailableResponse)(nil), // 108: substrate.ateapi.v1.MarkWorkerAvailableResponse - (*MarkWorkerUnavailableRequest)(nil), // 109: substrate.ateapi.v1.MarkWorkerUnavailableRequest - (*MarkWorkerUnavailableResponse)(nil), // 110: substrate.ateapi.v1.MarkWorkerUnavailableResponse - (*ListActorsRequest)(nil), // 111: substrate.ateapi.v1.ListActorsRequest - (*ListActorsResponse)(nil), // 112: substrate.ateapi.v1.ListActorsResponse - (*Worker)(nil), // 113: substrate.ateapi.v1.Worker - (*WorkerStatus)(nil), // 114: substrate.ateapi.v1.WorkerStatus - (*WorkerSandboxClass)(nil), // 115: substrate.ateapi.v1.WorkerSandboxClass - (*WorkerSandboxRuntime)(nil), // 116: substrate.ateapi.v1.WorkerSandboxRuntime - (*RuntimeOverhead)(nil), // 117: substrate.ateapi.v1.RuntimeOverhead - (*ActorSandboxRuntime)(nil), // 118: substrate.ateapi.v1.ActorSandboxRuntime - (*VersionedSandboxCompat)(nil), // 119: substrate.ateapi.v1.VersionedSandboxCompat - (*AttributeEntry)(nil), // 120: substrate.ateapi.v1.AttributeEntry - (*WorkerResources)(nil), // 121: substrate.ateapi.v1.WorkerResources - (*ActorAssignment)(nil), // 122: substrate.ateapi.v1.ActorAssignment - (*AcquireWorkerEpochRequest)(nil), // 123: substrate.ateapi.v1.AcquireWorkerEpochRequest - (*AcquireWorkerEpochResponse)(nil), // 124: substrate.ateapi.v1.AcquireWorkerEpochResponse - (*RegisterWorkerRequest)(nil), // 125: substrate.ateapi.v1.RegisterWorkerRequest - (*RegisterWorkerResponse)(nil), // 126: substrate.ateapi.v1.RegisterWorkerResponse - (*SetWorkerSandboxRuntimesRequest)(nil), // 127: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest - (*SetWorkerSandboxRuntimesResponse)(nil), // 128: substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse - (*MintWorkerActorCertificateRequest)(nil), // 129: substrate.ateapi.v1.MintWorkerActorCertificateRequest - (*MintWorkerActorCertificateResponse)(nil), // 130: substrate.ateapi.v1.MintWorkerActorCertificateResponse - (*MintWorkerActorJwtRequest)(nil), // 131: substrate.ateapi.v1.MintWorkerActorJwtRequest - (*MintWorkerActorJwtResponse)(nil), // 132: substrate.ateapi.v1.MintWorkerActorJwtResponse - (*RequestActorSuspendRequest)(nil), // 133: substrate.ateapi.v1.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 134: substrate.ateapi.v1.RequestActorSuspendResponse - (*ReportActorCrashedRequest)(nil), // 135: substrate.ateapi.v1.ReportActorCrashedRequest - (*ReportActorCrashedResponse)(nil), // 136: substrate.ateapi.v1.ReportActorCrashedResponse - (*ReportActorSnapshotStateRequest)(nil), // 137: substrate.ateapi.v1.ReportActorSnapshotStateRequest - (*ReportActorSnapshotStateResponse)(nil), // 138: substrate.ateapi.v1.ReportActorSnapshotStateResponse - (*ActorSnapshotState)(nil), // 139: substrate.ateapi.v1.ActorSnapshotState - (*SnapshotReport)(nil), // 140: substrate.ateapi.v1.SnapshotReport - (*AccessPolicy)(nil), // 141: substrate.ateapi.v1.AccessPolicy - (*Binding)(nil), // 142: substrate.ateapi.v1.Binding - (*GetGlobalAccessPolicyRequest)(nil), // 143: substrate.ateapi.v1.GetGlobalAccessPolicyRequest - (*CreateGlobalAccessPolicyRequest)(nil), // 144: substrate.ateapi.v1.CreateGlobalAccessPolicyRequest - (*UpdateGlobalAccessPolicyRequest)(nil), // 145: substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest - (*GetAtespaceAccessPolicyRequest)(nil), // 146: substrate.ateapi.v1.GetAtespaceAccessPolicyRequest - (*CreateAtespaceAccessPolicyRequest)(nil), // 147: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest - (*UpdateAtespaceAccessPolicyRequest)(nil), // 148: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest - (*DeleteAtespaceAccessPolicyRequest)(nil), // 149: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest - (*ResourceAnnotation)(nil), // 150: substrate.ateapi.v1.ResourceAnnotation - (*MethodAnnotation)(nil), // 151: substrate.ateapi.v1.MethodAnnotation - nil, // 152: substrate.ateapi.v1.Selector.MatchLabelsEntry - nil, // 153: substrate.ateapi.v1.ExternalVolumeStatus.VolumeContextEntry - nil, // 154: substrate.ateapi.v1.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 155: google.protobuf.Timestamp - (*descriptorpb.MessageOptions)(nil), // 156: google.protobuf.MessageOptions - (*descriptorpb.MethodOptions)(nil), // 157: google.protobuf.MethodOptions + (*ListTagsRequest)(nil), // 88: substrate.ateapi.v1.ListTagsRequest + (*ListTagsResponse)(nil), // 89: substrate.ateapi.v1.ListTagsResponse + (*CreateTagRequest)(nil), // 90: substrate.ateapi.v1.CreateTagRequest + (*UpdateTagRequest)(nil), // 91: substrate.ateapi.v1.UpdateTagRequest + (*DeleteTagRequest)(nil), // 92: substrate.ateapi.v1.DeleteTagRequest + (*DeleteOptions)(nil), // 93: substrate.ateapi.v1.DeleteOptions + (*ListOptions)(nil), // 94: substrate.ateapi.v1.ListOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 95: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 96: substrate.ateapi.v1.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 97: substrate.ateapi.v1.ListWorkersRequest + (*ListWorkersResponse)(nil), // 98: substrate.ateapi.v1.ListWorkersResponse + (*GetWorkerRequest)(nil), // 99: substrate.ateapi.v1.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 100: substrate.ateapi.v1.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 101: substrate.ateapi.v1.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 102: substrate.ateapi.v1.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 103: substrate.ateapi.v1.DrainWorkerRequest + (*DrainWorkerResponse)(nil), // 104: substrate.ateapi.v1.DrainWorkerResponse + (*MarkWorkerAvailableRequest)(nil), // 105: substrate.ateapi.v1.MarkWorkerAvailableRequest + (*MarkWorkerAvailableResponse)(nil), // 106: substrate.ateapi.v1.MarkWorkerAvailableResponse + (*MarkWorkerUnavailableRequest)(nil), // 107: substrate.ateapi.v1.MarkWorkerUnavailableRequest + (*MarkWorkerUnavailableResponse)(nil), // 108: substrate.ateapi.v1.MarkWorkerUnavailableResponse + (*ListActorsRequest)(nil), // 109: substrate.ateapi.v1.ListActorsRequest + (*ListActorsResponse)(nil), // 110: substrate.ateapi.v1.ListActorsResponse + (*Worker)(nil), // 111: substrate.ateapi.v1.Worker + (*WorkerStatus)(nil), // 112: substrate.ateapi.v1.WorkerStatus + (*WorkerSandboxClass)(nil), // 113: substrate.ateapi.v1.WorkerSandboxClass + (*WorkerSandboxRuntime)(nil), // 114: substrate.ateapi.v1.WorkerSandboxRuntime + (*RuntimeOverhead)(nil), // 115: substrate.ateapi.v1.RuntimeOverhead + (*ActorSandboxRuntime)(nil), // 116: substrate.ateapi.v1.ActorSandboxRuntime + (*VersionedSandboxCompat)(nil), // 117: substrate.ateapi.v1.VersionedSandboxCompat + (*AttributeEntry)(nil), // 118: substrate.ateapi.v1.AttributeEntry + (*WorkerResources)(nil), // 119: substrate.ateapi.v1.WorkerResources + (*ActorAssignment)(nil), // 120: substrate.ateapi.v1.ActorAssignment + (*AcquireWorkerEpochRequest)(nil), // 121: substrate.ateapi.v1.AcquireWorkerEpochRequest + (*AcquireWorkerEpochResponse)(nil), // 122: substrate.ateapi.v1.AcquireWorkerEpochResponse + (*RegisterWorkerRequest)(nil), // 123: substrate.ateapi.v1.RegisterWorkerRequest + (*RegisterWorkerResponse)(nil), // 124: substrate.ateapi.v1.RegisterWorkerResponse + (*SetWorkerSandboxRuntimesRequest)(nil), // 125: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest + (*SetWorkerSandboxRuntimesResponse)(nil), // 126: substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse + (*MintWorkerActorCertificateRequest)(nil), // 127: substrate.ateapi.v1.MintWorkerActorCertificateRequest + (*MintWorkerActorCertificateResponse)(nil), // 128: substrate.ateapi.v1.MintWorkerActorCertificateResponse + (*MintWorkerActorJwtRequest)(nil), // 129: substrate.ateapi.v1.MintWorkerActorJwtRequest + (*MintWorkerActorJwtResponse)(nil), // 130: substrate.ateapi.v1.MintWorkerActorJwtResponse + (*RequestActorSuspendRequest)(nil), // 131: substrate.ateapi.v1.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 132: substrate.ateapi.v1.RequestActorSuspendResponse + (*ReportActorCrashedRequest)(nil), // 133: substrate.ateapi.v1.ReportActorCrashedRequest + (*ReportActorCrashedResponse)(nil), // 134: substrate.ateapi.v1.ReportActorCrashedResponse + (*ReportActorSnapshotStateRequest)(nil), // 135: substrate.ateapi.v1.ReportActorSnapshotStateRequest + (*ReportActorSnapshotStateResponse)(nil), // 136: substrate.ateapi.v1.ReportActorSnapshotStateResponse + (*ActorSnapshotState)(nil), // 137: substrate.ateapi.v1.ActorSnapshotState + (*SnapshotReport)(nil), // 138: substrate.ateapi.v1.SnapshotReport + (*AccessPolicy)(nil), // 139: substrate.ateapi.v1.AccessPolicy + (*Binding)(nil), // 140: substrate.ateapi.v1.Binding + (*GetGlobalAccessPolicyRequest)(nil), // 141: substrate.ateapi.v1.GetGlobalAccessPolicyRequest + (*CreateGlobalAccessPolicyRequest)(nil), // 142: substrate.ateapi.v1.CreateGlobalAccessPolicyRequest + (*UpdateGlobalAccessPolicyRequest)(nil), // 143: substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest + (*GetAtespaceAccessPolicyRequest)(nil), // 144: substrate.ateapi.v1.GetAtespaceAccessPolicyRequest + (*CreateAtespaceAccessPolicyRequest)(nil), // 145: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest + (*UpdateAtespaceAccessPolicyRequest)(nil), // 146: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest + (*DeleteAtespaceAccessPolicyRequest)(nil), // 147: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest + (*ResourceAnnotation)(nil), // 148: substrate.ateapi.v1.ResourceAnnotation + (*MethodAnnotation)(nil), // 149: substrate.ateapi.v1.MethodAnnotation + nil, // 150: substrate.ateapi.v1.Selector.MatchLabelsEntry + nil, // 151: substrate.ateapi.v1.ExternalVolumeStatus.VolumeContextEntry + nil, // 152: substrate.ateapi.v1.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 153: google.protobuf.Timestamp + (*descriptorpb.MessageOptions)(nil), // 154: google.protobuf.MessageOptions + (*descriptorpb.MethodOptions)(nil), // 155: google.protobuf.MethodOptions } var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 1, // 0: substrate.ateapi.v1.SnapshotStorage.state:type_name -> substrate.ateapi.v1.SnapshotStorageState @@ -10951,13 +10816,13 @@ var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 0, // 2: substrate.ateapi.v1.Snapshot.owner:type_name -> substrate.ateapi.v1.SnapshotOwner 2, // 3: substrate.ateapi.v1.Snapshot.fidelity:type_name -> substrate.ateapi.v1.SnapshotFidelity 11, // 4: substrate.ateapi.v1.Snapshot.durable_snapshot:type_name -> substrate.ateapi.v1.SnapshotStorage - 118, // 5: substrate.ateapi.v1.Snapshot.sandbox_runtime:type_name -> substrate.ateapi.v1.ActorSandboxRuntime - 152, // 6: substrate.ateapi.v1.Selector.match_labels:type_name -> substrate.ateapi.v1.Selector.MatchLabelsEntry - 155, // 7: substrate.ateapi.v1.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 155, // 8: substrate.ateapi.v1.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 155, // 9: substrate.ateapi.v1.ResourceMetadata.delete_time:type_name -> google.protobuf.Timestamp + 116, // 5: substrate.ateapi.v1.Snapshot.sandbox_runtime:type_name -> substrate.ateapi.v1.ActorSandboxRuntime + 150, // 6: substrate.ateapi.v1.Selector.match_labels:type_name -> substrate.ateapi.v1.Selector.MatchLabelsEntry + 153, // 7: substrate.ateapi.v1.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 153, // 8: substrate.ateapi.v1.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 153, // 9: substrate.ateapi.v1.ResourceMetadata.delete_time:type_name -> google.protobuf.Timestamp 16, // 10: substrate.ateapi.v1.ExternalVolumes.volumes:type_name -> substrate.ateapi.v1.ExternalVolumeStatus - 153, // 11: substrate.ateapi.v1.ExternalVolumeStatus.volume_context:type_name -> substrate.ateapi.v1.ExternalVolumeStatus.VolumeContextEntry + 151, // 11: substrate.ateapi.v1.ExternalVolumeStatus.volume_context:type_name -> substrate.ateapi.v1.ExternalVolumeStatus.VolumeContextEntry 14, // 12: substrate.ateapi.v1.Actor.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata 35, // 13: substrate.ateapi.v1.Actor.actor_template:type_name -> substrate.ateapi.v1.ObjectRef 13, // 14: substrate.ateapi.v1.Actor.worker_selector:type_name -> substrate.ateapi.v1.Selector @@ -10982,9 +10847,9 @@ var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 15, // 33: substrate.ateapi.v1.ActorStatus.external_volumes:type_name -> substrate.ateapi.v1.ExternalVolumes 30, // 34: substrate.ateapi.v1.ActorStatus.crash:type_name -> substrate.ateapi.v1.ActorCrash 12, // 35: substrate.ateapi.v1.ActorStatus.snapshots:type_name -> substrate.ateapi.v1.Snapshot - 155, // 36: substrate.ateapi.v1.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp + 153, // 36: substrate.ateapi.v1.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp 35, // 37: substrate.ateapi.v1.WorkerAssignment.worker:type_name -> substrate.ateapi.v1.ObjectRef - 118, // 38: substrate.ateapi.v1.WorkerAssignment.sandbox_runtime:type_name -> substrate.ateapi.v1.ActorSandboxRuntime + 116, // 38: substrate.ateapi.v1.WorkerAssignment.sandbox_runtime:type_name -> substrate.ateapi.v1.ActorSandboxRuntime 12, // 39: substrate.ateapi.v1.TagStatus.snapshot:type_name -> substrate.ateapi.v1.Snapshot 14, // 40: substrate.ateapi.v1.Tag.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata 32, // 41: substrate.ateapi.v1.Tag.status:type_name -> substrate.ateapi.v1.TagStatus @@ -11001,7 +10866,7 @@ var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 40, // 52: substrate.ateapi.v1.ActorTemplate.status:type_name -> substrate.ateapi.v1.ActorTemplateStatus 38, // 53: substrate.ateapi.v1.ResourceRequirements.limits:type_name -> substrate.ateapi.v1.Resources 35, // 54: substrate.ateapi.v1.GoldenSnapshotStatus.golden_tag:type_name -> substrate.ateapi.v1.ObjectRef - 155, // 55: substrate.ateapi.v1.GoldenSnapshotStatus.snapshot_time:type_name -> google.protobuf.Timestamp + 153, // 55: substrate.ateapi.v1.GoldenSnapshotStatus.snapshot_time:type_name -> google.protobuf.Timestamp 39, // 56: substrate.ateapi.v1.ActorTemplateStatus.golden_snapshot_status:type_name -> substrate.ateapi.v1.GoldenSnapshotStatus 2, // 57: substrate.ateapi.v1.SnapshotConfig.preferred_fidelity:type_name -> substrate.ateapi.v1.SnapshotFidelity 42, // 58: substrate.ateapi.v1.SnapshotConfig.golden_snapshot_config:type_name -> substrate.ateapi.v1.GoldenSnapshotConfig @@ -11025,16 +10890,16 @@ var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 6, // 76: substrate.ateapi.v1.ActorMetadataItem.field:type_name -> substrate.ateapi.v1.ActorMetadataField 34, // 77: substrate.ateapi.v1.CreateAtespaceRequest.atespace:type_name -> substrate.ateapi.v1.Atespace 35, // 78: substrate.ateapi.v1.GetAtespaceRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 96, // 79: substrate.ateapi.v1.ListAtespacesRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 94, // 79: substrate.ateapi.v1.ListAtespacesRequest.options:type_name -> substrate.ateapi.v1.ListOptions 34, // 80: substrate.ateapi.v1.ListAtespacesResponse.atespaces:type_name -> substrate.ateapi.v1.Atespace 35, // 81: substrate.ateapi.v1.DeleteAtespaceRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 82: substrate.ateapi.v1.DeleteAtespaceRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 93, // 82: substrate.ateapi.v1.DeleteAtespaceRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions 36, // 83: substrate.ateapi.v1.CreateActorTemplateRequest.actor_template:type_name -> substrate.ateapi.v1.ActorTemplate 35, // 84: substrate.ateapi.v1.GetActorTemplateRequest.actor_template:type_name -> substrate.ateapi.v1.ObjectRef - 96, // 85: substrate.ateapi.v1.ListActorTemplatesRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 94, // 85: substrate.ateapi.v1.ListActorTemplatesRequest.options:type_name -> substrate.ateapi.v1.ListOptions 36, // 86: substrate.ateapi.v1.ListActorTemplatesResponse.actor_templates:type_name -> substrate.ateapi.v1.ActorTemplate 35, // 87: substrate.ateapi.v1.DeleteActorTemplateRequest.actor_template:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 88: substrate.ateapi.v1.DeleteActorTemplateRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 93, // 88: substrate.ateapi.v1.DeleteActorTemplateRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions 35, // 89: substrate.ateapi.v1.GetActorRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef 17, // 90: substrate.ateapi.v1.CreateActorRequest.actor:type_name -> substrate.ateapi.v1.Actor 17, // 91: substrate.ateapi.v1.UpdateActorRequest.actor:type_name -> substrate.ateapi.v1.Actor @@ -11047,208 +10912,205 @@ var file_api_ateapi_v1_ateapi_proto_depIdxs = []int32{ 35, // 98: substrate.ateapi.v1.RevertActorRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef 17, // 99: substrate.ateapi.v1.RevertActorResponse.actor:type_name -> substrate.ateapi.v1.Actor 35, // 100: substrate.ateapi.v1.DeleteActorRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 101: substrate.ateapi.v1.DeleteActorRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 93, // 101: substrate.ateapi.v1.DeleteActorRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions 35, // 102: substrate.ateapi.v1.GetActorEgressPolicyRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef 35, // 103: substrate.ateapi.v1.CreateActorEgressPolicyRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef 18, // 104: substrate.ateapi.v1.CreateActorEgressPolicyRequest.egress_policy:type_name -> substrate.ateapi.v1.EgressPolicy 35, // 105: substrate.ateapi.v1.UpdateActorEgressPolicyRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef 18, // 106: substrate.ateapi.v1.UpdateActorEgressPolicyRequest.egress_policy:type_name -> substrate.ateapi.v1.EgressPolicy 35, // 107: substrate.ateapi.v1.DeleteActorEgressPolicyRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 108: substrate.ateapi.v1.DeleteActorEgressPolicyRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 93, // 108: substrate.ateapi.v1.DeleteActorEgressPolicyRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions 35, // 109: substrate.ateapi.v1.GetTagRequest.tag:type_name -> substrate.ateapi.v1.ObjectRef 35, // 110: substrate.ateapi.v1.MintActorJwtRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 155, // 111: substrate.ateapi.v1.MintActorJwtResponse.expire_time:type_name -> google.protobuf.Timestamp - 35, // 112: substrate.ateapi.v1.MintActorCertificateRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 96, // 113: substrate.ateapi.v1.ListTagsRequest.options:type_name -> substrate.ateapi.v1.ListOptions - 33, // 114: substrate.ateapi.v1.ListTagsResponse.tags:type_name -> substrate.ateapi.v1.Tag - 33, // 115: substrate.ateapi.v1.CreateTagRequest.tag:type_name -> substrate.ateapi.v1.Tag - 33, // 116: substrate.ateapi.v1.UpdateTagRequest.tag:type_name -> substrate.ateapi.v1.Tag - 35, // 117: substrate.ateapi.v1.DeleteTagRequest.tag:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 118: substrate.ateapi.v1.DeleteTagRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions - 35, // 119: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 96, // 120: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest.options:type_name -> substrate.ateapi.v1.ListOptions - 122, // 121: substrate.ateapi.v1.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> substrate.ateapi.v1.ActorAssignment - 96, // 122: substrate.ateapi.v1.ListWorkersRequest.options:type_name -> substrate.ateapi.v1.ListOptions - 113, // 123: substrate.ateapi.v1.ListWorkersResponse.workers:type_name -> substrate.ateapi.v1.Worker - 35, // 124: substrate.ateapi.v1.GetWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 113, // 125: substrate.ateapi.v1.CreateWorkerRequest.worker:type_name -> substrate.ateapi.v1.Worker - 113, // 126: substrate.ateapi.v1.UpdateWorkerRequest.worker:type_name -> substrate.ateapi.v1.Worker - 35, // 127: substrate.ateapi.v1.DeleteWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 128: substrate.ateapi.v1.DeleteWorkerRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions - 35, // 129: substrate.ateapi.v1.DrainWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 113, // 130: substrate.ateapi.v1.DrainWorkerResponse.worker:type_name -> substrate.ateapi.v1.Worker - 35, // 131: substrate.ateapi.v1.MarkWorkerAvailableRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 113, // 132: substrate.ateapi.v1.MarkWorkerAvailableResponse.worker:type_name -> substrate.ateapi.v1.Worker - 35, // 133: substrate.ateapi.v1.MarkWorkerUnavailableRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 113, // 134: substrate.ateapi.v1.MarkWorkerUnavailableResponse.worker:type_name -> substrate.ateapi.v1.Worker - 96, // 135: substrate.ateapi.v1.ListActorsRequest.options:type_name -> substrate.ateapi.v1.ListOptions - 17, // 136: substrate.ateapi.v1.ListActorsResponse.actors:type_name -> substrate.ateapi.v1.Actor - 14, // 137: substrate.ateapi.v1.Worker.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata - 154, // 138: substrate.ateapi.v1.Worker.labels:type_name -> substrate.ateapi.v1.Worker.LabelsEntry - 114, // 139: substrate.ateapi.v1.Worker.status:type_name -> substrate.ateapi.v1.WorkerStatus - 8, // 140: substrate.ateapi.v1.WorkerStatus.state:type_name -> substrate.ateapi.v1.WorkerState - 121, // 141: substrate.ateapi.v1.WorkerStatus.capacity:type_name -> substrate.ateapi.v1.WorkerResources - 121, // 142: substrate.ateapi.v1.WorkerStatus.allocated:type_name -> substrate.ateapi.v1.WorkerResources - 115, // 143: substrate.ateapi.v1.WorkerStatus.sandbox_classes:type_name -> substrate.ateapi.v1.WorkerSandboxClass - 116, // 144: substrate.ateapi.v1.WorkerSandboxClass.default_runtime:type_name -> substrate.ateapi.v1.WorkerSandboxRuntime - 116, // 145: substrate.ateapi.v1.WorkerSandboxClass.restorable_runtimes:type_name -> substrate.ateapi.v1.WorkerSandboxRuntime - 119, // 146: substrate.ateapi.v1.WorkerSandboxRuntime.version:type_name -> substrate.ateapi.v1.VersionedSandboxCompat - 117, // 147: substrate.ateapi.v1.WorkerSandboxRuntime.actor_overhead:type_name -> substrate.ateapi.v1.RuntimeOverhead - 119, // 148: substrate.ateapi.v1.ActorSandboxRuntime.version:type_name -> substrate.ateapi.v1.VersionedSandboxCompat - 120, // 149: substrate.ateapi.v1.VersionedSandboxCompat.attributes:type_name -> substrate.ateapi.v1.AttributeEntry - 14, // 150: substrate.ateapi.v1.ActorAssignment.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata - 35, // 151: substrate.ateapi.v1.ActorAssignment.actor:type_name -> substrate.ateapi.v1.ObjectRef - 38, // 152: substrate.ateapi.v1.ActorAssignment.resources:type_name -> substrate.ateapi.v1.Resources - 35, // 153: substrate.ateapi.v1.AcquireWorkerEpochRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 154: substrate.ateapi.v1.RegisterWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 121, // 155: substrate.ateapi.v1.RegisterWorkerRequest.capacity:type_name -> substrate.ateapi.v1.WorkerResources - 113, // 156: substrate.ateapi.v1.RegisterWorkerResponse.worker:type_name -> substrate.ateapi.v1.Worker - 35, // 157: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 115, // 158: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest.sandbox_classes:type_name -> substrate.ateapi.v1.WorkerSandboxClass - 113, // 159: substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse.worker:type_name -> substrate.ateapi.v1.Worker - 35, // 160: substrate.ateapi.v1.MintWorkerActorCertificateRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 161: substrate.ateapi.v1.MintWorkerActorCertificateRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 162: substrate.ateapi.v1.MintWorkerActorJwtRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 155, // 163: substrate.ateapi.v1.MintWorkerActorJwtResponse.expire_time:type_name -> google.protobuf.Timestamp - 35, // 164: substrate.ateapi.v1.RequestActorSuspendRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 165: substrate.ateapi.v1.RequestActorSuspendRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 17, // 166: substrate.ateapi.v1.RequestActorSuspendResponse.actor:type_name -> substrate.ateapi.v1.Actor - 35, // 167: substrate.ateapi.v1.ReportActorCrashedRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 168: substrate.ateapi.v1.ReportActorCrashedRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 17, // 169: substrate.ateapi.v1.ReportActorCrashedResponse.actor:type_name -> substrate.ateapi.v1.Actor - 35, // 170: substrate.ateapi.v1.ReportActorSnapshotStateRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef - 139, // 171: substrate.ateapi.v1.ReportActorSnapshotStateRequest.state:type_name -> substrate.ateapi.v1.ActorSnapshotState - 140, // 172: substrate.ateapi.v1.ActorSnapshotState.latest_local:type_name -> substrate.ateapi.v1.SnapshotReport - 140, // 173: substrate.ateapi.v1.ActorSnapshotState.uploading:type_name -> substrate.ateapi.v1.SnapshotReport - 140, // 174: substrate.ateapi.v1.ActorSnapshotState.latest_durable:type_name -> substrate.ateapi.v1.SnapshotReport - 155, // 175: substrate.ateapi.v1.ActorSnapshotState.upload_due_time:type_name -> google.protobuf.Timestamp - 2, // 176: substrate.ateapi.v1.SnapshotReport.fidelity:type_name -> substrate.ateapi.v1.SnapshotFidelity - 10, // 177: substrate.ateapi.v1.SnapshotReport.object:type_name -> substrate.ateapi.v1.ObjectSnapshot - 155, // 178: substrate.ateapi.v1.SnapshotReport.local_commit_time:type_name -> google.protobuf.Timestamp - 155, // 179: substrate.ateapi.v1.SnapshotReport.durable_complete_time:type_name -> google.protobuf.Timestamp - 14, // 180: substrate.ateapi.v1.AccessPolicy.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata - 142, // 181: substrate.ateapi.v1.AccessPolicy.bindings:type_name -> substrate.ateapi.v1.Binding - 141, // 182: substrate.ateapi.v1.CreateGlobalAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy - 141, // 183: substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy - 35, // 184: substrate.ateapi.v1.GetAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 35, // 185: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 141, // 186: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy - 35, // 187: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 141, // 188: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy - 35, // 189: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef - 95, // 190: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions - 9, // 191: substrate.ateapi.v1.ResourceAnnotation.scope:type_name -> substrate.ateapi.v1.Scope - 156, // 192: substrate.ateapi.v1.resource:extendee -> google.protobuf.MessageOptions - 157, // 193: substrate.ateapi.v1.method:extendee -> google.protobuf.MethodOptions - 150, // 194: substrate.ateapi.v1.resource:type_name -> substrate.ateapi.v1.ResourceAnnotation - 151, // 195: substrate.ateapi.v1.method:type_name -> substrate.ateapi.v1.MethodAnnotation - 70, // 196: substrate.ateapi.v1.Control.GetActor:input_type -> substrate.ateapi.v1.GetActorRequest - 71, // 197: substrate.ateapi.v1.Control.CreateActor:input_type -> substrate.ateapi.v1.CreateActorRequest - 72, // 198: substrate.ateapi.v1.Control.UpdateActor:input_type -> substrate.ateapi.v1.UpdateActorRequest - 73, // 199: substrate.ateapi.v1.Control.SuspendActor:input_type -> substrate.ateapi.v1.SuspendActorRequest - 76, // 200: substrate.ateapi.v1.Control.ResumeActor:input_type -> substrate.ateapi.v1.ResumeActorRequest - 78, // 201: substrate.ateapi.v1.Control.RevertActor:input_type -> substrate.ateapi.v1.RevertActorRequest - 80, // 202: substrate.ateapi.v1.Control.DeleteActor:input_type -> substrate.ateapi.v1.DeleteActorRequest - 81, // 203: substrate.ateapi.v1.Control.GetActorEgressPolicy:input_type -> substrate.ateapi.v1.GetActorEgressPolicyRequest - 82, // 204: substrate.ateapi.v1.Control.CreateActorEgressPolicy:input_type -> substrate.ateapi.v1.CreateActorEgressPolicyRequest - 83, // 205: substrate.ateapi.v1.Control.UpdateActorEgressPolicy:input_type -> substrate.ateapi.v1.UpdateActorEgressPolicyRequest - 84, // 206: substrate.ateapi.v1.Control.DeleteActorEgressPolicy:input_type -> substrate.ateapi.v1.DeleteActorEgressPolicyRequest - 86, // 207: substrate.ateapi.v1.Control.MintActorJwt:input_type -> substrate.ateapi.v1.MintActorJwtRequest - 88, // 208: substrate.ateapi.v1.Control.MintActorCertificate:input_type -> substrate.ateapi.v1.MintActorCertificateRequest - 92, // 209: substrate.ateapi.v1.Control.CreateTag:input_type -> substrate.ateapi.v1.CreateTagRequest - 85, // 210: substrate.ateapi.v1.Control.GetTag:input_type -> substrate.ateapi.v1.GetTagRequest - 90, // 211: substrate.ateapi.v1.Control.ListTags:input_type -> substrate.ateapi.v1.ListTagsRequest - 93, // 212: substrate.ateapi.v1.Control.UpdateTag:input_type -> substrate.ateapi.v1.UpdateTagRequest - 94, // 213: substrate.ateapi.v1.Control.DeleteTag:input_type -> substrate.ateapi.v1.DeleteTagRequest - 99, // 214: substrate.ateapi.v1.Control.ListWorkers:input_type -> substrate.ateapi.v1.ListWorkersRequest - 101, // 215: substrate.ateapi.v1.Control.GetWorker:input_type -> substrate.ateapi.v1.GetWorkerRequest - 102, // 216: substrate.ateapi.v1.Control.CreateWorker:input_type -> substrate.ateapi.v1.CreateWorkerRequest - 103, // 217: substrate.ateapi.v1.Control.UpdateWorker:input_type -> substrate.ateapi.v1.UpdateWorkerRequest - 104, // 218: substrate.ateapi.v1.Control.DeleteWorker:input_type -> substrate.ateapi.v1.DeleteWorkerRequest - 105, // 219: substrate.ateapi.v1.Control.DrainWorker:input_type -> substrate.ateapi.v1.DrainWorkerRequest - 107, // 220: substrate.ateapi.v1.Control.MarkWorkerAvailable:input_type -> substrate.ateapi.v1.MarkWorkerAvailableRequest - 109, // 221: substrate.ateapi.v1.Control.MarkWorkerUnavailable:input_type -> substrate.ateapi.v1.MarkWorkerUnavailableRequest - 97, // 222: substrate.ateapi.v1.Control.ListWorkerActorAssignments:input_type -> substrate.ateapi.v1.ListWorkerActorAssignmentsRequest - 111, // 223: substrate.ateapi.v1.Control.ListActors:input_type -> substrate.ateapi.v1.ListActorsRequest - 60, // 224: substrate.ateapi.v1.Control.CreateAtespace:input_type -> substrate.ateapi.v1.CreateAtespaceRequest - 61, // 225: substrate.ateapi.v1.Control.GetAtespace:input_type -> substrate.ateapi.v1.GetAtespaceRequest - 62, // 226: substrate.ateapi.v1.Control.ListAtespaces:input_type -> substrate.ateapi.v1.ListAtespacesRequest - 64, // 227: substrate.ateapi.v1.Control.DeleteAtespace:input_type -> substrate.ateapi.v1.DeleteAtespaceRequest - 65, // 228: substrate.ateapi.v1.Control.CreateActorTemplate:input_type -> substrate.ateapi.v1.CreateActorTemplateRequest - 66, // 229: substrate.ateapi.v1.Control.GetActorTemplate:input_type -> substrate.ateapi.v1.GetActorTemplateRequest - 67, // 230: substrate.ateapi.v1.Control.ListActorTemplates:input_type -> substrate.ateapi.v1.ListActorTemplatesRequest - 69, // 231: substrate.ateapi.v1.Control.DeleteActorTemplate:input_type -> substrate.ateapi.v1.DeleteActorTemplateRequest - 143, // 232: substrate.ateapi.v1.Control.GetGlobalAccessPolicy:input_type -> substrate.ateapi.v1.GetGlobalAccessPolicyRequest - 144, // 233: substrate.ateapi.v1.Control.CreateGlobalAccessPolicy:input_type -> substrate.ateapi.v1.CreateGlobalAccessPolicyRequest - 145, // 234: substrate.ateapi.v1.Control.UpdateGlobalAccessPolicy:input_type -> substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest - 146, // 235: substrate.ateapi.v1.Control.GetAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.GetAtespaceAccessPolicyRequest - 147, // 236: substrate.ateapi.v1.Control.CreateAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest - 148, // 237: substrate.ateapi.v1.Control.UpdateAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest - 149, // 238: substrate.ateapi.v1.Control.DeleteAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest - 123, // 239: substrate.ateapi.v1.WorkerService.AcquireWorkerEpoch:input_type -> substrate.ateapi.v1.AcquireWorkerEpochRequest - 125, // 240: substrate.ateapi.v1.WorkerService.RegisterWorker:input_type -> substrate.ateapi.v1.RegisterWorkerRequest - 127, // 241: substrate.ateapi.v1.WorkerService.SetWorkerSandboxRuntimes:input_type -> substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest - 129, // 242: substrate.ateapi.v1.WorkerService.MintWorkerActorCertificate:input_type -> substrate.ateapi.v1.MintWorkerActorCertificateRequest - 131, // 243: substrate.ateapi.v1.WorkerService.MintWorkerActorJwt:input_type -> substrate.ateapi.v1.MintWorkerActorJwtRequest - 133, // 244: substrate.ateapi.v1.WorkerService.RequestActorSuspend:input_type -> substrate.ateapi.v1.RequestActorSuspendRequest - 137, // 245: substrate.ateapi.v1.WorkerService.ReportActorSnapshotState:input_type -> substrate.ateapi.v1.ReportActorSnapshotStateRequest - 135, // 246: substrate.ateapi.v1.WorkerService.ReportActorCrashed:input_type -> substrate.ateapi.v1.ReportActorCrashedRequest - 17, // 247: substrate.ateapi.v1.Control.GetActor:output_type -> substrate.ateapi.v1.Actor - 17, // 248: substrate.ateapi.v1.Control.CreateActor:output_type -> substrate.ateapi.v1.Actor - 17, // 249: substrate.ateapi.v1.Control.UpdateActor:output_type -> substrate.ateapi.v1.Actor - 74, // 250: substrate.ateapi.v1.Control.SuspendActor:output_type -> substrate.ateapi.v1.SuspendActorResponse - 77, // 251: substrate.ateapi.v1.Control.ResumeActor:output_type -> substrate.ateapi.v1.ResumeActorResponse - 79, // 252: substrate.ateapi.v1.Control.RevertActor:output_type -> substrate.ateapi.v1.RevertActorResponse - 17, // 253: substrate.ateapi.v1.Control.DeleteActor:output_type -> substrate.ateapi.v1.Actor - 18, // 254: substrate.ateapi.v1.Control.GetActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy - 18, // 255: substrate.ateapi.v1.Control.CreateActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy - 18, // 256: substrate.ateapi.v1.Control.UpdateActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy - 18, // 257: substrate.ateapi.v1.Control.DeleteActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy - 87, // 258: substrate.ateapi.v1.Control.MintActorJwt:output_type -> substrate.ateapi.v1.MintActorJwtResponse - 89, // 259: substrate.ateapi.v1.Control.MintActorCertificate:output_type -> substrate.ateapi.v1.MintActorCertificateResponse - 33, // 260: substrate.ateapi.v1.Control.CreateTag:output_type -> substrate.ateapi.v1.Tag - 33, // 261: substrate.ateapi.v1.Control.GetTag:output_type -> substrate.ateapi.v1.Tag - 91, // 262: substrate.ateapi.v1.Control.ListTags:output_type -> substrate.ateapi.v1.ListTagsResponse - 33, // 263: substrate.ateapi.v1.Control.UpdateTag:output_type -> substrate.ateapi.v1.Tag - 33, // 264: substrate.ateapi.v1.Control.DeleteTag:output_type -> substrate.ateapi.v1.Tag - 100, // 265: substrate.ateapi.v1.Control.ListWorkers:output_type -> substrate.ateapi.v1.ListWorkersResponse - 113, // 266: substrate.ateapi.v1.Control.GetWorker:output_type -> substrate.ateapi.v1.Worker - 113, // 267: substrate.ateapi.v1.Control.CreateWorker:output_type -> substrate.ateapi.v1.Worker - 113, // 268: substrate.ateapi.v1.Control.UpdateWorker:output_type -> substrate.ateapi.v1.Worker - 113, // 269: substrate.ateapi.v1.Control.DeleteWorker:output_type -> substrate.ateapi.v1.Worker - 106, // 270: substrate.ateapi.v1.Control.DrainWorker:output_type -> substrate.ateapi.v1.DrainWorkerResponse - 108, // 271: substrate.ateapi.v1.Control.MarkWorkerAvailable:output_type -> substrate.ateapi.v1.MarkWorkerAvailableResponse - 110, // 272: substrate.ateapi.v1.Control.MarkWorkerUnavailable:output_type -> substrate.ateapi.v1.MarkWorkerUnavailableResponse - 98, // 273: substrate.ateapi.v1.Control.ListWorkerActorAssignments:output_type -> substrate.ateapi.v1.ListWorkerActorAssignmentsResponse - 112, // 274: substrate.ateapi.v1.Control.ListActors:output_type -> substrate.ateapi.v1.ListActorsResponse - 34, // 275: substrate.ateapi.v1.Control.CreateAtespace:output_type -> substrate.ateapi.v1.Atespace - 34, // 276: substrate.ateapi.v1.Control.GetAtespace:output_type -> substrate.ateapi.v1.Atespace - 63, // 277: substrate.ateapi.v1.Control.ListAtespaces:output_type -> substrate.ateapi.v1.ListAtespacesResponse - 34, // 278: substrate.ateapi.v1.Control.DeleteAtespace:output_type -> substrate.ateapi.v1.Atespace - 36, // 279: substrate.ateapi.v1.Control.CreateActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate - 36, // 280: substrate.ateapi.v1.Control.GetActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate - 68, // 281: substrate.ateapi.v1.Control.ListActorTemplates:output_type -> substrate.ateapi.v1.ListActorTemplatesResponse - 36, // 282: substrate.ateapi.v1.Control.DeleteActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate - 141, // 283: substrate.ateapi.v1.Control.GetGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 284: substrate.ateapi.v1.Control.CreateGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 285: substrate.ateapi.v1.Control.UpdateGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 286: substrate.ateapi.v1.Control.GetAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 287: substrate.ateapi.v1.Control.CreateAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 288: substrate.ateapi.v1.Control.UpdateAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 141, // 289: substrate.ateapi.v1.Control.DeleteAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy - 124, // 290: substrate.ateapi.v1.WorkerService.AcquireWorkerEpoch:output_type -> substrate.ateapi.v1.AcquireWorkerEpochResponse - 126, // 291: substrate.ateapi.v1.WorkerService.RegisterWorker:output_type -> substrate.ateapi.v1.RegisterWorkerResponse - 128, // 292: substrate.ateapi.v1.WorkerService.SetWorkerSandboxRuntimes:output_type -> substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse - 130, // 293: substrate.ateapi.v1.WorkerService.MintWorkerActorCertificate:output_type -> substrate.ateapi.v1.MintWorkerActorCertificateResponse - 132, // 294: substrate.ateapi.v1.WorkerService.MintWorkerActorJwt:output_type -> substrate.ateapi.v1.MintWorkerActorJwtResponse - 134, // 295: substrate.ateapi.v1.WorkerService.RequestActorSuspend:output_type -> substrate.ateapi.v1.RequestActorSuspendResponse - 138, // 296: substrate.ateapi.v1.WorkerService.ReportActorSnapshotState:output_type -> substrate.ateapi.v1.ReportActorSnapshotStateResponse - 136, // 297: substrate.ateapi.v1.WorkerService.ReportActorCrashed:output_type -> substrate.ateapi.v1.ReportActorCrashedResponse - 247, // [247:298] is the sub-list for method output_type - 196, // [196:247] is the sub-list for method input_type - 194, // [194:196] is the sub-list for extension type_name - 192, // [192:194] is the sub-list for extension extendee - 0, // [0:192] is the sub-list for field type_name + 153, // 111: substrate.ateapi.v1.MintActorJwtResponse.expire_time:type_name -> google.protobuf.Timestamp + 94, // 112: substrate.ateapi.v1.ListTagsRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 33, // 113: substrate.ateapi.v1.ListTagsResponse.tags:type_name -> substrate.ateapi.v1.Tag + 33, // 114: substrate.ateapi.v1.CreateTagRequest.tag:type_name -> substrate.ateapi.v1.Tag + 33, // 115: substrate.ateapi.v1.UpdateTagRequest.tag:type_name -> substrate.ateapi.v1.Tag + 35, // 116: substrate.ateapi.v1.DeleteTagRequest.tag:type_name -> substrate.ateapi.v1.ObjectRef + 93, // 117: substrate.ateapi.v1.DeleteTagRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 35, // 118: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 94, // 119: substrate.ateapi.v1.ListWorkerActorAssignmentsRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 120, // 120: substrate.ateapi.v1.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> substrate.ateapi.v1.ActorAssignment + 94, // 121: substrate.ateapi.v1.ListWorkersRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 111, // 122: substrate.ateapi.v1.ListWorkersResponse.workers:type_name -> substrate.ateapi.v1.Worker + 35, // 123: substrate.ateapi.v1.GetWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 111, // 124: substrate.ateapi.v1.CreateWorkerRequest.worker:type_name -> substrate.ateapi.v1.Worker + 111, // 125: substrate.ateapi.v1.UpdateWorkerRequest.worker:type_name -> substrate.ateapi.v1.Worker + 35, // 126: substrate.ateapi.v1.DeleteWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 93, // 127: substrate.ateapi.v1.DeleteWorkerRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 35, // 128: substrate.ateapi.v1.DrainWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 111, // 129: substrate.ateapi.v1.DrainWorkerResponse.worker:type_name -> substrate.ateapi.v1.Worker + 35, // 130: substrate.ateapi.v1.MarkWorkerAvailableRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 111, // 131: substrate.ateapi.v1.MarkWorkerAvailableResponse.worker:type_name -> substrate.ateapi.v1.Worker + 35, // 132: substrate.ateapi.v1.MarkWorkerUnavailableRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 111, // 133: substrate.ateapi.v1.MarkWorkerUnavailableResponse.worker:type_name -> substrate.ateapi.v1.Worker + 94, // 134: substrate.ateapi.v1.ListActorsRequest.options:type_name -> substrate.ateapi.v1.ListOptions + 17, // 135: substrate.ateapi.v1.ListActorsResponse.actors:type_name -> substrate.ateapi.v1.Actor + 14, // 136: substrate.ateapi.v1.Worker.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata + 152, // 137: substrate.ateapi.v1.Worker.labels:type_name -> substrate.ateapi.v1.Worker.LabelsEntry + 112, // 138: substrate.ateapi.v1.Worker.status:type_name -> substrate.ateapi.v1.WorkerStatus + 8, // 139: substrate.ateapi.v1.WorkerStatus.state:type_name -> substrate.ateapi.v1.WorkerState + 119, // 140: substrate.ateapi.v1.WorkerStatus.capacity:type_name -> substrate.ateapi.v1.WorkerResources + 119, // 141: substrate.ateapi.v1.WorkerStatus.allocated:type_name -> substrate.ateapi.v1.WorkerResources + 113, // 142: substrate.ateapi.v1.WorkerStatus.sandbox_classes:type_name -> substrate.ateapi.v1.WorkerSandboxClass + 114, // 143: substrate.ateapi.v1.WorkerSandboxClass.default_runtime:type_name -> substrate.ateapi.v1.WorkerSandboxRuntime + 114, // 144: substrate.ateapi.v1.WorkerSandboxClass.restorable_runtimes:type_name -> substrate.ateapi.v1.WorkerSandboxRuntime + 117, // 145: substrate.ateapi.v1.WorkerSandboxRuntime.version:type_name -> substrate.ateapi.v1.VersionedSandboxCompat + 115, // 146: substrate.ateapi.v1.WorkerSandboxRuntime.actor_overhead:type_name -> substrate.ateapi.v1.RuntimeOverhead + 117, // 147: substrate.ateapi.v1.ActorSandboxRuntime.version:type_name -> substrate.ateapi.v1.VersionedSandboxCompat + 118, // 148: substrate.ateapi.v1.VersionedSandboxCompat.attributes:type_name -> substrate.ateapi.v1.AttributeEntry + 14, // 149: substrate.ateapi.v1.ActorAssignment.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata + 35, // 150: substrate.ateapi.v1.ActorAssignment.actor:type_name -> substrate.ateapi.v1.ObjectRef + 38, // 151: substrate.ateapi.v1.ActorAssignment.resources:type_name -> substrate.ateapi.v1.Resources + 35, // 152: substrate.ateapi.v1.AcquireWorkerEpochRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 153: substrate.ateapi.v1.RegisterWorkerRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 119, // 154: substrate.ateapi.v1.RegisterWorkerRequest.capacity:type_name -> substrate.ateapi.v1.WorkerResources + 111, // 155: substrate.ateapi.v1.RegisterWorkerResponse.worker:type_name -> substrate.ateapi.v1.Worker + 35, // 156: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 113, // 157: substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest.sandbox_classes:type_name -> substrate.ateapi.v1.WorkerSandboxClass + 111, // 158: substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse.worker:type_name -> substrate.ateapi.v1.Worker + 35, // 159: substrate.ateapi.v1.MintWorkerActorCertificateRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 160: substrate.ateapi.v1.MintWorkerActorCertificateRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 161: substrate.ateapi.v1.MintWorkerActorJwtRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef + 153, // 162: substrate.ateapi.v1.MintWorkerActorJwtResponse.expire_time:type_name -> google.protobuf.Timestamp + 35, // 163: substrate.ateapi.v1.RequestActorSuspendRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 164: substrate.ateapi.v1.RequestActorSuspendRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef + 17, // 165: substrate.ateapi.v1.RequestActorSuspendResponse.actor:type_name -> substrate.ateapi.v1.Actor + 35, // 166: substrate.ateapi.v1.ReportActorCrashedRequest.worker:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 167: substrate.ateapi.v1.ReportActorCrashedRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef + 17, // 168: substrate.ateapi.v1.ReportActorCrashedResponse.actor:type_name -> substrate.ateapi.v1.Actor + 35, // 169: substrate.ateapi.v1.ReportActorSnapshotStateRequest.actor:type_name -> substrate.ateapi.v1.ObjectRef + 137, // 170: substrate.ateapi.v1.ReportActorSnapshotStateRequest.state:type_name -> substrate.ateapi.v1.ActorSnapshotState + 138, // 171: substrate.ateapi.v1.ActorSnapshotState.latest_local:type_name -> substrate.ateapi.v1.SnapshotReport + 138, // 172: substrate.ateapi.v1.ActorSnapshotState.uploading:type_name -> substrate.ateapi.v1.SnapshotReport + 138, // 173: substrate.ateapi.v1.ActorSnapshotState.latest_durable:type_name -> substrate.ateapi.v1.SnapshotReport + 153, // 174: substrate.ateapi.v1.ActorSnapshotState.upload_due_time:type_name -> google.protobuf.Timestamp + 2, // 175: substrate.ateapi.v1.SnapshotReport.fidelity:type_name -> substrate.ateapi.v1.SnapshotFidelity + 10, // 176: substrate.ateapi.v1.SnapshotReport.object:type_name -> substrate.ateapi.v1.ObjectSnapshot + 153, // 177: substrate.ateapi.v1.SnapshotReport.local_commit_time:type_name -> google.protobuf.Timestamp + 153, // 178: substrate.ateapi.v1.SnapshotReport.durable_complete_time:type_name -> google.protobuf.Timestamp + 14, // 179: substrate.ateapi.v1.AccessPolicy.metadata:type_name -> substrate.ateapi.v1.ResourceMetadata + 140, // 180: substrate.ateapi.v1.AccessPolicy.bindings:type_name -> substrate.ateapi.v1.Binding + 139, // 181: substrate.ateapi.v1.CreateGlobalAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy + 139, // 182: substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy + 35, // 183: substrate.ateapi.v1.GetAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef + 35, // 184: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef + 139, // 185: substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy + 35, // 186: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef + 139, // 187: substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> substrate.ateapi.v1.AccessPolicy + 35, // 188: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> substrate.ateapi.v1.ObjectRef + 93, // 189: substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest.options:type_name -> substrate.ateapi.v1.DeleteOptions + 9, // 190: substrate.ateapi.v1.ResourceAnnotation.scope:type_name -> substrate.ateapi.v1.Scope + 154, // 191: substrate.ateapi.v1.resource:extendee -> google.protobuf.MessageOptions + 155, // 192: substrate.ateapi.v1.method:extendee -> google.protobuf.MethodOptions + 148, // 193: substrate.ateapi.v1.resource:type_name -> substrate.ateapi.v1.ResourceAnnotation + 149, // 194: substrate.ateapi.v1.method:type_name -> substrate.ateapi.v1.MethodAnnotation + 70, // 195: substrate.ateapi.v1.Control.GetActor:input_type -> substrate.ateapi.v1.GetActorRequest + 71, // 196: substrate.ateapi.v1.Control.CreateActor:input_type -> substrate.ateapi.v1.CreateActorRequest + 72, // 197: substrate.ateapi.v1.Control.UpdateActor:input_type -> substrate.ateapi.v1.UpdateActorRequest + 73, // 198: substrate.ateapi.v1.Control.SuspendActor:input_type -> substrate.ateapi.v1.SuspendActorRequest + 76, // 199: substrate.ateapi.v1.Control.ResumeActor:input_type -> substrate.ateapi.v1.ResumeActorRequest + 78, // 200: substrate.ateapi.v1.Control.RevertActor:input_type -> substrate.ateapi.v1.RevertActorRequest + 80, // 201: substrate.ateapi.v1.Control.DeleteActor:input_type -> substrate.ateapi.v1.DeleteActorRequest + 81, // 202: substrate.ateapi.v1.Control.GetActorEgressPolicy:input_type -> substrate.ateapi.v1.GetActorEgressPolicyRequest + 82, // 203: substrate.ateapi.v1.Control.CreateActorEgressPolicy:input_type -> substrate.ateapi.v1.CreateActorEgressPolicyRequest + 83, // 204: substrate.ateapi.v1.Control.UpdateActorEgressPolicy:input_type -> substrate.ateapi.v1.UpdateActorEgressPolicyRequest + 84, // 205: substrate.ateapi.v1.Control.DeleteActorEgressPolicy:input_type -> substrate.ateapi.v1.DeleteActorEgressPolicyRequest + 86, // 206: substrate.ateapi.v1.Control.MintActorJwt:input_type -> substrate.ateapi.v1.MintActorJwtRequest + 90, // 207: substrate.ateapi.v1.Control.CreateTag:input_type -> substrate.ateapi.v1.CreateTagRequest + 85, // 208: substrate.ateapi.v1.Control.GetTag:input_type -> substrate.ateapi.v1.GetTagRequest + 88, // 209: substrate.ateapi.v1.Control.ListTags:input_type -> substrate.ateapi.v1.ListTagsRequest + 91, // 210: substrate.ateapi.v1.Control.UpdateTag:input_type -> substrate.ateapi.v1.UpdateTagRequest + 92, // 211: substrate.ateapi.v1.Control.DeleteTag:input_type -> substrate.ateapi.v1.DeleteTagRequest + 97, // 212: substrate.ateapi.v1.Control.ListWorkers:input_type -> substrate.ateapi.v1.ListWorkersRequest + 99, // 213: substrate.ateapi.v1.Control.GetWorker:input_type -> substrate.ateapi.v1.GetWorkerRequest + 100, // 214: substrate.ateapi.v1.Control.CreateWorker:input_type -> substrate.ateapi.v1.CreateWorkerRequest + 101, // 215: substrate.ateapi.v1.Control.UpdateWorker:input_type -> substrate.ateapi.v1.UpdateWorkerRequest + 102, // 216: substrate.ateapi.v1.Control.DeleteWorker:input_type -> substrate.ateapi.v1.DeleteWorkerRequest + 103, // 217: substrate.ateapi.v1.Control.DrainWorker:input_type -> substrate.ateapi.v1.DrainWorkerRequest + 105, // 218: substrate.ateapi.v1.Control.MarkWorkerAvailable:input_type -> substrate.ateapi.v1.MarkWorkerAvailableRequest + 107, // 219: substrate.ateapi.v1.Control.MarkWorkerUnavailable:input_type -> substrate.ateapi.v1.MarkWorkerUnavailableRequest + 95, // 220: substrate.ateapi.v1.Control.ListWorkerActorAssignments:input_type -> substrate.ateapi.v1.ListWorkerActorAssignmentsRequest + 109, // 221: substrate.ateapi.v1.Control.ListActors:input_type -> substrate.ateapi.v1.ListActorsRequest + 60, // 222: substrate.ateapi.v1.Control.CreateAtespace:input_type -> substrate.ateapi.v1.CreateAtespaceRequest + 61, // 223: substrate.ateapi.v1.Control.GetAtespace:input_type -> substrate.ateapi.v1.GetAtespaceRequest + 62, // 224: substrate.ateapi.v1.Control.ListAtespaces:input_type -> substrate.ateapi.v1.ListAtespacesRequest + 64, // 225: substrate.ateapi.v1.Control.DeleteAtespace:input_type -> substrate.ateapi.v1.DeleteAtespaceRequest + 65, // 226: substrate.ateapi.v1.Control.CreateActorTemplate:input_type -> substrate.ateapi.v1.CreateActorTemplateRequest + 66, // 227: substrate.ateapi.v1.Control.GetActorTemplate:input_type -> substrate.ateapi.v1.GetActorTemplateRequest + 67, // 228: substrate.ateapi.v1.Control.ListActorTemplates:input_type -> substrate.ateapi.v1.ListActorTemplatesRequest + 69, // 229: substrate.ateapi.v1.Control.DeleteActorTemplate:input_type -> substrate.ateapi.v1.DeleteActorTemplateRequest + 141, // 230: substrate.ateapi.v1.Control.GetGlobalAccessPolicy:input_type -> substrate.ateapi.v1.GetGlobalAccessPolicyRequest + 142, // 231: substrate.ateapi.v1.Control.CreateGlobalAccessPolicy:input_type -> substrate.ateapi.v1.CreateGlobalAccessPolicyRequest + 143, // 232: substrate.ateapi.v1.Control.UpdateGlobalAccessPolicy:input_type -> substrate.ateapi.v1.UpdateGlobalAccessPolicyRequest + 144, // 233: substrate.ateapi.v1.Control.GetAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.GetAtespaceAccessPolicyRequest + 145, // 234: substrate.ateapi.v1.Control.CreateAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.CreateAtespaceAccessPolicyRequest + 146, // 235: substrate.ateapi.v1.Control.UpdateAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.UpdateAtespaceAccessPolicyRequest + 147, // 236: substrate.ateapi.v1.Control.DeleteAtespaceAccessPolicy:input_type -> substrate.ateapi.v1.DeleteAtespaceAccessPolicyRequest + 121, // 237: substrate.ateapi.v1.WorkerService.AcquireWorkerEpoch:input_type -> substrate.ateapi.v1.AcquireWorkerEpochRequest + 123, // 238: substrate.ateapi.v1.WorkerService.RegisterWorker:input_type -> substrate.ateapi.v1.RegisterWorkerRequest + 125, // 239: substrate.ateapi.v1.WorkerService.SetWorkerSandboxRuntimes:input_type -> substrate.ateapi.v1.SetWorkerSandboxRuntimesRequest + 127, // 240: substrate.ateapi.v1.WorkerService.MintWorkerActorCertificate:input_type -> substrate.ateapi.v1.MintWorkerActorCertificateRequest + 129, // 241: substrate.ateapi.v1.WorkerService.MintWorkerActorJwt:input_type -> substrate.ateapi.v1.MintWorkerActorJwtRequest + 131, // 242: substrate.ateapi.v1.WorkerService.RequestActorSuspend:input_type -> substrate.ateapi.v1.RequestActorSuspendRequest + 135, // 243: substrate.ateapi.v1.WorkerService.ReportActorSnapshotState:input_type -> substrate.ateapi.v1.ReportActorSnapshotStateRequest + 133, // 244: substrate.ateapi.v1.WorkerService.ReportActorCrashed:input_type -> substrate.ateapi.v1.ReportActorCrashedRequest + 17, // 245: substrate.ateapi.v1.Control.GetActor:output_type -> substrate.ateapi.v1.Actor + 17, // 246: substrate.ateapi.v1.Control.CreateActor:output_type -> substrate.ateapi.v1.Actor + 17, // 247: substrate.ateapi.v1.Control.UpdateActor:output_type -> substrate.ateapi.v1.Actor + 74, // 248: substrate.ateapi.v1.Control.SuspendActor:output_type -> substrate.ateapi.v1.SuspendActorResponse + 77, // 249: substrate.ateapi.v1.Control.ResumeActor:output_type -> substrate.ateapi.v1.ResumeActorResponse + 79, // 250: substrate.ateapi.v1.Control.RevertActor:output_type -> substrate.ateapi.v1.RevertActorResponse + 17, // 251: substrate.ateapi.v1.Control.DeleteActor:output_type -> substrate.ateapi.v1.Actor + 18, // 252: substrate.ateapi.v1.Control.GetActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy + 18, // 253: substrate.ateapi.v1.Control.CreateActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy + 18, // 254: substrate.ateapi.v1.Control.UpdateActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy + 18, // 255: substrate.ateapi.v1.Control.DeleteActorEgressPolicy:output_type -> substrate.ateapi.v1.EgressPolicy + 87, // 256: substrate.ateapi.v1.Control.MintActorJwt:output_type -> substrate.ateapi.v1.MintActorJwtResponse + 33, // 257: substrate.ateapi.v1.Control.CreateTag:output_type -> substrate.ateapi.v1.Tag + 33, // 258: substrate.ateapi.v1.Control.GetTag:output_type -> substrate.ateapi.v1.Tag + 89, // 259: substrate.ateapi.v1.Control.ListTags:output_type -> substrate.ateapi.v1.ListTagsResponse + 33, // 260: substrate.ateapi.v1.Control.UpdateTag:output_type -> substrate.ateapi.v1.Tag + 33, // 261: substrate.ateapi.v1.Control.DeleteTag:output_type -> substrate.ateapi.v1.Tag + 98, // 262: substrate.ateapi.v1.Control.ListWorkers:output_type -> substrate.ateapi.v1.ListWorkersResponse + 111, // 263: substrate.ateapi.v1.Control.GetWorker:output_type -> substrate.ateapi.v1.Worker + 111, // 264: substrate.ateapi.v1.Control.CreateWorker:output_type -> substrate.ateapi.v1.Worker + 111, // 265: substrate.ateapi.v1.Control.UpdateWorker:output_type -> substrate.ateapi.v1.Worker + 111, // 266: substrate.ateapi.v1.Control.DeleteWorker:output_type -> substrate.ateapi.v1.Worker + 104, // 267: substrate.ateapi.v1.Control.DrainWorker:output_type -> substrate.ateapi.v1.DrainWorkerResponse + 106, // 268: substrate.ateapi.v1.Control.MarkWorkerAvailable:output_type -> substrate.ateapi.v1.MarkWorkerAvailableResponse + 108, // 269: substrate.ateapi.v1.Control.MarkWorkerUnavailable:output_type -> substrate.ateapi.v1.MarkWorkerUnavailableResponse + 96, // 270: substrate.ateapi.v1.Control.ListWorkerActorAssignments:output_type -> substrate.ateapi.v1.ListWorkerActorAssignmentsResponse + 110, // 271: substrate.ateapi.v1.Control.ListActors:output_type -> substrate.ateapi.v1.ListActorsResponse + 34, // 272: substrate.ateapi.v1.Control.CreateAtespace:output_type -> substrate.ateapi.v1.Atespace + 34, // 273: substrate.ateapi.v1.Control.GetAtespace:output_type -> substrate.ateapi.v1.Atespace + 63, // 274: substrate.ateapi.v1.Control.ListAtespaces:output_type -> substrate.ateapi.v1.ListAtespacesResponse + 34, // 275: substrate.ateapi.v1.Control.DeleteAtespace:output_type -> substrate.ateapi.v1.Atespace + 36, // 276: substrate.ateapi.v1.Control.CreateActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate + 36, // 277: substrate.ateapi.v1.Control.GetActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate + 68, // 278: substrate.ateapi.v1.Control.ListActorTemplates:output_type -> substrate.ateapi.v1.ListActorTemplatesResponse + 36, // 279: substrate.ateapi.v1.Control.DeleteActorTemplate:output_type -> substrate.ateapi.v1.ActorTemplate + 139, // 280: substrate.ateapi.v1.Control.GetGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 281: substrate.ateapi.v1.Control.CreateGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 282: substrate.ateapi.v1.Control.UpdateGlobalAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 283: substrate.ateapi.v1.Control.GetAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 284: substrate.ateapi.v1.Control.CreateAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 285: substrate.ateapi.v1.Control.UpdateAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 139, // 286: substrate.ateapi.v1.Control.DeleteAtespaceAccessPolicy:output_type -> substrate.ateapi.v1.AccessPolicy + 122, // 287: substrate.ateapi.v1.WorkerService.AcquireWorkerEpoch:output_type -> substrate.ateapi.v1.AcquireWorkerEpochResponse + 124, // 288: substrate.ateapi.v1.WorkerService.RegisterWorker:output_type -> substrate.ateapi.v1.RegisterWorkerResponse + 126, // 289: substrate.ateapi.v1.WorkerService.SetWorkerSandboxRuntimes:output_type -> substrate.ateapi.v1.SetWorkerSandboxRuntimesResponse + 128, // 290: substrate.ateapi.v1.WorkerService.MintWorkerActorCertificate:output_type -> substrate.ateapi.v1.MintWorkerActorCertificateResponse + 130, // 291: substrate.ateapi.v1.WorkerService.MintWorkerActorJwt:output_type -> substrate.ateapi.v1.MintWorkerActorJwtResponse + 132, // 292: substrate.ateapi.v1.WorkerService.RequestActorSuspend:output_type -> substrate.ateapi.v1.RequestActorSuspendResponse + 136, // 293: substrate.ateapi.v1.WorkerService.ReportActorSnapshotState:output_type -> substrate.ateapi.v1.ReportActorSnapshotStateResponse + 134, // 294: substrate.ateapi.v1.WorkerService.ReportActorCrashed:output_type -> substrate.ateapi.v1.ReportActorCrashedResponse + 245, // [245:295] is the sub-list for method output_type + 195, // [195:245] is the sub-list for method input_type + 193, // [193:195] is the sub-list for extension type_name + 191, // [191:193] is the sub-list for extension extendee + 0, // [0:191] is the sub-list for field type_name } func init() { file_api_ateapi_v1_ateapi_proto_init() } @@ -11262,7 +11124,7 @@ func file_api_ateapi_v1_ateapi_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_ateapi_v1_ateapi_proto_rawDesc), len(file_api_ateapi_v1_ateapi_proto_rawDesc)), NumEnums: 10, - NumMessages: 145, + NumMessages: 143, NumExtensions: 2, NumServices: 2, }, diff --git a/api/ateapi/v1/ateapi.proto b/api/ateapi/v1/ateapi.proto index 7a59f6a098..d997c8d365 100644 --- a/api/ateapi/v1/ateapi.proto +++ b/api/ateapi/v1/ateapi.proto @@ -90,16 +90,6 @@ service Control { option (method).resource = "Actor"; } - // Create a Substrate-issued SPIFFE certificate asserting the actor identity. - // - // SPIFFE URI: spiffe://${trustdomain}/actor/${atespace}/${actor} - // - // * Called by the egress gateway when actor client certificate injection is - // configured for outbound requests. - rpc MintActorCertificate(MintActorCertificateRequest) returns (MintActorCertificateResponse) { - option (method).resource = "Actor"; - } - // Tag the external snapshot a suspended Actor holds. The tag gets its own // copy of that snapshot, so suspending or deleting the Actor afterwards // cannot collect it. When the Actor's latest snapshot is not uploaded yet, @@ -2013,39 +2003,6 @@ message MintActorJwtResponse { google.protobuf.Timestamp expire_time = 2; } -// Request message for MintActorCertificate. -message MintActorCertificateRequest { - // The actor for which the certificate should be issued. - // - // Must be a valid actor that currently exists according to the actor store. - // - // +k8s:required - ObjectRef actor = 1; - - // The UID of the actor --- used to guard against deletion and recreation of - // an actor with the same name. - // - // +k8s:required - // +k8s:format=k8s-uuid - string actor_uid = 2; - - // Request contains DER encoded bytes of a x509 certificate signing request. - // The signer will ignore the contents of the CSR except to extract the - // subject public key. - // - // +k8s:required - // +k8s:maxBytes=16384 - bytes certificate_signing_request = 3; -} - -// Response message for MintActorCertificate. -message MintActorCertificateResponse { - // Response contains a list of DER encoded certificates. The first entry is the - // leaf certificate, and any remaining entries are intermediates in - // leaf-to-root order. - repeated bytes actor_certificates = 1; -} - message ListTagsRequest { // The atespace to list tags from. Empty lists across all atespaces. // diff --git a/api/ateapi/v1/ateapi_grpc.pb.go b/api/ateapi/v1/ateapi_grpc.pb.go index 4c2cadb5d9..50f21cc0c4 100644 --- a/api/ateapi/v1/ateapi_grpc.pb.go +++ b/api/ateapi/v1/ateapi_grpc.pb.go @@ -45,7 +45,6 @@ const ( Control_UpdateActorEgressPolicy_FullMethodName = "/substrate.ateapi.v1.Control/UpdateActorEgressPolicy" Control_DeleteActorEgressPolicy_FullMethodName = "/substrate.ateapi.v1.Control/DeleteActorEgressPolicy" Control_MintActorJwt_FullMethodName = "/substrate.ateapi.v1.Control/MintActorJwt" - Control_MintActorCertificate_FullMethodName = "/substrate.ateapi.v1.Control/MintActorCertificate" Control_CreateTag_FullMethodName = "/substrate.ateapi.v1.Control/CreateTag" Control_GetTag_FullMethodName = "/substrate.ateapi.v1.Control/GetTag" Control_ListTags_FullMethodName = "/substrate.ateapi.v1.Control/ListTags" @@ -115,13 +114,6 @@ type ControlClient interface { // // * Called by the egress gateway when actor JWT injection is configured for outbound requests. MintActorJwt(ctx context.Context, in *MintActorJwtRequest, opts ...grpc.CallOption) (*MintActorJwtResponse, error) - // Create a Substrate-issued SPIFFE certificate asserting the actor identity. - // - // SPIFFE URI: spiffe://${trustdomain}/actor/${atespace}/${actor} - // - // * Called by the egress gateway when actor client certificate injection is - // configured for outbound requests. - MintActorCertificate(ctx context.Context, in *MintActorCertificateRequest, opts ...grpc.CallOption) (*MintActorCertificateResponse, error) // Tag the external snapshot a suspended Actor holds. The tag gets its own // copy of that snapshot, so suspending or deleting the Actor afterwards // cannot collect it. When the Actor's latest snapshot is not uploaded yet, @@ -333,16 +325,6 @@ func (c *controlClient) MintActorJwt(ctx context.Context, in *MintActorJwtReques return out, nil } -func (c *controlClient) MintActorCertificate(ctx context.Context, in *MintActorCertificateRequest, opts ...grpc.CallOption) (*MintActorCertificateResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(MintActorCertificateResponse) - err := c.cc.Invoke(ctx, Control_MintActorCertificate_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *controlClient) CreateTag(ctx context.Context, in *CreateTagRequest, opts ...grpc.CallOption) (*Tag, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Tag) @@ -680,13 +662,6 @@ type ControlServer interface { // // * Called by the egress gateway when actor JWT injection is configured for outbound requests. MintActorJwt(context.Context, *MintActorJwtRequest) (*MintActorJwtResponse, error) - // Create a Substrate-issued SPIFFE certificate asserting the actor identity. - // - // SPIFFE URI: spiffe://${trustdomain}/actor/${atespace}/${actor} - // - // * Called by the egress gateway when actor client certificate injection is - // configured for outbound requests. - MintActorCertificate(context.Context, *MintActorCertificateRequest) (*MintActorCertificateResponse, error) // Tag the external snapshot a suspended Actor holds. The tag gets its own // copy of that snapshot, so suspending or deleting the Actor afterwards // cannot collect it. When the Actor's latest snapshot is not uploaded yet, @@ -814,9 +789,6 @@ func (UnimplementedControlServer) DeleteActorEgressPolicy(context.Context, *Dele func (UnimplementedControlServer) MintActorJwt(context.Context, *MintActorJwtRequest) (*MintActorJwtResponse, error) { return nil, status.Error(codes.Unimplemented, "method MintActorJwt not implemented") } -func (UnimplementedControlServer) MintActorCertificate(context.Context, *MintActorCertificateRequest) (*MintActorCertificateResponse, error) { - return nil, status.Error(codes.Unimplemented, "method MintActorCertificate not implemented") -} func (UnimplementedControlServer) CreateTag(context.Context, *CreateTagRequest) (*Tag, error) { return nil, status.Error(codes.Unimplemented, "method CreateTag not implemented") } @@ -1144,24 +1116,6 @@ func _Control_MintActorJwt_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } -func _Control_MintActorCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MintActorCertificateRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ControlServer).MintActorCertificate(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Control_MintActorCertificate_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ControlServer).MintActorCertificate(ctx, req.(*MintActorCertificateRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Control_CreateTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateTagRequest) if err := dec(in); err != nil { @@ -1757,10 +1711,6 @@ var Control_ServiceDesc = grpc.ServiceDesc{ MethodName: "MintActorJwt", Handler: _Control_MintActorJwt_Handler, }, - { - MethodName: "MintActorCertificate", - Handler: _Control_MintActorCertificate_Handler, - }, { MethodName: "CreateTag", Handler: _Control_CreateTag_Handler, diff --git a/cmd/ateapi/internal/apivalidation/actor.go b/cmd/ateapi/internal/apivalidation/actor.go index 138e4f5e4a..81cb30fc7f 100644 --- a/cmd/ateapi/internal/apivalidation/actor.go +++ b/cmd/ateapi/internal/apivalidation/actor.go @@ -82,12 +82,6 @@ func ValidateMintActorJWTRequest(ctx context.Context, req *ateapi.MintActorJwtRe return Validate_MintActorJwtRequest(ctx, op, nil, req, nil) } -func ValidateMintActorCertificateRequest(ctx context.Context, req *ateapi.MintActorCertificateRequest) field.ErrorList { - // Call the generated validation. - op := MakeCreateOp(ctx) - return Validate_MintActorCertificateRequest(ctx, op, nil, req, nil) -} - func ValidateMintWorkerActorCertificateRequest(ctx context.Context, req *ateapi.MintWorkerActorCertificateRequest) field.ErrorList { op := MakeCreateOp(ctx) return Validate_MintWorkerActorCertificateRequest(ctx, op, nil, req, nil) diff --git a/cmd/ateapi/internal/apivalidation/actor_test.go b/cmd/ateapi/internal/apivalidation/actor_test.go index 272ba567cc..750439ec1e 100644 --- a/cmd/ateapi/internal/apivalidation/actor_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_test.go @@ -1032,49 +1032,6 @@ func TestValidateSuspendActorRequest(t *testing.T) { } } -func TestValidateMintActorCertificateRequest(t *testing.T) { - validUID := "3b9f1e77-2c4d-4a80-91be-6d5c8f0a7e21" - tests := []struct { - name string - req *ateapi.MintActorCertificateRequest - want field.ErrorList - }{{ - "valid", - &ateapi.MintActorCertificateRequest{ - Actor: &ateapi.ObjectRef{Atespace: "ns1", Name: "id1"}, - ActorUid: validUID, - CertificateSigningRequest: []byte("csr"), - }, - nil, - }, { - "missing actor", - &ateapi.MintActorCertificateRequest{ - ActorUid: validUID, - CertificateSigningRequest: []byte("csr"), - }, - field.ErrorList{field.Required(field.NewPath("actor"), "")}, - }, { - "missing actor_uid", - &ateapi.MintActorCertificateRequest{ - Actor: &ateapi.ObjectRef{Atespace: "ns1", Name: "id1"}, - CertificateSigningRequest: []byte("csr"), - }, - field.ErrorList{field.Required(field.NewPath("actor_uid"), "")}, - }, { - "missing csr", - &ateapi.MintActorCertificateRequest{ - Actor: &ateapi.ObjectRef{Atespace: "ns1", Name: "id1"}, - ActorUid: validUID, - }, - field.ErrorList{field.Required(field.NewPath("certificate_signing_request"), "")}, - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assertValidateErr(t, ValidateMintActorCertificateRequest(context.Background(), tt.req), tt.want) - }) - } -} - // validActor returns a minimal Actor which should pass input validation. func validActor(mods ...func(*ateapi.Actor)) *ateapi.Actor { a := &ateapi.Actor{ diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index bfe1672f01..9d177ca23f 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -5878,110 +5878,6 @@ func Validate_MarkWorkerUnavailableRequest( return errs } -// Validate_MintActorCertificateRequest validates an instance of MintActorCertificateRequest according -// to declarative validation rules in the API schema. -func Validate_MintActorCertificateRequest( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *v1.MintActorCertificateRequest) (errs field.ErrorList) { - - { // field v1.MintActorCertificateRequest.Actor - fn := func( - fldPath *field.Path, - obj, oldObj *v1.ObjectRef, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if ateDeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // call the type's validation function - errs = append(errs, Validate_ObjectRef(ctx, op, fldPath, obj, oldObj)...) - return - } - oldVal := safe.Field(oldObj, - func(oldObj *v1.MintActorCertificateRequest) *v1.ObjectRef { - return oldObj.Actor - }) - errs = append(errs, fn(fldPath.Child("actor"), obj.Actor, oldVal, oldObj != nil)...) - } - - { // field v1.MintActorCertificateRequest.ActorUid - fn := func( - fldPath *field.Path, - obj, oldObj *string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - if e := validate.UUID(ctx, op, fldPath, obj, oldObj); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *v1.MintActorCertificateRequest) *string { - return &oldObj.ActorUid - }) - errs = append(errs, fn(fldPath.Child("actor_uid"), &obj.ActorUid, oldVal, oldObj != nil)...) - } - - { // field v1.MintActorCertificateRequest.CertificateSigningRequest - fn := func( - fldPath *field.Path, - obj, oldObj []byte, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if ateDeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - if e := validate.MaxBytesSlice(ctx, op, fldPath, obj, oldObj, 16384); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *v1.MintActorCertificateRequest) []byte { - return oldObj.CertificateSigningRequest - }) - errs = append(errs, fn(fldPath.Child("certificate_signing_request"), obj.CertificateSigningRequest, oldVal, oldObj != nil)...) - } - - return errs -} - // Validate_MintActorJwtRequest validates an instance of MintActorJwtRequest according // to declarative validation rules in the API schema. func Validate_MintActorJwtRequest( diff --git a/cmd/ateapi/internal/authz/authz_util.go b/cmd/ateapi/internal/authz/authz_util.go index 1e1734d6cd..45b52375c5 100644 --- a/cmd/ateapi/internal/authz/authz_util.go +++ b/cmd/ateapi/internal/authz/authz_util.go @@ -79,7 +79,6 @@ const ( RelationCanListTags = "can_list_tags" RelationCanUseTag = "can_use_tag" RelationCanMintActorJWT = "can_mint_actor_jwt" - RelationCanMintActorCertificate = "can_mint_actor_certificate" // maxTuplesPerWrite is OpenFGA's default maximum number of tuples allowed in a single Write request. maxTuplesPerWrite = 100 diff --git a/cmd/ateapi/internal/authz/interceptor_test.go b/cmd/ateapi/internal/authz/interceptor_test.go index b20bd6a7a6..ea6d6dece8 100644 --- a/cmd/ateapi/internal/authz/interceptor_test.go +++ b/cmd/ateapi/internal/authz/interceptor_test.go @@ -484,7 +484,6 @@ func TestUnaryServerInterceptor_LifecycleEgressWorkerAndTagChecks(t *testing.T) }}} deleteTag := rpcCall{ateapi.Control_DeleteTag_FullMethodName, &ateapi.DeleteTagRequest{Tag: tag}} mintJWT := rpcCall{ateapi.Control_MintActorJwt_FullMethodName, &ateapi.MintActorJwtRequest{Actor: actor}} - mintCert := rpcCall{ateapi.Control_MintActorCertificate_FullMethodName, &ateapi.MintActorCertificateRequest{Actor: actor}} // cloneTag creates an actor in atespace from team-a's tag v1, with a // template in that same atespace so only the tag check can differ. cloneTag := func(atespace string, sourceTag *ateapi.ObjectRef) rpcCall { @@ -586,7 +585,7 @@ func TestUnaryServerInterceptor_LifecycleEgressWorkerAndTagChecks(t *testing.T) // Only the egress gateway mints actor credentials; not even owners. {"editor cannot mint actor JWT", "editor", mintJWT, codes.PermissionDenied}, {"global owner cannot mint actor JWT", "global-owner", mintJWT, codes.PermissionDenied}, - {"bootstrap owner cannot mint actor certificate", "bootstrap-owner", mintCert, codes.PermissionDenied}, + {"bootstrap owner cannot mint actor JWT", "bootstrap-owner", mintJWT, codes.PermissionDenied}, } interceptor := UnaryServerInterceptor(authorizer) @@ -661,7 +660,6 @@ func TestUnaryServerInterceptor_SystemPrincipals(t *testing.T) { markUnavailable := rpcCall{ateapi.Control_MarkWorkerUnavailable_FullMethodName, &ateapi.MarkWorkerUnavailableRequest{Worker: worker}} listAssignments := rpcCall{ateapi.Control_ListWorkerActorAssignments_FullMethodName, &ateapi.ListWorkerActorAssignmentsRequest{Worker: worker}} mintJWT := rpcCall{ateapi.Control_MintActorJwt_FullMethodName, &ateapi.MintActorJwtRequest{Actor: actor}} - mintCert := rpcCall{ateapi.Control_MintActorCertificate_FullMethodName, &ateapi.MintActorCertificateRequest{Actor: actor}} mtls := func(id string) principal.PrincipalInfo { return principal.PrincipalInfo{ID: id, Kind: principal.KindMTLS} @@ -699,7 +697,6 @@ func TestUnaryServerInterceptor_SystemPrincipals(t *testing.T) { {"egress gateway lists actors", mtls(egressID), listAllActors, codes.OK}, {"egress gateway cannot get worker", mtls(egressID), getWorker, codes.PermissionDenied}, {"egress gateway mints actor JWT", mtls(egressID), mintJWT, codes.OK}, - {"egress gateway mints actor certificate", mtls(egressID), mintCert, codes.OK}, // atenet-router resumes actors. Both it and atenet-egress list actors // as their ateapi health check. @@ -711,7 +708,7 @@ func TestUnaryServerInterceptor_SystemPrincipals(t *testing.T) { {"ingress router cannot get egress policy", mtls(routerID), getEgress, codes.PermissionDenied}, {"ingress router cannot create worker", mtls(routerID), createWorker, codes.PermissionDenied}, {"ingress router cannot mint actor JWT", mtls(routerID), mintJWT, codes.PermissionDenied}, - {"controller cannot mint actor certificate", mtls(controllerID), mintCert, codes.PermissionDenied}, + {"controller cannot mint actor JWT", mtls(controllerID), mintJWT, codes.PermissionDenied}, // atelet reads egress policies for the worker that enforces them, and // nothing else. diff --git a/cmd/ateapi/internal/authz/model.fga b/cmd/ateapi/internal/authz/model.fga index 1d42a82e3e..5f71197ffe 100644 --- a/cmd/ateapi/internal/authz/model.fga +++ b/cmd/ateapi/internal/authz/model.fga @@ -169,7 +169,6 @@ type actor # Credentials asserting the actor's own identity. Only the egress gateway # mints them; an editor holding one could impersonate the actor. define can_mint_actor_jwt: egress_gateway from parent_atespace - define can_mint_actor_certificate: egress_gateway from parent_atespace # Data Plane Ingress: Routers (or editors) can resume define can_resume: [user] or editor from parent_atespace or ingress_router from parent_atespace diff --git a/cmd/ateapi/internal/authz/model_test.fga.yaml b/cmd/ateapi/internal/authz/model_test.fga.yaml index 02741ca1db..3962a8072b 100644 --- a/cmd/ateapi/internal/authz/model_test.fga.yaml +++ b/cmd/ateapi/internal/authz/model_test.fga.yaml @@ -401,7 +401,6 @@ tests: can_get: true can_get_egress_policy: true can_mint_actor_jwt: true - can_mint_actor_certificate: true can_update: false can_delete: false can_create_egress_policy: false @@ -430,7 +429,6 @@ tests: can_update_egress_policy: false can_delete_egress_policy: false can_mint_actor_jwt: false - can_mint_actor_certificate: false can_resume: false can_suspend: false - user: user:sys-atelet @@ -456,7 +454,6 @@ tests: can_resume: false can_suspend: false can_mint_actor_jwt: false - can_mint_actor_certificate: false - user: user:sys-api-server-sidecar object: atespace:space-1 assertions: @@ -567,14 +564,11 @@ tests: object: actor:runner-1 assertions: can_mint_actor_jwt: false - can_mint_actor_certificate: false - user: user:bob # Atespace editor object: actor:runner-1 assertions: can_mint_actor_jwt: false - can_mint_actor_certificate: false - user: user:sys-router object: actor:runner-1 assertions: can_mint_actor_jwt: false - can_mint_actor_certificate: false diff --git a/cmd/ateapi/internal/authz/registry.go b/cmd/ateapi/internal/authz/registry.go index 741e716bbd..951a27480b 100644 --- a/cmd/ateapi/internal/authz/registry.go +++ b/cmd/ateapi/internal/authz/registry.go @@ -298,9 +298,6 @@ var defaultRPCPermissions = map[string]rpcRule{ ateapi.Control_MintActorJwt_FullMethodName: rule(checksOf(func(r *ateapi.MintActorJwtRequest) ([]check, field.ErrorList) { return onActor(RelationCanMintActorJWT, r.GetActor(), field.NewPath("actor")) })), - ateapi.Control_MintActorCertificate_FullMethodName: rule(checksOf(func(r *ateapi.MintActorCertificateRequest) ([]check, field.ErrorList) { - return onActor(RelationCanMintActorCertificate, r.GetActor(), field.NewPath("actor")) - })), // Tags. CreateTag stores the tag in its source actor's atespace, so that is // the atespace checked. Validation also requires metadata.atespace to diff --git a/cmd/ateapi/internal/authz/registry_test.go b/cmd/ateapi/internal/authz/registry_test.go index 57d2b6bc77..51ada93341 100644 --- a/cmd/ateapi/internal/authz/registry_test.go +++ b/cmd/ateapi/internal/authz/registry_test.go @@ -281,12 +281,6 @@ func TestDefaultRPCPermissions(t *testing.T) { req: &ateapi.MintActorJwtRequest{Actor: actorRef}, want: []check{{RelationCanMintActorJWT, "actor:team-a/runner"}}, }, - { - name: "MintActorCertificate", - fullMethod: ateapi.Control_MintActorCertificate_FullMethodName, - req: &ateapi.MintActorCertificateRequest{Actor: actorRef}, - want: []check{{RelationCanMintActorCertificate, "actor:team-a/runner"}}, - }, // Tags. { @@ -603,12 +597,6 @@ func TestDefaultRPCPermissions_MalformedIdentifierFailsClosed(t *testing.T) { req: &ateapi.MintActorJwtRequest{}, wantField: "actor.atespace", }, - { - name: "MintActorCertificate with an invalid name", - fullMethod: ateapi.Control_MintActorCertificate_FullMethodName, - req: &ateapi.MintActorCertificateRequest{Actor: &ateapi.ObjectRef{Atespace: "team-a", Name: "a/b"}}, - wantField: "actor.name", - }, { name: "CreateTag without a source actor", fullMethod: ateapi.Control_CreateTag_FullMethodName, diff --git a/cmd/ateapi/internal/controlapi/access_policy_test.go b/cmd/ateapi/internal/controlapi/access_policy_test.go index 316628d073..ac9271cf09 100644 --- a/cmd/ateapi/internal/controlapi/access_policy_test.go +++ b/cmd/ateapi/internal/controlapi/access_policy_test.go @@ -48,7 +48,7 @@ func TestAccessPolicy_GlobalAndAtespaceGovernance(t *testing.T) { } persistence.SetPolicyManager(policyManager) - svc := NewRPCService(persistence, nil, nil, nil, nil, nil, "", nil, nil, "", nil, nil, "") + svc := NewRPCService(persistence, nil, nil, nil, nil, nil, "", nil, nil, "", nil, "") interceptor := authz.UnaryServerInterceptor(authorizer) userCtx := func(id string) context.Context { diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index bd092788e0..8cac775de9 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -17,11 +17,8 @@ package controlapi import ( "context" "crypto/rand" - "crypto/x509" "errors" "fmt" - "log/slog" - "net/url" "slices" "time" @@ -34,10 +31,7 @@ import ( "go.ate.dev/substrate/internal/ateattr" "go.ate.dev/substrate/internal/preview" "go.ate.dev/substrate/internal/resources" - "go.ate.dev/substrate/internal/substratex509" "go.opentelemetry.io/otel/attribute" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" "k8s.io/apimachinery/pkg/util/validation/field" @@ -608,87 +602,3 @@ func (s *RPCService) MintActorJwt(ctx context.Context, req *ateapi.MintActorJwtR ExpireTime: timestamppb.New(expiresAt), }, nil } - -func (s *RPCService) MintActorCertificate(ctx context.Context, req *ateapi.MintActorCertificateRequest) (*ateapi.MintActorCertificateResponse, error) { - if errs := apivalidation.ValidateMintActorCertificateRequest(ctx, req); len(errs) > 0 { - return nil, resources.ToAPIError(errs) - } - - // With authz enforced, the interceptor requires can_mint_actor_certificate - // on the actor, which only the egress gateway holds. - - // Check that the caller authenticated with a client certificate --- we - // should not allow bootstrapping a proof-of-possession credential from a - // bearer credential. Note, we don't care that it was a certificate issued - // by Substrate, or something else. - // - // TODO(authz): Perhaps this can be handled with an OpenFGA condition. - p, ok := peer.FromContext(ctx) - if !ok { - return nil, apierror.Unauthenticated("no peer transport information found") - } - tlsInfo, ok := p.AuthInfo.(credentials.TLSInfo) - if !ok { - return nil, apierror.Unauthenticated("unexpected peer transport credentials") - } - if len(tlsInfo.State.PeerCertificates) == 0 { - return nil, apierror.Unauthenticated("could not verify peer certificate") - } - - // Verify that this actor exists in the store. It doesn't need to be - // running, since we may need to issue certificates during actor boot / resume. - dbActor, err := s.impl.GetActor(ctx, resources.ActorRefFromObjectRef(req.GetActor())) - if errors.Is(err, store.ErrNotFound) { - return nil, apierror.NotFound("actor not found") - } else if err != nil { - return nil, fmt.Errorf("while retrieving actor: %w", err) - } - if dbActor.GetMetadata().GetUid() != req.GetActorUid() { - return nil, apierror.Aborted("conflict; actor has been deleted and recreated") - } - - // Parse the CSR - csr, err := x509.ParseCertificateRequest(req.GetCertificateSigningRequest()) - if err != nil { - return nil, fmt.Errorf("while parsing CSR: %w", err) - } - if err := csr.CheckSignature(); err != nil { - slog.ErrorContext(ctx, "Failed to verify CSR signature", slog.Any("err", err)) - return nil, apierror.InvalidArgument("Failed to verify CSR signature") - } - - template := &x509.Certificate{ - URIs: []*url.URL{resources.ActorSPIFFEID(resources.ActorRef{ - Atespace: dbActor.GetMetadata().GetAtespace(), - Name: dbActor.GetMetadata().GetName(), - })}, - NotBefore: time.Now().Add(-5 * time.Minute), - NotAfter: time.Now().Add(time.Hour), - KeyUsage: x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - IsCA: false, - } - - err = substratex509.AddActorIdentityToCertificate( - &substratex509.ActorIdentity{ - Atespace: dbActor.GetMetadata().GetAtespace(), - ActorName: dbActor.GetMetadata().GetName(), - ActorUid: dbActor.GetMetadata().GetUid(), - }, - template, - ) - if err != nil { - return nil, fmt.Errorf("while adding Substrate extension: %w", err) - } - - // Sign and return the actor cert. - chain, err := s.actorIDCAPool.CreateCertificate(template, csr.PublicKey) - if err != nil { - return nil, fmt.Errorf("while signing certificate: %w", err) - } - - return &ateapi.MintActorCertificateResponse{ - ActorCertificates: chain, - }, nil -} diff --git a/cmd/ateapi/internal/controlapi/actor_test.go b/cmd/ateapi/internal/controlapi/actor_test.go index f1c3b5fd96..1c8ea23255 100644 --- a/cmd/ateapi/internal/controlapi/actor_test.go +++ b/cmd/ateapi/internal/controlapi/actor_test.go @@ -16,16 +16,10 @@ package controlapi import ( "context" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" "errors" "fmt" "strings" "testing" - "time" "github.com/google/go-cmp/cmp" "go.ate.dev/substrate/api/ateapi/v1" @@ -34,13 +28,9 @@ import ( "go.ate.dev/substrate/cmd/ateapi/internal/store/storetest" "go.ate.dev/substrate/internal/apierror" "go.ate.dev/substrate/internal/ateattr" - "go.ate.dev/substrate/internal/localca" "go.ate.dev/substrate/internal/preview" "go.ate.dev/substrate/internal/resources" - "go.ate.dev/substrate/internal/substratex509" "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/timestamppb" @@ -1069,101 +1059,3 @@ func TestCreateActor_GoldenTagDefault(t *testing.T) { }) } } - -type fakeActorServiceStore struct { - serviceStore - actors map[resources.ActorRef]*ateapi.Actor -} - -func (f *fakeActorServiceStore) GetActor(_ context.Context, actorRef resources.ActorRef) (*ateapi.Actor, error) { - a, ok := f.actors[actorRef] - if !ok { - return nil, store.ErrNotFound - } - return a, nil -} - -func TestMintActorCertificate(t *testing.T) { - ctx := peer.NewContext(context.Background(), &peer.Peer{ - AuthInfo: credentials.TLSInfo{ - State: tls.ConnectionState{ - PeerCertificates: []*x509.Certificate{{}}, - }, - }, - }) - - actorUID := "3b9f1e77-2c4d-4a80-91be-6d5c8f0a7e21" - created := &ateapi.Actor{ - Metadata: &ateapi.ResourceMetadata{Atespace: testAtespace, Name: testActorID, Uid: actorUID}, - ActorTemplate: &ateapi.ObjectRef{Atespace: testAtespace, Name: "tmpl-1"}, - Status: &ateapi.ActorStatus{State: ateapi.ActorState_ACTOR_STATE_RUNNING}, - } - fakeStore := &fakeActorServiceStore{ - actors: map[resources.ActorRef]*ateapi.Actor{ - {Atespace: testAtespace, Name: testActorID}: created, - }, - } - - ca, err := localca.GenerateCA("1", localca.KeyTypeECDSAP256, 24*time.Hour) - if err != nil { - t.Fatalf("GenerateCA: %v", err) - } - caPool := &localca.ConcretePool{ - CAs: []*localca.CA{ca}, - ActiveForSigning: "1", - } - - svc := &RPCService{ - impl: fakeStore, - actorIDCAPool: caPool, - } - - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatalf("GenerateKey: %v", err) - } - csr, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{}, key) - if err != nil { - t.Fatalf("CreateCertificateRequest: %v", err) - } - - resp, err := svc.MintActorCertificate(ctx, &ateapi.MintActorCertificateRequest{ - Actor: &ateapi.ObjectRef{Atespace: testAtespace, Name: testActorID}, - ActorUid: created.GetMetadata().GetUid(), - CertificateSigningRequest: csr, - }) - if err != nil { - t.Fatalf("MintActorCertificate() failed: %v", err) - } - - chain := resp.GetActorCertificates() - if len(chain) == 0 { - t.Fatal("MintActorCertificate() returned empty chain") - } - - leaf, err := x509.ParseCertificate(chain[0]) - if err != nil { - t.Fatalf("ParseCertificate: %v", err) - } - if !key.PublicKey.Equal(leaf.PublicKey) { - t.Error("leaf public key does not match CSR key") - } - - wantURI := fmt.Sprintf("spiffe://substrate-actor.local/actor/%s/%s", testAtespace, testActorID) - if len(leaf.URIs) != 1 || leaf.URIs[0].String() != wantURI { - t.Errorf("leaf URIs = %v, want [%s]", leaf.URIs, wantURI) - } - - identity, err := substratex509.ActorIdentityFromCertificate(leaf) - if err != nil { - t.Fatalf("ActorIdentityFromCertificate: %v", err) - } - wantIdentity := &substratex509.ActorIdentity{ - Atespace: testAtespace, - ActorName: testActorID, - ActorUid: created.GetMetadata().GetUid(), - } - if diff := cmp.Diff(wantIdentity, identity); diff != "" { - t.Errorf("ActorIdentity mismatch (-want +got):\n%s", diff) - } -} diff --git a/cmd/ateapi/internal/controlapi/functionaltest/common_test.go b/cmd/ateapi/internal/controlapi/functionaltest/common_test.go index 0bc8ae3206..769888ca71 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/common_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/common_test.go @@ -30,7 +30,6 @@ import ( "go.ate.dev/substrate/cmd/ateapi/internal/workercache" "go.ate.dev/substrate/internal/ateinterceptors" "go.ate.dev/substrate/internal/installdefaults" - "go.ate.dev/substrate/internal/localca" "go.ate.dev/substrate/internal/localjwtauthority" "go.ate.dev/substrate/internal/objectstore/objectstoretest" "go.ate.dev/substrate/internal/objectstoreplugin/objectstoreplugintest" @@ -219,18 +218,6 @@ func setupTestWithOptions(t *testing.T, ns string, options testOptions) *testCon ActiveForSigning: "1", } - actorCA, err := localca.GenerateCA("1", localca.KeyTypeECDSAP256, 365*24*time.Hour) - if err != nil { - t.Fatalf("Error generating actor CA: %v", err) - } - - actorCAPool := &localca.ConcretePool{ - CAs: []*localca.CA{ - actorCA, - }, - ActiveForSigning: "1", - } - objectStore := objectstoretest.New() service := controlapi.NewRPCService( @@ -245,7 +232,6 @@ func setupTestWithOptions(t *testing.T, ns string, options testOptions) *testCon objectstoreplugintest.ControlClient(objectStore), testActorJWTIssuer, actorJWTAuthorityPool, - actorCAPool, testStorageLocation, ) diff --git a/cmd/ateapi/internal/controlapi/service.go b/cmd/ateapi/internal/controlapi/service.go index 96881b73d8..639db638b0 100644 --- a/cmd/ateapi/internal/controlapi/service.go +++ b/cmd/ateapi/internal/controlapi/service.go @@ -22,7 +22,6 @@ import ( "go.ate.dev/substrate/api/objectstore/v1" "go.ate.dev/substrate/cmd/ateapi/internal/store" "go.ate.dev/substrate/cmd/ateapi/internal/workercache" - "go.ate.dev/substrate/internal/localca" "go.ate.dev/substrate/internal/localjwtauthority" "go.ate.dev/substrate/internal/resources" "go.ate.dev/substrate/internal/volume" @@ -52,7 +51,6 @@ type RPCService struct { actorJWTIssuer string actorIDJWTPool localjwtauthority.Pool - actorIDCAPool localca.Pool } var _ ateapi.ControlServer = (*RPCService)(nil) @@ -87,7 +85,6 @@ func NewRPCService( objectStorePlugin objectstore.ControlProviderClient, actorJWTIssuer string, actorIDJWTPool localjwtauthority.Pool, - actorIDCAPool localca.Pool, snapshotLocation string, ) *RPCService { impl := newServiceImpl(persistence, storageClassLister) @@ -103,7 +100,6 @@ func NewRPCService( objectStorePlugin: objectStorePlugin, actorJWTIssuer: actorJWTIssuer, actorIDJWTPool: actorIDJWTPool, - actorIDCAPool: actorIDCAPool, } s.actorWorkflow = NewActorWorkflow(impl, workerCache, dialer, storageClassLister, instruments, egressGatewayAddress, s, objectStorePlugin) s.actorWorkflow.clusterSnapshotLocation = snapshotLocation diff --git a/cmd/ateapi/main.go b/cmd/ateapi/main.go index 9ade6ee253..aadc9cd574 100644 --- a/cmd/ateapi/main.go +++ b/cmd/ateapi/main.go @@ -355,7 +355,6 @@ func main() { objectstore.NewControlProviderClient(objectStorePluginConn), *actorJWTIssuer, actorIDJWTAuthorityPool, - actorIDCAPool, *snapshotLocation, ) diff --git a/docs/guides/authorization.md b/docs/guides/authorization.md index 62fde72a62..fa726e2f7c 100644 --- a/docs/guides/authorization.md +++ b/docs/guides/authorization.md @@ -143,7 +143,7 @@ through their pod certificates. `ate-api-server`'s `--controller-spiffe-id`, | Role | Held by | Allows | |---|---|---| | `controller` | `ate-controller` | Create, get, list, update, delete and drain workers | -| `egress_gateway` | `atenet-egress`, and any other SPIFFE IDs passed with `--egress-gateway-spiffe-id`, which ate-setup sets from `ATE_EGRESS_GATEWAY_EXTRA_SPIFFE_IDS` | Get actors and their egress policies; list actors across all atespaces; mint actor JWTs and certificates | +| `egress_gateway` | `atenet-egress`, and any other SPIFFE IDs passed with `--egress-gateway-spiffe-id`, which ate-setup sets from `ATE_EGRESS_GATEWAY_EXTRA_SPIFFE_IDS` | Get actors and their egress policies; list actors across all atespaces; mint actor JWTs | | `ingress_router` | `atenet-router` | Resume actors; list actors across all atespaces | | `atelet` | `atelet` | Get actors' egress policies, for the worker that enforces them | | `api_server_sidecar` | the `ate-api-server` pod identity, which its sidecars share, today the objectstore control plugin | Get actors, to derive the snapshot prefixes a per-actor storage credential may cover | @@ -192,7 +192,7 @@ viewer, and a global role holds the same role in every atespace. So | `ResumeActor` | `can_resume`, the actor | Editor of its atespace; `atenet-router` | | `GetActorEgressPolicy` | `can_get_egress_policy`, the actor | Viewer of its atespace; `atenet-egress`; `atelet` | | `CreateActorEgressPolicy`, `UpdateActorEgressPolicy`, `DeleteActorEgressPolicy` | `can_create_egress_policy` / `can_update_egress_policy` / `can_delete_egress_policy`, the actor | Editor of its atespace | -| `MintActorJwt`, `MintActorCertificate` | `can_mint_actor_jwt` / `can_mint_actor_certificate`, the actor | `atenet-egress` only | +| `MintActorJwt` | `can_mint_actor_jwt`, the actor | `atenet-egress` only | ### Tags diff --git a/docs/reference/api-guide.md b/docs/reference/api-guide.md index e22e77f2c5..68e883c867 100644 --- a/docs/reference/api-guide.md +++ b/docs/reference/api-guide.md @@ -756,7 +756,7 @@ Query the physical resource pool. ate-api-server mints credentials that identify an actor to services outside Substrate. They name the logical actor, so they stay the same as the actor moves between workers. This is distinct from the `actorMetadata` data source described under [SystemInfo Volumes](#systeminfo-volumes), which only tells an actor its own identity fields (name, atespace, uid). -Both RPCs are on `substrate.ateapi.v1.Control`. Only the egress gateway may call them; see [authorization.md](../guides/authorization.md). It calls `MintActorJwt` when an egress policy injects an actor JWT into a request. +`MintActorJwt` is on `substrate.ateapi.v1.Control`. Only the egress gateway may call it; see [authorization.md](../guides/authorization.md). It calls this RPC when an egress policy injects an actor JWT into a request. ### `MintActorJwt` @@ -774,13 +774,6 @@ The token's header carries `typ: JWT`, the algorithm of the pool's active signin Relying parties find the signing keys through OpenID Connect Discovery at `/.well-known/openid-configuration`, which ate-idp-server serves in every install. -### `MintActorCertificate` - -* **Request:** `actor`; `actor_uid`, which must match the actor's current UID, so that a deleted and recreated actor isn't mistaken for the old one (`ABORTED` otherwise); and `certificate_signing_request`, a DER-encoded CSR. The signer checks the CSR's signature and uses only its public key. -* **Response:** `actor_certificates`, DER certificates with the leaf first, followed by any intermediates. - -The caller must connect with a client certificate; a bearer token is not enough. The leaf is valid for one hour, allows client and server authentication, carries the SPIFFE URI `spiffe://substrate-actor.local/actor//`, and has the `ActorIdentity` X.509 extension with the actor's atespace, name, and UID. - --- ## 8. Framework & Ecosystem Integration diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index c674b1fde6..ae8f1b4f7a 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -1772,7 +1772,7 @@ type MintActorCertificateRequest struct { // corresponding private key. // // +k8s:required - // +k8s:maxBytes=16384 # matches the control-plane MintActorCertificateRequest bound this is forwarded to + // +k8s:maxBytes=16384 # matches the control-plane MintWorkerActorCertificateRequest bound this is forwarded to CertificateSigningRequest []byte `protobuf:"bytes,4,opt,name=certificate_signing_request,json=certificateSigningRequest,proto3" json:"certificate_signing_request,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index 9b20950f62..4a1426ba25 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -436,7 +436,7 @@ message MintActorCertificateRequest { // corresponding private key. // // +k8s:required - // +k8s:maxBytes=16384 # matches the control-plane MintActorCertificateRequest bound this is forwarded to + // +k8s:maxBytes=16384 # matches the control-plane MintWorkerActorCertificateRequest bound this is forwarded to bytes certificate_signing_request = 4; } From 40bf20fe47bd66ea01e23454bcd2b8edda94abe8 Mon Sep 17 00:00:00 2001 From: Benjamin Elder Date: Thu, 29 Oct 2026 16:57:55 +0000 Subject: [PATCH 02/16] fix atelet deviceplugin wedge (#3323) Why is this needed? (Or link the issue. Open one first for features, API, install or CI changes.) Fixes #3272 Since 1.37, kubelet wedges a device plugin resource if a second Register for the same socket arrives while it is still closing the first stream. The failed connect deregisters both clients by socket path: https://github.com/kubernetes/kubernetes/blob/v1.37.0/pkg/kubelet/cm/devicemanager/plugin/v1beta1/handler.go#L82-L86 So when the first stream ends, kubelet never calls PluginDisconnected, and every later Register fails with "device plugin already connected" until kubelet restarts: https://github.com/kubernetes/kubernetes/blob/v1.37.0/pkg/kubelet/cm/devicemanager/plugin/v1beta1/handler.go#L137-L140 atelet keeps one fsnotify watcher across registration retries, so a kubelet.sock Create that was queued while it retried made it stop and re-register right after registering. It now ignores the Create if kubelet.sock is still the socket it registered with. A node that is already wedged still needs a kubelet restart. AI use: I used Claude to trace this through the kubelet source and draft the fix, and reviewed it. - [x] Tests pass - [x] Docs updated --------- Signed-off-by: Benjamin Elder --- cmd/atelet/main.go | 5 ++- internal/deviceplugin/deviceplugin.go | 28 +++++++++++-- internal/deviceplugin/deviceplugin_test.go | 49 ++++++++++++++++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 90926c2e07..24f86122fb 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -235,7 +235,10 @@ func main() { }() } - startDevicePlugins(ctx) + // stopped on SIGTERM because the replacement pod starts while we drain and + // registers the same socket, and kubelet can wedge the resource when two + // registrations for one socket overlap + startDevicePlugins(shutdownCtx) workerDialer := newWorkerDialer(256) diff --git a/internal/deviceplugin/deviceplugin.go b/internal/deviceplugin/deviceplugin.go index d834975b87..f64e0b69f7 100644 --- a/internal/deviceplugin/deviceplugin.go +++ b/internal/deviceplugin/deviceplugin.go @@ -165,7 +165,10 @@ func (p *Plugin) Run(ctx context.Context) error { slog.InfoContext(ctx, "Device plugin registered", slog.String("resource", p.dev.ResourceName), slog.String("device", p.dev.Path)) - p.waitForKubeletRestart(ctx, watcher) + // stat after registering, so a Create already queued for this same + // socket (say, kubelet came up while we slept on a retry) is ignored + registered, _ := os.Stat(pluginapi.KubeletSocket) + p.waitForKubeletRestart(ctx, watcher, registered) srv.Stop() } return ctx.Err() @@ -223,8 +226,9 @@ func (p *Plugin) register(ctx context.Context) error { } // waitForKubeletRestart blocks until kubelet recreates its socket (meaning it -// restarted and dropped our registration) or ctx is cancelled. -func (p *Plugin) waitForKubeletRestart(ctx context.Context, watcher *fsnotify.Watcher) { +// restarted and dropped our registration) or ctx is cancelled. registered is +// the kubelet socket we registered with, nil if it could not be stat'd. +func (p *Plugin) waitForKubeletRestart(ctx context.Context, watcher *fsnotify.Watcher, registered os.FileInfo) { for { select { case <-ctx.Done(): @@ -233,7 +237,7 @@ func (p *Plugin) waitForKubeletRestart(ctx context.Context, watcher *fsnotify.Wa if !ok { return } - if event.Name == pluginapi.KubeletSocket && event.Has(fsnotify.Create) { + if kubeletRestarted(event, pluginapi.KubeletSocket, registered) { slog.InfoContext(ctx, "Kubelet restarted; re-registering device plugin", slog.String("resource", p.dev.ResourceName)) return @@ -248,6 +252,22 @@ func (p *Plugin) waitForKubeletRestart(ctx context.Context, watcher *fsnotify.Wa } } +// kubeletRestarted reports whether event is kubelet recreating socket since we +// stat'd it as registered. Re-registering on a stale event can wedge the +// resource in kubelet as "already connected", if the second Register for our +// socket arrives while kubelet is still closing the first stream. +func kubeletRestarted(event fsnotify.Event, socket string, registered os.FileInfo) bool { + if event.Name != socket || !event.Has(fsnotify.Create) { + return false + } + if registered == nil { + return true + } + // mtime too, as a just freed inode can be reused for the new socket + fi, err := os.Stat(socket) + return err != nil || !os.SameFile(fi, registered) || !fi.ModTime().Equal(registered.ModTime()) +} + // GetDevicePluginOptions implements the device plugin API; the defaults are // correct here. func (p *Plugin) GetDevicePluginOptions(context.Context, *pluginapi.Empty) (*pluginapi.DevicePluginOptions, error) { diff --git a/internal/deviceplugin/deviceplugin_test.go b/internal/deviceplugin/deviceplugin_test.go index a67c1c839d..a66f5e76e0 100644 --- a/internal/deviceplugin/deviceplugin_test.go +++ b/internal/deviceplugin/deviceplugin_test.go @@ -19,7 +19,9 @@ import ( "os" "path/filepath" "testing" + "time" + "github.com/fsnotify/fsnotify" "google.golang.org/grpc" pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1" ) @@ -158,6 +160,53 @@ func TestListAndWatchSendsDevicesThenBlocks(t *testing.T) { } } +// Only a Create for a kubelet socket other than the one we registered with +// is a restart; one already queued for that same socket is stale. +func TestKubeletRestartedIgnoresStaleCreate(t *testing.T) { + dir := t.TempDir() + socket := filepath.Join(dir, "kubelet.sock") + if err := os.WriteFile(socket, nil, 0o600); err != nil { + t.Fatal(err) + } + registered, err := os.Stat(socket) + if err != nil { + t.Fatal(err) + } + create := fsnotify.Event{Name: socket, Op: fsnotify.Create} + + if kubeletRestarted(create, socket, registered) { + t.Error("kubeletRestarted() = true for a Create of the registered socket") + } + if kubeletRestarted(fsnotify.Event{Name: filepath.Join(dir, "other.sock"), Op: fsnotify.Create}, socket, registered) { + t.Error("kubeletRestarted() = true for another socket") + } + if kubeletRestarted(fsnotify.Event{Name: socket, Op: fsnotify.Write}, socket, registered) { + t.Error("kubeletRestarted() = true for a Write") + } + if !kubeletRestarted(create, socket, nil) { + t.Error("kubeletRestarted() = false with no registered socket") + } + + // kubelet restarting unlinks and recreates its socket + if err := os.Remove(socket); err != nil { + t.Fatal(err) + } + if !kubeletRestarted(create, socket, registered) { + t.Error("kubeletRestarted() = false with the socket gone") + } + if err := os.WriteFile(socket, nil, 0o600); err != nil { + t.Fatal(err) + } + // the inode may be reused, so only mtime tells them apart + later := registered.ModTime().Add(time.Second) + if err := os.Chtimes(socket, later, later); err != nil { + t.Fatal(err) + } + if !kubeletRestarted(create, socket, registered) { + t.Error("kubeletRestarted() = false for a recreated socket") + } +} + type fakeListAndWatchStream struct { grpc.ServerStream ctx context.Context From 427f2fba76df963d106856e3276ea6aeaa2880e1 Mon Sep 17 00:00:00 2001 From: Greg Castle Date: Thu, 29 Oct 2026 17:20:02 +0000 Subject: [PATCH 03/16] docs: say "no escape" from the sandbox on the ate.dev home page and security overview (#3440) The zero-trust tagline said "no unauthorized way out of the sandbox" on the home page and "no way out of the sandbox" in the security overview, and the home page's sandboxing card was labelled "No way out". This changes all three to "no escape", which is a shorter and catchier way to say "no unauthorized" and makes the home page and security overview match. AI use: AI-assisted, I reviewed and tested it. - [x] Tests pass - [x] Docs updated Signed-off-by: Greg Castle --- docs/security/security.md | 2 +- site/layouts/_shortcodes/home.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/security/security.md b/docs/security/security.md index 8d871097ee..92860e4aa2 100644 --- a/docs/security/security.md +++ b/docs/security/security.md @@ -8,7 +8,7 @@ description: > # Substrate Security -Substrate delivers zero trust for agents. Every agent has an identity, but no credentials, no open network, and no way out of the sandbox. +Substrate delivers zero trust for agents. Every agent has an identity, but no credentials, no open network, and no escape from the sandbox. Agent Substrate executes untrusted actors at scale in a multi-tenant environment where workloads are dynamic and memory states migrate continuously across physical infrastructure. All security controls operate within Substrate's cold-start and resume latency budget. This document defines the high-level security principles. For identity and credential configuration, see the [Authentication Guide](../guides/authentication.md). Detailed threat scenarios and mitigating invariants are documented [in the threat model](threat-model.md). diff --git a/site/layouts/_shortcodes/home.html b/site/layouts/_shortcodes/home.html index dabfec5092..a2cf4f18e8 100644 --- a/site/layouts/_shortcodes/home.html +++ b/site/layouts/_shortcodes/home.html @@ -177,7 +177,7 @@

Run millions of agents, secur
ZERO TRUST FOR AGENTS -

Every agent has an identity, but no credentials, no open network, and no unauthorized way out of the sandbox.

+

Every agent has an identity, but no credentials, no open network, and no escape from the sandbox.

Instead of sharing a process across users, Agent Substrate isolates every actor in its own single-tenant sandbox while multiplexing thousands of them across shared physical hosts.

@@ -243,7 +243,7 @@

Every agent has an identity, but no credentials, no
- No way out + No escape

Sandboxed Single-Tenant Actors
From 6949841e9dc98edbd2e0042ef95c19b4ce20aef5 Mon Sep 17 00:00:00 2001 From: Luomu Date: Thu, 29 Oct 2026 17:40:11 +0000 Subject: [PATCH 04/16] docs: average ate.workerpool.workers across replicas before summing (#3193) The aggregation note from #3056 tells readers to take the `max` across ate-api-server replicas and then `sum`. As #3162 shows, the replicas read separate worker caches and can disagree for a few seconds: one reports `{ate_worker_state="partial"} 3` while the other still reports `{ate_worker_state="idle"} 3`, so `max by (ate_worker_state)` keeps both series and the pool sums to 6 workers. Take the average across replicas instead. It keeps the sum across the states equal to the pool size; the counts can be fractional for those few seconds. Updates the registry note and the observability guide. No code change: the locust collector already reads a single process's series, and nothing else aggregates this instrument. Fixes #3162 AI use: Claude Code analyzed the issue and wrote the change and this description. I reviewed the diff. Codex rebased the branch onto main and resolved the documentation conflicts. --------- Signed-off-by: cloudonly --- docs/guides/observability.md | 6 +++--- docs/metrics/registry/metrics.yaml | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/guides/observability.md b/docs/guides/observability.md index 8a69862a17..5450025b06 100644 --- a/docs/guides/observability.md +++ b/docs/guides/observability.md @@ -290,7 +290,7 @@ Agent Substrate emits foundational OpenTelemetry system and server metrics to mo | `atelet.snapshot.size` | atelet | histogram | uncompressed allocated size in bytes of each snapshot image written during checkpoint (`st_blocks * 512`, excluding sparse holes in microVM `memory-ranges`) (labels `file.name`, `ate.template.atespace`, `ate.template.name`) | | `ate.workerpool.desired_workers` | atecontroller | up/down counter | number of worker pods requested for a WorkerPool, from `spec.replicas` (labels `ate.workerpool.namespace`, `ate.workerpool.name`) | | `ate.workerpool.ready_workers` | atecontroller | up/down counter | number of worker pods currently ready for a WorkerPool, from `status.readyReplicas` (labels `ate.workerpool.namespace`, `ate.workerpool.name`) | -| `ate.workerpool.workers` | ateapi | up/down counter | live worker count per pool, split by state (`idle`/`partial`/`at_capacity`/`unschedulable`) and sandbox class to provide fleet capacity and saturation at a glance. Every ateapi replica reports the whole fleet: take the `max` by pool namespace, pool, state, and sandbox class first, then `sum` (example query below the table) | +| `ate.workerpool.workers` | ateapi | up/down counter | live worker count per pool, split by state (`idle`/`partial`/`at_capacity`/`unschedulable`) and sandbox class to provide fleet capacity and saturation at a glance. Every ateapi replica reports the whole fleet: take the `avg` by pool namespace, pool, state, and sandbox class first, then `sum` (example query below the table) | | `ate.actor.lifecycle.operation.duration` | ateapi | histogram | how long each actor operation (create/resume/suspend/delete/revert) takes and whether it failed (`error.type` present = failure, absent = success); labeled by operation, template, pool (`ate.workerpool.namespace` + `ate.workerpool.name`), sandbox class, snapshot kind on resume, and snapshot fidelity on resume and suspend; already-running resume no-ops are not recorded so the histogram tracks actual activations, not router traffic | | `ate.scheduler.assignment.duration` | ateapi | histogram | time of one attempt to assign a worker to an actor, with one record for each resume (ateapi retries an attempt that loses a race for a worker and records only the last attempt), with the outcome (`assigned` / `no_capacity` / `error`), the assigned pool (`ate.workerpool.namespace` + `ate.workerpool.name`) and sandbox class to catch scheduling latency and capacity starvation problems | | `ate.actor.restore.duration` | atelet | histogram | how long each phase of a restore takes on the worker node, which is where cold-start latency actually goes once ateapi hands off (labels `ate.snapshot.phase`, `ate.snapshot.kind`, `ate.snapshot.fidelity`, `ate.template.atespace`, `ate.template.name`, `ate.sandbox.class`) | @@ -313,11 +313,11 @@ For `ate.workerpool.desired_workers` and `ate.workerpool.ready_workers`: * **Autoscaling Control Loop & Anti-Windup**: `desired - ready > 0` sustained beyond a few minutes indicates undelivered capacity due to node pool exhaustion, quota limits, or stuck worker pods, serving as anti-windup input for demand-reactive capacity scaling. For `ate.workerpool.workers`: -* Every ateapi replica reports the whole fleet, so a plain `sum` counts each worker once per replica ([#3055](https://github.com/agent-substrate/substrate/issues/3055)). Take the `max` across replicas first, keeping the pool namespace, pool, state, and sandbox class, then `sum`. Workers per pool: +* Every ateapi replica reports the whole fleet, so a plain `sum` counts each worker once per replica ([#3055](https://github.com/agent-substrate/substrate/issues/3055)). The replicas read separate worker caches and can disagree for a few seconds: a worker that changed state sits under its old state on one replica and its new state on the other ([#3162](https://github.com/agent-substrate/substrate/issues/3162)). Take the `avg` across replicas first, keeping the pool namespace, pool, state, and sandbox class, then `sum`. A `max` would keep that worker under both states and the summed pool outgrows its real size. The average keeps the sum equal to the pool size; the counts can be fractional while the replicas disagree. Workers per pool: ```promql sum by ("ate.workerpool.namespace", "ate.workerpool.name") ( - max by ("ate.workerpool.namespace", "ate.workerpool.name", "ate.worker.state", "ate.sandbox.class") ( + avg by ("ate.workerpool.namespace", "ate.workerpool.name", "ate.worker.state", "ate.sandbox.class") ( {"ate.workerpool.workers"} ) ) diff --git a/docs/metrics/registry/metrics.yaml b/docs/metrics/registry/metrics.yaml index 41f9171fdf..6ff75f258c 100644 --- a/docs/metrics/registry/metrics.yaml +++ b/docs/metrics/registry/metrics.yaml @@ -846,13 +846,18 @@ groups: brief: The number of workers in each pool, divided by state and by sandbox class. note: > ateapi reads this value with a callback. Each ateapi replica reports the - whole fleet, and the default install runs two replicas. Thus a sum across - the replicas counts each worker once for each replica. Take the maximum - across the replicas first, by pool namespace, pool, state and sandbox - class, and add after that. Within one replica you can add the counts - together. The sum across the states is the size of the pool. The sum - across the pools is the size of the fleet. Thus this instrument is an - UpDownCounter + whole fleet from its own worker cache, and the default install runs two + replicas. Thus a sum across the replicas counts each worker once for + each replica. The caches can disagree for a few seconds, and a worker + that changed state then sits under its old state on one replica and + under its new state on the other. Take the average across the replicas + first, by pool namespace, pool, state and sandbox class, and add after + that. A maximum would count that worker twice, once under each state. + The average keeps the sum across the states equal to the size of the + pool, and the counts can be fractional while the replicas disagree. + Within one replica you can add the counts together. The sum across the + states is the size of the pool. The sum across the pools is the size of + the fleet. Thus this instrument is an UpDownCounter and not a gauge. ateapi sets every state to 0 for each known pool. Thus a full pool or an empty pool reports 0. An absent series would stop an alert on idle == 0. From 0d662b85d3a986e004d5f475b2aeec6b5498791a Mon Sep 17 00:00:00 2001 From: haiyanmeng Date: Thu, 29 Oct 2026 20:31:24 +0000 Subject: [PATCH 05/16] benchmarking: stop uploading the duplicate {name}.jsonl (#3309) The locust runner uploads the same stats file twice, as `stats.jsonl` and `{name}.jsonl`. The second copy was kept for a data migration (see the removed TODO). Nothing in the repo reads it now. I used Claude Code to find the duplicate upload and make the edit. I reviewed the diff. Signed-off-by: Haiyan Meng --- benchmarking/locust/runner.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/benchmarking/locust/runner.py b/benchmarking/locust/runner.py index 03bf485e89..0877c07cc5 100644 --- a/benchmarking/locust/runner.py +++ b/benchmarking/locust/runner.py @@ -708,8 +708,6 @@ def main() -> None: (work_dir / f"{args.name}_failures.csv", "failures.csv"), (work_dir / f"{args.name}_stats_history.csv", "stats_history.csv"), (server_summary_json, "server_summary.json"), - # TODO: remove after data migration - (jsonl_path, f"{args.name}.jsonl"), ] for src, basename in files: if not src.exists(): From 3aa3eeca4147aec096fdb3934c6e6c5e13664a2b Mon Sep 17 00:00:00 2001 From: Anna Pendleton Date: Thu, 29 Oct 2026 20:49:26 +0000 Subject: [PATCH 06/16] ate-setup: retry each ko release image with backoff (#3446) The v1.0.0-rc.1 release run (https://github.com/agent-substrate/substrate/actions/runs/40925903340) failed in **Publish images** with `DENIED: permission_denied`. ghcr.io can briefly deny pushes to a package it has just created, and this is the first release that creates them. `ate-setup publish release-images` now builds each ko image in its own `ko build`. If an image fails, it logs the error and retries that image, for up to 3 attempts, waiting 10s then 20s. The workflow is unchanged. --------- Signed-off-by: Anna Pendleton <13793293+annapendleton@users.noreply.github.com> Co-authored-by: Anna Pendleton <13793293+annapendleton@users.noreply.github.com> --- cmd/ate-setup/internal/ko/ko.go | 34 ++++++++++ cmd/ate-setup/internal/ko/ko_test.go | 82 +++++++++++++++++++++++++ cmd/ate-setup/internal/steps/publish.go | 2 +- 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/cmd/ate-setup/internal/ko/ko.go b/cmd/ate-setup/internal/ko/ko.go index 139fa6bd63..c2b719c5c3 100644 --- a/cmd/ate-setup/internal/ko/ko.go +++ b/cmd/ate-setup/internal/ko/ko.go @@ -33,6 +33,9 @@ import ( "strings" "time" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" + "go.ate.dev/substrate/cmd/ate-setup/internal/log" ) @@ -162,6 +165,37 @@ func (r *Runner) BuildTagged(ctx context.Context, tag string, labels []string, i return refs, nil } +// buildBackoff paces the retries of an image that fails to build or push: 3 +// attempts, 10s then 20s apart. ghcr.io can briefly deny pushes to a package it +// has just created. +var buildBackoff = wait.Backoff{Steps: 3, Duration: 10 * time.Second, Factor: 2} + +// BuildEach runs BuildTagged once per import path, retrying each failure per +// buildBackoff. It returns the refs in importPaths order. +func (r *Runner) BuildEach(ctx context.Context, tag string, labels []string, importPaths ...string) ([]string, error) { + refs := make([]string, 0, len(importPaths)) + for _, path := range importPaths { + var ref string + logAndRetry := func(err error) bool { + log.Warnf("%s: %v", path, err) + return true + } + err := retry.OnError(buildBackoff, logAndRetry, func() error { + built, err := r.BuildTagged(ctx, tag, labels, path) + if err != nil { + return err + } + ref = built[0] + return nil + }) + if err != nil { + return nil, err + } + refs = append(refs, ref) + } + return refs, nil +} + // ResolveBytes resolves an in-memory manifest, such as kustomize output. func (r *Runner) ResolveBytes(ctx context.Context, manifest []byte) ([]byte, error) { return r.Resolve(ctx, "-", manifest) diff --git a/cmd/ate-setup/internal/ko/ko_test.go b/cmd/ate-setup/internal/ko/ko_test.go index 8c5377a60b..415676b4be 100644 --- a/cmd/ate-setup/internal/ko/ko_test.go +++ b/cmd/ate-setup/internal/ko/ko_test.go @@ -15,12 +15,17 @@ package ko import ( + "errors" "os" "os/exec" "path/filepath" "slices" + "strconv" "strings" "testing" + "time" + + "k8s.io/apimachinery/pkg/util/wait" ) // Without --base-import-paths ko publishes cmd/atelet as "atelet-", and @@ -174,3 +179,80 @@ func TestBuildTaggedRejectsMissingRefs(t *testing.T) { t.Error("BuildTagged() error = nil, want one for 1 ref from 2 packages") } } + +// flakyKo writes a ko stand-in that fails the first failures builds of each +// package, printing stderr, then prints a ref for it. It returns the +// directory where it counts builds per package. +func flakyKo(t *testing.T, failures int, stderr string) (binary, dir string) { + t.Helper() + dir = t.TempDir() + binary = filepath.Join(dir, "ko") + script := "#!/bin/sh\n" + + "pkg=$(basename \"$2\")\n" + + "echo run >> " + dir + "/runs-$pkg\n" + + "if [ $(wc -l < " + dir + "/runs-$pkg) -le " + strconv.Itoa(failures) + " ]; then echo '" + stderr + "' >&2; exit 1; fi\n" + + "echo repo/$pkg:v1@sha256:a\n" + if err := os.WriteFile(binary, []byte(script), 0o755); err != nil { + t.Fatal(err) + } + return binary, dir +} + +// koRuns returns how many times flakyKo built pkg. +func koRuns(t *testing.T, dir, pkg string) int { + t.Helper() + raw, err := os.ReadFile(filepath.Join(dir, "runs-"+pkg)) + if errors.Is(err, os.ErrNotExist) { + return 0 + } + if err != nil { + t.Fatal(err) + } + return strings.Count(string(raw), "run") +} + +// fastBackoff shortens buildBackoff for the test. +func fastBackoff(t *testing.T) { + t.Helper() + original := buildBackoff + buildBackoff = wait.Backoff{Steps: original.Steps, Duration: time.Millisecond, Factor: 1} + t.Cleanup(func() { buildBackoff = original }) +} + +const deniedStderr = "PATCH https://ghcr.io/v2/agent-substrate/substrate/ateapi/blobs/upload/1: DENIED: permission_denied: write_package" + +func TestBuildEachRetriesEachImage(t *testing.T) { + fastBackoff(t) + binary, dir := flakyKo(t, 2, deniedStderr) + r := &Runner{Root: t.TempDir(), binary: binary} + + refs, err := r.BuildEach(t.Context(), "v1", nil, "./cmd/ateapi", "./cmd/atelet") + if err != nil { + t.Fatalf("BuildEach() error = %v", err) + } + if want := []string{"repo/ateapi:v1@sha256:a", "repo/atelet:v1@sha256:a"}; !slices.Equal(refs, want) { + t.Errorf("BuildEach() = %q, want %q", refs, want) + } + for _, pkg := range []string{"ateapi", "atelet"} { + if got := koRuns(t, dir, pkg); got != 3 { + t.Errorf("ko built %s %d times, want 3", pkg, got) + } + } +} + +func TestBuildEachStopsAfterAttempts(t *testing.T) { + fastBackoff(t) + binary, dir := flakyKo(t, 100, deniedStderr) + r := &Runner{Root: t.TempDir(), binary: binary} + + _, err := r.BuildEach(t.Context(), "v1", nil, "./cmd/ateapi", "./cmd/atelet") + if err == nil { + t.Error("BuildEach() error = nil, want one after 3 failed attempts") + } + if got := koRuns(t, dir, "ateapi"); got != 3 { + t.Errorf("ko built ateapi %d times, want 3", got) + } + if got := koRuns(t, dir, "atelet"); got != 0 { + t.Errorf("ko built atelet %d times, want 0", got) + } +} diff --git a/cmd/ate-setup/internal/steps/publish.go b/cmd/ate-setup/internal/steps/publish.go index f98326e733..cbeac86ad0 100644 --- a/cmd/ate-setup/internal/steps/publish.go +++ b/cmd/ate-setup/internal/steps/publish.go @@ -254,7 +254,7 @@ func (e *Env) PublishReleaseImages(ctx context.Context, w io.Writer, opts Publis } refs = append(refs, ref) } - koRefs, err := runner.BuildTagged(ctx, tag, labels, pkgs...) + koRefs, err := runner.BuildEach(ctx, tag, labels, pkgs...) if err != nil { return err } From 5d226a509c201262ac77a7f631f877f9585e0e99 Mon Sep 17 00:00:00 2001 From: Anish Ramasekar Date: Thu, 29 Oct 2026 22:25:25 +0000 Subject: [PATCH 07/16] Run containers as the image's USER and WORKDIR, with layer file owners kept (#2392) Containers ignored the image's `USER` and `WORKDIR` and ran as root in `/`, and atelet's unpack dropped the file owners image layers record. So an image that hands a directory to its user, such as jupyter's `/home/jovyan`, didn't work as built. - atelet applies each tar entry's uid/gid and keeps setuid, setgid and sticky bits. It adds `CHOWN`, `FOWNER` and `FSETID` to its `DAC_OVERRIDE`. The image cache layout moves to version 3. - The process runs as the image's `USER`, resolved as Docker does against the image's own `/etc/passwd` and `/etc/group`, and starts in its `WORKDIR` (default `/`). - The jupyter demo runs as jovyan and drops `DAC_OVERRIDE` and `--allow-root`. The `USER` and `WORKDIR` commits are @dims's from #1918, kept as written. This PR supersedes #1918. Fixes #2036 #### Breaking change Please add the `breaking-change` label. - After an upgrade or rollback, atelet refuses the existing image cache. Delete `/var/lib/ate/image-cache` on each node once no actor runs on it, as atelet's error says. After an upgrade, a node reboot also works. - A custom atelet securityContext needs `CHOWN`, `DAC_OVERRIDE`, `FOWNER` and `FSETID`. - Images with a `USER` stop running as root, and images with a `WORKDIR` stop starting in `/`. A non-root `USER` is expected to have no effective capabilities, so `securityContext.capabilities.add` no longer helps it. This is checked under runc and in the gVisor source, not yet inside a gVisor or microVM sandbox. - gVisor snapshots of such images don't restore, because `runsc restore` checks each container's user and working directory. Recreate those templates. MicroVM snapshots resume as they were. - Files an earlier run wrote as root into a durable dir stay root-owned. Tested: `go test -race` on atelet, imagecache, ocispec, tarutil, kata and the probe fixture, on macOS and on Linux as non-root, and imagecache with `-count=3 -shuffle=on`. The root-only imagecache and tarutil tests pass as root on a privileged Linux container. `hack/verify-all.sh` passes. The jupyter image serves `/api` under Docker as 1000:100 with every capability dropped. @dims ran the jupyter demo and a non-root node image as their users on kind, on both runtimes, before #1904 merged; on microVM uid 1000 couldn't bind :80 then. A new imagefs e2e starts an actor from a probe image with `USER nonroot:nonroot` and `WORKDIR /home/nonroot`. It checks uid and gid 65532, no supplementary group besides 65532, no effective capabilities, the working directory, and that the user can create a file there. CI runs it on gVisor and on microVM. At this head nothing ran in a gVisor or microVM sandbox yet: not the jupyter demo and not the imagefs e2e. - [ ] Tests pass - [x] Docs updated --------- Signed-off-by: Anish Ramasekar Signed-off-by: Davanum Srinivas Co-authored-by: Davanum Srinivas --- .ko.yaml | 9 + cmd/atelet/imagevolume_test.go | 15 + cmd/atelet/main.go | 12 +- cmd/atelet/main_test.go | 59 ++ cmd/atelet/oci.go | 99 ++- cmd/atelet/oci_test.go | 71 ++ .../internal/kata/specconv_linux_test.go | 20 + demos/jupyter/jupyter-template.yaml.tmpl | 1 - docs/reference/api-guide.md | 7 + go.mod | 2 +- .../zz_generated.validation.go | 2 + internal/e2e/fixture.go | 13 +- internal/e2e/fixtures/probe/main.go | 31 + internal/e2e/fixtures/probe/main_test.go | 45 ++ internal/e2e/fixtures/probe/nonroot/main.go | 91 +++ .../probe/probe-nonroot-template.yaml.tmpl | 38 + internal/e2e/manifest.go | 8 +- internal/e2e/sandbox_test.go | 4 + internal/e2e/suites/imagefs/imagefs_test.go | 243 +++++++ internal/e2e/suites/imagefs/testmain_test.go | 24 + internal/imagecache/README.md | 33 +- internal/imagecache/ateletcaps_test.go | 199 ++++++ internal/imagecache/bundle_linux.go | 9 + internal/imagecache/bundle_linux_test.go | 178 ++++- internal/imagecache/imagecache.go | 20 +- internal/imagecache/imagefile.go | 117 +++ internal/imagecache/imagefile_test.go | 127 ++++ internal/imagecache/implicitdirs.go | 16 +- internal/imagecache/removeall.go | 9 +- internal/imagecache/retire.go | 6 +- internal/imagecache/spec.go | 2 +- internal/imagecache/unpack.go | 263 +++++-- internal/imagecache/unpack_owner_test.go | 673 ++++++++++++++++++ internal/imagecache/unpack_test.go | 161 +++++ internal/ocispec/ocispec.go | 13 +- internal/ocispec/ocispec_test.go | 21 + internal/ocispec/parity_test.go | 39 + internal/proto/ateworkerpb/ateworker.pb.go | 302 +++++--- internal/proto/ateworkerpb/ateworker.proto | 13 + internal/tarutil/owner.go | 58 ++ internal/tarutil/owner_linux.go | 21 - internal/tarutil/tarutil.go | 24 +- manifests/ate-install/atelet.yaml | 29 +- 43 files changed, 2844 insertions(+), 283 deletions(-) create mode 100644 internal/e2e/fixtures/probe/nonroot/main.go create mode 100644 internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl create mode 100644 internal/e2e/suites/imagefs/imagefs_test.go create mode 100644 internal/e2e/suites/imagefs/testmain_test.go create mode 100644 internal/imagecache/ateletcaps_test.go create mode 100644 internal/imagecache/imagefile.go create mode 100644 internal/imagecache/imagefile_test.go create mode 100644 internal/imagecache/unpack_owner_test.go create mode 100644 internal/tarutil/owner.go diff --git a/.ko.yaml b/.ko.yaml index 80d54c7973..6465081548 100644 --- a/.ko.yaml +++ b/.ko.yaml @@ -19,6 +19,15 @@ defaultPlatforms: - linux/arm64 baseImageOverrides: + # The actor images built here write at the root of their filesystem and into + # volumes atelet creates as root. A container runs as its image's USER, so + # they stay on the root base. + go.ate.dev/substrate/demos/counter: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 + go.ate.dev/substrate/demos/egress: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 + go.ate.dev/substrate/demos/multi-template/fspersist: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 + go.ate.dev/substrate/internal/e2e/fixtures/probe: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 + go.ate.dev/substrate/internal/e2e/fixtures/testserver: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 + go.ate.dev/substrate/cmd/benchmarking/glutton: gcr.io/distroless/static-debian13:latest@sha256:15f8637509792e05b97d83451b0b6ccfa4abd548f997e406ac1e72c87fe1fa78 go.ate.dev/substrate/demos/sandbox: alpine:3.24.3@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a # atelet needs glibc to run the node's kubelet credential provider, which # some platforms ship dynamically linked (e.g. AKS, GKE Ubuntu). diff --git a/cmd/atelet/imagevolume_test.go b/cmd/atelet/imagevolume_test.go index 387688a823..c5a2bd17cb 100644 --- a/cmd/atelet/imagevolume_test.go +++ b/cmd/atelet/imagevolume_test.go @@ -75,11 +75,26 @@ func singleFileLayer(t *testing.T, path, body string) v1.Layer { // pushTestImage pushes the image and returns its digest-pinned reference, // which is what validated workload specs carry. func pushTestImage(t *testing.T, ref string, layers ...v1.Layer) string { + t.Helper() + return pushTestImageWithConfig(t, ref, v1.Config{}, layers...) +} + +// pushTestImageWithConfig is pushTestImage with the image config set. +func pushTestImageWithConfig(t *testing.T, ref string, cfg v1.Config, layers ...v1.Layer) string { t.Helper() img, err := mutate.AppendLayers(empty.Image, layers...) if err != nil { t.Fatalf("mutate.AppendLayers: %v", err) } + cf, err := img.ConfigFile() + if err != nil { + t.Fatalf("img.ConfigFile: %v", err) + } + cf = cf.DeepCopy() + cf.Config = cfg + if img, err = mutate.ConfigFile(img, cf); err != nil { + t.Fatalf("mutate.ConfigFile: %v", err) + } tag, err := name.ParseReference(ref, name.Insecure) if err != nil { t.Fatalf("name.ParseReference(%q): %v", ref, err) diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 24f86122fb..1b51210e32 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -2262,19 +2262,25 @@ func (s *Atelet) prepareOCIBundles( envs = append(envs, fmt.Sprintf("%s=%s", env.GetName(), env.GetValue())) } g.Go(func() error { - imageConfig, err := prepareOCIDirectory(gCtx, s.imageCache, actorUID, ctr.GetName(), ctr.GetImage(), spec.GetVolumes(), ctr.GetVolumeMounts()) + img, cwd, err := prepareOCIDirectory(gCtx, s.imageCache, actorUID, ctr.GetName(), ctr.GetImage(), spec.GetVolumes(), ctr.GetVolumeMounts()) if err != nil { return wrapFileSystemErr(fmt.Sprintf("while creating %q OCI bundle", ctr.GetName()), err) } - args, err := resolveProcessArgs(imageConfig, ctr.GetCommand(), ctr.GetArgs()) + args, err := resolveProcessArgs(&img.Config, ctr.GetCommand(), ctr.GetArgs()) if err != nil { return fmt.Errorf("while resolving process args for container %q: %w", ctr.GetName(), err) } + user, err := resolveImageUser(img) + if err != nil { + return fmt.Errorf("while resolving user for container %q: %w", ctr.GetName(), err) + } containerSpecs[i] = &ateworkerpb.ContainerSpec{ Args: args, - Env: resolveActorEnv(imageConfig, envs), + Env: resolveActorEnv(&img.Config, envs), Capabilities: resolveCapabilities(ctr.GetSecurityContext().GetCapabilities()), Resources: toAteworkerResources(ctr.GetResources()), + User: user, + Cwd: cwd, } return nil }) diff --git a/cmd/atelet/main_test.go b/cmd/atelet/main_test.go index d3daf4e277..162d1fba5b 100644 --- a/cmd/atelet/main_test.go +++ b/cmd/atelet/main_test.go @@ -34,6 +34,7 @@ import ( "time" "github.com/google/go-cmp/cmp" + v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/spf13/pflag" "go.ate.dev/substrate/cmd/atelet/internal/actordirs" "go.ate.dev/substrate/cmd/atelet/internal/ateletpath" @@ -42,6 +43,7 @@ import ( "go.ate.dev/substrate/internal/ateattr" "go.ate.dev/substrate/internal/ateinterceptors" "go.ate.dev/substrate/internal/atelet" + "go.ate.dev/substrate/internal/imagecache" "go.ate.dev/substrate/internal/proto/ateletpb" "go.ate.dev/substrate/internal/proto/ateworkerpb" "go.ate.dev/substrate/internal/resources" @@ -265,12 +267,69 @@ func TestPrepareOCIBundlesFillsContainerSpec(t *testing.T) { Env: []string{"GREETING=hello", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, Capabilities: []string{"CAP_AUDIT_WRITE", "CAP_NET_ADMIN", "CAP_NET_BIND_SERVICE"}, Resources: &ateworkerpb.ResourceRequirements{Limits: &ateworkerpb.Resources{MemoryBytes: 1 << 30, CpuMillicores: 500}}, + Cwd: "/", }} if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" { t.Errorf("prepareOCIBundles container specs mismatch (-want +got):\n%s", diff) } } +// TestPrepareOCIBundlesResolvesUsers pins that a container runs as its image's +// USER, resolved against the image's own passwd and group files; a USER the +// image cannot resolve fails the run. +func TestPrepareOCIBundlesResolvesUsers(t *testing.T) { + useTempNodeDirs(t) + host := imageVolumeTestRegistry(t) + etc := []v1.Layer{ + singleFileLayer(t, "etc/passwd", "root:x:0:0:root:/root:/bin/sh\nnonroot:x:65532:65532::/home/nonroot:/sbin/nologin\n"), + singleFileLayer(t, "etc/group", "root:x:0:\nnonroot:x:65532:\nvideo:x:44:nonroot\n"), + } + app := pushTestImageWithConfig(t, host+"/app:v1", v1.Config{User: "nonroot", Cmd: []string{"/bin/app"}}, etc...) + s := &Atelet{imageCache: newImageVolumeStore(t)} + + spec := &ateletpb.WorkloadSpec{Containers: []*ateletpb.Container{{Name: "app", Image: app}}} + got, err := s.prepareOCIBundles(t.Context(), "actor-uid-1", resources.ActorRef{}, spec) + if err != nil { + t.Fatalf("prepareOCIBundles: %v", err) + } + want := &ateworkerpb.ProcessUser{Uid: 65532, Gid: 65532, AdditionalGids: []uint32{44}} + if diff := cmp.Diff(want, got[0].GetUser(), protocmp.Transform()); diff != "" { + t.Errorf("app user mismatch (-want +got):\n%s", diff) + } + + unresolvable := pushTestImageWithConfig(t, host+"/nobody:v1", v1.Config{User: "nobody", Cmd: []string{"/bin/app"}}) + spec = &ateletpb.WorkloadSpec{Containers: []*ateletpb.Container{{Name: "app", Image: unresolvable}}} + if _, err := s.prepareOCIBundles(t.Context(), "actor-uid-2", resources.ActorRef{}, spec); err == nil { + t.Error("prepareOCIBundles succeeded with a USER the image has no passwd entry for, want an error") + } +} + +// TestPrepareOCIBundlesStartsInTheImageWorkdir pins that a container starts in +// its image's WORKDIR, created through the overlay when the image lacks it. +func TestPrepareOCIBundlesStartsInTheImageWorkdir(t *testing.T) { + useTempNodeDirs(t) + host := imageVolumeTestRegistry(t) + image := pushTestImageWithConfig(t, host+"/app:v1", v1.Config{Cmd: []string{"/bin/app"}, WorkingDir: "/home/nonroot"}) + spec := &ateletpb.WorkloadSpec{Containers: []*ateletpb.Container{{Name: "app", Image: image}}} + + const actorUID = "actor-uid-1" + s := &Atelet{imageCache: newImageVolumeStore(t)} + got, err := s.prepareOCIBundles(t.Context(), actorUID, resources.ActorRef{}, spec) + if err != nil { + t.Fatalf("prepareOCIBundles: %v", err) + } + if cwd := got[0].GetCwd(); cwd != "/home/nonroot" { + t.Errorf("Cwd = %q, want /home/nonroot", cwd) + } + overlay, err := imagecache.ReadSpec(ateletpath.OCIBundlePath(actorUID, "app")) + if err != nil { + t.Fatalf("imagecache.ReadSpec: %v", err) + } + if !slices.Contains(overlay.ExtraDirs, "/home/nonroot") { + t.Errorf("ExtraDirs = %v, want the working directory", overlay.ExtraDirs) + } +} + func TestSnapshotManifestRejectsNonLocalFile(t *testing.T) { manifest, err := json.Marshal(sandboxAssetsRecord{ SandboxClass: "gvisor", diff --git a/cmd/atelet/oci.go b/cmd/atelet/oci.go index 3f72633d5b..1cf5a1a9ca 100644 --- a/cmd/atelet/oci.go +++ b/cmd/atelet/oci.go @@ -15,17 +15,23 @@ package main import ( + "bytes" "context" + "errors" "fmt" + "io" + "io/fs" "os" "path" "sort" "strings" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/moby/sys/user" "go.ate.dev/substrate/cmd/atelet/internal/ateletpath" "go.ate.dev/substrate/internal/imagecache" "go.ate.dev/substrate/internal/proto/ateletpb" + "go.ate.dev/substrate/internal/proto/ateworkerpb" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "golang.org/x/sync/errgroup" @@ -74,7 +80,10 @@ func resolveCapabilities(caps *ateletpb.Capabilities) []string { return out } -func prepareOCIDirectory(ctx context.Context, imageCache *imagecache.Store, actorUID, containerName, ref string, volumes []*ateletpb.Volume, volumeMounts []*ateletpb.VolumeMount) (*v1.Config, error) { +// prepareOCIDirectory pulls the container's image and writes the overlay spec +// the worker composes its rootfs from. It returns the image and the process's +// working directory, which the worker creates through the overlay. +func prepareOCIDirectory(ctx context.Context, imageCache *imagecache.Store, actorUID, containerName, ref string, volumes []*ateletpb.Volume, volumeMounts []*ateletpb.VolumeMount) (*imagecache.Image, string, error) { tracer := otel.Tracer("prepareOCIDirectory") ctx, span := tracer.Start(ctx, "prepareOCIDirectory") @@ -87,18 +96,18 @@ func prepareOCIDirectory(ctx context.Context, imageCache *imagecache.Store, acto // actordirs.ResetActorDirs already wiped the bundle dir on the Run/Restore // path). if err := imagecache.RemoveAllWritable(bundlePath); err != nil { - return nil, fmt.Errorf("while clearing bundle %q: %w", bundlePath, err) + return nil, "", fmt.Errorf("while clearing bundle %q: %w", bundlePath, err) } // The bundle's rootfs is composed by worker as an overlay mount just before // the workload runs: the cached image layers are the read-only lowerdirs, // and the bundle-local upper/work hold this actor's private writes (wiped // between runs, preserving the pristine-rootfs-per-run contract the old - // full re-untar provided). atelet only prepares the (empty) directories — - // it deliberately runs with no capabilities, so it cannot mount. + // full re-untar provided). atelet only prepares the (empty) directories: + // it has no CAP_SYS_ADMIN, so it cannot mount. for _, d := range []string{"rootfs", "upper", "work"} { if err := os.MkdirAll(path.Join(bundlePath, d), 0o700); err != nil { - return nil, fmt.Errorf("in os.MkdirAll for container bundle dir: %w", err) + return nil, "", fmt.Errorf("in os.MkdirAll for container bundle dir: %w", err) } } @@ -120,26 +129,45 @@ func prepareOCIDirectory(ctx context.Context, imageCache *imagecache.Store, acto return err }) if err := g.Wait(); err != nil { - return nil, err + return nil, "", err + } + cwd, err := resolveCwd(&img.Config) + if err != nil { + return nil, "", fmt.Errorf("while resolving the working directory of container %q: %w", containerName, err) } - // Every bind target must exist in the rootfs for the mount to attach; - // worker creates them through the mounted overlay (they land in the - // actor's upper). + // Every bind target must exist in the rootfs for the mount to attach, and + // the working directory for the process to start; worker creates them + // through the mounted overlay (they land in the actor's upper). var extraDirs []string for _, vm := range volumeMounts { extraDirs = append(extraDirs, vm.GetMountPath()) } + if cwd != "/" { + extraDirs = append(extraDirs, cwd) + } if err := imagecache.WriteSpec(bundlePath, &imagecache.OverlaySpec{ ImageDigest: img.Digest.String(), Layers: img.LayerDirs, ExtraDirs: extraDirs, ImageVolumes: imageVolumes, }); err != nil { - return nil, fmt.Errorf("while writing overlay spec: %w", err) + return nil, "", fmt.Errorf("while writing overlay spec: %w", err) } - return &img.Config, nil + return img, cwd, nil +} + +// resolveCwd reads the image's WORKDIR; none means "/". The OCI spec requires +// an absolute path. +func resolveCwd(imageCfg *v1.Config) (string, error) { + if imageCfg == nil || imageCfg.WorkingDir == "" { + return "/", nil + } + if !path.IsAbs(imageCfg.WorkingDir) { + return "", fmt.Errorf("image WorkingDir %q is not absolute", imageCfg.WorkingDir) + } + return path.Clean(imageCfg.WorkingDir), nil } // resolveImageVolumes pulls the image behind every image-typed volume this @@ -241,3 +269,52 @@ func resolveProcessArgs(imageCfg *v1.Config, command, args []string) ([]string, } return argv, nil } + +// resolveImageUser resolves the image's USER against the image's own +// /etc/passwd and /etc/group, either of which may be absent. No USER is root, +// reported as nil. +func resolveImageUser(img *imagecache.Image) (*ateworkerpb.ProcessUser, error) { + if img.Config.User == "" { + return nil, nil + } + passwd, err := readOptionalImageFile(img, "etc/passwd") + if err != nil { + return nil, err + } + group, err := readOptionalImageFile(img, "etc/group") + if err != nil { + return nil, err + } + return resolveUser(img.Config.User, passwd, group) +} + +// readOptionalImageFile returns a nil reader for a file the image lacks. +func readOptionalImageFile(img *imagecache.Image, name string) (io.Reader, error) { + b, err := img.ReadFile(name) + if errors.Is(err, fs.ErrNotExist) { + return nil, nil + } + if err != nil { + return nil, err + } + return bytes.NewReader(b), nil +} + +// resolveUser follows Docker's rules for USER "user[:group]": numeric ids as +// is, a bare uid with its login group from passwd (gid 0 without an entry), +// names looked up or an error, group memberships as supplementary groups. +// Ids are bounded to int32. A nil reader means the image lacks the file. +func resolveUser(userSpec string, passwd, group io.Reader) (*ateworkerpb.ProcessUser, error) { + if strings.Count(userSpec, ":") > 1 { + return nil, fmt.Errorf("image User %q: want user[:group]", userSpec) + } + u, err := user.GetExecUser(userSpec, nil, passwd, group) + if err != nil { + return nil, fmt.Errorf("image User %q: %w", userSpec, err) + } + identity := &ateworkerpb.ProcessUser{Uid: uint32(u.Uid), Gid: uint32(u.Gid)} + for _, gid := range u.Sgids { + identity.AdditionalGids = append(identity.AdditionalGids, uint32(gid)) + } + return identity, nil +} diff --git a/cmd/atelet/oci_test.go b/cmd/atelet/oci_test.go index c76d2d0d03..1eed244303 100644 --- a/cmd/atelet/oci_test.go +++ b/cmd/atelet/oci_test.go @@ -15,11 +15,16 @@ package main import ( + "io" "slices" + "strings" "testing" + "github.com/google/go-cmp/cmp" v1 "github.com/google/go-containerregistry/pkg/v1" "go.ate.dev/substrate/internal/proto/ateletpb" + "go.ate.dev/substrate/internal/proto/ateworkerpb" + "google.golang.org/protobuf/testing/protocmp" ) func TestResolveActorEnv(t *testing.T) { @@ -176,6 +181,72 @@ func withCaps(in []string, add ...string) []string { return out } +func TestResolveUser(t *testing.T) { + const passwd = "root:x:0:0:root:/root:/bin/sh\n" + + "jovyan:x:1000:100::/home/jovyan:/bin/bash\n" + + "nonroot:x:65532:65532::/home/nonroot:/sbin/nologin\n" + const group = "root:x:0:\n" + + "users:x:100:\n" + + "nonroot:x:65532:\n" + + "video:x:44:nonroot,jovyan\n" + + "audio:x:29:nonroot\n" + tests := []struct { + name string + user string + passwd, group string // empty: the image lacks the file + want *ateworkerpb.ProcessUser + wantErr bool + }{ + {name: "bare uid, no passwd", user: "1000", want: &ateworkerpb.ProcessUser{Uid: 1000}}, + {name: "bare uid takes its login group and memberships", user: "1000", passwd: passwd, group: group, want: &ateworkerpb.ProcessUser{Uid: 1000, Gid: 100, AdditionalGids: []uint32{44}}}, + {name: "bare uid without a passwd entry", user: "1001", passwd: passwd, group: group, want: &ateworkerpb.ProcessUser{Uid: 1001}}, + {name: "uid:gid passes through", user: "1000:2000", passwd: passwd, group: group, want: &ateworkerpb.ProcessUser{Uid: 1000, Gid: 2000}}, + {name: "named user", user: "nonroot", passwd: passwd, group: group, want: &ateworkerpb.ProcessUser{Uid: 65532, Gid: 65532, AdditionalGids: []uint32{44, 29}}}, + {name: "named user and group", user: "jovyan:video", passwd: passwd, group: group, want: &ateworkerpb.ProcessUser{Uid: 1000, Gid: 44}}, + {name: "named user missing from passwd", user: "nobody", passwd: passwd, wantErr: true}, + {name: "named group missing from group", user: "1000:staff", passwd: passwd, group: group, wantErr: true}, + {name: "above int32", user: "2147483648", wantErr: true}, + {name: "third field", user: "1000:1000:1", wantErr: true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var passwdR, groupR io.Reader + if tc.passwd != "" { + passwdR = strings.NewReader(tc.passwd) + } + if tc.group != "" { + groupR = strings.NewReader(tc.group) + } + got, err := resolveUser(tc.user, passwdR, groupR) + if (err != nil) != tc.wantErr { + t.Fatalf("resolveUser(%q) = %v, %v; wantErr %v", tc.user, got, err, tc.wantErr) + } + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); err == nil && diff != "" { + t.Errorf("resolveUser(%q) mismatch (-want +got):\n%s", tc.user, diff) + } + }) + } +} + +func TestResolveCwd(t *testing.T) { + for _, tc := range []struct { + image *v1.Config + want string + wantErr bool + }{ + {image: nil, want: "/"}, + {image: &v1.Config{}, want: "/"}, + {image: &v1.Config{WorkingDir: "/home/jovyan"}, want: "/home/jovyan"}, + {image: &v1.Config{WorkingDir: "/app/"}, want: "/app"}, + {image: &v1.Config{WorkingDir: "app"}, wantErr: true}, + } { + got, err := resolveCwd(tc.image) + if (err != nil) != tc.wantErr || got != tc.want { + t.Errorf("resolveCwd(%+v) = %q, %v; want %q, wantErr %v", tc.image, got, err, tc.want, tc.wantErr) + } + } +} + func TestResolveCapabilities(t *testing.T) { tests := []struct { name string diff --git a/cmd/ateworker-microvm/internal/kata/specconv_linux_test.go b/cmd/ateworker-microvm/internal/kata/specconv_linux_test.go index 4b7d3afdc7..b211346f9f 100644 --- a/cmd/ateworker-microvm/internal/kata/specconv_linux_test.go +++ b/cmd/ateworker-microvm/internal/kata/specconv_linux_test.go @@ -17,6 +17,7 @@ package kata import ( + "slices" "testing" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -174,3 +175,22 @@ func TestSpecToAgentPB_ForwardsSysctl(t *testing.T) { t.Fatalf("Linux.Sysctl = %v, want %s=0 carried through", got.GetLinux().GetSysctl(), key) } } + +// The agent starts the process as the user it is sent; a dropped identity +// would run the workload as root in the guest. +func TestSpecToAgentPB_ForwardsProcessUser(t *testing.T) { + got := SpecToAgentPB(&specs.Spec{ + Process: &specs.Process{User: specs.User{UID: 65532, GID: 65534, AdditionalGids: []uint32{44}}}, + }) + u := got.GetProcess().GetUser() + if u == nil || u.UID != 65532 || u.GID != 65534 || !slices.Equal(u.AdditionalGids, []uint32{44}) { + t.Fatalf("Process.User = %v, want 65532:65534 +44", u) + } +} + +func TestSpecToAgentPB_ForwardsCwd(t *testing.T) { + got := SpecToAgentPB(&specs.Spec{Process: &specs.Process{Cwd: "/work"}}) + if got.GetProcess().GetCwd() != "/work" { + t.Fatalf("Process.Cwd = %q, want /work", got.GetProcess().GetCwd()) + } +} diff --git a/demos/jupyter/jupyter-template.yaml.tmpl b/demos/jupyter/jupyter-template.yaml.tmpl index df8cd69396..1877a397a1 100644 --- a/demos/jupyter/jupyter-template.yaml.tmpl +++ b/demos/jupyter/jupyter-template.yaml.tmpl @@ -28,7 +28,6 @@ containers: command: - jupyter - lab - - "--allow-root" - "--ServerApp.token=''" - "--ServerApp.password=''" - "--ServerApp.allow_origin='*'" diff --git a/docs/reference/api-guide.md b/docs/reference/api-guide.md index 68e883c867..9a26af21d4 100644 --- a/docs/reference/api-guide.md +++ b/docs/reference/api-guide.md @@ -309,10 +309,16 @@ Each entry in `containers` describes one process to run in the actor's sandbox. `command` and `args` resolve against the container image's `ENTRYPOINT`/`CMD` the same way [Kubernetes Pod `command`/`args`](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/) resolve against `ENTRYPOINT`/`CMD`. If the resolved argv is empty — the image sets neither `ENTRYPOINT` nor `CMD`, and the container sets neither `command` nor `args` — `Run`/`Restore` fails. +The process runs as the image's `USER`, resolved as Docker does against the image's own `/etc/passwd` and `/etc/group`: a numeric `uid:gid` as is; a bare uid with its login group, or gid 0 when it has no entry; a name must have an entry or `Run`/`Restore` fails. Group memberships become supplementary groups. Ids are at most 2147483647. No `USER` means root. There is no `runAsUser` field. + +The process starts in the image's `WORKDIR`, or in `/` when the image sets none. A `WORKDIR` the image lacks is created in the actor's writable layer. There is no `workingDir` field. + ### Container Capabilities (`securityContext.capabilities`) Each container runs with a default set of Linux capabilities — `AUDIT_WRITE`, `KILL` and `NET_BIND_SERVICE`. `securityContext.capabilities` adjusts that set, mirroring `securityContext.capabilities` on a Kubernetes Pod container. +A container running as root has that set as its effective capabilities. A container whose image `USER` is not root starts with no effective capabilities, as under Kubernetes, because ambient capabilities are not supported. Its set then only limits what a setuid-root program can gain. + | Field | Type | Description | | :--- | :--- | :--- | | `securityContext.capabilities.add` | `[]string` | Optional. Capabilities to grant on top of the default set. `ALL` is **not** accepted here. | @@ -333,6 +339,7 @@ Each container runs with a default set of Linux capabilities — `AUDIT_WRITE`, - **Ambient capabilities are not supported** ([gvisor#3166](https://github.com/google/gvisor/issues/3166)). - **Low ports.** A container may bind a port below 1024 without `NET_BIND_SERVICE` on both runtimes: gVisor's network stack has no privileged-port limit, and the micro-VM guest sets `net.ipv4.ip_unprivileged_port_start=0` to match. - **Setuid binaries work.** Neither runtime sets `no_new_privileges`, as for a Kubernetes container with `allowPrivilegeEscalation: true`; gVisor runs with `--allow-suid`. +- **Image files owned by other users.** Image files keep the owner their image's layers record, as under containerd. A container running as its image's `USER` can use what the image gave that user, for example after `RUN chown -R app:app /app` and `USER app`. A container running as root, because its image sets no `USER` or `USER root`, has no `DAC_OVERRIDE` or `DAC_READ_SEARCH` by default. On a file or directory another user owns, it gets only what the permission bits grant to others. Add `DAC_OVERRIDE` if it writes to such files, or `DAC_READ_SEARCH` if it only reads them. The sandbox — gVisor or microVM — remains the isolation boundary; capabilities constrain the workload *inside* it. diff --git a/go.mod b/go.mod index deca33e7cd..7e81ca7c74 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 github.com/jackc/pgx/v5 v5.10.0 github.com/klauspost/compress v1.19.1 + github.com/moby/sys/user v0.4.1 github.com/myzhan/boomer v1.6.1-0.20250711115830-8a2c7ce4c7b1 github.com/opencontainers/runtime-spec v1.3.0 github.com/openfga/api/proto v0.0.0-20260319214821-f153694bfc20 @@ -191,7 +192,6 @@ require ( github.com/moby/patternmatcher v0.6.1 // indirect github.com/moby/spdystream v0.5.1 // indirect github.com/moby/sys/sequential v0.7.0 // indirect - github.com/moby/sys/user v0.4.1 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect diff --git a/internal/ateworkervalidation/zz_generated.validation.go b/internal/ateworkervalidation/zz_generated.validation.go index eb633428cf..fc44c8eeed 100644 --- a/internal/ateworkervalidation/zz_generated.validation.go +++ b/internal/ateworkervalidation/zz_generated.validation.go @@ -922,6 +922,8 @@ func Validate_ContainerSpec( errs = append(errs, fn(fldPath.Child("resources"), obj.Resources, oldVal, oldObj != nil)...) } + // field ateworkerpb.ContainerSpec.User has no validation + // field ateworkerpb.ContainerSpec.Cwd has no validation return errs } diff --git a/internal/e2e/fixture.go b/internal/e2e/fixture.go index 5410bb7c0c..1abf83d227 100644 --- a/internal/e2e/fixture.go +++ b/internal/e2e/fixture.go @@ -92,6 +92,7 @@ type FixtureOption func(*fixtureConfig) type fixtureConfig struct { templateValues map[string]string + imageUser string } // WithTemplateValue replaces the inline placeholder ${name} in the fixture's @@ -105,6 +106,12 @@ func WithTemplateValue(name, value string) FixtureOption { } } +// WithImageUser sets user as the USER of the images ko builds for the +// fixture's ActorTemplates, as a Dockerfile USER line would. +func WithImageUser(user string) FixtureOption { + return func(c *fixtureConfig) { c.imageUser = user } +} + // SubstrateFixtureManifests names the two manifest templates a substrate // fixture is built from (both repo-relative, under internal/e2e/fixtures). type SubstrateFixtureManifests struct { @@ -157,7 +164,11 @@ func DeploySubstrateFixture(t *testing.T, ctx context.Context, clients *Clients, tmplInline, tmplBlocks := substrateTemplateSubstitutions(name, trustBundles) maps.Copy(tmplInline, cfg.templateValues) - rendered := koResolve(t, renderManifest(t, manifests.Template, tmplInline, tmplBlocks)) + var resolveArgs []string + if cfg.imageUser != "" { + resolveArgs = append(resolveArgs, "--image-user", cfg.imageUser) + } + rendered := koResolve(t, renderManifest(t, manifests.Template, tmplInline, tmplBlocks), resolveArgs...) templates := decodeSubstrateTemplates(t, rendered) atespace := templates[0].GetMetadata().GetAtespace() diff --git a/internal/e2e/fixtures/probe/main.go b/internal/e2e/fixtures/probe/main.go index 5dedcb1005..80a68179db 100644 --- a/internal/e2e/fixtures/probe/main.go +++ b/internal/e2e/fixtures/probe/main.go @@ -223,6 +223,36 @@ func readfile(w http.ResponseWriter, r *http.Request) { writeJSON(w, resp) } +// statResponse is the /stat payload: path's numeric owner and mode as the +// actor sees them, without following a final-component symlink. +type statResponse struct { + Path string `json:"path"` + UID uint32 `json:"uid"` + GID uint32 `json:"gid"` + // Mode is the os.FileMode string, e.g. "drwx------". + Mode string `json:"mode"` + Error string `json:"error,omitempty"` +} + +// stat reports a path's owner and mode inside the actor, so a test can assert +// on the ownership the image's layers gave it. +func stat(w http.ResponseWriter, r *http.Request) { + resp := statResponse{Path: r.URL.Query().Get("path")} + fi, err := os.Lstat(resp.Path) + if err != nil { + resp.Error = err.Error() + writeJSON(w, resp) + return + } + resp.Mode = fi.Mode().String() + if st, ok := fi.Sys().(*syscall.Stat_t); ok { + resp.UID, resp.GID = st.Uid, st.Gid + } else { + resp.Error = "no owner information for " + resp.Path + } + writeJSON(w, resp) +} + func writefile(w http.ResponseWriter, r *http.Request) { path := r.URL.Query().Get("path") resp := map[string]string{"path": path} @@ -629,6 +659,7 @@ func main() { mux.HandleFunc("/readfile", readfile) mux.HandleFunc("/writefile", writefile) mux.HandleFunc("/lookup", lookup) + mux.HandleFunc("/stat", stat) mux.HandleFunc("/resources", resources) mux.HandleFunc("/capabilities", capabilities) mux.HandleFunc("/healthz", healthz) diff --git a/internal/e2e/fixtures/probe/main_test.go b/internal/e2e/fixtures/probe/main_test.go index 7d26c6a151..e7ec377308 100644 --- a/internal/e2e/fixtures/probe/main_test.go +++ b/internal/e2e/fixtures/probe/main_test.go @@ -515,3 +515,48 @@ func TestRestoreFetchRetriesOnNextProbe(t *testing.T) { time.Sleep(50 * time.Millisecond) } } + +func doStat(t *testing.T, path string) statResponse { + t.Helper() + req := httptest.NewRequest(http.MethodGet, "/stat?"+url.Values{"path": {path}}.Encode(), nil) + rec := httptest.NewRecorder() + stat(rec, req) + var resp statResponse + if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil { + t.Fatalf("decoding /stat response %q: %v", rec.Body.String(), err) + } + return resp +} + +// The imagefs e2e suite asserts on /stat's owner and mode, so this pins both +// against files whose owner and mode the test sets itself. +func TestStatReportsOwnerAndMode(t *testing.T) { + dir := t.TempDir() + priv := filepath.Join(dir, "private") + if err := os.Mkdir(priv, 0o700); err != nil { + t.Fatal(err) + } + // Mkdir's mode is clipped by the umask; set it exactly. + if err := os.Chmod(priv, 0o700); err != nil { + t.Fatal(err) + } + link := filepath.Join(dir, "link") + if err := os.Symlink("private", link); err != nil { + t.Fatal(err) + } + + got := doStat(t, priv) + want := statResponse{Path: priv, UID: uint32(os.Getuid()), GID: got.GID, Mode: "drwx------"} + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("/stat %s mismatch (-want +got):\n%s", priv, diff) + } + + // The symlink itself, not its target. + if got := doStat(t, link); !strings.HasPrefix(got.Mode, "L") || got.Error != "" { + t.Errorf("/stat %s = %+v, want the symlink's own mode", link, got) + } + + if got := doStat(t, filepath.Join(dir, "missing")); got.Error == "" { + t.Errorf("/stat of a missing path reported no error: %+v", got) + } +} diff --git a/internal/e2e/fixtures/probe/nonroot/main.go b/internal/e2e/fixtures/probe/nonroot/main.go new file mode 100644 index 0000000000..587b69f283 --- /dev/null +++ b/internal/e2e/fixtures/probe/nonroot/main.go @@ -0,0 +1,91 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Command nonroot is the probe for an image with a non-root USER and a +// WORKDIR that user owns. It reports the identity, effective capabilities and +// working directory the actor's process runs with. +// +// It is a separate binary from the probe because ko picks the base image per +// import path. The probe stays on the root base, and this one builds on the +// default nonroot distroless base, whose WORKDIR is /home/nonroot. +package main + +import ( + "encoding/json" + "log" + "net/http" + "os" + "strings" +) + +// identityResponse is the /identity payload. +type identityResponse struct { + UID int `json:"uid"` + GID int `json:"gid"` + Groups []int `json:"groups"` + Cwd string `json:"cwd"` + // CapEff is the CapEff mask from /proc/self/status, in hex. + CapEff string `json:"capEff"` + // WriteError is why creating a file in the working directory failed. + WriteError string `json:"writeError,omitempty"` + Error string `json:"error,omitempty"` +} + +func identity(w http.ResponseWriter, _ *http.Request) { + resp := identityResponse{UID: os.Getuid(), GID: os.Getgid(), Groups: []int{}} + if groups, err := os.Getgroups(); err == nil { + resp.Groups = append(resp.Groups, groups...) + } else { + resp.Error += "getgroups: " + err.Error() + "; " + } + if cwd, err := os.Getwd(); err == nil { + resp.Cwd = cwd + } else { + resp.Error += "getwd: " + err.Error() + "; " + } + if status, err := os.ReadFile("/proc/self/status"); err == nil { + for line := range strings.Lines(string(status)) { + if v, ok := strings.CutPrefix(line, "CapEff:"); ok { + resp.CapEff = strings.TrimSpace(v) + } + } + } else { + resp.Error += "reading /proc/self/status: " + err.Error() + "; " + } + if f, err := os.CreateTemp(".", "write-check-"); err == nil { + _ = f.Close() + if err := os.Remove(f.Name()); err != nil { + resp.WriteError = err.Error() + } + } else { + resp.WriteError = err.Error() + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(resp); err != nil { + log.Printf("nonroot probe: writing response: %v", err) + } +} + +func main() { + mux := http.NewServeMux() + mux.HandleFunc("/identity", identity) + mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }) + + const addr = ":80" + log.Printf("nonroot probe listening on %s", addr) + if err := http.ListenAndServe(addr, mux); err != nil { + log.Fatalf("nonroot probe server: %v", err) + } +} diff --git a/internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl b/internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl new file mode 100644 index 0000000000..6ada59c5b1 --- /dev/null +++ b/internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl @@ -0,0 +1,38 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# An ActorTemplate on the probe pool (probe.yaml.tmpl) whose image runs as a +# named non-root USER in a WORKDIR that user owns. The imagefs suite resolves +# it with `ko resolve --image-user nonroot:nonroot` (e2e.WithImageUser); the +# nonroot distroless base sets WORKDIR /home/nonroot. + +metadata: + atespace: ate-e2e-probe${FIXTURE_SUFFIX} + name: probe-nonroot +workerSelector: + matchLabels: + workload: probe${FIXTURE_SUFFIX} +containers: +- name: probe + image: ko://go.ate.dev/substrate/internal/e2e/fixtures/probe/nonroot + command: ["/ko-app/nonroot"] + wakeupProbe: + httpGet: + path: /healthz + port: 80 + timeoutSeconds: 60 +resources: + limits: + cpuMillicores: 1000 + memoryBytes: 536870912 # 512Mi diff --git a/internal/e2e/manifest.go b/internal/e2e/manifest.go index 5714973ba6..b7623cd2ea 100644 --- a/internal/e2e/manifest.go +++ b/internal/e2e/manifest.go @@ -120,12 +120,14 @@ func koApply(t *testing.T, manifest string) { // the manifest with those references replaced by pushed digests. Same pinned // ko and KO_CONFIG_PATH rules as koApply; resolve is how a manifest that is // not destined for kubectl (a protojson ActorTemplate document) still gets -// its image built. -func koResolve(t *testing.T, manifest string) []byte { +// its image built. args go to ko resolve before the manifest. +func koResolve(t *testing.T, manifest string, args ...string) []byte { t.Helper() root, err := FindRepoRoot() if err != nil { t.Fatalf("FindRepoRoot: %v", err) } - return RunCmdOutput(t, []string{"KO_CONFIG_PATH=" + root}, filepath.Join(root, "hack/run-tool.sh"), "ko", "resolve", "-f", manifest) + resolveArgs := append([]string{"ko", "resolve"}, args...) + resolveArgs = append(resolveArgs, "-f", manifest) + return RunCmdOutput(t, []string{"KO_CONFIG_PATH=" + root}, filepath.Join(root, "hack/run-tool.sh"), resolveArgs...) } diff --git a/internal/e2e/sandbox_test.go b/internal/e2e/sandbox_test.go index 427bb5d823..d60ce2aec0 100644 --- a/internal/e2e/sandbox_test.go +++ b/internal/e2e/sandbox_test.go @@ -40,6 +40,10 @@ var substrateFixtures = []struct { Pool: "internal/e2e/fixtures/probe/probe.yaml.tmpl", Template: "internal/e2e/fixtures/probe/probe-template.yaml.tmpl", }, 1, nil}, + {SubstrateFixtureManifests{ + Pool: "internal/e2e/fixtures/probe/probe.yaml.tmpl", + Template: "internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl", + }, 1, nil}, {SubstrateFixtureManifests{ Pool: "internal/e2e/fixtures/probe/probe.yaml.tmpl", Template: "internal/e2e/fixtures/probe/probe-bootfetch-template.yaml.tmpl", diff --git a/internal/e2e/suites/imagefs/imagefs_test.go b/internal/e2e/suites/imagefs/imagefs_test.go new file mode 100644 index 0000000000..e354d420f8 --- /dev/null +++ b/internal/e2e/suites/imagefs/imagefs_test.go @@ -0,0 +1,243 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package imagefs checks the actor's view of its image's filesystem and +// process identity against what the image records. +package imagefs + +import ( + "context" + "encoding/json" + "io" + "net/http" + "net/url" + "strconv" + "testing" + + "go.ate.dev/substrate/api/ateapi/v1" + "go.ate.dev/substrate/internal/e2e" + "go.ate.dev/substrate/internal/resources" +) + +// statResponse mirrors the probe's /stat payload. +type statResponse struct { + Path string `json:"path"` + UID uint32 `json:"uid"` + GID uint32 `json:"gid"` + Mode string `json:"mode"` + Error string `json:"error"` +} + +// layerOwners are paths whose owner and mode the probe image's layers record. +// .ko.yaml builds the probe on the root distroless static base, whose base +// layer has /home/nonroot as drwx------ owned by 65532:65532 (distroless's +// nonroot user), /var/tmp as root-owned 1777, and root-owned system files. +// /var/tmp, not /tmp, checks the sticky bit: gVisor mounts its own 1777 tmpfs +// over an empty /tmp. +var layerOwners = []statResponse{ + {Path: "/home/nonroot", UID: 65532, GID: 65532, Mode: "drwx------"}, + {Path: "/var/tmp", UID: 0, GID: 0, Mode: "dtrwxrwxrwx"}, + {Path: "/etc/passwd", UID: 0, GID: 0, Mode: "-rw-r--r--"}, + {Path: "/home", UID: 0, GID: 0, Mode: "drwxr-xr-x"}, +} + +// TestImageLayerOwnership asserts that files keep the owners the image's +// layer tars record, as they do under containerd: a private home directory +// given to a non-root user must not show up as root-owned inside the actor. +// It checks once on the first start and again after a suspend and resume, +// which restores the actor over the same cached layers. +// +// It runs against whichever sandbox class E2E_SANDBOX_CLASS selects, so CI +// covers both gVisor and microVM from one suite. +func TestImageLayerOwnership(t *testing.T) { + if _, err := e2e.CheckEnv("KO_DOCKER_REPO"); err != nil { + t.Fatalf("CheckEnv failed: %v", err) + } + ctx := context.Background() + clients := e2e.GetClients() + + atespace, tmpl := e2e.DeployProbe(t, "imagefs") + ref := &ateapi.ObjectRef{Atespace: atespace, Name: "imagefs-actor"} + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapi.CreateActorRequest{Actor: &ateapi.Actor{ + Metadata: &ateapi.ResourceMetadata{Atespace: ref.Atespace, Name: ref.Name}, + ActorTemplate: &ateapi.ObjectRef{Atespace: atespace, Name: tmpl.GetMetadata().GetName()}, + }}); err != nil { + t.Fatalf("CreateActor %q: %v", ref.Name, err) + } + t.Cleanup(func() { + _, _ = clients.SubstrateAPI.DeleteActor(ctx, &ateapi.DeleteActorRequest{Actor: ref}) + }) + + rc, err := e2e.NewRouterClient(t, ctx) + if err != nil { + t.Fatalf("NewRouterClient: %v", err) + } + defer rc.Close() + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapi.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("ResumeActor %q: %v", ref.Name, err) + } + t.Run("first start", func(t *testing.T) { checkOwners(t, ctx, rc, ref) }) + + suspended, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapi.SuspendActorRequest{Actor: ref}) + if err != nil { + t.Fatalf("SuspendActor %q: %v", ref.Name, err) + } + if got := suspended.GetActor().GetStatus().GetState(); got != ateapi.ActorState_ACTOR_STATE_SUSPENDED { + t.Fatalf("SuspendActor %q: state %v, want %v", ref.Name, got, ateapi.ActorState_ACTOR_STATE_SUSPENDED) + } + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapi.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("ResumeActor %q after suspend: %v", ref.Name, err) + } + t.Run("after suspend and resume", func(t *testing.T) { checkOwners(t, ctx, rc, ref) }) +} + +// identityResponse mirrors the nonroot probe's /identity payload. +type identityResponse struct { + UID int `json:"uid"` + GID int `json:"gid"` + Groups []int `json:"groups"` + Cwd string `json:"cwd"` + CapEff string `json:"capEff"` + WriteError string `json:"writeError"` + Error string `json:"error"` +} + +// The nonroot probe image's USER is nonroot:nonroot. The distroless base's +// /etc/passwd and /etc/group give that user and group id 65532 and list the +// user in no other group. Its WORKDIR, /home/nonroot, is 65532:65532 and +// drwx------. +const ( + nonrootID = 65532 + nonrootWorkdir = "/home/nonroot" +) + +// TestImageUserAndWorkdir asserts that the actor's process runs as its image's +// USER, resolved by name against the image's own /etc/passwd and /etc/group, +// with no effective capabilities, and starts in the image's WORKDIR, where +// that user can create files. The WORKDIR is private to the user, so the +// write also needs the layer owners TestImageLayerOwnership checks. +// +// The golden bake runs the probe as that user and binds :80, and the actor +// resumes from that golden snapshot. It runs against whichever sandbox class +// E2E_SANDBOX_CLASS selects, so CI covers both gVisor and microVM. +func TestImageUserAndWorkdir(t *testing.T) { + if _, err := e2e.CheckEnv("KO_DOCKER_REPO"); err != nil { + t.Fatalf("CheckEnv failed: %v", err) + } + ctx := context.Background() + clients := e2e.GetClients() + + atespace, templates := e2e.DeploySubstrateFixture(t, ctx, clients, e2e.SubstrateFixtureManifests{ + Pool: "internal/e2e/fixtures/probe/probe.yaml.tmpl", + Template: "internal/e2e/fixtures/probe/probe-nonroot-template.yaml.tmpl", + }, "imagefs-user", nil, e2e.WithImageUser("nonroot:nonroot")) + ref := &ateapi.ObjectRef{Atespace: atespace, Name: "imagefs-user-actor"} + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapi.CreateActorRequest{Actor: &ateapi.Actor{ + Metadata: &ateapi.ResourceMetadata{Atespace: ref.Atespace, Name: ref.Name}, + ActorTemplate: &ateapi.ObjectRef{Atespace: atespace, Name: templates[0].GetMetadata().GetName()}, + }}); err != nil { + t.Fatalf("CreateActor %q: %v", ref.Name, err) + } + t.Cleanup(func() { + _, _ = clients.SubstrateAPI.DeleteActor(ctx, &ateapi.DeleteActorRequest{Actor: ref}) + }) + + rc, err := e2e.NewRouterClient(t, ctx) + if err != nil { + t.Fatalf("NewRouterClient: %v", err) + } + defer rc.Close() + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapi.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("ResumeActor %q: %v", ref.Name, err) + } + + got := probeIdentity(t, ctx, rc, ref) + if got.Error != "" { + t.Errorf("probe reported an error reading its identity: %s", got.Error) + } + if got.UID != nonrootID || got.GID != nonrootID { + t.Errorf("process runs as %d:%d, want %d:%d from the image's USER nonroot:nonroot", got.UID, got.GID, nonrootID, nonrootID) + } + // Linux may list the primary group among the supplementary ones. Any + // other group, such as root's 0, was not granted by the image. + for _, g := range got.Groups { + if g != nonrootID { + t.Errorf("supplementary groups = %v, want none besides %d", got.Groups, nonrootID) + break + } + } + // Without ambient capabilities, a non-root process has none effective. + if capEff, err := strconv.ParseUint(got.CapEff, 16, 64); err != nil || capEff != 0 { + t.Errorf("CapEff = %q, want no effective capabilities for a non-root USER", got.CapEff) + } + if got.Cwd != nonrootWorkdir { + t.Errorf("working directory = %q, want the image's WORKDIR %q", got.Cwd, nonrootWorkdir) + } + if got.WriteError != "" { + t.Errorf("creating a file in the WORKDIR as the image's USER: %s", got.WriteError) + } +} + +func probeIdentity(t *testing.T, ctx context.Context, rc *e2e.RouterClient, ref *ateapi.ObjectRef) identityResponse { + t.Helper() + resp, err := rc.Get(ctx, resources.ActorRef{Atespace: ref.Atespace, Name: ref.Name}, "/identity") + if err != nil { + t.Fatalf("GET /identity: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + t.Fatalf("GET /identity: status %d, body %q", resp.StatusCode, body) + } + var out identityResponse + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + t.Fatalf("decoding /identity: %v", err) + } + return out +} + +func checkOwners(t *testing.T, ctx context.Context, rc *e2e.RouterClient, ref *ateapi.ObjectRef) { + t.Helper() + for _, want := range layerOwners { + got := probeStat(t, ctx, rc, ref, want.Path) + if got.Error != "" { + t.Errorf("stat %s inside the actor: %s", want.Path, got.Error) + continue + } + if got.UID != want.UID || got.GID != want.GID || got.Mode != want.Mode { + t.Errorf("%s inside the actor is %s %d:%d, want %s %d:%d as the image's layer records it", + want.Path, got.Mode, got.UID, got.GID, want.Mode, want.UID, want.GID) + } + } +} + +func probeStat(t *testing.T, ctx context.Context, rc *e2e.RouterClient, ref *ateapi.ObjectRef, path string) statResponse { + t.Helper() + resp, err := rc.Get(ctx, resources.ActorRef{Atespace: ref.Atespace, Name: ref.Name}, "/stat?"+url.Values{"path": {path}}.Encode()) + if err != nil { + t.Fatalf("GET /stat %s: %v", path, err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + t.Fatalf("GET /stat %s: status %d, body %q", path, resp.StatusCode, body) + } + var out statResponse + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + t.Fatalf("decoding /stat %s: %v", path, err) + } + return out +} diff --git a/internal/e2e/suites/imagefs/testmain_test.go b/internal/e2e/suites/imagefs/testmain_test.go new file mode 100644 index 0000000000..e22b83e12d --- /dev/null +++ b/internal/e2e/suites/imagefs/testmain_test.go @@ -0,0 +1,24 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package imagefs + +import ( + "os" + "testing" + + "go.ate.dev/substrate/internal/e2e" +) + +func TestMain(m *testing.M) { os.Exit(e2e.RunTestMain(m)) } diff --git a/internal/imagecache/README.md b/internal/imagecache/README.md index db37c4c2e3..126a00deec 100644 --- a/internal/imagecache/README.md +++ b/internal/imagecache/README.md @@ -37,13 +37,15 @@ What it buys, concretely: ## The privilege split The design is shaped by an existing substrate boundary: **atelet runs as -plain root with every Linux capability dropped** ("atelet does no mounts" — -see `manifests/ate-install/atelet.yaml`), while the **worker pods are -privileged** and own all mounts on the node. The module is split accordingly: +root with every Linux capability dropped but a few for files other users +own** ("atelet does no mounts" — see +[`manifests/ate-install/atelet.yaml`](../../manifests/ate-install/atelet.yaml), +which gives the reason for each), while the **worker pods hold the mount +capabilities** and own all mounts on the node. The module is split accordingly: | Half | Runs in | Files | Needs | |---|---|---|---| -| Store: pull, parse, unpack, record | atelet | `imagecache.go`, `unpack.go`, `spec.go` (portable) | nothing but file I/O | +| Store: pull, parse, unpack, record | atelet | `imagecache.go`, `unpack.go`, `spec.go` (portable) | file I/O; `CAP_CHOWN`, `CAP_DAC_OVERRIDE`, `CAP_FOWNER`, `CAP_FSETID` | | Consumer: finalize, mount, unmount | ateworker-gvisor / ateworker-microvm | `bundle_linux.go` (`//go:build linux`) | `CAP_MKNOD`, `CAP_SYS_ADMIN` | The two halves communicate through the filesystem only: the shared cache @@ -59,7 +61,7 @@ anywhere. ``` / default: /var/lib/ate/image-cache - version layout version marker ("2") + version layout version marker ("3") layers/sha256// fs/ the unpacked layer tree (an overlay lowerdir) whiteouts.json whiteout state recorded at unpack time @@ -101,12 +103,18 @@ layer diffIDs in order — layers shared by N images exist once. confinement (path traversal and symlink/hardlink escapes are refused), "later entry wins" within a layer, read-only-dir handling that works without `CAP_DAC_OVERRIDE`, and creation of parent directories that the - layer tar omits (they may exist only in lower layers). Character and - block device nodes are skipped (atelet runs without `CAP_MKNOD` and the - runtime mounts `/dev`). Whiteout entries (`.wh.*`) are **not** written - into the tree — overlayfs whiteouts are char devices atelet cannot - create — they are recorded in `whiteouts.json` for the consumer to - materialize. + layer tar omits (they may exist only in lower layers). Every entry keeps + the numeric owner and the exact mode its tar header records, setuid, + setgid and sticky bits included, as containerd and moby apply them + (see `unpackLayer` for how a failed chown or chmod is handled). A root + atelet inside a user namespace (rootless or userns-remapped nodes) can + only give files to uids and gids the namespace maps, so a layer with an + owner outside that range fails to unpack, as it does under rootless + Docker. Character and block device nodes are skipped (atelet runs + without `CAP_MKNOD` and the runtime mounts `/dev`). Whiteout entries + (`.wh.*`) are **not** written into the tree — overlayfs whiteouts are + char devices atelet cannot create — they are recorded in + `whiteouts.json` for the consumer to materialize. 5. **Verify** before the layer enters the pool. Images share layers by diffID, but each image's author chooses the diffIDs in its config. So the uncompressed stream is hashed as it unpacks and must match the @@ -117,7 +125,8 @@ layer diffIDs in order — layers shared by N images exist once. A layer already in the pool is reused without re-hashing, because it was checked when it was written. The reusing image's own blob is never downloaded, so it is never checked. atelet refuses a layout version 1 - pool, whose layers may not have been checked. + pool, whose layers may not have been checked, and a version 2 pool, + whose layers are root-owned without setuid, setgid or sticky bits. 6. **Record**: the image config + diffID list is written under the requested digest (and the per-platform child digest for multi-arch refs). diff --git a/internal/imagecache/ateletcaps_test.go b/internal/imagecache/ateletcaps_test.go new file mode 100644 index 0000000000..26894ef135 --- /dev/null +++ b/internal/imagecache/ateletcaps_test.go @@ -0,0 +1,199 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package imagecache + +import ( + "bytes" + "os" + "os/exec" + "regexp" + "runtime" + "slices" + "strconv" + "strings" + "testing" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/yaml" +) + +// Capability bits, from linux/capability.h. +const ( + capChown = 0 + capDacOverride = 1 + capFowner = 3 + capFsetid = 4 + capSysAdmin = 21 + capMknod = 27 +) + +// capSet is a capability set a root-gated test runs under, as root with +// every other capability dropped. +type capSet struct { + // bounding is the set in setpriv(1)'s --bounding-set syntax. + bounding string + // eff is the effective set the child process must report. + eff uint64 +} + +var ( + // ateletCaps is the set manifests/ate-install/atelet.yaml grants atelet. + ateletCaps = capSet{ + bounding: "-all,+chown,+dac_override,+fowner,+fsetid", + eff: 1<
agent-substrate/substrate on Trendshift: #1 repository of the day [Quickstart](#quickstart-development) · [Security](docs/security/security.md) · [Architecture](docs/concepts/architecture.md) · [Contributing](CONTRIBUTING.md) + + Agents are idle most of the time. Agent Substrate suspends idle agents and resumes them on request onto a small pool of warm worker pods. + +
## What is Agent Substrate? diff --git a/docs/assets/readme-hero.svg b/docs/assets/readme-hero.svg new file mode 100644 index 0000000000..ce9e5a214d --- /dev/null +++ b/docs/assets/readme-hero.svg @@ -0,0 +1,392 @@ + + +Agent Substrate multiplexes 250 agents onto 8 warm worker pods +Agents are idle most of the time. Idle agents suspend, resume on any ready worker, and keep their memory and filesystem state. The atenet router routes requests and resumes suspended agents onto 8 warm worker pods. + + + +HOW IT WORKS +Agents are idle most of the time. +Stop paying for it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +250 agents +most of them suspended + +AGENT SUBSTRATE + + + + +atenet router + + + +suspend when idle + +resume on request +Agent Substrate +routes & resumes on request + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +8 warm worker pods +several agents per pod, each in its own sandbox + + + + + + +Idle agents suspend, resume on any ready worker, +and keep their memory and filesystem state. + +Visit ate.dev + + +$ kubectl ate create actor my-agent --template counter + From 61ea6c61df57acf916873b4200f731421c689b4d Mon Sep 17 00:00:00 2001 From: Mofi Rahman Date: Fri, 30 Oct 2026 01:15:03 +0000 Subject: [PATCH 11/16] site: publish per-page Markdown and fix llms.txt and llms-full.txt (#3435) `ate.dev/llms.txt` linked to full Docsy HTML pages instead of standalone Markdown files, omitted page status markers and schema links, and still used the old `ateom` component name. Meanwhile, `raw-markdown.html` wrote into an HTML template buffer and expanded `include-file` with `replaceRE`, which HTML-escaped code blocks and blockquotes across `ate.dev/llms-full.txt` and "Copy as Markdown" (`'`, `"`, `>`), stripped `$VAR` shell references as regexp capture groups, left relative links unrewritten, and kept decorative `
` HTML blocks. - Add the `MARKDOWN` output format for doc pages (`site/layouts/docs/single.md`) so each page publishes a clean `index.md` alongside `index.html` and exposes `` in ``. - Return a plain string from `raw-markdown.html`, expand `include-file` with literal replacement, drop decorative diagram HTML, and rewrite relative links to absolute URLs across `llms-full.txt`, per-page `index.md`, and "Copy as Markdown". - Update `index.llms.txt` to link to each page's `index.md` build, include `[Status: ...]` labels from front matter, link the `ateapi.proto`, `ate.dev/v1` CRD, and OpenTelemetry Weaver metric schemas, and summarize the sandbox model and the split between `ate.dev/v1` Kubernetes CRDs and the `ate-api-server` gRPC API. - Replace leftover `ateom`, `ate-api`, and `herder` references in docs with `ateworker`, `atenet-router`, and `ate-api-server`, and add template tests in `hack/test-site-templates.sh`. AI use: AI-assisted, I reviewed and tested it. - [x] Tests pass - [x] Docs updated --------- Signed-off-by: Mofi Rahman --- docs/concepts/architecture.md | 6 +- docs/get-started/overview.md | 8 +-- docs/get-started/quickstart.md | 12 ++-- docs/guides/authentication.md | 2 +- docs/guides/authorization.md | 2 +- docs/reference/api-guide.md | 6 +- docs/reference/glossary.md | 2 +- hack/test-site-templates.sh | 16 ++++- site/README.md | 15 ++++ site/hugo.yaml | 1 + site/layouts/404.html | 4 +- site/layouts/_partials/raw-markdown.html | 26 ++++--- .../layouts/_partials/rewrite-repo-links.html | 18 ++++- site/layouts/docs/single.md | 16 +++++ site/layouts/index.llms.txt | 69 ++++++++++++++++--- site/layouts/index.llmsfull.txt | 7 +- site/testdata/repo/docs/plain.md | 2 + 17 files changed, 167 insertions(+), 45 deletions(-) create mode 100644 site/layouts/docs/single.md diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md index c7920e27f7..7795d7c05a 100644 --- a/docs/concepts/architecture.md +++ b/docs/concepts/architecture.md @@ -331,9 +331,9 @@ manage actor lifecycles. The node-level subsystem manages the physical execution of sandboxes and the movement of snapshots. - * **atelet**: A lightweight supervisor running on each node as a DaemonSet. It acts as the "Herder," managing a pool of physical pods and communicating with the Control Plane. + * **atelet**: A lightweight supervisor running on each node as a DaemonSet. It manages local worker pods and communicates with the Control Plane. - * **ateworker**: A specialized sandbox-herder container image — one per sandbox class (`ateworker-gvisor`, `ateworker-microvm`) — that runs inside the physical worker pods. It provides a gRPC interface for `atelet` to trigger `RunWorkload`, `CheckpointWorkload`, and `RestoreWorkload` operations. This separation ensures that the physical pod lifecycle remains decoupled from the sandboxed agent process. + * **ateworker**: The worker container image (`ateworker-gvisor` or `ateworker-microvm`, one per sandbox class) that runs inside each physical worker pod. It provides a gRPC interface for `atelet` to trigger `RunWorkload`, `CheckpointWorkload`, and `RestoreWorkload` operations. This separation ensures that the physical pod lifecycle remains decoupled from the sandboxed agent process. * **Lifecycle Management**: The `ateworker` process invokes the sandbox runtime to checkpoint or restore processes within the physical pod boundaries — `runsc` for gVisor, or the Kata + Cloud Hypervisor stack for microVMs. (Note: the gVisor backend currently requires a `runsc` version with the `--allow-connected-on-save` flag to work around a bug in networking resumption during checkpointing.) @@ -343,7 +343,7 @@ The node-level subsystem manages the physical execution of sandboxes and the mov ### Sandbox Classes -A `WorkerPool` selects a **sandbox class** (`spec.sandboxClasses[].name`), and each class has a matching `ateworker` herder image. The sandbox binaries themselves are not baked into the worker image. They come at runtime from the cluster-scoped [`SandboxConfig`](../reference/api-guide.md#3-sandboxconfig-the-sandbox-itself) the `WorkerPool` resolves for its class (an explicit `configRef`, else the class default). Each snapshot records the sandbox runtime it was taken on, and a memory restore runs on a worker that still offers that runtime, so restores stay reproducible across runtime upgrades. +A `WorkerPool` selects a **sandbox class** (`spec.sandboxClasses[].name`), and each class has a matching `ateworker` image. The sandbox binaries themselves are not baked into the worker image. They come at runtime from the cluster-scoped [`SandboxConfig`](../reference/api-guide.md#3-sandboxconfig-the-sandbox-itself) the `WorkerPool` resolves for its class (an explicit `configRef`, else the class default). Each snapshot records the sandbox runtime it was taken on, and a memory restore runs on a worker that still offers that runtime, so restores stay reproducible across runtime upgrades. * **gVisor** (`ateworker-gvisor`, the default): Runs the workload under `runsc` for kernel-level sandboxing. Suspend and resume leverage gVisor's native checkpoint/restore of the sandboxed process tree. `DurableDir` volumes and each container's rootfs overlay are saved as separate filesystem checkpoint bundles (`fs/` and `rootfs/`). A `MEMORY` snapshot splits them out of the process checkpoint; `VOLUMES` and `ROOTFS` snapshots save only the bundles they need with `runsc fscheckpoint`, without memory, and restore them on a cold boot. diff --git a/docs/get-started/overview.md b/docs/get-started/overview.md index 224482845a..001ad8ce11 100644 --- a/docs/get-started/overview.md +++ b/docs/get-started/overview.md @@ -40,8 +40,8 @@ Substrate decouples the **Actor** (a stateful agent or workload instance) from t
Pre-Warmed Worker Pod (WorkerPool) - Worker (ateom + Sandbox) - ateom herder · atunnel mTLS · microVM / gVisor hosting Actor + Worker (ateworker + Sandbox) + ateworker · atunnel mTLS · microVM / gVisor hosting Actor
@@ -50,6 +50,6 @@ Substrate decouples the **Actor** (a stateful agent or workload instance) from t
-* **Core Platform Terms at a Glance:** Each actor lives in an `atespace` (`/`), traffic enters via `atenet`, node supervision and snapshot streaming are handled by `atelet`, and sandbox execution inside each warm `Worker` is managed by `ateom` (internally prefixed `ate` across binaries and CRDs). See the **[Glossary](../reference/glossary.md)** for complete definitions. +* **Core Platform Terms at a Glance:** Each actor lives in an `atespace` (`/`), traffic enters via `atenet-router`, node supervision and snapshot streaming are handled by `atelet`, and sandbox execution inside each warm `Worker` is managed by `ateworker` (internally prefixed `ate` across binaries and CRDs). See the **[Glossary](../reference/glossary.md)** for complete definitions. * **Framework Agnostic:** Runs standard OCI containers inside zero-trust sandboxes—supporting ADK, LangChain, Hermes, OpenClaw, MCP servers, and stateful coding environments out of the box. -* **Ready to try it?** Jump straight to **[Quickstart](quickstart.md)** to launch your first actor locally on Kind, follow the **[GKE Installation Guide](https://docs.cloud.google.com/kubernetes-engine/ai-ml/install-overview-substrate)** to deploy on Google Kubernetes Engine, or explore the **[Architecture](../concepts/architecture.md)**. +* **Ready to try it?** Jump straight to **[Quickstart](quickstart.md)** to launch your first actor locally on [kind](https://kind.sigs.k8s.io/), follow the **[GKE Installation Guide](https://docs.cloud.google.com/kubernetes-engine/ai-ml/install-overview-substrate)** to deploy on Google Kubernetes Engine, or explore the **[Architecture](../concepts/architecture.md)**. diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md index 1d37504b9d..3249d8e091 100644 --- a/docs/get-started/quickstart.md +++ b/docs/get-started/quickstart.md @@ -5,25 +5,25 @@ weight: 2 aliases: - "/docs/getting-started/" description: > - Deploy Agent Substrate on a local Kind cluster and invoke your first stateful actor. + Deploy Agent Substrate on a local kind cluster and invoke your first stateful actor. --- # Quickstart & Installation -Deploy the Agent Substrate control plane and the stateful **Counter** sample application on a local `kind` cluster. +Deploy the Agent Substrate control plane and the stateful **Counter** sample application on a local [kind](https://kind.sigs.k8s.io/) cluster. > [!NOTE] -> **Prerequisites:** Ensure [Go](https://go.dev/doc/install), [`kubectl`](https://kubernetes.io/docs/tasks/tools/), and [Docker](https://www.docker.com/) are installed (`kind` is managed automatically via Go). A Linux host that will run more than about a thousand sandboxes also needs a larger kernel neighbor table (`net.ipv4.neigh.default.gc_thresh1/2/3` = 4096/16384/32768); `hack/create-kind-cluster.sh` warns when the host is at the default of 1024. +> **Prerequisites:** Ensure [Go](https://go.dev/doc/install), [`kubectl`](https://kubernetes.io/docs/tasks/tools/), and [Docker](https://www.docker.com/) are installed ([`kind`](https://kind.sigs.k8s.io/) is managed automatically via Go). A Linux host that will run more than about a thousand sandboxes also needs a larger kernel neighbor table (`net.ipv4.neigh.default.gc_thresh1/2/3` = 4096/16384/32768); `hack/create-kind-cluster.sh` warns when the host is at the default of 1024. ## 1. Deploy Agent Substrate & Create an Actor Run the following commands from the repository root to provision a local `kind` cluster, install Agent Substrate, and create a `counter` actor: ```bash -# 1. Create a local Kind cluster and image registry (IPv4; IP_FAMILY=dual|ipv6 overrides) +# 1. Create a local kind cluster and image registry (IPv4; IP_FAMILY=dual|ipv6 overrides) hack/create-kind-cluster.sh -# 2. Target the local Kind cluster in every shell that runs ate-setup +# 2. Target the local kind cluster in every shell that runs ate-setup export ATE_INSTALL_KIND=true # 3. Install Agent Substrate, PostgreSQL, and snapshot storage (rustfs) @@ -66,7 +66,7 @@ data: OTEL_METRIC_EXPORT_TIMEOUT: "10000" OTEL_LOGS_EXPORTER: otlp --- -# ActorTemplate snapshotConfig rendered for Kind (local bucket) +# ActorTemplate snapshotConfig rendered for kind (local bucket) snapshotConfig: onPause: SNAPSHOT_CONTENT_SCOPE_FULL onCommit: SNAPSHOT_CONTENT_SCOPE_FULL diff --git a/docs/guides/authentication.md b/docs/guides/authentication.md index 4fee62633a..53130bf284 100644 --- a/docs/guides/authentication.md +++ b/docs/guides/authentication.md @@ -3,7 +3,7 @@ title: "Authentication" linkTitle: "Authentication" weight: 3 description: > - How clients authenticate to ate-api. + How clients authenticate to ate-api-server over SPIFFE mTLS or OIDC JWTs. --- # ate-api Authentication diff --git a/docs/guides/authorization.md b/docs/guides/authorization.md index fa726e2f7c..8d3b840e0f 100644 --- a/docs/guides/authorization.md +++ b/docs/guides/authorization.md @@ -3,7 +3,7 @@ title: "Authorization" linkTitle: "Authorization" weight: 4 description: > - How ate-api checks every call against an OpenFGA model, and how to manage roles and access. + How ate-api-server checks every call against an OpenFGA model, and how to manage roles and access. --- # ate-api Authorization diff --git a/docs/reference/api-guide.md b/docs/reference/api-guide.md index 9a26af21d4..ae1972f3e0 100644 --- a/docs/reference/api-guide.md +++ b/docs/reference/api-guide.md @@ -6,7 +6,7 @@ card_icon: "fa-solid fa-code" aliases: - "/docs/guides/api-guide/" description: > - Define WorkerPools and ActorTemplates, the workload blueprints of Agent Substrate. + Define WorkerPools, ActorTemplates, and SandboxConfigs, and call the Control Plane gRPC API. --- # Substrate API Guide: WorkerPool & ActorTemplate @@ -15,14 +15,14 @@ This guide explains how to configure Substrate resources to deploy high-density, ## 1. WorkerPool: The Physical Capacity -The `WorkerPool` defines the pool of physical "warm" compute capacity. It manages a fleet of standby pods (herders) that are ready to receive and execute actor states. +The `WorkerPool` defines the pool of physical "warm" compute capacity. It manages a fleet of standby worker pods that are ready to receive and execute actor states. ### Specification (`WorkerPoolSpec`) | Field | Type | Description | | :--- | :--- | :--- | | `replicas` | `int32` | **Required.** Number of physical standby pods to maintain in the cluster. | -| `workerImage` | `string` | **Required.** The container image for the `ateworker` herder process (e.g. `ko://go.ate.dev/substrate/cmd/ateworker-gvisor`). | +| `workerImage` | `string` | **Required.** The container image for the `ateworker` process (e.g. `ko://go.ate.dev/substrate/cmd/ateworker-gvisor`). | | `sandboxClasses` | `[]WorkerPoolSandboxClass` | **Required.** The sandbox runtime families the pool runs; exactly one entry today. Each entry has `name` (**required**, `gvisor` or `microvm`, immutable), which drives the worker pod shape (e.g. KVM device mounts, node placement), and `configRef.name` (optional), which names a cluster-scoped [`SandboxConfig`](#3-sandboxconfig-the-sandbox-itself) of the same class. Without `configRef`, the pool uses the class default (see [Class default](#class-default)). The controller records the result in `status.sandboxClasses`. The sandbox binaries an actor boots with come from the `SandboxConfig` the pool of its assigned worker resolved. | | `template` | `WorkerPoolPodTemplate` | **Optional.** Metadata, scheduling, and resource settings for worker workloads. | diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index c6ab5b604b..3951716204 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -22,7 +22,7 @@ For how the pieces fit together, see the [Architecture](../concepts/architecture overall platform and runtime, while **`ate`** (originally *Agent Task / Execution Engine*) is the internal prefix used across Kubernetes namespaces (`ate-system`), control-plane binaries (`ate-api-server`, `atecontroller`), - node and pod daemons (`atelet`, `ateom`), networking components (`atenet`, + node and pod daemons (`atelet`, `ateworker`), networking components (`atenet`, `atunnel`), HTTP routing headers (`ate-target-actor`), and the `kubectl-ate` CLI plugin. diff --git a/hack/test-site-templates.sh b/hack/test-site-templates.sh index f0e5ae0545..9a14c694a3 100755 --- a/hack/test-site-templates.sh +++ b/hack/test-site-templates.sh @@ -118,11 +118,23 @@ lacks main "${F}/override/index.html" 'as-status-banner--deprecated' lacks main "${F}/plain/index.html" 'as-status-banner' lacks main "${F}/index.html" 'as-status-banner' -# Copy as Markdown and llms-full.txt carry the status line. +# Copy as Markdown, per-page index.md, and llms-full.txt carry unescaped +# Markdown, preserve shell variables, and rewrite relative links. has main "${F}/experimental/index.html" '\*\*Status: Experimental\.\*\* This feature is experimental' -has main llms-full.txt '(>|>) \*\*Status: Deprecated\.\*\* Use the \[experimental page\]\(experimental\.md\) instead\.' +has main "${F}/deprecated/index.md" '> \*\*Status: Deprecated\.\*\* Use the \[experimental page\]\(https://example\.org/docs/fixtures/experimental/index\.md\) instead\.' +has main llms-full.txt '> \*\*Status: Deprecated\.\*\* Use the \[experimental page\]\(https://example\.org/docs/fixtures/experimental/index\.md\) instead\.' +has main "${F}/plain/index.md" '[$]SHELL_VAR' +has main llms-full.txt '[$]SHELL_VAR' +lacks main "${F}/plain/index.md" '>|<|"|'' +lacks main llms-full.txt '>|<|"|'' lacks main "${F}/plain/index.html" '\*\*Status:' +# llms.txt links to per-page Markdown files and prefixes non-GA statuses. +has main llms.txt '\[Plain Page\]\(https://example\.org/docs/fixtures/plain/index\.md\):' +has main llms.txt '\[Experimental Page\]\(https://example\.org/docs/fixtures/experimental/index\.md\): \[Status: Experimental\]' +has main llms.txt '\[Deprecated Page\]\(https://example\.org/docs/fixtures/deprecated/index\.md\): \[Status: Deprecated\]' +has main llms.txt '\[Planned Page\]\(https://example\.org/docs/fixtures/planned/index\.md\): \[Status: Planned\]' + # A status outside the allowed set fails the build and names the value. if build bogus testdata/hugo.bogus.yaml; then fail "bogus: build succeeded with status: experimantal" diff --git a/site/README.md b/site/README.md index 57541b2d4b..613a0817e1 100644 --- a/site/README.md +++ b/site/README.md @@ -70,6 +70,21 @@ writes `data/release.json`. `hack/site.sh test` builds the site against `testdata/` and checks the rendered templates. +## Machine-readable documentation (`llms.txt`) + +Hugo builds three plain-text outputs alongside the HTML pages: + +- `/llms.txt` (`layouts/index.llms.txt`), a concise project overview and index + linking to the Markdown build of each doc page and the repository's proto, + CRD, and metric schemas; +- `/llms-full.txt` (`layouts/index.llmsfull.txt`), a single-file compilation of + every published doc page; +- `/docs/
//index.md` (`layouts/docs/single.md`), the standalone + Markdown version of each page, with relative links rewritten to absolute URLs. + +All three share `layouts/_partials/raw-markdown.html` with the per-page +"Copy as Markdown" button. + ## Glossary hover cards On doc pages, the first mention of each glossary term gets a hover card with diff --git a/site/hugo.yaml b/site/hugo.yaml index 9e7381b02b..a6c15b87f9 100644 --- a/site/hugo.yaml +++ b/site/hugo.yaml @@ -87,6 +87,7 @@ outputFormats: outputs: home: [HTML, LLMS, LLMSFULL] section: [HTML] + page: [HTML, MARKDOWN] params: github_repo: "https://github.com/agent-substrate/substrate" diff --git a/site/layouts/404.html b/site/layouts/404.html index d2934786dc..377b164d9d 100644 --- a/site/layouts/404.html +++ b/site/layouts/404.html @@ -52,7 +52,7 @@