@astrasyncai/verification-gateway 1.1.0 → 2.0.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/adapter-interface/interface.d.mts +71 -0
- package/dist/adapter-interface/interface.d.ts +71 -0
- package/dist/adapter-interface/interface.js +36 -0
- package/dist/adapter-interface/interface.js.map +1 -0
- package/dist/adapter-interface/interface.mjs +10 -0
- package/dist/adapter-interface/interface.mjs.map +1 -0
- package/dist/adapter-interface/purpose-mapping.d.mts +28 -0
- package/dist/adapter-interface/purpose-mapping.d.ts +28 -0
- package/dist/adapter-interface/purpose-mapping.js +117 -0
- package/dist/adapter-interface/purpose-mapping.js.map +1 -0
- package/dist/adapter-interface/purpose-mapping.mjs +89 -0
- package/dist/adapter-interface/purpose-mapping.mjs.map +1 -0
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +6 -7
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +6 -7
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +5 -7
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +5 -7
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +6 -2
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +6 -2
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -0
- package/dist/agent/index.d.ts +2 -0
- package/dist/agent/index.js +354 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/index.mjs +323 -0
- package/dist/agent/index.mjs.map +1 -0
- package/dist/browser/browser-adapter.d.mts +106 -0
- package/dist/browser/browser-adapter.d.ts +106 -0
- package/dist/browser/browser-adapter.js +286 -0
- package/dist/browser/browser-adapter.js.map +1 -0
- package/dist/browser/browser-adapter.mjs +259 -0
- package/dist/browser/browser-adapter.mjs.map +1 -0
- package/dist/cli/index.d.mts +241 -0
- package/dist/cli/index.d.ts +241 -0
- package/dist/cli/index.js +3734 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +3688 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/cursor/cursor-adapter.d.mts +92 -0
- package/dist/cursor/cursor-adapter.d.ts +92 -0
- package/dist/cursor/cursor-adapter.js +273 -0
- package/dist/cursor/cursor-adapter.js.map +1 -0
- package/dist/cursor/cursor-adapter.mjs +246 -0
- package/dist/cursor/cursor-adapter.mjs.map +1 -0
- package/dist/{express-BoayLpqq.d.mts → express-Cp4eg77F.d.mts} +1 -1
- package/dist/{express-BGZiLINd.d.ts → express-DIEyq1Tz.d.ts} +1 -1
- package/dist/gateway/gateway.d.mts +70 -0
- package/dist/gateway/gateway.d.ts +70 -0
- package/dist/gateway/gateway.js +3726 -0
- package/dist/gateway/gateway.js.map +1 -0
- package/dist/gateway/gateway.mjs +3706 -0
- package/dist/gateway/gateway.mjs.map +1 -0
- package/dist/git-trigger/git-hooks.d.mts +69 -0
- package/dist/git-trigger/git-hooks.d.ts +69 -0
- package/dist/git-trigger/git-hooks.js +244 -0
- package/dist/git-trigger/git-hooks.js.map +1 -0
- package/dist/git-trigger/git-hooks.mjs +221 -0
- package/dist/git-trigger/git-hooks.mjs.map +1 -0
- package/dist/index-BhTbGU-o.d.mts +206 -0
- package/dist/index-Bhfxq9xI.d.ts +206 -0
- package/dist/index-CNkmHmpi.d.ts +89 -0
- package/dist/index-CoLebmwv.d.mts +89 -0
- package/dist/index.d.mts +8 -295
- package/dist/index.d.ts +8 -295
- package/dist/index.js +17 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17 -16
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +55 -0
- package/dist/local-evaluator/evaluator.d.ts +55 -0
- package/dist/local-evaluator/evaluator.js +272 -0
- package/dist/local-evaluator/evaluator.js.map +1 -0
- package/dist/local-evaluator/evaluator.mjs +244 -0
- package/dist/local-evaluator/evaluator.mjs.map +1 -0
- package/dist/{nextjs-DTCS5Sw8.d.ts → nextjs-Cag7libc.d.ts} +1 -1
- package/dist/{nextjs-BNbHm5Ui.d.mts → nextjs-_C_FcJY5.d.mts} +1 -1
- package/dist/{sdk-9TKZzhxE.d.ts → sdk-CMPDFUjo.d.ts} +3 -1
- package/dist/{sdk-VAFRmdt7.d.mts → sdk-DAJahT3p.d.mts} +3 -1
- package/dist/transport/index.d.mts +2 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/index.js +211 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/index.mjs +176 -0
- package/dist/transport/index.mjs.map +1 -0
- package/dist/{types-cA_xfFU7.d.mts → types-Bf8pML07.d.mts} +1 -1
- package/dist/{types-cA_xfFU7.d.ts → types-Bf8pML07.d.ts} +1 -1
- package/dist/types-BvpGdsv1.d.mts +153 -0
- package/dist/types-Ce2mFJkO.d.ts +153 -0
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +46 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AstraSyncGateway } from '../gateway/gateway.mjs';
|
|
2
|
+
import { V as VerificationDecision, P as PDLSSContext } from '../types-BvpGdsv1.mjs';
|
|
3
|
+
import '../types-Bf8pML07.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Git Trigger — Enterprise git push / PR verification
|
|
7
|
+
*
|
|
8
|
+
* Installs git hooks that evaluate changed files against the PDLSS policy
|
|
9
|
+
* before allowing pushes to remote repositories.
|
|
10
|
+
*
|
|
11
|
+
* Two enforcement modes (admin-configurable):
|
|
12
|
+
* - block: non-zero exit prevents the push
|
|
13
|
+
* - warn: push proceeds but warning is printed
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface GitTriggerConfig {
|
|
17
|
+
/** Block the push or just warn (default: 'warn') */
|
|
18
|
+
enforcement: 'block' | 'warn';
|
|
19
|
+
/** Which git hooks to install (default: ['pre-push']) */
|
|
20
|
+
hooks: ('pre-push' | 'pre-commit')[];
|
|
21
|
+
/** Only enforce on these branches (default: all) */
|
|
22
|
+
protectedBranches?: string[];
|
|
23
|
+
/** Custom message for blocked pushes */
|
|
24
|
+
blockMessage?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Install git hooks into the repository.
|
|
28
|
+
* Returns the paths of installed hooks.
|
|
29
|
+
*/
|
|
30
|
+
declare function installGitHooks(repoRoot: string, config?: Partial<GitTriggerConfig>): {
|
|
31
|
+
installed: string[];
|
|
32
|
+
skipped: string[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Remove AstraSync-managed git hooks.
|
|
36
|
+
*/
|
|
37
|
+
declare function uninstallGitHooks(repoRoot: string, hooks?: ('pre-push' | 'pre-commit')[]): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Get list of changed files for the current trigger context.
|
|
40
|
+
*/
|
|
41
|
+
declare function getChangedFiles(trigger: 'pre-push' | 'pre-commit', repoRoot: string): string[];
|
|
42
|
+
/**
|
|
43
|
+
* Map a file change to a PDLSS context for evaluation.
|
|
44
|
+
*/
|
|
45
|
+
declare function fileChangeToPDLSSContext(filePath: string): PDLSSContext;
|
|
46
|
+
/**
|
|
47
|
+
* Evaluate changed files against the gateway policy.
|
|
48
|
+
* Returns a summary of allow/deny/review decisions.
|
|
49
|
+
*/
|
|
50
|
+
declare function evaluateChangedFiles(gateway: AstraSyncGateway, files: string[], config?: Partial<GitTriggerConfig>): Promise<GitCheckResult>;
|
|
51
|
+
interface GitCheckResult {
|
|
52
|
+
allowed: number;
|
|
53
|
+
blocked: number;
|
|
54
|
+
warned: number;
|
|
55
|
+
total: number;
|
|
56
|
+
shouldBlock: boolean;
|
|
57
|
+
enforcement: 'block' | 'warn';
|
|
58
|
+
results: {
|
|
59
|
+
file: string;
|
|
60
|
+
decision: VerificationDecision;
|
|
61
|
+
}[];
|
|
62
|
+
blockMessage?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if the current branch is protected.
|
|
66
|
+
*/
|
|
67
|
+
declare function isProtectedBranch(config?: Partial<GitTriggerConfig>): boolean;
|
|
68
|
+
|
|
69
|
+
export { type GitCheckResult, type GitTriggerConfig, evaluateChangedFiles, fileChangeToPDLSSContext, getChangedFiles, installGitHooks, isProtectedBranch, uninstallGitHooks };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AstraSyncGateway } from '../gateway/gateway.js';
|
|
2
|
+
import { V as VerificationDecision, P as PDLSSContext } from '../types-Ce2mFJkO.js';
|
|
3
|
+
import '../types-Bf8pML07.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Git Trigger — Enterprise git push / PR verification
|
|
7
|
+
*
|
|
8
|
+
* Installs git hooks that evaluate changed files against the PDLSS policy
|
|
9
|
+
* before allowing pushes to remote repositories.
|
|
10
|
+
*
|
|
11
|
+
* Two enforcement modes (admin-configurable):
|
|
12
|
+
* - block: non-zero exit prevents the push
|
|
13
|
+
* - warn: push proceeds but warning is printed
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface GitTriggerConfig {
|
|
17
|
+
/** Block the push or just warn (default: 'warn') */
|
|
18
|
+
enforcement: 'block' | 'warn';
|
|
19
|
+
/** Which git hooks to install (default: ['pre-push']) */
|
|
20
|
+
hooks: ('pre-push' | 'pre-commit')[];
|
|
21
|
+
/** Only enforce on these branches (default: all) */
|
|
22
|
+
protectedBranches?: string[];
|
|
23
|
+
/** Custom message for blocked pushes */
|
|
24
|
+
blockMessage?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Install git hooks into the repository.
|
|
28
|
+
* Returns the paths of installed hooks.
|
|
29
|
+
*/
|
|
30
|
+
declare function installGitHooks(repoRoot: string, config?: Partial<GitTriggerConfig>): {
|
|
31
|
+
installed: string[];
|
|
32
|
+
skipped: string[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Remove AstraSync-managed git hooks.
|
|
36
|
+
*/
|
|
37
|
+
declare function uninstallGitHooks(repoRoot: string, hooks?: ('pre-push' | 'pre-commit')[]): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Get list of changed files for the current trigger context.
|
|
40
|
+
*/
|
|
41
|
+
declare function getChangedFiles(trigger: 'pre-push' | 'pre-commit', repoRoot: string): string[];
|
|
42
|
+
/**
|
|
43
|
+
* Map a file change to a PDLSS context for evaluation.
|
|
44
|
+
*/
|
|
45
|
+
declare function fileChangeToPDLSSContext(filePath: string): PDLSSContext;
|
|
46
|
+
/**
|
|
47
|
+
* Evaluate changed files against the gateway policy.
|
|
48
|
+
* Returns a summary of allow/deny/review decisions.
|
|
49
|
+
*/
|
|
50
|
+
declare function evaluateChangedFiles(gateway: AstraSyncGateway, files: string[], config?: Partial<GitTriggerConfig>): Promise<GitCheckResult>;
|
|
51
|
+
interface GitCheckResult {
|
|
52
|
+
allowed: number;
|
|
53
|
+
blocked: number;
|
|
54
|
+
warned: number;
|
|
55
|
+
total: number;
|
|
56
|
+
shouldBlock: boolean;
|
|
57
|
+
enforcement: 'block' | 'warn';
|
|
58
|
+
results: {
|
|
59
|
+
file: string;
|
|
60
|
+
decision: VerificationDecision;
|
|
61
|
+
}[];
|
|
62
|
+
blockMessage?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if the current branch is protected.
|
|
66
|
+
*/
|
|
67
|
+
declare function isProtectedBranch(config?: Partial<GitTriggerConfig>): boolean;
|
|
68
|
+
|
|
69
|
+
export { type GitCheckResult, type GitTriggerConfig, evaluateChangedFiles, fileChangeToPDLSSContext, getChangedFiles, installGitHooks, isProtectedBranch, uninstallGitHooks };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/git-trigger/git-hooks.ts
|
|
21
|
+
var git_hooks_exports = {};
|
|
22
|
+
__export(git_hooks_exports, {
|
|
23
|
+
evaluateChangedFiles: () => evaluateChangedFiles,
|
|
24
|
+
fileChangeToPDLSSContext: () => fileChangeToPDLSSContext,
|
|
25
|
+
getChangedFiles: () => getChangedFiles,
|
|
26
|
+
installGitHooks: () => installGitHooks,
|
|
27
|
+
isProtectedBranch: () => isProtectedBranch,
|
|
28
|
+
uninstallGitHooks: () => uninstallGitHooks
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(git_hooks_exports);
|
|
31
|
+
var import_fs = require("fs");
|
|
32
|
+
var import_path = require("path");
|
|
33
|
+
var import_child_process = require("child_process");
|
|
34
|
+
|
|
35
|
+
// src/adapter-interface/purpose-mapping.ts
|
|
36
|
+
var TOOL_PURPOSE_MAP = {
|
|
37
|
+
// Shell
|
|
38
|
+
shell_exec: "shell.exec",
|
|
39
|
+
run_command: "shell.exec",
|
|
40
|
+
execute: "shell.exec",
|
|
41
|
+
terminal_exec: "shell.exec",
|
|
42
|
+
run_terminal_command: "shell.exec",
|
|
43
|
+
// File read
|
|
44
|
+
file_read: "file.read",
|
|
45
|
+
read_file: "file.read",
|
|
46
|
+
// File write
|
|
47
|
+
file_write: "file.write",
|
|
48
|
+
write_file: "file.write",
|
|
49
|
+
create_file: "file.write",
|
|
50
|
+
edit_file: "file.write",
|
|
51
|
+
// File delete
|
|
52
|
+
file_delete: "file.delete",
|
|
53
|
+
delete_file: "file.delete",
|
|
54
|
+
// Network
|
|
55
|
+
http_request: "network.request",
|
|
56
|
+
fetch: "network.request",
|
|
57
|
+
web_request: "network.request",
|
|
58
|
+
// Email
|
|
59
|
+
send_email: "email.send",
|
|
60
|
+
read_email: "email.read",
|
|
61
|
+
// Calendar
|
|
62
|
+
create_event: "calendar.create",
|
|
63
|
+
// Database
|
|
64
|
+
query_database: "database.query",
|
|
65
|
+
write_database: "database.write",
|
|
66
|
+
// Payment
|
|
67
|
+
payment_execute: "payment.execute"
|
|
68
|
+
};
|
|
69
|
+
function mapToolToPurpose(toolName) {
|
|
70
|
+
return TOOL_PURPOSE_MAP[toolName] || `tool.${toolName}`;
|
|
71
|
+
}
|
|
72
|
+
function extractTarget(toolName, args) {
|
|
73
|
+
const purpose = mapToolToPurpose(toolName);
|
|
74
|
+
if (purpose.startsWith("shell.")) {
|
|
75
|
+
return String(args.command || args.cmd || args.script || "");
|
|
76
|
+
}
|
|
77
|
+
if (purpose.startsWith("file.")) {
|
|
78
|
+
return String(args.path || args.file || args.filename || args.file_path || "");
|
|
79
|
+
}
|
|
80
|
+
if (purpose.startsWith("network.")) {
|
|
81
|
+
return String(args.url || args.endpoint || args.uri || "");
|
|
82
|
+
}
|
|
83
|
+
if (purpose.startsWith("email.")) {
|
|
84
|
+
return String(args.to || args.recipient || args.address || "");
|
|
85
|
+
}
|
|
86
|
+
if (purpose.startsWith("database.")) {
|
|
87
|
+
return String(args.query || args.table || "");
|
|
88
|
+
}
|
|
89
|
+
if (purpose.startsWith("payment.")) {
|
|
90
|
+
return String(args.description || args.merchant || args.amount || "");
|
|
91
|
+
}
|
|
92
|
+
if (args.command) return String(args.command);
|
|
93
|
+
if (args.path) return String(args.path);
|
|
94
|
+
if (args.url) return String(args.url);
|
|
95
|
+
for (const val of Object.values(args)) {
|
|
96
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
97
|
+
}
|
|
98
|
+
return toolName;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/git-trigger/git-hooks.ts
|
|
102
|
+
var DEFAULT_CONFIG = {
|
|
103
|
+
enforcement: "warn",
|
|
104
|
+
hooks: ["pre-push"]
|
|
105
|
+
};
|
|
106
|
+
var HOOK_MARKER = "# AstraSync Local Guard \u2014 managed hook";
|
|
107
|
+
function makeHookScript(hookType) {
|
|
108
|
+
return `#!/bin/sh
|
|
109
|
+
${HOOK_MARKER}
|
|
110
|
+
# Runs AstraSync verification on changed files before ${hookType === "pre-push" ? "push" : "commit"}.
|
|
111
|
+
# Installed by: astrasync guard install-hooks
|
|
112
|
+
# To remove: delete this file or run astrasync guard uninstall-hooks
|
|
113
|
+
|
|
114
|
+
npx astrasync guard check --trigger=${hookType} "$@"
|
|
115
|
+
exit $?
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
function installGitHooks(repoRoot, config = {}) {
|
|
119
|
+
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
120
|
+
const hooksDir = (0, import_path.join)(repoRoot, ".git", "hooks");
|
|
121
|
+
const installed = [];
|
|
122
|
+
const skipped = [];
|
|
123
|
+
if (!(0, import_fs.existsSync)((0, import_path.join)(repoRoot, ".git"))) {
|
|
124
|
+
throw new Error(`Not a git repository: ${repoRoot}`);
|
|
125
|
+
}
|
|
126
|
+
if (!(0, import_fs.existsSync)(hooksDir)) {
|
|
127
|
+
(0, import_fs.mkdirSync)(hooksDir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
for (const hookType of merged.hooks) {
|
|
130
|
+
const hookPath = (0, import_path.join)(hooksDir, hookType);
|
|
131
|
+
if ((0, import_fs.existsSync)(hookPath)) {
|
|
132
|
+
const content = (0, import_fs.readFileSync)(hookPath, "utf-8");
|
|
133
|
+
if (!content.includes(HOOK_MARKER)) {
|
|
134
|
+
skipped.push(hookPath);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
(0, import_fs.writeFileSync)(hookPath, makeHookScript(hookType), "utf-8");
|
|
139
|
+
(0, import_fs.chmodSync)(hookPath, 493);
|
|
140
|
+
installed.push(hookPath);
|
|
141
|
+
}
|
|
142
|
+
return { installed, skipped };
|
|
143
|
+
}
|
|
144
|
+
function uninstallGitHooks(repoRoot, hooks = ["pre-push"]) {
|
|
145
|
+
const hooksDir = (0, import_path.join)(repoRoot, ".git", "hooks");
|
|
146
|
+
const removed = [];
|
|
147
|
+
for (const hookType of hooks) {
|
|
148
|
+
const hookPath = (0, import_path.join)(hooksDir, hookType);
|
|
149
|
+
if ((0, import_fs.existsSync)(hookPath)) {
|
|
150
|
+
const content = (0, import_fs.readFileSync)(hookPath, "utf-8");
|
|
151
|
+
if (content.includes(HOOK_MARKER)) {
|
|
152
|
+
const { unlinkSync } = require("fs");
|
|
153
|
+
unlinkSync(hookPath);
|
|
154
|
+
removed.push(hookPath);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return removed;
|
|
159
|
+
}
|
|
160
|
+
function getChangedFiles(trigger, repoRoot) {
|
|
161
|
+
try {
|
|
162
|
+
let output;
|
|
163
|
+
if (trigger === "pre-push") {
|
|
164
|
+
output = (0, import_child_process.execSync)("git diff --name-only @{push}.. 2>/dev/null || git diff --name-only HEAD~1", {
|
|
165
|
+
cwd: repoRoot,
|
|
166
|
+
encoding: "utf-8"
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
output = (0, import_child_process.execSync)("git diff --cached --name-only", {
|
|
170
|
+
cwd: repoRoot,
|
|
171
|
+
encoding: "utf-8"
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return output.split("\n").filter((f) => f.trim().length > 0);
|
|
175
|
+
} catch {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function fileChangeToPDLSSContext(filePath) {
|
|
180
|
+
const purpose = mapToolToPurpose("file_write");
|
|
181
|
+
const target = extractTarget("file_write", { path: filePath });
|
|
182
|
+
return {
|
|
183
|
+
purpose,
|
|
184
|
+
action: "file_write",
|
|
185
|
+
target,
|
|
186
|
+
dataAccess: ["write"],
|
|
187
|
+
resourceType: "file"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async function evaluateChangedFiles(gateway, files, config = {}) {
|
|
191
|
+
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
192
|
+
const results = [];
|
|
193
|
+
let blocked = 0;
|
|
194
|
+
let warned = 0;
|
|
195
|
+
let allowed = 0;
|
|
196
|
+
for (const file of files) {
|
|
197
|
+
const context = fileChangeToPDLSSContext(file);
|
|
198
|
+
const decision = await gateway.evaluate(context);
|
|
199
|
+
results.push({ file, decision });
|
|
200
|
+
if (decision.recommendation === "DENY") {
|
|
201
|
+
blocked++;
|
|
202
|
+
} else if (decision.recommendation === "MANUAL_REVIEW") {
|
|
203
|
+
warned++;
|
|
204
|
+
} else {
|
|
205
|
+
allowed++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const shouldBlock = merged.enforcement === "block" && blocked > 0;
|
|
209
|
+
return {
|
|
210
|
+
allowed,
|
|
211
|
+
blocked,
|
|
212
|
+
warned,
|
|
213
|
+
total: files.length,
|
|
214
|
+
shouldBlock,
|
|
215
|
+
enforcement: merged.enforcement,
|
|
216
|
+
results,
|
|
217
|
+
blockMessage: shouldBlock ? merged.blockMessage || `AstraSync blocked push: ${blocked} file(s) denied by policy` : void 0
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function isProtectedBranch(config = {}) {
|
|
221
|
+
if (!config.protectedBranches || config.protectedBranches.length === 0) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
const branch = (0, import_child_process.execSync)("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
|
|
226
|
+
return config.protectedBranches.some((pattern) => {
|
|
227
|
+
if (pattern === branch) return true;
|
|
228
|
+
if (pattern.endsWith("*") && branch.startsWith(pattern.slice(0, -1))) return true;
|
|
229
|
+
return false;
|
|
230
|
+
});
|
|
231
|
+
} catch {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
236
|
+
0 && (module.exports = {
|
|
237
|
+
evaluateChangedFiles,
|
|
238
|
+
fileChangeToPDLSSContext,
|
|
239
|
+
getChangedFiles,
|
|
240
|
+
installGitHooks,
|
|
241
|
+
isProtectedBranch,
|
|
242
|
+
uninstallGitHooks
|
|
243
|
+
});
|
|
244
|
+
//# sourceMappingURL=git-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/git-trigger/git-hooks.ts","../../src/adapter-interface/purpose-mapping.ts"],"sourcesContent":["/**\n * Git Trigger — Enterprise git push / PR verification\n *\n * Installs git hooks that evaluate changed files against the PDLSS policy\n * before allowing pushes to remote repositories.\n *\n * Two enforcement modes (admin-configurable):\n * - block: non-zero exit prevents the push\n * - warn: push proceeds but warning is printed\n */\n\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, chmodSync } from 'fs';\nimport { join } from 'path';\nimport { execSync } from 'child_process';\nimport type { AstraSyncGateway } from '../gateway/gateway';\nimport { mapToolToPurpose, extractTarget, extractNetworkDomains } from '../adapter-interface/purpose-mapping';\nimport type { PDLSSContext, VerificationDecision } from '../gateway/types';\n\n// -----------------------------------------------------------------------\n// Configuration\n// -----------------------------------------------------------------------\n\nexport interface GitTriggerConfig {\n /** Block the push or just warn (default: 'warn') */\n enforcement: 'block' | 'warn';\n /** Which git hooks to install (default: ['pre-push']) */\n hooks: ('pre-push' | 'pre-commit')[];\n /** Only enforce on these branches (default: all) */\n protectedBranches?: string[];\n /** Custom message for blocked pushes */\n blockMessage?: string;\n}\n\nconst DEFAULT_CONFIG: GitTriggerConfig = {\n enforcement: 'warn',\n hooks: ['pre-push'],\n};\n\n// -----------------------------------------------------------------------\n// Hook script content\n// -----------------------------------------------------------------------\n\nconst HOOK_MARKER = '# AstraSync Local Guard — managed hook';\n\nfunction makeHookScript(hookType: 'pre-push' | 'pre-commit'): string {\n return `#!/bin/sh\n${HOOK_MARKER}\n# Runs AstraSync verification on changed files before ${hookType === 'pre-push' ? 'push' : 'commit'}.\n# Installed by: astrasync guard install-hooks\n# To remove: delete this file or run astrasync guard uninstall-hooks\n\nnpx astrasync guard check --trigger=${hookType} \"$@\"\nexit $?\n`;\n}\n\n// -----------------------------------------------------------------------\n// Hook installer\n// -----------------------------------------------------------------------\n\n/**\n * Install git hooks into the repository.\n * Returns the paths of installed hooks.\n */\nexport function installGitHooks(\n repoRoot: string,\n config: Partial<GitTriggerConfig> = {},\n): { installed: string[]; skipped: string[] } {\n const merged = { ...DEFAULT_CONFIG, ...config };\n const hooksDir = join(repoRoot, '.git', 'hooks');\n const installed: string[] = [];\n const skipped: string[] = [];\n\n if (!existsSync(join(repoRoot, '.git'))) {\n throw new Error(`Not a git repository: ${repoRoot}`);\n }\n\n if (!existsSync(hooksDir)) {\n mkdirSync(hooksDir, { recursive: true });\n }\n\n for (const hookType of merged.hooks) {\n const hookPath = join(hooksDir, hookType);\n\n // Don't overwrite non-AstraSync hooks\n if (existsSync(hookPath)) {\n const content = readFileSync(hookPath, 'utf-8');\n if (!content.includes(HOOK_MARKER)) {\n skipped.push(hookPath);\n continue;\n }\n }\n\n writeFileSync(hookPath, makeHookScript(hookType), 'utf-8');\n chmodSync(hookPath, 0o755);\n installed.push(hookPath);\n }\n\n return { installed, skipped };\n}\n\n/**\n * Remove AstraSync-managed git hooks.\n */\nexport function uninstallGitHooks(\n repoRoot: string,\n hooks: ('pre-push' | 'pre-commit')[] = ['pre-push'],\n): string[] {\n const hooksDir = join(repoRoot, '.git', 'hooks');\n const removed: string[] = [];\n\n for (const hookType of hooks) {\n const hookPath = join(hooksDir, hookType);\n if (existsSync(hookPath)) {\n const content = readFileSync(hookPath, 'utf-8');\n if (content.includes(HOOK_MARKER)) {\n const { unlinkSync } = require('fs');\n unlinkSync(hookPath);\n removed.push(hookPath);\n }\n }\n }\n\n return removed;\n}\n\n// -----------------------------------------------------------------------\n// Evaluation logic\n// -----------------------------------------------------------------------\n\n/**\n * Get list of changed files for the current trigger context.\n */\nexport function getChangedFiles(trigger: 'pre-push' | 'pre-commit', repoRoot: string): string[] {\n try {\n let output: string;\n if (trigger === 'pre-push') {\n // Files changed between HEAD and remote tracking branch\n output = execSync('git diff --name-only @{push}.. 2>/dev/null || git diff --name-only HEAD~1', {\n cwd: repoRoot,\n encoding: 'utf-8',\n });\n } else {\n // Files staged for commit\n output = execSync('git diff --cached --name-only', {\n cwd: repoRoot,\n encoding: 'utf-8',\n });\n }\n return output.split('\\n').filter(f => f.trim().length > 0);\n } catch {\n return [];\n }\n}\n\n/**\n * Map a file change to a PDLSS context for evaluation.\n */\nexport function fileChangeToPDLSSContext(filePath: string): PDLSSContext {\n const purpose = mapToolToPurpose('file_write');\n const target = extractTarget('file_write', { path: filePath });\n\n return {\n purpose,\n action: 'file_write',\n target,\n dataAccess: ['write'],\n resourceType: 'file',\n };\n}\n\n/**\n * Evaluate changed files against the gateway policy.\n * Returns a summary of allow/deny/review decisions.\n */\nexport async function evaluateChangedFiles(\n gateway: AstraSyncGateway,\n files: string[],\n config: Partial<GitTriggerConfig> = {},\n): Promise<GitCheckResult> {\n const merged = { ...DEFAULT_CONFIG, ...config };\n const results: { file: string; decision: VerificationDecision }[] = [];\n let blocked = 0;\n let warned = 0;\n let allowed = 0;\n\n for (const file of files) {\n const context = fileChangeToPDLSSContext(file);\n const decision = await gateway.evaluate(context);\n\n results.push({ file, decision });\n\n if (decision.recommendation === 'DENY') {\n blocked++;\n } else if (decision.recommendation === 'MANUAL_REVIEW') {\n warned++;\n } else {\n allowed++;\n }\n }\n\n const shouldBlock = merged.enforcement === 'block' && (blocked > 0);\n\n return {\n allowed,\n blocked,\n warned,\n total: files.length,\n shouldBlock,\n enforcement: merged.enforcement,\n results,\n blockMessage: shouldBlock\n ? (merged.blockMessage || `AstraSync blocked push: ${blocked} file(s) denied by policy`)\n : undefined,\n };\n}\n\nexport interface GitCheckResult {\n allowed: number;\n blocked: number;\n warned: number;\n total: number;\n shouldBlock: boolean;\n enforcement: 'block' | 'warn';\n results: { file: string; decision: VerificationDecision }[];\n blockMessage?: string;\n}\n\n/**\n * Check if the current branch is protected.\n */\nexport function isProtectedBranch(config: Partial<GitTriggerConfig> = {}): boolean {\n if (!config.protectedBranches || config.protectedBranches.length === 0) {\n return true; // All branches protected by default\n }\n\n try {\n const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();\n return config.protectedBranches.some(pattern => {\n if (pattern === branch) return true;\n if (pattern.endsWith('*') && branch.startsWith(pattern.slice(0, -1))) return true;\n return false;\n });\n } catch {\n return true; // Can't determine branch, assume protected\n }\n}\n","/**\n * Shared purpose mapping utilities for Layer 4 platform adapters.\n *\n * Maps platform-native action names to PDLSS purpose categories.\n * Used by OpenClaw CLI, Cursor, browser, and future adapters.\n */\n\n// -----------------------------------------------------------------------\n// Tool → Purpose mapping\n// -----------------------------------------------------------------------\n\n/** Standard tool name → PDLSS purpose mapping used by all adapters */\nconst TOOL_PURPOSE_MAP: Record<string, string> = {\n // Shell\n shell_exec: 'shell.exec',\n run_command: 'shell.exec',\n execute: 'shell.exec',\n terminal_exec: 'shell.exec',\n run_terminal_command: 'shell.exec',\n\n // File read\n file_read: 'file.read',\n read_file: 'file.read',\n\n // File write\n file_write: 'file.write',\n write_file: 'file.write',\n create_file: 'file.write',\n edit_file: 'file.write',\n\n // File delete\n file_delete: 'file.delete',\n delete_file: 'file.delete',\n\n // Network\n http_request: 'network.request',\n fetch: 'network.request',\n web_request: 'network.request',\n\n // Email\n send_email: 'email.send',\n read_email: 'email.read',\n\n // Calendar\n create_event: 'calendar.create',\n\n // Database\n query_database: 'database.query',\n write_database: 'database.write',\n\n // Payment\n payment_execute: 'payment.execute',\n};\n\n/**\n * Map a tool/action name to a PDLSS purpose category.\n * Returns `tool.<name>` for unmapped tools (denied by default).\n */\nexport function mapToolToPurpose(toolName: string): string {\n return TOOL_PURPOSE_MAP[toolName] || `tool.${toolName}`;\n}\n\n/**\n * Register additional tool → purpose mappings (e.g. from a platform adapter).\n * Does not overwrite existing mappings.\n */\nexport function registerToolMappings(mappings: Record<string, string>): void {\n for (const [tool, purpose] of Object.entries(mappings)) {\n if (!(tool in TOOL_PURPOSE_MAP)) {\n TOOL_PURPOSE_MAP[tool] = purpose;\n }\n }\n}\n\n// -----------------------------------------------------------------------\n// Target extraction\n// -----------------------------------------------------------------------\n\n/**\n * Extract the meaningful target string from tool arguments.\n * Uses the purpose category to determine which argument field is relevant.\n */\nexport function extractTarget(toolName: string, args: Record<string, unknown>): string {\n const purpose = mapToolToPurpose(toolName);\n\n if (purpose.startsWith('shell.')) {\n return String(args.command || args.cmd || args.script || '');\n }\n\n if (purpose.startsWith('file.')) {\n return String(args.path || args.file || args.filename || args.file_path || '');\n }\n\n if (purpose.startsWith('network.')) {\n return String(args.url || args.endpoint || args.uri || '');\n }\n\n if (purpose.startsWith('email.')) {\n return String(args.to || args.recipient || args.address || '');\n }\n\n if (purpose.startsWith('database.')) {\n return String(args.query || args.table || '');\n }\n\n if (purpose.startsWith('payment.')) {\n return String(args.description || args.merchant || args.amount || '');\n }\n\n // Fallback: try common field names\n if (args.command) return String(args.command);\n if (args.path) return String(args.path);\n if (args.url) return String(args.url);\n\n // Default: use first non-empty string argument or tool name\n for (const val of Object.values(args)) {\n if (typeof val === 'string' && val.length > 0) return val;\n }\n return toolName;\n}\n\n// -----------------------------------------------------------------------\n// Network domain extraction\n// -----------------------------------------------------------------------\n\n/**\n * Extract network domains from a URL target.\n * Returns undefined if the target is not a URL.\n */\nexport function extractNetworkDomains(target: string): string[] | undefined {\n try {\n if (target.startsWith('http://') || target.startsWith('https://')) {\n const url = new URL(target);\n return [url.hostname];\n }\n } catch {\n // Not a URL\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/git-trigger/git-hooks.ts
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, chmodSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
|
|
13
|
+
// src/adapter-interface/purpose-mapping.ts
|
|
14
|
+
var TOOL_PURPOSE_MAP = {
|
|
15
|
+
// Shell
|
|
16
|
+
shell_exec: "shell.exec",
|
|
17
|
+
run_command: "shell.exec",
|
|
18
|
+
execute: "shell.exec",
|
|
19
|
+
terminal_exec: "shell.exec",
|
|
20
|
+
run_terminal_command: "shell.exec",
|
|
21
|
+
// File read
|
|
22
|
+
file_read: "file.read",
|
|
23
|
+
read_file: "file.read",
|
|
24
|
+
// File write
|
|
25
|
+
file_write: "file.write",
|
|
26
|
+
write_file: "file.write",
|
|
27
|
+
create_file: "file.write",
|
|
28
|
+
edit_file: "file.write",
|
|
29
|
+
// File delete
|
|
30
|
+
file_delete: "file.delete",
|
|
31
|
+
delete_file: "file.delete",
|
|
32
|
+
// Network
|
|
33
|
+
http_request: "network.request",
|
|
34
|
+
fetch: "network.request",
|
|
35
|
+
web_request: "network.request",
|
|
36
|
+
// Email
|
|
37
|
+
send_email: "email.send",
|
|
38
|
+
read_email: "email.read",
|
|
39
|
+
// Calendar
|
|
40
|
+
create_event: "calendar.create",
|
|
41
|
+
// Database
|
|
42
|
+
query_database: "database.query",
|
|
43
|
+
write_database: "database.write",
|
|
44
|
+
// Payment
|
|
45
|
+
payment_execute: "payment.execute"
|
|
46
|
+
};
|
|
47
|
+
function mapToolToPurpose(toolName) {
|
|
48
|
+
return TOOL_PURPOSE_MAP[toolName] || `tool.${toolName}`;
|
|
49
|
+
}
|
|
50
|
+
function extractTarget(toolName, args) {
|
|
51
|
+
const purpose = mapToolToPurpose(toolName);
|
|
52
|
+
if (purpose.startsWith("shell.")) {
|
|
53
|
+
return String(args.command || args.cmd || args.script || "");
|
|
54
|
+
}
|
|
55
|
+
if (purpose.startsWith("file.")) {
|
|
56
|
+
return String(args.path || args.file || args.filename || args.file_path || "");
|
|
57
|
+
}
|
|
58
|
+
if (purpose.startsWith("network.")) {
|
|
59
|
+
return String(args.url || args.endpoint || args.uri || "");
|
|
60
|
+
}
|
|
61
|
+
if (purpose.startsWith("email.")) {
|
|
62
|
+
return String(args.to || args.recipient || args.address || "");
|
|
63
|
+
}
|
|
64
|
+
if (purpose.startsWith("database.")) {
|
|
65
|
+
return String(args.query || args.table || "");
|
|
66
|
+
}
|
|
67
|
+
if (purpose.startsWith("payment.")) {
|
|
68
|
+
return String(args.description || args.merchant || args.amount || "");
|
|
69
|
+
}
|
|
70
|
+
if (args.command) return String(args.command);
|
|
71
|
+
if (args.path) return String(args.path);
|
|
72
|
+
if (args.url) return String(args.url);
|
|
73
|
+
for (const val of Object.values(args)) {
|
|
74
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
75
|
+
}
|
|
76
|
+
return toolName;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/git-trigger/git-hooks.ts
|
|
80
|
+
var DEFAULT_CONFIG = {
|
|
81
|
+
enforcement: "warn",
|
|
82
|
+
hooks: ["pre-push"]
|
|
83
|
+
};
|
|
84
|
+
var HOOK_MARKER = "# AstraSync Local Guard \u2014 managed hook";
|
|
85
|
+
function makeHookScript(hookType) {
|
|
86
|
+
return `#!/bin/sh
|
|
87
|
+
${HOOK_MARKER}
|
|
88
|
+
# Runs AstraSync verification on changed files before ${hookType === "pre-push" ? "push" : "commit"}.
|
|
89
|
+
# Installed by: astrasync guard install-hooks
|
|
90
|
+
# To remove: delete this file or run astrasync guard uninstall-hooks
|
|
91
|
+
|
|
92
|
+
npx astrasync guard check --trigger=${hookType} "$@"
|
|
93
|
+
exit $?
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
function installGitHooks(repoRoot, config = {}) {
|
|
97
|
+
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
98
|
+
const hooksDir = join(repoRoot, ".git", "hooks");
|
|
99
|
+
const installed = [];
|
|
100
|
+
const skipped = [];
|
|
101
|
+
if (!existsSync(join(repoRoot, ".git"))) {
|
|
102
|
+
throw new Error(`Not a git repository: ${repoRoot}`);
|
|
103
|
+
}
|
|
104
|
+
if (!existsSync(hooksDir)) {
|
|
105
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
for (const hookType of merged.hooks) {
|
|
108
|
+
const hookPath = join(hooksDir, hookType);
|
|
109
|
+
if (existsSync(hookPath)) {
|
|
110
|
+
const content = readFileSync(hookPath, "utf-8");
|
|
111
|
+
if (!content.includes(HOOK_MARKER)) {
|
|
112
|
+
skipped.push(hookPath);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
writeFileSync(hookPath, makeHookScript(hookType), "utf-8");
|
|
117
|
+
chmodSync(hookPath, 493);
|
|
118
|
+
installed.push(hookPath);
|
|
119
|
+
}
|
|
120
|
+
return { installed, skipped };
|
|
121
|
+
}
|
|
122
|
+
function uninstallGitHooks(repoRoot, hooks = ["pre-push"]) {
|
|
123
|
+
const hooksDir = join(repoRoot, ".git", "hooks");
|
|
124
|
+
const removed = [];
|
|
125
|
+
for (const hookType of hooks) {
|
|
126
|
+
const hookPath = join(hooksDir, hookType);
|
|
127
|
+
if (existsSync(hookPath)) {
|
|
128
|
+
const content = readFileSync(hookPath, "utf-8");
|
|
129
|
+
if (content.includes(HOOK_MARKER)) {
|
|
130
|
+
const { unlinkSync } = __require("fs");
|
|
131
|
+
unlinkSync(hookPath);
|
|
132
|
+
removed.push(hookPath);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return removed;
|
|
137
|
+
}
|
|
138
|
+
function getChangedFiles(trigger, repoRoot) {
|
|
139
|
+
try {
|
|
140
|
+
let output;
|
|
141
|
+
if (trigger === "pre-push") {
|
|
142
|
+
output = execSync("git diff --name-only @{push}.. 2>/dev/null || git diff --name-only HEAD~1", {
|
|
143
|
+
cwd: repoRoot,
|
|
144
|
+
encoding: "utf-8"
|
|
145
|
+
});
|
|
146
|
+
} else {
|
|
147
|
+
output = execSync("git diff --cached --name-only", {
|
|
148
|
+
cwd: repoRoot,
|
|
149
|
+
encoding: "utf-8"
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return output.split("\n").filter((f) => f.trim().length > 0);
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function fileChangeToPDLSSContext(filePath) {
|
|
158
|
+
const purpose = mapToolToPurpose("file_write");
|
|
159
|
+
const target = extractTarget("file_write", { path: filePath });
|
|
160
|
+
return {
|
|
161
|
+
purpose,
|
|
162
|
+
action: "file_write",
|
|
163
|
+
target,
|
|
164
|
+
dataAccess: ["write"],
|
|
165
|
+
resourceType: "file"
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async function evaluateChangedFiles(gateway, files, config = {}) {
|
|
169
|
+
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
170
|
+
const results = [];
|
|
171
|
+
let blocked = 0;
|
|
172
|
+
let warned = 0;
|
|
173
|
+
let allowed = 0;
|
|
174
|
+
for (const file of files) {
|
|
175
|
+
const context = fileChangeToPDLSSContext(file);
|
|
176
|
+
const decision = await gateway.evaluate(context);
|
|
177
|
+
results.push({ file, decision });
|
|
178
|
+
if (decision.recommendation === "DENY") {
|
|
179
|
+
blocked++;
|
|
180
|
+
} else if (decision.recommendation === "MANUAL_REVIEW") {
|
|
181
|
+
warned++;
|
|
182
|
+
} else {
|
|
183
|
+
allowed++;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const shouldBlock = merged.enforcement === "block" && blocked > 0;
|
|
187
|
+
return {
|
|
188
|
+
allowed,
|
|
189
|
+
blocked,
|
|
190
|
+
warned,
|
|
191
|
+
total: files.length,
|
|
192
|
+
shouldBlock,
|
|
193
|
+
enforcement: merged.enforcement,
|
|
194
|
+
results,
|
|
195
|
+
blockMessage: shouldBlock ? merged.blockMessage || `AstraSync blocked push: ${blocked} file(s) denied by policy` : void 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function isProtectedBranch(config = {}) {
|
|
199
|
+
if (!config.protectedBranches || config.protectedBranches.length === 0) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
const branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
|
|
204
|
+
return config.protectedBranches.some((pattern) => {
|
|
205
|
+
if (pattern === branch) return true;
|
|
206
|
+
if (pattern.endsWith("*") && branch.startsWith(pattern.slice(0, -1))) return true;
|
|
207
|
+
return false;
|
|
208
|
+
});
|
|
209
|
+
} catch {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
evaluateChangedFiles,
|
|
215
|
+
fileChangeToPDLSSContext,
|
|
216
|
+
getChangedFiles,
|
|
217
|
+
installGitHooks,
|
|
218
|
+
isProtectedBranch,
|
|
219
|
+
uninstallGitHooks
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=git-hooks.mjs.map
|