@ampsec/platform-client 87.3.0 → 87.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,31 +1,90 @@
1
1
  import {z} from 'zod';
2
2
 
3
- /* ─── Create / Upsert Schemas ──── */
3
+ /* ─── Database Input Schemas (Create / Upsert) ──── */
4
+
5
+ /**
6
+ * Flat condition format (backward compatible)
7
+ * Used when submitting simple or flat conditions
8
+ */
9
+ export const _FlatConditionSchema = z.object({
10
+ type: z.enum(['bool', 'numeric', 'string', 'array', 'datetime']),
11
+ name: z.string(),
12
+ operator: z.string(),
13
+ value: z.any().optional(),
14
+ });
15
+
16
+ /**
17
+ * Hierarchical condition group format (new)
18
+ * Supports nested AND/OR logic with unlimited depth
19
+ */
20
+ export const _ConditionGroupSchema: z.ZodType<any> = z.lazy(() =>
21
+ z.object({
22
+ id: z.string().optional(),
23
+ behavior: z.enum(['any', 'all']),
24
+ sort_order: z.number().default(0),
25
+ conditions: z.array(_FlatConditionSchema).optional(),
26
+ childGroups: z.array(_ConditionGroupSchema).optional(),
27
+ })
28
+ );
29
+
30
+ /**
31
+ * Action format
32
+ * Each action has a type and associated data
33
+ */
34
+ export const _ActionSchema = z.object({
35
+ action_type: z.enum(['then', 'else']),
36
+ action_data: z.record(z.any()).optional(),
37
+ });
38
+
39
+ /**
40
+ * Create rule schema - supports both flat and hierarchical conditions
41
+ */
4
42
  export const _CreateRuleSchema = z.object({
5
- cid: z.string(),
43
+ rule_set_id: z.string(),
44
+ cid: z.string().optional(),
45
+ tid: z.string().optional(),
6
46
  priority: z.number().default(0),
7
- conditions: z.any().optional(),
8
- actions: z.any().optional(),
47
+ conditions: z.array(_FlatConditionSchema).optional(),
48
+ conditionGroups: z.array(_ConditionGroupSchema).optional(),
49
+ actions: z.array(_ActionSchema).optional(),
9
50
  });
10
51
 
52
+ /**
53
+ * Upsert rule schema - for updates
54
+ */
11
55
  export const _RuleUpsertSchema = z.object({
12
56
  id: z.string(),
13
57
  priority: z.number().optional(),
14
- conditions: z.any().optional(),
15
- actions: z.any().optional(),
58
+ conditions: z.array(_FlatConditionSchema).optional(),
59
+ conditionGroups: z.array(_ConditionGroupSchema).optional(),
60
+ actions: z.array(_ActionSchema).optional(),
61
+ rule_set_id: z.string().optional(),
16
62
  });
17
63
 
18
64
  export type CreateRuleDtoSchema = z.infer<typeof _CreateRuleSchema> & {
19
65
  tid: string;
66
+ rule_set_id: string;
20
67
  };
21
68
 
22
69
  export type RuleUpsertDtoSchema = z.infer<typeof _RuleUpsertSchema>;
23
70
 
71
+ export type FlatConditionSchema = z.infer<typeof _FlatConditionSchema>;
72
+ export type ConditionGroupSchema = z.infer<typeof _ConditionGroupSchema>;
73
+ export type ActionSchema = z.infer<typeof _ActionSchema>;
74
+
24
75
  /* ─── Compiled Rule Types ─────────────────────────────────────────────────
25
76
  * Describe the JSON shape produced by RuleService.compileRulesToJson()
26
77
  * and consumed by the rules engine.
78
+ *
79
+ * NOTE: The RulesEngine receives COMPILED conditions (CompiledConditionNode),
80
+ * NOT raw database ConditionGroups. The compilation process converts the
81
+ * hierarchical ConditionGroup structure to this CompositeConditions format.
27
82
  * ────────────────────────────────────────────────────────────────────────── */
28
83
 
84
+ /**
85
+ * Leaf condition (single condition)
86
+ * e.g. { type: "string", name: "severity", operator: "equal_to", value: "CRITICAL" }
87
+ */
29
88
  export type CompiledLeafCondition = {
30
89
  type: string;
31
90
  name: string;
@@ -33,13 +92,26 @@ export type CompiledLeafCondition = {
33
92
  value: unknown;
34
93
  };
35
94
 
95
+ /**
96
+ * Composite condition (AND/OR grouping)
97
+ * e.g. { any: [...], all: [...] }
98
+ * Supports unlimited nesting
99
+ */
36
100
  export type CompiledCompositeCondition = {
37
101
  any?: CompiledConditionNode[];
38
102
  all?: CompiledConditionNode[];
39
103
  };
40
104
 
105
+ /**
106
+ * A condition node is either a leaf condition or composite group
107
+ * Recursive type supporting arbitrary nesting depth
108
+ */
41
109
  export type CompiledConditionNode = CompiledLeafCondition | CompiledCompositeCondition;
42
110
 
111
+ /**
112
+ * Action payload structure
113
+ * Each action has a type and arbitrary metadata
114
+ */
43
115
  export type CompiledActionData = {
44
116
  type: string;
45
117
  [key: string]: unknown;
@@ -53,14 +125,75 @@ export type CompiledActions = {
53
125
  [action_type: string]: CompiledActionData[];
54
126
  };
55
127
 
56
- /** Compiled rule as produced by compileRulesToJson */
128
+ /**
129
+ * Compiled rule as produced by compileRulesToJson()
130
+ * This is what RulesEngine.execute() receives
131
+ */
57
132
  export type CompiledRule = {
133
+ id: string;
58
134
  priority: number;
59
135
  conditions: CompiledConditionNode | null;
60
136
  actions: CompiledActions;
61
137
  };
62
138
 
139
+ /**
140
+ * Result type for getRuleSetByRuleIds()
141
+ * Maps rule ID to its compiled ruleset
142
+ */
63
143
  export type RuleSetByIdResult = {
64
144
  ruleId: string;
65
145
  ruleSet: CompiledRule[];
66
146
  };
147
+
148
+ /* ─── Internal Database Types ──────────────────────────────────────────── */
149
+
150
+ /**
151
+ * Database representation of a condition group (hierarchical storage)
152
+ * NOT used by RulesEngine - only internal storage
153
+ */
154
+ export type ConditionGroupEntity = {
155
+ id: string;
156
+ rule_id: string;
157
+ parent_group_id: string | null;
158
+ behavior: 'any' | 'all';
159
+ sort_order: number;
160
+ conditions?: FlatConditionSchema[];
161
+ childGroups?: ConditionGroupEntity[];
162
+ };
163
+
164
+ /**
165
+ * Database representation of a condition (flat storage)
166
+ * Can be used standalone (legacy) or within a ConditionGroup (new)
167
+ */
168
+ export type ConditionEntity = {
169
+ id: string;
170
+ rule_id: string;
171
+ condition_group_id?: string | null;
172
+ type: string;
173
+ name: string;
174
+ operator: string;
175
+ value: unknown;
176
+ };
177
+
178
+ /**
179
+ * Compilation flow:
180
+ *
181
+ * Database Layer:
182
+ * Rule.conditionGroups: ConditionGroupEntity[] (hierarchical)
183
+ * Rule.conditions: ConditionEntity[] (flat - legacy fallback)
184
+ *
185
+ * ↓ RuleService.compileRulesToJson()
186
+ *
187
+ * Compilation Layer:
188
+ * buildConditionsFromGroups(conditionGroups, conditions)
189
+ * - If conditionGroups exist: recursively build tree via buildGroupNode()
190
+ * - If empty: fallback to flat conditions
191
+ * buildActions() wraps in array-of-arrays
192
+ *
193
+ * ↓ Returns CompiledRule[]
194
+ *
195
+ * RulesEngine Layer:
196
+ * RulesEngine.execute(compiledRules, input)
197
+ * - Processes CompiledConditionNode (any/all nested structure)
198
+ * - Actions are array of arrays: `response.then.push(...rule.actions.then)`
199
+ */
@@ -31,6 +31,7 @@ import {
31
31
  NotificationService,
32
32
  PredictionService,
33
33
  CustomActionsService,
34
+ RulesService,
34
35
  } from '.';
35
36
  import {KIND, TARGET_API_AGENT} from './constants';
36
37
  import {getAmpRestClient, AmpRestClientOptions, AgentIdentityService, ConnectorInstallService, DefaultEnumService, EnumService, RestClient} from './rest';
@@ -43,6 +44,7 @@ import {TrainingsService} from './trainings.service';
43
44
  import {AnalyticsService} from './analytics.service';
44
45
  import {EngagementLogsService} from './engagementLogs.service';
45
46
  import {ConnectorReadinessService} from './connectorReadiness.service';
47
+ import {AmpSdkTagSpecsService} from './tagSpecs.service';
46
48
 
47
49
  export type AmpApiOptions = AmpRestClientOptions;
48
50
 
@@ -80,9 +82,11 @@ export class AmpApi {
80
82
  readonly providers: AmpDataService<ProviderDto>;
81
83
  readonly reportResults: AmpDataService<ReportResultDto>;
82
84
  readonly reports: AmpReportService;
85
+ readonly rules: RulesService;
83
86
  readonly saasAssets: AmpDataService<SaasAssetDto>;
84
87
  readonly saasComponents: AmpDataService<SaasComponentDto>;
85
88
  readonly saasUsers: AmpDataService<SaasUserDto>;
89
+ readonly tagSpecsService: AmpSdkTagSpecsService;
86
90
  readonly settings: AmpSettingsService;
87
91
  readonly tenants: AmpEntityService<TenantUpsertDto, TenantDto>;
88
92
  readonly tokens: AmpDataService<TokenDto>;
@@ -117,9 +121,12 @@ export class AmpApi {
117
121
  this.providers = new AmpDataServiceImpl<ProviderDto>(rest, KIND.PROVIDERS);
118
122
  this.reportResults = new AmpDataServiceImpl<ReportResultDto>(rest, KIND.REPORT_RESULTS);
119
123
  this.reports = new AmpReportServiceImpl(rest);
124
+ this.rules = new RulesService(rest, KIND.RULES, TARGET_API_AGENT);
120
125
  this.saasAssets = new AmpDataServiceImpl<SaasAssetDto>(rest, KIND.SAAS_ASSETS);
121
126
  this.saasComponents = new AmpDataServiceImpl<SaasComponentDto>(rest, KIND.SAAS_COMPONENTS);
122
127
  this.saasUsers = new AmpDataServiceImpl<SaasUserDto>(rest, KIND.SAAS_USERS);
128
+ //this.tagSpecsService = new TagSpecsService(rest, KIND.TAG_SPECS, TARGET_API_AGENT);
129
+ this.tagSpecsService = new AmpSdkTagSpecsService(rest, KIND.TAG_SPECS, TARGET_API_AGENT);
123
130
  this.settings = new AmpSettingsService(rest);
124
131
  this.tenants = new AmpEntityServiceImpl<TenantUpsertDto, TenantDto>(rest, KIND.TENANTS);
125
132
  this.tokens = new AmpDataServiceImpl<TokenDto>(rest, KIND.TOKENS);
@@ -60,7 +60,7 @@ import {
60
60
  } from './entity.service';
61
61
  import {AmpSdkCustomActionsService} from './customActions.platform.service';
62
62
  import {AmpRestClientOptions, RestClient, getAmpRestClient} from './rest';
63
- import {KIND, TARGET_API_PLATFORM} from './constants';
63
+ import {KIND, TARGET_API_AGENT, TARGET_API_PLATFORM} from './constants';
64
64
  import {DefaultEnumService, EnumService} from './rest/EnumService';
65
65
  import {AmpSdkSettingsService} from './settings.service';
66
66
  import {AmpSaaSEntityService, AmpSaaSEntityServiceImpl, AmpSdkSaasAssetService, AmpSdkSaasComponentService, AmpSdkSaasUserService} from './saasEntity.service';
@@ -176,7 +176,7 @@ export class AmpSdkServices {
176
176
  this.stagedSaaSUsers = new TruncatableAmpEntityServiceImpl<PlatformStagedSaasUserUpsertDto, PlatformStagedSaasUserDto>(rest, KIND.STAGED_SAAS_USERS, TARGET_API_PLATFORM);
177
177
 
178
178
  this.settings = new AmpSdkSettingsService(rest);
179
- this.tagSpecs = new AmpSdkTagSpecsService(rest);
179
+ this.tagSpecs = new AmpSdkTagSpecsService(rest, KIND.TAG_SPECS, TARGET_API_AGENT);
180
180
  this.tenants = new TenantsService(rest, TARGET_API_PLATFORM);
181
181
  this.tenantNotes = new TenantNotesService(rest, TARGET_API_PLATFORM);
182
182
  this.tokens = new AmpEntityServiceImpl<PlatformTokenUpsertDto, PlatformTokenDto>(rest, KIND.TOKENS, TARGET_API_PLATFORM);
@@ -1,16 +1,21 @@
1
1
  // sdk/services/tagSpec.sdk.service.ts
2
- import {RestClient} from './rest';
3
- import {TagSpecDto, TagSpecWithRuleSetDto} from '../dto/tagSpecs.dto';
4
- import {KIND} from './constants';
2
+ import {RestClient, RestResponse} from './rest';
3
+ import {TagSpecDto, TagSpecUpsertDto, TagSpecWithRuleSetDto} from '../dto/tagSpecs.dto';
4
+ import {KIND, TargetApi} from './constants';
5
5
  import {Page} from '../dto';
6
+ import {FilterCriteria} from '../FilterCriteria';
6
7
 
7
8
  const TAG_SPECS_PAGE_SIZE = 250;
8
9
 
9
10
  export class AmpSdkTagSpecsService {
10
11
  protected readonly rest: RestClient;
12
+ protected readonly targetApi: string;
13
+ protected readonly kind: string;
11
14
 
12
- constructor(rest: RestClient) {
15
+ constructor(rest: RestClient, kind?: string, targetApi?: TargetApi) {
13
16
  this.rest = rest;
17
+ this.kind = kind || KIND.TAG_SPECS;
18
+ this.targetApi = targetApi || 'platform';
14
19
  }
15
20
 
16
21
  async listByTenant(tid: string): Promise<TagSpecWithRuleSetDto[]> {
@@ -50,4 +55,55 @@ export class AmpSdkTagSpecsService {
50
55
 
51
56
  return res.data as TagSpecDto;
52
57
  }
58
+
59
+ async create(dto: TagSpecUpsertDto): Promise<RestResponse> {
60
+ return await this.rest.call({
61
+ url: `/${this.targetApi}/v1/${this.kind}`,
62
+ method: 'POST',
63
+ data: dto,
64
+ });
65
+ }
66
+
67
+ async update(id: string, dto: TagSpecUpsertDto): Promise<RestResponse> {
68
+ return await this.rest.call({
69
+ url: `/${this.targetApi}/v1/${this.kind}/${id}`,
70
+ method: 'PUT',
71
+ data: dto,
72
+ });
73
+ }
74
+
75
+ async get(id: string): Promise<RestResponse> {
76
+ return await this.rest.call({
77
+ url: `/${this.targetApi}/v1/${this.kind}/${id}`,
78
+ method: 'GET',
79
+ });
80
+ }
81
+
82
+ async listWithRules(params: {tid?: string; limit?: number; offset?: number}): Promise<RestResponse> {
83
+ const queryParams: Record<string, unknown> = {
84
+ limit: 200,
85
+ ...params,
86
+ };
87
+
88
+ return await this.rest.call({
89
+ url: `/${this.targetApi}/v1/${this.kind}/with-rules`,
90
+ method: 'GET',
91
+ params: queryParams,
92
+ });
93
+ }
94
+
95
+ async list(params: FilterCriteria): Promise<RestResponse> {
96
+ return await this.rest.call({
97
+ url: `/${this.targetApi}/v1/${this.kind}`,
98
+ method: 'GET',
99
+ params,
100
+ });
101
+ }
102
+
103
+ async delete(id: string): Promise<RestResponse> {
104
+ return await this.rest.call({
105
+ url: `/${this.targetApi}/v1/${this.kind}/${id}`,
106
+ method: 'DELETE',
107
+ });
108
+ }
53
109
  }