@build-astron-co/nimbus 0.2.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/LICENSE +21 -0
- package/README.md +628 -0
- package/bin/nimbus +38 -0
- package/package.json +80 -0
- package/src/__tests__/app.test.ts +76 -0
- package/src/__tests__/audit.test.ts +877 -0
- package/src/__tests__/circuit-breaker.test.ts +116 -0
- package/src/__tests__/cli-run.test.ts +115 -0
- package/src/__tests__/context-manager.test.ts +502 -0
- package/src/__tests__/context.test.ts +242 -0
- package/src/__tests__/enterprise.test.ts +401 -0
- package/src/__tests__/generator.test.ts +433 -0
- package/src/__tests__/hooks.test.ts +582 -0
- package/src/__tests__/init.test.ts +436 -0
- package/src/__tests__/intent-parser.test.ts +229 -0
- package/src/__tests__/llm-router.test.ts +209 -0
- package/src/__tests__/lsp.test.ts +293 -0
- package/src/__tests__/modes.test.ts +336 -0
- package/src/__tests__/permissions.test.ts +338 -0
- package/src/__tests__/serve.test.ts +275 -0
- package/src/__tests__/sessions.test.ts +227 -0
- package/src/__tests__/sharing.test.ts +288 -0
- package/src/__tests__/snapshots.test.ts +581 -0
- package/src/__tests__/state-db.test.ts +334 -0
- package/src/__tests__/stream-with-tools.test.ts +732 -0
- package/src/__tests__/subagents.test.ts +176 -0
- package/src/__tests__/system-prompt.test.ts +169 -0
- package/src/__tests__/tool-converter.test.ts +256 -0
- package/src/__tests__/tool-schemas.test.ts +397 -0
- package/src/__tests__/tools.test.ts +143 -0
- package/src/__tests__/version.test.ts +49 -0
- package/src/agent/compaction-agent.ts +227 -0
- package/src/agent/context-manager.ts +435 -0
- package/src/agent/context.ts +427 -0
- package/src/agent/deploy-preview.ts +426 -0
- package/src/agent/index.ts +68 -0
- package/src/agent/loop.ts +717 -0
- package/src/agent/modes.ts +429 -0
- package/src/agent/permissions.ts +466 -0
- package/src/agent/subagents/base.ts +116 -0
- package/src/agent/subagents/cost.ts +51 -0
- package/src/agent/subagents/explore.ts +42 -0
- package/src/agent/subagents/general.ts +54 -0
- package/src/agent/subagents/index.ts +102 -0
- package/src/agent/subagents/infra.ts +59 -0
- package/src/agent/subagents/security.ts +69 -0
- package/src/agent/system-prompt.ts +436 -0
- package/src/app.ts +122 -0
- package/src/audit/activity-log.ts +290 -0
- package/src/audit/compliance-checker.ts +540 -0
- package/src/audit/cost-tracker.ts +318 -0
- package/src/audit/index.ts +23 -0
- package/src/audit/security-scanner.ts +596 -0
- package/src/auth/guard.ts +75 -0
- package/src/auth/index.ts +56 -0
- package/src/auth/oauth.ts +455 -0
- package/src/auth/providers.ts +470 -0
- package/src/auth/sso.ts +113 -0
- package/src/auth/store.ts +505 -0
- package/src/auth/types.ts +187 -0
- package/src/build.ts +141 -0
- package/src/cli/index.ts +16 -0
- package/src/cli/init.ts +854 -0
- package/src/cli/openapi-spec.ts +356 -0
- package/src/cli/run.ts +237 -0
- package/src/cli/serve-auth.ts +80 -0
- package/src/cli/serve.ts +462 -0
- package/src/cli/web.ts +67 -0
- package/src/cli.ts +1417 -0
- package/src/clients/core-engine-client.ts +227 -0
- package/src/clients/enterprise-client.ts +334 -0
- package/src/clients/generator-client.ts +351 -0
- package/src/clients/git-client.ts +627 -0
- package/src/clients/github-client.ts +410 -0
- package/src/clients/helm-client.ts +504 -0
- package/src/clients/index.ts +80 -0
- package/src/clients/k8s-client.ts +497 -0
- package/src/clients/llm-client.ts +161 -0
- package/src/clients/rest-client.ts +130 -0
- package/src/clients/service-discovery.ts +33 -0
- package/src/clients/terraform-client.ts +482 -0
- package/src/clients/tools-client.ts +1843 -0
- package/src/clients/ws-client.ts +115 -0
- package/src/commands/analyze/index.ts +352 -0
- package/src/commands/apply/helm.ts +473 -0
- package/src/commands/apply/index.ts +213 -0
- package/src/commands/apply/k8s.ts +454 -0
- package/src/commands/apply/terraform.ts +582 -0
- package/src/commands/ask.ts +167 -0
- package/src/commands/audit/index.ts +238 -0
- package/src/commands/auth-cloud.ts +294 -0
- package/src/commands/auth-list.ts +134 -0
- package/src/commands/auth-profile.ts +121 -0
- package/src/commands/auth-status.ts +141 -0
- package/src/commands/aws/ec2.ts +501 -0
- package/src/commands/aws/iam.ts +397 -0
- package/src/commands/aws/index.ts +133 -0
- package/src/commands/aws/lambda.ts +396 -0
- package/src/commands/aws/rds.ts +439 -0
- package/src/commands/aws/s3.ts +439 -0
- package/src/commands/aws/vpc.ts +393 -0
- package/src/commands/aws-discover.ts +649 -0
- package/src/commands/aws-terraform.ts +805 -0
- package/src/commands/azure/aks.ts +376 -0
- package/src/commands/azure/functions.ts +253 -0
- package/src/commands/azure/index.ts +116 -0
- package/src/commands/azure/storage.ts +478 -0
- package/src/commands/azure/vm.ts +355 -0
- package/src/commands/billing/index.ts +256 -0
- package/src/commands/chat.ts +314 -0
- package/src/commands/config.ts +346 -0
- package/src/commands/cost/cloud-cost-estimator.ts +266 -0
- package/src/commands/cost/estimator.ts +79 -0
- package/src/commands/cost/index.ts +594 -0
- package/src/commands/cost/parsers/terraform.ts +273 -0
- package/src/commands/cost/parsers/types.ts +25 -0
- package/src/commands/cost/pricing/aws.ts +544 -0
- package/src/commands/cost/pricing/azure.ts +499 -0
- package/src/commands/cost/pricing/gcp.ts +396 -0
- package/src/commands/cost/pricing/index.ts +40 -0
- package/src/commands/demo.ts +250 -0
- package/src/commands/doctor.ts +794 -0
- package/src/commands/drift/index.ts +439 -0
- package/src/commands/explain.ts +277 -0
- package/src/commands/feedback.ts +389 -0
- package/src/commands/fix.ts +324 -0
- package/src/commands/fs/index.ts +402 -0
- package/src/commands/gcp/compute.ts +325 -0
- package/src/commands/gcp/functions.ts +271 -0
- package/src/commands/gcp/gke.ts +438 -0
- package/src/commands/gcp/iam.ts +344 -0
- package/src/commands/gcp/index.ts +129 -0
- package/src/commands/gcp/storage.ts +284 -0
- package/src/commands/generate-helm.ts +1249 -0
- package/src/commands/generate-k8s.ts +1560 -0
- package/src/commands/generate-terraform.ts +1460 -0
- package/src/commands/gh/index.ts +863 -0
- package/src/commands/git/index.ts +1343 -0
- package/src/commands/helm/index.ts +1126 -0
- package/src/commands/help.ts +539 -0
- package/src/commands/history.ts +142 -0
- package/src/commands/import.ts +868 -0
- package/src/commands/index.ts +367 -0
- package/src/commands/init.ts +1046 -0
- package/src/commands/k8s/index.ts +1137 -0
- package/src/commands/login.ts +631 -0
- package/src/commands/logout.ts +83 -0
- package/src/commands/onboarding.ts +228 -0
- package/src/commands/plan/display.ts +279 -0
- package/src/commands/plan/index.ts +599 -0
- package/src/commands/preview.ts +452 -0
- package/src/commands/questionnaire.ts +1270 -0
- package/src/commands/resume.ts +55 -0
- package/src/commands/team/index.ts +346 -0
- package/src/commands/template.ts +232 -0
- package/src/commands/tf/index.ts +1034 -0
- package/src/commands/upgrade.ts +550 -0
- package/src/commands/usage/index.ts +134 -0
- package/src/commands/version.ts +170 -0
- package/src/compat/index.ts +2 -0
- package/src/compat/runtime.ts +12 -0
- package/src/compat/sqlite.ts +107 -0
- package/src/config/index.ts +17 -0
- package/src/config/manager.ts +530 -0
- package/src/config/safety-policy.ts +358 -0
- package/src/config/schema.ts +125 -0
- package/src/config/types.ts +527 -0
- package/src/context/context-db.ts +199 -0
- package/src/demo/index.ts +349 -0
- package/src/demo/scenarios/full-journey.ts +229 -0
- package/src/demo/scenarios/getting-started.ts +127 -0
- package/src/demo/scenarios/helm-release.ts +341 -0
- package/src/demo/scenarios/k8s-deployment.ts +194 -0
- package/src/demo/scenarios/terraform-vpc.ts +170 -0
- package/src/demo/types.ts +92 -0
- package/src/engine/cost-estimator.ts +438 -0
- package/src/engine/diagram-generator.ts +256 -0
- package/src/engine/drift-detector.ts +902 -0
- package/src/engine/executor.ts +1035 -0
- package/src/engine/index.ts +76 -0
- package/src/engine/orchestrator.ts +636 -0
- package/src/engine/planner.ts +720 -0
- package/src/engine/safety.ts +743 -0
- package/src/engine/verifier.ts +770 -0
- package/src/enterprise/audit.ts +348 -0
- package/src/enterprise/auth.ts +270 -0
- package/src/enterprise/billing.ts +822 -0
- package/src/enterprise/index.ts +17 -0
- package/src/enterprise/teams.ts +443 -0
- package/src/generator/best-practices.ts +1608 -0
- package/src/generator/helm.ts +630 -0
- package/src/generator/index.ts +37 -0
- package/src/generator/intent-parser.ts +514 -0
- package/src/generator/kubernetes.ts +976 -0
- package/src/generator/terraform.ts +1867 -0
- package/src/history/index.ts +8 -0
- package/src/history/manager.ts +322 -0
- package/src/history/types.ts +34 -0
- package/src/hooks/config.ts +432 -0
- package/src/hooks/engine.ts +391 -0
- package/src/hooks/index.ts +4 -0
- package/src/llm/auth-bridge.ts +198 -0
- package/src/llm/circuit-breaker.ts +140 -0
- package/src/llm/config-loader.ts +201 -0
- package/src/llm/cost-calculator.ts +171 -0
- package/src/llm/index.ts +8 -0
- package/src/llm/model-aliases.ts +115 -0
- package/src/llm/provider-registry.ts +63 -0
- package/src/llm/providers/anthropic.ts +433 -0
- package/src/llm/providers/bedrock.ts +477 -0
- package/src/llm/providers/google.ts +405 -0
- package/src/llm/providers/ollama.ts +767 -0
- package/src/llm/providers/openai-compatible.ts +340 -0
- package/src/llm/providers/openai.ts +328 -0
- package/src/llm/providers/openrouter.ts +338 -0
- package/src/llm/router.ts +1035 -0
- package/src/llm/types.ts +232 -0
- package/src/lsp/client.ts +298 -0
- package/src/lsp/languages.ts +116 -0
- package/src/lsp/manager.ts +278 -0
- package/src/mcp/client.ts +402 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/manager.ts +133 -0
- package/src/nimbus.ts +214 -0
- package/src/plugins/index.ts +27 -0
- package/src/plugins/loader.ts +334 -0
- package/src/plugins/manager.ts +376 -0
- package/src/plugins/types.ts +284 -0
- package/src/scanners/cicd-scanner.ts +258 -0
- package/src/scanners/cloud-scanner.ts +466 -0
- package/src/scanners/framework-scanner.ts +469 -0
- package/src/scanners/iac-scanner.ts +388 -0
- package/src/scanners/index.ts +539 -0
- package/src/scanners/language-scanner.ts +276 -0
- package/src/scanners/package-manager-scanner.ts +277 -0
- package/src/scanners/types.ts +172 -0
- package/src/sessions/manager.ts +365 -0
- package/src/sessions/types.ts +44 -0
- package/src/sharing/sync.ts +296 -0
- package/src/sharing/viewer.ts +97 -0
- package/src/snapshots/index.ts +2 -0
- package/src/snapshots/manager.ts +530 -0
- package/src/state/artifacts.ts +147 -0
- package/src/state/audit.ts +137 -0
- package/src/state/billing.ts +240 -0
- package/src/state/checkpoints.ts +117 -0
- package/src/state/config.ts +67 -0
- package/src/state/conversations.ts +14 -0
- package/src/state/credentials.ts +154 -0
- package/src/state/db.ts +58 -0
- package/src/state/index.ts +26 -0
- package/src/state/messages.ts +115 -0
- package/src/state/projects.ts +123 -0
- package/src/state/schema.ts +236 -0
- package/src/state/sessions.ts +147 -0
- package/src/state/teams.ts +200 -0
- package/src/telemetry.ts +108 -0
- package/src/tools/aws-ops.ts +952 -0
- package/src/tools/azure-ops.ts +579 -0
- package/src/tools/file-ops.ts +593 -0
- package/src/tools/gcp-ops.ts +625 -0
- package/src/tools/git-ops.ts +773 -0
- package/src/tools/github-ops.ts +799 -0
- package/src/tools/helm-ops.ts +943 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/k8s-ops.ts +819 -0
- package/src/tools/schemas/converter.ts +184 -0
- package/src/tools/schemas/devops.ts +612 -0
- package/src/tools/schemas/index.ts +73 -0
- package/src/tools/schemas/standard.ts +1144 -0
- package/src/tools/schemas/types.ts +705 -0
- package/src/tools/terraform-ops.ts +862 -0
- package/src/types/ambient.d.ts +193 -0
- package/src/types/config.ts +83 -0
- package/src/types/drift.ts +116 -0
- package/src/types/enterprise.ts +335 -0
- package/src/types/index.ts +20 -0
- package/src/types/plan.ts +44 -0
- package/src/types/request.ts +65 -0
- package/src/types/response.ts +54 -0
- package/src/types/service.ts +51 -0
- package/src/ui/App.tsx +997 -0
- package/src/ui/DeployPreview.tsx +169 -0
- package/src/ui/Header.tsx +68 -0
- package/src/ui/InputBox.tsx +350 -0
- package/src/ui/MessageList.tsx +585 -0
- package/src/ui/PermissionPrompt.tsx +151 -0
- package/src/ui/StatusBar.tsx +158 -0
- package/src/ui/ToolCallDisplay.tsx +409 -0
- package/src/ui/chat-ui.ts +853 -0
- package/src/ui/index.ts +33 -0
- package/src/ui/ink/index.ts +711 -0
- package/src/ui/streaming.ts +176 -0
- package/src/ui/types.ts +57 -0
- package/src/utils/analytics.ts +72 -0
- package/src/utils/cost-warning.ts +27 -0
- package/src/utils/env.ts +46 -0
- package/src/utils/errors.ts +69 -0
- package/src/utils/event-bus.ts +38 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/logger.ts +171 -0
- package/src/utils/rate-limiter.ts +121 -0
- package/src/utils/service-auth.ts +49 -0
- package/src/utils/validation.ts +53 -0
- package/src/version.ts +4 -0
- package/src/watcher/index.ts +163 -0
- package/src/wizard/approval.ts +383 -0
- package/src/wizard/index.ts +25 -0
- package/src/wizard/prompts.ts +338 -0
- package/src/wizard/types.ts +171 -0
- package/src/wizard/ui.ts +556 -0
- package/src/wizard/wizard.ts +304 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS IAM Commands
|
|
3
|
+
*
|
|
4
|
+
* IAM user, role, and policy operations
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* nimbus aws iam users
|
|
8
|
+
* nimbus aws iam roles
|
|
9
|
+
* nimbus aws iam policies
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { logger } from '../../utils';
|
|
13
|
+
import { ui } from '../../wizard/ui';
|
|
14
|
+
import type { AwsCommandOptions } from './index';
|
|
15
|
+
|
|
16
|
+
interface IAMUser {
|
|
17
|
+
UserName: string;
|
|
18
|
+
UserId: string;
|
|
19
|
+
Arn: string;
|
|
20
|
+
CreateDate: string;
|
|
21
|
+
PasswordLastUsed?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface IAMRole {
|
|
25
|
+
RoleName: string;
|
|
26
|
+
RoleId: string;
|
|
27
|
+
Arn: string;
|
|
28
|
+
CreateDate: string;
|
|
29
|
+
Description?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface IAMPolicy {
|
|
33
|
+
PolicyName: string;
|
|
34
|
+
PolicyId: string;
|
|
35
|
+
Arn: string;
|
|
36
|
+
CreateDate: string;
|
|
37
|
+
AttachmentCount: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* IAM command router
|
|
42
|
+
*/
|
|
43
|
+
export async function iamCommand(
|
|
44
|
+
action: string,
|
|
45
|
+
args: string[],
|
|
46
|
+
options: AwsCommandOptions
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
logger.info('Running IAM command', { action, args, options });
|
|
49
|
+
|
|
50
|
+
switch (action) {
|
|
51
|
+
case 'users':
|
|
52
|
+
await listUsers(options);
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
case 'roles':
|
|
56
|
+
await listRoles(options);
|
|
57
|
+
break;
|
|
58
|
+
|
|
59
|
+
case 'policies':
|
|
60
|
+
await listPolicies(options);
|
|
61
|
+
break;
|
|
62
|
+
|
|
63
|
+
case 'user':
|
|
64
|
+
if (!args[0]) {
|
|
65
|
+
ui.error('User name is required');
|
|
66
|
+
ui.print('Usage: nimbus aws iam user <username>');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await describeUser(args[0], options);
|
|
70
|
+
break;
|
|
71
|
+
|
|
72
|
+
case 'role':
|
|
73
|
+
if (!args[0]) {
|
|
74
|
+
ui.error('Role name is required');
|
|
75
|
+
ui.print('Usage: nimbus aws iam role <rolename>');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
await describeRole(args[0], options);
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
default:
|
|
82
|
+
showIamHelp();
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* List all IAM users
|
|
89
|
+
*/
|
|
90
|
+
async function listUsers(options: AwsCommandOptions): Promise<void> {
|
|
91
|
+
ui.header('IAM Users');
|
|
92
|
+
|
|
93
|
+
ui.startSpinner({ message: 'Fetching IAM users...' });
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const result = await runAwsCommand<{ Users: IAMUser[] }>('iam list-users', options);
|
|
97
|
+
|
|
98
|
+
const users = result.Users || [];
|
|
99
|
+
|
|
100
|
+
ui.stopSpinnerSuccess(`Found ${users.length} user(s)`);
|
|
101
|
+
ui.newLine();
|
|
102
|
+
|
|
103
|
+
if (users.length === 0) {
|
|
104
|
+
ui.info('No IAM users found');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Display table
|
|
109
|
+
const headers = ['Username', 'User ID', 'Created', 'Last Login'];
|
|
110
|
+
const rows = users.map(user => [
|
|
111
|
+
user.UserName,
|
|
112
|
+
user.UserId,
|
|
113
|
+
new Date(user.CreateDate).toLocaleDateString(),
|
|
114
|
+
user.PasswordLastUsed ? new Date(user.PasswordLastUsed).toLocaleDateString() : 'Never',
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
displayTable(headers, rows);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
ui.stopSpinnerFail('Failed to list users');
|
|
120
|
+
ui.error((error as Error).message);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* List all IAM roles
|
|
126
|
+
*/
|
|
127
|
+
async function listRoles(options: AwsCommandOptions): Promise<void> {
|
|
128
|
+
ui.header('IAM Roles');
|
|
129
|
+
|
|
130
|
+
ui.startSpinner({ message: 'Fetching IAM roles...' });
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const result = await runAwsCommand<{ Roles: IAMRole[] }>('iam list-roles', options);
|
|
134
|
+
|
|
135
|
+
const roles = result.Roles || [];
|
|
136
|
+
|
|
137
|
+
ui.stopSpinnerSuccess(`Found ${roles.length} role(s)`);
|
|
138
|
+
ui.newLine();
|
|
139
|
+
|
|
140
|
+
if (roles.length === 0) {
|
|
141
|
+
ui.info('No IAM roles found');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Display table (filter out AWS service roles by default)
|
|
146
|
+
const customRoles = roles.filter(r => !r.RoleName.startsWith('AWS'));
|
|
147
|
+
const headers = ['Role Name', 'Role ID', 'Created', 'Description'];
|
|
148
|
+
const rows = customRoles.map(role => [
|
|
149
|
+
role.RoleName,
|
|
150
|
+
role.RoleId,
|
|
151
|
+
new Date(role.CreateDate).toLocaleDateString(),
|
|
152
|
+
role.Description || '-',
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
displayTable(headers, rows);
|
|
156
|
+
|
|
157
|
+
if (customRoles.length < roles.length) {
|
|
158
|
+
ui.newLine();
|
|
159
|
+
ui.dim(`(${roles.length - customRoles.length} AWS service roles hidden)`);
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
ui.stopSpinnerFail('Failed to list roles');
|
|
163
|
+
ui.error((error as Error).message);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* List all IAM policies
|
|
169
|
+
*/
|
|
170
|
+
async function listPolicies(options: AwsCommandOptions): Promise<void> {
|
|
171
|
+
ui.header('IAM Policies');
|
|
172
|
+
|
|
173
|
+
ui.startSpinner({ message: 'Fetching IAM policies...' });
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const result = await runAwsCommand<{ Policies: IAMPolicy[] }>(
|
|
177
|
+
'iam list-policies --scope Local',
|
|
178
|
+
options
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const policies = result.Policies || [];
|
|
182
|
+
|
|
183
|
+
ui.stopSpinnerSuccess(`Found ${policies.length} custom policy(ies)`);
|
|
184
|
+
ui.newLine();
|
|
185
|
+
|
|
186
|
+
if (policies.length === 0) {
|
|
187
|
+
ui.info('No custom IAM policies found');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Display table
|
|
192
|
+
const headers = ['Policy Name', 'Policy ID', 'Attachments', 'Created'];
|
|
193
|
+
const rows = policies.map(policy => [
|
|
194
|
+
policy.PolicyName,
|
|
195
|
+
policy.PolicyId,
|
|
196
|
+
String(policy.AttachmentCount),
|
|
197
|
+
new Date(policy.CreateDate).toLocaleDateString(),
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
displayTable(headers, rows);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
ui.stopSpinnerFail('Failed to list policies');
|
|
203
|
+
ui.error((error as Error).message);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Describe a specific IAM user
|
|
209
|
+
*/
|
|
210
|
+
async function describeUser(userName: string, options: AwsCommandOptions): Promise<void> {
|
|
211
|
+
ui.header(`IAM User: ${userName}`);
|
|
212
|
+
|
|
213
|
+
ui.startSpinner({ message: 'Fetching user details...' });
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const { execFile } = await import('child_process');
|
|
217
|
+
const { promisify } = await import('util');
|
|
218
|
+
const execFileAsync = promisify(execFile);
|
|
219
|
+
|
|
220
|
+
// Get user details
|
|
221
|
+
const userArgs = ['iam', 'get-user', '--user-name', userName, '--output', 'json'];
|
|
222
|
+
if (options.profile) {
|
|
223
|
+
userArgs.push('--profile', options.profile);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const { stdout: userOutput } = await execFileAsync('aws', userArgs);
|
|
227
|
+
const userData = JSON.parse(userOutput);
|
|
228
|
+
const user = userData.User;
|
|
229
|
+
|
|
230
|
+
// Get user groups
|
|
231
|
+
const groupArgs = ['iam', 'list-groups-for-user', '--user-name', userName, '--output', 'json'];
|
|
232
|
+
if (options.profile) {
|
|
233
|
+
groupArgs.push('--profile', options.profile);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const { stdout: groupOutput } = await execFileAsync('aws', groupArgs);
|
|
237
|
+
const groupData = JSON.parse(groupOutput);
|
|
238
|
+
const groups = groupData.Groups || [];
|
|
239
|
+
|
|
240
|
+
ui.stopSpinnerSuccess('User details retrieved');
|
|
241
|
+
ui.newLine();
|
|
242
|
+
|
|
243
|
+
ui.print(ui.bold('User Details:'));
|
|
244
|
+
ui.newLine();
|
|
245
|
+
ui.print(` Username: ${user.UserName}`);
|
|
246
|
+
ui.print(` User ID: ${user.UserId}`);
|
|
247
|
+
ui.print(` ARN: ${user.Arn}`);
|
|
248
|
+
ui.print(` Created: ${new Date(user.CreateDate).toLocaleString()}`);
|
|
249
|
+
ui.print(
|
|
250
|
+
` Last Login: ${user.PasswordLastUsed ? new Date(user.PasswordLastUsed).toLocaleString() : 'Never'}`
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (groups.length > 0) {
|
|
254
|
+
ui.newLine();
|
|
255
|
+
ui.print(ui.bold('Groups:'));
|
|
256
|
+
for (const group of groups) {
|
|
257
|
+
ui.print(` - ${group.GroupName}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
ui.stopSpinnerFail('Failed to describe user');
|
|
262
|
+
ui.error((error as Error).message);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Describe a specific IAM role
|
|
268
|
+
*/
|
|
269
|
+
async function describeRole(roleName: string, options: AwsCommandOptions): Promise<void> {
|
|
270
|
+
ui.header(`IAM Role: ${roleName}`);
|
|
271
|
+
|
|
272
|
+
ui.startSpinner({ message: 'Fetching role details...' });
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const { execFile } = await import('child_process');
|
|
276
|
+
const { promisify } = await import('util');
|
|
277
|
+
const execFileAsync = promisify(execFile);
|
|
278
|
+
|
|
279
|
+
// Get role details
|
|
280
|
+
const roleArgs = ['iam', 'get-role', '--role-name', roleName, '--output', 'json'];
|
|
281
|
+
if (options.profile) {
|
|
282
|
+
roleArgs.push('--profile', options.profile);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const { stdout: roleOutput } = await execFileAsync('aws', roleArgs);
|
|
286
|
+
const roleData = JSON.parse(roleOutput);
|
|
287
|
+
const role = roleData.Role;
|
|
288
|
+
|
|
289
|
+
// Get attached policies
|
|
290
|
+
const policyArgs = [
|
|
291
|
+
'iam',
|
|
292
|
+
'list-attached-role-policies',
|
|
293
|
+
'--role-name',
|
|
294
|
+
roleName,
|
|
295
|
+
'--output',
|
|
296
|
+
'json',
|
|
297
|
+
];
|
|
298
|
+
if (options.profile) {
|
|
299
|
+
policyArgs.push('--profile', options.profile);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const { stdout: policyOutput } = await execFileAsync('aws', policyArgs);
|
|
303
|
+
const policyData = JSON.parse(policyOutput);
|
|
304
|
+
const policies = policyData.AttachedPolicies || [];
|
|
305
|
+
|
|
306
|
+
ui.stopSpinnerSuccess('Role details retrieved');
|
|
307
|
+
ui.newLine();
|
|
308
|
+
|
|
309
|
+
ui.print(ui.bold('Role Details:'));
|
|
310
|
+
ui.newLine();
|
|
311
|
+
ui.print(` Role Name: ${role.RoleName}`);
|
|
312
|
+
ui.print(` Role ID: ${role.RoleId}`);
|
|
313
|
+
ui.print(` ARN: ${role.Arn}`);
|
|
314
|
+
ui.print(` Created: ${new Date(role.CreateDate).toLocaleString()}`);
|
|
315
|
+
if (role.Description) {
|
|
316
|
+
ui.print(` Description: ${role.Description}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (policies.length > 0) {
|
|
320
|
+
ui.newLine();
|
|
321
|
+
ui.print(ui.bold('Attached Policies:'));
|
|
322
|
+
for (const policy of policies) {
|
|
323
|
+
ui.print(` - ${policy.PolicyName}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
} catch (error) {
|
|
327
|
+
ui.stopSpinnerFail('Failed to describe role');
|
|
328
|
+
ui.error((error as Error).message);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Run AWS CLI command and parse JSON output
|
|
334
|
+
*/
|
|
335
|
+
async function runAwsCommand<T>(command: string, options: AwsCommandOptions): Promise<T> {
|
|
336
|
+
const { execFile } = await import('child_process');
|
|
337
|
+
const { promisify } = await import('util');
|
|
338
|
+
const execFileAsync = promisify(execFile);
|
|
339
|
+
|
|
340
|
+
const args = command.split(' ');
|
|
341
|
+
const baseCommand = args[0];
|
|
342
|
+
const commandArgs = args.slice(1);
|
|
343
|
+
|
|
344
|
+
// Add common options
|
|
345
|
+
if (options.profile) {
|
|
346
|
+
commandArgs.push('--profile', options.profile);
|
|
347
|
+
}
|
|
348
|
+
commandArgs.push('--output', 'json');
|
|
349
|
+
|
|
350
|
+
const { stdout } = await execFileAsync('aws', [baseCommand, ...commandArgs]);
|
|
351
|
+
return JSON.parse(stdout) as T;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Display a table
|
|
356
|
+
*/
|
|
357
|
+
function displayTable(headers: string[], rows: string[][]): void {
|
|
358
|
+
// Calculate column widths
|
|
359
|
+
const colWidths = headers.map((h, i) => {
|
|
360
|
+
const maxDataWidth = Math.max(...rows.map(r => (r[i] || '').length));
|
|
361
|
+
return Math.max(h.length, maxDataWidth);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Print header
|
|
365
|
+
const headerRow = headers.map((h, i) => h.padEnd(colWidths[i])).join(' ');
|
|
366
|
+
ui.print(ui.bold(headerRow));
|
|
367
|
+
ui.print('-'.repeat(headerRow.length));
|
|
368
|
+
|
|
369
|
+
// Print rows
|
|
370
|
+
for (const row of rows) {
|
|
371
|
+
const formattedRow = row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(' ');
|
|
372
|
+
ui.print(formattedRow);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Show IAM command help
|
|
378
|
+
*/
|
|
379
|
+
function showIamHelp(): void {
|
|
380
|
+
ui.print('Usage: nimbus aws iam <action> [args]');
|
|
381
|
+
ui.newLine();
|
|
382
|
+
|
|
383
|
+
ui.print(ui.bold('Actions:'));
|
|
384
|
+
ui.print(' users List all IAM users');
|
|
385
|
+
ui.print(' roles List all IAM roles');
|
|
386
|
+
ui.print(' policies List custom IAM policies');
|
|
387
|
+
ui.print(' user <name> Describe a specific user');
|
|
388
|
+
ui.print(' role <name> Describe a specific role');
|
|
389
|
+
ui.newLine();
|
|
390
|
+
|
|
391
|
+
ui.print(ui.bold('Examples:'));
|
|
392
|
+
ui.print(' nimbus aws iam users');
|
|
393
|
+
ui.print(' nimbus aws iam roles');
|
|
394
|
+
ui.print(' nimbus aws iam user admin');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export default iamCommand;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Wrapper for AWS CLI operations with enhanced output and safety checks
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* nimbus aws ec2 list
|
|
8
|
+
* nimbus aws s3 ls
|
|
9
|
+
* nimbus aws rds list
|
|
10
|
+
* nimbus aws lambda list
|
|
11
|
+
* nimbus aws iam users
|
|
12
|
+
* nimbus aws vpc list
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { logger } from '../../utils';
|
|
16
|
+
import { ui } from '../../wizard/ui';
|
|
17
|
+
import { ec2Command } from './ec2';
|
|
18
|
+
import { s3Command } from './s3';
|
|
19
|
+
import { rdsCommand } from './rds';
|
|
20
|
+
import { lambdaCommand } from './lambda';
|
|
21
|
+
import { iamCommand } from './iam';
|
|
22
|
+
import { vpcCommand } from './vpc';
|
|
23
|
+
|
|
24
|
+
export interface AwsCommandOptions {
|
|
25
|
+
profile?: string;
|
|
26
|
+
region?: string;
|
|
27
|
+
output?: 'json' | 'table' | 'text';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse common AWS options from args
|
|
32
|
+
*/
|
|
33
|
+
export function parseAwsOptions(args: string[]): AwsCommandOptions {
|
|
34
|
+
const options: AwsCommandOptions = {};
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < args.length; i++) {
|
|
37
|
+
const arg = args[i];
|
|
38
|
+
|
|
39
|
+
if ((arg === '--profile' || arg === '-p') && args[i + 1]) {
|
|
40
|
+
options.profile = args[++i];
|
|
41
|
+
} else if ((arg === '--region' || arg === '-r') && args[i + 1]) {
|
|
42
|
+
options.region = args[++i];
|
|
43
|
+
} else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
|
|
44
|
+
options.output = args[++i] as 'json' | 'table' | 'text';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return options;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Main AWS command router
|
|
53
|
+
*/
|
|
54
|
+
export async function awsCommand(subcommand: string, args: string[]): Promise<void> {
|
|
55
|
+
logger.info('Running AWS command', { subcommand, args });
|
|
56
|
+
|
|
57
|
+
const options = parseAwsOptions(args);
|
|
58
|
+
const positionalArgs = args.filter(arg => !arg.startsWith('-') && !arg.startsWith('--'));
|
|
59
|
+
|
|
60
|
+
switch (subcommand) {
|
|
61
|
+
case 'ec2':
|
|
62
|
+
await ec2Command(positionalArgs[0], positionalArgs.slice(1), options);
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case 's3':
|
|
66
|
+
await s3Command(positionalArgs[0], positionalArgs.slice(1), options);
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
case 'rds':
|
|
70
|
+
await rdsCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
71
|
+
break;
|
|
72
|
+
|
|
73
|
+
case 'lambda':
|
|
74
|
+
await lambdaCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case 'iam':
|
|
78
|
+
await iamCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
case 'vpc':
|
|
82
|
+
await vpcCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
default:
|
|
86
|
+
showAwsHelp();
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Show AWS command help
|
|
93
|
+
*/
|
|
94
|
+
function showAwsHelp(): void {
|
|
95
|
+
ui.header('Nimbus AWS Commands');
|
|
96
|
+
ui.newLine();
|
|
97
|
+
|
|
98
|
+
ui.print('Usage: nimbus aws <service> <action> [options]');
|
|
99
|
+
ui.newLine();
|
|
100
|
+
|
|
101
|
+
ui.print(ui.bold('Services:'));
|
|
102
|
+
ui.print(' ec2 EC2 instance operations');
|
|
103
|
+
ui.print(' s3 S3 bucket and object operations');
|
|
104
|
+
ui.print(' rds RDS database operations');
|
|
105
|
+
ui.print(' lambda Lambda function operations');
|
|
106
|
+
ui.print(' iam IAM user, role, and policy operations');
|
|
107
|
+
ui.print(' vpc VPC and networking operations');
|
|
108
|
+
ui.newLine();
|
|
109
|
+
|
|
110
|
+
ui.print(ui.bold('Common Options:'));
|
|
111
|
+
ui.print(' --profile, -p AWS profile to use');
|
|
112
|
+
ui.print(' --region, -r AWS region');
|
|
113
|
+
ui.print(' --output, -o Output format (json, table, text)');
|
|
114
|
+
ui.newLine();
|
|
115
|
+
|
|
116
|
+
ui.print(ui.bold('Examples:'));
|
|
117
|
+
ui.print(' nimbus aws ec2 list List all EC2 instances');
|
|
118
|
+
ui.print(' nimbus aws ec2 describe i-1234567890 Describe specific instance');
|
|
119
|
+
ui.print(' nimbus aws s3 ls List all S3 buckets');
|
|
120
|
+
ui.print(' nimbus aws s3 ls my-bucket List objects in bucket');
|
|
121
|
+
ui.print(' nimbus aws rds list List all RDS instances');
|
|
122
|
+
ui.print(' nimbus aws lambda list List all Lambda functions');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Re-export subcommands
|
|
126
|
+
export { ec2Command } from './ec2';
|
|
127
|
+
export { s3Command } from './s3';
|
|
128
|
+
export { rdsCommand } from './rds';
|
|
129
|
+
export { lambdaCommand } from './lambda';
|
|
130
|
+
export { iamCommand } from './iam';
|
|
131
|
+
export { vpcCommand } from './vpc';
|
|
132
|
+
|
|
133
|
+
export default awsCommand;
|