Skip to content

[Security GenAI] Autonomous vs hand-written PCI compliance skill — side-by-side eval harness#10

Closed
patrykkopycinski wants to merge 3926 commits into
mainfrom
pk/autonomous-vs-handwritten-pci
Closed

[Security GenAI] Autonomous vs hand-written PCI compliance skill — side-by-side eval harness#10
patrykkopycinski wants to merge 3926 commits into
mainfrom
pk/autonomous-vs-handwritten-pci

Conversation

@patrykkopycinski
Copy link
Copy Markdown
Owner

TL;DR

Adds a second PCI compliance skill (pci-compliance-autonomous) that ships alongside the hand-written pci-compliance skill (elastic#256060), and parameterizes the existing kbn-evals-suite-pci-compliance so the same 7-scenario eval suite can be run against either skill via the EVAL_PCI_VARIANT env var.

The autonomous skill was generated end-to-end by skill.architect against the current Kibana tool catalog, with PCI domain knowledge synthesized from autonomous web research + model knowledge. It deliberately reuses the same underlying tools as the hand-written skill, so "skill content" (instructions + domain knowledge + trigger phrases) is the only experimental variable — same tools, same dataset, same evaluators, same judge.

Comparison artifact

Side-by-side comparison report: comparison.html in this branch (rendered via htmlpreview)

Currently shows the structural comparison (skill metadata, content metrics, distinguishing autonomous contributions). The "Live evaluation results" section is wired and waits for output from compare_variants.sh once the AI-connector eval cluster runs the suite. The HTML re-renders deterministically from runs/{handwritten,autonomous}/results.json.

What ships

Server (security_solution plugin)

  • New skill definition pci_compliance_autonomous/ registering pci-compliance-autonomous against the existing PCI tool IDs.
  • Feature flag pciComplianceAutonomousAgentBuilder (default off).
  • Skill registration gated by the flag.
  • Allow-list entry for the new skill ID.

Eval harness (kbn-evals-suite-pci-compliance)

  • evaluate_dataset.ts reads EVAL_PCI_VARIANT (handwritten | autonomous) to select which skill createSkillInvocationEvaluator targets. Default remains handwritten so existing CI is unchanged.
  • scripts/compare_variants.sh runs both variants back-to-back and emits the side-by-side report.
  • scripts/build_comparison_html.mjs generates the report; all embedded paths are repo-relative so the artifact is portable.
  • README documents the variant matrix and the comparison workflow.

CI plumbing

  • New Scout config set evals_pci_compliance_autonomous flips ONLY the autonomous flag.
  • evals.suites.json registers the autonomous suite.
  • llm_evals.yml adds a Buildkite step for the autonomous variant; existing PCI step tagged EVAL_PCI_VARIANT=handwritten for symmetry.

How to reproduce locally

cd kibana
./x-pack/solutions/security/packages/kbn-evals-suite-pci-compliance/scripts/compare_variants.sh
open  ./x-pack/solutions/security/packages/kbn-evals-suite-pci-compliance/comparison.html

Or via Buildkite — both kbn-evals-weekly-pci-compliance and kbn-evals-weekly-pci-compliance-autonomous steps now exist in llm_evals.yml and can be triggered independently.

Why two skills, same tools?

The hand-written skill already has its real tool implementations in tree. Forking those tools for the autonomous variant would conflate two questions: "is the autonomous skill content better?" and "are different tool surfaces better?". Reusing the tools isolates skill content as the only variable — exactly what the comparison is meant to measure.

Verification done before push

  • ReadLints clean across all authored files.
  • ESLint clean on every staged file except evaluate_dataset.ts:17 — pre-existing @kbn/imports/no_boundary_crossing from Add PCI compliance skill and tools for Agent Builder elastic/kibana#256060 that reproduces identically on every sibling kbn-evals-suite-* package on main (verified against kbn-evals-suite-security-ai-rules). Endemic to the eval framework, out of scope for a skill comparison.
  • Secrets scan: clean.
  • Personal/absolute paths in diff or generated HTML: clean (HTML uses repoRelative() helper).
  • 15 files, +1373 / -1 — focused and reviewable.
  • Scoped tsc -b on security_solution/tsconfig.json OOMs at 8 GB locally (a known Kibana issue with this plugin's size). Per Kibana's defer-type-check rule, tier-1 ReadLints is the local signal; CI will run the authoritative type check.

Open as draft

Per local convention; not for review until the live evaluator output is attached to comparison.html.


Branch: https://github.com/patrykkopycinski/kibana/tree/pk/autonomous-vs-handwritten-pci
Comparison artifact: https://github.com/patrykkopycinski/kibana/blob/pk/autonomous-vs-handwritten-pci/x-pack/solutions/security/packages/kbn-evals-suite-pci-compliance/comparison.html

jillguyonnet and others added 30 commits May 6, 2026 10:34
## Summary

Closes elastic#245181

Fleet currently supports user customization at the type level (e.g.
`logs@custom`) and data-stream level (e.g.
`logs-system.application@custom`), but not at the namespace level. Users
managing multiple integrations under a shared namespace must configure
each data stream individually.

This PR implements namespace level customization by adding opt-in
per-namespace index templates.

This is an API-only solution for now.
elastic#264065 will implement UI
changes.

### Solution rationale

Fleet currently creates one base index template per data stream pattern
defined by the integration, e.g. `logs-system.application-*`. This index
templates applies to all matching data streams regardless of namespace,
e.g. `logs-system.application-production` and
`logs-system.application-staging`). This means that namespace-specific
component templates (e.g. `production@custom` and `staging@custom`)
cannot belong to that index template, otherwise they would compete with
each other and affect all data streams, not just the relevant namespace.

In this change, Fleet creates a dedicated index template per data stream
with a more specific index pattern and higher priority than the base
template. This namespace template is a clone of the base template with
`{namespace}@custom` added to `composed_of`. The base template is never
modified.

Example:

Template | index_patterns | Priority
-- | -- | --
logs-system.application | logs-system.application-* | 200
logs-system.application@namespace.production |
logs-system.application-production* | 250

Component templates in `logs-system.application`:
```js
"composed_of": [
  "logs@mappings",
  "logs@settings",
  "logs-system.application@package",
  "logs@custom",
  "system@custom",
  "logs-system.application@custom",
  "ecs@mappings",
  ".fleet_globals-1",
  ".fleet_agent_id_verification-1"
],
```

Component templates in `logs-system.application@namespace.production`:
```js
"composed_of": [
  "logs@mappings",
  "logs@settings",
  "logs-system.application@package",
  "logs@custom",
  "system@custom",
  "production@custom", // namespace level, between package and data stream
  "logs-system.application@custom",
  "ecs@mappings",
  ".fleet_globals-1",
  ".fleet_agent_id_verification-1"
],
```

### Opt-in mechanism

Creating namespace templates for every namespace by default could
potentially cause many templates to be created unnecessarily. To
mitigate this, namespace level customization is opt-in and managed in
the package installation:
```
{
  "item": {
    "name": "system",
    ...
    "installationInfo": {
      ...
      "namespace_customization_enabled_for": ["production"]
      }
    }
  }
}
```

Namespaces can be opted in by updating the package installation:
```
PUT kbn:/api/fleet/epm/packages/system
{
  "namespace_customization_enabled_for": ["production"]
}
```

Or using the new bulk API:
```
POST kbn:/api/fleet/epm/packages/_bulk_namespace_customization
{
  "packages": ["system", "nginx", "apache"],
  "enable":  ["production"],
  "disable": ["staging"]
}
```

### Space awareness

Installation saved objects are shared across spaces, meaning the list of
opted in namespaces for an installed package is cluster wide: any Kibana
space that can see an integration sees the same opt-in list. Index
templates and component templates are also cluster wide.

The present implementation attempts to mitigate the write-side of this
using the `allowed_namespace_prefixes` per-space restriction mechanism
in Fleet settings (which is already used to gate which namespaces a user
can choose for agent/package policies in a given space).

When the user attempts to modify the list of opted in namespaces, it
will be validated against allowed namespace prefixes if any (if none are
set, there's no validation). For example, if `prod` namespace is allowed
in space A, then from that space `prod_eu` and `prod_us` would be
allowed, but not `qa`.

### Performance and scaling

Namespace template creation and deletion is handled by an asynchronous
task. This addresses risks of latency/timeouts and provides a built-in
retry mechanism.

### Testing

1. **Per-package opt-in creates namespace templates (existing
policies)**

1. Install the System integration with a package policy using namespace
`production`.

   2. Verify no namespace template exists yet:
   ```
   GET _index_template/logs-system.application@namespace.production
   ```
   should return 404.

   3. Opt in `production`:
   ```
   PUT kbn:/api/fleet/epm/packages/system
     {
       "namespace_customization_enabled_for": ["production"]
     }
   ```

4. Wait a few seconds for the async task, then verify the namespace
index template was created:
   ```
   GET _index_template/logs-system.application@namespace.production
   ```
   In particular, check:
      * `index_patterns` is `["logs-system.application-production*"]`
      * `priority` is 250
      * `composed_of` includes `production@custom`

2. **Namespace template shows in Assets tab**

In Kibana UI → Integrations → System → Assets tab, confirm
`logs-system.application@namespace.production` (and any other
per-dataset variants) appear alongside other Fleet-managed assets.

3. **Namespace component templates are applied to their specific data
streams only**

   1. Create a `production@custom`component template, e.g.:
   ```
   PUT _component_template/production@custom
   {
     "template": {
       "settings": {
         "index.number_of_replicas": 2
       }
     }
   }
   ```
2. Trigger a rollover if you already have data, or ingest a document to
create backing indices, e.g.
   ```
   POST logs-system.application-production/_doc
   {
     "@timestamp": "2026-04-15T00:00:00Z",
     "message": "test document"
   }
   ```
This should create the data stream and its first backing index
automatically, using the `logs-system.application@namespace.production`
index template (priority 250) rather than the base
`logs-system.application template` (priority 200).
3. Verify the `production` namespace data stream has
`number_of_replicas: 2`:
   ```
GET
logs-system.application-production/_settings/index.number_of_replicas
   ```
4. Verify a data stream in a different namespace does not have
`number_of_replicas: 2`, confirming namespace isolation.

4. **Opt-out deletes index templates but keeps component templates**

   1. Opt out `production`:
   ```
   PUT kbn:/api/fleet/epm/packages/system
     {
       "namespace_customization_enabled_for": []
     }
   ```

2. Wait a few seconds for the async task, then verify the namespace
index templates were deleted but the `production@custom`component
template still exists.

5. **Uninstall cleans up namespace templates**

   1. Opt `production` back in, namespace index template should exist.
2. Delete all System policies, uninstall integration and verify the
namespace index templates were deleted.

6. **Bulk endpoint**

1. Install System and Nginx and enable `production` and `staging`
namespaces for both:
   ```
   POST kbn:/api/fleet/epm/packages/_bulk_namespace_customization
   {
     "packages": ["system", "nginx"],
     "enable": ["production", "staging"]
   }
   ```
   2. The response should be:
   ```
   {
     "items": [
       {
         "name": "system",
         "success": true,
         "namespace_customization_enabled_for": [
           "production"
         ]
       },
       {
         "name": "nginx",
         "success": true,
         "namespace_customization_enabled_for": [
           "production"
         ]
       }
     ]
   }
   ```
   3. Test combinations of `enable` and `disable`.
4. Verify that passing the name of a non installed package results in
error:
   ```
  {
     "items": [
       {
         "name": "system",
         "success": true,
         "namespace_customization_enabled_for": [
           "production"
         ]
       },
       {
         "name": "apache",
         "success": false,
         "error": "Package apache is not installed"
       }
     ]
   }
   ```
5. Verify that it is not allowed to pass the same namespace in `enable`
and `disable`:
   ```
   {
     "statusCode": 400,
     "error": "Bad Request",
"message": "Namespaces must not appear in both enable and disable:
production"
   }
   ```

7. **Space awareness**

   1. Create a custom space and go to it.
   2. Configure allowed namespace prefixes in that space:
   ```
   PUT kbn:/api/fleet/space_settings
   { 
     "allowed_namespace_prefixes": ["prod"] 
   }
   ```
3. Verify that you now can't opt in a namespace that doesn't match the
allowed prefix:
   ```
   PUT kbn:/s/team-a/api/fleet/epm/packages/system
   { 
     "namespace_customization_enabled_for": ["staging"] 
   }
   ```
   Should result in:
   ```
   {
     "statusCode": 400,
     "error": "Bad Request",
"message": "Cannot change namespace customization for: staging. Allowed
prefixes in this space: prod"
   }
   ```
   4. Repeat with a matching namespace (e.g. `prod_eu`), it should work.
5. Now change the allowed namespace prefixes to `staging` and try to opt
out `prod_eu` (pass an empty array): it should reject with `Cannot
change namespace customization for: prod_eu. Allowed prefixes in this
space: staging`.
6. Do similar checks with the bulk endpoint: note that if you pass
multiple namespaces to opt in/out and at least one of them fails for a
given package, the update will fail for this package.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Risk of eventual consistency gap if package installation SO is saved
(synchronous) but the async task fails to create/delete index templates.

## Release note

Add opt-in namespace level customization to integrations.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…ning import batches concurrently (elastic#266628)

## Summary

Fixes elastic#262663 (re-opened after elastic#264965)

### What happened

PR elastic#264965 fixed the per-request 502 errors on ECH by reducing the
import batch size from 6,000 → 1,000 objects per call, keeping each
request safely under HAProxy's ~60 s per-connection timeout. However,
the 12 batches now run **sequentially**, and their cumulative time
exceeds the `beforeAll` hook's 120 s limit:

```
"beforeAll" hook timeout of 120000ms exceeded.
```

Each 1,000-object `_import` call on ECH takes ~10–15 s (NDJSON multipart
parsing + Kibana bulk-index + response building). 12 × 10–15 s = 120–180
s.

### Fix

Run the import batches **concurrently** (`CONCURRENCY = 3`) rather than
sequentially, and increase the hook timeout to 5 minutes as a generous
safety net.

```
12 batches ÷ 3 concurrent = 4 rounds × ~15 s/round ≈ 60 s total
```

Even if server load slows concurrent batches to ~60 s each, 4 rounds ×
60 s = 240 s — still well within the 300 s limit. Each individual
request remains at 1,000 objects, so no per-request HAProxy concern.

This keeps the full Kibana `_import` pipeline in the setup path (proper
SO migration, correct index routing, correct namespace handling),
avoiding any coupling to internal storage format details.

### Why not insert directly via `esClient.bulk`?

A direct ES bulk insert was considered but rejected: it would bypass
Kibana's saved-objects migration pipeline, requiring the test to
manually track the correct index name (`ANALYTICS_SAVED_OBJECT_INDEX`),
document format, and migration version fields. Any change to the
`visualization` type registration or storage model would silently break
the test setup without a compile-time or schema error.

## Test plan

- [ ] Verify `returns the correct count for each included types` passes
on `cloud-stateful-classic` (ECH) in CI

Made with [Cursor](https://cursor.com)
…astic#265448)

Closes elastic#264179

## Summary
- Wraps all Zod schema definitions in `@kbn/connector-schemas` with
`lazySchema()`
Closes elastic#259501

## Summary

- Converted `connect/disconnect` actions from icon buttons to
`EuiButton` components
- Display a single loading button with "Connecting..." text (with
spinner) during both isConnecting and isAwaitingCallback states, with a
cancel (X) icon alongside during the awaiting callback phase
- Show "Disconnecting" text on the disconnect button during disconnect
loading state
- Moved the `Preconfigured` badge underneath the connector name in the
name column
## Summary

Fix elastic#259082

**How it was fixed**

When the visualization finishes reloading (signaled by `dataLoading$` →
`false`), the editor re-runs `getSuggestions` for the last submitted
ES|QL query with current time/filters so `dataGridAttrs` (the results
section) stays in sync with what the chart just used. Additionally,
`suppressNextChartLoadGridRefreshRef` avoids a duplicate grid fetch
right after submit.

<details>

<summary>Before</summary>


https://github.com/user-attachments/assets/22744171-9cb5-40b8-bb59-73beb9d9953e

_Changing the time range or applying filters updated the visualization
but did not refresh the “ES|QL query results” section._

</details>

<details>

<summary>After</summary>


https://github.com/user-attachments/assets/2045ea91-9001-42d2-b5b1-1e05bf0c2f1a

_Changing the time range or applying filters updates the visualization
and refreshes the “ES|QL query results” section._

</details>

## Checklist

- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
…tic#265482)

Closes elastic#264180
## Summary

Wraps all Zod schema definitions in `@kbn/connector-specs` with
`lazySchema()`
…lastic#267642)

## Summary

Closes elastic#266720



https://github.com/user-attachments/assets/377dec6a-bc4e-4c2e-8206-2ee29ea88b42



Fixes the ES|QL values control flyout so the Save button is disabled
when the values query has been edited after the last successful run.

Now if the query text changes, it can no longer be saved until the query
is run again

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Stratou <efstratia.kalafateli@elastic.co>
…elastic/ml-ui` files (elastic#267698)

Resolves 74 ESLint `@elastic/eui/icon-accessibility-rules` violations
across 47 files owned by `@elastic/ml-ui`.

## Changes

- Added `aria-hidden={true}` to decorative `EuiIcon` components (icons
adjacent to text labels)
- Added `aria-label` where icons convey meaning independently (e.g.,
status indicators)

Affected packages/plugins: `@kbn/aiops-components`, `@kbn/file-upload`,
`data_visualizer`, `aiops`, `ml`

**Example:**
```tsx
// Before
<EuiIcon type="checkCircleFill" color={euiTheme.colors.success} />

// After
<EuiIcon aria-hidden={true} type="checkCircleFill" color={euiTheme.colors.success} />
```

## Checklist
- [x] Added label `a11y:agent-pr`
- [x] Fixed all 47 files listed in the issue

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: alexwizp <20072247+alexwizp@users.noreply.github.com>
Co-authored-by: Alexey Antonov <alexwizp@gmail.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Closes elastic/obs-ai-team#533
Closes elastic/obs-ai-team#536
Closes elastic/obs-ai-team#534
Closes elastic/obs-ai-team#535

This PR introduces an evaluation dataset along with corresponding tests
for AI Insights across different scenarios.

**Added:**

1. **Error AI Insights** eval tests with the productCatalogFailure
feature
2. **Alert AI Insights** eval tests with paymentUnreachable 
3. **Logs AI Insights** eval tests with productCatalog and
paymentUnreachable scenarios

These tests aim to improve coverage and ensure consistent evaluation
across key AI Insights use cases.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
…pecific policy assignment (elastic#267647)

## Summary

Adds a Fleet setting for setting the task interval for version-specific
policy assignment.

Related to: elastic/docs-content#4777

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...
## Summary

Small fix to make the license check more robust.
…lastic#267796)

## Summary

- Replaced `getByRole('progressbar')` in
`DashboardsTab.waitForDashboardsToLoad` with a wait for
`apmMainTemplateServiceAgentLoader` to be hidden. The generic
progressbar role matched multiple concurrent EUI loaders (chrome,
environment filter, service title, etc.) and caused Playwright **strict
mode** failures.
- Extended `waitForTabLoad` on the dashboards tab to wait for the same
main template loader after the unified search bar is visible, matching
`MetricsTab` / `ServiceDetailsPage.goToPage` and stabilizing navigation
before the unlink test.

## Testing

- Ran `service_dashboards.spec.ts` locally — passed. Expect serverless
observability Scout (`local-serverless-observability_complete`) to
validate after CI merges.

Cc flaky Scout/serverless monitoring: worth confirming stability once
merged.

Closes elastic#256350


Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary

This is stage 1 of the migration, see [[Epic] [Cases] Migrate away from
io-ts](elastic/security-team#16437)

This implements all io-ts types as zod schemas; a stepping stone towards
full migration

None of the types are used for validation yet, they will be enforced in
future PR's that will follow this one.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary

Add a new `callContext` property to tool handler context to expose the
following info:
- tool id
- tool call id
- call source (`user`/`agent`/`mcp`)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…stic#260544)

## Summary

- Migrates the endpoint case attachment from the legacy
`ExternalReferenceAttachmentType` to the new unified
`UnifiedReferenceAttachmentType` on both client and server.
- New endpoint response-action attachments are written as `{ type:
'security.endpoint', attachmentId, metadata }`
(`UnifiedReferenceAttachmentPayload`) instead of the legacy
`externalReference` shape.
- Adds server-side `io-ts` schema validation for endpoint attachment
metadata (`command`, `comment`, `targets[]` with a closed union on
`agentType`, unknown keys rejected, non-empty `targets` required).
- Adds a generic `externalReference` ↔ unified transformer in the Cases
plugin so pre-existing legacy endpoint attachments render as unified on
read and unified writes fall back to legacy storage when the new SO type
is disabled — no data migration required.

## Details

Part of the [Cases Attachments v2
migration](elastic/security-team#15569). The
endpoint attachment (historically `externalReferenceAttachmentTypeId:
'endpoint'`) is now registered as the unified type
`SECURITY_ENDPOINT_ATTACHMENT_TYPE = 'security.endpoint'`, re-exported
from `@kbn/cases-plugin/common`.

### What changed

| Layer | Before | After |
|-------|--------|-------|
| Client registration (`security_solution/public/plugin.tsx`) |
`registerExternalReference(getExternalReferenceAttachmentEndpointRegular())`
| `registerUnified(getEndpointUnifiedAttachment())` |
| Server registration (`security_solution/server/plugin.ts`) |
`registerExternalReference({ id: CASE_ATTACHMENT_ENDPOINT_TYPE_ID })` |
`registerUnified({ id: SECURITY_ENDPOINT_ATTACHMENT_TYPE,
schemaValidator: validateEndpointAttachmentMetadata })` |
| Attachment creation (`base_response_actions_client.ts`) | `{ type:
'externalReference', externalReferenceId, externalReferenceStorage,
externalReferenceAttachmentTypeId: 'endpoint', externalReferenceMetadata
}` | `{ type: 'security.endpoint', attachmentId, metadata, owner }` |
| Metadata validation | none | `io-ts` validator run on the unified
write path |
| Client-side renderers | `external_reference.tsx` + 2 lazy wrappers |
`unified_attachment.tsx` + updated `endpoint_event.tsx` /
`endpoint_children.tsx` |
| Constant `CASE_ATTACHMENT_ENDPOINT_TYPE_ID` | defined in Security
Solution | removed; import `SECURITY_ENDPOINT_ATTACHMENT_TYPE` from
`@kbn/cases-plugin/common` |

### Backward compatibility (no data migration needed)

The legacy `registerExternalReference` calls are removed — BWC is
delivered instead by a generic transformer in the Cases plugin:

- **Read path** — the Kibana Cases UI reads cases via the internal
`resolve` endpoint with `mode: 'unified'`. The new
`externalReferenceAttachmentTransformer` in
`x-pack/platform/plugins/shared/cases/server/common/attachments/external_reference.ts`
converts any pre-existing legacy `externalReference` endpoint
attachments stored in `cases-comments` into the unified
`security.endpoint` shape on read, driven by
`EXTERNAL_REFERENCE_TYPE_MAP`. Existing cases render identically
post-deploy without any backfill.
- **Write path** — when `xpack.cases.attachments.enabled` is `false`
(default), the Cases plugin translates the unified payload back to the
legacy `externalReference` shape via `toLegacySchema` and persists it to
`cases-comments` — byte-for-byte equivalent to today's storage. When the
flag is `true`, the unified payload is stored as-is in the new
`cases-attachments` SO. Either way, the on-disk format stays consistent
with whatever the deployment is already using.

This also gives follow-up subtypes (e.g. `osquery`, other
response-action types) a clean seam: add an entry to
`EXTERNAL_REFERENCE_TYPE_MAP` / `UNIFIED_TO_EXTERNAL_REFERENCE_TYPE_MAP`
and they get the same round-trip behaviour for free.

### Public case APIs

`GET /api/cases/:id` (`totalComment`) and `GET
/api/cases/:id/comments/_find` continue to be scoped to user-generated
comments and do not surface endpoint attachments — this is pre-existing,
intended behaviour and is unchanged by this PR. The Kibana UI uses the
internal `resolve` endpoint which returns all attachment types and
renders endpoint attachments via the new unified registry.

## Incremental fixes after first review

A second pass addressed three review items from @szwarckonrad on the
upgrade-path walkthrough, plus one CI-driven snapshot follow-up. None of
them change the design described above; they harden the same migration
against edge cases the first pass missed.

1. **Back-compat for legacy-shape API writes**
(`security_solution/server/cases/attachments/register.ts` + `plugin.ts`)
— the legacy `endpoint` external-reference id is registered alongside
the new unified `security.endpoint` so existing API clients that still
POST `{ type: 'externalReference', externalReferenceAttachmentTypeId:
'endpoint', ... }` are not rejected with `400 "Attachment type endpoint
is not registered."`. The cases server's external-reference transformer
already converts these legacy SOs to the unified shape on read; this
restores the same behaviour for legacy-shape *writes*. Covered by a
focused unit test (`register.test.ts`) that explicitly asserts the BWC
registration so it can't be silently dropped in a future refactor.

2. **400 instead of 500 from the metadata validator**
(`endpoint_metadata_schema.ts`) — `validateEndpointAttachmentMetadata`
now throws `Boom.badRequest` on invalid metadata. Errors thrown from a
registered cases-plugin `schemaValidator` callback are surfaced to the
HTTP client as-is — a plain `Error` would have bubbled up as `500
Internal Server Error` with a stack trace in the server log for what is
really a caller mistake. Covered by new tests asserting `Boom.isBoom`
and `statusCode: 400` for
null/non-object/missing-fields/empty-targets/unknown-keys inputs.

3. **Byte-clean legacy storage**
(`cases/server/services/attachments/index.ts`) — when a unified payload
(`{ type: 'security.endpoint', attachmentId, metadata }`) is POSTed but
`xpack.cases.attachments.enabled` is OFF, the request attributes still
carry those keys after `io-ts` decoding and could leak into `_source`
(the `cases-comments` mapping is `dynamic: false`, so they would be
stored but not indexed). The new `stripUnifiedOnlyFields` helper
guarantees byte-for-byte equivalence with pre-migration legacy writes
for `create`/`bulkCreate`/`update`/`bulkUpdate`. Covered by two
regression tests in `services/attachments/index.test.ts`.

4. **Snapshot follow-up for #1**
(`cases_api_integration/.../external_references.ts`) — the
registry-snapshot assertion that guards the externalReference registry
now expects `endpoint: 'e13fe41b5c330dd923da91992ed0cedb7e30960f'`
again, with an inline comment explaining the BWC intent. **This file is
owned by Response Ops via CODEOWNERS** — the snapshot's purpose is
exactly to surface this kind of change for their review.

CI on the latest push: green (build #437809, 428/428 jobs).

## Test plan

- [x] Unit tests for the generic `externalReference` ↔ unified
transformer, storage-type resolver, and type-routing helper
(`x-pack/platform/plugins/shared/cases/server/common/attachments/*.test.ts`).
- [x] Unit tests for `validateEndpointAttachmentMetadata` covering:
valid metadata, each missing required field, empty `targets`, invalid
`agentType`, unknown top-level keys, and non-object input.
- [x] Updated `endpoint_actions_client` and
`base_response_actions_client` unit tests assert the new unified payload
shape (`type: 'security.endpoint'`, `attachmentId`, `metadata`).
- [x] Updated unit tests for `endpoint_event.tsx` /
`endpoint_children.tsx` against the unified props shape.
- [x] Integration-test registry expectations updated:
`security.endpoint` appears in `registered_unified_{basic,trial}.ts`.
`endpoint` is **kept** in `external_references.ts` with a comment
explaining the back-compat re-registration (see "Incremental fixes after
first review" below).
- [x] Type check and lint pass.
- [x] Manual end-to-end validation against **Microsoft Defender for
Endpoint** — unisolate action from Kibana correctly produces a
`cases-attachments` SO of `type: 'security.endpoint'` with
`microsoft_defender_endpoint` metadata, rendered by the UI via the
unified registry.
- [x] Manual end-to-end validation against **CrowdStrike Falcon** —
unisolate action from Kibana correctly produces a `cases-attachments` SO
of `type: 'security.endpoint'` with `crowdstrike` metadata, rendered by
the UI via the unified registry.
- [x] Manual verification: isolate a host via response actions and
confirm the case attachment renders correctly.

<img width="1798" height="1064" alt="CleanShot 2026-04-20 at 14 53
16@2x"
src="https://github.com/user-attachments/assets/8c216722-a2a4-42ac-b5ae-dc8962cb2d0d"
/>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Moves recently added licence checks to the `ml_license.ts` file and
renames them.
…astic#266524)

## Summary

- Improve error handling of errors, specifically those thrown by ES/SO
clients
- Logic in `wrapErrorIfNeeded()` will now check to see if the error
being wrapped is from ES and if so, it will attempt to generate a better
error message as well as capture additional debug data
Closes elastic#265639

## Summary

- Fix Service map embeddable
- Changed things in apex QA files to give us the option to use custom
timeouts, a number of the crashes was because the current hardcoded
timeouts aren't enough to pass in the CI (examples: [Comment
1](elastic#265639 (comment)),
[Comment
2](elastic#265639 (comment)),
[Comment
3](elastic#265639 (comment)))


### Ran against ECH environment

<img width="1918" height="1134" alt="image"
src="https://github.com/user-attachments/assets/de731bbf-2825-420f-bd29-6bb0baae5887"
/>


### How to run

#### Server

`node scripts/scout.js start-server --arch stateful --domain classic`

#### Client

`npx playwright test --project local --ui --config
x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel.playwright.config.ts`


#### On ECH

`npx playwright test --project=ech --ui --config
x-pack/solutions/observability/plugins/apm/test/scout/ui/parallel.playwright.config.ts`

### Checklist

- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed [(last successful
run)](elastic#267540 (comment))
…stic#224746) (elastic#267805)

closes elastic#224746

## Summary


When a screen reader user opened the **Add attachments** flyout on the
individual stream page (Attachments tab → "Add attachment" button),
VoiceOver announced the dialog as just *"…modal dialog…"* with no
accessible name — leaving non-sighted users with no idea which dialog
they had just entered.

The flyout already had `aria-labelledby` pointing to the `<h2>` header,
but in practice VoiceOver + WebKit silently failed to compute the
accessible name from that IDREF (the id contained colons from React's
`useId()`), and there was no fallback. The result was an empty
accessible name, which violates **WCAG 2.1 SC 1.3.1 — Info and
Relationships (Level A)**.

### Fix

Replaced `aria-labelledby` (which silently resolved to an empty
accessible name in VoiceOver) with a direct `aria-label` on `EuiFlyout`,
sourced from the same i18n string as the visible `<h2>` heading.

VoiceOver now announces:

> **"Add attachments, dialog, with 6 items. You are in a modal dialog.
Press Escape or tap/click outside the dialog on the shadowed overlay to
close…"**

<img width="2359" height="1266" alt="image"
src="https://github.com/user-attachments/assets/10ae6d6d-0f13-4d64-81c7-ccda1720bdf7"
/>

The visible `<h2>` heading is preserved for sighted users; the i18n
constant is shared between the visible text and the accessible name so
they cannot drift.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
…zations API pages (elastic#267776)

## Summary

Fixes 6 broken cross-page anchor links in the dashboards and
visualizations API overlays, following the split of the combined spec
into separate pages (see elastic/dashboards-api-spec#7).

Previously both pages were rendered together, so
`#operation/post-visualizations` and `#operation/post-dashboards` worked
as same-page anchors. Now that each API has its own page,
cross-references need to include the sibling page in the URL.

**`dashboards.overlays.yaml`** — 3 links updated:
- `#operation/post-visualizations` →
`visualizations#tag/Visualizations/operation/post-visualizations`

**`visualizations.overlays.yaml`** — 3 links updated:
- `#operation/post-dashboards` →
`dashboards#tag/Dashboards/operation/post-dashboards`

Same-page self-links (`#operation/post-dashboards` on the dashboards
page and `#operation/post-visualizations` on the visualizations page)
are unchanged.

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary
When entering full-screen mode on the entities table and opening the
Agent Builder chat, the chant sidebar and its resize handle were hidden
behind the DataGrid overlay but still account for when positioning the
flyout

- `use_full_screen_watcher.ts` + `layout_sidebar.tsx`: introduced a
`data-kbn-preserve-zindex` attribute to exclude elements from the
full-screen z-index reset. This is added to the Chrome sidebar to
preserve its stacking context
- `grid_global_app_style.tsx`: added a constrain to the grid's right
edge (_var(--kbn-layout--sidebar-width)_), so the full-screen DataGrid
no longer covers the sidebar column when the Agent Builder chat is open

## How to test

1. Start Elasticsearch locally
2. Start Kibana locally
      <details>
        <summary>feature flags used</summary>
   
        uiSettings:
          overrides:
            agentBuilder:experimentalFeatures: true
            securitySolution:entityStoreEnableV2: true
        
        xpack.securitySolution.enableExperimental:
          - entityAnalyticsEntityStoreV2
          - entityAnalyticsNewHomePageEnabled
      </details>
3. Add at least one entity to test
    <details>
          <summary>Kibana Dev Tools</summary>

          POST .entities.v2.latest.security_default-00001/_doc
          {
            "@timestamp": "2026-05-01T12:00:00.000Z",
            "user": { "name": "test.user" },
            "entity": {
              "name": "test.user",
              "type": "Identity",
              "id": "user:test.user",
"EngineMetadata": { "Type": "user", "UntypedId": "test.user" }
            }
          }
      </details>
4. Navigate to Security → Entity Analytics
5. Scroll to the entities table and click the full-screen icon
6. Click any entity row to open the entity flyout
7. Click _Add to chat_: click on expand details -> risk contribution to
see the button
8. Confirm that the Agent Builder sidebar is visible and the resize
handle on the sidebar's left edge is visible and draggable

### Before

<img width="1917" height="842" alt="Screenshot 2026-05-01 at 5 08 58 PM"
src="https://github.com/user-attachments/assets/1deaa2f3-b753-4092-9fc9-ade31879f3f3"
/>

### After


https://github.com/user-attachments/assets/829a60fc-80cc-4318-98a8-a69a65a4f89e
Closes elastic/rna-program#446

## Summary

This PR creates a new `WorkflowExtensionsService` and does the wiring
for registering workflow triggers and steps in the alerting v2 plugin.

## How registration works

I created a README with this information, but:

1. Define a shared trigger definition in `common` (`id` + `eventSchema`)
with Zod.
2. Register it on the server in
`server/lib/workflow_extensions/register_trigger_definitions.ts` via
`registerTriggerDefinitions(service)`, which calls
`WorkflowExtensionsService.registerTriggerDefinitions(...)`.
3. Define a public trigger definition (`PublicTriggerDefinition`) with
UI metadata (title, description, icon, docs).
4. Register it on the public side in
`public/lib/workflow_extensions/register_trigger_definitions.ts` via
`registerTriggerDefinitions(service)`.
5. Add/update the trigger schema hash in:
-
`src/platform/plugins/shared/workflows_extensions/test/scout/api/fixtures/approved_trigger_definitions.ts`
   
To confirm a trigger was created correctly:

How to visualize this in the UI
1. Start Kibana normally (your local dev workflow).
2. Go to Management -> Workflows.
3. Create/edit a workflow and open trigger selection.
4. Look for your trigger title
5. Open its docs panel; you should see the configured
description/example from translations.ts.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
… setup hook (elastic#267958)

Similar work to elastic#267910 - set
`discover.isEsqlDefault` to `false` to unblock Scout serverless
pipeline.
)

resolves elastic/kibana-team#3144

## Summary

Adds a `ci:skip-so-check` PR label that, when present, skips the "Check
changes in Saved Objects" CI step entirely. This gives contributors an
escape hatch for unrelated false positives so that the SO check can be
moved toward hard-fail enforcement without holding the whole repo
hostage to the next unanticipated edge case.

### Problem

- The "Check changes in Saved Objects" step is intended to become a
hard-blocking CI check, but historically has produced false positives in
cases the rules don't yet model (e.g. `Joi` version bumps that change
snapshot hashes without changing semantics, no-op schema refactors).
- Today there is no per-PR way to bypass the check when one of these
edge cases surfaces; every contributor would have to wait for a
Core-side fix.

### Solution

- Gate the existing SO-check pipeline step on
`!GITHUB_PR_LABELS.includes('ci:skip-so-check')` in
`.buildkite/scripts/pipelines/pull_request/pipeline.ts`, following the
same pattern as `ci:skip-cypress-osquery` and
`agent-builder:skip-smoke-tests`.
- When the label is present, the step is simply not emitted into the
generated pipeline.
- Document the label and its intended use in
`packages/kbn-check-saved-objects-cli/README.md` under the existing "How
it is used in CI" section.

## How to test

1. Open a PR that touches one of the gating paths (e.g.
`packages/kbn-check-saved-objects-cli/current_fields.json`) and confirm
the "Check changes in Saved Objects" step appears in Buildkite as today.
2. Add the `ci:skip-so-check` label to the PR, re-run the pipeline
build, and confirm the step is no longer emitted.
3. Remove the label and confirm the step reappears on the next pipeline
build.

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

- Misuse of the label could allow a real, unsafe Saved Object change to
merge without validation. Mitigated by the README guidance restricting
the label to false positives, and by the fact that the label is opt-in
per PR and visible to reviewers.
- No risk to existing PRs that do not apply the label — the gating
condition is purely additive.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Depends on elastic/elasticsearch#147811


Resolves elastic/search-team#14191
Resolves elastic/search-team#14190


## Summary

This PR adds a dedicated OpenTelemetry trace export path for **Agent
Builder inference spans**, so they can land in Elasticsearch under a
distinct dataset (`agent_builder`) while reusing Kibana’s Elasticsearch
connection (auth, TLS, transport). Generic tracing can remain sampled
down without silently dropping inference work: inference spans
identified via `kibana.inference.tracing` baggage are preserved through
sampling so downstream processors can export them on a copy.

**Why:** Agent Builder observability needs reliable inference-span
export and routing into its own traces data stream, aligned with
Elasticsearch’s native OTLP traces ingestion (`/_otlp/v1/traces` from
elastic/elasticsearch#147811).

## Architecture

- **`@kbn/tracing` — `InferencePreservingSampler`** wraps the existing
`ParentBasedSampler` in `init_tracing.ts`. Non-inference spans pass
through unchanged. Inference spans upgrade `NOT_RECORD` to `RECORD`
(without forcing `SAMPLED`) so domain processors can clone and set
`SAMPLED` for their pipeline.
- **`@kbn/inference-tracing` — `ElasticsearchOtlpExporter`** serializes
spans with `@opentelemetry/otlp-transformer` and POSTs OTLP-protobuf to
ES `/_otlp/v1/traces` via the ES client transport (same connection
settings as Kibana).
- **`should_track_span.ts` / `isInferenceSpan()`** extracts “should
track” logic from `BaseInferenceSpanProcessor.onStart`; shared by
`BaseInferenceSpanProcessor` and Agent Builder.
- **`agent_builder` — `AgentBuilderSpanProcessor`** copies eligible
spans, forces `SAMPLED` on the copy for export, adds
`data_stream.dataset: agent_builder`, and feeds a `BatchSpanProcessor`.
Enabled state comes from an LRU-backed saved-objects check against
`AGENT_BUILDER_EXPERIMENTAL_FEATURES_SETTING_ID`.
- **`register_tracing.ts`** chooses **`OTLPTraceExporter`** when a trace
URL is configured, otherwise **`ElasticsearchOtlpExporter`**; registers
via `LateBindingSpanProcessor.register()`.
- **Lifecycle:** exporter registration in `plugin.ts` `start()`, async
teardown in `stop()`.

```mermaid
flowchart LR
  subgraph tracing["Global tracing"]
    S["InferencePreservingSampler"]
    P["Span processors"]
  end
  subgraph ab["Agent Builder"]
    AB["AgentBuilderSpanProcessor"]
    BSP["BatchSpanProcessor"]
    E["OTLP URL exporter OR ElasticsearchOtlpExporter"]
  end
  S --> P
  P --> AB
  AB --> BSP --> E --> ES["Elasticsearch traces"]
```


### Package exports

- **`@kbn/tracing`:** `InferencePreservingSampler` (wired in
`init_tracing.ts`).
- **`@kbn/inference-tracing`:** `ElasticsearchOtlpExporter`,
`isInferenceSpan` / `should_track_span` helpers (via new module),
existing processors updated to use shared inference detection.

## How to test

1. Make sure your ES instance has the otlp endpoint enabled
elastic/elasticsearch#147811
2. Enable agent builder experimental setting
`agentBuilder:experimentalFeatures`
3. Enable Kibana tracing `telemetry.tracing.enabled: false`
4. Run a query through Agent Builder.
5. Confirm Agent Builder spans exist under `.ds-traces-agent_builder*`.

If the evals plugin is enabled `xpack.evals.enabled: true` you will see
a view traces button in agent builder the reasoning panel.

<img width="787" height="277" alt="Screenshot 2026-04-30 at 11 02 04"
src="https://github.com/user-attachments/assets/9a891a63-436c-4302-af48-3027406c8d1f"
/>
<img width="624" height="805" alt="Screenshot 2026-04-30 at 11 02 06"
src="https://github.com/user-attachments/assets/d1493730-8ef4-4c66-a50d-8237a24d0180"
/>

### Checklist

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
_(no product UI strings in this PR — server tracing/config only)_
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios **(not in this
PR yet — follow-up)**
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
**(`agent_builder.tracing.*` added — cloud/docker follow-up required
before merge)**
- [x] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
_(no breaking public HTTP API changes)_
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed _(no tests changed in this PR yet)_
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels. **`backport:skip`** — new
feature; no backport planned via this PR.

### Third-party Dependency
**Purpose:** Serializes ReadableSpan[] into OTLP-protobuf binary format
(ProtobufTraceSerializer.serializeRequest()) so the
ElasticsearchOtlpExporter can POST spans to ES's /_otlp/v1/traces via
the ES client transport — no separate OTLP collector needed.

**Justification:** The existing OTLP exporters
(exporter-trace-otlp-proto) bundle their own HTTP transport and can't
route through the ES client. We need the serialization layer standalone
to reuse Kibana's ES connection (auth, TLS).

**Alternatives explored:**

* Use exporter-trace-otlp-proto directly: Can't — it owns its HTTP
connection and can't use the ES client transport. We do use it for the
external OTLP URL path; the ES path needs standalone serialization.
* Implement serialization manually: OTLP-protobuf encoding is
non-trivial (protobuf schema, resource/scope/span mapping, attribute
encoding). Fragile and would drift from the spec.

**Existing dependencies:** Already a direct dep in root package.json
(0.214.0) and resolved in yarn.lock (3 versions). Transitively pulled by
exporter-trace-otlp-proto, exporter-trace-otlp-http,
exporter-logs-otlp-*, otlp-exporter-base, and sdk-node. No new package
enters node_modules — this PR just adds a direct import from
kbn-inference-tracing.


### Identify risks

- [x] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)

| Risk | Severity | Mitigation |
| --- | --- | --- |
| **Global sampling interaction** — `InferencePreservingSampler` changes
when inference spans are recorded vs dropped relative to parent-based
sampling. | Medium | Scoped to baggage-marked inference spans;
non-inference spans unchanged. Review trace volume and cardinality in
staging; validate alongside inference and platform tracing owners. |
| **Elasticsearch OTLP dependency** — native `/_otlp/v1/traces` must be
available and compatible for the fallback exporter path;
misconfiguration could mean lost or failed exports. | Medium | Depends
on elastic/elasticsearch#147811; test both OTLP URL and ES-transport
paths; monitor exporter errors and ES responses. |

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
… list creation to screen readers (elastic#267588)

Fixes elastic#247067

When a shared exception list is created, the user is navigated to the
detail page with no screen reader announcement.

**Fix:** pass the list name as router state on navigation; on the detail
page, derive a message from that state and render it in
`EuiScreenReaderLive` with `focusRegionOnTextChange`. The
`focusRegionOnTextChange` prop is required - the default aria-live
toggle path fails silently in VoiceOver+Safari (noted in EUI source).
The component is conditionally rendered to avoid stealing focus on page
mounts where no list was just created.
Closes elastic#266173

## Summary

- Added multiple information in the storybooks about the service map SLO
and Alert Badges
- List of pages affected/added (check be checked
[here](https://ci-artifacts.kibana.dev/storybooks/pr-267949/apm/index.html)):
    - `?path=/story/app-servicemap-servicenode--alert-badges`
    - `?path=/story/app-servicemap-servicenode--slo-badges`
    - `?path=/story/app-servicemap-servicenode--alert-and-slo-combined`
    - `?path=/story/app-servicemap-servicemap--generate-map`
    - `?path=/story/app-servicemap-popover--service-with-alerts`
    - `?path=/story/app-servicemap-popover--service-with-slo`
    - `?path=/story/app-servicemap-popover--service-with-all-badges`


### Video showing the generate map (new options)



https://github.com/user-attachments/assets/344dc754-7d53-4480-92c2-b98d44eb78f0


### How to test it locally

Just run 

- `yarn storybook apm`
mattnowzari and others added 26 commits May 8, 2026 13:13
## Summary

Replaces `<account>` with `{account}` inside the Snowflake connector's
`i18n` message strings as well as placholder URL text.

The presence of angle brackets was causing error messages on Kibana
startup:

```
installHook.js:1 Error: [@formatjs/intl Error FORMAT_ERROR] Error formatting default message for: "core.kibanaConnectorSpecs.snowflake.auth.oauth.authorizationUrl.helpText", rendering default message verbatim
MessageID: core.kibanaConnectorSpecs.snowflake.auth.oauth.authorizationUrl.helpText
Default Message: Snowflake OAuth authorization URL. Replace <account> with your Snowflake account identifier.
Description: undefined

installHook.js:1 Error: [@formatjs/intl Error FORMAT_ERROR] Error formatting default message for: "core.kibanaConnectorSpecs.snowflake.auth.oauth.tokenUrl.helpText", rendering default message verbatim
MessageID: core.kibanaConnectorSpecs.snowflake.auth.oauth.tokenUrl.helpText
Default Message: Snowflake OAuth token endpoint. Replace <account> with your Snowflake account identifier.
Description: undefined
```


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
## Summary

Ref: elastic#266825

This PR restores phrase-search behavior in the All Cases search bar that
regressed after elastic#245321 switched the cases search path from
`simple_query_string` (via SO `find`) to `multi_match`.

**After**

`test case` (without quotes) matches cases with word `test` or `case`
<img width="1033" height="253" alt="image"
src="https://github.com/user-attachments/assets/d3c9cb2f-69b7-4406-83c3-4f806399a56e"
/>


`"test case"` matches cases with phrase `test case`
<img width="1020" height="192" alt="image"
src="https://github.com/user-attachments/assets/308ef4d9-b1b8-4091-9325-7cfc59224a73"
/>


## How to test
1. Create a few cases with titles like `my awesome case`, `another
case`, `awesome work`.
2. In the All Cases page, search for `"awesome case"` (with quotes) and
confirm only `my awesome case` matches.
3. Add a comment containing `connection refused` to one case, then
search `"connection refused"` and confirm only that case matches.
4. Confirm unquoted multi-token search (`awesome case`) still returns
OR-style results, matching pre-elastic#245321 behavior.

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
…ssure (elastic#268498)

Disables video recording in the management Cypress suite
(`cypress_base.config.ts`). Videos were previously recorded and then
deleted for passing specs via `getVideosForFailedSpecs`, but the
recording itself still caused disk writes during the run — contributing
to CI disk pressure observed in the vagrant-cluster test environments.

Setting `video: false` avoids the disk I/O entirely. The
`getVideosForFailedSpecs` helper is already guarded against this (`if
(results && results.video)`) so it becomes a clean no-op.
…#263585)

Removes skipped flaky integration tests that are already covered by unit
tests or were testing external system behavior rather than our code.

### elastic#175791 — metadata transforms stats tests

The `describe.skip('get metadata transforms')` suite was testing that
our `METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE` API correctly returns
transform stats in started/stopped states. The flakiness was a race
condition — the previous test stops both transforms then restarts them,
but the restart hadn't fully completed before the next test asserted
STARTED state (`expected 1 to sort of equal 2`).

The route handler is a pure pass-through: it calls
`esClient.transform.getTransformStats()` and returns the result. The
meaningful coverage (authz check, correct ES call, response forwarding)
is already provided by unit tests in `metadata.test.ts`. The integration
tests were only validating that Elasticsearch transform state
transitions work — not our responsibility.

**Removed:** 3 skipped tests + unused imports/variables.

Closes elastic#175791
Update dispatcher readme to align with action policy terminology changes
across classes and interfaces
## Summary

Enables scoping agents to a subset of configured connectors, and adjusts
SML search to only the connectors that are enabled for the current
Agent.

To test:
1. enable the experimental feature flag
2.  create some connectors
3. go to the Agent UI, and type `@` (all your connectors auto-complete)
4. update the agent to just a subset of connector IDs
```
PUT kbn://api/agent_builder/agents/elastic-ai-agent                                                                                                   
{
  "configuration": {
    "connector_ids": [
      "<connector-id-1>",
      "<connector-id-2>"
    ]
  }
}
```

5. then go to the Agent UI and type `@` (only your configured connectors
auto-complete)


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Release Notes

Introduces an optional configuration for Agent Builder Agents:
`connector_ids`. If unset, a given agent has access to all configured
kibana connectors. When set, the Agent will have access only to the
listed connectors.
…lastic#268521)

Adds Fleet experimental features flag `enableIntegrationConditions` to support the work in: elastic#206012
…YAML editor (elastic#267667)

Before 
<img width="370" height="235" alt="image"
src="https://github.com/user-attachments/assets/98e6bc67-e6ab-40a0-98eb-c012774a26c4"
/>

After
<img width="410" height="264" alt="image"
src="https://github.com/user-attachments/assets/639634ef-717f-4b59-bc69-5e03c416cfea"
/>


## Summary

Replaces the default gray Monaco word-occurrence highlight (visible in
the workflows YAML editor when the cursor sits on a token like `name` or
`type`) with `euiTheme.colors.backgroundLightPrimary`, so the highlight
matches the EUI primary accents already used elsewhere in the editor
(selection, hover) instead of reading as a generic gray box.

The override is scoped via `[data-test-subj='workflowYamlEditor']` so it
only affects the workflows YAML editor — no impact on other Monaco
editors in Kibana.

### Before / After

- **Before:** Monaco's default neutral gray `wordHighlightText`
background.
- **After:** EUI `backgroundLightPrimary`, visually consistent with the
rest of the editor's primary-tinted highlights.

## Test plan

- [ ] Open a workflow in the workflows YAML editor.
- [ ] Place the cursor on a YAML key (e.g. `name`, `type`) — all
matching occurrences should be highlighted in soft EUI primary blue, not
gray.
- [ ] Verify the change does NOT bleed into other Monaco-based editors
in Kibana (Console, Lens formula bar, etc.).
- [ ] Verify in both light and dark EUI themes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
ES snapshots should trigger a cache update within an hour after an
upgrade.

During the interim period, or if there are cache update failures, we're
finding the parallelized number of download requests becoming
problematic. If there's a cache update issue, it will be fixed with the
same priority as a snapshot build.
…68164)

## Summary


https://github.com/user-attachments/assets/c19099e6-23e8-439f-9996-c4a2efddaa2e

Closes elastic#265896 

Adds a quick edit flyout to the v2 alerting rule list page, allowing
users to edit a subset of rule fields inline without navigating to the
full edit page.

### Entry points
- **Pencil icon in rule summary flyout** transforms the flyout in-place
to edit mode
- **Pencil icon in rule list table** opens the quick edit flyout
directly from the actions column

### Editable fields
- Name, Description, Tags
- Grouping key, Time field
- Interval , Lookback window 
- Alert delay, Recovery type, Recovery delay

### Read-only fields
- ES|QL query (displayed as code block)
- Track active/recovered state (disabled checkbox with tooltip)

### Changes

**New files:**
- `quick_edit_rule_flyout.tsx` — the quick edit flyout component
- `quick_edit_rule_flyout.test.tsx` — unit tests

**`@kbn/alerting-v2-rule-form` package:**
- `kind_field.tsx` — added `disabled` and `compact` props. Compact mode
renders a flat `EuiCheckableCard` with an `EuiIconTip` tooltip instead
of inline description text
- `gui_rule_form.tsx` — added `isEditing` prop to disable `KindField` in
edit mode
- `rule_form.tsx` — propagates `isEditing` based on `ruleId` presence
- Exported field group components (`RuleDetailsFieldGroup`,
`ConditionFieldGroup`, `RuleExecutionFieldGroup`,
`AlertConditionsFieldGroup`, `KindField`) for modular reuse

**`alerting_v2` plugin:**
- `rule_summary_flyout.tsx` — added pencil icon + `onQuickEdit` prop,
bumped flyout size to `m`
- `rules_list_table.tsx` — added pencil icon in actions column
- `rules_list_table_container.tsx` — wires quick edit state with mutual
exclusivity (only one flyout open at a time), uses `key={rule.id}` to
force re-mount on rule switch
- `rule_summary_flyout.test.tsx` — added missing `onQuickEdit` prop +
test for pencil icon

#### Figma design for reference:
[URL](https://www.figma.com/design/tY4wbu3wXh4XK9p4MmYRLQ/RnA---Rule-Authoring-experience?node-id=1623-185133&t=4NKBSypfSS9mI97H-0)
…includedDataStreamNamespacesForRuleExecution` advanced settings to yaml file (elastic#266247)

## Summary

Adds the `cases:maxOpenCasesPerRuleRun` and
`securitySolution:includedDataStreamNamespacesForRuleExecution` advanced
settings to yaml file as per @florent-leborgne's
[request](elastic#263876 (review)).

---------

Co-authored-by: Florent LB <florent.leborgne@elastic.co>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
## Summary
AI assisted with Cursor + `gpt-5.4-high`

Adds a Github Workflow that automatically assigns a reviewer for manual
backports and removes `kibanamachine`. This avoids common confusion with
`kibanamachine` being the codeowner and improves DX. This workflow is
gated behind PRs where `kibanamachine` is not the author, therefore it
does not collide with backports that were created automatically and are
auto-approved through `.github/workflows/auto-approve-backports.yml`.

The reviewer is chosen with this algorithm:
1. Try to find the intersection of the PR author's teams and the
codeowner teams which submitted reviews in the source PR (via
`onBehalfOf` property).
2. If there are matching team(s), they are requested for review on the
backport.
3. If no matching teams were found, we fallback to the last human
reviewer that approved.
4. If that is also not found, this workflow is a no-op and
`kibanamachine` stays as the reviewer.

### Testing
I used a generated `json` event for an old backport:
elastic#260565. You can see the reviewers
changed at the bottom when running locally with `act`.

<details>

<summary>Local run</summary>

```zsh
➜ kibana (ci/assign-backport-reviewer) ✗ act pull_request_target \
  -W .github/workflows/assign-backport-reviewer.yml \
  -e data/assign-backport-reviewer.pull_request_target.pr-260565.json \
  --env GITHUB_REPOSITORY=elastic/kibana \
  --env GITHUB_REPOSITORY_OWNER=elastic \
  -s GITHUB_TOKEN="$(gh auth token)" \
  -s KIBANAMACHINE_TOKEN="$(gh auth token)"
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock' 
[Assign backport reviewer/Assign team reviewer for manual backport] ⭐ Run Set up job
[Assign backport reviewer/Assign team reviewer for manual backport] 🚀  Start image=catthehacker/ubuntu:act-latest
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker exec cmd=[node --no-warnings -e console.log(process.execPath)] user= workdir=
[Assign backport reviewer/Assign team reviewer for manual backport]   ✅  Success - Set up job
[Assign backport reviewer/Assign team reviewer for manual backport]   ☁  git clone 'https://github.com/actions/github-script' # ref=ed597411d8f924073f98dfc5c65a23a2325f34cd
[Assign backport reviewer/Assign team reviewer for manual backport] Non-terminating error while running 'git clone': some refs were not updated
[Assign backport reviewer/Assign team reviewer for manual backport]   ☁  git clone 'https://github.com/actions/github-script' # ref=ed597411d8f924073f98dfc5c65a23a2325f34cd
[Assign backport reviewer/Assign team reviewer for manual backport] Non-terminating error while running 'git clone': some refs were not updated
[Assign backport reviewer/Assign team reviewer for manual backport] ⭐ Run Main Select reviewers
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker cp src=/home/brad/.cache/act/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/ dst=/var/run/act/actions/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker exec cmd=[/opt/acttoolcache/node/24.14.1/x64/bin/node /var/run/act/actions/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/dist/index.js] user= workdir=
[Assign backport reviewer/Assign team reviewer for manual backport]   ✅  Success - Main Select reviewers [1.27416023s]
[Assign backport reviewer/Assign team reviewer for manual backport]   ⚙  ::set-output:: reviewer=jbudz
[Assign backport reviewer/Assign team reviewer for manual backport]   ⚙  ::set-output:: result=
[Assign backport reviewer/Assign team reviewer for manual backport]   ⚙  ::set-output:: team_reviewers=elastic/kibana-operations
[Assign backport reviewer/Assign team reviewer for manual backport] ⭐ Run Main Update reviewers
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker cp src=/home/brad/.cache/act/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/ dst=/var/run/act/actions/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/
[Assign backport reviewer/Assign team reviewer for manual backport]   🐳  docker exec cmd=[/opt/acttoolcache/node/24.14.1/x64/bin/node /var/run/act/actions/actions-github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd/dist/index.js] user= workdir=
| Updating reviewers: teamReviewers=elastic/kibana-operations, reviewer=jbudz
[Assign backport reviewer/Assign team reviewer for manual backport]   ✅  Success - Main Update reviewers [321.09717ms]
[Assign backport reviewer/Assign team reviewer for manual backport]   ⚙  ::set-output:: result=
[Assign backport reviewer/Assign team reviewer for manual backport] ⭐ Run Complete job
[Assign backport reviewer/Assign team reviewer for manual backport] Cleaning up container for job Assign team reviewer for manual backport
[Assign backport reviewer/Assign team reviewer for manual backport]   ✅  Success - Complete job
[Assign backport reviewer/Assign team reviewer for manual backport] 🏁  Job succeeded


```






</details>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary

Adds explicit `maxLength` validation to the body schema of `POST
/internal/security/login`.

| Field | maxLength | Notes |
|---|---|---|
| `providerType` | 1024 | Real values are short identifiers (`basic`,
`saml`, `oidc`, etc.); 1024 leaves substantial headroom and matches the
plugin's `OAUTH_MAX_STRING_FIELD_LENGTH` convention. |
| `providerName` | 1024 | Admin-defined in `kibana.yml`; 1024 fits any
realistic name. |
| `currentURL` | 8192 | Login redirects can include serialized Kibana
app state (Discover filters, Dashboard panel state, etc.); 8192 matches
typical web-server URL caps (Apache `LimitRequestLine`, Nginx
`large_client_header_buffers`). |
| `params.username` | 1024 | Matches the `maxLength: 1024` already
enforced on `username` in every other route under
`x-pack/platform/plugins/shared/security/server/routes/users/`. |
| `params.password` | 1024 | bcrypt only consumes 72 bytes; 1024 is well
above any realistic password policy. |

The values are intentionally generous to avoid breaking existing flows
(e.g., users logging in from deep-linked Kibana pages where `currentURL`
carries serialized app state).

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

- The new caps are large enough that any realistic login flow continues
to work unchanged.
- Requests exceeding the new limits will receive a `400 Bad Request`
from `@kbn/config-schema` validation rather than reaching the
authentication service.


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…stic#268318)

## Summary

This PR implements an optimization opportunity in the `getAll` method
implementation of the server side client in the UserStorage service.

* Replaces two parallel soClient.get() calls (one per scope) with a
single soClient.bulkGet() request
* Deletes the readSoData helper
* Detects missing docs via doc.error instead of catching
isNotFoundError.


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- ~[ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)~
- ~[ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials~
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- ~[ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~
- ~[ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.~
- ~[ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed~
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
## Summary

The 9.3.4 release notes (elastic#265129)
might've been accidentally overwritten or removed, so I'm re-adding them
in this PR.


[Preview](https://docs-v3-preview.elastic.dev/elastic/kibana/pull/268543/release-notes#kibana-9.3.4-release-notes)
Co-authored-by: Ryan Keairns <contactryank@gmail.com>
…t because of missing services (elastic#268249)

## Summary

This PR makes a super small couple of changes:

#### Fix wrong banner message

Move the `RemoteDocumentCallout` inside the `flyoutProviders` to ensure
that the `services` are setup correctly. There was an inconsistency when
opening the flyout in Discover (which was showing `This attack
originates from a linked project. Some features may not be available.`)
and opening the same flyout in a Dashboard where Discover is embedded
(which was showing `This attack originates from a remote cluster. Some
features may not be available.`).

#### Remove the `metadataCallout`

Remove the `EuiCallOut` for missing metadata when the `services` or
`store` aren't defined. This is for better consistency with the header
and footer sections of the flyout, which are currently both returning
`null`.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
…lastic#268557)

## Summary

Does what it says on the tin. Resolves
elastic#268166 flickering issue.

### Checklist

- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [x] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.
…show error in UI

Closes elastic#256168

## Summary

This PR improves error handling and visibility in the **log AI insight**
flow, especially in **Cross-Project Search (CPS)** scenarios.

It fixes an issue where “Explain this log entry” could fail with a **500
Internal Server Error** when the log originates from a **linked
project**, and ensures the UI displays the **Elasticsearch error
message** .


### Problem

This work addresses the issue using Kibana CPS: [[Logs][Discover]
"Explain this log entry" returns 500 for linked-project
elastic#256168](elastic#256168)

#### Root cause
- In **Cross-Project Search (Project = All)**, logs can originate from
**linked projects**
- When triggering **“Explain this log entry”**
- Elasticsearch can return `no_matching_project_exception ` or
`index_not_found_exception` error

### Solution
- Wrap log AI insight execution in error handling
- Detect missing index
- Return a **404 response with a meaningful error message**
- Log underlying errors for debugging
- Avoid falling back to generic 500 responses


### How to test

1. Setup a CPS environment with origin + linked project
2. In Discover:
   - Select **Project = All**
   - Open a log entry from the **linked project**
3. Trigger **“Explain this log entry”**
4. Verify:
   - No generic 500 error
   - API returns a meaningful error response
   - UI displays the error



https://github.com/user-attachments/assets/e0b7b140-9b7b-44d8-a49e-5c46349eb09f

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Viduni Wickramarachchi <viduni.wickramarachchi@elastic.co>
Co-authored-by: Viduni Wickramarachchi <viduni.ushanka@gmail.com>
…bility (elastic#266469)

The Anomaly score button in the Anomaly Explorer only announces its
selection value ("Multiple") to screen readers, missing the "Anomaly
score" title context. This violates WCAG SC 4.1.2 (Name, Role, Value).

Fixes elastic#264988

### Changes

- Added optional `aria-label` prop to `MultiSuperSelect` component,
forwarded to the inner `EuiButtonEmpty`
- Passed the "Anomaly score" label as `aria-label` in `SelectSeverityUI`
so assistive technology announces the full context

Screen readers will now announce: *"Anomaly score, Multiple, collapsed,
button"* instead of just *"Multiple, collapsed, button"*.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `ci-stats.kibana.dev`
> - Triggering command:
`/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node
/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node
scripts/yarn_install_scripts.js run x86-64.so.2 0.8.2 if (a[i] &lt;`
(dns block)
> - Triggering command:
`/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node
/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node scripts/kbn
bootstrap` (dns block)
> - Triggering command:
`/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node node
scripts/check_changes.ts dd ldd s/li��` (dns block)
> - `clients3.google.com`
> - Triggering command:
`/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
run :build-webpack ldd 0.8.2` (dns block)
> - `detectportal.firefox.com`
> - Triggering command:
`/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
run :build-webpack ldd 0.8.2` (dns block)
> - `google.com`
> - Triggering command:
`/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
/home/REDACTED/work/kibana/kibana/node_modules/@moonrepo/core-linux-x64-gnu/moon
run :build-webpack ldd 0.8.2` (dns block)
> - `googlechromelabs.github.io`
> - Triggering command:
`/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node
/home/REDACTED/.nvm/versions/node/v24.14.1/bin/node install.js
_TOKEN&elastic#34;; }; f ldd b/li��
nibrowser-gtk/sys/lib/libbrotlienc.so.1.0.7` (dns block)
> - `iojs.org`
> - Triggering command: `/usr/bin/curl curl -q --fail --compressed -L -s
REDACTED -o -` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/elastic/kibana/settings/copilot/coding_agent)
(admins only)
>
> </details>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: L1nBra <178042654+L1nBra@users.noreply.github.com>
Co-authored-by: Bhavya RM <bhavya@elastic.co>
Co-authored-by: L1nBra <lina.braziulyte@gmail.com>
Co-authored-by: Alexey Antonov <alexwizp@gmail.com>
…y-side eval harness

Adds a second PCI compliance skill (`pci-compliance-autonomous`) that ships
ALONGSIDE the existing hand-written `pci-compliance` skill, so the same eval
suite can be run against both variants and compared head-to-head. The
autonomous variant deliberately reuses the SAME underlying tools as the
hand-written variant, isolating "skill content" (instructions + domain
knowledge + trigger phrases) as the only experimental variable.

## What ships

Server (security_solution plugin)
- New skill definition `pci_compliance_autonomous/` registering
  `pci-compliance-autonomous` against the existing PCI tool IDs.
- New feature flag `pciComplianceAutonomousAgentBuilder` (default off).
- Skill registration gated by the flag in `register_skills.ts`.
- Allow-list entry for the new skill ID.

Eval harness (kbn-evals-suite-pci-compliance)
- `evaluate_dataset.ts` reads `EVAL_PCI_VARIANT` (`handwritten` | `autonomous`)
  to select which skill `createSkillInvocationEvaluator` targets. Default
  remains `handwritten` so existing CI is unchanged.
- `scripts/compare_variants.sh` runs both variants back-to-back and emits a
  side-by-side `comparison.html` with structural metrics + slots for live
  evaluator output (per-scenario scores, judge rationales, latency).
- `scripts/build_comparison_html.mjs` generates the report; all embedded paths
  are repo-relative so the artifact is portable.
- README documents the variant matrix and the comparison workflow.

CI plumbing
- New Scout config set `evals_pci_compliance_autonomous` that flips ONLY the
  autonomous flag, so the autonomous run sees only the autonomous skill.
- `evals.suites.json` registers `pci-compliance-autonomous`.
- `llm_evals.yml` adds a Buildkite step for the autonomous variant and tags
  the existing PCI step with `EVAL_PCI_VARIANT=handwritten` for symmetry.

## Why

The hand-written PCI skill (`pci-compliance`, elastic#256060) is the production
baseline. The autonomous skill was generated end-to-end by `skill.architect`
against the current Kibana tool catalog, with PCI domain knowledge synthesized
from autonomous web research + model knowledge (SAQ taxonomy, v3->v4 deltas,
scope-reduction levers, technical-vs-process classification). Running the
existing 7-scenario PCI eval suite against both — same tools, same dataset,
same evaluators, same judge — gives a clean A/B that answers "is the
autonomously generated skill at least as good as the hand-written one?".

## Out of scope (not introduced by this commit)

`evaluate_dataset.ts:17` triggers `@kbn/imports/no_boundary_crossing` because
`@kbn/evals` is declared `type: "test-helper"` and the suite imports value
exports from it. This lint reproduces identically on every sibling
`kbn-evals-suite-*` package on `main` (verified against
`kbn-evals-suite-security-ai-rules`), so it is endemic to the eval framework
and would require a cross-cutting change to `@kbn/evals` ownership /
visibility — out of scope for this skill comparison.
@github-actions
Copy link
Copy Markdown

@patrykkopycinski, it looks like you're updating the parameters for a rule type!

Please review the guidelines for making additive changes to rule type parameters and determine if your changes require an intermediate release.

@patrykkopycinski
Copy link
Copy Markdown
Owner Author

Re-opening with a fresh base — fork main was 3925 commits behind upstream when this PR was created, polluting the diff with all those upstream commits. Fork main is now fast-forwarded; reopening will give a clean 15-file diff.

patrykkopycinski added a commit that referenced this pull request May 13, 2026
…patch (PROD-6)

Adds the operator-side panic-stop knob the post-PROD-5 risk register flagged as
the remaining "block new dispatches without a Kibana restart" gap (Risk #10
residual). Folds cleanly into the existing two-key feature-flag gate so call
sites shrink instead of grow.

## What ships

* New optional config `xpack.securitySolution.detectionEmulation.realExecutionEnabled`
  (defaults to `true`). Operators flip via `kibana.yml` reload — no restart.

* `feature_flag.ts` is now two-keyed: `realExecution` (static
  `experimentalFeatures` flag, ships dark) AND `realExecutionRuntimeEnabled`
  (runtime kill switch, defaults open). `isRealExecutionEnabled` requires both.
  New `getRealExecutionDisableReason` + `REAL_EXECUTION_DISABLE_REASON_TEXT`
  produce a precise `likely_cause` so operators flip the right knob — not
  restart Kibana when the runtime knob is the cause.

* All four real-execution gate sites (`api/run_command/route.ts`,
  `api/validate_rule/route.ts`, `validate_rule_tool.ts`,
  `with_command_gates.ts`) use the new helper. Errors carry the new
  `disable_reason` field on tool surfaces and richer body text on REST
  surfaces. The helper signature change (`experimentalFeatures` → full
  `ConfigType`) is the only structural touch.

## Why this shape (anti-overengineering)

* Gate 1 (existing-abstraction): `feature_flag.ts` literally docstrings
  "future flags can be layered in without touching call sites" — used.
* Gate 2 (named consumer): production deployments needing fast halt of
  anomalous LLM-driven dispatches without a Kibana restart. The static
  feature flag gate (which closes the same path) requires a restart;
  the runtime knob is the same gate with a faster knob.
* Gate 3 (in-place): one new schema field, one signature change, one
  helper. ~150 LOC including tests; no new plugin, no new abstraction
  layer, no new "engine" or "registry".
* Gate 5 (existing isolation): PROD-1..5 are all SLOW knobs (allowlist
  propagation, restart, role assignment). The kill switch is the only
  fast operator response to "something is wrong, halt now". No existing
  mechanism covers this failure mode.
* Gate 6 (cost): one config field, four call-site touches, ~50 LOC
  tests. No UI, no bundle weight, no review tax beyond the additive
  schema field.

## Tests

* NEW `feature_flag.test.ts` (12 cases) covers the four-quadrant matrix
  of (static on/off × runtime on/off) plus the disable-reason helper +
  text constants.
* `api/run_command/route.test.ts` extended with a kill-switch case
  asserting the body surfaces `realExecutionEnabled` and does NOT
  mention `detectionEmulationRealExecution` (would mislead operators
  into restarting Kibana). Existing flag-disabled case extended with
  the inverse assertion.
* `api/validate_rule/route.test.ts` adds a PROD-6 describe block with
  one positive case (kill switch + real_execution → 403 with
  kill-switch text, gate fires before scenario generation) and one
  negative case (log_injection request + kill switch engaged → no
  kill-switch text in body, regardless of other 4xx outcomes).

All 78 agent_builder skill tests + 45 detection_emulation lib tests pass
locally.

## Skill body

`detection_emulation_skill.ts` Guardrails table gets a new row for the
runtime kill switch + a paragraph explaining the operator playbook
(flip `kibana.yml`, reload, no restart). The two existing static-flag
sentences are unchanged so the skill still ships dark by default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.