@skyhook-io/k8s-ui 1.10.4 → 1.11.0

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.
Files changed (99) hide show
  1. package/package.json +5 -5
  2. package/src/components/applications/ApplicationDetail.test.tsx +46 -0
  3. package/src/components/applications/ApplicationDetail.tsx +14 -15
  4. package/src/components/issues/IssuesView.tsx +9 -0
  5. package/src/components/issues/diagnostic.ts +3 -0
  6. package/src/components/issues/issues.test.ts +11 -0
  7. package/src/components/issues/severity.ts +3 -0
  8. package/src/components/issues/types.ts +3 -0
  9. package/src/components/resources/ResourcesSidebar.tsx +1 -1
  10. package/src/components/resources/ResourcesView.tsx +259 -30
  11. package/src/components/resources/index.ts +2 -0
  12. package/src/components/resources/kyverno-cell-gating.test.ts +93 -0
  13. package/src/components/resources/kyverno-modern-posture.test.ts +290 -0
  14. package/src/components/resources/renderers/CNPGClusterRenderer.test.tsx +85 -0
  15. package/src/components/resources/renderers/CNPGClusterRenderer.tsx +109 -9
  16. package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +8 -4
  17. package/src/components/resources/renderers/EventRenderer.test.tsx +23 -0
  18. package/src/components/resources/renderers/EventRenderer.tsx +10 -18
  19. package/src/components/resources/renderers/KyvernoCELPolicyRenderers.tsx +317 -0
  20. package/src/components/resources/renderers/KyvernoExceptionRenderers.tsx +264 -0
  21. package/src/components/resources/renderers/KyvernoPolicyShared.tsx +212 -0
  22. package/src/components/resources/renderers/VeleroBSLRenderer.tsx +2 -4
  23. package/src/components/resources/renderers/VeleroBackupRenderer.tsx +32 -9
  24. package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +30 -9
  25. package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +12 -6
  26. package/src/components/resources/renderers/badge-no-handrolled.test.tsx +1 -1
  27. package/src/components/resources/renderers/cnpg-cells.tsx +37 -2
  28. package/src/components/resources/renderers/index.ts +4 -0
  29. package/src/components/resources/renderers/kyverno-modern-cells.tsx +152 -0
  30. package/src/components/resources/renderers/velero-cells.tsx +128 -9
  31. package/src/components/resources/renderers/velero-phase-recovery.test.tsx +79 -0
  32. package/src/components/resources/resource-utils-cnpg.golden.test.ts +112 -0
  33. package/src/components/resources/resource-utils-cnpg.test.ts +527 -1
  34. package/src/components/resources/resource-utils-cnpg.ts +373 -56
  35. package/src/components/resources/resource-utils-kyverno-exceptions.ts +182 -0
  36. package/src/components/resources/resource-utils-kyverno-modern.ts +588 -0
  37. package/src/components/resources/resource-utils-velero.test.ts +237 -0
  38. package/src/components/resources/resource-utils-velero.ts +214 -22
  39. package/src/components/resources/resource-utils.ts +70 -3
  40. package/src/components/shared/ResourceActionsBar.tsx +3 -1
  41. package/src/components/shared/ResourceRendererDispatch.test.tsx +119 -1
  42. package/src/components/shared/ResourceRendererDispatch.tsx +116 -22
  43. package/src/components/topology/K8sResourceNode.tsx +11 -0
  44. package/src/components/topology/TopologyGraph.tsx +85 -5
  45. package/src/components/trace/ReachabilityGraph.tsx +517 -0
  46. package/src/components/trace/ReachabilityView.tsx +1173 -0
  47. package/src/components/trace/TracePanel.test.ts +172 -0
  48. package/src/components/trace/TracePanel.tsx +558 -0
  49. package/src/components/trace/TraceSummary.test.ts +213 -0
  50. package/src/components/trace/TraceSummary.tsx +168 -0
  51. package/src/components/trace/inClusterSummary.test.ts +98 -0
  52. package/src/components/trace/inClusterSummary.ts +81 -0
  53. package/src/components/trace/index.ts +19 -0
  54. package/src/components/trace/podReach.test.ts +71 -0
  55. package/src/components/trace/podReach.ts +37 -0
  56. package/src/components/trace/probe-display.test.ts +107 -0
  57. package/src/components/trace/probe-display.ts +37 -0
  58. package/src/components/trace/problemRows.test.ts +107 -0
  59. package/src/components/trace/reachFixtures.ts +261 -0
  60. package/src/components/trace/reachGraphModel.test.ts +1423 -0
  61. package/src/components/trace/reachGraphModel.ts +1521 -0
  62. package/src/components/trace/reachInspector.test.ts +892 -0
  63. package/src/components/trace/reachInspector.ts +797 -0
  64. package/src/components/trace/reachMarks.test.ts +698 -0
  65. package/src/components/trace/reachMarks.ts +623 -0
  66. package/src/components/trace/reachOrigins.test.ts +392 -0
  67. package/src/components/trace/reachOrigins.ts +449 -0
  68. package/src/components/trace/reachVerdict.test.ts +537 -0
  69. package/src/components/trace/reachVerdict.ts +601 -0
  70. package/src/components/trace/traceFingerprint.test.ts +214 -0
  71. package/src/components/trace/traceFingerprint.ts +122 -0
  72. package/src/components/trace/traceToSubgraph.test.ts +623 -0
  73. package/src/components/trace/traceToSubgraph.ts +463 -0
  74. package/src/components/trace/types.ts +414 -0
  75. package/src/components/ui/Badge.tsx +36 -0
  76. package/src/components/ui/ForceDeleteConfirmDialog.tsx +12 -1
  77. package/src/components/ui/InClusterConsentDialog.test.tsx +83 -0
  78. package/src/components/ui/InClusterConsentDialog.tsx +141 -0
  79. package/src/components/ui/index.ts +1 -0
  80. package/src/components/workload/WorkloadView.tsx +58 -5
  81. package/src/components/workload/index.ts +1 -1
  82. package/src/components/workload/reachabilityTab.test.ts +47 -0
  83. package/src/index.ts +5 -0
  84. package/src/theme/components.css +64 -0
  85. package/src/theme/variables.css +5 -0
  86. package/src/types/core.ts +8 -0
  87. package/src/utils/api-resources.ts +2 -0
  88. package/src/utils/application-history.test.ts +1 -1
  89. package/src/utils/applications.test.ts +63 -1
  90. package/src/utils/applications.ts +27 -0
  91. package/src/utils/inClusterConsent.test.ts +109 -0
  92. package/src/utils/inClusterConsent.ts +72 -0
  93. package/src/utils/index.ts +1 -0
  94. package/src/utils/navigation.test.ts +61 -0
  95. package/src/utils/navigation.ts +11 -9
  96. package/src/utils/pluralize.test.ts +80 -1
  97. package/src/utils/pluralize.ts +34 -0
  98. package/src/utils/resource-icons.test.ts +33 -0
  99. package/src/utils/resource-icons.ts +65 -2
@@ -0,0 +1,182 @@
1
+ // PolicyException + CleanupPolicy accessors.
2
+ //
3
+ // PolicyException is served by BOTH Kyverno API families under the same Kind
4
+ // and the same plural, with genuinely different spec shapes:
5
+ //
6
+ // kyverno.io/v2 spec.exceptions[].{policyName, ruleNames[]}, spec.match, spec.conditions, spec.background
7
+ // policies.kyverno.io/v1 spec.policyRefs[].{kind, name}, spec.matchConditions[], spec.reportResult, spec.images
8
+ //
9
+ // So every accessor here is group-qualified. Reading `spec.exceptions` off a
10
+ // modern object (or `spec.policyRefs` off a legacy one) silently yields
11
+ // nothing, which on THIS surface means "no policies are excepted" — the exact
12
+ // opposite of the truth for an object that exempts a workload from
13
+ // enforcement.
14
+
15
+ import type { StatusBadge } from './resource-utils'
16
+ import { healthColors } from './resource-utils'
17
+
18
+ export const KYVERNO_LEGACY_GROUP = 'kyverno.io'
19
+ export const KYVERNO_MODERN_GROUP_PREFIX = 'policies.kyverno.io/'
20
+
21
+ export function isLegacyKyvernoPolicyException(resource: any): boolean {
22
+ return typeof resource?.apiVersion === 'string' && resource.apiVersion.startsWith(`${KYVERNO_LEGACY_GROUP}/`)
23
+ }
24
+
25
+ export function isModernKyvernoPolicyException(resource: any): boolean {
26
+ return typeof resource?.apiVersion === 'string' && resource.apiVersion.startsWith(KYVERNO_MODERN_GROUP_PREFIX)
27
+ }
28
+
29
+ /** Either family — the guard dispatch uses before rendering a PolicyException. */
30
+ export function isAnyKyvernoPolicyException(resource: any): boolean {
31
+ return isLegacyKyvernoPolicyException(resource) || isModernKyvernoPolicyException(resource)
32
+ }
33
+
34
+ /** One excepted policy, normalized across both spec shapes. */
35
+ export interface KyvernoExceptedPolicy {
36
+ /** Policy object name. */
37
+ name: string
38
+ /**
39
+ * Rule names excepted within that policy (legacy only — the modern family
40
+ * exempts whole policies, since CEL policies have no named rules).
41
+ */
42
+ ruleNames: string[]
43
+ /**
44
+ * Policy Kind being referenced (modern only). Load-bearing because
45
+ * policyRefs can point at ValidatingPolicy or ImageValidatingPolicy and the
46
+ * name alone doesn't say which.
47
+ */
48
+ kind: string
49
+ }
50
+
51
+ export function getKyvernoExceptedPolicies(resource: any): KyvernoExceptedPolicy[] {
52
+ if (isModernKyvernoPolicyException(resource)) {
53
+ const refs = resource?.spec?.policyRefs
54
+ if (!Array.isArray(refs)) return []
55
+ return refs.map((r: any) => ({
56
+ name: r?.name || '',
57
+ kind: r?.kind || '',
58
+ ruleNames: [],
59
+ }))
60
+ }
61
+
62
+ const exceptions = resource?.spec?.exceptions
63
+ if (!Array.isArray(exceptions)) return []
64
+ return exceptions.map((e: any) => ({
65
+ name: e?.policyName || '',
66
+ kind: '',
67
+ ruleNames: Array.isArray(e?.ruleNames) ? e.ruleNames.filter((r: unknown): r is string => typeof r === 'string') : [],
68
+ }))
69
+ }
70
+
71
+ /**
72
+ * The legacy `spec.match` block (any/all → resources). Absent on the modern
73
+ * family, which scopes via matchConditions instead.
74
+ */
75
+ export function getKyvernoExceptionMatch(resource: any): any {
76
+ return isLegacyKyvernoPolicyException(resource) ? resource?.spec?.match : undefined
77
+ }
78
+
79
+ export interface KyvernoNamedCEL {
80
+ name: string
81
+ expression: string
82
+ }
83
+
84
+ /**
85
+ * CEL conditions narrowing the exception. Both families have them under
86
+ * different keys: legacy `spec.conditions` (which is Kyverno's own
87
+ * any/all condition DSL, not CEL) versus modern `spec.matchConditions` (CEL).
88
+ * Only the modern one is a named-expression list; the legacy block is returned
89
+ * raw by getKyvernoExceptionLegacyConditions.
90
+ */
91
+ export function getKyvernoExceptionMatchConditions(resource: any): KyvernoNamedCEL[] {
92
+ if (!isModernKyvernoPolicyException(resource)) return []
93
+ const conditions = resource?.spec?.matchConditions
94
+ if (!Array.isArray(conditions)) return []
95
+ return conditions.map((c: any) => ({ name: c?.name || '', expression: c?.expression || '' }))
96
+ }
97
+
98
+ export function getKyvernoExceptionLegacyConditions(resource: any): any {
99
+ return isLegacyKyvernoPolicyException(resource) ? resource?.spec?.conditions : undefined
100
+ }
101
+
102
+ /** Modern only: what result the excepted resource is reported as. */
103
+ export function getKyvernoExceptionReportResult(resource: any): string {
104
+ return isModernKyvernoPolicyException(resource) ? resource?.spec?.reportResult || '' : ''
105
+ }
106
+
107
+ /**
108
+ * True when the exception names no policy at all. Both shapes can express it,
109
+ * and it means the exception applies to every policy in scope — the widest
110
+ * possible exemption, and worth flagging.
111
+ */
112
+ export function isBlanketKyvernoException(resource: any): boolean {
113
+ return getKyvernoExceptedPolicies(resource).length === 0
114
+ }
115
+
116
+ export function getKyvernoPolicyExceptionStatus(resource: any): StatusBadge {
117
+ const count = getKyvernoExceptedPolicies(resource).length
118
+ if (count === 0) {
119
+ return { text: 'All policies', color: healthColors.alert, level: 'alert' }
120
+ }
121
+ return {
122
+ text: count === 1 ? '1 policy' : `${count} policies`,
123
+ color: healthColors.neutral,
124
+ level: 'neutral',
125
+ }
126
+ }
127
+
128
+ // ============================================================================
129
+ // CLEANUP POLICY (kyverno.io/v2 — deprecated in 1.18 in favour of DeletingPolicy)
130
+ // ============================================================================
131
+
132
+ export function getKyvernoCleanupSchedule(resource: any): string {
133
+ return resource?.spec?.schedule || ''
134
+ }
135
+
136
+ export function getKyvernoCleanupPropagationPolicy(resource: any): string {
137
+ return resource?.spec?.deletionPropagationPolicy || ''
138
+ }
139
+
140
+ export function getKyvernoCleanupLastExecution(resource: any): string {
141
+ return resource?.status?.lastExecutionTime || ''
142
+ }
143
+
144
+ export function getKyvernoCleanupConditions(resource: any): any {
145
+ return resource?.spec?.conditions
146
+ }
147
+
148
+ export function getKyvernoCleanupMatch(resource: any): any {
149
+ return resource?.spec?.match
150
+ }
151
+
152
+ export function getKyvernoCleanupExclude(resource: any): any {
153
+ return resource?.spec?.exclude
154
+ }
155
+
156
+ /**
157
+ * Kinds a cleanup policy matches, flattened out of the any/all match block for
158
+ * a one-line summary. This is a delete-on-schedule object, so "what does it
159
+ * delete" is the only question that matters at a glance.
160
+ */
161
+ export function getKyvernoCleanupMatchedKinds(resource: any): string[] {
162
+ const kinds = new Set<string>()
163
+ const collect = (block: any) => {
164
+ if (!Array.isArray(block)) return
165
+ for (const entry of block) {
166
+ const entryKinds = entry?.resources?.kinds
167
+ if (Array.isArray(entryKinds)) {
168
+ for (const k of entryKinds) if (typeof k === 'string') kinds.add(k)
169
+ }
170
+ }
171
+ }
172
+ collect(resource?.spec?.match?.any)
173
+ collect(resource?.spec?.match?.all)
174
+ return Array.from(kinds)
175
+ }
176
+
177
+ export function getKyvernoCleanupPolicyStatus(resource: any): StatusBadge {
178
+ if (!getKyvernoCleanupSchedule(resource)) {
179
+ return { text: 'No schedule', color: healthColors.unknown, level: 'unknown' }
180
+ }
181
+ return { text: 'Scheduled', color: healthColors.alert, level: 'alert' }
182
+ }