Skip to content

Commit 56f5a53

Browse files
KDKHDkibanamachineelasticmachine
authored
[Security Solution] [AI assistant] Security labs citations link to https://www.elastic.co/security-labs instead of knowledge base (#220668)
## Summary Summarize your PR. If it involves visual changes include a screenshot or gif. This PR improves citations for the security labs content. Instead of just opening app/management/kibana/securityAiAssistantManagement?tab=knowledge_base, citations now link to `https://www.elastic.co/security-labs/<slug>` <img width="1726" alt="image" src="https://github.com/user-attachments/assets/f77d7b09-e287-4246-8931-431eba5226ca" /> ### How to test - Start Kibana - Load the knowledge base with security labs content (http://localhost:5601/app/management/kibana/securityAiAssistantManagement?tab=knowledge_base) - Wait for the security labs content to finish loading - Open the security AI assistant - Ask the following `Tell me what is in the security labs content` - In the response, there should be a citation `[1]` - Click on the citation link, and `https://www.elastic.co/security-labs/<article>` should open in a new tab. ### 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 - [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] 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) - [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. - [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) ### 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. - [x] [See some risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) - [ ] ... --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent 1b2f09c commit 56f5a53

13 files changed

Lines changed: 360 additions & 9 deletions

File tree

oas_docs/output/kibana.serverless.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57223,6 +57223,7 @@ components:
5722357223
- $ref: '#/components/schemas/Security_AI_Assistant_API_SecurityAlertsPageContentReference'
5722457224
- $ref: '#/components/schemas/Security_AI_Assistant_API_ProductDocumentationContentReference'
5722557225
- $ref: '#/components/schemas/Security_AI_Assistant_API_EsqlContentReference'
57226+
- $ref: '#/components/schemas/Security_AI_Assistant_API_HrefContentReference'
5722657227
additionalProperties: false
5722757228
description: A union of all content reference types
5722857229
type: object
@@ -57566,6 +57567,25 @@ components:
5756657567
- updated_at
5756757568
example: created_at
5756857569
type: string
57570+
Security_AI_Assistant_API_HrefContentReference:
57571+
allOf:
57572+
- $ref: '#/components/schemas/Security_AI_Assistant_API_BaseContentReference'
57573+
- type: object
57574+
properties:
57575+
href:
57576+
description: URL to the external resource
57577+
type: string
57578+
label:
57579+
description: Label of the query
57580+
type: string
57581+
type:
57582+
enum:
57583+
- Href
57584+
type: string
57585+
required:
57586+
- type
57587+
- href
57588+
description: References an external URL
5756957589
Security_AI_Assistant_API_IndexEntry:
5757057590
allOf:
5757157591
- type: object

oas_docs/output/kibana.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66540,6 +66540,7 @@ components:
6654066540
- $ref: '#/components/schemas/Security_AI_Assistant_API_SecurityAlertsPageContentReference'
6654166541
- $ref: '#/components/schemas/Security_AI_Assistant_API_ProductDocumentationContentReference'
6654266542
- $ref: '#/components/schemas/Security_AI_Assistant_API_EsqlContentReference'
66543+
- $ref: '#/components/schemas/Security_AI_Assistant_API_HrefContentReference'
6654366544
additionalProperties: false
6654466545
description: A union of all content reference types
6654566546
type: object
@@ -66883,6 +66884,25 @@ components:
6688366884
- updated_at
6688466885
example: created_at
6688566886
type: string
66887+
Security_AI_Assistant_API_HrefContentReference:
66888+
allOf:
66889+
- $ref: '#/components/schemas/Security_AI_Assistant_API_BaseContentReference'
66890+
- type: object
66891+
properties:
66892+
href:
66893+
description: URL to the external resource
66894+
type: string
66895+
label:
66896+
description: Label of the query
66897+
type: string
66898+
type:
66899+
enum:
66900+
- Href
66901+
type: string
66902+
required:
66903+
- type
66904+
- href
66905+
description: References an external URL
6688666906
Security_AI_Assistant_API_IndexEntry:
6688766907
allOf:
6688866908
- type: object

x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,7 @@ components:
18291829
- $ref: '#/components/schemas/SecurityAlertsPageContentReference'
18301830
- $ref: '#/components/schemas/ProductDocumentationContentReference'
18311831
- $ref: '#/components/schemas/EsqlContentReference'
1832+
- $ref: '#/components/schemas/HrefContentReference'
18321833
additionalProperties: false
18331834
description: A union of all content reference types
18341835
type: object
@@ -2184,6 +2185,25 @@ components:
21842185
- updated_at
21852186
example: created_at
21862187
type: string
2188+
HrefContentReference:
2189+
allOf:
2190+
- $ref: '#/components/schemas/BaseContentReference'
2191+
- type: object
2192+
properties:
2193+
href:
2194+
description: URL to the external resource
2195+
type: string
2196+
label:
2197+
description: Label of the query
2198+
type: string
2199+
type:
2200+
enum:
2201+
- Href
2202+
type: string
2203+
required:
2204+
- type
2205+
- href
2206+
description: References an external URL
21872207
IndexEntry:
21882208
allOf:
21892209
- type: object

x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,7 @@ components:
18291829
- $ref: '#/components/schemas/SecurityAlertsPageContentReference'
18301830
- $ref: '#/components/schemas/ProductDocumentationContentReference'
18311831
- $ref: '#/components/schemas/EsqlContentReference'
1832+
- $ref: '#/components/schemas/HrefContentReference'
18321833
additionalProperties: false
18331834
description: A union of all content reference types
18341835
type: object
@@ -2184,6 +2185,25 @@ components:
21842185
- updated_at
21852186
example: created_at
21862187
type: string
2188+
HrefContentReference:
2189+
allOf:
2190+
- $ref: '#/components/schemas/BaseContentReference'
2191+
- type: object
2192+
properties:
2193+
href:
2194+
description: URL to the external resource
2195+
type: string
2196+
label:
2197+
description: Label of the query
2198+
type: string
2199+
type:
2200+
enum:
2201+
- Href
2202+
type: string
2203+
required:
2204+
- type
2205+
- href
2206+
description: References an external URL
21872207
IndexEntry:
21882208
allOf:
21892209
- type: object

x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/content_references/references/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
KnowledgeBaseEntryContentReference,
1212
ProductDocumentationContentReference,
1313
EsqlContentReference,
14+
HrefContentReference,
1415
} from '../../schemas';
1516
import { ContentReferenceId } from '../types';
1617

@@ -63,6 +64,26 @@ export const knowledgeBaseReference = (
6364
};
6465
};
6566

67+
/**
68+
* Generates a contentReference for when a external page is referenced.
69+
* @param id id of the contentReference
70+
* @param href the external page url
71+
* @param label content reference label
72+
* @returns HrefContentReference
73+
*/
74+
export const hrefReference = (
75+
id: ContentReferenceId,
76+
href: string,
77+
label?: string
78+
): HrefContentReference => {
79+
return {
80+
type: 'Href',
81+
id,
82+
href,
83+
label,
84+
};
85+
};
86+
6687
/**
6788
* Generates a contentReference for when a ESQL query is referenced.
6889
* @param id id of the contentReference

x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.gen.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,24 @@ export const SecurityAlertContentReference = BaseContentReference.merge(
107107
})
108108
);
109109

110+
/**
111+
* References an external URL
112+
*/
113+
export type HrefContentReference = z.infer<typeof HrefContentReference>;
114+
export const HrefContentReference = BaseContentReference.merge(
115+
z.object({
116+
type: z.literal('Href'),
117+
/**
118+
* Label of the query
119+
*/
120+
label: z.string().optional(),
121+
/**
122+
* URL to the external resource
123+
*/
124+
href: z.string(),
125+
})
126+
);
127+
110128
/**
111129
* References the security alerts page
112130
*/
@@ -146,6 +164,7 @@ export const ContentReferenceInternal = z.union([
146164
SecurityAlertsPageContentReference,
147165
ProductDocumentationContentReference,
148166
EsqlContentReference,
167+
HrefContentReference,
149168
]);
150169

151170
export type ContentReference = z.infer<typeof ContentReferenceInternal>;
@@ -164,6 +183,7 @@ export const ContentReferences = z
164183
SecurityAlertsPageContentReference,
165184
ProductDocumentationContentReference,
166185
EsqlContentReference,
186+
HrefContentReference,
167187
])
168188
);
169189

x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/conversations/common_attributes.schema.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,25 @@ components:
113113
type: string
114114
example: 'alert789'
115115

116+
HrefContentReference:
117+
description: References an external URL
118+
allOf:
119+
- $ref: '#/components/schemas/BaseContentReference'
120+
- type: object
121+
required:
122+
- 'type'
123+
- 'href'
124+
properties:
125+
type:
126+
type: string
127+
enum: [Href]
128+
label:
129+
description: Label of the query
130+
type: string
131+
href:
132+
description: URL to the external resource
133+
type: string
134+
116135
SecurityAlertsPageContentReference:
117136
description: References the security alerts page
118137
allOf:
@@ -157,6 +176,7 @@ components:
157176
- $ref: '#/components/schemas/SecurityAlertsPageContentReference'
158177
- $ref: '#/components/schemas/ProductDocumentationContentReference'
159178
- $ref: '#/components/schemas/EsqlContentReference'
179+
- $ref: '#/components/schemas/HrefContentReference'
160180
additionalProperties: false
161181

162182
ContentReferences:
@@ -168,6 +188,7 @@ components:
168188
- $ref: '#/components/schemas/SecurityAlertsPageContentReference'
169189
- $ref: '#/components/schemas/ProductDocumentationContentReference'
170190
- $ref: '#/components/schemas/EsqlContentReference'
191+
- $ref: '#/components/schemas/HrefContentReference'
171192
additionalProperties: false
172193
type: object
173194

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import fs from 'fs';
9+
import path from 'path';
10+
import yaml from 'js-yaml';
11+
12+
describe('Security labs content', () => {
13+
describe('content format', () => {
14+
const contentDir = path.join(__dirname, 'security_labs');
15+
16+
const files = fs.readdirSync(contentDir);
17+
18+
files.forEach((file) => {
19+
it(`should have non-empty string content in file: ${file}`, () => {
20+
const filePath = path.join(contentDir, file);
21+
const content = fs.readFileSync(filePath, 'utf-8');
22+
23+
expect(typeof content).toBe('string');
24+
expect(content.trim().length).toBeGreaterThan(0);
25+
});
26+
});
27+
28+
files.forEach((file) => {
29+
it(`should have title and slug defined in yaml header: ${file}`, () => {
30+
const filePath = path.join(contentDir, file);
31+
const content = fs.readFileSync(filePath, 'utf-8');
32+
33+
const split = content.split('---');
34+
const yamlString = split[1];
35+
const article = split[2];
36+
const parsed = yaml.load(yamlString) as {
37+
slug: string;
38+
title: string;
39+
};
40+
41+
const slug = parsed.slug;
42+
const title = parsed.title;
43+
expect(slug).toBeDefined();
44+
expect(title).toBeDefined();
45+
expect(typeof slug).toBe('string');
46+
expect(typeof title).toBe('string');
47+
expect(slug.trim().length).toBeGreaterThan(0);
48+
expect(title.trim().length).toBeGreaterThan(0);
49+
50+
expect(article).toBeDefined();
51+
expect(typeof article).toBe('string');
52+
});
53+
});
54+
55+
files.forEach((file) => {
56+
it(`article should come after yaml definition: ${file}`, () => {
57+
const filePath = path.join(contentDir, file);
58+
const content = fs.readFileSync(filePath, 'utf-8');
59+
60+
const split = content.split('---');
61+
const article = split[2];
62+
63+
expect(article).toBeDefined();
64+
expect(typeof article).toBe('string');
65+
expect(article.trim().length).toBeGreaterThan(0);
66+
});
67+
});
68+
});
69+
});

x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/content_reference/components/content_reference_component_factory.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ describe('contentReferenceComponentFactory', () => {
7575
type: 'SecurityAlertsPage',
7676
} as ContentReference,
7777
],
78+
[
79+
'HrefReference',
80+
{
81+
id: '1',
82+
type: 'Href',
83+
} as ContentReference,
84+
],
7885
])(
7986
"Renders correct component for '%s'",
8087
async (testId: string, contentReference: ContentReference) => {

x-pack/solutions/security/plugins/security_solution/public/assistant/get_comments/content_reference/components/content_reference_component_factory.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import type {
99
ContentReferences,
1010
EsqlContentReference,
11+
HrefContentReference,
1112
KnowledgeBaseEntryContentReference,
1213
ProductDocumentationContentReference,
1314
SecurityAlertContentReference,
@@ -24,6 +25,7 @@ import { SecurityAlertsPageReference } from './security_alerts_page_reference';
2425
import { ContentReferenceButton } from './content_reference_button';
2526
import { ProductDocumentationReference } from './product_documentation_reference';
2627
import { EsqlQueryReference } from './esql_query_reference';
28+
import { HrefReference } from './href_reference';
2729

2830
/** While a message is being streamed, content references are null. When a message has finished streaming, content references are either defined or undefined */
2931
export type StreamingOrFinalContentReferences = ContentReferences | undefined | null;
@@ -93,7 +95,17 @@ export const ContentReferenceComponentFactory: React.FC<Props> = ({
9395
/>
9496
);
9597
}
98+
case 'Href': {
99+
return (
100+
<HrefReference
101+
contentReferenceNode={
102+
contentReferenceNode as ResolvedContentReferenceNode<HrefContentReference>
103+
}
104+
/>
105+
);
106+
}
96107
default:
97-
return null;
108+
const _exhaustiveCheck: never = contentReferenceNode.contentReference;
109+
throw new Error(`Unhandled case: ${_exhaustiveCheck}`);
98110
}
99111
};

0 commit comments

Comments
 (0)