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.
- package/README.md +132 -0
- package/dist/api/api-client.d.ts +78 -0
- package/dist/api/api-client.d.ts.map +1 -0
- package/dist/api/api-client.js +197 -0
- package/dist/api/api-client.js.map +1 -0
- package/dist/api/index.d.ts +3 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/auth/__mocks__/auth-handler.d.ts +27 -0
- package/dist/auth/__mocks__/auth-handler.d.ts.map +1 -0
- package/dist/auth/__mocks__/auth-handler.js +24 -0
- package/dist/auth/__mocks__/auth-handler.js.map +1 -0
- package/dist/auth/auth-handler.d.ts +80 -0
- package/dist/auth/auth-handler.d.ts.map +1 -0
- package/dist/auth/auth-handler.js +266 -0
- package/dist/auth/auth-handler.js.map +1 -0
- package/dist/auth/callback-server.d.ts +31 -0
- package/dist/auth/callback-server.d.ts.map +1 -0
- package/dist/auth/callback-server.js +143 -0
- package/dist/auth/callback-server.js.map +1 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +422 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/accounts.d.ts +15 -0
- package/dist/commands/accounts.d.ts.map +1 -0
- package/dist/commands/accounts.js +307 -0
- package/dist/commands/accounts.js.map +1 -0
- package/dist/commands/audit.d.ts +23 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +348 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/config.d.ts +15 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +148 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/incident.d.ts +59 -0
- package/dist/commands/incident.d.ts.map +1 -0
- package/dist/commands/incident.js +1032 -0
- package/dist/commands/incident.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +300 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/investigate.d.ts +15 -0
- package/dist/commands/investigate.d.ts.map +1 -0
- package/dist/commands/investigate.js +65 -0
- package/dist/commands/investigate.js.map +1 -0
- package/dist/commands/runbook.d.ts +20 -0
- package/dist/commands/runbook.d.ts.map +1 -0
- package/dist/commands/runbook.js +265 -0
- package/dist/commands/runbook.js.map +1 -0
- package/dist/config/__mocks__/config-handler.d.ts +11 -0
- package/dist/config/__mocks__/config-handler.d.ts.map +1 -0
- package/dist/config/__mocks__/config-handler.js +31 -0
- package/dist/config/__mocks__/config-handler.js.map +1 -0
- package/dist/config/certificate-pinning.d.ts +68 -0
- package/dist/config/certificate-pinning.d.ts.map +1 -0
- package/dist/config/certificate-pinning.js +249 -0
- package/dist/config/certificate-pinning.js.map +1 -0
- package/dist/config/config-handler.d.ts +45 -0
- package/dist/config/config-handler.d.ts.map +1 -0
- package/dist/config/config-handler.js +149 -0
- package/dist/config/config-handler.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/types/cli-options.d.ts +31 -0
- package/dist/types/cli-options.d.ts.map +1 -0
- package/dist/types/cli-options.js +3 -0
- package/dist/types/cli-options.js.map +1 -0
- package/dist/utils/output-formatter.d.ts +67 -0
- package/dist/utils/output-formatter.d.ts.map +1 -0
- package/dist/utils/output-formatter.js +147 -0
- package/dist/utils/output-formatter.js.map +1 -0
- 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
|