@pagopa/dx-savemoney 0.1.6 → 0.2.1

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 (76) hide show
  1. package/README.md +104 -27
  2. package/dist/azure/analyzer.d.ts +4 -4
  3. package/dist/azure/analyzer.d.ts.map +1 -1
  4. package/dist/azure/analyzer.js +16 -10
  5. package/dist/azure/analyzer.js.map +1 -1
  6. package/dist/azure/config.d.ts +15 -3
  7. package/dist/azure/config.d.ts.map +1 -1
  8. package/dist/azure/config.js +35 -17
  9. package/dist/azure/config.js.map +1 -1
  10. package/dist/azure/report.d.ts +2 -2
  11. package/dist/azure/report.d.ts.map +1 -1
  12. package/dist/azure/report.js +68 -3
  13. package/dist/azure/report.js.map +1 -1
  14. package/dist/azure/resources/app-service.d.ts +2 -2
  15. package/dist/azure/resources/app-service.d.ts.map +1 -1
  16. package/dist/azure/resources/app-service.js +8 -5
  17. package/dist/azure/resources/app-service.js.map +1 -1
  18. package/dist/azure/resources/container-app.d.ts +2 -2
  19. package/dist/azure/resources/container-app.d.ts.map +1 -1
  20. package/dist/azure/resources/container-app.js +10 -8
  21. package/dist/azure/resources/container-app.js.map +1 -1
  22. package/dist/azure/resources/public-ip.d.ts +2 -2
  23. package/dist/azure/resources/public-ip.d.ts.map +1 -1
  24. package/dist/azure/resources/public-ip.js +3 -3
  25. package/dist/azure/resources/public-ip.js.map +1 -1
  26. package/dist/azure/resources/static-web-app.d.ts +2 -2
  27. package/dist/azure/resources/static-web-app.d.ts.map +1 -1
  28. package/dist/azure/resources/static-web-app.js +4 -5
  29. package/dist/azure/resources/static-web-app.js.map +1 -1
  30. package/dist/azure/resources/storage.d.ts +2 -2
  31. package/dist/azure/resources/storage.d.ts.map +1 -1
  32. package/dist/azure/resources/storage.js +4 -3
  33. package/dist/azure/resources/storage.js.map +1 -1
  34. package/dist/azure/resources/vm.d.ts +2 -2
  35. package/dist/azure/resources/vm.d.ts.map +1 -1
  36. package/dist/azure/resources/vm.js +4 -5
  37. package/dist/azure/resources/vm.js.map +1 -1
  38. package/dist/azure/types.d.ts +10 -2
  39. package/dist/azure/types.d.ts.map +1 -1
  40. package/dist/azure/utils.d.ts +9 -0
  41. package/dist/azure/utils.d.ts.map +1 -1
  42. package/dist/azure/utils.js +14 -0
  43. package/dist/azure/utils.js.map +1 -1
  44. package/dist/index.d.ts +16 -11
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +18 -54
  47. package/dist/index.js.map +1 -1
  48. package/dist/schema.d.ts +210 -0
  49. package/dist/schema.d.ts.map +1 -0
  50. package/dist/schema.js +97 -0
  51. package/dist/schema.js.map +1 -0
  52. package/dist/types.d.ts +35 -0
  53. package/dist/types.d.ts.map +1 -1
  54. package/dist/types.js +6 -0
  55. package/dist/types.js.map +1 -1
  56. package/package.json +10 -4
  57. package/src/azure/__tests__/config.test.ts +97 -0
  58. package/src/azure/__tests__/fixtures/full-override.yaml +25 -0
  59. package/src/azure/__tests__/fixtures/partial-override.yaml +10 -0
  60. package/src/azure/__tests__/report.test.ts +138 -0
  61. package/src/azure/__tests__/utils.test.ts +124 -0
  62. package/src/azure/analyzer.ts +24 -3
  63. package/src/azure/config.ts +36 -21
  64. package/src/azure/report.ts +81 -4
  65. package/src/azure/resources/__tests__/storage.test.ts +185 -0
  66. package/src/azure/resources/app-service.ts +13 -5
  67. package/src/azure/resources/container-app.ts +13 -4
  68. package/src/azure/resources/public-ip.ts +4 -3
  69. package/src/azure/resources/static-web-app.ts +5 -5
  70. package/src/azure/resources/storage.ts +7 -3
  71. package/src/azure/resources/vm.ts +5 -5
  72. package/src/azure/types.ts +15 -2
  73. package/src/azure/utils.ts +21 -0
  74. package/src/index.ts +19 -69
  75. package/src/schema.ts +134 -0
  76. package/src/types.ts +14 -0
package/README.md CHANGED
@@ -80,7 +80,10 @@ yarn add @pagopa/dx-savemoney
80
80
  - `table`: A human-readable summary for the terminal.
81
81
  - `json`: Standard format for integration with other tools.
82
82
  - `detailed-json`: A comprehensive output with all resource metadata, ideal for in-depth analysis via AI or custom scripts.
83
+ - `lint`: A linter-style output grouped by resource, with risk icons and a summary — ideal for CI pipelines and quick triage.
83
84
  - **Simplified Configuration**: Supports configuration via files, command-line options, environment variables, or an interactive prompt.
85
+ - **Configurable Thresholds**: All analysis thresholds (CPU%, memory, transaction counts, etc.) can be overridden via the `thresholds` section of the YAML config file.
86
+ - **Tag Filtering**: Restrict the analysis to resources that match specific tag key-value pairs.
84
87
 
85
88
  ### Analyzed Resources
86
89
 
@@ -123,7 +126,7 @@ All resources are also checked for:
123
126
  import { azure, loadConfig } from "@pagopa/dx-savemoney";
124
127
 
125
128
  // Load configuration (from file, env vars, or interactive prompt)
126
- const config = await loadConfig("./config.json");
129
+ const config = await loadConfig("./config.yaml");
127
130
 
128
131
  // Run analysis and generate report
129
132
  await azure.analyzeAzureResources(config, "table");
@@ -133,63 +136,139 @@ await azure.analyzeAzureResources(config, "table");
133
136
 
134
137
  The tool requires the following configuration:
135
138
 
136
- | Input | Type | Required | Default | Description |
137
- | :------------------ | :--------- | :------: | :----------- | :----------------------------------------------------------- |
138
- | `tenantId` | `string` | ✅ | - | Azure Active Directory Tenant ID |
139
- | `subscriptionIds` | `string[]` | | - | Array of Azure subscription IDs to analyze |
140
- | `preferredLocation` | `string` | ❌ | `italynorth` | Preferred Azure region (resources elsewhere will be flagged) |
141
- | `timespanDays` | `number` | ❌ | `30` | Number of days to look back for metrics analysis |
142
- | `verbose` | `boolean` | ❌ | `false` | Enable detailed logging for each resource analyzed |
139
+ | Input | Type | Required | Default | Description |
140
+ | :------------------ | :----------------------- | :------: | :----------- | :------------------------------------------------------------------------ |
141
+ | `subscriptionIds` | `string[]` | ✅ | - | Array of Azure subscription IDs to analyze |
142
+ | `preferredLocation` | `string` | | `italynorth` | Preferred Azure region (resources elsewhere will be flagged) |
143
+ | `timespanDays` | `number` | ❌ | `30` | Number of days to look back for metrics analysis |
144
+ | `verbose` | `boolean` | ❌ | `false` | Enable detailed logging for each resource analyzed |
145
+ | `filterTags` | `Record<string, string>` | ❌ | - | Only analyze resources matching **all** the specified tag key-value pairs |
146
+ | `thresholds` | `Thresholds` | ❌ | see below | Override the default numeric thresholds used during analysis |
143
147
 
144
148
  #### Output Formats
145
149
 
146
150
  The tool supports multiple output formats for different use cases:
147
151
 
148
- | Format | Description | Use Case |
149
- | :-------------- | :---------------------------------------------- | :----------------------------- |
150
- | `table` | Human-readable table in terminal | Quick visual inspection |
151
- | `json` | Structured JSON with resource summaries | Integration with other tools |
152
- | `detailed-json` | Complete JSON with full Azure resource metadata | AI analysis or deep inspection |
152
+ | Format | Description | Use Case |
153
+ | :-------------- | :-------------------------------------------------- | :----------------------------- |
154
+ | `table` | Human-readable table in terminal | Quick visual inspection |
155
+ | `json` | Structured JSON with resource summaries | Integration with other tools |
156
+ | `detailed-json` | Complete JSON with full Azure resource metadata | AI analysis or deep inspection |
157
+ | `lint` | Linter-style output grouped by resource, with icons | CI pipelines and quick triage |
153
158
 
154
159
  #### How to Load Configuration
155
160
 
156
161
  The `loadConfig()` function loads configuration in the following priority order:
157
162
 
158
163
  1. **Configuration file** (pass file path as parameter)
159
- 2. **Environment variables** (`ARM_TENANT_ID`, `ARM_SUBSCRIPTION_ID`)
164
+ 2. **Environment variable** (`ARM_SUBSCRIPTION_ID`)
160
165
  3. **Interactive prompt** (if no other configuration is found)
161
166
 
162
167
  **Example:**
163
168
 
164
169
  ```typescript
165
170
  // From file
166
- const config1 = await loadConfig("./config.json");
171
+ const config1 = await loadConfig("./config.yaml");
167
172
 
168
- // From environment variables or prompt
173
+ // From environment variable or prompt
169
174
  const config2 = await loadConfig();
170
175
  ```
171
176
 
172
177
  #### Configuration File Example
173
178
 
174
- ```json
175
- {
176
- "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
177
- "subscriptionIds": ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],
178
- "preferredLocation": "italynorth",
179
- "timespanDays": 30,
180
- "verbose": false
181
- }
179
+ ```yaml
180
+ azure:
181
+ subscriptionIds:
182
+ - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
183
+ preferredLocation: italynorth
184
+ timespanDays: 30
185
+ verbose: false
186
+ thresholds: # optional — omit to use built-in defaults
187
+ vm:
188
+ cpuPercent: 5
189
+ storage:
190
+ transactionsPerDay: 50
182
191
  ```
183
192
 
193
+ #### Thresholds Configuration
194
+
195
+ All numeric thresholds used during analysis can be overridden by adding a
196
+ `thresholds` section inside the `azure` block of your config YAML.
197
+ Only the fields you want to change are required — all others keep their
198
+ built-in defaults.
199
+
200
+ **Example (full override, `config.yaml`):**
201
+
202
+ ```yaml
203
+ azure:
204
+ subscriptionIds:
205
+ - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
206
+ thresholds:
207
+ vm:
208
+ cpuPercent: 5
209
+ networkInBytesPerDay: 10485760
210
+ appService:
211
+ cpuPercent: 10
212
+ memoryPercent: 20
213
+ premiumCpuPercent: 15
214
+ containerApp:
215
+ cpuNanoCores: 5000000
216
+ memoryBytes: 52428800
217
+ networkBytes: 100000
218
+ storage:
219
+ transactionsPerDay: 50
220
+ publicIp:
221
+ bytesInDDoS: 1048576
222
+ staticSite:
223
+ siteHits: 500
224
+ bytesSent: 5242880
225
+ ```
226
+
227
+ **Default threshold values:**
228
+
229
+ | Resource | Field | Default Value | Description |
230
+ | :------------- | :--------------------- | :---------------------- | :-------------------------------------------- |
231
+ | `vm` | `cpuPercent` | `1` (%) | Average CPU below which VM is flagged |
232
+ | `vm` | `networkInBytesPerDay` | `3145728` (3 MB) | Average inbound traffic below which flagged |
233
+ | `appService` | `cpuPercent` | `5` (%) | Average CPU below which plan is flagged |
234
+ | `appService` | `memoryPercent` | `10` (%) | Average memory below which plan is flagged |
235
+ | `appService` | `premiumCpuPercent` | `10` (%) | CPU threshold for Premium-tier over-provision |
236
+ | `containerApp` | `cpuNanoCores` | `1000000` (0.001 cores) | Average CPU below which app is flagged |
237
+ | `containerApp` | `memoryBytes` | `10485760` (10 MB) | Average memory below which app is flagged |
238
+ | `containerApp` | `networkBytes` | `34000` (~33 KB) | Combined Rx+Tx below which app is flagged |
239
+ | `storage` | `transactionsPerDay` | `10` | Avg daily transactions below which flagged |
240
+ | `publicIp` | `bytesInDDoS` | `340000` (~332 KB) | Avg inbound bytes/day below which flagged |
241
+ | `staticSite` | `siteHits` | `100` | Total requests below which site is flagged |
242
+ | `staticSite` | `bytesSent` | `1048576` (1 MB) | Total bytes sent below which site is flagged |
243
+
184
244
  #### Usage Examples
185
245
 
246
+ ##### Tag Filtering
247
+
248
+ ```typescript
249
+ import { azure, loadConfig } from "@pagopa/dx-savemoney";
250
+
251
+ const config = await loadConfig("./config.yaml");
252
+ // Analyze only resources tagged with environment=prod AND team=platform
253
+ await azure.analyzeAzureResources(
254
+ {
255
+ ...config,
256
+ filterTags: new Map([
257
+ ["environment", "prod"],
258
+ ["team", "platform"],
259
+ ]),
260
+ },
261
+ "lint",
262
+ );
263
+ ```
264
+
186
265
  ##### Basic Usage
187
266
 
188
267
  ```typescript
189
268
  import { azure, loadConfig } from "@pagopa/dx-savemoney";
190
269
 
191
270
  // Load from config file
192
- const config = await loadConfig("./config.json");
271
+ const config = await loadConfig("./config.yaml");
193
272
  await azure.analyzeAzureResources(config, "table");
194
273
  ```
195
274
 
@@ -200,7 +279,6 @@ import { azure } from "@pagopa/dx-savemoney";
200
279
  import type { AzureConfig } from "@pagopa/dx-savemoney";
201
280
 
202
281
  const config: AzureConfig = {
203
- tenantId: "your-tenant-id",
204
282
  subscriptionIds: ["sub-id-1", "sub-id-2"],
205
283
  preferredLocation: "italynorth",
206
284
  timespanDays: 30,
@@ -226,7 +304,6 @@ await azure.analyzeAzureResources(config, "detailed-json");
226
304
  import { loadConfig, azure } from "@pagopa/dx-savemoney";
227
305
 
228
306
  // Set environment variables
229
- // ARM_TENANT_ID=xxx
230
307
  // ARM_SUBSCRIPTION_ID=sub1,sub2
231
308
 
232
309
  const config = await loadConfig(); // Will read from env vars
@@ -8,14 +8,14 @@ import { MonitorClient } from "@azure/arm-monitor";
8
8
  import { NetworkManagementClient } from "@azure/arm-network";
9
9
  import * as armResources from "@azure/arm-resources";
10
10
  import type { AzureConfig } from "./types.js";
11
- import { type AnalysisResult } from "../types.js";
11
+ import { type AnalysisResult, type Thresholds } from "../types.js";
12
12
  /**
13
13
  * Analyzes resources in multiple Azure subscriptions and generates a report.
14
14
  *
15
15
  * @param config - Azure configuration with subscription IDs and settings
16
- * @param format - Output format (table, json, or detailed-json)
16
+ * @param format - Output format (table, json, detailed-json, or lint)
17
17
  */
18
- export declare function analyzeAzureResources(config: AzureConfig, format: "detailed-json" | "json" | "table"): Promise<void>;
18
+ export declare function analyzeAzureResources(config: AzureConfig, format: "detailed-json" | "json" | "lint" | "table"): Promise<void>;
19
19
  /**
20
20
  * Analyzes a single Azure resource based on its type.
21
21
  *
@@ -30,5 +30,5 @@ export declare function analyzeAzureResources(config: AzureConfig, format: "deta
30
30
  * @param verbose - Whether verbose logging is enabled
31
31
  * @returns Analysis result with cost risk and reason
32
32
  */
33
- export declare function analyzeResource(resource: armResources.GenericResource, monitorClient: MonitorClient, computeClient: ComputeManagementClient, networkClient: NetworkManagementClient, webSiteClient: WebSiteManagementClient, containerAppsClient: ContainerAppsAPIClient, preferredLocation: string, timespanDays: number, verbose?: boolean): Promise<AnalysisResult>;
33
+ export declare function analyzeResource(resource: armResources.GenericResource, monitorClient: MonitorClient, computeClient: ComputeManagementClient, networkClient: NetworkManagementClient, webSiteClient: WebSiteManagementClient, containerAppsClient: ContainerAppsAPIClient, preferredLocation: string, timespanDays: number, thresholds: Thresholds, verbose?: boolean): Promise<AnalysisResult>;
34
34
  //# sourceMappingURL=analyzer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/azure/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAIrD,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,aAAa,CAAC;AAchE;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,OAAO,iBAmE3C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,CAAC,eAAe,EACtC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,uBAAuB,EACtC,mBAAmB,EAAE,sBAAsB,EAC3C,iBAAiB,EAAE,MAAM,EACzB,YAAY,EAAE,MAAM,EACpB,OAAO,UAAQ,GACd,OAAO,CAAC,cAAc,CAAC,CAiHzB"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/azure/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAIrD,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,YAAY,CAAC;AAE3E,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAerB;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,iBA2EpD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,CAAC,eAAe,EACtC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,uBAAuB,EACtC,mBAAmB,EAAE,sBAAsB,EAC3C,iBAAiB,EAAE,MAAM,EACzB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,UAAU,EACtB,OAAO,UAAQ,GACd,OAAO,CAAC,cAAc,CAAC,CAuHzB"}
@@ -9,14 +9,15 @@ import { NetworkManagementClient } from "@azure/arm-network";
9
9
  import * as armResources from "@azure/arm-resources";
10
10
  import { DefaultAzureCredential } from "@azure/identity";
11
11
  import { getLogger } from "@logtape/logtape";
12
- import { mergeResults } from "../types.js";
12
+ import { DEFAULT_THRESHOLDS, mergeResults, } from "../types.js";
13
13
  import { generateReport } from "./report.js";
14
14
  import { analyzeAppServicePlan, analyzeContainerApp, analyzeDisk, analyzeNic, analyzePrivateEndpoint, analyzePublicIp, analyzeStaticSite, analyzeStorageAccount, analyzeVM, } from "./resources/index.js";
15
+ import { matchesTags } from "./utils.js";
15
16
  /**
16
17
  * Analyzes resources in multiple Azure subscriptions and generates a report.
17
18
  *
18
19
  * @param config - Azure configuration with subscription IDs and settings
19
- * @param format - Output format (table, json, or detailed-json)
20
+ * @param format - Output format (table, json, detailed-json, or lint)
20
21
  */
21
22
  export async function analyzeAzureResources(config, format) {
22
23
  const logger = getLogger(["savemoney", "azure"]);
@@ -30,9 +31,14 @@ export async function analyzeAzureResources(config, format) {
30
31
  const networkClient = new NetworkManagementClient(credential, subscriptionId.trim());
31
32
  const webSiteClient = new WebSiteManagementClient(credential, subscriptionId.trim());
32
33
  const containerAppsClient = new ContainerAppsAPIClient(credential, subscriptionId.trim());
34
+ const thresholds = config.thresholds ?? DEFAULT_THRESHOLDS;
33
35
  // Use the async iterator to avoid memory explosion for large environments
34
36
  for await (const resource of resourceClient.resources.list()) {
35
- const { costRisk, reason, suspectedUnused } = await analyzeResource(resource, monitorClient, computeClient, networkClient, webSiteClient, containerAppsClient, config.preferredLocation, config.timespanDays, config.verbose || false);
37
+ // Skip resources that don't match the requested tag filter
38
+ if (!matchesTags(resource, config.filterTags)) {
39
+ continue;
40
+ }
41
+ const { costRisk, reason, suspectedUnused } = await analyzeResource(resource, monitorClient, computeClient, networkClient, webSiteClient, containerAppsClient, config.preferredLocation, config.timespanDays, thresholds, config.verbose || false);
36
42
  if (suspectedUnused) {
37
43
  allReports.push({
38
44
  analysis: {
@@ -68,7 +74,7 @@ export async function analyzeAzureResources(config, format) {
68
74
  * @param verbose - Whether verbose logging is enabled
69
75
  * @returns Analysis result with cost risk and reason
70
76
  */
71
- export async function analyzeResource(resource, monitorClient, computeClient, networkClient, webSiteClient, containerAppsClient, preferredLocation, timespanDays, verbose = false) {
77
+ export async function analyzeResource(resource, monitorClient, computeClient, networkClient, webSiteClient, containerAppsClient, preferredLocation, timespanDays, thresholds, verbose = false) {
72
78
  const type = resource.type?.toLowerCase() || "";
73
79
  let result = {
74
80
  costRisk: "low",
@@ -83,7 +89,7 @@ export async function analyzeResource(resource, monitorClient, computeClient, ne
83
89
  // Route to type-specific analysis hooks
84
90
  switch (type) {
85
91
  case "microsoft.app/containerapps": {
86
- const containerAppResult = await analyzeContainerApp(resource, containerAppsClient, monitorClient, timespanDays, verbose);
92
+ const containerAppResult = await analyzeContainerApp(resource, containerAppsClient, monitorClient, timespanDays, thresholds, verbose);
87
93
  result = mergeResults(result, containerAppResult);
88
94
  break;
89
95
  }
@@ -93,7 +99,7 @@ export async function analyzeResource(resource, monitorClient, computeClient, ne
93
99
  break;
94
100
  }
95
101
  case "microsoft.compute/virtualmachines": {
96
- const vmResult = await analyzeVM(resource, monitorClient, computeClient, timespanDays, verbose);
102
+ const vmResult = await analyzeVM(resource, monitorClient, computeClient, timespanDays, thresholds, verbose);
97
103
  result = mergeResults(result, vmResult);
98
104
  break;
99
105
  }
@@ -108,22 +114,22 @@ export async function analyzeResource(resource, monitorClient, computeClient, ne
108
114
  break;
109
115
  }
110
116
  case "microsoft.network/publicipaddresses": {
111
- const pipResult = await analyzePublicIp(resource, networkClient, monitorClient, timespanDays, verbose);
117
+ const pipResult = await analyzePublicIp(resource, networkClient, monitorClient, timespanDays, thresholds, verbose);
112
118
  result = mergeResults(result, pipResult);
113
119
  break;
114
120
  }
115
121
  case "microsoft.storage/storageaccounts": {
116
- const storageResult = await analyzeStorageAccount(resource, monitorClient, timespanDays, verbose);
122
+ const storageResult = await analyzeStorageAccount(resource, monitorClient, timespanDays, thresholds, verbose);
117
123
  result = mergeResults(result, storageResult);
118
124
  break;
119
125
  }
120
126
  case "microsoft.web/serverfarms": {
121
- const aspResult = await analyzeAppServicePlan(resource, webSiteClient, monitorClient, timespanDays, verbose);
127
+ const aspResult = await analyzeAppServicePlan(resource, webSiteClient, monitorClient, timespanDays, thresholds, verbose);
122
128
  result = mergeResults(result, aspResult);
123
129
  break;
124
130
  }
125
131
  case "microsoft.web/staticsites": {
126
- const staticSiteResult = await analyzeStaticSite(resource, monitorClient, timespanDays, verbose);
132
+ const staticSiteResult = await analyzeStaticSite(resource, monitorClient, timespanDays, thresholds, verbose);
127
133
  result = mergeResults(result, staticSiteResult);
128
134
  break;
129
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/azure/analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/azure/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAEL,kBAAkB,EAClB,YAAY,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAmB,EACnB,MAAmD;IAEnD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,sBAAsB,EAAE,CAAC;IAChD,MAAM,UAAU,GAAkC,EAAE,CAAC;IAErD,KAAK,MAAM,cAAc,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,2BAA2B,cAAc,EAAE,CAAC,CAAC;QAEzD,MAAM,cAAc,GAAG,IAAI,YAAY,CAAC,wBAAwB,CAC9D,UAAU,EACV,cAAc,CAAC,IAAI,EAAE,CACtB,CAAC;QACF,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,UAAU,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,aAAa,GAAG,IAAI,uBAAuB,CAC/C,UAAU,EACV,cAAc,CAAC,IAAI,EAAE,CACtB,CAAC;QACF,MAAM,aAAa,GAAG,IAAI,uBAAuB,CAC/C,UAAU,EACV,cAAc,CAAC,IAAI,EAAE,CACtB,CAAC;QACF,MAAM,aAAa,GAAG,IAAI,uBAAuB,CAC/C,UAAU,EACV,cAAc,CAAC,IAAI,EAAE,CACtB,CAAC;QACF,MAAM,mBAAmB,GAAG,IAAI,sBAAsB,CACpD,UAAU,EACV,cAAc,CAAC,IAAI,EAAE,CACtB,CAAC;QAEF,MAAM,UAAU,GAAe,MAAM,CAAC,UAAU,IAAI,kBAAkB,CAAC;QAEvE,0EAA0E;QAC1E,IAAI,KAAK,EAAE,MAAM,QAAQ,IAAI,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YAC7D,2DAA2D;YAC3D,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9C,SAAS;YACX,CAAC;YAED,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,eAAe,CACjE,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,YAAY,EACnB,UAAU,EACV,MAAM,CAAC,OAAO,IAAI,KAAK,CACxB,CAAC;YAEF,IAAI,eAAe,EAAE,CAAC;gBACpB,UAAU,CAAC,IAAI,CAAC;oBACd,QAAQ,EAAE;wBACR,QAAQ;wBACR,MAAM,EAAE,MAAM,IAAI,uBAAuB;wBACzC,eAAe;qBAChB;oBACD,QAAQ,EAAE,QAAQ;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ;YAC7C,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QAC7C,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAsC,EACtC,aAA4B,EAC5B,aAAsC,EACtC,aAAsC,EACtC,aAAsC,EACtC,mBAA2C,EAC3C,iBAAyB,EACzB,YAAoB,EACpB,UAAsB,EACtB,OAAO,GAAG,KAAK;IAEf,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAChD,IAAI,MAAM,GAAG;QACX,QAAQ,EAAE,KAAkC;QAC5C,MAAM,EAAE,EAAE;QACV,eAAe,EAAE,KAAK;KACvB,CAAC;IAEF,uEAAuE;IACvE,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,MAAM,CAAC,MAAM,IAAI,iBAAiB,CAAC;IACrC,CAAC;IAED,wCAAwC;IACxC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,6BAA6B,CAAC,CAAC,CAAC;YACnC,MAAM,kBAAkB,GAAG,MAAM,mBAAmB,CAClD,QAAQ,EACR,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAClD,MAAM;QACR,CAAC;QACD,KAAK,yBAAyB,CAAC,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;YACvE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC1C,MAAM;QACR,CAAC;QACD,KAAK,mCAAmC,CAAC,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACxC,MAAM;QACR,CAAC;QACD,KAAK,qCAAqC,CAAC,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;YACrE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACzC,MAAM;QACR,CAAC;QACD,KAAK,oCAAoC,CAAC,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAC3C,QAAQ,EACR,aAAa,EACb,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACxC,MAAM;QACR,CAAC;QACD,KAAK,qCAAqC,CAAC,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,MAAM,eAAe,CACrC,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACzC,MAAM;QACR,CAAC;QACD,KAAK,mCAAmC,CAAC,CAAC,CAAC;YACzC,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAC/C,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YAC7C,MAAM;QACR,CAAC;QACD,KAAK,2BAA2B,CAAC,CAAC,CAAC;YACjC,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAC3C,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACzC,MAAM;QACR,CAAC;QACD,KAAK,2BAA2B,CAAC,CAAC,CAAC;YACjC,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAC9C,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,CACR,CAAC;YACF,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;YAChD,MAAM;QACR,CAAC;QACD;YACE,MAAM,CAAC,MAAM,IAAI,+CAA+C,CAAC;YACjE,MAAM;IACV,CAAC;IAED,6BAA6B;IAC7B,IACE,QAAQ,CAAC,QAAQ;QACjB,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,WAAW,EAAE,CAAC,EAC1E,CAAC;QACD,MAAM,CAAC,MAAM,IAAI,uCAAuC,iBAAiB,KAAK,CAAC;IACjF,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;AACrD,CAAC"}
@@ -3,10 +3,22 @@
3
3
  */
4
4
  import type { AzureConfig } from "./types.js";
5
5
  /**
6
- * Loads Azure configuration from file, environment variables, or interactive prompts.
6
+ * Loads Azure configuration from a YAML file, environment variables, or interactive prompts.
7
7
  *
8
- * @param configPath - Optional path to JSON configuration file
9
- * @returns Azure configuration object with subscription IDs and settings
8
+ * The YAML file must have an `azure` top-level key:
9
+ * ```yaml
10
+ * azure:
11
+ * subscriptionIds:
12
+ * - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
13
+ * preferredLocation: italynorth
14
+ * timespanDays: 30
15
+ * thresholds:
16
+ * vm:
17
+ * cpuPercent: 5
18
+ * ```
19
+ *
20
+ * @param configPath - Optional path to a YAML configuration file
21
+ * @returns Azure configuration object with subscription IDs, settings and thresholds
10
22
  */
11
23
  export declare function loadAzureConfig(configPath?: string): Promise<AzureConfig>;
12
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/azure/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CA2CtB;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,CA0CtB;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW9D"}
@@ -3,43 +3,61 @@
3
3
  */
4
4
  import { getLogger } from "@logtape/logtape";
5
5
  import * as fs from "fs";
6
+ import * as yaml from "js-yaml";
6
7
  import * as readline from "readline";
8
+ import { z } from "zod";
9
+ import { ConfigSchema } from "../schema.js";
7
10
  /**
8
- * Loads Azure configuration from file, environment variables, or interactive prompts.
11
+ * Loads Azure configuration from a YAML file, environment variables, or interactive prompts.
9
12
  *
10
- * @param configPath - Optional path to JSON configuration file
11
- * @returns Azure configuration object with subscription IDs and settings
13
+ * The YAML file must have an `azure` top-level key:
14
+ * ```yaml
15
+ * azure:
16
+ * subscriptionIds:
17
+ * - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
18
+ * preferredLocation: italynorth
19
+ * timespanDays: 30
20
+ * thresholds:
21
+ * vm:
22
+ * cpuPercent: 5
23
+ * ```
24
+ *
25
+ * @param configPath - Optional path to a YAML configuration file
26
+ * @returns Azure configuration object with subscription IDs, settings and thresholds
12
27
  */
13
28
  export async function loadAzureConfig(configPath) {
14
- if (configPath && fs.existsSync(configPath)) {
29
+ if (configPath) {
30
+ if (!fs.existsSync(configPath)) {
31
+ throw new Error(`Config file not found: ${configPath}`);
32
+ }
15
33
  try {
16
- const configContent = fs.readFileSync(configPath, "utf-8");
17
- const config = JSON.parse(configContent);
18
- if (!config.tenantId || !config.subscriptionIds) {
19
- throw new Error("Config file must contain 'tenantId' and 'subscriptionIds'");
20
- }
34
+ const raw = fs.readFileSync(configPath, "utf-8");
35
+ const rawYaml = yaml.load(raw);
36
+ const parsed = ConfigSchema.parse(rawYaml);
21
37
  return {
22
- ...config,
23
- preferredLocation: config.preferredLocation || "italynorth",
24
- subscriptionIds: config.subscriptionIds,
25
- tenantId: config.tenantId,
26
- timespanDays: config.timespanDays || 30,
38
+ preferredLocation: parsed.azure.preferredLocation,
39
+ subscriptionIds: parsed.azure.subscriptionIds,
40
+ thresholds: parsed.azure.thresholds,
41
+ timespanDays: parsed.azure.timespanDays,
27
42
  };
28
43
  }
29
44
  catch (error) {
30
- throw new Error(`Failed to load config file: ${error instanceof Error ? error.message : error}`);
45
+ if (error instanceof z.ZodError) {
46
+ throw new Error(`Invalid config file:\n${z.prettifyError(error)}`, {
47
+ cause: error,
48
+ });
49
+ }
50
+ throw new Error(`Failed to load config file: ${error instanceof Error ? error.message : error}`, { cause: error });
31
51
  }
32
52
  }
33
53
  const logger = getLogger(["savemoney", "azure", "config"]);
34
54
  logger.info("Configuration file not found. Checking environment variables...");
35
- const tenantId = process.env.ARM_TENANT_ID || (await prompt("Enter Tenant ID: "));
36
55
  const subscriptionIds = process.env.ARM_SUBSCRIPTION_ID
37
56
  ? process.env.ARM_SUBSCRIPTION_ID.split(",")
38
57
  : (await prompt("Enter Subscription IDs (comma-separated): ")).split(",");
39
58
  return {
40
59
  preferredLocation: "italynorth",
41
60
  subscriptionIds,
42
- tenantId,
43
61
  timespanDays: 30,
44
62
  };
45
63
  }
@@ -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,QAAQ,MAAM,UAAU,CAAC;AAIrC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAmB;IAEnB,IAAI,UAAU,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAyB,CAAC;YAEjE,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;gBAChD,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,GAAG,MAAM;gBACT,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,YAAY;gBAC3D,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;aACxC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAChF,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,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACnE,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,QAAQ;QACR,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":"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"}
@@ -6,7 +6,7 @@ import type { AzureDetailedResourceReport } from "./types.js";
6
6
  * Generates a report from Azure resource analysis in the specified format.
7
7
  *
8
8
  * @param report - Array of detailed resource reports
9
- * @param format - Output format (table, json, or detailed-json)
9
+ * @param format - Output format (table, json, detailed-json, or lint)
10
10
  */
11
- export declare function generateReport(report: AzureDetailedResourceReport[], format: "detailed-json" | "json" | "table"): Promise<void>;
11
+ export declare function generateReport(report: AzureDetailedResourceReport[], format: "detailed-json" | "json" | "lint" | "table"): Promise<void>;
12
12
  //# sourceMappingURL=report.d.ts.map
@@ -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;AAEpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,2BAA2B,EAAE,EACrC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,OAAO,iBAkC3C"}
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,11 +1,29 @@
1
1
  /**
2
2
  * Azure report generation
3
3
  */
4
+ // ANSI color codes — only applied when stdout is a TTY to avoid cluttering redirected output
5
+ const isTTY = process.stdout.isTTY ?? false;
6
+ const RED = isTTY ? "\x1b[31m" : "";
7
+ const YELLOW = isTTY ? "\x1b[33m" : "";
8
+ const BLUE = isTTY ? "\x1b[34m" : "";
9
+ const BOLD = isTTY ? "\x1b[1m" : "";
10
+ const RESET = isTTY ? "\x1b[0m" : "";
11
+ const DIM = isTTY ? "\x1b[2m" : "";
12
+ const RISK_ICON = {
13
+ high: `${RED}✖${RESET}`,
14
+ low: `${BLUE}ℹ${RESET}`,
15
+ medium: `${YELLOW}⚠${RESET}`,
16
+ };
17
+ const RISK_COLOR = {
18
+ high: RED,
19
+ low: BLUE,
20
+ medium: YELLOW,
21
+ };
4
22
  /**
5
23
  * Generates a report from Azure resource analysis in the specified format.
6
24
  *
7
25
  * @param report - Array of detailed resource reports
8
- * @param format - Output format (table, json, or detailed-json)
26
+ * @param format - Output format (table, json, detailed-json, or lint)
9
27
  */
10
28
  export async function generateReport(report, format) {
11
29
  if (format === "detailed-json") {
@@ -26,6 +44,9 @@ export async function generateReport(report, format) {
26
44
  if (format === "json") {
27
45
  console.log(JSON.stringify(summaryReport, null, 2));
28
46
  }
47
+ else if (format === "lint") {
48
+ generateLintReport(report);
49
+ }
29
50
  else {
30
51
  console.table(summaryReport.map((r) => ({
31
52
  Name: r.name,
@@ -33,8 +54,52 @@ export async function generateReport(report, format) {
33
54
  "Resource Group": r.resourceGroup || "N/A",
34
55
  Risk: r.costRisk,
35
56
  Type: r.type,
36
- Unused: r.suspectedUnused ? "Yes" : "No",
37
- })), ["Name", "Type", "Resource Group", "Risk", "Unused", "Reason"]);
57
+ })), ["Name", "Type", "Resource Group", "Risk", "Reason"]);
38
58
  }
39
59
  }
60
+ /**
61
+ * Renders a linter-style report to stdout, grouping findings by resource.
62
+ *
63
+ * Example output:
64
+ *
65
+ * /subscriptions/.../virtualMachines/my-vm
66
+ * ✖ HIGH VM is deallocated.
67
+ * ✖ HIGH No tags found.
68
+ *
69
+ * Summary: 3 issues found (2 high, 0 medium, 1 low)
70
+ */
71
+ function generateLintReport(report) {
72
+ const counts = { high: 0, low: 0, medium: 0 };
73
+ for (const entry of report) {
74
+ const resourceId = entry.resource.id ?? `unknown/${entry.resource.name ?? "unknown"}`;
75
+ const risk = entry.analysis.costRisk;
76
+ const findings = splitReasons(entry.analysis.reason);
77
+ console.log(`${BOLD}${resourceId}${RESET}`);
78
+ for (const finding of findings) {
79
+ const icon = RISK_ICON[risk];
80
+ const color = RISK_COLOR[risk];
81
+ const label = `${color}${risk.toUpperCase().padEnd(6)}${RESET}`;
82
+ console.log(` ${icon} ${label} ${DIM}${finding}${RESET}`);
83
+ counts[risk]++;
84
+ }
85
+ console.log();
86
+ }
87
+ const total = counts.high + counts.medium + counts.low;
88
+ const summaryLine = `${BOLD}Summary:${RESET} ${total} issue${total !== 1 ? "s" : ""} found` +
89
+ ` ${RED}(${counts.high} high${RESET}` +
90
+ `, ${YELLOW}${counts.medium} medium${RESET}` +
91
+ `, ${BLUE}${counts.low} low${RESET})`;
92
+ console.log(summaryLine);
93
+ }
94
+ /**
95
+ * Splits a concatenated reason string (sentences separated by ". ") into
96
+ * individual finding strings, stripping trailing whitespace.
97
+ */
98
+ function splitReasons(reason) {
99
+ return reason
100
+ .split(/\.\s+/)
101
+ .map((s) => s.trim())
102
+ .filter((s) => s.length > 0)
103
+ .map((s) => (s.endsWith(".") ? s : `${s}.`));
104
+ }
40
105
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqC,EACrC,MAA0C;IAE1C,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,kDAAkD;IAClD,MAAM,aAAa,GAA0B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9D,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ;QAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE;QACnC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;QAClC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM;QACzB,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3C,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS;QACzD,eAAe,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe;QAC3C,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS;KACnC,CAAC,CAAC,CAAC;IAEJ,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CACX,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,gBAAgB,EAAE,CAAC,CAAC,aAAa,IAAI,KAAK;YAC1C,IAAI,EAAE,CAAC,CAAC,QAAQ;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SACzC,CAAC,CAAC,EACH,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAC/D,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/azure/report.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  import type { WebSiteManagementClient } from "@azure/arm-appservice";
5
5
  import type { MonitorClient } from "@azure/arm-monitor";
6
6
  import * as armResources from "@azure/arm-resources";
7
- import type { AnalysisResult } from "../../types.js";
7
+ import type { AnalysisResult, Thresholds } from "../../types.js";
8
8
  /**
9
9
  * Analyzes an Azure App Service Plan for potential cost optimization.
10
10
  *
@@ -14,5 +14,5 @@ import type { AnalysisResult } from "../../types.js";
14
14
  * @param timespanDays - Number of days to analyze metrics
15
15
  * @returns Analysis result with cost risk and reason
16
16
  */
17
- export declare function analyzeAppServicePlan(resource: armResources.GenericResource, webSiteClient: WebSiteManagementClient, monitorClient: MonitorClient, timespanDays: number, verbose?: boolean): Promise<AnalysisResult>;
17
+ export declare function analyzeAppServicePlan(resource: armResources.GenericResource, webSiteClient: WebSiteManagementClient, monitorClient: MonitorClient, timespanDays: number, thresholds?: Thresholds, verbose?: boolean): Promise<AnalysisResult>;
18
18
  //# sourceMappingURL=app-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-service.d.ts","sourceRoot":"","sources":["../../../src/azure/resources/app-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AASrD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,YAAY,CAAC,eAAe,EACtC,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,MAAM,EACpB,OAAO,UAAQ,GACd,OAAO,CAAC,cAAc,CAAC,CAmFzB"}
1
+ {"version":3,"file":"app-service.d.ts","sourceRoot":"","sources":["../../../src/azure/resources/app-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAUjE;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,YAAY,CAAC,eAAe,EACtC,aAAa,EAAE,uBAAuB,EACtC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,MAAM,EACpB,UAAU,GAAE,UAA+B,EAC3C,OAAO,UAAQ,GACd,OAAO,CAAC,cAAc,CAAC,CAyFzB"}