Skip to content

Commit

Permalink
feat: restructure validator
Browse files Browse the repository at this point in the history
  • Loading branch information
WitoDelnat committed Sep 7, 2023
1 parent 7a37375 commit c4659f4
Show file tree
Hide file tree
Showing 41 changed files with 537 additions and 643 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 29 additions & 57 deletions packages/validation/src/MonokleValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,36 @@ import difference from 'lodash/difference.js';
import isEqual from 'lodash/isEqual.js';
import {ResourceParser} from './common/resourceParser.js';
import type {Suppression, Tool, ValidationResponse, ValidationResult, ValidationRun} from './common/sarif.js';
import type {CustomSchema, Incremental, Plugin, Resource} from './common/types.js';
import type {CustomSchema, Plugin, Resource} from './common/types.js';
import {Config} from './config/parse.js';
import {CIS_TAXONOMY} from './taxonomies/cis.js';
import {NSA_TAXONOMY} from './taxonomies/nsa.js';
import {PluginMetadataWithConfig, PluginName, RuleMetadataWithConfig, Validator} from './types.js';
import {CIS_TAXONOMY, NSA_TAXONOMY} from './taxonomies';
import {PluginMetadataWithConfig, PluginName, RuleMetadataWithConfig, ValidateParams, Validator} from './types.js';
import {nextTick, throwIfAborted} from './utils/abort.js';
import {extractSchema, findDefaultVersion} from './utils/customResourceDefinitions.js';
import {PluginLoadError} from './utils/error.js';
import invariant from './utils/invariant.js';
import {isDefined} from './utils/isDefined.js';
import {AnnotationSuppressor, FingerprintSuppressor, Suppressor} from './sarif/suppressions/index.js';
import {Fixer, Suppressor} from './sarif';
import {SuppressEngine} from './sarif/suppressions/engine.js';
import {Fixer} from './sarif/fix/index.js';
import {SchemaLoader} from './validators/kubernetes-schema/schemaLoader.js';
import {SchemaLoader} from './validators';
import {PluginLoader} from './pluginLoaders/PluginLoader.js';
import {ValidationConfig} from '@monokle/types';
import {noop} from "lodash";
import {PluginContext} from "./pluginLoaders/types";

export type PluginLoader = (name: string, settings?: Record<string, any>) => Promise<Plugin>;
export type CustomPluginLoader = (name: string, parser: ResourceParser, fixer?: Fixer) => Promise<Plugin>;

type MonokleInit = {
export type ValidatorInit = {
loader: PluginLoader;
parser?: ResourceParser;
suppressors?: Suppressor[];
fixer?: Fixer;
schemaLoader?: SchemaLoader;
};

export function createMonokleValidator(init: MonokleInit) {
return new MonokleValidator(init);
}

const DEFAULT_SUPPRESSORS = [new AnnotationSuppressor(), new FingerprintSuppressor()];

type ValidateParams = {
/**
* The resources that will be validated.
*/
resources: Resource[];

/**
* The list of resources that recently got updated.
*
* @remarks Validators can use this information to skip non-modified resources.
*/
incremental?: Incremental;

/**
* A previous run which acts as the baseline for detected problems.
*
* @remark Providing a baseline will set run.baselineGuid and result.baselineStatus.
* @remark Newly fixed problems will be added as 'absent' results.
* When using baseline, it is important to properly filter or
* indicate absent results or they appear as false positives.
*/
baseline?: ValidationResponse;

/**
* A signal that can be used to abort processing.
*/
abortSignal?: AbortSignal;
parser: ResourceParser;
suppressors: Suppressor[];
fixer: Fixer;
schemaLoader: SchemaLoader;
};

export class MonokleValidator implements Validator {
_config: Config = {};
_abortController: AbortController = new AbortController();
_loading?: Promise<void>;
_pluginContext: PluginContext;
_loader: PluginLoader;
_previousPluginsInit?: Record<string, boolean>;
_plugins: Plugin[] = [];
Expand All @@ -77,9 +42,15 @@ export class MonokleValidator implements Validator {
_suppressions: Suppression[] = [];
private _suppressor: SuppressEngine;

constructor(init: MonokleInit) {
constructor(init: ValidatorInit, config?: ValidationConfig) {
this._loader = init.loader;
this._suppressor = new SuppressEngine(init.suppressors ?? DEFAULT_SUPPRESSORS);
this._pluginContext = {
parser: init.parser,
fixer: init.fixer,
schemaLoader: init.schemaLoader,
}
this._suppressor = new SuppressEngine(init.suppressors ?? []);
if (config) this.preload(config).catch(noop);
}

get config(): Config {
Expand Down Expand Up @@ -133,16 +104,17 @@ export class MonokleValidator implements Validator {
* Eagerly load and configure the validation plugins.
*
* @param config - the new configuration of the validator.
* @param suppressions - a list with suppression requests.
*/
async preload(config: Config): Promise<void> {
async preload(config: Config, suppressions?: Suppression[]): Promise<void> {
this._config = config;
this._suppressions = suppressions || [];
return this.load();
}

/**
* Load the plugin and prepare it.
* Afterwards plugin and rule metadata are available.
* Afterward plugin and rule metadata are available.
*
* @see config.plugins
*/
Expand Down Expand Up @@ -181,8 +153,7 @@ export class MonokleValidator implements Validator {
const loading = await Promise.allSettled(
missingPlugins.map(async p => {
try {
const validator = await this._loader(p, config.settings?.[p]);
return validator;
return await this._loader.load(p, this._pluginContext, config.settings?.[p]);
} catch (err) {
const msg = err instanceof Error ? err.message : 'reason unknown';
throw new PluginLoadError(p, msg);
Expand Down Expand Up @@ -223,6 +194,7 @@ export class MonokleValidator implements Validator {
settings: config.settings,
})
),
this._suppressor.preload(this._suppressions),
]);
}

Expand Down Expand Up @@ -435,7 +407,7 @@ export class MonokleValidator implements Validator {
}

/**
* Unloads the Monokle Validator so it can be used as new.
* Unloads the Monokle Validator, so it can be used as new.
*/
async unload(): Promise<void> {
this.cancelLoad('unload');
Expand Down
31 changes: 24 additions & 7 deletions packages/validation/src/__tests__/MonokleConfiguration.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import {expect, it} from 'vitest';
import {processRefs, ResourceParser, createDefaultMonokleValidator} from '../index.js';
import {processRefs, ResourceParser, DisabledFixer, SchemaLoader, MonokleValidator} from '../index.js';

// Usage note: This library relies on fetch being on global scope!
import 'isomorphic-fetch';
import {BAD_DEPLOYMENT, BAD_SERVICE, RESOURCES} from './badResources.js';
import {DefaultPluginLoader} from '../pluginLoaders/PluginLoader.js';

it('should work with monokle.validation.yaml', async () => {
// Step 1: Create the validator
const parser = new ResourceParser();
const validator = createDefaultMonokleValidator(parser);
const validator = createTestValidator(parser);

// Step 2: Configure validator with monokle.validation.yaml
await validator.preload({
// Responsible for validator construction
plugins: {
'open-policy-agent': true,
'yaml-syntax': true,
labels: false,
'kubernetes-schema': false,
'resource-links': false,
},
Expand Down Expand Up @@ -49,13 +49,12 @@ it('should work with monokle.validation.yaml', async () => {

it('should handle race conditions', async () => {
for (let i = 0; i < 3; i++) {
const validator = createDefaultMonokleValidator();
const validator = createTestValidator();

validator.preload({
plugins: {
'open-policy-agent': true,
'yaml-syntax': true,
labels: true,
'kubernetes-schema': true,
'resource-links': true,
},
Expand All @@ -69,7 +68,6 @@ it('should handle race conditions', async () => {
plugins: {
'open-policy-agent': false,
'yaml-syntax': true,
labels: false,
'kubernetes-schema': false,
'resource-links': false,
},
Expand All @@ -84,7 +82,6 @@ it('should handle race conditions', async () => {
plugins: {
'open-policy-agent': true,
'yaml-syntax': false,
labels: false,
'kubernetes-schema': false,
'resource-links': false,
},
Expand Down Expand Up @@ -112,3 +109,23 @@ it('should handle race conditions', async () => {
expect(hasErrors).toMatchInlineSnapshot('11');
}
});

function createTestValidator(parser?: ResourceParser) {
return new MonokleValidator(
{
parser: parser ?? new ResourceParser(),
schemaLoader: new SchemaLoader(),
loader: new DefaultPluginLoader(),
suppressors: [],
fixer: new DisabledFixer(),
},
{
plugins: {
'kubernetes-schema': true,
'yaml-syntax': true,
'pod-security-standards': true,
'resource-links': true,
},
}
);
}
73 changes: 0 additions & 73 deletions packages/validation/src/__tests__/MonokleCustom.test.ts

This file was deleted.

Loading

0 comments on commit c4659f4

Please sign in to comment.