From 6d7090f8a72d6546571020c4668fdb2e6f958e64 Mon Sep 17 00:00:00 2001 From: Andreas Hippler Date: Tue, 22 Nov 2022 18:48:59 +0100 Subject: [PATCH] fix: getAllowedResources for all namespaces using SelfSubjectRulesReview (#6614) * fix: getAllowedResources for all namespaces using SelfSubjectRulesReview Signed-off-by: Andreas Hippler * fix: refresh accessibility every 15 min Signed-off-by: Andreas Hippler * chore: remove unused clusterRefreshHandler Signed-off-by: Andreas Hippler * fix: resolve SelfSubjectRulesReview globs Signed-off-by: Andreas Hippler Signed-off-by: Andreas Hippler Co-authored-by: Andreas Hippler --- integration/__tests__/cluster-pages.tests.ts | 10 +- src/common/cluster-types.ts | 7 - ...thorization-namespace-review.injectable.ts | 87 +++++++++++ .../authorization-review.injectable.ts | 63 ++++---- src/common/cluster/cluster.ts | 138 ++++++++++-------- .../cluster/list-api-resources.injectable.ts | 91 ++++++++++++ src/common/ipc/cluster.ts | 2 +- src/main/__test__/cluster.test.ts | 5 + .../create-cluster.injectable.ts | 4 + .../setup-ipc-main-handlers.ts | 8 +- .../create-cluster.injectable.ts | 2 + 11 files changed, 311 insertions(+), 106 deletions(-) create mode 100644 src/common/cluster/authorization-namespace-review.injectable.ts create mode 100644 src/common/cluster/list-api-resources.injectable.ts diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index e1474a4332..c2896309f4 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -390,12 +390,6 @@ const scenarios = [ sidebarItemTestId: "sidebar-item-link-for-service-accounts", }, - { - expectedSelector: "h5.title", - parentSidebarItemTestId: "sidebar-item-link-for-user-management", - sidebarItemTestId: "sidebar-item-link-for-roles", - }, - { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", @@ -405,7 +399,7 @@ const scenarios = [ { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", - sidebarItemTestId: "sidebar-item-link-for-role-bindings", + sidebarItemTestId: "sidebar-item-link-for-roles", }, { @@ -417,7 +411,7 @@ const scenarios = [ { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", - sidebarItemTestId: "sidebar-item-link-for-pod-security-policies", + sidebarItemTestId: "sidebar-item-link-for-role-bindings", }, { diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts index faf6debbab..0cd447f0e2 100644 --- a/src/common/cluster-types.ts +++ b/src/common/cluster-types.ts @@ -195,13 +195,6 @@ export enum ClusterMetricsResourceType { */ export const initialNodeShellImage = "docker.io/alpine:3.13"; -/** - * The arguments for requesting to refresh a cluster's metadata - */ -export interface ClusterRefreshOptions { - refreshMetadata?: boolean; -} - /** * The data representing a cluster's state, for passing between main and renderer */ diff --git a/src/common/cluster/authorization-namespace-review.injectable.ts b/src/common/cluster/authorization-namespace-review.injectable.ts new file mode 100644 index 0000000000..aa78453569 --- /dev/null +++ b/src/common/cluster/authorization-namespace-review.injectable.ts @@ -0,0 +1,87 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { KubeConfig } from "@kubernetes/client-node"; +import { AuthorizationV1Api } from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; +import type { Logger } from "../logger"; +import loggerInjectable from "../logger.injectable"; +import type { KubeApiResource } from "../rbac"; + +/** + * Requests the permissions for actions on the kube cluster + * @param namespace The namespace of the resources + * @param availableResources List of available resources in the cluster to resolve glob values fir api groups + * @returns list of allowed resources names + */ +export type RequestNamespaceResources = (namespace: string, availableResources: KubeApiResource[]) => Promise; + +/** + * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster + */ +export type AuthorizationNamespaceReview = (proxyConfig: KubeConfig) => RequestNamespaceResources; + +interface Dependencies { + logger: Logger; +} + +const authorizationNamespaceReview = ({ logger }: Dependencies): AuthorizationNamespaceReview => { + return (proxyConfig) => { + + const api = proxyConfig.makeApiClient(AuthorizationV1Api); + + return async (namespace, availableResources) => { + try { + const { body } = await api.createSelfSubjectRulesReview({ + apiVersion: "authorization.k8s.io/v1", + kind: "SelfSubjectRulesReview", + spec: { namespace }, + }); + + const resources = new Set(); + + body.status?.resourceRules.forEach(resourceRule => { + if (!resourceRule.verbs.some(verb => ["*", "list"].includes(verb)) || !resourceRule.resources) { + return; + } + + const apiGroups = resourceRule.apiGroups; + + if (resourceRule.resources.length === 1 && resourceRule.resources[0] === "*" && apiGroups) { + if (apiGroups[0] === "*") { + availableResources.forEach(resource => resources.add(resource.apiName)); + } else { + availableResources.forEach((apiResource)=> { + if (apiGroups.includes(apiResource.group || "")) { + resources.add(apiResource.apiName); + } + }); + } + } else { + resourceRule.resources.forEach(resource => resources.add(resource)); + } + + }); + + return [...resources]; + } catch (error) { + logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review: ${error}`, { namespace }); + + return []; + } + }; + }; +}; + +const authorizationNamespaceReviewInjectable = getInjectable({ + id: "authorization-namespace-review", + instantiate: (di) => { + const logger = di.inject(loggerInjectable); + + return authorizationNamespaceReview({ logger }); + }, +}); + +export default authorizationNamespaceReviewInjectable; diff --git a/src/common/cluster/authorization-review.injectable.ts b/src/common/cluster/authorization-review.injectable.ts index c622893b63..4c9b83330d 100644 --- a/src/common/cluster/authorization-review.injectable.ts +++ b/src/common/cluster/authorization-review.injectable.ts @@ -5,42 +5,55 @@ import type { KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { AuthorizationV1Api } from "@kubernetes/client-node"; -import logger from "../logger"; import { getInjectable } from "@ogre-tools/injectable"; +import type { Logger } from "../logger"; +import loggerInjectable from "../logger.injectable"; +/** + * Requests the permissions for actions on the kube cluster + * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed + * @returns `true` if the actions described are allowed + */ export type CanI = (resourceAttributes: V1ResourceAttributes) => Promise; /** * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export function authorizationReview(proxyConfig: KubeConfig): CanI { - const api = proxyConfig.makeApiClient(AuthorizationV1Api); + */ +export type AuthorizationReview = (proxyConfig: KubeConfig) => CanI; - /** - * Requests the permissions for actions on the kube cluster - * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed - * @returns `true` if the actions described are allowed - */ - return async (resourceAttributes: V1ResourceAttributes): Promise => { - try { - const { body } = await api.createSelfSubjectAccessReview({ - apiVersion: "authorization.k8s.io/v1", - kind: "SelfSubjectAccessReview", - spec: { resourceAttributes }, - }); - - return body.status?.allowed ?? false; - } catch (error) { - logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); - - return false; - } - }; +interface Dependencies { + logger: Logger; } +const authorizationReview = ({ logger }: Dependencies): AuthorizationReview => { + return (proxyConfig) => { + const api = proxyConfig.makeApiClient(AuthorizationV1Api); + + return async (resourceAttributes: V1ResourceAttributes): Promise => { + try { + const { body } = await api.createSelfSubjectAccessReview({ + apiVersion: "authorization.k8s.io/v1", + kind: "SelfSubjectAccessReview", + spec: { resourceAttributes }, + }); + + return body.status?.allowed ?? false; + } catch (error) { + logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); + + return false; + } + }; + }; +}; + const authorizationReviewInjectable = getInjectable({ id: "authorization-review", - instantiate: () => authorizationReview, + instantiate: (di) => { + const logger = di.inject(loggerInjectable); + + return authorizationReview({ logger }); + }, }); export default authorizationReviewInjectable; diff --git a/src/common/cluster/cluster.ts b/src/common/cluster/cluster.ts index b0d7fbfbc3..7f27025190 100644 --- a/src/common/cluster/cluster.ts +++ b/src/common/cluster/cluster.ts @@ -14,7 +14,7 @@ import { apiResourceRecord, apiResources } from "../rbac"; import type { VersionDetector } from "../../main/cluster-detectors/version-detector"; import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry"; import plimit from "p-limit"; -import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate, ClusterConfigData } from "../cluster-types"; +import type { ClusterState, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate, ClusterConfigData } from "../cluster-types"; import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus, clusterModelIdChecker, updateClusterModelChecker } from "../cluster-types"; import { disposer, isDefined, isRequestError, toJS } from "../utils"; import type { Response } from "request"; @@ -25,6 +25,8 @@ import assert from "assert"; import type { Logger } from "../logger"; import type { BroadcastMessage } from "../ipc/broadcast-message.injectable"; import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable"; +import type { RequestNamespaceResources } from "./authorization-namespace-review.injectable"; +import type { RequestListApiResources } from "./list-api-resources.injectable"; export interface ClusterDependencies { readonly directoryForKubeConfigs: string; @@ -34,6 +36,8 @@ export interface ClusterDependencies { createContextHandler: (cluster: Cluster) => ClusterContextHandler; createKubectl: (clusterVersion: string) => Kubectl; createAuthorizationReview: (config: KubeConfig) => CanI; + createAuthorizationNamespaceReview: (config: KubeConfig) => RequestNamespaceResources; + createListApiResources: (cluster: Cluster) => RequestListApiResources; createListNamespaces: (config: KubeConfig) => ListNamespaces; createVersionDetector: (cluster: Cluster) => VersionDetector; broadcastMessage: BroadcastMessage; @@ -309,7 +313,7 @@ export class Cluster implements ClusterModel, ClusterState { protected bindEvents() { this.dependencies.logger.info(`[CLUSTER]: bind events`, this.getMeta()); const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s - const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes + const refreshMetadataTimer = setInterval(() => this.available && this.refreshAccessibilityAndMetadata(), 900000); // every 15 minutes this.eventsDisposer.push( reaction(() => this.getState(), state => this.pushState(state)), @@ -439,66 +443,68 @@ export class Cluster implements ClusterModel, ClusterState { /** * @internal - * @param opts refresh options */ @action - async refresh(opts: ClusterRefreshOptions = {}) { + async refresh() { this.dependencies.logger.info(`[CLUSTER]: refresh`, this.getMeta()); await this.refreshConnectionStatus(); - - if (this.accessible) { - await this.refreshAccessibility(); - - if (opts.refreshMetadata) { - this.refreshMetadata(); - } - } this.pushState(); } /** * @internal */ - @action - async refreshMetadata() { - this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await this.dependencies.detectorRegistry.detectForCluster(this); - const existingMetadata = this.metadata; - - this.metadata = Object.assign(existingMetadata, metadata); + @action + async refreshAccessibilityAndMetadata() { + await this.refreshAccessibility(); + await this.refreshMetadata(); } - /** + /** * @internal */ - private async refreshAccessibility(): Promise { - const proxyConfig = await this.getProxyKubeconfig(); - const canI = this.dependencies.createAuthorizationReview(proxyConfig); + async refreshMetadata() { + this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); + const metadata = await this.dependencies.detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; - this.isAdmin = await canI({ - namespace: "kube-system", - resource: "*", - verb: "create", - }); - this.isGlobalWatchEnabled = await canI({ - verb: "watch", - resource: "*", - }); - this.allowedNamespaces = await this.getAllowedNamespaces(proxyConfig); - this.allowedResources = await this.getAllowedResources(canI); - this.ready = true; - } + this.metadata = Object.assign(existingMetadata, metadata); + } + + /** + * @internal + */ + private async refreshAccessibility(): Promise { + this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.getMeta()); + const proxyConfig = await this.getProxyKubeconfig(); + const canI = this.dependencies.createAuthorizationReview(proxyConfig); + const requestNamespaceResources = this.dependencies.createAuthorizationNamespaceReview(proxyConfig); + const listApiResources = this.dependencies.createListApiResources(this); + + this.isAdmin = await canI({ + namespace: "kube-system", + resource: "*", + verb: "create", + }); + this.isGlobalWatchEnabled = await canI({ + verb: "watch", + resource: "*", + }); + this.allowedNamespaces = await this.getAllowedNamespaces(proxyConfig); + this.allowedResources = await this.getAllowedResources(listApiResources, requestNamespaceResources); + this.ready = true; + } /** * @internal */ @action - async refreshConnectionStatus() { - const connectionStatus = await this.getConnectionStatus(); + async refreshConnectionStatus() { + const connectionStatus = await this.getConnectionStatus(); - this.online = connectionStatus > ClusterStatus.Offline; - this.accessible = connectionStatus == ClusterStatus.AccessGranted; - } + this.online = connectionStatus > ClusterStatus.Offline; + this.accessible = connectionStatus == ClusterStatus.AccessGranted; + } async getKubeconfig(): Promise { const { config } = await this.dependencies.loadConfigfromFile(this.kubeConfigPath); @@ -667,32 +673,48 @@ export class Cluster implements ClusterModel, ClusterState { } } - protected async getAllowedResources(canI: CanI) { + protected async getAllowedResources(listApiResources:RequestListApiResources, requestNamespaceResources: RequestNamespaceResources) { try { if (!this.allowedNamespaces.length) { return []; } - const resources = apiResources.filter((resource) => this.resourceAccessStatuses.get(resource) === undefined); - const apiLimit = plimit(5); // 5 concurrent api requests - const requests = []; - for (const apiResource of resources) { - requests.push(apiLimit(async () => { - for (const namespace of this.allowedNamespaces.slice(0, 10)) { - if (!this.resourceAccessStatuses.get(apiResource)) { - const result = await canI({ - resource: apiResource.apiName, - group: apiResource.group, - verb: "list", - namespace, - }); + const unknownResources = new Map(apiResources.map(resource => ([resource.apiName, resource]))); - this.resourceAccessStatuses.set(apiResource, result); + const availableResources = await listApiResources(); + const availableResourcesNames = new Set(availableResources.map(apiResource => apiResource.apiName)); + + [...unknownResources.values()].map(unknownResource => { + if (!availableResourcesNames.has(unknownResource.apiName)) { + this.resourceAccessStatuses.set(unknownResource, false); + unknownResources.delete(unknownResource.apiName); + } + }); + + if (unknownResources.size > 0) { + const apiLimit = plimit(5); // 5 concurrent api requests + + await Promise.all(this.allowedNamespaces.map(namespace => apiLimit(async () => { + if (unknownResources.size === 0) { + return; + } + + const namespaceResources = await requestNamespaceResources(namespace, availableResources); + + for (const resourceName of namespaceResources) { + const unknownResource = unknownResources.get(resourceName); + + if (unknownResource) { + this.resourceAccessStatuses.set(unknownResource, true); + unknownResources.delete(resourceName); } } - })); + }))); + + for (const forbiddenResource of unknownResources.values()) { + this.resourceAccessStatuses.set(forbiddenResource, false); + } } - await Promise.all(requests); return apiResources .filter((resource) => this.resourceAccessStatuses.get(resource)) diff --git a/src/common/cluster/list-api-resources.injectable.ts b/src/common/cluster/list-api-resources.injectable.ts new file mode 100644 index 0000000000..ed9d5c9c39 --- /dev/null +++ b/src/common/cluster/list-api-resources.injectable.ts @@ -0,0 +1,91 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { + V1APIGroupList, + V1APIResourceList, + V1APIVersions, +} from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; +import type { K8sRequest } from "../../main/k8s-request.injectable"; +import k8SRequestInjectable from "../../main/k8s-request.injectable"; +import type { Logger } from "../logger"; +import loggerInjectable from "../logger.injectable"; +import type { KubeApiResource, KubeResource } from "../rbac"; +import type { Cluster } from "./cluster"; +import plimit from "p-limit"; + +export type RequestListApiResources = () => Promise; + +/** + * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster + */ +export type ListApiResources = (cluster: Cluster) => RequestListApiResources; + +interface Dependencies { + logger: Logger; + k8sRequest: K8sRequest; +} + +const listApiResources = ({ k8sRequest, logger }: Dependencies): ListApiResources => { + return (cluster) => { + const clusterRequest = (path: string) => k8sRequest(cluster, path); + const apiLimit = plimit(5); + + return async () => { + const resources: KubeApiResource[] = []; + + try { + const resourceListGroups:{ group:string;path:string }[] = []; + + await Promise.all( + [ + clusterRequest("/api").then((response:V1APIVersions)=>response.versions.forEach(version => resourceListGroups.push({ group:version, path:`/api/${version}` }))), + clusterRequest("/apis").then((response:V1APIGroupList) => response.groups.forEach(group => { + const preferredVersion = group.preferredVersion?.groupVersion; + + if (preferredVersion) { + resourceListGroups.push({ group:group.name, path:`/apis/${preferredVersion}` }); + } + })), + ], + ); + + await Promise.all( + resourceListGroups.map(({ group, path }) => apiLimit(async () => { + const apiResources:V1APIResourceList = await clusterRequest(path); + + if (apiResources.resources) { + resources.push( + ...apiResources.resources.filter(resource => resource.verbs.includes("list")).map((resource) => ({ + apiName: resource.name as KubeResource, + kind: resource.kind, + group, + })), + ); + } + }), + ), + ); + } catch (error) { + logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`); + } + + return resources; + }; + }; +}; + +const listApiResourcesInjectable = getInjectable({ + id: "list-api-resources", + instantiate: (di) => { + const k8sRequest = di.inject(k8SRequestInjectable); + const logger = di.inject(loggerInjectable); + + return listApiResources({ k8sRequest, logger }); + }, +}); + +export default listApiResourcesInjectable; diff --git a/src/common/ipc/cluster.ts b/src/common/ipc/cluster.ts index c89e2f5010..803069c00e 100644 --- a/src/common/ipc/cluster.ts +++ b/src/common/ipc/cluster.ts @@ -5,7 +5,7 @@ export const clusterActivateHandler = "cluster:activate"; export const clusterSetFrameIdHandler = "cluster:set-frame-id"; -export const clusterRefreshHandler = "cluster:refresh"; +export const clusterVisibilityHandler = "cluster:visibility"; export const clusterDisconnectHandler = "cluster:disconnect"; export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 0244141ab3..980b63c767 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -10,6 +10,7 @@ import { getDiForUnitTesting } from "../getDiForUnitTesting"; import type { CreateCluster } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; +import authorizationNamespaceReviewInjectable from "../../common/cluster/authorization-namespace-review.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import type { ClusterContextHandler } from "../context-handler/context-handler"; @@ -19,6 +20,8 @@ import directoryForTempInjectable from "../../common/app-paths/directory-for-tem import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable"; +import { apiResourceRecord, apiResources } from "../../common/rbac"; +import listApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable"; console = new Console(process.stdout, process.stderr); // fix mockFS @@ -39,6 +42,8 @@ describe("create clusters", () => { di.override(normalizedPlatformInjectable, () => "darwin"); di.override(broadcastMessageInjectable, () => async () => {}); di.override(authorizationReviewInjectable, () => () => () => Promise.resolve(true)); + di.override(authorizationNamespaceReviewInjectable, () => () => () => Promise.resolve(Object.keys(apiResourceRecord))); + di.override(listApiResourcesInjectable, () => () => () => Promise.resolve(apiResources)); di.override(listNamespacesInjectable, () => () => () => Promise.resolve([ "default" ])); di.override(createContextHandlerInjectable, () => (cluster) => ({ restartServer: jest.fn(), diff --git a/src/main/create-cluster/create-cluster.injectable.ts b/src/main/create-cluster/create-cluster.injectable.ts index 5290e92db3..e1782ec6c9 100644 --- a/src/main/create-cluster/create-cluster.injectable.ts +++ b/src/main/create-cluster/create-cluster.injectable.ts @@ -11,7 +11,9 @@ import createKubectlInjectable from "../kubectl/create-kubectl.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; +import createAuthorizationNamespaceReview from "../../common/cluster/authorization-namespace-review.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; +import createListApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable"; import loggerInjectable from "../../common/logger.injectable"; import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable"; import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable"; @@ -28,6 +30,8 @@ const createClusterInjectable = getInjectable({ createKubectl: di.inject(createKubectlInjectable), createContextHandler: di.inject(createContextHandlerInjectable), createAuthorizationReview: di.inject(authorizationReviewInjectable), + createAuthorizationNamespaceReview: di.inject(createAuthorizationNamespaceReview), + createListApiResources: di.inject(createListApiResourcesInjectable), createListNamespaces: di.inject(listNamespacesInjectable), logger: di.inject(loggerInjectable), detectorRegistry: di.inject(detectorRegistryInjectable), diff --git a/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts b/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts index 165d1beb64..89814d92f2 100644 --- a/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts +++ b/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts @@ -5,7 +5,7 @@ import type { IpcMainInvokeEvent } from "electron"; import { BrowserWindow, Menu } from "electron"; import { clusterFrameMap } from "../../../../common/cluster-frames"; -import { clusterActivateHandler, clusterSetFrameIdHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster"; +import { clusterActivateHandler, clusterSetFrameIdHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster"; import type { ClusterId } from "../../../../common/cluster-types"; import { ClusterStore } from "../../../../common/cluster-store/cluster-store"; import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc"; @@ -61,12 +61,6 @@ export const setupIpcMainHandlers = ({ } }); - ipcMainHandle(clusterRefreshHandler, (event, clusterId: ClusterId) => { - return ClusterStore.getInstance() - .getById(clusterId) - ?.refresh({ refreshMetadata: true }); - }); - ipcMainHandle(clusterDisconnectHandler, (event, clusterId: ClusterId) => { emitAppEvent({ name: "cluster", action: "stop" }); const cluster = ClusterStore.getInstance().getById(clusterId); diff --git a/src/renderer/create-cluster/create-cluster.injectable.ts b/src/renderer/create-cluster/create-cluster.injectable.ts index 0c73eb82fa..e0a9f51656 100644 --- a/src/renderer/create-cluster/create-cluster.injectable.ts +++ b/src/renderer/create-cluster/create-cluster.injectable.ts @@ -27,7 +27,9 @@ const createClusterInjectable = getInjectable({ createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");}, createContextHandler: () => undefined as never, createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, + createAuthorizationNamespaceReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); }, + createListApiResources: ()=> { throw new Error("Tried to access back-end feature in front-end."); }, detectorRegistry: undefined as never, createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); }, };