feat(executor): print server-side token permissions (#26)
- commit
- 9c50523b2cfc843e1f78eb02c98252b727b0ccaf
- author
- brice · · 2026-10-14 23:30 UTC
- committer
- bnema · · 2026-10-14 23:30 UTC
- parent
- c936897
- signature
- SSH Unverified
SHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivAThe key is unknown
9 files · +414 -103
M internal/execstream/exec.proto +12 -0
| @@ -107,6 +107,18 @@ message JobSpec { | |||
| 107 | 107 | // secrets are not available. Never set for servers without the feature, for | |
| 108 | 108 | // which an absent Job.trusted only means "not sent". | |
| 109 | 109 | bool secrets_withheld = 19; | |
| 110 | + | // token_permissions are the effective permissions of the job's GITHUB_TOKEN | |
| 111 | + | // as the server sent them (Job.permissions, feature ci.secrets): "Set up job" | |
| 112 | + | // prints them instead of working them out from the workflow. Unset when the | |
| 113 | + | // server sent none (an older server): the executor then reads them from the | |
| 114 | + | // workflow. | |
| 115 | + | TokenPermissions token_permissions = 20; | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // TokenPermissions maps a permission key ("contents", "pull-requests", ...) to | |
| 119 | + | // "read", "write" or "none"; a key that is absent is none. | |
| 120 | + | message TokenPermissions { | |
| 121 | + | map<string, string> levels = 1; | |
| 110 | 122 | } | |
| 111 | 123 | ||
| 112 | 124 | enum StreamKind { | |
| @@ -107,6 +107,18 @@ message JobSpec { | |||||
| 107 | // secrets are not available. Never set for servers without the feature, for | 107 | // secrets are not available. Never set for servers without the feature, for | ||
| 108 | // which an absent Job.trusted only means "not sent". | 108 | // which an absent Job.trusted only means "not sent". | ||
| 109 | bool secrets_withheld = 19; | 109 | bool secrets_withheld = 19; | ||
| 110 | + | // token_permissions are the effective permissions of the job's GITHUB_TOKEN | |||
| 111 | + | // as the server sent them (Job.permissions, feature ci.secrets): "Set up job" | |||
| 112 | + | // prints them instead of working them out from the workflow. Unset when the | |||
| 113 | + | // server sent none (an older server): the executor then reads them from the | |||
| 114 | + | // workflow. | |||
| 115 | + | TokenPermissions token_permissions = 20; | |||
| 116 | + | } | |||
| 117 | + | ||||
| 118 | + | // TokenPermissions maps a permission key ("contents", "pull-requests", ...) to | |||
| 119 | + | // "read", "write" or "none"; a key that is absent is none. | |||
| 120 | + | message TokenPermissions { | |||
| 121 | + | map<string, string> levels = 1; | |||
| 110 | } | 122 | } | ||
| 111 | 123 | ||||
| 112 | enum StreamKind { | 124 | enum StreamKind { | ||
M internal/execstream/execpb/exec.pb.go +164 -95
| @@ -756,8 +756,14 @@ type JobSpec struct { | |||
| 756 | 756 | // secrets are not available. Never set for servers without the feature, for | |
| 757 | 757 | // which an absent Job.trusted only means "not sent". | |
| 758 | 758 | SecretsWithheld bool `protobuf:"varint,19,opt,name=secrets_withheld,json=secretsWithheld,proto3" json:"secrets_withheld,omitempty"` | |
| 759 | - | unknownFields protoimpl.UnknownFields | |
| 760 | - | sizeCache protoimpl.SizeCache | |
| 759 | + | // token_permissions are the effective permissions of the job's GITHUB_TOKEN | |
| 760 | + | // as the server sent them (Job.permissions, feature ci.secrets): "Set up job" | |
| 761 | + | // prints them instead of working them out from the workflow. Unset when the | |
| 762 | + | // server sent none (an older server): the executor then reads them from the | |
| 763 | + | // workflow. | |
| 764 | + | TokenPermissions *TokenPermissions `protobuf:"bytes,20,opt,name=token_permissions,json=tokenPermissions,proto3" json:"token_permissions,omitempty"` | |
| 765 | + | unknownFields protoimpl.UnknownFields | |
| 766 | + | sizeCache protoimpl.SizeCache | |
| 761 | 767 | } | |
| 762 | 768 | ||
| 763 | 769 | func (x *JobSpec) Reset() { | |
| @@ -909,6 +915,59 @@ func (x *JobSpec) GetSecretsWithheld() bool { | |||
| 909 | 915 | return false | |
| 910 | 916 | } | |
| 911 | 917 | ||
| 918 | + | func (x *JobSpec) GetTokenPermissions() *TokenPermissions { | |
| 919 | + | if x != nil { | |
| 920 | + | return x.TokenPermissions | |
| 921 | + | } | |
| 922 | + | return nil | |
| 923 | + | } | |
| 924 | + | ||
| 925 | + | // TokenPermissions maps a permission key ("contents", "pull-requests", ...) to | |
| 926 | + | // "read", "write" or "none"; a key that is absent is none. | |
| 927 | + | type TokenPermissions struct { | |
| 928 | + | state protoimpl.MessageState `protogen:"open.v1"` | |
| 929 | + | Levels map[string]string `protobuf:"bytes,1,rep,name=levels,proto3" json:"levels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` | |
| 930 | + | unknownFields protoimpl.UnknownFields | |
| 931 | + | sizeCache protoimpl.SizeCache | |
| 932 | + | } | |
| 933 | + | ||
| 934 | + | func (x *TokenPermissions) Reset() { | |
| 935 | + | *x = TokenPermissions{} | |
| 936 | + | mi := &file_exec_proto_msgTypes[5] | |
| 937 | + | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 938 | + | ms.StoreMessageInfo(mi) | |
| 939 | + | } | |
| 940 | + | ||
| 941 | + | func (x *TokenPermissions) String() string { | |
| 942 | + | return protoimpl.X.MessageStringOf(x) | |
| 943 | + | } | |
| 944 | + | ||
| 945 | + | func (*TokenPermissions) ProtoMessage() {} | |
| 946 | + | ||
| 947 | + | func (x *TokenPermissions) ProtoReflect() protoreflect.Message { | |
| 948 | + | mi := &file_exec_proto_msgTypes[5] | |
| 949 | + | if x != nil { | |
| 950 | + | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 951 | + | if ms.LoadMessageInfo() == nil { | |
| 952 | + | ms.StoreMessageInfo(mi) | |
| 953 | + | } | |
| 954 | + | return ms | |
| 955 | + | } | |
| 956 | + | return mi.MessageOf(x) | |
| 957 | + | } | |
| 958 | + | ||
| 959 | + | // Deprecated: Use TokenPermissions.ProtoReflect.Descriptor instead. | |
| 960 | + | func (*TokenPermissions) Descriptor() ([]byte, []int) { | |
| 961 | + | return file_exec_proto_rawDescGZIP(), []int{5} | |
| 962 | + | } | |
| 963 | + | ||
| 964 | + | func (x *TokenPermissions) GetLevels() map[string]string { | |
| 965 | + | if x != nil { | |
| 966 | + | return x.Levels | |
| 967 | + | } | |
| 968 | + | return nil | |
| 969 | + | } | |
| 970 | + | ||
| 912 | 971 | type Output struct { | |
| 913 | 972 | state protoimpl.MessageState `protogen:"open.v1"` | |
| 914 | 973 | Stream StreamKind `protobuf:"varint,1,opt,name=stream,proto3,enum=ermite.runner.exec.v1.StreamKind" json:"stream,omitempty"` | |
| @@ -920,7 +979,7 @@ type Output struct { | |||
| 920 | 979 | ||
| 921 | 980 | func (x *Output) Reset() { | |
| 922 | 981 | *x = Output{} | |
| 923 | - | mi := &file_exec_proto_msgTypes[5] | |
| 982 | + | mi := &file_exec_proto_msgTypes[6] | |
| 924 | 983 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 925 | 984 | ms.StoreMessageInfo(mi) | |
| 926 | 985 | } | |
| @@ -932,7 +991,7 @@ func (x *Output) String() string { | |||
| 932 | 991 | func (*Output) ProtoMessage() {} | |
| 933 | 992 | ||
| 934 | 993 | func (x *Output) ProtoReflect() protoreflect.Message { | |
| 935 | - | mi := &file_exec_proto_msgTypes[5] | |
| 994 | + | mi := &file_exec_proto_msgTypes[6] | |
| 936 | 995 | if x != nil { | |
| 937 | 996 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 938 | 997 | if ms.LoadMessageInfo() == nil { | |
| @@ -945,7 +1004,7 @@ func (x *Output) ProtoReflect() protoreflect.Message { | |||
| 945 | 1004 | ||
| 946 | 1005 | // Deprecated: Use Output.ProtoReflect.Descriptor instead. | |
| 947 | 1006 | func (*Output) Descriptor() ([]byte, []int) { | |
| 948 | - | return file_exec_proto_rawDescGZIP(), []int{5} | |
| 1007 | + | return file_exec_proto_rawDescGZIP(), []int{6} | |
| 949 | 1008 | } | |
| 950 | 1009 | ||
| 951 | 1010 | func (x *Output) GetStream() StreamKind { | |
| @@ -979,7 +1038,7 @@ type Exit struct { | |||
| 979 | 1038 | ||
| 980 | 1039 | func (x *Exit) Reset() { | |
| 981 | 1040 | *x = Exit{} | |
| 982 | - | mi := &file_exec_proto_msgTypes[6] | |
| 1041 | + | mi := &file_exec_proto_msgTypes[7] | |
| 983 | 1042 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 984 | 1043 | ms.StoreMessageInfo(mi) | |
| 985 | 1044 | } | |
| @@ -991,7 +1050,7 @@ func (x *Exit) String() string { | |||
| 991 | 1050 | func (*Exit) ProtoMessage() {} | |
| 992 | 1051 | ||
| 993 | 1052 | func (x *Exit) ProtoReflect() protoreflect.Message { | |
| 994 | - | mi := &file_exec_proto_msgTypes[6] | |
| 1053 | + | mi := &file_exec_proto_msgTypes[7] | |
| 995 | 1054 | if x != nil { | |
| 996 | 1055 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 997 | 1056 | if ms.LoadMessageInfo() == nil { | |
| @@ -1004,7 +1063,7 @@ func (x *Exit) ProtoReflect() protoreflect.Message { | |||
| 1004 | 1063 | ||
| 1005 | 1064 | // Deprecated: Use Exit.ProtoReflect.Descriptor instead. | |
| 1006 | 1065 | func (*Exit) Descriptor() ([]byte, []int) { | |
| 1007 | - | return file_exec_proto_rawDescGZIP(), []int{6} | |
| 1066 | + | return file_exec_proto_rawDescGZIP(), []int{7} | |
| 1008 | 1067 | } | |
| 1009 | 1068 | ||
| 1010 | 1069 | func (x *Exit) GetCode() int32 { | |
| @@ -1038,7 +1097,7 @@ type Cancel struct { | |||
| 1038 | 1097 | ||
| 1039 | 1098 | func (x *Cancel) Reset() { | |
| 1040 | 1099 | *x = Cancel{} | |
| 1041 | - | mi := &file_exec_proto_msgTypes[7] | |
| 1100 | + | mi := &file_exec_proto_msgTypes[8] | |
| 1042 | 1101 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1043 | 1102 | ms.StoreMessageInfo(mi) | |
| 1044 | 1103 | } | |
| @@ -1050,7 +1109,7 @@ func (x *Cancel) String() string { | |||
| 1050 | 1109 | func (*Cancel) ProtoMessage() {} | |
| 1051 | 1110 | ||
| 1052 | 1111 | func (x *Cancel) ProtoReflect() protoreflect.Message { | |
| 1053 | - | mi := &file_exec_proto_msgTypes[7] | |
| 1112 | + | mi := &file_exec_proto_msgTypes[8] | |
| 1054 | 1113 | if x != nil { | |
| 1055 | 1114 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1056 | 1115 | if ms.LoadMessageInfo() == nil { | |
| @@ -1063,7 +1122,7 @@ func (x *Cancel) ProtoReflect() protoreflect.Message { | |||
| 1063 | 1122 | ||
| 1064 | 1123 | // Deprecated: Use Cancel.ProtoReflect.Descriptor instead. | |
| 1065 | 1124 | func (*Cancel) Descriptor() ([]byte, []int) { | |
| 1066 | - | return file_exec_proto_rawDescGZIP(), []int{7} | |
| 1125 | + | return file_exec_proto_rawDescGZIP(), []int{8} | |
| 1067 | 1126 | } | |
| 1068 | 1127 | ||
| 1069 | 1128 | func (x *Cancel) GetReason() string { | |
| @@ -1093,7 +1152,7 @@ type StepStarted struct { | |||
| 1093 | 1152 | ||
| 1094 | 1153 | func (x *StepStarted) Reset() { | |
| 1095 | 1154 | *x = StepStarted{} | |
| 1096 | - | mi := &file_exec_proto_msgTypes[8] | |
| 1155 | + | mi := &file_exec_proto_msgTypes[9] | |
| 1097 | 1156 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1098 | 1157 | ms.StoreMessageInfo(mi) | |
| 1099 | 1158 | } | |
| @@ -1105,7 +1164,7 @@ func (x *StepStarted) String() string { | |||
| 1105 | 1164 | func (*StepStarted) ProtoMessage() {} | |
| 1106 | 1165 | ||
| 1107 | 1166 | func (x *StepStarted) ProtoReflect() protoreflect.Message { | |
| 1108 | - | mi := &file_exec_proto_msgTypes[8] | |
| 1167 | + | mi := &file_exec_proto_msgTypes[9] | |
| 1109 | 1168 | if x != nil { | |
| 1110 | 1169 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1111 | 1170 | if ms.LoadMessageInfo() == nil { | |
| @@ -1118,7 +1177,7 @@ func (x *StepStarted) ProtoReflect() protoreflect.Message { | |||
| 1118 | 1177 | ||
| 1119 | 1178 | // Deprecated: Use StepStarted.ProtoReflect.Descriptor instead. | |
| 1120 | 1179 | func (*StepStarted) Descriptor() ([]byte, []int) { | |
| 1121 | - | return file_exec_proto_rawDescGZIP(), []int{8} | |
| 1180 | + | return file_exec_proto_rawDescGZIP(), []int{9} | |
| 1122 | 1181 | } | |
| 1123 | 1182 | ||
| 1124 | 1183 | func (x *StepStarted) GetNumber() int32 { | |
| @@ -1158,7 +1217,7 @@ type StepCompleted struct { | |||
| 1158 | 1217 | ||
| 1159 | 1218 | func (x *StepCompleted) Reset() { | |
| 1160 | 1219 | *x = StepCompleted{} | |
| 1161 | - | mi := &file_exec_proto_msgTypes[9] | |
| 1220 | + | mi := &file_exec_proto_msgTypes[10] | |
| 1162 | 1221 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1163 | 1222 | ms.StoreMessageInfo(mi) | |
| 1164 | 1223 | } | |
| @@ -1170,7 +1229,7 @@ func (x *StepCompleted) String() string { | |||
| 1170 | 1229 | func (*StepCompleted) ProtoMessage() {} | |
| 1171 | 1230 | ||
| 1172 | 1231 | func (x *StepCompleted) ProtoReflect() protoreflect.Message { | |
| 1173 | - | mi := &file_exec_proto_msgTypes[9] | |
| 1232 | + | mi := &file_exec_proto_msgTypes[10] | |
| 1174 | 1233 | if x != nil { | |
| 1175 | 1234 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1176 | 1235 | if ms.LoadMessageInfo() == nil { | |
| @@ -1183,7 +1242,7 @@ func (x *StepCompleted) ProtoReflect() protoreflect.Message { | |||
| 1183 | 1242 | ||
| 1184 | 1243 | // Deprecated: Use StepCompleted.ProtoReflect.Descriptor instead. | |
| 1185 | 1244 | func (*StepCompleted) Descriptor() ([]byte, []int) { | |
| 1186 | - | return file_exec_proto_rawDescGZIP(), []int{9} | |
| 1245 | + | return file_exec_proto_rawDescGZIP(), []int{10} | |
| 1187 | 1246 | } | |
| 1188 | 1247 | ||
| 1189 | 1248 | func (x *StepCompleted) GetNumber() int32 { | |
| @@ -1239,7 +1298,7 @@ type Annotation struct { | |||
| 1239 | 1298 | ||
| 1240 | 1299 | func (x *Annotation) Reset() { | |
| 1241 | 1300 | *x = Annotation{} | |
| 1242 | - | mi := &file_exec_proto_msgTypes[10] | |
| 1301 | + | mi := &file_exec_proto_msgTypes[11] | |
| 1243 | 1302 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1244 | 1303 | ms.StoreMessageInfo(mi) | |
| 1245 | 1304 | } | |
| @@ -1251,7 +1310,7 @@ func (x *Annotation) String() string { | |||
| 1251 | 1310 | func (*Annotation) ProtoMessage() {} | |
| 1252 | 1311 | ||
| 1253 | 1312 | func (x *Annotation) ProtoReflect() protoreflect.Message { | |
| 1254 | - | mi := &file_exec_proto_msgTypes[10] | |
| 1313 | + | mi := &file_exec_proto_msgTypes[11] | |
| 1255 | 1314 | if x != nil { | |
| 1256 | 1315 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1257 | 1316 | if ms.LoadMessageInfo() == nil { | |
| @@ -1264,7 +1323,7 @@ func (x *Annotation) ProtoReflect() protoreflect.Message { | |||
| 1264 | 1323 | ||
| 1265 | 1324 | // Deprecated: Use Annotation.ProtoReflect.Descriptor instead. | |
| 1266 | 1325 | func (*Annotation) Descriptor() ([]byte, []int) { | |
| 1267 | - | return file_exec_proto_rawDescGZIP(), []int{10} | |
| 1326 | + | return file_exec_proto_rawDescGZIP(), []int{11} | |
| 1268 | 1327 | } | |
| 1269 | 1328 | ||
| 1270 | 1329 | func (x *Annotation) GetLevel() AnnotationLevel { | |
| @@ -1337,7 +1396,7 @@ type StepAnnotations struct { | |||
| 1337 | 1396 | ||
| 1338 | 1397 | func (x *StepAnnotations) Reset() { | |
| 1339 | 1398 | *x = StepAnnotations{} | |
| 1340 | - | mi := &file_exec_proto_msgTypes[11] | |
| 1399 | + | mi := &file_exec_proto_msgTypes[12] | |
| 1341 | 1400 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1342 | 1401 | ms.StoreMessageInfo(mi) | |
| 1343 | 1402 | } | |
| @@ -1349,7 +1408,7 @@ func (x *StepAnnotations) String() string { | |||
| 1349 | 1408 | func (*StepAnnotations) ProtoMessage() {} | |
| 1350 | 1409 | ||
| 1351 | 1410 | func (x *StepAnnotations) ProtoReflect() protoreflect.Message { | |
| 1352 | - | mi := &file_exec_proto_msgTypes[11] | |
| 1411 | + | mi := &file_exec_proto_msgTypes[12] | |
| 1353 | 1412 | if x != nil { | |
| 1354 | 1413 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1355 | 1414 | if ms.LoadMessageInfo() == nil { | |
| @@ -1362,7 +1421,7 @@ func (x *StepAnnotations) ProtoReflect() protoreflect.Message { | |||
| 1362 | 1421 | ||
| 1363 | 1422 | // Deprecated: Use StepAnnotations.ProtoReflect.Descriptor instead. | |
| 1364 | 1423 | func (*StepAnnotations) Descriptor() ([]byte, []int) { | |
| 1365 | - | return file_exec_proto_rawDescGZIP(), []int{11} | |
| 1424 | + | return file_exec_proto_rawDescGZIP(), []int{12} | |
| 1366 | 1425 | } | |
| 1367 | 1426 | ||
| 1368 | 1427 | func (x *StepAnnotations) GetStep() int32 { | |
| @@ -1391,7 +1450,7 @@ type StepSummary struct { | |||
| 1391 | 1450 | ||
| 1392 | 1451 | func (x *StepSummary) Reset() { | |
| 1393 | 1452 | *x = StepSummary{} | |
| 1394 | - | mi := &file_exec_proto_msgTypes[12] | |
| 1453 | + | mi := &file_exec_proto_msgTypes[13] | |
| 1395 | 1454 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1396 | 1455 | ms.StoreMessageInfo(mi) | |
| 1397 | 1456 | } | |
| @@ -1403,7 +1462,7 @@ func (x *StepSummary) String() string { | |||
| 1403 | 1462 | func (*StepSummary) ProtoMessage() {} | |
| 1404 | 1463 | ||
| 1405 | 1464 | func (x *StepSummary) ProtoReflect() protoreflect.Message { | |
| 1406 | - | mi := &file_exec_proto_msgTypes[12] | |
| 1465 | + | mi := &file_exec_proto_msgTypes[13] | |
| 1407 | 1466 | if x != nil { | |
| 1408 | 1467 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1409 | 1468 | if ms.LoadMessageInfo() == nil { | |
| @@ -1416,7 +1475,7 @@ func (x *StepSummary) ProtoReflect() protoreflect.Message { | |||
| 1416 | 1475 | ||
| 1417 | 1476 | // Deprecated: Use StepSummary.ProtoReflect.Descriptor instead. | |
| 1418 | 1477 | func (*StepSummary) Descriptor() ([]byte, []int) { | |
| 1419 | - | return file_exec_proto_rawDescGZIP(), []int{12} | |
| 1478 | + | return file_exec_proto_rawDescGZIP(), []int{13} | |
| 1420 | 1479 | } | |
| 1421 | 1480 | ||
| 1422 | 1481 | func (x *StepSummary) GetStep() int32 { | |
| @@ -1448,7 +1507,7 @@ type Log struct { | |||
| 1448 | 1507 | ||
| 1449 | 1508 | func (x *Log) Reset() { | |
| 1450 | 1509 | *x = Log{} | |
| 1451 | - | mi := &file_exec_proto_msgTypes[13] | |
| 1510 | + | mi := &file_exec_proto_msgTypes[14] | |
| 1452 | 1511 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1453 | 1512 | ms.StoreMessageInfo(mi) | |
| 1454 | 1513 | } | |
| @@ -1460,7 +1519,7 @@ func (x *Log) String() string { | |||
| 1460 | 1519 | func (*Log) ProtoMessage() {} | |
| 1461 | 1520 | ||
| 1462 | 1521 | func (x *Log) ProtoReflect() protoreflect.Message { | |
| 1463 | - | mi := &file_exec_proto_msgTypes[13] | |
| 1522 | + | mi := &file_exec_proto_msgTypes[14] | |
| 1464 | 1523 | if x != nil { | |
| 1465 | 1524 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1466 | 1525 | if ms.LoadMessageInfo() == nil { | |
| @@ -1473,7 +1532,7 @@ func (x *Log) ProtoReflect() protoreflect.Message { | |||
| 1473 | 1532 | ||
| 1474 | 1533 | // Deprecated: Use Log.ProtoReflect.Descriptor instead. | |
| 1475 | 1534 | func (*Log) Descriptor() ([]byte, []int) { | |
| 1476 | - | return file_exec_proto_rawDescGZIP(), []int{13} | |
| 1535 | + | return file_exec_proto_rawDescGZIP(), []int{14} | |
| 1477 | 1536 | } | |
| 1478 | 1537 | ||
| 1479 | 1538 | func (x *Log) GetStep() int32 { | |
| @@ -1517,7 +1576,7 @@ type JobResult struct { | |||
| 1517 | 1576 | ||
| 1518 | 1577 | func (x *JobResult) Reset() { | |
| 1519 | 1578 | *x = JobResult{} | |
| 1520 | - | mi := &file_exec_proto_msgTypes[14] | |
| 1579 | + | mi := &file_exec_proto_msgTypes[15] | |
| 1521 | 1580 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1522 | 1581 | ms.StoreMessageInfo(mi) | |
| 1523 | 1582 | } | |
| @@ -1529,7 +1588,7 @@ func (x *JobResult) String() string { | |||
| 1529 | 1588 | func (*JobResult) ProtoMessage() {} | |
| 1530 | 1589 | ||
| 1531 | 1590 | func (x *JobResult) ProtoReflect() protoreflect.Message { | |
| 1532 | - | mi := &file_exec_proto_msgTypes[14] | |
| 1591 | + | mi := &file_exec_proto_msgTypes[15] | |
| 1533 | 1592 | if x != nil { | |
| 1534 | 1593 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1535 | 1594 | if ms.LoadMessageInfo() == nil { | |
| @@ -1542,7 +1601,7 @@ func (x *JobResult) ProtoReflect() protoreflect.Message { | |||
| 1542 | 1601 | ||
| 1543 | 1602 | // Deprecated: Use JobResult.ProtoReflect.Descriptor instead. | |
| 1544 | 1603 | func (*JobResult) Descriptor() ([]byte, []int) { | |
| 1545 | - | return file_exec_proto_rawDescGZIP(), []int{14} | |
| 1604 | + | return file_exec_proto_rawDescGZIP(), []int{15} | |
| 1546 | 1605 | } | |
| 1547 | 1606 | ||
| 1548 | 1607 | func (x *JobResult) GetConclusion() StepConclusion { | |
| @@ -1587,7 +1646,7 @@ type ResolveRequest struct { | |||
| 1587 | 1646 | ||
| 1588 | 1647 | func (x *ResolveRequest) Reset() { | |
| 1589 | 1648 | *x = ResolveRequest{} | |
| 1590 | - | mi := &file_exec_proto_msgTypes[15] | |
| 1649 | + | mi := &file_exec_proto_msgTypes[16] | |
| 1591 | 1650 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1592 | 1651 | ms.StoreMessageInfo(mi) | |
| 1593 | 1652 | } | |
| @@ -1599,7 +1658,7 @@ func (x *ResolveRequest) String() string { | |||
| 1599 | 1658 | func (*ResolveRequest) ProtoMessage() {} | |
| 1600 | 1659 | ||
| 1601 | 1660 | func (x *ResolveRequest) ProtoReflect() protoreflect.Message { | |
| 1602 | - | mi := &file_exec_proto_msgTypes[15] | |
| 1661 | + | mi := &file_exec_proto_msgTypes[16] | |
| 1603 | 1662 | if x != nil { | |
| 1604 | 1663 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1605 | 1664 | if ms.LoadMessageInfo() == nil { | |
| @@ -1612,7 +1671,7 @@ func (x *ResolveRequest) ProtoReflect() protoreflect.Message { | |||
| 1612 | 1671 | ||
| 1613 | 1672 | // Deprecated: Use ResolveRequest.ProtoReflect.Descriptor instead. | |
| 1614 | 1673 | func (*ResolveRequest) Descriptor() ([]byte, []int) { | |
| 1615 | - | return file_exec_proto_rawDescGZIP(), []int{15} | |
| 1674 | + | return file_exec_proto_rawDescGZIP(), []int{16} | |
| 1616 | 1675 | } | |
| 1617 | 1676 | ||
| 1618 | 1677 | func (x *ResolveRequest) GetId() int64 { | |
| @@ -1642,7 +1701,7 @@ type ResolveResponse struct { | |||
| 1642 | 1701 | ||
| 1643 | 1702 | func (x *ResolveResponse) Reset() { | |
| 1644 | 1703 | *x = ResolveResponse{} | |
| 1645 | - | mi := &file_exec_proto_msgTypes[16] | |
| 1704 | + | mi := &file_exec_proto_msgTypes[17] | |
| 1646 | 1705 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1647 | 1706 | ms.StoreMessageInfo(mi) | |
| 1648 | 1707 | } | |
| @@ -1654,7 +1713,7 @@ func (x *ResolveResponse) String() string { | |||
| 1654 | 1713 | func (*ResolveResponse) ProtoMessage() {} | |
| 1655 | 1714 | ||
| 1656 | 1715 | func (x *ResolveResponse) ProtoReflect() protoreflect.Message { | |
| 1657 | - | mi := &file_exec_proto_msgTypes[16] | |
| 1716 | + | mi := &file_exec_proto_msgTypes[17] | |
| 1658 | 1717 | if x != nil { | |
| 1659 | 1718 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1660 | 1719 | if ms.LoadMessageInfo() == nil { | |
| @@ -1667,7 +1726,7 @@ func (x *ResolveResponse) ProtoReflect() protoreflect.Message { | |||
| 1667 | 1726 | ||
| 1668 | 1727 | // Deprecated: Use ResolveResponse.ProtoReflect.Descriptor instead. | |
| 1669 | 1728 | func (*ResolveResponse) Descriptor() ([]byte, []int) { | |
| 1670 | - | return file_exec_proto_rawDescGZIP(), []int{16} | |
| 1729 | + | return file_exec_proto_rawDescGZIP(), []int{17} | |
| 1671 | 1730 | } | |
| 1672 | 1731 | ||
| 1673 | 1732 | func (x *ResolveResponse) GetId() int64 { | |
| @@ -1714,7 +1773,7 @@ type ResolvedAction struct { | |||
| 1714 | 1773 | ||
| 1715 | 1774 | func (x *ResolvedAction) Reset() { | |
| 1716 | 1775 | *x = ResolvedAction{} | |
| 1717 | - | mi := &file_exec_proto_msgTypes[17] | |
| 1776 | + | mi := &file_exec_proto_msgTypes[18] | |
| 1718 | 1777 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1719 | 1778 | ms.StoreMessageInfo(mi) | |
| 1720 | 1779 | } | |
| @@ -1726,7 +1785,7 @@ func (x *ResolvedAction) String() string { | |||
| 1726 | 1785 | func (*ResolvedAction) ProtoMessage() {} | |
| 1727 | 1786 | ||
| 1728 | 1787 | func (x *ResolvedAction) ProtoReflect() protoreflect.Message { | |
| 1729 | - | mi := &file_exec_proto_msgTypes[17] | |
| 1788 | + | mi := &file_exec_proto_msgTypes[18] | |
| 1730 | 1789 | if x != nil { | |
| 1731 | 1790 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |
| 1732 | 1791 | if ms.LoadMessageInfo() == nil { | |
| @@ -1739,7 +1798,7 @@ func (x *ResolvedAction) ProtoReflect() protoreflect.Message { | |||
| 1739 | 1798 | ||
| 1740 | 1799 | // Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead. | |
| 1741 | 1800 | func (*ResolvedAction) Descriptor() ([]byte, []int) { | |
| 1742 | - | return file_exec_proto_rawDescGZIP(), []int{17} | |
| 1801 | + | return file_exec_proto_rawDescGZIP(), []int{18} | |
| 1743 | 1802 | } | |
| 1744 | 1803 | ||
| 1745 | 1804 | func (x *ResolvedAction) GetRef() string { | |
| @@ -1844,7 +1903,7 @@ const file_exec_proto_rawDesc = "" + | |||
| 1844 | 1903 | "\x03job\x18\x03 \x01(\v2\x1e.ermite.runner.exec.v1.JobSpecR\x03job\x1a6\n" + | |
| 1845 | 1904 | "\bEnvEntry\x12\x10\n" + | |
| 1846 | 1905 | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + | |
| 1847 | - | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xe3\x04\n" + | |
| 1906 | + | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xb9\x05\n" + | |
| 1848 | 1907 | "\aJobSpec\x12#\n" + | |
| 1849 | 1908 | "\rworkflow_path\x18\x01 \x01(\tR\fworkflowPath\x12#\n" + | |
| 1850 | 1909 | "\rworkflow_yaml\x18\x02 \x01(\tR\fworkflowYaml\x12\x17\n" + | |
| @@ -1867,7 +1926,13 @@ const file_exec_proto_rawDesc = "" + | |||
| 1867 | 1926 | "cache_port\x18\x0f \x01(\rR\tcachePort\x12\x1f\n" + | |
| 1868 | 1927 | "\vcache_token\x18\x10 \x01(\tR\n" + | |
| 1869 | 1928 | "cacheToken\x12)\n" + | |
| 1870 | - | "\x10secrets_withheld\x18\x13 \x01(\bR\x0fsecretsWithheldJ\x04\b\x11\x10\x12J\x04\b\x12\x10\x13R\asecretsR\x04vars\"t\n" + | |
| 1929 | + | "\x10secrets_withheld\x18\x13 \x01(\bR\x0fsecretsWithheld\x12T\n" + | |
| 1930 | + | "\x11token_permissions\x18\x14 \x01(\v2'.ermite.runner.exec.v1.TokenPermissionsR\x10tokenPermissionsJ\x04\b\x11\x10\x12J\x04\b\x12\x10\x13R\asecretsR\x04vars\"\x9a\x01\n" + | |
| 1931 | + | "\x10TokenPermissions\x12K\n" + | |
| 1932 | + | "\x06levels\x18\x01 \x03(\v23.ermite.runner.exec.v1.TokenPermissions.LevelsEntryR\x06levels\x1a9\n" + | |
| 1933 | + | "\vLevelsEntry\x12\x10\n" + | |
| 1934 | + | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + | |
| 1935 | + | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"t\n" + | |
| 1871 | 1936 | "\x06Output\x129\n" + | |
| 1872 | 1937 | "\x06stream\x18\x01 \x01(\x0e2!.ermite.runner.exec.v1.StreamKindR\x06stream\x12\x12\n" + | |
| 1873 | 1938 | "\x04data\x18\x02 \x01(\fR\x04data\x12\x1b\n" + | |
| @@ -1979,65 +2044,69 @@ func file_exec_proto_rawDescGZIP() []byte { | |||
| 1979 | 2044 | } | |
| 1980 | 2045 | ||
| 1981 | 2046 | var file_exec_proto_enumTypes = make([]protoimpl.EnumInfo, 4) | |
| 1982 | - | var file_exec_proto_msgTypes = make([]protoimpl.MessageInfo, 20) | |
| 2047 | + | var file_exec_proto_msgTypes = make([]protoimpl.MessageInfo, 22) | |
| 1983 | 2048 | var file_exec_proto_goTypes = []any{ | |
| 1984 | - | (StreamKind)(0), // 0: ermite.runner.exec.v1.StreamKind | |
| 1985 | - | (CancelKind)(0), // 1: ermite.runner.exec.v1.CancelKind | |
| 1986 | - | (AnnotationLevel)(0), // 2: ermite.runner.exec.v1.AnnotationLevel | |
| 1987 | - | (StepConclusion)(0), // 3: ermite.runner.exec.v1.StepConclusion | |
| 1988 | - | (*Frame)(nil), // 4: ermite.runner.exec.v1.Frame | |
| 1989 | - | (*NamedValue)(nil), // 5: ermite.runner.exec.v1.NamedValue | |
| 1990 | - | (*Hello)(nil), // 6: ermite.runner.exec.v1.Hello | |
| 1991 | - | (*Run)(nil), // 7: ermite.runner.exec.v1.Run | |
| 1992 | - | (*JobSpec)(nil), // 8: ermite.runner.exec.v1.JobSpec | |
| 1993 | - | (*Output)(nil), // 9: ermite.runner.exec.v1.Output | |
| 1994 | - | (*Exit)(nil), // 10: ermite.runner.exec.v1.Exit | |
| 1995 | - | (*Cancel)(nil), // 11: ermite.runner.exec.v1.Cancel | |
| 1996 | - | (*StepStarted)(nil), // 12: ermite.runner.exec.v1.StepStarted | |
| 1997 | - | (*StepCompleted)(nil), // 13: ermite.runner.exec.v1.StepCompleted | |
| 1998 | - | (*Annotation)(nil), // 14: ermite.runner.exec.v1.Annotation | |
| 1999 | - | (*StepAnnotations)(nil), // 15: ermite.runner.exec.v1.StepAnnotations | |
| 2000 | - | (*StepSummary)(nil), // 16: ermite.runner.exec.v1.StepSummary | |
| 2001 | - | (*Log)(nil), // 17: ermite.runner.exec.v1.Log | |
| 2002 | - | (*JobResult)(nil), // 18: ermite.runner.exec.v1.JobResult | |
| 2003 | - | (*ResolveRequest)(nil), // 19: ermite.runner.exec.v1.ResolveRequest | |
| 2004 | - | (*ResolveResponse)(nil), // 20: ermite.runner.exec.v1.ResolveResponse | |
| 2005 | - | (*ResolvedAction)(nil), // 21: ermite.runner.exec.v1.ResolvedAction | |
| 2006 | - | nil, // 22: ermite.runner.exec.v1.Run.EnvEntry | |
| 2007 | - | nil, // 23: ermite.runner.exec.v1.JobResult.OutputsEntry | |
| 2049 | + | (StreamKind)(0), // 0: ermite.runner.exec.v1.StreamKind | |
| 2050 | + | (CancelKind)(0), // 1: ermite.runner.exec.v1.CancelKind | |
| 2051 | + | (AnnotationLevel)(0), // 2: ermite.runner.exec.v1.AnnotationLevel | |
| 2052 | + | (StepConclusion)(0), // 3: ermite.runner.exec.v1.StepConclusion | |
| 2053 | + | (*Frame)(nil), // 4: ermite.runner.exec.v1.Frame | |
| 2054 | + | (*NamedValue)(nil), // 5: ermite.runner.exec.v1.NamedValue | |
| 2055 | + | (*Hello)(nil), // 6: ermite.runner.exec.v1.Hello | |
| 2056 | + | (*Run)(nil), // 7: ermite.runner.exec.v1.Run | |
| 2057 | + | (*JobSpec)(nil), // 8: ermite.runner.exec.v1.JobSpec | |
| 2058 | + | (*TokenPermissions)(nil), // 9: ermite.runner.exec.v1.TokenPermissions | |
| 2059 | + | (*Output)(nil), // 10: ermite.runner.exec.v1.Output | |
| 2060 | + | (*Exit)(nil), // 11: ermite.runner.exec.v1.Exit | |
| 2061 | + | (*Cancel)(nil), // 12: ermite.runner.exec.v1.Cancel | |
| 2062 | + | (*StepStarted)(nil), // 13: ermite.runner.exec.v1.StepStarted | |
| 2063 | + | (*StepCompleted)(nil), // 14: ermite.runner.exec.v1.StepCompleted | |
| 2064 | + | (*Annotation)(nil), // 15: ermite.runner.exec.v1.Annotation | |
| 2065 | + | (*StepAnnotations)(nil), // 16: ermite.runner.exec.v1.StepAnnotations | |
| 2066 | + | (*StepSummary)(nil), // 17: ermite.runner.exec.v1.StepSummary | |
| 2067 | + | (*Log)(nil), // 18: ermite.runner.exec.v1.Log | |
| 2068 | + | (*JobResult)(nil), // 19: ermite.runner.exec.v1.JobResult | |
| 2069 | + | (*ResolveRequest)(nil), // 20: ermite.runner.exec.v1.ResolveRequest | |
| 2070 | + | (*ResolveResponse)(nil), // 21: ermite.runner.exec.v1.ResolveResponse | |
| 2071 | + | (*ResolvedAction)(nil), // 22: ermite.runner.exec.v1.ResolvedAction | |
| 2072 | + | nil, // 23: ermite.runner.exec.v1.Run.EnvEntry | |
| 2073 | + | nil, // 24: ermite.runner.exec.v1.TokenPermissions.LevelsEntry | |
| 2074 | + | nil, // 25: ermite.runner.exec.v1.JobResult.OutputsEntry | |
| 2008 | 2075 | } | |
| 2009 | 2076 | var file_exec_proto_depIdxs = []int32{ | |
| 2010 | 2077 | 6, // 0: ermite.runner.exec.v1.Frame.hello:type_name -> ermite.runner.exec.v1.Hello | |
| 2011 | 2078 | 7, // 1: ermite.runner.exec.v1.Frame.run:type_name -> ermite.runner.exec.v1.Run | |
| 2012 | - | 9, // 2: ermite.runner.exec.v1.Frame.output:type_name -> ermite.runner.exec.v1.Output | |
| 2013 | - | 10, // 3: ermite.runner.exec.v1.Frame.exit:type_name -> ermite.runner.exec.v1.Exit | |
| 2014 | - | 11, // 4: ermite.runner.exec.v1.Frame.cancel:type_name -> ermite.runner.exec.v1.Cancel | |
| 2015 | - | 12, // 5: ermite.runner.exec.v1.Frame.step_started:type_name -> ermite.runner.exec.v1.StepStarted | |
| 2016 | - | 13, // 6: ermite.runner.exec.v1.Frame.step_completed:type_name -> ermite.runner.exec.v1.StepCompleted | |
| 2017 | - | 17, // 7: ermite.runner.exec.v1.Frame.log:type_name -> ermite.runner.exec.v1.Log | |
| 2018 | - | 18, // 8: ermite.runner.exec.v1.Frame.job_result:type_name -> ermite.runner.exec.v1.JobResult | |
| 2019 | - | 15, // 9: ermite.runner.exec.v1.Frame.step_annotations:type_name -> ermite.runner.exec.v1.StepAnnotations | |
| 2020 | - | 16, // 10: ermite.runner.exec.v1.Frame.step_summary:type_name -> ermite.runner.exec.v1.StepSummary | |
| 2021 | - | 19, // 11: ermite.runner.exec.v1.Frame.resolve_request:type_name -> ermite.runner.exec.v1.ResolveRequest | |
| 2022 | - | 20, // 12: ermite.runner.exec.v1.Frame.resolve_response:type_name -> ermite.runner.exec.v1.ResolveResponse | |
| 2079 | + | 10, // 2: ermite.runner.exec.v1.Frame.output:type_name -> ermite.runner.exec.v1.Output | |
| 2080 | + | 11, // 3: ermite.runner.exec.v1.Frame.exit:type_name -> ermite.runner.exec.v1.Exit | |
| 2081 | + | 12, // 4: ermite.runner.exec.v1.Frame.cancel:type_name -> ermite.runner.exec.v1.Cancel | |
| 2082 | + | 13, // 5: ermite.runner.exec.v1.Frame.step_started:type_name -> ermite.runner.exec.v1.StepStarted | |
| 2083 | + | 14, // 6: ermite.runner.exec.v1.Frame.step_completed:type_name -> ermite.runner.exec.v1.StepCompleted | |
| 2084 | + | 18, // 7: ermite.runner.exec.v1.Frame.log:type_name -> ermite.runner.exec.v1.Log | |
| 2085 | + | 19, // 8: ermite.runner.exec.v1.Frame.job_result:type_name -> ermite.runner.exec.v1.JobResult | |
| 2086 | + | 16, // 9: ermite.runner.exec.v1.Frame.step_annotations:type_name -> ermite.runner.exec.v1.StepAnnotations | |
| 2087 | + | 17, // 10: ermite.runner.exec.v1.Frame.step_summary:type_name -> ermite.runner.exec.v1.StepSummary | |
| 2088 | + | 20, // 11: ermite.runner.exec.v1.Frame.resolve_request:type_name -> ermite.runner.exec.v1.ResolveRequest | |
| 2089 | + | 21, // 12: ermite.runner.exec.v1.Frame.resolve_response:type_name -> ermite.runner.exec.v1.ResolveResponse | |
| 2023 | 2090 | 5, // 13: ermite.runner.exec.v1.Frame.secret:type_name -> ermite.runner.exec.v1.NamedValue | |
| 2024 | 2091 | 5, // 14: ermite.runner.exec.v1.Frame.var:type_name -> ermite.runner.exec.v1.NamedValue | |
| 2025 | - | 22, // 15: ermite.runner.exec.v1.Run.env:type_name -> ermite.runner.exec.v1.Run.EnvEntry | |
| 2092 | + | 23, // 15: ermite.runner.exec.v1.Run.env:type_name -> ermite.runner.exec.v1.Run.EnvEntry | |
| 2026 | 2093 | 8, // 16: ermite.runner.exec.v1.Run.job:type_name -> ermite.runner.exec.v1.JobSpec | |
| 2027 | - | 0, // 17: ermite.runner.exec.v1.Output.stream:type_name -> ermite.runner.exec.v1.StreamKind | |
| 2028 | - | 1, // 18: ermite.runner.exec.v1.Cancel.kind:type_name -> ermite.runner.exec.v1.CancelKind | |
| 2029 | - | 3, // 19: ermite.runner.exec.v1.StepCompleted.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2030 | - | 3, // 20: ermite.runner.exec.v1.StepCompleted.outcome:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2031 | - | 2, // 21: ermite.runner.exec.v1.Annotation.level:type_name -> ermite.runner.exec.v1.AnnotationLevel | |
| 2032 | - | 14, // 22: ermite.runner.exec.v1.StepAnnotations.annotations:type_name -> ermite.runner.exec.v1.Annotation | |
| 2033 | - | 3, // 23: ermite.runner.exec.v1.JobResult.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2034 | - | 23, // 24: ermite.runner.exec.v1.JobResult.outputs:type_name -> ermite.runner.exec.v1.JobResult.OutputsEntry | |
| 2035 | - | 21, // 25: ermite.runner.exec.v1.ResolveResponse.actions:type_name -> ermite.runner.exec.v1.ResolvedAction | |
| 2036 | - | 26, // [26:26] is the sub-list for method output_type | |
| 2037 | - | 26, // [26:26] is the sub-list for method input_type | |
| 2038 | - | 26, // [26:26] is the sub-list for extension type_name | |
| 2039 | - | 26, // [26:26] is the sub-list for extension extendee | |
| 2040 | - | 0, // [0:26] is the sub-list for field type_name | |
| 2094 | + | 9, // 17: ermite.runner.exec.v1.JobSpec.token_permissions:type_name -> ermite.runner.exec.v1.TokenPermissions | |
| 2095 | + | 24, // 18: ermite.runner.exec.v1.TokenPermissions.levels:type_name -> ermite.runner.exec.v1.TokenPermissions.LevelsEntry | |
| 2096 | + | 0, // 19: ermite.runner.exec.v1.Output.stream:type_name -> ermite.runner.exec.v1.StreamKind | |
| 2097 | + | 1, // 20: ermite.runner.exec.v1.Cancel.kind:type_name -> ermite.runner.exec.v1.CancelKind | |
| 2098 | + | 3, // 21: ermite.runner.exec.v1.StepCompleted.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2099 | + | 3, // 22: ermite.runner.exec.v1.StepCompleted.outcome:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2100 | + | 2, // 23: ermite.runner.exec.v1.Annotation.level:type_name -> ermite.runner.exec.v1.AnnotationLevel | |
| 2101 | + | 15, // 24: ermite.runner.exec.v1.StepAnnotations.annotations:type_name -> ermite.runner.exec.v1.Annotation | |
| 2102 | + | 3, // 25: ermite.runner.exec.v1.JobResult.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | |
| 2103 | + | 25, // 26: ermite.runner.exec.v1.JobResult.outputs:type_name -> ermite.runner.exec.v1.JobResult.OutputsEntry | |
| 2104 | + | 22, // 27: ermite.runner.exec.v1.ResolveResponse.actions:type_name -> ermite.runner.exec.v1.ResolvedAction | |
| 2105 | + | 28, // [28:28] is the sub-list for method output_type | |
| 2106 | + | 28, // [28:28] is the sub-list for method input_type | |
| 2107 | + | 28, // [28:28] is the sub-list for extension type_name | |
| 2108 | + | 28, // [28:28] is the sub-list for extension extendee | |
| 2109 | + | 0, // [0:28] is the sub-list for field type_name | |
| 2041 | 2110 | } | |
| 2042 | 2111 | ||
| 2043 | 2112 | func init() { file_exec_proto_init() } | |
| @@ -2068,7 +2137,7 @@ func file_exec_proto_init() { | |||
| 2068 | 2137 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | |
| 2069 | 2138 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_exec_proto_rawDesc), len(file_exec_proto_rawDesc)), | |
| 2070 | 2139 | NumEnums: 4, | |
| 2071 | - | NumMessages: 20, | |
| 2140 | + | NumMessages: 22, | |
| 2072 | 2141 | NumExtensions: 0, | |
| 2073 | 2142 | NumServices: 0, | |
| 2074 | 2143 | }, | |
| @@ -756,8 +756,14 @@ type JobSpec struct { | |||||
| 756 | // secrets are not available. Never set for servers without the feature, for | 756 | // secrets are not available. Never set for servers without the feature, for | ||
| 757 | // which an absent Job.trusted only means "not sent". | 757 | // which an absent Job.trusted only means "not sent". | ||
| 758 | SecretsWithheld bool `protobuf:"varint,19,opt,name=secrets_withheld,json=secretsWithheld,proto3" json:"secrets_withheld,omitempty"` | 758 | SecretsWithheld bool `protobuf:"varint,19,opt,name=secrets_withheld,json=secretsWithheld,proto3" json:"secrets_withheld,omitempty"` | ||
| 759 | - | unknownFields protoimpl.UnknownFields | 759 | + | // token_permissions are the effective permissions of the job's GITHUB_TOKEN |
| 760 | - | sizeCache protoimpl.SizeCache | 760 | + | // as the server sent them (Job.permissions, feature ci.secrets): "Set up job" |
| 761 | + | // prints them instead of working them out from the workflow. Unset when the | |||
| 762 | + | // server sent none (an older server): the executor then reads them from the | |||
| 763 | + | // workflow. | |||
| 764 | + | TokenPermissions *TokenPermissions `protobuf:"bytes,20,opt,name=token_permissions,json=tokenPermissions,proto3" json:"token_permissions,omitempty"` | |||
| 765 | + | unknownFields protoimpl.UnknownFields | |||
| 766 | + | sizeCache protoimpl.SizeCache | |||
| 761 | } | 767 | } | ||
| 762 | 768 | ||||
| 763 | func (x *JobSpec) Reset() { | 769 | func (x *JobSpec) Reset() { | ||
| @@ -909,6 +915,59 @@ func (x *JobSpec) GetSecretsWithheld() bool { | |||||
| 909 | return false | 915 | return false | ||
| 910 | } | 916 | } | ||
| 911 | 917 | ||||
| 918 | + | func (x *JobSpec) GetTokenPermissions() *TokenPermissions { | |||
| 919 | + | if x != nil { | |||
| 920 | + | return x.TokenPermissions | |||
| 921 | + | } | |||
| 922 | + | return nil | |||
| 923 | + | } | |||
| 924 | + | ||||
| 925 | + | // TokenPermissions maps a permission key ("contents", "pull-requests", ...) to | |||
| 926 | + | // "read", "write" or "none"; a key that is absent is none. | |||
| 927 | + | type TokenPermissions struct { | |||
| 928 | + | state protoimpl.MessageState `protogen:"open.v1"` | |||
| 929 | + | Levels map[string]string `protobuf:"bytes,1,rep,name=levels,proto3" json:"levels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` | |||
| 930 | + | unknownFields protoimpl.UnknownFields | |||
| 931 | + | sizeCache protoimpl.SizeCache | |||
| 932 | + | } | |||
| 933 | + | ||||
| 934 | + | func (x *TokenPermissions) Reset() { | |||
| 935 | + | *x = TokenPermissions{} | |||
| 936 | + | mi := &file_exec_proto_msgTypes[5] | |||
| 937 | + | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |||
| 938 | + | ms.StoreMessageInfo(mi) | |||
| 939 | + | } | |||
| 940 | + | ||||
| 941 | + | func (x *TokenPermissions) String() string { | |||
| 942 | + | return protoimpl.X.MessageStringOf(x) | |||
| 943 | + | } | |||
| 944 | + | ||||
| 945 | + | func (*TokenPermissions) ProtoMessage() {} | |||
| 946 | + | ||||
| 947 | + | func (x *TokenPermissions) ProtoReflect() protoreflect.Message { | |||
| 948 | + | mi := &file_exec_proto_msgTypes[5] | |||
| 949 | + | if x != nil { | |||
| 950 | + | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | |||
| 951 | + | if ms.LoadMessageInfo() == nil { | |||
| 952 | + | ms.StoreMessageInfo(mi) | |||
| 953 | + | } | |||
| 954 | + | return ms | |||
| 955 | + | } | |||
| 956 | + | return mi.MessageOf(x) | |||
| 957 | + | } | |||
| 958 | + | ||||
| 959 | + | // Deprecated: Use TokenPermissions.ProtoReflect.Descriptor instead. | |||
| 960 | + | func (*TokenPermissions) Descriptor() ([]byte, []int) { | |||
| 961 | + | return file_exec_proto_rawDescGZIP(), []int{5} | |||
| 962 | + | } | |||
| 963 | + | ||||
| 964 | + | func (x *TokenPermissions) GetLevels() map[string]string { | |||
| 965 | + | if x != nil { | |||
| 966 | + | return x.Levels | |||
| 967 | + | } | |||
| 968 | + | return nil | |||
| 969 | + | } | |||
| 970 | + | ||||
| 912 | type Output struct { | 971 | type Output struct { | ||
| 913 | state protoimpl.MessageState `protogen:"open.v1"` | 972 | state protoimpl.MessageState `protogen:"open.v1"` | ||
| 914 | Stream StreamKind `protobuf:"varint,1,opt,name=stream,proto3,enum=ermite.runner.exec.v1.StreamKind" json:"stream,omitempty"` | 973 | Stream StreamKind `protobuf:"varint,1,opt,name=stream,proto3,enum=ermite.runner.exec.v1.StreamKind" json:"stream,omitempty"` | ||
| @@ -920,7 +979,7 @@ type Output struct { | |||||
| 920 | 979 | ||||
| 921 | func (x *Output) Reset() { | 980 | func (x *Output) Reset() { | ||
| 922 | *x = Output{} | 981 | *x = Output{} | ||
| 923 | - | mi := &file_exec_proto_msgTypes[5] | 982 | + | mi := &file_exec_proto_msgTypes[6] |
| 924 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 983 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 925 | ms.StoreMessageInfo(mi) | 984 | ms.StoreMessageInfo(mi) | ||
| 926 | } | 985 | } | ||
| @@ -932,7 +991,7 @@ func (x *Output) String() string { | |||||
| 932 | func (*Output) ProtoMessage() {} | 991 | func (*Output) ProtoMessage() {} | ||
| 933 | 992 | ||||
| 934 | func (x *Output) ProtoReflect() protoreflect.Message { | 993 | func (x *Output) ProtoReflect() protoreflect.Message { | ||
| 935 | - | mi := &file_exec_proto_msgTypes[5] | 994 | + | mi := &file_exec_proto_msgTypes[6] |
| 936 | if x != nil { | 995 | if x != nil { | ||
| 937 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 996 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 938 | if ms.LoadMessageInfo() == nil { | 997 | if ms.LoadMessageInfo() == nil { | ||
| @@ -945,7 +1004,7 @@ func (x *Output) ProtoReflect() protoreflect.Message { | |||||
| 945 | 1004 | ||||
| 946 | // Deprecated: Use Output.ProtoReflect.Descriptor instead. | 1005 | // Deprecated: Use Output.ProtoReflect.Descriptor instead. | ||
| 947 | func (*Output) Descriptor() ([]byte, []int) { | 1006 | func (*Output) Descriptor() ([]byte, []int) { | ||
| 948 | - | return file_exec_proto_rawDescGZIP(), []int{5} | 1007 | + | return file_exec_proto_rawDescGZIP(), []int{6} |
| 949 | } | 1008 | } | ||
| 950 | 1009 | ||||
| 951 | func (x *Output) GetStream() StreamKind { | 1010 | func (x *Output) GetStream() StreamKind { | ||
| @@ -979,7 +1038,7 @@ type Exit struct { | |||||
| 979 | 1038 | ||||
| 980 | func (x *Exit) Reset() { | 1039 | func (x *Exit) Reset() { | ||
| 981 | *x = Exit{} | 1040 | *x = Exit{} | ||
| 982 | - | mi := &file_exec_proto_msgTypes[6] | 1041 | + | mi := &file_exec_proto_msgTypes[7] |
| 983 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1042 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 984 | ms.StoreMessageInfo(mi) | 1043 | ms.StoreMessageInfo(mi) | ||
| 985 | } | 1044 | } | ||
| @@ -991,7 +1050,7 @@ func (x *Exit) String() string { | |||||
| 991 | func (*Exit) ProtoMessage() {} | 1050 | func (*Exit) ProtoMessage() {} | ||
| 992 | 1051 | ||||
| 993 | func (x *Exit) ProtoReflect() protoreflect.Message { | 1052 | func (x *Exit) ProtoReflect() protoreflect.Message { | ||
| 994 | - | mi := &file_exec_proto_msgTypes[6] | 1053 | + | mi := &file_exec_proto_msgTypes[7] |
| 995 | if x != nil { | 1054 | if x != nil { | ||
| 996 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1055 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 997 | if ms.LoadMessageInfo() == nil { | 1056 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1004,7 +1063,7 @@ func (x *Exit) ProtoReflect() protoreflect.Message { | |||||
| 1004 | 1063 | ||||
| 1005 | // Deprecated: Use Exit.ProtoReflect.Descriptor instead. | 1064 | // Deprecated: Use Exit.ProtoReflect.Descriptor instead. | ||
| 1006 | func (*Exit) Descriptor() ([]byte, []int) { | 1065 | func (*Exit) Descriptor() ([]byte, []int) { | ||
| 1007 | - | return file_exec_proto_rawDescGZIP(), []int{6} | 1066 | + | return file_exec_proto_rawDescGZIP(), []int{7} |
| 1008 | } | 1067 | } | ||
| 1009 | 1068 | ||||
| 1010 | func (x *Exit) GetCode() int32 { | 1069 | func (x *Exit) GetCode() int32 { | ||
| @@ -1038,7 +1097,7 @@ type Cancel struct { | |||||
| 1038 | 1097 | ||||
| 1039 | func (x *Cancel) Reset() { | 1098 | func (x *Cancel) Reset() { | ||
| 1040 | *x = Cancel{} | 1099 | *x = Cancel{} | ||
| 1041 | - | mi := &file_exec_proto_msgTypes[7] | 1100 | + | mi := &file_exec_proto_msgTypes[8] |
| 1042 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1101 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1043 | ms.StoreMessageInfo(mi) | 1102 | ms.StoreMessageInfo(mi) | ||
| 1044 | } | 1103 | } | ||
| @@ -1050,7 +1109,7 @@ func (x *Cancel) String() string { | |||||
| 1050 | func (*Cancel) ProtoMessage() {} | 1109 | func (*Cancel) ProtoMessage() {} | ||
| 1051 | 1110 | ||||
| 1052 | func (x *Cancel) ProtoReflect() protoreflect.Message { | 1111 | func (x *Cancel) ProtoReflect() protoreflect.Message { | ||
| 1053 | - | mi := &file_exec_proto_msgTypes[7] | 1112 | + | mi := &file_exec_proto_msgTypes[8] |
| 1054 | if x != nil { | 1113 | if x != nil { | ||
| 1055 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1114 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1056 | if ms.LoadMessageInfo() == nil { | 1115 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1063,7 +1122,7 @@ func (x *Cancel) ProtoReflect() protoreflect.Message { | |||||
| 1063 | 1122 | ||||
| 1064 | // Deprecated: Use Cancel.ProtoReflect.Descriptor instead. | 1123 | // Deprecated: Use Cancel.ProtoReflect.Descriptor instead. | ||
| 1065 | func (*Cancel) Descriptor() ([]byte, []int) { | 1124 | func (*Cancel) Descriptor() ([]byte, []int) { | ||
| 1066 | - | return file_exec_proto_rawDescGZIP(), []int{7} | 1125 | + | return file_exec_proto_rawDescGZIP(), []int{8} |
| 1067 | } | 1126 | } | ||
| 1068 | 1127 | ||||
| 1069 | func (x *Cancel) GetReason() string { | 1128 | func (x *Cancel) GetReason() string { | ||
| @@ -1093,7 +1152,7 @@ type StepStarted struct { | |||||
| 1093 | 1152 | ||||
| 1094 | func (x *StepStarted) Reset() { | 1153 | func (x *StepStarted) Reset() { | ||
| 1095 | *x = StepStarted{} | 1154 | *x = StepStarted{} | ||
| 1096 | - | mi := &file_exec_proto_msgTypes[8] | 1155 | + | mi := &file_exec_proto_msgTypes[9] |
| 1097 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1156 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1098 | ms.StoreMessageInfo(mi) | 1157 | ms.StoreMessageInfo(mi) | ||
| 1099 | } | 1158 | } | ||
| @@ -1105,7 +1164,7 @@ func (x *StepStarted) String() string { | |||||
| 1105 | func (*StepStarted) ProtoMessage() {} | 1164 | func (*StepStarted) ProtoMessage() {} | ||
| 1106 | 1165 | ||||
| 1107 | func (x *StepStarted) ProtoReflect() protoreflect.Message { | 1166 | func (x *StepStarted) ProtoReflect() protoreflect.Message { | ||
| 1108 | - | mi := &file_exec_proto_msgTypes[8] | 1167 | + | mi := &file_exec_proto_msgTypes[9] |
| 1109 | if x != nil { | 1168 | if x != nil { | ||
| 1110 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1169 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1111 | if ms.LoadMessageInfo() == nil { | 1170 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1118,7 +1177,7 @@ func (x *StepStarted) ProtoReflect() protoreflect.Message { | |||||
| 1118 | 1177 | ||||
| 1119 | // Deprecated: Use StepStarted.ProtoReflect.Descriptor instead. | 1178 | // Deprecated: Use StepStarted.ProtoReflect.Descriptor instead. | ||
| 1120 | func (*StepStarted) Descriptor() ([]byte, []int) { | 1179 | func (*StepStarted) Descriptor() ([]byte, []int) { | ||
| 1121 | - | return file_exec_proto_rawDescGZIP(), []int{8} | 1180 | + | return file_exec_proto_rawDescGZIP(), []int{9} |
| 1122 | } | 1181 | } | ||
| 1123 | 1182 | ||||
| 1124 | func (x *StepStarted) GetNumber() int32 { | 1183 | func (x *StepStarted) GetNumber() int32 { | ||
| @@ -1158,7 +1217,7 @@ type StepCompleted struct { | |||||
| 1158 | 1217 | ||||
| 1159 | func (x *StepCompleted) Reset() { | 1218 | func (x *StepCompleted) Reset() { | ||
| 1160 | *x = StepCompleted{} | 1219 | *x = StepCompleted{} | ||
| 1161 | - | mi := &file_exec_proto_msgTypes[9] | 1220 | + | mi := &file_exec_proto_msgTypes[10] |
| 1162 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1221 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1163 | ms.StoreMessageInfo(mi) | 1222 | ms.StoreMessageInfo(mi) | ||
| 1164 | } | 1223 | } | ||
| @@ -1170,7 +1229,7 @@ func (x *StepCompleted) String() string { | |||||
| 1170 | func (*StepCompleted) ProtoMessage() {} | 1229 | func (*StepCompleted) ProtoMessage() {} | ||
| 1171 | 1230 | ||||
| 1172 | func (x *StepCompleted) ProtoReflect() protoreflect.Message { | 1231 | func (x *StepCompleted) ProtoReflect() protoreflect.Message { | ||
| 1173 | - | mi := &file_exec_proto_msgTypes[9] | 1232 | + | mi := &file_exec_proto_msgTypes[10] |
| 1174 | if x != nil { | 1233 | if x != nil { | ||
| 1175 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1234 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1176 | if ms.LoadMessageInfo() == nil { | 1235 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1183,7 +1242,7 @@ func (x *StepCompleted) ProtoReflect() protoreflect.Message { | |||||
| 1183 | 1242 | ||||
| 1184 | // Deprecated: Use StepCompleted.ProtoReflect.Descriptor instead. | 1243 | // Deprecated: Use StepCompleted.ProtoReflect.Descriptor instead. | ||
| 1185 | func (*StepCompleted) Descriptor() ([]byte, []int) { | 1244 | func (*StepCompleted) Descriptor() ([]byte, []int) { | ||
| 1186 | - | return file_exec_proto_rawDescGZIP(), []int{9} | 1245 | + | return file_exec_proto_rawDescGZIP(), []int{10} |
| 1187 | } | 1246 | } | ||
| 1188 | 1247 | ||||
| 1189 | func (x *StepCompleted) GetNumber() int32 { | 1248 | func (x *StepCompleted) GetNumber() int32 { | ||
| @@ -1239,7 +1298,7 @@ type Annotation struct { | |||||
| 1239 | 1298 | ||||
| 1240 | func (x *Annotation) Reset() { | 1299 | func (x *Annotation) Reset() { | ||
| 1241 | *x = Annotation{} | 1300 | *x = Annotation{} | ||
| 1242 | - | mi := &file_exec_proto_msgTypes[10] | 1301 | + | mi := &file_exec_proto_msgTypes[11] |
| 1243 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1302 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1244 | ms.StoreMessageInfo(mi) | 1303 | ms.StoreMessageInfo(mi) | ||
| 1245 | } | 1304 | } | ||
| @@ -1251,7 +1310,7 @@ func (x *Annotation) String() string { | |||||
| 1251 | func (*Annotation) ProtoMessage() {} | 1310 | func (*Annotation) ProtoMessage() {} | ||
| 1252 | 1311 | ||||
| 1253 | func (x *Annotation) ProtoReflect() protoreflect.Message { | 1312 | func (x *Annotation) ProtoReflect() protoreflect.Message { | ||
| 1254 | - | mi := &file_exec_proto_msgTypes[10] | 1313 | + | mi := &file_exec_proto_msgTypes[11] |
| 1255 | if x != nil { | 1314 | if x != nil { | ||
| 1256 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1315 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1257 | if ms.LoadMessageInfo() == nil { | 1316 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1264,7 +1323,7 @@ func (x *Annotation) ProtoReflect() protoreflect.Message { | |||||
| 1264 | 1323 | ||||
| 1265 | // Deprecated: Use Annotation.ProtoReflect.Descriptor instead. | 1324 | // Deprecated: Use Annotation.ProtoReflect.Descriptor instead. | ||
| 1266 | func (*Annotation) Descriptor() ([]byte, []int) { | 1325 | func (*Annotation) Descriptor() ([]byte, []int) { | ||
| 1267 | - | return file_exec_proto_rawDescGZIP(), []int{10} | 1326 | + | return file_exec_proto_rawDescGZIP(), []int{11} |
| 1268 | } | 1327 | } | ||
| 1269 | 1328 | ||||
| 1270 | func (x *Annotation) GetLevel() AnnotationLevel { | 1329 | func (x *Annotation) GetLevel() AnnotationLevel { | ||
| @@ -1337,7 +1396,7 @@ type StepAnnotations struct { | |||||
| 1337 | 1396 | ||||
| 1338 | func (x *StepAnnotations) Reset() { | 1397 | func (x *StepAnnotations) Reset() { | ||
| 1339 | *x = StepAnnotations{} | 1398 | *x = StepAnnotations{} | ||
| 1340 | - | mi := &file_exec_proto_msgTypes[11] | 1399 | + | mi := &file_exec_proto_msgTypes[12] |
| 1341 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1400 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1342 | ms.StoreMessageInfo(mi) | 1401 | ms.StoreMessageInfo(mi) | ||
| 1343 | } | 1402 | } | ||
| @@ -1349,7 +1408,7 @@ func (x *StepAnnotations) String() string { | |||||
| 1349 | func (*StepAnnotations) ProtoMessage() {} | 1408 | func (*StepAnnotations) ProtoMessage() {} | ||
| 1350 | 1409 | ||||
| 1351 | func (x *StepAnnotations) ProtoReflect() protoreflect.Message { | 1410 | func (x *StepAnnotations) ProtoReflect() protoreflect.Message { | ||
| 1352 | - | mi := &file_exec_proto_msgTypes[11] | 1411 | + | mi := &file_exec_proto_msgTypes[12] |
| 1353 | if x != nil { | 1412 | if x != nil { | ||
| 1354 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1413 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1355 | if ms.LoadMessageInfo() == nil { | 1414 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1362,7 +1421,7 @@ func (x *StepAnnotations) ProtoReflect() protoreflect.Message { | |||||
| 1362 | 1421 | ||||
| 1363 | // Deprecated: Use StepAnnotations.ProtoReflect.Descriptor instead. | 1422 | // Deprecated: Use StepAnnotations.ProtoReflect.Descriptor instead. | ||
| 1364 | func (*StepAnnotations) Descriptor() ([]byte, []int) { | 1423 | func (*StepAnnotations) Descriptor() ([]byte, []int) { | ||
| 1365 | - | return file_exec_proto_rawDescGZIP(), []int{11} | 1424 | + | return file_exec_proto_rawDescGZIP(), []int{12} |
| 1366 | } | 1425 | } | ||
| 1367 | 1426 | ||||
| 1368 | func (x *StepAnnotations) GetStep() int32 { | 1427 | func (x *StepAnnotations) GetStep() int32 { | ||
| @@ -1391,7 +1450,7 @@ type StepSummary struct { | |||||
| 1391 | 1450 | ||||
| 1392 | func (x *StepSummary) Reset() { | 1451 | func (x *StepSummary) Reset() { | ||
| 1393 | *x = StepSummary{} | 1452 | *x = StepSummary{} | ||
| 1394 | - | mi := &file_exec_proto_msgTypes[12] | 1453 | + | mi := &file_exec_proto_msgTypes[13] |
| 1395 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1454 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1396 | ms.StoreMessageInfo(mi) | 1455 | ms.StoreMessageInfo(mi) | ||
| 1397 | } | 1456 | } | ||
| @@ -1403,7 +1462,7 @@ func (x *StepSummary) String() string { | |||||
| 1403 | func (*StepSummary) ProtoMessage() {} | 1462 | func (*StepSummary) ProtoMessage() {} | ||
| 1404 | 1463 | ||||
| 1405 | func (x *StepSummary) ProtoReflect() protoreflect.Message { | 1464 | func (x *StepSummary) ProtoReflect() protoreflect.Message { | ||
| 1406 | - | mi := &file_exec_proto_msgTypes[12] | 1465 | + | mi := &file_exec_proto_msgTypes[13] |
| 1407 | if x != nil { | 1466 | if x != nil { | ||
| 1408 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1467 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1409 | if ms.LoadMessageInfo() == nil { | 1468 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1416,7 +1475,7 @@ func (x *StepSummary) ProtoReflect() protoreflect.Message { | |||||
| 1416 | 1475 | ||||
| 1417 | // Deprecated: Use StepSummary.ProtoReflect.Descriptor instead. | 1476 | // Deprecated: Use StepSummary.ProtoReflect.Descriptor instead. | ||
| 1418 | func (*StepSummary) Descriptor() ([]byte, []int) { | 1477 | func (*StepSummary) Descriptor() ([]byte, []int) { | ||
| 1419 | - | return file_exec_proto_rawDescGZIP(), []int{12} | 1478 | + | return file_exec_proto_rawDescGZIP(), []int{13} |
| 1420 | } | 1479 | } | ||
| 1421 | 1480 | ||||
| 1422 | func (x *StepSummary) GetStep() int32 { | 1481 | func (x *StepSummary) GetStep() int32 { | ||
| @@ -1448,7 +1507,7 @@ type Log struct { | |||||
| 1448 | 1507 | ||||
| 1449 | func (x *Log) Reset() { | 1508 | func (x *Log) Reset() { | ||
| 1450 | *x = Log{} | 1509 | *x = Log{} | ||
| 1451 | - | mi := &file_exec_proto_msgTypes[13] | 1510 | + | mi := &file_exec_proto_msgTypes[14] |
| 1452 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1511 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1453 | ms.StoreMessageInfo(mi) | 1512 | ms.StoreMessageInfo(mi) | ||
| 1454 | } | 1513 | } | ||
| @@ -1460,7 +1519,7 @@ func (x *Log) String() string { | |||||
| 1460 | func (*Log) ProtoMessage() {} | 1519 | func (*Log) ProtoMessage() {} | ||
| 1461 | 1520 | ||||
| 1462 | func (x *Log) ProtoReflect() protoreflect.Message { | 1521 | func (x *Log) ProtoReflect() protoreflect.Message { | ||
| 1463 | - | mi := &file_exec_proto_msgTypes[13] | 1522 | + | mi := &file_exec_proto_msgTypes[14] |
| 1464 | if x != nil { | 1523 | if x != nil { | ||
| 1465 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1524 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1466 | if ms.LoadMessageInfo() == nil { | 1525 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1473,7 +1532,7 @@ func (x *Log) ProtoReflect() protoreflect.Message { | |||||
| 1473 | 1532 | ||||
| 1474 | // Deprecated: Use Log.ProtoReflect.Descriptor instead. | 1533 | // Deprecated: Use Log.ProtoReflect.Descriptor instead. | ||
| 1475 | func (*Log) Descriptor() ([]byte, []int) { | 1534 | func (*Log) Descriptor() ([]byte, []int) { | ||
| 1476 | - | return file_exec_proto_rawDescGZIP(), []int{13} | 1535 | + | return file_exec_proto_rawDescGZIP(), []int{14} |
| 1477 | } | 1536 | } | ||
| 1478 | 1537 | ||||
| 1479 | func (x *Log) GetStep() int32 { | 1538 | func (x *Log) GetStep() int32 { | ||
| @@ -1517,7 +1576,7 @@ type JobResult struct { | |||||
| 1517 | 1576 | ||||
| 1518 | func (x *JobResult) Reset() { | 1577 | func (x *JobResult) Reset() { | ||
| 1519 | *x = JobResult{} | 1578 | *x = JobResult{} | ||
| 1520 | - | mi := &file_exec_proto_msgTypes[14] | 1579 | + | mi := &file_exec_proto_msgTypes[15] |
| 1521 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1580 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1522 | ms.StoreMessageInfo(mi) | 1581 | ms.StoreMessageInfo(mi) | ||
| 1523 | } | 1582 | } | ||
| @@ -1529,7 +1588,7 @@ func (x *JobResult) String() string { | |||||
| 1529 | func (*JobResult) ProtoMessage() {} | 1588 | func (*JobResult) ProtoMessage() {} | ||
| 1530 | 1589 | ||||
| 1531 | func (x *JobResult) ProtoReflect() protoreflect.Message { | 1590 | func (x *JobResult) ProtoReflect() protoreflect.Message { | ||
| 1532 | - | mi := &file_exec_proto_msgTypes[14] | 1591 | + | mi := &file_exec_proto_msgTypes[15] |
| 1533 | if x != nil { | 1592 | if x != nil { | ||
| 1534 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1593 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1535 | if ms.LoadMessageInfo() == nil { | 1594 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1542,7 +1601,7 @@ func (x *JobResult) ProtoReflect() protoreflect.Message { | |||||
| 1542 | 1601 | ||||
| 1543 | // Deprecated: Use JobResult.ProtoReflect.Descriptor instead. | 1602 | // Deprecated: Use JobResult.ProtoReflect.Descriptor instead. | ||
| 1544 | func (*JobResult) Descriptor() ([]byte, []int) { | 1603 | func (*JobResult) Descriptor() ([]byte, []int) { | ||
| 1545 | - | return file_exec_proto_rawDescGZIP(), []int{14} | 1604 | + | return file_exec_proto_rawDescGZIP(), []int{15} |
| 1546 | } | 1605 | } | ||
| 1547 | 1606 | ||||
| 1548 | func (x *JobResult) GetConclusion() StepConclusion { | 1607 | func (x *JobResult) GetConclusion() StepConclusion { | ||
| @@ -1587,7 +1646,7 @@ type ResolveRequest struct { | |||||
| 1587 | 1646 | ||||
| 1588 | func (x *ResolveRequest) Reset() { | 1647 | func (x *ResolveRequest) Reset() { | ||
| 1589 | *x = ResolveRequest{} | 1648 | *x = ResolveRequest{} | ||
| 1590 | - | mi := &file_exec_proto_msgTypes[15] | 1649 | + | mi := &file_exec_proto_msgTypes[16] |
| 1591 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1650 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1592 | ms.StoreMessageInfo(mi) | 1651 | ms.StoreMessageInfo(mi) | ||
| 1593 | } | 1652 | } | ||
| @@ -1599,7 +1658,7 @@ func (x *ResolveRequest) String() string { | |||||
| 1599 | func (*ResolveRequest) ProtoMessage() {} | 1658 | func (*ResolveRequest) ProtoMessage() {} | ||
| 1600 | 1659 | ||||
| 1601 | func (x *ResolveRequest) ProtoReflect() protoreflect.Message { | 1660 | func (x *ResolveRequest) ProtoReflect() protoreflect.Message { | ||
| 1602 | - | mi := &file_exec_proto_msgTypes[15] | 1661 | + | mi := &file_exec_proto_msgTypes[16] |
| 1603 | if x != nil { | 1662 | if x != nil { | ||
| 1604 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1663 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1605 | if ms.LoadMessageInfo() == nil { | 1664 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1612,7 +1671,7 @@ func (x *ResolveRequest) ProtoReflect() protoreflect.Message { | |||||
| 1612 | 1671 | ||||
| 1613 | // Deprecated: Use ResolveRequest.ProtoReflect.Descriptor instead. | 1672 | // Deprecated: Use ResolveRequest.ProtoReflect.Descriptor instead. | ||
| 1614 | func (*ResolveRequest) Descriptor() ([]byte, []int) { | 1673 | func (*ResolveRequest) Descriptor() ([]byte, []int) { | ||
| 1615 | - | return file_exec_proto_rawDescGZIP(), []int{15} | 1674 | + | return file_exec_proto_rawDescGZIP(), []int{16} |
| 1616 | } | 1675 | } | ||
| 1617 | 1676 | ||||
| 1618 | func (x *ResolveRequest) GetId() int64 { | 1677 | func (x *ResolveRequest) GetId() int64 { | ||
| @@ -1642,7 +1701,7 @@ type ResolveResponse struct { | |||||
| 1642 | 1701 | ||||
| 1643 | func (x *ResolveResponse) Reset() { | 1702 | func (x *ResolveResponse) Reset() { | ||
| 1644 | *x = ResolveResponse{} | 1703 | *x = ResolveResponse{} | ||
| 1645 | - | mi := &file_exec_proto_msgTypes[16] | 1704 | + | mi := &file_exec_proto_msgTypes[17] |
| 1646 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1705 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1647 | ms.StoreMessageInfo(mi) | 1706 | ms.StoreMessageInfo(mi) | ||
| 1648 | } | 1707 | } | ||
| @@ -1654,7 +1713,7 @@ func (x *ResolveResponse) String() string { | |||||
| 1654 | func (*ResolveResponse) ProtoMessage() {} | 1713 | func (*ResolveResponse) ProtoMessage() {} | ||
| 1655 | 1714 | ||||
| 1656 | func (x *ResolveResponse) ProtoReflect() protoreflect.Message { | 1715 | func (x *ResolveResponse) ProtoReflect() protoreflect.Message { | ||
| 1657 | - | mi := &file_exec_proto_msgTypes[16] | 1716 | + | mi := &file_exec_proto_msgTypes[17] |
| 1658 | if x != nil { | 1717 | if x != nil { | ||
| 1659 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1718 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1660 | if ms.LoadMessageInfo() == nil { | 1719 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1667,7 +1726,7 @@ func (x *ResolveResponse) ProtoReflect() protoreflect.Message { | |||||
| 1667 | 1726 | ||||
| 1668 | // Deprecated: Use ResolveResponse.ProtoReflect.Descriptor instead. | 1727 | // Deprecated: Use ResolveResponse.ProtoReflect.Descriptor instead. | ||
| 1669 | func (*ResolveResponse) Descriptor() ([]byte, []int) { | 1728 | func (*ResolveResponse) Descriptor() ([]byte, []int) { | ||
| 1670 | - | return file_exec_proto_rawDescGZIP(), []int{16} | 1729 | + | return file_exec_proto_rawDescGZIP(), []int{17} |
| 1671 | } | 1730 | } | ||
| 1672 | 1731 | ||||
| 1673 | func (x *ResolveResponse) GetId() int64 { | 1732 | func (x *ResolveResponse) GetId() int64 { | ||
| @@ -1714,7 +1773,7 @@ type ResolvedAction struct { | |||||
| 1714 | 1773 | ||||
| 1715 | func (x *ResolvedAction) Reset() { | 1774 | func (x *ResolvedAction) Reset() { | ||
| 1716 | *x = ResolvedAction{} | 1775 | *x = ResolvedAction{} | ||
| 1717 | - | mi := &file_exec_proto_msgTypes[17] | 1776 | + | mi := &file_exec_proto_msgTypes[18] |
| 1718 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1777 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1719 | ms.StoreMessageInfo(mi) | 1778 | ms.StoreMessageInfo(mi) | ||
| 1720 | } | 1779 | } | ||
| @@ -1726,7 +1785,7 @@ func (x *ResolvedAction) String() string { | |||||
| 1726 | func (*ResolvedAction) ProtoMessage() {} | 1785 | func (*ResolvedAction) ProtoMessage() {} | ||
| 1727 | 1786 | ||||
| 1728 | func (x *ResolvedAction) ProtoReflect() protoreflect.Message { | 1787 | func (x *ResolvedAction) ProtoReflect() protoreflect.Message { | ||
| 1729 | - | mi := &file_exec_proto_msgTypes[17] | 1788 | + | mi := &file_exec_proto_msgTypes[18] |
| 1730 | if x != nil { | 1789 | if x != nil { | ||
| 1731 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | 1790 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||
| 1732 | if ms.LoadMessageInfo() == nil { | 1791 | if ms.LoadMessageInfo() == nil { | ||
| @@ -1739,7 +1798,7 @@ func (x *ResolvedAction) ProtoReflect() protoreflect.Message { | |||||
| 1739 | 1798 | ||||
| 1740 | // Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead. | 1799 | // Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead. | ||
| 1741 | func (*ResolvedAction) Descriptor() ([]byte, []int) { | 1800 | func (*ResolvedAction) Descriptor() ([]byte, []int) { | ||
| 1742 | - | return file_exec_proto_rawDescGZIP(), []int{17} | 1801 | + | return file_exec_proto_rawDescGZIP(), []int{18} |
| 1743 | } | 1802 | } | ||
| 1744 | 1803 | ||||
| 1745 | func (x *ResolvedAction) GetRef() string { | 1804 | func (x *ResolvedAction) GetRef() string { | ||
| @@ -1844,7 +1903,7 @@ const file_exec_proto_rawDesc = "" + | |||||
| 1844 | "\x03job\x18\x03 \x01(\v2\x1e.ermite.runner.exec.v1.JobSpecR\x03job\x1a6\n" + | 1903 | "\x03job\x18\x03 \x01(\v2\x1e.ermite.runner.exec.v1.JobSpecR\x03job\x1a6\n" + | ||
| 1845 | "\bEnvEntry\x12\x10\n" + | 1904 | "\bEnvEntry\x12\x10\n" + | ||
| 1846 | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + | 1905 | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + | ||
| 1847 | - | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xe3\x04\n" + | 1906 | + | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xb9\x05\n" + |
| 1848 | "\aJobSpec\x12#\n" + | 1907 | "\aJobSpec\x12#\n" + | ||
| 1849 | "\rworkflow_path\x18\x01 \x01(\tR\fworkflowPath\x12#\n" + | 1908 | "\rworkflow_path\x18\x01 \x01(\tR\fworkflowPath\x12#\n" + | ||
| 1850 | "\rworkflow_yaml\x18\x02 \x01(\tR\fworkflowYaml\x12\x17\n" + | 1909 | "\rworkflow_yaml\x18\x02 \x01(\tR\fworkflowYaml\x12\x17\n" + | ||
| @@ -1867,7 +1926,13 @@ const file_exec_proto_rawDesc = "" + | |||||
| 1867 | "cache_port\x18\x0f \x01(\rR\tcachePort\x12\x1f\n" + | 1926 | "cache_port\x18\x0f \x01(\rR\tcachePort\x12\x1f\n" + | ||
| 1868 | "\vcache_token\x18\x10 \x01(\tR\n" + | 1927 | "\vcache_token\x18\x10 \x01(\tR\n" + | ||
| 1869 | "cacheToken\x12)\n" + | 1928 | "cacheToken\x12)\n" + | ||
| 1870 | - | "\x10secrets_withheld\x18\x13 \x01(\bR\x0fsecretsWithheldJ\x04\b\x11\x10\x12J\x04\b\x12\x10\x13R\asecretsR\x04vars\"t\n" + | 1929 | + | "\x10secrets_withheld\x18\x13 \x01(\bR\x0fsecretsWithheld\x12T\n" + |
| 1930 | + | "\x11token_permissions\x18\x14 \x01(\v2'.ermite.runner.exec.v1.TokenPermissionsR\x10tokenPermissionsJ\x04\b\x11\x10\x12J\x04\b\x12\x10\x13R\asecretsR\x04vars\"\x9a\x01\n" + | |||
| 1931 | + | "\x10TokenPermissions\x12K\n" + | |||
| 1932 | + | "\x06levels\x18\x01 \x03(\v23.ermite.runner.exec.v1.TokenPermissions.LevelsEntryR\x06levels\x1a9\n" + | |||
| 1933 | + | "\vLevelsEntry\x12\x10\n" + | |||
| 1934 | + | "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + | |||
| 1935 | + | "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"t\n" + | |||
| 1871 | "\x06Output\x129\n" + | 1936 | "\x06Output\x129\n" + | ||
| 1872 | "\x06stream\x18\x01 \x01(\x0e2!.ermite.runner.exec.v1.StreamKindR\x06stream\x12\x12\n" + | 1937 | "\x06stream\x18\x01 \x01(\x0e2!.ermite.runner.exec.v1.StreamKindR\x06stream\x12\x12\n" + | ||
| 1873 | "\x04data\x18\x02 \x01(\fR\x04data\x12\x1b\n" + | 1938 | "\x04data\x18\x02 \x01(\fR\x04data\x12\x1b\n" + | ||
| @@ -1979,65 +2044,69 @@ func file_exec_proto_rawDescGZIP() []byte { | |||||
| 1979 | } | 2044 | } | ||
| 1980 | 2045 | ||||
| 1981 | var file_exec_proto_enumTypes = make([]protoimpl.EnumInfo, 4) | 2046 | var file_exec_proto_enumTypes = make([]protoimpl.EnumInfo, 4) | ||
| 1982 | - | var file_exec_proto_msgTypes = make([]protoimpl.MessageInfo, 20) | 2047 | + | var file_exec_proto_msgTypes = make([]protoimpl.MessageInfo, 22) |
| 1983 | var file_exec_proto_goTypes = []any{ | 2048 | var file_exec_proto_goTypes = []any{ | ||
| 1984 | - | (StreamKind)(0), // 0: ermite.runner.exec.v1.StreamKind | 2049 | + | (StreamKind)(0), // 0: ermite.runner.exec.v1.StreamKind |
| 1985 | - | (CancelKind)(0), // 1: ermite.runner.exec.v1.CancelKind | 2050 | + | (CancelKind)(0), // 1: ermite.runner.exec.v1.CancelKind |
| 1986 | - | (AnnotationLevel)(0), // 2: ermite.runner.exec.v1.AnnotationLevel | 2051 | + | (AnnotationLevel)(0), // 2: ermite.runner.exec.v1.AnnotationLevel |
| 1987 | - | (StepConclusion)(0), // 3: ermite.runner.exec.v1.StepConclusion | 2052 | + | (StepConclusion)(0), // 3: ermite.runner.exec.v1.StepConclusion |
| 1988 | - | (*Frame)(nil), // 4: ermite.runner.exec.v1.Frame | 2053 | + | (*Frame)(nil), // 4: ermite.runner.exec.v1.Frame |
| 1989 | - | (*NamedValue)(nil), // 5: ermite.runner.exec.v1.NamedValue | 2054 | + | (*NamedValue)(nil), // 5: ermite.runner.exec.v1.NamedValue |
| 1990 | - | (*Hello)(nil), // 6: ermite.runner.exec.v1.Hello | 2055 | + | (*Hello)(nil), // 6: ermite.runner.exec.v1.Hello |
| 1991 | - | (*Run)(nil), // 7: ermite.runner.exec.v1.Run | 2056 | + | (*Run)(nil), // 7: ermite.runner.exec.v1.Run |
| 1992 | - | (*JobSpec)(nil), // 8: ermite.runner.exec.v1.JobSpec | 2057 | + | (*JobSpec)(nil), // 8: ermite.runner.exec.v1.JobSpec |
| 1993 | - | (*Output)(nil), // 9: ermite.runner.exec.v1.Output | 2058 | + | (*TokenPermissions)(nil), // 9: ermite.runner.exec.v1.TokenPermissions |
| 1994 | - | (*Exit)(nil), // 10: ermite.runner.exec.v1.Exit | 2059 | + | (*Output)(nil), // 10: ermite.runner.exec.v1.Output |
| 1995 | - | (*Cancel)(nil), // 11: ermite.runner.exec.v1.Cancel | 2060 | + | (*Exit)(nil), // 11: ermite.runner.exec.v1.Exit |
| 1996 | - | (*StepStarted)(nil), // 12: ermite.runner.exec.v1.StepStarted | 2061 | + | (*Cancel)(nil), // 12: ermite.runner.exec.v1.Cancel |
| 1997 | - | (*StepCompleted)(nil), // 13: ermite.runner.exec.v1.StepCompleted | 2062 | + | (*StepStarted)(nil), // 13: ermite.runner.exec.v1.StepStarted |
| 1998 | - | (*Annotation)(nil), // 14: ermite.runner.exec.v1.Annotation | 2063 | + | (*StepCompleted)(nil), // 14: ermite.runner.exec.v1.StepCompleted |
| 1999 | - | (*StepAnnotations)(nil), // 15: ermite.runner.exec.v1.StepAnnotations | 2064 | + | (*Annotation)(nil), // 15: ermite.runner.exec.v1.Annotation |
| 2000 | - | (*StepSummary)(nil), // 16: ermite.runner.exec.v1.StepSummary | 2065 | + | (*StepAnnotations)(nil), // 16: ermite.runner.exec.v1.StepAnnotations |
| 2001 | - | (*Log)(nil), // 17: ermite.runner.exec.v1.Log | 2066 | + | (*StepSummary)(nil), // 17: ermite.runner.exec.v1.StepSummary |
| 2002 | - | (*JobResult)(nil), // 18: ermite.runner.exec.v1.JobResult | 2067 | + | (*Log)(nil), // 18: ermite.runner.exec.v1.Log |
| 2003 | - | (*ResolveRequest)(nil), // 19: ermite.runner.exec.v1.ResolveRequest | 2068 | + | (*JobResult)(nil), // 19: ermite.runner.exec.v1.JobResult |
| 2004 | - | (*ResolveResponse)(nil), // 20: ermite.runner.exec.v1.ResolveResponse | 2069 | + | (*ResolveRequest)(nil), // 20: ermite.runner.exec.v1.ResolveRequest |
| 2005 | - | (*ResolvedAction)(nil), // 21: ermite.runner.exec.v1.ResolvedAction | 2070 | + | (*ResolveResponse)(nil), // 21: ermite.runner.exec.v1.ResolveResponse |
| 2006 | - | nil, // 22: ermite.runner.exec.v1.Run.EnvEntry | 2071 | + | (*ResolvedAction)(nil), // 22: ermite.runner.exec.v1.ResolvedAction |
| 2007 | - | nil, // 23: ermite.runner.exec.v1.JobResult.OutputsEntry | 2072 | + | nil, // 23: ermite.runner.exec.v1.Run.EnvEntry |
| 2073 | + | nil, // 24: ermite.runner.exec.v1.TokenPermissions.LevelsEntry | |||
| 2074 | + | nil, // 25: ermite.runner.exec.v1.JobResult.OutputsEntry | |||
| 2008 | } | 2075 | } | ||
| 2009 | var file_exec_proto_depIdxs = []int32{ | 2076 | var file_exec_proto_depIdxs = []int32{ | ||
| 2010 | 6, // 0: ermite.runner.exec.v1.Frame.hello:type_name -> ermite.runner.exec.v1.Hello | 2077 | 6, // 0: ermite.runner.exec.v1.Frame.hello:type_name -> ermite.runner.exec.v1.Hello | ||
| 2011 | 7, // 1: ermite.runner.exec.v1.Frame.run:type_name -> ermite.runner.exec.v1.Run | 2078 | 7, // 1: ermite.runner.exec.v1.Frame.run:type_name -> ermite.runner.exec.v1.Run | ||
| 2012 | - | 9, // 2: ermite.runner.exec.v1.Frame.output:type_name -> ermite.runner.exec.v1.Output | 2079 | + | 10, // 2: ermite.runner.exec.v1.Frame.output:type_name -> ermite.runner.exec.v1.Output |
| 2013 | - | 10, // 3: ermite.runner.exec.v1.Frame.exit:type_name -> ermite.runner.exec.v1.Exit | 2080 | + | 11, // 3: ermite.runner.exec.v1.Frame.exit:type_name -> ermite.runner.exec.v1.Exit |
| 2014 | - | 11, // 4: ermite.runner.exec.v1.Frame.cancel:type_name -> ermite.runner.exec.v1.Cancel | 2081 | + | 12, // 4: ermite.runner.exec.v1.Frame.cancel:type_name -> ermite.runner.exec.v1.Cancel |
| 2015 | - | 12, // 5: ermite.runner.exec.v1.Frame.step_started:type_name -> ermite.runner.exec.v1.StepStarted | 2082 | + | 13, // 5: ermite.runner.exec.v1.Frame.step_started:type_name -> ermite.runner.exec.v1.StepStarted |
| 2016 | - | 13, // 6: ermite.runner.exec.v1.Frame.step_completed:type_name -> ermite.runner.exec.v1.StepCompleted | 2083 | + | 14, // 6: ermite.runner.exec.v1.Frame.step_completed:type_name -> ermite.runner.exec.v1.StepCompleted |
| 2017 | - | 17, // 7: ermite.runner.exec.v1.Frame.log:type_name -> ermite.runner.exec.v1.Log | 2084 | + | 18, // 7: ermite.runner.exec.v1.Frame.log:type_name -> ermite.runner.exec.v1.Log |
| 2018 | - | 18, // 8: ermite.runner.exec.v1.Frame.job_result:type_name -> ermite.runner.exec.v1.JobResult | 2085 | + | 19, // 8: ermite.runner.exec.v1.Frame.job_result:type_name -> ermite.runner.exec.v1.JobResult |
| 2019 | - | 15, // 9: ermite.runner.exec.v1.Frame.step_annotations:type_name -> ermite.runner.exec.v1.StepAnnotations | 2086 | + | 16, // 9: ermite.runner.exec.v1.Frame.step_annotations:type_name -> ermite.runner.exec.v1.StepAnnotations |
| 2020 | - | 16, // 10: ermite.runner.exec.v1.Frame.step_summary:type_name -> ermite.runner.exec.v1.StepSummary | 2087 | + | 17, // 10: ermite.runner.exec.v1.Frame.step_summary:type_name -> ermite.runner.exec.v1.StepSummary |
| 2021 | - | 19, // 11: ermite.runner.exec.v1.Frame.resolve_request:type_name -> ermite.runner.exec.v1.ResolveRequest | 2088 | + | 20, // 11: ermite.runner.exec.v1.Frame.resolve_request:type_name -> ermite.runner.exec.v1.ResolveRequest |
| 2022 | - | 20, // 12: ermite.runner.exec.v1.Frame.resolve_response:type_name -> ermite.runner.exec.v1.ResolveResponse | 2089 | + | 21, // 12: ermite.runner.exec.v1.Frame.resolve_response:type_name -> ermite.runner.exec.v1.ResolveResponse |
| 2023 | 5, // 13: ermite.runner.exec.v1.Frame.secret:type_name -> ermite.runner.exec.v1.NamedValue | 2090 | 5, // 13: ermite.runner.exec.v1.Frame.secret:type_name -> ermite.runner.exec.v1.NamedValue | ||
| 2024 | 5, // 14: ermite.runner.exec.v1.Frame.var:type_name -> ermite.runner.exec.v1.NamedValue | 2091 | 5, // 14: ermite.runner.exec.v1.Frame.var:type_name -> ermite.runner.exec.v1.NamedValue | ||
| 2025 | - | 22, // 15: ermite.runner.exec.v1.Run.env:type_name -> ermite.runner.exec.v1.Run.EnvEntry | 2092 | + | 23, // 15: ermite.runner.exec.v1.Run.env:type_name -> ermite.runner.exec.v1.Run.EnvEntry |
| 2026 | 8, // 16: ermite.runner.exec.v1.Run.job:type_name -> ermite.runner.exec.v1.JobSpec | 2093 | 8, // 16: ermite.runner.exec.v1.Run.job:type_name -> ermite.runner.exec.v1.JobSpec | ||
| 2027 | - | 0, // 17: ermite.runner.exec.v1.Output.stream:type_name -> ermite.runner.exec.v1.StreamKind | 2094 | + | 9, // 17: ermite.runner.exec.v1.JobSpec.token_permissions:type_name -> ermite.runner.exec.v1.TokenPermissions |
| 2028 | - | 1, // 18: ermite.runner.exec.v1.Cancel.kind:type_name -> ermite.runner.exec.v1.CancelKind | 2095 | + | 24, // 18: ermite.runner.exec.v1.TokenPermissions.levels:type_name -> ermite.runner.exec.v1.TokenPermissions.LevelsEntry |
| 2029 | - | 3, // 19: ermite.runner.exec.v1.StepCompleted.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | 2096 | + | 0, // 19: ermite.runner.exec.v1.Output.stream:type_name -> ermite.runner.exec.v1.StreamKind |
| 2030 | - | 3, // 20: ermite.runner.exec.v1.StepCompleted.outcome:type_name -> ermite.runner.exec.v1.StepConclusion | 2097 | + | 1, // 20: ermite.runner.exec.v1.Cancel.kind:type_name -> ermite.runner.exec.v1.CancelKind |
| 2031 | - | 2, // 21: ermite.runner.exec.v1.Annotation.level:type_name -> ermite.runner.exec.v1.AnnotationLevel | 2098 | + | 3, // 21: ermite.runner.exec.v1.StepCompleted.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion |
| 2032 | - | 14, // 22: ermite.runner.exec.v1.StepAnnotations.annotations:type_name -> ermite.runner.exec.v1.Annotation | 2099 | + | 3, // 22: ermite.runner.exec.v1.StepCompleted.outcome:type_name -> ermite.runner.exec.v1.StepConclusion |
| 2033 | - | 3, // 23: ermite.runner.exec.v1.JobResult.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion | 2100 | + | 2, // 23: ermite.runner.exec.v1.Annotation.level:type_name -> ermite.runner.exec.v1.AnnotationLevel |
| 2034 | - | 23, // 24: ermite.runner.exec.v1.JobResult.outputs:type_name -> ermite.runner.exec.v1.JobResult.OutputsEntry | 2101 | + | 15, // 24: ermite.runner.exec.v1.StepAnnotations.annotations:type_name -> ermite.runner.exec.v1.Annotation |
| 2035 | - | 21, // 25: ermite.runner.exec.v1.ResolveResponse.actions:type_name -> ermite.runner.exec.v1.ResolvedAction | 2102 | + | 3, // 25: ermite.runner.exec.v1.JobResult.conclusion:type_name -> ermite.runner.exec.v1.StepConclusion |
| 2036 | - | 26, // [26:26] is the sub-list for method output_type | 2103 | + | 25, // 26: ermite.runner.exec.v1.JobResult.outputs:type_name -> ermite.runner.exec.v1.JobResult.OutputsEntry |
| 2037 | - | 26, // [26:26] is the sub-list for method input_type | 2104 | + | 22, // 27: ermite.runner.exec.v1.ResolveResponse.actions:type_name -> ermite.runner.exec.v1.ResolvedAction |
| 2038 | - | 26, // [26:26] is the sub-list for extension type_name | 2105 | + | 28, // [28:28] is the sub-list for method output_type |
| 2039 | - | 26, // [26:26] is the sub-list for extension extendee | 2106 | + | 28, // [28:28] is the sub-list for method input_type |
| 2040 | - | 0, // [0:26] is the sub-list for field type_name | 2107 | + | 28, // [28:28] is the sub-list for extension type_name |
| 2108 | + | 28, // [28:28] is the sub-list for extension extendee | |||
| 2109 | + | 0, // [0:28] is the sub-list for field type_name | |||
| 2041 | } | 2110 | } | ||
| 2042 | 2111 | ||||
| 2043 | func init() { file_exec_proto_init() } | 2112 | func init() { file_exec_proto_init() } | ||
| @@ -2068,7 +2137,7 @@ func file_exec_proto_init() { | |||||
| 2068 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | 2137 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||
| 2069 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_exec_proto_rawDesc), len(file_exec_proto_rawDesc)), | 2138 | RawDescriptor: unsafe.Slice(unsafe.StringData(file_exec_proto_rawDesc), len(file_exec_proto_rawDesc)), | ||
| 2070 | NumEnums: 4, | 2139 | NumEnums: 4, | ||
| 2071 | - | NumMessages: 20, | 2140 | + | NumMessages: 22, |
| 2072 | NumExtensions: 0, | 2141 | NumExtensions: 0, | ||
| 2073 | NumServices: 0, | 2142 | NumServices: 0, | ||
| 2074 | }, | 2143 | }, | ||
M internal/executor/job.go +18 -5
| @@ -85,6 +85,11 @@ type Config struct { | |||
| 85 | 85 | // SecretsWithheld says that the server did not send secrets because the run | |
| 86 | 86 | // is not trusted: "Set up job" says so. | |
| 87 | 87 | SecretsWithheld bool | |
| 88 | + | // TokenPermissions are the permissions of GITHUB_TOKEN as the server sent | |
| 89 | + | // them (Job.permissions: key to "read", "write" or "none"), which "Set up | |
| 90 | + | // job" prints as they are. Nil means the server sent none: they are then | |
| 91 | + | // worked out from the workflow. An empty, non-nil map is "none at all". | |
| 92 | + | TokenPermissions map[string]string | |
| 88 | 93 | // Debug turns ##[debug] lines on (ACTIONS_STEP_DEBUG). | |
| 89 | 94 | Debug bool | |
| 90 | 95 | // Actions configures the actions of the job (resolution, downloads, Node.js, | |
| @@ -729,13 +734,21 @@ const SecretsWithheldLine = "Secrets are not available to this job: the run was | |||
| 729 | 734 | // and the cache mode. | |
| 730 | 735 | // | |
| 731 | 736 | // GitHub's runner prints what the server sends as | |
| 732 | - | // system.github.token.permissions (JobExtension.cs:154-166); ermite's Job | |
| 733 | - | // message does not carry it, so the group is worked out from the workflow | |
| 734 | - | // with the rules recorded on github.com (tokenPermissionLines). It is always | |
| 735 | - | // printed: Metadata is listed even for "permissions: {}". | |
| 737 | + | // system.github.token.permissions (JobExtension.cs:154-166). ermite's server | |
| 738 | + | // sends them in Job.permissions, already merged and lowered by its trust rule: | |
| 739 | + | // they are printed as they are (serverPermissionLines). From a server that | |
| 740 | + | // sends none the group is worked out from the workflow with the rules recorded | |
| 741 | + | // on github.com (tokenPermissionLines). It is always printed: Metadata is listed | |
| 742 | + | // even for "permissions: {}". | |
| 736 | 743 | func (j *job) printTokenInfo() { | |
| 737 | 744 | j.out(1, "##[group]GITHUB_TOKEN Permissions") | |
| 738 | - | for _, p := range tokenPermissionLines(j.wf, j.jb) { | |
| 745 | + | var lines []permissionLine | |
| 746 | + | if j.cfg.TokenPermissions != nil { | |
| 747 | + | lines = serverPermissionLines(j.cfg.TokenPermissions) | |
| 748 | + | } else { | |
| 749 | + | lines = tokenPermissionLines(j.wf, j.jb) | |
| 750 | + | } | |
| 751 | + | for _, p := range lines { | |
| 739 | 752 | j.out(1, p.name+": "+p.level) | |
| 740 | 753 | } | |
| 741 | 754 | j.out(1, "##[endgroup]") | |
| @@ -85,6 +85,11 @@ type Config struct { | |||||
| 85 | // SecretsWithheld says that the server did not send secrets because the run | 85 | // SecretsWithheld says that the server did not send secrets because the run | ||
| 86 | // is not trusted: "Set up job" says so. | 86 | // is not trusted: "Set up job" says so. | ||
| 87 | SecretsWithheld bool | 87 | SecretsWithheld bool | ||
| 88 | + | // TokenPermissions are the permissions of GITHUB_TOKEN as the server sent | |||
| 89 | + | // them (Job.permissions: key to "read", "write" or "none"), which "Set up | |||
| 90 | + | // job" prints as they are. Nil means the server sent none: they are then | |||
| 91 | + | // worked out from the workflow. An empty, non-nil map is "none at all". | |||
| 92 | + | TokenPermissions map[string]string | |||
| 88 | // Debug turns ##[debug] lines on (ACTIONS_STEP_DEBUG). | 93 | // Debug turns ##[debug] lines on (ACTIONS_STEP_DEBUG). | ||
| 89 | Debug bool | 94 | Debug bool | ||
| 90 | // Actions configures the actions of the job (resolution, downloads, Node.js, | 95 | // Actions configures the actions of the job (resolution, downloads, Node.js, | ||
| @@ -729,13 +734,21 @@ const SecretsWithheldLine = "Secrets are not available to this job: the run was | |||||
| 729 | // and the cache mode. | 734 | // and the cache mode. | ||
| 730 | // | 735 | // | ||
| 731 | // GitHub's runner prints what the server sends as | 736 | // GitHub's runner prints what the server sends as | ||
| 732 | - | // system.github.token.permissions (JobExtension.cs:154-166); ermite's Job | 737 | + | // system.github.token.permissions (JobExtension.cs:154-166). ermite's server |
| 733 | - | // message does not carry it, so the group is worked out from the workflow | 738 | + | // sends them in Job.permissions, already merged and lowered by its trust rule: |
| 734 | - | // with the rules recorded on github.com (tokenPermissionLines). It is always | 739 | + | // they are printed as they are (serverPermissionLines). From a server that |
| 735 | - | // printed: Metadata is listed even for "permissions: {}". | 740 | + | // sends none the group is worked out from the workflow with the rules recorded |
| 741 | + | // on github.com (tokenPermissionLines). It is always printed: Metadata is listed | |||
| 742 | + | // even for "permissions: {}". | |||
| 736 | func (j *job) printTokenInfo() { | 743 | func (j *job) printTokenInfo() { | ||
| 737 | j.out(1, "##[group]GITHUB_TOKEN Permissions") | 744 | j.out(1, "##[group]GITHUB_TOKEN Permissions") | ||
| 738 | - | for _, p := range tokenPermissionLines(j.wf, j.jb) { | 745 | + | var lines []permissionLine |
| 746 | + | if j.cfg.TokenPermissions != nil { | |||
| 747 | + | lines = serverPermissionLines(j.cfg.TokenPermissions) | |||
| 748 | + | } else { | |||
| 749 | + | lines = tokenPermissionLines(j.wf, j.jb) | |||
| 750 | + | } | |||
| 751 | + | for _, p := range lines { | |||
| 739 | j.out(1, p.name+": "+p.level) | 752 | j.out(1, p.name+": "+p.level) | ||
| 740 | } | 753 | } | ||
| 741 | j.out(1, "##[endgroup]") | 754 | j.out(1, "##[endgroup]") | ||
M internal/executor/secrets_test.go +36 -0
| @@ -317,3 +317,39 @@ func TestOnlyDiagUsesTheDiagnosticsLogger(t *testing.T) { | |||
| 317 | 317 | } | |
| 318 | 318 | } | |
| 319 | 319 | } | |
| 320 | + | ||
| 321 | + | // The group prints what the server sent in Job.permissions, as GitHub's runner | |
| 322 | + | // prints system.github.token.permissions, and not what the workflow says. | |
| 323 | + | func TestSetUpJobPrintsTheServersTokenPermissions(t *testing.T) { | |
| 324 | + | needTools(t, "bash") | |
| 325 | + | group := func(log string) string { | |
| 326 | + | _, rest, _ := strings.Cut(log, "##[group]GITHUB_TOKEN Permissions\n") | |
| 327 | + | g, _, _ := strings.Cut(rest, "\n##[endgroup]") | |
| 328 | + | return g | |
| 329 | + | } | |
| 330 | + | // The workflow asks for write-all; the server lowered it (an untrusted run). | |
| 331 | + | yaml := "on: push\npermissions: write-all\njobs:\n j:\n runs-on: ubuntu-latest\n steps:\n - run: echo hi\n" | |
| 332 | + | for _, tc := range []struct { | |
| 333 | + | name string | |
| 334 | + | levels map[string]string | |
| 335 | + | want string | |
| 336 | + | }{ | |
| 337 | + | {"lowered by the server", map[string]string{"contents": "read", "pull-requests": "read", "issues": "read", "metadata": "read"}, | |
| 338 | + | "Contents: read\nIssues: read\nMetadata: read\nPullRequests: read"}, | |
| 339 | + | {"write kept", map[string]string{"contents": "write", "metadata": "read", "packages": "read"}, "Contents: write\nMetadata: read\nPackages: read"}, | |
| 340 | + | {"none and id-token are not listed, metadata always is", map[string]string{"contents": "none", "id-token": "write", "actions": "read"}, | |
| 341 | + | "Actions: read\nMetadata: read"}, | |
| 342 | + | {"nothing at all is metadata only", map[string]string{}, "Metadata: read"}, | |
| 343 | + | {"a key the runner does not know", map[string]string{"made-up-key": "read"}, "MadeUpKey: read\nMetadata: read"}, | |
| 344 | + | } { | |
| 345 | + | got := group(setupLog(t, yaml, "j", func(c *Config) { c.TokenPermissions = tc.levels })) | |
| 346 | + | if got != tc.want { | |
| 347 | + | t.Errorf("%s:\n%s\nwant:\n%s", tc.name, got, tc.want) | |
| 348 | + | } | |
| 349 | + | } | |
| 350 | + | // A server that sends none: worked out from the workflow, as before. | |
| 351 | + | got := group(setupLog(t, yaml, "j", nil)) | |
| 352 | + | if !strings.Contains(got, "Contents: write") || !strings.Contains(got, "Models: read") { | |
| 353 | + | t.Errorf("fallback to the workflow:\n%s", got) | |
| 354 | + | } | |
| 355 | + | } | |
| @@ -317,3 +317,39 @@ func TestOnlyDiagUsesTheDiagnosticsLogger(t *testing.T) { | |||||
| 317 | } | 317 | } | ||
| 318 | } | 318 | } | ||
| 319 | } | 319 | } | ||
| 320 | + | ||||
| 321 | + | // The group prints what the server sent in Job.permissions, as GitHub's runner | |||
| 322 | + | // prints system.github.token.permissions, and not what the workflow says. | |||
| 323 | + | func TestSetUpJobPrintsTheServersTokenPermissions(t *testing.T) { | |||
| 324 | + | needTools(t, "bash") | |||
| 325 | + | group := func(log string) string { | |||
| 326 | + | _, rest, _ := strings.Cut(log, "##[group]GITHUB_TOKEN Permissions\n") | |||
| 327 | + | g, _, _ := strings.Cut(rest, "\n##[endgroup]") | |||
| 328 | + | return g | |||
| 329 | + | } | |||
| 330 | + | // The workflow asks for write-all; the server lowered it (an untrusted run). | |||
| 331 | + | yaml := "on: push\npermissions: write-all\njobs:\n j:\n runs-on: ubuntu-latest\n steps:\n - run: echo hi\n" | |||
| 332 | + | for _, tc := range []struct { | |||
| 333 | + | name string | |||
| 334 | + | levels map[string]string | |||
| 335 | + | want string | |||
| 336 | + | }{ | |||
| 337 | + | {"lowered by the server", map[string]string{"contents": "read", "pull-requests": "read", "issues": "read", "metadata": "read"}, | |||
| 338 | + | "Contents: read\nIssues: read\nMetadata: read\nPullRequests: read"}, | |||
| 339 | + | {"write kept", map[string]string{"contents": "write", "metadata": "read", "packages": "read"}, "Contents: write\nMetadata: read\nPackages: read"}, | |||
| 340 | + | {"none and id-token are not listed, metadata always is", map[string]string{"contents": "none", "id-token": "write", "actions": "read"}, | |||
| 341 | + | "Actions: read\nMetadata: read"}, | |||
| 342 | + | {"nothing at all is metadata only", map[string]string{}, "Metadata: read"}, | |||
| 343 | + | {"a key the runner does not know", map[string]string{"made-up-key": "read"}, "MadeUpKey: read\nMetadata: read"}, | |||
| 344 | + | } { | |||
| 345 | + | got := group(setupLog(t, yaml, "j", func(c *Config) { c.TokenPermissions = tc.levels })) | |||
| 346 | + | if got != tc.want { | |||
| 347 | + | t.Errorf("%s:\n%s\nwant:\n%s", tc.name, got, tc.want) | |||
| 348 | + | } | |||
| 349 | + | } | |||
| 350 | + | // A server that sends none: worked out from the workflow, as before. | |||
| 351 | + | got := group(setupLog(t, yaml, "j", nil)) | |||
| 352 | + | if !strings.Contains(got, "Contents: write") || !strings.Contains(got, "Models: read") { | |||
| 353 | + | t.Errorf("fallback to the workflow:\n%s", got) | |||
| 354 | + | } | |||
| 355 | + | } | |||
M internal/executor/token_permissions.go +35 -0
| @@ -4,6 +4,7 @@ package executor | |||
| 4 | 4 | ||
| 5 | 5 | import ( | |
| 6 | 6 | "sort" | |
| 7 | + | "strings" | |
| 7 | 8 | ||
| 8 | 9 | "bnema.dev/ermite-actions/workflow" | |
| 9 | 10 | ) | |
| @@ -106,3 +107,37 @@ func tokenPermissionLines(wf *workflow.Workflow, jb *workflow.Job) []permissionL | |||
| 106 | 107 | sort.Slice(lines, func(a, b int) bool { return lines[a].name < lines[b].name }) | |
| 107 | 108 | return lines | |
| 108 | 109 | } | |
| 110 | + | ||
| 111 | + | // serverPermissionLines returns the lines of the group for the permissions the | |
| 112 | + | // server sent (Job.permissions): one per key at "read" or "write", sorted by | |
| 113 | + | // display name like GitHub's runner prints them. Metadata is always listed as | |
| 114 | + | // read. A key at "none" or absent is not listed, nor is id-token (GitHub never | |
| 115 | + | // lists it); a key the runner does not know is listed under its name in Pascal | |
| 116 | + | // case, as the known ones are ("pull-requests" is "PullRequests"). | |
| 117 | + | func serverPermissionLines(levels map[string]string) []permissionLine { | |
| 118 | + | lines := []permissionLine{{"Metadata", "read"}} | |
| 119 | + | for key, level := range levels { | |
| 120 | + | if (level != "read" && level != "write") || key == "metadata" || key == "id-token" { | |
| 121 | + | continue | |
| 122 | + | } | |
| 123 | + | lines = append(lines, permissionLine{displayName(key), level}) | |
| 124 | + | } | |
| 125 | + | sort.Slice(lines, func(a, b int) bool { return lines[a].name < lines[b].name }) | |
| 126 | + | return lines | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // displayName is the name "Set up job" prints for a permission key. | |
| 130 | + | func displayName(key string) string { | |
| 131 | + | for _, s := range tokenScopes { | |
| 132 | + | if s.key == key { | |
| 133 | + | return s.display | |
| 134 | + | } | |
| 135 | + | } | |
| 136 | + | var b strings.Builder | |
| 137 | + | for _, part := range strings.Split(key, "-") { | |
| 138 | + | if part != "" { | |
| 139 | + | b.WriteString(strings.ToUpper(part[:1]) + part[1:]) | |
| 140 | + | } | |
| 141 | + | } | |
| 142 | + | return b.String() | |
| 143 | + | } | |
| @@ -4,6 +4,7 @@ package executor | |||||
| 4 | 4 | ||||
| 5 | import ( | 5 | import ( | ||
| 6 | "sort" | 6 | "sort" | ||
| 7 | + | "strings" | |||
| 7 | 8 | ||||
| 8 | "bnema.dev/ermite-actions/workflow" | 9 | "bnema.dev/ermite-actions/workflow" | ||
| 9 | ) | 10 | ) | ||
| @@ -106,3 +107,37 @@ func tokenPermissionLines(wf *workflow.Workflow, jb *workflow.Job) []permissionL | |||||
| 106 | sort.Slice(lines, func(a, b int) bool { return lines[a].name < lines[b].name }) | 107 | sort.Slice(lines, func(a, b int) bool { return lines[a].name < lines[b].name }) | ||
| 107 | return lines | 108 | return lines | ||
| 108 | } | 109 | } | ||
| 110 | + | ||||
| 111 | + | // serverPermissionLines returns the lines of the group for the permissions the | |||
| 112 | + | // server sent (Job.permissions): one per key at "read" or "write", sorted by | |||
| 113 | + | // display name like GitHub's runner prints them. Metadata is always listed as | |||
| 114 | + | // read. A key at "none" or absent is not listed, nor is id-token (GitHub never | |||
| 115 | + | // lists it); a key the runner does not know is listed under its name in Pascal | |||
| 116 | + | // case, as the known ones are ("pull-requests" is "PullRequests"). | |||
| 117 | + | func serverPermissionLines(levels map[string]string) []permissionLine { | |||
| 118 | + | lines := []permissionLine{{"Metadata", "read"}} | |||
| 119 | + | for key, level := range levels { | |||
| 120 | + | if (level != "read" && level != "write") || key == "metadata" || key == "id-token" { | |||
| 121 | + | continue | |||
| 122 | + | } | |||
| 123 | + | lines = append(lines, permissionLine{displayName(key), level}) | |||
| 124 | + | } | |||
| 125 | + | sort.Slice(lines, func(a, b int) bool { return lines[a].name < lines[b].name }) | |||
| 126 | + | return lines | |||
| 127 | + | } | |||
| 128 | + | ||||
| 129 | + | // displayName is the name "Set up job" prints for a permission key. | |||
| 130 | + | func displayName(key string) string { | |||
| 131 | + | for _, s := range tokenScopes { | |||
| 132 | + | if s.key == key { | |||
| 133 | + | return s.display | |||
| 134 | + | } | |||
| 135 | + | } | |||
| 136 | + | var b strings.Builder | |||
| 137 | + | for _, part := range strings.Split(key, "-") { | |||
| 138 | + | if part != "" { | |||
| 139 | + | b.WriteString(strings.ToUpper(part[:1]) + part[1:]) | |||
| 140 | + | } | |||
| 141 | + | } | |||
| 142 | + | return b.String() | |||
| 143 | + | } | |||
M internal/guest/jobexec.go +14 -1
| @@ -259,7 +259,7 @@ func runJob(ctx context.Context, conn *execstream.Conn, cfg ExecConfig, spec *ex | |||
| 259 | 259 | Home: su.Home, ToolCache: os.Getenv("RUNNER_TOOL_CACHE"), BaseEnv: stepEnv(os.Environ(), su), Credential: su.Credential, | |
| 260 | 260 | CacheURL: cacheURL(os.Getenv("ERMITE_GATEWAY"), spec.GetCachePort()), CacheToken: spec.GetCacheToken(), | |
| 261 | 261 | Debug: spec.GetDebug(), Reporter: rep, Actions: executor.DefaultActionsConfig(res.resolve), Log: zerowrap.FromCtx(ctx), | |
| 262 | - | Secrets: vals.secrets, Vars: vals.vars, SecretsWithheld: spec.GetSecretsWithheld(), | |
| 262 | + | Secrets: vals.secrets, Vars: vals.vars, SecretsWithheld: spec.GetSecretsWithheld(), TokenPermissions: tokenPermissions(spec), | |
| 263 | 263 | SendAnnotations: spec.GetSendAnnotations(), SendSummaries: spec.GetSendSummaries(), | |
| 264 | 264 | TermAfter: cfg.TermAfter, KillAfter: cfg.KillAfter, WaitDelay: cfg.WaitDelay, | |
| 265 | 265 | }) | |
| @@ -290,3 +290,16 @@ func failSetup(conn *execstream.Conn, msg string) int { | |||
| 290 | 290 | rep.JobCompleted(executor.Result{Conclusion: executor.ConclusionFailure, Error: msg}) | |
| 291 | 291 | return 1 | |
| 292 | 292 | } | |
| 293 | + | ||
| 294 | + | // tokenPermissions is the permissions of GITHUB_TOKEN the server sent, nil when | |
| 295 | + | // it sent none (the executor then works them out from the workflow). | |
| 296 | + | func tokenPermissions(spec *execpb.JobSpec) map[string]string { | |
| 297 | + | p := spec.GetTokenPermissions() | |
| 298 | + | if p == nil { | |
| 299 | + | return nil | |
| 300 | + | } | |
| 301 | + | if p.GetLevels() == nil { | |
| 302 | + | return map[string]string{} | |
| 303 | + | } | |
| 304 | + | return p.GetLevels() | |
| 305 | + | } | |
| @@ -259,7 +259,7 @@ func runJob(ctx context.Context, conn *execstream.Conn, cfg ExecConfig, spec *ex | |||||
| 259 | Home: su.Home, ToolCache: os.Getenv("RUNNER_TOOL_CACHE"), BaseEnv: stepEnv(os.Environ(), su), Credential: su.Credential, | 259 | Home: su.Home, ToolCache: os.Getenv("RUNNER_TOOL_CACHE"), BaseEnv: stepEnv(os.Environ(), su), Credential: su.Credential, | ||
| 260 | CacheURL: cacheURL(os.Getenv("ERMITE_GATEWAY"), spec.GetCachePort()), CacheToken: spec.GetCacheToken(), | 260 | CacheURL: cacheURL(os.Getenv("ERMITE_GATEWAY"), spec.GetCachePort()), CacheToken: spec.GetCacheToken(), | ||
| 261 | Debug: spec.GetDebug(), Reporter: rep, Actions: executor.DefaultActionsConfig(res.resolve), Log: zerowrap.FromCtx(ctx), | 261 | Debug: spec.GetDebug(), Reporter: rep, Actions: executor.DefaultActionsConfig(res.resolve), Log: zerowrap.FromCtx(ctx), | ||
| 262 | - | Secrets: vals.secrets, Vars: vals.vars, SecretsWithheld: spec.GetSecretsWithheld(), | 262 | + | Secrets: vals.secrets, Vars: vals.vars, SecretsWithheld: spec.GetSecretsWithheld(), TokenPermissions: tokenPermissions(spec), |
| 263 | SendAnnotations: spec.GetSendAnnotations(), SendSummaries: spec.GetSendSummaries(), | 263 | SendAnnotations: spec.GetSendAnnotations(), SendSummaries: spec.GetSendSummaries(), | ||
| 264 | TermAfter: cfg.TermAfter, KillAfter: cfg.KillAfter, WaitDelay: cfg.WaitDelay, | 264 | TermAfter: cfg.TermAfter, KillAfter: cfg.KillAfter, WaitDelay: cfg.WaitDelay, | ||
| 265 | }) | 265 | }) | ||
| @@ -290,3 +290,16 @@ func failSetup(conn *execstream.Conn, msg string) int { | |||||
| 290 | rep.JobCompleted(executor.Result{Conclusion: executor.ConclusionFailure, Error: msg}) | 290 | rep.JobCompleted(executor.Result{Conclusion: executor.ConclusionFailure, Error: msg}) | ||
| 291 | return 1 | 291 | return 1 | ||
| 292 | } | 292 | } | ||
| 293 | + | ||||
| 294 | + | // tokenPermissions is the permissions of GITHUB_TOKEN the server sent, nil when | |||
| 295 | + | // it sent none (the executor then works them out from the workflow). | |||
| 296 | + | func tokenPermissions(spec *execpb.JobSpec) map[string]string { | |||
| 297 | + | p := spec.GetTokenPermissions() | |||
| 298 | + | if p == nil { | |||
| 299 | + | return nil | |||
| 300 | + | } | |||
| 301 | + | if p.GetLevels() == nil { | |||
| 302 | + | return map[string]string{} | |||
| 303 | + | } | |||
| 304 | + | return p.GetLevels() | |||
| 305 | + | } | |||
M internal/guest/jobexec_test.go +85 -2
| @@ -13,12 +13,20 @@ import ( | |||
| 13 | 13 | "testing" | |
| 14 | 14 | "time" | |
| 15 | 15 | ||
| 16 | + | "google.golang.org/protobuf/proto" | |
| 17 | + | ||
| 16 | 18 | "bnema.dev/ermite-runner/internal/execstream" | |
| 17 | 19 | "bnema.dev/ermite-runner/internal/execstream/execpb" | |
| 18 | 20 | ) | |
| 19 | 21 | ||
| 20 | 22 | // runJobSession starts Exec on a unix socket and drives it with a job. | |
| 21 | 23 | func runJobSession(t *testing.T, yaml string, cancelOn string, tweak func(*ExecConfig)) (steps []string, logs []*execpb.Log, res *execpb.JobResult, exit *execpb.Exit) { | |
| 24 | + | t.Helper() | |
| 25 | + | return runJobSessionSpec(t, yaml, cancelOn, tweak, nil) | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | // runJobSessionSpec is runJobSession with a change to the JobSpec sent. | |
| 29 | + | func runJobSessionSpec(t *testing.T, yaml string, cancelOn string, tweak func(*ExecConfig), spec func(*execpb.JobSpec)) (steps []string, logs []*execpb.Log, res *execpb.JobResult, exit *execpb.Exit) { | |
| 22 | 30 | t.Helper() | |
| 23 | 31 | sock := filepath.Join(t.TempDir(), "s") | |
| 24 | 32 | ln, err := net.Listen("unix", sock) | |
| @@ -53,10 +61,14 @@ func runJobSession(t *testing.T, yaml string, cancelOn string, tweak func(*ExecC | |||
| 53 | 61 | } | |
| 54 | 62 | var cancelOnce sync.Once | |
| 55 | 63 | var mu sync.Mutex | |
| 56 | - | _, exit, err = execstream.DriveJob(conn, &execpb.Run{Job: &execpb.JobSpec{ | |
| 64 | + | js := &execpb.JobSpec{ | |
| 57 | 65 | WorkflowPath: ".github/workflows/ci.yml", WorkflowYaml: yaml, JobKey: "j", Repo: "hello", RunnerName: "r", RunnerVersion: "v", | |
| 58 | 66 | Contexts: `{"github":{"repository":"octo/hello","event_name":"push","job":"j"}}`, Matrix: "{}", | |
| 59 | - | }}, cancel, execstream.JobHandler{ | |
| 67 | + | } | |
| 68 | + | if spec != nil { | |
| 69 | + | spec(js) | |
| 70 | + | } | |
| 71 | + | _, exit, err = execstream.DriveJob(conn, &execpb.Run{Job: js}, cancel, execstream.JobHandler{ | |
| 60 | 72 | StepStarted: func(s *execpb.StepStarted) { | |
| 61 | 73 | mu.Lock() | |
| 62 | 74 | steps = append(steps, s.Name) | |
| @@ -331,3 +343,74 @@ func TestExecSendsResultsFrames(t *testing.T) { | |||
| 331 | 343 | } | |
| 332 | 344 | } | |
| 333 | 345 | } | |
| 346 | + | ||
| 347 | + | // The permissions the server sent reach "Set up job" through the Run frame as | |
| 348 | + | // the guest reads them: absent keeps the workflow's, present but empty is | |
| 349 | + | // "Metadata only", populated is printed as sent. The frame is marshalled and | |
| 350 | + | // parsed on the way, where a nil and an empty map would look alike. | |
| 351 | + | func TestExecJobPrintsTheServersTokenPermissions(t *testing.T) { | |
| 352 | + | requireBash(t) | |
| 353 | + | yaml := "on: push\npermissions: write-all\njobs:\n j:\n runs-on: x\n steps:\n - run: echo hi\n" | |
| 354 | + | group := func(logs []*execpb.Log) string { | |
| 355 | + | var lines []string | |
| 356 | + | in := false | |
| 357 | + | for _, l := range logs { | |
| 358 | + | switch { | |
| 359 | + | case l.Text == "##[group]GITHUB_TOKEN Permissions": | |
| 360 | + | in = true | |
| 361 | + | case l.Text == "##[endgroup]": | |
| 362 | + | in = false | |
| 363 | + | case in: | |
| 364 | + | lines = append(lines, l.Text) | |
| 365 | + | } | |
| 366 | + | } | |
| 367 | + | return strings.Join(lines, "\n") | |
| 368 | + | } | |
| 369 | + | for _, tc := range []struct { | |
| 370 | + | name string | |
| 371 | + | set func(*execpb.JobSpec) | |
| 372 | + | want string | |
| 373 | + | }{ | |
| 374 | + | {"absent: from the workflow", nil, "Actions: write\nArtifactMetadata: write\nAttestations: write\nChecks: write\nCodeQuality: write\nContents: write\n" + | |
| 375 | + | "CopilotRequests: write\nDeployments: write\nDiscussions: write\nDrives: write\nIssues: write\nMetadata: read\nModels: read\nPackages: write\n" + | |
| 376 | + | "Pages: write\nPullRequests: write\nRepositoryProjects: write\nSecurityEvents: write\nStatuses: write\nVulnerabilityAlerts: read"}, | |
| 377 | + | {"present and empty: metadata only", func(s *execpb.JobSpec) { s.TokenPermissions = &execpb.TokenPermissions{} }, "Metadata: read"}, | |
| 378 | + | {"populated: as sent", func(s *execpb.JobSpec) { | |
| 379 | + | s.TokenPermissions = &execpb.TokenPermissions{Levels: map[string]string{"contents": "read", "issues": "none"}} | |
| 380 | + | }, "Contents: read\nMetadata: read"}, | |
| 381 | + | } { | |
| 382 | + | _, logs, res, _ := runJobSessionSpec(t, yaml, "", nil, tc.set) | |
| 383 | + | if res == nil || res.Conclusion != execpb.StepConclusion_STEP_CONCLUSION_SUCCESS { | |
| 384 | + | t.Fatalf("%s: %+v", tc.name, res) | |
| 385 | + | } | |
| 386 | + | if got := group(logs); got != tc.want { | |
| 387 | + | t.Errorf("%s:\n%s\nwant:\n%s", tc.name, got, tc.want) | |
| 388 | + | } | |
| 389 | + | } | |
| 390 | + | } | |
| 391 | + | ||
| 392 | + | func TestTokenPermissionsNilVersusEmpty(t *testing.T) { | |
| 393 | + | for name, tc := range map[string]struct { | |
| 394 | + | spec *execpb.JobSpec | |
| 395 | + | wantNil bool | |
| 396 | + | want int | |
| 397 | + | }{ | |
| 398 | + | "absent": {&execpb.JobSpec{}, true, 0}, | |
| 399 | + | "empty": {&execpb.JobSpec{TokenPermissions: &execpb.TokenPermissions{}}, false, 0}, | |
| 400 | + | "populated": {&execpb.JobSpec{TokenPermissions: &execpb.TokenPermissions{Levels: map[string]string{"contents": "read"}}}, false, 1}, | |
| 401 | + | } { | |
| 402 | + | // After the trip a frame makes. | |
| 403 | + | raw, err := proto.Marshal(tc.spec) | |
| 404 | + | if err != nil { | |
| 405 | + | t.Fatal(err) | |
| 406 | + | } | |
| 407 | + | var got execpb.JobSpec | |
| 408 | + | if err := proto.Unmarshal(raw, &got); err != nil { | |
| 409 | + | t.Fatal(err) | |
| 410 | + | } | |
| 411 | + | m := tokenPermissions(&got) | |
| 412 | + | if (m == nil) != tc.wantNil || len(m) != tc.want { | |
| 413 | + | t.Errorf("%s: %#v", name, m) | |
| 414 | + | } | |
| 415 | + | } | |
| 416 | + | } | |
| @@ -13,12 +13,20 @@ import ( | |||||
| 13 | "testing" | 13 | "testing" | ||
| 14 | "time" | 14 | "time" | ||
| 15 | 15 | ||||
| 16 | + | "google.golang.org/protobuf/proto" | |||
| 17 | + | ||||
| 16 | "bnema.dev/ermite-runner/internal/execstream" | 18 | "bnema.dev/ermite-runner/internal/execstream" | ||
| 17 | "bnema.dev/ermite-runner/internal/execstream/execpb" | 19 | "bnema.dev/ermite-runner/internal/execstream/execpb" | ||
| 18 | ) | 20 | ) | ||
| 19 | 21 | ||||
| 20 | // runJobSession starts Exec on a unix socket and drives it with a job. | 22 | // runJobSession starts Exec on a unix socket and drives it with a job. | ||
| 21 | func runJobSession(t *testing.T, yaml string, cancelOn string, tweak func(*ExecConfig)) (steps []string, logs []*execpb.Log, res *execpb.JobResult, exit *execpb.Exit) { | 23 | func runJobSession(t *testing.T, yaml string, cancelOn string, tweak func(*ExecConfig)) (steps []string, logs []*execpb.Log, res *execpb.JobResult, exit *execpb.Exit) { | ||
| 24 | + | t.Helper() | |||
| 25 | + | return runJobSessionSpec(t, yaml, cancelOn, tweak, nil) | |||
| 26 | + | } | |||
| 27 | + | ||||
| 28 | + | // runJobSessionSpec is runJobSession with a change to the JobSpec sent. | |||
| 29 | + | func runJobSessionSpec(t *testing.T, yaml string, cancelOn string, tweak func(*ExecConfig), spec func(*execpb.JobSpec)) (steps []string, logs []*execpb.Log, res *execpb.JobResult, exit *execpb.Exit) { | |||
| 22 | t.Helper() | 30 | t.Helper() | ||
| 23 | sock := filepath.Join(t.TempDir(), "s") | 31 | sock := filepath.Join(t.TempDir(), "s") | ||
| 24 | ln, err := net.Listen("unix", sock) | 32 | ln, err := net.Listen("unix", sock) | ||
| @@ -53,10 +61,14 @@ func runJobSession(t *testing.T, yaml string, cancelOn string, tweak func(*ExecC | |||||
| 53 | } | 61 | } | ||
| 54 | var cancelOnce sync.Once | 62 | var cancelOnce sync.Once | ||
| 55 | var mu sync.Mutex | 63 | var mu sync.Mutex | ||
| 56 | - | _, exit, err = execstream.DriveJob(conn, &execpb.Run{Job: &execpb.JobSpec{ | 64 | + | js := &execpb.JobSpec{ |
| 57 | WorkflowPath: ".github/workflows/ci.yml", WorkflowYaml: yaml, JobKey: "j", Repo: "hello", RunnerName: "r", RunnerVersion: "v", | 65 | WorkflowPath: ".github/workflows/ci.yml", WorkflowYaml: yaml, JobKey: "j", Repo: "hello", RunnerName: "r", RunnerVersion: "v", | ||
| 58 | Contexts: `{"github":{"repository":"octo/hello","event_name":"push","job":"j"}}`, Matrix: "{}", | 66 | Contexts: `{"github":{"repository":"octo/hello","event_name":"push","job":"j"}}`, Matrix: "{}", | ||
| 59 | - | }}, cancel, execstream.JobHandler{ | 67 | + | } |
| 68 | + | if spec != nil { | |||
| 69 | + | spec(js) | |||
| 70 | + | } | |||
| 71 | + | _, exit, err = execstream.DriveJob(conn, &execpb.Run{Job: js}, cancel, execstream.JobHandler{ | |||
| 60 | StepStarted: func(s *execpb.StepStarted) { | 72 | StepStarted: func(s *execpb.StepStarted) { | ||
| 61 | mu.Lock() | 73 | mu.Lock() | ||
| 62 | steps = append(steps, s.Name) | 74 | steps = append(steps, s.Name) | ||
| @@ -331,3 +343,74 @@ func TestExecSendsResultsFrames(t *testing.T) { | |||||
| 331 | } | 343 | } | ||
| 332 | } | 344 | } | ||
| 333 | } | 345 | } | ||
| 346 | + | ||||
| 347 | + | // The permissions the server sent reach "Set up job" through the Run frame as | |||
| 348 | + | // the guest reads them: absent keeps the workflow's, present but empty is | |||
| 349 | + | // "Metadata only", populated is printed as sent. The frame is marshalled and | |||
| 350 | + | // parsed on the way, where a nil and an empty map would look alike. | |||
| 351 | + | func TestExecJobPrintsTheServersTokenPermissions(t *testing.T) { | |||
| 352 | + | requireBash(t) | |||
| 353 | + | yaml := "on: push\npermissions: write-all\njobs:\n j:\n runs-on: x\n steps:\n - run: echo hi\n" | |||
| 354 | + | group := func(logs []*execpb.Log) string { | |||
| 355 | + | var lines []string | |||
| 356 | + | in := false | |||
| 357 | + | for _, l := range logs { | |||
| 358 | + | switch { | |||
| 359 | + | case l.Text == "##[group]GITHUB_TOKEN Permissions": | |||
| 360 | + | in = true | |||
| 361 | + | case l.Text == "##[endgroup]": | |||
| 362 | + | in = false | |||
| 363 | + | case in: | |||
| 364 | + | lines = append(lines, l.Text) | |||
| 365 | + | } | |||
| 366 | + | } | |||
| 367 | + | return strings.Join(lines, "\n") | |||
| 368 | + | } | |||
| 369 | + | for _, tc := range []struct { | |||
| 370 | + | name string | |||
| 371 | + | set func(*execpb.JobSpec) | |||
| 372 | + | want string | |||
| 373 | + | }{ | |||
| 374 | + | {"absent: from the workflow", nil, "Actions: write\nArtifactMetadata: write\nAttestations: write\nChecks: write\nCodeQuality: write\nContents: write\n" + | |||
| 375 | + | "CopilotRequests: write\nDeployments: write\nDiscussions: write\nDrives: write\nIssues: write\nMetadata: read\nModels: read\nPackages: write\n" + | |||
| 376 | + | "Pages: write\nPullRequests: write\nRepositoryProjects: write\nSecurityEvents: write\nStatuses: write\nVulnerabilityAlerts: read"}, | |||
| 377 | + | {"present and empty: metadata only", func(s *execpb.JobSpec) { s.TokenPermissions = &execpb.TokenPermissions{} }, "Metadata: read"}, | |||
| 378 | + | {"populated: as sent", func(s *execpb.JobSpec) { | |||
| 379 | + | s.TokenPermissions = &execpb.TokenPermissions{Levels: map[string]string{"contents": "read", "issues": "none"}} | |||
| 380 | + | }, "Contents: read\nMetadata: read"}, | |||
| 381 | + | } { | |||
| 382 | + | _, logs, res, _ := runJobSessionSpec(t, yaml, "", nil, tc.set) | |||
| 383 | + | if res == nil || res.Conclusion != execpb.StepConclusion_STEP_CONCLUSION_SUCCESS { | |||
| 384 | + | t.Fatalf("%s: %+v", tc.name, res) | |||
| 385 | + | } | |||
| 386 | + | if got := group(logs); got != tc.want { | |||
| 387 | + | t.Errorf("%s:\n%s\nwant:\n%s", tc.name, got, tc.want) | |||
| 388 | + | } | |||
| 389 | + | } | |||
| 390 | + | } | |||
| 391 | + | ||||
| 392 | + | func TestTokenPermissionsNilVersusEmpty(t *testing.T) { | |||
| 393 | + | for name, tc := range map[string]struct { | |||
| 394 | + | spec *execpb.JobSpec | |||
| 395 | + | wantNil bool | |||
| 396 | + | want int | |||
| 397 | + | }{ | |||
| 398 | + | "absent": {&execpb.JobSpec{}, true, 0}, | |||
| 399 | + | "empty": {&execpb.JobSpec{TokenPermissions: &execpb.TokenPermissions{}}, false, 0}, | |||
| 400 | + | "populated": {&execpb.JobSpec{TokenPermissions: &execpb.TokenPermissions{Levels: map[string]string{"contents": "read"}}}, false, 1}, | |||
| 401 | + | } { | |||
| 402 | + | // After the trip a frame makes. | |||
| 403 | + | raw, err := proto.Marshal(tc.spec) | |||
| 404 | + | if err != nil { | |||
| 405 | + | t.Fatal(err) | |||
| 406 | + | } | |||
| 407 | + | var got execpb.JobSpec | |||
| 408 | + | if err := proto.Unmarshal(raw, &got); err != nil { | |||
| 409 | + | t.Fatal(err) | |||
| 410 | + | } | |||
| 411 | + | m := tokenPermissions(&got) | |||
| 412 | + | if (m == nil) != tc.wantNil || len(m) != tc.want { | |||
| 413 | + | t.Errorf("%s: %#v", name, m) | |||
| 414 | + | } | |||
| 415 | + | } | |||
| 416 | + | } | |||
M internal/host/job.go +3 -0
| @@ -697,6 +697,9 @@ func (j *jobRun) drive(conn sandbox.Conn, rt *Runner) (*execpb.Exit, error) { | |||
| 697 | 697 | // only when the server has ci.secrets. | |
| 698 | 698 | SecretsWithheld: j.features.secrets && !j.job.Trusted, | |
| 699 | 699 | }} | |
| 700 | + | if p := j.job.Permissions; p != nil && j.features.secrets { | |
| 701 | + | run.Job.TokenPermissions = &execpb.TokenPermissions{Levels: p.GetLevels()} | |
| 702 | + | } | |
| 700 | 703 | run.Job.CachePort, run.Job.CacheToken = j.cacheFor(rt) | |
| 701 | 704 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | |
| 702 | 705 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | |
| @@ -697,6 +697,9 @@ func (j *jobRun) drive(conn sandbox.Conn, rt *Runner) (*execpb.Exit, error) { | |||||
| 697 | // only when the server has ci.secrets. | 697 | // only when the server has ci.secrets. | ||
| 698 | SecretsWithheld: j.features.secrets && !j.job.Trusted, | 698 | SecretsWithheld: j.features.secrets && !j.job.Trusted, | ||
| 699 | }} | 699 | }} | ||
| 700 | + | if p := j.job.Permissions; p != nil && j.features.secrets { | |||
| 701 | + | run.Job.TokenPermissions = &execpb.TokenPermissions{Levels: p.GetLevels()} | |||
| 702 | + | } | |||
| 700 | run.Job.CachePort, run.Job.CacheToken = j.cacheFor(rt) | 703 | run.Job.CachePort, run.Job.CacheToken = j.cacheFor(rt) | ||
| 701 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | 704 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | ||
| 702 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | 705 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | ||
M internal/host/secrets_test.go +47 -0
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | "go/format" | |
| 10 | 10 | "go/parser" | |
| 11 | 11 | "go/token" | |
| 12 | + | "maps" | |
| 12 | 13 | "os" | |
| 13 | 14 | "path/filepath" | |
| 14 | 15 | "regexp" | |
| @@ -17,6 +18,8 @@ import ( | |||
| 17 | 18 | ||
| 18 | 19 | "google.golang.org/protobuf/proto" | |
| 19 | 20 | ||
| 21 | + | ermite "bnema.dev/ermite-api/gen/ermite" | |
| 22 | + | ||
| 20 | 23 | "bnema.dev/ermite-runner/internal/execstream/execpb" | |
| 21 | 24 | ) | |
| 22 | 25 | ||
| @@ -300,3 +303,47 @@ func TestPrintLeaksHeuristic(t *testing.T) { | |||
| 300 | 303 | } | |
| 301 | 304 | } | |
| 302 | 305 | } | |
| 306 | + | ||
| 307 | + | // Job.permissions reaches the executor in the Run frame when the server has | |
| 308 | + | // ci.secrets (it sent them); an old server's absent field stays unset, so that | |
| 309 | + | // the executor works them out from the workflow. | |
| 310 | + | func TestTokenPermissionsReachTheExecutor(t *testing.T) { | |
| 311 | + | for _, tc := range []struct { | |
| 312 | + | name string | |
| 313 | + | features []string | |
| 314 | + | perms *ermite.JobPermissions | |
| 315 | + | want map[string]string // nil: unset in the frame | |
| 316 | + | }{ | |
| 317 | + | {"sent", []string{FeatureSecrets}, &ermite.JobPermissions{Levels: map[string]string{"contents": "write", "metadata": "read"}}, | |
| 318 | + | map[string]string{"contents": "write", "metadata": "read"}}, | |
| 319 | + | {"sent and empty", []string{FeatureSecrets}, &ermite.JobPermissions{}, map[string]string{}}, | |
| 320 | + | {"not sent", []string{FeatureSecrets}, nil, nil}, | |
| 321 | + | {"old server", []string{FeatureAnnotations}, &ermite.JobPermissions{Levels: map[string]string{"contents": "write"}}, nil}, | |
| 322 | + | } { | |
| 323 | + | t.Run(tc.name, func(t *testing.T) { | |
| 324 | + | seenRun.Store(nil) | |
| 325 | + | h := newHarness(t, resultsScript(nil)) | |
| 326 | + | h.runner.Cfg.StateDir = t.TempDir() | |
| 327 | + | h.runner.Features = func(context.Context) ([]string, error) { return tc.features, nil } | |
| 328 | + | j := testJob("j1") | |
| 329 | + | j.Permissions = tc.perms | |
| 330 | + | h.srv.jobs = []*ermite.Job{j} | |
| 331 | + | stop := h.run(t) | |
| 332 | + | eventually(t, "CompleteJob", func() bool { return h.srv.completeCount() == 1 }) | |
| 333 | + | if err := stop(); err != nil { | |
| 334 | + | t.Fatal(err) | |
| 335 | + | } | |
| 336 | + | run := seenRun.Load() | |
| 337 | + | if run == nil { | |
| 338 | + | t.Fatal("no Run frame") | |
| 339 | + | } | |
| 340 | + | got := run.Job.GetTokenPermissions() | |
| 341 | + | switch { | |
| 342 | + | case tc.want == nil && got != nil: | |
| 343 | + | t.Errorf("unexpected permissions %v", got.GetLevels()) | |
| 344 | + | case tc.want != nil && (got == nil || !maps.Equal(got.GetLevels(), tc.want)): | |
| 345 | + | t.Errorf("permissions %v, want %v", got.GetLevels(), tc.want) | |
| 346 | + | } | |
| 347 | + | }) | |
| 348 | + | } | |
| 349 | + | } | |
| @@ -9,6 +9,7 @@ import ( | |||||
| 9 | "go/format" | 9 | "go/format" | ||
| 10 | "go/parser" | 10 | "go/parser" | ||
| 11 | "go/token" | 11 | "go/token" | ||
| 12 | + | "maps" | |||
| 12 | "os" | 13 | "os" | ||
| 13 | "path/filepath" | 14 | "path/filepath" | ||
| 14 | "regexp" | 15 | "regexp" | ||
| @@ -17,6 +18,8 @@ import ( | |||||
| 17 | 18 | ||||
| 18 | "google.golang.org/protobuf/proto" | 19 | "google.golang.org/protobuf/proto" | ||
| 19 | 20 | ||||
| 21 | + | ermite "bnema.dev/ermite-api/gen/ermite" | |||
| 22 | + | ||||
| 20 | "bnema.dev/ermite-runner/internal/execstream/execpb" | 23 | "bnema.dev/ermite-runner/internal/execstream/execpb" | ||
| 21 | ) | 24 | ) | ||
| 22 | 25 | ||||
| @@ -300,3 +303,47 @@ func TestPrintLeaksHeuristic(t *testing.T) { | |||||
| 300 | } | 303 | } | ||
| 301 | } | 304 | } | ||
| 302 | } | 305 | } | ||
| 306 | + | ||||
| 307 | + | // Job.permissions reaches the executor in the Run frame when the server has | |||
| 308 | + | // ci.secrets (it sent them); an old server's absent field stays unset, so that | |||
| 309 | + | // the executor works them out from the workflow. | |||
| 310 | + | func TestTokenPermissionsReachTheExecutor(t *testing.T) { | |||
| 311 | + | for _, tc := range []struct { | |||
| 312 | + | name string | |||
| 313 | + | features []string | |||
| 314 | + | perms *ermite.JobPermissions | |||
| 315 | + | want map[string]string // nil: unset in the frame | |||
| 316 | + | }{ | |||
| 317 | + | {"sent", []string{FeatureSecrets}, &ermite.JobPermissions{Levels: map[string]string{"contents": "write", "metadata": "read"}}, | |||
| 318 | + | map[string]string{"contents": "write", "metadata": "read"}}, | |||
| 319 | + | {"sent and empty", []string{FeatureSecrets}, &ermite.JobPermissions{}, map[string]string{}}, | |||
| 320 | + | {"not sent", []string{FeatureSecrets}, nil, nil}, | |||
| 321 | + | {"old server", []string{FeatureAnnotations}, &ermite.JobPermissions{Levels: map[string]string{"contents": "write"}}, nil}, | |||
| 322 | + | } { | |||
| 323 | + | t.Run(tc.name, func(t *testing.T) { | |||
| 324 | + | seenRun.Store(nil) | |||
| 325 | + | h := newHarness(t, resultsScript(nil)) | |||
| 326 | + | h.runner.Cfg.StateDir = t.TempDir() | |||
| 327 | + | h.runner.Features = func(context.Context) ([]string, error) { return tc.features, nil } | |||
| 328 | + | j := testJob("j1") | |||
| 329 | + | j.Permissions = tc.perms | |||
| 330 | + | h.srv.jobs = []*ermite.Job{j} | |||
| 331 | + | stop := h.run(t) | |||
| 332 | + | eventually(t, "CompleteJob", func() bool { return h.srv.completeCount() == 1 }) | |||
| 333 | + | if err := stop(); err != nil { | |||
| 334 | + | t.Fatal(err) | |||
| 335 | + | } | |||
| 336 | + | run := seenRun.Load() | |||
| 337 | + | if run == nil { | |||
| 338 | + | t.Fatal("no Run frame") | |||
| 339 | + | } | |||
| 340 | + | got := run.Job.GetTokenPermissions() | |||
| 341 | + | switch { | |||
| 342 | + | case tc.want == nil && got != nil: | |||
| 343 | + | t.Errorf("unexpected permissions %v", got.GetLevels()) | |||
| 344 | + | case tc.want != nil && (got == nil || !maps.Equal(got.GetLevels(), tc.want)): | |||
| 345 | + | t.Errorf("permissions %v, want %v", got.GetLevels(), tc.want) | |||
| 346 | + | } | |||
| 347 | + | }) | |||
| 348 | + | } | |||
| 349 | + | } | |||