gitsieve 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +362 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +147 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +161 -0
- package/dist/config.js.map +1 -0
- package/dist/controls.d.ts +16 -0
- package/dist/controls.js +161 -0
- package/dist/controls.js.map +1 -0
- package/dist/corpus.d.ts +34 -0
- package/dist/corpus.js +121 -0
- package/dist/corpus.js.map +1 -0
- package/dist/git.d.ts +66 -0
- package/dist/git.js +214 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/matcher.d.ts +34 -0
- package/dist/matcher.js +75 -0
- package/dist/matcher.js.map +1 -0
- package/dist/preflight.d.ts +21 -0
- package/dist/preflight.js +52 -0
- package/dist/preflight.js.map +1 -0
- package/dist/report.d.ts +8 -0
- package/dist/report.js +0 -0
- package/dist/report.js.map +1 -0
- package/dist/scan.d.ts +17 -0
- package/dist/scan.js +134 -0
- package/dist/scan.js.map +1 -0
- package/dist/secrets.d.ts +13 -0
- package/dist/secrets.js +48 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/dist/git.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export class GitError extends Error {
|
|
5
|
+
}
|
|
6
|
+
const FIELD_SEP = "\u0000";
|
|
7
|
+
const RECORD_SEP = "\u001e";
|
|
8
|
+
const LOG_FORMAT = "--format=%H%x00%an%x00%ae%x00%cn%x00%ce%x00%B%x1e";
|
|
9
|
+
export class RealGitRepo {
|
|
10
|
+
root;
|
|
11
|
+
includeReflog;
|
|
12
|
+
constructor(root, options = {}) {
|
|
13
|
+
this.root = root;
|
|
14
|
+
this.includeReflog = options.includeReflog ?? true;
|
|
15
|
+
}
|
|
16
|
+
run(args, input) {
|
|
17
|
+
const result = spawnSync("git", args, {
|
|
18
|
+
cwd: this.root,
|
|
19
|
+
input,
|
|
20
|
+
maxBuffer: 512 * 1024 * 1024,
|
|
21
|
+
});
|
|
22
|
+
if (result.error)
|
|
23
|
+
throw new GitError(`git ${args[0]}: ${result.error.message}`);
|
|
24
|
+
if (result.status !== 0) {
|
|
25
|
+
throw new GitError(`git ${args.join(" ")} exited ${result.status}: ${result.stderr.toString().trim()}`);
|
|
26
|
+
}
|
|
27
|
+
return result.stdout;
|
|
28
|
+
}
|
|
29
|
+
tryRun(args) {
|
|
30
|
+
try {
|
|
31
|
+
return this.run(args);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** `--all` plus, by default, `--reflog`: an amended commit is still on disk. */
|
|
38
|
+
historyArgs() {
|
|
39
|
+
return this.includeReflog ? ["--all", "--reflog"] : ["--all"];
|
|
40
|
+
}
|
|
41
|
+
isShallow() {
|
|
42
|
+
const out = this.tryRun(["rev-parse", "--is-shallow-repository"]);
|
|
43
|
+
return out?.toString().trim() === "true";
|
|
44
|
+
}
|
|
45
|
+
refNames() {
|
|
46
|
+
const out = this.tryRun(["for-each-ref", "--format=%(refname)"]);
|
|
47
|
+
if (!out)
|
|
48
|
+
return [];
|
|
49
|
+
return out.toString("utf8").split("\n").filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
commits() {
|
|
52
|
+
const out = this.tryRun([
|
|
53
|
+
"log",
|
|
54
|
+
...this.historyArgs(),
|
|
55
|
+
"--no-color",
|
|
56
|
+
LOG_FORMAT,
|
|
57
|
+
]);
|
|
58
|
+
if (!out)
|
|
59
|
+
return [];
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
const commits = [];
|
|
62
|
+
for (const record of out.toString("utf8").split(RECORD_SEP)) {
|
|
63
|
+
const trimmed = record.replace(/^\n+/, "");
|
|
64
|
+
if (!trimmed)
|
|
65
|
+
continue;
|
|
66
|
+
const fields = trimmed.split(FIELD_SEP);
|
|
67
|
+
if (fields.length < 6)
|
|
68
|
+
continue;
|
|
69
|
+
const sha = fields[0].trim();
|
|
70
|
+
if (!/^[0-9a-f]{7,64}$/.test(sha) || seen.has(sha))
|
|
71
|
+
continue;
|
|
72
|
+
seen.add(sha);
|
|
73
|
+
commits.push({
|
|
74
|
+
sha,
|
|
75
|
+
authorName: fields[1],
|
|
76
|
+
authorEmail: fields[2],
|
|
77
|
+
committerName: fields[3],
|
|
78
|
+
committerEmail: fields[4],
|
|
79
|
+
message: fields[5],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return commits;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* `-m` is load-bearing: without it, a path introduced only by a merge commit
|
|
86
|
+
* ("evil merge") never appears in the output. See docs/decisions/0001.
|
|
87
|
+
*/
|
|
88
|
+
paths() {
|
|
89
|
+
const paths = new Set();
|
|
90
|
+
const log = this.tryRun([
|
|
91
|
+
"log",
|
|
92
|
+
...this.historyArgs(),
|
|
93
|
+
"-m",
|
|
94
|
+
"--name-only",
|
|
95
|
+
"--no-color",
|
|
96
|
+
"--pretty=format:",
|
|
97
|
+
]);
|
|
98
|
+
if (log) {
|
|
99
|
+
for (const line of log.toString("utf8").split("\n")) {
|
|
100
|
+
const path = line.trim();
|
|
101
|
+
if (path)
|
|
102
|
+
paths.add(path);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Belt and braces: the full tree at each ref tip, directories included.
|
|
106
|
+
for (const ref of this.refNames()) {
|
|
107
|
+
const tree = this.tryRun(["ls-tree", "-r", "-t", "--name-only", ref]);
|
|
108
|
+
if (!tree)
|
|
109
|
+
continue;
|
|
110
|
+
for (const line of tree.toString("utf8").split("\n")) {
|
|
111
|
+
const path = line.trim();
|
|
112
|
+
if (path)
|
|
113
|
+
paths.add(path);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return [...paths];
|
|
117
|
+
}
|
|
118
|
+
objects() {
|
|
119
|
+
const listed = this.tryRun([
|
|
120
|
+
"rev-list",
|
|
121
|
+
"--objects",
|
|
122
|
+
...this.historyArgs(),
|
|
123
|
+
]);
|
|
124
|
+
if (!listed)
|
|
125
|
+
return [];
|
|
126
|
+
const pathBySha = new Map();
|
|
127
|
+
const shas = [];
|
|
128
|
+
for (const line of listed.toString("utf8").split("\n")) {
|
|
129
|
+
if (!line)
|
|
130
|
+
continue;
|
|
131
|
+
const space = line.indexOf(" ");
|
|
132
|
+
const sha = space === -1 ? line : line.slice(0, space);
|
|
133
|
+
if (!/^[0-9a-f]{7,64}$/.test(sha))
|
|
134
|
+
continue;
|
|
135
|
+
if (pathBySha.has(sha))
|
|
136
|
+
continue;
|
|
137
|
+
shas.push(sha);
|
|
138
|
+
pathBySha.set(sha, space === -1 ? "" : line.slice(space + 1));
|
|
139
|
+
}
|
|
140
|
+
if (shas.length === 0)
|
|
141
|
+
return [];
|
|
142
|
+
const check = this.run(["cat-file", "--batch-check"], Buffer.from(shas.join("\n") + "\n", "utf8"));
|
|
143
|
+
const objects = [];
|
|
144
|
+
for (const line of check.toString("utf8").split("\n")) {
|
|
145
|
+
if (!line)
|
|
146
|
+
continue;
|
|
147
|
+
const [sha, type, size] = line.split(" ");
|
|
148
|
+
if (!sha || !type)
|
|
149
|
+
continue;
|
|
150
|
+
if (type !== "blob" &&
|
|
151
|
+
type !== "tree" &&
|
|
152
|
+
type !== "commit" &&
|
|
153
|
+
type !== "tag")
|
|
154
|
+
continue;
|
|
155
|
+
const path = pathBySha.get(sha);
|
|
156
|
+
objects.push({
|
|
157
|
+
sha,
|
|
158
|
+
type,
|
|
159
|
+
size: Number(size ?? 0),
|
|
160
|
+
...(path ? { path } : {}),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return objects;
|
|
164
|
+
}
|
|
165
|
+
readObjects(shas) {
|
|
166
|
+
const out = new Map();
|
|
167
|
+
const batchSize = 64;
|
|
168
|
+
for (let i = 0; i < shas.length; i += batchSize) {
|
|
169
|
+
const chunk = shas.slice(i, i + batchSize);
|
|
170
|
+
const raw = this.run(["cat-file", "--batch"], Buffer.from(chunk.join("\n") + "\n", "utf8"));
|
|
171
|
+
parseBatch(raw, out);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
workingTreeFile(relativePath) {
|
|
176
|
+
try {
|
|
177
|
+
return readFileSync(join(this.root, relativePath), "utf8");
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
remoteFetchSpecs() {
|
|
184
|
+
const out = this.tryRun(["config", "--get-all", "remote.origin.fetch"]);
|
|
185
|
+
if (!out)
|
|
186
|
+
return [];
|
|
187
|
+
return out.toString("utf8").split("\n").filter(Boolean);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* `git cat-file --batch` frames each object as
|
|
192
|
+
* "<sha> <type> <size>\n" + <size bytes> + "\n"
|
|
193
|
+
* and a missing object as "<sha> missing\n".
|
|
194
|
+
*/
|
|
195
|
+
export function parseBatch(raw, into) {
|
|
196
|
+
let cursor = 0;
|
|
197
|
+
while (cursor < raw.length) {
|
|
198
|
+
const newline = raw.indexOf(0x0a, cursor);
|
|
199
|
+
if (newline === -1)
|
|
200
|
+
break;
|
|
201
|
+
const header = raw.subarray(cursor, newline).toString("utf8");
|
|
202
|
+
cursor = newline + 1;
|
|
203
|
+
const parts = header.split(" ");
|
|
204
|
+
if (parts.length < 3)
|
|
205
|
+
continue; // "<sha> missing"
|
|
206
|
+
const sha = parts[0];
|
|
207
|
+
const size = Number(parts[2]);
|
|
208
|
+
if (!Number.isFinite(size))
|
|
209
|
+
break;
|
|
210
|
+
into.set(sha, raw.subarray(cursor, cursor + size));
|
|
211
|
+
cursor += size + 1;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { scan } from "./scan.js";
|
|
2
|
+
export type { ScanOptions } from "./scan.js";
|
|
3
|
+
export { buildCorpus } from "./corpus.js";
|
|
4
|
+
export type { Corpus, TextUnit } from "./corpus.js";
|
|
5
|
+
export { deriveControls, verifyControls } from "./controls.js";
|
|
6
|
+
export { preflight, isDenyAllIgnoreFile } from "./preflight.js";
|
|
7
|
+
export { compileTerm, findMatches, shouldUseWordBoundary } from "./matcher.js";
|
|
8
|
+
export { SECRET_PATTERNS } from "./secrets.js";
|
|
9
|
+
export { loadConfig, parseConfig, assertTermsFileOutsideRepo, ConfigError, EMPTY_CONFIG, } from "./config.js";
|
|
10
|
+
export { RealGitRepo, GitError } from "./git.js";
|
|
11
|
+
export type { GitRepo, CommitMeta, ObjectMeta } from "./git.js";
|
|
12
|
+
export { formatReport, formatJson, exitCodeFor, EXIT_OK, EXIT_FINDINGS, EXIT_UNTRUSTED, EXIT_USAGE, } from "./report.js";
|
|
13
|
+
export { main, parseArgs } from "./cli.js";
|
|
14
|
+
export * from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { scan } from "./scan.js";
|
|
2
|
+
export { buildCorpus } from "./corpus.js";
|
|
3
|
+
export { deriveControls, verifyControls } from "./controls.js";
|
|
4
|
+
export { preflight, isDenyAllIgnoreFile } from "./preflight.js";
|
|
5
|
+
export { compileTerm, findMatches, shouldUseWordBoundary } from "./matcher.js";
|
|
6
|
+
export { SECRET_PATTERNS } from "./secrets.js";
|
|
7
|
+
export { loadConfig, parseConfig, assertTermsFileOutsideRepo, ConfigError, EMPTY_CONFIG, } from "./config.js";
|
|
8
|
+
export { RealGitRepo, GitError } from "./git.js";
|
|
9
|
+
export { formatReport, formatJson, exitCodeFor, EXIT_OK, EXIT_FINDINGS, EXIT_UNTRUSTED, EXIT_USAGE, } from "./report.js";
|
|
10
|
+
export { main, parseArgs } from "./cli.js";
|
|
11
|
+
export * from "./types.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,WAAW,EACX,0BAA0B,EAC1B,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EACL,YAAY,EACZ,UAAU,EACV,WAAW,EACX,OAAO,EACP,aAAa,EACb,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC3C,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TermSpec } from "./types.js";
|
|
2
|
+
export interface Match {
|
|
3
|
+
index: number;
|
|
4
|
+
line: number;
|
|
5
|
+
/** The matched text plus a little surrounding context. Redact before printing. */
|
|
6
|
+
context: string;
|
|
7
|
+
}
|
|
8
|
+
export interface CompiledTerm {
|
|
9
|
+
spec: TermSpec;
|
|
10
|
+
regex: RegExp;
|
|
11
|
+
wholeWord: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Terms are literals, so every regex metacharacter is escaped. The `u` flag is
|
|
15
|
+
* deliberately not used: under `u`, an escaped non-syntax character is a syntax
|
|
16
|
+
* error, which would make escaping user input harder rather than safer. Hangul,
|
|
17
|
+
* Kana and Han are all in the BMP, so UTF-16 matching is exact for them.
|
|
18
|
+
*/
|
|
19
|
+
export declare function escapeLiteral(value: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* `\b` is defined against [A-Za-z0-9_]. Wrapping a Hangul term in `\b` asserts
|
|
22
|
+
* a word character sits next to it, so the term matches only by accident.
|
|
23
|
+
* Boundaries are therefore applied only when the term's own first and last
|
|
24
|
+
* characters are ASCII word characters.
|
|
25
|
+
*/
|
|
26
|
+
export declare function shouldUseWordBoundary(spec: TermSpec): boolean;
|
|
27
|
+
export declare function compileTerm(spec: TermSpec): CompiledTerm;
|
|
28
|
+
export declare function findMatches(regex: RegExp, text: string): Match[];
|
|
29
|
+
export declare function lineNumberAt(text: string, index: number): number;
|
|
30
|
+
/**
|
|
31
|
+
* Reports name the term and its location; they do not repeat the secret. A
|
|
32
|
+
* report pasted into a CI log or a ticket must not become the leak.
|
|
33
|
+
*/
|
|
34
|
+
export declare function redact(context: string): string;
|
package/dist/matcher.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terms are literals, so every regex metacharacter is escaped. The `u` flag is
|
|
3
|
+
* deliberately not used: under `u`, an escaped non-syntax character is a syntax
|
|
4
|
+
* error, which would make escaping user input harder rather than safer. Hangul,
|
|
5
|
+
* Kana and Han are all in the BMP, so UTF-16 matching is exact for them.
|
|
6
|
+
*/
|
|
7
|
+
export function escapeLiteral(value) {
|
|
8
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `\b` is defined against [A-Za-z0-9_]. Wrapping a Hangul term in `\b` asserts
|
|
12
|
+
* a word character sits next to it, so the term matches only by accident.
|
|
13
|
+
* Boundaries are therefore applied only when the term's own first and last
|
|
14
|
+
* characters are ASCII word characters.
|
|
15
|
+
*/
|
|
16
|
+
export function shouldUseWordBoundary(spec) {
|
|
17
|
+
if (spec.wholeWord === "always")
|
|
18
|
+
return true;
|
|
19
|
+
if (spec.wholeWord === "never")
|
|
20
|
+
return false;
|
|
21
|
+
const first = spec.value.at(0);
|
|
22
|
+
const last = spec.value.at(-1);
|
|
23
|
+
const wordy = /^[A-Za-z0-9_]$/;
|
|
24
|
+
return Boolean(first && last && wordy.test(first) && wordy.test(last));
|
|
25
|
+
}
|
|
26
|
+
export function compileTerm(spec) {
|
|
27
|
+
if (spec.value.length === 0) {
|
|
28
|
+
throw new Error(`term "${spec.id}" has an empty value`);
|
|
29
|
+
}
|
|
30
|
+
const wholeWord = shouldUseWordBoundary(spec);
|
|
31
|
+
const body = escapeLiteral(spec.value);
|
|
32
|
+
const source = wholeWord ? `\\b${body}\\b` : body;
|
|
33
|
+
const flags = spec.caseSensitive ? "g" : "gi";
|
|
34
|
+
return { spec, regex: new RegExp(source, flags), wholeWord };
|
|
35
|
+
}
|
|
36
|
+
const MAX_MATCHES_PER_UNIT = 200;
|
|
37
|
+
export function findMatches(regex, text) {
|
|
38
|
+
const matches = [];
|
|
39
|
+
const search = new RegExp(regex.source, regex.flags.includes("g") ? regex.flags : regex.flags + "g");
|
|
40
|
+
search.lastIndex = 0;
|
|
41
|
+
let hit;
|
|
42
|
+
while ((hit = search.exec(text)) !== null) {
|
|
43
|
+
matches.push({
|
|
44
|
+
index: hit.index,
|
|
45
|
+
line: lineNumberAt(text, hit.index),
|
|
46
|
+
context: contextAt(text, hit.index, hit[0].length),
|
|
47
|
+
});
|
|
48
|
+
if (hit[0].length === 0)
|
|
49
|
+
search.lastIndex += 1;
|
|
50
|
+
if (matches.length >= MAX_MATCHES_PER_UNIT)
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
return matches;
|
|
54
|
+
}
|
|
55
|
+
export function lineNumberAt(text, index) {
|
|
56
|
+
let line = 1;
|
|
57
|
+
for (let i = 0; i < index && i < text.length; i++) {
|
|
58
|
+
if (text.charCodeAt(i) === 10)
|
|
59
|
+
line += 1;
|
|
60
|
+
}
|
|
61
|
+
return line;
|
|
62
|
+
}
|
|
63
|
+
function contextAt(text, index, length) {
|
|
64
|
+
const start = Math.max(0, index - 24);
|
|
65
|
+
const end = Math.min(text.length, index + length + 24);
|
|
66
|
+
return text.slice(start, end).replace(/\s+/g, " ").trim();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Reports name the term and its location; they do not repeat the secret. A
|
|
70
|
+
* report pasted into a CI log or a ticket must not become the leak.
|
|
71
|
+
*/
|
|
72
|
+
export function redact(context) {
|
|
73
|
+
return `<${context.length} chars, redacted; rerun with --show-matches>`;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { GitRepo } from "./git.js";
|
|
2
|
+
import type { Warning } from "./types.js";
|
|
3
|
+
export interface Preflight {
|
|
4
|
+
warnings: Warning[];
|
|
5
|
+
/** Reasons the scan cannot be trusted no matter what it finds. */
|
|
6
|
+
blockers: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A `.gitignore` whose first effective rule ignores everything, followed by
|
|
10
|
+
* negations, is a whitelist. It is a normal thing to write and a hazard to
|
|
11
|
+
* audit with: every tool that honours `.gitignore` -- ripgrep, ugrep with
|
|
12
|
+
* `--ignore-files`, most editor search -- will silently skip almost the whole
|
|
13
|
+
* repository and report a clean result.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isDenyAllIgnoreFile(text: string): boolean;
|
|
16
|
+
export interface PreflightOptions {
|
|
17
|
+
allowShallow?: boolean;
|
|
18
|
+
/** Paths of ignore files to inspect, relative to the repo root. */
|
|
19
|
+
ignoreFiles?: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function preflight(repo: GitRepo, options?: PreflightOptions): Preflight;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `.gitignore` whose first effective rule ignores everything, followed by
|
|
3
|
+
* negations, is a whitelist. It is a normal thing to write and a hazard to
|
|
4
|
+
* audit with: every tool that honours `.gitignore` -- ripgrep, ugrep with
|
|
5
|
+
* `--ignore-files`, most editor search -- will silently skip almost the whole
|
|
6
|
+
* repository and report a clean result.
|
|
7
|
+
*/
|
|
8
|
+
export function isDenyAllIgnoreFile(text) {
|
|
9
|
+
const lines = text
|
|
10
|
+
.split("\n")
|
|
11
|
+
.map((line) => line.trim())
|
|
12
|
+
.filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
13
|
+
const denyAll = new Set(["*", "/*", "**", "**/*", "*/"]);
|
|
14
|
+
return lines.some((line) => denyAll.has(line));
|
|
15
|
+
}
|
|
16
|
+
export function preflight(repo, options = {}) {
|
|
17
|
+
const warnings = [];
|
|
18
|
+
const blockers = [];
|
|
19
|
+
// 1. A shallow clone holds one commit. `git grep` over it is not a history
|
|
20
|
+
// check, however confidently it returns zero.
|
|
21
|
+
if (repo.isShallow()) {
|
|
22
|
+
const message = "this is a shallow clone; its history is truncated and a clean result here proves nothing";
|
|
23
|
+
if (options.allowShallow)
|
|
24
|
+
warnings.push({ code: "shallow-clone", message });
|
|
25
|
+
else
|
|
26
|
+
blockers.push(message);
|
|
27
|
+
}
|
|
28
|
+
// 2. A single-branch clone fetches one ref. Other branches are not on disk.
|
|
29
|
+
const fetchSpecs = repo.remoteFetchSpecs();
|
|
30
|
+
if (fetchSpecs.length > 0 &&
|
|
31
|
+
!fetchSpecs.some((spec) => spec.includes("refs/heads/*"))) {
|
|
32
|
+
warnings.push({
|
|
33
|
+
code: "single-branch-clone",
|
|
34
|
+
message: `remote.origin.fetch is ${fetchSpecs.join(", ")}; branches outside that refspec were never fetched`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// 3. Deny-everything ignore files.
|
|
38
|
+
const candidates = options.ignoreFiles ?? [".gitignore", ".git/info/exclude"];
|
|
39
|
+
for (const path of candidates) {
|
|
40
|
+
const text = repo.workingTreeFile(path);
|
|
41
|
+
if (!text)
|
|
42
|
+
continue;
|
|
43
|
+
if (isDenyAllIgnoreFile(text)) {
|
|
44
|
+
warnings.push({
|
|
45
|
+
code: "deny-all-ignore-file",
|
|
46
|
+
message: `${path} ignores everything and then re-allows specific paths; any scanner that honours ignore files will skip most of this repository and report it clean`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { warnings, blockers };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,KAAK,GAAG,IAAI;SACf,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAQD,MAAM,UAAU,SAAS,CACvB,IAAa,EACb,UAA4B,EAAE;IAE9B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,2EAA2E;IAC3E,iDAAiD;IACjD,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACrB,MAAM,OAAO,GACX,0FAA0F,CAAC;QAC7F,IAAI,OAAO,CAAC,YAAY;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,CAAC;;YACvE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC3C,IACE,UAAU,CAAC,MAAM,GAAG,CAAC;QACrB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,EACzD,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,qBAAqB;YAC3B,OAAO,EAAE,0BAA0B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,oDAAoD;SAC7G,CAAC,CAAC;IACL,CAAC;IAED,mCAAmC;IACnC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;IAC9E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,GAAG,IAAI,oJAAoJ;aACrK,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ScanReport } from "./types.js";
|
|
2
|
+
export declare const EXIT_OK = 0;
|
|
3
|
+
export declare const EXIT_FINDINGS = 1;
|
|
4
|
+
export declare const EXIT_UNTRUSTED = 2;
|
|
5
|
+
export declare const EXIT_USAGE = 3;
|
|
6
|
+
export declare function exitCodeFor(report: ScanReport): number;
|
|
7
|
+
export declare function formatReport(report: ScanReport): string;
|
|
8
|
+
export declare function formatJson(report: ScanReport): string;
|
package/dist/report.js
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
package/dist/scan.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GitRepo } from "./git.js";
|
|
2
|
+
import type { Config, ScanReport, SuppressionSpec } from "./types.js";
|
|
3
|
+
export interface ScanOptions {
|
|
4
|
+
repo: GitRepo;
|
|
5
|
+
config: Config;
|
|
6
|
+
/** Scan a shallow clone anyway, downgrading the blocker to a warning. */
|
|
7
|
+
allowShallow?: boolean;
|
|
8
|
+
/** Print the matched text instead of a redaction placeholder. */
|
|
9
|
+
showMatches?: boolean;
|
|
10
|
+
maxBlobBytes?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function suppressionMatches(suppression: SuppressionSpec, finding: {
|
|
13
|
+
id: string;
|
|
14
|
+
channel: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
}): boolean;
|
|
17
|
+
export declare function scan(options: ScanOptions): ScanReport;
|
package/dist/scan.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { buildCorpus } from "./corpus.js";
|
|
2
|
+
import { deriveControls, verifyControls } from "./controls.js";
|
|
3
|
+
import { compileTerm, findMatches, redact } from "./matcher.js";
|
|
4
|
+
import { preflight } from "./preflight.js";
|
|
5
|
+
import { SECRET_PATTERNS } from "./secrets.js";
|
|
6
|
+
import { CHANNELS } from "./types.js";
|
|
7
|
+
export function suppressionMatches(suppression, finding) {
|
|
8
|
+
if (suppression.termId !== finding.id)
|
|
9
|
+
return false;
|
|
10
|
+
if (suppression.channel && suppression.channel !== finding.channel)
|
|
11
|
+
return false;
|
|
12
|
+
if (suppression.path && suppression.path !== finding.path)
|
|
13
|
+
return false;
|
|
14
|
+
if (suppression.pathPrefix) {
|
|
15
|
+
if (!finding.path || !finding.path.startsWith(suppression.pathPrefix))
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
function unitsForChannels(corpus, channels) {
|
|
21
|
+
return corpus.units.filter((unit) => channels.includes(unit.channel));
|
|
22
|
+
}
|
|
23
|
+
export function scan(options) {
|
|
24
|
+
const { repo, config } = options;
|
|
25
|
+
const checks = preflight(repo, {
|
|
26
|
+
allowShallow: options.allowShallow ?? false,
|
|
27
|
+
});
|
|
28
|
+
const corpus = buildCorpus(repo, {
|
|
29
|
+
...((options.maxBlobBytes ?? config.maxBlobBytes)
|
|
30
|
+
? { maxBlobBytes: options.maxBlobBytes ?? config.maxBlobBytes }
|
|
31
|
+
: {}),
|
|
32
|
+
});
|
|
33
|
+
// --- controls first. Everything below is only meaningful if these pass. ---
|
|
34
|
+
const derived = deriveControls(corpus);
|
|
35
|
+
const verification = verifyControls(corpus, derived.controls, config.controls ?? []);
|
|
36
|
+
const untrustedReasons = [...checks.blockers, ...corpus.integrityProblems];
|
|
37
|
+
for (const failure of verification.failures) {
|
|
38
|
+
untrustedReasons.push(`control string for the ${failure.channel} channel matched 0 times; ` +
|
|
39
|
+
`the scanner is not reading ${failure.channel}, so a clean result there means nothing`);
|
|
40
|
+
}
|
|
41
|
+
for (const channel of derived.underivable) {
|
|
42
|
+
untrustedReasons.push(`the ${channel} channel holds data but no control string could be derived from it; ` +
|
|
43
|
+
`the scanner cannot prove it is reading ${channel}`);
|
|
44
|
+
}
|
|
45
|
+
// No controls at all means nothing checked the scanner. "No findings" from a
|
|
46
|
+
// scanner nobody checked is the exact sentence this tool exists to refuse.
|
|
47
|
+
if (verification.results.length === 0) {
|
|
48
|
+
untrustedReasons.push("no control string could be established, so nothing verified that the scanner reads anything at all");
|
|
49
|
+
}
|
|
50
|
+
// A channel with nothing in it cannot be verified, and in a repository that
|
|
51
|
+
// plainly has data an empty channel means the scanner is not reading it.
|
|
52
|
+
const repositoryHasData = corpus.stats.objects > 0 || corpus.stats.refs > 0;
|
|
53
|
+
for (const channel of derived.empty) {
|
|
54
|
+
if (!repositoryHasData)
|
|
55
|
+
continue;
|
|
56
|
+
untrustedReasons.push(`the ${channel} channel produced nothing to scan, in a repository with ` +
|
|
57
|
+
`${corpus.stats.objects} objects and ${corpus.stats.refs} refs; ` +
|
|
58
|
+
`the scanner cannot prove it is reading ${channel}`);
|
|
59
|
+
}
|
|
60
|
+
// --- terms ---------------------------------------------------------------
|
|
61
|
+
const findings = [];
|
|
62
|
+
const suppressed = [];
|
|
63
|
+
const suppressions = config.suppress ?? [];
|
|
64
|
+
const record = (finding) => {
|
|
65
|
+
const hit = suppressions.find((s) => suppressionMatches(s, finding));
|
|
66
|
+
if (hit) {
|
|
67
|
+
suppressed.push({
|
|
68
|
+
id: finding.id,
|
|
69
|
+
channel: finding.channel,
|
|
70
|
+
location: finding.location,
|
|
71
|
+
reason: hit.reason,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
findings.push(finding);
|
|
76
|
+
};
|
|
77
|
+
for (const spec of config.terms) {
|
|
78
|
+
const compiled = compileTerm(spec);
|
|
79
|
+
const channels = spec.channels ?? CHANNELS;
|
|
80
|
+
for (const unit of unitsForChannels(corpus, channels)) {
|
|
81
|
+
const matches = findMatches(compiled.regex, unit.text);
|
|
82
|
+
if (matches.length === 0)
|
|
83
|
+
continue;
|
|
84
|
+
const first = matches[0];
|
|
85
|
+
record({
|
|
86
|
+
kind: "term",
|
|
87
|
+
id: spec.id,
|
|
88
|
+
channel: unit.channel,
|
|
89
|
+
location: unit.location,
|
|
90
|
+
...(unit.path ? { path: unit.path } : {}),
|
|
91
|
+
...(unit.channel === "contents" ? { line: first.line } : {}),
|
|
92
|
+
matches: matches.length,
|
|
93
|
+
sample: options.showMatches ? first.context : redact(first.context),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// --- secrets (secondary) --------------------------------------------------
|
|
98
|
+
if (config.secrets !== false) {
|
|
99
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
100
|
+
for (const unit of corpus.units) {
|
|
101
|
+
const matches = findMatches(pattern.regex, unit.text);
|
|
102
|
+
if (matches.length === 0)
|
|
103
|
+
continue;
|
|
104
|
+
const first = matches[0];
|
|
105
|
+
record({
|
|
106
|
+
kind: "secret",
|
|
107
|
+
id: pattern.id,
|
|
108
|
+
channel: unit.channel,
|
|
109
|
+
location: unit.location,
|
|
110
|
+
...(unit.path ? { path: unit.path } : {}),
|
|
111
|
+
...(unit.channel === "contents" ? { line: first.line } : {}),
|
|
112
|
+
matches: matches.length,
|
|
113
|
+
// Never echo a credential, even with --show-matches.
|
|
114
|
+
sample: redact(first.context),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
repo: repo.root,
|
|
121
|
+
trusted: untrustedReasons.length === 0,
|
|
122
|
+
untrustedReasons,
|
|
123
|
+
controls: verification.results,
|
|
124
|
+
findings,
|
|
125
|
+
suppressed,
|
|
126
|
+
warnings: [
|
|
127
|
+
...checks.warnings,
|
|
128
|
+
...corpus.warnings,
|
|
129
|
+
...verification.warnings,
|
|
130
|
+
],
|
|
131
|
+
stats: corpus.stats,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=scan.js.map
|
package/dist/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|