diff --git a/x-pack/plugins/security_solution/server/endpoint/ingest_integration.ts b/x-pack/plugins/security_solution/server/endpoint/ingest_integration.ts index 0c1b13f0646a3..11d4b12d0b76a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/ingest_integration.ts +++ b/x-pack/plugins/security_solution/server/endpoint/ingest_integration.ts @@ -11,7 +11,7 @@ import { NewPolicyData } from '../../common/endpoint/types'; import { ManifestManager } from './services/artifacts'; import { Manifest } from './lib/artifacts'; import { reportErrors, ManifestConstants } from './lib/artifacts/common'; -import { InternalArtifactSchema } from './schemas/artifacts'; +import { InternalArtifactCompleteSchema } from './schemas/artifacts'; import { manifestDispatchSchema } from '../../common/endpoint/schema/manifest'; const getManifest = async (logger: Logger, manifestManager: ManifestManager): Promise => { @@ -39,7 +39,7 @@ const getManifest = async (logger: Logger, manifestManager: ManifestManager): Pr // Persist new artifacts const artifacts = adds .map((artifactId) => newManifest.getArtifact(artifactId)) - .filter((artifact) => artifact !== undefined) as InternalArtifactSchema[]; + .filter((artifact): artifact is InternalArtifactCompleteSchema => artifact !== undefined); if (artifacts.length !== adds.length) { throw new Error('Invalid artifact encountered.'); } diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/common.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/common.ts index cfaed56c25e59..7298a9bfa72a6 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/common.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/common.ts @@ -4,7 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import { Logger } from 'src/core/server'; -import { InternalArtifactSchema } from '../../schemas/artifacts'; +import { + InternalArtifactSchema, + InternalArtifactCompleteSchema, + internalArtifactCompleteSchema, +} from '../../schemas/artifacts'; export const ArtifactConstants = { GLOBAL_ALLOWLIST_NAME: 'endpoint-exceptionlist', @@ -22,6 +26,12 @@ export const getArtifactId = (artifact: InternalArtifactSchema) => { return `${artifact.identifier}-${artifact.decodedSha256}`; }; +export const isCompleteArtifact = ( + artifact: InternalArtifactSchema +): artifact is InternalArtifactCompleteSchema => { + return internalArtifactCompleteSchema.is(artifact); +}; + export const reportErrors = (logger: Logger, errors: Error[]) => { errors.forEach((err) => { logger.error(err); diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.test.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.test.ts index 95f9eeef2194f..95587c6fc105d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.test.ts @@ -5,7 +5,7 @@ */ import { ManifestSchemaVersion } from '../../../../common/endpoint/schema/common'; -import { InternalArtifactSchema } from '../../schemas'; +import { InternalArtifactCompleteSchema } from '../../schemas'; import { ManifestConstants, getArtifactId } from './common'; import { Manifest } from './manifest'; import { @@ -17,7 +17,7 @@ import { describe('manifest', () => { describe('Manifest object sanity checks', () => { - let artifacts: InternalArtifactSchema[] = []; + let artifacts: InternalArtifactCompleteSchema[] = []; let manifest1: Manifest; let manifest2: Manifest; let emptyManifest: Manifest; diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.ts index bf49108529170..6ece2bf0f48e8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/manifest.ts @@ -10,6 +10,7 @@ import { InternalArtifactSchema, InternalManifestSchema, internalArtifactCompleteSchema, + InternalArtifactCompleteSchema, } from '../../schemas/artifacts'; import { manifestSchemaVersion, @@ -53,7 +54,7 @@ export class Manifest { } public static fromArtifacts( - artifacts: InternalArtifactSchema[], + artifacts: InternalArtifactCompleteSchema[], schemaVersion: string, oldManifest: Manifest ): Manifest { diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts index 904b19e8e02a8..097151ee835ba 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InternalArtifactSchema } from '../../schemas/artifacts'; +import { InternalArtifactCompleteSchema } from '../../schemas/artifacts'; import { getInternalArtifactMock, getInternalArtifactMockWithDiffs, @@ -15,7 +15,7 @@ import { Manifest } from './manifest'; export const getMockArtifacts = async (opts?: { compress: boolean }) => { return Promise.all( - ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( + ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( async (os) => { return getInternalArtifactMock(os, 'v1', opts); } @@ -25,7 +25,7 @@ export const getMockArtifacts = async (opts?: { compress: boolean }) => { export const getMockArtifactsWithDiff = async (opts?: { compress: boolean }) => { return Promise.all( - ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( + ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( async (os) => { if (os === 'linux') { return getInternalArtifactMockWithDiffs(os, 'v1'); @@ -38,7 +38,7 @@ export const getMockArtifactsWithDiff = async (opts?: { compress: boolean }) => export const getEmptyMockArtifacts = async (opts?: { compress: boolean }) => { return Promise.all( - ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( + ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map>( async (os) => { return getEmptyInternalArtifactMock(os, 'v1', opts); } diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/task.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/task.ts index fec9434dd8532..ba164059866ea 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/task.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/task.ts @@ -12,7 +12,7 @@ import { } from '../../../../../task_manager/server'; import { EndpointAppContext } from '../../types'; import { reportErrors, ManifestConstants } from './common'; -import { InternalArtifactSchema } from '../../schemas/artifacts'; +import { InternalArtifactCompleteSchema } from '../../schemas/artifacts'; export const ManifestTaskConstants = { TIMEOUT: '1m', @@ -119,7 +119,7 @@ export class ManifestTask { // Persist new artifacts const artifacts = adds .map((artifactId) => newManifest.getArtifact(artifactId)) - .filter((artifact) => artifact !== undefined) as InternalArtifactSchema[]; + .filter((artifact): artifact is InternalArtifactCompleteSchema => artifact !== undefined); if (artifacts.length !== adds.length) { throw new Error('Invalid artifact encountered.'); } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index fde786f5622cc..ff331f7d017f4 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -7,7 +7,12 @@ import { inflateSync } from 'zlib'; import { savedObjectsClientMock } from 'src/core/server/mocks'; import { createPackageConfigServiceMock } from '../../../../../../ingest_manager/server/mocks'; -import { ArtifactConstants, ManifestConstants, ExceptionsCache } from '../../../lib/artifacts'; +import { + ArtifactConstants, + ManifestConstants, + ExceptionsCache, + isCompleteArtifact, +} from '../../../lib/artifacts'; import { getManifestManagerMock } from './manifest_manager.mock'; describe('manifest_manager', () => { @@ -61,7 +66,13 @@ describe('manifest_manager', () => { const newArtifactId = diffs[1].id; await newManifest.compressArtifact(newArtifactId); - await manifestManager.pushArtifacts([newManifest.getArtifact(newArtifactId)!]); // caches the artifact + const artifact = newManifest.getArtifact(newArtifactId)!; + + if (isCompleteArtifact(artifact)) { + await manifestManager.pushArtifacts([artifact]); // caches the artifact + } else { + throw new Error('Artifact is missing a body.'); + } const entry = JSON.parse(inflateSync(cache.get(newArtifactId)! as Buffer).toString()); expect(entry).toEqual({ @@ -205,7 +216,14 @@ describe('manifest_manager', () => { const oldArtifactId = diffs[0].id; const newArtifactId = diffs[1].id; await newManifest.compressArtifact(newArtifactId); - await manifestManager.pushArtifacts([newManifest.getArtifact(newArtifactId)!]); + + const artifact = newManifest.getArtifact(newArtifactId)!; + if (isCompleteArtifact(artifact)) { + await manifestManager.pushArtifacts([artifact]); + } else { + throw new Error('Artifact is missing a body.'); + } + await manifestManager.commit(newManifest); await manifestManager.deleteArtifacts([oldArtifactId]); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts index 9c6f1b93ae00c..2501f07cb26e0 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts @@ -21,7 +21,6 @@ import { getArtifactId, } from '../../../lib/artifacts'; import { - InternalArtifactSchema, InternalArtifactCompleteSchema, internalArtifactCompleteSchema, } from '../../../schemas/artifacts'; @@ -78,25 +77,24 @@ export class ManifestManager { * state of exception-list-agnostic SOs. * * @param schemaVersion The schema version of the artifact - * @returns {Promise} An array of uncompressed artifacts built from exception-list-agnostic SOs. + * @returns {Promise} An array of uncompressed artifacts built from exception-list-agnostic SOs. * @throws Throws/rejects if there are errors building the list. */ protected async buildExceptionListArtifacts( schemaVersion: string - ): Promise { - return ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.reduce>( - async (acc, os) => { - const exceptionList = await getFullEndpointExceptionList( - this.exceptionListClient, - os, - schemaVersion - ); - const artifacts = await acc; - const artifact = await buildArtifact(exceptionList, os, schemaVersion); - return Promise.resolve([...artifacts, artifact]); - }, - Promise.resolve([]) - ); + ): Promise { + return ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.reduce< + Promise + >(async (acc, os) => { + const exceptionList = await getFullEndpointExceptionList( + this.exceptionListClient, + os, + schemaVersion + ); + const artifacts = await acc; + const artifact = await buildArtifact(exceptionList, os, schemaVersion); + return Promise.resolve([...artifacts, artifact]); + }, Promise.resolve([])); } /** @@ -130,7 +128,7 @@ export class ManifestManager { * @param artifacts An InternalArtifactCompleteSchema array representing the artifacts. * @returns {Promise} Any errors encountered. */ - public async pushArtifacts(artifacts: InternalArtifactSchema[]): Promise { + public async pushArtifacts(artifacts: InternalArtifactCompleteSchema[]): Promise { const errors: Error[] = []; for (const artifact of artifacts) { if (internalArtifactCompleteSchema.is(artifact)) {