Skip to content

Commit 0e5a5f6

Browse files
authored
Merge branch 'main' into fix-add-env-variable
2 parents 7a47b53 + 15ad2d6 commit 0e5a5f6

File tree

17 files changed

+454
-7
lines changed

17 files changed

+454
-7
lines changed

oas_docs/output/kibana.serverless.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94330,6 +94330,10 @@ components:
9433094330
description: The Slack channel identifier.
9433194331
example: C123ABC456
9433294332
params_property_apm_anomaly:
94333+
title: APM anomaly
94334+
description: |
94335+
The parameters for the APM anomaly rule. These parameters are appropriate when `rule_type_id` is `apm.rules.anomaly`.
94336+
type: object
9433394337
required:
9433494338
- windowSize
9433594339
- windowUnit
@@ -94368,6 +94372,10 @@ components:
9436894372
- minor
9436994373
- warning
9437094374
params_property_apm_error_count:
94375+
title: APM error count
94376+
description: |
94377+
The parameters for the APM error count rule. These parameters are appropriate when `rule_type_id` is `apm.error_rate`.
94378+
type: object
9437194379
required:
9437294380
- windowSize
9437394381
- windowUnit
@@ -94416,6 +94424,10 @@ components:
9441694424
description: |
9441794425
Filter the errors coming from your application to apply the rule to a specific error grouping key, which is a hash of the stack trace and other properties.
9441894426
params_property_apm_transaction_duration:
94427+
title: APM transaction duration
94428+
description: |
94429+
The parameters for the APM transaction duration rule. These parameters are appropriate when `rule_type_id` is `apm.transaction_duration`.
94430+
type: object
9441994431
required:
9442094432
- windowSize
9442194433
- windowUnit
@@ -94475,6 +94487,10 @@ components:
9447594487
- 99th
9447694488
description: The type of aggregation to perform.
9447794489
params_property_apm_transaction_error_rate:
94490+
title: APM transaction error rate
94491+
description: |
94492+
The parameters for the APM transaction error rate rule. These parameters are appropriate when `rule_type_id` is `apm.transaction_error_rate`.
94493+
type: object
9447894494
required:
9447994495
- windowSize
9448094496
- windowUnit
@@ -95352,6 +95368,10 @@ components:
9535295368
description: |
9535395369
If true, an alert occurs if a group that previously reported metrics does not report them again over the expected time period. This check is not recommended for dynamically scaling infrastructures that might rapidly start and stop nodes automatically.
9535495370
params_property_slo_burn_rate:
95371+
title: SLO burn rate
95372+
description: |
95373+
The parameters for the SLO burn rate rule. These parameters are appropriate when `rule_type_id` is `slo.rules.burnRate`.
95374+
type: object
9535595375
properties:
9535695376
sloId:
9535795377
description: The SLO identifier used by the rule

oas_docs/output/kibana.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105416,6 +105416,10 @@ components:
105416105416
description: The Slack channel identifier.
105417105417
example: C123ABC456
105418105418
params_property_apm_anomaly:
105419+
title: APM anomaly
105420+
description: |
105421+
The parameters for the APM anomaly rule. These parameters are appropriate when `rule_type_id` is `apm.rules.anomaly`.
105422+
type: object
105419105423
required:
105420105424
- windowSize
105421105425
- windowUnit
@@ -105454,6 +105458,10 @@ components:
105454105458
- minor
105455105459
- warning
105456105460
params_property_apm_error_count:
105461+
title: APM error count
105462+
description: |
105463+
The parameters for the APM error count rule. These parameters are appropriate when `rule_type_id` is `apm.error_rate`.
105464+
type: object
105457105465
required:
105458105466
- windowSize
105459105467
- windowUnit
@@ -105502,6 +105510,10 @@ components:
105502105510
description: |
105503105511
Filter the errors coming from your application to apply the rule to a specific error grouping key, which is a hash of the stack trace and other properties.
105504105512
params_property_apm_transaction_duration:
105513+
title: APM transaction duration
105514+
description: |
105515+
The parameters for the APM transaction duration rule. These parameters are appropriate when `rule_type_id` is `apm.transaction_duration`.
105516+
type: object
105505105517
required:
105506105518
- windowSize
105507105519
- windowUnit
@@ -105561,6 +105573,10 @@ components:
105561105573
- 99th
105562105574
description: The type of aggregation to perform.
105563105575
params_property_apm_transaction_error_rate:
105576+
title: APM transaction error rate
105577+
description: |
105578+
The parameters for the APM transaction error rate rule. These parameters are appropriate when `rule_type_id` is `apm.transaction_error_rate`.
105579+
type: object
105564105580
required:
105565105581
- windowSize
105566105582
- windowUnit
@@ -106438,6 +106454,10 @@ components:
106438106454
description: |
106439106455
If true, an alert occurs if a group that previously reported metrics does not report them again over the expected time period. This check is not recommended for dynamically scaling infrastructures that might rapidly start and stop nodes automatically.
106440106456
params_property_slo_burn_rate:
106457+
title: SLO burn rate
106458+
description: |
106459+
The parameters for the SLO burn rate rule. These parameters are appropriate when `rule_type_id` is `slo.rules.burnRate`.
106460+
type: object
106441106461
properties:
106442106462
sloId:
106443106463
description: The SLO identifier used by the rule

src/platform/packages/private/kbn-scout-info/llms/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Instructions:
6363
@src/platform/packages/private/kbn-scout-info/llms/generate-scout-page-objects.md contains instructions on how to perform this task
6464
@src/platform/packages/private/kbn-scout-info/llms/what-is-scout.md contains a high-level description of the Scout framework
6565
@src/platform/packages/private/kbn-scout-info/llms/scout-page-objects.md contains a high-level overview of page objects in Scout
66+
@src/platform/packages/private/kbn-scout-info/llms/scout-browser-auth.md contains information on how browser authentication works in Scout
6667
```
6768

6869
**Checkpoint**: the AI will generate or modify Scout page objects. For this step, you may need to manually move these files to the correct directory (either the plugin's page objects folder, or one of the Scout packages), and register them in the `pageObjects` fixture. Refer to the official Scout documentation.
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# Browser authentication in Scout
2+
3+
Scout uses [SAML](https://www.elastic.co/docs/deploy-manage/users-roles/cluster-or-deployment-auth/saml) as a unified authentication protocol across all deployment types. In this article we'll explore how to authenticate your Playwright tests using the `browserAuth` fixture.
4+
5+
## Log in with the `browserAuth` fixture
6+
7+
The `browserAuth` fixture provides convenient methods to authenticate with different user roles in your tests, regardless of where your tests run:
8+
9+
| Method | Description |
10+
| :-------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
11+
| `loginAsAdmin()` | Logs in with the `admin` role (full Kibana and Elasticsearch access). |
12+
| `loginAsPrivilegedUser()` | Logs in with a privileged non-admin role (`editor`, except for Elasticsearch projects that use the `developer` role). |
13+
| `loginAsViewer()` | Logs in with the `viewer` role (read-only permissions). |
14+
| `loginAs(role: string)` | Logs in a specific built-in role by name. The role must exist in the deployment's role configuration, otherwise an error is thrown. |
15+
| `loginWithCustomRole(role: KibanaRole)` | Creates a custom role with the specified Kibana and Elasticsearch privileges, and then logs in with that role. |
16+
17+
These authentication methods are **asynchronous** and must be awaited.
18+
19+
**Basic usage example:**
20+
21+
```ts
22+
import { expect, tags } from '@kbn/scout';
23+
import { test } from '../fixtures';
24+
25+
// ...
26+
27+
test.describe('My sample test suite', { tag: tags.DEPLOYMENT_AGNOSTIC }, () => {
28+
test.beforeEach(async ({ browserAuth, pageObjects }) => {
29+
// [1]
30+
// log in as an admin
31+
await browserAuth.loginAsAdmin(); // [2]
32+
// ...
33+
});
34+
35+
test('my sample test 1', async ({ pageObjects }) => {
36+
// the browser is already authenticated as admin here
37+
// ...
38+
});
39+
40+
test('my sample test 2', async ({ pageObjects }) => {
41+
// the browser is already authenticated as admin here
42+
// ...
43+
});
44+
});
45+
```
46+
47+
1. We first unpack the **`browserAuth`** fixture from the test context.
48+
2. We then log in with the **`admin`** role before each test in the **`beforeEach`** hook.
49+
50+
> **SAML authentication: local deployment vs Elastic Cloud**
51+
>
52+
> When running tests in **local** stateful and serverless environments, Scout creates **on-demand** SAML identities using a trusted **mock Identity Provider (IdP)**, bypassing the need for pre-provisioned users.
53+
>
54+
> However, when running tests on Elastic Cloud, Scout authenticates with **real Elastic Cloud accounts** using credentials from the `<KIBANA_ROOT>/.ftr/role_users.json` or `<KIBANA_ROOT>/.scout/role_users.json` files through the actual cloud Identity Provider.
55+
56+
### Logging in with a custom role
57+
58+
You can log in with a custom role with the `loginWithCustomRole()` method. This is ideal for testing specific permission sets in your plugin:
59+
60+
```ts
61+
test.describe(
62+
'Discover app with a restricted read-only role',
63+
{ tag: tags.DEPLOYMENT_AGNOSTIC },
64+
() => {
65+
test.beforeAll(async () => {
66+
// load test data
67+
// ...
68+
});
69+
70+
test.beforeEach(async ({ browserAuth, pageObjects }) => {
71+
// log in with custom role
72+
await browserAuth.loginWithCustomRole({
73+
kibana: [
74+
{
75+
base: [], // [1]
76+
feature: {
77+
discover: ['read'],
78+
},
79+
spaces: ['*'],
80+
},
81+
],
82+
elasticsearch: {
83+
cluster: [], // [2]
84+
indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }], // [3]
85+
},
86+
});
87+
});
88+
89+
test('should display a disabled save button', async ({ browserAuth }) => {
90+
// navigate to Discover and verify read-only access
91+
// ...
92+
});
93+
}
94+
);
95+
```
96+
97+
1. For testing specific features, use `base: []` and explicit `feature` definitions.
98+
2. We leave this empty as no cluster privileges are needed for this test.
99+
3. We define the minimum index privileges needed to access Discover.
100+
101+
> **Warning: Scout vs FTR**
102+
>
103+
> Scout's `loginWithCustomRole()` method internally uses similar role creation logic to FTR's `samlAuth.setCustomRole()` method, but wraps it with **automatic authentication** and **cleanup**, making it a one-step solution for Playwright tests compared to FTR's multi-step approach.
104+
105+
> **What happens behind the scenes?**
106+
>
107+
> When you call `loginWithCustomRole()`, Scout first creates a uniquely named role in Elasticsearch for each Playwright worker (`custom_role_worker_1`, `custom_role_worker_2`, etc.). If your tests run sequentially, Scout will create just one role named `custom_role_worker_1`.
108+
>
109+
> Scout then:
110+
>
111+
> 1. Creates an authenticated SAML session for the custom role
112+
> 2. Caches the session for performance (subsequent calls with the same role definition reuse the cached session)
113+
> 3. Sets the session cookie in your browser context
114+
> 4. Automatically deletes the custom role after test completion (no matter if the test passed or failed)
115+
>
116+
> If you call `loginWithCustomRole()` again with a different role definition in the same test, Scout **recreates** the role with the new privileges and authenticates with a fresh session.
117+
118+
### Predefined roles vs custom roles
119+
120+
Let's compare **predefined roles** with **custom roles**:
121+
122+
- **Predefined roles** are built-in Elastic roles available to all customers out-of-the-box (like `admin`, `editor`, `viewer`). These work with `loginAs()` and are defined in the appropriate `roles.yml` file. Here's a [list](https://www.elastic.co/docs/deploy-manage/users-roles/cloud-organization/user-roles) for Elastic Cloud.
123+
- **Custom roles** are roles you create specifically for testing with particular permission sets. These require `loginWithCustomRole()` instead.
124+
125+
> **Warning: Scout vs FTR**
126+
>
127+
> **FTR** allows defining custom roles in the test config file under `security.roles`. **Scout** takes a different approach: custom roles are created dynamically using `loginWithCustomRole()`.
128+
129+
### Extending the `browserAuth` fixture
130+
131+
Using `loginWithCustomRole()` works well for one-off cases, but if you need to log in with the same custom role across multiple tests, it's more convenient to extend the `browserAuth` fixture with solution-specific or plugin-specific authentication methods.
132+
133+
#### Solution-scoped extension
134+
135+
The `@kbn/scout-security` package [extends](https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/packages/kbn-scout-security/src/playwright/fixtures/test/browser_auth/index.ts) the `browserAuth` fixture to expose Security-specific authentication methods (e.g. `loginAsPlatformEngineer()`):
136+
137+
```ts
138+
// loginAsPlatformEngineer() is available in all tests importing @kbn/scout-security
139+
test.beforeEach(async ({ browserAuth }) => {
140+
await browserAuth.loginAsPlatformEngineer();
141+
});
142+
```
143+
144+
All Security tests importing `@kbn/scout-security` can now use this method to log in as a Platform Engineer without redefining the custom role in each test.
145+
146+
#### Plugin-scoped extension
147+
148+
A plugin can also extend the `browserAuth` fixture by creating a custom fixture in the plugin's `test/scout/ui/fixtures` directory. For example, the Observability APM plugin [exposes](https://github.com/elastic/kibana/blob/main/x-pack/solutions/observability/plugins/apm/test/scout/ui/fixtures/index.ts#L82-L99) `loginAsApmMonitor()`:
149+
150+
```ts
151+
// loginAsApmMonitor() is available in all tests importing the plugin fixture
152+
test.beforeEach(async ({ browserAuth }) => {
153+
await browserAuth.loginAsApmMonitor();
154+
});
155+
```
156+
157+
Create a custom fixture that extends `browserAuth` in your plugin's test directory:
158+
159+
```ts
160+
// x-pack/solutions/<solution>/plugins/<private or shared>/my-plugin/test/scout/ui/fixtures/index.ts
161+
162+
import { scoutTestFixtures } from '@kbn/scout'; // [1]
163+
import type { BrowserAuthFixture } from '@kbn/scout'; // [1]
164+
165+
interface MyPluginAuthFixture extends BrowserAuthFixture {
166+
loginAsMyPluginUser: () => Promise<void>;
167+
}
168+
169+
export const fixtures = scoutTestFixtures.extend<{ browserAuth: MyPluginAuthFixture }>({
170+
browserAuth: async ({ browserAuth }, use) => {
171+
const loginAsMyPluginUser = async () =>
172+
browserAuth.loginWithCustomRole({
173+
// update as necessary
174+
elasticsearch: {
175+
cluster: ['monitor'],
176+
indices: [{ names: ['my-plugin-*'], privileges: ['read', 'write'] }],
177+
},
178+
// update as necessary
179+
kibana: [
180+
{
181+
feature: { myPlugin: ['all'] },
182+
spaces: ['*'],
183+
},
184+
],
185+
});
186+
187+
// make the new method available via the browserAuth fixture
188+
await use({
189+
...browserAuth,
190+
loginAsMyPluginUser,
191+
});
192+
},
193+
});
194+
```
195+
196+
1. Import from `@kbn/scout-oblt` or from `@kbn/scout-security` if your plugin belongs to a specific solution.
197+
198+
Then use it in your tests:
199+
200+
```ts
201+
import { expect, test } from '../fixtures';
202+
203+
test('my plugin feature works', async ({ browserAuth, page }) => {
204+
await browserAuth.loginAsMyPluginUser();
205+
await page.goto('/app/my-plugin');
206+
// Your test logic
207+
});
208+
```
209+
210+
## Best practices
211+
212+
#### Use deployment-agnostic methods
213+
214+
Scout tests are designed to be deployment agnostic by default. Prefer `loginAsPrivilegedUser()` over `loginAs('editor')` when writing deployment-agnostic tests, as it automatically selects the appropriate role for the deployment type.
215+
216+
#### Keep custom roles minimal
217+
218+
Only grant the **minimum privileges** needed for your test. This makes tests more realistic and helps catch permission-related bugs.
219+
220+
#### Reuse custom roles via fixtures
221+
222+
If multiple tests need the same custom role, extend the `browserAuth` fixture instead of repeating `loginWithCustomRole()` calls.
223+
224+
#### Test permission boundaries
225+
226+
Use custom roles to explicitly test both what users **can** and **cannot** do:
227+
228+
```ts
229+
test('viewer cannot save dashboards', async ({ browserAuth, page }) => {
230+
await browserAuth.loginAsViewer();
231+
await page.gotoApp('dashboards');
232+
233+
// Verify save button is disabled
234+
await expect(page.testSubj.locator('dashboardSaveButton')).toBeDisabled();
235+
});
236+
```

src/platform/packages/shared/kbn-storage-adapter/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,21 @@ export type StorageClientBulkOperation<TDocument extends { _id?: string }> =
5555
}
5656
| { delete: { _id: string } };
5757

58+
export interface StorageClientBulkOptions {
59+
/**
60+
* If true, throws BulkOperationError when any operation in the bulk request fails.
61+
* If false (default), returns the response with errors field populated, similar to Promise.allSettled behavior.
62+
* @default false
63+
*/
64+
throwOnFail?: boolean;
65+
}
66+
5867
export type StorageClientBulkRequest<TDocument extends { _id?: string }> = Omit<
5968
BulkRequest,
6069
'operations' | 'index'
6170
> & {
6271
operations: Array<StorageClientBulkOperation<TDocument>>;
63-
};
72+
} & StorageClientBulkOptions;
6473
export type StorageClientBulkResponse = BulkResponse;
6574

6675
export type StorageClientDeleteRequest = Omit<DeleteRequest, 'index'>;
@@ -91,6 +100,13 @@ export type StorageClientSearch<TDocumentType = never> = <
91100
request: TSearchRequest
92101
) => Promise<StorageClientSearchResponse<TDocumentType, TSearchRequest>>;
93102

103+
/**
104+
* Performs bulk operations on documents.
105+
*
106+
* By default, behaves similar to Promise.allSettled - individual operation failures
107+
* are returned in the response without throwing an error. Set `throwOnFail: true`
108+
* to throw a BulkOperationError when any operation fails.
109+
*/
94110
export type StorageClientBulk<TDocumentType extends { _id?: string } = never> = (
95111
request: StorageClientBulkRequest<TDocumentType>
96112
) => Promise<StorageClientBulkResponse>;
@@ -159,4 +175,6 @@ export type StorageDocumentOf<TStorageSettings extends StorageSettings> = Partia
159175

160176
export { StorageIndexAdapter } from './src/index_adapter';
161177

178+
export { BulkOperationError } from './src/errors';
179+
162180
export { types } from './types';

0 commit comments

Comments
 (0)