Skip to content

Commit

Permalink
Merge branch 'main' into extend-rule-upgrade-integration-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
maximpn authored Feb 5, 2025
2 parents 8523cbd + 5f5b6bc commit 1a3df74
Show file tree
Hide file tree
Showing 90 changed files with 2,049 additions and 1,618 deletions.
1 change: 0 additions & 1 deletion .buildkite/scripts/steps/checks/quick_checks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
.buildkite/scripts/steps/checks/packages.sh
.buildkite/scripts/steps/checks/bazel_packages.sh
.buildkite/scripts/steps/checks/verify_notice.sh
.buildkite/scripts/steps/checks/plugin_list_docs.sh
.buildkite/scripts/steps/checks/event_log.sh
.buildkite/scripts/steps/checks/telemetry.sh
.buildkite/scripts/steps/checks/jest_configs.sh
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-apm-synthtrace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Scenario files accept 3 arguments, 2 of them optional and 1 mandatory
|-------------|:----------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `generate` | mandatory | This is the main function responsible for returning the events which will be indexed |
| `bootstrap` | optional | In case some setup needs to be done, before the data is generated, this function provides access to all available ES Clients to play with |
| `setClient` | optional | By default the apmEsClient used to generate data. If anyother client like logsEsClient needs to be used instead, this is where it should be returned |
| `teardown` | optional | In case some setup needs to be done, after all data is generated, this function provides access to all available ES Clients to play with |

The following options are supported:

Expand Down
1 change: 1 addition & 0 deletions packages/kbn-apm-synthtrace/src/cli/scenario.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ type Generate<TFields> = (options: {
export type Scenario<TFields> = (options: RunOptions & { logger: Logger }) => Promise<{
bootstrap?: (options: EsClients & KibanaClients) => Promise<void>;
generate: Generate<TFields>;
teardown?: (options: EsClients & KibanaClients) => Promise<void>;
}>;
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export async function startLiveDataUpload({
} = await bootstrap(runOptions);

const scenario = await getScenario({ file, logger });
const { generate, bootstrap: scenarioBootsrap } = await scenario({ ...runOptions, logger });
const {
generate,
bootstrap: scenarioBootsrap,
teardown: scenarioTearDown,
} = await scenario({ ...runOptions, logger });

if (scenarioBootsrap) {
await scenarioBootsrap({
Expand All @@ -59,11 +63,27 @@ export async function startLiveDataUpload({
// @ts-expect-error upgrade typescript v4.9.5
const cachedStreams: WeakMap<SynthtraceEsClient, PassThrough> = new WeakMap();

process.on('SIGINT', () => closeStreams());
process.on('SIGTERM', () => closeStreams());
process.on('SIGQUIT', () => closeStreams());
process.on('SIGINT', () => closeStreamsAndTeardown());
process.on('SIGTERM', () => closeStreamsAndTeardown());
process.on('SIGQUIT', () => closeStreamsAndTeardown());

async function closeStreamsAndTeardown() {
if (scenarioTearDown) {
try {
await scenarioTearDown({
apmEsClient,
logsEsClient,
infraEsClient,
otelEsClient,
syntheticsEsClient,
entitiesEsClient,
entitiesKibanaClient,
});
} catch (error) {
logger.error('Error during scenario teardown', error);
}
}

function closeStreams() {
currentStreams.forEach((stream) => {
stream.end(() => {
process.exit(0);
Expand Down
14 changes: 13 additions & 1 deletion packages/kbn-apm-synthtrace/src/cli/utils/synthtrace_worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async function start() {

logger.info(`Running scenario from ${bucketFrom.toISOString()} to ${bucketTo.toISOString()}`);

const { generate, bootstrap } = await scenario({ ...runOptions, logger });
const { generate, bootstrap, teardown } = await scenario({ ...runOptions, logger });

if (bootstrap) {
await bootstrap({
Expand Down Expand Up @@ -142,6 +142,18 @@ async function start() {

await Promise.all(promises);
});

if (teardown) {
await teardown({
apmEsClient,
logsEsClient,
infraEsClient,
syntheticsEsClient,
otelEsClient,
entitiesEsClient,
entitiesKibanaClient,
});
}
}

parentPort!.on('message', (message) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ export class LogsSynthtraceEsClient extends SynthtraceEsClient<LogDocument> {
}
}

async deleteIndexTemplate(name: IndexTemplateName) {
try {
await this.client.indices.deleteIndexTemplate({ name });
this.logger.info(`Index template successfully deleted: ${name}`);
} catch (err) {
this.logger.error(`Index template deletion failed: ${name} - ${err.message}`);
}
}

async createComponentTemplate({
name,
mappings,
Expand Down Expand Up @@ -150,6 +159,17 @@ export class LogsSynthtraceEsClient extends SynthtraceEsClient<LogDocument> {
}
}

async deleteCustomPipeline(id = LogsCustom) {
try {
this.client.ingest.deletePipeline({
id,
});
this.logger.info(`Custom pipeline deleted: ${id}`);
} catch (err) {
this.logger.error(`Custom pipeline deletion failed: ${id} - ${err.message}`);
}
}

getDefaultPipeline({ includeSerialization }: Pipeline = { includeSerialization: true }) {
return logsPipeline({ includeSerialization });
}
Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-apm-synthtrace/src/scenarios/degraded_logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
bootstrap: async ({ logsEsClient }) => {
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient } }) => {
const { logger } = runOptions;

Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-apm-synthtrace/src/scenarios/failed_logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
},
});
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteComponentTemplate(LogsCustom);
await logsEsClient.deleteCustomPipeline();
if (isLogsDb) await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient } }) => {
const { logger } = runOptions;

Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-apm-synthtrace/src/scenarios/logs_and_metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
bootstrap: async ({ logsEsClient }) => {
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient, apmEsClient } }) => {
const { numServices = 3 } = runOptions.scenarioOpts || {};
const { logger } = runOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const scenario: Scenario<LogDocument | InfraDocument | ApmFields> = async (runOp
bootstrap: async ({ logsEsClient }) => {
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient, infraEsClient, apmEsClient } }) => {
const {
numSpaces,
Expand Down
3 changes: 3 additions & 0 deletions packages/kbn-apm-synthtrace/src/scenarios/simple_logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
bootstrap: async ({ logsEsClient }) => {
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient } }) => {
const { logger } = runOptions;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
await logsEsClient.createIndex('cloud-logs-synth.2-default');
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient } }) => {
const { logger } = runOptions;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const scenario: Scenario<LogDocument> = async (runOptions) => {
bootstrap: async ({ logsEsClient }) => {
if (isLogsDb) await logsEsClient.createIndexTemplate(IndexTemplateName.LogsDb);
},
teardown: async ({ logsEsClient }) => {
await logsEsClient.deleteIndexTemplate(IndexTemplateName.LogsDb);
},
generate: ({ range, clients: { logsEsClient } }) => {
const { logger } = runOptions;

Expand Down
4 changes: 3 additions & 1 deletion packages/kbn-scout-reporting/src/reporting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ export const scoutPlaywrightReporter = (
export const scoutFailedTestsReporter = (
options?: ScoutPlaywrightReporterOptions
): ReporterDescription => {
return ['@kbn/scout-reporting/src/reporting/playwright/failed_test', options];
return SCOUT_REPORTER_ENABLED
? ['@kbn/scout-reporting/src/reporting/playwright/failed_test', options]
: ['null'];
};
70 changes: 57 additions & 13 deletions packages/kbn-scout/src/playwright/config/create_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,35 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { SCOUT_REPORTER_ENABLED, SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { scoutPlaywrightReporter, scoutFailedTestsReporter } from '@kbn/scout-reporting';
import { createPlaywrightConfig } from './create_config';
import { VALID_CONFIG_MARKER } from '../types';
import { generateTestRunId } from '@kbn/scout-reporting';

jest.mock('@kbn/scout-reporting', () => ({
...jest.requireActual('@kbn/scout-reporting'),
generateTestRunId: jest.fn(),
scoutPlaywrightReporter: jest.fn(),
scoutFailedTestsReporter: jest.fn(),
}));

describe('createPlaywrightConfig', () => {
const mockedRunId = 'mocked-run-id';
const mockGenerateTestRunId = generateTestRunId as jest.Mock;
const mockedScoutPlaywrightReporter = scoutPlaywrightReporter as jest.Mock;
const mockedScoutFailedTestsReporter = scoutFailedTestsReporter as jest.Mock;

beforeEach(() => {
jest.clearAllMocks();
delete process.env.TEST_RUN_ID;
});

it('should return a valid default Playwright configuration', () => {
const testRunId = 'test-run-id';
mockGenerateTestRunId.mockImplementationOnce(() => testRunId);
mockGenerateTestRunId.mockImplementationOnce(() => mockedRunId);
// Scout reporters are disabled by default
mockedScoutPlaywrightReporter.mockReturnValueOnce(['null']);
mockedScoutFailedTestsReporter.mockReturnValueOnce(['null']);

const testDir = './my_tests';
const config = createPlaywrightConfig({ testDir });
Expand All @@ -49,28 +58,63 @@ describe('createPlaywrightConfig', () => {
expect(config.reporter).toEqual([
['html', { open: 'never', outputFolder: './output/reports' }],
['json', { outputFile: './output/reports/test-results.json' }],
SCOUT_REPORTER_ENABLED
? [
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: testRunId },
]
: ['null'],
[
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: testRunId },
],
['null'],
['null'],
]);
expect(config.timeout).toBe(60000);
expect(config.expect?.timeout).toBe(10000);
expect(config.outputDir).toBe('./output/test-artifacts');
expect(config.projects![0].name).toEqual('chromium');
});

it('should return a Playwright configuration with Scout reporters', () => {
mockGenerateTestRunId.mockImplementationOnce(() => mockedRunId);
mockedScoutPlaywrightReporter.mockReturnValueOnce([
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: mockedRunId },
]);
mockedScoutFailedTestsReporter.mockReturnValueOnce([
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: mockedRunId },
]);

const testDir = './my_tests';
const config = createPlaywrightConfig({ testDir });

expect(mockGenerateTestRunId).toHaveBeenCalledTimes(1);
expect(config.reporter).toEqual([
['html', { open: 'never', outputFolder: './output/reports' }],
['json', { outputFile: './output/reports/test-results.json' }],
[
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: mockedRunId },
],
[
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: mockedRunId },
],
]);
});

it(`should override 'workers' count in Playwright configuration`, () => {
const testDir = './my_tests';
const workers = 2;

const config = createPlaywrightConfig({ testDir, workers });
expect(config.workers).toBe(workers);
});

it('should generate and cache runId in process.env.TEST_RUN_ID', () => {
mockGenerateTestRunId.mockReturnValue(mockedRunId);

// First call to create config
createPlaywrightConfig({ testDir: 'tests' });
expect(process.env.TEST_RUN_ID).toBe(mockedRunId);

// Second call (should use the cached value)
createPlaywrightConfig({ testDir: 'tests' });

expect(generateTestRunId).toHaveBeenCalledTimes(1);
expect(process.env.TEST_RUN_ID).toBe(mockedRunId);
});
});
10 changes: 9 additions & 1 deletion packages/kbn-scout/src/playwright/config/create_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ import { SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { ScoutPlaywrightOptions, ScoutTestOptions, VALID_CONFIG_MARKER } from '../types';

export function createPlaywrightConfig(options: ScoutPlaywrightOptions): PlaywrightTestConfig {
const runId = generateTestRunId();
/**
* Playwright loads the config file multiple times, so we need to generate a unique run id
* and store it in the environment to be used across all config function calls.
*/
let runId = process.env.TEST_RUN_ID;
if (!runId) {
runId = generateTestRunId();
process.env.TEST_RUN_ID = runId;
}

return defineConfig<ScoutTestOptions>({
testDir: options.testDir,
Expand Down
4 changes: 4 additions & 0 deletions src/core/packages/http/server-internal/src/csp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ const configSchema = schema.object(
defaultValue: [],
validate: getDirectiveValidator({ allowNone: false, allowNonce: false }),
}),
object_src: schema.arrayOf(schema.string(), {
defaultValue: [],
validate: getDirectiveValidator({ allowNone: true, allowNonce: false }),
}),
})
),
strict: schema.boolean({ defaultValue: true }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('CspConfig', () => {
"disableEmbedding": false,
"disableUnsafeEval": true,
"header": "script-src 'report-sample' 'self'; worker-src 'report-sample' 'self' blob:; style-src 'report-sample' 'self' 'unsafe-inline'",
"reportOnlyHeader": "form-action 'report-sample' 'self'",
"reportOnlyHeader": "form-action 'report-sample' 'self'; object-src 'report-sample' 'none'",
"strict": true,
"warnLegacyBrowsers": true,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ export type CspDirectiveName =
| 'img-src'
| 'report-uri'
| 'report-to'
| 'form-action';
| 'form-action'
| 'object-src';

/**
* The default report only directives rules
*/
export const defaultReportOnlyRules: Partial<Record<CspDirectiveName, string[]>> = {
'form-action': [`'report-sample'`, `'self'`],
'object-src': [`'report-sample'`, `'none'`],
};

/**
Expand Down Expand Up @@ -189,6 +191,10 @@ const parseConfigDirectives = (cspConfig: CspConfigType): CspConfigDirectives =>
reportOnlyDirectives.set('form-action', cspConfig.report_only?.form_action);
}

if (cspConfig.report_only?.object_src?.length) {
reportOnlyDirectives.set('object-src', cspConfig.report_only?.object_src);
}

return {
enforceDirectives,
reportOnlyDirectives,
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/integration_tests/http/lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ describe('runs with default preResponse handlers', () => {
`script-src 'report-sample' 'self' 'unsafe-eval'; worker-src 'report-sample' 'self' blob:; style-src 'report-sample' 'self' 'unsafe-inline'`
);
expect(response.header['content-security-policy-report-only']).toBe(
`form-action 'report-sample' 'self'`
`form-action 'report-sample' 'self'; object-src 'report-sample' 'none'`
);
});
});
Expand Down
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 1a3df74

Please sign in to comment.