@infrascan/shared-types 0.2.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/.eslintrc.js ADDED
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ extends: ["custom"],
3
+ root: true,
4
+ parserOptions: {
5
+ project: "./tsconfig.json",
6
+ tsconfigRootDir: __dirname
7
+ },
8
+ ignorePatterns: [".eslintrc.js"]
9
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # @infrascan/shared-types
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7d71a0e: Restructure the project into per service scanner modules. Each module must be registered with the SDK for the service to be scanned and graphed.
8
+
9
+ The initial implementation for Infrascan used a single config file which defined the scanning approach for every service, and their graph structure. It very quickly became difficult to debug, and reason about. The core logic was also completely untestable in any sane way.
10
+
11
+ This release is a rewrite of the entire project. The SDK by default will do nothing. Each individual service's scanner has to be registered into an instance of the SDK for it to be scanned or graphed. This reduces the SDK complexity massively, as it only needs to step through the registered services and call into their APIs.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @infrascan/shared-types
2
+
3
+ Infrascan shared-types defines the common type interfaces for the SDK, Config and CLI.
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@infrascan/shared-types",
3
+ "version": "0.2.0",
4
+ "description": "Shared types for multiple infrascan packages",
5
+ "main": "src/index.ts",
6
+ "scripts": {
7
+ "lint": "tsc --noEmit ; eslint ."
8
+ },
9
+ "keywords": [],
10
+ "author": "Liam Farrelly <liam@l3f7.dev> (https://whoisli.am/)",
11
+ "license": "MPL-2.0",
12
+ "dependencies": {
13
+ "@aws-sdk/client-apigatewayv2": "3.428.0",
14
+ "@aws-sdk/client-auto-scaling": "3.428.0",
15
+ "@aws-sdk/client-cloudfront": "3.428.0",
16
+ "@aws-sdk/client-cloudwatch-logs": "3.428.0",
17
+ "@aws-sdk/client-dynamodb": "3.428.0",
18
+ "@aws-sdk/client-ec2": "3.428.0",
19
+ "@aws-sdk/client-ecs": "3.428.0",
20
+ "@aws-sdk/client-elastic-load-balancing-v2": "3.428.0",
21
+ "@aws-sdk/client-iam": "3.428.0",
22
+ "@aws-sdk/client-lambda": "3.428.0",
23
+ "@aws-sdk/client-rds": "3.428.0",
24
+ "@aws-sdk/client-route-53": "3.428.0",
25
+ "@aws-sdk/client-s3": "3.428.0",
26
+ "@aws-sdk/client-sns": "3.428.0",
27
+ "@aws-sdk/client-sqs": "3.428.0",
28
+ "@aws-sdk/client-sts": "3.428.0"
29
+ },
30
+ "devDependencies": {
31
+ "@aws-sdk/types": "3.428.0",
32
+ "eslint-config-custom": "*",
33
+ "tsconfig": "*",
34
+ "typescript": "^5.1.6"
35
+ }
36
+ }
package/src/api.ts ADDED
@@ -0,0 +1,138 @@
1
+ import type { AwsCredentialIdentityProvider } from "@aws-sdk/types";
2
+
3
+ import type { Service } from "./services";
4
+ import type { BaseEdgeResolver } from "./config";
5
+ import type { GraphEdge, GraphNode } from "./graph";
6
+
7
+
8
+ /**
9
+ * Callback to store state from a specific function call
10
+ *
11
+ * This is callback is invoked after every full scan of a service endpoint.
12
+ */
13
+ export type ServiceScanCompleteCallbackFn = (
14
+ /**
15
+ * The AWS account being scanned
16
+ */
17
+ account: string,
18
+ /**
19
+ * The region being scanned
20
+ */
21
+ region: string,
22
+ /**
23
+ * The service being scanned
24
+ */
25
+ service: Service | "IAM",
26
+ /**
27
+ * The specific function called during scanning
28
+ */
29
+ functionName: string,
30
+ /* eslint-disable @typescript-eslint/no-explicit-any */
31
+ /**
32
+ * The state retrieved from the function call
33
+ */
34
+ functionState: any,
35
+ ) => Promise<void>;
36
+
37
+ /* eslint-disable @typescript-eslint/no-explicit-any */
38
+ /**
39
+ * Callback to load scan state from a specific service call.
40
+ *
41
+ * This is used by the scan function pull back parameters for future function calls
42
+ * A common pattern is to have resources listed, and then described.
43
+ */
44
+ export type ResolveStateForServiceFunction = (
45
+ /**
46
+ * The AWS account that was scanned
47
+ */
48
+ account: string,
49
+ /**
50
+ * The scanned region
51
+ */
52
+ region: string,
53
+ /**
54
+ * The scanned service e.g. Lambda
55
+ */
56
+ service: Service,
57
+ /**
58
+ * The specific function called during the scan e.g. GetFunction
59
+ */
60
+ functionName: string,
61
+ ) => Promise<any>;
62
+
63
+ /* eslint-disable @typescript-eslint/no-explicit-any */
64
+ export type GetGlobalStateForServiceFunction = (
65
+ service: string,
66
+ functionName: string,
67
+ ) => Promise<any>;
68
+
69
+ export interface Connector {
70
+ onServiceScanCompleteCallback: ServiceScanCompleteCallbackFn;
71
+ resolveStateForServiceFunction: ResolveStateForServiceFunction;
72
+ getGlobalStateForServiceFunction: GetGlobalStateForServiceFunction;
73
+ };
74
+
75
+ type ClientBuilder<T, P extends Provider> = (
76
+ credentials: AwsCredentialIdentityProvider,
77
+ context: ProviderContextMap[P],
78
+ ) => T;
79
+
80
+ type GetterFn<T, P extends Provider> = (
81
+ client: T,
82
+ stateConnector: Connector,
83
+ context: ProviderContextMap[P]
84
+ ) => Promise<void>;
85
+
86
+ type GetNodeFn<T extends Provider> = (
87
+ stateConnector: Connector,
88
+ context: ProviderContextMap[T]
89
+ ) => Promise<GraphNode[]>;
90
+
91
+ type GetEdgeFn = (stateConnector: Connector) => Promise<GraphEdge[]>;
92
+
93
+
94
+ export type Provider = "aws";
95
+
96
+ export type AwsContext = {
97
+ account: string;
98
+ region: string;
99
+ partition?: string;
100
+ };
101
+
102
+ type ProviderContextMap = {
103
+ aws: AwsContext
104
+ }
105
+
106
+ export type ProviderContext<T extends Provider> = {
107
+ provider: T;
108
+ context: ProviderContextMap[T];
109
+ };
110
+
111
+ type FormatNodeFn<P extends Provider> = (node: GraphNode, context: ProviderContextMap[P]) => GraphNode;
112
+ type FormatEdgeFn<P extends Provider> = (
113
+ node: GraphEdge,
114
+ context: ProviderContextMap[P]
115
+ ) => GraphEdge;
116
+
117
+ export type EntityRoleData = {
118
+ roleArn: string;
119
+ executor: string;
120
+ };
121
+ type GetIamRoleFn = (stateConnector: Connector) => Promise<EntityRoleData[]>;
122
+
123
+ export interface ServiceModule<T, P extends Provider> {
124
+ provider: P;
125
+ service: string;
126
+ arnLabel?: string;
127
+ key: string;
128
+ getClient: ClientBuilder<T, P>;
129
+ callPerRegion: boolean;
130
+ getters: GetterFn<T, P>[];
131
+ nodes?: string[];
132
+ getNodes?: GetNodeFn<P>;
133
+ formatNode?: FormatNodeFn<P>;
134
+ edges?: BaseEdgeResolver[];
135
+ getEdges?: GetEdgeFn;
136
+ formatEdge?: FormatEdgeFn<P>;
137
+ getIamRoles?: GetIamRoleFn;
138
+ };
package/src/config.ts ADDED
@@ -0,0 +1,134 @@
1
+ export type GenericEdgeSelector = `${string}|${string}`;
2
+
3
+ export type BaseEdgeResolver = {
4
+ state: GenericEdgeSelector;
5
+ from: string;
6
+ to: string;
7
+ };
8
+
9
+ export type PaginationToken = {
10
+ request?: string;
11
+ response?: string;
12
+ };
13
+
14
+ export type BaseGetter = {
15
+ id?: string;
16
+ fn: string;
17
+ /* eslint-disable @typescript-eslint/no-explicit-any */
18
+ parameters?: (BaseParameterResolver & { Value?: any, Selector?: string })[];
19
+ formatter?: string;
20
+ paginationToken?: PaginationToken;
21
+ iamRoleSelectors?: string[];
22
+ };
23
+
24
+ export type GenericNodeSelector = `${string}|${string}|${string}`;
25
+
26
+ export type BaseScannerDefinition = {
27
+ provider?: string;
28
+ // Name of the service to be scanned
29
+ service: string;
30
+ // Key of the client in imported SDK
31
+ clientKey: string;
32
+ // Label used to identify this service within AWS ARNs
33
+ arnLabel?: string;
34
+ // Default 'type' for the generated graph entities, useful for applying a default style to a service's nodes.
35
+ key: string;
36
+ // Should the codegen skip implementing the client builder. Defaults to false.
37
+ skipClientBuilder?: boolean;
38
+ // Should this scanner be called in every region, or is it considered global (e.g. S3, Cloudfront, Route53)
39
+ callPerRegion: boolean;
40
+ // Scanner functions for pulling state from a service
41
+ getters: BaseGetter[];
42
+ // Scrapers for pulling Nodes from service state
43
+ nodes?: GenericNodeSelector[];
44
+ // Scrapers for pulling Edges from service state
45
+ edges?: BaseEdgeResolver[];
46
+ // Scrapers for pulling IAM Roles from service state, used to generate permission based edges
47
+ iamRoles?: GenericNodeSelector[];
48
+ };
49
+
50
+ type AsCommand<S extends string> = `${S}Command`;
51
+ export type AvailableCommand<
52
+ Serv extends object,
53
+ Funcs extends string,
54
+ > = AsCommand<Funcs> extends `${infer P}Command` & keyof Serv ? P : never;
55
+
56
+ export type StateSelector<
57
+ ServiceName extends string,
58
+ Serv extends object,
59
+ Funcs extends string,
60
+ > = `${ServiceName}|${AvailableCommand<Serv, Funcs>}|${string}`;
61
+
62
+ export type EdgeSelector<
63
+ ServiceName extends string,
64
+ Serv extends object,
65
+ Funcs extends string,
66
+ > = {
67
+ state: StateSelector<ServiceName, Serv, Funcs>;
68
+ to: string;
69
+ from: string;
70
+ };
71
+
72
+ export type BaseParameterResolver = {
73
+ Key: string;
74
+ };
75
+
76
+ /* eslint-disable @typescript-eslint/no-explicit-any */
77
+ export type ConstantParameterResolver = {
78
+ Value: any;
79
+ } & BaseParameterResolver;
80
+
81
+ export type StatefulParameterResolver<
82
+ ServiceName extends string,
83
+ Serv extends object,
84
+ Funcs extends string,
85
+ > = {
86
+ Selector: StateSelector<ServiceName, Serv, Funcs>;
87
+ } & BaseParameterResolver;
88
+
89
+ export type GenericStatefulParameterResolver = {
90
+ Selector: string;
91
+ } & BaseParameterResolver;
92
+
93
+ export type ParameterResolver<
94
+ ServiceName extends string,
95
+ Serv extends object,
96
+ Funcs extends string,
97
+ > =
98
+ | ConstantParameterResolver
99
+ | StatefulParameterResolver<ServiceName, Serv, Funcs>;
100
+
101
+ export type GenericParameterResolver = BaseParameterResolver & {
102
+ Selector?: string;
103
+ Value?: any;
104
+ };
105
+
106
+ export type ServiceGetter<
107
+ ServiceName extends string,
108
+ Serv extends object,
109
+ Funcs extends string,
110
+ > = {
111
+ id?: string;
112
+ fn: AvailableCommand<Serv, Funcs>;
113
+ paginationToken?: PaginationToken;
114
+ parameters?: ParameterResolver<ServiceName, Serv, Funcs>[];
115
+ iamRoleSelectors?: string[];
116
+ };
117
+
118
+ export type ScannerDefinition<
119
+ ServiceName extends string,
120
+ Serv extends object,
121
+ Funcs extends string,
122
+ > = {
123
+ provider: string;
124
+ service: string;
125
+ clientKey: ServiceName;
126
+ arnLabel?: string;
127
+ key: string;
128
+ skipClientBuilder?: boolean;
129
+ callPerRegion: boolean;
130
+ getters: ServiceGetter<ServiceName, Serv, Funcs>[];
131
+ nodes?: StateSelector<ServiceName, Serv, Funcs>[];
132
+ edges?: EdgeSelector<ServiceName, Serv, Funcs>[];
133
+ iamRoles?: StateSelector<ServiceName, Serv, Funcs>[];
134
+ };
package/src/graph.ts ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * A node returned from a state selector before its been formatted for a graphing library
3
+ */
4
+ export type SelectedNode = {
5
+ id: string;
6
+ name?: string;
7
+ parent?: string;
8
+ type?: string;
9
+ rawState?: any;
10
+ };
11
+
12
+ /**
13
+ * A node on the graph
14
+ */
15
+ export type GraphNode = {
16
+ group: "nodes";
17
+ id: string;
18
+ data: {
19
+ id: string;
20
+ type: string;
21
+ /**
22
+ * Parent node (account, region etc)
23
+ */
24
+ parent?: string;
25
+ name?: string;
26
+ service?: string;
27
+ };
28
+ /* eslint-disable @typescript-eslint/no-explicit-any */
29
+ metadata?: any;
30
+ };
31
+
32
+ /**
33
+ * An edge connecting two nodes within a graph
34
+ */
35
+ export type GraphEdge = {
36
+ group: "edges";
37
+ /**
38
+ * Unique ID for the edge
39
+ */
40
+ id?: string;
41
+ data: {
42
+ id: string;
43
+ name: string;
44
+ /**
45
+ * Source Node
46
+ */
47
+ source: string;
48
+ /**
49
+ * Target Node
50
+ */
51
+ target: string;
52
+ type: string;
53
+ };
54
+ metadata?: {
55
+ label: string;
56
+ roleArn?: string;
57
+ /* eslint-disable @typescript-eslint/no-explicit-any */
58
+ statement?: any;
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Generic type for elements in a graph
64
+ */
65
+ export type GraphElement = GraphNode | GraphEdge;
66
+
67
+ export type EdgeTarget = {
68
+ name: string;
69
+ target: string;
70
+ };
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ import {
2
+ GlobalServiceClients,
3
+ RegionalServiceClients,
4
+ ServiceClients,
5
+ } from "./services";
6
+ import type { GlobalService, RegionalService, Service } from "./services";
7
+
8
+ export {
9
+ ServiceClients,
10
+ GlobalServiceClients,
11
+ RegionalServiceClients,
12
+ GlobalService,
13
+ RegionalService,
14
+ Service,
15
+ };
16
+ export * from "./api";
17
+ export * from "./config";
18
+ export * from "./graph";
19
+ export * from "./scan";
package/src/scan.ts ADDED
@@ -0,0 +1,12 @@
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;
9
+ };
10
+
11
+ /* eslint-disable @typescript-eslint/no-explicit-any */
12
+ export type GenericState = State<any>;
@@ -0,0 +1,64 @@
1
+ import * as S3 from "@aws-sdk/client-s3";
2
+ import * as CloudFront from "@aws-sdk/client-cloudfront";
3
+ import * as Route53 from "@aws-sdk/client-route-53";
4
+
5
+ import * as ApiGatewayV2 from "@aws-sdk/client-apigatewayv2";
6
+ import * as AutoScaling from "@aws-sdk/client-auto-scaling";
7
+ import * as CloudWatchLogs from "@aws-sdk/client-cloudwatch-logs";
8
+ import * as DynamoDB from "@aws-sdk/client-dynamodb";
9
+ import * as EC2 from "@aws-sdk/client-ec2";
10
+ import * as ECS from "@aws-sdk/client-ecs";
11
+ import * as ElasticLoadBalancingV2 from "@aws-sdk/client-elastic-load-balancing-v2";
12
+ import * as Lambda from "@aws-sdk/client-lambda";
13
+ import * as RDS from "@aws-sdk/client-rds";
14
+ import * as SNS from "@aws-sdk/client-sns";
15
+ import * as SQS from "@aws-sdk/client-sqs";
16
+
17
+ /**
18
+ * Clients for Global Services
19
+ */
20
+ export const GlobalServiceClients = {
21
+ S3,
22
+ CloudFront,
23
+ Route53,
24
+ };
25
+
26
+ /**
27
+ * Clients for Regional Services
28
+ */
29
+ export const RegionalServiceClients = {
30
+ ApiGatewayV2,
31
+ AutoScaling,
32
+ CloudWatchLogs,
33
+ DynamoDB,
34
+ EC2,
35
+ ECS,
36
+ ElasticLoadBalancingV2,
37
+ Lambda,
38
+ RDS,
39
+ SNS,
40
+ SQS,
41
+ };
42
+
43
+ /**
44
+ * Clients for every service
45
+ */
46
+ export const ServiceClients = {
47
+ ...GlobalServiceClients,
48
+ ...RegionalServiceClients,
49
+ };
50
+
51
+ /**
52
+ * Type for Global Services
53
+ */
54
+ export type GlobalService = keyof typeof GlobalServiceClients;
55
+
56
+ /**
57
+ * Type for Regional Services
58
+ */
59
+ export type RegionalService = keyof typeof RegionalServiceClients;
60
+
61
+ /**
62
+ * Type for any support service
63
+ */
64
+ export type Service = GlobalService | RegionalService;
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "tsconfig/base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "src",
5
+ "noEmit": true,
6
+ "module": "Node16"
7
+ }
8
+ }
package/typedoc.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": ["../../typedoc.base.json"],
3
+ "entryPoints": ["src/index.ts"],
4
+ }