mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-19 01:58:44 +08:00
feat: GHA + K8s guide improvements (#62778)
* Add IaC info alert to welcome step * Add conditional info alert to "allow any branch" input * Rename "done" button (to "finish") * Add repo restriction help text * Ensure "refs/heads/" prefix for branch input * Add code panel to Welcome step * Add `inProgress` mode to CodePanel * Shift CodePanel left on finish step * De-emphasise final button and make prior steps clearer * Explain how to apply terraform template * Improve manual label entry * Update labels field label * Enforce wildcard label * Update label values format (OR) * Explain workflows on "main branch" * Clarify prerequisites * Improve groups and users entry * Copy tweak on Configure Access step * Add groups and users validation * Add kubernetes cluster selector * Fix Terraform template tests * Move cluster select to Setup Workflow step * Tweak copy warning wording * With emphasis not clarity * Replace "setup" with "set up" * Make cluster selector async searchable * Fix lint issue * Fix lint issue (again)
This commit is contained in:
@@ -563,6 +563,7 @@ const (
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS IntegrationEnrollField = 9
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS IntegrationEnrollField = 10
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES IntegrationEnrollField = 11
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME IntegrationEnrollField = 12
|
||||
)
|
||||
|
||||
var IntegrationEnrollField_name = map[int32]string{
|
||||
@@ -578,6 +579,7 @@ var IntegrationEnrollField_name = map[int32]string{
|
||||
9: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS",
|
||||
10: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS",
|
||||
11: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES",
|
||||
12: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME",
|
||||
}
|
||||
|
||||
var IntegrationEnrollField_value = map[string]int32{
|
||||
@@ -593,6 +595,7 @@ var IntegrationEnrollField_value = map[string]int32{
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS": 9,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS": 10,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES": 11,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME": 12,
|
||||
}
|
||||
|
||||
func (x IntegrationEnrollField) String() string {
|
||||
@@ -6320,14 +6323,14 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
// 6496 bytes of a gzipped FileDescriptorProto
|
||||
// 6507 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7d, 0x5b, 0x6c, 0x1c, 0xc9,
|
||||
0x75, 0xe8, 0xf4, 0x90, 0x94, 0xc8, 0x92, 0x44, 0xb5, 0x5a, 0x12, 0x35, 0x22, 0x45, 0x3d, 0x46,
|
||||
0x6f, 0xee, 0x2e, 0xb5, 0xd2, 0x6a, 0xbd, 0xda, 0x87, 0xbd, 0xdb, 0xec, 0x69, 0xce, 0xb4, 0x38,
|
||||
0x33, 0x3d, 0x5b, 0xdd, 0x23, 0x9a, 0x6b, 0x18, 0x75, 0x9b, 0xd3, 0x45, 0xb2, 0x2f, 0x87, 0xd3,
|
||||
0xe3, 0xee, 0x1e, 0x72, 0x89, 0x0b, 0xc3, 0xbe, 0xbe, 0xf7, 0x1a, 0x17, 0xd7, 0xf6, 0x75, 0x02,
|
||||
0xe3, 0xee, 0x1e, 0x72, 0x89, 0x0b, 0xc3, 0xbe, 0xbe, 0xf7, 0x1a, 0x17, 0xd7, 0xf6, 0xb5, 0x03,
|
||||
0x24, 0x46, 0x80, 0x0d, 0xf2, 0x40, 0x1e, 0x08, 0xe0, 0x00, 0xf9, 0x32, 0xfc, 0x95, 0x8f, 0xfc,
|
||||
0x05, 0x48, 0x3e, 0x0c, 0x04, 0xc8, 0x47, 0xf2, 0x13, 0xf8, 0x2b, 0x7f, 0xfe, 0x4a, 0x80, 0xc4,
|
||||
0x05, 0x48, 0x3e, 0x02, 0x04, 0xc8, 0x47, 0xf2, 0x13, 0xf8, 0x2b, 0x7f, 0xfe, 0x4a, 0x80, 0xc4,
|
||||
0x79, 0xa1, 0x1e, 0x3d, 0xd3, 0x33, 0xd3, 0x3d, 0xdd, 0xda, 0x68, 0x63, 0x43, 0xfb, 0xc7, 0xa9,
|
||||
0x3a, 0xaf, 0x3a, 0x75, 0xea, 0x9c, 0x53, 0x55, 0xa7, 0x9a, 0xe0, 0x7e, 0x80, 0xdb, 0xb8, 0xeb,
|
||||
0x7a, 0xc1, 0x83, 0x9e, 0x6f, 0xed, 0x62, 0x7c, 0x88, 0x3b, 0x81, 0xff, 0xe0, 0xf0, 0x61, 0xf4,
|
||||
@@ -6353,14 +6356,14 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x59, 0x8f, 0xb7, 0x51, 0x8c, 0xf9, 0x47, 0xf7, 0x57, 0x13, 0x16, 0xc6, 0xea, 0x28, 0x11, 0xd8,
|
||||
0x47, 0x2d, 0xee, 0x03, 0x29, 0xec, 0x35, 0x02, 0xdc, 0x35, 0x02, 0x2b, 0xe8, 0xf9, 0xd2, 0xfb,
|
||||
0xe0, 0x84, 0x4f, 0xff, 0xe2, 0xa4, 0xef, 0xa6, 0x92, 0x66, 0x88, 0x90, 0xa3, 0x91, 0xb5, 0x84,
|
||||
0x3d, 0xcf, 0xf5, 0xf8, 0x84, 0xb2, 0x1f, 0xc5, 0xdf, 0x17, 0xc0, 0x42, 0x53, 0x8b, 0xa0, 0x78,
|
||||
0x3d, 0xcf, 0xf5, 0xf8, 0x84, 0xb2, 0x1f, 0xc5, 0xdf, 0x13, 0xc0, 0x42, 0x53, 0x8b, 0xa0, 0x78,
|
||||
0x01, 0xb6, 0x99, 0xaa, 0x54, 0x30, 0x7b, 0xc0, 0x87, 0x46, 0x79, 0x9e, 0xca, 0x30, 0x9c, 0x50,
|
||||
0x17, 0xb0, 0x8f, 0x2a, 0x29, 0x7d, 0xc1, 0xf3, 0x94, 0xc8, 0x2b, 0x19, 0x04, 0x0f, 0x47, 0x1d,
|
||||
0x0a, 0x5f, 0xfc, 0x57, 0x01, 0x5c, 0x1f, 0x88, 0x19, 0x2a, 0xcd, 0xc0, 0x6d, 0xdc, 0x22, 0x2b,
|
||||
0xe4, 0x85, 0x0a, 0x5c, 0x8b, 0x4c, 0x23, 0x13, 0xf9, 0x61, 0xe6, 0x69, 0x1c, 0x90, 0x0b, 0x49,
|
||||
0x44, 0xc6, 0x3f, 0xf5, 0xe9, 0xc7, 0xff, 0x7f, 0xf2, 0xc4, 0x09, 0x85, 0x00, 0x5a, 0x27, 0xc0,
|
||||
0xbb, 0x9e, 0x45, 0x46, 0x2e, 0x6f, 0x1a, 0xba, 0x56, 0x52, 0x14, 0xb7, 0xd3, 0xc1, 0xad, 0xe0,
|
||||
0xa5, 0xd7, 0xc3, 0x8f, 0xf3, 0x51, 0x3b, 0x28, 0x59, 0x81, 0xb5, 0x6d, 0xf9, 0x18, 0x96, 0x0c,
|
||||
0xa5, 0xd7, 0xc3, 0x4f, 0xf2, 0x51, 0x3b, 0x28, 0x59, 0x81, 0xb5, 0x6d, 0xf9, 0x18, 0x96, 0x0c,
|
||||
0xb5, 0xe3, 0xb9, 0xed, 0xf6, 0xcb, 0x3e, 0x7e, 0xe9, 0x09, 0x28, 0xf8, 0xd4, 0xe8, 0xb1, 0x8d,
|
||||
0x42, 0xca, 0x3e, 0x6a, 0xb9, 0xbd, 0x4e, 0x50, 0x98, 0xbe, 0x2e, 0xdc, 0x9b, 0x82, 0x0b, 0x61,
|
||||
0x7f, 0x28, 0x8a, 0xaf, 0x90, 0xde, 0xe2, 0x3f, 0x09, 0xe0, 0xca, 0x40, 0x73, 0x1b, 0xbd, 0x6d,
|
||||
@@ -6379,7 +6382,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x5a, 0x04, 0x0b, 0xd1, 0x7e, 0xb9, 0x26, 0x7f, 0xa4, 0xd7, 0x91, 0xaa, 0x18, 0x62, 0xbe, 0xf8,
|
||||
0xc9, 0x34, 0xb8, 0x35, 0x18, 0xbf, 0xe2, 0x61, 0x2b, 0xc0, 0xe1, 0xaf, 0x63, 0xc5, 0xed, 0xec,
|
||||
0x38, 0xbb, 0x2f, 0xbd, 0x5d, 0xba, 0xe0, 0x4c, 0x8b, 0x8e, 0x74, 0xd8, 0x2e, 0x9f, 0x66, 0x30,
|
||||
0x98, 0x64, 0x85, 0xad, 0xb2, 0xbf, 0x43, 0xfb, 0x6c, 0x45, 0x7e, 0x15, 0xff, 0x50, 0x00, 0xa7,
|
||||
0x98, 0x64, 0x85, 0xad, 0xb2, 0xbf, 0x43, 0xfb, 0x6c, 0x45, 0x7e, 0x15, 0xff, 0x40, 0x00, 0xa7,
|
||||
0xa3, 0xdd, 0xc4, 0x7a, 0x14, 0xbd, 0xbe, 0xae, 0x95, 0xe3, 0xad, 0x67, 0xac, 0x5b, 0xde, 0x34,
|
||||
0x90, 0xaa, 0x3c, 0x42, 0x86, 0x51, 0x13, 0x05, 0x32, 0xff, 0xf1, 0xdd, 0xaa, 0xa6, 0xa8, 0x62,
|
||||
0x3e, 0x1e, 0x1d, 0x96, 0x0c, 0x6a, 0x02, 0x53, 0xd2, 0x65, 0x70, 0x31, 0x06, 0x7d, 0xc3, 0x10,
|
||||
@@ -6387,7 +6390,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0xf3, 0xd1, 0xc5, 0x11, 0x0e, 0x9f, 0xcd, 0x5c, 0xcf, 0xc3, 0x35, 0xb3, 0x6a, 0xbc, 0xf4, 0x3a,
|
||||
0xf8, 0xff, 0x79, 0xf0, 0x30, 0xea, 0x20, 0xfd, 0xfd, 0xc0, 0xed, 0x92, 0x30, 0x78, 0x88, 0x4b,
|
||||
0x8e, 0x87, 0x5b, 0x81, 0xeb, 0x1d, 0x9b, 0xae, 0xdb, 0xf6, 0xb5, 0x8e, 0x1f, 0x58, 0x9f, 0x83,
|
||||
0x6c, 0xe0, 0x3b, 0x79, 0xb0, 0x9a, 0xa6, 0x90, 0xbe, 0x89, 0xbc, 0xf4, 0xda, 0xf8, 0xe3, 0x3c,
|
||||
0x6c, 0xe0, 0x3b, 0x79, 0xb0, 0x9a, 0xa6, 0x90, 0xbe, 0x89, 0xbc, 0xf4, 0xda, 0xf8, 0xa3, 0x3c,
|
||||
0xb8, 0x33, 0xd0, 0x86, 0xdc, 0x0b, 0xdc, 0xf0, 0xef, 0x48, 0x0a, 0xf9, 0xd2, 0x47, 0x90, 0xbb,
|
||||
0xe0, 0x6c, 0x7c, 0x3a, 0x3d, 0xef, 0x0d, 0xa7, 0xd1, 0xdf, 0xcc, 0x83, 0x9b, 0x03, 0x75, 0xa9,
|
||||
0xca, 0x23, 0xba, 0x6a, 0x3a, 0x9f, 0xa7, 0xbd, 0xe8, 0x3f, 0x0a, 0xe0, 0xf2, 0x68, 0xc6, 0x45,
|
||||
@@ -6397,7 +6400,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x14, 0x07, 0x8a, 0x68, 0x78, 0x4e, 0xa7, 0xe5, 0x74, 0xad, 0xb6, 0xff, 0xf9, 0x09, 0x96, 0xff,
|
||||
0x2c, 0x80, 0xe5, 0x81, 0x06, 0x4c, 0xec, 0x07, 0xfc, 0xe0, 0xed, 0xf3, 0xe0, 0xf7, 0xff, 0x41,
|
||||
0x00, 0x85, 0x88, 0x17, 0xe0, 0x17, 0x2f, 0xf6, 0x4b, 0x3f, 0xee, 0x25, 0xe2, 0xf5, 0xb9, 0xb7,
|
||||
0xc7, 0x47, 0xd0, 0x6d, 0x47, 0x2f, 0x87, 0xfe, 0x92, 0x5a, 0xc4, 0x50, 0xaf, 0x61, 0x1d, 0x46,
|
||||
0xc7, 0x47, 0xd0, 0x6d, 0x47, 0x2f, 0x87, 0xfe, 0x82, 0x5a, 0xc4, 0x50, 0xaf, 0x61, 0x1d, 0x46,
|
||||
0x2f, 0x3b, 0x6e, 0x82, 0x33, 0x24, 0x43, 0xb0, 0x2d, 0xcf, 0x46, 0x3d, 0x1f, 0xb3, 0xcb, 0x84,
|
||||
0x59, 0x78, 0x3a, 0x6c, 0x6c, 0xfa, 0xd8, 0x96, 0x96, 0xc0, 0xdc, 0xb1, 0x75, 0xd0, 0x66, 0x00,
|
||||
0x79, 0x0a, 0x30, 0x4b, 0x1a, 0x68, 0xe7, 0x1d, 0x70, 0xf6, 0xc0, 0xb5, 0x31, 0x3a, 0xda, 0xc3,
|
||||
@@ -6406,7 +6409,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x43, 0xec, 0xf9, 0x8e, 0xdb, 0x41, 0xf4, 0xac, 0xdf, 0x2f, 0x4c, 0x5f, 0x9f, 0xba, 0x37, 0x07,
|
||||
0x17, 0x19, 0xd0, 0xa6, 0x13, 0xec, 0x29, 0x7d, 0x10, 0x95, 0x42, 0x14, 0x6f, 0x90, 0xed, 0xe2,
|
||||
0xf0, 0x58, 0x49, 0x72, 0xd3, 0x8e, 0x8c, 0xf8, 0x55, 0xb0, 0x32, 0x02, 0xf2, 0xcc, 0xc1, 0x47,
|
||||
0x25, 0xb7, 0xd5, 0x3b, 0xc0, 0x9d, 0xc0, 0x1a, 0x3e, 0x5e, 0x2b, 0xfe, 0x48, 0x00, 0x17, 0x65,
|
||||
0x25, 0xb7, 0xd5, 0x3b, 0xc0, 0x9d, 0xc0, 0x1a, 0x3e, 0x5e, 0x2b, 0xfe, 0x58, 0x00, 0x17, 0x65,
|
||||
0xdf, 0x77, 0xc8, 0x4a, 0xa1, 0x06, 0xd3, 0x5f, 0x29, 0x77, 0xc1, 0x59, 0x2e, 0x21, 0xc5, 0x41,
|
||||
0xfd, 0x6b, 0x96, 0xf9, 0x68, 0xb3, 0x66, 0x4b, 0x37, 0xc0, 0xe9, 0xc0, 0x0d, 0xac, 0x36, 0x0a,
|
||||
0xdc, 0x7d, 0xdc, 0x61, 0xd7, 0x08, 0x53, 0xf0, 0x14, 0x6d, 0x33, 0x69, 0x13, 0xd1, 0x71, 0xd7,
|
||||
@@ -6415,7 +6418,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x93, 0x5b, 0xfd, 0x18, 0xb7, 0x7a, 0x9f, 0x42, 0xec, 0x65, 0x00, 0x3a, 0x64, 0xd6, 0x58, 0x36,
|
||||
0xc9, 0x84, 0x9e, 0x23, 0x2d, 0x34, 0x91, 0x1c, 0x1b, 0xd5, 0x54, 0x86, 0x51, 0x4d, 0x67, 0x1d,
|
||||
0xd5, 0x4c, 0xc2, 0xa8, 0x9e, 0x80, 0x45, 0x36, 0xa8, 0x3a, 0x3e, 0x52, 0x22, 0xe2, 0xf6, 0xef,
|
||||
0xc6, 0x5a, 0x56, 0x80, 0x77, 0x5d, 0xef, 0x38, 0xbc, 0x1b, 0x0b, 0x7f, 0x17, 0xff, 0x44, 0x00,
|
||||
0xc6, 0x5a, 0x56, 0x80, 0x77, 0x5d, 0xef, 0x38, 0xbc, 0x1b, 0x0b, 0x7f, 0x17, 0xff, 0x58, 0x00,
|
||||
0xe7, 0x19, 0xaa, 0x4c, 0xaf, 0x6e, 0x21, 0xfe, 0x5a, 0x0f, 0xfb, 0xd4, 0xba, 0xc3, 0xd5, 0xc6,
|
||||
0xce, 0xea, 0x18, 0xe2, 0xe9, 0xb0, 0x91, 0x1e, 0x7e, 0xfd, 0x42, 0x66, 0xf0, 0x13, 0x01, 0x9c,
|
||||
0x0e, 0x25, 0x26, 0xcd, 0xd2, 0x02, 0x38, 0x61, 0xd1, 0xbf, 0xb8, 0x8c, 0xfc, 0xd7, 0x2f, 0x46,
|
||||
@@ -6425,16 +6428,16 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x5f, 0xe4, 0xea, 0xfd, 0xf0, 0xe1, 0x6a, 0xad, 0x0f, 0xbe, 0xe1, 0x74, 0x6c, 0x38, 0x7f, 0x30,
|
||||
0xf4, 0xbb, 0xf8, 0x15, 0x20, 0x0e, 0x04, 0x60, 0x8b, 0x5e, 0x2a, 0x8f, 0xb9, 0xfa, 0x64, 0xb7,
|
||||
0x3a, 0x3e, 0xc6, 0x81, 0xb3, 0x1f, 0x26, 0xde, 0xec, 0xda, 0x9f, 0x1d, 0xf1, 0x12, 0x26, 0xa1,
|
||||
0xea, 0xc5, 0x11, 0xff, 0x53, 0x01, 0x2c, 0x8c, 0x4e, 0xcc, 0x0b, 0xd6, 0x8e, 0xf4, 0x51, 0x38,
|
||||
0xea, 0xc5, 0x11, 0xff, 0x13, 0x01, 0x2c, 0x8c, 0x4e, 0xcc, 0x0b, 0xd6, 0x8e, 0xf4, 0x51, 0x38,
|
||||
0x97, 0xa8, 0x4f, 0x2f, 0x2d, 0x22, 0x26, 0xd9, 0x4a, 0x38, 0xad, 0xb5, 0x49, 0xf2, 0xbf, 0xe0,
|
||||
0x09, 0xf8, 0x2f, 0x97, 0xff, 0x05, 0xcf, 0xf1, 0x67, 0x2a, 0xff, 0x6f, 0xe7, 0xa3, 0xf2, 0x97,
|
||||
0x09, 0xf8, 0x2f, 0x97, 0xff, 0x05, 0xcf, 0xf1, 0x67, 0x2a, 0xff, 0x6f, 0xe5, 0xa3, 0xf2, 0x97,
|
||||
0x3d, 0xab, 0x13, 0xf8, 0xa6, 0xdb, 0xf4, 0xb1, 0x27, 0xad, 0x82, 0xf3, 0x34, 0x62, 0x20, 0xcf,
|
||||
0x6d, 0x63, 0x1f, 0xed, 0x92, 0x3e, 0x9e, 0x34, 0xcc, 0xc0, 0x73, 0xb4, 0x8b, 0xc4, 0x5c, 0xbf,
|
||||
0xcc, 0x3a, 0x48, 0xd0, 0x67, 0xf0, 0x4e, 0x67, 0x0f, 0x7b, 0x0e, 0xbd, 0x18, 0x1c, 0xc2, 0x9c,
|
||||
0xa2, 0x98, 0x8b, 0x14, 0x48, 0x0b, 0x61, 0x86, 0x48, 0xbc, 0x0e, 0x2e, 0x30, 0x12, 0x81, 0x67,
|
||||
0x39, 0xc1, 0x00, 0x33, 0x4f, 0x31, 0x25, 0xda, 0x67, 0xd2, 0xae, 0x10, 0x43, 0x01, 0x57, 0x47,
|
||||
0x99, 0x8e, 0xe0, 0x4e, 0x53, 0xdc, 0xa5, 0x61, 0xae, 0xc3, 0x44, 0x96, 0xc0, 0x5c, 0xcf, 0xc7,
|
||||
0x1e, 0xa2, 0x5e, 0x6c, 0x66, 0x50, 0x8b, 0x51, 0xb7, 0x0e, 0x70, 0xf1, 0x07, 0x53, 0x51, 0x0d,
|
||||
0x1e, 0xa2, 0x5e, 0x6c, 0x66, 0x50, 0x8b, 0x51, 0xb7, 0x0e, 0x70, 0xf1, 0x87, 0x53, 0x51, 0x0d,
|
||||
0x41, 0x7c, 0xe8, 0xe0, 0xa3, 0x17, 0xbd, 0xc2, 0x9e, 0x80, 0xcb, 0xb6, 0x75, 0xec, 0xa3, 0xae,
|
||||
0xe5, 0x07, 0xa8, 0x83, 0x3f, 0x0e, 0x90, 0xd5, 0xb3, 0x9d, 0x00, 0x91, 0x75, 0xc0, 0x07, 0x7f,
|
||||
0x91, 0x00, 0x34, 0x2c, 0x12, 0x30, 0x3f, 0x0e, 0x64, 0xd2, 0x5b, 0x22, 0x22, 0xac, 0x83, 0x6b,
|
||||
@@ -6445,7 +6448,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0xed, 0x90, 0x9c, 0x8f, 0x23, 0xcf, 0x50, 0xe4, 0x4b, 0x0c, 0xa4, 0x64, 0x1d, 0xeb, 0x3b, 0x35,
|
||||
0xd2, 0x1f, 0x62, 0xbf, 0x0d, 0x2e, 0x77, 0x7a, 0xd4, 0xb6, 0xdd, 0x1d, 0xe4, 0xe1, 0x03, 0xf7,
|
||||
0x10, 0xdb, 0x88, 0x8b, 0x5a, 0x38, 0x41, 0x47, 0xbe, 0xc0, 0x00, 0xf4, 0x1d, 0xc8, 0xba, 0x79,
|
||||
0xa0, 0x28, 0xfe, 0x9a, 0x30, 0x3e, 0x31, 0x2f, 0x7a, 0xe9, 0x3d, 0x04, 0x17, 0x59, 0x94, 0x42,
|
||||
0xa0, 0x28, 0xfe, 0xaa, 0x30, 0x3e, 0x31, 0x2f, 0x7a, 0xe9, 0x3d, 0x04, 0x17, 0x59, 0x94, 0x42,
|
||||
0x24, 0x4c, 0x21, 0x3e, 0x50, 0xc7, 0xe6, 0xa5, 0x2b, 0x92, 0x35, 0xc2, 0x5f, 0xb3, 0x8b, 0xdf,
|
||||
0x15, 0xc0, 0xe5, 0x48, 0x59, 0x04, 0xbb, 0xd8, 0x4e, 0x8a, 0xab, 0xd2, 0x1a, 0x98, 0x8e, 0x04,
|
||||
0xc7, 0xd5, 0x44, 0x29, 0xc7, 0x28, 0xd2, 0x20, 0x49, 0x71, 0x87, 0xcd, 0x77, 0x6a, 0xc4, 0x7c,
|
||||
@@ -6460,7 +6463,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x8a, 0x58, 0x27, 0x3b, 0xdd, 0xcf, 0x74, 0x11, 0xbc, 0x10, 0x55, 0xa8, 0x60, 0x86, 0xee, 0xc9,
|
||||
0xb9, 0x22, 0x1e, 0x64, 0x27, 0x42, 0x07, 0x08, 0x19, 0x76, 0xf1, 0xdf, 0x84, 0x04, 0x27, 0x40,
|
||||
0xf6, 0x9c, 0xdd, 0xe3, 0x5f, 0xde, 0xf1, 0xaf, 0x83, 0x69, 0xba, 0x77, 0x64, 0xc3, 0x7f, 0x0e,
|
||||
0x79, 0xc8, 0xd0, 0x68, 0x65, 0x07, 0xc5, 0x2f, 0xfe, 0x85, 0x00, 0x6e, 0xc4, 0x28, 0xa0, 0xea,
|
||||
0x79, 0xc8, 0xd0, 0x68, 0x65, 0x07, 0xc5, 0x2f, 0xfe, 0xb9, 0x00, 0x6e, 0xc4, 0x28, 0xa0, 0xea,
|
||||
0x74, 0xf6, 0x23, 0x07, 0x32, 0xbf, 0x8c, 0x1a, 0x90, 0xc0, 0x74, 0xdb, 0xe9, 0xec, 0xf3, 0x38,
|
||||
0x42, 0xff, 0x2e, 0xfe, 0xad, 0x00, 0xce, 0xf7, 0xcb, 0x91, 0x69, 0xea, 0xd3, 0x3f, 0x50, 0x4a,
|
||||
0xdf, 0x72, 0x47, 0x2e, 0xb4, 0x90, 0xeb, 0x39, 0xbb, 0x4e, 0x87, 0x3b, 0xcf, 0xfe, 0x85, 0x96,
|
||||
@@ -6489,7 +6492,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x03, 0xbf, 0x30, 0x4b, 0x81, 0x99, 0x70, 0xc6, 0x1b, 0x6b, 0xac, 0x95, 0xec, 0xcb, 0x38, 0xa4,
|
||||
0x75, 0xd0, 0xee, 0xaf, 0x4f, 0xbf, 0x30, 0x47, 0xa1, 0x99, 0x8c, 0x86, 0x75, 0xd0, 0x0e, 0x17,
|
||||
0x69, 0x04, 0xc3, 0x75, 0xec, 0x56, 0x04, 0x03, 0x44, 0x30, 0x74, 0xc7, 0x6e, 0x0d, 0x30, 0xfa,
|
||||
0x2a, 0xb1, 0x5a, 0x74, 0xaf, 0xe6, 0x17, 0x4e, 0x45, 0x54, 0x22, 0xf3, 0xc6, 0xe2, 0x0f, 0x04,
|
||||
0x2a, 0xb1, 0x5a, 0x74, 0xaf, 0xe6, 0x17, 0x4e, 0x45, 0x54, 0x22, 0xf3, 0xc6, 0xe2, 0x0f, 0x05,
|
||||
0x70, 0xab, 0xa9, 0x45, 0x26, 0x5b, 0xf1, 0xdc, 0xa3, 0xce, 0x53, 0x7c, 0x84, 0xdb, 0x25, 0x67,
|
||||
0x67, 0xe7, 0x99, 0x83, 0x8f, 0xd8, 0xbc, 0x3f, 0x01, 0x05, 0x6b, 0x67, 0x67, 0xb8, 0x40, 0x15,
|
||||
0x45, 0x6a, 0xe2, 0xe7, 0xe0, 0x42, 0xd8, 0xdf, 0xaf, 0xe2, 0x66, 0x67, 0xf5, 0x8f, 0xc1, 0xc2,
|
||||
@@ -6501,7 +6504,7 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x7d, 0x8f, 0x14, 0x58, 0xfe, 0x7e, 0xd4, 0xd9, 0xcd, 0x92, 0x86, 0xf0, 0xb5, 0x85, 0xe3, 0xfb,
|
||||
0xbd, 0x21, 0xaa, 0x73, 0xb4, 0x85, 0x76, 0x5f, 0x00, 0x33, 0xc4, 0xbb, 0x84, 0xfb, 0x0f, 0xf6,
|
||||
0x83, 0xf8, 0xfe, 0xbe, 0x1d, 0x46, 0x8a, 0x19, 0x66, 0xe0, 0x7c, 0xbf, 0x99, 0x15, 0x33, 0xfc,
|
||||
0xe6, 0x07, 0xe0, 0x6c, 0x93, 0x78, 0x21, 0x2a, 0x89, 0xde, 0xc1, 0xfa, 0x8e, 0xd4, 0x04, 0x67,
|
||||
0xc6, 0x07, 0xe0, 0x6c, 0x93, 0x78, 0x21, 0x2a, 0x89, 0xde, 0xc1, 0xfa, 0x8e, 0xd4, 0x04, 0x67,
|
||||
0x7b, 0x0e, 0xda, 0xa6, 0x2f, 0x71, 0x50, 0x8b, 0x44, 0xcd, 0xd4, 0xbd, 0xdc, 0xf8, 0xc3, 0x9d,
|
||||
0x4a, 0x0e, 0x9e, 0xe9, 0x39, 0x91, 0x56, 0xe9, 0x13, 0x01, 0xdc, 0xef, 0x39, 0xc8, 0x65, 0x0f,
|
||||
0x53, 0x10, 0x3f, 0x0f, 0xc5, 0x68, 0xd7, 0x45, 0x81, 0x8b, 0xec, 0xf0, 0xe5, 0x0e, 0xe7, 0xc8,
|
||||
@@ -6511,202 +6514,202 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x8a, 0x05, 0x1b, 0xd5, 0x55, 0x8c, 0x34, 0x6d, 0x2b, 0xe8, 0xcf, 0xce, 0x4c, 0x56, 0x5d, 0xa5,
|
||||
0xbc, 0x5d, 0x1a, 0xd2, 0x55, 0x32, 0xac, 0xf4, 0xbf, 0x05, 0x70, 0x3d, 0x22, 0x9d, 0x8f, 0x03,
|
||||
0xd4, 0xea, 0x3f, 0x73, 0x42, 0x3e, 0x7d, 0x61, 0x44, 0x9d, 0xe5, 0xa9, 0x47, 0xef, 0xa4, 0x0b,
|
||||
0x95, 0xf4, 0x48, 0xaa, 0x92, 0x83, 0x57, 0xfa, 0xd2, 0xc4, 0x00, 0x49, 0xbf, 0x22, 0x80, 0x5b,
|
||||
0x11, 0x31, 0x3c, 0x5e, 0xd2, 0x88, 0x5a, 0xe1, 0x5b, 0xa7, 0x50, 0x94, 0x93, 0x54, 0x94, 0x2f,
|
||||
0xa5, 0x8b, 0x32, 0xe9, 0xb5, 0x54, 0x25, 0x07, 0xaf, 0xf7, 0xc5, 0x49, 0x00, 0x0c, 0x35, 0xe3,
|
||||
0xf1, 0xf7, 0x47, 0x88, 0xec, 0x5d, 0xc9, 0x02, 0x64, 0xef, 0x9f, 0xf8, 0x74, 0xcd, 0xa6, 0x6a,
|
||||
0x26, 0xe5, 0xf5, 0x14, 0xd3, 0x4c, 0x32, 0x90, 0xf4, 0x31, 0xb8, 0x12, 0x27, 0x45, 0xf7, 0x98,
|
||||
0x4b, 0x30, 0x47, 0x25, 0xf8, 0x42, 0x76, 0x09, 0xa2, 0xcf, 0xaf, 0x2a, 0x39, 0x58, 0x18, 0xe3,
|
||||
0xce, 0x01, 0xa4, 0xff, 0x01, 0x96, 0xc7, 0x39, 0x77, 0x3d, 0xa7, 0x13, 0x70, 0xd6, 0x80, 0xb2,
|
||||
0x7e, 0x2b, 0x2b, 0xeb, 0x91, 0xc7, 0x5b, 0x95, 0x1c, 0xbc, 0x3c, 0xc2, 0x7b, 0x00, 0x21, 0xb5,
|
||||
0xc1, 0xe5, 0x9e, 0x83, 0x6c, 0xee, 0xc4, 0x49, 0xd6, 0xe5, 0x91, 0x50, 0x42, 0x89, 0xd3, 0xa0,
|
||||
0x76, 0x6a, 0xc2, 0xc6, 0x2a, 0xfe, 0x09, 0x54, 0x25, 0x07, 0x17, 0x7a, 0x4e, 0xec, 0xe3, 0xa8,
|
||||
0xef, 0x30, 0xf3, 0xeb, 0xb3, 0x1b, 0xc4, 0xba, 0xb0, 0x0e, 0x8c, 0x73, 0x3e, 0x4d, 0x39, 0xbf,
|
||||
0x9d, 0x81, 0x73, 0xfc, 0xab, 0x26, 0x66, 0x79, 0x29, 0x2f, 0x9f, 0xbe, 0x41, 0x0d, 0xaf, 0x2f,
|
||||
0x0c, 0xaf, 0x9d, 0xf7, 0x59, 0x19, 0x3c, 0x17, 0xe4, 0x0c, 0x15, 0xe4, 0xcd, 0x4f, 0x55, 0x44,
|
||||
0xcf, 0x6c, 0x6e, 0xc2, 0xa3, 0x87, 0xff, 0xcb, 0x1c, 0xe8, 0x40, 0x02, 0x9e, 0xd0, 0x0f, 0xd6,
|
||||
0x25, 0x13, 0x62, 0x9e, 0x0a, 0xf1, 0x24, 0x8b, 0x10, 0x71, 0xb5, 0xca, 0x95, 0x1c, 0xbc, 0x16,
|
||||
0x91, 0x23, 0xb6, 0x9c, 0xf9, 0x37, 0x98, 0xf7, 0x1c, 0x17, 0xa5, 0x15, 0x96, 0xa9, 0xa0, 0x83,
|
||||
0xa0, 0xed, 0x73, 0x81, 0xce, 0x52, 0x81, 0xbe, 0xf8, 0x1c, 0x02, 0x8d, 0x57, 0x0f, 0x57, 0x72,
|
||||
0xf0, 0xd6, 0xb8, 0x54, 0x03, 0xb8, 0xa0, 0xcd, 0x0b, 0x28, 0xff, 0x4c, 0x00, 0x4f, 0x86, 0xe7,
|
||||
0x89, 0xd6, 0x9e, 0x22, 0x8b, 0x16, 0x9f, 0x22, 0x3b, 0xac, 0x3e, 0x45, 0x81, 0xeb, 0xb6, 0x79,
|
||||
0x32, 0xd9, 0x6e, 0x73, 0x49, 0x45, 0x2a, 0xe9, 0xd3, 0x4c, 0xf3, 0x97, 0xa9, 0xc6, 0xb7, 0x92,
|
||||
0x83, 0x0f, 0xa3, 0x93, 0x9a, 0xad, 0x30, 0xf8, 0xc7, 0x02, 0x78, 0x9c, 0x69, 0x0c, 0x03, 0x75,
|
||||
0x33, 0xf9, 0xcf, 0x51, 0xf9, 0xcb, 0x9f, 0x5a, 0xfe, 0xe1, 0x2a, 0xa3, 0x4a, 0x0e, 0xae, 0xa6,
|
||||
0x09, 0x3f, 0x52, 0x97, 0xf4, 0x5b, 0x02, 0x78, 0x25, 0x2a, 0xb9, 0xd5, 0x23, 0x99, 0x47, 0x7f,
|
||||
0x0f, 0x1a, 0x79, 0x4f, 0xc5, 0x04, 0x96, 0xa8, 0xc0, 0xef, 0x67, 0x10, 0x78, 0x52, 0xd5, 0x6c,
|
||||
0x25, 0x07, 0xef, 0x0c, 0x04, 0x9d, 0x58, 0x5f, 0xfb, 0x47, 0x02, 0x78, 0x90, 0x62, 0xb9, 0x8e,
|
||||
0x75, 0xc0, 0x36, 0x2f, 0xc7, 0x5c, 0xc8, 0xf3, 0x54, 0xc8, 0xb5, 0x4f, 0x63, 0xbf, 0xc3, 0x85,
|
||||
0x6b, 0x95, 0x1c, 0xbc, 0x3f, 0xc1, 0x88, 0x35, 0xeb, 0x20, 0x5a, 0xe5, 0xf6, 0xab, 0x02, 0xb8,
|
||||
0x13, 0x15, 0xb5, 0xdb, 0x2f, 0x06, 0x1b, 0x9b, 0xf7, 0x0b, 0x54, 0xc2, 0x77, 0x33, 0x48, 0x98,
|
||||
0x54, 0x51, 0x56, 0xc9, 0xc1, 0xe2, 0x40, 0xb4, 0xc4, 0xba, 0xb3, 0x6f, 0x09, 0xe0, 0x46, 0x54,
|
||||
0xa6, 0x00, 0xfb, 0x01, 0x91, 0xa6, 0x33, 0xe4, 0x8f, 0x2f, 0xa6, 0x46, 0xbf, 0x09, 0xe5, 0x5d,
|
||||
0x95, 0x1c, 0x5c, 0x1e, 0x48, 0x12, 0x57, 0xff, 0xe5, 0x81, 0xa5, 0xa8, 0x0c, 0x61, 0x9e, 0x1b,
|
||||
0xc6, 0xa1, 0x85, 0x94, 0x1b, 0xc4, 0xa4, 0xfa, 0x2a, 0x16, 0x76, 0x13, 0x6a, 0xaf, 0xda, 0xa0,
|
||||
0xd0, 0x73, 0x48, 0x12, 0x66, 0x05, 0x18, 0x75, 0xf0, 0x11, 0xdd, 0xff, 0xf2, 0x88, 0x7b, 0x29,
|
||||
0xe5, 0x80, 0x2b, 0xb1, 0xb2, 0xa9, 0x92, 0x83, 0x17, 0x7a, 0xce, 0x78, 0xa7, 0x74, 0x4c, 0x83,
|
||||
0xfc, 0x28, 0x37, 0xdf, 0x3a, 0x0c, 0x59, 0x16, 0x52, 0x35, 0x3c, 0xa1, 0x5c, 0x8a, 0x0d, 0x34,
|
||||
0x1e, 0x40, 0xfa, 0x06, 0xb8, 0x16, 0x37, 0x50, 0x5a, 0xa1, 0xc4, 0x99, 0x5f, 0x4e, 0x0d, 0x30,
|
||||
0x13, 0xab, 0x9b, 0x2a, 0x39, 0xb8, 0x38, 0x3a, 0xea, 0x01, 0x88, 0xf4, 0xbb, 0xcc, 0x85, 0x8c,
|
||||
0x4a, 0xc0, 0xee, 0xe1, 0xa2, 0x15, 0x50, 0x5c, 0x9a, 0x45, 0x2a, 0x8d, 0x92, 0x55, 0x9a, 0x09,
|
||||
0x85, 0x54, 0x95, 0x1c, 0xbc, 0x3d, 0x22, 0x58, 0x3c, 0xb4, 0xf4, 0x07, 0x02, 0x58, 0x8d, 0x9a,
|
||||
0xa0, 0x33, 0x38, 0x76, 0x44, 0xd6, 0x91, 0xcf, 0x8e, 0x06, 0xf8, 0xb2, 0xe0, 0x56, 0xb9, 0x94,
|
||||
0xba, 0x85, 0xc8, 0xf6, 0xf2, 0xb8, 0x92, 0x83, 0xf7, 0x06, 0x56, 0x1a, 0x85, 0x3d, 0xf2, 0x75,
|
||||
0xc7, 0x6e, 0x0d, 0xbd, 0x52, 0xfe, 0xae, 0x00, 0x6e, 0xc7, 0xa7, 0x0c, 0xb6, 0x8f, 0x30, 0x3d,
|
||||
0x20, 0xe5, 0xe2, 0x5d, 0xc9, 0x9c, 0x42, 0xc5, 0x3f, 0x08, 0x1e, 0x4e, 0xa1, 0xfa, 0x30, 0xb6,
|
||||
0x1f, 0x7d, 0xfe, 0x1a, 0x30, 0xb3, 0x26, 0xf1, 0x36, 0x70, 0x11, 0x2b, 0x0d, 0x62, 0xb3, 0xc8,
|
||||
0xa5, 0x58, 0x4e, 0x5d, 0xba, 0xf1, 0x2f, 0x4c, 0xb9, 0x45, 0xc7, 0xbf, 0x3e, 0xfd, 0x2a, 0x38,
|
||||
0x67, 0xd1, 0x1a, 0x25, 0x34, 0xa8, 0x10, 0x2a, 0x5c, 0xa5, 0x9c, 0x92, 0x0f, 0x92, 0x63, 0xeb,
|
||||
0xe9, 0x2a, 0x39, 0x28, 0x5a, 0x23, 0x1d, 0xa1, 0x4b, 0x8c, 0x9a, 0x00, 0xd7, 0x2c, 0x4d, 0x8f,
|
||||
0xf9, 0xc8, 0xae, 0xa5, 0x2e, 0xd8, 0x09, 0x37, 0x99, 0xcc, 0x25, 0x4e, 0xba, 0xea, 0xe4, 0xa9,
|
||||
0x72, 0x8c, 0x10, 0xfd, 0x53, 0x00, 0x26, 0xc7, 0xf5, 0xd4, 0x79, 0x9e, 0x7c, 0xc1, 0xc9, 0xe6,
|
||||
0x39, 0xe5, 0x12, 0xf4, 0x7f, 0x09, 0xd4, 0x89, 0x84, 0xfb, 0xc6, 0xaf, 0x45, 0xbf, 0xb1, 0x11,
|
||||
0x6e, 0x19, 0x6f, 0x64, 0xdd, 0xbd, 0x26, 0x7d, 0xa1, 0x63, 0x68, 0xf7, 0x1a, 0x03, 0x24, 0x7d,
|
||||
0x04, 0xf8, 0x64, 0x21, 0x1c, 0x96, 0x17, 0x16, 0x8a, 0x94, 0xeb, 0x6b, 0x29, 0xd3, 0x3e, 0x5c,
|
||||
0x8e, 0x58, 0xc9, 0xc1, 0xb3, 0xd6, 0x70, 0xbb, 0x74, 0x00, 0x2e, 0x71, 0xda, 0xc4, 0x41, 0x45,
|
||||
0xab, 0x12, 0x0b, 0x37, 0x53, 0x4e, 0xee, 0x93, 0x8b, 0x03, 0x2b, 0x39, 0x78, 0xd1, 0x8a, 0xeb,
|
||||
0x95, 0xb6, 0xc1, 0xc5, 0xc1, 0x29, 0x09, 0x73, 0x8c, 0x6c, 0x3a, 0x6f, 0x51, 0x66, 0xaf, 0x26,
|
||||
0x32, 0x8b, 0xb9, 0xdb, 0xa8, 0xe4, 0xe0, 0x79, 0x2f, 0xe6, 0xca, 0xe3, 0x08, 0x5c, 0x49, 0x38,
|
||||
0x5c, 0x67, 0xac, 0x6e, 0xa7, 0x8c, 0x2b, 0xf9, 0x42, 0x80, 0x38, 0xfc, 0x9d, 0xe4, 0xeb, 0x82,
|
||||
0x6d, 0xc0, 0x47, 0x8d, 0x78, 0x41, 0x82, 0xc7, 0xea, 0x1e, 0x0b, 0x77, 0x52, 0x06, 0x17, 0x53,
|
||||
0x2b, 0x49, 0x06, 0x67, 0xc5, 0x94, 0x50, 0x56, 0xc1, 0x99, 0x3e, 0x0f, 0x3a, 0x4b, 0x77, 0x29,
|
||||
0xed, 0xdb, 0xa9, 0xb4, 0x09, 0x70, 0x25, 0x07, 0x4f, 0x5b, 0xd1, 0x2a, 0xc7, 0x2d, 0x20, 0x45,
|
||||
0x6b, 0x27, 0xd8, 0x8c, 0x14, 0xee, 0xa5, 0x94, 0x64, 0x8f, 0x16, 0xf9, 0x51, 0x6f, 0x32, 0x5a,
|
||||
0xf8, 0x37, 0x42, 0xba, 0x47, 0x0b, 0xc6, 0x0a, 0xf7, 0x33, 0x93, 0x66, 0x15, 0x66, 0xc3, 0xa4,
|
||||
0x79, 0xd5, 0xd9, 0x08, 0x69, 0x9b, 0x16, 0x94, 0x14, 0x56, 0x32, 0x93, 0x66, 0x15, 0x28, 0xc3,
|
||||
0xa4, 0x79, 0x55, 0x4a, 0x1b, 0x5c, 0x8e, 0x92, 0xe6, 0x35, 0x5d, 0x5c, 0x2f, 0xaf, 0xa4, 0x9c,
|
||||
0x0b, 0xc4, 0x17, 0xf9, 0x55, 0x72, 0x70, 0xc1, 0x8a, 0x2f, 0xff, 0x8b, 0xe7, 0xc6, 0x55, 0xf5,
|
||||
0xea, 0x73, 0x72, 0xeb, 0x2b, 0x6c, 0x8c, 0x1b, 0x57, 0x5b, 0x3c, 0x37, 0xae, 0xbd, 0xd7, 0x9e,
|
||||
0x93, 0x5b, 0x5f, 0x87, 0x63, 0xdc, 0xb8, 0x26, 0x0f, 0xc0, 0x62, 0x94, 0x1b, 0x2d, 0xf5, 0xf2,
|
||||
0x49, 0xb4, 0xec, 0xf9, 0xd8, 0x2b, 0xac, 0x66, 0x66, 0x17, 0xad, 0x77, 0x1b, 0x66, 0x37, 0x54,
|
||||
0x09, 0xf7, 0xff, 0x04, 0x50, 0x8c, 0x26, 0x08, 0xd1, 0x9b, 0xa4, 0xc1, 0x31, 0x4b, 0xe1, 0x41,
|
||||
0xea, 0x99, 0x6c, 0xea, 0x6b, 0x3d, 0x76, 0x26, 0xdb, 0x07, 0x6b, 0x8d, 0x83, 0x49, 0xfb, 0xe0,
|
||||
0x52, 0xcc, 0x09, 0x0b, 0x76, 0x5a, 0xb8, 0xf0, 0x7a, 0x6a, 0x8a, 0x9d, 0xf0, 0x56, 0x8e, 0xa5,
|
||||
0xd8, 0x23, 0x9d, 0x4e, 0x0b, 0x8f, 0x32, 0x0b, 0xd3, 0x4d, 0xd7, 0xc6, 0x85, 0x87, 0x99, 0x99,
|
||||
0x8d, 0xbc, 0x4f, 0x1b, 0x66, 0x36, 0xe8, 0x94, 0xbe, 0x02, 0xce, 0x05, 0xd6, 0x2e, 0x8f, 0x43,
|
||||
0x98, 0x04, 0x44, 0xef, 0xb8, 0xf0, 0x28, 0x25, 0x16, 0xc5, 0x5d, 0x38, 0x92, 0x58, 0x14, 0x58,
|
||||
0xbb, 0xd1, 0x76, 0x29, 0x00, 0x8b, 0x3e, 0xbf, 0x9e, 0x41, 0x1e, 0xa5, 0x84, 0x76, 0x31, 0x3d,
|
||||
0xc8, 0xee, 0xb5, 0x83, 0xc2, 0x1b, 0x29, 0x47, 0x52, 0x93, 0x6e, 0x76, 0x2a, 0x39, 0x78, 0xc9,
|
||||
0x8f, 0xef, 0x1f, 0x5d, 0x16, 0xbc, 0x7e, 0x8c, 0x2f, 0xf9, 0xc7, 0x99, 0xed, 0x34, 0x5a, 0x75,
|
||||
0x38, 0x6c, 0xa7, 0x43, 0xf5, 0x88, 0xf1, 0xdc, 0xf8, 0x22, 0x7c, 0xf3, 0x39, 0xb9, 0xc5, 0x2d,
|
||||
0xc2, 0xa1, 0x22, 0xbb, 0x6d, 0x70, 0x31, 0x34, 0x8c, 0x63, 0xb4, 0x83, 0x83, 0xd6, 0x1e, 0x8f,
|
||||
0x81, 0x5f, 0x48, 0x89, 0x48, 0x31, 0xd7, 0x5b, 0x24, 0x22, 0xd9, 0x31, 0xb7, 0x5e, 0xdf, 0x1b,
|
||||
0x39, 0xcd, 0xe3, 0x06, 0x38, 0xe0, 0xcb, 0xf6, 0xf8, 0x85, 0xb7, 0x32, 0x1f, 0x9e, 0x25, 0x7f,
|
||||
0x66, 0x61, 0xf8, 0x48, 0x2f, 0x16, 0x4e, 0xfa, 0xe6, 0xc8, 0xce, 0x7e, 0xbf, 0xb7, 0x8d, 0xe9,
|
||||
0xe5, 0xec, 0xd0, 0x36, 0xe1, 0x49, 0xe6, 0x03, 0xce, 0xf1, 0xaf, 0xdf, 0x0c, 0x1f, 0x70, 0xd2,
|
||||
0xfe, 0xfd, 0xa1, 0xed, 0xc1, 0xb7, 0xe3, 0x55, 0x62, 0x75, 0xbb, 0xf4, 0x98, 0xb5, 0x7f, 0xc0,
|
||||
0xf9, 0x76, 0xea, 0x09, 0xf7, 0xa4, 0x67, 0x94, 0xc3, 0x8e, 0x28, 0xf6, 0xa1, 0x65, 0x17, 0x2c,
|
||||
0x71, 0x6b, 0xdb, 0xf5, 0xac, 0xee, 0x1e, 0xdd, 0xd2, 0xf9, 0x2d, 0x2b, 0xcc, 0x84, 0xde, 0xa1,
|
||||
0xfc, 0x5f, 0x4f, 0xb1, 0xb7, 0xb1, 0xfb, 0x7a, 0xb2, 0x9a, 0xac, 0x48, 0xd7, 0x91, 0x3f, 0xb8,
|
||||
0xca, 0xff, 0x3e, 0xdb, 0xa8, 0x0d, 0x71, 0x6d, 0x79, 0xee, 0x51, 0x07, 0xfd, 0x77, 0x7c, 0x84,
|
||||
0xdb, 0xc8, 0x76, 0x76, 0x76, 0xe8, 0x16, 0xb8, 0xf0, 0x6e, 0xaa, 0x3d, 0xa4, 0xdf, 0x20, 0x33,
|
||||
0x7b, 0x98, 0x08, 0x27, 0xfd, 0x37, 0x70, 0x91, 0x16, 0x71, 0xd0, 0x7b, 0x53, 0x7a, 0xe7, 0xc9,
|
||||
0x47, 0xff, 0x5e, 0xda, 0x4d, 0xe5, 0xd8, 0xf5, 0x6b, 0x25, 0x07, 0xa5, 0xde, 0xf8, 0xa5, 0x2c,
|
||||
0x3b, 0x50, 0x8f, 0xdd, 0x37, 0xe1, 0x2e, 0x67, 0xf6, 0xc5, 0x54, 0x7b, 0x4b, 0xae, 0x4d, 0x64,
|
||||
0xf6, 0x36, 0xa1, 0x76, 0xf1, 0xd7, 0x05, 0x70, 0x2f, 0x41, 0x02, 0x7e, 0x9c, 0xe5, 0x76, 0x71,
|
||||
0x38, 0xe9, 0x5f, 0x4a, 0x0d, 0x81, 0xa9, 0x25, 0x82, 0xec, 0xf6, 0x2f, 0xbd, 0x92, 0xf0, 0x13,
|
||||
0x01, 0xac, 0xc4, 0xcb, 0x45, 0x6b, 0xd0, 0x46, 0xb7, 0x74, 0xef, 0xa7, 0x5e, 0xbe, 0x65, 0xa8,
|
||||
0xd9, 0x63, 0x67, 0x1f, 0x59, 0x8a, 0xfb, 0xf8, 0x99, 0x42, 0xec, 0x56, 0x93, 0x3e, 0xc5, 0xea,
|
||||
0x86, 0xe7, 0xa6, 0x1f, 0x7c, 0x9a, 0xbd, 0x66, 0xa4, 0x8e, 0x2e, 0x71, 0xaf, 0x19, 0xad, 0xb5,
|
||||
0xfb, 0x3e, 0x3b, 0x25, 0x8d, 0x11, 0xa7, 0xed, 0x74, 0xf6, 0x87, 0x4e, 0x17, 0xe4, 0xd4, 0x2d,
|
||||
0x67, 0x4a, 0x59, 0x5b, 0x25, 0x07, 0x6f, 0xc4, 0x08, 0x34, 0x0c, 0xb4, 0x76, 0x12, 0xcc, 0x50,
|
||||
0x9a, 0x4f, 0xa7, 0x67, 0xf3, 0xe2, 0x14, 0xb1, 0xc1, 0xfe, 0x4e, 0x98, 0xc4, 0xe5, 0xf0, 0xd2,
|
||||
0x8c, 0x4a, 0xb6, 0xf2, 0x43, 0x71, 0xf0, 0x41, 0xc4, 0x70, 0xb3, 0x26, 0xdd, 0x00, 0xcb, 0x25,
|
||||
0xcd, 0x50, 0xf4, 0x67, 0x2a, 0x44, 0x50, 0x35, 0xf4, 0x26, 0x54, 0x46, 0x3f, 0x67, 0x74, 0x05,
|
||||
0x14, 0xc6, 0x41, 0x0c, 0x15, 0x3e, 0x53, 0xa1, 0x28, 0x48, 0xd7, 0xc1, 0x95, 0xf1, 0xde, 0x8d,
|
||||
0xe6, 0x9a, 0x0a, 0xeb, 0xaa, 0xa9, 0x1a, 0x62, 0x5e, 0x7a, 0x03, 0x3c, 0x18, 0x87, 0x28, 0xc9,
|
||||
0xa6, 0xbc, 0x26, 0x1b, 0x2a, 0x6a, 0xe8, 0x86, 0x59, 0x86, 0xaa, 0x81, 0x0c, 0xb5, 0xba, 0x8e,
|
||||
0x2a, 0xba, 0x61, 0xaa, 0x25, 0x71, 0x4a, 0x7a, 0x1d, 0xbc, 0x3a, 0x01, 0xa9, 0xb6, 0x65, 0x7c,
|
||||
0x58, 0x1d, 0xc2, 0x98, 0x96, 0x1e, 0x81, 0xd5, 0x49, 0x18, 0x7a, 0xbd, 0xac, 0x97, 0xd6, 0x86,
|
||||
0x70, 0x66, 0xa4, 0x57, 0xc0, 0xdd, 0x2c, 0xa2, 0xc1, 0x92, 0x21, 0x9e, 0x90, 0xee, 0x81, 0x5b,
|
||||
0xa9, 0x22, 0x11, 0xc8, 0x93, 0xd2, 0x1d, 0x50, 0x1c, 0x87, 0x94, 0x1b, 0x8d, 0xaa, 0xa6, 0xc8,
|
||||
0xa6, 0xa6, 0xd7, 0x51, 0xc5, 0x34, 0x1b, 0xe2, 0xac, 0x74, 0x1b, 0xdc, 0x98, 0x0c, 0x67, 0x2a,
|
||||
0x0d, 0x71, 0x2e, 0x1e, 0x6c, 0x53, 0xab, 0x97, 0xf4, 0x4d, 0x03, 0x95, 0x54, 0x63, 0xc3, 0xd4,
|
||||
0x1b, 0x22, 0x90, 0x5e, 0x05, 0xf7, 0x26, 0xc8, 0x67, 0x7c, 0x58, 0x65, 0x73, 0x46, 0x65, 0x3c,
|
||||
0x95, 0xa2, 0xe0, 0xc1, 0xd0, 0xd5, 0x92, 0x51, 0xd1, 0xd6, 0x4d, 0xf1, 0xb4, 0xf4, 0x18, 0xbc,
|
||||
0x9e, 0x89, 0x7e, 0x54, 0xc5, 0x67, 0x52, 0xf8, 0x40, 0xb5, 0xa4, 0x0d, 0x4f, 0xfd, 0x7c, 0xd6,
|
||||
0x49, 0x29, 0x2b, 0x0d, 0xf1, 0x6c, 0xa6, 0x49, 0x21, 0x90, 0x62, 0x66, 0xf5, 0x10, 0xe8, 0x73,
|
||||
0xd2, 0xbb, 0xe0, 0xad, 0xe7, 0x51, 0x0f, 0x5f, 0x0f, 0x55, 0xd5, 0x30, 0x44, 0x49, 0x7a, 0x0d,
|
||||
0xdc, 0xcf, 0x82, 0x2c, 0x7f, 0xd4, 0x84, 0xaa, 0x78, 0x5e, 0xba, 0x0b, 0x6e, 0x4e, 0x00, 0x2f,
|
||||
0x6d, 0xd5, 0xe5, 0x9a, 0x5e, 0x5a, 0x13, 0x2f, 0xa4, 0x98, 0xb8, 0x22, 0x1b, 0x86, 0x5c, 0x2f,
|
||||
0x41, 0x19, 0x6d, 0xa8, 0x5b, 0x46, 0x43, 0x56, 0x54, 0x43, 0xbc, 0x98, 0x32, 0x6b, 0x03, 0x9c,
|
||||
0xe8, 0x1c, 0x2c, 0x48, 0x4f, 0xc0, 0xe3, 0x09, 0x58, 0x6a, 0x55, 0x36, 0x4c, 0x4d, 0x31, 0x54,
|
||||
0x19, 0x2a, 0x95, 0x21, 0xcc, 0x4b, 0x99, 0xe6, 0x9b, 0xe3, 0xcb, 0x4a, 0x45, 0x15, 0x0b, 0x29,
|
||||
0xda, 0x62, 0x18, 0x35, 0xb5, 0xa6, 0xc3, 0xad, 0xd2, 0x9a, 0x78, 0x39, 0x13, 0x03, 0xaa, 0x59,
|
||||
0xc4, 0x18, 0x2c, 0xa6, 0x0c, 0x86, 0x61, 0x28, 0xd5, 0xa6, 0x61, 0x8e, 0x18, 0xef, 0x92, 0xb4,
|
||||
0x02, 0xee, 0xa4, 0x5a, 0x17, 0x9b, 0xc5, 0x2b, 0xd2, 0x2a, 0x58, 0xc9, 0x64, 0x5f, 0x0c, 0x7e,
|
||||
0x39, 0x65, 0x32, 0x07, 0xf0, 0x35, 0x4d, 0x81, 0xba, 0xa1, 0xaf, 0x9b, 0xe2, 0x55, 0xe9, 0x0b,
|
||||
0xe0, 0xd1, 0xa4, 0xc9, 0xd4, 0x95, 0x0d, 0xa8, 0xcb, 0x4a, 0x65, 0xc4, 0xcf, 0x5d, 0x4b, 0xb1,
|
||||
0xfd, 0xd0, 0x37, 0xca, 0x66, 0x55, 0x36, 0xc4, 0xeb, 0x29, 0x6b, 0xca, 0xa8, 0xeb, 0x9b, 0xeb,
|
||||
0x55, 0x79, 0x43, 0x15, 0x6f, 0x24, 0xd0, 0xd5, 0x95, 0x88, 0x76, 0x4b, 0x06, 0x6a, 0x40, 0xfd,
|
||||
0xcb, 0x5b, 0x62, 0x31, 0xc1, 0x14, 0xa3, 0xd0, 0x15, 0xad, 0x5c, 0x41, 0xf2, 0x33, 0x59, 0xab,
|
||||
0xca, 0x6b, 0x5a, 0x55, 0x33, 0xb7, 0xc4, 0x9b, 0xd2, 0x5b, 0xe0, 0x8d, 0x14, 0x2c, 0xba, 0x42,
|
||||
0x34, 0x05, 0x41, 0xb5, 0xac, 0x19, 0x26, 0xa4, 0xae, 0x53, 0xbc, 0x15, 0xef, 0x85, 0x0d, 0xb9,
|
||||
0x56, 0x8d, 0xba, 0x58, 0xf1, 0xb6, 0x54, 0x04, 0x57, 0xc7, 0xe1, 0x54, 0xe5, 0x11, 0xfb, 0x70,
|
||||
0x5f, 0x5d, 0x51, 0xc5, 0x3b, 0x09, 0x46, 0xa7, 0x2b, 0xa3, 0x6e, 0x18, 0xd5, 0xf5, 0x3a, 0x92,
|
||||
0x4b, 0xe2, 0x5d, 0xe9, 0x16, 0xb8, 0x3e, 0x29, 0x2e, 0xd2, 0x0f, 0xba, 0xdd, 0x8b, 0xb7, 0xfd,
|
||||
0x68, 0x04, 0x90, 0x37, 0x0d, 0xa4, 0xe8, 0x75, 0x43, 0xaf, 0xaa, 0xe2, 0x7d, 0xe9, 0x1a, 0x58,
|
||||
0x1a, 0x07, 0xaf, 0x29, 0x0d, 0x64, 0x98, 0x25, 0x4d, 0x17, 0x57, 0xe8, 0x67, 0x0f, 0xe3, 0x01,
|
||||
0x0c, 0x55, 0x7c, 0x45, 0xba, 0x0f, 0x6e, 0x27, 0xe1, 0x43, 0x55, 0xae, 0xc9, 0x6b, 0x55, 0x95,
|
||||
0xc5, 0xa6, 0x57, 0x57, 0x7e, 0x4f, 0x00, 0xf3, 0xc3, 0x9f, 0x1e, 0x1e, 0xe2, 0x6e, 0x98, 0xb2,
|
||||
0xd9, 0x34, 0x46, 0x32, 0x85, 0x25, 0x70, 0x69, 0x14, 0xc0, 0x68, 0x2a, 0x0a, 0x71, 0x8a, 0x42,
|
||||
0x6c, 0xe7, 0x86, 0xd6, 0x68, 0xa8, 0x25, 0x31, 0x2f, 0x5d, 0x06, 0x17, 0x47, 0x3b, 0x55, 0x08,
|
||||
0x75, 0x28, 0x4e, 0xc5, 0xe1, 0xc9, 0x6b, 0x3a, 0xa4, 0x41, 0x7f, 0xe5, 0x67, 0x79, 0x30, 0xa5,
|
||||
0x98, 0xb2, 0x74, 0x1e, 0x9c, 0x55, 0x4c, 0x79, 0xfc, 0x23, 0x8f, 0xa4, 0x51, 0x6e, 0x9a, 0x15,
|
||||
0xa2, 0xc3, 0xba, 0xaa, 0x98, 0x3a, 0x49, 0x59, 0x2e, 0x81, 0xf3, 0xb4, 0x5d, 0x31, 0xb5, 0x67,
|
||||
0x24, 0x93, 0x31, 0x0c, 0x4d, 0xaf, 0x93, 0x4c, 0xa5, 0xdf, 0x41, 0x44, 0x46, 0x50, 0xfd, 0xb0,
|
||||
0xa9, 0x1a, 0xa6, 0x21, 0x4e, 0x85, 0x1d, 0x0d, 0xa8, 0xd6, 0xb4, 0x66, 0x0d, 0x19, 0xcd, 0x46,
|
||||
0x43, 0x87, 0xa6, 0x38, 0x1d, 0x76, 0x98, 0x90, 0x78, 0x8f, 0x12, 0x2a, 0xa9, 0xcf, 0x34, 0xe2,
|
||||
0x76, 0x67, 0x42, 0xde, 0xcd, 0x46, 0x19, 0xca, 0x25, 0x15, 0xad, 0xc9, 0xf5, 0xba, 0x0a, 0xc5,
|
||||
0x13, 0x21, 0xc2, 0x9a, 0x56, 0xad, 0x6a, 0xf5, 0x32, 0x32, 0x9a, 0xb5, 0x9a, 0x0c, 0xb7, 0xc4,
|
||||
0x93, 0xe1, 0x08, 0x38, 0xef, 0xaa, 0x66, 0x98, 0xe2, 0x2c, 0xfd, 0x14, 0xe0, 0xa0, 0xb1, 0xa6,
|
||||
0xd7, 0x35, 0x53, 0x87, 0x5a, 0xbd, 0x2c, 0xce, 0xd1, 0x8f, 0x0c, 0x9a, 0x32, 0x52, 0xbf, 0x6c,
|
||||
0xaa, 0xb0, 0x2e, 0x57, 0x91, 0xdc, 0x2c, 0x69, 0x26, 0x32, 0x4c, 0x1d, 0xca, 0x65, 0x55, 0x04,
|
||||
0xa1, 0x00, 0xfa, 0x06, 0x91, 0xc2, 0x20, 0xba, 0xdb, 0xaa, 0x2b, 0xe2, 0x29, 0x49, 0x04, 0xa7,
|
||||
0x29, 0x5e, 0xdd, 0x84, 0x32, 0xd2, 0x4a, 0xe2, 0x69, 0xe9, 0x1c, 0x38, 0xd3, 0x87, 0x34, 0x14,
|
||||
0xad, 0x26, 0x9e, 0x09, 0xf9, 0x6a, 0x25, 0xb5, 0x6e, 0x6a, 0xe6, 0x16, 0x32, 0x54, 0xa5, 0x09,
|
||||
0xc9, 0x72, 0x9c, 0x5f, 0xf9, 0x11, 0x00, 0x17, 0x63, 0xdf, 0xd1, 0x91, 0x30, 0xa6, 0xd5, 0x4d,
|
||||
0xb5, 0xcc, 0x16, 0x20, 0x52, 0xeb, 0x50, 0xaf, 0x56, 0xd1, 0x86, 0x56, 0x1f, 0xfd, 0x7c, 0xe2,
|
||||
0x0d, 0xb0, 0x9c, 0x04, 0x68, 0x54, 0x65, 0x65, 0x43, 0x14, 0xc8, 0xea, 0x49, 0x02, 0x21, 0x2b,
|
||||
0x42, 0xd7, 0x4a, 0x8a, 0x98, 0x27, 0x89, 0x51, 0x12, 0x54, 0x43, 0x2e, 0xab, 0xb0, 0xd4, 0x34,
|
||||
0xb7, 0xc4, 0xa9, 0x49, 0xfc, 0xd4, 0x9a, 0xac, 0x55, 0xc5, 0x69, 0x92, 0xc5, 0x26, 0x81, 0x3c,
|
||||
0xd5, 0xa0, 0x2c, 0xce, 0x48, 0x37, 0xc1, 0xb5, 0x24, 0x08, 0x6a, 0x9e, 0xb0, 0x24, 0x9e, 0x20,
|
||||
0x2e, 0x27, 0x09, 0xa8, 0x26, 0x9b, 0xa6, 0x0a, 0x6b, 0xba, 0x61, 0x8a, 0x27, 0x27, 0x0d, 0xaf,
|
||||
0x66, 0x20, 0x53, 0x95, 0x6b, 0x86, 0x38, 0x3b, 0x09, 0x4a, 0x6f, 0x18, 0x65, 0xb5, 0xae, 0xa9,
|
||||
0xe2, 0xdc, 0x24, 0xd1, 0xc9, 0x94, 0x8a, 0x60, 0xe2, 0xe0, 0xe4, 0xda, 0xba, 0x78, 0x6a, 0xb2,
|
||||
0xdc, 0x4a, 0x45, 0xab, 0xab, 0xcc, 0x54, 0xde, 0x04, 0x0f, 0xd3, 0xe1, 0x50, 0x59, 0x33, 0x2b,
|
||||
0xcd, 0x35, 0xba, 0xbe, 0xc8, 0xba, 0x3a, 0x23, 0x3d, 0x00, 0xaf, 0x64, 0x40, 0x53, 0x34, 0xa8,
|
||||
0x54, 0x55, 0x45, 0x13, 0xe7, 0x89, 0x5b, 0xcc, 0xc6, 0xa7, 0x2a, 0xaf, 0x89, 0x67, 0x49, 0xe8,
|
||||
0xcd, 0x00, 0xfe, 0x54, 0xad, 0x6f, 0x68, 0x75, 0x43, 0x14, 0x33, 0xc2, 0xcb, 0x75, 0x43, 0x5b,
|
||||
0xab, 0xaa, 0xe2, 0xb9, 0x49, 0xea, 0x21, 0x41, 0x5a, 0x53, 0xd4, 0xba, 0xbe, 0x29, 0x4a, 0x93,
|
||||
0x26, 0xac, 0xbf, 0xde, 0xce, 0x93, 0x80, 0x96, 0x68, 0x49, 0xb2, 0x29, 0x97, 0xf4, 0x32, 0xd2,
|
||||
0xea, 0x0a, 0x5d, 0x7b, 0xa8, 0x26, 0xd7, 0xe5, 0xb2, 0x5a, 0x53, 0xeb, 0xa6, 0x78, 0x81, 0x64,
|
||||
0x23, 0x59, 0xc4, 0xde, 0x24, 0x69, 0x5f, 0x36, 0x58, 0x92, 0xeb, 0x2e, 0x90, 0x28, 0x9e, 0x85,
|
||||
0x2e, 0xcd, 0x5b, 0x68, 0x82, 0x97, 0x01, 0x9a, 0xe6, 0x9f, 0x55, 0xb2, 0x71, 0x28, 0x48, 0x0f,
|
||||
0xc1, 0x6b, 0x19, 0x30, 0x22, 0x7b, 0xc6, 0xcb, 0x93, 0x2c, 0x86, 0xac, 0xff, 0xbe, 0x63, 0x52,
|
||||
0xd4, 0xba, 0xa9, 0x42, 0x71, 0x71, 0xd2, 0x94, 0x72, 0x73, 0x84, 0x6a, 0x43, 0xe7, 0x9e, 0x54,
|
||||
0x5c, 0xca, 0x68, 0x61, 0x32, 0x2c, 0xeb, 0x4a, 0x49, 0xbc, 0x22, 0x7d, 0x00, 0xde, 0x7b, 0x6e,
|
||||
0xc3, 0x8f, 0x8e, 0x68, 0x79, 0xe5, 0xaf, 0x67, 0x62, 0xfc, 0xa6, 0x11, 0xe0, 0x6e, 0x82, 0xdf,
|
||||
0x34, 0x4c, 0xb5, 0x31, 0xe2, 0x37, 0xe3, 0xc7, 0x48, 0x01, 0xe5, 0x4d, 0x43, 0x53, 0xc2, 0x20,
|
||||
0xc7, 0xdc, 0xa3, 0x20, 0x7d, 0x09, 0xbc, 0x33, 0x19, 0xde, 0x50, 0x4d, 0xae, 0x11, 0x12, 0x6f,
|
||||
0x50, 0x49, 0x5d, 0x97, 0x9b, 0x55, 0x13, 0xe9, 0x9b, 0x24, 0x56, 0xe5, 0xa5, 0x2f, 0x82, 0xb7,
|
||||
0x27, 0xe3, 0x37, 0x1b, 0x55, 0x5d, 0x66, 0x33, 0x42, 0xf3, 0x2a, 0xa3, 0x81, 0x6a, 0xaa, 0x29,
|
||||
0x13, 0x2b, 0x16, 0xa7, 0x48, 0xb2, 0x3a, 0x19, 0xdd, 0x54, 0x0d, 0x93, 0x46, 0x9c, 0x50, 0x70,
|
||||
0x92, 0x8f, 0x4d, 0x27, 0xac, 0x0f, 0x8a, 0xc7, 0x14, 0x0c, 0x65, 0xa4, 0x40, 0x55, 0x36, 0x55,
|
||||
0x14, 0x81, 0x13, 0x67, 0x26, 0x31, 0x1c, 0x45, 0x2c, 0x6b, 0xe1, 0x96, 0x4d, 0x3c, 0x91, 0x8d,
|
||||
0x21, 0xfd, 0x22, 0x2f, 0xd9, 0x55, 0x18, 0x46, 0x05, 0x29, 0x2a, 0x24, 0x6e, 0x3c, 0x7e, 0x29,
|
||||
0xc4, 0x32, 0x84, 0x24, 0x81, 0x9b, 0x25, 0x29, 0x70, 0x12, 0x46, 0x6d, 0x53, 0x2b, 0x57, 0xe4,
|
||||
0x8d, 0x27, 0x46, 0x7f, 0x1a, 0x19, 0x0d, 0x71, 0x6e, 0xd2, 0xc0, 0x86, 0xb0, 0xb8, 0x84, 0xdc,
|
||||
0xc8, 0x41, 0x36, 0x6e, 0x86, 0x6a, 0x36, 0x1b, 0x68, 0x53, 0x87, 0x1b, 0xeb, 0x55, 0x7d, 0x53,
|
||||
0x3c, 0x95, 0xb0, 0x34, 0x46, 0xb0, 0x36, 0xd5, 0xaa, 0xa2, 0xd7, 0x54, 0xf1, 0xf4, 0xca, 0xcf,
|
||||
0x85, 0xd8, 0x77, 0xe3, 0xe1, 0x9b, 0xef, 0x44, 0xab, 0xa5, 0x99, 0x9c, 0xa2, 0x97, 0x46, 0x8f,
|
||||
0x9b, 0xe2, 0x3d, 0x57, 0x14, 0x7e, 0x90, 0x53, 0x66, 0x80, 0xed, 0xa7, 0x98, 0xf7, 0xc0, 0xad,
|
||||
0x14, 0xd8, 0x30, 0xe3, 0x4c, 0xa7, 0x3a, 0x48, 0x40, 0xff, 0x26, 0x0f, 0x0a, 0x49, 0xc7, 0xac,
|
||||
0x49, 0x84, 0x98, 0xa5, 0x8f, 0x0c, 0x3b, 0xde, 0xc3, 0x84, 0xb0, 0x03, 0xc5, 0x87, 0x3e, 0xa6,
|
||||
0xf4, 0x8c, 0x6c, 0x4d, 0x48, 0x26, 0xc0, 0xa2, 0xac, 0x90, 0x99, 0x42, 0x64, 0x13, 0x52, 0x95,
|
||||
0xd7, 0xd4, 0x2a, 0x6a, 0x68, 0xca, 0x06, 0x5d, 0xf0, 0x25, 0xf0, 0xc1, 0xf3, 0x52, 0x18, 0x93,
|
||||
0x63, 0x4a, 0xaa, 0x80, 0xd2, 0xf3, 0x52, 0xe9, 0xef, 0x45, 0x60, 0xb3, 0xaa, 0x86, 0xf2, 0x4c,
|
||||
0xaf, 0xfc, 0x64, 0x06, 0x2c, 0xc4, 0x9f, 0x13, 0x27, 0xcc, 0xe6, 0xba, 0xa6, 0x56, 0x47, 0xb3,
|
||||
0x95, 0xf4, 0x48, 0xaa, 0x92, 0x83, 0x57, 0xfa, 0xd2, 0xc4, 0x00, 0x49, 0x3f, 0x10, 0xc0, 0xad,
|
||||
0x88, 0x18, 0x1e, 0x2f, 0x69, 0x44, 0xad, 0xf0, 0xad, 0x53, 0x28, 0xca, 0x49, 0x2a, 0xca, 0x97,
|
||||
0xd2, 0x45, 0x99, 0xf4, 0x5a, 0xaa, 0x92, 0x83, 0xd7, 0xfb, 0xe2, 0x24, 0x00, 0x86, 0x9a, 0xf1,
|
||||
0xf8, 0xfb, 0x23, 0x44, 0xf6, 0xae, 0x64, 0x01, 0xb2, 0xf7, 0x4f, 0x7c, 0xba, 0x66, 0x53, 0x35,
|
||||
0x93, 0xf2, 0x7a, 0x8a, 0x69, 0x26, 0x19, 0x48, 0xfa, 0x18, 0x5c, 0x89, 0x93, 0xa2, 0x7b, 0xcc,
|
||||
0x25, 0x98, 0xa3, 0x12, 0x7c, 0x21, 0xbb, 0x04, 0xd1, 0xe7, 0x57, 0x95, 0x1c, 0x2c, 0x8c, 0x71,
|
||||
0xe7, 0x00, 0xd2, 0xff, 0x00, 0xcb, 0xe3, 0x9c, 0xbb, 0x9e, 0xd3, 0x09, 0x38, 0x6b, 0x40, 0x59,
|
||||
0xbf, 0x95, 0x95, 0xf5, 0xc8, 0xe3, 0xad, 0x4a, 0x0e, 0x5e, 0x1e, 0xe1, 0x3d, 0x80, 0x90, 0xda,
|
||||
0xe0, 0x72, 0xcf, 0x41, 0x36, 0x77, 0xe2, 0x24, 0xeb, 0xf2, 0x48, 0x28, 0xa1, 0xc4, 0x69, 0x50,
|
||||
0x3b, 0x35, 0x61, 0x63, 0x15, 0xff, 0x04, 0xaa, 0x92, 0x83, 0x0b, 0x3d, 0x27, 0xf6, 0x71, 0xd4,
|
||||
0x77, 0x98, 0xf9, 0xf5, 0xd9, 0x0d, 0x62, 0x5d, 0x58, 0x07, 0xc6, 0x39, 0x9f, 0xa6, 0x9c, 0xdf,
|
||||
0xce, 0xc0, 0x39, 0xfe, 0x55, 0x13, 0xb3, 0xbc, 0x94, 0x97, 0x4f, 0xdf, 0xa0, 0x86, 0xd7, 0x17,
|
||||
0x86, 0xd7, 0xce, 0xfb, 0xac, 0x0c, 0x9e, 0x0b, 0x72, 0x86, 0x0a, 0xf2, 0xe6, 0xa7, 0x2a, 0xa2,
|
||||
0x67, 0x36, 0x37, 0xe1, 0xd1, 0xc3, 0xff, 0x65, 0x0e, 0x74, 0x20, 0x01, 0x4f, 0xe8, 0x07, 0xeb,
|
||||
0x92, 0x09, 0x31, 0x4f, 0x85, 0x78, 0x92, 0x45, 0x88, 0xb8, 0x5a, 0xe5, 0x4a, 0x0e, 0x5e, 0x8b,
|
||||
0xc8, 0x11, 0x5b, 0xce, 0xfc, 0xeb, 0xcc, 0x7b, 0x8e, 0x8b, 0xd2, 0x0a, 0xcb, 0x54, 0xd0, 0x41,
|
||||
0xd0, 0xf6, 0xb9, 0x40, 0x67, 0xa9, 0x40, 0x5f, 0x7c, 0x0e, 0x81, 0xc6, 0xab, 0x87, 0x2b, 0x39,
|
||||
0x78, 0x6b, 0x5c, 0xaa, 0x01, 0x5c, 0xd0, 0xe6, 0x05, 0x94, 0x7f, 0x2a, 0x80, 0x27, 0xc3, 0xf3,
|
||||
0x44, 0x6b, 0x4f, 0x91, 0x45, 0x8b, 0x4f, 0x91, 0x1d, 0x56, 0x9f, 0xa2, 0xc0, 0x75, 0xdb, 0x3c,
|
||||
0x99, 0x6c, 0xb7, 0xb9, 0xa4, 0x22, 0x95, 0xf4, 0x69, 0xa6, 0xf9, 0xcb, 0x54, 0xe3, 0x5b, 0xc9,
|
||||
0xc1, 0x87, 0xd1, 0x49, 0xcd, 0x56, 0x18, 0xfc, 0x13, 0x01, 0x3c, 0xce, 0x34, 0x86, 0x81, 0xba,
|
||||
0x99, 0xfc, 0xe7, 0xa8, 0xfc, 0xe5, 0x4f, 0x2d, 0xff, 0x70, 0x95, 0x51, 0x25, 0x07, 0x57, 0xd3,
|
||||
0x84, 0x1f, 0xa9, 0x4b, 0xfa, 0x4d, 0x01, 0xbc, 0x12, 0x95, 0xdc, 0xea, 0x91, 0xcc, 0xa3, 0xbf,
|
||||
0x07, 0x8d, 0xbc, 0xa7, 0x62, 0x02, 0x4b, 0x54, 0xe0, 0xf7, 0x33, 0x08, 0x3c, 0xa9, 0x6a, 0xb6,
|
||||
0x92, 0x83, 0x77, 0x06, 0x82, 0x4e, 0xac, 0xaf, 0xfd, 0x43, 0x01, 0x3c, 0x48, 0xb1, 0x5c, 0xc7,
|
||||
0x3a, 0x60, 0x9b, 0x97, 0x63, 0x2e, 0xe4, 0x79, 0x2a, 0xe4, 0xda, 0xa7, 0xb1, 0xdf, 0xe1, 0xc2,
|
||||
0xb5, 0x4a, 0x0e, 0xde, 0x9f, 0x60, 0xc4, 0x9a, 0x75, 0x10, 0xad, 0x72, 0xfb, 0x15, 0x01, 0xdc,
|
||||
0x89, 0x8a, 0xda, 0xed, 0x17, 0x83, 0x8d, 0xcd, 0xfb, 0x05, 0x2a, 0xe1, 0xbb, 0x19, 0x24, 0x4c,
|
||||
0xaa, 0x28, 0xab, 0xe4, 0x60, 0x71, 0x20, 0x5a, 0x62, 0xdd, 0xd9, 0xb7, 0x04, 0x70, 0x23, 0x2a,
|
||||
0x53, 0x80, 0xfd, 0x80, 0x48, 0xd3, 0x19, 0xf2, 0xc7, 0x17, 0x53, 0xa3, 0xdf, 0x84, 0xf2, 0xae,
|
||||
0x4a, 0x0e, 0x2e, 0x0f, 0x24, 0x89, 0xab, 0xff, 0xf2, 0xc0, 0x52, 0x54, 0x86, 0x30, 0xcf, 0x0d,
|
||||
0xe3, 0xd0, 0x42, 0xca, 0x0d, 0x62, 0x52, 0x7d, 0x15, 0x0b, 0xbb, 0x09, 0xb5, 0x57, 0x6d, 0x50,
|
||||
0xe8, 0x39, 0x24, 0x09, 0xb3, 0x02, 0x8c, 0x3a, 0xf8, 0x88, 0xee, 0x7f, 0x79, 0xc4, 0xbd, 0x94,
|
||||
0x72, 0xc0, 0x95, 0x58, 0xd9, 0x54, 0xc9, 0xc1, 0x0b, 0x3d, 0x67, 0xbc, 0x53, 0x3a, 0xa6, 0x41,
|
||||
0x7e, 0x94, 0x9b, 0x6f, 0x1d, 0x86, 0x2c, 0x0b, 0xa9, 0x1a, 0x9e, 0x50, 0x2e, 0xc5, 0x06, 0x1a,
|
||||
0x0f, 0x20, 0x7d, 0x03, 0x5c, 0x8b, 0x1b, 0x28, 0xad, 0x50, 0xe2, 0xcc, 0x2f, 0xa7, 0x06, 0x98,
|
||||
0x89, 0xd5, 0x4d, 0x95, 0x1c, 0x5c, 0x1c, 0x1d, 0xf5, 0x00, 0x44, 0xfa, 0x1d, 0xe6, 0x42, 0x46,
|
||||
0x25, 0x60, 0xf7, 0x70, 0xd1, 0x0a, 0x28, 0x2e, 0xcd, 0x22, 0x95, 0x46, 0xc9, 0x2a, 0xcd, 0x84,
|
||||
0x42, 0xaa, 0x4a, 0x0e, 0xde, 0x1e, 0x11, 0x2c, 0x1e, 0x5a, 0xfa, 0x7d, 0x01, 0xac, 0x46, 0x4d,
|
||||
0xd0, 0x19, 0x1c, 0x3b, 0x22, 0xeb, 0xc8, 0x67, 0x47, 0x03, 0x7c, 0x59, 0x70, 0xab, 0x5c, 0x4a,
|
||||
0xdd, 0x42, 0x64, 0x7b, 0x79, 0x5c, 0xc9, 0xc1, 0x7b, 0x03, 0x2b, 0x8d, 0xc2, 0x1e, 0xf9, 0xba,
|
||||
0x63, 0xb7, 0x86, 0x5e, 0x29, 0x7f, 0x57, 0x00, 0xb7, 0xe3, 0x53, 0x06, 0xdb, 0x47, 0x98, 0x1e,
|
||||
0x90, 0x72, 0xf1, 0xae, 0x64, 0x4e, 0xa1, 0xe2, 0x1f, 0x04, 0x0f, 0xa7, 0x50, 0x7d, 0x18, 0xdb,
|
||||
0x8f, 0x3e, 0x7f, 0x0d, 0x98, 0x59, 0x93, 0x78, 0x1b, 0xb8, 0x88, 0x95, 0x06, 0xb1, 0x59, 0xe4,
|
||||
0x52, 0x2c, 0xa7, 0x2e, 0xdd, 0xf8, 0x17, 0xa6, 0xdc, 0xa2, 0xe3, 0x5f, 0x9f, 0x7e, 0x15, 0x9c,
|
||||
0xb3, 0x68, 0x8d, 0x12, 0x1a, 0x54, 0x08, 0x15, 0xae, 0x52, 0x4e, 0xc9, 0x07, 0xc9, 0xb1, 0xf5,
|
||||
0x74, 0x95, 0x1c, 0x14, 0xad, 0x91, 0x8e, 0xd0, 0x25, 0x46, 0x4d, 0x80, 0x6b, 0x96, 0xa6, 0xc7,
|
||||
0x7c, 0x64, 0xd7, 0x52, 0x17, 0xec, 0x84, 0x9b, 0x4c, 0xe6, 0x12, 0x27, 0x5d, 0x75, 0xf2, 0x54,
|
||||
0x39, 0x46, 0x88, 0xfe, 0x29, 0x00, 0x93, 0xe3, 0x7a, 0xea, 0x3c, 0x4f, 0xbe, 0xe0, 0x64, 0xf3,
|
||||
0x9c, 0x72, 0x09, 0xfa, 0xbf, 0x04, 0xea, 0x44, 0xc2, 0x7d, 0xe3, 0xd7, 0xa2, 0xdf, 0xd8, 0x08,
|
||||
0xb7, 0x8c, 0x37, 0xb2, 0xee, 0x5e, 0x93, 0xbe, 0xd0, 0x31, 0xb4, 0x7b, 0x8d, 0x01, 0x92, 0x3e,
|
||||
0x02, 0x7c, 0xb2, 0x10, 0x0e, 0xcb, 0x0b, 0x0b, 0x45, 0xca, 0xf5, 0xb5, 0x94, 0x69, 0x1f, 0x2e,
|
||||
0x47, 0xac, 0xe4, 0xe0, 0x59, 0x6b, 0xb8, 0x5d, 0x3a, 0x00, 0x97, 0x38, 0x6d, 0xe2, 0xa0, 0xa2,
|
||||
0x55, 0x89, 0x85, 0x9b, 0x29, 0x27, 0xf7, 0xc9, 0xc5, 0x81, 0x95, 0x1c, 0xbc, 0x68, 0xc5, 0xf5,
|
||||
0x4a, 0xdb, 0xe0, 0xe2, 0xe0, 0x94, 0x84, 0x39, 0x46, 0x36, 0x9d, 0xb7, 0x28, 0xb3, 0x57, 0x13,
|
||||
0x99, 0xc5, 0xdc, 0x6d, 0x54, 0x72, 0xf0, 0xbc, 0x17, 0x73, 0xe5, 0x71, 0x04, 0xae, 0x24, 0x1c,
|
||||
0xae, 0x33, 0x56, 0xb7, 0x53, 0xc6, 0x95, 0x7c, 0x21, 0x40, 0x1c, 0xfe, 0x4e, 0xf2, 0x75, 0xc1,
|
||||
0x36, 0xe0, 0xa3, 0x46, 0xbc, 0x20, 0xc1, 0x63, 0x75, 0x8f, 0x85, 0x3b, 0x29, 0x83, 0x8b, 0xa9,
|
||||
0x95, 0x24, 0x83, 0xb3, 0x62, 0x4a, 0x28, 0xab, 0xe0, 0x4c, 0x9f, 0x07, 0x9d, 0xa5, 0xbb, 0x94,
|
||||
0xf6, 0xed, 0x54, 0xda, 0x04, 0xb8, 0x92, 0x83, 0xa7, 0xad, 0x68, 0x95, 0xe3, 0x16, 0x90, 0xa2,
|
||||
0xb5, 0x13, 0x6c, 0x46, 0x0a, 0xf7, 0x52, 0x4a, 0xb2, 0x47, 0x8b, 0xfc, 0xa8, 0x37, 0x19, 0x2d,
|
||||
0xfc, 0x1b, 0x21, 0xdd, 0xa3, 0x05, 0x63, 0x85, 0xfb, 0x99, 0x49, 0xb3, 0x0a, 0xb3, 0x61, 0xd2,
|
||||
0xbc, 0xea, 0x6c, 0x84, 0xb4, 0x4d, 0x0b, 0x4a, 0x0a, 0x2b, 0x99, 0x49, 0xb3, 0x0a, 0x94, 0x61,
|
||||
0xd2, 0xbc, 0x2a, 0xa5, 0x0d, 0x2e, 0x47, 0x49, 0xf3, 0x9a, 0x2e, 0xae, 0x97, 0x57, 0x52, 0xce,
|
||||
0x05, 0xe2, 0x8b, 0xfc, 0x2a, 0x39, 0xb8, 0x60, 0xc5, 0x97, 0xff, 0xc5, 0x73, 0xe3, 0xaa, 0x7a,
|
||||
0xf5, 0x39, 0xb9, 0xf5, 0x15, 0x36, 0xc6, 0x8d, 0xab, 0x2d, 0x9e, 0x1b, 0xd7, 0xde, 0x6b, 0xcf,
|
||||
0xc9, 0xad, 0xaf, 0xc3, 0x31, 0x6e, 0x5c, 0x93, 0x07, 0x60, 0x31, 0xca, 0x8d, 0x96, 0x7a, 0xf9,
|
||||
0x24, 0x5a, 0xf6, 0x7c, 0xec, 0x15, 0x56, 0x33, 0xb3, 0x8b, 0xd6, 0xbb, 0x0d, 0xb3, 0x1b, 0xaa,
|
||||
0x84, 0xfb, 0x7f, 0x02, 0x28, 0x46, 0x13, 0x84, 0xe8, 0x4d, 0xd2, 0xe0, 0x98, 0xa5, 0xf0, 0x20,
|
||||
0xf5, 0x4c, 0x36, 0xf5, 0xb5, 0x1e, 0x3b, 0x93, 0xed, 0x83, 0xb5, 0xc6, 0xc1, 0xa4, 0x7d, 0x70,
|
||||
0x29, 0xe6, 0x84, 0x05, 0x3b, 0x2d, 0x5c, 0x78, 0x3d, 0x35, 0xc5, 0x4e, 0x78, 0x2b, 0xc7, 0x52,
|
||||
0xec, 0x91, 0x4e, 0xa7, 0x85, 0x47, 0x99, 0x85, 0xe9, 0xa6, 0x6b, 0xe3, 0xc2, 0xc3, 0xcc, 0xcc,
|
||||
0x46, 0xde, 0xa7, 0x0d, 0x33, 0x1b, 0x74, 0x4a, 0x5f, 0x01, 0xe7, 0x02, 0x6b, 0x97, 0xc7, 0x21,
|
||||
0x4c, 0x02, 0xa2, 0x77, 0x5c, 0x78, 0x94, 0x12, 0x8b, 0xe2, 0x2e, 0x1c, 0x49, 0x2c, 0x0a, 0xac,
|
||||
0xdd, 0x68, 0xbb, 0x14, 0x80, 0x45, 0x9f, 0x5f, 0xcf, 0x20, 0x8f, 0x52, 0x42, 0xbb, 0x98, 0x1e,
|
||||
0x64, 0xf7, 0xda, 0x41, 0xe1, 0x8d, 0x94, 0x23, 0xa9, 0x49, 0x37, 0x3b, 0x95, 0x1c, 0xbc, 0xe4,
|
||||
0xc7, 0xf7, 0x8f, 0x2e, 0x0b, 0x5e, 0x3f, 0xc6, 0x97, 0xfc, 0xe3, 0xcc, 0x76, 0x1a, 0xad, 0x3a,
|
||||
0x1c, 0xb6, 0xd3, 0xa1, 0x7a, 0xc4, 0x78, 0x6e, 0x7c, 0x11, 0xbe, 0xf9, 0x9c, 0xdc, 0xe2, 0x16,
|
||||
0xe1, 0x50, 0x91, 0xdd, 0x36, 0xb8, 0x18, 0x1a, 0xc6, 0x31, 0xda, 0xc1, 0x41, 0x6b, 0x8f, 0xc7,
|
||||
0xc0, 0x2f, 0xa4, 0x44, 0xa4, 0x98, 0xeb, 0x2d, 0x12, 0x91, 0xec, 0x98, 0x5b, 0xaf, 0xef, 0x8d,
|
||||
0x9c, 0xe6, 0x71, 0x03, 0x1c, 0xf0, 0x65, 0x7b, 0xfc, 0xc2, 0x5b, 0x99, 0x0f, 0xcf, 0x92, 0x3f,
|
||||
0xb3, 0x30, 0x7c, 0xa4, 0x17, 0x0b, 0x27, 0x7d, 0x73, 0x64, 0x67, 0xbf, 0xdf, 0xdb, 0xc6, 0xf4,
|
||||
0x72, 0x76, 0x68, 0x9b, 0xf0, 0x24, 0xf3, 0x01, 0xe7, 0xf8, 0xd7, 0x6f, 0x86, 0x0f, 0x38, 0x69,
|
||||
0xff, 0xfe, 0xd0, 0xf6, 0xe0, 0xdb, 0xf1, 0x2a, 0xb1, 0xba, 0x5d, 0x7a, 0xcc, 0xda, 0x3f, 0xe0,
|
||||
0x7c, 0x3b, 0xf5, 0x84, 0x7b, 0xd2, 0x33, 0xca, 0x61, 0x47, 0x14, 0xfb, 0xd0, 0xb2, 0x0b, 0x96,
|
||||
0xb8, 0xb5, 0xed, 0x7a, 0x56, 0x77, 0x8f, 0x6e, 0xe9, 0xfc, 0x96, 0x15, 0x66, 0x42, 0xef, 0x50,
|
||||
0xfe, 0xaf, 0xa7, 0xd8, 0xdb, 0xd8, 0x7d, 0x3d, 0x59, 0x4d, 0x56, 0xa4, 0xeb, 0xc8, 0x1f, 0x5c,
|
||||
0xe5, 0x7f, 0x9f, 0x6d, 0xd4, 0x86, 0xb8, 0xb6, 0x3c, 0xf7, 0xa8, 0x83, 0xfe, 0x3b, 0x3e, 0xc2,
|
||||
0x6d, 0x64, 0x3b, 0x3b, 0x3b, 0x74, 0x0b, 0x5c, 0x78, 0x37, 0xd5, 0x1e, 0xd2, 0x6f, 0x90, 0x99,
|
||||
0x3d, 0x4c, 0x84, 0x93, 0xfe, 0x1b, 0xb8, 0x48, 0x8b, 0x38, 0xe8, 0xbd, 0x29, 0xbd, 0xf3, 0xe4,
|
||||
0xa3, 0x7f, 0x2f, 0xed, 0xa6, 0x72, 0xec, 0xfa, 0xb5, 0x92, 0x83, 0x52, 0x6f, 0xfc, 0x52, 0x96,
|
||||
0x1d, 0xa8, 0xc7, 0xee, 0x9b, 0x70, 0x97, 0x33, 0xfb, 0x62, 0xaa, 0xbd, 0x25, 0xd7, 0x26, 0x32,
|
||||
0x7b, 0x9b, 0x50, 0xbb, 0xf8, 0x6b, 0x02, 0xb8, 0x97, 0x20, 0x01, 0x3f, 0xce, 0x72, 0xbb, 0x38,
|
||||
0x9c, 0xf4, 0x2f, 0xa5, 0x86, 0xc0, 0xd4, 0x12, 0x41, 0x76, 0xfb, 0x97, 0x5e, 0x49, 0xf8, 0x89,
|
||||
0x00, 0x56, 0xe2, 0xe5, 0xa2, 0x35, 0x68, 0xa3, 0x5b, 0xba, 0xf7, 0x53, 0x2f, 0xdf, 0x32, 0xd4,
|
||||
0xec, 0xb1, 0xb3, 0x8f, 0x2c, 0xc5, 0x7d, 0xfc, 0x4c, 0x21, 0x76, 0xab, 0x49, 0x9f, 0x62, 0x75,
|
||||
0xc3, 0x73, 0xd3, 0x0f, 0x3e, 0xcd, 0x5e, 0x33, 0x52, 0x47, 0x97, 0xb8, 0xd7, 0x8c, 0xd6, 0xda,
|
||||
0x7d, 0x9f, 0x9d, 0x92, 0xc6, 0x88, 0xd3, 0x76, 0x3a, 0xfb, 0x43, 0xa7, 0x0b, 0x72, 0xea, 0x96,
|
||||
0x33, 0xa5, 0xac, 0xad, 0x92, 0x83, 0x37, 0x62, 0x04, 0x1a, 0x06, 0x5a, 0x3b, 0x09, 0x66, 0x28,
|
||||
0xcd, 0xa7, 0xd3, 0xb3, 0x79, 0x71, 0x8a, 0xd8, 0x60, 0x7f, 0x27, 0x4c, 0xe2, 0x72, 0x78, 0x69,
|
||||
0x46, 0x25, 0x5b, 0xf9, 0x91, 0x38, 0xf8, 0x20, 0x62, 0xb8, 0x59, 0x93, 0x6e, 0x80, 0xe5, 0x92,
|
||||
0x66, 0x28, 0xfa, 0x33, 0x15, 0x22, 0xa8, 0x1a, 0x7a, 0x13, 0x2a, 0xa3, 0x9f, 0x33, 0xba, 0x02,
|
||||
0x0a, 0xe3, 0x20, 0x86, 0x0a, 0x9f, 0xa9, 0x50, 0x14, 0xa4, 0xeb, 0xe0, 0xca, 0x78, 0xef, 0x46,
|
||||
0x73, 0x4d, 0x85, 0x75, 0xd5, 0x54, 0x0d, 0x31, 0x2f, 0xbd, 0x01, 0x1e, 0x8c, 0x43, 0x94, 0x64,
|
||||
0x53, 0x5e, 0x93, 0x0d, 0x15, 0x35, 0x74, 0xc3, 0x2c, 0x43, 0xd5, 0x40, 0x86, 0x5a, 0x5d, 0x47,
|
||||
0x15, 0xdd, 0x30, 0xd5, 0x92, 0x38, 0x25, 0xbd, 0x0e, 0x5e, 0x9d, 0x80, 0x54, 0xdb, 0x32, 0x3e,
|
||||
0xac, 0x0e, 0x61, 0x4c, 0x4b, 0x8f, 0xc0, 0xea, 0x24, 0x0c, 0xbd, 0x5e, 0xd6, 0x4b, 0x6b, 0x43,
|
||||
0x38, 0x33, 0xd2, 0x2b, 0xe0, 0x6e, 0x16, 0xd1, 0x60, 0xc9, 0x10, 0x4f, 0x48, 0xf7, 0xc0, 0xad,
|
||||
0x54, 0x91, 0x08, 0xe4, 0x49, 0xe9, 0x0e, 0x28, 0x8e, 0x43, 0xca, 0x8d, 0x46, 0x55, 0x53, 0x64,
|
||||
0x53, 0xd3, 0xeb, 0xa8, 0x62, 0x9a, 0x0d, 0x71, 0x56, 0xba, 0x0d, 0x6e, 0x4c, 0x86, 0x33, 0x95,
|
||||
0x86, 0x38, 0x17, 0x0f, 0xb6, 0xa9, 0xd5, 0x4b, 0xfa, 0xa6, 0x81, 0x4a, 0xaa, 0xb1, 0x61, 0xea,
|
||||
0x0d, 0x11, 0x48, 0xaf, 0x82, 0x7b, 0x13, 0xe4, 0x33, 0x3e, 0xac, 0xb2, 0x39, 0xa3, 0x32, 0x9e,
|
||||
0x4a, 0x51, 0xf0, 0x60, 0xe8, 0x6a, 0xc9, 0xa8, 0x68, 0xeb, 0xa6, 0x78, 0x5a, 0x7a, 0x0c, 0x5e,
|
||||
0xcf, 0x44, 0x3f, 0xaa, 0xe2, 0x33, 0x29, 0x7c, 0xa0, 0x5a, 0xd2, 0x86, 0xa7, 0x7e, 0x3e, 0xeb,
|
||||
0xa4, 0x94, 0x95, 0x86, 0x78, 0x36, 0xd3, 0xa4, 0x10, 0x48, 0x31, 0xb3, 0x7a, 0x08, 0xf4, 0x39,
|
||||
0xe9, 0x5d, 0xf0, 0xd6, 0xf3, 0xa8, 0x87, 0xaf, 0x87, 0xaa, 0x6a, 0x18, 0xa2, 0x24, 0xbd, 0x06,
|
||||
0xee, 0x67, 0x41, 0x96, 0x3f, 0x6a, 0x42, 0x55, 0x3c, 0x2f, 0xdd, 0x05, 0x37, 0x27, 0x80, 0x97,
|
||||
0xb6, 0xea, 0x72, 0x4d, 0x2f, 0xad, 0x89, 0x17, 0x52, 0x4c, 0x5c, 0x91, 0x0d, 0x43, 0xae, 0x97,
|
||||
0xa0, 0x8c, 0x36, 0xd4, 0x2d, 0xa3, 0x21, 0x2b, 0xaa, 0x21, 0x5e, 0x4c, 0x99, 0xb5, 0x01, 0x4e,
|
||||
0x74, 0x0e, 0x16, 0xa4, 0x27, 0xe0, 0xf1, 0x04, 0x2c, 0xb5, 0x2a, 0x1b, 0xa6, 0xa6, 0x18, 0xaa,
|
||||
0x0c, 0x95, 0xca, 0x10, 0xe6, 0xa5, 0x4c, 0xf3, 0xcd, 0xf1, 0x65, 0xa5, 0xa2, 0x8a, 0x85, 0x14,
|
||||
0x6d, 0x31, 0x8c, 0x9a, 0x5a, 0xd3, 0xe1, 0x56, 0x69, 0x4d, 0xbc, 0x9c, 0x89, 0x01, 0xd5, 0x2c,
|
||||
0x62, 0x0c, 0x16, 0x53, 0x06, 0xc3, 0x30, 0x94, 0x6a, 0xd3, 0x30, 0x47, 0x8c, 0x77, 0x49, 0x5a,
|
||||
0x01, 0x77, 0x52, 0xad, 0x8b, 0xcd, 0xe2, 0x15, 0x69, 0x15, 0xac, 0x64, 0xb2, 0x2f, 0x06, 0xbf,
|
||||
0x9c, 0x32, 0x99, 0x03, 0xf8, 0x9a, 0xa6, 0x40, 0xdd, 0xd0, 0xd7, 0x4d, 0xf1, 0xaa, 0xf4, 0x05,
|
||||
0xf0, 0x68, 0xd2, 0x64, 0xea, 0xca, 0x06, 0xd4, 0x65, 0xa5, 0x32, 0xe2, 0xe7, 0xae, 0xa5, 0xd8,
|
||||
0x7e, 0xe8, 0x1b, 0x65, 0xb3, 0x2a, 0x1b, 0xe2, 0xf5, 0x94, 0x35, 0x65, 0xd4, 0xf5, 0xcd, 0xf5,
|
||||
0xaa, 0xbc, 0xa1, 0x8a, 0x37, 0x12, 0xe8, 0xea, 0x4a, 0x44, 0xbb, 0x25, 0x03, 0x35, 0xa0, 0xfe,
|
||||
0xe5, 0x2d, 0xb1, 0x98, 0x60, 0x8a, 0x51, 0xe8, 0x8a, 0x56, 0xae, 0x20, 0xf9, 0x99, 0xac, 0x55,
|
||||
0xe5, 0x35, 0xad, 0xaa, 0x99, 0x5b, 0xe2, 0x4d, 0xe9, 0x2d, 0xf0, 0x46, 0x0a, 0x16, 0x5d, 0x21,
|
||||
0x9a, 0x82, 0xa0, 0x5a, 0xd6, 0x0c, 0x13, 0x52, 0xd7, 0x29, 0xde, 0x8a, 0xf7, 0xc2, 0x86, 0x5c,
|
||||
0xab, 0x46, 0x5d, 0xac, 0x78, 0x5b, 0x2a, 0x82, 0xab, 0xe3, 0x70, 0xaa, 0xf2, 0x88, 0x7d, 0xb8,
|
||||
0xaf, 0xae, 0xa8, 0xe2, 0x9d, 0x04, 0xa3, 0xd3, 0x95, 0x51, 0x37, 0x8c, 0xea, 0x7a, 0x1d, 0xc9,
|
||||
0x25, 0xf1, 0xae, 0x74, 0x0b, 0x5c, 0x9f, 0x14, 0x17, 0xe9, 0x07, 0xdd, 0xee, 0xc5, 0xdb, 0x7e,
|
||||
0x34, 0x02, 0xc8, 0x9b, 0x06, 0x52, 0xf4, 0xba, 0xa1, 0x57, 0x55, 0xf1, 0xbe, 0x74, 0x0d, 0x2c,
|
||||
0x8d, 0x83, 0xd7, 0x94, 0x06, 0x32, 0xcc, 0x92, 0xa6, 0x8b, 0x2b, 0xf4, 0xb3, 0x87, 0xf1, 0x00,
|
||||
0x86, 0x2a, 0xbe, 0x22, 0xdd, 0x07, 0xb7, 0x93, 0xf0, 0xa1, 0x2a, 0xd7, 0xe4, 0xb5, 0xaa, 0xca,
|
||||
0x62, 0xd3, 0xab, 0x2b, 0xbf, 0x2b, 0x80, 0xf9, 0xe1, 0x4f, 0x0f, 0x0f, 0x71, 0x37, 0x4c, 0xd9,
|
||||
0x6c, 0x1a, 0x23, 0x99, 0xc2, 0x12, 0xb8, 0x34, 0x0a, 0x60, 0x34, 0x15, 0x85, 0x38, 0x45, 0x21,
|
||||
0xb6, 0x73, 0x43, 0x6b, 0x34, 0xd4, 0x92, 0x98, 0x97, 0x2e, 0x83, 0x8b, 0xa3, 0x9d, 0x2a, 0x84,
|
||||
0x3a, 0x14, 0xa7, 0xe2, 0xf0, 0xe4, 0x35, 0x1d, 0xd2, 0xa0, 0xbf, 0xf2, 0xb3, 0x3c, 0x98, 0x52,
|
||||
0x4c, 0x59, 0x3a, 0x0f, 0xce, 0x2a, 0xa6, 0x3c, 0xfe, 0x91, 0x47, 0xd2, 0x28, 0x37, 0xcd, 0x0a,
|
||||
0xd1, 0x61, 0x5d, 0x55, 0x4c, 0x9d, 0xa4, 0x2c, 0x97, 0xc0, 0x79, 0xda, 0xae, 0x98, 0xda, 0x33,
|
||||
0x92, 0xc9, 0x18, 0x86, 0xa6, 0xd7, 0x49, 0xa6, 0xd2, 0xef, 0x20, 0x22, 0x23, 0xa8, 0x7e, 0xd8,
|
||||
0x54, 0x0d, 0xd3, 0x10, 0xa7, 0xc2, 0x8e, 0x06, 0x54, 0x6b, 0x5a, 0xb3, 0x86, 0x8c, 0x66, 0xa3,
|
||||
0xa1, 0x43, 0x53, 0x9c, 0x0e, 0x3b, 0x4c, 0x48, 0xbc, 0x47, 0x09, 0x95, 0xd4, 0x67, 0x1a, 0x71,
|
||||
0xbb, 0x33, 0x21, 0xef, 0x66, 0xa3, 0x0c, 0xe5, 0x92, 0x8a, 0xd6, 0xe4, 0x7a, 0x5d, 0x85, 0xe2,
|
||||
0x89, 0x10, 0x61, 0x4d, 0xab, 0x56, 0xb5, 0x7a, 0x19, 0x19, 0xcd, 0x5a, 0x4d, 0x86, 0x5b, 0xe2,
|
||||
0xc9, 0x70, 0x04, 0x9c, 0x77, 0x55, 0x33, 0x4c, 0x71, 0x96, 0x7e, 0x0a, 0x70, 0xd0, 0x58, 0xd3,
|
||||
0xeb, 0x9a, 0xa9, 0x43, 0xad, 0x5e, 0x16, 0xe7, 0xe8, 0x47, 0x06, 0x4d, 0x19, 0xa9, 0x5f, 0x36,
|
||||
0x55, 0x58, 0x97, 0xab, 0x48, 0x6e, 0x96, 0x34, 0x13, 0x19, 0xa6, 0x0e, 0xe5, 0xb2, 0x2a, 0x82,
|
||||
0x50, 0x00, 0x7d, 0x83, 0x48, 0x61, 0x10, 0xdd, 0x6d, 0xd5, 0x15, 0xf1, 0x94, 0x24, 0x82, 0xd3,
|
||||
0x14, 0xaf, 0x6e, 0x42, 0x19, 0x69, 0x25, 0xf1, 0xb4, 0x74, 0x0e, 0x9c, 0xe9, 0x43, 0x1a, 0x8a,
|
||||
0x56, 0x13, 0xcf, 0x84, 0x7c, 0xb5, 0x92, 0x5a, 0x37, 0x35, 0x73, 0x0b, 0x19, 0xaa, 0xd2, 0x84,
|
||||
0x64, 0x39, 0xce, 0xaf, 0xfc, 0x18, 0x80, 0x8b, 0xb1, 0xef, 0xe8, 0x48, 0x18, 0xd3, 0xea, 0xa6,
|
||||
0x5a, 0x66, 0x0b, 0x10, 0xa9, 0x75, 0xa8, 0x57, 0xab, 0x68, 0x43, 0xab, 0x8f, 0x7e, 0x3e, 0xf1,
|
||||
0x06, 0x58, 0x4e, 0x02, 0x34, 0xaa, 0xb2, 0xb2, 0x21, 0x0a, 0x64, 0xf5, 0x24, 0x81, 0x90, 0x15,
|
||||
0xa1, 0x6b, 0x25, 0x45, 0xcc, 0x93, 0xc4, 0x28, 0x09, 0xaa, 0x21, 0x97, 0x55, 0x58, 0x6a, 0x9a,
|
||||
0x5b, 0xe2, 0xd4, 0x24, 0x7e, 0x6a, 0x4d, 0xd6, 0xaa, 0xe2, 0x34, 0xc9, 0x62, 0x93, 0x40, 0x9e,
|
||||
0x6a, 0x50, 0x16, 0x67, 0xa4, 0x9b, 0xe0, 0x5a, 0x12, 0x04, 0x35, 0x4f, 0x58, 0x12, 0x4f, 0x10,
|
||||
0x97, 0x93, 0x04, 0x54, 0x93, 0x4d, 0x53, 0x85, 0x35, 0xdd, 0x30, 0xc5, 0x93, 0x93, 0x86, 0x57,
|
||||
0x33, 0x90, 0xa9, 0xca, 0x35, 0x43, 0x9c, 0x9d, 0x04, 0xa5, 0x37, 0x8c, 0xb2, 0x5a, 0xd7, 0x54,
|
||||
0x71, 0x6e, 0x92, 0xe8, 0x64, 0x4a, 0x45, 0x30, 0x71, 0x70, 0x72, 0x6d, 0x5d, 0x3c, 0x35, 0x59,
|
||||
0x6e, 0xa5, 0xa2, 0xd5, 0x55, 0x66, 0x2a, 0x6f, 0x82, 0x87, 0xe9, 0x70, 0xa8, 0xac, 0x99, 0x95,
|
||||
0xe6, 0x1a, 0x5d, 0x5f, 0x64, 0x5d, 0x9d, 0x91, 0x1e, 0x80, 0x57, 0x32, 0xa0, 0x29, 0x1a, 0x54,
|
||||
0xaa, 0xaa, 0xa2, 0x89, 0xf3, 0xc4, 0x2d, 0x66, 0xe3, 0x53, 0x95, 0xd7, 0xc4, 0xb3, 0x24, 0xf4,
|
||||
0x66, 0x00, 0x7f, 0xaa, 0xd6, 0x37, 0xb4, 0xba, 0x21, 0x8a, 0x19, 0xe1, 0xe5, 0xba, 0xa1, 0xad,
|
||||
0x55, 0x55, 0xf1, 0xdc, 0x24, 0xf5, 0x90, 0x20, 0xad, 0x29, 0x6a, 0x5d, 0xdf, 0x14, 0xa5, 0x49,
|
||||
0x13, 0xd6, 0x5f, 0x6f, 0xe7, 0x49, 0x40, 0x4b, 0xb4, 0x24, 0xd9, 0x94, 0x4b, 0x7a, 0x19, 0x69,
|
||||
0x75, 0x85, 0xae, 0x3d, 0x54, 0x93, 0xeb, 0x72, 0x59, 0xad, 0xa9, 0x75, 0x53, 0xbc, 0x40, 0xb2,
|
||||
0x91, 0x2c, 0x62, 0x6f, 0x92, 0xb4, 0x2f, 0x1b, 0x2c, 0xc9, 0x75, 0x17, 0x48, 0x14, 0xcf, 0x42,
|
||||
0x97, 0xe6, 0x2d, 0x34, 0xc1, 0xcb, 0x00, 0x4d, 0xf3, 0xcf, 0x2a, 0xd9, 0x38, 0x14, 0xa4, 0x87,
|
||||
0xe0, 0xb5, 0x0c, 0x18, 0x91, 0x3d, 0xe3, 0xe5, 0x49, 0x16, 0x43, 0xd6, 0x7f, 0xdf, 0x31, 0x29,
|
||||
0x6a, 0xdd, 0x54, 0xa1, 0xb8, 0x38, 0x69, 0x4a, 0xb9, 0x39, 0x42, 0xb5, 0xa1, 0x73, 0x4f, 0x2a,
|
||||
0x2e, 0x65, 0xb4, 0x30, 0x19, 0x96, 0x75, 0xa5, 0x24, 0x5e, 0x91, 0x3e, 0x00, 0xef, 0x3d, 0xb7,
|
||||
0xe1, 0x47, 0x47, 0xb4, 0xbc, 0xf2, 0xd7, 0x33, 0x31, 0x7e, 0xd3, 0x08, 0x70, 0x37, 0xc1, 0x6f,
|
||||
0x1a, 0xa6, 0xda, 0x18, 0xf1, 0x9b, 0xf1, 0x63, 0xa4, 0x80, 0xf2, 0xa6, 0xa1, 0x29, 0x61, 0x90,
|
||||
0x63, 0xee, 0x51, 0x90, 0xbe, 0x04, 0xde, 0x99, 0x0c, 0x6f, 0xa8, 0x26, 0xd7, 0x08, 0x89, 0x37,
|
||||
0xa8, 0xa4, 0xae, 0xcb, 0xcd, 0xaa, 0x89, 0xf4, 0x4d, 0x12, 0xab, 0xf2, 0xd2, 0x17, 0xc1, 0xdb,
|
||||
0x93, 0xf1, 0x9b, 0x8d, 0xaa, 0x2e, 0xb3, 0x19, 0xa1, 0x79, 0x95, 0xd1, 0x40, 0x35, 0xd5, 0x94,
|
||||
0x89, 0x15, 0x8b, 0x53, 0x24, 0x59, 0x9d, 0x8c, 0x6e, 0xaa, 0x86, 0x49, 0x23, 0x4e, 0x28, 0x38,
|
||||
0xc9, 0xc7, 0xa6, 0x13, 0xd6, 0x07, 0xc5, 0x63, 0x0a, 0x86, 0x32, 0x52, 0xa0, 0x2a, 0x9b, 0x2a,
|
||||
0x8a, 0xc0, 0x89, 0x33, 0x93, 0x18, 0x8e, 0x22, 0x96, 0xb5, 0x70, 0xcb, 0x26, 0x9e, 0xc8, 0xc6,
|
||||
0x90, 0x7e, 0x91, 0x97, 0xec, 0x2a, 0x0c, 0xa3, 0x82, 0x14, 0x15, 0x12, 0x37, 0x1e, 0xbf, 0x14,
|
||||
0x62, 0x19, 0x42, 0x92, 0xc0, 0xcd, 0x92, 0x14, 0x38, 0x09, 0xa3, 0xb6, 0xa9, 0x95, 0x2b, 0xf2,
|
||||
0xc6, 0x13, 0xa3, 0x3f, 0x8d, 0x8c, 0x86, 0x38, 0x37, 0x69, 0x60, 0x43, 0x58, 0x5c, 0x42, 0x6e,
|
||||
0xe4, 0x20, 0x1b, 0x37, 0x43, 0x35, 0x9b, 0x0d, 0xb4, 0xa9, 0xc3, 0x8d, 0xf5, 0xaa, 0xbe, 0x29,
|
||||
0x9e, 0x4a, 0x58, 0x1a, 0x23, 0x58, 0x9b, 0x6a, 0x55, 0xd1, 0x6b, 0xaa, 0x78, 0x7a, 0xe5, 0xe7,
|
||||
0x42, 0xec, 0xbb, 0xf1, 0xf0, 0xcd, 0x77, 0xa2, 0xd5, 0xd2, 0x4c, 0x4e, 0xd1, 0x4b, 0xa3, 0xc7,
|
||||
0x4d, 0xf1, 0x9e, 0x2b, 0x0a, 0x3f, 0xc8, 0x29, 0x33, 0xc0, 0xf6, 0x53, 0xcc, 0x7b, 0xe0, 0x56,
|
||||
0x0a, 0x6c, 0x98, 0x71, 0xa6, 0x53, 0x1d, 0x24, 0xa0, 0x7f, 0x93, 0x07, 0x85, 0xa4, 0x63, 0xd6,
|
||||
0x24, 0x42, 0xcc, 0xd2, 0x47, 0x86, 0x1d, 0xef, 0x61, 0x42, 0xd8, 0x81, 0xe2, 0x43, 0x1f, 0x53,
|
||||
0x7a, 0x46, 0xb6, 0x26, 0x24, 0x13, 0x60, 0x51, 0x56, 0xc8, 0x4c, 0x21, 0xb2, 0x09, 0xa9, 0xca,
|
||||
0x6b, 0x6a, 0x15, 0x35, 0x34, 0x65, 0x83, 0x2e, 0xf8, 0x12, 0xf8, 0xe0, 0x79, 0x29, 0x8c, 0xc9,
|
||||
0x31, 0x25, 0x55, 0x40, 0xe9, 0x79, 0xa9, 0xf4, 0xf7, 0x22, 0xb0, 0x59, 0x55, 0x43, 0x79, 0xa6,
|
||||
0x57, 0x7e, 0x70, 0x02, 0x2c, 0xc4, 0x9f, 0x13, 0x27, 0xcc, 0xe6, 0xba, 0xa6, 0x56, 0x47, 0xb3,
|
||||
0xcd, 0xf7, 0xc0, 0x93, 0x44, 0xc8, 0x31, 0xb5, 0x92, 0x20, 0x61, 0x90, 0x24, 0x7b, 0x0b, 0x35,
|
||||
0x61, 0x55, 0x14, 0x12, 0x96, 0x50, 0x02, 0xf6, 0x1a, 0x94, 0xeb, 0x4a, 0x45, 0xcc, 0x27, 0x2c,
|
||||
0xd8, 0x04, 0xac, 0xfe, 0xd2, 0x9b, 0x92, 0xde, 0x06, 0x6f, 0x66, 0xc7, 0x53, 0xeb, 0xcf, 0x34,
|
||||
@@ -6715,18 +6718,19 @@ var fileDescriptor_94cf2ca1c69fd564 = []byte{
|
||||
0x64, 0x40, 0x37, 0x65, 0x53, 0x53, 0xd0, 0xd3, 0xcd, 0x0d, 0x43, 0x3c, 0x29, 0x3d, 0x01, 0x8f,
|
||||
0x33, 0x50, 0x19, 0xb5, 0x59, 0x92, 0x1e, 0x3f, 0x37, 0x66, 0x19, 0xea, 0xcd, 0x86, 0x21, 0xce,
|
||||
0x25, 0x38, 0xfc, 0x09, 0x98, 0x64, 0x03, 0x45, 0x1c, 0x6a, 0xfc, 0x12, 0x9b, 0x80, 0x38, 0x64,
|
||||
0xd8, 0x86, 0x78, 0x6a, 0xe5, 0x87, 0x71, 0x1f, 0x36, 0x09, 0xdf, 0xbd, 0x27, 0x64, 0x62, 0xd4,
|
||||
0xe5, 0xc4, 0xfc, 0x9f, 0x81, 0x78, 0xf7, 0x32, 0x80, 0x36, 0x55, 0x08, 0xe5, 0x75, 0x1d, 0xd6,
|
||||
0x12, 0xed, 0x78, 0x00, 0x3b, 0x92, 0xba, 0x6c, 0xc9, 0xb5, 0xaa, 0x98, 0x5f, 0x79, 0x1f, 0x9c,
|
||||
0xe4, 0xb5, 0x56, 0x64, 0xe3, 0xba, 0xae, 0xca, 0x26, 0x89, 0x2f, 0x63, 0x9b, 0xfe, 0xb0, 0x63,
|
||||
0x74, 0x1b, 0x2c, 0xac, 0xfc, 0x8e, 0x00, 0x96, 0x26, 0xbc, 0x84, 0x26, 0xb1, 0x26, 0x44, 0x86,
|
||||
0xaa, 0xa2, 0xd7, 0x6a, 0x6a, 0xbd, 0xc4, 0x24, 0x8c, 0x3d, 0x60, 0x58, 0x01, 0x77, 0x26, 0x83,
|
||||
0xd7, 0x75, 0x93, 0xc1, 0x0a, 0x24, 0x69, 0x9f, 0x0c, 0x5b, 0xd2, 0xeb, 0xaa, 0x98, 0x5f, 0xfb,
|
||||
0xea, 0x9f, 0xff, 0xf4, 0xaa, 0xf0, 0x93, 0x9f, 0x5e, 0x15, 0xfe, 0xee, 0xa7, 0x57, 0x85, 0x8f,
|
||||
0xf4, 0x5d, 0x27, 0xd8, 0xeb, 0x6d, 0xaf, 0xb6, 0xdc, 0x83, 0x07, 0xbb, 0x9e, 0x75, 0xe8, 0xb0,
|
||||
0x5a, 0x5c, 0xab, 0xfd, 0x60, 0xf0, 0xaf, 0xcf, 0xba, 0xce, 0x83, 0x5d, 0xdc, 0x79, 0x40, 0x5f,
|
||||
0xad, 0x3f, 0xd8, 0x75, 0x47, 0xfe, 0x9f, 0xda, 0xbb, 0x91, 0x9f, 0x87, 0x0f, 0xb7, 0x4f, 0x50,
|
||||
0xb0, 0x37, 0xfe, 0x23, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc7, 0x14, 0xee, 0x7f, 0x6d, 0x00, 0x00,
|
||||
0xd8, 0x86, 0x78, 0x2a, 0x21, 0x26, 0x4f, 0xa0, 0x10, 0x1e, 0x4c, 0xd5, 0x65, 0xea, 0x6d, 0x7f,
|
||||
0x14, 0xf7, 0x61, 0x94, 0xf0, 0xdd, 0x7c, 0x42, 0x26, 0x47, 0x5d, 0x56, 0xcc, 0xff, 0x29, 0x88,
|
||||
0x77, 0x4f, 0x03, 0x68, 0x53, 0x85, 0x50, 0x5e, 0xd7, 0x61, 0x2d, 0x71, 0x1d, 0x0c, 0x60, 0x47,
|
||||
0x52, 0x9f, 0x2d, 0xb9, 0x56, 0x15, 0xf3, 0x2b, 0xef, 0x83, 0x93, 0xbc, 0x56, 0x8b, 0x6c, 0x7c,
|
||||
0xd7, 0x55, 0xd9, 0x24, 0xf1, 0x69, 0xec, 0xd0, 0x20, 0xec, 0x18, 0xdd, 0x46, 0x0b, 0x2b, 0xbf,
|
||||
0x2d, 0x80, 0xa5, 0x09, 0x2f, 0xa9, 0x49, 0xac, 0x0a, 0x91, 0xa1, 0xaa, 0xe8, 0xb5, 0x9a, 0x5a,
|
||||
0x2f, 0x31, 0x09, 0x63, 0x0f, 0x28, 0x56, 0xc0, 0x9d, 0xc9, 0xe0, 0x75, 0xdd, 0x64, 0xb0, 0x02,
|
||||
0x49, 0xfa, 0x27, 0xc3, 0x96, 0xf4, 0xba, 0x2a, 0xe6, 0xd7, 0xbe, 0xfa, 0x67, 0x3f, 0xbd, 0x2a,
|
||||
0xfc, 0xe5, 0x4f, 0xaf, 0x0a, 0x7f, 0xf7, 0xd3, 0xab, 0xc2, 0x47, 0xfa, 0xae, 0x13, 0xec, 0xf5,
|
||||
0xb6, 0x57, 0x5b, 0xee, 0xc1, 0x83, 0x5d, 0xcf, 0x3a, 0x74, 0x58, 0x2d, 0xaf, 0xd5, 0x7e, 0x30,
|
||||
0xf8, 0xd7, 0x69, 0x5d, 0xe7, 0xc1, 0x2e, 0xee, 0x3c, 0xa0, 0xaf, 0xde, 0x1f, 0xec, 0xba, 0x23,
|
||||
0xff, 0x8f, 0xed, 0xdd, 0xc8, 0xcf, 0xc3, 0x87, 0xdb, 0x27, 0x28, 0xd8, 0x1b, 0xff, 0x11, 0x00,
|
||||
0x00, 0xff, 0xff, 0x34, 0x10, 0x18, 0x83, 0xbf, 0x6d, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *UIBannerClickEvent) Marshal() (dAtA []byte, err error) {
|
||||
|
||||
@@ -758,6 +758,7 @@ enum IntegrationEnrollField {
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS = 9;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS = 10;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES = 11;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME = 12;
|
||||
}
|
||||
|
||||
// UIIntegrationEnrollCodeCopyEvent is emitted when the user copies generated
|
||||
|
||||
@@ -935,6 +935,7 @@ const (
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS IntegrationEnrollField = 9
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS IntegrationEnrollField = 10
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES IntegrationEnrollField = 11
|
||||
IntegrationEnrollField_INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME IntegrationEnrollField = 12
|
||||
)
|
||||
|
||||
// Enum value maps for IntegrationEnrollField.
|
||||
@@ -952,6 +953,7 @@ var (
|
||||
9: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS",
|
||||
10: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS",
|
||||
11: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES",
|
||||
12: "INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME",
|
||||
}
|
||||
IntegrationEnrollField_value = map[string]int32{
|
||||
"INTEGRATION_ENROLL_FIELD_UNSPECIFIED": 0,
|
||||
@@ -966,6 +968,7 @@ var (
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS": 9,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS": 10,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES": 11,
|
||||
"INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME": 12,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -11384,7 +11387,7 @@ const file_prehog_v1alpha_teleport_proto_rawDesc = "" +
|
||||
"<INTEGRATION_ENROLL_SECTION_MWIGHAK8S_GITHUB_ADVANCED_OPTIONS\x10\x01\x12@\n" +
|
||||
"<INTEGRATION_ENROLL_SECTION_MWIGHAK8S_KUBERNETES_LABEL_PICKER\x10\x02\x12D\n" +
|
||||
"@INTEGRATION_ENROLL_SECTION_MWIGHAK8S_KUBERNETES_ADVANCED_OPTIONS\x10\x03\x12H\n" +
|
||||
"DINTEGRATION_ENROLL_SECTION_MWIGHAK8S_KUBERNETES_RESOURCE_RULE_PICKER\x10\x04*\xd0\x05\n" +
|
||||
"DINTEGRATION_ENROLL_SECTION_MWIGHAK8S_KUBERNETES_RESOURCE_RULE_PICKER\x10\x04*\x90\x06\n" +
|
||||
"\x16IntegrationEnrollField\x12(\n" +
|
||||
"$INTEGRATION_ENROLL_FIELD_UNSPECIFIED\x10\x00\x12<\n" +
|
||||
"8INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_REPOSITORY_URL\x10\x01\x124\n" +
|
||||
@@ -11398,7 +11401,8 @@ const file_prehog_v1alpha_teleport_proto_rawDesc = "" +
|
||||
"4INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS\x10\t\x127\n" +
|
||||
"3INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS\x10\n" +
|
||||
"\x12@\n" +
|
||||
"<INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES\x10\v*\xab\x01\n" +
|
||||
"<INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES\x10\v\x12>\n" +
|
||||
":INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME\x10\f*\xab\x01\n" +
|
||||
"\x19IntegrationEnrollCodeType\x12,\n" +
|
||||
"(INTEGRATION_ENROLL_CODE_TYPE_UNSPECIFIED\x10\x00\x12*\n" +
|
||||
"&INTEGRATION_ENROLL_CODE_TYPE_TERRAFORM\x10\x01\x124\n" +
|
||||
|
||||
+5
-1
@@ -4474,7 +4474,11 @@ export enum IntegrationEnrollField {
|
||||
/**
|
||||
* @generated from protobuf enum value: INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES = 11;
|
||||
*/
|
||||
MWIGHAK8S_KUBERNETES_RESOURCE_RULES = 11
|
||||
MWIGHAK8S_KUBERNETES_RESOURCE_RULES = 11,
|
||||
/**
|
||||
* @generated from protobuf enum value: INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME = 12;
|
||||
*/
|
||||
MWIGHAK8S_KUBERNETES_CLUSTER_NAME = 12
|
||||
}
|
||||
/**
|
||||
* IntegrationEnrollCodeType identifies the type of code that was copied in an
|
||||
|
||||
@@ -129,18 +129,28 @@ func TestMachineIDWizard(t *testing.T) {
|
||||
// Cut the provider configuration out of the golden file, as this
|
||||
// contains values that will change between test runs (e.g. major
|
||||
// version number and proxy address).
|
||||
providerConfigIdx := strings.Index(body.Terraform, "terraform {")
|
||||
beforeProviderConfig := body.Terraform[:providerConfigIdx]
|
||||
providerConfig := body.Terraform[providerConfigIdx:]
|
||||
const providerConfigStartLine = 17
|
||||
const providerConfigEndLine = 29
|
||||
terraformLines := strings.Split(body.Terraform, "\n")
|
||||
|
||||
providerConfig := strings.Join(
|
||||
terraformLines[providerConfigStartLine-1:providerConfigEndLine],
|
||||
"\n",
|
||||
)
|
||||
remainingLines := append(
|
||||
terraformLines[:providerConfigStartLine-1],
|
||||
terraformLines[providerConfigEndLine:]...,
|
||||
)
|
||||
remainingConfig := strings.Join(remainingLines, "\n")
|
||||
|
||||
if golden.ShouldSet() {
|
||||
golden.Set(t, []byte(beforeProviderConfig))
|
||||
golden.Set(t, []byte(remainingConfig))
|
||||
}
|
||||
|
||||
require.Empty(t,
|
||||
cmp.Diff(
|
||||
string(golden.Get(t)),
|
||||
beforeProviderConfig,
|
||||
remainingConfig,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -2,10 +2,19 @@
|
||||
# Actions workflow to enroll with Teleport and connect to allowed Kubernetes
|
||||
# clusters protected by Teleport.
|
||||
|
||||
# To apply this template
|
||||
# - Log in to your cluster using `tsh login --proxy=teleport.example.com --user=email@example.com`
|
||||
# - Generate a temporary bot using `eval "$(tctl terraform env)"`
|
||||
# - Run `terraform init` followed by `terraform plan`
|
||||
# - To apply the changes, run `terraform apply`
|
||||
# Note: Consider contributing the resources below to your Infrastructure as
|
||||
# Code (IaC) repo (if you have one) instead of executing Terraform locally.
|
||||
|
||||
# See the Teleport Terraform Provider docs for more information about using
|
||||
# Terraform to manage Teleport resources:
|
||||
# https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/
|
||||
|
||||
{{ template "terraform-provider.tf.tmpl" . }}
|
||||
# A role defines which Kubernetes clusters can be accessed, and the level of
|
||||
# access granted. Fine tune the access using the `kubernetes_*` attributes.
|
||||
# All available options can be found in the Teleport Terraform Provider
|
||||
@@ -18,4 +27,3 @@
|
||||
# A provision token allows a GitHub Actions workflow to enroll with Teleport and
|
||||
# assume the identity of the bot defined above and its access.
|
||||
{{ .TokenConfig }}
|
||||
{{ template "terraform-provider.tf.tmpl" . }}
|
||||
|
||||
+8
@@ -2,6 +2,14 @@
|
||||
# Actions workflow to enroll with Teleport and connect to allowed Kubernetes
|
||||
# clusters protected by Teleport.
|
||||
|
||||
# To apply this template
|
||||
# - Log in to your cluster using `tsh login --proxy=teleport.example.com --user=email@example.com`
|
||||
# - Generate a temporary bot using `eval "$(tctl terraform env)"`
|
||||
# - Run `terraform init` followed by `terraform plan`
|
||||
# - To apply the changes, run `terraform apply`
|
||||
# Note: Consider contributing the resources below to your Infrastructure as
|
||||
# Code (IaC) repo (if you have one) instead of executing Terraform locally.
|
||||
|
||||
# See the Teleport Terraform Provider docs for more information about using
|
||||
# Terraform to manage Teleport resources:
|
||||
# https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
# Actions workflow to enroll with Teleport and connect to allowed Kubernetes
|
||||
# clusters protected by Teleport.
|
||||
|
||||
# To apply this template
|
||||
# - Log in to your cluster using `tsh login --proxy=teleport.example.com --user=email@example.com`
|
||||
# - Generate a temporary bot using `eval "$(tctl terraform env)"`
|
||||
# - Run `terraform init` followed by `terraform plan`
|
||||
# - To apply the changes, run `terraform apply`
|
||||
# Note: Consider contributing the resources below to your Infrastructure as
|
||||
# Code (IaC) repo (if you have one) instead of executing Terraform locally.
|
||||
|
||||
# See the Teleport Terraform Provider docs for more information about using
|
||||
# Terraform to manage Teleport resources:
|
||||
# https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
# Actions workflow to enroll with Teleport and connect to allowed Kubernetes
|
||||
# clusters protected by Teleport.
|
||||
|
||||
# To apply this template
|
||||
# - Log in to your cluster using `tsh login --proxy=teleport.example.com --user=email@example.com`
|
||||
# - Generate a temporary bot using `eval "$(tctl terraform env)"`
|
||||
# - Run `terraform init` followed by `terraform plan`
|
||||
# - To apply the changes, run `terraform apply`
|
||||
# Note: Consider contributing the resources below to your Infrastructure as
|
||||
# Code (IaC) repo (if you have one) instead of executing Terraform locally.
|
||||
|
||||
# See the Teleport Terraform Provider docs for more information about using
|
||||
# Terraform to manage Teleport resources:
|
||||
# https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
# Actions workflow to enroll with Teleport and connect to allowed Kubernetes
|
||||
# clusters protected by Teleport.
|
||||
|
||||
# To apply this template
|
||||
# - Log in to your cluster using `tsh login --proxy=teleport.example.com --user=email@example.com`
|
||||
# - Generate a temporary bot using `eval "$(tctl terraform env)"`
|
||||
# - Run `terraform init` followed by `terraform plan`
|
||||
# - To apply the changes, run `terraform apply`
|
||||
# Note: Consider contributing the resources below to your Infrastructure as
|
||||
# Code (IaC) repo (if you have one) instead of executing Terraform locally.
|
||||
|
||||
# See the Teleport Terraform Provider docs for more information about using
|
||||
# Terraform to manage Teleport resources:
|
||||
# https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/
|
||||
|
||||
@@ -1294,6 +1294,7 @@ enum IntegrationEnrollField {
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS = 9;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS = 10;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES = 11;
|
||||
INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME = 12;
|
||||
}
|
||||
|
||||
// UIIntegrationEnrollCodeCopyEvent is emitted when the user copies generated
|
||||
|
||||
@@ -36,6 +36,10 @@ import StyledTextEditor from './StyledTextEditor';
|
||||
const { UndoManager } = ace.require('ace/undomanager');
|
||||
|
||||
class TextEditor extends Component {
|
||||
handleEditorCopy = () => {
|
||||
this.props.onCopy?.();
|
||||
};
|
||||
|
||||
onChange = () => {
|
||||
const isClean = this.editor.session.getUndoManager().isClean();
|
||||
if (this.props.onDirty) {
|
||||
@@ -115,6 +119,7 @@ class TextEditor extends Component {
|
||||
this.editor.renderer.setShowPrintMargin(false);
|
||||
this.editor.renderer.setShowGutter(true);
|
||||
this.editor.on('input', this.onChange);
|
||||
this.editor.on('copy', this.handleEditorCopy);
|
||||
this.editor.setReadOnly(readOnly);
|
||||
this.editor.setTheme({ cssClass: 'ace-teleport' });
|
||||
this.initSessions(data);
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { ButtonSecondary } from 'design/Button';
|
||||
import Dialog, {
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from 'design/Dialog';
|
||||
import Text from 'design/Text';
|
||||
import { Tabs } from 'shared/components/Editor/Tabs';
|
||||
import TextEditor from 'shared/components/TextEditor/TextEditor';
|
||||
|
||||
@@ -29,9 +37,13 @@ import {
|
||||
import { useTracking } from '../Shared/useTracking';
|
||||
import { useGitHubK8sFlow } from './useGitHubK8sFlow';
|
||||
|
||||
export function CodePanel(props: { trackingStep: IntegrationEnrollStep }) {
|
||||
const { trackingStep } = props;
|
||||
export function CodePanel(props: {
|
||||
trackingStep: IntegrationEnrollStep;
|
||||
inProgress?: boolean;
|
||||
}) {
|
||||
const { trackingStep, inProgress = false } = props;
|
||||
const [activeCodeTab, setActiveCodeTab] = useState(0);
|
||||
const [showCopyDialog, setShowCopyDialog] = useState(false);
|
||||
|
||||
const { template } = useGitHubK8sFlow();
|
||||
|
||||
@@ -58,16 +70,42 @@ export function CodePanel(props: { trackingStep: IntegrationEnrollStep }) {
|
||||
]}
|
||||
activeIndex={activeCodeTab}
|
||||
readOnly={true}
|
||||
copyButton={true}
|
||||
downloadButton={true}
|
||||
copyButton={!inProgress}
|
||||
downloadButton={!inProgress}
|
||||
downloadFileName={files[activeCodeTab]}
|
||||
onCopy={() => {
|
||||
tracking.codeCopy(trackingStep, trackingTypes[activeCodeTab]);
|
||||
if (inProgress) {
|
||||
setShowCopyDialog(true);
|
||||
}
|
||||
}}
|
||||
onDownload={() => {
|
||||
tracking.codeCopy(trackingStep, trackingTypes[activeCodeTab]);
|
||||
}}
|
||||
/>
|
||||
<Dialog
|
||||
open={showCopyDialog}
|
||||
onClose={() => setShowCopyDialog(false)}
|
||||
dialogCss={() => ({
|
||||
maxWidth: '480px',
|
||||
width: '100%',
|
||||
})}
|
||||
>
|
||||
<DialogHeader mb={4}>
|
||||
<DialogTitle>Incomplete templates</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DialogContent mb={4}>
|
||||
<Text>
|
||||
The code templates may not be complete yet. Continue to the end of
|
||||
the guide to ensure you've added all the required details.
|
||||
</Text>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<ButtonSecondary onClick={() => setShowCopyDialog(false)}>
|
||||
Ok
|
||||
</ButtonSecondary>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,11 @@ import {
|
||||
genWizardCiCdForever,
|
||||
genWizardCiCdSuccess,
|
||||
} from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import {
|
||||
fetchUnifiedResourcesError,
|
||||
fetchUnifiedResourcesForever,
|
||||
fetchUnifiedResourcesSuccess,
|
||||
} from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { TrackingProvider } from '../Shared/useTracking';
|
||||
@@ -52,7 +56,7 @@ export const Happy: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
genWizardCiCdSuccess(),
|
||||
genWizardCiCdSuccess({ prettyFormat: true }),
|
||||
fetchUnifiedResourcesSuccess(),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
@@ -84,6 +88,30 @@ export const TemplateFetching: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const ClustersFetchFailed: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
genWizardCiCdSuccess({ prettyFormat: true }),
|
||||
fetchUnifiedResourcesError(500, 'something went wrong'),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ClustersFetching: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
genWizardCiCdSuccess({ prettyFormat: true }),
|
||||
fetchUnifiedResourcesForever(),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
|
||||
@@ -34,6 +34,10 @@ import {
|
||||
|
||||
import { ContextProvider } from 'teleport/index';
|
||||
import { createTeleportContext } from 'teleport/mocks/contexts';
|
||||
import {
|
||||
ResourcesResponse,
|
||||
UnifiedResource,
|
||||
} from 'teleport/services/agents/types';
|
||||
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
@@ -65,6 +69,8 @@ afterAll(() => {
|
||||
|
||||
describe('ConfigureAccess', () => {
|
||||
test('renders', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
renderComponent({
|
||||
initialState: {
|
||||
allowAnyBranch: false,
|
||||
@@ -80,6 +86,7 @@ describe('ConfigureAccess', () => {
|
||||
kubernetesGroups: ['viewers'],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: ['user@example.com'],
|
||||
kubernetesCluster: 'my-kubernetes-cluster',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -87,13 +94,46 @@ describe('ConfigureAccess', () => {
|
||||
screen.getByRole('heading', { name: 'Configure Access' })
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByLabelText('Kubernetes Groups')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Labels')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Teleport Labels')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Kubernetes Users')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Kubernetes Groups')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('navigation', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
const { onNextStep, onPrevStep, user } = renderComponent({
|
||||
initialState: {
|
||||
allowAnyBranch: false,
|
||||
branch: 'main',
|
||||
enterpriseJwks: '{"keys":[]}',
|
||||
enterpriseSlug: 'octo-enterprise',
|
||||
environment: 'production',
|
||||
gitHubUrl: 'https://github.com/gravitational/teleport',
|
||||
isBranchDisabled: false,
|
||||
ref: 'main',
|
||||
refType: 'branch',
|
||||
workflow: 'my-workflow',
|
||||
kubernetesGroups: ['viewers'],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: 'my-kubernetes-cluster',
|
||||
},
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Next' }));
|
||||
expect(onNextStep).toHaveBeenCalledTimes(1);
|
||||
expect(onPrevStep).toHaveBeenCalledTimes(0);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Back' }));
|
||||
expect(onNextStep).toHaveBeenCalledTimes(1);
|
||||
expect(onPrevStep).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('validates that groups or users are provided', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
const { onNextStep, user } = renderComponent({
|
||||
initialState: {
|
||||
allowAnyBranch: false,
|
||||
branch: 'main',
|
||||
@@ -108,25 +148,29 @@ describe('ConfigureAccess', () => {
|
||||
kubernetesGroups: [],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: 'my-kubernetes-cluster',
|
||||
},
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Next' }));
|
||||
expect(onNextStep).toHaveBeenCalledTimes(1);
|
||||
expect(onPrevStep).toHaveBeenCalledTimes(0);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Back' }));
|
||||
expect(onNextStep).toHaveBeenCalledTimes(1);
|
||||
expect(onPrevStep).toHaveBeenCalledTimes(1);
|
||||
expect(onNextStep).not.toHaveBeenCalled();
|
||||
expect(
|
||||
screen.getAllByText('A Kubernetes group or user is required')
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('input groups', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
const tracking = trackingTester();
|
||||
|
||||
const { user } = renderComponent();
|
||||
|
||||
const input = screen.getByLabelText('Kubernetes Groups');
|
||||
await selectEvent.create(input, 'system:masters');
|
||||
await selectEvent.create(input, 'system:masters', {
|
||||
createOptionText: 'Add group "system:masters"',
|
||||
});
|
||||
await user.type(input, 'viewers{enter}');
|
||||
|
||||
expect(screen.getByText('system:masters')).toBeInTheDocument();
|
||||
@@ -145,16 +189,20 @@ describe('ConfigureAccess', () => {
|
||||
});
|
||||
|
||||
test('input labels', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
const tracking = trackingTester();
|
||||
|
||||
const { user } = renderComponent();
|
||||
|
||||
const input = screen.getByLabelText('Labels');
|
||||
const input = screen.getByLabelText('Teleport Labels');
|
||||
await user.click(within(input).getByRole('button'));
|
||||
|
||||
const modal = screen.getByTestId('Modal');
|
||||
const manualInput = within(modal).getByPlaceholderText('name: value');
|
||||
await user.type(manualInput, 'foo: bar{enter}');
|
||||
const manualNameInput = within(modal).getByPlaceholderText('e.g. env');
|
||||
await user.type(manualNameInput, 'foo');
|
||||
const manualValueInput = within(modal).getByPlaceholderText('e.g. prod');
|
||||
await user.type(manualValueInput, 'bar{enter}');
|
||||
await user.click(within(modal).getByRole('button', { name: 'Done' }));
|
||||
|
||||
expect(modal).not.toBeInTheDocument();
|
||||
@@ -175,12 +223,16 @@ describe('ConfigureAccess', () => {
|
||||
});
|
||||
|
||||
test('input users', async () => {
|
||||
withListUnifiedResourcesSuccess();
|
||||
|
||||
const tracking = trackingTester();
|
||||
|
||||
const { user } = renderComponent();
|
||||
|
||||
const input = screen.getByLabelText('Kubernetes Users');
|
||||
await selectEvent.create(input, 'user1@example.com');
|
||||
await selectEvent.create(input, 'user1@example.com', {
|
||||
createOptionText: 'Add user "user1@example.com"',
|
||||
});
|
||||
await user.type(input, 'user2@example.com{enter}');
|
||||
|
||||
expect(screen.getByText('user1@example.com')).toBeInTheDocument();
|
||||
@@ -241,3 +293,18 @@ function makeWrapper(opts?: {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function withListUnifiedResourcesSuccess(opts?: {
|
||||
response?: ResourcesResponse<UnifiedResource>;
|
||||
}) {
|
||||
server.use(
|
||||
fetchUnifiedResourcesSuccess({
|
||||
response: opts?.response
|
||||
? {
|
||||
...opts.response,
|
||||
items: opts.response.agents,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { MultiValue } from 'react-select';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Box from 'design/Box/Box';
|
||||
@@ -24,6 +25,7 @@ import Flex from 'design/Flex/Flex';
|
||||
import Link from 'design/Link/Link';
|
||||
import Text, { H2 } from 'design/Text';
|
||||
import { FieldSelectCreatable } from 'shared/components/FieldSelect/FieldSelectCreatable';
|
||||
import { Rule } from 'shared/components/Validation/rules';
|
||||
import Validator, { Validation } from 'shared/components/Validation/Validation';
|
||||
|
||||
import { SectionBox } from 'teleport/Roles/RoleEditor/StandardEditor/sections';
|
||||
@@ -63,6 +65,18 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
nextStep?.();
|
||||
};
|
||||
|
||||
const kubernetesAccessRule: Rule<
|
||||
MultiValue<{ label: string; value: string }>
|
||||
> = () => () => {
|
||||
const valid =
|
||||
state.kubernetesGroups.length > 0 || state.kubernetesUsers.length > 0;
|
||||
|
||||
return {
|
||||
valid,
|
||||
message: valid ? '' : 'A Kubernetes group or user is required',
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<FormContainer>
|
||||
@@ -72,9 +86,9 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
</H2>
|
||||
|
||||
<Text mb={3}>
|
||||
Fine tune the access your workflow needs to perform its steps.
|
||||
Restrict which clusters can be accessed using labels and what level
|
||||
of access using the other options.
|
||||
Choose a cluster to access. Then fine tune the access your workflow
|
||||
needs. Restrict <em>which</em> clusters can be accessed using labels
|
||||
and <em>what</em> level of access using groups and users.
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
@@ -111,7 +125,7 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
>
|
||||
Teleport Kubernetes Access Controls
|
||||
</Link>{' '}
|
||||
docs for information about using Kubernetes labels.
|
||||
docs for information about using labels.
|
||||
</Text>
|
||||
|
||||
<FieldSelectCreatable
|
||||
@@ -119,6 +133,7 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
mt={2}
|
||||
placeholder="e.g. system:masters"
|
||||
isMulti
|
||||
rule={kubernetesAccessRule}
|
||||
value={state.kubernetesGroups.map(g => ({
|
||||
label: g,
|
||||
value: g,
|
||||
@@ -134,6 +149,13 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
);
|
||||
}}
|
||||
createOptionPosition="last"
|
||||
components={{
|
||||
// Hide the dropdown indicator and spacing
|
||||
DropdownIndicator: () => null,
|
||||
IndicatorSeparator: () => null,
|
||||
}}
|
||||
noOptionsMessage={() => 'Type to add a value'}
|
||||
formatCreateLabel={input => `Add group "${input}"`}
|
||||
/>
|
||||
<Text mb={3}>
|
||||
Add Kubernetes groups created using RoleBinding or
|
||||
@@ -173,6 +195,7 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
mt={2}
|
||||
isMulti
|
||||
placeholder={'e.g. user@example.com'}
|
||||
rule={kubernetesAccessRule}
|
||||
value={state.kubernetesUsers.map(g => ({
|
||||
label: g,
|
||||
value: g,
|
||||
@@ -188,6 +211,13 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
);
|
||||
}}
|
||||
createOptionPosition="last"
|
||||
components={{
|
||||
// Hide the dropdown indicator and spacing
|
||||
DropdownIndicator: () => null,
|
||||
IndicatorSeparator: () => null,
|
||||
}}
|
||||
noOptionsMessage={() => 'Type to add a value'}
|
||||
formatCreateLabel={input => `Add user "${input}"`}
|
||||
/>
|
||||
<Text mb={3}>
|
||||
See the{' '}
|
||||
@@ -216,6 +246,7 @@ export function ConfigureAccess(props: FlowStepProps) {
|
||||
<CodeContainer>
|
||||
<CodePanel
|
||||
trackingStep={IntegrationEnrollStep.MWIGHAK8SConfigureAccess}
|
||||
inProgress
|
||||
/>
|
||||
</CodeContainer>
|
||||
</Container>
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
genWizardCiCdForever,
|
||||
genWizardCiCdSuccess,
|
||||
} from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { TrackingProvider } from '../Shared/useTracking';
|
||||
@@ -50,7 +51,11 @@ export default meta;
|
||||
export const Happy: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [genWizardCiCdSuccess(), userEventCaptureSuccess()],
|
||||
handlers: [
|
||||
genWizardCiCdSuccess({ prettyFormat: true }),
|
||||
fetchUnifiedResourcesSuccess(),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -60,6 +65,7 @@ export const TemplateFetchFailed: Story = {
|
||||
msw: {
|
||||
handlers: [
|
||||
genWizardCiCdError(500, 'something went wrong'),
|
||||
fetchUnifiedResourcesSuccess(),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
@@ -69,7 +75,11 @@ export const TemplateFetchFailed: Story = {
|
||||
export const TemplateFetching: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [genWizardCiCdForever(), userEventCaptureSuccess()],
|
||||
handlers: [
|
||||
genWizardCiCdForever(),
|
||||
fetchUnifiedResourcesSuccess(),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@ import cfg from 'teleport/config';
|
||||
import { ContextProvider } from 'teleport/index';
|
||||
import { createTeleportContext } from 'teleport/mocks/contexts';
|
||||
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { trackingTester } from '../Shared/trackingTester';
|
||||
@@ -49,6 +50,7 @@ beforeAll(() => {
|
||||
|
||||
// Basic mock for all tests
|
||||
server.use(genWizardCiCdSuccess());
|
||||
server.use(fetchUnifiedResourcesSuccess());
|
||||
server.use(userEventCaptureSuccess());
|
||||
|
||||
jest.useFakeTimers();
|
||||
@@ -72,12 +74,13 @@ describe('ConnectGitHub', () => {
|
||||
environment: 'production',
|
||||
gitHubUrl: 'https://github.com/gravitational/teleport',
|
||||
isBranchDisabled: false,
|
||||
ref: 'main',
|
||||
ref: 'refs/heads/main',
|
||||
refType: 'branch',
|
||||
workflow: 'my-workflow',
|
||||
kubernetesGroups: [],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: '',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -89,9 +92,7 @@ describe('ConnectGitHub', () => {
|
||||
screen.getByPlaceholderText('https://github.com/gravitational/teleport')
|
||||
).toHaveValue('https://github.com/gravitational/teleport');
|
||||
|
||||
expect(screen.getAllByPlaceholderText('refs/heads/main')[0]).toHaveValue(
|
||||
'main'
|
||||
);
|
||||
expect(screen.getByPlaceholderText('main')).toHaveValue('main');
|
||||
|
||||
expect(screen.getByPlaceholderText('my-workflow')).toHaveValue(
|
||||
'my-workflow'
|
||||
@@ -99,8 +100,8 @@ describe('ConnectGitHub', () => {
|
||||
|
||||
expect(screen.getByPlaceholderText('production')).toHaveValue('production');
|
||||
|
||||
expect(screen.getAllByPlaceholderText('refs/heads/main')[1]).toHaveValue(
|
||||
'main'
|
||||
expect(screen.getByPlaceholderText('refs/heads/main')).toHaveValue(
|
||||
'refs/heads/main'
|
||||
);
|
||||
|
||||
expect(screen.getByPlaceholderText('octo-enterprise')).toHaveValue(
|
||||
@@ -122,12 +123,13 @@ describe('ConnectGitHub', () => {
|
||||
environment: 'production',
|
||||
gitHubUrl: 'https://github.com/gravitational/teleport',
|
||||
isBranchDisabled: false,
|
||||
ref: 'main',
|
||||
ref: 'refs/heads/main',
|
||||
refType: 'branch',
|
||||
workflow: 'my-workflow',
|
||||
kubernetesGroups: [],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: '',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -171,7 +173,7 @@ describe('ConnectGitHub', () => {
|
||||
await user.type(input, 'main');
|
||||
|
||||
expect(input).toHaveValue('main');
|
||||
expect(screen.getByLabelText('Git Ref')).toHaveValue('main');
|
||||
expect(screen.getByLabelText('Git Ref')).toHaveValue('refs/heads/main');
|
||||
|
||||
// Skip start event
|
||||
tracking.skip();
|
||||
|
||||
@@ -75,6 +75,8 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
|
||||
const refTypeValue: RefTypeOption =
|
||||
refTypeOptions.find(o => o.value === state.refType) ?? refTypeOptions[0];
|
||||
const refPlaceholder =
|
||||
refTypeValue.value === 'tag' ? 'refs/tags/release-v1' : 'refs/heads/main';
|
||||
|
||||
const hasGHEHost = !!state.info?.host && state.info.host !== GITHUB_HOST;
|
||||
|
||||
@@ -120,7 +122,7 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
}
|
||||
disabled={state.isBranchDisabled}
|
||||
label="Branch"
|
||||
placeholder="refs/heads/main"
|
||||
placeholder="main"
|
||||
value={state.branch}
|
||||
onChange={e => {
|
||||
dispatch({
|
||||
@@ -146,10 +148,16 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
}
|
||||
size="small"
|
||||
/>
|
||||
<Text mb={3}>
|
||||
Specifying a branch is recommended to prevent workflows running
|
||||
from any branch to access your Teleport resources.
|
||||
</Text>
|
||||
{state.allowAnyBranch && (
|
||||
<Info
|
||||
mt={3}
|
||||
mb={3}
|
||||
alignItems="flex-start"
|
||||
details="Specifying a branch is recommended to prevent workflows running from unintended branches (such as PR branches) from accessing your Teleport resources."
|
||||
>
|
||||
Recommended restriction
|
||||
</Info>
|
||||
)}
|
||||
|
||||
{/* TODO(nicholasmarais1158): Make SectionBox a component instead of reusing it from Roles */}
|
||||
<SectionBox
|
||||
@@ -172,6 +180,10 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Text mb={3}>
|
||||
Use the options below to further restrict which workflows can
|
||||
access your Teleport resources.
|
||||
</Text>
|
||||
<FieldInput
|
||||
label="Workflow"
|
||||
placeholder="my-workflow"
|
||||
@@ -210,7 +222,7 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
<FieldInput
|
||||
flex={1}
|
||||
label={'Git Ref'}
|
||||
placeholder="refs/heads/main"
|
||||
placeholder={refPlaceholder}
|
||||
value={state.ref}
|
||||
onChange={e => {
|
||||
dispatch({
|
||||
@@ -333,6 +345,7 @@ export function ConnectGitHub(props: FlowStepProps) {
|
||||
<CodeContainer>
|
||||
<CodePanel
|
||||
trackingStep={IntegrationEnrollStep.MWIGHAK8SConnectGitHub}
|
||||
inProgress
|
||||
/>
|
||||
</CodeContainer>
|
||||
</Container>
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Teleport
|
||||
* Copyright (C) 2026 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import selectEvent from 'react-select-event';
|
||||
|
||||
import darkTheme from 'design/theme/themes/darkTheme';
|
||||
import { ConfiguredThemeProvider } from 'design/ThemeProvider';
|
||||
import {
|
||||
act,
|
||||
render,
|
||||
screen,
|
||||
testQueryClient,
|
||||
userEvent,
|
||||
} from 'design/utils/testing';
|
||||
|
||||
import { ContextProvider } from 'teleport/index';
|
||||
import { createTeleportContext } from 'teleport/mocks/contexts';
|
||||
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { trackingTester } from '../Shared/trackingTester';
|
||||
import { TrackingProvider } from '../Shared/useTracking';
|
||||
import { Finish } from './Finish';
|
||||
import { GitHubK8sFlowProvider, useGitHubK8sFlow } from './useGitHubK8sFlow';
|
||||
|
||||
// Switching the async component for its sync equivalent - the latter is a pain
|
||||
// to test without getting act() warnings and errors.
|
||||
jest.mock('shared/components/FieldSelect/FieldSelectCreatable', () => {
|
||||
const actual = jest.requireActual(
|
||||
'shared/components/FieldSelect/FieldSelectCreatable'
|
||||
);
|
||||
return {
|
||||
...actual,
|
||||
FieldSelectCreatableAsync: (props: {
|
||||
loadOptions?: unknown;
|
||||
defaultOptions?: unknown;
|
||||
}) => {
|
||||
const {
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
loadOptions,
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
defaultOptions,
|
||||
...rest
|
||||
} = props;
|
||||
return <actual.FieldSelectCreatable {...rest} />;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const server = setupServer();
|
||||
|
||||
beforeAll(() => {
|
||||
server.listen();
|
||||
|
||||
// Basic mock for all tests
|
||||
server.use(genWizardCiCdSuccess());
|
||||
server.use(fetchUnifiedResourcesSuccess());
|
||||
server.use(userEventCaptureSuccess());
|
||||
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.close();
|
||||
|
||||
jest.useRealTimers();
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('Finish', () => {
|
||||
test('renders', async () => {
|
||||
renderComponent({
|
||||
initialState: {
|
||||
allowAnyBranch: false,
|
||||
branch: 'main',
|
||||
enterpriseJwks: '{"keys":[]}',
|
||||
enterpriseSlug: 'octo-enterprise',
|
||||
environment: 'production',
|
||||
gitHubUrl: 'https://github.com/gravitational/teleport',
|
||||
isBranchDisabled: false,
|
||||
ref: 'main',
|
||||
refType: 'branch',
|
||||
workflow: 'my-workflow',
|
||||
kubernetesGroups: ['viewers'],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: ['user@example.com'],
|
||||
kubernetesCluster: 'my-kubernetes-cluster',
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { name: 'Set Up Workflow' })
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
screen.getByLabelText('Select a cluster to access')
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('To complete the setup')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('cluster', async () => {
|
||||
const tracking = trackingTester();
|
||||
|
||||
renderComponent();
|
||||
|
||||
const input = screen.getByLabelText('Select a cluster to access');
|
||||
await selectEvent.create(input, 'test-cluster', {
|
||||
createOptionText: 'Use cluster "test-cluster"',
|
||||
});
|
||||
|
||||
expect(screen.getByText('test-cluster')).toBeInTheDocument();
|
||||
|
||||
// Skip start event
|
||||
tracking.skip();
|
||||
|
||||
// Field tracking is debounced, so move time along to send the event
|
||||
await act(() => jest.advanceTimersByTimeAsync(1000));
|
||||
tracking.assertField(
|
||||
expect.any(String),
|
||||
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW',
|
||||
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME'
|
||||
);
|
||||
});
|
||||
|
||||
test('validates that a cluster is provided', async () => {
|
||||
const { onNextStep, user } = renderComponent({
|
||||
initialState: {
|
||||
allowAnyBranch: false,
|
||||
branch: 'main',
|
||||
enterpriseJwks: '{"keys":[]}',
|
||||
enterpriseSlug: 'octo-enterprise',
|
||||
environment: 'production',
|
||||
gitHubUrl: 'https://github.com/gravitational/teleport',
|
||||
isBranchDisabled: false,
|
||||
ref: 'main',
|
||||
refType: 'branch',
|
||||
workflow: 'my-workflow',
|
||||
kubernetesGroups: ['viewers'],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: '',
|
||||
},
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Close' }));
|
||||
|
||||
expect(onNextStep).not.toHaveBeenCalled();
|
||||
expect(
|
||||
screen.getAllByText('A Kubernetes cluster is required')
|
||||
).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
function renderComponent(opts?: {
|
||||
initialState?: ReturnType<typeof useGitHubK8sFlow>['state'];
|
||||
disableTracking?: boolean;
|
||||
}) {
|
||||
const user = userEvent.setup({
|
||||
advanceTimers: t => jest.advanceTimersByTime(t),
|
||||
});
|
||||
const onNextStep = jest.fn();
|
||||
const onPrevStep = jest.fn();
|
||||
return {
|
||||
...render(<Finish nextStep={onNextStep} prevStep={onPrevStep} />, {
|
||||
wrapper: makeWrapper(opts),
|
||||
}),
|
||||
user,
|
||||
onNextStep,
|
||||
onPrevStep,
|
||||
};
|
||||
}
|
||||
|
||||
function makeWrapper(opts?: {
|
||||
initialState?: ReturnType<typeof useGitHubK8sFlow>['state'];
|
||||
disableTracking?: boolean;
|
||||
}) {
|
||||
const { initialState, disableTracking = false } = opts ?? {};
|
||||
const ctx = createTeleportContext();
|
||||
|
||||
return ({ children }: PropsWithChildren) => {
|
||||
return (
|
||||
<QueryClientProvider client={testQueryClient}>
|
||||
<ContextProvider ctx={ctx}>
|
||||
<ConfiguredThemeProvider theme={darkTheme}>
|
||||
<TrackingProvider disabled={disableTracking}>
|
||||
<GitHubK8sFlowProvider intitialState={initialState}>
|
||||
{children}
|
||||
</GitHubK8sFlowProvider>
|
||||
</TrackingProvider>
|
||||
</ConfiguredThemeProvider>
|
||||
</ContextProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -16,10 +16,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import { Warning } from 'design/Alert/Alert';
|
||||
import Box from 'design/Box/Box';
|
||||
import {
|
||||
ButtonPrimary,
|
||||
@@ -33,26 +35,97 @@ import DialogTitle from 'design/Dialog/DialogTitle';
|
||||
import Flex from 'design/Flex/Flex';
|
||||
import Link from 'design/Link/Link';
|
||||
import { H2, P2 } from 'design/Text/Text';
|
||||
import { FieldSelectCreatableAsync } from 'shared/components/FieldSelect/FieldSelectCreatable';
|
||||
import { Rule } from 'shared/components/Validation/rules';
|
||||
import Validator, { Validation } from 'shared/components/Validation/Validation';
|
||||
|
||||
import cfg from 'teleport/config';
|
||||
import { Kube } from 'teleport/services/kube/types';
|
||||
import {
|
||||
IntegrationEnrollField,
|
||||
IntegrationEnrollStatusCode,
|
||||
IntegrationEnrollStep,
|
||||
} from 'teleport/services/userEvent';
|
||||
import useTeleport from 'teleport/useTeleport';
|
||||
|
||||
import { FlowStepProps } from '../Shared/GuidedFlow';
|
||||
import { makeKubernetesAccessChecker } from '../Shared/kubernetes';
|
||||
import { useTracking } from '../Shared/useTracking';
|
||||
import { CodePanel } from './CodePanel';
|
||||
import { useGitHubK8sFlow } from './useGitHubK8sFlow';
|
||||
|
||||
export function Finish(props: FlowStepProps) {
|
||||
const { prevStep } = props;
|
||||
|
||||
const [showDoneCheck, setShowDoneCheck] = useState(false);
|
||||
const { dispatch, state } = useGitHubK8sFlow();
|
||||
|
||||
const [showCloseCheck, setShowCloseCheck] = useState(false);
|
||||
const [kubernetesClusters, setKubernetesClusters] = useState<Kube[]>([]);
|
||||
|
||||
const history = useHistory();
|
||||
const tracking = useTracking();
|
||||
|
||||
const handleDone = () => {
|
||||
const ctx = useTeleport();
|
||||
const flags = ctx.getFeatureFlags();
|
||||
const hasKubernetesListPermission = flags.kubernetes;
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const fetchClusters = async (search: string) => {
|
||||
if (!hasKubernetesListPermission) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Use an imperative query instead of `useQuery` (reactive). Results need to
|
||||
// be returned from this function.
|
||||
const result = await queryClient.fetchQuery({
|
||||
queryKey: [
|
||||
'list',
|
||||
'unified_resources',
|
||||
cfg.proxyCluster,
|
||||
['kube_cluster'],
|
||||
search,
|
||||
],
|
||||
queryFn: ({ signal }) =>
|
||||
ctx.resourceService.fetchUnifiedResources(
|
||||
cfg.proxyCluster,
|
||||
{
|
||||
kinds: ['kube_cluster'],
|
||||
limit: 32,
|
||||
search,
|
||||
},
|
||||
signal
|
||||
),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
|
||||
const clusters = result.agents.filter(
|
||||
(resource): resource is Kube => resource.kind === 'kube_cluster'
|
||||
);
|
||||
|
||||
setKubernetesClusters(clusters);
|
||||
|
||||
const options = clusters.map(cluster => ({
|
||||
label: cluster.name,
|
||||
value: cluster.name,
|
||||
}));
|
||||
|
||||
return options ?? [];
|
||||
};
|
||||
|
||||
const handleClose = (validator: Validator) => {
|
||||
if (!validator.validate()) {
|
||||
tracking.error(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
'validation error'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setShowCloseCheck(true);
|
||||
};
|
||||
|
||||
const handleConfirmClose = () => {
|
||||
tracking.step(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
IntegrationEnrollStatusCode.Success
|
||||
@@ -61,70 +134,139 @@ export function Finish(props: FlowStepProps) {
|
||||
history.replace(cfg.getBotsRoute());
|
||||
};
|
||||
|
||||
const accessChecker = useMemo(
|
||||
() => makeKubernetesAccessChecker(state.kubernetesLabels),
|
||||
[state.kubernetesLabels]
|
||||
);
|
||||
|
||||
const selectedCluster = kubernetesClusters.find(
|
||||
c => c.name === state.kubernetesCluster
|
||||
);
|
||||
const showSelectedClusterAccessWarning = selectedCluster
|
||||
? !accessChecker.check(selectedCluster.labels)
|
||||
: false;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Box flex={4}>
|
||||
<H2 mb={3} mt={3}>
|
||||
Setup Workflow
|
||||
</H2>
|
||||
|
||||
<P2>
|
||||
<strong>To complete the setup</strong>;
|
||||
</P2>
|
||||
<ul>
|
||||
<li>Use the Infrastructure as Code templates to create resources</li>
|
||||
<li>Copy the workflow template and add it to your repository</li>
|
||||
</ul>
|
||||
|
||||
<P2>
|
||||
See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={IAC_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
IAC_LINK
|
||||
);
|
||||
}}
|
||||
>
|
||||
Infrastructure as Code
|
||||
</Link>{' '}
|
||||
docs for information about setting up and using IaC with Teleport.
|
||||
</P2>
|
||||
|
||||
<P2>
|
||||
See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={TBOT_GHA_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
TBOT_GHA_LINK
|
||||
);
|
||||
}}
|
||||
>
|
||||
Deploying tbot on GitHub Actions
|
||||
</Link>{' '}
|
||||
docs for information about running tbot in a GitHub Actions workflow.
|
||||
</P2>
|
||||
|
||||
<Flex gap={2} pt={5}>
|
||||
<ButtonPrimary onClick={() => setShowDoneCheck(true)}>
|
||||
Done
|
||||
</ButtonPrimary>
|
||||
<ButtonSecondary onClick={prevStep}>Back</ButtonSecondary>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<CodeContainer>
|
||||
<CodePanel
|
||||
trackingStep={IntegrationEnrollStep.MWIGHAK8SSetupWorkflow}
|
||||
inProgress={!state.kubernetesCluster}
|
||||
/>
|
||||
</CodeContainer>
|
||||
|
||||
<Dialog open={showDoneCheck} onClose={() => setShowDoneCheck(false)}>
|
||||
<Validation>
|
||||
{({ validator }) => (
|
||||
<Box flex={4}>
|
||||
<H2 mb={3} mt={3}>
|
||||
Set Up Workflow
|
||||
</H2>
|
||||
|
||||
<FieldSelectCreatableAsync
|
||||
label="Select a cluster to access"
|
||||
mt={2}
|
||||
isClearable
|
||||
isSearchable
|
||||
defaultOptions
|
||||
loadOptions={fetchClusters}
|
||||
rule={kubernetesClusterRule}
|
||||
value={
|
||||
state.kubernetesCluster
|
||||
? {
|
||||
label: state.kubernetesCluster,
|
||||
value: state.kubernetesCluster,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onChange={option => {
|
||||
dispatch({
|
||||
type: 'kubernetes-cluster-changed',
|
||||
value: option?.value ?? '',
|
||||
});
|
||||
tracking.field(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
IntegrationEnrollField.MWIGHAK8SKubernetesClusterName
|
||||
);
|
||||
}}
|
||||
noOptionsMessage={() => {
|
||||
return 'Enter a cluster name manually';
|
||||
}}
|
||||
formatCreateLabel={input => `Use cluster "${input}"`}
|
||||
/>
|
||||
|
||||
{showSelectedClusterAccessWarning && (
|
||||
<Warning
|
||||
alignItems="flex-start"
|
||||
mt={4}
|
||||
details={
|
||||
<>
|
||||
Based on the labels configured, the workflow will not have
|
||||
access to the selected cluster. Amend the labels, or select
|
||||
another cluster.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Cluster is inaccessible
|
||||
</Warning>
|
||||
)}
|
||||
|
||||
<P2>
|
||||
<strong>To complete the setup</strong>;
|
||||
</P2>
|
||||
<ol>
|
||||
<li>
|
||||
Use the Infrastructure as Code templates to create resources
|
||||
</li>
|
||||
<li>Copy the workflow template and add it to your repository</li>
|
||||
<li>Run the workflow</li>
|
||||
</ol>
|
||||
|
||||
<P2>
|
||||
See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={IAC_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
IAC_LINK
|
||||
);
|
||||
}}
|
||||
>
|
||||
Infrastructure as Code
|
||||
</Link>{' '}
|
||||
docs for information about setting up and using IaC with Teleport.
|
||||
</P2>
|
||||
|
||||
<P2>
|
||||
See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={TBOT_GHA_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(
|
||||
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
|
||||
TBOT_GHA_LINK
|
||||
);
|
||||
}}
|
||||
>
|
||||
Deploying tbot on GitHub Actions
|
||||
</Link>{' '}
|
||||
docs for information about running tbot in a GitHub Actions
|
||||
workflow.
|
||||
</P2>
|
||||
|
||||
<Flex gap={2} pt={5}>
|
||||
<ButtonPrimary onClick={() => handleClose(validator)}>
|
||||
Close
|
||||
</ButtonPrimary>
|
||||
<ButtonSecondary onClick={prevStep}>Back</ButtonSecondary>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
</Validation>
|
||||
|
||||
<Dialog open={showCloseCheck} onClose={() => setShowCloseCheck(false)}>
|
||||
<DialogHeader mb={4}>
|
||||
<DialogTitle>
|
||||
Are you sure you would like to complete the guide?
|
||||
@@ -137,14 +279,14 @@ export function Finish(props: FlowStepProps) {
|
||||
</P2>
|
||||
</DialogContent>
|
||||
<Flex gap={3}>
|
||||
<ButtonWarning block size="large" onClick={handleDone}>
|
||||
<ButtonWarning block size="large" onClick={handleConfirmClose}>
|
||||
Confirm
|
||||
</ButtonWarning>
|
||||
<ButtonSecondary
|
||||
block
|
||||
size="large"
|
||||
autoFocus
|
||||
onClick={() => setShowDoneCheck(false)}
|
||||
onClick={() => setShowCloseCheck(false)}
|
||||
>
|
||||
Cancel
|
||||
</ButtonSecondary>
|
||||
@@ -170,3 +312,12 @@ const IAC_LINK =
|
||||
'https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/';
|
||||
const TBOT_GHA_LINK =
|
||||
'https://goteleport.com/docs/machine-workload-identity/deployment/github-actions/';
|
||||
|
||||
const kubernetesClusterRule: Rule<{ label: string; value: string } | null> =
|
||||
value => () => {
|
||||
const valid = Boolean(value?.value);
|
||||
return {
|
||||
valid,
|
||||
message: valid ? '' : 'A Kubernetes cluster is required',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Teleport
|
||||
* Copyright (C) 2026 Gravitational, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Flex from 'design/Flex/Flex';
|
||||
import { InfoGuidePanelProvider } from 'shared/components/SlidingSidePanel/InfoGuide';
|
||||
|
||||
import { BotFlowType } from 'teleport/Bots/types';
|
||||
import cfg from 'teleport/config';
|
||||
import { ContextProvider } from 'teleport/index';
|
||||
import { ContentMinWidth } from 'teleport/Main/Main';
|
||||
import { createTeleportContext } from 'teleport/mocks/contexts';
|
||||
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { GitHubActionsK8s } from './GitHubActionsK8s';
|
||||
|
||||
const meta = {
|
||||
title: 'Teleport/Bots/Add/GitHubActions+K8s/GitHubActionsK8s',
|
||||
component: Wrapper,
|
||||
beforeEach: () => {
|
||||
queryClient.clear(); // Prevent cached data sharing between stories
|
||||
},
|
||||
} satisfies Meta<typeof Wrapper>;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Happy: Story = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
genWizardCiCdSuccess({ prettyFormat: true }),
|
||||
fetchUnifiedResourcesSuccess({
|
||||
delayMs: 1000,
|
||||
mockSearch: true,
|
||||
}),
|
||||
userEventCaptureSuccess(),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: false,
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function Wrapper() {
|
||||
const ctx = createTeleportContext();
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ContextProvider ctx={ctx}>
|
||||
<InfoGuidePanelProvider>
|
||||
<ContentMinWidth>
|
||||
<MemoryRouter
|
||||
initialEntries={[
|
||||
cfg.getBotsNewRoute(BotFlowType.GitHubActionsK8s),
|
||||
]}
|
||||
>
|
||||
<Container>
|
||||
<GitHubActionsK8s />
|
||||
</Container>
|
||||
</MemoryRouter>
|
||||
</ContentMinWidth>
|
||||
</InfoGuidePanelProvider>
|
||||
</ContextProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const Container = styled(Flex)`
|
||||
flex-direction: column;
|
||||
height: 820px;
|
||||
overflow: auto;
|
||||
`;
|
||||
@@ -21,6 +21,7 @@ import { createMemoryHistory } from 'history';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { Router } from 'react-router';
|
||||
import selectEvent from 'react-select-event';
|
||||
|
||||
import darkTheme from 'design/theme/themes/darkTheme';
|
||||
import { ConfiguredThemeProvider } from 'design/ThemeProvider';
|
||||
@@ -39,6 +40,7 @@ import { ContextProvider } from 'teleport/index';
|
||||
import { ContentMinWidth } from 'teleport/Main/Main';
|
||||
import { createTeleportContext } from 'teleport/mocks/contexts';
|
||||
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
|
||||
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
|
||||
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
|
||||
|
||||
import { trackingTester } from '../Shared/trackingTester';
|
||||
@@ -52,6 +54,7 @@ beforeAll(() => {
|
||||
|
||||
server.use(genWizardCiCdSuccess());
|
||||
server.use(userEventCaptureSuccess());
|
||||
server.use(fetchUnifiedResourcesSuccess());
|
||||
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
@@ -135,6 +138,9 @@ describe('GitHubActionsK8s', () => {
|
||||
screen.getByRole('heading', { name: 'Configure Access' })
|
||||
).toBeInTheDocument();
|
||||
|
||||
const input = screen.getByLabelText('Kubernetes Groups');
|
||||
await user.type(input, 'viewers{enter}');
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Next' }));
|
||||
|
||||
tracking.assertStep(
|
||||
@@ -144,10 +150,20 @@ describe('GitHubActionsK8s', () => {
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { name: 'Setup Workflow' })
|
||||
screen.getByRole('heading', { name: 'Set Up Workflow' })
|
||||
).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Done' }));
|
||||
const select = screen.getByLabelText('Select a cluster to access');
|
||||
await selectEvent.select(select, 'kube-lon-staging-01.example.com');
|
||||
|
||||
await act(() => jest.advanceTimersByTimeAsync(1000));
|
||||
tracking.assertField(
|
||||
'test-tracking-event-id',
|
||||
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW',
|
||||
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME'
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Close' }));
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'Confirm' }));
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ const views: View[] = [
|
||||
component: ConfigureAccess,
|
||||
},
|
||||
{
|
||||
name: 'Setup workflow',
|
||||
name: 'Set Up Workflow',
|
||||
component: Finish,
|
||||
},
|
||||
];
|
||||
|
||||
+42
-14
@@ -271,11 +271,12 @@ describe('KubernetesLabelsSelect', () => {
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
within(modal).getByRole('heading', { name: 'Selected Labels (0)' })
|
||||
within(modal).getByRole('heading', { name: 'Selected Labels (1)' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
within(selectedSection!).queryByText('env: dev')
|
||||
).not.toBeInTheDocument();
|
||||
expect(within(selectedSection!).getByText('*: *')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('manual entry', async () => {
|
||||
@@ -292,16 +293,30 @@ describe('KubernetesLabelsSelect', () => {
|
||||
.getByRole('heading', { name: 'Selected Labels (0)' })
|
||||
.closest('div');
|
||||
|
||||
const input = within(selectedSection!).getByPlaceholderText('name: value');
|
||||
await user.type(input, 'foo: bar{enter}');
|
||||
await user.type(input, 'foo2:bar: baz{enter}'); // colon in name
|
||||
await user.type(input, 'foo3: bar:baz{enter}'); // colon in value
|
||||
await user.type(input, 'foo4: bar: baz{enter}'); // colon in value
|
||||
await user.type(input, 'env: *{enter}');
|
||||
const nameInput = within(selectedSection!).getByLabelText('Name');
|
||||
const valueInput = within(selectedSection!).getByLabelText('Value');
|
||||
|
||||
await user.type(nameInput, 'foo');
|
||||
await user.type(valueInput, 'bar{enter}');
|
||||
|
||||
await user.type(nameInput, 'foo2:bar'); // colon in name
|
||||
await user.type(valueInput, 'baz{enter}');
|
||||
|
||||
await user.type(nameInput, 'foo3');
|
||||
await user.type(valueInput, 'bar:baz'); // colon in value
|
||||
await user.type(nameInput, '{enter}');
|
||||
|
||||
await user.type(nameInput, 'foo4');
|
||||
await user.type(valueInput, 'bar: baz{enter}'); // colon and space in value
|
||||
|
||||
await user.type(nameInput, 'env');
|
||||
await user.type(valueInput, '*{enter}');
|
||||
|
||||
await user.type(nameInput, 'region');
|
||||
// Extra square brackets are required to escape the initial pair
|
||||
await user.type(input, 'region: ^eu-(west|east)-[[0-9]]+$');
|
||||
await user.type(valueInput, '^eu-(west|east)-[[0-9]]+$');
|
||||
await user.click(
|
||||
within(selectedSection!).getByRole('button', { name: 'Add' })
|
||||
within(selectedSection!).getByRole('button', { name: 'add label' })
|
||||
);
|
||||
|
||||
expect(
|
||||
@@ -329,8 +344,10 @@ describe('KubernetesLabelsSelect', () => {
|
||||
|
||||
const modal = screen.getByTestId('Modal');
|
||||
|
||||
const input = within(modal).getByPlaceholderText('name: value');
|
||||
await user.type(input, 'foo: bar{enter}');
|
||||
const nameInput = within(modal).getByLabelText('Name');
|
||||
const valueInput = within(modal).getByLabelText('Value');
|
||||
await user.type(nameInput, 'foo');
|
||||
await user.type(valueInput, 'bar{enter}');
|
||||
|
||||
await user.click(within(modal).getByRole('button', { name: 'Done' }));
|
||||
|
||||
@@ -358,8 +375,10 @@ describe('KubernetesLabelsSelect', () => {
|
||||
|
||||
const modal = screen.getByTestId('Modal');
|
||||
|
||||
const input = within(modal).getByPlaceholderText('name: value');
|
||||
await user.type(input, 'foo:bar{enter}');
|
||||
const nameInput = within(modal).getByLabelText('Name');
|
||||
const valueInput = within(modal).getByLabelText('Value');
|
||||
await user.type(nameInput, 'foo');
|
||||
await user.type(valueInput, 'bar{enter}');
|
||||
|
||||
await user.click(within(modal).getByRole('button', { name: 'Cancel' }));
|
||||
|
||||
@@ -430,5 +449,14 @@ function makeWrapper(opts?: {
|
||||
function withListUnifiedResourcesSuccess(opts?: {
|
||||
response?: ResourcesResponse<UnifiedResource>;
|
||||
}) {
|
||||
server.use(fetchUnifiedResourcesSuccess(opts));
|
||||
server.use(
|
||||
fetchUnifiedResourcesSuccess({
|
||||
response: opts?.response
|
||||
? {
|
||||
...opts.response,
|
||||
items: opts.response.agents,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,10 +94,10 @@ export function KubernetesLabelsSelect(
|
||||
|
||||
return (
|
||||
<Box {...styles}>
|
||||
<LabelInput mb={0} aria-label="Labels">
|
||||
<LabelContent>Labels</LabelContent>
|
||||
<LabelInput mb={0} aria-label="Teleport Labels">
|
||||
<LabelContent>Teleport Labels</LabelContent>
|
||||
|
||||
<LabelsContainer aria-describedby={'labels-select-helper-text'}>
|
||||
<LabelsContainer aria-describedby={'labels-select-helper-text'} mt={1}>
|
||||
{selected.map(l => (
|
||||
<Label key={l.name} label={formatLabel(l)} style="secondary" />
|
||||
))}
|
||||
@@ -153,7 +153,8 @@ function Picker(props: {
|
||||
const { selected: initial, onChange, onCancel } = props;
|
||||
|
||||
const [selected, setSelected] = useState(initial);
|
||||
const [manualInput, setManualInput] = useState('');
|
||||
const [manualName, setManualName] = useState('');
|
||||
const [manualValue, setManualValue] = useState('');
|
||||
|
||||
const ctx = useTeleport();
|
||||
const flags = ctx.getFeatureFlags();
|
||||
@@ -178,7 +179,13 @@ function Picker(props: {
|
||||
fetchNextPage,
|
||||
} = useInfiniteQuery({
|
||||
enabled: hasListPermission,
|
||||
queryKey: ['list', 'unified_resources', cfg.proxyCluster, ['kube_cluster']],
|
||||
queryKey: [
|
||||
'list',
|
||||
'unified_resources',
|
||||
'paged',
|
||||
cfg.proxyCluster,
|
||||
['kube_cluster'],
|
||||
],
|
||||
queryFn: ({ pageParam, signal }) =>
|
||||
ctx.resourceService.fetchUnifiedResources(
|
||||
cfg.proxyCluster,
|
||||
@@ -197,20 +204,29 @@ function Picker(props: {
|
||||
|
||||
const handleAdd = (name: string, value: string) => {
|
||||
setSelected(prev => {
|
||||
const index = prev.findIndex(l => l.name === name);
|
||||
if (index == -1) {
|
||||
return [...prev, { name, values: [value] }];
|
||||
// Clear other labels when the wildcard is added
|
||||
if (isWildcardPair(name, value)) {
|
||||
return [WILDCARD_LABEL];
|
||||
}
|
||||
return prev.map(l => {
|
||||
if (l.name === name) {
|
||||
const vs = new Set([...l.values, value]);
|
||||
return {
|
||||
...l,
|
||||
values: [...vs],
|
||||
};
|
||||
}
|
||||
return l;
|
||||
});
|
||||
|
||||
const index = prev.findIndex(l => l.name === name);
|
||||
let next: KubernetesLabel[];
|
||||
if (index == -1) {
|
||||
next = [...prev, { name, values: [value] }];
|
||||
} else {
|
||||
next = prev.map(l => {
|
||||
if (l.name === name) {
|
||||
const vs = new Set([...l.values, value]);
|
||||
return {
|
||||
...l,
|
||||
values: [...vs],
|
||||
};
|
||||
}
|
||||
return l;
|
||||
});
|
||||
}
|
||||
|
||||
return stripWildcard(next);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -219,32 +235,36 @@ function Picker(props: {
|
||||
return;
|
||||
}
|
||||
|
||||
const [n, ...rest] = manualInput.split(': ');
|
||||
const name = n.trim();
|
||||
const value = rest.join(': ').trim();
|
||||
const name = manualName.trim();
|
||||
const value = manualValue.trim();
|
||||
handleAdd(name, value);
|
||||
|
||||
validator.reset();
|
||||
setManualInput('');
|
||||
setManualName('');
|
||||
setManualValue('');
|
||||
};
|
||||
|
||||
const handleRemove = (name: string, value?: string) => {
|
||||
setSelected(prev => {
|
||||
let next: KubernetesLabel[];
|
||||
if (value === undefined) {
|
||||
return prev.filter(l => l.name !== name);
|
||||
next = prev.filter(l => l.name !== name);
|
||||
} else {
|
||||
next = prev.flatMap(l => {
|
||||
if (l.name === name) {
|
||||
l.values = l.values.filter(v => v != value);
|
||||
|
||||
if (l.values.length < 1) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [l];
|
||||
});
|
||||
}
|
||||
|
||||
return prev.flatMap(l => {
|
||||
if (l.name === name) {
|
||||
l.values = l.values.filter(v => v != value);
|
||||
|
||||
if (l.values.length < 1) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [l];
|
||||
});
|
||||
// Add wildcard if all labels are removed
|
||||
return next.length === 0 ? [WILDCARD_LABEL] : next;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -261,7 +281,7 @@ function Picker(props: {
|
||||
<Dialog open onClose={onCancel}>
|
||||
<DialogHeader>
|
||||
<Box width={'100%'}>
|
||||
<DialogTitle>Kubernetes Labels</DialogTitle>
|
||||
<DialogTitle>Teleport Labels</DialogTitle>
|
||||
<Text>Select one or more labels to configure access.</Text>
|
||||
|
||||
{!hasListPermission ? (
|
||||
@@ -362,14 +382,26 @@ function Picker(props: {
|
||||
flex={1}
|
||||
m={0}
|
||||
size="small"
|
||||
rule={requireValidManualLabel}
|
||||
label={'Add custom label'}
|
||||
placeholder="name: value"
|
||||
value={manualInput}
|
||||
onChange={e => setManualInput(e.target.value)}
|
||||
toolTipContent="e.g. env: prod, region: us-*, name: ^kube-(a|b).+$"
|
||||
rule={requireValidLabelName}
|
||||
label="Name"
|
||||
placeholder="e.g. env"
|
||||
value={manualName}
|
||||
onChange={e => setManualName(e.target.value)}
|
||||
/>
|
||||
<ButtonSecondary type="submit">Add</ButtonSecondary>
|
||||
<FieldInput
|
||||
flex={1}
|
||||
m={0}
|
||||
size="small"
|
||||
rule={requireValidLabelValue}
|
||||
label="Value"
|
||||
placeholder="e.g. prod"
|
||||
value={manualValue}
|
||||
onChange={e => setManualValue(e.target.value)}
|
||||
toolTipContent="e.g. prod, us-*, ^kube-(a|b).+$"
|
||||
/>
|
||||
<ButtonIcon type="submit" aria-label="add label">
|
||||
<Plus size="small" />
|
||||
</ButtonIcon>
|
||||
</ManualInputContainer>
|
||||
</div>
|
||||
</form>
|
||||
@@ -396,6 +428,7 @@ const PickerContainer = styled(Flex)`
|
||||
`;
|
||||
|
||||
const ColumnContainer = styled(Flex)`
|
||||
min-width: 360px;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
@@ -424,16 +457,42 @@ const EmptyText = styled(Text)`
|
||||
color: ${p => p.theme.colors.text.muted};
|
||||
`;
|
||||
|
||||
function formatLabel(label: KubernetesLabel) {
|
||||
return `${label.name}: ${label.values.join(' or ')}`;
|
||||
function formatLabel({ name, values }: KubernetesLabel) {
|
||||
if (values.length === 1) {
|
||||
return `${name}: ${values[0]}`;
|
||||
}
|
||||
return `${name}: ( ${values.join(' | ')} )`;
|
||||
}
|
||||
|
||||
const manualLabelRegex = /^ *[a-z0-9:*]+ *: .+$/;
|
||||
export const requireValidManualLabel: Rule = value => () => {
|
||||
const match = manualLabelRegex.test(value);
|
||||
const WILDCARD_LABEL_NAME = '*';
|
||||
const WILDCARD_LABEL_VALUE = '*';
|
||||
const WILDCARD_LABEL: KubernetesLabel = {
|
||||
name: WILDCARD_LABEL_NAME,
|
||||
values: [WILDCARD_LABEL_VALUE],
|
||||
};
|
||||
|
||||
function isWildcardPair(name: string, value: string) {
|
||||
return name === WILDCARD_LABEL_NAME && value === WILDCARD_LABEL_VALUE;
|
||||
}
|
||||
|
||||
function stripWildcard(labels: KubernetesLabel[]) {
|
||||
return labels.filter(l => l.name !== WILDCARD_LABEL_NAME);
|
||||
}
|
||||
|
||||
const labelNameRegex = /^([a-z0-9:]+|\*)$/; // 1-n alphanumerics or colon, or a single asterisk
|
||||
export const requireValidLabelName: Rule = value => () => {
|
||||
const match = labelNameRegex.test(value.trim());
|
||||
return {
|
||||
valid: match,
|
||||
message: match ? undefined : 'Must be in the format "name: value"',
|
||||
message: match ? undefined : 'Alphanumeric or * is required',
|
||||
};
|
||||
};
|
||||
|
||||
export const requireValidLabelValue: Rule = value => () => {
|
||||
const trimmed = value.trim();
|
||||
return {
|
||||
valid: trimmed.length > 0,
|
||||
message: trimmed.length > 0 ? undefined : 'Value is required',
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import styled, { useTheme } from 'styled-components';
|
||||
|
||||
import { Info } from 'design/Alert/Alert';
|
||||
import Box from 'design/Box/Box';
|
||||
import { ButtonPrimary } from 'design/Button/Button';
|
||||
import Flex from 'design/Flex/Flex';
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
|
||||
import { FlowStepProps } from '../Shared/GuidedFlow';
|
||||
import { useTracking } from '../Shared/useTracking';
|
||||
import { CodePanel } from './CodePanel';
|
||||
import welcomeDark from './gha-k8s-welcome-dark.svg';
|
||||
import welcomeLight from './gha-k8s-welcome-light.svg';
|
||||
|
||||
@@ -58,53 +60,87 @@ export function Welcome(props: FlowStepProps) {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Box>
|
||||
<H2 mb={3} mt={3}>
|
||||
GitHub Actions + Kubernetes
|
||||
</H2>
|
||||
<FormContainer>
|
||||
<Box>
|
||||
<H2 mb={3} mt={3}>
|
||||
GitHub Actions + Kubernetes
|
||||
</H2>
|
||||
|
||||
<P2>
|
||||
Use <code>kubectl</code> and other tools from your GitHub Actions
|
||||
workflows.
|
||||
</P2>
|
||||
<P2>
|
||||
Use <code>kubectl</code> and other tools from your GitHub Actions
|
||||
workflows.
|
||||
</P2>
|
||||
|
||||
<P2>You’ll need:</P2>
|
||||
<ul>
|
||||
<li>A GitHub repository</li>
|
||||
<li>Access rules for your workflow</li>
|
||||
</ul>
|
||||
<Image py={4} width={420} src={welcomeImage[theme.type]} />
|
||||
|
||||
<P2>
|
||||
See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={IAC_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(IntegrationEnrollStep.MWIGHAK8SWelcome, IAC_LINK);
|
||||
}}
|
||||
<P2>You’ll need:</P2>
|
||||
<ul>
|
||||
<li>A GitHub repository</li>
|
||||
<li>An enrolled Kubernetes cluster</li>
|
||||
</ul>
|
||||
|
||||
<Info
|
||||
alignItems="flex-start"
|
||||
mt={4}
|
||||
details={
|
||||
<>
|
||||
This guide uses Infrastructure as Code (IaC) to create the
|
||||
resources required to complete the setup. See the{' '}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={IAC_LINK}
|
||||
onClick={() => {
|
||||
tracking.link(
|
||||
IntegrationEnrollStep.MWIGHAK8SWelcome,
|
||||
IAC_LINK
|
||||
);
|
||||
}}
|
||||
>
|
||||
Infrastructure as Code
|
||||
</Link>{' '}
|
||||
docs for information about setting up and using IaC with
|
||||
Teleport.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Infrastructure as Code
|
||||
</Link>{' '}
|
||||
docs for information about setting up and using IaC with Teleport.
|
||||
</P2>
|
||||
Infrastructure as Code required
|
||||
</Info>
|
||||
|
||||
<Flex gap={2} pt={5}>
|
||||
<ButtonPrimary onClick={handleNext}>Start</ButtonPrimary>
|
||||
</Flex>
|
||||
</Box>
|
||||
<Flex gap={2} pt={1}>
|
||||
<ButtonPrimary onClick={handleNext}>Start</ButtonPrimary>
|
||||
</Flex>
|
||||
</Box>
|
||||
</FormContainer>
|
||||
|
||||
<Image p={5} width={420} src={welcomeImage[theme.type]} />
|
||||
<CodeContainer>
|
||||
<CodePanel
|
||||
trackingStep={IntegrationEnrollStep.MWIGHAK8SWelcome}
|
||||
inProgress
|
||||
/>
|
||||
</CodeContainer>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const Container = styled(Flex)`
|
||||
align-items: flex-start;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
gap: ${({ theme }) => theme.space[1]}px;
|
||||
`;
|
||||
|
||||
const FormContainer = styled(Flex)`
|
||||
flex: 4;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding-right: ${({ theme }) => theme.space[5]}px;
|
||||
`;
|
||||
|
||||
const CodeContainer = styled(Flex)`
|
||||
flex: 6;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
type ImageSpec = {
|
||||
[K in Theme['type']]: string;
|
||||
};
|
||||
|
||||
@@ -19,11 +19,17 @@
|
||||
export function makeGhaWorkflow(params: {
|
||||
tokenName: string;
|
||||
clusterPublicUrl: string;
|
||||
clusterName: string;
|
||||
}) {
|
||||
return GHA_WORKFLOW.replaceAll(
|
||||
':token_name',
|
||||
JSON.stringify(params.tokenName)
|
||||
).replaceAll(':cluster_public_url', JSON.stringify(params.clusterPublicUrl));
|
||||
)
|
||||
.replaceAll(':cluster_public_url', JSON.stringify(params.clusterPublicUrl))
|
||||
.replaceAll(
|
||||
':kubernetes_cluster',
|
||||
JSON.stringify(params.clusterName || 'my-kubernetes-cluster')
|
||||
);
|
||||
}
|
||||
|
||||
export const GHA_WORKFLOW = `# This file contains a GitHub Actions workflow which enrolls with Teleport in
|
||||
@@ -34,6 +40,9 @@ export const GHA_WORKFLOW = `# This file contains a GitHub Actions workflow whic
|
||||
# the events that trigger your workflow, such as when pushing to a named branch
|
||||
# or triggering it manually.
|
||||
|
||||
# Note: the workflow file may need to exist on the "main branch" in your repo
|
||||
# before it will appear in GitHub Actions.
|
||||
|
||||
# For more information about using GitHub Actions read the getting started
|
||||
# guide; https://docs.github.com/en/actions/get-started/quickstart
|
||||
|
||||
@@ -42,9 +51,7 @@ on: workflow_dispatch
|
||||
env:
|
||||
TELEPORT_PROXY_ADDR: :cluster_public_url
|
||||
TELEPORT_JOIN_TOKEN_NAME: :token_name
|
||||
|
||||
# TODO: Provide the name of the Kubernetes cluster in Teleport
|
||||
TELEPORT_K8S_CLUSTER_NAME: my-kubernetes-cluster
|
||||
TELEPORT_K8S_CLUSTER_NAME: :kubernetes_cluster
|
||||
|
||||
jobs:
|
||||
demo:
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.state).toStrictEqual(withDefaultState({}));
|
||||
expect(result.current.template.terraform.data).toBe(
|
||||
@@ -108,7 +108,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"enterprise_server_host":"github.example.com"'
|
||||
@@ -153,14 +153,14 @@ describe('useGitHubK8sFlow', () => {
|
||||
expect(result.current.state).toStrictEqual(
|
||||
withDefaultState({
|
||||
branch: 'release-*',
|
||||
ref: 'release-*',
|
||||
ref: 'refs/heads/release-*',
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"ref":"release-*"'
|
||||
'"ref":"refs/heads/release-*"'
|
||||
);
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"ref_type":"branch"'
|
||||
@@ -206,7 +206,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"workflow":"my-workflow"'
|
||||
@@ -233,7 +233,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"environment":"production"'
|
||||
@@ -261,7 +261,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"ref":"release-*"'
|
||||
@@ -296,7 +296,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"ref_type":"tag"'
|
||||
@@ -323,7 +323,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"enterprise_slug":"octo-enterprise"'
|
||||
@@ -350,13 +350,40 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"static_jwks":"{\\"keys\\": []}"'
|
||||
);
|
||||
});
|
||||
|
||||
test('kubernetes cluster', async () => {
|
||||
withGenWizardCiCdSuccess();
|
||||
|
||||
const { result } = renderHook(() => useGitHubK8sFlow(), {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.dispatch({
|
||||
type: 'kubernetes-cluster-changed',
|
||||
value: 'my-kubernetes-cluster',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.state).toStrictEqual(
|
||||
withDefaultState({
|
||||
kubernetesCluster: 'my-kubernetes-cluster',
|
||||
})
|
||||
);
|
||||
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.ghaWorkflow).toContain(
|
||||
'TELEPORT_K8S_CLUSTER_NAME: "my-kubernetes-cluster"'
|
||||
);
|
||||
});
|
||||
|
||||
test('kubernetes groups', async () => {
|
||||
withGenWizardCiCdSuccess();
|
||||
|
||||
@@ -377,7 +404,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"groups":["system:masters"]'
|
||||
@@ -409,7 +436,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"labels":{"foo":["bar"]}'
|
||||
@@ -436,7 +463,7 @@ describe('useGitHubK8sFlow', () => {
|
||||
})
|
||||
);
|
||||
|
||||
await waitForAPI(result.current);
|
||||
await waitForGenerateCall(result);
|
||||
|
||||
expect(result.current.template.terraform.data).toContain(
|
||||
'"users":["user1@example.com"]'
|
||||
@@ -444,9 +471,13 @@ describe('useGitHubK8sFlow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
async function waitForAPI(context: ReturnType<typeof useGitHubK8sFlow>) {
|
||||
async function waitForGenerateCall(result: {
|
||||
current: ReturnType<typeof useGitHubK8sFlow>;
|
||||
}) {
|
||||
await act(jest.advanceTimersToNextTimerAsync);
|
||||
return waitFor(() => expect(context.template.terraform.loading).toBeFalsy());
|
||||
return waitFor(() => {
|
||||
expect(result.current.template.terraform.loading).toBeFalsy();
|
||||
});
|
||||
}
|
||||
|
||||
function withDefaultState(
|
||||
@@ -471,6 +502,7 @@ function withDefaultState(
|
||||
},
|
||||
],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: '',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ export function GitHubK8sFlowProvider(
|
||||
ghaWorkflow: makeGhaWorkflow({
|
||||
tokenName: `gha-${state.info?.owner ?? 'gravitational'}-${state.info?.repository ?? 'teleport'}`,
|
||||
clusterPublicUrl: cluster.publicURL,
|
||||
clusterName: state.kubernetesCluster,
|
||||
}),
|
||||
},
|
||||
};
|
||||
@@ -175,11 +176,17 @@ function reducer(prev: State, action: Action): State {
|
||||
info,
|
||||
};
|
||||
case 'branch-changed':
|
||||
const branch = action.value;
|
||||
const ref = branch
|
||||
? branch.startsWith('refs/heads/')
|
||||
? branch
|
||||
: `refs/heads/${branch}`
|
||||
: '';
|
||||
return {
|
||||
...prev,
|
||||
branch: action.value,
|
||||
branch,
|
||||
allowAnyBranch: false,
|
||||
ref: action.value,
|
||||
ref,
|
||||
refType: 'branch',
|
||||
};
|
||||
case 'allow-any-branch-toggled':
|
||||
@@ -189,14 +196,19 @@ function reducer(prev: State, action: Action): State {
|
||||
branch: '',
|
||||
ref: '',
|
||||
};
|
||||
case 'ref-changed':
|
||||
case 'ref-changed': {
|
||||
const branch =
|
||||
prev.refType === 'branch'
|
||||
? action.value.replace(/^refs\/heads\//, '')
|
||||
: '';
|
||||
return {
|
||||
...prev,
|
||||
ref: action.value,
|
||||
// Keep ref in sync with branch while ref type is 'branch'
|
||||
branch: prev.refType === 'branch' ? action.value : '',
|
||||
branch: branch,
|
||||
isBranchDisabled: prev.refType !== 'branch',
|
||||
};
|
||||
}
|
||||
case 'ref-type-changed':
|
||||
return {
|
||||
...prev,
|
||||
@@ -240,6 +252,11 @@ function reducer(prev: State, action: Action): State {
|
||||
...prev,
|
||||
kubernetesUsers: action.value,
|
||||
};
|
||||
case 'kubernetes-cluster-changed':
|
||||
return {
|
||||
...prev,
|
||||
kubernetesCluster: action.value,
|
||||
};
|
||||
default:
|
||||
const exhaustiveCheck: never = action;
|
||||
throw new Error(`Unhandled action type: ${exhaustiveCheck}`);
|
||||
@@ -255,7 +272,8 @@ type Action =
|
||||
| 'workflow-changed'
|
||||
| 'environment-changed'
|
||||
| 'slug-changed'
|
||||
| 'jwks-changed';
|
||||
| 'jwks-changed'
|
||||
| 'kubernetes-cluster-changed';
|
||||
value: string;
|
||||
}
|
||||
| {
|
||||
@@ -294,6 +312,7 @@ type State = {
|
||||
kubernetesGroups: string[];
|
||||
kubernetesLabels: KubernetesLabel[];
|
||||
kubernetesUsers: string[];
|
||||
kubernetesCluster: string;
|
||||
};
|
||||
|
||||
const defaultState: State = {
|
||||
@@ -310,6 +329,7 @@ const defaultState: State = {
|
||||
kubernetesGroups: [],
|
||||
kubernetesLabels: [{ name: '*', values: ['*'] }],
|
||||
kubernetesUsers: [],
|
||||
kubernetesCluster: '',
|
||||
};
|
||||
|
||||
type Context = {
|
||||
|
||||
@@ -164,6 +164,7 @@ export enum IntegrationEnrollField {
|
||||
MWIGHAK8SKubernetesGroups = 'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS',
|
||||
MWIGHAK8SKubernetesUsers = 'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS',
|
||||
MWIGHAK8SKubernetesResourceRules = 'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_RESOURCE_RULES',
|
||||
MWIGHAK8SKubernetesClusterName = 'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_CLUSTER_NAME',
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -179,17 +179,25 @@ export const editBotForever = () =>
|
||||
|
||||
export const genWizardCiCdSuccess = (options?: {
|
||||
response?: Awaited<ReturnType<typeof generateGhaK8sTemplates>>;
|
||||
prettyFormat?: boolean;
|
||||
}) => {
|
||||
return http.post(cfg.api.bot.genWizardCiCd, async ({ request }) => {
|
||||
const {
|
||||
response = {
|
||||
terraform: TERRAFORM_MOCK.replaceAll(
|
||||
':body',
|
||||
await request.clone().text()
|
||||
),
|
||||
},
|
||||
} = options ?? {};
|
||||
return HttpResponse.json(response);
|
||||
const { response, prettyFormat } = options ?? {};
|
||||
|
||||
const body = prettyFormat
|
||||
? JSON.stringify(await request.clone().json(), undefined, 2)
|
||||
.split('\n')
|
||||
.map(l => `# ${l}`)
|
||||
.join('\n')
|
||||
: `# ${await request.clone().text()}`;
|
||||
|
||||
const terraform = TERRAFORM_MOCK.replaceAll(':body', body);
|
||||
|
||||
return HttpResponse.json(
|
||||
response ?? {
|
||||
terraform,
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -215,7 +223,7 @@ export const genWizardCiCdForever = () =>
|
||||
);
|
||||
|
||||
const TERRAFORM_MOCK = `# POST ${cfg.api.bot.genWizardCiCd}
|
||||
# :body
|
||||
:body
|
||||
|
||||
# This is a mocked Terraform template
|
||||
resource "teleport_bot" "bot_name" {
|
||||
|
||||
@@ -28,7 +28,9 @@ import { JsonObject } from 'teleport/types';
|
||||
const path = '/v1/webapi/sites/:clusterId/resources';
|
||||
|
||||
export const fetchUnifiedResourcesSuccess = (opts?: {
|
||||
response?: ResourcesResponse<UnifiedResource>;
|
||||
response?: ResourcesResponse<UnifiedResource> & { items: UnifiedResource[] };
|
||||
delayMs?: number;
|
||||
mockSearch?: boolean;
|
||||
}) => {
|
||||
const {
|
||||
response = {
|
||||
@@ -91,10 +93,28 @@ export const fetchUnifiedResourcesSuccess = (opts?: {
|
||||
},
|
||||
],
|
||||
},
|
||||
delayMs = 0,
|
||||
mockSearch = false,
|
||||
} = opts ?? {};
|
||||
|
||||
return http.get(path, () => {
|
||||
return HttpResponse.json(response);
|
||||
return http.get(path, async ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
const search = url.searchParams.get('search');
|
||||
|
||||
if (delayMs) {
|
||||
await new Promise(res => setTimeout(res, delayMs));
|
||||
}
|
||||
|
||||
return HttpResponse.json({
|
||||
...response,
|
||||
...(mockSearch && search
|
||||
? {
|
||||
items: response.items.filter(
|
||||
a => a.kind != 'kube_cluster' || a.name.includes(search)
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user