Skip to content

Commit 06502b9

Browse files
author
Dmitrii Shevchenko
authored
[Security Solution] Migrate rules management endpoints to OpenAPI and code generation (#165091)
**Part of: https://github.com/elastic/security-team/issues/7491** ## Summary Migrated Detection Engine APIs to OpenAPI schema and code generation: - [x] `PUT /api/detection_engine/rules/prepackaged` - [x] `POST /api/detection_engine/rules/_export` - [x] `POST /api/detection_engine/rules/_import` - [x] `GET /api/detection_engine/tags` - [x] `GET /internal/detection_engine/rules/{ruleId}/execution/results`
1 parent b053973 commit 06502b9

80 files changed

Lines changed: 2100 additions & 992 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.

packages/kbn-openapi-generator/src/template_service/templates/zod_query_item.handlebars

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,17 @@
4343
{{~/if~}}
4444

4545
{{~#if (eq type "integer")}}
46-
{{> zod_schema_item}}
46+
z.coerce.number().int()
47+
{{~#if minimum includeZero=true}}.min({{minimum}}){{/if~}}
48+
{{~#if maximum includeZero=true}}.max({{maximum}}){{/if~}}
49+
{{~#if (eq requiredBool false)}}.optional(){{/if~}}
50+
{{~#if (defined default)}}.default({{{toJSON default}}}){{/if~}}
4751
{{~/if~}}
4852

4953
{{~#if (eq type "number")}}
50-
{{> zod_schema_item}}
54+
z.coerce.number()
55+
{{~#if minimum includeZero=true}}.min({{minimum}}){{/if~}}
56+
{{~#if maximum includeZero=true}}.max({{maximum}}){{/if~}}
57+
{{~#if (eq requiredBool false)}}.optional(){{/if~}}
58+
{{~#if (defined default)}}.default({{{toJSON default}}}){{/if~}}
5159
{{~/if~}}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 { z } from 'zod';
9+
10+
/*
11+
* NOTICE: Do not edit this file manually.
12+
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
13+
*/
14+
15+
import { RuleSignatureId } from './rule_schema/common_attributes.gen';
16+
17+
export type ErrorSchema = z.infer<typeof ErrorSchema>;
18+
export const ErrorSchema = z
19+
.object({
20+
id: z.string().optional(),
21+
rule_id: RuleSignatureId.optional(),
22+
list_id: z.string().min(1).optional(),
23+
item_id: z.string().min(1).optional(),
24+
error: z.object({
25+
status_code: z.number().int().min(400),
26+
message: z.string(),
27+
}),
28+
})
29+
.strict();

x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.schema.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ info:
44
version: 'not applicable'
55
paths: {}
66
components:
7-
x-codegen-enabled: false
7+
x-codegen-enabled: true
88
schemas:
99
ErrorSchema:
1010
type: object
1111
required:
1212
- error
13+
additionalProperties: false
1314
properties:
1415
id:
1516
type: string

x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils';
99
import { left } from 'fp-ts/lib/Either';
1010
import { pipe } from 'fp-ts/lib/pipeable';
11-
import type { ErrorSchema } from './error_schema';
12-
import { errorSchema } from './error_schema';
11+
import { ErrorSchema } from './error_schema';
1312
import { getErrorSchemaMock } from './error_schema.mock';
1413

1514
describe('error_schema', () => {
1615
test('it should validate an error with a UUID given for id', () => {
1716
const error = getErrorSchemaMock();
18-
const decoded = errorSchema.decode(getErrorSchemaMock());
17+
const decoded = ErrorSchema.decode(getErrorSchemaMock());
1918
const checked = exactCheck(error, decoded);
2019
const message = pipe(checked, foldLeftRight);
2120

@@ -25,7 +24,7 @@ describe('error_schema', () => {
2524

2625
test('it should validate an error with a plain string given for id since sometimes we echo the user id which might not be a UUID back out to them', () => {
2726
const error = getErrorSchemaMock('fake id');
28-
const decoded = errorSchema.decode(error);
27+
const decoded = ErrorSchema.decode(error);
2928
const checked = exactCheck(error, decoded);
3029
const message = pipe(checked, foldLeftRight);
3130

@@ -37,7 +36,7 @@ describe('error_schema', () => {
3736
type InvalidError = ErrorSchema & { invalid_extra_data?: string };
3837
const error: InvalidError = getErrorSchemaMock();
3938
error.invalid_extra_data = 'invalid_extra_data';
40-
const decoded = errorSchema.decode(error);
39+
const decoded = ErrorSchema.decode(error);
4140
const checked = exactCheck(error, decoded);
4241
const message = pipe(checked, foldLeftRight);
4342

@@ -49,7 +48,7 @@ describe('error_schema', () => {
4948
const error = getErrorSchemaMock();
5049
// @ts-expect-error
5150
delete error.error;
52-
const decoded = errorSchema.decode(error);
51+
const decoded = ErrorSchema.decode(error);
5352
const checked = exactCheck(error, decoded);
5453
const message = pipe(checked, foldLeftRight);
5554

x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ const required = t.exact(
3131
})
3232
);
3333

34-
export const errorSchema = t.intersection([partial, required]);
35-
export type ErrorSchema = t.TypeOf<typeof errorSchema>;
34+
export const ErrorSchema = t.intersection([partial, required]);
35+
export type ErrorSchema = t.TypeOf<typeof ErrorSchema>;
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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 { z } from 'zod';
9+
10+
/*
11+
* NOTICE: Do not edit this file manually.
12+
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
13+
*/
14+
15+
/**
16+
* A universally unique identifier
17+
*/
18+
export type UUID = z.infer<typeof UUID>;
19+
export const UUID = z.string();
20+
21+
export type RuleObjectId = z.infer<typeof RuleObjectId>;
22+
export const RuleObjectId = z.string();
23+
24+
/**
25+
* Could be any string, not necessarily a UUID
26+
*/
27+
export type RuleSignatureId = z.infer<typeof RuleSignatureId>;
28+
export const RuleSignatureId = z.string();
29+
30+
export type RuleName = z.infer<typeof RuleName>;
31+
export const RuleName = z.string().min(1);
32+
33+
export type RuleDescription = z.infer<typeof RuleDescription>;
34+
export const RuleDescription = z.string().min(1);
35+
36+
export type RuleVersion = z.infer<typeof RuleVersion>;
37+
export const RuleVersion = z.string();
38+
39+
export type IsRuleImmutable = z.infer<typeof IsRuleImmutable>;
40+
export const IsRuleImmutable = z.boolean();
41+
42+
export type IsRuleEnabled = z.infer<typeof IsRuleEnabled>;
43+
export const IsRuleEnabled = z.boolean();
44+
45+
export type RuleTagArray = z.infer<typeof RuleTagArray>;
46+
export const RuleTagArray = z.array(z.string());
47+
48+
export type RuleMetadata = z.infer<typeof RuleMetadata>;
49+
export const RuleMetadata = z.object({});
50+
51+
export type RuleLicense = z.infer<typeof RuleLicense>;
52+
export const RuleLicense = z.string();
53+
54+
export type RuleAuthorArray = z.infer<typeof RuleAuthorArray>;
55+
export const RuleAuthorArray = z.array(z.string());
56+
57+
export type RuleFalsePositiveArray = z.infer<typeof RuleFalsePositiveArray>;
58+
export const RuleFalsePositiveArray = z.array(z.string());
59+
60+
export type RuleReferenceArray = z.infer<typeof RuleReferenceArray>;
61+
export const RuleReferenceArray = z.array(z.string());
62+
63+
export type InvestigationGuide = z.infer<typeof InvestigationGuide>;
64+
export const InvestigationGuide = z.string();
65+
66+
export type SetupGuide = z.infer<typeof SetupGuide>;
67+
export const SetupGuide = z.string();
68+
69+
export type BuildingBlockType = z.infer<typeof BuildingBlockType>;
70+
export const BuildingBlockType = z.string();
71+
72+
export type AlertsIndex = z.infer<typeof AlertsIndex>;
73+
export const AlertsIndex = z.string();
74+
75+
export type AlertsIndexNamespace = z.infer<typeof AlertsIndexNamespace>;
76+
export const AlertsIndexNamespace = z.string();
77+
78+
export type MaxSignals = z.infer<typeof MaxSignals>;
79+
export const MaxSignals = z.number().int().min(1);
80+
81+
export type Subtechnique = z.infer<typeof Subtechnique>;
82+
export const Subtechnique = z.object({
83+
/**
84+
* Subtechnique ID
85+
*/
86+
id: z.string(),
87+
/**
88+
* Subtechnique name
89+
*/
90+
name: z.string(),
91+
/**
92+
* Subtechnique reference
93+
*/
94+
reference: z.string(),
95+
});
96+
97+
export type Technique = z.infer<typeof Technique>;
98+
export const Technique = z.object({
99+
/**
100+
* Technique ID
101+
*/
102+
id: z.string(),
103+
/**
104+
* Technique name
105+
*/
106+
name: z.string(),
107+
/**
108+
* Technique reference
109+
*/
110+
reference: z.string(),
111+
/**
112+
* Array containing more specific information on the attack technique
113+
*/
114+
subtechnique: z.array(Subtechnique).optional(),
115+
});
116+
117+
export type Threat = z.infer<typeof Threat>;
118+
export const Threat = z.object({
119+
/**
120+
* Relevant attack framework
121+
*/
122+
framework: z.string(),
123+
tactic: z.object({
124+
/**
125+
* Tactic ID
126+
*/
127+
id: z.string(),
128+
/**
129+
* Tactic name
130+
*/
131+
name: z.string(),
132+
/**
133+
* Tactic reference
134+
*/
135+
reference: z.string(),
136+
}),
137+
/**
138+
* Array containing information on the attack techniques (optional)
139+
*/
140+
technique: z.array(Technique).optional(),
141+
});
142+
143+
export type ThreatArray = z.infer<typeof ThreatArray>;
144+
export const ThreatArray = z.array(Threat);
145+
146+
export type IndexPatternArray = z.infer<typeof IndexPatternArray>;
147+
export const IndexPatternArray = z.array(z.string());
148+
149+
export type DataViewId = z.infer<typeof DataViewId>;
150+
export const DataViewId = z.string();
151+
152+
export type RuleQuery = z.infer<typeof RuleQuery>;
153+
export const RuleQuery = z.string();
154+
155+
export type RuleFilterArray = z.infer<typeof RuleFilterArray>;
156+
export const RuleFilterArray = z.array(z.object({}));
157+
158+
export type RuleNameOverride = z.infer<typeof RuleNameOverride>;
159+
export const RuleNameOverride = z.string();
160+
161+
export type TimestampOverride = z.infer<typeof TimestampOverride>;
162+
export const TimestampOverride = z.string();
163+
164+
export type TimestampOverrideFallbackDisabled = z.infer<typeof TimestampOverrideFallbackDisabled>;
165+
export const TimestampOverrideFallbackDisabled = z.boolean();
166+
167+
export type RequiredField = z.infer<typeof RequiredField>;
168+
export const RequiredField = z.object({
169+
name: z.string().min(1).optional(),
170+
type: z.string().min(1).optional(),
171+
ecs: z.boolean().optional(),
172+
});
173+
174+
export type RequiredFieldArray = z.infer<typeof RequiredFieldArray>;
175+
export const RequiredFieldArray = z.array(RequiredField);
176+
177+
export type TimelineTemplateId = z.infer<typeof TimelineTemplateId>;
178+
export const TimelineTemplateId = z.string();
179+
180+
export type TimelineTemplateTitle = z.infer<typeof TimelineTemplateTitle>;
181+
export const TimelineTemplateTitle = z.string();
182+
183+
export type SavedObjectResolveOutcome = z.infer<typeof SavedObjectResolveOutcome>;
184+
export const SavedObjectResolveOutcome = z.enum(['exactMatch', 'aliasMatch', 'conflict']);
185+
export const SavedObjectResolveOutcomeEnum = SavedObjectResolveOutcome.enum;
186+
export type SavedObjectResolveOutcomeEnum = typeof SavedObjectResolveOutcome.enum;
187+
188+
export type SavedObjectResolveAliasTargetId = z.infer<typeof SavedObjectResolveAliasTargetId>;
189+
export const SavedObjectResolveAliasTargetId = z.string();
190+
191+
export type SavedObjectResolveAliasPurpose = z.infer<typeof SavedObjectResolveAliasPurpose>;
192+
export const SavedObjectResolveAliasPurpose = z.enum([
193+
'savedObjectConversion',
194+
'savedObjectImport',
195+
]);
196+
export const SavedObjectResolveAliasPurposeEnum = SavedObjectResolveAliasPurpose.enum;
197+
export type SavedObjectResolveAliasPurposeEnum = typeof SavedObjectResolveAliasPurpose.enum;
198+
199+
export type RelatedIntegration = z.infer<typeof RelatedIntegration>;
200+
export const RelatedIntegration = z.object({
201+
package: z.string().min(1),
202+
version: z.string().min(1),
203+
integration: z.string().min(1).optional(),
204+
});
205+
206+
export type RelatedIntegrationArray = z.infer<typeof RelatedIntegrationArray>;
207+
export const RelatedIntegrationArray = z.array(RelatedIntegration);

x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ info:
44
version: 'not applicable'
55
paths: {}
66
components:
7-
x-codegen-enabled: false
7+
x-codegen-enabled: true
88
schemas:
99
UUID:
1010
type: string

0 commit comments

Comments
 (0)