commit-cop 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -20
- package/dist/checks/binaryFileCheck.d.ts +3 -0
- package/dist/checks/binaryFileCheck.d.ts.map +1 -0
- package/dist/checks/binaryFileCheck.js +53 -0
- package/dist/checks/binaryFileCheck.js.map +1 -0
- package/dist/checks/debuggerCheck.d.ts +3 -0
- package/dist/checks/debuggerCheck.d.ts.map +1 -0
- package/dist/checks/debuggerCheck.js +28 -0
- package/dist/checks/debuggerCheck.js.map +1 -0
- package/dist/checks/generatedFolderCheck.d.ts.map +1 -1
- package/dist/checks/generatedFolderCheck.js +7 -2
- package/dist/checks/generatedFolderCheck.js.map +1 -1
- package/dist/checks/junkFileCheck.d.ts +3 -0
- package/dist/checks/junkFileCheck.d.ts.map +1 -0
- package/dist/checks/junkFileCheck.js +30 -0
- package/dist/checks/junkFileCheck.js.map +1 -0
- package/dist/checks/lockfileDriftCheck.d.ts +3 -0
- package/dist/checks/lockfileDriftCheck.d.ts.map +1 -0
- package/dist/checks/lockfileDriftCheck.js +32 -0
- package/dist/checks/lockfileDriftCheck.js.map +1 -0
- package/dist/checks/mergeConflictCheck.d.ts +3 -0
- package/dist/checks/mergeConflictCheck.d.ts.map +1 -0
- package/dist/checks/mergeConflictCheck.js +33 -0
- package/dist/checks/mergeConflictCheck.js.map +1 -0
- package/dist/checks/secretCheck.d.ts.map +1 -1
- package/dist/checks/secretCheck.js +15 -4
- package/dist/checks/secretCheck.js.map +1 -1
- package/dist/checks/sensitiveFilenameCheck.d.ts +3 -0
- package/dist/checks/sensitiveFilenameCheck.d.ts.map +1 -0
- package/dist/checks/sensitiveFilenameCheck.js +41 -0
- package/dist/checks/sensitiveFilenameCheck.js.map +1 -0
- package/dist/checks/utils.d.ts +9 -0
- package/dist/checks/utils.d.ts.map +1 -0
- package/dist/checks/utils.js +48 -0
- package/dist/checks/utils.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +14 -2
- package/dist/scanner.js.map +1 -1
- package/package.json +6 -5
- package/src/brand.ts +3 -0
- package/src/checks/binaryFileCheck.ts +64 -0
- package/src/checks/consoleLogCheck.ts +3 -2
- package/src/checks/debuggerCheck.ts +33 -0
- package/src/checks/envFileCheck.ts +3 -2
- package/src/checks/focusedTestCheck.ts +2 -2
- package/src/checks/generatedFolderCheck.ts +13 -5
- package/src/checks/junkFileCheck.ts +40 -0
- package/src/checks/largeFileCheck.ts +2 -2
- package/src/checks/localHostCheck.ts +2 -2
- package/src/checks/lockfileDriftCheck.ts +40 -0
- package/src/checks/mergeConflictCheck.ts +41 -0
- package/src/checks/secretCheck.ts +33 -17
- package/src/checks/sensitiveFilenameCheck.ts +51 -0
- package/src/checks/utils.ts +62 -0
- package/src/fix/debugCode.ts +74 -0
- package/src/fix/focusedTests.ts +26 -0
- package/src/fix/gitignore.ts +108 -0
- package/src/fix/junkFiles.ts +16 -0
- package/src/fix/lockfile.ts +23 -0
- package/src/fix/matchers.ts +141 -0
- package/src/fix/runFix.ts +96 -0
- package/src/fix/unstage.ts +25 -0
- package/src/fix/utils.ts +50 -0
- package/src/git.ts +2 -1
- package/src/hook.ts +98 -0
- package/src/index.ts +45 -27
- package/src/reporter.ts +70 -30
- package/src/runScan.ts +35 -0
- package/src/scanner.ts +19 -4
- package/src/types.ts +5 -0
- package/test.ts +5 -1
- package/testing.ts +3 -0
package/README.md
CHANGED
|
@@ -1,36 +1,112 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Commit Cop
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Commit Cop is a pre-commit safety checker that scans your **staged files** and warns you about common mistakes before they get pushed to GitHub.
|
|
4
4
|
|
|
5
5
|
Built for students, hackathons, and dev teams who want practical guardrails—not just formatting checks.
|
|
6
6
|
|
|
7
|
+
> **Commit Cop** (`commit-cop`) — catch bad commits before they hit GitHub.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install commit-cop
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Run automatically on every commit (recommended)
|
|
16
|
+
|
|
17
|
+
From your Git repo:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx commit-cop install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This adds a pre-commit hook. After that, **Commit Cop runs whenever you `git commit`**. If it finds errors, the commit is blocked.
|
|
24
|
+
|
|
25
|
+
Treat warnings as errors in the hook:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx commit-cop install --strict
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Remove the hook:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx commit-cop uninstall
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Run manually
|
|
38
|
+
|
|
39
|
+
Scan staged changes once:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx commit-cop
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Treat warnings as errors:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx commit-cop --strict
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Allow `console.log` in staged code (skips the console.log check):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx commit-cop --allow-console-log
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Auto-fix (work in progress)
|
|
58
|
+
|
|
59
|
+
`wip-fix` is a placeholder command name that applies common repo fixes. More fixes may be added over time.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx commit-cop wip-fix
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
By default, `wip-fix` does **not** remove `console.log` lines. Pass `--fix-console-log` to include that fix. `debugger` lines are still removed from staged files.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx commit-cop wip-fix --fix-console-log
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Check | Fix |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| Generated folders / env files | Adds missing `.gitignore` entries (`.env`, `node_modules/`, `dist/`, `build/`, `.next/`, `coverage/`, junk patterns) |
|
|
74
|
+
| Focused tests | Replaces `test.only`, `it.only`, `describe.only` in test/spec files |
|
|
75
|
+
| Debug logs | Removes standalone `console.log(...)` from **staged** JS/TS files only with `--fix-console-log` |
|
|
76
|
+
| Debugger | Always removes standalone `debugger` lines from **staged** JS/TS files |
|
|
77
|
+
| Junk files | Deletes `.DS_Store`, `Thumbs.db`, swap/backup files found on disk |
|
|
78
|
+
| Env / sensitive / generated / junk / binary / large (staged) | Runs `git restore --staged` on matching staged files |
|
|
79
|
+
| Lockfile drift | Runs `npm install` when `package-lock.json` is missing or older than `package.json` |
|
|
80
|
+
| Merge conflicts, secrets, localhost | **Manual only** — reported at the end; not auto-fixed |
|
|
81
|
+
|
|
82
|
+
Review all changes before committing. `wip-fix` may run `npm install` and unstaging commands against your Git index.
|
|
83
|
+
|
|
7
84
|
## What it checks
|
|
8
85
|
|
|
9
86
|
| Check | Severity | What it catches |
|
|
10
87
|
| --- | --- | --- |
|
|
88
|
+
| Merge conflicts | Error | `<<<<<<<`, `=======`, `>>>>>>>` markers left in code |
|
|
11
89
|
| Environment files | Error | `.env`, `.env.local`, and other `.env.*` files |
|
|
12
|
-
|
|
|
13
|
-
|
|
|
90
|
+
| Sensitive filenames | Error | Keys, certs, `credentials.json`, `.npmrc`, and similar |
|
|
91
|
+
| Generated folders | Error | `node_modules/`, `dist/`, `build/`, `.next/`, `coverage/` (including nested paths) |
|
|
92
|
+
| Secrets | Error | API keys, GitHub/AWS/Stripe tokens, JWT secrets, database URLs |
|
|
14
93
|
| Focused tests | Error | `test.only`, `it.only`, `describe.only` left in test files |
|
|
15
|
-
| Debug logs | Warning | `console.log` in staged JS/TS code |
|
|
94
|
+
| Debug logs | Warning | `console.log` in staged JS/TS code (skip with `--allow-console-log`) |
|
|
95
|
+
| Debugger statements | Warning | `debugger` in staged JS/TS code |
|
|
16
96
|
| Localhost URLs | Warning | Hardcoded `localhost` or `127.0.0.1` URLs |
|
|
97
|
+
| Junk files | Warning | `.DS_Store`, `Thumbs.db`, swap/backup files |
|
|
98
|
+
| Lockfile drift | Warning | `package.json` staged without `package-lock.json` (or vice versa) |
|
|
17
99
|
| Large files | Warning | Staged files over 5 MB |
|
|
100
|
+
| Binary files | Warning | `.zip`, `.exe`, `.mp4`, and other non-text files |
|
|
18
101
|
|
|
19
102
|
Errors block the commit. Warnings are reported but do not block unless you use `--strict`.
|
|
20
103
|
|
|
21
|
-
##
|
|
22
|
-
|
|
23
|
-
Run inside a Git repository with staged changes:
|
|
104
|
+
## Local development
|
|
24
105
|
|
|
25
106
|
```bash
|
|
26
107
|
npm install
|
|
27
|
-
npm run
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Treat warnings as errors:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm run commitclean -- --strict
|
|
108
|
+
npm run commit-cop
|
|
109
|
+
npm run commit-cop -- wip-fix
|
|
34
110
|
```
|
|
35
111
|
|
|
36
112
|
Build and run the compiled CLI:
|
|
@@ -44,19 +120,21 @@ npm start
|
|
|
44
120
|
|
|
45
121
|
```
|
|
46
122
|
src/
|
|
47
|
-
index.ts CLI entry point
|
|
123
|
+
index.ts CLI entry point (scan + wip-fix subcommand)
|
|
48
124
|
git.ts Reads staged files from Git
|
|
49
125
|
scanner.ts Runs all checks
|
|
50
126
|
reporter.ts Prints the report
|
|
51
127
|
types.ts Shared types
|
|
52
128
|
checks/ One file per check
|
|
129
|
+
fix/ Auto-fix helpers used by wip-fix
|
|
53
130
|
```
|
|
54
131
|
|
|
55
132
|
Each check implements the same interface: receive staged files, return findings with a message and suggested fix.
|
|
56
133
|
|
|
57
134
|
## How it works
|
|
58
135
|
|
|
59
|
-
1.
|
|
60
|
-
2.
|
|
61
|
-
3.
|
|
62
|
-
4.
|
|
136
|
+
1. Install the hook with `npx commit-cop install` (or run manually)
|
|
137
|
+
2. Read staged file paths with `git diff --cached --name-only`
|
|
138
|
+
3. Run every check in `src/checks/`
|
|
139
|
+
4. Print a summary with file locations and fix suggestions
|
|
140
|
+
5. Exit with code `1` if errors are found (or warnings in strict mode), which blocks the commit
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binaryFileCheck.d.ts","sourceRoot":"","sources":["../../src/checks/binaryFileCheck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AA0BlD,eAAO,MAAM,eAAe,EAAE,KAoC7B,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { getBaseName } from "./utils.js";
|
|
3
|
+
const binaryExtensions = new Set([
|
|
4
|
+
".zip",
|
|
5
|
+
".exe",
|
|
6
|
+
".dll",
|
|
7
|
+
".mp4",
|
|
8
|
+
".mov",
|
|
9
|
+
".sqlite",
|
|
10
|
+
".db",
|
|
11
|
+
]);
|
|
12
|
+
function hasNullBytes(file) {
|
|
13
|
+
const buffer = fs.readFileSync(file);
|
|
14
|
+
const sampleSize = Math.min(buffer.length, 8192);
|
|
15
|
+
for (let index = 0; index < sampleSize; index += 1) {
|
|
16
|
+
if (buffer[index] === 0) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
export const binaryFileCheck = {
|
|
23
|
+
name: "binary-file-check",
|
|
24
|
+
async run(context) {
|
|
25
|
+
const findings = [];
|
|
26
|
+
for (const file of context.stagedFiles) {
|
|
27
|
+
if (!fs.existsSync(file))
|
|
28
|
+
continue;
|
|
29
|
+
const baseName = getBaseName(file);
|
|
30
|
+
const extension = baseName.includes(".")
|
|
31
|
+
? baseName.slice(baseName.lastIndexOf(".")).toLowerCase()
|
|
32
|
+
: "";
|
|
33
|
+
let isBinary = binaryExtensions.has(extension);
|
|
34
|
+
try {
|
|
35
|
+
isBinary ||= hasNullBytes(file);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (isBinary) {
|
|
41
|
+
findings.push({
|
|
42
|
+
severity: "warning",
|
|
43
|
+
checkName: this.name,
|
|
44
|
+
file,
|
|
45
|
+
message: "Binary or non-text file is staged.",
|
|
46
|
+
suggestion: "Remove it from the commit or store it outside Git (e.g. Git LFS).",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return findings;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=binaryFileCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binaryFileCheck.js","sourceRoot":"","sources":["../../src/checks/binaryFileCheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,SAAS;IACT,KAAK;CACN,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAEjD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAU;IACpC,IAAI,EAAE,mBAAmB;IAEzB,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,SAAS;YAEnC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACtC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;gBACzD,CAAC,CAAC,EAAE,CAAC;YAEP,IAAI,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAE/C,IAAI,CAAC;gBACH,QAAQ,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,SAAS;oBACnB,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,IAAI;oBACJ,OAAO,EAAE,oCAAoC;oBAC7C,UAAU,EACR,mEAAmE;iBACtE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debuggerCheck.d.ts","sourceRoot":"","sources":["../../src/checks/debuggerCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,aAAa,EAAE,KA4B3B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isCodeFile, readFileLines } from "./utils.js";
|
|
2
|
+
export const debuggerCheck = {
|
|
3
|
+
name: "debugger-check",
|
|
4
|
+
async run(context) {
|
|
5
|
+
const findings = [];
|
|
6
|
+
for (const file of context.stagedFiles) {
|
|
7
|
+
if (!isCodeFile(file))
|
|
8
|
+
continue;
|
|
9
|
+
const lines = readFileLines(file);
|
|
10
|
+
if (!lines)
|
|
11
|
+
continue;
|
|
12
|
+
lines.forEach((line, index) => {
|
|
13
|
+
if (/\bdebugger\b/.test(line)) {
|
|
14
|
+
findings.push({
|
|
15
|
+
severity: "warning",
|
|
16
|
+
checkName: this.name,
|
|
17
|
+
file,
|
|
18
|
+
line: index + 1,
|
|
19
|
+
message: "debugger statement found in staged code.",
|
|
20
|
+
suggestion: "Remove debugger statements before committing.",
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return findings;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=debuggerCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debuggerCheck.js","sourceRoot":"","sources":["../../src/checks/debuggerCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,CAAC,MAAM,aAAa,GAAU;IAClC,IAAI,EAAE,gBAAgB;IAEtB,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,SAAS;YAEhC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC5B,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9B,QAAQ,CAAC,IAAI,CAAC;wBACZ,QAAQ,EAAE,SAAS;wBACnB,SAAS,EAAE,IAAI,CAAC,IAAI;wBACpB,IAAI;wBACJ,IAAI,EAAE,KAAK,GAAG,CAAC;wBACf,OAAO,EAAE,0CAA0C;wBACnD,UAAU,EAAE,+CAA+C;qBAC5D,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generatedFolderCheck.d.ts","sourceRoot":"","sources":["../../src/checks/generatedFolderCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"generatedFolderCheck.d.ts","sourceRoot":"","sources":["../../src/checks/generatedFolderCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAkBlD,eAAO,MAAM,oBAAoB,EAAE,KA0BlC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePath } from "./utils.js";
|
|
1
2
|
const blockedFolders = [
|
|
2
3
|
"node_modules/",
|
|
3
4
|
"dist/",
|
|
@@ -5,13 +6,17 @@ const blockedFolders = [
|
|
|
5
6
|
".next/",
|
|
6
7
|
"coverage/",
|
|
7
8
|
];
|
|
9
|
+
function matchesBlockedFolder(normalizedPath, folder) {
|
|
10
|
+
return (normalizedPath.startsWith(folder) ||
|
|
11
|
+
normalizedPath.includes(`/${folder}`));
|
|
12
|
+
}
|
|
8
13
|
export const generatedFolderCheck = {
|
|
9
14
|
name: "generated-folder-check",
|
|
10
15
|
async run(context) {
|
|
11
16
|
const findings = [];
|
|
12
17
|
for (const file of context.stagedFiles) {
|
|
13
|
-
const normalized = file
|
|
14
|
-
const matchedFolder = blockedFolders.find((folder) => normalized
|
|
18
|
+
const normalized = normalizePath(file);
|
|
19
|
+
const matchedFolder = blockedFolders.find((folder) => matchesBlockedFolder(normalized, folder));
|
|
15
20
|
if (matchedFolder) {
|
|
16
21
|
findings.push({
|
|
17
22
|
severity: "error",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generatedFolderCheck.js","sourceRoot":"","sources":["../../src/checks/generatedFolderCheck.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generatedFolderCheck.js","sourceRoot":"","sources":["../../src/checks/generatedFolderCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,cAAc,GAAG;IACrB,eAAe;IACf,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,WAAW;CACZ,CAAC;AAEF,SAAS,oBAAoB,CAAC,cAAsB,EAAE,MAAc;IAClE,OAAO,CACL,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC;QACjC,cAAc,CAAC,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC,CACtC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAU;IACzC,IAAI,EAAE,wBAAwB;IAE9B,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAEvC,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CACnD,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,CACzC,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,IAAI;oBACJ,OAAO,EAAE,GAAG,aAAa,kEAAkE;oBAC3F,UAAU,EAAE,OAAO,aAAa,gDAAgD,IAAI,EAAE;iBACvF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junkFileCheck.d.ts","sourceRoot":"","sources":["../../src/checks/junkFileCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAWlD,eAAO,MAAM,aAAa,EAAE,KA2B3B,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getBaseName, matchesAnyPattern } from "./utils.js";
|
|
2
|
+
const junkExactNames = new Set([
|
|
3
|
+
".ds_store",
|
|
4
|
+
"thumbs.db",
|
|
5
|
+
"desktop.ini",
|
|
6
|
+
]);
|
|
7
|
+
const junkNamePatterns = [/\.swp$/i, /\.bak$/i, /\.tmp$/i, /~$/];
|
|
8
|
+
export const junkFileCheck = {
|
|
9
|
+
name: "junk-file-check",
|
|
10
|
+
async run(context) {
|
|
11
|
+
const findings = [];
|
|
12
|
+
for (const file of context.stagedFiles) {
|
|
13
|
+
const baseName = getBaseName(file);
|
|
14
|
+
const normalizedBaseName = baseName.toLowerCase();
|
|
15
|
+
const isJunk = junkExactNames.has(normalizedBaseName) ||
|
|
16
|
+
matchesAnyPattern(baseName, junkNamePatterns);
|
|
17
|
+
if (isJunk) {
|
|
18
|
+
findings.push({
|
|
19
|
+
severity: "warning",
|
|
20
|
+
checkName: this.name,
|
|
21
|
+
file,
|
|
22
|
+
message: "OS or editor junk file is staged.",
|
|
23
|
+
suggestion: `Run: git restore --staged ${file}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return findings;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=junkFileCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junkFileCheck.js","sourceRoot":"","sources":["../../src/checks/junkFileCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW;IACX,WAAW;IACX,aAAa;CACd,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AAEjE,MAAM,CAAC,MAAM,aAAa,GAAU;IAClC,IAAI,EAAE,iBAAiB;IAEvB,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;YAElD,MAAM,MAAM,GACV,cAAc,CAAC,GAAG,CAAC,kBAAkB,CAAC;gBACtC,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;YAEhD,IAAI,MAAM,EAAE,CAAC;gBACX,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,SAAS;oBACnB,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,IAAI;oBACJ,OAAO,EAAE,mCAAmC;oBAC5C,UAAU,EAAE,6BAA6B,IAAI,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfileDriftCheck.d.ts","sourceRoot":"","sources":["../../src/checks/lockfileDriftCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAOlD,eAAO,MAAM,kBAAkB,EAAE,KA8BhC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { normalizePath } from "./utils.js";
|
|
2
|
+
function isStaged(stagedFiles, target) {
|
|
3
|
+
return stagedFiles.some((file) => normalizePath(file) === target);
|
|
4
|
+
}
|
|
5
|
+
export const lockfileDriftCheck = {
|
|
6
|
+
name: "lockfile-drift-check",
|
|
7
|
+
async run(context) {
|
|
8
|
+
const findings = [];
|
|
9
|
+
const packageJsonStaged = isStaged(context.stagedFiles, "package.json");
|
|
10
|
+
const lockfileStaged = isStaged(context.stagedFiles, "package-lock.json");
|
|
11
|
+
if (packageJsonStaged && !lockfileStaged) {
|
|
12
|
+
findings.push({
|
|
13
|
+
severity: "warning",
|
|
14
|
+
checkName: this.name,
|
|
15
|
+
file: "package.json",
|
|
16
|
+
message: "package.json is staged but package-lock.json is not.",
|
|
17
|
+
suggestion: "Run npm install and stage package-lock.json.",
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (lockfileStaged && !packageJsonStaged) {
|
|
21
|
+
findings.push({
|
|
22
|
+
severity: "warning",
|
|
23
|
+
checkName: this.name,
|
|
24
|
+
file: "package-lock.json",
|
|
25
|
+
message: "package-lock.json is staged but package.json is not.",
|
|
26
|
+
suggestion: "Stage package.json or unstage the lockfile.",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return findings;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=lockfileDriftCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfileDriftCheck.js","sourceRoot":"","sources":["../../src/checks/lockfileDriftCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,SAAS,QAAQ,CAAC,WAAqB,EAAE,MAAc;IACrD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAU;IACvC,IAAI,EAAE,sBAAsB;IAE5B,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QACxE,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;QAE1E,IAAI,iBAAiB,IAAI,CAAC,cAAc,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,IAAI,CAAC,IAAI;gBACpB,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,sDAAsD;gBAC/D,UAAU,EAAE,8CAA8C;aAC3D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,cAAc,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,IAAI,CAAC,IAAI;gBACpB,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,sDAAsD;gBAC/D,UAAU,EAAE,6CAA6C;aAC1D,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeConflictCheck.d.ts","sourceRoot":"","sources":["../../src/checks/mergeConflictCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAKlD,eAAO,MAAM,kBAAkB,EAAE,KAkChC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFileLines, shouldSkipContentScan } from "./utils.js";
|
|
2
|
+
const conflictMarkers = ["<<<<<<<", "=======", ">>>>>>>"];
|
|
3
|
+
export const mergeConflictCheck = {
|
|
4
|
+
name: "merge-conflict-check",
|
|
5
|
+
async run(context) {
|
|
6
|
+
const findings = [];
|
|
7
|
+
for (const file of context.stagedFiles) {
|
|
8
|
+
if (shouldSkipContentScan(file))
|
|
9
|
+
continue;
|
|
10
|
+
const lines = readFileLines(file);
|
|
11
|
+
if (!lines)
|
|
12
|
+
continue;
|
|
13
|
+
lines.forEach((line, index) => {
|
|
14
|
+
const trimmed = line.trim();
|
|
15
|
+
for (const marker of conflictMarkers) {
|
|
16
|
+
if (trimmed.startsWith(marker)) {
|
|
17
|
+
findings.push({
|
|
18
|
+
severity: "error",
|
|
19
|
+
checkName: this.name,
|
|
20
|
+
file,
|
|
21
|
+
line: index + 1,
|
|
22
|
+
message: "Merge conflict marker found in staged file.",
|
|
23
|
+
suggestion: "Resolve the conflict, remove the markers, and restage the file.",
|
|
24
|
+
});
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return findings;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=mergeConflictCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeConflictCheck.js","sourceRoot":"","sources":["../../src/checks/mergeConflictCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,kBAAkB,GAAU;IACvC,IAAI,EAAE,sBAAsB;IAE5B,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,qBAAqB,CAAC,IAAI,CAAC;gBAAE,SAAS;YAE1C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAE5B,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;oBACrC,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC/B,QAAQ,CAAC,IAAI,CAAC;4BACZ,QAAQ,EAAE,OAAO;4BACjB,SAAS,EAAE,IAAI,CAAC,IAAI;4BACpB,IAAI;4BACJ,IAAI,EAAE,KAAK,GAAG,CAAC;4BACf,OAAO,EAAE,6CAA6C;4BACtD,UAAU,EACR,iEAAiE;yBACpE,CAAC,CAAC;wBACH,OAAO;oBACT,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secretCheck.d.ts","sourceRoot":"","sources":["../../src/checks/secretCheck.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"secretCheck.d.ts","sourceRoot":"","sources":["../../src/checks/secretCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAyBlD,eAAO,MAAM,WAAW,EAAE,KAkCzB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isCommentLine, isPlaceholderValue, readFileLines, shouldSkipContentScan, } from "./utils.js";
|
|
2
2
|
const secretPatterns = [
|
|
3
3
|
/OPENAI_API_KEY\s*=/i,
|
|
4
4
|
/DATABASE_URL\s*=/i,
|
|
@@ -7,17 +7,27 @@ const secretPatterns = [
|
|
|
7
7
|
/PRIVATE_KEY\s*=/i,
|
|
8
8
|
/SECRET_KEY\s*=/i,
|
|
9
9
|
/sk-[A-Za-z0-9_-]{20,}/,
|
|
10
|
+
/ghp_[A-Za-z0-9]{36,}/,
|
|
11
|
+
/github_pat_[A-Za-z0-9_]+/,
|
|
12
|
+
/AKIA[0-9A-Z]{16}/,
|
|
13
|
+
/sk_live_[A-Za-z0-9]+/,
|
|
14
|
+
/AIza[0-9A-Za-z_-]{35}/,
|
|
15
|
+
/hooks\.slack\.com\/services\//,
|
|
16
|
+
/password\s*=\s*['"][^'"]{8,}['"]/i,
|
|
10
17
|
];
|
|
11
18
|
export const secretCheck = {
|
|
12
19
|
name: "secret-check",
|
|
13
20
|
async run(context) {
|
|
14
21
|
const findings = [];
|
|
15
22
|
for (const file of context.stagedFiles) {
|
|
16
|
-
if (
|
|
23
|
+
if (shouldSkipContentScan(file))
|
|
24
|
+
continue;
|
|
25
|
+
const lines = readFileLines(file);
|
|
26
|
+
if (!lines)
|
|
17
27
|
continue;
|
|
18
|
-
const content = fs.readFileSync(file, "utf-8");
|
|
19
|
-
const lines = content.split("\n");
|
|
20
28
|
lines.forEach((line, index) => {
|
|
29
|
+
if (isCommentLine(line) || isPlaceholderValue(line))
|
|
30
|
+
return;
|
|
21
31
|
for (const pattern of secretPatterns) {
|
|
22
32
|
if (pattern.test(line)) {
|
|
23
33
|
findings.push({
|
|
@@ -28,6 +38,7 @@ export const secretCheck = {
|
|
|
28
38
|
message: "Possible secret found in staged file.",
|
|
29
39
|
suggestion: "Remove the secret and rotate it if it was already pushed.",
|
|
30
40
|
});
|
|
41
|
+
return;
|
|
31
42
|
}
|
|
32
43
|
}
|
|
33
44
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secretCheck.js","sourceRoot":"","sources":["../../src/checks/secretCheck.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"secretCheck.js","sourceRoot":"","sources":["../../src/checks/secretCheck.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,MAAM,cAAc,GAAG;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,uBAAuB;IACvB,sBAAsB;IACtB,0BAA0B;IAC1B,kBAAkB;IAClB,sBAAsB;IACtB,uBAAuB;IACvB,+BAA+B;IAC/B,mCAAmC;CACpC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAU;IAChC,IAAI,EAAE,cAAc;IAEpB,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,qBAAqB,CAAC,IAAI,CAAC;gBAAE,SAAS;YAE1C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAC5B,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAE5D,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;oBACrC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,QAAQ,CAAC,IAAI,CAAC;4BACZ,QAAQ,EAAE,OAAO;4BACjB,SAAS,EAAE,IAAI,CAAC,IAAI;4BACpB,IAAI;4BACJ,IAAI,EAAE,KAAK,GAAG,CAAC;4BACf,OAAO,EAAE,uCAAuC;4BAChD,UAAU,EACR,2DAA2D;yBAC9D,CAAC,CAAC;wBACH,OAAO;oBACT,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitiveFilenameCheck.d.ts","sourceRoot":"","sources":["../../src/checks/sensitiveFilenameCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAW,MAAM,aAAa,CAAC;AAmBlD,eAAO,MAAM,sBAAsB,EAAE,KA8BpC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getBaseName, matchesAnyPattern, normalizePath } from "./utils.js";
|
|
2
|
+
const sensitiveExactNames = new Set([
|
|
3
|
+
"id_rsa",
|
|
4
|
+
"id_ed25519",
|
|
5
|
+
"credentials.json",
|
|
6
|
+
"serviceaccountkey.json",
|
|
7
|
+
".npmrc",
|
|
8
|
+
".pypirc",
|
|
9
|
+
]);
|
|
10
|
+
const sensitiveNamePatterns = [
|
|
11
|
+
/\.pem$/i,
|
|
12
|
+
/\.p12$/i,
|
|
13
|
+
/\.key$/i,
|
|
14
|
+
/^firebase-adminsdk.*\.json$/i,
|
|
15
|
+
];
|
|
16
|
+
export const sensitiveFilenameCheck = {
|
|
17
|
+
name: "sensitive-filename-check",
|
|
18
|
+
async run(context) {
|
|
19
|
+
const findings = [];
|
|
20
|
+
for (const file of context.stagedFiles) {
|
|
21
|
+
const baseName = getBaseName(file);
|
|
22
|
+
const normalizedBaseName = baseName.toLowerCase();
|
|
23
|
+
const normalizedPath = normalizePath(file).toLowerCase();
|
|
24
|
+
const isSensitive = sensitiveExactNames.has(normalizedBaseName) ||
|
|
25
|
+
matchesAnyPattern(baseName, sensitiveNamePatterns) ||
|
|
26
|
+
normalizedPath.endsWith("/credentials.json") ||
|
|
27
|
+
normalizedPath.includes("serviceaccountkey.json");
|
|
28
|
+
if (isSensitive) {
|
|
29
|
+
findings.push({
|
|
30
|
+
severity: "error",
|
|
31
|
+
checkName: this.name,
|
|
32
|
+
file,
|
|
33
|
+
message: "Sensitive credential file is staged.",
|
|
34
|
+
suggestion: `Run: git restore --staged ${file}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return findings;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=sensitiveFilenameCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitiveFilenameCheck.js","sourceRoot":"","sources":["../../src/checks/sensitiveFilenameCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,QAAQ;IACR,YAAY;IACZ,kBAAkB;IAClB,wBAAwB;IACxB,QAAQ;IACR,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG;IAC5B,SAAS;IACT,SAAS;IACT,SAAS;IACT,8BAA8B;CAC/B,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAU;IAC3C,IAAI,EAAE,0BAA0B;IAEhC,KAAK,CAAC,GAAG,CAAC,OAAO;QACf,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;YAClD,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAEzD,MAAM,WAAW,GACf,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,CAAC;gBAC3C,iBAAiB,CAAC,QAAQ,EAAE,qBAAqB,CAAC;gBAClD,cAAc,CAAC,QAAQ,CAAC,mBAAmB,CAAC;gBAC5C,cAAc,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;YAEpD,IAAI,WAAW,EAAE,CAAC;gBAChB,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,IAAI;oBACJ,OAAO,EAAE,sCAAsC;oBAC/C,UAAU,EAAE,6BAA6B,IAAI,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function normalizePath(file: string): string;
|
|
2
|
+
export declare function getBaseName(file: string): string;
|
|
3
|
+
export declare function isCodeFile(file: string): boolean;
|
|
4
|
+
export declare function shouldSkipContentScan(file: string): boolean;
|
|
5
|
+
export declare function readFileLines(file: string): string[] | null;
|
|
6
|
+
export declare function isCommentLine(line: string): boolean;
|
|
7
|
+
export declare function isPlaceholderValue(line: string): boolean;
|
|
8
|
+
export declare function matchesAnyPattern(value: string, patterns: RegExp[]): boolean;
|
|
9
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"AAgBA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAQ3D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQnD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAET"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const CODE_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx"];
|
|
3
|
+
const SKIP_CONTENT_EXTENSIONS = [".md", ".example", ".sample"];
|
|
4
|
+
const PLACEHOLDER_PATTERNS = [
|
|
5
|
+
/your-api-key/i,
|
|
6
|
+
/changeme/i,
|
|
7
|
+
/xxx+/i,
|
|
8
|
+
/TODO/i,
|
|
9
|
+
/placeholder/i,
|
|
10
|
+
/example/i,
|
|
11
|
+
/replace-me/i,
|
|
12
|
+
];
|
|
13
|
+
export function normalizePath(file) {
|
|
14
|
+
return file.replaceAll("\\", "/");
|
|
15
|
+
}
|
|
16
|
+
export function getBaseName(file) {
|
|
17
|
+
return normalizePath(file).split("/").pop() ?? "";
|
|
18
|
+
}
|
|
19
|
+
export function isCodeFile(file) {
|
|
20
|
+
return CODE_EXTENSIONS.some((ext) => file.endsWith(ext));
|
|
21
|
+
}
|
|
22
|
+
export function shouldSkipContentScan(file) {
|
|
23
|
+
return SKIP_CONTENT_EXTENSIONS.some((ext) => file.endsWith(ext));
|
|
24
|
+
}
|
|
25
|
+
export function readFileLines(file) {
|
|
26
|
+
if (!fs.existsSync(file))
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
return fs.readFileSync(file, "utf-8").split("\n");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function isCommentLine(line) {
|
|
36
|
+
const trimmed = line.trim();
|
|
37
|
+
return (trimmed.startsWith("//") ||
|
|
38
|
+
trimmed.startsWith("#") ||
|
|
39
|
+
trimmed.startsWith("*") ||
|
|
40
|
+
trimmed.startsWith("/*"));
|
|
41
|
+
}
|
|
42
|
+
export function isPlaceholderValue(line) {
|
|
43
|
+
return PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(line));
|
|
44
|
+
}
|
|
45
|
+
export function matchesAnyPattern(value, patterns) {
|
|
46
|
+
return patterns.some((pattern) => pattern.test(value));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEvD,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAE/D,MAAM,oBAAoB,GAAG;IAC3B,eAAe;IACf,WAAW;IACX,OAAO;IACP,OAAO;IACP,cAAc;IACd,UAAU;IACV,aAAa;CACd,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,CACL,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QACxB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QACvB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QACvB,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,QAAkB;IAElB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { runChecks } from "./scanner.js";
|
|
|
5
5
|
import { printReport } from "./reporter.js";
|
|
6
6
|
const program = new Command();
|
|
7
7
|
program
|
|
8
|
-
.name("
|
|
8
|
+
.name("commit-cop")
|
|
9
9
|
.description("Pre-commit safety checker for staged files")
|
|
10
10
|
.option("--strict", "Treat warnings as errors")
|
|
11
11
|
.action(async (options) => {
|