@intutic/sync-daemon 1.6.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 +73 -0
- package/dist/brainIndexer.d.ts +51 -0
- package/dist/brainIndexer.d.ts.map +1 -0
- package/dist/brainIndexer.js +148 -0
- package/dist/brainIndexer.js.map +1 -0
- package/dist/configReader.d.ts +46 -0
- package/dist/configReader.d.ts.map +1 -0
- package/dist/configReader.js +133 -0
- package/dist/configReader.js.map +1 -0
- package/dist/configWriter.d.ts +53 -0
- package/dist/configWriter.d.ts.map +1 -0
- package/dist/configWriter.js +503 -0
- package/dist/configWriter.js.map +1 -0
- package/dist/harness/aiderConfigMerger.d.ts +27 -0
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -0
- package/dist/harness/aiderConfigMerger.js +139 -0
- package/dist/harness/aiderConfigMerger.js.map +1 -0
- package/dist/harness/antigravityHooks.d.ts +43 -0
- package/dist/harness/antigravityHooks.d.ts.map +1 -0
- package/dist/harness/antigravityHooks.js +193 -0
- package/dist/harness/antigravityHooks.js.map +1 -0
- package/dist/harness/claudeCodeHooks.d.ts +59 -0
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -0
- package/dist/harness/claudeCodeHooks.js +414 -0
- package/dist/harness/claudeCodeHooks.js.map +1 -0
- package/dist/harness/claudeDesktopHooks.d.ts +30 -0
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -0
- package/dist/harness/claudeDesktopHooks.js +267 -0
- package/dist/harness/claudeDesktopHooks.js.map +1 -0
- package/dist/harness/clineHooks.d.ts +23 -0
- package/dist/harness/clineHooks.d.ts.map +1 -0
- package/dist/harness/clineHooks.js +169 -0
- package/dist/harness/clineHooks.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +33 -0
- package/dist/harness/continueHooks.d.ts.map +1 -0
- package/dist/harness/continueHooks.js +124 -0
- package/dist/harness/continueHooks.js.map +1 -0
- package/dist/harness/cursorHooks.d.ts +27 -0
- package/dist/harness/cursorHooks.d.ts.map +1 -0
- package/dist/harness/cursorHooks.js +221 -0
- package/dist/harness/cursorHooks.js.map +1 -0
- package/dist/harness/cursorHooksJson.d.ts +29 -0
- package/dist/harness/cursorHooksJson.d.ts.map +1 -0
- package/dist/harness/cursorHooksJson.js +130 -0
- package/dist/harness/cursorHooksJson.js.map +1 -0
- package/dist/harness/gooseHardener.d.ts +39 -0
- package/dist/harness/gooseHardener.d.ts.map +1 -0
- package/dist/harness/gooseHardener.js +152 -0
- package/dist/harness/gooseHardener.js.map +1 -0
- package/dist/harness/gooseHooks.d.ts +24 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -0
- package/dist/harness/gooseHooks.js +175 -0
- package/dist/harness/gooseHooks.js.map +1 -0
- package/dist/harness/gooseHooksWriter.d.ts +27 -0
- package/dist/harness/gooseHooksWriter.d.ts.map +1 -0
- package/dist/harness/gooseHooksWriter.js +147 -0
- package/dist/harness/gooseHooksWriter.js.map +1 -0
- package/dist/harness/hermesHooks.d.ts +31 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -0
- package/dist/harness/hermesHooks.js +245 -0
- package/dist/harness/hermesHooks.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +35 -0
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -0
- package/dist/harness/mcpAutoWrite.js +334 -0
- package/dist/harness/mcpAutoWrite.js.map +1 -0
- package/dist/harness/n8nHooks.d.ts +28 -0
- package/dist/harness/n8nHooks.d.ts.map +1 -0
- package/dist/harness/n8nHooks.js +205 -0
- package/dist/harness/n8nHooks.js.map +1 -0
- package/dist/harness/openWebuiHooks.d.ts +31 -0
- package/dist/harness/openWebuiHooks.d.ts.map +1 -0
- package/dist/harness/openWebuiHooks.js +166 -0
- package/dist/harness/openWebuiHooks.js.map +1 -0
- package/dist/harness/openclawHooks.d.ts +34 -0
- package/dist/harness/openclawHooks.d.ts.map +1 -0
- package/dist/harness/openclawHooks.js +296 -0
- package/dist/harness/openclawHooks.js.map +1 -0
- package/dist/harness/openhandsHooks.d.ts +24 -0
- package/dist/harness/openhandsHooks.d.ts.map +1 -0
- package/dist/harness/openhandsHooks.js +178 -0
- package/dist/harness/openhandsHooks.js.map +1 -0
- package/dist/harness/openhandsHooksWriter.d.ts +23 -0
- package/dist/harness/openhandsHooksWriter.d.ts.map +1 -0
- package/dist/harness/openhandsHooksWriter.js +146 -0
- package/dist/harness/openhandsHooksWriter.js.map +1 -0
- package/dist/harness/piHooks.d.ts +32 -0
- package/dist/harness/piHooks.d.ts.map +1 -0
- package/dist/harness/piHooks.js +257 -0
- package/dist/harness/piHooks.js.map +1 -0
- package/dist/harness/rooCodeHooks.d.ts +31 -0
- package/dist/harness/rooCodeHooks.d.ts.map +1 -0
- package/dist/harness/rooCodeHooks.js +300 -0
- package/dist/harness/rooCodeHooks.js.map +1 -0
- package/dist/harness/windsurfHooks.d.ts +27 -0
- package/dist/harness/windsurfHooks.d.ts.map +1 -0
- package/dist/harness/windsurfHooks.js +202 -0
- package/dist/harness/windsurfHooks.js.map +1 -0
- package/dist/hashReporter.d.ts +33 -0
- package/dist/hashReporter.d.ts.map +1 -0
- package/dist/hashReporter.js +69 -0
- package/dist/hashReporter.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/integrityStore.d.ts +43 -0
- package/dist/integrityStore.d.ts.map +1 -0
- package/dist/integrityStore.js +94 -0
- package/dist/integrityStore.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts +39 -0
- package/dist/lib/complianceProbes.d.ts.map +1 -0
- package/dist/lib/complianceProbes.js +115 -0
- package/dist/lib/complianceProbes.js.map +1 -0
- package/dist/lib/processPoller.d.ts +2 -0
- package/dist/lib/processPoller.d.ts.map +1 -0
- package/dist/lib/processPoller.js +87 -0
- package/dist/lib/processPoller.js.map +1 -0
- package/dist/lib/runtimeEnv.d.ts +49 -0
- package/dist/lib/runtimeEnv.d.ts.map +1 -0
- package/dist/lib/runtimeEnv.js +70 -0
- package/dist/lib/runtimeEnv.js.map +1 -0
- package/dist/skillWriter.d.ts +24 -0
- package/dist/skillWriter.d.ts.map +1 -0
- package/dist/skillWriter.js +112 -0
- package/dist/skillWriter.js.map +1 -0
- package/dist/syncLoop.d.ts +70 -0
- package/dist/syncLoop.d.ts.map +1 -0
- package/dist/syncLoop.js +546 -0
- package/dist/syncLoop.js.map +1 -0
- package/dist/trajectoryMonitor.d.ts +126 -0
- package/dist/trajectoryMonitor.d.ts.map +1 -0
- package/dist/trajectoryMonitor.js +291 -0
- package/dist/trajectoryMonitor.js.map +1 -0
- package/dist/watcher/driftWatcher.d.ts +25 -0
- package/dist/watcher/driftWatcher.d.ts.map +1 -0
- package/dist/watcher/driftWatcher.js +72 -0
- package/dist/watcher/driftWatcher.js.map +1 -0
- package/dist/watcher/settingsGuard.d.ts +32 -0
- package/dist/watcher/settingsGuard.d.ts.map +1 -0
- package/dist/watcher/settingsGuard.js +250 -0
- package/dist/watcher/settingsGuard.js.map +1 -0
- package/dist/wsClient.d.ts +49 -0
- package/dist/wsClient.d.ts.map +1 -0
- package/dist/wsClient.js +149 -0
- package/dist/wsClient.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cursorHooks.ts — Cursor beforeShellExecution/beforeMCPExecution hook injection.
|
|
3
|
+
*
|
|
4
|
+
* Writes hooks.json at THREE levels per enterprise-readiness requirement:
|
|
5
|
+
* 1. Project-level: <workspaceRoot>/.cursor/hooks.json
|
|
6
|
+
* 2. User-level: ~/.cursor/hooks.json
|
|
7
|
+
* 3. System-level: /etc/cursor/hooks.json (Linux) — written only by system administrators
|
|
8
|
+
*
|
|
9
|
+
* All three levels use failClosed: true so that if the governance script
|
|
10
|
+
* fails or is missing the tool call is blocked, not allowed.
|
|
11
|
+
*
|
|
12
|
+
* LLD #14 — Phase 3 cross-harness defence
|
|
13
|
+
* HLD §3.14 — Three-Tier Defense Cascade
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Write Cursor hooks at user-level and project-level.
|
|
19
|
+
* System-level (/etc/cursor) is handled by the corporate policy installer.
|
|
20
|
+
*
|
|
21
|
+
* @param workspaceRoot - Absolute workspace root.
|
|
22
|
+
* @param proxyUrl - Intutic proxy URL.
|
|
23
|
+
* @param workspaceId - Workspace ID embedded in hook event payloads.
|
|
24
|
+
* @param writeSystemLevel - If true, also attempt /etc/cursor (requires root).
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeCursorHooks(workspaceRoot: string, proxyUrl: string, workspaceId?: string, writeSystemLevel?: boolean): Promise<void>;
|
|
27
|
+
//# sourceMappingURL=cursorHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursorHooks.d.ts","sourceRoot":"","sources":["../../src/harness/cursorHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAqKH;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAK,EAChB,gBAAgB,UAAQ,GACvB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cursorHooks.ts — Cursor beforeShellExecution/beforeMCPExecution hook injection.
|
|
3
|
+
*
|
|
4
|
+
* Writes hooks.json at THREE levels per enterprise-readiness requirement:
|
|
5
|
+
* 1. Project-level: <workspaceRoot>/.cursor/hooks.json
|
|
6
|
+
* 2. User-level: ~/.cursor/hooks.json
|
|
7
|
+
* 3. System-level: /etc/cursor/hooks.json (Linux) — written only by system administrators
|
|
8
|
+
*
|
|
9
|
+
* All three levels use failClosed: true so that if the governance script
|
|
10
|
+
* fails or is missing the tool call is blocked, not allowed.
|
|
11
|
+
*
|
|
12
|
+
* LLD #14 — Phase 3 cross-harness defence
|
|
13
|
+
* HLD §3.14 — Three-Tier Defense Cascade
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'node:fs/promises';
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import * as os from 'node:os';
|
|
20
|
+
import { createLogger } from '@intutic/logger';
|
|
21
|
+
import { newIso } from '@intutic/id';
|
|
22
|
+
const log = createLogger('sync-cursor-hooks');
|
|
23
|
+
/** Hook events Cursor fires before execution. */
|
|
24
|
+
const HOOK_EVENTS = [
|
|
25
|
+
'beforeShellExecution',
|
|
26
|
+
'beforeMCPExecution',
|
|
27
|
+
'beforeFileEdit',
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Build a Cursor hooks.json config object.
|
|
31
|
+
*
|
|
32
|
+
* @param hookScriptPath - Absolute path to the pre-tool-check script.
|
|
33
|
+
*/
|
|
34
|
+
function buildHooksConfig(hookScriptPath) {
|
|
35
|
+
return {
|
|
36
|
+
_comment: 'Intutic governance hooks — auto-generated. DO NOT EDIT.',
|
|
37
|
+
_lastSync: newIso(),
|
|
38
|
+
failClosed: true,
|
|
39
|
+
hooks: Object.fromEntries(HOOK_EVENTS.map((event) => [
|
|
40
|
+
event,
|
|
41
|
+
{
|
|
42
|
+
command: `node "${hookScriptPath}"`,
|
|
43
|
+
failClosed: true,
|
|
44
|
+
},
|
|
45
|
+
])),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Governance-sensitive paths — mirrors the list in claudeCodeHooks.ts.
|
|
50
|
+
* Any write/edit targeting these paths is blocked.
|
|
51
|
+
*/
|
|
52
|
+
const PROTECTED_PATHS = [
|
|
53
|
+
'.cursor/hooks.json',
|
|
54
|
+
'.claude/settings.json',
|
|
55
|
+
'.cline/hooks',
|
|
56
|
+
'.intutic/hooks',
|
|
57
|
+
'.intutic/integrity.json',
|
|
58
|
+
'.codeium/windsurf/hooks.json',
|
|
59
|
+
'.agents/plugins/intutic-governance',
|
|
60
|
+
'.openhands/hooks.json',
|
|
61
|
+
];
|
|
62
|
+
/**
|
|
63
|
+
* The pre-tool-check.js script content — receives JSON context from Cursor
|
|
64
|
+
* on stdin, exits 0 to allow or exits 2 to block.
|
|
65
|
+
*/
|
|
66
|
+
function buildHookScript(proxyUrl, workspaceRoot, workspaceId) {
|
|
67
|
+
const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'hook-events.jsonl');
|
|
68
|
+
return `#!/usr/bin/env node
|
|
69
|
+
/**
|
|
70
|
+
* Intutic Cursor governance gate.
|
|
71
|
+
* Auto-generated by intutic sync-daemon. DO NOT EDIT.
|
|
72
|
+
* Proxy: ${proxyUrl}
|
|
73
|
+
* Generated: ${newIso()}
|
|
74
|
+
*/
|
|
75
|
+
const path = require('path');
|
|
76
|
+
const os = require('os');
|
|
77
|
+
const fs = require('fs');
|
|
78
|
+
const crypto = require('crypto');
|
|
79
|
+
const https = require('https');
|
|
80
|
+
|
|
81
|
+
// Runtime credentials
|
|
82
|
+
const _runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
|
|
83
|
+
let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
|
|
84
|
+
try {
|
|
85
|
+
fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
|
|
86
|
+
const eq = line.indexOf('='); if (eq < 0) return;
|
|
87
|
+
const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
|
|
88
|
+
if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
|
|
89
|
+
if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
|
|
90
|
+
if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
|
|
91
|
+
});
|
|
92
|
+
} catch {}
|
|
93
|
+
|
|
94
|
+
const PROTECTED_PATHS = ${JSON.stringify(PROTECTED_PATHS)};
|
|
95
|
+
|
|
96
|
+
function logEvent(verdict, toolName, reason) {
|
|
97
|
+
try {
|
|
98
|
+
const ts = new Date().toISOString();
|
|
99
|
+
const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
|
|
100
|
+
const entry = JSON.stringify({
|
|
101
|
+
event: verdict === 'blocked' ? 'tool_blocked' : 'tool_allowed',
|
|
102
|
+
toolName, reason: reason || '',
|
|
103
|
+
workspaceId: _intuticWsId,
|
|
104
|
+
harnessType: 'cursor',
|
|
105
|
+
timestamp: ts,
|
|
106
|
+
incidentId,
|
|
107
|
+
}) + '\\n';
|
|
108
|
+
fs.appendFileSync(${JSON.stringify(hookEventsLog)}, entry, { flag: 'a' });
|
|
109
|
+
if (_intuticKey) {
|
|
110
|
+
try {
|
|
111
|
+
const body = JSON.stringify({ events: [JSON.parse(entry)] });
|
|
112
|
+
const urlObj = new URL('/api/v1/hook-events', _intuticHost);
|
|
113
|
+
const mod = urlObj.protocol === 'https:' ? https : require('http');
|
|
114
|
+
const req = mod.request({ hostname: urlObj.hostname, port: urlObj.port || 443, path: urlObj.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'Authorization': 'Bearer ' + _intuticKey } });
|
|
115
|
+
req.on('error', () => { /* fire-and-forget */ });
|
|
116
|
+
req.write(body); req.end();
|
|
117
|
+
} catch { /* never crash the hook */ }
|
|
118
|
+
}
|
|
119
|
+
} catch { /* never crash the hook */ }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let raw = '';
|
|
123
|
+
process.stdin.on('data', (c) => { raw += c; });
|
|
124
|
+
process.stdin.on('end', () => {
|
|
125
|
+
try {
|
|
126
|
+
const ctx = JSON.parse(raw);
|
|
127
|
+
const event = (ctx.event || '').toLowerCase();
|
|
128
|
+
const input = ctx.input || ctx.tool_input || ctx;
|
|
129
|
+
|
|
130
|
+
// For file edits: check target path
|
|
131
|
+
const targetPath = input.path || input.file || input.target || '';
|
|
132
|
+
if (event === 'beforefileedit' || (input.path && input.path.length > 0)) {
|
|
133
|
+
for (const p of PROTECTED_PATHS) {
|
|
134
|
+
if (String(targetPath).includes(p)) {
|
|
135
|
+
const reason = 'Attempt to modify governance-protected path "' + targetPath + '"';
|
|
136
|
+
process.stderr.write('[Intutic Governance] BLOCKED: ' + reason + '\\n');
|
|
137
|
+
logEvent('blocked', 'edit', reason);
|
|
138
|
+
process.exit(2);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Shell execution: scan command for dangerous patterns
|
|
144
|
+
const command = input.command || input.cmd || '';
|
|
145
|
+
const dangerPatterns = [
|
|
146
|
+
/chmod\\s+[0-9]*7[0-9]*\\s+.*hooks/, // chmod on hook files
|
|
147
|
+
/chattr\\s+-i\\s+/, // remove immutable flag
|
|
148
|
+
/chflags\\s+nouchg/, // macOS remove uchg
|
|
149
|
+
];
|
|
150
|
+
for (const pat of dangerPatterns) {
|
|
151
|
+
if (pat.test(command)) {
|
|
152
|
+
const reason = 'Command matches governance bypass pattern: "' + command + '"';
|
|
153
|
+
process.stderr.write('[Intutic Governance] BLOCKED: ' + reason + '\\n');
|
|
154
|
+
logEvent('blocked', 'bash', reason);
|
|
155
|
+
process.exit(2);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Allow
|
|
160
|
+
logEvent('allowed', event || 'tool', '');
|
|
161
|
+
process.exit(0);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
// Fail CLOSED
|
|
164
|
+
const errMsg = String(err);
|
|
165
|
+
process.stderr.write('[Intutic Governance] Hook error (fail-closed): ' + errMsg + '\\n');
|
|
166
|
+
logEvent('blocked', 'unknown', errMsg);
|
|
167
|
+
process.exit(2);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Write Cursor hooks at user-level and project-level.
|
|
174
|
+
* System-level (/etc/cursor) is handled by the corporate policy installer.
|
|
175
|
+
*
|
|
176
|
+
* @param workspaceRoot - Absolute workspace root.
|
|
177
|
+
* @param proxyUrl - Intutic proxy URL.
|
|
178
|
+
* @param workspaceId - Workspace ID embedded in hook event payloads.
|
|
179
|
+
* @param writeSystemLevel - If true, also attempt /etc/cursor (requires root).
|
|
180
|
+
*/
|
|
181
|
+
export async function writeCursorHooks(workspaceRoot, proxyUrl, workspaceId = '', writeSystemLevel = false) {
|
|
182
|
+
const hookScriptDir = path.join(workspaceRoot, '.intutic', 'hooks');
|
|
183
|
+
await fs.mkdir(hookScriptDir, { recursive: true });
|
|
184
|
+
// Ensure hook events log directory exists
|
|
185
|
+
await fs.mkdir(path.join(workspaceRoot, '.intutic', 'events'), { recursive: true });
|
|
186
|
+
const hookScriptPath = path.join(hookScriptDir, 'pre-tool-check.js');
|
|
187
|
+
// Write the hook script
|
|
188
|
+
const tmpScript = hookScriptPath + '.cursor-tmp';
|
|
189
|
+
await fs.writeFile(tmpScript, buildHookScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
|
|
190
|
+
await fs.rename(tmpScript, hookScriptPath);
|
|
191
|
+
await fs.chmod(hookScriptPath, 0o755);
|
|
192
|
+
const config = buildHooksConfig(hookScriptPath);
|
|
193
|
+
// 1. Project-level: .cursor/hooks.json
|
|
194
|
+
const projectCursorDir = path.join(workspaceRoot, '.cursor');
|
|
195
|
+
await fs.mkdir(projectCursorDir, { recursive: true });
|
|
196
|
+
await atomicWriteJson(path.join(projectCursorDir, 'hooks.json'), config);
|
|
197
|
+
log.info({ action: 'cursor_hooks_written', level: 'project', path: projectCursorDir }, 'Cursor project-level hooks written');
|
|
198
|
+
// 2. User-level: ~/.cursor/hooks.json
|
|
199
|
+
const userCursorDir = path.join(os.homedir(), '.cursor');
|
|
200
|
+
await fs.mkdir(userCursorDir, { recursive: true });
|
|
201
|
+
await atomicWriteJson(path.join(userCursorDir, 'hooks.json'), config);
|
|
202
|
+
log.info({ action: 'cursor_hooks_written', level: 'user', path: userCursorDir }, 'Cursor user-level hooks written');
|
|
203
|
+
// 3. System-level: /etc/cursor/hooks.json (system administrator installation only)
|
|
204
|
+
if (writeSystemLevel) {
|
|
205
|
+
const systemCursorDir = '/etc/cursor';
|
|
206
|
+
try {
|
|
207
|
+
await fs.mkdir(systemCursorDir, { recursive: true });
|
|
208
|
+
await atomicWriteJson(path.join(systemCursorDir, 'hooks.json'), config);
|
|
209
|
+
log.info({ action: 'cursor_hooks_written', level: 'system', path: systemCursorDir }, 'Cursor system-level hooks written');
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
log.error({ action: 'cursor_system_hooks_failed', err }, 'System-level Cursor hooks require root — skipping');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function atomicWriteJson(filePath, data) {
|
|
217
|
+
const tmp = filePath + '.intutic-tmp';
|
|
218
|
+
await fs.writeFile(tmp, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
219
|
+
await fs.rename(tmp, filePath);
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=cursorHooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursorHooks.js","sourceRoot":"","sources":["../../src/harness/cursorHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAA;AAE7C,iDAAiD;AACjD,MAAM,WAAW,GAAG;IAClB,sBAAsB;IACtB,oBAAoB;IACpB,gBAAgB;CACR,CAAA;AAEV;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,cAAsB;IAC9C,OAAO;QACL,QAAQ,EAAE,yDAAyD;QACnE,SAAS,EAAE,MAAM,EAAE;QACnB,UAAU,EAAE,IAAI;QAChB,KAAK,EAAE,MAAM,CAAC,WAAW,CACvB,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YACzB,KAAK;YACL;gBACE,OAAO,EAAE,SAAS,cAAc,GAAG;gBACnC,UAAU,EAAE,IAAI;aACjB;SACF,CAAC,CACH;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,eAAe,GAAG;IACtB,oBAAoB;IACpB,uBAAuB;IACvB,cAAc;IACd,gBAAgB;IAChB,yBAAyB;IACzB,8BAA8B;IAC9B,oCAAoC;IACpC,uBAAuB;CACxB,CAAA;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,aAAqB,EAAE,WAAmB;IACnF,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,OAAO;;;;YAIG,QAAQ;gBACJ,MAAM,EAAE;;;;;;;;;;gFAUwD,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;;;;;;;;;0BAWjF,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;;;;;;;;;;;;;;wBAcjC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DpD,CAAA;AACD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,aAAqB,EACrB,QAAgB,EAChB,WAAW,GAAG,EAAE,EAChB,gBAAgB,GAAG,KAAK;IAExB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACnE,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAElD,0CAA0C;IAC1C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEnF,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAA;IAEpE,wBAAwB;IACxB,MAAM,SAAS,GAAG,cAAc,GAAG,aAAa,CAAA;IAChD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAA;IAC7F,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAA;IAC1C,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IAErC,MAAM,MAAM,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAA;IAE/C,uCAAuC;IACvC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;IAC5D,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAA;IACxE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,oCAAoC,CAAC,CAAA;IAE5H,sCAAsC;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAA;IACxD,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAA;IACrE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,iCAAiC,CAAC,CAAA;IAEnH,mFAAmF;IACnF,IAAI,gBAAgB,EAAE,CAAC;QACrB,MAAM,eAAe,GAAG,aAAa,CAAA;QACrC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACpD,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAA;YACvE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,mCAAmC,CAAC,CAAA;QAC3H,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,4BAA4B,EAAE,GAAG,EAAE,EAAE,mDAAmD,CAAC,CAAA;QAC/G,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,IAAa;IAC5D,MAAM,GAAG,GAAG,QAAQ,GAAG,cAAc,CAAA;IACrC,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;IACtE,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cursorHooksJson.ts — Cursor native hooks.json writer (v1.7+ hook API).
|
|
3
|
+
*
|
|
4
|
+
* Writes Cursor's native hooks.json at two levels:
|
|
5
|
+
* 1. User-level: ~/.cursor/hooks.json
|
|
6
|
+
* 2. Project-level: <workspaceRoot>/.cursor/hooks.json
|
|
7
|
+
*
|
|
8
|
+
* The hook command references the shared pre-tool-check.js script installed
|
|
9
|
+
* by WS-4A. On beforeMCPExecution and beforeShellExecution events, Cursor
|
|
10
|
+
* invokes this script with the tool context on stdin; exit 0 allows,
|
|
11
|
+
* exit 2 blocks (fail-closed).
|
|
12
|
+
*
|
|
13
|
+
* Deep-merges into any existing hooks.json so other hooks are preserved.
|
|
14
|
+
*
|
|
15
|
+
* LLD #14 — Phase 4 WS-4C native hook script writers
|
|
16
|
+
* HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Write Cursor native hooks.json at user-level and project-level.
|
|
22
|
+
*
|
|
23
|
+
* The hook command (`node ~/.intutic/hooks/pre-tool-check.js`) is installed
|
|
24
|
+
* by WS-4A; this writer only registers it in hooks.json.
|
|
25
|
+
*
|
|
26
|
+
* @param workspaceRoot - Absolute path to the workspace root.
|
|
27
|
+
*/
|
|
28
|
+
export declare function writeCursorHooksJson(workspaceRoot: string): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=cursorHooksJson.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursorHooksJson.d.ts","sourceRoot":"","sources":["../../src/harness/cursorHooksJson.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA+GH;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/E"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cursorHooksJson.ts — Cursor native hooks.json writer (v1.7+ hook API).
|
|
3
|
+
*
|
|
4
|
+
* Writes Cursor's native hooks.json at two levels:
|
|
5
|
+
* 1. User-level: ~/.cursor/hooks.json
|
|
6
|
+
* 2. Project-level: <workspaceRoot>/.cursor/hooks.json
|
|
7
|
+
*
|
|
8
|
+
* The hook command references the shared pre-tool-check.js script installed
|
|
9
|
+
* by WS-4A. On beforeMCPExecution and beforeShellExecution events, Cursor
|
|
10
|
+
* invokes this script with the tool context on stdin; exit 0 allows,
|
|
11
|
+
* exit 2 blocks (fail-closed).
|
|
12
|
+
*
|
|
13
|
+
* Deep-merges into any existing hooks.json so other hooks are preserved.
|
|
14
|
+
*
|
|
15
|
+
* LLD #14 — Phase 4 WS-4C native hook script writers
|
|
16
|
+
* HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import * as node_fs from 'node:fs/promises';
|
|
21
|
+
import * as node_path from 'node:path';
|
|
22
|
+
import * as node_os from 'node:os';
|
|
23
|
+
import { createLogger } from '@intutic/logger';
|
|
24
|
+
const log = createLogger('sync-cursor-hooks-json');
|
|
25
|
+
/** Absolute path to the shared pre-tool-check.js installed by WS-4A. */
|
|
26
|
+
const HOOK_SCRIPT = node_path.join(node_os.homedir(), '.intutic', 'hooks', 'pre-tool-check.js');
|
|
27
|
+
/** Hook events covered by this writer (Cursor v1.7+ API). */
|
|
28
|
+
const HOOK_EVENTS = ['beforeMCPExecution', 'beforeShellExecution'];
|
|
29
|
+
/**
|
|
30
|
+
* Build the Intutic hook entry for a given event.
|
|
31
|
+
*
|
|
32
|
+
* @param hookScriptPath - Absolute path to the pre-tool-check.js script.
|
|
33
|
+
*/
|
|
34
|
+
function buildHookEntry(hookScriptPath) {
|
|
35
|
+
return { command: `node ${hookScriptPath}` };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read and parse an existing hooks.json, returning a default document if
|
|
39
|
+
* the file does not exist or is not valid JSON.
|
|
40
|
+
*/
|
|
41
|
+
async function readExistingHooksJson(filePath) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = await node_fs.readFile(filePath, 'utf-8');
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
if (parsed !== null &&
|
|
46
|
+
typeof parsed === 'object' &&
|
|
47
|
+
!Array.isArray(parsed) &&
|
|
48
|
+
'hooks' in parsed &&
|
|
49
|
+
typeof parsed.hooks === 'object') {
|
|
50
|
+
return parsed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// File absent or malformed — start from scratch
|
|
55
|
+
}
|
|
56
|
+
return { version: 1, hooks: {} };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Deep-merge our Intutic hook entries into an existing hooks map.
|
|
60
|
+
*
|
|
61
|
+
* For each covered event, we append our entry if a hook with the same
|
|
62
|
+
* command is not already present, preserving all other hooks.
|
|
63
|
+
*
|
|
64
|
+
* @param existing - The existing hooks map (mutated in place).
|
|
65
|
+
* @param hookScriptPath - Absolute path to the governance hook script.
|
|
66
|
+
* @returns The merged hooks map.
|
|
67
|
+
*/
|
|
68
|
+
function mergeHooks(existing, hookScriptPath) {
|
|
69
|
+
const entry = buildHookEntry(hookScriptPath);
|
|
70
|
+
for (const event of HOOK_EVENTS) {
|
|
71
|
+
const current = Array.isArray(existing[event])
|
|
72
|
+
? existing[event]
|
|
73
|
+
: [];
|
|
74
|
+
const alreadyPresent = current.some((h) => h.command === entry.command);
|
|
75
|
+
if (!alreadyPresent) {
|
|
76
|
+
existing[event] = [...current, entry];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
existing[event] = current;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return existing;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Write hooks.json atomically (tmp → rename) to the given path,
|
|
86
|
+
* deep-merging our entries into any existing configuration.
|
|
87
|
+
*
|
|
88
|
+
* @param filePath - Absolute path to the hooks.json to write.
|
|
89
|
+
* @param hookScriptPath - Absolute path to the governance hook script.
|
|
90
|
+
* @param level - Human-readable label for log context.
|
|
91
|
+
*/
|
|
92
|
+
async function writeHooksJson(filePath, hookScriptPath, level) {
|
|
93
|
+
await node_fs.mkdir(node_path.dirname(filePath), { recursive: true });
|
|
94
|
+
const doc = await readExistingHooksJson(filePath);
|
|
95
|
+
doc.version = 1;
|
|
96
|
+
doc.hooks = mergeHooks(doc.hooks, hookScriptPath);
|
|
97
|
+
const tmp = filePath + '.intutic-tmp';
|
|
98
|
+
await node_fs.writeFile(tmp, JSON.stringify(doc, null, 2) + '\n', 'utf-8');
|
|
99
|
+
await node_fs.rename(tmp, filePath);
|
|
100
|
+
log.info({ action: 'cursor_hooks_json_written', level, path: filePath }, `Cursor hooks.json written (${level})`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Write Cursor native hooks.json at user-level and project-level.
|
|
104
|
+
*
|
|
105
|
+
* The hook command (`node ~/.intutic/hooks/pre-tool-check.js`) is installed
|
|
106
|
+
* by WS-4A; this writer only registers it in hooks.json.
|
|
107
|
+
*
|
|
108
|
+
* @param workspaceRoot - Absolute path to the workspace root.
|
|
109
|
+
*/
|
|
110
|
+
export async function writeCursorHooksJson(workspaceRoot) {
|
|
111
|
+
// 1. User-level: ~/.cursor/hooks.json
|
|
112
|
+
//
|
|
113
|
+
// GUARD (bugfix): never touch the user's real global Cursor config from a
|
|
114
|
+
// test run — the same failure already fixed for ~/.claude in
|
|
115
|
+
// claudeCodeHooks.ts. Vitest sets VITEST=1; without this guard every run of
|
|
116
|
+
// the sync-daemon suite rewrote the developer's real ~/.cursor/hooks.json
|
|
117
|
+
// and pointed it at a temp dir the test then deleted, leaving a dead hook.
|
|
118
|
+
// INTUTIC_SKIP_GLOBAL_HOOKS=1 is an explicit opt-out for dev machines.
|
|
119
|
+
if (process.env['VITEST'] || process.env['INTUTIC_SKIP_GLOBAL_HOOKS']) {
|
|
120
|
+
log.info({ action: 'cursor_user_hooks_skipped' }, 'Skipping global ~/.cursor/hooks.json write (test or opt-out environment)');
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const userHooksPath = node_path.join(node_os.homedir(), '.cursor', 'hooks.json');
|
|
124
|
+
await writeHooksJson(userHooksPath, HOOK_SCRIPT, 'user');
|
|
125
|
+
}
|
|
126
|
+
// 2. Project-level: <workspaceRoot>/.cursor/hooks.json
|
|
127
|
+
const projectHooksPath = node_path.join(workspaceRoot, '.cursor', 'hooks.json');
|
|
128
|
+
await writeHooksJson(projectHooksPath, HOOK_SCRIPT, 'project');
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=cursorHooksJson.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursorHooksJson.js","sourceRoot":"","sources":["../../src/harness/cursorHooksJson.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gooseHardener.ts — Cross-platform immutable flag management for Goose plugin files.
|
|
3
|
+
*
|
|
4
|
+
* After the Goose governance plugin is written, this module applies:
|
|
5
|
+
* 1. chmod 444 — no write for owner, group, or others
|
|
6
|
+
* 2. OS-level immutable flag:
|
|
7
|
+
* macOS: chflags uchg (user immutable, does not require root)
|
|
8
|
+
* Linux: chattr +i (requires root; graceful fallback on permission error)
|
|
9
|
+
*
|
|
10
|
+
* The drift watcher checks for immutable status before auto-restoring.
|
|
11
|
+
* If a file is immutable but has been tampered with, a governance_override_attempt
|
|
12
|
+
* incident is emitted to the control plane instead of a silent restore.
|
|
13
|
+
*
|
|
14
|
+
* LLD #14 — Phase 3 cross-harness defence
|
|
15
|
+
* HLD §3.14 — Three-Tier Defense Cascade
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Apply chmod 444 and OS immutable flags to all files in the
|
|
21
|
+
* Goose governance plugin directory.
|
|
22
|
+
*
|
|
23
|
+
* @param pluginDir - Absolute path to the plugin directory
|
|
24
|
+
* (e.g. ~/.agents/plugins/intutic-governance)
|
|
25
|
+
*/
|
|
26
|
+
export declare function hardenGoosePlugin(pluginDir: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Remove immutable flags from a file (needed before sync daemon can overwrite
|
|
29
|
+
* during a legitimate governance refresh).
|
|
30
|
+
*
|
|
31
|
+
* @param filePath - Absolute path to the file
|
|
32
|
+
*/
|
|
33
|
+
export declare function unharden(filePath: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Check whether a file has an OS immutable flag set.
|
|
36
|
+
* Used by the drift watcher to decide whether to restore or emit an incident.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isImmutable(filePath: string): Promise<boolean>;
|
|
39
|
+
//# sourceMappingURL=gooseHardener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gooseHardener.d.ts","sourceRoot":"","sources":["../../src/harness/gooseHardener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBxE;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB9D;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBpE"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gooseHardener.ts — Cross-platform immutable flag management for Goose plugin files.
|
|
3
|
+
*
|
|
4
|
+
* After the Goose governance plugin is written, this module applies:
|
|
5
|
+
* 1. chmod 444 — no write for owner, group, or others
|
|
6
|
+
* 2. OS-level immutable flag:
|
|
7
|
+
* macOS: chflags uchg (user immutable, does not require root)
|
|
8
|
+
* Linux: chattr +i (requires root; graceful fallback on permission error)
|
|
9
|
+
*
|
|
10
|
+
* The drift watcher checks for immutable status before auto-restoring.
|
|
11
|
+
* If a file is immutable but has been tampered with, a governance_override_attempt
|
|
12
|
+
* incident is emitted to the control plane instead of a silent restore.
|
|
13
|
+
*
|
|
14
|
+
* LLD #14 — Phase 3 cross-harness defence
|
|
15
|
+
* HLD §3.14 — Three-Tier Defense Cascade
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import * as fs from 'node:fs/promises';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { execFile } from 'node:child_process';
|
|
22
|
+
import { promisify } from 'node:util';
|
|
23
|
+
import { createLogger } from '@intutic/logger';
|
|
24
|
+
const log = createLogger('sync-goose-hardener');
|
|
25
|
+
const execFileAsync = promisify(execFile);
|
|
26
|
+
/**
|
|
27
|
+
* Apply chmod 444 and OS immutable flags to all files in the
|
|
28
|
+
* Goose governance plugin directory.
|
|
29
|
+
*
|
|
30
|
+
* @param pluginDir - Absolute path to the plugin directory
|
|
31
|
+
* (e.g. ~/.agents/plugins/intutic-governance)
|
|
32
|
+
*/
|
|
33
|
+
export async function hardenGoosePlugin(pluginDir) {
|
|
34
|
+
const targets = [
|
|
35
|
+
path.join(pluginDir, 'hooks', 'hooks.json'),
|
|
36
|
+
path.join(pluginDir, 'scripts', 'intutic-check.sh'),
|
|
37
|
+
];
|
|
38
|
+
for (const target of targets) {
|
|
39
|
+
try {
|
|
40
|
+
await fs.access(target);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
log.warn({ action: 'harden_skip', target }, 'Goose plugin file not found — skipping hardening');
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
// Step 1: chmod 444
|
|
47
|
+
try {
|
|
48
|
+
await fs.chmod(target, 0o444);
|
|
49
|
+
log.debug({ action: 'chmod_444', target }, 'chmod 444 applied');
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
log.error({ action: 'chmod_failed', target, err }, 'chmod 444 failed');
|
|
53
|
+
}
|
|
54
|
+
// Step 2: OS immutable flag
|
|
55
|
+
await applyImmutableFlag(target);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Remove immutable flags from a file (needed before sync daemon can overwrite
|
|
60
|
+
* during a legitimate governance refresh).
|
|
61
|
+
*
|
|
62
|
+
* @param filePath - Absolute path to the file
|
|
63
|
+
*/
|
|
64
|
+
export async function unharden(filePath) {
|
|
65
|
+
if (process.platform === 'darwin') {
|
|
66
|
+
try {
|
|
67
|
+
await execFileAsync('chflags', ['nouchg', filePath]);
|
|
68
|
+
log.debug({ action: 'chflags_nouchg', filePath }, 'Removed macOS uchg flag');
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
log.warn({ action: 'chflags_nouchg_failed', filePath, err }, 'chflags nouchg failed');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (process.platform === 'linux') {
|
|
75
|
+
try {
|
|
76
|
+
await execFileAsync('chattr', ['-i', filePath]);
|
|
77
|
+
log.debug({ action: 'chattr_minus_i', filePath }, 'Removed Linux immutable flag');
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Best-effort — may not have root
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Restore writable mode temporarily
|
|
84
|
+
try {
|
|
85
|
+
await fs.chmod(filePath, 0o644);
|
|
86
|
+
}
|
|
87
|
+
catch { /* ignore */ }
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check whether a file has an OS immutable flag set.
|
|
91
|
+
* Used by the drift watcher to decide whether to restore or emit an incident.
|
|
92
|
+
*/
|
|
93
|
+
export async function isImmutable(filePath) {
|
|
94
|
+
if (process.platform === 'darwin') {
|
|
95
|
+
try {
|
|
96
|
+
const { stdout } = await execFileAsync('ls', ['-lO', filePath]);
|
|
97
|
+
return stdout.includes('uchg') || stdout.includes('uimmutable');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (process.platform === 'linux') {
|
|
104
|
+
try {
|
|
105
|
+
const { stdout } = await execFileAsync('lsattr', [filePath]);
|
|
106
|
+
return stdout.includes('-i-') || /\bi\b/.test(stdout.split(' ')[0] ?? '');
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// ─── Internal ────────────────────────────────────────────────────────
|
|
115
|
+
async function applyImmutableFlag(target) {
|
|
116
|
+
if (process.platform === 'darwin') {
|
|
117
|
+
try {
|
|
118
|
+
await execFileAsync('chflags', ['uchg', target]);
|
|
119
|
+
log.info({ action: 'chflags_uchg', target }, 'macOS uchg immutable flag applied');
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
log.error({ action: 'chflags_uchg_failed', target, err }, 'chflags uchg failed');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else if (process.platform === 'linux') {
|
|
126
|
+
try {
|
|
127
|
+
await execFileAsync('chattr', ['+i', target]);
|
|
128
|
+
log.info({ action: 'chattr_plus_i', target }, 'Linux immutable flag applied');
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
// chattr requires root on most distros; fail gracefully
|
|
132
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
133
|
+
if (msg.includes('Operation not permitted') || msg.includes('EPERM')) {
|
|
134
|
+
log.warn({ action: 'chattr_needs_root', target }, 'chattr +i requires root — immutable flag not applied (chmod 444 still in effect)');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
log.error({ action: 'chattr_failed', target, err }, 'chattr +i failed unexpectedly');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (process.platform === 'win32') {
|
|
142
|
+
// Windows: SetFileAttributes READONLY via attrib
|
|
143
|
+
try {
|
|
144
|
+
await execFileAsync('attrib', ['+R', target]);
|
|
145
|
+
log.info({ action: 'attrib_readonly', target }, 'Windows read-only attribute applied');
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
log.warn({ action: 'attrib_failed', target, err }, 'Windows attrib +R failed');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=gooseHardener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gooseHardener.js","sourceRoot":"","sources":["../../src/harness/gooseHardener.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gooseHooks.ts — Goose PreToolUse governance plugin injection.
|
|
3
|
+
*
|
|
4
|
+
* Writes the Intutic governance plugin to the Goose plugin directory:
|
|
5
|
+
* ~/.agents/plugins/intutic-governance/hooks/hooks.json
|
|
6
|
+
* ~/.agents/plugins/intutic-governance/scripts/intutic-check.sh
|
|
7
|
+
*
|
|
8
|
+
* Also merges the Intutic proxy URL into ~/.config/goose/config.yaml.
|
|
9
|
+
* After writing, calls gooseHardener to apply chmod 444 + immutable flags.
|
|
10
|
+
*
|
|
11
|
+
* LLD #14 — Phase 3 cross-harness defence
|
|
12
|
+
* HLD §3.14 — Three-Tier Defense Cascade
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Write Goose governance plugin and harden it.
|
|
18
|
+
*
|
|
19
|
+
* @param proxyUrl - Intutic proxy URL written into the plugin script.
|
|
20
|
+
* @param workspaceRoot - Absolute workspace root (for hook events log path).
|
|
21
|
+
* @param workspaceId - Workspace ID embedded in hook event payloads.
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeGooseHooks(proxyUrl: string, workspaceRoot?: string, workspaceId?: string): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=gooseHooks.d.ts.map
|