Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
390af80
add initial Scout Osquery tests
csr Mar 19, 2026
89ead7f
use correct matcher
csr Mar 19, 2026
3f966b9
fix spacing
csr Mar 19, 2026
1c3bedb
capitalize Osquery
csr Mar 19, 2026
05032cd
use `apiServices` instead of `kbnClient` or `apiClient` for setup and…
csr Mar 19, 2026
f89c521
add API tests that test permission bounderies (shoul return unauthori…
csr Mar 19, 2026
bc87674
split monolithic API test into three focused tests
csr Mar 19, 2026
b26ca4d
define common constants file
csr Mar 19, 2026
58d18b8
split sequential test into multiple parallel tests + global setup hook
csr Mar 19, 2026
d457e10
minor tweaks to UI tests
csr Mar 19, 2026
b643cf5
remove UI tests (will create a separate follow-up PR)
csr Mar 19, 2026
5bbca9c
remove FTR tests that were migrated to Scout
csr Mar 19, 2026
f82900d
Merge branch 'main' into scout-osquery-first-steps
csr Mar 19, 2026
a7ed131
Merge branch 'main' into scout-osquery-first-steps
csr Mar 20, 2026
e383d22
Fix `createdBy` query parameter encoding for MKI compatibility
csr Mar 20, 2026
10796be
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Mar 20, 2026
7ae9d3e
Merge branch 'main' into scout-osquery-first-steps
csr Mar 24, 2026
e207506
check for 404 not found response
csr Mar 24, 2026
c14bfc2
temporarily exclude test suites from ECH test runs
csr Mar 24, 2026
ab4cfdb
replace `deploymentAgnostic` tags with Security-specific tags
csr Mar 24, 2026
3d191fd
add `tsconfig.json`
csr Mar 24, 2026
5cdeabb
re-add FTR test suite (without tests that are already migrated)
csr Mar 25, 2026
88ba38c
filter pack by `enabled` status (both `true` and `false`)
csr Mar 25, 2026
e300d7e
update comments
csr Mar 25, 2026
c9e22d6
update tags
csr Mar 25, 2026
455163d
update comments
csr Mar 25, 2026
e381663
remove `tsconfig.json`
csr Mar 25, 2026
7680bf8
add TODO comment
csr Mar 25, 2026
4d281f4
update plugin's `tsconfig.json`
csr Mar 25, 2026
288bb06
Changes from node scripts/lint_ts_projects --fix
kibanamachine Mar 25, 2026
99b381c
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .buildkite/scout_ci_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ plugins:
- navigation
- observability
- observability_onboarding
- osquery
- painless_lab
- profiling
- search_getting_started
Expand Down
2 changes: 2 additions & 0 deletions x-pack/platform/plugins/shared/osquery/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ dependsOn:
- '@kbn/unified-search-plugin'
- '@kbn/core-notifications-browser'
- '@kbn/core-chrome-browser'
- '@kbn/scout'
tags:
- plugin
- prod
Expand All @@ -98,6 +99,7 @@ fileGroups:
- scripts/**/*
- scripts/**/*.json
- server/**/*
- test/scout/**/*
- public/common/schemas/*/*.json
- '!target/**/*'
tasks:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { OSQUERY_API_VERSION } from '../../common/constants';

export { OSQUERY_API_VERSION };

export const COMMON_HEADERS = {
'kbn-xsrf': 'some-xsrf-token',
'x-elastic-internal-origin': 'kibana',
'Content-Type': 'application/json;charset=UTF-8',
'elastic-api-version': OSQUERY_API_VERSION,
} as const;

export const API_PATHS = {
DETECTION_RULES: 'api/detection_engine/rules',
OSQUERY_SAVED_QUERIES: 'api/osquery/saved_queries',
OSQUERY_PACKS: 'api/osquery/packs',
} as const;

const uniqueId = () => `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;

export const getMinimalRule = (overrides: Record<string, unknown> = {}) => ({
type: 'query',
index: ['auditbeat-*'],
language: 'kuery',
query: '_id:*',
name: `Test rule ${uniqueId()}`,
description: 'Test rule for Osquery response actions',
risk_score: 21,
severity: 'low',
interval: '5m',
from: 'now-360s',
to: 'now',
enabled: false,
...overrides,
});

export const getMinimalPack = (overrides: Record<string, unknown> = {}) => ({
name: `test-pack-${uniqueId()}`,
description: 'Test pack for Osquery Scout tests',
enabled: true,
queries: {
testQuery: {
query: 'select * from uptime;',
interval: 3600,
},
},
shards: {},
...overrides,
});

export const getMinimalSavedQuery = (overrides: Record<string, unknown> = {}) => ({
id: `test-saved-query-${uniqueId()}`,
query: 'select 1;',
interval: '3600',
...overrides,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { ApiServicesFixture, ScoutTestFixtures, ScoutWorkerFixtures } from '@kbn/scout';
import { apiTest as baseApiTest } from '@kbn/scout';
import {
getOsqueryApiService,
type OsqueryApiService,
} from '../../common/services/osquery_api_service';

export interface OsqueryApiServicesFixture extends ApiServicesFixture {
osquery: OsqueryApiService;
}

export const apiTest = baseApiTest.extend<
ScoutTestFixtures,
{ apiServices: OsqueryApiServicesFixture }
>({
apiServices: [
async (
{
apiServices,
kbnClient,
log,
}: {
apiServices: ApiServicesFixture;
kbnClient: ScoutWorkerFixtures['kbnClient'];
log: ScoutWorkerFixtures['log'];
},
use: (extendedApiServices: OsqueryApiServicesFixture) => Promise<void>
) => {
const extendedApiServices = apiServices as OsqueryApiServicesFixture;
extendedApiServices.osquery = getOsqueryApiService({ kbnClient, log });
await use(extendedApiServices);
},
{ scope: 'worker' },
],
});

export * as testData from './constants';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { createPlaywrightConfig } from '@kbn/scout';

export default createPlaywrightConfig({
testDir: './tests',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { RoleSessionCredentials } from '@kbn/scout';
import { expect } from '@kbn/scout/api';
import { tags } from '@kbn/scout';
import { apiTest, testData } from '../fixtures';

// TODO: run on ECH once PR #258866 makes it to prod
apiTest.describe(
'Osquery packs - admin',
{
tag: ['@local-stateful-classic', ...tags.serverless.security.complete],
},
() => {
let adminCredentials: RoleSessionCredentials;
const createdPackIds: string[] = [];

apiTest.beforeAll(async ({ samlAuth }) => {
// TODO: investigate why this test only passes with cookie-based authentication while similar
// tests (saved_queries_admin.spec.ts) pass with API key-based authentication
adminCredentials = await samlAuth.asInteractiveUser('admin');
});

apiTest.afterAll(async ({ apiServices }) => {
for (const packId of createdPackIds) {
await apiServices.osquery.packs.delete(packId);
}
});

apiTest('includes profile_uid fields on create and find', async ({ apiClient }) => {
const createResponse = await apiClient.post(testData.API_PATHS.OSQUERY_PACKS, {
headers: { ...testData.COMMON_HEADERS, ...adminCredentials.cookieHeader },
body: testData.getMinimalPack(),
responseType: 'json',
});
expect(createResponse).toHaveStatusCode(200);
expect(createResponse.body.data).toBeDefined();
createdPackIds.push(createResponse.body.data.saved_object_id);

expect('created_by_profile_uid' in createResponse.body.data).toBe(true);
expect('updated_by_profile_uid' in createResponse.body.data).toBe(true);
expect(createResponse.body.data.created_by).toBeDefined();

const findResponse = await apiClient.get(
`${testData.API_PATHS.OSQUERY_PACKS}?search=${createResponse.body.data.name}`,
{
headers: { ...testData.COMMON_HEADERS, ...adminCredentials.cookieHeader },
responseType: 'json',
}
);
expect(findResponse).toHaveStatusCode(200);
expect(findResponse.body.data).toBeDefined();
expect('created_by_profile_uid' in findResponse.body.data[0]).toBe(true);
});
Comment on lines +56 to +59
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low tests/packs_admin.spec.ts:55

findResponse.body.data[0] on line 57 throws TypeError when the search returns an empty array. The check on line 56 only verifies data is defined, not that it contains elements. If the pack isn't found due to eventual consistency, data[0] is undefined and 'created_by_profile_uid' in undefined throws. Consider asserting data.length > 0 before the element access, or use optional chaining with a fallback assertion.

      expect(findResponse).toHaveStatusCode(200);
       expect(findResponse.body.data).toBeDefined();
-      expect('created_by_profile_uid' in findResponse.body.data[0]).toBe(true);
+      expect(findResponse.body.data.length).toBeGreaterThan(0);
+      expect('created_by_profile_uid' in findResponse.body.data[0]).toBe(true);
🤖 Copy this AI Prompt to have your agent fix this:
In file x-pack/platform/plugins/shared/osquery/test/scout/api/tests/packs_admin.spec.ts around lines 55-58:

`findResponse.body.data[0]` on line 57 throws `TypeError` when the search returns an empty array. The check on line 56 only verifies `data` is defined, not that it contains elements. If the pack isn't found due to eventual consistency, `data[0]` is `undefined` and `'created_by_profile_uid' in undefined` throws. Consider asserting `data.length > 0` before the element access, or use optional chaining with a fallback assertion.

Evidence trail:
x-pack/platform/plugins/shared/osquery/test/scout/api/tests/packs_admin.spec.ts lines 56-57 at REVIEWED_COMMIT - shows `expect(findResponse.body.data).toBeDefined()` followed by `expect('created_by_profile_uid' in findResponse.body.data[0]).toBe(true)` with no length check between them.

}
);
Loading
Loading