@prism-d1/cli 1.2.0 → 1.4.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 (181) hide show
  1. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +2 -2
  2. package/dist/assets/infra/bin/app.ts +61 -37
  3. package/dist/assets/infra/lib/constructs/security-agent-construct.ts +35 -30
  4. package/dist/assets/infra/lib/metrics-pipeline-stack.ts +2 -110
  5. package/dist/assets/infra/lib/security-agent-resources.ts +136 -0
  6. package/dist/assets/infra/lib/security-agent-stack.ts +69 -0
  7. package/dist/assets/pentest-cdk/bin/app.ts +12 -0
  8. package/dist/assets/pentest-cdk/cdk.json +7 -0
  9. package/dist/assets/pentest-cdk/lib/pentest-target-stack.ts +206 -0
  10. package/dist/assets/pentest-cdk/package.json +18 -0
  11. package/dist/assets/pentest-cdk/tsconfig.json +12 -0
  12. package/dist/src/aws/advice.d.ts +33 -0
  13. package/dist/src/aws/advice.d.ts.map +1 -0
  14. package/dist/src/aws/advice.js +174 -0
  15. package/dist/src/aws/advice.js.map +1 -0
  16. package/dist/src/aws/check.d.ts +64 -0
  17. package/dist/src/aws/check.d.ts.map +1 -0
  18. package/dist/src/aws/check.js +269 -0
  19. package/dist/src/aws/check.js.map +1 -0
  20. package/dist/src/aws/connect.d.ts +65 -0
  21. package/dist/src/aws/connect.d.ts.map +1 -0
  22. package/dist/src/aws/connect.js +250 -0
  23. package/dist/src/aws/connect.js.map +1 -0
  24. package/dist/src/aws/connection.d.ts +67 -0
  25. package/dist/src/aws/connection.d.ts.map +1 -0
  26. package/dist/src/aws/connection.js +137 -0
  27. package/dist/src/aws/connection.js.map +1 -0
  28. package/dist/src/aws/recommend.d.ts +70 -0
  29. package/dist/src/aws/recommend.d.ts.map +1 -0
  30. package/dist/src/aws/recommend.js +244 -0
  31. package/dist/src/aws/recommend.js.map +1 -0
  32. package/dist/src/aws/run-check.d.ts +31 -0
  33. package/dist/src/aws/run-check.d.ts.map +1 -0
  34. package/dist/src/aws/run-check.js +91 -0
  35. package/dist/src/aws/run-check.js.map +1 -0
  36. package/dist/src/codewatch/results.d.ts +155 -4
  37. package/dist/src/codewatch/results.d.ts.map +1 -1
  38. package/dist/src/codewatch/results.js +12 -2
  39. package/dist/src/codewatch/results.js.map +1 -1
  40. package/dist/src/commands/_top/version.d.ts +62 -0
  41. package/dist/src/commands/_top/version.d.ts.map +1 -0
  42. package/dist/src/commands/_top/version.js +175 -0
  43. package/dist/src/commands/_top/version.js.map +1 -0
  44. package/dist/src/commands/aws/check.d.ts +25 -0
  45. package/dist/src/commands/aws/check.d.ts.map +1 -0
  46. package/dist/src/commands/aws/check.js +42 -0
  47. package/dist/src/commands/aws/check.js.map +1 -0
  48. package/dist/src/commands/aws/connect.d.ts +16 -0
  49. package/dist/src/commands/aws/connect.d.ts.map +1 -0
  50. package/dist/src/commands/aws/connect.js +39 -0
  51. package/dist/src/commands/aws/connect.js.map +1 -0
  52. package/dist/src/commands/aws/recommend.d.ts +12 -0
  53. package/dist/src/commands/aws/recommend.d.ts.map +1 -0
  54. package/dist/src/commands/aws/recommend.js +21 -0
  55. package/dist/src/commands/aws/recommend.js.map +1 -0
  56. package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -1
  57. package/dist/src/commands/bedrock-protection/scan-account.js +14 -35
  58. package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -1
  59. package/dist/src/commands/bedrock-protection/scan-org.d.ts.map +1 -1
  60. package/dist/src/commands/bedrock-protection/scan-org.js +12 -5
  61. package/dist/src/commands/bedrock-protection/scan-org.js.map +1 -1
  62. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts +12 -6
  63. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
  64. package/dist/src/commands/bootstrapper/setup-otel-sync.js +18 -409
  65. package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
  66. package/dist/src/commands/enable/codeburn.d.ts +59 -0
  67. package/dist/src/commands/enable/codeburn.d.ts.map +1 -0
  68. package/dist/src/commands/enable/codeburn.js +531 -0
  69. package/dist/src/commands/enable/codeburn.js.map +1 -0
  70. package/dist/src/commands/enable/security.d.ts +41 -0
  71. package/dist/src/commands/enable/security.d.ts.map +1 -0
  72. package/dist/src/commands/enable/security.js +128 -0
  73. package/dist/src/commands/enable/security.js.map +1 -0
  74. package/dist/src/commands/export/otel.d.ts +31 -0
  75. package/dist/src/commands/export/otel.d.ts.map +1 -0
  76. package/dist/src/commands/export/otel.js +52 -0
  77. package/dist/src/commands/export/otel.js.map +1 -0
  78. package/dist/src/commands/security/code-review.d.ts +22 -0
  79. package/dist/src/commands/security/code-review.d.ts.map +1 -0
  80. package/dist/src/commands/security/code-review.js +44 -0
  81. package/dist/src/commands/security/code-review.js.map +1 -0
  82. package/dist/src/commands/security/findings.d.ts +15 -0
  83. package/dist/src/commands/security/findings.d.ts.map +1 -0
  84. package/dist/src/commands/security/findings.js +33 -0
  85. package/dist/src/commands/security/findings.js.map +1 -0
  86. package/dist/src/commands/security/pentest.d.ts +18 -0
  87. package/dist/src/commands/security/pentest.d.ts.map +1 -0
  88. package/dist/src/commands/security/pentest.js +33 -0
  89. package/dist/src/commands/security/pentest.js.map +1 -0
  90. package/dist/src/commands/security/threat-model.d.ts +16 -0
  91. package/dist/src/commands/security/threat-model.d.ts.map +1 -0
  92. package/dist/src/commands/security/threat-model.js +25 -0
  93. package/dist/src/commands/security/threat-model.js.map +1 -0
  94. package/dist/src/commands/security/threats.d.ts +12 -0
  95. package/dist/src/commands/security/threats.d.ts.map +1 -0
  96. package/dist/src/commands/security/threats.js +24 -0
  97. package/dist/src/commands/security/threats.js.map +1 -0
  98. package/dist/src/commands/securityagent/setup.d.ts +19 -5
  99. package/dist/src/commands/securityagent/setup.d.ts.map +1 -1
  100. package/dist/src/commands/securityagent/setup.js +25 -189
  101. package/dist/src/commands/securityagent/setup.js.map +1 -1
  102. package/dist/src/dashboard/aws.d.ts +39 -0
  103. package/dist/src/dashboard/aws.d.ts.map +1 -0
  104. package/dist/src/dashboard/aws.js +35 -0
  105. package/dist/src/dashboard/aws.js.map +1 -0
  106. package/dist/src/dashboard/codewatch.d.ts.map +1 -1
  107. package/dist/src/dashboard/codewatch.js +2 -1
  108. package/dist/src/dashboard/codewatch.js.map +1 -1
  109. package/dist/src/dashboard/page.d.ts.map +1 -1
  110. package/dist/src/dashboard/page.js +193 -5
  111. package/dist/src/dashboard/page.js.map +1 -1
  112. package/dist/src/dashboard/payload.d.ts +11 -5
  113. package/dist/src/dashboard/payload.d.ts.map +1 -1
  114. package/dist/src/dashboard/payload.js +7 -2
  115. package/dist/src/dashboard/payload.js.map +1 -1
  116. package/dist/src/dashboard/security.d.ts +130 -0
  117. package/dist/src/dashboard/security.d.ts.map +1 -0
  118. package/dist/src/dashboard/security.js +144 -0
  119. package/dist/src/dashboard/security.js.map +1 -0
  120. package/dist/src/dashboard/setup.d.ts +15 -0
  121. package/dist/src/dashboard/setup.d.ts.map +1 -1
  122. package/dist/src/dashboard/setup.js +20 -3
  123. package/dist/src/dashboard/setup.js.map +1 -1
  124. package/dist/src/dashboard/usage.js +1 -1
  125. package/dist/src/dashboard/usage.js.map +1 -1
  126. package/dist/src/index.d.ts.map +1 -1
  127. package/dist/src/index.js +9 -2
  128. package/dist/src/index.js.map +1 -1
  129. package/dist/src/security/cfn-diff.d.ts +57 -0
  130. package/dist/src/security/cfn-diff.d.ts.map +1 -0
  131. package/dist/src/security/cfn-diff.js +112 -0
  132. package/dist/src/security/cfn-diff.js.map +1 -0
  133. package/dist/src/security/errors.d.ts +45 -0
  134. package/dist/src/security/errors.d.ts.map +1 -0
  135. package/dist/src/security/errors.js +116 -0
  136. package/dist/src/security/errors.js.map +1 -0
  137. package/dist/src/security/marker.d.ts +46 -0
  138. package/dist/src/security/marker.d.ts.map +1 -0
  139. package/dist/src/security/marker.js +120 -0
  140. package/dist/src/security/marker.js.map +1 -0
  141. package/dist/src/security/pentest-dockerfile.d.ts +8 -0
  142. package/dist/src/security/pentest-dockerfile.d.ts.map +1 -0
  143. package/dist/src/security/pentest-dockerfile.js +163 -0
  144. package/dist/src/security/pentest-dockerfile.js.map +1 -0
  145. package/dist/src/security/pentest.d.ts +233 -0
  146. package/dist/src/security/pentest.d.ts.map +1 -0
  147. package/dist/src/security/pentest.js +1057 -0
  148. package/dist/src/security/pentest.js.map +1 -0
  149. package/dist/src/security/repo.d.ts +25 -0
  150. package/dist/src/security/repo.d.ts.map +1 -0
  151. package/dist/src/security/repo.js +38 -0
  152. package/dist/src/security/repo.js.map +1 -0
  153. package/dist/src/security/review.d.ts +202 -0
  154. package/dist/src/security/review.d.ts.map +1 -0
  155. package/dist/src/security/review.js +706 -0
  156. package/dist/src/security/review.js.map +1 -0
  157. package/dist/src/security/setup.d.ts +209 -0
  158. package/dist/src/security/setup.d.ts.map +1 -0
  159. package/dist/src/security/setup.js +742 -0
  160. package/dist/src/security/setup.js.map +1 -0
  161. package/dist/src/security/threat-model.d.ts +133 -0
  162. package/dist/src/security/threat-model.d.ts.map +1 -0
  163. package/dist/src/security/threat-model.js +653 -0
  164. package/dist/src/security/threat-model.js.map +1 -0
  165. package/dist/src/utils/audit-account.d.ts +50 -0
  166. package/dist/src/utils/audit-account.d.ts.map +1 -0
  167. package/dist/src/utils/audit-account.js +69 -0
  168. package/dist/src/utils/audit-account.js.map +1 -0
  169. package/dist/src/utils/audit-iam.d.ts +1 -1
  170. package/dist/src/utils/audit-iam.d.ts.map +1 -1
  171. package/dist/src/utils/audit-iam.js +11 -7
  172. package/dist/src/utils/audit-iam.js.map +1 -1
  173. package/dist/src/utils/exec.d.ts +6 -0
  174. package/dist/src/utils/exec.d.ts.map +1 -1
  175. package/dist/src/utils/exec.js +12 -1
  176. package/dist/src/utils/exec.js.map +1 -1
  177. package/dist/src/utils/otel-sync-schedule.d.ts +19 -0
  178. package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -1
  179. package/dist/src/utils/otel-sync-schedule.js +24 -2
  180. package/dist/src/utils/otel-sync-schedule.js.map +1 -1
  181. package/package.json +3 -3
@@ -0,0 +1,269 @@
1
+ /**
2
+ * `prism-cli aws check`: read-only account checks on the audit framework
3
+ * (utils/audit.ts), in pluggable sections. A section is a name, a heading,
4
+ * the check ids it can return, and a run function; SECTIONS is the registry.
5
+ *
6
+ * Every AWS call here is a read. INDETERMINATE (a denied or failed read) is
7
+ * never counted as a pass.
8
+ */
9
+ import { aws } from '../utils/aws.js';
10
+ import { severityRank } from '../utils/audit.js';
11
+ import { auditAccount, ACCOUNT_AUDIT_IDS } from '../utils/audit-account.js';
12
+ import { configuredSyncUrl } from '../commands/enable/codeburn.js';
13
+ import { collectSecurityStatus, PIPELINE_STACK, } from '../security/setup.js';
14
+ /** `<section>.<id>`: one id space across sections (a check appears in one section only). */
15
+ export const checkId = (section, id) => `${section}.${id}`;
16
+ const call = (c, args, region = c.region) => aws([...args, '--region', region], c.target);
17
+ const why = (r) => r.errorCode || r.raw.split('\n').map((l) => l.trim()).filter(Boolean).pop() || 'unknown error';
18
+ const pass = (b, detail) => ({ ...b, status: 'PASS', detail });
19
+ const fail = (b, detail, remediation) => ({ ...b, status: 'FAIL', detail, remediation });
20
+ /** A read that did not answer. `action` is the IAM action the check needs, when known. */
21
+ const unknown = (b, r, action) => ({
22
+ ...b, status: 'INDETERMINATE',
23
+ detail: `Could not check (${typeof r === 'string' ? r : why(r)}).${action ? ` Needs ${action}.` : ''}`,
24
+ remediation: action ? `Grant ${action} (read-only) and re-run prism-cli aws check.` : undefined,
25
+ });
26
+ // ---------------------------------------------------------------------------
27
+ // bedrock: the bedrock-protection scan-account checks, unchanged
28
+ // ---------------------------------------------------------------------------
29
+ export const bedrockSection = {
30
+ name: 'bedrock',
31
+ heading: 'Bedrock protection (the bedrock-protection scan-account checks)',
32
+ ids: ACCOUNT_AUDIT_IDS,
33
+ run(c) {
34
+ // generateCredentialReport false: aws check never calls iam generate-credential-report.
35
+ return auditAccount(c.target, c.account, c.region, { maxKeyAge: 90, unusedDays: 90, runIam: true, runBedrock: true, generateCredentialReport: false })
36
+ .map((f) => ({ ...f, id: checkId('bedrock', f.id), category: 'bedrock' }));
37
+ },
38
+ };
39
+ // ---------------------------------------------------------------------------
40
+ // prism-setup
41
+ // ---------------------------------------------------------------------------
42
+ const PS = (id, title, severity) => ({ id: checkId('prism-setup', id), category: 'prism-setup', title, severity });
43
+ const GITHUB_OIDC_HOST = 'token.actions.githubusercontent.com';
44
+ /** Role names bootstrapper setup-github-oidc / setup-gitlab-oidc create. */
45
+ const CI_ROLE = /^(GitHubActions|GitLabCI)-/;
46
+ export function metricsPipeline(c) {
47
+ const b = PS('metrics-pipeline', `PRISM metrics pipeline stack (${PIPELINE_STACK})`, 'MEDIUM');
48
+ const r = call(c, ['cloudformation', 'describe-stacks', '--stack-name', PIPELINE_STACK]);
49
+ const fix = `Deploy the metrics pipeline (infra/, cdk deploy ${PIPELINE_STACK}); see the PRISM workshop setup guide.`;
50
+ if (!r.ok)
51
+ return /does not exist/.test(r.raw) ? fail(b, `${PIPELINE_STACK} is not deployed in ${c.region}.`, fix) : unknown(b, r, 'cloudformation:DescribeStacks');
52
+ const status = String(r.json?.Stacks?.[0]?.StackStatus || 'UNKNOWN');
53
+ if (/_COMPLETE$/.test(status) && !/ROLLBACK_COMPLETE$|^DELETE_COMPLETE$/.test(status))
54
+ return pass(b, `${PIPELINE_STACK} is ${status} in ${c.region}.`);
55
+ return fail(b, `${PIPELINE_STACK} is ${status} in ${c.region}.`, fix);
56
+ }
57
+ /** Maps the enable security --status rows to findings. A row that never appeared (the report stopped) is INDETERMINATE. */
58
+ export function securityAgent(c) {
59
+ const { rows } = collectSecurityStatus(c.security);
60
+ const row = (label) => rows.find((r) => r[1] === label);
61
+ const stopped = rows.find((r) => r[1] === 'Stopped' || (r[1] === 'Credentials' && r[0] !== 'ok'));
62
+ const fix = 'Run prism-cli enable security (it shows a diff and asks before any change).';
63
+ const one = (b, r) => {
64
+ if (!r)
65
+ return unknown(b, stopped ? stopped[2] : 'not reached', undefined);
66
+ if (r[0] === 'ok')
67
+ return pass(b, r[2]);
68
+ if (r[0] === 'unknown')
69
+ return unknown(b, r[2]);
70
+ return fail(b, r[2], fix);
71
+ };
72
+ const ssm = ['SSM agent-space-id', 'SSM scan-bucket', 'SSM service-role-arn'].map(row);
73
+ const ssmB = PS('security-agent-ssm', 'Security Agent SSM parameters (/prism/continuum/*)', 'MEDIUM');
74
+ const ssmF = ssm.some((r) => !r) ? one(ssmB, undefined)
75
+ : ssm.every((r) => r[0] === 'ok') ? pass(ssmB, ssm.map((r) => r[2]).join('; '))
76
+ : fail(ssmB, ssm.filter((r) => r[0] !== 'ok').map((r) => r[2]).join('; '), fix);
77
+ return [
78
+ one(PS('security-agent-stack', 'Security Agent stack (PrismD1SecurityAgent or pipeline-hosted)', 'MEDIUM'), row('Stack')),
79
+ ssmF,
80
+ one(PS('scan-bucket-listed', 'Scan bucket listed on the Security Agent space', 'LOW'), row('Scan bucket on agent space')),
81
+ ];
82
+ }
83
+ export function ciOidcRole(c) {
84
+ const b = PS('ci-oidc-role', 'GitHub/GitLab OIDC provider and CI role', 'MEDIUM');
85
+ const fix = 'Run prism-cli bootstrapper setup-github-oidc (or setup-gitlab-oidc) for the repo whose CI publishes PRISM metrics.';
86
+ const p = call(c, ['iam', 'list-open-id-connect-providers']);
87
+ if (!p.ok)
88
+ return unknown(b, p, 'iam:ListOpenIDConnectProviders');
89
+ const arns = (p.json?.OpenIDConnectProviderList || []).map((x) => String(x?.Arn || ''));
90
+ const providers = arns.filter((a) => a.endsWith(`/${GITHUB_OIDC_HOST}`) || /gitlab/i.test(a)).map((a) => a.split('oidc-provider/')[1]);
91
+ const r = call(c, ['iam', 'list-roles', '--query', 'Roles[].RoleName']);
92
+ if (!r.ok)
93
+ return unknown(b, r, 'iam:ListRoles');
94
+ const roles = (Array.isArray(r.json) ? r.json : []).map(String).filter((n) => CI_ROLE.test(n));
95
+ if (providers.length && roles.length)
96
+ return pass(b, `OIDC provider ${providers.join(', ')}; CI role ${roles.slice(0, 3).join(', ')}${roles.length > 3 ? ` and ${roles.length - 3} more` : ''}.`);
97
+ const missing = [providers.length ? '' : 'no GitHub or GitLab OIDC provider', roles.length ? '' : 'no GitHubActions-* or GitLabCI-* role'].filter(Boolean);
98
+ return fail(b, `${missing.join(' and ')}, so CI cannot publish PRISM metrics with short-lived credentials.`, fix);
99
+ }
100
+ /** Local only: the endpoint codeburn syncs to (~/.config/codeburn/sync.json). No AWS call. */
101
+ export function codeburnSync(c) {
102
+ const b = PS('codeburn-sync', 'codeburn sync endpoint configured on this machine', 'LOW');
103
+ const url = configuredSyncUrl(c.home);
104
+ if (url === null)
105
+ return fail(b, 'codeburn sync is not set up here, so this machine sends no usage telemetry to the PRISM collector.', 'Run prism-cli enable codeburn.');
106
+ if (!url)
107
+ return unknown(b, 'the codeburn sync config could not be read');
108
+ return pass(b, `codeburn syncs to ${url}.`);
109
+ }
110
+ export const prismSetupSection = {
111
+ name: 'prism-setup',
112
+ heading: 'PRISM setup',
113
+ ids: ['metrics-pipeline', 'security-agent-stack', 'security-agent-ssm', 'scan-bucket-listed', 'ci-oidc-role', 'codeburn-sync'],
114
+ run: (c) => [metricsPipeline(c), ...securityAgent(c), ciOidcRole(c), codeburnSync(c)],
115
+ };
116
+ // ---------------------------------------------------------------------------
117
+ // baseline
118
+ // ---------------------------------------------------------------------------
119
+ const BL = (id, title, severity) => ({ id: checkId('baseline', id), category: 'baseline', title, severity });
120
+ export function cloudTrail(c) {
121
+ const b = BL('cloudtrail-multiregion', 'CloudTrail: a multi-region trail that is logging', 'HIGH');
122
+ const fix = 'Create a multi-region trail (aws cloudtrail create-trail --is-multi-region-trail, then start-logging), or an organization trail from the management account.';
123
+ const r = call(c, ['cloudtrail', 'describe-trails']);
124
+ if (!r.ok)
125
+ return unknown(b, r, 'cloudtrail:DescribeTrails');
126
+ const multi = (r.json?.trailList || []).filter((t) => t?.IsMultiRegionTrail);
127
+ if (!multi.length)
128
+ return fail(b, 'No multi-region trail, so API activity in other regions is not recorded.', fix);
129
+ let readable = 0;
130
+ for (const t of multi) {
131
+ const s = call(c, ['cloudtrail', 'get-trail-status', '--name', String(t.TrailARN || t.Name)], String(t.HomeRegion || c.region));
132
+ if (!s.ok)
133
+ continue;
134
+ readable++;
135
+ if (s.json?.IsLogging)
136
+ return pass(b, `${t.Name} is multi-region and logging.`);
137
+ }
138
+ if (!readable)
139
+ return unknown(b, 'get-trail-status was denied for every multi-region trail', 'cloudtrail:GetTrailStatus');
140
+ return fail(b, `Multi-region trail(s) ${multi.map((t) => t.Name).join(', ')} exist but none is logging.`, 'Start logging: aws cloudtrail start-logging --name <trail>.');
141
+ }
142
+ export function guardDuty(c) {
143
+ const b = BL('guardduty', `GuardDuty detector enabled in ${c.region}`, 'HIGH');
144
+ const fix = `Enable GuardDuty in ${c.region} (aws guardduty create-detector --enable), ideally org-wide from a delegated administrator.`;
145
+ const r = call(c, ['guardduty', 'list-detectors']);
146
+ if (!r.ok)
147
+ return unknown(b, r, 'guardduty:ListDetectors');
148
+ const ids = r.json?.DetectorIds || [];
149
+ if (!ids.length)
150
+ return fail(b, `No GuardDuty detector in ${c.region}.`, fix);
151
+ const d = call(c, ['guardduty', 'get-detector', '--detector-id', ids[0]]);
152
+ if (!d.ok)
153
+ return unknown(b, d, 'guardduty:GetDetector');
154
+ return d.json?.Status === 'ENABLED' ? pass(b, `Detector ${ids[0]} is enabled.`) : fail(b, `Detector ${ids[0]} is ${d.json?.Status || 'not enabled'}.`, fix);
155
+ }
156
+ export function securityHub(c) {
157
+ const b = BL('securityhub', `Security Hub enabled in ${c.region}`, 'MEDIUM');
158
+ const r = call(c, ['securityhub', 'describe-hub']);
159
+ if (r.ok)
160
+ return pass(b, `Security Hub is enabled${r.json?.SubscribedAt ? ` (since ${r.json.SubscribedAt})` : ''}.`);
161
+ if (/^(InvalidAccessException|ResourceNotFoundException)$/.test(r.errorCode)) {
162
+ return fail(b, `Security Hub is not enabled in ${c.region}.`, `Enable Security Hub in ${c.region} with the AWS Foundational Security Best Practices standard.`);
163
+ }
164
+ return unknown(b, r, 'securityhub:DescribeHub');
165
+ }
166
+ export function accessAnalyzer(c) {
167
+ const b = BL('access-analyzer', `IAM Access Analyzer in ${c.region}`, 'MEDIUM');
168
+ const r = call(c, ['accessanalyzer', 'list-analyzers']);
169
+ if (!r.ok)
170
+ return unknown(b, r, 'access-analyzer:ListAnalyzers');
171
+ const active = (r.json?.analyzers || []).filter((a) => a?.status === 'ACTIVE');
172
+ return active.length ? pass(b, `Analyzer ${active[0].name} (${active[0].type}) is active.`)
173
+ : fail(b, `No active Access Analyzer in ${c.region}, so resources shared outside the account are not flagged.`, `Create one: aws accessanalyzer create-analyzer --analyzer-name prism --type ACCOUNT --region ${c.region}.`);
174
+ }
175
+ // Root MFA is not repeated here: the bedrock section's bedrock.root-mfa reads the same
176
+ // iam get-account-summary, and a second copy listed the same fix twice.
177
+ export function budget(c) {
178
+ const b = BL('budget', 'At least one AWS Budget', 'MEDIUM');
179
+ const r = call(c, ['budgets', 'describe-budgets', '--account-id', c.account]);
180
+ if (!r.ok)
181
+ return unknown(b, r, 'budgets:ViewBudget');
182
+ const n = (r.json?.Budgets || []).length;
183
+ return n ? pass(b, `${n} budget(s) defined.`) : fail(b, 'No budgets, so unexpected spend raises no alert.', 'Create a monthly cost budget with 80% and 100% alerts (Billing console > Budgets).');
184
+ }
185
+ export function s3PublicAccess(c) {
186
+ const b = BL('s3-account-bpa', 'S3 Block Public Access at the account level', 'HIGH');
187
+ const fix = `Turn on all four settings: aws s3control put-public-access-block --account-id ${c.account} --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true.`;
188
+ const r = call(c, ['s3control', 'get-public-access-block', '--account-id', c.account]);
189
+ if (!r.ok)
190
+ return r.errorCode === 'NoSuchPublicAccessBlockConfiguration' ? fail(b, 'No account-level Block Public Access configuration.', fix) : unknown(b, r, 's3:GetAccountPublicAccessBlock');
191
+ const cfg = r.json?.PublicAccessBlockConfiguration ?? {};
192
+ const off = ['BlockPublicAcls', 'IgnorePublicAcls', 'BlockPublicPolicy', 'RestrictPublicBuckets'].filter((k) => cfg[k] !== true);
193
+ return off.length ? fail(b, `Off: ${off.join(', ')}.`, fix) : pass(b, 'All four account-level settings are on.');
194
+ }
195
+ export function ebsEncryption(c) {
196
+ const b = BL('ebs-default-encryption', `EBS encryption by default in ${c.region}`, 'MEDIUM');
197
+ const r = call(c, ['ec2', 'get-ebs-encryption-by-default']);
198
+ if (!r.ok)
199
+ return unknown(b, r, 'ec2:GetEbsEncryptionByDefault');
200
+ return r.json?.EbsEncryptionByDefault === true ? pass(b, 'New EBS volumes are encrypted by default.')
201
+ : fail(b, `New EBS volumes in ${c.region} are not encrypted by default.`, `aws ec2 enable-ebs-encryption-by-default --region ${c.region}.`);
202
+ }
203
+ export const baselineSection = {
204
+ name: 'baseline',
205
+ heading: 'Account baseline',
206
+ ids: ['cloudtrail-multiregion', 'guardduty', 'securityhub', 'access-analyzer', 'budget', 's3-account-bpa', 'ebs-default-encryption'],
207
+ run: (c) => [cloudTrail(c), guardDuty(c), securityHub(c), accessAnalyzer(c), budget(c), s3PublicAccess(c), ebsEncryption(c)],
208
+ };
209
+ // ---------------------------------------------------------------------------
210
+ // startup-advisor: placeholder until how it is consumed (and its license) is known
211
+ // ---------------------------------------------------------------------------
212
+ export const startupAdvisorSection = {
213
+ name: 'startup-advisor',
214
+ heading: 'Startup Advisor',
215
+ ids: ['not-integrated'],
216
+ run: () => [{
217
+ id: checkId('startup-advisor', 'not-integrated'), category: 'startup-advisor', title: 'Startup Advisor account checks',
218
+ status: 'INDETERMINATE', severity: 'INFO',
219
+ detail: 'Not integrated yet: how PRISM consumes Startup Advisor, and under what license, is still open.',
220
+ }],
221
+ };
222
+ export const SECTIONS = [bedrockSection, prismSetupSection, baselineSection, startupAdvisorSection];
223
+ /** Every full check id any section can return. */
224
+ export const ALL_CHECK_IDS = SECTIONS.flatMap((s) => s.ids.map((id) => checkId(s.name, id)));
225
+ /** The sections named by --section (all when none), or an error naming the valid ones. */
226
+ export function selectSections(names) {
227
+ if (!names?.length)
228
+ return SECTIONS;
229
+ const bad = names.filter((n) => !SECTIONS.some((s) => s.name === n));
230
+ if (bad.length)
231
+ return { error: `unknown --section ${bad.join(', ')}; choose from ${SECTIONS.map((s) => s.name).join(', ')}` };
232
+ return SECTIONS.filter((s) => names.includes(s.name));
233
+ }
234
+ export function countFindings(findings) {
235
+ return {
236
+ pass: findings.filter((f) => f.status === 'PASS').length,
237
+ fail: findings.filter((f) => f.status === 'FAIL').length,
238
+ indeterminate: findings.filter((f) => f.status === 'INDETERMINATE').length,
239
+ };
240
+ }
241
+ export function failBySeverity(findings) {
242
+ const out = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0, INFO: 0 };
243
+ for (const f of findings)
244
+ if (f.status === 'FAIL')
245
+ out[f.severity]++;
246
+ return out;
247
+ }
248
+ /** FAIL findings at or above `failOn` (none when failOn is null). */
249
+ export function breaching(findings, failOn) {
250
+ if (!failOn)
251
+ return [];
252
+ return findings.filter((f) => f.status === 'FAIL' && severityRank(f.severity) >= severityRank(failOn));
253
+ }
254
+ /** A read-only enable-security context for collectSecurityStatus. Repo rows are skipped (git reports no repo). */
255
+ export function securityContext(opts, aws, env, awsVersion, log) {
256
+ const unused = () => { throw new Error('internal: not available in aws check'); };
257
+ const deps = {
258
+ aws, env, awsVersion, log,
259
+ configRegion: () => null,
260
+ cdk: { synth: unused, diff: unused, deploy: unused },
261
+ git: () => ({ ok: false, stdout: '', stderr: 'not used by aws check' }),
262
+ makeTempDir: unused,
263
+ isTTY: false,
264
+ ask: async () => '',
265
+ now: () => new Date(),
266
+ };
267
+ return { opts, deps, cliVersion: awsVersion(), readOnly: true };
268
+ }
269
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/aws/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import type { AwsResult } from '../utils/aws.js';
2
+ import type { RunResult } from '../utils/exec.js';
3
+ export interface ConnectOptions {
4
+ profile?: string;
5
+ region?: string;
6
+ /** Write (or clear) the per-repo file instead of the per-user one. */
7
+ repo?: boolean;
8
+ status?: boolean;
9
+ clear?: boolean;
10
+ }
11
+ export interface ConnectDeps {
12
+ /** A read-only `aws <args>` call as `profile` in `region` (JSON output). */
13
+ aws(args: string[], profile: string, region: string): AwsResult;
14
+ listProfiles(): string[];
15
+ configRegion(profile?: string): string | null;
16
+ git(args: string[]): RunResult;
17
+ env: NodeJS.ProcessEnv;
18
+ home: string;
19
+ cwd(): string;
20
+ isTTY: boolean;
21
+ ask(question: string): Promise<string>;
22
+ log(line?: string): void;
23
+ now(): Date;
24
+ }
25
+ export declare const CONNECT_NOTICE = "Read-only (aws connect): it checks the profile with STS and reads the account alias, Organizations and IAM; nothing in AWS is changed. No credentials are stored, only the profile name and region.";
26
+ export interface Identity {
27
+ account: string;
28
+ arn: string;
29
+ }
30
+ export type OrgRole = {
31
+ kind: 'management';
32
+ orgId: string;
33
+ } | {
34
+ kind: 'member';
35
+ orgId: string;
36
+ } | {
37
+ kind: 'none';
38
+ } | {
39
+ kind: 'unknown';
40
+ reason: string;
41
+ };
42
+ export interface AccessLevel {
43
+ level: 'admin' | 'read-only' | 'unknown';
44
+ basis: string;
45
+ }
46
+ export declare function callerIdentity(d: ConnectDeps, profile: string, region: string): Identity | {
47
+ error: string;
48
+ };
49
+ export declare function accountAlias(d: ConnectDeps, profile: string, region: string): string | null;
50
+ /** Whether the account is its organization's management account. AccessDenied is "unknown", never "no". */
51
+ export declare function orgRole(d: ConnectDeps, profile: string, region: string, account: string): OrgRole;
52
+ /** The principal behind a caller ARN: an assumed role, an IAM user, or root. */
53
+ export declare function principalOf(arn: string): {
54
+ kind: 'role' | 'user' | 'root' | 'other';
55
+ name: string;
56
+ };
57
+ /**
58
+ * Admin or read-only, as far as can be told without simulating policies:
59
+ * the attached managed policies when they can be read, else the role or user
60
+ * name. "unknown" whenever neither is conclusive.
61
+ */
62
+ export declare function accessLevel(d: ConnectDeps, profile: string, region: string, arn: string): AccessLevel;
63
+ /** Runs `aws connect`. Returns the exit code. */
64
+ export declare function awsConnect(o: ConnectOptions, d: ConnectDeps): Promise<number>;
65
+ //# sourceMappingURL=connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../../src/aws/connect.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQlD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAChE,YAAY,IAAI,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,IAAI,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,GAAG,IAAI,IAAI,CAAC;CACb;AAED,eAAO,MAAM,cAAc,wMAAwM,CAAC;AAEpO,MAAM,WAAW,QAAQ;IAAG,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAC1D,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzJ,MAAM,WAAW,WAAW;IAAG,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AAIxF,wBAAgB,cAAc,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAK5G;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3F;AAED,2GAA2G;AAC3G,wBAAgB,OAAO,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAUjG;AAOD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAOnG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAarG;AA8ED,iDAAiD;AACjD,wBAAsB,UAAU,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAsDnF"}
@@ -0,0 +1,250 @@
1
+ /**
2
+ * `prism-cli aws connect`: choose the AWS profile and region the other AWS
3
+ * commands default to, verify them, and save the choice. Read-only in AWS;
4
+ * stores no credentials (see connection.ts for the files and precedence).
5
+ */
6
+ import { existsSync } from 'node:fs';
7
+ import { ensureMarkerIgnored } from '../security/marker.js';
8
+ import { accountChangeWarning, applyConnection, clearConnectionFile, connectionLabel, ENV_CREDENTIAL_VARS, loadConnection, PROFILE_RE, readConnectionFile, REGION_RE, REPO_CONNECTION_PATH, repoConnectionPath, repoRootOf, userConnectionPath, writeConnectionFile, } from './connection.js';
9
+ export const CONNECT_NOTICE = 'Read-only (aws connect): it checks the profile with STS and reads the account alias, Organizations and IAM; nothing in AWS is changed. No credentials are stored, only the profile name and region.';
10
+ const reason = (r) => r.errorCode || r.raw.split('\n').map((l) => l.trim()).filter(Boolean).pop() || 'unknown error';
11
+ export function callerIdentity(d, profile, region) {
12
+ const r = d.aws(['sts', 'get-caller-identity'], profile, region);
13
+ if (!r.ok)
14
+ return { error: reason(r) };
15
+ const account = String(r.json?.Account || '');
16
+ return account ? { account, arn: String(r.json?.Arn || '') } : { error: 'get-caller-identity returned no account' };
17
+ }
18
+ export function accountAlias(d, profile, region) {
19
+ const r = d.aws(['iam', 'list-account-aliases'], profile, region);
20
+ const a = r.ok && Array.isArray(r.json?.AccountAliases) ? r.json.AccountAliases[0] : null;
21
+ return a ? String(a) : null;
22
+ }
23
+ /** Whether the account is its organization's management account. AccessDenied is "unknown", never "no". */
24
+ export function orgRole(d, profile, region, account) {
25
+ const r = d.aws(['organizations', 'describe-organization'], profile, region);
26
+ if (r.ok) {
27
+ const org = r.json?.Organization ?? {};
28
+ // The API names the management account's id field MasterAccountId.
29
+ const managementId = String(org.MasterAccountId || '');
30
+ return managementId === account ? { kind: 'management', orgId: String(org.Id || '') } : { kind: 'member', orgId: String(org.Id || '') };
31
+ }
32
+ if (r.errorCode === 'AWSOrganizationsNotInUseException')
33
+ return { kind: 'none' };
34
+ return { kind: 'unknown', reason: reason(r) };
35
+ }
36
+ const ADMIN_POLICY = /^(AdministratorAccess|PowerUserAccess)$|FullAccess$/;
37
+ const READ_POLICY = /^(ReadOnlyAccess|ViewOnlyAccess|SecurityAudit)$|ReadOnly/;
38
+ const ADMIN_NAME = /admin|poweruser|fullaccess/i;
39
+ const READ_NAME = /read-?only|view-?only|audit/i;
40
+ /** The principal behind a caller ARN: an assumed role, an IAM user, or root. */
41
+ export function principalOf(arn) {
42
+ const m = /^arn:[^:]+:(sts|iam)::\d{12}:(assumed-role|user|root|role)(?:\/(.*))?$/.exec(arn);
43
+ if (!m)
44
+ return { kind: 'other', name: '' };
45
+ if (m[2] === 'root')
46
+ return { kind: 'root', name: 'root' };
47
+ const parts = (m[3] || '').split('/');
48
+ if (m[2] === 'assumed-role' || m[2] === 'role')
49
+ return { kind: 'role', name: m[2] === 'assumed-role' ? parts[0] : parts[parts.length - 1] };
50
+ return { kind: 'user', name: parts[parts.length - 1] };
51
+ }
52
+ /**
53
+ * Admin or read-only, as far as can be told without simulating policies:
54
+ * the attached managed policies when they can be read, else the role or user
55
+ * name. "unknown" whenever neither is conclusive.
56
+ */
57
+ export function accessLevel(d, profile, region, arn) {
58
+ const p = principalOf(arn);
59
+ if (p.kind === 'root')
60
+ return { level: 'admin', basis: 'the root user' };
61
+ if (p.kind === 'other' || !p.name)
62
+ return { level: 'unknown', basis: 'the caller ARN has an unexpected form' };
63
+ const call = p.kind === 'role' ? ['iam', 'list-attached-role-policies', '--role-name', p.name] : ['iam', 'list-attached-user-policies', '--user-name', p.name];
64
+ const r = d.aws(call, profile, region);
65
+ const names = r.ok ? (r.json?.AttachedPolicies || []).map((x) => String(x?.PolicyName || '')).filter(Boolean) : [];
66
+ if (names.some((n) => ADMIN_POLICY.test(n)))
67
+ return { level: 'admin', basis: `attached policy ${names.find((n) => ADMIN_POLICY.test(n))}` };
68
+ if (names.length && names.every((n) => READ_POLICY.test(n)))
69
+ return { level: 'read-only', basis: `attached policies ${names.join(', ')}` };
70
+ const why = r.ok ? (names.length ? `custom policies (${names.join(', ')})` : 'no managed policies attached') : `policies not readable (${reason(r)})`;
71
+ if (ADMIN_NAME.test(p.name))
72
+ return { level: 'admin', basis: `the ${p.kind} name ${p.name}; ${why}` };
73
+ if (READ_NAME.test(p.name))
74
+ return { level: 'read-only', basis: `the ${p.kind} name ${p.name}; ${why}` };
75
+ return { level: 'unknown', basis: why };
76
+ }
77
+ const orgText = (o) => o.kind === 'management' ? `yes, the management account of ${o.orgId}`
78
+ : o.kind === 'member' ? `no, a member account of ${o.orgId}` : o.kind === 'none' ? 'no, not in an organization' : `unknown (${o.reason})`;
79
+ async function chooseProfile(o, d, saved) {
80
+ if (o.profile)
81
+ return o.profile;
82
+ const profiles = d.listProfiles();
83
+ if (!d.isTTY) {
84
+ if (d.env.AWS_PROFILE)
85
+ return d.env.AWS_PROFILE;
86
+ return { error: 'no --profile given and there is no terminal to choose on. Pass --profile <name> (see aws configure list-profiles).' };
87
+ }
88
+ if (!profiles.length)
89
+ return { error: 'no AWS profiles are configured. Create one with aws configure sso (or aws configure --profile <name>), then re-run.' };
90
+ const preferred = d.env.AWS_PROFILE || saved?.profile || (profiles.includes('default') ? 'default' : profiles[0]);
91
+ const def = Math.max(0, profiles.indexOf(preferred));
92
+ d.log('AWS profiles (from aws configure list-profiles):');
93
+ profiles.forEach((p, i) => d.log(` ${i + 1}) ${p}${i === def ? ' (default)' : ''}`));
94
+ const a = (await d.ask(`Profile [${def + 1}]: `)).trim();
95
+ if (!a)
96
+ return profiles[def];
97
+ const n = Number.parseInt(a, 10);
98
+ if (String(n) === a && n >= 1 && n <= profiles.length)
99
+ return profiles[n - 1];
100
+ return profiles.includes(a) ? a : { error: `"${a}" is not one of the listed profiles.` };
101
+ }
102
+ async function chooseRegion(o, d, profile) {
103
+ if (o.region)
104
+ return o.region;
105
+ const def = d.env.AWS_REGION || d.env.AWS_DEFAULT_REGION || d.configRegion(profile) || '';
106
+ if (!d.isTTY)
107
+ return def || { error: `no --region given and profile ${profile} has no configured region. Pass --region <region>.` };
108
+ const a = (await d.ask(`Region${def ? ` [${def}]` : ''}: `)).trim();
109
+ return a || def || { error: 'a region is required.' };
110
+ }
111
+ function repoRoot(d) {
112
+ return repoRootOf(d.cwd(), d.git);
113
+ }
114
+ /** `--clear`: removes the user file, or the repo file with --repo. */
115
+ function clear(o, d) {
116
+ let path;
117
+ if (o.repo) {
118
+ const root = repoRoot(d);
119
+ if (!root) {
120
+ d.log('Error: --repo needs to run inside a git repository.');
121
+ return 1;
122
+ }
123
+ path = repoConnectionPath(root);
124
+ }
125
+ else
126
+ path = userConnectionPath(d.home);
127
+ d.log(clearConnectionFile(path) ? `Removed ${path}. Nothing in AWS was changed.` : `Nothing to clear: ${path} does not exist.`);
128
+ return 0;
129
+ }
130
+ function describeFile(label, path, d) {
131
+ const c = readConnectionFile(path);
132
+ if (c)
133
+ d.log(` ${label}: ${path}\n profile ${c.profile}, region ${c.region}, account ${c.account}${c.alias ? ` (${c.alias})` : ''}, verified ${c.verifiedAt || 'unknown'}`);
134
+ else
135
+ d.log(` ${label}: ${path} (${existsSync(path) ? 'not a valid connection; ignored. Re-run prism-cli aws connect' : 'not set'})`);
136
+ }
137
+ /** `--status`: what is saved, which file applies, and whether it still validates. */
138
+ function status(d) {
139
+ const root = repoRoot(d);
140
+ d.log('Saved AWS connection:');
141
+ describeFile('user', userConnectionPath(d.home), d);
142
+ if (root)
143
+ describeFile('repo', repoConnectionPath(root), d);
144
+ else
145
+ d.log(' repo: (not in a git repository)');
146
+ const saved = loadConnection(d.home, root);
147
+ if (!saved) {
148
+ d.log('');
149
+ d.log('No saved connection: AWS commands use the default credential chain. Save one with: prism-cli aws connect');
150
+ return 0;
151
+ }
152
+ const applied = applyConnection({}, saved, d.env);
153
+ d.log('');
154
+ if (applied.profileSource)
155
+ d.log(`In use: profile ${saved.profile}, region ${saved.region} (${connectionLabel(saved)}, ${saved.path})`);
156
+ else {
157
+ const v = ENV_CREDENTIAL_VARS.find((k) => d.env[k]);
158
+ d.log(`Not in use for credentials: ${v} is set, and the environment wins over the saved connection${applied.connection ? ` (the saved region ${saved.region} still applies)` : ''}.`);
159
+ }
160
+ if (d.env.AWS_REGION || d.env.AWS_DEFAULT_REGION)
161
+ d.log(`Region note: ${d.env.AWS_REGION ? 'AWS_REGION' : 'AWS_DEFAULT_REGION'} is set and wins over the saved region.`);
162
+ const id = callerIdentity(d, saved.profile, saved.region);
163
+ if ('error' in id) {
164
+ d.log(`Validation: FAILED for profile ${saved.profile}: ${id.error}. Sign in again (e.g. aws sso login --profile ${saved.profile}) or re-run prism-cli aws connect.`);
165
+ return 1;
166
+ }
167
+ const w = accountChangeWarning(saved, id.account);
168
+ d.log(w ?? `Validation: ok, profile ${saved.profile} is account ${id.account} as saved (caller ${id.arn}).`);
169
+ return w ? 1 : 0;
170
+ }
171
+ /** Runs `aws connect`. Returns the exit code. */
172
+ export async function awsConnect(o, d) {
173
+ if (o.status && o.clear) {
174
+ d.log('Error: --status and --clear cannot be combined.');
175
+ return 1;
176
+ }
177
+ if (o.clear)
178
+ return clear(o, d);
179
+ d.log(CONNECT_NOTICE);
180
+ d.log('');
181
+ if (o.status)
182
+ return status(d);
183
+ const root = repoRoot(d);
184
+ if (o.repo && !root) {
185
+ d.log('Error: --repo needs to run inside a git repository.');
186
+ return 1;
187
+ }
188
+ const before = loadConnection(d.home, root);
189
+ const profile = await chooseProfile(o, d, before);
190
+ if (typeof profile !== 'string') {
191
+ d.log(`Error: ${profile.error}`);
192
+ return 1;
193
+ }
194
+ if (!PROFILE_RE.test(profile)) {
195
+ d.log(`Error: "${profile}" is not a valid profile name.`);
196
+ return 1;
197
+ }
198
+ const known = d.listProfiles();
199
+ if (known.length && !known.includes(profile)) {
200
+ d.log(`Error: profile ${profile} is not configured here (aws configure list-profiles lists: ${known.join(', ')}).`);
201
+ return 1;
202
+ }
203
+ const region = await chooseRegion(o, d, profile);
204
+ if (typeof region !== 'string') {
205
+ d.log(`Error: ${region.error}`);
206
+ return 1;
207
+ }
208
+ if (!REGION_RE.test(region)) {
209
+ d.log(`Error: "${region}" is not a valid AWS region name (e.g. us-west-2).`);
210
+ return 1;
211
+ }
212
+ const id = callerIdentity(d, profile, region);
213
+ if ('error' in id) {
214
+ d.log(`Error: profile ${profile} does not validate: ${id.error}. Sign in (e.g. aws sso login --profile ${profile}) and re-run. Nothing was saved.`);
215
+ return 1;
216
+ }
217
+ const alias = accountAlias(d, profile, region);
218
+ const org = orgRole(d, profile, region, id.account);
219
+ const access = accessLevel(d, profile, region, id.arn);
220
+ d.log(`Profile: ${profile}`);
221
+ d.log(`Region: ${region}`);
222
+ d.log(`Account: ${id.account}${alias ? ` (${alias})` : ' (no account alias)'}`);
223
+ d.log(`Caller: ${id.arn || 'unknown'}`);
224
+ d.log(`Org management account: ${orgText(org)}`);
225
+ d.log(`Access: ${access.level} (${access.basis})`);
226
+ if (access.level === 'admin')
227
+ d.log(' prism-cli aws check and aws recommend only need read access; a read-only profile is enough for them.');
228
+ const path = o.repo && root ? repoConnectionPath(root) : userConnectionPath(d.home);
229
+ const prev = readConnectionFile(path);
230
+ if (prev && prev.profile === profile && prev.account !== id.account) {
231
+ d.log(`Warning: profile ${profile} was saved as account ${prev.account}; it now resolves to account ${id.account}.`);
232
+ }
233
+ const conn = { profile, region, account: id.account, alias, verifiedAt: d.now().toISOString() };
234
+ if (o.repo && root) {
235
+ const excluded = ensureMarkerIgnored(root, d.git, REPO_CONNECTION_PATH, 'prism-cli aws connect');
236
+ if (excluded)
237
+ d.log(`Added ${REPO_CONNECTION_PATH} to ${excluded} so git ignores it in this clone.`);
238
+ }
239
+ writeConnectionFile(path, conn);
240
+ d.log('');
241
+ d.log(`Saved ${path} (profile name, region, account and alias; no credentials).`);
242
+ d.log(`AWS commands now default to profile ${profile} in ${region}${o.repo ? ' in this repo' : ''}. --profile/--region and AWS_PROFILE/AWS_REGION still win.`);
243
+ const env = ENV_CREDENTIAL_VARS.find((k) => d.env[k]);
244
+ if (env && d.env.AWS_PROFILE !== profile)
245
+ d.log(`Note: ${env} is set in this shell, so it wins here until it is unset.`);
246
+ if (!o.repo && root && readConnectionFile(repoConnectionPath(root)))
247
+ d.log(`Note: this repo has its own ${REPO_CONNECTION_PATH}, which wins over the user file here.`);
248
+ return 0;
249
+ }
250
+ //# sourceMappingURL=connect.js.map