Skip to content
195 changes: 106 additions & 89 deletions x-pack/plugins/security_solution/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
PluginInitializerContext,
Plugin as IPlugin,
} from '@kbn/core/public';
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { AppStatus, DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public';
import { uiMetricService } from '@kbn/cloud-security-posture-common/utils/ui_metrics';
Expand Down Expand Up @@ -208,88 +208,20 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S

public start(core: CoreStart, plugins: StartPlugins): PluginStart {
this.services.start(core, plugins);

if (plugins.fleet) {
const { registerExtension } = plugins.fleet;
const registerOptions: FleetUiExtensionGetterOptions = {
coreStart: core,
depsStart: plugins,
services: {
upsellingService: this.contract.upsellingService,
},
};

registerExtension({
package: 'endpoint',
view: 'package-policy-edit',
Component: getLazyEndpointPolicyEditExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-response',
Component: getLazyEndpointPolicyResponseExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-generic-errors-list',
Component: getLazyEndpointGenericErrorsListExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create',
Component: getLazyEndpointPolicyCreateExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create-multi-step',
Component: LazyEndpointPolicyCreateMultiStepExtension,
});

registerExtension({
package: 'endpoint',
view: 'package-detail-custom',
Component: getLazyEndpointPackageCustomExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-detail-assets',
Component: LazyEndpointCustomAssetsExtension,
});

registerExtension({
package: 'endpoint',
view: 'endpoint-agent-tamper-protection',
Component: getLazyEndpointAgentTamperProtectionExtension(registerOptions),
});

registerExtension({
package: 'cloud_security_posture',
view: 'pli-auth-block',
Component: getLazyCloudSecurityPosturePliAuthBlockExtension(registerOptions),
});

registerExtension({
package: 'cribl',
view: 'package-policy-replace-define-step',
Component: LazyCustomCriblExtension,
});
}

// Not using await to prevent blocking start execution
this.registerAppLinks(core, plugins);

this.registerFleetExtensions(core, plugins);
this.registerPluginUpdates(core, plugins); // Not awaiting to prevent blocking start execution
return this.contract.getStartContract(core);
}

public stop() {
this.services.stop();
}

/**
* SubPlugins are the individual building blocks of the Security Solution plugin.
* They are lazily instantiated to improve startup time.
* TODO: Move these functions to ./lazy_sub_plugins.ts
*/
private async createSubPlugins(): Promise<SubPlugins> {
if (!this._subPlugins) {
const { subPluginClasses } = await this.lazySubPlugins();
Expand Down Expand Up @@ -317,9 +249,6 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
return this._subPlugins;
}

/**
* All started subPlugins.
*/
private async startSubPlugins(
storage: Storage,
core: CoreStart,
Expand Down Expand Up @@ -389,7 +318,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
}

/**
* Registers the alerts tables configurations.
* Registers the alerts tables configurations to the triggersActionsUi plugin.
*/
private async registerAlertsTableConfiguration(
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup
Expand All @@ -406,38 +335,126 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
}

/**
* Registers deepLinks and appUpdater for appLinks using license.
* Registers the plugin updates including status, visibleIn, and deepLinks via the plugin updater$.
*/
async registerAppLinks(core: CoreStart, plugins: StartPlugins) {
private async registerPluginUpdates(core: CoreStart, plugins: StartPlugins) {
const { license$ } = plugins.licensing;
const { capabilities } = core.application;
const { upsellingService, isSolutionNavigationEnabled$ } = this.contract;

// When the user does not have access to SIEM (main Security feature) nor Security Cases feature, the plugin must be inaccessible.
if (!capabilities.siem?.show && !capabilities.securitySolutionCases?.read_cases) {
this.appUpdater$.next(() => ({
status: AppStatus.inaccessible,
visibleIn: [],
}));
// no need to register the links updater when the plugin is inaccessible
return;
}
Comment on lines +345 to +353
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only code addition in this PR, the rest is a small housekeeping refactor.


// Configuration of AppLinks updater registration based on license and capabilities
const {
appLinks: initialAppLinks,
getFilteredLinks,
solutionAppLinksSwitcher,
} = await this.lazyApplicationLinks();
const { license$ } = plugins.licensing;
const { upsellingService, isSolutionNavigationEnabled$ } = this.contract;

registerDeepLinksUpdater(this.appUpdater$, isSolutionNavigationEnabled$);

const appLinks$ = new Subject<AppLinkItems>();
appLinks$.next(initialAppLinks);
const appLinksToUpdate$ = new Subject<AppLinkItems>();
appLinksToUpdate$.next(initialAppLinks);

appLinks$
appLinksToUpdate$
.pipe(combineLatestWith(license$, isSolutionNavigationEnabled$))
.subscribe(([appLinks, license, isSolutionNavigationEnabled]) => {
const links = isSolutionNavigationEnabled ? solutionAppLinksSwitcher(appLinks) : appLinks;
const linksPermissions: LinksPermissions = {
experimentalFeatures: this.experimentalFeatures,
upselling: upsellingService,
capabilities: core.application.capabilities,
capabilities,
uiSettingsClient: core.uiSettings,
...(license.type != null && { license }),
};
updateAppLinks(links, linksPermissions);
});

const filteredLinks = await getFilteredLinks(core, plugins);
appLinks$.next(filteredLinks);
appLinksToUpdate$.next(filteredLinks);
}

private registerFleetExtensions(core: CoreStart, plugins: StartPlugins) {
if (!plugins.fleet) {
return;
}

const { registerExtension } = plugins.fleet;
const registerOptions: FleetUiExtensionGetterOptions = {
coreStart: core,
depsStart: plugins,
services: {
upsellingService: this.contract.upsellingService,
},
};

registerExtension({
package: 'endpoint',
view: 'package-policy-edit',
Component: getLazyEndpointPolicyEditExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-response',
Component: getLazyEndpointPolicyResponseExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-generic-errors-list',
Component: getLazyEndpointGenericErrorsListExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create',
Component: getLazyEndpointPolicyCreateExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create-multi-step',
Component: LazyEndpointPolicyCreateMultiStepExtension,
});

registerExtension({
package: 'endpoint',
view: 'package-detail-custom',
Component: getLazyEndpointPackageCustomExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-detail-assets',
Component: LazyEndpointCustomAssetsExtension,
});

registerExtension({
package: 'endpoint',
view: 'endpoint-agent-tamper-protection',
Component: getLazyEndpointAgentTamperProtectionExtension(registerOptions),
});

registerExtension({
package: 'cloud_security_posture',
view: 'pli-auth-block',
Component: getLazyCloudSecurityPosturePliAuthBlockExtension(registerOptions),
});

registerExtension({
package: 'cribl',
view: 'package-policy-replace-define-step',
Component: LazyCustomCriblExtension,
});
}

// Lazy loaded dependencies
Expand Down