@greenarmor/ges-git-hooks 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/dist/index.d.ts +16 -0
- package/dist/index.js +112 -0
- package/package.json +43 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Finding } from "@greenarmor/ges-audit-engine";
|
|
2
|
+
export declare const PRE_COMMIT_HOOK = "#!/bin/sh\n# GESF Pre-Commit Hook - Runs compliance audit before allowing commits\n# Installed by @greenarmor/ges-git-hooks\n\necho \"[GESF] Running compliance audit...\"\n\n# Find the GESF CLI\nGES_CLI=\"\"\nif [ -f \"./node_modules/.bin/ges\" ]; then\n GES_CLI=\"./node_modules/.bin/ges\"\nelif command -v ges >/dev/null 2>&1; then\n GES_CLI=\"ges\"\nelif [ -f \"./node_modules/@greenarmor/ges/dist/cli.js\" ]; then\n GES_CLI=\"node ./node_modules/@greenarmor/ges/dist/cli.js\"\nfi\n\nif [ -z \"$GES_CLI\" ]; then\n echo \"[GESF] Warning: ges CLI not found. Skipping audit.\"\n echo \"[GESF] Install with: npm install @greenarmor/ges\"\n exit 0\nfi\n\n# Run audit in CI mode (exits non-zero on findings)\n$GES_CLI audit --ci\nRESULT=$?\n\nif [ $RESULT -ne 0 ]; then\n echo \"\"\n echo \"[GESF] Commit blocked: compliance audit found issues.\"\n echo \"[GESF] Fix with: ges fix\"\n echo \"[GESF] Or bypass with: git commit --no-verify\"\n exit 1\nfi\n\necho \"[GESF] Audit passed. Commit allowed.\"\nexit 0\n";
|
|
3
|
+
export interface HookInstallResult {
|
|
4
|
+
installed: string[];
|
|
5
|
+
skipped: string[];
|
|
6
|
+
errors: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function installHooks(projectRoot: string, hooks?: string[]): HookInstallResult;
|
|
9
|
+
export declare function uninstallHooks(projectRoot: string, hooks?: string[]): HookInstallResult;
|
|
10
|
+
export interface PreCommitResult {
|
|
11
|
+
passed: boolean;
|
|
12
|
+
findings: Finding[];
|
|
13
|
+
totalFindings: number;
|
|
14
|
+
criticalFindings: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function runPreCommitCheck(projectRoot: string): PreCommitResult;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { runAudit, deduplicateFindings } from "@greenarmor/ges-audit-engine";
|
|
4
|
+
export const PRE_COMMIT_HOOK = `#!/bin/sh
|
|
5
|
+
# GESF Pre-Commit Hook - Runs compliance audit before allowing commits
|
|
6
|
+
# Installed by @greenarmor/ges-git-hooks
|
|
7
|
+
|
|
8
|
+
echo "[GESF] Running compliance audit..."
|
|
9
|
+
|
|
10
|
+
# Find the GESF CLI
|
|
11
|
+
GES_CLI=""
|
|
12
|
+
if [ -f "./node_modules/.bin/ges" ]; then
|
|
13
|
+
GES_CLI="./node_modules/.bin/ges"
|
|
14
|
+
elif command -v ges >/dev/null 2>&1; then
|
|
15
|
+
GES_CLI="ges"
|
|
16
|
+
elif [ -f "./node_modules/@greenarmor/ges/dist/cli.js" ]; then
|
|
17
|
+
GES_CLI="node ./node_modules/@greenarmor/ges/dist/cli.js"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
if [ -z "$GES_CLI" ]; then
|
|
21
|
+
echo "[GESF] Warning: ges CLI not found. Skipping audit."
|
|
22
|
+
echo "[GESF] Install with: npm install @greenarmor/ges"
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Run audit in CI mode (exits non-zero on findings)
|
|
27
|
+
$GES_CLI audit --ci
|
|
28
|
+
RESULT=$?
|
|
29
|
+
|
|
30
|
+
if [ $RESULT -ne 0 ]; then
|
|
31
|
+
echo ""
|
|
32
|
+
echo "[GESF] Commit blocked: compliance audit found issues."
|
|
33
|
+
echo "[GESF] Fix with: ges fix"
|
|
34
|
+
echo "[GESF] Or bypass with: git commit --no-verify"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
echo "[GESF] Audit passed. Commit allowed."
|
|
39
|
+
exit 0
|
|
40
|
+
`;
|
|
41
|
+
export function installHooks(projectRoot, hooks = ["pre-commit"]) {
|
|
42
|
+
const result = { installed: [], skipped: [], errors: [] };
|
|
43
|
+
const gitDir = path.join(projectRoot, ".git");
|
|
44
|
+
if (!fs.existsSync(gitDir)) {
|
|
45
|
+
result.errors.push("Not a git repository (.git directory not found)");
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
const hooksDir = path.join(gitDir, "hooks");
|
|
49
|
+
if (!fs.existsSync(hooksDir)) {
|
|
50
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
const hookContents = {
|
|
53
|
+
"pre-commit": PRE_COMMIT_HOOK,
|
|
54
|
+
};
|
|
55
|
+
for (const hookName of hooks) {
|
|
56
|
+
const hookPath = path.join(hooksDir, hookName);
|
|
57
|
+
if (hookContents[hookName] === undefined) {
|
|
58
|
+
result.errors.push(`Unsupported hook: ${hookName}`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (fs.existsSync(hookPath)) {
|
|
62
|
+
const existing = fs.readFileSync(hookPath, "utf-8");
|
|
63
|
+
if (existing.includes("@greenarmor/ges-git-hooks")) {
|
|
64
|
+
fs.writeFileSync(hookPath, hookContents[hookName], "utf-8");
|
|
65
|
+
fs.chmodSync(hookPath, 0o755);
|
|
66
|
+
result.installed.push(hookName);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
result.skipped.push(`${hookName} (already exists, not a GESF hook)`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
fs.writeFileSync(hookPath, hookContents[hookName], "utf-8");
|
|
73
|
+
fs.chmodSync(hookPath, 0o755);
|
|
74
|
+
result.installed.push(hookName);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
export function uninstallHooks(projectRoot, hooks = ["pre-commit"]) {
|
|
79
|
+
const result = { installed: [], skipped: [], errors: [] };
|
|
80
|
+
const hooksDir = path.join(projectRoot, ".git", "hooks");
|
|
81
|
+
if (!fs.existsSync(hooksDir)) {
|
|
82
|
+
result.errors.push("No .git/hooks directory found");
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
for (const hookName of hooks) {
|
|
86
|
+
const hookPath = path.join(hooksDir, hookName);
|
|
87
|
+
if (!fs.existsSync(hookPath)) {
|
|
88
|
+
result.skipped.push(`${hookName} (not installed)`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const content = fs.readFileSync(hookPath, "utf-8");
|
|
92
|
+
if (content.includes("@greenarmor/ges-git-hooks")) {
|
|
93
|
+
fs.unlinkSync(hookPath);
|
|
94
|
+
result.installed.push(`removed ${hookName}`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
result.skipped.push(`${hookName} (not a GESF hook, skipping)`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
export function runPreCommitCheck(projectRoot) {
|
|
103
|
+
const { findings: rawFindings } = runAudit(projectRoot);
|
|
104
|
+
const findings = deduplicateFindings(rawFindings);
|
|
105
|
+
const criticalFindings = findings.filter(f => f.severity === "critical").length;
|
|
106
|
+
return {
|
|
107
|
+
passed: findings.length === 0,
|
|
108
|
+
findings,
|
|
109
|
+
totalFindings: findings.length,
|
|
110
|
+
criticalFindings,
|
|
111
|
+
};
|
|
112
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@greenarmor/ges-git-hooks",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "GESF Git Hooks - Pre-commit compliance enforcement",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
17
|
+
"test": "vitest run"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@greenarmor/ges-core": "workspace:*",
|
|
21
|
+
"@greenarmor/ges-audit-engine": "workspace:*"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"gdpr",
|
|
25
|
+
"compliance",
|
|
26
|
+
"security",
|
|
27
|
+
"git-hooks",
|
|
28
|
+
"pre-commit",
|
|
29
|
+
"gesf",
|
|
30
|
+
"green-armor"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typescript": "^6.0.0",
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"vitest": "^4.1.8"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/greenarmor/gesf"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/greenarmor/gesf"
|
|
43
|
+
}
|