Skip to content

Commit

Permalink
use translations for csv parsing errors
Browse files Browse the repository at this point in the history
  • Loading branch information
hop-dev committed Apr 9, 2024
1 parent 007bd8c commit 5ee0498
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,87 +9,93 @@ import { parseAssetCriticalityCsvRow } from './parse_asset_criticality_csv_row';

describe('parseAssetCriticalityCsvRow', () => {
it('should return valid false if the row has no columns', () => {
expect(parseAssetCriticalityCsvRow([])).toEqual({
valid: false,
error: 'Expected 3 columns got 0',
});
const result = parseAssetCriticalityCsvRow([]);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Expected 3 columns, got 0"`);
});

it('should return valid false if the row has 2 columns', () => {
expect(parseAssetCriticalityCsvRow(['host', 'host-1'])).toEqual({
valid: false,
error: 'Expected 3 columns got 2',
});
const result = parseAssetCriticalityCsvRow(['host', 'host-1']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Expected 3 columns, got 2"`);
});

it('should return valid false if the row has 4 columns', () => {
expect(parseAssetCriticalityCsvRow(['host', 'host-1', 'low_impact', 'extra_data'])).toEqual({
valid: false,
error: 'Expected 3 columns got 4',
});
const result = parseAssetCriticalityCsvRow(['host', 'host-1', 'low_impact', 'extra']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Expected 3 columns, got 4"`);
});

it('should return valid false if the entity type is missing', () => {
expect(parseAssetCriticalityCsvRow(['', 'host-1', 'low_impact'])).toEqual({
valid: false,
error: 'Missing entity type',
});
const result = parseAssetCriticalityCsvRow(['', 'host-1', 'low_impact']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Missing entity type"`);
});

it('should return valid false if the entity type is invalid', () => {
expect(parseAssetCriticalityCsvRow(['invalid', 'host-1', 'low_impact'])).toEqual({
valid: false,
error: 'Invalid entity type invalid expected host or user',
});
const result = parseAssetCriticalityCsvRow(['invalid', 'host-1', 'low_impact']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(
`"Invalid entity type \\"invalid\\", expected host or user"`
);
});

it('should return valid false if the entity type is invalid and only log 1000 characters', () => {
const invalidEntityType = 'x'.repeat(1001);
expect(parseAssetCriticalityCsvRow([invalidEntityType, 'host-1', 'low_impact'])).toEqual({
valid: false,
error: `Invalid entity type ${invalidEntityType.substring(0, 1000)}... expected host or user`,
});
const result = parseAssetCriticalityCsvRow([invalidEntityType, 'host-1', 'low_impact']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(
`"Invalid entity type \\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...\\", expected host or user"`
);
});

it('should return valid false if the ID is missing', () => {
expect(parseAssetCriticalityCsvRow(['host', '', 'low_impact'])).toEqual({
valid: false,
error: 'Missing ID',
});
const result = parseAssetCriticalityCsvRow(['host', '', 'low_impact']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Missing ID"`);
});

it('should return valid false if the criticality level is missing', () => {
expect(parseAssetCriticalityCsvRow(['host', 'host-1', ''])).toEqual({
valid: false,
error: 'Missing criticality level',
});
const result = parseAssetCriticalityCsvRow(['host', 'host-1', '']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(`"Missing criticality level"`);
});

it('should return valid false if the criticality level is invalid', () => {
expect(parseAssetCriticalityCsvRow(['host', 'host-1', 'invalid'])).toEqual({
valid: false,
error:
'Invalid criticality level invalid expected one of extreme_impact, high_impact, medium_impact, low_impact',
});
const result = parseAssetCriticalityCsvRow(['host', 'host-1', 'invalid']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(
`"Invalid criticality level \\"invalid\\", expected one of extreme_impact, high_impact, medium_impact, low_impact"`
);
});

it('should return valid false if the criticality level is invalid and only log 1000 characters', () => {
const invalidCriticalityLevel = 'x'.repeat(1001);
expect(parseAssetCriticalityCsvRow(['host', 'host-1', invalidCriticalityLevel])).toEqual({
valid: false,
error: `Invalid criticality level ${invalidCriticalityLevel.substring(
0,
1000
)}... expected one of extreme_impact, high_impact, medium_impact, low_impact`,
});
const result = parseAssetCriticalityCsvRow(['host', 'host-1', invalidCriticalityLevel]);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(
`"Invalid criticality level \\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...\\", expected one of extreme_impact, high_impact, medium_impact, low_impact"`
);
});

it('should return valid false if the ID is too long', () => {
const idValue = 'x'.repeat(1001);
expect(parseAssetCriticalityCsvRow(['host', idValue, 'low_impact'])).toEqual({
valid: false,
error: `ID is too long, expected less than 1000 characters got ${idValue.length}`,
});
const result = parseAssetCriticalityCsvRow(['host', idValue, 'low_impact']);
expect(result.valid).toBe(false);

expect(result.error).toMatchInlineSnapshot(
`"ID is too long, expected less than 1000 characters, got 1001"`
);
});

it('should return the parsed row', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { CriticalityLevels } from './constants';
import { ValidCriticalityLevels } from './constants';
import type { AssetCriticalityUpsert, CriticalityLevel } from './types';
Expand Down Expand Up @@ -31,45 +32,99 @@ const trimColumn = (column: string): string => {

export const parseAssetCriticalityCsvRow = (row: string[]): ReturnType => {
if (row.length !== 3) {
return { valid: false, error: `Expected 3 columns got ${row.length}` };
return {
valid: false,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.expectedColumnsError',
{
defaultMessage: 'Expected 3 columns, got {rowLength}',
values: { rowLength: row.length },
}
),
};
}

const [entityType, idValue, criticalityLevel] = row;

if (!entityType) {
return { valid: false, error: 'Missing entity type' };
return {
valid: false,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.missingEntityTypeError',
{
defaultMessage: 'Missing entity type',
}
),
};
}

if (!idValue) {
return { valid: false, error: 'Missing ID' };
return {
valid: false,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.missingIdError',
{
defaultMessage: 'Missing ID',
}
),
};
}

if (idValue.length > MAX_COLUMN_CHARS) {
return {
valid: false,
error: `ID is too long, expected less than ${MAX_COLUMN_CHARS} characters got ${idValue.length}`,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.idTooLongError',
{
defaultMessage:
'ID is too long, expected less than {maxChars} characters, got {idLength}',
values: { maxChars: MAX_COLUMN_CHARS, idLength: idValue.length },
}
),
};
}

if (!criticalityLevel) {
return { valid: false, error: 'Missing criticality level' };
return {
valid: false,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.missingCriticalityError',
{
defaultMessage: 'Missing criticality level',
}
),
};
}

const lowerCaseCriticalityLevel = criticalityLevel.toLowerCase();

if (!isValidCriticalityLevel(lowerCaseCriticalityLevel)) {
return {
valid: false,
error: `Invalid criticality level ${trimColumn(
criticalityLevel
)} expected one of ${ValidCriticalityLevels.join(', ')}`,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.invalidCriticalityError',
{
defaultMessage:
'Invalid criticality level "{criticalityLevel}", expected one of {validLevels}',
values: {
criticalityLevel: trimColumn(criticalityLevel),
validLevels: ValidCriticalityLevels.join(', '),
},
}
),
};
}

if (entityType !== 'host' && entityType !== 'user') {
return {
valid: false,
error: `Invalid entity type ${trimColumn(entityType)} expected host or user`,
error: i18n.translate(
'xpack.securitySolution.api.assetCriticality.csvUpload.invalidEntityTypeError',
{
defaultMessage: 'Invalid entity type "{entityType}", expected host or user',
values: { entityType: trimColumn(entityType) },
}
),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ export default ({ getService }: FtrProviderContext) => {
{
index: 0,
message:
'Invalid criticality level invalid_criticality expected one of extreme_impact, high_impact, medium_impact, low_impact',
'Invalid criticality level "invalid_criticality", expected one of extreme_impact, high_impact, medium_impact, low_impact',
},
{
index: 1,
message: 'Invalid entity type invalid_entity expected host or user',
message: 'Invalid entity type "invalid_entity", expected host or user',
},
{
index: 2,
Expand All @@ -136,15 +136,15 @@ export default ({ getService }: FtrProviderContext) => {
},
{
index: 5,
message: 'Expected 3 columns got 2',
message: 'Expected 3 columns, got 2',
},
{
index: 6,
message: 'Expected 3 columns got 4',
message: 'Expected 3 columns, got 4',
},
{
index: 7,
message: `ID is too long, expected less than 1000 characters got 1001`,
message: `ID is too long, expected less than 1000 characters, got 1001`,
},
]);
});
Expand All @@ -169,7 +169,7 @@ export default ({ getService }: FtrProviderContext) => {
{
index: 1,
message:
'Invalid criticality level invalid_criticality expected one of extreme_impact, high_impact, medium_impact, low_impact',
'Invalid criticality level "invalid_criticality", expected one of extreme_impact, high_impact, medium_impact, low_impact',
},
]);

Expand Down

0 comments on commit 5ee0498

Please sign in to comment.