diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index 858104fcb6c0c..4443ee4eaf674 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -5740,6 +5740,159 @@ "items" ] }, + "kibana_saved_object_type": { + "title": "Kibana saved object asset type", + "type": "string", + "enum": [ + "dashboard", + "visualization", + "search", + "index-pattern", + "map", + "lens", + "ml-module", + "security-rule", + "csp_rule_template" + ] + }, + "elasticsearch_asset_type": { + "title": "Elasticsearch asset type", + "type": "string", + "enum": [ + "component_template", + "ingest_pipeline", + "index_template", + "ilm_policy", + "transform", + "data_stream_ilm_policy" + ] + }, + "installation_info": { + "title": "Installation info object", + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "namespaces": { + "type": "array", + "items": { + "type": "string" + } + }, + "installed_kibana": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/kibana_saved_object_type" + } + } + }, + "installed_es": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "deferred": { + "type": "boolean" + }, + "type": { + "$ref": "#/components/schemas/elasticsearch_asset_type" + } + } + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "install_status": { + "type": "string", + "enum": [ + "installed", + "installing", + "install_failed" + ] + }, + "install_source": { + "type": "string", + "enum": [ + "registry", + "upload", + "bundled" + ] + }, + "install_kibana_space_id": { + "type": "string" + }, + "install_format_schema_version": { + "type": "string" + }, + "verification_status": { + "type": "string", + "enum": [ + "verified", + "unverified", + "unknown" + ] + }, + "verification_key_id": { + "type": "string", + "nullable": true + }, + "experimental_data_stream_features": { + "type": "array", + "properties": { + "data_stream": { + "type": "string" + }, + "features": { + "type": "object", + "properties": { + "synthetic_source": { + "type": "boolean", + "nullable": true + }, + "tsdb": { + "type": "boolean", + "nullable": true + }, + "doc_value_only_numeric": { + "type": "boolean", + "nullable": true + }, + "doc_value_only_other": { + "type": "boolean", + "nullable": true + } + } + } + } + } + }, + "required": [ + "installed_kibana", + "installed_es", + "name", + "version", + "install_status", + "install_version", + "install_started_at", + "install_source", + "verification_status" + ] + }, "search_result": { "title": "Search result", "type": "object", @@ -5771,6 +5924,9 @@ "status": { "type": "string" }, + "installationInfo": { + "$ref": "#/components/schemas/installation_info" + }, "savedObject": { "type": "object", "deprecated": true @@ -5810,33 +5966,6 @@ "items" ] }, - "kibana_saved_object_type": { - "title": "Kibana saved object asset type", - "type": "string", - "enum": [ - "dashboard", - "visualization", - "search", - "index-pattern", - "map", - "lens", - "ml-module", - "security-rule", - "csp_rule_template" - ] - }, - "elasticsearch_asset_type": { - "title": "Elasticsearch asset type", - "type": "string", - "enum": [ - "component_template", - "ingest_pipeline", - "index_template", - "ilm_policy", - "transform", - "data_stream_ilm_policy" - ] - }, "bulk_install_packages_response": { "title": "Bulk install packages response", "type": "object", diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 027fcf617cf83..5a7b470e4cfda 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -3602,6 +3602,118 @@ components: - count required: - items + kibana_saved_object_type: + title: Kibana saved object asset type + type: string + enum: + - dashboard + - visualization + - search + - index-pattern + - map + - lens + - ml-module + - security-rule + - csp_rule_template + elasticsearch_asset_type: + title: Elasticsearch asset type + type: string + enum: + - component_template + - ingest_pipeline + - index_template + - ilm_policy + - transform + - data_stream_ilm_policy + installation_info: + title: Installation info object + type: object + properties: + type: + type: string + created_at: + type: string + updated_at: + type: string + namespaces: + type: array + items: + type: string + installed_kibana: + type: object + properties: + id: + type: string + type: + $ref: '#/components/schemas/kibana_saved_object_type' + installed_es: + type: object + properties: + id: + type: string + deferred: + type: boolean + type: + $ref: '#/components/schemas/elasticsearch_asset_type' + name: + type: string + version: + type: string + install_status: + type: string + enum: + - installed + - installing + - install_failed + install_source: + type: string + enum: + - registry + - upload + - bundled + install_kibana_space_id: + type: string + install_format_schema_version: + type: string + verification_status: + type: string + enum: + - verified + - unverified + - unknown + verification_key_id: + type: string + nullable: true + experimental_data_stream_features: + type: array + properties: + data_stream: + type: string + features: + type: object + properties: + synthetic_source: + type: boolean + nullable: true + tsdb: + type: boolean + nullable: true + doc_value_only_numeric: + type: boolean + nullable: true + doc_value_only_other: + type: boolean + nullable: true + required: + - installed_kibana + - installed_es + - name + - version + - install_status + - install_version + - install_started_at + - install_source + - verification_status search_result: title: Search result type: object @@ -3624,6 +3736,8 @@ components: type: string status: type: string + installationInfo: + $ref: '#/components/schemas/installation_info' savedObject: type: object deprecated: true @@ -3652,29 +3766,6 @@ components: $ref: '#/components/schemas/search_result' required: - items - kibana_saved_object_type: - title: Kibana saved object asset type - type: string - enum: - - dashboard - - visualization - - search - - index-pattern - - map - - lens - - ml-module - - security-rule - - csp_rule_template - elasticsearch_asset_type: - title: Elasticsearch asset type - type: string - enum: - - component_template - - ingest_pipeline - - index_template - - ilm_policy - - transform - - data_stream_ilm_policy bulk_install_packages_response: title: Bulk install packages response type: object diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml new file mode 100644 index 0000000000000..4d13611a6afbd --- /dev/null +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/installation_info.yaml @@ -0,0 +1,88 @@ +title: Installation info object +type: object +properties: + type: + type: string + created_at: + type: string + updated_at: + type: string + namespaces: + type: array + items: + type: string + installed_kibana: + type: object + properties: + id: + type: string + type: + $ref: ./kibana_saved_object_type.yaml + installed_es: + type: object + properties: + id: + type: string + deferred: + type: boolean + type: + $ref: ./elasticsearch_asset_type.yaml + name: + type: string + version: + type: string + install_status: + type: string + enum: + - installed + - installing + - install_failed + install_source: + type: string + enum: + - registry + - upload + - bundled + install_kibana_space_id: + type: string + install_format_schema_version: + type: string + verification_status: + type: string + enum: + - verified + - unverified + - unknown + verification_key_id: + type: string + nullable: true + experimental_data_stream_features: + type: array + properties: + data_stream: + type: string + features: + type: object + properties: + synthetic_source: + type: boolean + nullable: true + tsdb: + type: boolean + nullable: true + doc_value_only_numeric: + type: boolean + nullable: true + doc_value_only_other: + type: boolean + nullable: true +required: + - installed_kibana + - installed_es + - name + - version + - install_status + - install_version + - install_started_at + - install_source + - verification_status diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/search_result.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/search_result.yaml index f06e524187faf..bc285a8ae9b29 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/search_result.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/search_result.yaml @@ -19,6 +19,8 @@ properties: type: string status: type: string + installationInfo: + $ref: ./installation_info.yaml savedObject: type: object deprecated: true diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index c9f5201ebff85..bcfff4b33ff3d 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -365,18 +365,16 @@ describe('Fleet - packageToPackagePolicy', () => { packageToPackagePolicy( { ...mockPackage, - savedObject: { - attributes: { - experimental_data_stream_features: [ - { - data_stream: 'metrics-test.testdataset', - features: { - synthetic_source: true, - tsdb: true, - }, + installationInfo: { + experimental_data_stream_features: [ + { + data_stream: 'metrics-test.testdataset', + features: { + synthetic_source: true, + tsdb: true, }, - ], - }, + }, + ], } as any, }, '1' diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index 52d55f384e96e..48810180aade7 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -206,8 +206,8 @@ export const packageToPackagePolicy = ( integrationToEnable?: string ): NewPackagePolicy => { const experimentalDataStreamFeatures = - 'savedObject' in packageInfo - ? packageInfo.savedObject?.attributes?.experimental_data_stream_features + 'installationInfo' in packageInfo + ? packageInfo.installationInfo?.experimental_data_stream_features : undefined; const packagePolicy: NewPackagePolicy = { diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 2f86af93476f8..759fa02229ef0 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -421,7 +421,7 @@ export interface RegistryVarsEntry { // Deprecated as part of the removing public references to saved object schemas // See /~https://github.com/elastic/kibana/issues/149098 /** - * @deprecated + * @deprecated replaced with installationInfo */ export interface InstallableSavedObject { type: string; @@ -434,6 +434,21 @@ export interface InstallableSavedObject { coreMigrationVersion?: string; namespaces?: string[]; } +export type InstallationInfo = { + type: string; + created_at?: string; + updated_at?: string; + namespaces?: string[]; +} & Omit< + Installation, + | 'package_assets' + | 'es_index_patterns' + | 'install_version' + | 'install_started_at' + | 'keep_policies_up_to_date' + | 'internal' + | 'removable' +>; // Deprecated as part of the removing public references to saved object schemas // See /~https://github.com/elastic/kibana/issues/149098 @@ -462,9 +477,12 @@ type Merge = Omit & { id: string; integration?: string; + installationInfo?: InstallationInfo; savedObject?: InstallableSavedObject; }; export type PackagesGroupedByStatus = Record, PackageList>; @@ -504,14 +522,11 @@ export interface Installation { install_format_schema_version?: string; verification_status: PackageVerificationStatus; verification_key_id?: string | null; - // TypeScript doesn't like using the `ExperimentalDataStreamFeature` type defined above here - experimental_data_stream_features?: Array<{ - data_stream: string; - features: Partial>; - }>; + experimental_data_stream_features?: ExperimentalDataStreamFeature[]; internal?: boolean; removable?: boolean; } + export interface PackageUsageStats { agent_policy_count: number; } @@ -530,11 +545,13 @@ export type InstallStatusExcluded = T & { export type InstalledRegistry = T & { status: InstallationStatus['Installed']; savedObject?: InstallableSavedObject; + installationInfo?: InstallationInfo; }; export type Installing = T & { status: InstallationStatus['Installing']; savedObject?: InstallableSavedObject; + installationInfo?: InstallationInfo; }; export type NotInstalled = T & { diff --git a/x-pack/plugins/fleet/cypress/e2e/install_assets.cy.ts b/x-pack/plugins/fleet/cypress/e2e/install_assets.cy.ts index 4234df15d861e..886f439a1a2ef 100644 --- a/x-pack/plugins/fleet/cypress/e2e/install_assets.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/install_assets.cy.ts @@ -37,8 +37,8 @@ describe('Install unverified package assets', () => { // save mocking out the whole package response, but make it so that fleet server is always uninstalled cy.intercept('GET', '/api/fleet/epm/packages/fleet_server*', (req) => { req.continue((res) => { - if (res.body?.item?.savedObject) { - delete res.body.item.savedObject; + if (res.body?.item?.installationInfo) { + delete res.body.item.installationInfo; } if (res.body?.item?.status) { res.body.item.status = 'not_installed'; diff --git a/x-pack/plugins/fleet/cypress/e2e/integrations_mock.cy.ts b/x-pack/plugins/fleet/cypress/e2e/integrations_mock.cy.ts index 3095f628599d6..d40cae5b58971 100644 --- a/x-pack/plugins/fleet/cypress/e2e/integrations_mock.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/integrations_mock.cy.ts @@ -22,7 +22,7 @@ describe('Add Integration - Mock API', () => { name: 'apache', id: 'apache', version: newVersion, - savedObject: { attributes: { version: oldVersion } }, + installationInfo: { version: oldVersion }, status: 'installed', }, ], @@ -35,7 +35,7 @@ describe('Add Integration - Mock API', () => { latestVersion: newVersion, status: 'installed', assets: [], - savedObject: { attributes: { version: oldVersion } }, + installationInfo: { version: oldVersion }, }, }); cy.intercept('/api/fleet/epm/packages/apache/stats', { response: { agent_policy_count: 1 } }); @@ -106,7 +106,7 @@ describe('Add Integration - Mock API', () => { latestVersion: newVersion, status: 'installed', assets: [], - savedObject: { attributes: { version: newVersion } }, + installationInfo: { version: newVersion }, }, }).as('updatePackage'); cy.getBySel(UPDATE_PACKAGE_BTN).click(); @@ -123,7 +123,7 @@ describe('Add Integration - Mock API', () => { latestVersion: newVersion, status: 'installed', assets: [], - savedObject: { attributes: { version: newVersion } }, + installationInfo: { version: newVersion }, }, }); cy.intercept('/api/fleet/epm/packages/apache/stats', { response: { agent_policy_count: 1 } }); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/assets/assets.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/assets/assets.tsx index ece2ae24c45f2..b9a023bef1ef7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/assets/assets.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/assets/assets.tsx @@ -62,10 +62,10 @@ export const AssetsPage = ({ packageInfo }: AssetsPanelProps) => { useEffect(() => { const fetchAssetSavedObjects = async () => { - if ('savedObject' in packageInfo) { + if ('installationInfo' in packageInfo) { if (spaces) { const { id: spaceId } = await spaces.getActiveSpace(); - const assetInstallSpaceId = packageInfo.savedObject?.attributes.installed_kibana_space_id; + const assetInstallSpaceId = packageInfo.installationInfo?.installed_kibana_space_id; // if assets are installed in a different space no need to attempt to load them. if (assetInstallSpaceId && assetInstallSpaceId !== spaceId) { @@ -75,25 +75,26 @@ export const AssetsPage = ({ packageInfo }: AssetsPanelProps) => { } } - const packageAttributes = packageInfo.savedObject?.attributes; + const pkgInstallationInfo = packageInfo.installationInfo; if ( - packageAttributes?.installed_es && - Array.isArray(packageAttributes.installed_es) && - packageAttributes.installed_es.length > 0 + pkgInstallationInfo?.installed_es && + Array.isArray(pkgInstallationInfo.installed_es) && + pkgInstallationInfo.installed_es.length > 0 ) { - const deferredAssets = packageAttributes.installed_es.filter( + const deferredAssets = pkgInstallationInfo.installed_es.filter( (asset) => asset.deferred === true ); setDeferredInstallations(deferredAssets); } - const authorizedTransforms = (packageAttributes?.installed_es || []).filter( + const authorizedTransforms = (pkgInstallationInfo?.installed_es || []).filter( (asset) => asset.type === ElasticsearchAssetType.transform && !asset.deferred ); if ( authorizedTransforms?.length === 0 && - (!packageAttributes?.installed_kibana || packageAttributes.installed_kibana.length === 0) + (!pkgInstallationInfo?.installed_kibana || + pkgInstallationInfo.installed_kibana.length === 0) ) { setIsLoading(false); return; @@ -101,7 +102,7 @@ export const AssetsPage = ({ packageInfo }: AssetsPanelProps) => { try { const assetIds: AssetSOObject[] = [ ...authorizedTransforms, - ...(packageAttributes?.installed_kibana || []), + ...(pkgInstallationInfo?.installed_kibana || []), ].map(({ id, type }) => ({ id, type, diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index 9f5e5f8eab682..3347c8e8f6216 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -175,9 +175,9 @@ export function Detail() { const updateAvailable = packageInfo && - 'savedObject' in packageInfo && - packageInfo.savedObject && - semverLt(packageInfo.savedObject.attributes.version, packageInfo.latestVersion); + 'installationInfo' in packageInfo && + packageInfo.installationInfo?.version && + semverLt(packageInfo.installationInfo.version, packageInfo.latestVersion); const [prereleaseIntegrationsEnabled, setPrereleaseIntegrationsEnabled] = React.useState< boolean | undefined @@ -256,8 +256,8 @@ export function Detail() { let installedVersion; const { name } = packageInfoData.item; - if ('savedObject' in packageInfoResponse) { - installedVersion = packageInfoResponse.savedObject?.attributes.version; + if ('installationInfo' in packageInfoResponse) { + installedVersion = packageInfoResponse.installationInfo?.version; } const status: InstallStatus = packageInfoResponse?.status as any; if (name) { diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx index d7e132d47462e..9c2ca98479a85 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/settings/settings.tsx @@ -455,9 +455,9 @@ export const SettingsPage: React.FC = memo(({ packageInfo, theme$ }: Prop diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx index 500918385d399..c66727836fed5 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/index.tsx @@ -101,8 +101,8 @@ export const mapToCard = ({ : item.uiExternalLink || getAbsolutePath(item.uiInternalPath); } else { let urlVersion = item.version; - if ('savedObject' in item && item?.savedObject?.attributes.version) { - urlVersion = item.savedObject.attributes.version || item.version; + if (item?.installationInfo?.version) { + urlVersion = item.installationInfo.version || item.version; isUnverified = isPackageUnverified(item, packageVerificationKeyId); isUpdateAvailable = isPackageUpdatable(item); @@ -151,9 +151,8 @@ export const EPMHomePage: React.FC = () => { const unverifiedPackageCount = installedPackages.filter( (pkg) => - 'savedObject' in pkg && - pkg.savedObject?.attributes.verification_status && - pkg.savedObject.attributes.verification_status === 'unverified' + pkg.installationInfo?.verification_status && + pkg.installationInfo.verification_status === 'unverified' ).length; const upgradeablePackageCount = installedPackages.filter(isPackageUpdatable).length; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx index d683e93c5bb48..bf916f231ca40 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/installed_packages.tsx @@ -171,8 +171,7 @@ export const InstalledPackages: React.FC<{ () => installedPackages.filter( (item) => - item.savedObject?.attributes.version && - semverLt(item.savedObject.attributes.version, item.version) + item?.installationInfo?.version && semverLt(item.installationInfo.version, item.version) ), [installedPackages] ); diff --git a/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.test.tsx b/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.test.tsx index c5aa4d30a2837..b928a74c306ea 100644 --- a/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.test.tsx +++ b/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.test.tsx @@ -24,11 +24,9 @@ describe('useIsPackagePolicyUpgradable', () => { items: [ { status: 'installed', - savedObject: { - attributes: { - name: 'test', - version: '1.0.0', - }, + installationInfo: { + name: 'test', + version: '1.0.0', }, }, ], diff --git a/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.tsx b/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.tsx index 0ba7a8fb99d57..e993c035f15e3 100644 --- a/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.tsx +++ b/x-pack/plugins/fleet/public/hooks/use_is_package_policy_upgradable.tsx @@ -31,11 +31,11 @@ export const useIsPackagePolicyUpgradable = () => { const { name, version } = pkgPolicy.package; const installedPackage = allInstalledPackages.find( (installedPkg) => - 'savedObject' in installedPkg && installedPkg.savedObject?.attributes.name === name + 'installationInfo' in installedPkg && installedPkg.installationInfo?.name === name ); if ( - installedPackage?.savedObject?.attributes.version && - semverLt(version, installedPackage.savedObject.attributes.version) + installedPackage?.installationInfo?.version && + semverLt(version, installedPackage.installationInfo.version) ) { return true; } diff --git a/x-pack/plugins/fleet/public/hooks/use_package_installations.tsx b/x-pack/plugins/fleet/public/hooks/use_package_installations.tsx index 10ea26b749fbe..9147d781336de 100644 --- a/x-pack/plugins/fleet/public/hooks/use_package_installations.tsx +++ b/x-pack/plugins/fleet/public/hooks/use_package_installations.tsx @@ -44,9 +44,9 @@ export const usePackageInstallationsQuery = () => { () => allInstalledPackages.filter( (item) => - 'savedObject' in item && - item.savedObject?.attributes.version && - semverLt(item.savedObject.attributes.version, item.version) + 'installationInfo' in item && + item.installationInfo?.version && + semverLt(item.installationInfo.version, item.version) ), [allInstalledPackages] ); @@ -59,16 +59,16 @@ export const usePackageInstallationsQuery = () => { const { name, version } = pkgPolicy.package; const installedPackage = allInstalledPackages.find( (installedPkg) => - 'savedObject' in installedPkg && installedPkg?.savedObject?.attributes.name === name + 'installationInfo' in installedPkg && installedPkg?.installationInfo?.name === name ); if ( installedPackage && - 'savedObject' in installedPackage && - installedPackage?.savedObject?.attributes?.version && - semverLt(version, installedPackage.savedObject.attributes.version) + 'installationInfo' in installedPackage && + installedPackage?.installationInfo?.version && + semverLt(version, installedPackage.installationInfo.version) ) { const packageData = result.get(name) ?? { - currentVersion: installedPackage.savedObject.attributes.version, + currentVersion: installedPackage.installationInfo.version, policiesToUpgrade: [], }; packageData.policiesToUpgrade.push({ diff --git a/x-pack/plugins/fleet/public/search_provider.test.ts b/x-pack/plugins/fleet/public/search_provider.test.ts index eef6d30c023e3..5f95eef60546c 100644 --- a/x-pack/plugins/fleet/public/search_provider.test.ts +++ b/x-pack/plugins/fleet/public/search_provider.test.ts @@ -32,7 +32,7 @@ const testResponse: GetPackagesResponse['items'] = [ name: 'test', path: 'test', release: 'experimental', - savedObject: {} as any, + installationInfo: {} as any, status: 'installed', title: 'test', version: 'test', diff --git a/x-pack/plugins/fleet/public/services/has_deferred_installations.test.ts b/x-pack/plugins/fleet/public/services/has_deferred_installations.test.ts index f4f39ed7115d1..1899383c686eb 100644 --- a/x-pack/plugins/fleet/public/services/has_deferred_installations.test.ts +++ b/x-pack/plugins/fleet/public/services/has_deferred_installations.test.ts @@ -32,23 +32,16 @@ const createPackage = ({ policy_templates: [], // @ts-ignore assets: {}, - savedObject: { - id: '1234', + installationInfo: { type: 'epm-package', - references: [], - attributes: { - installed_kibana: [], - installed_es: installedEs ?? [], - es_index_patterns: {}, - name: 'test-package', - version: '0.0.1', - install_status: 'installed', - install_version: '0.0.1', - install_started_at: new Date().toString(), - install_source: 'registry', - verification_status: 'verified', - verification_key_id: '', - }, + installed_kibana: [], + installed_es: installedEs ?? [], + name: 'test-package', + version: '0.0.1', + install_status: 'installed', + install_source: 'registry', + verification_status: 'verified', + verification_key_id: '', }, }); @@ -61,10 +54,10 @@ describe('isPackageUnverified', () => { } as ReturnType); }); - it('Should return false for a package with no saved object', () => { + it('Should return false for a package with no installationInfo', () => { const noSoPkg = createPackage(); - // @ts-ignore we know pkg has savedObject but ts doesn't - delete noSoPkg.savedObject; + // @ts-ignore we know pkg has installationInfo but ts doesn't + delete noSoPkg.installationInfo; expect(hasDeferredInstallations(noSoPkg)).toEqual(false); }); @@ -75,7 +68,7 @@ describe('isPackageUnverified', () => { { id: '', type: ElasticsearchAssetType.transform, deferred: true }, ], }); - // @ts-ignore we know pkg has savedObject but ts doesn't + expect(hasDeferredInstallations(pkgWithDeferredInstallations)).toEqual(true); }); diff --git a/x-pack/plugins/fleet/public/services/has_deferred_installations.ts b/x-pack/plugins/fleet/public/services/has_deferred_installations.ts index 8d2bbc47d2f65..31a33066dfdea 100644 --- a/x-pack/plugins/fleet/public/services/has_deferred_installations.ts +++ b/x-pack/plugins/fleet/public/services/has_deferred_installations.ts @@ -10,8 +10,8 @@ import type { PackageInfo, PackageListItem } from '../../common'; export const getDeferredInstallationsCnt = (pkg?: PackageInfo | PackageListItem | null): number => { if (!pkg) return 0; - return pkg && 'savedObject' in pkg && pkg.savedObject - ? pkg.savedObject.attributes?.installed_es?.filter((d) => d.deferred).length + return pkg && 'installationInfo' in pkg && pkg.installationInfo + ? pkg.installationInfo.installed_es?.filter((d) => d.deferred).length : 0; }; diff --git a/x-pack/plugins/fleet/public/services/is_package_updatable.ts b/x-pack/plugins/fleet/public/services/is_package_updatable.ts index 45ed46c3321c9..c8341f14ac8c4 100644 --- a/x-pack/plugins/fleet/public/services/is_package_updatable.ts +++ b/x-pack/plugins/fleet/public/services/is_package_updatable.ts @@ -9,6 +9,6 @@ import semverLt from 'semver/functions/lt'; import type { PackageListItem } from '../types'; export const isPackageUpdatable = (pkg: PackageListItem): boolean => - 'savedObject' in pkg && pkg.savedObject?.attributes.version - ? semverLt(pkg.savedObject.attributes.version, pkg.version) + 'installationInfo' in pkg && pkg.installationInfo?.version + ? semverLt(pkg.installationInfo?.version, pkg.version) : false; diff --git a/x-pack/plugins/fleet/public/services/package_verification.test.ts b/x-pack/plugins/fleet/public/services/package_verification.test.ts index eeea17522795a..f098651c710ed 100644 --- a/x-pack/plugins/fleet/public/services/package_verification.test.ts +++ b/x-pack/plugins/fleet/public/services/package_verification.test.ts @@ -30,23 +30,16 @@ const createPackage = ({ policy_templates: [], // @ts-ignore assets: {}, - savedObject: { - id: '1234', + installationInfo: { type: 'epm-package', - references: [], - attributes: { - installed_kibana: [], - installed_es: [], - es_index_patterns: {}, - name: 'test-package', - version: '0.0.1', - install_status: 'installed', - install_version: '0.0.1', - install_started_at: new Date().toString(), - install_source: 'registry', - verification_status: verificationStatus, - ...(verificationKeyId && { verification_key_id: verificationKeyId }), - }, + installed_kibana: [], + installed_es: [], + name: 'test-package', + version: '0.0.1', + install_status: 'installed', + install_source: 'registry', + verification_status: verificationStatus, + ...(verificationKeyId && { verification_key_id: verificationKeyId }), }, }); @@ -61,8 +54,8 @@ describe('isPackageUnverified', () => { it('Should return false for a package with no saved object', () => { const noSoPkg = createPackage(); - // @ts-ignore we know pkg has savedObject but ts doesn't - delete noSoPkg.savedObject; + // @ts-ignore we know pkg has installationInfo but ts doesn't + delete noSoPkg.installationInfo; expect(isPackageUnverified(noSoPkg)).toEqual(false); }); it('Should return false for an unverified package', () => { @@ -100,8 +93,8 @@ describe('isPackageUnverified', () => { }); it('Should return false for a package with no saved object', () => { const noSoPkg = createPackage(); - // @ts-ignore we know pkg has savedObject but ts doesn't - delete noSoPkg.savedObject; + // @ts-ignore we know pkg has installationInfo but ts doesn't + delete noSoPkg.installationInfo; expect(isPackageUnverified(noSoPkg)).toEqual(false); }); it('Should return false for a verified package', () => { diff --git a/x-pack/plugins/fleet/public/services/package_verification.ts b/x-pack/plugins/fleet/public/services/package_verification.ts index 2c390ff50548f..a8e580a22604f 100644 --- a/x-pack/plugins/fleet/public/services/package_verification.ts +++ b/x-pack/plugins/fleet/public/services/package_verification.ts @@ -17,10 +17,10 @@ export function isPackageUnverified( pkg: PackageInfo | PackageListItem, packageVerificationKeyId?: string ) { - if (!('savedObject' in pkg) || !pkg.savedObject?.attributes) return false; + if (!('installationInfo' in pkg) || !pkg.installationInfo) return false; const { verification_status: verificationStatus, verification_key_id: verificationKeyId } = - pkg?.savedObject?.attributes; + pkg?.installationInfo; const { packageVerification: isPackageVerificationEnabled } = ExperimentalFeaturesService.get(); const isKeyOutdated = !!verificationKeyId && verificationKeyId !== packageVerificationKeyId; diff --git a/x-pack/plugins/fleet/server/routes/epm/handlers.ts b/x-pack/plugins/fleet/server/routes/epm/handlers.ts index b02666e7e3738..bb96636504141 100644 --- a/x-pack/plugins/fleet/server/routes/epm/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/epm/handlers.ts @@ -12,6 +12,8 @@ import mime from 'mime-types'; import semverValid from 'semver/functions/valid'; import type { ResponseHeaders, KnownHeaders, HttpResponseOptions } from '@kbn/core/server'; +import { pick } from 'lodash'; + import { HTTPAuthorizationHeader } from '../../../common/http_authorization_header'; import { generateTransformSecondaryAuthHeaders } from '../../services/api_keys/transform_api_keys'; import { handleTransformReauthorizeAndStart } from '../../services/epm/elasticsearch/transform/reauthorize'; @@ -72,7 +74,14 @@ import { getAsset } from '../../services/epm/archive/storage'; import { getPackageUsageStats } from '../../services/epm/packages/get'; import { updatePackage } from '../../services/epm/packages/update'; import { getGpgKeyIdOrUndefined } from '../../services/epm/packages/package_verification'; -import type { ReauthorizeTransformRequestSchema, SimpleSOAssetAttributes } from '../../types'; +import type { + ReauthorizeTransformRequestSchema, + SimpleSOAssetAttributes, + PackageListItem, + PackageList, + PackageInfo, + InstallationInfo, +} from '../../types'; import type { KibanaSavedObjectType, ElasticsearchAssetType } from '../../../common/types/models'; import { getDataStreams } from '../../services/epm/data_streams'; import { allowedAssetTypesLookup } from '../../../common/constants'; @@ -109,9 +118,9 @@ export const getListHandler: FleetRequestHandler< savedObjectsClient, ...request.query, }); - + const flattenedRes = res.map((pkg) => soToInstallationInfo(pkg)) as PackageList; const body: GetPackagesResponse = { - items: res, + items: flattenedRes, response: res, }; return response.ok({ @@ -291,9 +300,10 @@ export const getInfoHandler: FleetRequestHandler< ignoreUnverified, prerelease, }); + const flattenedRes = soToInstallationInfo(res) as PackageInfo; const body: GetInfoResponse = { - item: res, + item: flattenedRes, }; return response.ok({ body }); } catch (error) { @@ -594,3 +604,29 @@ export const reauthorizeTransformsHandler: FleetRequestHandler< return defaultFleetErrorHandler({ error, response }); } }; + +// Don't expose the whole SO in the API response, only selected fields +const soToInstallationInfo = (pkg: PackageListItem | PackageInfo) => { + if ('savedObject' in pkg && pkg.savedObject?.attributes) { + const { attributes } = pkg.savedObject; + const installationInfo: InstallationInfo = { + ...pick(pkg.savedObject, ['created_at', 'updated_at', 'namespaces', 'type']), + installed_kibana: attributes.installed_kibana, + installed_kibana_space_id: attributes.installed_kibana_space_id, + installed_es: attributes.installed_es, + install_status: attributes.install_status, + install_source: attributes.install_source, + name: attributes.name, + version: attributes.version, + verification_status: attributes.verification_status, + verification_key_id: attributes.verification_key_id, + experimental_data_stream_features: attributes.experimental_data_stream_features, + }; + return { + // When savedObject gets removed, replace `pkg` with `...omit(pkg, 'savedObject')` + ...pkg, + installationInfo, + }; + } + return pkg; +}; diff --git a/x-pack/plugins/fleet/server/types/index.tsx b/x-pack/plugins/fleet/server/types/index.tsx index 33cf6bf983293..d9c7ff9db74af 100644 --- a/x-pack/plugins/fleet/server/types/index.tsx +++ b/x-pack/plugins/fleet/server/types/index.tsx @@ -86,6 +86,9 @@ export type { SecretElasticDoc, VarSecretReference, PolicySecretReference, + PackageListItem, + PackageList, + InstallationInfo, } from '../../common/types'; export { ElasticsearchAssetType, KibanaAssetType, KibanaSavedObjectType } from '../../common/types'; export { dataTypes } from '../../common/constants';