@prism-d1/cli 1.0.94 → 1.0.95

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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Audit the AWS account side of Bedrock protection.
3
+ *
4
+ * LLMjacking is credential theft aimed at model inference: an attacker obtains a
5
+ * long-lived AWS key and burns it on Bedrock, where the marginal cost per request
6
+ * is high enough that one compromised key can run five figures in days. The
7
+ * account-side exposure is therefore two-sided, and both halves are audited here
8
+ * because a finding in either one alone understates the risk:
9
+ *
10
+ * - the way in -- IAM credential hygiene (audit-iam.ts): what can be
11
+ * stolen, and how long it has been sitting there
12
+ * - the blast radius -- Bedrock spend guardrails (audit-bedrock.ts): what
13
+ * bounds the damage, how fast you find out, and whether
14
+ * you can attribute it afterwards
15
+ *
16
+ * Perfect hygiene with no spend ceiling still permits an unbounded bill from a
17
+ * key leaked any other way; a tight budget over a decade-old idle admin key
18
+ * still invites the incident. Reporting them together is the point.
19
+ *
20
+ * The repository side -- whether a credential is already committed -- is
21
+ * `bedrock-protection scan-repo`.
22
+ *
23
+ * Audit-only. Every AWS call is a read except the one documented at
24
+ * `credentialReport()` in audit-iam.ts, which generates an IAM report artifact
25
+ * and modifies no resource.
26
+ */
27
+ declare const _default: {
28
+ description: string;
29
+ options: {
30
+ flags: string;
31
+ description: string;
32
+ }[];
33
+ action(opts: {
34
+ region?: string;
35
+ profile?: string;
36
+ maxKeyAge?: string;
37
+ unusedDays?: string;
38
+ iamOnly?: boolean;
39
+ bedrockOnly?: boolean;
40
+ json?: boolean;
41
+ failOn?: string;
42
+ }): Promise<void>;
43
+ };
44
+ export default _default;
45
+ //# sourceMappingURL=scan-account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-account.d.ts","sourceRoot":"","sources":["../../../../src/commands/bedrock-protection/scan-account.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;;;;;;iBAckB;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC3E;;AAfH,wBA8EE"}
@@ -0,0 +1,105 @@
1
+ import { resolveAccount, PROFILE_OPTION } from '../../utils/aws.js';
2
+ import { DEFAULT_REGION } from '../../utils/region.js';
3
+ import { validateAwsRegion } from '../../utils/validate.js';
4
+ import { renderReport, parseFailOn, applyFailOn, FAIL_ON_OPTION, JSON_OPTION, } from '../../utils/audit.js';
5
+ import { auditRoot, auditPasswordPolicy, auditUsers, auditUserPolicies } from '../../utils/audit-iam.js';
6
+ import { auditBudgets, auditBudgetAlerting, auditDetection, auditCommitments, auditForensics } from '../../utils/audit-bedrock.js';
7
+ /**
8
+ * Audit the AWS account side of Bedrock protection.
9
+ *
10
+ * LLMjacking is credential theft aimed at model inference: an attacker obtains a
11
+ * long-lived AWS key and burns it on Bedrock, where the marginal cost per request
12
+ * is high enough that one compromised key can run five figures in days. The
13
+ * account-side exposure is therefore two-sided, and both halves are audited here
14
+ * because a finding in either one alone understates the risk:
15
+ *
16
+ * - the way in -- IAM credential hygiene (audit-iam.ts): what can be
17
+ * stolen, and how long it has been sitting there
18
+ * - the blast radius -- Bedrock spend guardrails (audit-bedrock.ts): what
19
+ * bounds the damage, how fast you find out, and whether
20
+ * you can attribute it afterwards
21
+ *
22
+ * Perfect hygiene with no spend ceiling still permits an unbounded bill from a
23
+ * key leaked any other way; a tight budget over a decade-old idle admin key
24
+ * still invites the incident. Reporting them together is the point.
25
+ *
26
+ * The repository side -- whether a credential is already committed -- is
27
+ * `bedrock-protection scan-repo`.
28
+ *
29
+ * Audit-only. Every AWS call is a read except the one documented at
30
+ * `credentialReport()` in audit-iam.ts, which generates an IAM report artifact
31
+ * and modifies no resource.
32
+ */
33
+ export default {
34
+ description: 'Audit the AWS account for LLMjacking exposure: IAM credential hygiene plus Bedrock spend guardrails, detection speed and invocation logging',
35
+ options: [
36
+ { flags: '--region <region>', description: 'Region for Bedrock, CloudWatch and Provisioned Throughput checks', default: DEFAULT_REGION },
37
+ PROFILE_OPTION,
38
+ { flags: '--max-key-age <days>', description: 'Flag active access keys older than this', default: '90' },
39
+ { flags: '--unused-days <days>', description: 'Flag credentials idle longer than this', default: '90' },
40
+ { flags: '--iam-only', description: 'Only run the IAM credential hygiene checks' },
41
+ { flags: '--bedrock-only', description: 'Only run the Bedrock spend guardrail and forensics checks' },
42
+ JSON_OPTION,
43
+ FAIL_ON_OPTION,
44
+ ],
45
+ async action(opts) {
46
+ const region = validateAwsRegion(opts.region || DEFAULT_REGION);
47
+ const failOn = parseFailOn(opts.failOn);
48
+ if (opts.iamOnly && opts.bedrockOnly) {
49
+ throw new Error('--iam-only and --bedrock-only are mutually exclusive; omit both to run everything');
50
+ }
51
+ const maxKeyAge = Number.parseInt(opts.maxKeyAge ?? '90', 10);
52
+ const unusedDays = Number.parseInt(opts.unusedDays ?? '90', 10);
53
+ if (!Number.isFinite(maxKeyAge) || maxKeyAge < 1)
54
+ throw new Error('--max-key-age must be a positive integer');
55
+ if (!Number.isFinite(unusedDays) || unusedDays < 1)
56
+ throw new Error('--unused-days must be a positive integer');
57
+ const accountId = resolveAccount(opts.profile);
58
+ if (!accountId) {
59
+ process.exitCode = 2;
60
+ return;
61
+ }
62
+ const runIam = !opts.bedrockOnly;
63
+ const runBedrock = !opts.iamOnly;
64
+ // auditBudgets returns the covering budget names so the alerting check can
65
+ // scope its per-notification calls to them rather than every budget.
66
+ const budgets = runBedrock ? auditBudgets(opts.profile, accountId) : null;
67
+ const findings = [
68
+ ...(runIam ? [
69
+ ...auditRoot(opts.profile),
70
+ auditPasswordPolicy(opts.profile),
71
+ ...auditUsers(opts.profile, maxKeyAge, unusedDays),
72
+ auditUserPolicies(opts.profile),
73
+ ] : []),
74
+ ...(runBedrock && budgets ? [
75
+ ...budgets.findings,
76
+ auditBudgetAlerting(opts.profile, accountId, budgets.coveringBudgets),
77
+ ...auditDetection(opts.profile, region),
78
+ auditCommitments(opts.profile, region),
79
+ auditForensics(opts.profile, region),
80
+ ] : []),
81
+ ];
82
+ const scope = runIam && runBedrock ? '' : runIam ? ' Scope: IAM only' : ' Scope: Bedrock only';
83
+ renderReport(findings, {
84
+ title: 'šŸ›”ļø Bedrock protection — account audit',
85
+ subtitle: `Account: ${accountId} Region: ${region}${scope}`,
86
+ groups: [
87
+ ['root', 'Root user — unconstrainable by design'],
88
+ ['users', 'IAM users and access keys'],
89
+ ['policy', 'Account-wide policy'],
90
+ ['budget', 'Spend ceilings — both billing surfaces'],
91
+ ['detection', 'Detection speed — how fast you find out'],
92
+ ['commitment', 'Standing commitments'],
93
+ ['forensics', 'Forensics — can you answer "who?"'],
94
+ ],
95
+ json: Boolean(opts.json),
96
+ jsonContext: {
97
+ account: accountId,
98
+ region,
99
+ scope: runIam && runBedrock ? 'full' : runIam ? 'iam-only' : 'bedrock-only',
100
+ },
101
+ });
102
+ applyFailOn(findings, failOn, Boolean(opts.json));
103
+ },
104
+ };
105
+ //# sourceMappingURL=scan-account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-account.js","sourceRoot":"","sources":["../../../../src/commands/bedrock-protection/scan-account.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ declare const _default: {
2
+ description: string;
3
+ options: {
4
+ flags: string;
5
+ description: string;
6
+ }[];
7
+ action(opts: {
8
+ repo?: string;
9
+ gitleaks?: string;
10
+ skipHistory?: boolean;
11
+ json?: boolean;
12
+ failOn?: string;
13
+ }): Promise<void>;
14
+ };
15
+ export default _default;
16
+ //# sourceMappingURL=scan-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-repo.d.ts","sourceRoot":"","sources":["../../../../src/commands/bedrock-protection/scan-repo.ts"],"names":[],"mappings":";;;;;;iBA0VqB;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KAC1F;;AAXH,wBA+EE"}
@@ -0,0 +1,397 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
+ import { join, dirname, resolve as resolvePath } from 'node:path';
3
+ import { run } from '../../utils/exec.js';
4
+ import { withPrivateTemp } from '../../utils/tempfile.js';
5
+ import { renderReport, parseFailOn, applyFailOn, FAIL_ON_OPTION, JSON_OPTION, } from '../../utils/audit.js';
6
+ /**
7
+ * Audit a git repository for credentials, using gitleaks for all detection.
8
+ *
9
+ * The account-side companion is `bedrock-protection scan-account`, which audits
10
+ * IAM credential hygiene and Bedrock spend guardrails. This command answers a
11
+ * different question: is a credential already sitting in a repository?
12
+ *
13
+ * Detection is gitleaks-only by design: this command contains no credential
14
+ * patterns of its own. The filename and .gitignore checks below inspect
15
+ * *hygiene* (is `.env` ignored? is a scanner wired into the hook?) and never
16
+ * attempt to recognise a secret.
17
+ *
18
+ * Three ARCC requirements shape this (SAX-03 Outcome 4, "Policy Engine Risk
19
+ * Detection for Credential Violations", plus the metadata-leak recommendation):
20
+ *
21
+ * - "Not scanning Git history for previously committed credentials" is a named
22
+ * pitfall, so history is scanned in full rather than a PR range. This is the
23
+ * opposite trade-off from the CI eval gate, which scans only BASE..HEAD so
24
+ * the gate can go green on a repo with pre-existing findings.
25
+ * - "Check the git history of every branch of your repo" -- satisfied by
26
+ * gitleaks' default, verified rather than assumed: a `gitleaks git` scan
27
+ * reported a finding in a commit NOT reachable from HEAD, and adding
28
+ * `--log-opts=--all` changed nothing.
29
+ * - "Do not put sensitive data into any metadata such as git commit messages."
30
+ * gitleaks does NOT scan commit messages -- measured: a commit whose message
31
+ * contained a valid AWS key id produced zero findings from both a default and
32
+ * an --all scan. That gap is closed by `auditCommitMessages` below, still
33
+ * using gitleaks for the matching.
34
+ *
35
+ * Also measured: `gitleaks dir` does NOT honour .gitignore, which is what makes
36
+ * the working-tree scan worth running separately -- an ignored `.env` is absent
37
+ * from history but present on disk.
38
+ *
39
+ * Audit-only. Nothing is written to the repository.
40
+ */
41
+ /** Filenames that should never be tracked. A name check, not secret detection. */
42
+ const CREDENTIAL_FILENAMES = [
43
+ '.env', '.env.local', '.env.production', '.env.development',
44
+ 'credentials', '.npmrc', '.pypirc', '.netrc',
45
+ 'id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519',
46
+ ];
47
+ /** Patterns a .gitignore should carry to keep the above from being added. */
48
+ const EXPECTED_IGNORES = ['.env', '*.pem', '*.key', 'credentials', 'id_rsa'];
49
+ function findGitleaks(explicit) {
50
+ if (explicit)
51
+ return existsSync(explicit) ? explicit : null;
52
+ if (process.env.GITLEAKS_PATH && existsSync(process.env.GITLEAKS_PATH))
53
+ return process.env.GITLEAKS_PATH;
54
+ const which = run('which', ['gitleaks']);
55
+ if (which.ok && which.stdout)
56
+ return which.stdout.trim();
57
+ return null;
58
+ }
59
+ /**
60
+ * Run gitleaks and summarise its report.
61
+ *
62
+ * `--redact` is mandatory, not stylistic: without it gitleaks prints the matched
63
+ * secret into its own report and stdout, so a tool run to find an exposure would
64
+ * become a second copy of it -- on a terminal, in scrollback, and in whatever
65
+ * captures this command's output.
66
+ *
67
+ * The clean/leaks/failed distinction keys on the REPORT rather than the exit
68
+ * code. gitleaks exits 1 both for "leaks found" and, combined with other
69
+ * failures, for conditions that establish nothing -- and `run()` collapses every
70
+ * non-zero exit into ok:false. The report is the actual evidence: findings
71
+ * present means findings, while a missing or unparseable report alongside a
72
+ * non-zero exit means the scan produced no verdict, which is INDETERMINATE and
73
+ * must never read as clean.
74
+ */
75
+ function runGitleaks(bin, args, reportPath) {
76
+ const res = run(bin, [...args, '--no-banner', '--redact', '--report-format=json', `--report-path=${reportPath}`]);
77
+ let parsed = null;
78
+ if (existsSync(reportPath)) {
79
+ try {
80
+ const body = readFileSync(reportPath, 'utf8').trim();
81
+ parsed = body ? JSON.parse(body) : [];
82
+ }
83
+ catch {
84
+ parsed = null;
85
+ }
86
+ }
87
+ if (parsed === null) {
88
+ // No usable report. Exit 0 with no report is a clean scan on some gitleaks
89
+ // paths; a non-zero exit with no report is a failure.
90
+ if (res.ok)
91
+ return { count: 0, hits: [] };
92
+ return { count: -1, hits: [], error: (res.stderr || 'gitleaks failed and wrote no report').split('\n')[0] };
93
+ }
94
+ const hits = parsed.map((f) => {
95
+ const where = f.File ? `${f.File}:${f.StartLine}` : `line ${f.StartLine}`;
96
+ const commit = f.Commit ? ` @${String(f.Commit).slice(0, 8)}` : '';
97
+ return `[${f.RuleID}] ${where}${commit}`;
98
+ });
99
+ return { count: parsed.length, hits };
100
+ }
101
+ const ROTATE_FIRST = 'Rotate the credential FIRST. ARCC names "assuming removal from source code is sufficient" as a pitfall — rewriting history does not un-expose anything already cloned, forked or mirrored.';
102
+ /**
103
+ * Extra args aligning this command with the CI eval gate's tuning surface.
104
+ *
105
+ * `.gitleaks.toml` needs no flag: gitleaks auto-loads it from the SCANNED path,
106
+ * verified rather than assumed -- a scan run from an unrelated cwd still
107
+ * honoured a config sitting in the target repo, in both `dir` and `git` mode.
108
+ * A baseline does need an explicit flag.
109
+ *
110
+ * Both are surfaced in the report, because a silently applied allowlist is
111
+ * indistinguishable from a clean repo, and "0 findings" means something quite
112
+ * different when a suppression file is in play.
113
+ */
114
+ function tuningArgs(repo) {
115
+ const args = [];
116
+ const notes = [];
117
+ if (existsSync(join(repo, '.gitleaks.toml')))
118
+ notes.push('.gitleaks.toml (auto-loaded)');
119
+ const baseline = join(repo, '.prism', 'gitleaks-baseline.json');
120
+ if (existsSync(baseline)) {
121
+ args.push(`--baseline-path=${baseline}`);
122
+ notes.push('.prism/gitleaks-baseline.json');
123
+ }
124
+ return { args, notes };
125
+ }
126
+ function auditHistory(bin, repo, reportDir, tuning) {
127
+ // gitleaks scans every ref by default (verified), so this covers commits on
128
+ // branches other than the checked-out one.
129
+ const r = runGitleaks(bin, ['git', repo, ...tuning], join(reportDir, 'history.json'));
130
+ if (r.count < 0) {
131
+ return {
132
+ id: 'history-secrets', category: 'detection', title: 'Credentials in git history (all refs)',
133
+ status: 'INDETERMINATE', severity: 'CRITICAL',
134
+ detail: `The history scan produced no verdict (${r.error ?? 'unknown error'}), so this repository is NOT cleared.`,
135
+ };
136
+ }
137
+ return {
138
+ id: 'history-secrets', category: 'detection', title: 'Credentials in git history (all refs)',
139
+ status: r.count ? 'FAIL' : 'PASS',
140
+ severity: 'CRITICAL',
141
+ detail: r.count
142
+ ? `${r.count} credential(s) committed at some point in this repository's history: ${r.hits.slice(0, 10).join(', ')}${r.count > 10 ? `, … (+${r.count - 10})` : ''}. A deleted file does not remove the blob — it stays reachable in history.`
143
+ : 'No credentials found in any commit on any ref.',
144
+ remediation: r.count ? ROTATE_FIRST : undefined,
145
+ };
146
+ }
147
+ function auditWorkingTree(bin, repo, reportDir, tuning) {
148
+ // `gitleaks dir` does NOT honour .gitignore (verified), which is the point:
149
+ // an ignored .env never enters history but sits on disk, and leaks through
150
+ // backups, screen shares, bundled archives and stray `docker build` contexts.
151
+ const r = runGitleaks(bin, ['dir', repo, ...tuning], join(reportDir, 'worktree.json'));
152
+ if (r.count < 0) {
153
+ return {
154
+ id: 'worktree-secrets', category: 'detection', title: 'Credentials in the working tree (including ignored files)',
155
+ status: 'INDETERMINATE', severity: 'HIGH',
156
+ detail: `The working-tree scan produced no verdict (${r.error ?? 'unknown error'}).`,
157
+ };
158
+ }
159
+ return {
160
+ id: 'worktree-secrets', category: 'detection', title: 'Credentials in the working tree (including ignored files)',
161
+ status: r.count ? 'FAIL' : 'PASS',
162
+ severity: 'HIGH',
163
+ detail: r.count
164
+ ? `${r.count} credential(s) present on disk: ${r.hits.slice(0, 10).join(', ')}${r.count > 10 ? `, … (+${r.count - 10})` : ''}. This scan ignores .gitignore, so some of these may never have been committed — still exposed via backups, archives and build contexts.`
165
+ : 'No credentials on disk, including files excluded by .gitignore.',
166
+ remediation: r.count ? 'Move each value into Secrets Manager or Parameter Store and read it at runtime. If any is also in history, rotate first.' : undefined,
167
+ };
168
+ }
169
+ /**
170
+ * Commit messages, which gitleaks does not scan.
171
+ *
172
+ * Measured: a commit whose message contained a valid AWS key id produced zero
173
+ * findings from both a default `gitleaks git` scan and an `--log-opts=--all`
174
+ * one. ARCC explicitly calls this out ("Do not put sensitive data into any
175
+ * metadata such as git commit messages ... This type of data is difficult to
176
+ * wipe ... and are going to stay forever in the repository").
177
+ *
178
+ * Detection stays with gitleaks: the messages are written to a private temp file
179
+ * and gitleaks scans that. No pattern matching happens here. The temp file holds
180
+ * real credentials, so it goes through `withPrivateTemp` -- mode 0600 inside a
181
+ * mkdtemp directory, removed on every path including throws.
182
+ */
183
+ function auditCommitMessages(bin, repo) {
184
+ const log = run('git', ['-C', repo, 'log', '--all', '--format=%H%n%B%n']);
185
+ if (!log.ok) {
186
+ return {
187
+ id: 'commit-message-secrets', category: 'detection', title: 'Credentials in commit messages',
188
+ status: 'INDETERMINATE', severity: 'HIGH',
189
+ detail: `Could not read the commit log (${(log.stderr || '').split('\n')[0] || 'unknown error'}).`,
190
+ };
191
+ }
192
+ const body = log.stdout || '';
193
+ const lines = body.split('\n');
194
+ return withPrivateTemp('commit-messages.txt', body, (file) => {
195
+ const r = runGitleaks(bin, ['dir', file], join(dirname(file), 'messages.json'));
196
+ if (r.count < 0) {
197
+ return {
198
+ id: 'commit-message-secrets', category: 'detection', title: 'Credentials in commit messages',
199
+ status: 'INDETERMINATE', severity: 'HIGH',
200
+ detail: `The commit-message scan produced no verdict (${r.error ?? 'unknown error'}).`,
201
+ };
202
+ }
203
+ if (r.count === 0) {
204
+ return {
205
+ id: 'commit-message-secrets', category: 'detection', title: 'Credentials in commit messages',
206
+ status: 'PASS', severity: 'HIGH',
207
+ detail: 'No credentials in any commit message. Worth checking separately because gitleaks scans patch content, not message text.',
208
+ };
209
+ }
210
+ // Map each hit back to a commit: walk backwards from the reported line to
211
+ // the nearest 40-hex SHA, which is the %H written before each message.
212
+ const commits = new Set();
213
+ for (const hit of r.hits) {
214
+ const m = /line (\d+)/.exec(hit) ?? /:(\d+)/.exec(hit);
215
+ if (!m)
216
+ continue;
217
+ const lineNo = Number.parseInt(m[1], 10);
218
+ for (let i = Math.min(lineNo, lines.length) - 1; i >= 0; i--) {
219
+ if (/^[0-9a-f]{40}$/.test(lines[i].trim())) {
220
+ commits.add(lines[i].trim().slice(0, 8));
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ return {
226
+ id: 'commit-message-secrets', category: 'detection', title: 'Credentials in commit messages',
227
+ status: 'FAIL', severity: 'HIGH',
228
+ detail: `${r.count} credential(s) in commit message text${commits.size ? `, in commit(s): ${[...commits].join(', ')}` : ''}. Message text is not part of any diff, so neither this repo's CI gate nor a plain gitleaks run would report it — and a message cannot be edited without rewriting every descendant commit.`,
229
+ remediation: ROTATE_FIRST,
230
+ };
231
+ });
232
+ }
233
+ function auditTrackedFiles(repo) {
234
+ const ls = run('git', ['-C', repo, 'ls-files']);
235
+ if (!ls.ok) {
236
+ return {
237
+ id: 'tracked-credential-files', category: 'hygiene', title: 'Credential-bearing files tracked in git',
238
+ status: 'INDETERMINATE', severity: 'HIGH',
239
+ detail: `Could not list tracked files (${(ls.stderr || '').split('\n')[0] || 'unknown error'}).`,
240
+ };
241
+ }
242
+ const tracked = (ls.stdout || '').split('\n').filter(Boolean);
243
+ const bad = tracked.filter((f) => {
244
+ const base = f.split('/').pop() ?? f;
245
+ return CREDENTIAL_FILENAMES.includes(base) || base.endsWith('.pem');
246
+ });
247
+ return {
248
+ id: 'tracked-credential-files', category: 'hygiene', title: 'Credential-bearing files tracked in git',
249
+ status: bad.length ? 'FAIL' : 'PASS', severity: 'HIGH',
250
+ detail: bad.length
251
+ ? `${bad.length} file(s) of a kind that normally holds credentials are tracked: ${bad.slice(0, 10).join(', ')}. Flagged by filename — whether each actually contains a live credential is answered by the history and working-tree scans above.`
252
+ : `None of ${tracked.length} tracked file(s) has a credential-bearing filename.`,
253
+ remediation: bad.length ? 'Untrack each file, add it to .gitignore, and rotate anything it contained — it is in history regardless.' : undefined,
254
+ };
255
+ }
256
+ function auditGitignore(repo) {
257
+ const path = join(repo, '.gitignore');
258
+ if (!existsSync(path)) {
259
+ return {
260
+ id: 'gitignore-hygiene', category: 'hygiene', title: '.gitignore covers credential file patterns',
261
+ status: 'FAIL', severity: 'MEDIUM',
262
+ detail: 'No .gitignore at the repository root, so nothing stops a .env or private key from being staged by an ordinary `git add -A`.',
263
+ remediation: `Add a .gitignore covering at least: ${EXPECTED_IGNORES.join(', ')}.`,
264
+ };
265
+ }
266
+ const content = readFileSync(path, 'utf8');
267
+ const lines = content.split('\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
268
+ const missing = EXPECTED_IGNORES.filter((pat) => !lines.some((l) => l === pat || l === `/${pat}` || l === `**/${pat}`));
269
+ return {
270
+ id: 'gitignore-hygiene', category: 'hygiene', title: '.gitignore covers credential file patterns',
271
+ status: missing.length ? 'FAIL' : 'PASS', severity: 'MEDIUM',
272
+ detail: missing.length
273
+ ? `.gitignore does not cover: ${missing.join(', ')}. Each is a pattern a credential commonly arrives under, and an uncovered one gets staged by a routine \`git add -A\`.`
274
+ : 'All expected credential file patterns are ignored.',
275
+ remediation: missing.length ? `Add the missing patterns: ${missing.join(', ')}.` : undefined,
276
+ };
277
+ }
278
+ function auditPreCommitHook(repo) {
279
+ // Look in both the default hooks dir and core.hooksPath, since a repo using
280
+ // pre-commit or husky relocates it and .git/hooks would look empty.
281
+ const candidates = [];
282
+ const hooksPath = run('git', ['-C', repo, 'config', '--get', 'core.hooksPath']);
283
+ if (hooksPath.ok && hooksPath.stdout.trim())
284
+ candidates.push(resolvePath(repo, hooksPath.stdout.trim()));
285
+ candidates.push(join(repo, '.git', 'hooks'));
286
+ let wired = false;
287
+ const inspected = [];
288
+ for (const dir of candidates) {
289
+ if (!existsSync(dir))
290
+ continue;
291
+ inspected.push(dir);
292
+ for (const entry of readdirSync(dir)) {
293
+ if (!entry.startsWith('pre-commit'))
294
+ continue;
295
+ try {
296
+ if (/gitleaks/i.test(readFileSync(join(dir, entry), 'utf8'))) {
297
+ wired = true;
298
+ break;
299
+ }
300
+ }
301
+ catch { /* unreadable hook — treat as not wired */ }
302
+ }
303
+ if (wired)
304
+ break;
305
+ }
306
+ // A pre-commit config that references gitleaks also counts.
307
+ const preCommitCfg = join(repo, '.pre-commit-config.yaml');
308
+ if (!wired && existsSync(preCommitCfg)) {
309
+ try {
310
+ wired = /gitleaks/i.test(readFileSync(preCommitCfg, 'utf8'));
311
+ }
312
+ catch { /* ignore */ }
313
+ }
314
+ return {
315
+ id: 'pre-commit-scanner', category: 'hygiene', title: 'gitleaks wired as a pre-commit hook',
316
+ status: wired ? 'PASS' : 'FAIL', severity: 'LOW',
317
+ detail: wired
318
+ ? 'A pre-commit hook or .pre-commit-config.yaml invokes gitleaks, so a credential is caught before it becomes a commit.'
319
+ : `No pre-commit hook invokes gitleaks${inspected.length ? ` (checked ${inspected.join(', ')})` : ''}. Without one, the earliest catch is CI — by which point the credential is already in history and, on a push, already off the machine.`,
320
+ remediation: wired ? undefined : 'Install `gitleaks protect --staged --redact` as a pre-commit hook. Severity is LOW only because a hook is advisory: it is trivially bypassed with --no-verify and is not a control.',
321
+ };
322
+ }
323
+ export default {
324
+ description: 'Scan a git repository for credentials with gitleaks: full history across all refs, working tree, commit messages, and ignore-file hygiene',
325
+ options: [
326
+ { flags: '--repo <path>', description: 'Repository to scan', default: '.' },
327
+ { flags: '--gitleaks <path>', description: 'Path to the gitleaks binary (default: $GITLEAKS_PATH, then PATH)' },
328
+ { flags: '--skip-history', description: 'Skip the full-history scan (it is the slow one on a large repo)' },
329
+ JSON_OPTION,
330
+ FAIL_ON_OPTION,
331
+ ],
332
+ async action(opts) {
333
+ const failOn = parseFailOn(opts.failOn);
334
+ const repo = resolvePath(opts.repo || '.');
335
+ if (!existsSync(join(repo, '.git'))) {
336
+ console.error(`\nāŒ ${repo} is not a git repository (no .git directory).\n`);
337
+ process.exitCode = 2;
338
+ return;
339
+ }
340
+ // Deliberately not auto-downloaded. The CI eval gate fetches a
341
+ // version-pinned, checksum-verified binary because it runs in a disposable
342
+ // container; a developer CLI silently pulling an executable onto a
343
+ // workstation is a different risk, so this reports and stops.
344
+ const bin = findGitleaks(opts.gitleaks);
345
+ const tuning = tuningArgs(repo);
346
+ const findings = [];
347
+ if (!bin) {
348
+ for (const [id, title, sev] of [
349
+ ['history-secrets', 'Credentials in git history (all refs)', 'CRITICAL'],
350
+ ['worktree-secrets', 'Credentials in the working tree (including ignored files)', 'HIGH'],
351
+ ['commit-message-secrets', 'Credentials in commit messages', 'HIGH'],
352
+ ]) {
353
+ findings.push({
354
+ id, category: 'detection', title,
355
+ status: 'INDETERMINATE', severity: sev,
356
+ detail: 'gitleaks is not installed, so no credential detection ran. This repository is NOT cleared.',
357
+ remediation: 'Install gitleaks (`brew install gitleaks`, or a release binary from github.com/gitleaks/gitleaks), or pass --gitleaks <path>.',
358
+ });
359
+ }
360
+ }
361
+ else {
362
+ // One temp dir holds every gitleaks report; reports can name files but
363
+ // never contain secret values, because --redact is always passed.
364
+ withPrivateTemp('.keep', '', (keep) => {
365
+ const reportDir = dirname(keep);
366
+ if (opts.skipHistory) {
367
+ findings.push({
368
+ id: 'history-secrets', category: 'detection', title: 'Credentials in git history (all refs)',
369
+ status: 'INDETERMINATE', severity: 'CRITICAL',
370
+ detail: 'Skipped via --skip-history. The check most likely to find an already-leaked credential did not run.',
371
+ });
372
+ }
373
+ else {
374
+ findings.push(auditHistory(bin, repo, reportDir, tuning.args));
375
+ }
376
+ findings.push(auditWorkingTree(bin, repo, reportDir, tuning.args));
377
+ findings.push(auditCommitMessages(bin, repo));
378
+ });
379
+ }
380
+ findings.push(auditTrackedFiles(repo));
381
+ findings.push(auditGitignore(repo));
382
+ findings.push(auditPreCommitHook(repo));
383
+ renderReport(findings, {
384
+ title: 'šŸ” Repository credential scan',
385
+ subtitle: `Repo: ${repo}${bin ? ` gitleaks: ${bin}` : ' gitleaks: NOT FOUND'}`
386
+ + (tuning.notes.length ? `\n Suppression in effect: ${tuning.notes.join(', ')} — "0 findings" is relative to these.` : ''),
387
+ groups: [
388
+ ['detection', 'Credential detection (gitleaks)'],
389
+ ['hygiene', 'Repository hygiene — what stops the next one'],
390
+ ],
391
+ json: Boolean(opts.json),
392
+ jsonContext: { repo, gitleaks: bin, suppression: tuning.notes },
393
+ });
394
+ applyFailOn(findings, failOn, Boolean(opts.json));
395
+ },
396
+ };
397
+ //# sourceMappingURL=scan-repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-repo.js","sourceRoot":"","sources":["../../../../src/commands/bedrock-protection/scan-repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Finding } from './audit.js';
2
+ export declare function auditBudgets(profile: string | undefined, accountId: string): {
3
+ findings: Finding[];
4
+ coveringBudgets: string[];
5
+ };
6
+ /**
7
+ * A budget that alerts nobody is a record, not a control.
8
+ *
9
+ * `describe-budgets` says nothing about whether anyone is told when a threshold
10
+ * is crossed -- notifications and their subscribers are separate resources. A
11
+ * budget created without them still shows a spend bar in the console and still
12
+ * reports as "a Bedrock budget exists", while nothing reaches a human. For
13
+ * LLMjacking specifically, being told is the entire value: the spend has already
14
+ * happened by the time anyone opens the Billing console.
15
+ *
16
+ * `DescribeBudgetNotificationsForAccount` returns notifications for every budget
17
+ * in ONE call. Subscribers need a call per notification, which is why this is
18
+ * scoped to the budgets that actually cover Bedrock rather than all of them.
19
+ */
20
+ export declare function auditBudgetAlerting(profile: string | undefined, accountId: string, coveringBudgets: string[]): Finding;
21
+ export declare function auditDetection(profile: string | undefined, region: string): Finding[];
22
+ export declare function auditCommitments(profile: string | undefined, region: string): Finding;
23
+ export declare function auditForensics(profile: string | undefined, region: string): Finding;
24
+ //# sourceMappingURL=audit-bedrock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-bedrock.d.ts","sourceRoot":"","sources":["../../../src/utils/audit-bedrock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAiErC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAA;CAAE,CA2D/H;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CA8DT;AAWD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CA+FrF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAmBrF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAoBnF"}