@pagopa/dx-savemoney 0.2.5 → 0.3.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 (103) hide show
  1. package/README.md +33 -27
  2. package/dist/azure/analyzer.d.ts +49 -21
  3. package/dist/azure/analyzer.d.ts.map +1 -1
  4. package/dist/azure/analyzer.js +369 -93
  5. package/dist/azure/analyzer.js.map +1 -1
  6. package/dist/azure/analyzers/advisor.d.ts +68 -0
  7. package/dist/azure/analyzers/advisor.d.ts.map +1 -0
  8. package/dist/azure/analyzers/advisor.js +234 -0
  9. package/dist/azure/analyzers/advisor.js.map +1 -0
  10. package/dist/azure/analyzers/index.d.ts +8 -0
  11. package/dist/azure/analyzers/index.d.ts.map +1 -0
  12. package/dist/azure/analyzers/index.js +6 -0
  13. package/dist/azure/analyzers/index.js.map +1 -0
  14. package/dist/azure/analyzers/registry.d.ts +29 -0
  15. package/dist/azure/analyzers/registry.d.ts.map +1 -0
  16. package/dist/azure/analyzers/registry.js +79 -0
  17. package/dist/azure/analyzers/registry.js.map +1 -0
  18. package/dist/azure/analyzers/subscription.d.ts +53 -0
  19. package/dist/azure/analyzers/subscription.d.ts.map +1 -0
  20. package/dist/azure/analyzers/subscription.js +18 -0
  21. package/dist/azure/analyzers/subscription.js.map +1 -0
  22. package/dist/azure/analyzers/types.d.ts +62 -0
  23. package/dist/azure/analyzers/types.d.ts.map +1 -0
  24. package/dist/azure/analyzers/types.js +15 -0
  25. package/dist/azure/analyzers/types.js.map +1 -0
  26. package/dist/azure/config.d.ts.map +1 -1
  27. package/dist/azure/config.js +2 -0
  28. package/dist/azure/config.js.map +1 -1
  29. package/dist/azure/index.d.ts +1 -0
  30. package/dist/azure/index.d.ts.map +1 -1
  31. package/dist/azure/index.js +1 -0
  32. package/dist/azure/index.js.map +1 -1
  33. package/dist/azure/report.d.ts.map +1 -1
  34. package/dist/azure/report.js +178 -29
  35. package/dist/azure/report.js.map +1 -1
  36. package/dist/azure/resources/app-service.d.ts +2 -1
  37. package/dist/azure/resources/app-service.d.ts.map +1 -1
  38. package/dist/azure/resources/app-service.js +3 -3
  39. package/dist/azure/resources/app-service.js.map +1 -1
  40. package/dist/azure/resources/container-app.d.ts +2 -1
  41. package/dist/azure/resources/container-app.d.ts.map +1 -1
  42. package/dist/azure/resources/container-app.js +9 -9
  43. package/dist/azure/resources/container-app.js.map +1 -1
  44. package/dist/azure/resources/public-ip.d.ts +2 -1
  45. package/dist/azure/resources/public-ip.d.ts.map +1 -1
  46. package/dist/azure/resources/public-ip.js +2 -2
  47. package/dist/azure/resources/public-ip.js.map +1 -1
  48. package/dist/azure/resources/static-web-app.d.ts +2 -1
  49. package/dist/azure/resources/static-web-app.d.ts.map +1 -1
  50. package/dist/azure/resources/static-web-app.js +3 -3
  51. package/dist/azure/resources/static-web-app.js.map +1 -1
  52. package/dist/azure/resources/storage.d.ts +2 -1
  53. package/dist/azure/resources/storage.d.ts.map +1 -1
  54. package/dist/azure/resources/storage.js +2 -2
  55. package/dist/azure/resources/storage.js.map +1 -1
  56. package/dist/azure/resources/vm.d.ts +2 -1
  57. package/dist/azure/resources/vm.d.ts.map +1 -1
  58. package/dist/azure/resources/vm.js +3 -3
  59. package/dist/azure/resources/vm.js.map +1 -1
  60. package/dist/azure/types.d.ts +34 -1
  61. package/dist/azure/types.d.ts.map +1 -1
  62. package/dist/azure/utils.d.ts +35 -3
  63. package/dist/azure/utils.d.ts.map +1 -1
  64. package/dist/azure/utils.js +70 -29
  65. package/dist/azure/utils.js.map +1 -1
  66. package/dist/finding.d.ts +114 -0
  67. package/dist/finding.d.ts.map +1 -0
  68. package/dist/finding.js +51 -0
  69. package/dist/finding.js.map +1 -0
  70. package/dist/index.d.ts +4 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +3 -0
  73. package/dist/index.js.map +1 -1
  74. package/dist/schema.d.ts +5 -0
  75. package/dist/schema.d.ts.map +1 -1
  76. package/dist/schema.js +14 -0
  77. package/dist/schema.js.map +1 -1
  78. package/package.json +4 -1
  79. package/src/__tests__/finding.test.ts +149 -0
  80. package/src/azure/__tests__/analyzer-tags.test.ts +74 -0
  81. package/src/azure/__tests__/report.test.ts +27 -0
  82. package/src/azure/__tests__/utils.test.ts +164 -2
  83. package/src/azure/analyzer.ts +513 -182
  84. package/src/azure/analyzers/__tests__/advisor.test.ts +367 -0
  85. package/src/azure/analyzers/advisor.ts +324 -0
  86. package/src/azure/analyzers/index.ts +14 -0
  87. package/src/azure/analyzers/registry.ts +196 -0
  88. package/src/azure/analyzers/subscription.ts +56 -0
  89. package/src/azure/analyzers/types.ts +66 -0
  90. package/src/azure/config.ts +2 -0
  91. package/src/azure/index.ts +1 -0
  92. package/src/azure/report.ts +206 -35
  93. package/src/azure/resources/app-service.ts +4 -0
  94. package/src/azure/resources/container-app.ts +10 -0
  95. package/src/azure/resources/public-ip.ts +3 -0
  96. package/src/azure/resources/static-web-app.ts +4 -0
  97. package/src/azure/resources/storage.ts +3 -0
  98. package/src/azure/resources/vm.ts +4 -0
  99. package/src/azure/types.ts +35 -1
  100. package/src/azure/utils.ts +110 -39
  101. package/src/finding.ts +152 -0
  102. package/src/index.ts +19 -1
  103. package/src/schema.ts +14 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Azure Advisor analyzer.
3
+ *
4
+ * Fetches all `Cost` recommendations for the target subscription via the
5
+ * `@azure/arm-advisor` SDK and normalises them into the unified `Finding`
6
+ * model.
7
+ *
8
+ * ## Two kinds of Advisor cost recommendations
9
+ *
10
+ * ### Resource-specific (resourceMetadata.resourceId contains /providers/)
11
+ * Recommendations about a particular Azure resource (e.g. "right-size this
12
+ * VM"). Each is emitted as a separate Finding so it appears next to the
13
+ * resource in the per-resource section of the report. `enrichReason` adds
14
+ * SKU / region / term context from `extendedProperties` so findings for
15
+ * the same recommendation type on different resources are distinguishable.
16
+ *
17
+ * ### Subscription-scoped (no resourceId, or resourceId without /providers/)
18
+ * Reserved Instance and Savings Plan recommendations. The Advisor API
19
+ * returns **one entry per qualifying combination** (term, scope, quantity,
20
+ * etc.) but the Azure Portal **groups them by `recommendationTypeId`** and
21
+ * shows a single entry for the best option — matching the mental model
22
+ * a user has when deciding whether to buy a commitment.
23
+ *
24
+ * Different amounts within the same `recommendationTypeId` represent
25
+ * **mutually exclusive purchase options** (e.g. different DB sizes or
26
+ * quantities); the user would choose one, not buy all. We therefore report
27
+ * the **maximum** savings amount across all unique configurations, matching
28
+ * the portal's behaviour. Scope variants (Shared / Single / ResourceGroup)
29
+ * that carry the same amount are deduplicated so they do not count more
30
+ * than once. True duplicates — recommendations with the same ARM ID —
31
+ * are also removed before taking the maximum.
32
+ */
33
+ import { AdvisorManagementClient } from "@azure/arm-advisor";
34
+ import { getLogger } from "@logtape/logtape";
35
+ /**
36
+ * Builds the Advisor subscription-level analyzer.
37
+ *
38
+ * @param clientFactory Optional override to inject a mock client in tests.
39
+ * In production the default factory builds a real
40
+ * `AdvisorManagementClient` from the credential.
41
+ */
42
+ export function createAdvisorAnalyzer(clientFactory) {
43
+ const build = clientFactory?.build ??
44
+ ((credential, subscriptionId) => new AdvisorManagementClient(credential, subscriptionId));
45
+ return {
46
+ async analyze(ctx) {
47
+ const logger = getLogger(["savemoney", "azure", "advisor"]);
48
+ const client = build(ctx.credential, ctx.subscriptionId);
49
+ const resourceFindings = [];
50
+ const subGroups = new Map();
51
+ for await (const rec of client.recommendations.list({
52
+ filter: "Category eq 'Cost'",
53
+ })) {
54
+ if (rec.category?.toLowerCase() !== "cost")
55
+ continue;
56
+ const rawResourceId = rec.resourceMetadata?.resourceId;
57
+ const props = rec.extendedProperties;
58
+ const savings = parseSavings(props);
59
+ if (rawResourceId && /\/providers\//i.test(rawResourceId)) {
60
+ resourceFindings.push(buildResourceFinding(rec, savings, props, rawResourceId));
61
+ }
62
+ else {
63
+ addToSubGroups(subGroups, rec, savings, ctx, logger);
64
+ }
65
+ }
66
+ const findings = [...resourceFindings, ...flushSubGroups(subGroups)];
67
+ logger.info(`Advisor: ${findings.length} cost finding(s) for ${ctx.subscriptionId}` +
68
+ ` (${resourceFindings.length} resource-specific, ${subGroups.size} subscription-level)`);
69
+ return findings;
70
+ },
71
+ id: "azure.advisor",
72
+ };
73
+ }
74
+ // ── helpers — extracted to keep `analyze` complexity within linter limits —
75
+ function addToSubGroups(subGroups, rec, savings, ctx, logger) {
76
+ const typeKey = rec.recommendationTypeId ??
77
+ `unknown.${rec.shortDescription?.problem ?? ""}`;
78
+ const existing = subGroups.get(typeKey);
79
+ if (existing) {
80
+ updateSubGroup(existing, rec.id ?? "", savings);
81
+ }
82
+ else {
83
+ subGroups.set(typeKey, createSubGroup(rec, typeKey, savings, ctx, logger));
84
+ }
85
+ }
86
+ function buildResourceFinding(rec, savings, props, rawResourceId) {
87
+ const problem = rec.shortDescription?.problem ??
88
+ rec.shortDescription?.solution ??
89
+ "Azure Advisor cost recommendation";
90
+ return {
91
+ category: "cost",
92
+ code: `advisor.${rec.recommendationTypeId ?? "unknown"}`,
93
+ estimatedMonthlySavings: savings,
94
+ reason: enrichReason(problem, props),
95
+ recommendedAction: rec.shortDescription?.solution,
96
+ resourceId: rawResourceId,
97
+ severity: mapImpact(rec.impact),
98
+ source: "advisor",
99
+ };
100
+ }
101
+ function createSubGroup(rec, typeKey, savings, ctx, logger) {
102
+ const problem = rec.shortDescription?.problem ??
103
+ rec.shortDescription?.solution ??
104
+ "Azure Advisor cost recommendation";
105
+ const reason = problem.endsWith(".") ? problem : `${problem}.`;
106
+ const rawResourceId = rec.resourceMetadata?.resourceId;
107
+ const resourceId = rawResourceId ?? `/subscriptions/${ctx.subscriptionId}`;
108
+ if (!rawResourceId && ctx.verbose) {
109
+ logger.debug(`Advisor recommendation has no resourceId, attributed to subscription: ${typeKey}`);
110
+ }
111
+ return {
112
+ bestAmount: savings?.amount ?? 0,
113
+ count: savings ? 1 : 0,
114
+ currency: savings?.currency ?? "USD",
115
+ proto: {
116
+ category: "cost",
117
+ code: `advisor.${typeKey}`,
118
+ reason,
119
+ recommendedAction: rec.shortDescription?.solution,
120
+ resourceId,
121
+ severity: mapImpact(rec.impact),
122
+ source: "advisor",
123
+ },
124
+ recIds: new Set(rec.id ? [rec.id] : []),
125
+ uniqueSavingsKeys: new Set(savings ? [`${savings.amount}`] : []),
126
+ };
127
+ }
128
+ /**
129
+ * Appends discriminating context (SKU, region, term, scope, …) to the
130
+ * Advisor short description so visually-duplicated reasons can be told
131
+ * apart. RI / Savings Plan recommendations in particular return the same
132
+ * `problem` string for every SKU+region+term combination, which made the
133
+ * report look like it carried duplicated rows. Each call stays a single
134
+ * Finding — we do NOT deduplicate, because every recommendation refers
135
+ * to a different commitment with its own savings figure.
136
+ */
137
+ function enrichReason(problem, props) {
138
+ const base = problem.endsWith(".") ? problem : `${problem}.`;
139
+ if (!props)
140
+ return base;
141
+ const parts = [];
142
+ // armSkuName covers VM RIs; productName/serviceType cover SQL/Cosmos/etc.
143
+ const sku = props.armSkuName ?? props.productName ?? props.serviceType ?? props.sku;
144
+ if (sku)
145
+ parts.push(sku);
146
+ const region = props.region ?? props.location;
147
+ if (region)
148
+ parts.push(region);
149
+ // Normalise term values (P1Y / P3Y / 1_Year / 3_Year) into a compact label.
150
+ const rawTerm = props.term;
151
+ if (rawTerm) {
152
+ const term = /3/.test(rawTerm) ? "3y" : /1/.test(rawTerm) ? "1y" : rawTerm;
153
+ parts.push(term);
154
+ }
155
+ const scope = props.scope;
156
+ if (scope)
157
+ parts.push(scope.toLowerCase());
158
+ const qty = props.displayQuantity ?? props.quantity;
159
+ if (qty)
160
+ parts.push(`x${qty}`);
161
+ if (parts.length === 0)
162
+ return base;
163
+ return `${base} (${parts.join(", ")})`;
164
+ }
165
+ function flushSubGroups(subGroups) {
166
+ const findings = [];
167
+ for (const { bestAmount, count, currency, proto } of subGroups.values()) {
168
+ const estimatedMonthlySavings = bestAmount > 0 ? { amount: bestAmount, currency } : undefined;
169
+ const reason = count > 1
170
+ ? proto.reason.replace(/\.$/, ` (${count} options).`)
171
+ : proto.reason;
172
+ findings.push({ ...proto, estimatedMonthlySavings, reason });
173
+ }
174
+ return findings;
175
+ }
176
+ /**
177
+ * Maps Advisor's `impact` (`High` | `Medium` | `Low`) onto the savemoney
178
+ * `CostRisk` scale. Falls back to `low` for any unexpected value to keep
179
+ * the analyzer resilient to future Advisor enum extensions.
180
+ */
181
+ function mapImpact(impact) {
182
+ switch (impact?.toLowerCase()) {
183
+ case "high":
184
+ return "high";
185
+ case "medium":
186
+ return "medium";
187
+ default:
188
+ return "low";
189
+ }
190
+ }
191
+ /**
192
+ * Parses the savings amount from Advisor's `extendedProperties`. Advisor
193
+ * returns it as a string; treat anything non-numeric as "no estimate".
194
+ */
195
+ function parseSavings(extendedProperties) {
196
+ if (!extendedProperties)
197
+ return undefined;
198
+ const raw = extendedProperties.savingsAmount ?? extendedProperties.savings;
199
+ if (!raw)
200
+ return undefined;
201
+ const amount = Number(raw);
202
+ if (!Number.isFinite(amount))
203
+ return undefined;
204
+ const currency = extendedProperties.savingsCurrency ?? extendedProperties.currency ?? "USD";
205
+ return { amount, currency };
206
+ }
207
+ function updateSubGroup(group, recId, savings) {
208
+ if (recId && group.recIds.has(recId))
209
+ return; // true API duplicate
210
+ if (recId)
211
+ group.recIds.add(recId);
212
+ if (!savings)
213
+ return;
214
+ // Bootstrap currency from the first recommendation that carries savings.
215
+ // createSubGroup() defaults currency to "USD" when the first entry has no
216
+ // savings; without this check, later entries with a different currency (e.g.
217
+ // "EUR") would be silently dropped and no savings would ever be surfaced.
218
+ if (group.count === 0) {
219
+ group.currency = savings.currency;
220
+ group.uniqueSavingsKeys.add(`${savings.amount}`);
221
+ group.bestAmount = savings.amount;
222
+ group.count = 1;
223
+ return;
224
+ }
225
+ if (savings.currency !== group.currency)
226
+ return;
227
+ const key = `${savings.amount}`;
228
+ if (group.uniqueSavingsKeys.has(key))
229
+ return; // scope variant, already seen
230
+ group.uniqueSavingsKeys.add(key);
231
+ group.bestAmount = Math.max(group.bestAmount, savings.amount);
232
+ group.count++;
233
+ }
234
+ //# sourceMappingURL=advisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advisor.js","sourceRoot":"","sources":["../../../src/azure/analyzers/advisor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Re-exports for the Azure analyzer plugin layer.
3
+ */
4
+ export { createAdvisorAnalyzer } from "./advisor.js";
5
+ export { createDefaultAnalyzers, createDefaultSubscriptionAnalyzers, } from "./registry.js";
6
+ export type { SubscriptionAnalyzer, SubscriptionContext, } from "./subscription.js";
7
+ export type { Analyzer, AnalyzerContext, AzureClients } from "./types.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/azure/analyzers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-exports for the Azure analyzer plugin layer.
3
+ */
4
+ export { createAdvisorAnalyzer } from "./advisor.js";
5
+ export { createDefaultAnalyzers, createDefaultSubscriptionAnalyzers, } from "./registry.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/azure/analyzers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,eAAe,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Default registry of Azure analyzers.
3
+ *
4
+ * Each entry wraps an existing per-type analyzer function (kept in
5
+ * `../resources/`) and exposes it through the unified `Analyzer`
6
+ * interface. The orchestrator simply iterates the registry — no big
7
+ * `switch` statement, no risk of forgetting to wire a new analyzer
8
+ * into the orchestrator when the catalog grows.
9
+ *
10
+ * Adding a new analyzer is a single insertion here.
11
+ */
12
+ import type { SubscriptionAnalyzer } from "./subscription.js";
13
+ import type { Analyzer } from "./types.js";
14
+ /**
15
+ * Builds the default set of analyzers in the same order they were
16
+ * previously evaluated by the orchestrator's `switch` statement. The
17
+ * order is not behaviourally meaningful today (each resource is matched
18
+ * by exactly one analyzer) but is kept deterministic for predictable
19
+ * logging and to ease future debugging.
20
+ */
21
+ export declare function createDefaultAnalyzers(): Analyzer[];
22
+ /**
23
+ * Builds the default set of subscription-level analyzers.
24
+ *
25
+ * Today this is just Azure Advisor; Phase 4 will add a quota / usages
26
+ * analyzer here. Adding new sources is a single insertion.
27
+ */
28
+ export declare function createDefaultSubscriptionAnalyzers(): SubscriptionAnalyzer[];
29
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/azure/analyzers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAe3C;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,QAAQ,EAAE,CAsJnD;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,IAAI,oBAAoB,EAAE,CAE3E"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Default registry of Azure analyzers.
3
+ *
4
+ * Each entry wraps an existing per-type analyzer function (kept in
5
+ * `../resources/`) and exposes it through the unified `Analyzer`
6
+ * interface. The orchestrator simply iterates the registry — no big
7
+ * `switch` statement, no risk of forgetting to wire a new analyzer
8
+ * into the orchestrator when the catalog grows.
9
+ *
10
+ * Adding a new analyzer is a single insertion here.
11
+ */
12
+ import { analyzeAppServicePlan, analyzeContainerApp, analyzeDisk, analyzeNic, analyzePrivateEndpoint, analyzePublicIp, analyzeStaticSite, analyzeStorageAccount, analyzeVM, } from "../resources/index.js";
13
+ import { createAdvisorAnalyzer } from "./advisor.js";
14
+ /**
15
+ * Builds the default set of analyzers in the same order they were
16
+ * previously evaluated by the orchestrator's `switch` statement. The
17
+ * order is not behaviourally meaningful today (each resource is matched
18
+ * by exactly one analyzer) but is kept deterministic for predictable
19
+ * logging and to ease future debugging.
20
+ */
21
+ export function createDefaultAnalyzers() {
22
+ return [
23
+ {
24
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzeContainerApp(resource, clients.containerApps, clients.monitor, timespanDays, thresholds, verbose, metricsCache),
25
+ id: "azure.container-app",
26
+ supports: (r) => r.type?.toLowerCase() === "microsoft.app/containerapps",
27
+ },
28
+ {
29
+ analyze: ({ clients, resource, verbose }) => analyzeDisk(resource, clients.compute, verbose),
30
+ id: "azure.disk",
31
+ supports: (r) => r.type?.toLowerCase() === "microsoft.compute/disks",
32
+ },
33
+ {
34
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzeVM(resource, clients.monitor, clients.compute, timespanDays, thresholds, verbose, metricsCache),
35
+ id: "azure.vm",
36
+ supports: (r) => r.type?.toLowerCase() === "microsoft.compute/virtualmachines",
37
+ },
38
+ {
39
+ analyze: ({ clients, resource, verbose }) => analyzeNic(resource, clients.network, verbose),
40
+ id: "azure.nic",
41
+ supports: (r) => r.type?.toLowerCase() === "microsoft.network/networkinterfaces",
42
+ },
43
+ {
44
+ analyze: ({ clients, resource, verbose }) => analyzePrivateEndpoint(resource, clients.network, verbose),
45
+ id: "azure.private-endpoint",
46
+ supports: (r) => r.type?.toLowerCase() === "microsoft.network/privateendpoints",
47
+ },
48
+ {
49
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzePublicIp(resource, clients.network, clients.monitor, timespanDays, thresholds, verbose, metricsCache),
50
+ id: "azure.public-ip",
51
+ supports: (r) => r.type?.toLowerCase() === "microsoft.network/publicipaddresses",
52
+ },
53
+ {
54
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzeStorageAccount(resource, clients.monitor, timespanDays, thresholds, verbose, metricsCache),
55
+ id: "azure.storage-account",
56
+ supports: (r) => r.type?.toLowerCase() === "microsoft.storage/storageaccounts",
57
+ },
58
+ {
59
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzeAppServicePlan(resource, clients.webSite, clients.monitor, timespanDays, thresholds, verbose, metricsCache),
60
+ id: "azure.app-service-plan",
61
+ supports: (r) => r.type?.toLowerCase() === "microsoft.web/serverfarms",
62
+ },
63
+ {
64
+ analyze: ({ clients, metricsCache, resource, thresholds, timespanDays, verbose, }) => analyzeStaticSite(resource, clients.monitor, timespanDays, thresholds, verbose, metricsCache),
65
+ id: "azure.static-web-app",
66
+ supports: (r) => r.type?.toLowerCase() === "microsoft.web/staticsites",
67
+ },
68
+ ];
69
+ }
70
+ /**
71
+ * Builds the default set of subscription-level analyzers.
72
+ *
73
+ * Today this is just Azure Advisor; Phase 4 will add a quota / usages
74
+ * analyzer here. Adding new sources is a single insertion.
75
+ */
76
+ export function createDefaultSubscriptionAnalyzers() {
77
+ return [createAdvisorAnalyzer()];
78
+ }
79
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/azure/analyzers/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Subscription-level analyzer plugin contract.
3
+ *
4
+ * Some data sources are not naturally per-resource. Azure Advisor, for
5
+ * example, returns a flat list of recommendations for an entire
6
+ * subscription in a single call; future quota / `Microsoft.Capacity/usages`
7
+ * analyzers will follow the same shape.
8
+ *
9
+ * A `SubscriptionAnalyzer` is invoked once per subscription. It returns a
10
+ * flat list of `Finding`s carrying the `resourceId` they refer to; the
11
+ * orchestrator merges those findings into the per-resource reports.
12
+ *
13
+ * This interface is intentionally additive: per-resource `Analyzer`s
14
+ * (see `./types.ts`) keep working untouched. Sources written against the
15
+ * two interfaces can coexist in the same run.
16
+ */
17
+ import type { TokenCredential } from "@azure/identity";
18
+ import type { Finding } from "../../finding.js";
19
+ /**
20
+ * Contract every subscription-level analyzer must satisfy.
21
+ */
22
+ export type SubscriptionAnalyzer = {
23
+ /**
24
+ * Runs the analyzer for the given subscription. Implementations should
25
+ * be resilient: a failure here must not abort the whole run, the
26
+ * orchestrator logs and continues with the remaining analyzers.
27
+ */
28
+ analyze(ctx: SubscriptionContext): Promise<Finding[]>;
29
+ /**
30
+ * Stable identifier of the analyzer (e.g. `azure.advisor`,
31
+ * `azure.quota`). Used for logging and future deduplication logic.
32
+ */
33
+ readonly id: string;
34
+ };
35
+ /**
36
+ * Context passed to every subscription-level analyzer.
37
+ */
38
+ export type SubscriptionContext = {
39
+ /**
40
+ * Azure credential to instantiate management clients. The orchestrator
41
+ * builds it once and reuses it across analyzers.
42
+ */
43
+ credential: TokenCredential;
44
+ /**
45
+ * Subscription ID to analyze.
46
+ */
47
+ subscriptionId: string;
48
+ /**
49
+ * Whether verbose logging is enabled.
50
+ */
51
+ verbose: boolean;
52
+ };
53
+ //# sourceMappingURL=subscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../../src/azure/analyzers/subscription.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;OAIG;IACH,OAAO,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACtD;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,UAAU,EAAE,eAAe,CAAC;IAC5B;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Subscription-level analyzer plugin contract.
3
+ *
4
+ * Some data sources are not naturally per-resource. Azure Advisor, for
5
+ * example, returns a flat list of recommendations for an entire
6
+ * subscription in a single call; future quota / `Microsoft.Capacity/usages`
7
+ * analyzers will follow the same shape.
8
+ *
9
+ * A `SubscriptionAnalyzer` is invoked once per subscription. It returns a
10
+ * flat list of `Finding`s carrying the `resourceId` they refer to; the
11
+ * orchestrator merges those findings into the per-resource reports.
12
+ *
13
+ * This interface is intentionally additive: per-resource `Analyzer`s
14
+ * (see `./types.ts`) keep working untouched. Sources written against the
15
+ * two interfaces can coexist in the same run.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../src/azure/analyzers/subscription.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Plugin architecture for Azure resource analyzers.
3
+ *
4
+ * Each `Analyzer` is a self-contained unit that:
5
+ * 1. declares the resource types it can handle (`supports`)
6
+ * 2. produces an `AnalysisResult` for a given resource (`analyze`)
7
+ *
8
+ * The orchestrator in `analyzer.ts` walks the registered analyzers for
9
+ * every resource it encounters. New sources (Azure Advisor, custom
10
+ * checks, pricing-enriched analyzers, …) can be added by implementing
11
+ * the interface and registering them in `registry.ts` without touching
12
+ * the orchestrator.
13
+ */
14
+ import type { ContainerAppsAPIClient } from "@azure/arm-appcontainers";
15
+ import type { WebSiteManagementClient } from "@azure/arm-appservice";
16
+ import type { ComputeManagementClient } from "@azure/arm-compute";
17
+ import type { MonitorClient } from "@azure/arm-monitor";
18
+ import type { NetworkManagementClient } from "@azure/arm-network";
19
+ import type * as armResources from "@azure/arm-resources";
20
+ import type { AnalysisResult, Thresholds } from "../../types.js";
21
+ import type { MetricsCache } from "../utils.js";
22
+ /**
23
+ * Contract every analyzer must satisfy.
24
+ */
25
+ export type Analyzer = {
26
+ analyze(ctx: AnalyzerContext): Promise<AnalysisResult>;
27
+ /**
28
+ * Stable identifier of the analyzer (e.g. `azure.vm`, `azure.advisor`).
29
+ * Used for logging, telemetry and future deduplication logic.
30
+ */
31
+ readonly id: string;
32
+ supports(resource: armResources.GenericResource): boolean;
33
+ };
34
+ /**
35
+ * Per-resource analysis context handed to every analyzer.
36
+ */
37
+ export type AnalyzerContext = {
38
+ clients: AzureClients;
39
+ /**
40
+ * Run-scoped metrics cache. Pass through to `getMetric` calls so that
41
+ * concurrent `analyzeAzureResources` invocations stay isolated.
42
+ */
43
+ metricsCache: MetricsCache;
44
+ preferredLocation: string;
45
+ resource: armResources.GenericResource;
46
+ thresholds: Thresholds;
47
+ timespanDays: number;
48
+ verbose: boolean;
49
+ };
50
+ /**
51
+ * Bundle of Azure SDK clients an analyzer might need. The orchestrator
52
+ * builds them once per subscription and passes the same instances to
53
+ * every analyzer.
54
+ */
55
+ export type AzureClients = {
56
+ compute: ComputeManagementClient;
57
+ containerApps: ContainerAppsAPIClient;
58
+ monitor: MonitorClient;
59
+ network: NetworkManagementClient;
60
+ webSite: WebSiteManagementClient;
61
+ };
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/azure/analyzers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACvD;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,eAAe,GAAG,OAAO,CAAC;CAC3D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,YAAY,CAAC;IACtB;;;OAGG;IACH,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,uBAAuB,CAAC;IACjC,aAAa,EAAE,sBAAsB,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,uBAAuB,CAAC;IACjC,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Plugin architecture for Azure resource analyzers.
3
+ *
4
+ * Each `Analyzer` is a self-contained unit that:
5
+ * 1. declares the resource types it can handle (`supports`)
6
+ * 2. produces an `AnalysisResult` for a given resource (`analyze`)
7
+ *
8
+ * The orchestrator in `analyzer.ts` walks the registered analyzers for
9
+ * every resource it encounters. New sources (Azure Advisor, custom
10
+ * checks, pricing-enriched analyzers, …) can be added by implementing
11
+ * the interface and registering them in `registry.ts` without touching
12
+ * the orchestrator.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/azure/analyzers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/azure/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CA0CtB;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW9D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/azure/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CA4CtB;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW9D"}
@@ -35,7 +35,9 @@ export async function loadAzureConfig(configPath) {
35
35
  const rawYaml = yaml.load(raw);
36
36
  const parsed = ConfigSchema.parse(rawYaml);
37
37
  return {
38
+ concurrency: parsed.azure.concurrency,
38
39
  preferredLocation: parsed.azure.preferredLocation,
40
+ sources: parsed.azure.sources,
39
41
  subscriptionIds: parsed.azure.subscriptionIds,
40
42
  thresholds: parsed.azure.thresholds,
41
43
  timespanDays: parsed.azure.timespanDays,
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/azure/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAmB;IAEnB,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO;gBACL,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB;gBACjD,eAAe,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe;gBAC7C,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU;gBACnC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY;aACxC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE;oBACjE,KAAK,EAAE,KAAK;iBACb,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,KAAK,CACb,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,EAC/E,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC3D,MAAM,CAAC,IAAI,CACT,iEAAiE,CAClE,CAAC;IAEF,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB;QACrD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC;QAC5C,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE5E,OAAO;QACL,iBAAiB,EAAE,YAAY;QAC/B,eAAe;QACf,YAAY,EAAE,EAAE;KACjB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAgB;IAC3C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/azure/config.ts"],"names":[],"mappings":"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"}
@@ -5,5 +5,6 @@
5
5
  */
6
6
  export * from "./analyzer.js";
7
7
  export * from "./config.js";
8
+ export * from "./report.js";
8
9
  export * from "./types.js";
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/azure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/azure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
@@ -5,5 +5,6 @@
5
5
  */
6
6
  export * from "./analyzer.js";
7
7
  export * from "./config.js";
8
+ export * from "./report.js";
8
9
  export * from "./types.js";
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/azure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/azure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,2BAA2B,EAE5B,MAAM,YAAY,CAAC;AAuBpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,2BAA2B,EAAE,EACrC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,iBAmCpD"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EACV,2BAA2B,EAE5B,MAAM,YAAY,CAAC;AAmCpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,2BAA2B,EAAE,EACrC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,iBAmDpD"}