@infrascan/shared-types 0.5.1 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @infrascan/shared-types
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#89](https://github.com/infrascan/infrascan/pull/89) [`913867b73a72791c79a69ebfec8bf94331654c1d`](https://github.com/infrascan/infrascan/commit/913867b73a72791c79a69ebfec8bf94331654c1d) Thanks [@lfarrel6](https://github.com/lfarrel6)! - Migrate graph output to a standard schema for easier search/filter
8
+
3
9
  ## 0.5.1
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infrascan/shared-types",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Shared types for multiple infrascan packages",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
package/src/api.ts CHANGED
@@ -6,6 +6,7 @@ import type {
6
6
 
7
7
  import type { SelectedEdge, SelectedNode } from "./graph";
8
8
  import type { BaseEdgeResolver } from "./config";
9
+ import type { TranslatedEntity, BaseState } from "./scan";
9
10
 
10
11
  /**
11
12
  * Callback to store state from a specific function call
@@ -116,7 +117,15 @@ export type EntityRoleData = {
116
117
  };
117
118
  type GetIamRoleFn = (stateConnector: Connector) => Promise<EntityRoleData[]>;
118
119
 
119
- export interface ServiceModule<T, P extends Provider> {
120
+ export interface ServiceModule<
121
+ T,
122
+ P extends Provider,
123
+ E extends TranslatedEntity<BaseState, any, any> = TranslatedEntity<
124
+ BaseState,
125
+ any,
126
+ any
127
+ >,
128
+ > {
120
129
  provider: P;
121
130
  service: string;
122
131
  arnLabel?: string;
@@ -124,9 +133,9 @@ export interface ServiceModule<T, P extends Provider> {
124
133
  getClient: ClientBuilder<T, P>;
125
134
  callPerRegion: boolean;
126
135
  getters: GetterFn<T, P>[];
127
- nodes?: string[];
128
136
  getNodes?: GetNodeFn<P>;
129
137
  edges?: BaseEdgeResolver[];
130
138
  getEdges?: GetEdgeFn;
131
139
  getIamRoles?: GetIamRoleFn;
140
+ entities?: E[];
132
141
  }
package/src/config.ts CHANGED
@@ -38,8 +38,6 @@ export type BaseScannerDefinition = {
38
38
  callPerRegion: boolean;
39
39
  // Scanner functions for pulling state from a service
40
40
  getters: BaseGetter[];
41
- // Scrapers for pulling Nodes from service state
42
- nodes?: GenericNodeSelector[];
43
41
  // Scrapers for pulling Edges from service state
44
42
  edges?: BaseEdgeResolver[];
45
43
  // Scrapers for pulling IAM Roles from service state, used to generate permission based edges
@@ -47,8 +45,10 @@ export type BaseScannerDefinition = {
47
45
  };
48
46
 
49
47
  type AsCommand<S extends string> = `${S}Command`;
50
- export type AvailableCommand<Serv extends object, Funcs extends string> =
51
- AsCommand<Funcs> extends `${infer P}Command` & keyof Serv ? P : never;
48
+ export type AvailableCommand<
49
+ Serv extends object,
50
+ Funcs extends string,
51
+ > = AsCommand<Funcs> extends `${infer P}Command` & keyof Serv ? P : never;
52
52
 
53
53
  export type StateSelector<
54
54
  ServiceName extends string,
@@ -124,7 +124,6 @@ export type ScannerDefinition<
124
124
  skipClientBuilder?: boolean;
125
125
  callPerRegion: boolean;
126
126
  getters: ServiceGetter<ServiceName, Serv, Funcs>[];
127
- nodes?: StateSelector<ServiceName, Serv, Funcs>[];
128
127
  edges?: EdgeSelector<ServiceName, Serv, Funcs>[];
129
128
  iamRoles?: StateSelector<ServiceName, Serv, Funcs>[];
130
129
  };
package/src/graph.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { BaseState } from "./scan";
2
+
1
3
  /**
2
4
  * A node returned from a state selector before its been formatted for a graphing library
3
5
  */
@@ -6,6 +8,7 @@ export interface SelectedNode {
6
8
  name?: string;
7
9
  parent?: string;
8
10
  type?: string;
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
12
  rawState?: any;
10
13
  }
11
14
 
@@ -26,16 +29,19 @@ export type ElementType<ReadType, WriteType> = {
26
29
  readonly _write: WriteType;
27
30
  };
28
31
 
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
33
  export type ElementRecord<K extends keyof any, R, W> = ElementType<
30
34
  Record<K, Readable<R>>,
31
35
  Record<K, Writable<W>>
32
36
  >;
33
37
 
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
39
  export type ReadType<T> = T extends ElementType<infer R, any> ? Readable<R> : T;
35
40
  export type Readable<T> = {
36
41
  [K in keyof T]: ReadType<T[K]>;
37
42
  };
38
43
 
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
45
  export type WriteType<T> = T extends ElementType<any, infer W>
40
46
  ? Writable<W>
41
47
  : T;
@@ -43,7 +49,14 @@ export type Writable<T> = {
43
49
  [K in keyof T]: WriteType<T[K]>;
44
50
  };
45
51
 
46
- export interface Node {
52
+ export interface Node extends BaseState<unknown> {
53
+ parent?: ElementType<Node, string>;
54
+ children?: ElementRecord<string, Node, string>;
55
+ incomingEdges: ElementRecord<string, Edge, string>;
56
+ outgoingEdges: ElementRecord<string, Edge, string>;
57
+ }
58
+
59
+ export interface NodeOld {
47
60
  id: string;
48
61
  name: string;
49
62
  metadata: Record<string, unknown>;
@@ -66,12 +79,7 @@ export interface Edge {
66
79
  export interface Graph {
67
80
  nodes: Readable<Node>[];
68
81
  edges: Readable<Edge>[];
69
- addNode: (
70
- node: Pick<
71
- Writable<Node>,
72
- "id" | "name" | "metadata" | "parent" | "service" | "type"
73
- >,
74
- ) => void;
82
+ addNode: (node: BaseState<unknown>) => void;
75
83
  addEdge: (
76
84
  edge: Pick<Writable<Edge>, "name" | "source" | "target" | "metadata">,
77
85
  ) => void;
package/src/scan.ts CHANGED
@@ -1,12 +1,347 @@
1
- export type State<T> = {
2
- _metadata: {
3
- account: string;
4
- region: string;
5
- };
6
- _result: T;
7
- /* eslint-disable @typescript-eslint/no-explicit-any */
8
- _parameters?: any;
1
+ import { AwsContext, Connector } from "./api";
2
+
3
+ export interface CommandCallMetadata {
4
+ account: string;
5
+ region: string;
6
+ partition?: string;
7
+ timestamp: number;
8
+ }
9
+
10
+ export interface State<O, I = unknown> {
11
+ _metadata: CommandCallMetadata;
12
+ _result: O;
13
+ _parameters?: I;
14
+ }
15
+
16
+ export type GenericState = State<unknown>;
17
+
18
+ /**
19
+ * Metadata for any piece of state generated — when it was scanned, and what version of the state schema it uses
20
+ */
21
+ export interface StateMetadata {
22
+ version: string;
23
+ /**
24
+ * Epoch value (in ms)
25
+ */
26
+ timestamp: number;
27
+ }
28
+
29
+ /**
30
+ * Coordinates of a node in the graph including an optional position on the Z axis
31
+ */
32
+ export interface Coordinates {
33
+ x: number;
34
+ y: number;
35
+ z?: number;
36
+ }
37
+
38
+ /**
39
+ * Details about the nodes position in the graph and how it relates to other components
40
+ */
41
+ export interface GraphInfo {
42
+ /**
43
+ * The unique ID of the node in the graph
44
+ */
45
+ id: string;
46
+ /**
47
+ * The human readable name of the node in the graph
48
+ */
49
+ label: string;
50
+ /**
51
+ * The type of the node, used for assigning an icon in the graph
52
+ */
53
+ nodeType: string;
54
+ /**
55
+ * The ID of the parent node, optional.
56
+ */
57
+ parent?: string;
58
+ /**
59
+ * The coordinates of the node in the graph, optional.
60
+ */
61
+ coords?: Coordinates;
62
+ }
63
+
64
+ /**
65
+ * The tenant that the resource has been created in, typically an account or org. Should be defined for every resource.
66
+ */
67
+ export interface Tenant {
68
+ /**
69
+ * CSP that the state refers to (aws, gcp, azure)
70
+ */
71
+ provider: string;
72
+ /**
73
+ * The partition of this state e.g. govcloud, cn partitions
74
+ */
75
+ partition?: string;
76
+ /**
77
+ * The unique ID for the tenant (e.g. account id)
78
+ */
79
+ tenantId: string;
80
+ }
81
+
82
+ /**
83
+ * The geo data for a resource tracking where it is deployed to and, if known, which specific zones (i.e. datacenters) its in.
84
+ */
85
+ export interface Location {
86
+ /**
87
+ * The standard reference name for the region e.g. us-east-1
88
+ */
89
+ code: string;
90
+ /**
91
+ * The availability zone/datacenter that the resource is in e.g. us-east-1a
92
+ */
93
+ zone?: string[];
94
+ }
95
+
96
+ /**
97
+ * Details which identify a resource within the state
98
+ */
99
+ export interface Resource {
100
+ /**
101
+ * Category tracks whether this resource is a higher level concept like an account, or a service of a resource
102
+ */
103
+ category: string;
104
+ /**
105
+ * Subcategory tracks the resource's more specific resource type e.g. sub-service entity type. Not set for higher level concepts
106
+ */
107
+ subcategory?: string;
108
+ /**
109
+ * The unique ID of the resource — either an account number or a resource ID
110
+ */
111
+ id: string;
112
+ /**
113
+ * The human-readable name of the resource
114
+ */
115
+ name: string;
116
+ /**
117
+ * The recorded description for the resource
118
+ */
119
+ description?: string;
120
+ /**
121
+ * The resource level policy which dictates access
122
+ */
123
+ policy?: string;
124
+ }
125
+
126
+ export interface Role {
127
+ arn: string;
128
+ label: string;
129
+ }
130
+
131
+ /**
132
+ * The IAM roles associated with a resource. Supports resources with many roles assigned to varying lifecycles
133
+ */
134
+ export interface IAM {
135
+ roles: Role[];
136
+ }
137
+
138
+ /**
139
+ * The audit details of any existing resource where available - tracks who created the resource and when.
140
+ */
141
+ export interface Audit {
142
+ createdAt?: string | Date;
143
+ createdBy?: string;
144
+ }
145
+
146
+ /**
147
+ * The domain names that a resource can be accessed at
148
+ */
149
+ export interface DNS {
150
+ /**
151
+ * List of domain names at which a resource is accessible
152
+ */
153
+ domains: string[];
154
+ }
155
+
156
+ export type PublicIpStatus = "enabled" | "disabled";
157
+
158
+ /**
159
+ * The network information for a scanned resource which aims to cover both resources being assigned an address
160
+ * and the networking resource itself (VPC, subnet)
161
+ */
162
+ export interface Network {
163
+ /**
164
+ * Information about the public IP of the resource
165
+ */
166
+ publicIp?: {
167
+ status?: PublicIpStatus;
168
+ address?: string;
169
+ };
170
+ /**
171
+ * List of security group IDs that are associated with the resource
172
+ */
173
+ securityGroups?: string[];
174
+ /**
175
+ * The subnets that the resource is deployed into
176
+ */
177
+ targetSubnets?: string[];
178
+ /**
179
+ * The IPs that have been assigned to the resource within the private network.
180
+ */
181
+ assignedAddresses?: {
182
+ ipv4?: string;
183
+ ipv6?: string;
184
+ };
185
+ /**
186
+ * The IP ranges reserved for a networking resource (VPC, subnet)
187
+ */
188
+ reservedAddresses?: [
189
+ {
190
+ family: "ipv4" | "ipv6";
191
+ cidrBlock: string;
192
+ cidrBlockAssociationSets?: [
193
+ {
194
+ associationId: string;
195
+ cidrBlock: string;
196
+ state: string;
197
+ stateMessage: string;
198
+ },
199
+ ];
200
+ firstAddress: string;
201
+ lastAddress: string;
202
+ },
203
+ ];
204
+ /**
205
+ * The information relating to a specific subnet
206
+ */
207
+ subnet?: {
208
+ ipv6Only?: boolean;
209
+ availableAddressCount?: number;
210
+ };
211
+ /**
212
+ * The information relating to a specific VPC.
213
+ */
214
+ vpc?: {
215
+ id?: string;
216
+ dhcpOptionsId?: string;
217
+ state?: string;
218
+ instanceTenancy?: string;
219
+ default?: boolean;
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Generic structure for tracking key value datatypes
225
+ */
226
+ export interface KVPair {
227
+ key?: string;
228
+ value?: string;
229
+ }
230
+
231
+ /**
232
+ * Structure for tracking the source of state that was scanned
233
+ */
234
+ export interface Source<T> {
235
+ command: string;
236
+ parameters?: T;
237
+ }
238
+
239
+ /**
240
+ * Structure for representing the relationship between resources and the load balancers that route to them
241
+ */
242
+ export interface LoadBalancer {
243
+ name?: string;
244
+ port?: number;
245
+ targetGroupArn?: string;
246
+ }
247
+
248
+ export type SizeUnit = "B" | "MB" | "MiB" | "GB" | "GiB";
249
+
250
+ export type TimeUnit = "s" | "ms" | "m" | "h" | "d";
251
+
252
+ export interface QualifiedMeasure<T> {
253
+ unit: T;
254
+ value: number;
255
+ }
256
+
257
+ export interface HealthcheckConfig {
258
+ status?: string;
259
+ gracePeriod?: QualifiedMeasure<TimeUnit>;
260
+ }
261
+
262
+ /**
263
+ * Structure for tracking resources which have an associated encryption key
264
+ */
265
+ export interface EncryptionConfig {
266
+ keyId?: string;
267
+ }
268
+
269
+ export interface DeadLetterConfig {
270
+ targetId?: string;
271
+ }
272
+
273
+ /**
274
+ * Base state type to be extended on a per-service basis with the service specific context to use for linking.
275
+ * Attribute specific information can be found on each type.
276
+ */
277
+ export interface BaseState<T = unknown> {
278
+ $metadata: StateMetadata;
279
+ $graph: GraphInfo;
280
+ $source?: Source<T>;
281
+ deadLetter?: DeadLetterConfig;
282
+ tenant: Tenant;
283
+ location?: Location;
284
+ loadBalancers?: LoadBalancer[];
285
+ resource: Resource;
286
+ dns?: DNS;
287
+ iam?: IAM;
288
+ healthcheck?: HealthcheckConfig;
289
+ network?: Network;
290
+ audit?: Audit;
291
+ tags?: KVPair[];
292
+ encryption?: EncryptionConfig;
293
+ }
294
+
295
+ /**
296
+ * Generic type signature for any ode responsible for translating between data types
297
+ */
298
+ type Translate<A, B> = (val: A) => B;
299
+
300
+ /**
301
+ * Definition of a an entity's translators to convert the raw input state into the common schema
302
+ */
303
+ export type ComponentFactory<Input, Schema = BaseState<unknown>> = {
304
+ [ComponentName in keyof Schema]: Translate<Input, Schema[ComponentName]>;
9
305
  };
10
306
 
11
- /* eslint-disable @typescript-eslint/no-explicit-any */
12
- export type GenericState = State<any>;
307
+ export interface CommonEntity<Schema, RawState, TranslatedState = RawState> {
308
+ version: string;
309
+ selector: string;
310
+ debugLabel: string;
311
+ provider: string;
312
+ command: string;
313
+ category: string;
314
+ subcategory: string;
315
+ nodeType: string;
316
+
317
+ getState: (state: Connector, context: AwsContext) => Promise<RawState[]>;
318
+ components: ComponentFactory<TranslatedState, Schema>;
319
+ }
320
+
321
+ /**
322
+ * Entity which can act directly on its raw state, and does not require any pre-processing before
323
+ */
324
+ export interface SimpleEntity<Schema, RawState>
325
+ extends CommonEntity<Schema, RawState> {
326
+ translate?: never;
327
+ }
328
+
329
+ /**
330
+ * Entity which needs to translate its stored raw state before it can produce the standard schema
331
+ */
332
+ export interface TranslatedEntity<Schema, RawState, TranslatedState>
333
+ extends CommonEntity<Schema, RawState, TranslatedState> {
334
+ translate: Translate<RawState, TranslatedState[]>;
335
+ }
336
+
337
+ /**
338
+ * Discriminated union type for both simple and translated entities
339
+ */
340
+ export type EntityETL<Schema, RawState, TranslatedState = RawState> =
341
+ | SimpleEntity<Schema, RawState>
342
+ | TranslatedEntity<Schema, RawState, TranslatedState>;
343
+
344
+ export type WithCallContext<T, Input> = T & {
345
+ $metadata: CommandCallMetadata;
346
+ $parameters?: Input;
347
+ };