Skip to content

Commit b0eb7f1

Browse files
authored
Merge branch 'main' into retry-on-any-search-phase-execution-error
2 parents 67e39af + 2b31b97 commit b0eb7f1

1,530 files changed

Lines changed: 19312 additions & 10220 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ x-pack/platform/plugins/shared/screenshotting @elastic/kibana-reporting-services
10841084
x-pack/platform/plugins/shared/searchprofiler @elastic/kibana-management
10851085
x-pack/platform/plugins/shared/security @elastic/kibana-security
10861086
x-pack/platform/plugins/shared/serverless @elastic/appex-sharedux
1087+
x-pack/platform/plugins/shared/slo_shared @elastic/actionable-obs-team
10871088
x-pack/platform/plugins/shared/spaces @elastic/kibana-security
10881089
x-pack/platform/plugins/shared/stack_alerts @elastic/response-ops
10891090
x-pack/platform/plugins/shared/stack_connectors @elastic/response-ops
@@ -2215,6 +2216,7 @@ x-pack/platform/plugins/private/cloud_integrations/cloud_full_story/server/confi
22152216
/.github/workflows/codeql.yml @elastic/kibana-security
22162217
/.github/workflows/codeql-pr.yml @elastic/kibana-security
22172218
/.github/workflows/codeql-stats.yml @elastic/kibana-security
2219+
/.github/instructions/security.instructions.md @elastic/kibana-security
22182220
/.github/workflows/evaluate-dependency-health.yml @elastic/kibana-security
22192221
/src/dev/eslint/security_eslint_rule_tests.ts @elastic/kibana-security
22202222
/src/core/server/integration_tests/config/check_dynamic_config.test.ts @elastic/kibana-security
@@ -2727,21 +2729,22 @@ x-pack/solutions/security/test/security_solution_api_integration/test_suites/inv
27272729

27282730
## Generative AI owner connectors
27292731
# OpenAI
2730-
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/openai @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2731-
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/openai @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2732-
/x-pack/platform/plugins/shared/stack_connectors/common/openai @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2733-
/src/platform/packages/shared/kbn-connector-schemas/openai @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2732+
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/openai @elastic/security-generative-ai
2733+
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/openai @elastic/security-generative-ai
2734+
/x-pack/platform/plugins/shared/stack_connectors/common/openai @elastic/security-generative-ai
2735+
/src/platform/packages/shared/kbn-connector-schemas/openai @elastic/security-generative-ai
2736+
27342737
# Bedrock
2735-
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/bedrock @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2736-
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/bedrock @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2737-
/x-pack/platform/plugins/shared/stack_connectors/common/bedrock @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2738-
/src/platform/packages/shared/kbn-connector-schemas/bedrock @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2738+
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/bedrock @elastic/security-generative-ai
2739+
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/bedrock @elastic/security-generative-ai
2740+
/x-pack/platform/plugins/shared/stack_connectors/common/bedrock @elastic/security-generative-ai
2741+
/src/platform/packages/shared/kbn-connector-schemas/bedrock @elastic/security-generative-ai
27392742

27402743
# Gemini
2741-
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/gemini @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2742-
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/gemini @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2743-
/x-pack/platform/plugins/shared/stack_connectors/common/gemini @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2744-
/src/platform/packages/shared/kbn-connector-schemas/gemini @elastic/security-generative-ai @elastic/obs-ai-team @elastic/appex-ai-infra
2744+
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/gemini @elastic/security-generative-ai
2745+
/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/gemini @elastic/security-generative-ai
2746+
/x-pack/platform/plugins/shared/stack_connectors/common/gemini @elastic/security-generative-ai
2747+
/src/platform/packages/shared/kbn-connector-schemas/gemini @elastic/security-generative-ai
27452748

27462749
# Inference API
27472750
/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/inference @elastic/appex-ai-infra @elastic/security-generative-ai @elastic/obs-ai-team
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
applyTo: "{**/plugins/**/*.ts,**/packages/**/*.ts}"
3+
excludeAgent: "coding-agent"
4+
---
5+
6+
# Security & Authorization Review Guidelines
7+
8+
> **Critical Security Requirement:** All API routes in Kibana must have proper authorization checks. Authorization is not optional, even for `internal` routes.
9+
10+
## Review Style
11+
- Be specific and actionable in feedback
12+
- Explain the "why" behind recommendations
13+
- Acknowledge good patterns when you see them
14+
- Ask clarifying questions when code intent is unclear
15+
16+
## Authorization Configuration
17+
18+
Routes use the `security` configuration in `KibanaRouteOptions`:
19+
20+
```ts
21+
router.get({
22+
path: '/api/path',
23+
security: {
24+
authz: {
25+
requiredPrivileges: ['<privilege_1>', '<privilege_2>'],
26+
},
27+
},
28+
...
29+
}, handler);
30+
```
31+
32+
## Critical Review Checklist
33+
34+
Focus on these three key areas when reviewing API authorization:
35+
36+
### 1. Branching Logic with AuthzResult
37+
38+
**REQUIRED:** If a route handler branches its logic based on user privileges (e.g., returns different data or features), it MUST use `request.authzResult` to check which privileges were granted. Do NOT use `capabilities.resolveCapabilities()` or other authorization checks for branching—`authzResult` is the single source of truth.
39+
40+
**Patterns to search for:**
41+
- Routes with `anyRequired` or complex privilege configurations (OR logic)
42+
- Handlers that return different data or behavior based on user privileges
43+
- Handlers that conditionally expose features or data based on permissions
44+
- Handlers that check `capabilities.resolveCapabilities()` or similar methods for authorization decisions
45+
- Functions that check permissions/privileges and return boolean values used for branching
46+
47+
** Correct Implementation:**
48+
```ts
49+
router.get({
50+
path: '/api/path',
51+
security: {
52+
authz: {
53+
requiredPrivileges: ['privilege_3', { anyRequired: ['privilege_1', 'privilege_2'] }],
54+
},
55+
},
56+
...
57+
}, (context, request, response) => {
58+
// CORRECT: Use request.authzResult to check which privileges were granted
59+
const authzResult = request.authzResult;
60+
// {
61+
// "<privilege_3>": true,
62+
// "<privilege_1>": true,
63+
// "<privilege_2>": false
64+
// }
65+
66+
// Branch logic based on specific privileges
67+
if (authzResult.privilege_1) {
68+
// User has privilege_1, return enhanced data
69+
return response.ok({ body: ... });
70+
} else if (authzResult.privilege_2) {
71+
// User has privilege_2, return basic data
72+
return response.ok({ body: ... });
73+
}
74+
75+
// Fallback (should not reach here if security config is correct)
76+
return response.ok({ body: { data: ... } });
77+
});
78+
```
79+
80+
**Flag using Capabilities Instead of AuthzResult:**
81+
```ts
82+
// WRONG: Using capabilities.resolveCapabilities() for authorization branching
83+
const canReadDecryptedParams = async (routeContext: RouteContext) => {
84+
const { request, server } = routeContext;
85+
86+
const capabilities = await server.coreStart.capabilities.resolveCapabilities(request, {
87+
capabilityPath: 'my_capability.*',
88+
});
89+
90+
return capabilities.my_capability?.canReadParams ?? false;
91+
};
92+
93+
// In handler:
94+
if (await canReadDecryptedParams(routeContext)) {
95+
return getDecryptedParams(routeContext, paramId);
96+
} else {
97+
return getBasicParams(routeContext, paramId);
98+
}
99+
100+
// CORRECT: Use authzResult instead
101+
router.get({
102+
path: '/api/params',
103+
security: {
104+
authz: {
105+
requiredPrivileges: [{ anyRequired: ['read_params_decrypted', 'read_params'] }],
106+
},
107+
},
108+
}, (context, request, response) => {
109+
if (request.authzResult.read_params_decrypted) {
110+
return getDecryptedParams(routeContext, paramId);
111+
} else {
112+
return getBasicParams(routeContext, paramId);
113+
}
114+
});
115+
```
116+
117+
### 2. Opt-Out Authorization Reason
118+
119+
**When reviewing:** Check all routes with `authz: { enabled: false }` or `AuthzDisabled.*` usage. Verify they use predefined reasons when applicable, or provide specific context.
120+
121+
**If a route opts out of authorization, use predefined `AuthzOptOutReason` enum or `AuthzDisabled` helpers:**
122+
123+
```ts
124+
import { AuthzDisabled, AuthzOptOutReason } from '@kbn/core-security-server';
125+
126+
// CORRECT: Use predefined reason for Saved Objects client
127+
router.get({
128+
path: '/api/path',
129+
security: {
130+
authz: AuthzDisabled.delegateToSOClient,
131+
},
132+
...
133+
}, handler);
134+
135+
// CORRECT: Use predefined reason enum
136+
router.get({
137+
path: '/api/path',
138+
security: {
139+
authz: {
140+
enabled: false,
141+
reason: AuthzOptOutReason.DelegateToSOClient,
142+
},
143+
},
144+
...
145+
}, handler);
146+
147+
// CORRECT: Custom string when no predefined reason applies
148+
router.get({
149+
path: '/api/health',
150+
security: {
151+
authz: {
152+
enabled: false,
153+
reason: 'This route is a health check endpoint that returns no sensitive information',
154+
},
155+
},
156+
...
157+
}, handler);
158+
```
159+
160+
**Flag if:** `reason` is:
161+
-`"Opt out from authorization"` (too generic, no context)
162+
- `"This route does not need authorization"` (no explanation why)
163+
- `"Authorization not required"` (no context provided)
164+
- `Authorization is delegated to SO Client` (semantically equivalent to the already predefined reason `AuthzOptOutReason.DelegateToSOClient`)
165+
166+
## Summary
167+
168+
**Key Points for Reviewers:**
169+
170+
1. **Privilege names must follow `<operation>_<subject>` convention**
171+
- Incorrect privilege names:
172+
- `read-entity-a`: Uses `-` instead of `_`
173+
- `delete_entity-a`: Mixes `_` and `-`
174+
- `entity_manage`: Places the subject name before the operation
175+
- Correct privilege names:
176+
- `read_entity_a`
177+
- `delete_entity_a`
178+
- `manage_entity`
179+
2. **Routes with privilege-based branching MUST use `request.authzResult`**
180+
3. **Opt-out routes must have clear, specific reasons with context (not just "Opt out from authorization")*
181+
182+
## References
183+
184+
- [Kibana API Authorization Documentation](dev_docs/key_concepts/api_authorization.mdx)
185+
- [Kibana HTTP API Design Guidelines](dev_docs/contributing/kibana_http_api_design_guidelines.mdx)
186+

api_docs/actions.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions
88
title: "actions"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the actions plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions']
1313
---
1414
import actionsObj from './actions.devdocs.json';

api_docs/advanced_settings.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings
88
title: "advancedSettings"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the advancedSettings plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings']
1313
---
1414
import advancedSettingsObj from './advanced_settings.devdocs.json';

api_docs/agent_builder_platform.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/agentBuilderPlatform
88
title: "agentBuilderPlatform"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the agentBuilderPlatform plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'agentBuilderPlatform']
1313
---
1414
import agentBuilderPlatformObj from './agent_builder_platform.devdocs.json';

api_docs/ai_assistant_management_selection.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection
88
title: "aiAssistantManagementSelection"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the aiAssistantManagementSelection plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection']
1313
---
1414
import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json';

api_docs/aiops.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops
88
title: "aiops"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the aiops plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops']
1313
---
1414
import aiopsObj from './aiops.devdocs.json';

api_docs/alerting.devdocs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5179,7 +5179,7 @@
51795179
"BulkFillGapsByRuleIdsOptions",
51805180
") => Promise<",
51815181
"BulkFillGapsByRuleIdsResult",
5182-
">; getRuleIdsWithGaps: (params: Readonly<{ start?: string | undefined; end?: string | undefined; sortOrder?: \"asc\" | \"desc\" | undefined; statuses?: (\"unfilled\" | \"filled\" | \"partially_filled\")[] | undefined; hasUnfilledIntervals?: boolean | undefined; hasInProgressIntervals?: boolean | undefined; hasFilledIntervals?: boolean | undefined; highestPriorityGapFillStatuses?: (\"unfilled\" | \"filled\" | \"in_progress\")[] | undefined; ruleTypes?: Readonly<{} & { type: string; consumer: string; }>[] | undefined; maxRulesToFetch?: number | undefined; } & {}>) => Promise<Readonly<{ latestGapTimestamp?: number | undefined; } & { ruleIds: string[]; total: number; }>>; getGapsSummaryByRuleIds: (params: Readonly<{} & { start: string; end: string; ruleIds: string[]; }>) => Promise<Readonly<{} & { data: Readonly<{ gapFillStatus?: string | undefined; } & { ruleId: string; totalUnfilledDurationMs: number; totalInProgressDurationMs: number; totalFilledDurationMs: number; }>[]; }>>; getRuleTypesByQuery: (params: Readonly<{ filter?: string | undefined; ids?: string[] | undefined; } & {}>) => Promise<Readonly<{} & { ruleTypes: string[]; }>>; createGapAutoFillScheduler: (params: ",
5182+
">; getRuleIdsWithGaps: (params: Readonly<{ start?: string | undefined; end?: string | undefined; sortOrder?: \"asc\" | \"desc\" | undefined; ruleIds?: string[] | undefined; statuses?: (\"unfilled\" | \"filled\" | \"partially_filled\")[] | undefined; hasUnfilledIntervals?: boolean | undefined; hasInProgressIntervals?: boolean | undefined; hasFilledIntervals?: boolean | undefined; highestPriorityGapFillStatuses?: (\"unfilled\" | \"filled\" | \"in_progress\")[] | undefined; ruleTypes?: Readonly<{} & { type: string; consumer: string; }>[] | undefined; maxRulesToFetch?: number | undefined; } & {}>) => Promise<Readonly<{ latestGapTimestamp?: number | undefined; } & { ruleIds: string[]; total: number; }>>; getGapsSummaryByRuleIds: (params: Readonly<{} & { start: string; end: string; ruleIds: string[]; }>) => Promise<Readonly<{} & { data: Readonly<{ gapFillStatus?: string | undefined; } & { ruleId: string; totalUnfilledDurationMs: number; totalInProgressDurationMs: number; totalFilledDurationMs: number; }>[]; }>>; getRuleTypesByQuery: (params: Readonly<{ filter?: string | undefined; ids?: string[] | undefined; } & {}>) => Promise<Readonly<{} & { ruleTypes: string[]; }>>; createGapAutoFillScheduler: (params: ",
51835183
"CreateGapAutoFillSchedulerParams",
51845184
") => Promise<",
51855185
"GapAutoFillSchedulerResponse",

api_docs/alerting.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting
88
title: "alerting"
99
image: https://source.unsplash.com/400x175/?github
1010
description: API docs for the alerting plugin
11-
date: 2025-12-18
11+
date: 2025-12-19
1212
tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting']
1313
---
1414
import alertingObj from './alerting.devdocs.json';

api_docs/apm.devdocs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6491,7 +6491,7 @@
64916491
"section": "def-common.Error",
64926492
"text": "Error"
64936493
},
6494-
"[]; }, ",
6494+
"[]; agentMarks: Record<string, number>; }, ",
64956495
"APMRouteCreateOptions",
64966496
">; \"GET /internal/apm/traces/{traceId}\": ",
64976497
{

0 commit comments

Comments
 (0)