@skyhook-io/k8s-ui 1.6.0 → 1.6.2

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 (79) hide show
  1. package/package.json +7 -2
  2. package/src/components/charts/AreaChart.tsx +371 -0
  3. package/src/components/charts/MetricsSummary.tsx +49 -0
  4. package/src/components/charts/SeriesLegend.tsx +27 -0
  5. package/src/components/charts/colors.ts +49 -0
  6. package/src/components/charts/format.ts +41 -0
  7. package/src/components/charts/index.ts +14 -0
  8. package/src/components/charts/saturation.test.ts +60 -0
  9. package/src/components/charts/saturation.ts +32 -0
  10. package/src/components/charts/types.ts +36 -0
  11. package/src/components/compare/CompareResourcePicker.tsx +192 -0
  12. package/src/components/compare/CompareTray.tsx +130 -0
  13. package/src/components/compare/ResourceCompareView.tsx +272 -0
  14. package/src/components/compare/index.ts +14 -0
  15. package/src/components/compare/normalize.test.ts +193 -0
  16. package/src/components/compare/normalize.ts +69 -0
  17. package/src/components/compare/picks.test.ts +97 -0
  18. package/src/components/compare/picks.ts +35 -0
  19. package/src/components/compare/sort.test.ts +78 -0
  20. package/src/components/compare/sort.ts +26 -0
  21. package/src/components/compare/types.ts +43 -0
  22. package/src/components/compare/url.test.ts +61 -0
  23. package/src/components/compare/url.ts +26 -0
  24. package/src/components/gitops/GitOpsDetailLayout.tsx +621 -0
  25. package/src/components/gitops/GitOpsGraphFilterRail.tsx +216 -0
  26. package/src/components/gitops/GitOpsTableView.tsx +1441 -0
  27. package/src/components/gitops/RollbackDialog.tsx +117 -0
  28. package/src/components/gitops/SyncOptionsDialog.tsx +160 -0
  29. package/src/components/gitops/detail-helpers.test.ts +97 -0
  30. package/src/components/gitops/detail-helpers.ts +112 -0
  31. package/src/components/gitops/index.ts +52 -1
  32. package/src/components/gitops/short-cluster-name.test.ts +36 -0
  33. package/src/components/gitops/tree/index.ts +2 -0
  34. package/src/components/gitops/tree/merge.test.ts +240 -0
  35. package/src/components/gitops/tree/merge.ts +160 -0
  36. package/src/components/resources/ResourcesSidebar.tsx +42 -15
  37. package/src/components/resources/ResourcesView.tsx +403 -69
  38. package/src/components/resources/index.ts +1 -0
  39. package/src/components/resources/renderers/CompositeRenderer.tsx +233 -0
  40. package/src/components/resources/renderers/CompositionRenderer.tsx +218 -0
  41. package/src/components/resources/renderers/CrossplanePackageRenderer.tsx +145 -0
  42. package/src/components/resources/renderers/CrossplaneProviderConfigRenderer.tsx +71 -0
  43. package/src/components/resources/renderers/HPARenderer.tsx +6 -1
  44. package/src/components/resources/renderers/ManagedResourceRenderer.tsx +131 -0
  45. package/src/components/resources/renderers/NamespaceRenderer.tsx +223 -0
  46. package/src/components/resources/renderers/PVCRenderer.tsx +6 -1
  47. package/src/components/resources/renderers/PodRenderer.tsx +207 -2
  48. package/src/components/resources/renderers/RoleBindingRenderer.tsx +132 -20
  49. package/src/components/resources/renderers/RoleRenderer.tsx +148 -18
  50. package/src/components/resources/renderers/ServiceAccountRenderer.tsx +456 -3
  51. package/src/components/resources/renderers/WorkloadRenderer.tsx +189 -2
  52. package/src/components/resources/renderers/XRDRenderer.tsx +153 -0
  53. package/src/components/resources/renderers/crossplane-cells.tsx +146 -0
  54. package/src/components/resources/renderers/flux-cells.tsx +12 -0
  55. package/src/components/resources/renderers/index.ts +8 -0
  56. package/src/components/resources/resource-utils-crossplane.test.ts +609 -0
  57. package/src/components/resources/resource-utils-crossplane.ts +325 -0
  58. package/src/components/resources/resource-utils-flux.ts +14 -0
  59. package/src/components/resources/resource-utils.ts +1 -0
  60. package/src/components/resources/resources-column-filter.test.ts +74 -0
  61. package/src/components/shared/ResourceActionsBar.tsx +77 -0
  62. package/src/components/shared/ResourceRendererDispatch.tsx +138 -9
  63. package/src/components/ui/YamlEditor.tsx +28 -15
  64. package/src/components/ui/drawer-components.tsx +8 -20
  65. package/src/components/workload/ResourceDetailDrawer.tsx +1 -1
  66. package/src/components/workload/WorkloadView.tsx +2 -2
  67. package/src/index.ts +3 -0
  68. package/src/types/core.ts +31 -6
  69. package/src/types/index.ts +1 -0
  70. package/src/types/rbac.ts +99 -0
  71. package/src/utils/api-resources.ts +9 -1
  72. package/src/utils/badge-colors.ts +25 -0
  73. package/src/utils/gitops-owner.test.ts +70 -111
  74. package/src/utils/gitops-owner.ts +37 -74
  75. package/src/utils/helm-status.test.ts +50 -0
  76. package/src/utils/index.ts +1 -0
  77. package/src/utils/rbac-badges.ts +61 -0
  78. package/src/utils/rbac-blast-radius.test.ts +137 -0
  79. package/src/utils/rbac-blast-radius.ts +98 -0
@@ -0,0 +1,98 @@
1
+ // Pure helpers for the "what's the blast radius of this Pod / Workload / SA"
2
+ // detection. Lives outside the renderers because it's the security-UX core
3
+ // of the RBAC visibility feature — the rule that resource-only wildcards do
4
+ // NOT trigger (because `view` covers every fluxcd CRD via wildcards and would
5
+ // alarm on every authenticated SA) is load-bearing and easily regressed
6
+ // silently. Tested via rbac-blast-radius.test.ts; keep it pure.
7
+
8
+ import type { RBACBindingRules, RBACPolicyRule, RBACSubjectResponse } from '../types/rbac'
9
+
10
+ export const RBAC_BLAST_READ_VERBS = new Set(['get', 'list', 'watch'])
11
+ export const RBAC_BLAST_WRITE_VERBS = new Set(['create', 'update', 'patch'])
12
+ export const RBAC_BLAST_DELETE_VERBS = new Set(['delete', 'deletecollection'])
13
+ export const RBAC_BLAST_ESCALATION_VERBS = new Set(['escalate', 'bind', 'impersonate'])
14
+
15
+ /**
16
+ * Score a single PolicyRule by max permissiveness. Higher is scarier.
17
+ * The ordering matters more than the absolute scale — used to sort the
18
+ * rule preview so dangerous rules surface first in incident response.
19
+ */
20
+ export function rulePermissivenessScore(r: RBACPolicyRule): number {
21
+ let score = 0
22
+ const verbs = r.verbs ?? []
23
+ const resources = r.resources ?? []
24
+ const groups = r.apiGroups ?? []
25
+ if (verbs.includes('*')) score += 100
26
+ if (resources.includes('*')) score += 100
27
+ if (groups.includes('*')) score += 100
28
+ for (const v of verbs) {
29
+ if (RBAC_BLAST_ESCALATION_VERBS.has(v)) score += 80
30
+ else if (RBAC_BLAST_DELETE_VERBS.has(v)) score += 40
31
+ else if (RBAC_BLAST_WRITE_VERBS.has(v)) score += 20
32
+ else if (RBAC_BLAST_READ_VERBS.has(v)) score += 5
33
+ else score += 10
34
+ }
35
+ if (verbs.includes('create') && resources.includes('pods')) score += 50
36
+ return score
37
+ }
38
+
39
+ export interface BlastRadiusReason {
40
+ binding: RBACBindingRules
41
+ reason: string
42
+ }
43
+
44
+ /**
45
+ * Detect bindings that genuinely make a Pod's compromise a cluster takeover.
46
+ * Triggers on, in priority order:
47
+ *
48
+ * 1. cluster-admin role-name match (covers the "bound my SA to cluster-admin
49
+ * for testing" pattern even when rules aren't loaded)
50
+ * 2. verb wildcards (`*`)
51
+ * 3. escalation verbs (`escalate` / `bind` / `impersonate`)
52
+ * 4. cluster-wide `create pods` (lateral-movement vector)
53
+ *
54
+ * Resource-only wildcards (e.g. `view`'s fluxcd CRD coverage) deliberately
55
+ * do NOT trigger — they fire on every authenticated SA and would train
56
+ * operators to ignore the alarm. The current set is the calibrated minimum
57
+ * for "the Pod's identity is genuinely god-mode".
58
+ *
59
+ * Dedupes by binding identity so a binding with multiple risky rules
60
+ * counts once; first matching reason wins.
61
+ */
62
+ export function detectBlastRadius(rbacData: RBACSubjectResponse): BlastRadiusReason[] {
63
+ const reasons: BlastRadiusReason[] = []
64
+ const allBindings = [
65
+ ...rbacData.direct,
66
+ ...rbacData.inheritedFromGroups.flatMap((g) => g.bindings),
67
+ ]
68
+ for (const br of allBindings) {
69
+ if (br.role.name === 'cluster-admin' && br.role.kind === 'ClusterRole') {
70
+ reasons.push({ binding: br, reason: 'bound to cluster-admin (full god-mode access)' })
71
+ continue
72
+ }
73
+ for (const r of br.rules ?? []) {
74
+ const verbs = r.verbs ?? []
75
+ const resources = r.resources ?? []
76
+ if (verbs.includes('*')) {
77
+ reasons.push({ binding: br, reason: 'grants verb wildcard (*) — every action on the listed resources' })
78
+ break
79
+ }
80
+ const escalations = verbs.filter((v) => RBAC_BLAST_ESCALATION_VERBS.has(v))
81
+ if (escalations.length > 0) {
82
+ reasons.push({ binding: br, reason: `grants privilege-escalation verbs: ${escalations.join(', ')}` })
83
+ break
84
+ }
85
+ if (verbs.includes('create') && resources.includes('pods') && br.binding.kind === 'ClusterRoleBinding') {
86
+ reasons.push({ binding: br, reason: 'grants cluster-wide "create pods" — a known lateral-movement vector' })
87
+ break
88
+ }
89
+ }
90
+ }
91
+ const seen = new Set<string>()
92
+ return reasons.filter((r) => {
93
+ const key = r.binding.binding.kind + '/' + r.binding.binding.namespace + '/' + r.binding.binding.name
94
+ if (seen.has(key)) return false
95
+ seen.add(key)
96
+ return true
97
+ })
98
+ }