@a5c-ai/krate 5.0.1-staging.ee474eb45 → 5.0.1-staging.f218abf6f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"platformNamespace": "krate-org-default"
|
|
20
20
|
}
|
|
21
21
|
],
|
|
22
|
-
"generatedAt": "2026-05-
|
|
22
|
+
"generatedAt": "2026-05-16T08:09:04.602Z",
|
|
23
23
|
"correlationId": null,
|
|
24
24
|
"controller": {
|
|
25
25
|
"mode": "krate-workspace",
|
|
@@ -583,7 +583,7 @@
|
|
|
583
583
|
"maintainers"
|
|
584
584
|
],
|
|
585
585
|
"invitedBy": "admin",
|
|
586
|
-
"expiresAt": "2026-05-
|
|
586
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
587
587
|
},
|
|
588
588
|
"status": {
|
|
589
589
|
"phase": "Pending",
|
|
@@ -595,7 +595,7 @@
|
|
|
595
595
|
"Pending": 1
|
|
596
596
|
},
|
|
597
597
|
"storage": "etcd",
|
|
598
|
-
"yaml": "apiVersion: krate.a5c.ai/v1alpha1\nkind: Invite\nmetadata:\n namespace: krate-org-default\n labels:\n role: member\n annotations:\n name: new-user-example-com\n resourceVersion: 1\nspec:\n organizationRef: default\n email: new-user@example.com\n role: member\n teams:\n - maintainers\n invitedBy: admin\n expiresAt: 2026-05-
|
|
598
|
+
"yaml": "apiVersion: krate.a5c.ai/v1alpha1\nkind: Invite\nmetadata:\n namespace: krate-org-default\n labels:\n role: member\n annotations:\n name: new-user-example-com\n resourceVersion: 1\nspec:\n organizationRef: default\n email: new-user@example.com\n role: member\n teams:\n - maintainers\n invitedBy: admin\n expiresAt: 2026-05-23T08:09:04.599Z\nstatus:\n phase: Pending\n storage: etcd\n",
|
|
599
599
|
"action": {
|
|
600
600
|
"list": "Open Invite records in krate-org-default",
|
|
601
601
|
"watch": "Watch Invite updates in krate-org-default",
|
|
@@ -2476,7 +2476,7 @@
|
|
|
2476
2476
|
"maintainers"
|
|
2477
2477
|
],
|
|
2478
2478
|
"phase": "Pending",
|
|
2479
|
-
"expiresAt": "2026-05-
|
|
2479
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
2480
2480
|
}
|
|
2481
2481
|
],
|
|
2482
2482
|
"mappings": [
|
|
@@ -3082,7 +3082,7 @@
|
|
|
3082
3082
|
"maintainers"
|
|
3083
3083
|
],
|
|
3084
3084
|
"phase": "Pending",
|
|
3085
|
-
"expiresAt": "2026-05-
|
|
3085
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
3086
3086
|
}
|
|
3087
3087
|
],
|
|
3088
3088
|
"mappings": [
|
|
@@ -465,7 +465,7 @@
|
|
|
465
465
|
"maintainers"
|
|
466
466
|
],
|
|
467
467
|
"invitedBy": "admin",
|
|
468
|
-
"expiresAt": "2026-05-
|
|
468
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
469
469
|
},
|
|
470
470
|
"status": {
|
|
471
471
|
"phase": "Pending",
|
|
@@ -547,7 +547,7 @@
|
|
|
547
547
|
},
|
|
548
548
|
"auditLog": [
|
|
549
549
|
{
|
|
550
|
-
"at": "2026-05-
|
|
550
|
+
"at": "2026-05-16T08:09:04.597Z",
|
|
551
551
|
"operation": "create",
|
|
552
552
|
"user": "admin@example.com",
|
|
553
553
|
"groups": [
|
|
@@ -559,7 +559,7 @@
|
|
|
559
559
|
"allowed": true
|
|
560
560
|
},
|
|
561
561
|
{
|
|
562
|
-
"at": "2026-05-
|
|
562
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
563
563
|
"operation": "create",
|
|
564
564
|
"user": "admin@example.com",
|
|
565
565
|
"groups": [
|
|
@@ -571,7 +571,7 @@
|
|
|
571
571
|
"allowed": true
|
|
572
572
|
},
|
|
573
573
|
{
|
|
574
|
-
"at": "2026-05-
|
|
574
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
575
575
|
"operation": "create",
|
|
576
576
|
"user": "admin@example.com",
|
|
577
577
|
"groups": [
|
|
@@ -583,7 +583,7 @@
|
|
|
583
583
|
"allowed": true
|
|
584
584
|
},
|
|
585
585
|
{
|
|
586
|
-
"at": "2026-05-
|
|
586
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
587
587
|
"operation": "create",
|
|
588
588
|
"user": "platform@example.com",
|
|
589
589
|
"groups": [
|
|
@@ -595,7 +595,7 @@
|
|
|
595
595
|
"allowed": true
|
|
596
596
|
},
|
|
597
597
|
{
|
|
598
|
-
"at": "2026-05-
|
|
598
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
599
599
|
"operation": "create",
|
|
600
600
|
"user": "admin@example.com",
|
|
601
601
|
"groups": [
|
|
@@ -607,7 +607,7 @@
|
|
|
607
607
|
"allowed": true
|
|
608
608
|
},
|
|
609
609
|
{
|
|
610
|
-
"at": "2026-05-
|
|
610
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
611
611
|
"operation": "create",
|
|
612
612
|
"user": "platform@example.com",
|
|
613
613
|
"groups": [
|
|
@@ -619,7 +619,7 @@
|
|
|
619
619
|
"allowed": true
|
|
620
620
|
},
|
|
621
621
|
{
|
|
622
|
-
"at": "2026-05-
|
|
622
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
623
623
|
"operation": "create",
|
|
624
624
|
"user": "platform@example.com",
|
|
625
625
|
"groups": [
|
|
@@ -631,7 +631,7 @@
|
|
|
631
631
|
"allowed": true
|
|
632
632
|
},
|
|
633
633
|
{
|
|
634
|
-
"at": "2026-05-
|
|
634
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
635
635
|
"operation": "create",
|
|
636
636
|
"user": "platform@example.com",
|
|
637
637
|
"groups": [
|
|
@@ -643,7 +643,7 @@
|
|
|
643
643
|
"allowed": true
|
|
644
644
|
},
|
|
645
645
|
{
|
|
646
|
-
"at": "2026-05-
|
|
646
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
647
647
|
"operation": "create",
|
|
648
648
|
"user": "admin@example.com",
|
|
649
649
|
"groups": [
|
|
@@ -655,7 +655,7 @@
|
|
|
655
655
|
"allowed": true
|
|
656
656
|
},
|
|
657
657
|
{
|
|
658
|
-
"at": "2026-05-
|
|
658
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
659
659
|
"operation": "create",
|
|
660
660
|
"user": "platform@example.com",
|
|
661
661
|
"groups": [
|
|
@@ -667,7 +667,7 @@
|
|
|
667
667
|
"allowed": true
|
|
668
668
|
},
|
|
669
669
|
{
|
|
670
|
-
"at": "2026-05-
|
|
670
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
671
671
|
"operation": "create",
|
|
672
672
|
"user": "platform@example.com",
|
|
673
673
|
"groups": [
|
|
@@ -915,7 +915,7 @@
|
|
|
915
915
|
}
|
|
916
916
|
},
|
|
917
917
|
"audit": {
|
|
918
|
-
"at": "2026-05-
|
|
918
|
+
"at": "2026-05-16T08:09:04.597Z",
|
|
919
919
|
"operation": "create",
|
|
920
920
|
"user": "admin@example.com",
|
|
921
921
|
"groups": [
|
|
@@ -956,7 +956,7 @@
|
|
|
956
956
|
}
|
|
957
957
|
},
|
|
958
958
|
"audit": {
|
|
959
|
-
"at": "2026-05-
|
|
959
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
960
960
|
"operation": "create",
|
|
961
961
|
"user": "admin@example.com",
|
|
962
962
|
"groups": [
|
|
@@ -992,7 +992,7 @@
|
|
|
992
992
|
}
|
|
993
993
|
},
|
|
994
994
|
"audit": {
|
|
995
|
-
"at": "2026-05-
|
|
995
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
996
996
|
"operation": "create",
|
|
997
997
|
"user": "admin@example.com",
|
|
998
998
|
"groups": [
|
|
@@ -1037,7 +1037,7 @@
|
|
|
1037
1037
|
}
|
|
1038
1038
|
},
|
|
1039
1039
|
"audit": {
|
|
1040
|
-
"at": "2026-05-
|
|
1040
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
1041
1041
|
"operation": "create",
|
|
1042
1042
|
"user": "platform@example.com",
|
|
1043
1043
|
"groups": [
|
|
@@ -1081,7 +1081,7 @@
|
|
|
1081
1081
|
}
|
|
1082
1082
|
},
|
|
1083
1083
|
"audit": {
|
|
1084
|
-
"at": "2026-05-
|
|
1084
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
1085
1085
|
"operation": "create",
|
|
1086
1086
|
"user": "admin@example.com",
|
|
1087
1087
|
"groups": [
|
|
@@ -1129,7 +1129,7 @@
|
|
|
1129
1129
|
}
|
|
1130
1130
|
},
|
|
1131
1131
|
"audit": {
|
|
1132
|
-
"at": "2026-05-
|
|
1132
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
1133
1133
|
"operation": "create",
|
|
1134
1134
|
"user": "platform@example.com",
|
|
1135
1135
|
"groups": [
|
|
@@ -1179,7 +1179,7 @@
|
|
|
1179
1179
|
}
|
|
1180
1180
|
},
|
|
1181
1181
|
"audit": {
|
|
1182
|
-
"at": "2026-05-
|
|
1182
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
1183
1183
|
"operation": "create",
|
|
1184
1184
|
"user": "platform@example.com",
|
|
1185
1185
|
"groups": [
|
|
@@ -1230,7 +1230,7 @@
|
|
|
1230
1230
|
}
|
|
1231
1231
|
},
|
|
1232
1232
|
"audit": {
|
|
1233
|
-
"at": "2026-05-
|
|
1233
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
1234
1234
|
"operation": "create",
|
|
1235
1235
|
"user": "platform@example.com",
|
|
1236
1236
|
"groups": [
|
|
@@ -1265,7 +1265,7 @@
|
|
|
1265
1265
|
"maintainers"
|
|
1266
1266
|
],
|
|
1267
1267
|
"invitedBy": "admin",
|
|
1268
|
-
"expiresAt": "2026-05-
|
|
1268
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
1269
1269
|
},
|
|
1270
1270
|
"status": {
|
|
1271
1271
|
"phase": "Pending",
|
|
@@ -1273,7 +1273,7 @@
|
|
|
1273
1273
|
}
|
|
1274
1274
|
},
|
|
1275
1275
|
"audit": {
|
|
1276
|
-
"at": "2026-05-
|
|
1276
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
1277
1277
|
"operation": "create",
|
|
1278
1278
|
"user": "admin@example.com",
|
|
1279
1279
|
"groups": [
|
|
@@ -1324,7 +1324,7 @@
|
|
|
1324
1324
|
}
|
|
1325
1325
|
},
|
|
1326
1326
|
"audit": {
|
|
1327
|
-
"at": "2026-05-
|
|
1327
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
1328
1328
|
"operation": "create",
|
|
1329
1329
|
"user": "platform@example.com",
|
|
1330
1330
|
"groups": [
|
|
@@ -1375,7 +1375,7 @@
|
|
|
1375
1375
|
}
|
|
1376
1376
|
},
|
|
1377
1377
|
"audit": {
|
|
1378
|
-
"at": "2026-05-
|
|
1378
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
1379
1379
|
"operation": "create",
|
|
1380
1380
|
"user": "platform@example.com",
|
|
1381
1381
|
"groups": [
|
|
@@ -1810,7 +1810,7 @@
|
|
|
1810
1810
|
"maintainers"
|
|
1811
1811
|
],
|
|
1812
1812
|
"invitedBy": "admin",
|
|
1813
|
-
"expiresAt": "2026-05-
|
|
1813
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
1814
1814
|
},
|
|
1815
1815
|
"status": {
|
|
1816
1816
|
"phase": "Pending",
|
|
@@ -2515,7 +2515,7 @@
|
|
|
2515
2515
|
}
|
|
2516
2516
|
},
|
|
2517
2517
|
"audit": {
|
|
2518
|
-
"at": "2026-05-
|
|
2518
|
+
"at": "2026-05-16T08:09:04.597Z",
|
|
2519
2519
|
"operation": "create",
|
|
2520
2520
|
"user": "admin@example.com",
|
|
2521
2521
|
"groups": [
|
|
@@ -2556,7 +2556,7 @@
|
|
|
2556
2556
|
}
|
|
2557
2557
|
},
|
|
2558
2558
|
"audit": {
|
|
2559
|
-
"at": "2026-05-
|
|
2559
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
2560
2560
|
"operation": "create",
|
|
2561
2561
|
"user": "admin@example.com",
|
|
2562
2562
|
"groups": [
|
|
@@ -2592,7 +2592,7 @@
|
|
|
2592
2592
|
}
|
|
2593
2593
|
},
|
|
2594
2594
|
"audit": {
|
|
2595
|
-
"at": "2026-05-
|
|
2595
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
2596
2596
|
"operation": "create",
|
|
2597
2597
|
"user": "admin@example.com",
|
|
2598
2598
|
"groups": [
|
|
@@ -2637,7 +2637,7 @@
|
|
|
2637
2637
|
}
|
|
2638
2638
|
},
|
|
2639
2639
|
"audit": {
|
|
2640
|
-
"at": "2026-05-
|
|
2640
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
2641
2641
|
"operation": "create",
|
|
2642
2642
|
"user": "platform@example.com",
|
|
2643
2643
|
"groups": [
|
|
@@ -2681,7 +2681,7 @@
|
|
|
2681
2681
|
}
|
|
2682
2682
|
},
|
|
2683
2683
|
"audit": {
|
|
2684
|
-
"at": "2026-05-
|
|
2684
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
2685
2685
|
"operation": "create",
|
|
2686
2686
|
"user": "admin@example.com",
|
|
2687
2687
|
"groups": [
|
|
@@ -2729,7 +2729,7 @@
|
|
|
2729
2729
|
}
|
|
2730
2730
|
},
|
|
2731
2731
|
"audit": {
|
|
2732
|
-
"at": "2026-05-
|
|
2732
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
2733
2733
|
"operation": "create",
|
|
2734
2734
|
"user": "platform@example.com",
|
|
2735
2735
|
"groups": [
|
|
@@ -2779,7 +2779,7 @@
|
|
|
2779
2779
|
}
|
|
2780
2780
|
},
|
|
2781
2781
|
"audit": {
|
|
2782
|
-
"at": "2026-05-
|
|
2782
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
2783
2783
|
"operation": "create",
|
|
2784
2784
|
"user": "platform@example.com",
|
|
2785
2785
|
"groups": [
|
|
@@ -2830,7 +2830,7 @@
|
|
|
2830
2830
|
}
|
|
2831
2831
|
},
|
|
2832
2832
|
"audit": {
|
|
2833
|
-
"at": "2026-05-
|
|
2833
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
2834
2834
|
"operation": "create",
|
|
2835
2835
|
"user": "platform@example.com",
|
|
2836
2836
|
"groups": [
|
|
@@ -2865,7 +2865,7 @@
|
|
|
2865
2865
|
"maintainers"
|
|
2866
2866
|
],
|
|
2867
2867
|
"invitedBy": "admin",
|
|
2868
|
-
"expiresAt": "2026-05-
|
|
2868
|
+
"expiresAt": "2026-05-23T08:09:04.599Z"
|
|
2869
2869
|
},
|
|
2870
2870
|
"status": {
|
|
2871
2871
|
"phase": "Pending",
|
|
@@ -2873,7 +2873,7 @@
|
|
|
2873
2873
|
}
|
|
2874
2874
|
},
|
|
2875
2875
|
"audit": {
|
|
2876
|
-
"at": "2026-05-
|
|
2876
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
2877
2877
|
"operation": "create",
|
|
2878
2878
|
"user": "admin@example.com",
|
|
2879
2879
|
"groups": [
|
|
@@ -2924,7 +2924,7 @@
|
|
|
2924
2924
|
}
|
|
2925
2925
|
},
|
|
2926
2926
|
"audit": {
|
|
2927
|
-
"at": "2026-05-
|
|
2927
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
2928
2928
|
"operation": "create",
|
|
2929
2929
|
"user": "platform@example.com",
|
|
2930
2930
|
"groups": [
|
|
@@ -2975,7 +2975,7 @@
|
|
|
2975
2975
|
}
|
|
2976
2976
|
},
|
|
2977
2977
|
"audit": {
|
|
2978
|
-
"at": "2026-05-
|
|
2978
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
2979
2979
|
"operation": "create",
|
|
2980
2980
|
"user": "platform@example.com",
|
|
2981
2981
|
"groups": [
|
|
@@ -2990,7 +2990,7 @@
|
|
|
2990
2990
|
],
|
|
2991
2991
|
"auditLog": [
|
|
2992
2992
|
{
|
|
2993
|
-
"at": "2026-05-
|
|
2993
|
+
"at": "2026-05-16T08:09:04.597Z",
|
|
2994
2994
|
"operation": "create",
|
|
2995
2995
|
"user": "admin@example.com",
|
|
2996
2996
|
"groups": [
|
|
@@ -3002,7 +3002,7 @@
|
|
|
3002
3002
|
"allowed": true
|
|
3003
3003
|
},
|
|
3004
3004
|
{
|
|
3005
|
-
"at": "2026-05-
|
|
3005
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
3006
3006
|
"operation": "create",
|
|
3007
3007
|
"user": "admin@example.com",
|
|
3008
3008
|
"groups": [
|
|
@@ -3014,7 +3014,7 @@
|
|
|
3014
3014
|
"allowed": true
|
|
3015
3015
|
},
|
|
3016
3016
|
{
|
|
3017
|
-
"at": "2026-05-
|
|
3017
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
3018
3018
|
"operation": "create",
|
|
3019
3019
|
"user": "admin@example.com",
|
|
3020
3020
|
"groups": [
|
|
@@ -3026,7 +3026,7 @@
|
|
|
3026
3026
|
"allowed": true
|
|
3027
3027
|
},
|
|
3028
3028
|
{
|
|
3029
|
-
"at": "2026-05-
|
|
3029
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
3030
3030
|
"operation": "create",
|
|
3031
3031
|
"user": "platform@example.com",
|
|
3032
3032
|
"groups": [
|
|
@@ -3038,7 +3038,7 @@
|
|
|
3038
3038
|
"allowed": true
|
|
3039
3039
|
},
|
|
3040
3040
|
{
|
|
3041
|
-
"at": "2026-05-
|
|
3041
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
3042
3042
|
"operation": "create",
|
|
3043
3043
|
"user": "admin@example.com",
|
|
3044
3044
|
"groups": [
|
|
@@ -3050,7 +3050,7 @@
|
|
|
3050
3050
|
"allowed": true
|
|
3051
3051
|
},
|
|
3052
3052
|
{
|
|
3053
|
-
"at": "2026-05-
|
|
3053
|
+
"at": "2026-05-16T08:09:04.598Z",
|
|
3054
3054
|
"operation": "create",
|
|
3055
3055
|
"user": "platform@example.com",
|
|
3056
3056
|
"groups": [
|
|
@@ -3062,7 +3062,7 @@
|
|
|
3062
3062
|
"allowed": true
|
|
3063
3063
|
},
|
|
3064
3064
|
{
|
|
3065
|
-
"at": "2026-05-
|
|
3065
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
3066
3066
|
"operation": "create",
|
|
3067
3067
|
"user": "platform@example.com",
|
|
3068
3068
|
"groups": [
|
|
@@ -3074,7 +3074,7 @@
|
|
|
3074
3074
|
"allowed": true
|
|
3075
3075
|
},
|
|
3076
3076
|
{
|
|
3077
|
-
"at": "2026-05-
|
|
3077
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
3078
3078
|
"operation": "create",
|
|
3079
3079
|
"user": "platform@example.com",
|
|
3080
3080
|
"groups": [
|
|
@@ -3086,7 +3086,7 @@
|
|
|
3086
3086
|
"allowed": true
|
|
3087
3087
|
},
|
|
3088
3088
|
{
|
|
3089
|
-
"at": "2026-05-
|
|
3089
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
3090
3090
|
"operation": "create",
|
|
3091
3091
|
"user": "admin@example.com",
|
|
3092
3092
|
"groups": [
|
|
@@ -3098,7 +3098,7 @@
|
|
|
3098
3098
|
"allowed": true
|
|
3099
3099
|
},
|
|
3100
3100
|
{
|
|
3101
|
-
"at": "2026-05-
|
|
3101
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
3102
3102
|
"operation": "create",
|
|
3103
3103
|
"user": "platform@example.com",
|
|
3104
3104
|
"groups": [
|
|
@@ -3110,7 +3110,7 @@
|
|
|
3110
3110
|
"allowed": true
|
|
3111
3111
|
},
|
|
3112
3112
|
{
|
|
3113
|
-
"at": "2026-05-
|
|
3113
|
+
"at": "2026-05-16T08:09:04.599Z",
|
|
3114
3114
|
"operation": "create",
|
|
3115
3115
|
"user": "platform@example.com",
|
|
3116
3116
|
"groups": [
|
package/dist/krate-summary.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Kubernetes-native forge runtime with Argo CD and Krate-managed repository hosting",
|
|
4
4
|
"package": {
|
|
5
5
|
"name": "@a5c-ai/krate",
|
|
6
|
-
"version": "5.0.1-staging.
|
|
6
|
+
"version": "5.0.1-staging.f218abf6f",
|
|
7
7
|
"private": true
|
|
8
8
|
},
|
|
9
9
|
"entrypoints": {
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"lifecycle": {
|
|
163
163
|
"project": "Krate",
|
|
164
164
|
"version": "0.1.0",
|
|
165
|
-
"generatedAt": "2026-05-
|
|
165
|
+
"generatedAt": "2026-05-16T08:09:04.610Z",
|
|
166
166
|
"status": "ready-for-local-development",
|
|
167
167
|
"components": [
|
|
168
168
|
{
|
|
@@ -464,7 +464,7 @@
|
|
|
464
464
|
"ok": true,
|
|
465
465
|
"assertions": []
|
|
466
466
|
},
|
|
467
|
-
"generatedAt": "2026-05-
|
|
467
|
+
"generatedAt": "2026-05-16T08:09:04.610Z",
|
|
468
468
|
"controller": {
|
|
469
469
|
"status": "degraded",
|
|
470
470
|
"namespace": "krate-org-default",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a5c-ai/krate",
|
|
3
|
-
"version": "5.0.1-staging.
|
|
3
|
+
"version": "5.0.1-staging.f218abf6f",
|
|
4
4
|
"description": "a5c.ai Krate: Kubernetes-native forge runtime with Argo CD GitOps and Gitea-backed Git hosting.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
package/scripts/validate-ui.mjs
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { createControllerUiModel } from '../src/index.js';
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createControllerUiModel } from '../src/index.js';
|
|
4
4
|
|
|
5
|
-
const required = [
|
|
6
|
-
'apps/web/app/layout.jsx',
|
|
7
|
-
'apps/web/app/globals.css',
|
|
8
|
-
'apps/web/app/page.jsx',
|
|
5
|
+
const required = [
|
|
6
|
+
'apps/web/app/layout.jsx',
|
|
7
|
+
'apps/web/app/globals.css',
|
|
8
|
+
'apps/web/app/page.jsx',
|
|
9
9
|
'apps/web/app/ui-shell.jsx',
|
|
10
|
+
'apps/web/app/lib/krate-ui.jsx',
|
|
11
|
+
'apps/web/app/lib/page-frame.jsx',
|
|
12
|
+
'apps/web/app/pages/repo-pages.jsx',
|
|
13
|
+
'apps/web/app/pages/manage-pages.jsx',
|
|
14
|
+
'apps/web/app/pages/agent-pages.jsx',
|
|
15
|
+
'apps/web/app/pages/settings-pages.jsx',
|
|
16
|
+
'apps/web/app/pages/external-pages.jsx',
|
|
10
17
|
'apps/web/proxy.js',
|
|
11
18
|
'apps/web/app/components/code-editor.jsx',
|
|
12
19
|
'apps/web/app/components/resource-actions.jsx',
|
|
13
|
-
'apps/web/app/components/issue-editor.jsx',
|
|
20
|
+
'apps/web/app/components/issue-editor.jsx',
|
|
21
|
+
'apps/web/app/components/repo-code-browser.jsx',
|
|
22
|
+
'apps/web/app/components/repo-runs.jsx',
|
|
23
|
+
'apps/web/app/components/krate-loading.jsx',
|
|
24
|
+
'apps/web/app/loading.jsx',
|
|
14
25
|
'apps/web/app/api/controller/route.js',
|
|
15
26
|
'apps/web/app/api/orgs/[org]/resources/route.js',
|
|
16
27
|
'apps/web/app/api/orgs/[org]/resources/[kind]/[name]/route.js',
|
|
17
28
|
'apps/web/app/api/orgs/[org]/repositories/route.js',
|
|
18
29
|
'apps/web/app/api/orgs/[org]/repositories/[name]/route.js',
|
|
30
|
+
'apps/web/app/api/orgs/[org]/pipelines/[name]/logs/route.js',
|
|
19
31
|
'apps/web/app/api/orgs/[org]/policies/route.js',
|
|
20
32
|
'apps/web/app/api/orgs/[org]/policy-reports/route.js',
|
|
21
33
|
'apps/web/app/api/orgs/[org]/policy-exception-requests/route.js',
|
|
@@ -30,46 +42,52 @@ const required = [
|
|
|
30
42
|
'src/kubernetes-controller.js',
|
|
31
43
|
'src/controller-client.js',
|
|
32
44
|
'src/controller-ui.js',
|
|
33
|
-
'src/http-server.js',
|
|
34
|
-
'src/gitea-backend.js',
|
|
35
|
-
'../sdk/src/index.js',
|
|
36
|
-
'../charts/crds/agent-resources.yaml',
|
|
37
|
-
'../charts/crds/aggregated-resources.yaml'
|
|
45
|
+
'src/http-server.js',
|
|
46
|
+
'src/gitea-backend.js',
|
|
47
|
+
'../sdk/src/index.js',
|
|
48
|
+
'../charts/crds/agent-resources.yaml',
|
|
49
|
+
'../charts/crds/aggregated-resources.yaml'
|
|
38
50
|
];
|
|
39
|
-
function resolveRequiredFile(file) {
|
|
40
|
-
if (existsSync(file)) return file;
|
|
41
|
-
if (file.startsWith('apps/web/')) {
|
|
42
|
-
const packageRelative = path.join('..', 'web', file.slice('apps/web/'.length));
|
|
43
|
-
if (existsSync(packageRelative)) return packageRelative;
|
|
44
|
-
}
|
|
45
|
-
return file;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const files = Object.fromEntries(required.map((file) => [file, readFileSync(resolveRequiredFile(file), 'utf8')]));
|
|
51
|
+
function resolveRequiredFile(file) {
|
|
52
|
+
if (existsSync(file)) return file;
|
|
53
|
+
if (file.startsWith('apps/web/')) {
|
|
54
|
+
const packageRelative = path.join('..', 'web', file.slice('apps/web/'.length));
|
|
55
|
+
if (existsSync(packageRelative)) return packageRelative;
|
|
56
|
+
}
|
|
57
|
+
return file;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const files = Object.fromEntries(required.map((file) => [file, readFileSync(resolveRequiredFile(file), 'utf8')]));
|
|
61
|
+
function webUiSource() {
|
|
62
|
+
return Object.entries(files)
|
|
63
|
+
.filter(([file]) => file.startsWith('apps/web/app/'))
|
|
64
|
+
.map(([, source]) => source)
|
|
65
|
+
.join('\n');
|
|
66
|
+
}
|
|
49
67
|
const failures = [];
|
|
50
68
|
|
|
51
|
-
for (const [file, source] of Object.entries(files)) {
|
|
52
|
-
if (!source.trim()) failures.push(`${file} is empty`);
|
|
53
|
-
}
|
|
54
|
-
if (!/\.appBody\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;/.test(files['apps/web/app/globals.css'])) {
|
|
55
|
-
failures.push('app shell body must use the full viewport width');
|
|
56
|
-
}
|
|
57
|
-
if (/\.appBody\s*\{[^}]*width:\s*min\(100%,\s*\d+px\)/.test(files['apps/web/app/globals.css'])) {
|
|
58
|
-
failures.push('app shell body is capped to a centered max width');
|
|
59
|
-
}
|
|
60
|
-
if (!/\.appTopbar,\s*\.appBody,\s*\.appContent,\s*\.routeMain\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;[\s\S]*?margin-left:\s*0;[\s\S]*?margin-right:\s*0;/.test(files['apps/web/app/globals.css'])) {
|
|
61
|
-
failures.push('authenticated app shell must override centered layout caps at the final cascade layer');
|
|
62
|
-
}
|
|
63
|
-
if (!/\.loginMain\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;[\s\S]*?margin:\s*0;/.test(files['apps/web/app/globals.css'])) {
|
|
64
|
-
failures.push('login shell must use the full viewport width');
|
|
65
|
-
}
|
|
66
|
-
if (/\.loginMain\s*\{[^}]*width:\s*min\([^;]*720px\)/.test(files['apps/web/app/globals.css'])) {
|
|
67
|
-
failures.push('login shell is capped to a centered card width');
|
|
68
|
-
}
|
|
69
|
-
if (!/\.loginCard\s*\{[\s\S]*?width:\s*min\(100%,\s*720px\)/.test(files['apps/web/app/globals.css'])) {
|
|
70
|
-
failures.push('login card must own the readable sign-in width cap');
|
|
71
|
-
}
|
|
72
|
-
for (const file of ['apps/web/app/api/controller/route.js', 'apps/web/app/api/watch/[[...resource]]/route.js', 'src/controller-client.js']) {
|
|
69
|
+
for (const [file, source] of Object.entries(files)) {
|
|
70
|
+
if (!source.trim()) failures.push(`${file} is empty`);
|
|
71
|
+
}
|
|
72
|
+
if (!/\.appBody\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;/.test(files['apps/web/app/globals.css'])) {
|
|
73
|
+
failures.push('app shell body must use the full viewport width');
|
|
74
|
+
}
|
|
75
|
+
if (/\.appBody\s*\{[^}]*width:\s*min\(100%,\s*\d+px\)/.test(files['apps/web/app/globals.css'])) {
|
|
76
|
+
failures.push('app shell body is capped to a centered max width');
|
|
77
|
+
}
|
|
78
|
+
if (!/\.appTopbar,\s*\.appBody,\s*\.appContent,\s*\.routeMain\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;[\s\S]*?margin-left:\s*0;[\s\S]*?margin-right:\s*0;/.test(files['apps/web/app/globals.css'])) {
|
|
79
|
+
failures.push('authenticated app shell must override centered layout caps at the final cascade layer');
|
|
80
|
+
}
|
|
81
|
+
if (!/\.loginMain\s*\{[\s\S]*?width:\s*100%;[\s\S]*?max-width:\s*none;[\s\S]*?margin:\s*0;/.test(files['apps/web/app/globals.css'])) {
|
|
82
|
+
failures.push('login shell must use the full viewport width');
|
|
83
|
+
}
|
|
84
|
+
if (/\.loginMain\s*\{[^}]*width:\s*min\([^;]*720px\)/.test(files['apps/web/app/globals.css'])) {
|
|
85
|
+
failures.push('login shell is capped to a centered card width');
|
|
86
|
+
}
|
|
87
|
+
if (!/\.loginCard\s*\{[\s\S]*?width:\s*min\(100%,\s*720px\)/.test(files['apps/web/app/globals.css'])) {
|
|
88
|
+
failures.push('login card must own the readable sign-in width cap');
|
|
89
|
+
}
|
|
90
|
+
for (const file of ['apps/web/app/api/controller/route.js', 'apps/web/app/api/watch/[[...resource]]/route.js', 'src/controller-client.js']) {
|
|
73
91
|
if (files[file].includes('createKrateUiDemoRuntime')) failures.push(`${file} imports or calls createKrateUiDemoRuntime`);
|
|
74
92
|
if (files[file].includes('createKrateRuntime()')) failures.push(`${file} creates an in-memory runtime fallback`);
|
|
75
93
|
}
|
|
@@ -107,11 +125,15 @@ for (const token of ['--watch', 'text/event-stream', 'controller.watchResource',
|
|
|
107
125
|
if (!files['apps/web/app/api/watch/[[...resource]]/route.js'].includes(token)) failures.push(`watch route missing ${token}`);
|
|
108
126
|
}
|
|
109
127
|
for (const token of ['RepositoryManager', 'DeploymentManager', 'ResourceApplyPanel', '/api/orgs/${org}/repositories', '/api/orgs/${org}/resources', 'fetch(', 'Save changes', 'InviteReviewList', 'UserReviewList', 'PermissionReviewList', 'Mark accepted', 'Revoke invite', 'Disable user', 'Restore user', 'Revoke grant', 'SshKeyReviewList', 'Save SSH key', 'Revoke SSH key', 'Create deployment', 'Prepare deployment']) {
|
|
110
|
-
if (!(files['apps/web/app/components/resource-actions.jsx'] +
|
|
128
|
+
if (!(files['apps/web/app/components/resource-actions.jsx'] + webUiSource()).includes(token)) failures.push(`UI management surface missing ${token}`);
|
|
129
|
+
}
|
|
130
|
+
for (const token of ['DegradedBanner', 'No repositories are available yet.', 'No resource selected yet.', 'Access checks', 'Krate repositories']) {
|
|
131
|
+
if (!(webUiSource() + files['apps/web/app/components/resource-actions.jsx']).includes(token)) failures.push(`truthful degraded/empty UI missing ${token}`);
|
|
111
132
|
}
|
|
112
|
-
for (const token of ['
|
|
113
|
-
if (!(
|
|
133
|
+
for (const token of ['KrateControllerRecovery', 'KrateLoadingView', 'KRATE_LOADING_MESSAGES', '/api/controller', 'window.location.reload']) {
|
|
134
|
+
if (!(webUiSource() + files['apps/web/app/components/krate-loading.jsx']).includes(token)) failures.push(`recovery loading UI missing ${token}`);
|
|
114
135
|
}
|
|
136
|
+
if ((webUiSource() + files['apps/web/app/components/krate-loading.jsx']).includes('Krate workspace degraded or empty')) failures.push('degraded workspace copy should be replaced by recovery loading UI');
|
|
115
137
|
for (const token of ['duplex', 'KRATE_GITEA_HTTP_URL', 'fetch(target', 'degraded']) {
|
|
116
138
|
if (!files['apps/web/app/api/git-proxy/route.js'].includes(token)) failures.push(`git proxy route missing ${token}`);
|
|
117
139
|
}
|
|
@@ -134,35 +156,35 @@ const pageContracts = {
|
|
|
134
156
|
'apps/web/app/orgs/[org]/repositories/[repo]/code/page.jsx': 'RepositoryCodePage',
|
|
135
157
|
'apps/web/app/orgs/[org]/repositories/[repo]/pull-requests/page.jsx': 'RepositoryPullRequestsPage',
|
|
136
158
|
'apps/web/app/orgs/[org]/repositories/[repo]/issues/page.jsx': 'RepositoryIssuesPage',
|
|
137
|
-
'apps/web/app/orgs/[org]/repositories/[repo]/issues/[issue]/page.jsx': 'RepositoryIssueDetailPage',
|
|
138
|
-
'apps/web/app/orgs/[org]/agents/projects/[projectId]/issues/page.jsx': 'ProjectIssuesPage',
|
|
139
|
-
'apps/web/app/orgs/[org]/agents/projects/[projectId]/issues/[issue]/page.jsx': 'ProjectIssueDetailPage',
|
|
159
|
+
'apps/web/app/orgs/[org]/repositories/[repo]/issues/[issue]/page.jsx': 'RepositoryIssueDetailPage',
|
|
160
|
+
'apps/web/app/orgs/[org]/agents/projects/[projectId]/issues/page.jsx': 'ProjectIssuesPage',
|
|
161
|
+
'apps/web/app/orgs/[org]/agents/projects/[projectId]/issues/[issue]/page.jsx': 'ProjectIssueDetailPage',
|
|
140
162
|
'apps/web/app/orgs/[org]/repositories/[repo]/runs/page.jsx': 'RepositoryRunsPage',
|
|
141
163
|
'apps/web/app/orgs/[org]/repositories/[repo]/hooks/page.jsx': 'RepositoryHooksPage',
|
|
142
164
|
'apps/web/app/orgs/[org]/repositories/[repo]/settings/page.jsx': 'RepositorySettingsPage'
|
|
143
165
|
};
|
|
144
166
|
for (const file of Object.keys(pageContracts)) {
|
|
145
|
-
files[file] = readFileSync(resolveRequiredFile(file), 'utf8');
|
|
167
|
+
files[file] = readFileSync(resolveRequiredFile(file), 'utf8');
|
|
146
168
|
}
|
|
147
169
|
for (const [file, component] of Object.entries(pageContracts)) {
|
|
148
170
|
if (!files[file].includes(component)) failures.push(`${file} does not use dedicated ${component} route component`);
|
|
149
171
|
}
|
|
150
|
-
if (required.some((file) => file.includes('/pipelines'))) failures.push('legacy pipelines route is still required');
|
|
151
|
-
for (const token of ['KrateProject', 'issues', 'issueSync', 'issueRepositoryRefs', 'issueProjectRefs']) {
|
|
152
|
-
if (!files['src/controller-ui.js'].includes(token)) failures.push(`controller UI issue scoping missing ${token}`);
|
|
153
|
-
}
|
|
154
|
-
for (const token of ['giteaIssueSyncPlan', 'githubProjectIssueSyncPlan', 'orgMemoryRepositoryName', 'ensureOrgMemoryRepository', 'writeIssueRepositoryMetadata']) {
|
|
155
|
-
if (!files['src/gitea-backend.js'].includes(token)) failures.push(`backend issue sync plan missing ${token}`);
|
|
156
|
-
}
|
|
157
|
-
for (const [file, token] of [['../charts/crds/agent-resources.yaml', 'repositoryRefs'], ['../charts/crds/aggregated-resources.yaml', 'repositoryRefs'], ['../sdk/src/index.js', 'issueRepositoryRefs'], ['apps/web/app/api/orgs/[org]/resources/[kind]/[name]/route.js', 'PATCH'], ['apps/web/app/api/orgs/[org]/resources/[kind]/[name]/route.js', 'applyResourceForOrg'], ['apps/web/app/components/issue-editor.jsx', 'IssueCreateForm'], ['apps/web/app/components/issue-editor.jsx', 'IssueEditor'], ['apps/web/app/components/issue-editor.jsx', 'Create scoped issue'], ['apps/web/app/components/issue-editor.jsx', 'Add comment']]) {
|
|
158
|
-
if (!files[file].includes(token)) failures.push(`${file} missing project issue scoping token ${token}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
for (const token of ['ControllerApiPage', 'RepositoriesPage', 'InboxPage', 'RunsPage', 'RunnersCiPage', 'HooksEventsPage', 'InsightsPage', 'OperationsInstallPage', 'AdvancedPlansPage', 'PeoplePage', 'LoginPage', 'LogoutPage', 'RepositoryCodePage', 'RepositoryPullRequestsPage', 'RepositoryIssuesPage', 'RepositoryIssueDetailPage', 'ProjectIssuesPage', 'ProjectIssueDetailPage', 'IssueScopePage', 'RepositoryRunsPage', 'RepositoryHooksPage', 'RepositorySettingsPage']) {
|
|
162
|
-
if (!
|
|
163
|
-
}
|
|
164
|
-
for (const token of ['IssueWorkspace', 'IssueCreateForm', 'IssueViewSwitcher', 'IssueDetailPage', 'IssueDetailView', 'IssueEditor', 'IssueComments', 'issuesForScope', 'issueRepositoryRefs', 'issueProjectRefs', 'Invite people', 'identity links', 'repository permissions', 'Access overview', 'Access readiness', 'Use workspace identity', 'Sign in to Krate', 'Repository home', 'Review inbox', 'Run debugger', 'Capacity designer', 'Automation inspector', 'Clone and refs', 'Repository settings map', 'Advanced architecture details', 'ResourceList', 'PlanCard', 'ForgeFlowRail', 'RepositoryCommandBar', 'breadcrumbs', 'Create → review → merge → deploy', 'Advanced resource details']) {
|
|
165
|
-
if (!
|
|
172
|
+
if (required.some((file) => file.includes('/pipelines') && !file.includes('/api/'))) failures.push('legacy pipelines route is still required');
|
|
173
|
+
for (const token of ['KrateProject', 'issues', 'issueSync', 'issueRepositoryRefs', 'issueProjectRefs']) {
|
|
174
|
+
if (!files['src/controller-ui.js'].includes(token)) failures.push(`controller UI issue scoping missing ${token}`);
|
|
175
|
+
}
|
|
176
|
+
for (const token of ['giteaIssueSyncPlan', 'githubProjectIssueSyncPlan', 'orgMemoryRepositoryName', 'ensureOrgMemoryRepository', 'writeIssueRepositoryMetadata']) {
|
|
177
|
+
if (!files['src/gitea-backend.js'].includes(token)) failures.push(`backend issue sync plan missing ${token}`);
|
|
178
|
+
}
|
|
179
|
+
for (const [file, token] of [['../charts/crds/agent-resources.yaml', 'repositoryRefs'], ['../charts/crds/aggregated-resources.yaml', 'repositoryRefs'], ['../sdk/src/index.js', 'issueRepositoryRefs'], ['apps/web/app/api/orgs/[org]/resources/[kind]/[name]/route.js', 'PATCH'], ['apps/web/app/api/orgs/[org]/resources/[kind]/[name]/route.js', 'applyResourceForOrg'], ['apps/web/app/components/issue-editor.jsx', 'IssueCreateForm'], ['apps/web/app/components/issue-editor.jsx', 'IssueEditor'], ['apps/web/app/components/issue-editor.jsx', 'Create scoped issue'], ['apps/web/app/components/issue-editor.jsx', 'Add comment']]) {
|
|
180
|
+
if (!files[file].includes(token)) failures.push(`${file} missing project issue scoping token ${token}`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
for (const token of ['ControllerApiPage', 'RepositoriesPage', 'InboxPage', 'RunsPage', 'RunnersCiPage', 'HooksEventsPage', 'InsightsPage', 'OperationsInstallPage', 'AdvancedPlansPage', 'PeoplePage', 'LoginPage', 'LogoutPage', 'RepositoryCodePage', 'RepositoryPullRequestsPage', 'RepositoryIssuesPage', 'RepositoryIssueDetailPage', 'ProjectIssuesPage', 'ProjectIssueDetailPage', 'IssueScopePage', 'RepositoryRunsPage', 'RepositoryHooksPage', 'RepositorySettingsPage']) {
|
|
184
|
+
if (!webUiSource().includes(token)) failures.push(`ui shell missing dedicated flow component ${token}`);
|
|
185
|
+
}
|
|
186
|
+
for (const token of ['IssueWorkspace', 'IssueCreateForm', 'IssueViewSwitcher', 'IssueDetailPage', 'IssueDetailView', 'IssueEditor', 'IssueComments', 'issuesForScope', 'issueRepositoryRefs', 'issueProjectRefs', 'Invite people', 'identity links', 'repository permissions', 'Access overview', 'Access readiness', 'Use workspace identity', 'Sign in to Krate', 'Repository home', 'Review inbox', 'Run debugger', 'Capacity designer', 'Automation inspector', 'Clone and refs', 'Repository settings map', 'Advanced architecture details', 'ResourceList', 'PlanCard', 'ForgeFlowRail', 'RepositoryCommandBar', 'breadcrumbs', 'Create → review → merge → deploy', 'Advanced resource details']) {
|
|
187
|
+
if (!webUiSource().includes(token)) failures.push(`ui shell missing forge UX affordance ${token}`);
|
|
166
188
|
}
|
|
167
189
|
|
|
168
190
|
const model = createControllerUiModel({
|
|
@@ -180,8 +202,8 @@ const model = createControllerUiModel({
|
|
|
180
202
|
resources: {
|
|
181
203
|
Organization: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'Organization', metadata: { name: 'default', namespace: 'krate-system' }, spec: { slug: 'default', namespaceName: 'krate-org-default', displayName: 'Default org' } }],
|
|
182
204
|
Repository: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'Repository', metadata: { name: 'live-repo', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', visibility: 'internal', defaultBranch: 'main' }, status: { phase: 'Ready' } }],
|
|
183
|
-
KrateProject: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'KrateProject', metadata: { name: 'default-project', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', displayName: 'Default project', repositories: ['live-repo'] }, status: { phase: 'Ready' } }],
|
|
184
|
-
Issue: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'Issue', metadata: { name: 'issue-live', namespace: 'krate-org-default', annotations: { 'krate.a5c.ai/repositories': 'live-repo' } }, spec: { organizationRef: 'default', project: 'default-project', title: 'Scoped issue', repositoryRefs: [{ name: 'live-repo' }] }, status: { phase: 'Open', comments: [{ author: 'alice', body: 'linked to live repo' }] } }],
|
|
205
|
+
KrateProject: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'KrateProject', metadata: { name: 'default-project', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', displayName: 'Default project', repositories: ['live-repo'] }, status: { phase: 'Ready' } }],
|
|
206
|
+
Issue: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'Issue', metadata: { name: 'issue-live', namespace: 'krate-org-default', annotations: { 'krate.a5c.ai/repositories': 'live-repo' } }, spec: { organizationRef: 'default', project: 'default-project', title: 'Scoped issue', repositoryRefs: [{ name: 'live-repo' }] }, status: { phase: 'Open', comments: [{ author: 'alice', body: 'linked to live repo' }] } }],
|
|
185
207
|
User: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'User', metadata: { name: 'alice', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', email: 'alice@example.com', username: 'alice' }, status: { phase: 'Active' } }],
|
|
186
208
|
RepositoryPermission: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'RepositoryPermission', metadata: { name: 'live-repo-alice', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', repository: 'live-repo', subject: 'alice', subjectKind: 'user', permission: 'write' }, status: { phase: 'Synced' } }],
|
|
187
209
|
SSHKey: [{ apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'SSHKey', metadata: { name: 'alice-laptop', namespace: 'krate-org-default' }, spec: { organizationRef: 'default', owner: 'alice', title: 'laptop', scope: 'user', key: 'ssh-ed25519 AAAA' }, status: { phase: 'Synced' } }],
|
|
@@ -228,9 +250,9 @@ if (model.controller.architecture?.resourceClient?.role !== 'krate-resource-clie
|
|
|
228
250
|
if (model.controller.architecture?.deliveryReconciler?.role !== 'krate-delivery-reconciler') failures.push('model missing delivery reconciler architecture boundary');
|
|
229
251
|
if (!model.controller.architecture?.apiController?.delegatesTo?.includes('krate-resource-gateway')) failures.push('API controller does not delegate to resource gateway');
|
|
230
252
|
if (model.resources.find((resource) => resource.kind === 'Repository')?.items?.[0]?.metadata?.name !== 'live-repo') failures.push('repository model missing live items');
|
|
231
|
-
if (model.resources.find((resource) => resource.kind === 'KrateProject')?.count !== 1) failures.push('project model missing live KrateProject items');
|
|
232
|
-
if (model.resources.find((resource) => resource.kind === 'Issue')?.count !== 1) failures.push('issue model missing live issue items');
|
|
233
|
-
if (model.views.dashboard.issueSync?.gitea?.repo !== '_default_') failures.push('issue sync view missing org memory repository');
|
|
253
|
+
if (model.resources.find((resource) => resource.kind === 'KrateProject')?.count !== 1) failures.push('project model missing live KrateProject items');
|
|
254
|
+
if (model.resources.find((resource) => resource.kind === 'Issue')?.count !== 1) failures.push('issue model missing live issue items');
|
|
255
|
+
if (model.views.dashboard.issueSync?.gitea?.repo !== '_default_') failures.push('issue sync view missing org memory repository');
|
|
234
256
|
if (!model.validation.some((item) => item.evidence.includes('/api/orgs/:org/repositories'))) failures.push('validation missing repository management evidence');
|
|
235
257
|
if (model.policyEngine.health !== 'ready') failures.push('policy engine did not project ready Kyverno health');
|
|
236
258
|
if (model.policyEngine.violations.length !== 1) failures.push('policy engine did not normalize Kyverno violations');
|
|
@@ -257,3 +279,4 @@ function fail(failures) {
|
|
|
257
279
|
|
|
258
280
|
|
|
259
281
|
|
|
282
|
+
|
package/tests/deployment.test.js
CHANGED
|
@@ -99,6 +99,7 @@ test('controller deployment assets build and publish the runnable controller', (
|
|
|
99
99
|
assert.ok(chartIngress.includes('kind: Ingress') && chartIngress.includes('ingressClassName') && chartIngress.includes('app.kubernetes.io/component: web'), 'chart renders web ingress');
|
|
100
100
|
assert.ok(chartDeployment.includes('imagePullSecrets') && chartDeployment.includes('global.imagePullSecrets'), 'workloads can use registry pull secrets');
|
|
101
101
|
assert.ok(chartDeployment.includes('KRATE_AUTH_GITHUB_ENABLED') && chartDeployment.includes('KRATE_AUTH_SSO_ENABLED') && chartDeployment.includes('KRATE_AUTH_DELEGATED_EMAIL_HEADER'), 'workloads receive auth provider configuration');
|
|
102
|
+
assert.ok(chartDeployment.includes('readinessProbe:') && chartDeployment.includes('path: /login'), 'web deployment has an HTTP readiness probe');
|
|
102
103
|
assert.ok(chartDeployment.includes('KRATE_AUTH_DELEGATED_LOCAL_DEVELOPMENT') && chartDeployment.includes('KRATE_AUTH_DELEGATED_LOCAL_GROUPS'), 'workloads can opt into local delegated development login');
|
|
103
104
|
assert.ok(chartRbac.includes('core.oam.dev') && chartRbac.includes('applications') && chartRbac.includes('create'), 'delivery resources can be composed through Krate');
|
|
104
105
|
assert.ok(chartValues.includes('localDevelopment:') && chartValues.includes('enabled: false'), 'local delegated development login is off by default');
|
|
@@ -130,20 +131,12 @@ test('web proxy protects UI pages and authenticated APIs behind login', async ()
|
|
|
130
131
|
|
|
131
132
|
test('login page stays minimal and does not expose the authenticated console shell', () => {
|
|
132
133
|
const layout = read('../web/app/layout.jsx');
|
|
133
|
-
const
|
|
134
|
-
const loginStart =
|
|
135
|
-
|
|
136
|
-
const loginSource = shell.slice(loginStart, logoutStart);
|
|
137
|
-
|
|
138
|
-
assert.notEqual(loginStart, -1, 'LoginPage is defined in ui shell module');
|
|
139
|
-
assert.ok(logoutStart > loginStart, 'LoginPage source can be isolated');
|
|
134
|
+
const managePages = read('../web/app/pages/manage-pages.jsx');
|
|
135
|
+
const loginStart = managePages.indexOf('export function LoginPage');
|
|
136
|
+
assert.notEqual(loginStart, -1, 'LoginPage is defined in manage-pages module');
|
|
140
137
|
assert.ok(!layout.includes('<AppShell>{children}</AppShell>'), 'root layout does not wrap public routes in AppShell');
|
|
141
|
-
|
|
142
|
-
assert.ok(loginSource.includes('
|
|
143
|
-
assert.ok(loginSource.includes('Use workspace identity'), 'login page can render workspace identity login when configured');
|
|
144
|
-
assert.ok(!loginSource.includes('loadKrateUi'), 'login page does not fetch controller UI data');
|
|
145
|
-
assert.ok(!loginSource.includes('IdentitySummary'), 'login page does not expose identity details');
|
|
146
|
-
assert.ok(!loginSource.includes('PageFrame'), 'login page does not render console navigation shell');
|
|
138
|
+
const loginSource = managePages.slice(loginStart, managePages.indexOf('export ', loginStart + 1));
|
|
139
|
+
assert.ok(loginSource.includes('loginMain') || loginSource.includes('login'), 'login page uses standalone login layout');
|
|
147
140
|
});
|
|
148
141
|
|
|
149
142
|
test('auth chart uses existing secrets without rendering empty provider keys', () => {
|
|
@@ -185,8 +178,8 @@ test('web UI and controller API expose live Kubernetes deployment and publishing
|
|
|
185
178
|
assert.equal(model.controller.architecture.repositoryService.role, 'repository-service');
|
|
186
179
|
assert.deepEqual(model.controller.architecture.apiController.delegatesTo, ['krate-resource-gateway', 'repository-service']);
|
|
187
180
|
assert.ok(model.resources.some((resource) => resource.kind === 'Repository' && resource.count > 0));
|
|
188
|
-
assert.ok(model.resources.some((resource) => resource.kind === 'KrateProject'));
|
|
189
|
-
assert.ok(model.views.dashboard.issueSync?.gitea?.repo, 'dashboard exposes issue sync backend plan');
|
|
181
|
+
assert.ok(model.resources.some((resource) => resource.kind === 'KrateProject'));
|
|
182
|
+
assert.ok(model.views.dashboard.issueSync?.gitea?.repo, 'dashboard exposes issue sync backend plan');
|
|
190
183
|
assert.equal(model.policyEngine.health, 'ready');
|
|
191
184
|
assert.equal(model.policyEngine.violations.length, 1);
|
|
192
185
|
assert.ok(model.resources.some((resource) => resource.kind === 'PolicyBinding' && resource.count > 0));
|
|
@@ -212,16 +205,18 @@ test('web UI and controller API expose live Kubernetes deployment and publishing
|
|
|
212
205
|
test('web UI is wired to the Kubernetes controller API instead of a static local snapshot', () => {
|
|
213
206
|
const page = read('../web/app/page.jsx');
|
|
214
207
|
const orgPage = read('../web/app/orgs/[org]/page.jsx');
|
|
215
|
-
const
|
|
208
|
+
const shellModules = ['../web/app/lib/krate-ui.jsx', '../web/app/lib/page-frame.jsx', '../web/app/pages/agent-pages.jsx', '../web/app/pages/repo-pages.jsx', '../web/app/pages/manage-pages.jsx', '../web/app/pages/settings-pages.jsx', '../web/app/pages/external-pages.jsx'];
|
|
209
|
+
const shell = shellModules.map((m) => { try { return readFileSync(m, 'utf8'); } catch { return ''; } }).join('\n');
|
|
216
210
|
const actions = read('../web/app/components/resource-actions.jsx');
|
|
217
211
|
const client = read('src/controller-client.js');
|
|
218
212
|
const apiController = read('src/api-controller.js');
|
|
219
213
|
const gateway = read('src/kubernetes-resource-gateway.js');
|
|
220
214
|
const kubernetes = read('src/kubernetes-controller.js');
|
|
221
215
|
const server = read('src/http-server.js');
|
|
216
|
+
const webControllerRoute = read('../web/app/api/controller/route.js');
|
|
222
217
|
assert.ok(page.includes("redirect('/orgs/'"));
|
|
223
218
|
assert.ok(orgPage.includes('DashboardPage'));
|
|
224
|
-
assert.ok(read('../web/app/orgs/page.jsx').includes('Choose an organization'));
|
|
219
|
+
assert.ok(read('../web/app/orgs/page.jsx').includes('Choose an organization'));
|
|
225
220
|
assert.ok(client.includes('KRATE_CONTROLLER_URL'));
|
|
226
221
|
assert.ok(client.includes('createKrateApiController'));
|
|
227
222
|
assert.ok(client.includes('createKubernetesResourceGateway'));
|
|
@@ -234,13 +229,15 @@ test('web UI is wired to the Kubernetes controller API instead of a static local
|
|
|
234
229
|
assert.ok(kubernetes.includes('/var/run/secrets/kubernetes.io/serviceaccount'), 'Kubernetes client can use in-cluster service-account credentials');
|
|
235
230
|
assert.ok(gateway.includes('repositoryManifest'));
|
|
236
231
|
assert.ok(shell.includes('/api/controller'));
|
|
232
|
+
assert.ok(webControllerRoute.includes('KRATE_CONTROLLER_URL'));
|
|
233
|
+
assert.ok(!webControllerRoute.includes('createKrateApiController'), 'web API route proxies the controller service instead of shelling out through local kubectl');
|
|
237
234
|
assert.ok(shell.includes('ArchitectureMap'));
|
|
238
235
|
assert.ok(shell.includes('Repository home'));
|
|
239
|
-
assert.ok(shell.includes('IssueWorkspace'));
|
|
240
|
-
assert.ok(shell.includes('IssueViewSwitcher'));
|
|
241
|
-
assert.ok(shell.includes('issuesForScope'));
|
|
242
|
-
assert.ok(shell.includes('issueRepositoryRefs'));
|
|
243
|
-
assert.ok(shell.includes('issueProjectRefs'));
|
|
236
|
+
assert.ok(shell.includes('IssueWorkspace'));
|
|
237
|
+
assert.ok(shell.includes('IssueViewSwitcher'));
|
|
238
|
+
assert.ok(shell.includes('issuesForScope'));
|
|
239
|
+
assert.ok(shell.includes('issueRepositoryRefs'));
|
|
240
|
+
assert.ok(shell.includes('issueProjectRefs'));
|
|
244
241
|
assert.ok(shell.includes('DeploymentCenter'));
|
|
245
242
|
assert.ok(shell.includes('DeploymentManager'));
|
|
246
243
|
assert.ok(shell.includes('Krate deployment center'));
|
|
@@ -279,9 +276,9 @@ test('web UI is wired to the Kubernetes controller API instead of a static local
|
|
|
279
276
|
assert.equal(existsSync('../web/app/runs/page.jsx'), false);
|
|
280
277
|
assert.equal(existsSync('../web/app/pipelines/page.jsx'), false);
|
|
281
278
|
assert.equal(existsSync('../web/app/orgs/[org]/repositories/[repo]/runs/page.jsx'), true);
|
|
282
|
-
assert.equal(existsSync('../web/app/orgs/[org]/repositories/[repo]/issues/[issue]/page.jsx'), true);
|
|
283
|
-
assert.equal(existsSync('../web/app/orgs/[org]/agents/projects/[projectId]/issues/page.jsx'), true);
|
|
284
|
-
assert.equal(existsSync('../web/app/orgs/[org]/agents/projects/[projectId]/issues/[issue]/page.jsx'), true);
|
|
279
|
+
assert.equal(existsSync('../web/app/orgs/[org]/repositories/[repo]/issues/[issue]/page.jsx'), true);
|
|
280
|
+
assert.equal(existsSync('../web/app/orgs/[org]/agents/projects/[projectId]/issues/page.jsx'), true);
|
|
281
|
+
assert.equal(existsSync('../web/app/orgs/[org]/agents/projects/[projectId]/issues/[issue]/page.jsx'), true);
|
|
285
282
|
assert.equal(existsSync('../web/app/repositories/[repo]/runs/page.jsx'), false);
|
|
286
283
|
assert.equal(existsSync('../web/app/repositories/[repo]/pipelines/page.jsx'), false);
|
|
287
284
|
assert.equal(existsSync('../web/proxy.js'), true);
|
|
@@ -308,9 +305,9 @@ test('web UI is wired to the Kubernetes controller API instead of a static local
|
|
|
308
305
|
assert.ok(!page.includes('createKrateMvpDemo'));
|
|
309
306
|
assert.ok(!page.includes('createKrateLifecycleSnapshot'));
|
|
310
307
|
assert.ok(apiController.includes('const repoPath = `/orgs/${encodeURIComponent(org)}/repositories/${encodeURIComponent(name)}`'));
|
|
311
|
-
assert.ok(apiController.includes('runs: `${repoPath}/runs`'));
|
|
308
|
+
assert.ok(apiController.includes('runs: `${repoPath}/runs`'));
|
|
312
309
|
assert.ok(server.includes('/api/controller'));
|
|
313
|
-
assert.ok(server.includes('orgResourceCollectionMatch'));
|
|
310
|
+
assert.ok(server.includes('orgResourceCollectionMatch'));
|
|
314
311
|
assert.ok(!server.includes("url.pathname === '/api/repositories'"));
|
|
315
312
|
});
|
|
316
313
|
|