mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security solution][Endpoint] Removes zip compression when creating artifacts (#101379)
* Removes zlib compression when creating artifacts. Also fixes related unit tests and removes old code * Replaces artifact in new manifest using the ones from fleet client with zlip compression * Fixes create_policy_artifact_manifest pushArtifacts missing new manifest. Also fixes unit tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
06aaa529d4
commit
ec2ec6ab40
17 changed files with 158 additions and 193 deletions
|
@ -15,6 +15,7 @@ export type CompressionAlgorithm = t.TypeOf<typeof compressionAlgorithm>;
|
|||
|
||||
export const compressionAlgorithmDispatch = t.keyof({
|
||||
zlib: null,
|
||||
none: null,
|
||||
});
|
||||
export type CompressionAlgorithmDispatch = t.TypeOf<typeof compressionAlgorithmDispatch>;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import { createHash } from 'crypto';
|
||||
import { deflate } from 'zlib';
|
||||
import type {
|
||||
Entry,
|
||||
EntryNested,
|
||||
|
@ -21,9 +20,7 @@ import {
|
|||
} from '@kbn/securitysolution-list-constants';
|
||||
import { ExceptionListClient } from '../../../../../lists/server';
|
||||
import {
|
||||
internalArtifactCompleteSchema,
|
||||
InternalArtifactCompleteSchema,
|
||||
InternalArtifactSchema,
|
||||
TranslatedEntry,
|
||||
translatedEntry as translatedEntryType,
|
||||
translatedEntryMatchAnyMatcher,
|
||||
|
@ -60,28 +57,6 @@ export async function buildArtifact(
|
|||
};
|
||||
}
|
||||
|
||||
export async function maybeCompressArtifact(
|
||||
uncompressedArtifact: InternalArtifactSchema
|
||||
): Promise<InternalArtifactSchema> {
|
||||
const compressedArtifact = { ...uncompressedArtifact };
|
||||
if (internalArtifactCompleteSchema.is(uncompressedArtifact)) {
|
||||
const compressedArtifactBody = await compressExceptionList(
|
||||
Buffer.from(uncompressedArtifact.body, 'base64')
|
||||
);
|
||||
compressedArtifact.body = compressedArtifactBody.toString('base64');
|
||||
compressedArtifact.encodedSize = compressedArtifactBody.byteLength;
|
||||
compressedArtifact.compressionAlgorithm = 'zlib';
|
||||
compressedArtifact.encodedSha256 = createHash('sha256')
|
||||
.update(compressedArtifactBody)
|
||||
.digest('hex');
|
||||
}
|
||||
return compressedArtifact;
|
||||
}
|
||||
|
||||
export function isCompressed(artifact: InternalArtifactSchema) {
|
||||
return artifact.compressionAlgorithm === 'zlib';
|
||||
}
|
||||
|
||||
export async function getFilteredEndpointExceptionList(
|
||||
eClient: ExceptionListClient,
|
||||
schemaVersion: string,
|
||||
|
@ -297,15 +272,3 @@ function translateEntry(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function compressExceptionList(buffer: Buffer): Promise<Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
deflate(buffer, function (err, buf) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(buf);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ describe('manifest', () => {
|
|||
let ARTIFACT_COPY_TRUSTED_APPS_WINDOWS: InternalArtifactCompleteSchema;
|
||||
|
||||
beforeAll(async () => {
|
||||
ARTIFACTS = await getMockArtifacts({ compress: true });
|
||||
ARTIFACTS_COPY = await getMockArtifacts({ compress: true });
|
||||
ARTIFACTS = await getMockArtifacts();
|
||||
ARTIFACTS_COPY = await getMockArtifacts();
|
||||
ARTIFACT_EXCEPTIONS_MACOS = ARTIFACTS[0];
|
||||
ARTIFACT_EXCEPTIONS_WINDOWS = ARTIFACTS[1];
|
||||
ARTIFACT_EXCEPTIONS_LINUX = ARTIFACTS[2];
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
InternalArtifactSchema,
|
||||
InternalManifestSchema,
|
||||
InternalManifestEntrySchema,
|
||||
InternalArtifactCompleteSchema,
|
||||
} from '../../schemas/artifacts';
|
||||
import {
|
||||
ManifestSchemaVersion,
|
||||
|
@ -139,6 +140,27 @@ export class Manifest {
|
|||
return this.allEntries.get(getArtifactId(artifact))?.specificTargetPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an artifact from all the collections.
|
||||
*
|
||||
* @param artifact An InternalArtifactCompleteSchema representing the artifact.
|
||||
*/
|
||||
public replaceArtifact(artifact: InternalArtifactCompleteSchema) {
|
||||
const existingEntry = this.allEntries.get(getArtifactId(artifact));
|
||||
if (existingEntry) {
|
||||
existingEntry.entry = new ManifestEntry(artifact);
|
||||
|
||||
this.allEntries.set(getArtifactId(artifact), existingEntry);
|
||||
this.defaultEntries.set(getArtifactId(artifact), existingEntry.entry);
|
||||
|
||||
existingEntry.specificTargetPolicies.forEach((policyId) => {
|
||||
const entries = this.policySpecificEntries.get(policyId) || new Map();
|
||||
entries.set(existingEntry.entry.getDocId(), existingEntry.entry);
|
||||
this.policySpecificEntries.set(policyId, entries);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public diff(manifest: Manifest): ManifestDiff {
|
||||
const diff: ManifestDiff = {
|
||||
additions: [],
|
||||
|
|
|
@ -15,7 +15,7 @@ describe('manifest_entry', () => {
|
|||
let manifestEntry: ManifestEntry;
|
||||
|
||||
beforeAll(async () => {
|
||||
artifact = await getInternalArtifactMock('windows', 'v1', { compress: true });
|
||||
artifact = await getInternalArtifactMock('windows', 'v1');
|
||||
manifestEntry = new ManifestEntry(artifact);
|
||||
});
|
||||
|
||||
|
@ -35,7 +35,7 @@ describe('manifest_entry', () => {
|
|||
|
||||
test('Correct sha256 is returned', () => {
|
||||
expect(manifestEntry.getEncodedSha256()).toEqual(
|
||||
'975382ab55d019cbab0bbac207a54e2a7d489fad6e8f6de34fc6402e5ef37b1e'
|
||||
'96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3'
|
||||
);
|
||||
expect(manifestEntry.getDecodedSha256()).toEqual(
|
||||
'96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3'
|
||||
|
@ -43,7 +43,7 @@ describe('manifest_entry', () => {
|
|||
});
|
||||
|
||||
test('Correct size is returned', () => {
|
||||
expect(manifestEntry.getEncodedSize()).toEqual(147);
|
||||
expect(manifestEntry.getEncodedSize()).toEqual(432);
|
||||
expect(manifestEntry.getDecodedSize()).toEqual(432);
|
||||
});
|
||||
|
||||
|
@ -59,12 +59,12 @@ describe('manifest_entry', () => {
|
|||
|
||||
test('Correct record is returned', () => {
|
||||
expect(manifestEntry.getRecord()).toEqual({
|
||||
compression_algorithm: 'zlib',
|
||||
compression_algorithm: 'none',
|
||||
encryption_algorithm: 'none',
|
||||
decoded_sha256: '96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3',
|
||||
encoded_sha256: '975382ab55d019cbab0bbac207a54e2a7d489fad6e8f6de34fc6402e5ef37b1e',
|
||||
encoded_sha256: '96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3',
|
||||
decoded_size: 432,
|
||||
encoded_size: 147,
|
||||
encoded_size: 432,
|
||||
relative_url:
|
||||
'/api/fleet/artifacts/endpoint-exceptionlist-windows-v1/96b76a1a911662053a1562ac14c4ff1e87c2ff550d6fe52e1e0b3790526597d3',
|
||||
});
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('When migrating artifacts to fleet', () => {
|
|||
type: '',
|
||||
id: 'abc123',
|
||||
references: [],
|
||||
attributes: await getInternalArtifactMock('windows', 'v1', { compress: true }),
|
||||
attributes: await getInternalArtifactMock('windows', 'v1'),
|
||||
},
|
||||
])
|
||||
);
|
||||
|
|
|
@ -17,49 +17,49 @@ import {
|
|||
import { ArtifactConstants } from './common';
|
||||
import { Manifest } from './manifest';
|
||||
|
||||
export const getMockArtifacts = async (opts?: { compress: boolean }) => {
|
||||
export const getMockArtifacts = async () => {
|
||||
return Promise.all([
|
||||
// Exceptions items
|
||||
...ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map<Promise<InternalArtifactCompleteSchema>>(
|
||||
async (os) => {
|
||||
return getInternalArtifactMock(os, 'v1', opts);
|
||||
return getInternalArtifactMock(os, 'v1');
|
||||
}
|
||||
),
|
||||
// Trusted Apps items
|
||||
...ArtifactConstants.SUPPORTED_TRUSTED_APPS_OPERATING_SYSTEMS.map<
|
||||
Promise<InternalArtifactCompleteSchema>
|
||||
>(async (os) => {
|
||||
return getInternalArtifactMock(os, 'v1', opts, ArtifactConstants.GLOBAL_TRUSTED_APPS_NAME);
|
||||
return getInternalArtifactMock(os, 'v1', ArtifactConstants.GLOBAL_TRUSTED_APPS_NAME);
|
||||
}),
|
||||
]);
|
||||
};
|
||||
|
||||
export const getMockArtifactsWithDiff = async (opts?: { compress: boolean }) => {
|
||||
export const getMockArtifactsWithDiff = async () => {
|
||||
return Promise.all(
|
||||
ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map<Promise<InternalArtifactCompleteSchema>>(
|
||||
async (os) => {
|
||||
if (os === 'macos') {
|
||||
return getInternalArtifactMockWithDiffs(os, 'v1');
|
||||
}
|
||||
return getInternalArtifactMock(os, 'v1', opts);
|
||||
return getInternalArtifactMock(os, 'v1');
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getEmptyMockArtifacts = async (opts?: { compress: boolean }) => {
|
||||
export const getEmptyMockArtifacts = async () => {
|
||||
return Promise.all(
|
||||
ArtifactConstants.SUPPORTED_OPERATING_SYSTEMS.map<Promise<InternalArtifactCompleteSchema>>(
|
||||
async (os) => {
|
||||
return getEmptyInternalArtifactMock(os, 'v1', opts);
|
||||
return getEmptyInternalArtifactMock(os, 'v1');
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getMockManifest = async (opts?: { compress: boolean }) => {
|
||||
export const getMockManifest = async () => {
|
||||
const manifest = new Manifest();
|
||||
const artifacts = await getMockArtifacts(opts);
|
||||
const artifacts = await getMockArtifacts();
|
||||
artifacts.forEach((artifact) => manifest.addEntry(artifact));
|
||||
return manifest;
|
||||
};
|
||||
|
|
|
@ -106,7 +106,7 @@ describe('task', () => {
|
|||
let ARTIFACT_TRUSTED_APPS_MACOS: InternalArtifactCompleteSchema;
|
||||
|
||||
beforeAll(async () => {
|
||||
const artifacts = await getMockArtifacts({ compress: true });
|
||||
const artifacts = await getMockArtifacts();
|
||||
ARTIFACT_EXCEPTIONS_MACOS = artifacts[0];
|
||||
ARTIFACT_EXCEPTIONS_WINDOWS = artifacts[1];
|
||||
ARTIFACT_TRUSTED_APPS_MACOS = artifacts[2];
|
||||
|
@ -167,7 +167,7 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([], newManifest);
|
||||
expect(manifestManager.commit).not.toHaveBeenCalled();
|
||||
expect(manifestManager.tryDispatch).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.deleteArtifacts).toHaveBeenCalledWith([]);
|
||||
|
@ -192,10 +192,10 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_TRUSTED_APPS_MACOS,
|
||||
]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_TRUSTED_APPS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).not.toHaveBeenCalled();
|
||||
expect(manifestManager.tryDispatch).not.toHaveBeenCalled();
|
||||
expect(manifestManager.deleteArtifacts).not.toHaveBeenCalled();
|
||||
|
@ -221,10 +221,10 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_TRUSTED_APPS_MACOS,
|
||||
]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_TRUSTED_APPS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.tryDispatch).not.toHaveBeenCalled();
|
||||
expect(manifestManager.deleteArtifacts).not.toHaveBeenCalled();
|
||||
|
@ -251,10 +251,10 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_TRUSTED_APPS_MACOS,
|
||||
]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_TRUSTED_APPS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.tryDispatch).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.deleteArtifacts).not.toHaveBeenCalled();
|
||||
|
@ -284,7 +284,10 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([ARTIFACT_TRUSTED_APPS_MACOS]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_TRUSTED_APPS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.tryDispatch).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.deleteArtifacts).toHaveBeenCalledWith([ARTIFACT_ID_1]);
|
||||
|
@ -314,7 +317,7 @@ describe('task', () => {
|
|||
|
||||
expect(manifestManager.getLastComputedManifest).toHaveBeenCalled();
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith(lastManifest);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([], newManifest);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.tryDispatch).toHaveBeenCalledWith(newManifest);
|
||||
expect(manifestManager.deleteArtifacts).toHaveBeenCalledWith([]);
|
||||
|
|
|
@ -130,7 +130,8 @@ export class ManifestTask {
|
|||
const diff = newManifest.diff(oldManifest);
|
||||
|
||||
const persistErrors = await manifestManager.pushArtifacts(
|
||||
diff.additions as InternalArtifactCompleteSchema[]
|
||||
diff.additions as InternalArtifactCompleteSchema[],
|
||||
newManifest
|
||||
);
|
||||
if (persistErrors.length) {
|
||||
reportErrors(this.logger, persistErrors);
|
||||
|
|
|
@ -5,33 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
buildArtifact,
|
||||
maybeCompressArtifact,
|
||||
isCompressed,
|
||||
ArtifactConstants,
|
||||
} from '../../lib/artifacts';
|
||||
import { buildArtifact, ArtifactConstants } from '../../lib/artifacts';
|
||||
import { getTranslatedExceptionListMock } from './lists.mock';
|
||||
import {
|
||||
InternalManifestSchema,
|
||||
internalArtifactCompleteSchema,
|
||||
InternalArtifactCompleteSchema,
|
||||
} from './saved_objects';
|
||||
|
||||
const compressArtifact = async (artifact: InternalArtifactCompleteSchema) => {
|
||||
const compressedArtifact = await maybeCompressArtifact(artifact);
|
||||
if (!isCompressed(compressedArtifact)) {
|
||||
throw new Error(`Unable to compress artifact: ${artifact.identifier}`);
|
||||
} else if (!internalArtifactCompleteSchema.is(compressedArtifact)) {
|
||||
throw new Error(`Incomplete artifact detected: ${artifact.identifier}`);
|
||||
}
|
||||
return compressedArtifact;
|
||||
};
|
||||
import { InternalManifestSchema, InternalArtifactCompleteSchema } from './saved_objects';
|
||||
|
||||
export const getInternalArtifactMock = async (
|
||||
os: string,
|
||||
schemaVersion: string,
|
||||
opts?: { compress: boolean },
|
||||
artifactName: string = ArtifactConstants.GLOBAL_ALLOWLIST_NAME
|
||||
): Promise<InternalArtifactCompleteSchema> => {
|
||||
const artifact = await buildArtifact(
|
||||
|
@ -40,23 +20,21 @@ export const getInternalArtifactMock = async (
|
|||
os,
|
||||
artifactName
|
||||
);
|
||||
return opts?.compress ? compressArtifact(artifact) : artifact;
|
||||
return artifact;
|
||||
};
|
||||
|
||||
export const getEmptyInternalArtifactMock = async (
|
||||
os: string,
|
||||
schemaVersion: string,
|
||||
opts?: { compress: boolean },
|
||||
artifactName: string = ArtifactConstants.GLOBAL_ALLOWLIST_NAME
|
||||
): Promise<InternalArtifactCompleteSchema> => {
|
||||
const artifact = await buildArtifact({ entries: [] }, schemaVersion, os, artifactName);
|
||||
return opts?.compress ? compressArtifact(artifact) : artifact;
|
||||
return artifact;
|
||||
};
|
||||
|
||||
export const getInternalArtifactMockWithDiffs = async (
|
||||
os: string,
|
||||
schemaVersion: string,
|
||||
opts?: { compress: boolean }
|
||||
schemaVersion: string
|
||||
): Promise<InternalArtifactCompleteSchema> => {
|
||||
const mock = getTranslatedExceptionListMock();
|
||||
mock.entries.pop();
|
||||
|
@ -66,7 +44,7 @@ export const getInternalArtifactMockWithDiffs = async (
|
|||
os,
|
||||
ArtifactConstants.GLOBAL_ALLOWLIST_NAME
|
||||
);
|
||||
return opts?.compress ? compressArtifact(artifact) : artifact;
|
||||
return artifact;
|
||||
};
|
||||
|
||||
export const getInternalManifestMock = (): InternalManifestSchema => ({
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('artifact_client', () => {
|
|||
});
|
||||
|
||||
test('can create artifact', async () => {
|
||||
const artifact = await getInternalArtifactMock('linux', 'v1', { compress: true });
|
||||
const artifact = await getInternalArtifactMock('linux', 'v1');
|
||||
await artifactClient.createArtifact(artifact);
|
||||
expect(fleetArtifactClient.createArtifact).toHaveBeenCalledWith({
|
||||
identifier: artifact.identifier,
|
||||
|
|
|
@ -5,13 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { inflate as _inflate } from 'zlib';
|
||||
import { promisify } from 'util';
|
||||
import { InternalArtifactCompleteSchema } from '../../schemas/artifacts';
|
||||
import { Artifact, ArtifactsClientInterface } from '../../../../../fleet/server';
|
||||
|
||||
const inflateAsync = promisify(_inflate);
|
||||
|
||||
export interface EndpointArtifactClientInterface {
|
||||
getArtifact(id: string): Promise<InternalArtifactCompleteSchema | undefined>;
|
||||
|
||||
|
@ -56,12 +52,8 @@ export class EndpointArtifactClient implements EndpointArtifactClientInterface {
|
|||
async createArtifact(
|
||||
artifact: InternalArtifactCompleteSchema
|
||||
): Promise<InternalArtifactCompleteSchema> {
|
||||
// FIXME:PT refactor to make this more efficient by passing through the uncompressed artifact content
|
||||
// Artifact `.body` is compressed/encoded. We need it decoded and as a string
|
||||
const artifactContent = await inflateAsync(Buffer.from(artifact.body, 'base64'));
|
||||
|
||||
const createdArtifact = await this.fleetArtifacts.createArtifact({
|
||||
content: artifactContent.toString(),
|
||||
content: Buffer.from(artifact.body, 'base64').toString(),
|
||||
identifier: artifact.identifier,
|
||||
type: this.parseArtifactId(artifact.identifier).type,
|
||||
});
|
||||
|
|
|
@ -140,7 +140,7 @@ export const getManifestManagerMock = (
|
|||
case ManifestManagerMockType.InitialSystemState:
|
||||
return null;
|
||||
case ManifestManagerMockType.NormalFlow:
|
||||
return getMockManifest({ compress: true });
|
||||
return getMockManifest();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { inflateSync } from 'zlib';
|
||||
import { savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import {
|
||||
ENDPOINT_LIST_ID,
|
||||
|
@ -27,7 +26,6 @@ import {
|
|||
import {
|
||||
ManifestConstants,
|
||||
getArtifactId,
|
||||
isCompressed,
|
||||
translateToEndpointExceptions,
|
||||
Manifest,
|
||||
} from '../../../lib/artifacts';
|
||||
|
@ -40,10 +38,8 @@ import {
|
|||
import { ManifestManager } from './manifest_manager';
|
||||
import { EndpointArtifactClientInterface } from '../artifact_client';
|
||||
|
||||
const uncompressData = async (data: Buffer) => JSON.parse(await inflateSync(data).toString());
|
||||
|
||||
const uncompressArtifact = async (artifact: InternalArtifactSchema) =>
|
||||
uncompressData(Buffer.from(artifact.body!, 'base64'));
|
||||
const getArtifactObject = (artifact: InternalArtifactSchema) =>
|
||||
JSON.parse(Buffer.from(artifact.body!, 'base64').toString());
|
||||
|
||||
describe('ManifestManager', () => {
|
||||
const TEST_POLICY_ID_1 = 'c6d16e42-c32d-4dce-8a88-113cfe276ad1';
|
||||
|
@ -77,7 +73,7 @@ describe('ManifestManager', () => {
|
|||
let ARTIFACT_TRUSTED_APPS_WINDOWS: InternalArtifactCompleteSchema;
|
||||
|
||||
beforeAll(async () => {
|
||||
ARTIFACTS = await getMockArtifacts({ compress: true });
|
||||
ARTIFACTS = await getMockArtifacts();
|
||||
ARTIFACTS_BY_ID = {
|
||||
[ARTIFACT_ID_EXCEPTIONS_MACOS]: ARTIFACTS[0],
|
||||
[ARTIFACT_ID_EXCEPTIONS_WINDOWS]: ARTIFACTS[1],
|
||||
|
@ -270,10 +266,9 @@ describe('ManifestManager', () => {
|
|||
|
||||
expect(artifacts.length).toBe(9);
|
||||
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);
|
||||
expect(artifacts.every(isCompressed)).toBe(true);
|
||||
|
||||
for (const artifact of artifacts) {
|
||||
expect(await uncompressArtifact(artifact)).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifact)).toStrictEqual({ entries: [] });
|
||||
expect(manifest.isDefaultArtifact(artifact)).toBe(true);
|
||||
expect(manifest.getArtifactTargetPolicies(artifact)).toStrictEqual(
|
||||
new Set([TEST_POLICY_ID_1])
|
||||
|
@ -308,21 +303,20 @@ describe('ManifestManager', () => {
|
|||
|
||||
expect(artifacts.length).toBe(9);
|
||||
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);
|
||||
expect(artifacts.every(isCompressed)).toBe(true);
|
||||
|
||||
expect(await uncompressArtifact(artifacts[0])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[0])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions([exceptionListItem], 'v1'),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[5])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[5])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions([trustedAppListItem], 'v1'),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
|
||||
for (const artifact of artifacts) {
|
||||
expect(manifest.isDefaultArtifact(artifact)).toBe(true);
|
||||
|
@ -364,19 +358,18 @@ describe('ManifestManager', () => {
|
|||
|
||||
expect(artifacts.length).toBe(9);
|
||||
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);
|
||||
expect(artifacts.every(isCompressed)).toBe(true);
|
||||
|
||||
expect(artifacts[0]).toStrictEqual(oldManifest.getAllArtifacts()[0]);
|
||||
expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[5])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[5])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions([trustedAppListItem], 'v1'),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
|
||||
for (const artifact of artifacts) {
|
||||
expect(manifest.isDefaultArtifact(artifact)).toBe(true);
|
||||
|
@ -426,27 +419,26 @@ describe('ManifestManager', () => {
|
|||
|
||||
expect(artifacts.length).toBe(10);
|
||||
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);
|
||||
expect(artifacts.every(isCompressed)).toBe(true);
|
||||
|
||||
expect(await uncompressArtifact(artifacts[0])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[0])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions([exceptionListItem], 'v1'),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[5])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[1])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[2])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[3])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[4])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[5])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions([trustedAppListItem], 'v1'),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[6])).toStrictEqual({
|
||||
expect(getArtifactObject(artifacts[6])).toStrictEqual({
|
||||
entries: translateToEndpointExceptions(
|
||||
[trustedAppListItem, trustedAppListItemPolicy2],
|
||||
'v1'
|
||||
),
|
||||
});
|
||||
expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
expect(await uncompressArtifact(artifacts[9])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[8])).toStrictEqual({ entries: [] });
|
||||
expect(getArtifactObject(artifacts[9])).toStrictEqual({ entries: [] });
|
||||
|
||||
for (const artifact of artifacts.slice(0, 5)) {
|
||||
expect(manifest.isDefaultArtifact(artifact)).toBe(true);
|
||||
|
@ -520,9 +512,13 @@ describe('ManifestManager', () => {
|
|||
const context = buildManifestManagerContextMock({});
|
||||
const artifactClient = context.artifactClient as jest.Mocked<EndpointArtifactClientInterface>;
|
||||
const manifestManager = new ManifestManager(context);
|
||||
const newManifest = ManifestManager.createDefaultManifest();
|
||||
|
||||
await expect(
|
||||
manifestManager.pushArtifacts([ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_EXCEPTIONS_WINDOWS])
|
||||
manifestManager.pushArtifacts(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_EXCEPTIONS_WINDOWS],
|
||||
newManifest
|
||||
)
|
||||
).resolves.toStrictEqual([]);
|
||||
|
||||
expect(artifactClient.createArtifact).toHaveBeenCalledTimes(2);
|
||||
|
@ -533,17 +529,18 @@ describe('ManifestManager', () => {
|
|||
...ARTIFACT_EXCEPTIONS_WINDOWS,
|
||||
});
|
||||
expect(
|
||||
await uncompressData(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_MACOS))!)
|
||||
).toStrictEqual(await uncompressArtifact(ARTIFACT_EXCEPTIONS_MACOS));
|
||||
JSON.parse(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_MACOS))!.toString())
|
||||
).toStrictEqual(getArtifactObject(ARTIFACT_EXCEPTIONS_MACOS));
|
||||
expect(
|
||||
await uncompressData(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_WINDOWS))!)
|
||||
).toStrictEqual(await uncompressArtifact(ARTIFACT_EXCEPTIONS_WINDOWS));
|
||||
JSON.parse(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_WINDOWS))!.toString())
|
||||
).toStrictEqual(getArtifactObject(ARTIFACT_EXCEPTIONS_WINDOWS));
|
||||
});
|
||||
|
||||
test('Returns errors for partial failures', async () => {
|
||||
const context = buildManifestManagerContextMock({});
|
||||
const artifactClient = context.artifactClient as jest.Mocked<EndpointArtifactClientInterface>;
|
||||
const manifestManager = new ManifestManager(context);
|
||||
const newManifest = ManifestManager.createDefaultManifest();
|
||||
const error = new Error();
|
||||
const { body, ...incompleteArtifact } = ARTIFACT_TRUSTED_APPS_MACOS;
|
||||
|
||||
|
@ -558,11 +555,14 @@ describe('ManifestManager', () => {
|
|||
);
|
||||
|
||||
await expect(
|
||||
manifestManager.pushArtifacts([
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_EXCEPTIONS_WINDOWS,
|
||||
incompleteArtifact as InternalArtifactCompleteSchema,
|
||||
])
|
||||
manifestManager.pushArtifacts(
|
||||
[
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_EXCEPTIONS_WINDOWS,
|
||||
incompleteArtifact as InternalArtifactCompleteSchema,
|
||||
],
|
||||
newManifest
|
||||
)
|
||||
).resolves.toStrictEqual([
|
||||
error,
|
||||
new Error(`Incomplete artifact: ${ARTIFACT_ID_TRUSTED_APPS_MACOS}`),
|
||||
|
@ -573,8 +573,8 @@ describe('ManifestManager', () => {
|
|||
...ARTIFACT_EXCEPTIONS_MACOS,
|
||||
});
|
||||
expect(
|
||||
await uncompressData(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_MACOS))!)
|
||||
).toStrictEqual(await uncompressArtifact(ARTIFACT_EXCEPTIONS_MACOS));
|
||||
JSON.parse(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_MACOS))!.toString())
|
||||
).toStrictEqual(getArtifactObject(ARTIFACT_EXCEPTIONS_MACOS));
|
||||
expect(context.cache.get(getArtifactId(ARTIFACT_EXCEPTIONS_WINDOWS))).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
@ -843,10 +843,7 @@ describe('ManifestManager', () => {
|
|||
artifacts: toArtifactRecords({
|
||||
[ARTIFACT_NAME_EXCEPTIONS_MACOS]: await getEmptyInternalArtifactMock(
|
||||
'macos',
|
||||
'v1',
|
||||
{
|
||||
compress: true,
|
||||
}
|
||||
'v1'
|
||||
),
|
||||
}),
|
||||
manifest_version: '1.0.0',
|
||||
|
|
|
@ -25,9 +25,7 @@ import {
|
|||
getEndpointEventFiltersList,
|
||||
getEndpointExceptionList,
|
||||
getEndpointTrustedAppsList,
|
||||
isCompressed,
|
||||
Manifest,
|
||||
maybeCompressArtifact,
|
||||
} from '../../../lib/artifacts';
|
||||
import {
|
||||
InternalArtifactCompleteSchema,
|
||||
|
@ -239,13 +237,16 @@ export class ManifestManager {
|
|||
* Writes new artifact SO.
|
||||
*
|
||||
* @param artifact An InternalArtifactCompleteSchema representing the artifact.
|
||||
* @returns {Promise<Error | null>} An error, if encountered, or null.
|
||||
* @returns {Promise<[Error | null, InternalArtifactCompleteSchema | undefined]>} An array with the error if encountered or null and the generated artifact or null.
|
||||
*/
|
||||
protected async pushArtifact(artifact: InternalArtifactCompleteSchema): Promise<Error | null> {
|
||||
protected async pushArtifact(
|
||||
artifact: InternalArtifactCompleteSchema
|
||||
): Promise<[Error | null, InternalArtifactCompleteSchema | undefined]> {
|
||||
const artifactId = getArtifactId(artifact);
|
||||
let fleetArtifact;
|
||||
try {
|
||||
// Write the artifact SO
|
||||
await this.artifactClient.createArtifact(artifact);
|
||||
fleetArtifact = await this.artifactClient.createArtifact(artifact);
|
||||
|
||||
// Cache the compressed body of the artifact
|
||||
this.cache.set(artifactId, Buffer.from(artifact.body, 'base64'));
|
||||
|
@ -253,26 +254,32 @@ export class ManifestManager {
|
|||
if (this.savedObjectsClient.errors.isConflictError(err)) {
|
||||
this.logger.debug(`Tried to create artifact ${artifactId}, but it already exists.`);
|
||||
} else {
|
||||
return err;
|
||||
return [err, undefined];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return [null, fleetArtifact];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes new artifact SOs.
|
||||
*
|
||||
* @param artifacts An InternalArtifactCompleteSchema array representing the artifacts.
|
||||
* @param newManifest A Manifest representing the new manifest
|
||||
* @returns {Promise<Error[]>} Any errors encountered.
|
||||
*/
|
||||
public async pushArtifacts(artifacts: InternalArtifactCompleteSchema[]): Promise<Error[]> {
|
||||
public async pushArtifacts(
|
||||
artifacts: InternalArtifactCompleteSchema[],
|
||||
newManifest: Manifest
|
||||
): Promise<Error[]> {
|
||||
const errors: Error[] = [];
|
||||
for (const artifact of artifacts) {
|
||||
if (internalArtifactCompleteSchema.is(artifact)) {
|
||||
const err = await this.pushArtifact(artifact);
|
||||
const [err, fleetArtifact] = await this.pushArtifact(artifact);
|
||||
if (err) {
|
||||
errors.push(err);
|
||||
} else if (fleetArtifact) {
|
||||
newManifest.replaceArtifact(fleetArtifact);
|
||||
}
|
||||
} else {
|
||||
errors.push(new Error(`Incomplete artifact: ${getArtifactId(artifact)}`));
|
||||
|
@ -372,16 +379,10 @@ export class ManifestManager {
|
|||
|
||||
for (const result of results) {
|
||||
await iterateArtifactsBuildResult(result, async (artifact, policyId) => {
|
||||
let artifactToAdd = baselineManifest.getArtifact(getArtifactId(artifact)) || artifact;
|
||||
|
||||
if (!isCompressed(artifactToAdd)) {
|
||||
artifactToAdd = await maybeCompressArtifact(artifactToAdd);
|
||||
|
||||
if (!isCompressed(artifactToAdd)) {
|
||||
throw new Error(`Unable to compress artifact: ${getArtifactId(artifactToAdd)}`);
|
||||
} else if (!internalArtifactCompleteSchema.is(artifactToAdd)) {
|
||||
throw new Error(`Incomplete artifact detected: ${getArtifactId(artifactToAdd)}`);
|
||||
}
|
||||
const artifactToAdd = baselineManifest.getArtifact(getArtifactId(artifact)) || artifact;
|
||||
artifactToAdd.compressionAlgorithm = 'none';
|
||||
if (!internalArtifactCompleteSchema.is(artifactToAdd)) {
|
||||
throw new Error(`Incomplete artifact detected: ${getArtifactId(artifactToAdd)}`);
|
||||
}
|
||||
|
||||
manifest.addEntry(artifactToAdd, policyId);
|
||||
|
|
|
@ -100,7 +100,7 @@ describe('ingest_integration tests ', () => {
|
|||
let ARTIFACT_TRUSTED_APPS_WINDOWS: InternalArtifactCompleteSchema;
|
||||
|
||||
beforeAll(async () => {
|
||||
const artifacts = await getMockArtifacts({ compress: true });
|
||||
const artifacts = await getMockArtifacts();
|
||||
ARTIFACT_EXCEPTIONS_MACOS = artifacts[0];
|
||||
ARTIFACT_EXCEPTIONS_WINDOWS = artifacts[1];
|
||||
ARTIFACT_TRUSTED_APPS_MACOS = artifacts[3];
|
||||
|
@ -147,7 +147,10 @@ describe('ingest_integration tests ', () => {
|
|||
);
|
||||
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith();
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([ARTIFACT_EXCEPTIONS_MACOS]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -170,7 +173,10 @@ describe('ingest_integration tests ', () => {
|
|||
);
|
||||
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith();
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([ARTIFACT_EXCEPTIONS_MACOS]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
});
|
||||
|
||||
|
@ -197,10 +203,10 @@ describe('ingest_integration tests ', () => {
|
|||
);
|
||||
|
||||
expect(manifestManager.buildNewManifest).toHaveBeenCalledWith();
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith([
|
||||
ARTIFACT_EXCEPTIONS_MACOS,
|
||||
ARTIFACT_TRUSTED_APPS_MACOS,
|
||||
]);
|
||||
expect(manifestManager.pushArtifacts).toHaveBeenCalledWith(
|
||||
[ARTIFACT_EXCEPTIONS_MACOS, ARTIFACT_TRUSTED_APPS_MACOS],
|
||||
newManifest
|
||||
);
|
||||
expect(manifestManager.commit).toHaveBeenCalledWith(newManifest);
|
||||
});
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ const getManifest = async (logger: Logger, manifestManager: ManifestManager): Pr
|
|||
|
||||
// Persist new artifacts
|
||||
const persistErrors = await manifestManager.pushArtifacts(
|
||||
newManifest.getAllArtifacts() as InternalArtifactCompleteSchema[]
|
||||
newManifest.getAllArtifacts() as InternalArtifactCompleteSchema[],
|
||||
newManifest
|
||||
);
|
||||
if (persistErrors.length) {
|
||||
reportErrors(logger, persistErrors);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue