ownerlens 0.1.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.
Files changed (144) hide show
  1. package/LICENSE +183 -0
  2. package/README.md +209 -0
  3. package/bin/ownerlens.js +92 -0
  4. package/dist/assets/index-B9aAYpVl.css +1 -0
  5. package/dist/assets/index-BcwLk2bx.js +10 -0
  6. package/dist/index.html +13 -0
  7. package/package.json +73 -0
  8. package/src/App.tsx +18 -0
  9. package/src/components/azure/AzureComponent.test.tsx +625 -0
  10. package/src/components/azure/AzureComponent.tsx +189 -0
  11. package/src/components/azure/AzureRbacComponent.tsx +104 -0
  12. package/src/components/azure/ClosableAzureTab.tsx +42 -0
  13. package/src/components/azure/EntraPermissionsComponent.tsx +194 -0
  14. package/src/components/azure/ManagedIdentityComponent.test.tsx +324 -0
  15. package/src/components/azure/ManagedIdentityComponent.tsx +141 -0
  16. package/src/components/azure/ResourceGroupComponent.tsx +157 -0
  17. package/src/components/azure/ServicePrincipalComponent.test.tsx +457 -0
  18. package/src/components/azure/ServicePrincipalComponent.tsx +155 -0
  19. package/src/components/azure/ServicePrincipalFieldRenderers.tsx +140 -0
  20. package/src/components/azure/ZtaComponent.test.tsx +267 -0
  21. package/src/components/azure/ZtaComponent.tsx +276 -0
  22. package/src/components/azure/ZtaRemediationBadge.tsx +70 -0
  23. package/src/components/azure/api.ts +216 -0
  24. package/src/components/azure/azureReportConfig.ts +247 -0
  25. package/src/core/azure/azureRbac.ts +70 -0
  26. package/src/core/azure/entra/index.ts +1 -0
  27. package/src/core/azure/entra/managedIdentity.ts +21 -0
  28. package/src/core/azure/entra/servicePrincipal.ts +34 -0
  29. package/src/core/azure/entra/types.ts +56 -0
  30. package/src/core/azure/identityEnrichment.ts +65 -0
  31. package/src/core/azure/resources.ts +141 -0
  32. package/src/core/azure/ztaReport.ts +58 -0
  33. package/src/core/config.ts +39 -0
  34. package/src/core/ownership/OwnershipTarget.ts +32 -0
  35. package/src/core/ownership/resolveOwner.ts +5 -0
  36. package/src/core/ownership/types.ts +14 -0
  37. package/src/core/risk/types.ts +1 -0
  38. package/src/core/runtime/index.ts +1 -0
  39. package/src/core/runtime/localSnapshotFiles.ts +74 -0
  40. package/src/core/runtime/rest.ts +61 -0
  41. package/src/lib/searchFilterUtils.ts +17 -0
  42. package/src/lib/utils.ts +48 -0
  43. package/src/main.tsx +10 -0
  44. package/src/providers/azure/identities/azureIdentityTypes.ts +1 -0
  45. package/src/providers/azure/identities/buildAzureManagedIdentityAssignmentIndex.test.ts +32 -0
  46. package/src/providers/azure/identities/buildAzureManagedIdentityAssignmentIndex.ts +35 -0
  47. package/src/providers/azure/identities/userAssignedIdentityAssignments.ts +52 -0
  48. package/src/providers/azure/inputTransferObject/entra/EntraAppRoleAssignment.ts +10 -0
  49. package/src/providers/azure/inputTransferObject/entra/EntraApplication.ts +27 -0
  50. package/src/providers/azure/inputTransferObject/entra/EntraOAuth2PermissionGrant.ts +8 -0
  51. package/src/providers/azure/inputTransferObject/entra/EntraServicePrincipal.ts +43 -0
  52. package/src/providers/azure/inputTransferObject/entra/EntraSnapshot.ts +13 -0
  53. package/src/providers/azure/inputTransferObject/entra/EntraSnapshotMeta.ts +12 -0
  54. package/src/providers/azure/inputTransferObject/resources/AzureActivityLog.ts +1 -0
  55. package/src/providers/azure/inputTransferObject/resources/AzureResource.ts +1 -0
  56. package/src/providers/azure/inputTransferObject/resources/AzureResourceGroup.ts +1 -0
  57. package/src/providers/azure/inputTransferObject/resources/AzureRoleAssignment.ts +1 -0
  58. package/src/providers/azure/inputTransferObject/resources/AzureSnapshot.ts +1 -0
  59. package/src/providers/azure/inputTransferObject/resources/AzureSnapshotMeta.ts +1 -0
  60. package/src/providers/azure/inputTransferObject/resources/AzureSubscription.ts +1 -0
  61. package/src/providers/azure/inputTransferObject/resources/AzureUserAssignedManagedIdentity.ts +1 -0
  62. package/src/providers/azure/ownership/azureActivityOwnershipEvidence.ts +60 -0
  63. package/src/providers/azure/ownership/azureOwnerReportTypes.ts +13 -0
  64. package/src/providers/azure/ownership/azureOwnershipConfig.ts +21 -0
  65. package/src/providers/azure/ownership/azureOwnershipTypes.ts +46 -0
  66. package/src/providers/azure/ownership/buildAzureOwnershipReport.test.ts +99 -0
  67. package/src/providers/azure/ownership/buildAzureOwnershipReport.ts +90 -0
  68. package/src/providers/azure/ownership/buildAzureOwnershipTargets.test.ts +87 -0
  69. package/src/providers/azure/ownership/buildAzureOwnershipTargets.ts +42 -0
  70. package/src/providers/azure/ownership/resolveAzureOwner.ts +146 -0
  71. package/src/providers/azure/runtime/DisabledEvidenceStore.ts +34 -0
  72. package/src/providers/azure/runtime/EnrichmentService.ts +35 -0
  73. package/src/providers/azure/runtime/LocalReportRuntime.test.ts +2318 -0
  74. package/src/providers/azure/runtime/LocalReportRuntime.ts +302 -0
  75. package/src/providers/azure/runtime/RuntimeHost.ts +60 -0
  76. package/src/providers/azure/runtime/SnapshotImporter.ts +44 -0
  77. package/src/providers/azure/runtime/enrichment/azureIdentityEnrichment.ts +523 -0
  78. package/src/providers/azure/runtime/enrichment/azureScopeClassifier.ts +30 -0
  79. package/src/providers/azure/runtime/enrichment/evaluateAzureRoleAssignmentRisk.ts +88 -0
  80. package/src/providers/azure/runtime/entra/EntraCollectionQueryService.ts +307 -0
  81. package/src/providers/azure/runtime/entra/LocalEntraReportRuntime.ts +227 -0
  82. package/src/providers/azure/runtime/entra/appRoleAssignmentsTable.ts +52 -0
  83. package/src/providers/azure/runtime/entra/applicationsTable.ts +175 -0
  84. package/src/providers/azure/runtime/entra/entraServicePrincipalMapper.ts +63 -0
  85. package/src/providers/azure/runtime/entra/localReportRuntimeRest.ts +41 -0
  86. package/src/providers/azure/runtime/entra/oauth2PermissionGrantsTable.ts +48 -0
  87. package/src/providers/azure/runtime/entra/principalProjection.ts +173 -0
  88. package/src/providers/azure/runtime/entra/servicePrincipalsTable.ts +149 -0
  89. package/src/providers/azure/runtime/entra/snapshotMetadataTable.ts +18 -0
  90. package/src/providers/azure/runtime/entra/snapshotStore.ts +102 -0
  91. package/src/providers/azure/runtime/localReportCollections.ts +101 -0
  92. package/src/providers/azure/runtime/localReportRuntimeRest.ts +71 -0
  93. package/src/providers/azure/runtime/resources/AzureResourcesCollectionQueryService.ts +145 -0
  94. package/src/providers/azure/runtime/resources/LocalAzureResourcesReportRuntime.ts +114 -0
  95. package/src/providers/azure/runtime/resources/disabledOwnerEvidenceTable.ts +60 -0
  96. package/src/providers/azure/runtime/resources/localReportRuntimeRest.ts +81 -0
  97. package/src/providers/azure/runtime/resources/resourceGroupOwnership.ts +90 -0
  98. package/src/providers/azure/runtime/resources/snapshotMetadataTable.ts +19 -0
  99. package/src/providers/azure/runtime/resources/snapshotStore.ts +128 -0
  100. package/src/providers/azure/runtime/resources/tables.ts +441 -0
  101. package/src/providers/azure/runtime/runtimeRestQuery.ts +46 -0
  102. package/src/providers/azure/runtime/runtimeSqlSchema.ts +357 -0
  103. package/src/providers/azure/runtime/zta/Discovery.ts +141 -0
  104. package/src/providers/azure/runtime/zta/LocalZeroTrustAssessmentReportRuntime.ts +86 -0
  105. package/src/providers/azure/runtime/zta/ZeroTrustAssessmentQueryService.ts +124 -0
  106. package/src/providers/azure/runtime/zta/localReportRuntimeRest.ts +15 -0
  107. package/src/providers/azure/runtime/zta/snapshotMetadataTable.ts +77 -0
  108. package/src/providers/azure/runtime/zta/snapshotStore.ts +112 -0
  109. package/src/providers/azure/runtime/zta/tables.ts +361 -0
  110. package/src/providers/azure/runtime/zta/types.ts +7 -0
  111. package/src/providers/azure/runtime/zta/ztaReportMapper.ts +12 -0
  112. package/src/report/applyCollectionControls.ts +289 -0
  113. package/src/report/buildCollectionColumns.tsx +38 -0
  114. package/src/report/components/ConfidenceBadge.tsx +10 -0
  115. package/src/report/components/EvidenceList.test.ts +25 -0
  116. package/src/report/components/EvidenceList.tsx +52 -0
  117. package/src/report/components/GenericTable.tsx +373 -0
  118. package/src/report/components/PermissionRiskBadge.tsx +19 -0
  119. package/src/report/components/reportTableControls.test.ts +175 -0
  120. package/src/report/components/reportTableControls.tsx +483 -0
  121. package/src/report/components/ui/badge.tsx +35 -0
  122. package/src/report/components/ui/button.tsx +38 -0
  123. package/src/report/components/ui/card.tsx +23 -0
  124. package/src/report/components/ui/input.tsx +15 -0
  125. package/src/report/components/ui/table.tsx +44 -0
  126. package/src/report/components/ui/tabs.tsx +29 -0
  127. package/src/report/export/csv.ts +34 -0
  128. package/src/report/ownerManualPrecheck.test.ts +137 -0
  129. package/src/report/ownerManualPrecheck.ts +132 -0
  130. package/src/report/reportArchitecture.test.ts +125 -0
  131. package/src/report/reportTypes.ts +54 -0
  132. package/src/report/reportValueRenderers.tsx +54 -0
  133. package/src/report/runtimeCollectionQuery.ts +23 -0
  134. package/src/report/types.ts +14 -0
  135. package/src/styles.css +43 -0
  136. package/tools/README.md +108 -0
  137. package/tools/azure-activity-check.ps1 +164 -0
  138. package/tools/collect-azure.ps1 +54 -0
  139. package/tools/collect-entra.ps1 +47 -0
  140. package/tools/collect-scripts.test.ts +22 -0
  141. package/tools/prepare-entra-snapshot.ps1 +403 -0
  142. package/tools/prepare-entra-snapshot.test.ts +14 -0
  143. package/tools/prepare-resource-snapshot.ps1 +345 -0
  144. package/vite.config.ts +23 -0
@@ -0,0 +1,302 @@
1
+ import type { DuckDBConnection } from "@duckdb/node-api";
2
+
3
+ import {
4
+ listLocalSnapshotFiles,
5
+ pathExists,
6
+ readLocalSnapshotFile,
7
+ validateSnapshotFileName,
8
+ type LocalSnapshotData,
9
+ type LocalSnapshotFile
10
+ } from "../../../core/runtime/localSnapshotFiles";
11
+ import type { ManagedIdentity } from "../../../core/azure/entra/managedIdentity";
12
+ import type { ServicePrincipal } from "../../../core/azure/entra/servicePrincipal";
13
+ import type { ZtaReport, ZtaReportTest } from "../../../core/azure/ztaReport";
14
+ import type { AzureIdentityEnrichmentStatus } from "./enrichment/azureIdentityEnrichment";
15
+ import { EntraCollectionQueryService } from "./entra/EntraCollectionQueryService";
16
+ import {
17
+ LocalEntraReportRuntime,
18
+ type EntraPrincipalPermissions,
19
+ type LocalEntraReportCollectionId
20
+ } from "./entra/LocalEntraReportRuntime";
21
+ import type { EntraDuckDbImportStatus } from "./entra/snapshotStore";
22
+ import {
23
+ AzureResourcesCollectionQueryService,
24
+ type LocalAzureResourcesExtendedCollectionId
25
+ } from "./resources/AzureResourcesCollectionQueryService";
26
+ import { LocalAzureResourcesReportRuntime } from "./resources/LocalAzureResourcesReportRuntime";
27
+ import type { AzureResourcesDuckDbImportStatus } from "./resources/snapshotStore";
28
+ import { LocalZeroTrustAssessmentReportRuntime } from "./zta/LocalZeroTrustAssessmentReportRuntime";
29
+ import type { ZeroTrustAssessmentDuckDbImportStatus } from "./zta/snapshotStore";
30
+ import {
31
+ ZeroTrustAssessmentQueryService,
32
+ type LocalZeroTrustAssessmentReportCollectionId
33
+ } from "./zta/ZeroTrustAssessmentQueryService";
34
+ import {
35
+ type LocalReportCollectionQueryOptions,
36
+ type LocalReportPaginatedCollection
37
+ } from "./localReportCollections";
38
+ import { RuntimeHost } from "./RuntimeHost";
39
+ import { SnapshotImporter } from "./SnapshotImporter";
40
+ import { EnrichmentService } from "./EnrichmentService";
41
+ import { DisabledEvidenceStore, type DisabledOwnerKey } from "./DisabledEvidenceStore";
42
+ import { prepareRuntimeSqlSchema } from "./runtimeSqlSchema";
43
+
44
+ export type LocalReportRuntimeOptions = {
45
+ dataDir: string;
46
+ databasePath?: string;
47
+ };
48
+
49
+ export type LocalReportRuntimeStatus = {
50
+ initialized: boolean;
51
+ databasePath: string;
52
+ entra: EntraDuckDbImportStatus;
53
+ azureResources: AzureResourcesDuckDbImportStatus;
54
+ zeroTrustAssessment: ZeroTrustAssessmentDuckDbImportStatus;
55
+ enrichment: AzureIdentityEnrichmentStatus;
56
+ };
57
+
58
+ export type LocalReportCollectionId =
59
+ | LocalEntraReportCollectionId
60
+ | LocalAzureResourcesExtendedCollectionId
61
+ | LocalZeroTrustAssessmentReportCollectionId;
62
+
63
+ export class LocalReportRuntime {
64
+ private readonly dataDir: string;
65
+ private readonly host: RuntimeHost;
66
+ private readonly entra: LocalEntraReportRuntime;
67
+ private readonly azureResources: LocalAzureResourcesReportRuntime;
68
+ private readonly zeroTrustAssessment: LocalZeroTrustAssessmentReportRuntime;
69
+ private readonly zeroTrustAssessmentQueries: ZeroTrustAssessmentQueryService;
70
+ private readonly azureResourcesQueries: AzureResourcesCollectionQueryService;
71
+ private readonly entraQueries: EntraCollectionQueryService;
72
+ private readonly snapshotImporter: SnapshotImporter;
73
+ private readonly enrichmentService: EnrichmentService;
74
+ private readonly disabledEvidenceStore: DisabledEvidenceStore;
75
+ private initializePromise: Promise<void> | null = null;
76
+
77
+ constructor(options: LocalReportRuntimeOptions) {
78
+ this.dataDir = options.dataDir;
79
+ this.host = new RuntimeHost({ databasePath: options.databasePath ?? ":memory:" });
80
+ this.entra = new LocalEntraReportRuntime({
81
+ dataDir: this.dataDir,
82
+ getConnection: () => this.requireConnection()
83
+ });
84
+ this.azureResources = new LocalAzureResourcesReportRuntime({
85
+ dataDir: this.dataDir,
86
+ getConnection: () => this.requireConnection()
87
+ });
88
+ this.zeroTrustAssessment = new LocalZeroTrustAssessmentReportRuntime({
89
+ dataDir: this.dataDir,
90
+ getConnection: () => this.requireConnection()
91
+ });
92
+ this.zeroTrustAssessmentQueries = new ZeroTrustAssessmentQueryService({
93
+ zeroTrustAssessment: this.zeroTrustAssessment
94
+ });
95
+ this.snapshotImporter = new SnapshotImporter({
96
+ entra: this.entra,
97
+ azureResources: this.azureResources,
98
+ zeroTrustAssessment: this.zeroTrustAssessment
99
+ });
100
+ this.enrichmentService = new EnrichmentService(() => this.requireConnection());
101
+ this.disabledEvidenceStore = new DisabledEvidenceStore(() => this.requireConnection());
102
+ this.azureResourcesQueries = new AzureResourcesCollectionQueryService({
103
+ entra: this.entra,
104
+ azureResources: this.azureResources,
105
+ disabledEvidenceStore: this.disabledEvidenceStore
106
+ });
107
+ this.entraQueries = new EntraCollectionQueryService({
108
+ entra: this.entra,
109
+ azureResources: this.azureResources,
110
+ azureResourcesQueries: this.azureResourcesQueries,
111
+ zeroTrustAssessmentQueries: this.zeroTrustAssessmentQueries
112
+ });
113
+ }
114
+
115
+ initialize(): Promise<void> {
116
+ this.initializePromise ??= this.initializeInternal();
117
+ return this.initializePromise;
118
+ }
119
+
120
+ async listSnapshots(): Promise<{ files: LocalSnapshotFile[]; error?: string }> {
121
+ await this.initialize();
122
+
123
+ if (!(await pathExists(this.dataDir))) {
124
+ return {
125
+ files: [],
126
+ error:
127
+ "Snapshot directory ./data was not found. Run the snapshot scripts to create ./data/snapshot.json and ./data/entra-snapshot.json."
128
+ };
129
+ }
130
+
131
+ return { files: await listLocalSnapshotFiles(this.dataDir) };
132
+ }
133
+
134
+ async readSnapshot(name: string): Promise<LocalSnapshotData> {
135
+ await this.initialize();
136
+ validateSnapshotFileName(name);
137
+
138
+ if (this.entra.canReadSnapshot(name)) {
139
+ return this.entra.readSnapshot();
140
+ }
141
+
142
+ if (this.azureResources.canReadSnapshot(name)) {
143
+ return this.azureResources.readSnapshot();
144
+ }
145
+
146
+ return readLocalSnapshotFile(this.dataDir, name);
147
+ }
148
+
149
+ getStatus(): LocalReportRuntimeStatus {
150
+ const importStatus = this.snapshotImporter.getStatus();
151
+
152
+ return {
153
+ initialized: this.host.isInitialized(),
154
+ databasePath: this.host.getDatabasePath(),
155
+ entra: importStatus.entra,
156
+ azureResources: importStatus.azureResources,
157
+ zeroTrustAssessment: importStatus.zeroTrustAssessment,
158
+ enrichment: this.enrichmentService.getStatus()
159
+ };
160
+ }
161
+
162
+ async readServicePrincipals(): Promise<ServicePrincipal[]> {
163
+ await this.initialize();
164
+ return this.entra.readServicePrincipals();
165
+ }
166
+
167
+ async readManagedIdentities(): Promise<ManagedIdentity[]> {
168
+ await this.initialize();
169
+ return this.entra.readManagedIdentities();
170
+ }
171
+
172
+ async readZeroTrustAssessmentReport(): Promise<ZtaReport> {
173
+ await this.initialize();
174
+ return this.zeroTrustAssessmentQueries.readReport();
175
+ }
176
+
177
+ async recalculateEnrichment(): Promise<void> {
178
+ await this.initialize();
179
+ await this.enrichmentService.recalculate();
180
+ }
181
+
182
+ async setOwnerEvidenceDisabled(key: DisabledOwnerKey, disabled: boolean): Promise<number> {
183
+ await this.initialize();
184
+ return this.disabledEvidenceStore.setDisabled(key, disabled);
185
+ }
186
+
187
+ async queryEntraServicePrincipals(
188
+ options: LocalReportCollectionQueryOptions
189
+ ): Promise<LocalReportPaginatedCollection<"entra.servicePrincipals">> {
190
+ await this.initialize();
191
+ return this.entraQueries.queryServicePrincipals(options);
192
+ }
193
+
194
+ async queryEntraManagedIdentities(
195
+ options: LocalReportCollectionQueryOptions
196
+ ): Promise<LocalReportPaginatedCollection<"entra.managedIdentities">> {
197
+ await this.initialize();
198
+ return this.entraQueries.queryManagedIdentities(options);
199
+ }
200
+
201
+ async queryEntraOAuth2PermissionGrants(
202
+ options: LocalReportCollectionQueryOptions
203
+ ): Promise<LocalReportPaginatedCollection<"entra.oauth2PermissionGrants">> {
204
+ await this.initialize();
205
+ return this.entraQueries.queryOAuth2PermissionGrants(options);
206
+ }
207
+
208
+ async queryEntraAppRoleAssignments(
209
+ options: LocalReportCollectionQueryOptions
210
+ ): Promise<LocalReportPaginatedCollection<"entra.appRoleAssignments">> {
211
+ await this.initialize();
212
+ return this.entraQueries.queryAppRoleAssignments(options);
213
+ }
214
+
215
+ async readEntraPrincipalPermissions(principalId: string): Promise<EntraPrincipalPermissions> {
216
+ await this.initialize();
217
+ return this.entra.readEntraPrincipalPermissions(principalId);
218
+ }
219
+
220
+ async queryAzureSubscriptions(
221
+ options: LocalReportCollectionQueryOptions
222
+ ): Promise<LocalReportPaginatedCollection<"azureResources.subscriptions">> {
223
+ await this.initialize();
224
+ return this.azureResourcesQueries.querySubscriptions(options);
225
+ }
226
+
227
+ async queryAzureResourceGroups(
228
+ options: LocalReportCollectionQueryOptions
229
+ ): Promise<LocalReportPaginatedCollection<"azureResources.resourceGroups">> {
230
+ await this.initialize();
231
+ return this.azureResourcesQueries.queryResourceGroups(options);
232
+ }
233
+
234
+ async queryAzureResourceGroupOwnership(
235
+ options: LocalReportCollectionQueryOptions
236
+ ): Promise<LocalReportPaginatedCollection<"azureResources.resourceGroupOwnership">> {
237
+ await this.initialize();
238
+ return this.azureResourcesQueries.queryResourceGroupOwnership(options);
239
+ }
240
+
241
+ async queryAzureResources(
242
+ options: LocalReportCollectionQueryOptions
243
+ ): Promise<LocalReportPaginatedCollection<"azureResources.resources">> {
244
+ await this.initialize();
245
+ return this.azureResourcesQueries.queryResources(options);
246
+ }
247
+
248
+ async queryAzureUserAssignedManagedIdentities(
249
+ options: LocalReportCollectionQueryOptions
250
+ ): Promise<LocalReportPaginatedCollection<"azureResources.userAssignedManagedIdentities">> {
251
+ await this.initialize();
252
+ return this.azureResourcesQueries.queryUserAssignedManagedIdentities(options);
253
+ }
254
+
255
+ async queryAzureRoleAssignments(
256
+ options: LocalReportCollectionQueryOptions
257
+ ): Promise<LocalReportPaginatedCollection<"azureResources.roleAssignments">> {
258
+ await this.initialize();
259
+ return this.azureResourcesQueries.queryRoleAssignments(options);
260
+ }
261
+
262
+ async queryAzureRbac(
263
+ servicePrincipalId: string,
264
+ options: LocalReportCollectionQueryOptions
265
+ ): Promise<LocalReportPaginatedCollection<"azureRbac">> {
266
+ await this.initialize();
267
+ return this.azureResourcesQueries.queryAzureRbac(servicePrincipalId, options);
268
+ }
269
+
270
+ async queryAzureActivityLogs(
271
+ options: LocalReportCollectionQueryOptions
272
+ ): Promise<LocalReportPaginatedCollection<"azureResources.activityLogs">> {
273
+ await this.initialize();
274
+ return this.azureResourcesQueries.queryActivityLogs(options);
275
+ }
276
+
277
+ async queryZeroTrustAssessmentReport(
278
+ options: LocalReportCollectionQueryOptions
279
+ ): Promise<
280
+ LocalReportPaginatedCollection<"zeroTrustAssessment.report"> & Pick<ZtaReport, "Meta"> & { Tests: ZtaReportTest[] }
281
+ > {
282
+ await this.initialize();
283
+ return this.zeroTrustAssessmentQueries.queryReport(options);
284
+ }
285
+
286
+ async close(): Promise<void> {
287
+ await this.host.close();
288
+ this.initializePromise = null;
289
+ }
290
+
291
+ private async initializeInternal(): Promise<void> {
292
+ await this.host.initialize();
293
+ await prepareRuntimeSqlSchema(this.requireConnection());
294
+ await this.snapshotImporter.importSnapshots();
295
+ await this.enrichmentService.recalculate();
296
+ await this.enrichmentService.readStatus();
297
+ }
298
+
299
+ private requireConnection(): DuckDBConnection {
300
+ return this.host.requireConnection();
301
+ }
302
+ }
@@ -0,0 +1,60 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { DuckDBInstance, type DuckDBConnection } from "@duckdb/node-api";
5
+
6
+ export type RuntimeHostOptions = {
7
+ databasePath: string;
8
+ };
9
+
10
+ export class RuntimeHost {
11
+ private readonly databasePath: string;
12
+ private instance: DuckDBInstance | null = null;
13
+ private connection: DuckDBConnection | null = null;
14
+ private initializePromise: Promise<void> | null = null;
15
+ private initialized = false;
16
+
17
+ constructor(options: RuntimeHostOptions) {
18
+ this.databasePath = options.databasePath;
19
+ }
20
+
21
+ getDatabasePath(): string {
22
+ return this.databasePath;
23
+ }
24
+
25
+ isInitialized(): boolean {
26
+ return this.initialized;
27
+ }
28
+
29
+ initialize(): Promise<void> {
30
+ this.initializePromise ??= this.initializeInternal();
31
+ return this.initializePromise;
32
+ }
33
+
34
+ requireConnection(): DuckDBConnection {
35
+ if (!this.connection) {
36
+ throw new Error("Local report runtime is not initialized.");
37
+ }
38
+
39
+ return this.connection;
40
+ }
41
+
42
+ async close(): Promise<void> {
43
+ this.connection?.disconnectSync();
44
+ this.connection = null;
45
+ this.instance?.closeSync();
46
+ this.instance = null;
47
+ this.initializePromise = null;
48
+ this.initialized = false;
49
+ }
50
+
51
+ private async initializeInternal(): Promise<void> {
52
+ if (this.databasePath !== ":memory:") {
53
+ await mkdir(path.dirname(this.databasePath), { recursive: true });
54
+ }
55
+
56
+ this.instance = await DuckDBInstance.create(this.databasePath);
57
+ this.connection = await this.instance.connect();
58
+ this.initialized = true;
59
+ }
60
+ }
@@ -0,0 +1,44 @@
1
+ import { LocalEntraReportRuntime } from "./entra/LocalEntraReportRuntime";
2
+ import type { EntraDuckDbImportStatus } from "./entra/snapshotStore";
3
+ import { LocalAzureResourcesReportRuntime } from "./resources/LocalAzureResourcesReportRuntime";
4
+ import type { AzureResourcesDuckDbImportStatus } from "./resources/snapshotStore";
5
+ import { LocalZeroTrustAssessmentReportRuntime } from "./zta/LocalZeroTrustAssessmentReportRuntime";
6
+ import type { ZeroTrustAssessmentDuckDbImportStatus } from "./zta/snapshotStore";
7
+
8
+ export type SnapshotImporterOptions = {
9
+ entra: LocalEntraReportRuntime;
10
+ azureResources: LocalAzureResourcesReportRuntime;
11
+ zeroTrustAssessment: LocalZeroTrustAssessmentReportRuntime;
12
+ };
13
+
14
+ export type SnapshotImporterStatus = {
15
+ entra: EntraDuckDbImportStatus;
16
+ azureResources: AzureResourcesDuckDbImportStatus;
17
+ zeroTrustAssessment: ZeroTrustAssessmentDuckDbImportStatus;
18
+ };
19
+
20
+ export class SnapshotImporter {
21
+ private readonly entra: LocalEntraReportRuntime;
22
+ private readonly azureResources: LocalAzureResourcesReportRuntime;
23
+ private readonly zeroTrustAssessment: LocalZeroTrustAssessmentReportRuntime;
24
+
25
+ constructor(options: SnapshotImporterOptions) {
26
+ this.entra = options.entra;
27
+ this.azureResources = options.azureResources;
28
+ this.zeroTrustAssessment = options.zeroTrustAssessment;
29
+ }
30
+
31
+ getStatus(): SnapshotImporterStatus {
32
+ return {
33
+ entra: this.entra.getStatus(),
34
+ azureResources: this.azureResources.getStatus(),
35
+ zeroTrustAssessment: this.zeroTrustAssessment.getStatus()
36
+ };
37
+ }
38
+
39
+ async importSnapshots(): Promise<void> {
40
+ await this.entra.importSnapshot();
41
+ await this.azureResources.importSnapshot();
42
+ await this.zeroTrustAssessment.importSnapshot();
43
+ }
44
+ }