cloudops-cli 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 (86) hide show
  1. package/README.md +132 -0
  2. package/dist/api/api-client.d.ts +78 -0
  3. package/dist/api/api-client.d.ts.map +1 -0
  4. package/dist/api/api-client.js +197 -0
  5. package/dist/api/api-client.js.map +1 -0
  6. package/dist/api/index.d.ts +3 -0
  7. package/dist/api/index.d.ts.map +1 -0
  8. package/dist/api/index.js +8 -0
  9. package/dist/api/index.js.map +1 -0
  10. package/dist/auth/__mocks__/auth-handler.d.ts +27 -0
  11. package/dist/auth/__mocks__/auth-handler.d.ts.map +1 -0
  12. package/dist/auth/__mocks__/auth-handler.js +24 -0
  13. package/dist/auth/__mocks__/auth-handler.js.map +1 -0
  14. package/dist/auth/auth-handler.d.ts +80 -0
  15. package/dist/auth/auth-handler.d.ts.map +1 -0
  16. package/dist/auth/auth-handler.js +266 -0
  17. package/dist/auth/auth-handler.js.map +1 -0
  18. package/dist/auth/callback-server.d.ts +31 -0
  19. package/dist/auth/callback-server.d.ts.map +1 -0
  20. package/dist/auth/callback-server.js +143 -0
  21. package/dist/auth/callback-server.js.map +1 -0
  22. package/dist/auth/index.d.ts +3 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +8 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +422 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/commands/accounts.d.ts +15 -0
  31. package/dist/commands/accounts.d.ts.map +1 -0
  32. package/dist/commands/accounts.js +307 -0
  33. package/dist/commands/accounts.js.map +1 -0
  34. package/dist/commands/audit.d.ts +23 -0
  35. package/dist/commands/audit.d.ts.map +1 -0
  36. package/dist/commands/audit.js +348 -0
  37. package/dist/commands/audit.js.map +1 -0
  38. package/dist/commands/config.d.ts +15 -0
  39. package/dist/commands/config.d.ts.map +1 -0
  40. package/dist/commands/config.js +148 -0
  41. package/dist/commands/config.js.map +1 -0
  42. package/dist/commands/incident.d.ts +59 -0
  43. package/dist/commands/incident.d.ts.map +1 -0
  44. package/dist/commands/incident.js +1032 -0
  45. package/dist/commands/incident.js.map +1 -0
  46. package/dist/commands/init.d.ts +9 -0
  47. package/dist/commands/init.d.ts.map +1 -0
  48. package/dist/commands/init.js +300 -0
  49. package/dist/commands/init.js.map +1 -0
  50. package/dist/commands/investigate.d.ts +15 -0
  51. package/dist/commands/investigate.d.ts.map +1 -0
  52. package/dist/commands/investigate.js +65 -0
  53. package/dist/commands/investigate.js.map +1 -0
  54. package/dist/commands/runbook.d.ts +20 -0
  55. package/dist/commands/runbook.d.ts.map +1 -0
  56. package/dist/commands/runbook.js +265 -0
  57. package/dist/commands/runbook.js.map +1 -0
  58. package/dist/config/__mocks__/config-handler.d.ts +11 -0
  59. package/dist/config/__mocks__/config-handler.d.ts.map +1 -0
  60. package/dist/config/__mocks__/config-handler.js +31 -0
  61. package/dist/config/__mocks__/config-handler.js.map +1 -0
  62. package/dist/config/certificate-pinning.d.ts +68 -0
  63. package/dist/config/certificate-pinning.d.ts.map +1 -0
  64. package/dist/config/certificate-pinning.js +249 -0
  65. package/dist/config/certificate-pinning.js.map +1 -0
  66. package/dist/config/config-handler.d.ts +45 -0
  67. package/dist/config/config-handler.d.ts.map +1 -0
  68. package/dist/config/config-handler.js +149 -0
  69. package/dist/config/config-handler.js.map +1 -0
  70. package/dist/config/index.d.ts +2 -0
  71. package/dist/config/index.d.ts.map +1 -0
  72. package/dist/config/index.js +7 -0
  73. package/dist/config/index.js.map +1 -0
  74. package/dist/index.d.ts +4 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +25 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/types/cli-options.d.ts +31 -0
  79. package/dist/types/cli-options.d.ts.map +1 -0
  80. package/dist/types/cli-options.js +3 -0
  81. package/dist/types/cli-options.js.map +1 -0
  82. package/dist/utils/output-formatter.d.ts +67 -0
  83. package/dist/utils/output-formatter.d.ts.map +1 -0
  84. package/dist/utils/output-formatter.js +147 -0
  85. package/dist/utils/output-formatter.js.map +1 -0
  86. package/package.json +65 -0
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runbookListCommand = runbookListCommand;
7
+ exports.runbookShowCommand = runbookShowCommand;
8
+ exports.runbookExecuteCommand = runbookExecuteCommand;
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const cli_table3_1 = __importDefault(require("cli-table3"));
11
+ const api_client_1 = require("../api/api-client");
12
+ /**
13
+ * List all available runbooks
14
+ */
15
+ async function runbookListCommand(_options) {
16
+ console.log(chalk_1.default.bold.blue(`\n📚 Fetching runbooks...\n`));
17
+ try {
18
+ const apiClient = (0, api_client_1.createAPIClient)();
19
+ const runbooks = await apiClient.get('/api/v1/runbooks');
20
+ if (runbooks.length === 0) {
21
+ console.log(chalk_1.default.yellow('No runbooks found'));
22
+ console.log(chalk_1.default.gray(' Contact your administrator to create runbooks.'));
23
+ console.log();
24
+ return;
25
+ }
26
+ console.log(chalk_1.default.green(`✓ Found ${runbooks.length} runbook(s)\n`));
27
+ // Display runbooks in a table
28
+ const table = new cli_table3_1.default({
29
+ head: [
30
+ chalk_1.default.bold('Name'),
31
+ chalk_1.default.bold('Description'),
32
+ chalk_1.default.bold('Steps'),
33
+ chalk_1.default.bold('Approval Required'),
34
+ chalk_1.default.bold('Created By'),
35
+ ],
36
+ colWidths: [25, 35, 8, 18, 20],
37
+ wordWrap: true,
38
+ });
39
+ runbooks.forEach((runbook) => {
40
+ table.push([
41
+ chalk_1.default.cyan(runbook.name),
42
+ runbook.description || chalk_1.default.gray('No description'),
43
+ runbook.steps.length.toString(),
44
+ runbook.approval_required ? chalk_1.default.yellow('YES') : chalk_1.default.green('NO'),
45
+ runbook.created_by,
46
+ ]);
47
+ });
48
+ console.log(table.toString());
49
+ console.log();
50
+ // Show next steps
51
+ console.log(chalk_1.default.bold('Next Steps:'));
52
+ console.log(chalk_1.default.gray(' • View runbook details: cloudops runbook show <name>'));
53
+ console.log(chalk_1.default.gray(' • Execute runbook: cloudops runbook execute <name> --params KEY=VALUE'));
54
+ console.log();
55
+ }
56
+ catch (error) {
57
+ handleAPIError(error, 'list runbooks');
58
+ }
59
+ }
60
+ /**
61
+ * Show details of a specific runbook
62
+ */
63
+ async function runbookShowCommand(name, _options) {
64
+ if (!name || name.trim().length === 0) {
65
+ console.error(chalk_1.default.red('Error: Runbook name is required'));
66
+ process.exit(1);
67
+ }
68
+ console.log(chalk_1.default.bold.blue(`\n📖 Fetching runbook details...\n`));
69
+ try {
70
+ const apiClient = (0, api_client_1.createAPIClient)();
71
+ const runbook = await apiClient.get(`/api/v1/runbooks/${encodeURIComponent(name)}`);
72
+ console.log(chalk_1.default.green('✓ Runbook found\n'));
73
+ // Display runbook metadata
74
+ const metadataTable = new cli_table3_1.default({
75
+ colWidths: [25, 55],
76
+ wordWrap: true,
77
+ });
78
+ metadataTable.push([chalk_1.default.bold('Runbook ID'), chalk_1.default.cyan(runbook.runbook_id)], [chalk_1.default.bold('Name'), runbook.name], [chalk_1.default.bold('Description'), runbook.description || chalk_1.default.gray('No description')], [chalk_1.default.bold('Total Steps'), runbook.steps.length.toString()], [chalk_1.default.bold('Approval Required'), runbook.approval_required ? chalk_1.default.yellow('YES') : chalk_1.default.green('NO')], [chalk_1.default.bold('Created By'), runbook.created_by], [chalk_1.default.bold('Created At'), new Date(runbook.created_at).toLocaleString()], [chalk_1.default.bold('Updated At'), new Date(runbook.updated_at).toLocaleString()]);
79
+ console.log(metadataTable.toString());
80
+ console.log();
81
+ // Display parameters if any
82
+ if (runbook.parameters && runbook.parameters.length > 0) {
83
+ console.log(chalk_1.default.bold('Parameters:\n'));
84
+ const paramTable = new cli_table3_1.default({
85
+ head: [
86
+ chalk_1.default.bold('Name'),
87
+ chalk_1.default.bold('Type'),
88
+ chalk_1.default.bold('Required'),
89
+ chalk_1.default.bold('Default'),
90
+ chalk_1.default.bold('Description'),
91
+ ],
92
+ colWidths: [15, 10, 10, 15, 30],
93
+ wordWrap: true,
94
+ });
95
+ runbook.parameters.forEach((param) => {
96
+ paramTable.push([
97
+ chalk_1.default.cyan(param.name),
98
+ param.type,
99
+ param.required ? chalk_1.default.yellow('YES') : chalk_1.default.gray('NO'),
100
+ param.default !== undefined ? String(param.default) : chalk_1.default.gray('None'),
101
+ param.description,
102
+ ]);
103
+ });
104
+ console.log(paramTable.toString());
105
+ console.log();
106
+ }
107
+ // Display steps
108
+ if (runbook.steps.length > 0) {
109
+ console.log(chalk_1.default.bold('Steps:\n'));
110
+ runbook.steps.forEach((step) => {
111
+ console.log(chalk_1.default.bold(`Step ${step.step_number}: `) + chalk_1.default.cyan(step.action));
112
+ console.log(chalk_1.default.gray(` ${step.description}`));
113
+ if (step.parameters && Object.keys(step.parameters).length > 0) {
114
+ console.log(chalk_1.default.gray(' Parameters:'));
115
+ Object.entries(step.parameters).forEach(([key, value]) => {
116
+ console.log(chalk_1.default.gray(` ${key}: ${value}`));
117
+ });
118
+ }
119
+ if (step.verification) {
120
+ console.log(chalk_1.default.gray(` Verification: ${step.verification}`));
121
+ }
122
+ if (step.step_number < runbook.steps.length) {
123
+ console.log();
124
+ }
125
+ });
126
+ console.log();
127
+ }
128
+ // Show execution command
129
+ console.log(chalk_1.default.bold('Execute:'));
130
+ if (runbook.parameters && runbook.parameters.length > 0) {
131
+ const requiredParams = runbook.parameters
132
+ .filter((p) => p.required)
133
+ .map((p) => `${p.name}=<value>`)
134
+ .join(' ');
135
+ console.log(chalk_1.default.gray(` cloudops runbook execute ${name} --params ${requiredParams}`));
136
+ }
137
+ else {
138
+ console.log(chalk_1.default.gray(` cloudops runbook execute ${name}`));
139
+ }
140
+ console.log();
141
+ }
142
+ catch (error) {
143
+ handleAPIError(error, 'fetch runbook details');
144
+ }
145
+ }
146
+ /**
147
+ * Execute a runbook
148
+ */
149
+ async function runbookExecuteCommand(name, options) {
150
+ if (!name || name.trim().length === 0) {
151
+ console.error(chalk_1.default.red('Error: Runbook name is required'));
152
+ process.exit(1);
153
+ }
154
+ console.log(chalk_1.default.bold.blue(`\n⚙️ Executing runbook...\n`));
155
+ try {
156
+ // Parse parameters from --params options
157
+ const parameters = {};
158
+ if (options.params && options.params.length > 0) {
159
+ options.params.forEach((param) => {
160
+ const [key, value] = param.split('=');
161
+ if (!key || value === undefined) {
162
+ console.error(chalk_1.default.red(`Error: Invalid parameter format: ${param}`));
163
+ console.error(chalk_1.default.gray(' Expected format: KEY=VALUE'));
164
+ process.exit(1);
165
+ }
166
+ // Try to parse as number or boolean
167
+ if (value === 'true') {
168
+ parameters[key] = true;
169
+ }
170
+ else if (value === 'false') {
171
+ parameters[key] = false;
172
+ }
173
+ else if (!isNaN(Number(value))) {
174
+ parameters[key] = Number(value);
175
+ }
176
+ else {
177
+ parameters[key] = value;
178
+ }
179
+ });
180
+ }
181
+ // Build request body
182
+ const requestBody = {
183
+ runbook_name: name,
184
+ parameters: Object.keys(parameters).length > 0 ? parameters : undefined,
185
+ };
186
+ // Call execute endpoint
187
+ const apiClient = (0, api_client_1.createAPIClient)();
188
+ const response = await apiClient.post(`/api/v1/runbooks/${encodeURIComponent(name)}/execute`, requestBody);
189
+ // Display execution result
190
+ console.log(chalk_1.default.green('✓ Runbook execution initiated\n'));
191
+ const resultTable = new cli_table3_1.default({
192
+ colWidths: [25, 55],
193
+ wordWrap: true,
194
+ });
195
+ resultTable.push([chalk_1.default.bold('Execution ID'), chalk_1.default.cyan(response.execution_id)], [chalk_1.default.bold('Status'), formatExecutionStatus(response.status)], [chalk_1.default.bold('Started At'), new Date(response.started_at).toLocaleString()]);
196
+ console.log(resultTable.toString());
197
+ console.log();
198
+ // Show next steps based on status
199
+ if (response.status === 'pending_approval') {
200
+ console.log(chalk_1.default.bold('Next Steps:'));
201
+ console.log(chalk_1.default.yellow(' ⏳ Waiting for approval from designated approvers'));
202
+ console.log(chalk_1.default.gray(' • The runbook requires approval before execution'));
203
+ console.log(chalk_1.default.gray(' • Approvers will be notified via configured channels'));
204
+ console.log();
205
+ }
206
+ else if (response.status === 'executing') {
207
+ console.log(chalk_1.default.bold('Next Steps:'));
208
+ console.log(chalk_1.default.blue(' 🔄 Runbook is executing...'));
209
+ console.log(chalk_1.default.gray(' • Monitor execution progress in your control plane'));
210
+ console.log();
211
+ }
212
+ else if (response.status === 'completed') {
213
+ console.log(chalk_1.default.green(' ✓ Runbook execution completed successfully'));
214
+ console.log();
215
+ }
216
+ else if (response.status === 'failed') {
217
+ console.log(chalk_1.default.red(' ✗ Runbook execution failed'));
218
+ console.log(chalk_1.default.gray(' • Check audit logs for details'));
219
+ console.log();
220
+ }
221
+ }
222
+ catch (error) {
223
+ handleAPIError(error, 'execute runbook');
224
+ }
225
+ }
226
+ /**
227
+ * Format execution status with color
228
+ */
229
+ function formatExecutionStatus(status) {
230
+ const statusColors = {
231
+ pending_approval: chalk_1.default.yellow,
232
+ executing: chalk_1.default.blue,
233
+ completed: chalk_1.default.green,
234
+ failed: chalk_1.default.red,
235
+ };
236
+ const colorFn = statusColors[status] || chalk_1.default.white;
237
+ return colorFn(status.replace(/_/g, ' ').toUpperCase());
238
+ }
239
+ /**
240
+ * Handle API errors consistently
241
+ */
242
+ function handleAPIError(error, action) {
243
+ if (error instanceof api_client_1.APIError) {
244
+ console.error(chalk_1.default.red(`\n✗ Failed to ${action}:`));
245
+ console.error(chalk_1.default.red(` ${error.message}`));
246
+ if (error.statusCode === 401) {
247
+ console.error(chalk_1.default.yellow('\nAuthentication required. Please run: cloudops init'));
248
+ }
249
+ else if (error.statusCode === 403) {
250
+ console.error(chalk_1.default.yellow('\nAccess denied. Check your permissions.'));
251
+ }
252
+ else if (error.statusCode === 404) {
253
+ console.error(chalk_1.default.yellow('\nRunbook not found. Check the runbook name.'));
254
+ }
255
+ else if (error.details) {
256
+ console.error(chalk_1.default.gray('\nDetails:'), error.details);
257
+ }
258
+ }
259
+ else {
260
+ console.error(chalk_1.default.red(`\n✗ Unexpected error:`));
261
+ console.error(chalk_1.default.red(` ${error instanceof Error ? error.message : 'Unknown error'}`));
262
+ }
263
+ process.exit(1);
264
+ }
265
+ //# sourceMappingURL=runbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runbook.js","sourceRoot":"","sources":["../../src/commands/runbook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { CLIConfig } from '@cloudops/shared';
2
+ export declare class ConfigHandler {
3
+ private configPath;
4
+ constructor(configPath?: string);
5
+ readConfig(): CLIConfig;
6
+ writeConfig(_config: CLIConfig): void;
7
+ configExists(): boolean;
8
+ getConfigPath(): string;
9
+ }
10
+ export declare function getDefaultConfigHandler(): ConfigHandler;
11
+ //# sourceMappingURL=config-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-handler.d.ts","sourceRoot":"","sources":["../../../src/config/__mocks__/config-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,CAAC,EAAE,MAAM;IAI/B,UAAU,IAAI,SAAS;IAUvB,WAAW,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAErC,YAAY,IAAI,OAAO;IAIvB,aAAa,IAAI,MAAM;CAGxB;AAED,wBAAgB,uBAAuB,IAAI,aAAa,CAEvD"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigHandler = void 0;
4
+ exports.getDefaultConfigHandler = getDefaultConfigHandler;
5
+ class ConfigHandler {
6
+ configPath;
7
+ constructor(configPath) {
8
+ this.configPath = configPath || '~/.cloudops/config.yaml';
9
+ }
10
+ readConfig() {
11
+ return {
12
+ tenant_id: 'mock-tenant',
13
+ control_plane_url: 'https://mock-api.com',
14
+ auth: {
15
+ method: 'sso',
16
+ },
17
+ };
18
+ }
19
+ writeConfig(_config) { }
20
+ configExists() {
21
+ return true;
22
+ }
23
+ getConfigPath() {
24
+ return this.configPath;
25
+ }
26
+ }
27
+ exports.ConfigHandler = ConfigHandler;
28
+ function getDefaultConfigHandler() {
29
+ return new ConfigHandler();
30
+ }
31
+ //# sourceMappingURL=config-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-handler.js","sourceRoot":"","sources":["../../../src/config/__mocks__/config-handler.ts"],"names":[],"mappings":";;;AA8BA,0DAEC;AA9BD,MAAa,aAAa;IAChB,UAAU,CAAS;IAE3B,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,yBAAyB,CAAC;IAC5D,CAAC;IAED,UAAU;QACR,OAAO;YACL,SAAS,EAAE,aAAa;YACxB,iBAAiB,EAAE,sBAAsB;YACzC,IAAI,EAAE;gBACJ,MAAM,EAAE,KAAK;aACd;SACF,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,OAAkB,IAAS,CAAC;IAExC,YAAY;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF;AA1BD,sCA0BC;AAED,SAAgB,uBAAuB;IACrC,OAAO,IAAI,aAAa,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Certificate Pinning Configuration for CloudOps CLI
3
+ *
4
+ * Implements certificate pinning to prevent man-in-the-middle attacks
5
+ * when communicating with the control plane API.
6
+ */
7
+ import https from 'https';
8
+ /**
9
+ * Certificate pin configuration
10
+ */
11
+ export interface CertificatePin {
12
+ hostname: string;
13
+ fingerprints: string[];
14
+ }
15
+ /**
16
+ * Load certificate pins from configuration file
17
+ *
18
+ * Pins are stored in ~/.cloudops/certificate-pins.json
19
+ */
20
+ export declare function loadCertificatePins(): CertificatePin[];
21
+ /**
22
+ * Save certificate pins to configuration file
23
+ */
24
+ export declare function saveCertificatePins(pins: CertificatePin[]): void;
25
+ /**
26
+ * Get certificate pins for a hostname
27
+ */
28
+ export declare function getPinsForHostname(hostname: string): string[];
29
+ /**
30
+ * Add certificate pin for a hostname
31
+ */
32
+ export declare function addCertificatePin(hostname: string, fingerprint: string): void;
33
+ /**
34
+ * Remove certificate pin for a hostname
35
+ */
36
+ export declare function removeCertificatePin(hostname: string, fingerprint?: string): void;
37
+ /**
38
+ * Create HTTPS agent with certificate pinning
39
+ *
40
+ * This agent validates the server certificate against pinned fingerprints.
41
+ */
42
+ export declare function createPinnedHttpsAgent(hostname: string): https.Agent;
43
+ /**
44
+ * Fetch and display server certificate fingerprint
45
+ *
46
+ * Useful for initial setup and certificate rotation.
47
+ */
48
+ export declare function fetchCertificateFingerprint(hostname: string, port?: number): Promise<string>;
49
+ /**
50
+ * Validate certificate pinning configuration
51
+ *
52
+ * Checks that pins are properly formatted and not expired.
53
+ */
54
+ export declare function validateCertificatePins(pins: CertificatePin[]): {
55
+ isValid: boolean;
56
+ errors: string[];
57
+ };
58
+ /**
59
+ * Check if certificate pinning is enabled for a hostname
60
+ */
61
+ export declare function isCertificatePinningEnabled(hostname: string): boolean;
62
+ /**
63
+ * Disable certificate pinning for a hostname
64
+ *
65
+ * This should only be used in development/testing environments.
66
+ */
67
+ export declare function disableCertificatePinning(hostname: string): void;
68
+ //# sourceMappingURL=certificate-pinning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate-pinning.d.ts","sourceRoot":"","sources":["../../src/config/certificate-pinning.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAoBD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,EAAE,CAetD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,IAAI,CAUhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAgB7E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAuBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CA8CpE;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CA6BA;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGrE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMhE"}
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ /**
3
+ * Certificate Pinning Configuration for CloudOps CLI
4
+ *
5
+ * Implements certificate pinning to prevent man-in-the-middle attacks
6
+ * when communicating with the control plane API.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.loadCertificatePins = loadCertificatePins;
13
+ exports.saveCertificatePins = saveCertificatePins;
14
+ exports.getPinsForHostname = getPinsForHostname;
15
+ exports.addCertificatePin = addCertificatePin;
16
+ exports.removeCertificatePin = removeCertificatePin;
17
+ exports.createPinnedHttpsAgent = createPinnedHttpsAgent;
18
+ exports.fetchCertificateFingerprint = fetchCertificateFingerprint;
19
+ exports.validateCertificatePins = validateCertificatePins;
20
+ exports.isCertificatePinningEnabled = isCertificatePinningEnabled;
21
+ exports.disableCertificatePinning = disableCertificatePinning;
22
+ const https_1 = __importDefault(require("https"));
23
+ const tls_1 = __importDefault(require("tls"));
24
+ const fs_1 = __importDefault(require("fs"));
25
+ const path_1 = __importDefault(require("path"));
26
+ const os_1 = __importDefault(require("os"));
27
+ /**
28
+ * Default certificate pins for CloudOps control plane
29
+ *
30
+ * In production, these should be updated with actual certificate fingerprints.
31
+ * Pins should be rotated before certificate expiration.
32
+ */
33
+ const DEFAULT_PINS = [
34
+ {
35
+ hostname: 'api.cloudops.example.com',
36
+ fingerprints: [
37
+ // Primary certificate fingerprint
38
+ // 'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99',
39
+ // Backup certificate fingerprint (for rotation)
40
+ // 'BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA',
41
+ ],
42
+ },
43
+ ];
44
+ /**
45
+ * Load certificate pins from configuration file
46
+ *
47
+ * Pins are stored in ~/.cloudops/certificate-pins.json
48
+ */
49
+ function loadCertificatePins() {
50
+ const configDir = path_1.default.join(os_1.default.homedir(), '.cloudops');
51
+ const pinsFile = path_1.default.join(configDir, 'certificate-pins.json');
52
+ try {
53
+ if (fs_1.default.existsSync(pinsFile)) {
54
+ const content = fs_1.default.readFileSync(pinsFile, 'utf-8');
55
+ const pins = JSON.parse(content);
56
+ return pins;
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn('Failed to load certificate pins, using defaults:', error);
61
+ }
62
+ return DEFAULT_PINS;
63
+ }
64
+ /**
65
+ * Save certificate pins to configuration file
66
+ */
67
+ function saveCertificatePins(pins) {
68
+ const configDir = path_1.default.join(os_1.default.homedir(), '.cloudops');
69
+ const pinsFile = path_1.default.join(configDir, 'certificate-pins.json');
70
+ // Ensure config directory exists
71
+ if (!fs_1.default.existsSync(configDir)) {
72
+ fs_1.default.mkdirSync(configDir, { recursive: true, mode: 0o700 });
73
+ }
74
+ fs_1.default.writeFileSync(pinsFile, JSON.stringify(pins, null, 2), { mode: 0o600 });
75
+ }
76
+ /**
77
+ * Get certificate pins for a hostname
78
+ */
79
+ function getPinsForHostname(hostname) {
80
+ const pins = loadCertificatePins();
81
+ const pin = pins.find(p => p.hostname === hostname);
82
+ return pin?.fingerprints || [];
83
+ }
84
+ /**
85
+ * Add certificate pin for a hostname
86
+ */
87
+ function addCertificatePin(hostname, fingerprint) {
88
+ const pins = loadCertificatePins();
89
+ const existingPin = pins.find(p => p.hostname === hostname);
90
+ if (existingPin) {
91
+ if (!existingPin.fingerprints.includes(fingerprint)) {
92
+ existingPin.fingerprints.push(fingerprint);
93
+ }
94
+ }
95
+ else {
96
+ pins.push({
97
+ hostname,
98
+ fingerprints: [fingerprint],
99
+ });
100
+ }
101
+ saveCertificatePins(pins);
102
+ }
103
+ /**
104
+ * Remove certificate pin for a hostname
105
+ */
106
+ function removeCertificatePin(hostname, fingerprint) {
107
+ const pins = loadCertificatePins();
108
+ if (fingerprint) {
109
+ // Remove specific fingerprint
110
+ const pin = pins.find(p => p.hostname === hostname);
111
+ if (pin) {
112
+ pin.fingerprints = pin.fingerprints.filter(fp => fp !== fingerprint);
113
+ if (pin.fingerprints.length === 0) {
114
+ // Remove entire pin if no fingerprints left
115
+ const index = pins.indexOf(pin);
116
+ pins.splice(index, 1);
117
+ }
118
+ }
119
+ }
120
+ else {
121
+ // Remove all pins for hostname
122
+ const index = pins.findIndex(p => p.hostname === hostname);
123
+ if (index !== -1) {
124
+ pins.splice(index, 1);
125
+ }
126
+ }
127
+ saveCertificatePins(pins);
128
+ }
129
+ /**
130
+ * Create HTTPS agent with certificate pinning
131
+ *
132
+ * This agent validates the server certificate against pinned fingerprints.
133
+ */
134
+ function createPinnedHttpsAgent(hostname) {
135
+ const pins = getPinsForHostname(hostname);
136
+ // If no pins configured, use standard secure agent
137
+ if (pins.length === 0) {
138
+ return new https_1.default.Agent({
139
+ minVersion: 'TLSv1.3',
140
+ maxVersion: 'TLSv1.3',
141
+ rejectUnauthorized: true,
142
+ });
143
+ }
144
+ // Create agent with certificate pinning
145
+ return new https_1.default.Agent({
146
+ minVersion: 'TLSv1.3',
147
+ maxVersion: 'TLSv1.3',
148
+ rejectUnauthorized: true,
149
+ checkServerIdentity: (host, cert) => {
150
+ // Verify hostname first
151
+ const hostnameError = tls_1.default.checkServerIdentity(host, cert);
152
+ if (hostnameError) {
153
+ return hostnameError;
154
+ }
155
+ // Verify certificate fingerprint
156
+ const fingerprint = cert.fingerprint256;
157
+ if (!fingerprint) {
158
+ return new Error('Certificate does not have SHA-256 fingerprint');
159
+ }
160
+ // Normalize fingerprint format
161
+ const normalizedFingerprint = fingerprint.replace(/:/g, '').toLowerCase();
162
+ const normalizedPins = pins.map(fp => fp.replace(/:/g, '').toLowerCase());
163
+ if (!normalizedPins.includes(normalizedFingerprint)) {
164
+ return new Error(`Certificate pinning failed: Server certificate fingerprint ${fingerprint} ` +
165
+ `does not match any pinned certificates for ${hostname}. ` +
166
+ `This could indicate a man-in-the-middle attack or certificate rotation. ` +
167
+ `Please verify the server certificate and update pins if needed.`);
168
+ }
169
+ return undefined; // Certificate is valid
170
+ },
171
+ });
172
+ }
173
+ /**
174
+ * Fetch and display server certificate fingerprint
175
+ *
176
+ * Useful for initial setup and certificate rotation.
177
+ */
178
+ async function fetchCertificateFingerprint(hostname, port = 443) {
179
+ return new Promise((resolve, reject) => {
180
+ const options = {
181
+ host: hostname,
182
+ port,
183
+ method: 'GET',
184
+ rejectUnauthorized: true,
185
+ };
186
+ const req = https_1.default.request(options, (res) => {
187
+ const cert = res.socket.getPeerCertificate();
188
+ if (cert && cert.fingerprint256) {
189
+ resolve(cert.fingerprint256);
190
+ }
191
+ else {
192
+ reject(new Error('Could not retrieve certificate fingerprint'));
193
+ }
194
+ res.resume(); // Consume response
195
+ });
196
+ req.on('error', reject);
197
+ req.end();
198
+ });
199
+ }
200
+ /**
201
+ * Validate certificate pinning configuration
202
+ *
203
+ * Checks that pins are properly formatted and not expired.
204
+ */
205
+ function validateCertificatePins(pins) {
206
+ const errors = [];
207
+ for (const pin of pins) {
208
+ // Validate hostname
209
+ if (!pin.hostname || typeof pin.hostname !== 'string') {
210
+ errors.push('Invalid hostname in certificate pin');
211
+ continue;
212
+ }
213
+ // Validate fingerprints
214
+ if (!Array.isArray(pin.fingerprints) || pin.fingerprints.length === 0) {
215
+ errors.push(`No fingerprints configured for ${pin.hostname}`);
216
+ continue;
217
+ }
218
+ // Validate fingerprint format (SHA-256 is 64 hex chars with optional colons)
219
+ for (const fp of pin.fingerprints) {
220
+ const normalized = fp.replace(/:/g, '');
221
+ if (!/^[a-fA-F0-9]{64}$/.test(normalized)) {
222
+ errors.push(`Invalid fingerprint format for ${pin.hostname}: ${fp}`);
223
+ }
224
+ }
225
+ }
226
+ return {
227
+ isValid: errors.length === 0,
228
+ errors,
229
+ };
230
+ }
231
+ /**
232
+ * Check if certificate pinning is enabled for a hostname
233
+ */
234
+ function isCertificatePinningEnabled(hostname) {
235
+ const pins = getPinsForHostname(hostname);
236
+ return pins.length > 0;
237
+ }
238
+ /**
239
+ * Disable certificate pinning for a hostname
240
+ *
241
+ * This should only be used in development/testing environments.
242
+ */
243
+ function disableCertificatePinning(hostname) {
244
+ if (process.env.NODE_ENV === 'production') {
245
+ throw new Error('Cannot disable certificate pinning in production');
246
+ }
247
+ removeCertificatePin(hostname);
248
+ }
249
+ //# sourceMappingURL=certificate-pinning.js.map