log-llm-config 1.3.23 → 1.3.25
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/compliance_check_runner.js +5 -29
- package/dist/endpoint_client/index.js +1 -1
- package/dist/endpoint_client/registry_api.js +6 -2
- package/dist/execute_trusted_restarts.js +14 -5
- package/dist/log_config_files/runtime/compliance_check.js +26 -3
- package/dist/log_config_files/runtime/hook_logger.js +26 -8
- package/dist/log_config_files/runtime/management_storage.js +5 -0
- package/dist/log_config_files/runtime/remediation_sync.js +10 -14
- package/dist/log_config_files/runtime/trusted_restarts.js +34 -4
- package/package.json +1 -1
|
@@ -1,40 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { OPT_AI_SEC_MANAGEMENT_REL } from './bootstrap_constants.js';
|
|
5
|
-
import { hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
|
|
1
|
+
import { complianceRunnerRunnerLine, hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
|
|
6
2
|
import { runComplianceCheck } from './log_config_files/runtime/compliance_check.js';
|
|
7
|
-
/** Append-only log for compliance runner lifecycle; hook_log.txt uses a fresh session from the gate then this section. */
|
|
8
|
-
function runnerFileLog(message) {
|
|
9
|
-
try {
|
|
10
|
-
const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
|
|
11
|
-
if (!existsSync(dir))
|
|
12
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
13
|
-
const path = join(dir, 'compliance_runner.log');
|
|
14
|
-
appendFileSync(path, `${new Date().toISOString()} ${message}\n`, 'utf8');
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
/* ignore */
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
3
|
(async () => {
|
|
21
4
|
hookLogAppendSection('compliance_check_runner (background sync + check)');
|
|
22
|
-
|
|
5
|
+
complianceRunnerRunnerLine('compliance_check_runner: start');
|
|
23
6
|
try {
|
|
24
7
|
await runComplianceCheck();
|
|
25
|
-
|
|
8
|
+
complianceRunnerRunnerLine('compliance_check_runner: finished ok');
|
|
26
9
|
}
|
|
27
10
|
catch (err) {
|
|
28
11
|
const detail = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
|
|
32
|
-
const path = join(dir, 'compliance_runner.log');
|
|
33
|
-
appendFileSync(path, `${detail}\n\n`, 'utf8');
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
/* ignore */
|
|
37
|
-
}
|
|
12
|
+
complianceRunnerRunnerLine(`compliance_check_runner: uncaught error — ${err instanceof Error ? err.message : String(err)}`);
|
|
13
|
+
complianceRunnerRunnerLine(`compliance_check_runner: stack_or_detail ${detail.slice(0, 4000)}`);
|
|
38
14
|
process.stderr.write(`compliance_check_runner error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
39
15
|
process.exit(1);
|
|
40
16
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { FILE_PATH_REGISTRY_FILE_PATTERNS_PATH, FILE_PATH_REGISTRY_SENSITIVE_PATHS_PATH, } from './types.js';
|
|
2
|
-
export { getFileCollectionPatterns, getSensitivePathsAuditCandidates } from './registry_api.js';
|
|
2
|
+
export { buildApiUrl, getFileCollectionPatterns, getSensitivePathsAuditCandidates, } from './registry_api.js';
|
|
3
3
|
export { postStartupPayload, patchPayload, classifyEndpointResponse } from './startup_api.js';
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
1
2
|
import { executeGet } from './http_transport.js';
|
|
2
3
|
import { FILE_PATH_REGISTRY_FILE_PATTERNS_PATH, FILE_PATH_REGISTRY_SENSITIVE_PATHS_PATH, } from './types.js';
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
/** Join API base (may include a path prefix, e.g. https://host/optimus/) with an absolute API path. */
|
|
5
|
+
export function buildApiUrl(base, path) {
|
|
6
|
+
const normalizedBase = `${base.replace(/\/+$/, '')}/`;
|
|
7
|
+
const relativePath = path.replace(/^\/+/, '');
|
|
8
|
+
return new URL(relativePath, normalizedBase).href;
|
|
5
9
|
}
|
|
6
10
|
/**
|
|
7
11
|
* GET file collection patterns from the backend (what to look for).
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync } from 'node:fs';
|
|
7
7
|
import { isThisCliModule } from './cli_invocation_match.js';
|
|
8
|
-
import { hookRunLog } from './log_config_files/runtime/hook_logger.js';
|
|
8
|
+
import { appendComplianceRunnerLine, hookRunLog } from './log_config_files/runtime/hook_logger.js';
|
|
9
9
|
import { executeTrustedRestartCommands } from './log_config_files/runtime/trusted_restarts.js';
|
|
10
10
|
function main() {
|
|
11
11
|
let raw;
|
|
@@ -13,24 +13,33 @@ function main() {
|
|
|
13
13
|
raw = readFileSync(0, 'utf8');
|
|
14
14
|
}
|
|
15
15
|
catch {
|
|
16
|
-
|
|
16
|
+
const msg = 'execute_trusted_restarts: could not read stdin';
|
|
17
|
+
hookRunLog(msg);
|
|
18
|
+
appendComplianceRunnerLine('RESTART', msg);
|
|
17
19
|
return;
|
|
18
20
|
}
|
|
19
21
|
const first = raw.trim().split(/\r?\n/)[0]?.trim() ?? '';
|
|
20
|
-
if (!first)
|
|
22
|
+
if (!first) {
|
|
23
|
+
appendComplianceRunnerLine('RESTART', 'empty stdin — no restart_commands');
|
|
21
24
|
return;
|
|
25
|
+
}
|
|
22
26
|
let j;
|
|
23
27
|
try {
|
|
24
28
|
j = JSON.parse(first);
|
|
25
29
|
}
|
|
26
30
|
catch {
|
|
27
|
-
|
|
31
|
+
const msg = 'execute_trusted_restarts: stdin is not valid JSON';
|
|
32
|
+
hookRunLog(msg);
|
|
33
|
+
appendComplianceRunnerLine('RESTART', msg);
|
|
28
34
|
return;
|
|
29
35
|
}
|
|
30
36
|
const cmds = j.restart_commands;
|
|
31
|
-
if (!Array.isArray(cmds))
|
|
37
|
+
if (!Array.isArray(cmds)) {
|
|
38
|
+
appendComplianceRunnerLine('RESTART', 'JSON missing restart_commands array — nothing to run');
|
|
32
39
|
return;
|
|
40
|
+
}
|
|
33
41
|
const strings = cmds.filter((c) => typeof c === 'string');
|
|
42
|
+
appendComplianceRunnerLine('RESTART', `stdin ok restart_commands=${strings.length}`);
|
|
34
43
|
executeTrustedRestartCommands(strings);
|
|
35
44
|
}
|
|
36
45
|
if (isThisCliModule(process.argv[1], import.meta.url)) {
|
|
@@ -143,19 +143,29 @@ export function runLocalRemediationComplianceCheck() {
|
|
|
143
143
|
}
|
|
144
144
|
const uuids = entries.map((e) => e.uuid);
|
|
145
145
|
const violations = [];
|
|
146
|
+
let skippedNoCompliance = 0;
|
|
147
|
+
let skippedNonJson = 0;
|
|
148
|
+
let skippedNoChecks = 0;
|
|
149
|
+
let skippedUnreadable = 0;
|
|
146
150
|
for (const entry of entries) {
|
|
147
151
|
const compliance = entry.fix ?? entry.compliance;
|
|
148
|
-
if (!compliance)
|
|
152
|
+
if (!compliance) {
|
|
153
|
+
skippedNoCompliance++;
|
|
149
154
|
continue;
|
|
155
|
+
}
|
|
150
156
|
if (compliance.file_format !== 'json') {
|
|
157
|
+
skippedNonJson++;
|
|
151
158
|
hookRunLog(`compliance_check: skipping non-json entry uuid=${entry.uuid}`);
|
|
152
159
|
continue;
|
|
153
160
|
}
|
|
154
161
|
const checks = compliance.checks ?? [];
|
|
155
|
-
if (checks.length === 0)
|
|
162
|
+
if (checks.length === 0) {
|
|
163
|
+
skippedNoChecks++;
|
|
156
164
|
continue;
|
|
165
|
+
}
|
|
157
166
|
const loaded = loadRemediationConfigJson(entry.config_file_path, checks.map((c) => c.setting_path));
|
|
158
167
|
if (!loaded.ok) {
|
|
168
|
+
skippedUnreadable++;
|
|
159
169
|
const msg = loaded.reason === 'file_not_found'
|
|
160
170
|
? `compliance_check: config file not found, skipping uuid=${entry.uuid}`
|
|
161
171
|
: loaded.reason === 'db_not_found'
|
|
@@ -228,7 +238,20 @@ export function runLocalRemediationComplianceCheck() {
|
|
|
228
238
|
manifest_uuids: uuids,
|
|
229
239
|
violations,
|
|
230
240
|
};
|
|
231
|
-
|
|
241
|
+
const skipParts = [];
|
|
242
|
+
if (skippedNoCompliance)
|
|
243
|
+
skipParts.push(`no_fix=${skippedNoCompliance}`);
|
|
244
|
+
if (skippedNonJson)
|
|
245
|
+
skipParts.push(`non_json=${skippedNonJson}`);
|
|
246
|
+
if (skippedNoChecks)
|
|
247
|
+
skipParts.push(`no_checks=${skippedNoChecks}`);
|
|
248
|
+
if (skippedUnreadable)
|
|
249
|
+
skipParts.push(`unreadable_config=${skippedUnreadable}`);
|
|
250
|
+
const skipSummary = skipParts.length > 0 ? ` skipped{${skipParts.join(' ')}}` : '';
|
|
251
|
+
hookRunLog(`compliance_check: done — status=${status.status} violations=${violations.length} manifest_entries=${uuids.length}${skipSummary}`);
|
|
252
|
+
if (skippedUnreadable > 0) {
|
|
253
|
+
complianceRunnerDiag(`compliance_check: ${skippedUnreadable} manifest row(s) skipped — vscdb/config unreadable (often DB locked while Cursor runs, or sqlite3/PATH). Autofix cannot evaluate until read succeeds.`);
|
|
254
|
+
}
|
|
232
255
|
return status;
|
|
233
256
|
}
|
|
234
257
|
catch (err) {
|
|
@@ -26,9 +26,10 @@ function getRemediationApplyFailuresLogPath() {
|
|
|
26
26
|
return path.join(homeDir, OPT_AI_SEC_MANAGEMENT_REL, REMEDIATION_APPLY_FAILURES_FILENAME);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Append
|
|
29
|
+
* Append one ISO-timestamped line to compliance_runner.log.
|
|
30
|
+
* `level` examples: INFO, RUNNER, RESTART, FAIL
|
|
30
31
|
*/
|
|
31
|
-
function
|
|
32
|
+
function appendComplianceRunnerLine(level, message) {
|
|
32
33
|
const logPath = getComplianceRunnerLogPath();
|
|
33
34
|
if (!logPath)
|
|
34
35
|
return;
|
|
@@ -37,12 +38,24 @@ function complianceRunnerDiag(message) {
|
|
|
37
38
|
if (!existsSync(dir))
|
|
38
39
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
39
40
|
const ts = new Date().toISOString();
|
|
40
|
-
appendFileSync(logPath, `${ts} ${message}\n`, 'utf8');
|
|
41
|
+
appendFileSync(logPath, `${ts} [${level}] pid=${process.pid} ${message}\n`, 'utf8');
|
|
41
42
|
}
|
|
42
43
|
catch {
|
|
43
44
|
// best-effort
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Append-only diagnostics for remediation sync / compliance (structured).
|
|
49
|
+
*/
|
|
50
|
+
function complianceRunnerDiag(message) {
|
|
51
|
+
appendComplianceRunnerLine('INFO', message);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Background compliance_check_runner should use this so entries match the same format.
|
|
55
|
+
*/
|
|
56
|
+
function complianceRunnerRunnerLine(message) {
|
|
57
|
+
appendComplianceRunnerLine('RUNNER', message);
|
|
58
|
+
}
|
|
46
59
|
/**
|
|
47
60
|
* Loud, append-only record when a remediation cannot be verified or applied. Writes
|
|
48
61
|
* {@link REMEDIATION_APPLY_FAILURES_FILENAME} and mirrors the same block to compliance_runner.log;
|
|
@@ -66,7 +79,7 @@ function logRemediationApplyFailure(context, fields) {
|
|
|
66
79
|
: fields.message != null
|
|
67
80
|
? String(fields.message)
|
|
68
81
|
: 'see fields above';
|
|
69
|
-
const
|
|
82
|
+
const writeFailAppend = (filePath) => {
|
|
70
83
|
const dir = path.dirname(filePath);
|
|
71
84
|
if (!existsSync(dir))
|
|
72
85
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
@@ -75,10 +88,14 @@ function logRemediationApplyFailure(context, fields) {
|
|
|
75
88
|
try {
|
|
76
89
|
const failPath = getRemediationApplyFailuresLogPath();
|
|
77
90
|
if (failPath)
|
|
78
|
-
|
|
91
|
+
writeFailAppend(failPath);
|
|
79
92
|
const crPath = getComplianceRunnerLogPath();
|
|
80
|
-
if (crPath)
|
|
81
|
-
|
|
93
|
+
if (crPath) {
|
|
94
|
+
const dir = path.dirname(crPath);
|
|
95
|
+
if (!existsSync(dir))
|
|
96
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
97
|
+
appendFileSync(crPath, block, 'utf8');
|
|
98
|
+
}
|
|
82
99
|
}
|
|
83
100
|
catch {
|
|
84
101
|
/* best-effort */
|
|
@@ -89,6 +106,7 @@ function logRemediationApplyFailure(context, fields) {
|
|
|
89
106
|
catch {
|
|
90
107
|
/* best-effort */
|
|
91
108
|
}
|
|
109
|
+
appendComplianceRunnerLine('FAIL', `${context} — ${summary}`);
|
|
92
110
|
}
|
|
93
111
|
function ensureHookLogUnderCap() {
|
|
94
112
|
const logPath = getHookLogPath();
|
|
@@ -176,4 +194,4 @@ function hookLogLine(message) {
|
|
|
176
194
|
// best-effort
|
|
177
195
|
}
|
|
178
196
|
}
|
|
179
|
-
export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, logRemediationApplyFailure, };
|
|
197
|
+
export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, complianceRunnerRunnerLine, appendComplianceRunnerLine, logRemediationApplyFailure, };
|
|
@@ -9,6 +9,8 @@ import { OPT_AI_SEC_MANAGEMENT_REL } from '../../bootstrap_constants.js';
|
|
|
9
9
|
export const REMEDIATION_INSTRUCTIONS_BASENAME = 'remediation_instructions.json';
|
|
10
10
|
/** Pending state.vscdb writes applied after Cursor exits (IDE holds the DB locked). */
|
|
11
11
|
export const DEFERRED_VSCDB_APPLY_BASENAME = 'optimus_deferred_vscdb_apply.json';
|
|
12
|
+
/** Shell stdout/stderr from the trusted deferred restart pipeline (apply_deferred_vscdb + open Cursor). */
|
|
13
|
+
export const DEFERRED_VSCDB_RESTART_LOG_BASENAME = 'deferred_vscdb_restart.log';
|
|
12
14
|
/**
|
|
13
15
|
* Cached subset of GET file-patterns: reactive ItemTable key + composer shadow keys from the backend.
|
|
14
16
|
* Written when patterns are fetched; remediations and vscdb reads use this so the npm package stays free
|
|
@@ -24,6 +26,9 @@ export function getRemediationInstructionsPath() {
|
|
|
24
26
|
export function getDeferredVscdbApplyPath() {
|
|
25
27
|
return join(getManagementDir(), DEFERRED_VSCDB_APPLY_BASENAME);
|
|
26
28
|
}
|
|
29
|
+
export function getDeferredVscdbRestartLogPath() {
|
|
30
|
+
return join(getManagementDir(), DEFERRED_VSCDB_RESTART_LOG_BASENAME);
|
|
31
|
+
}
|
|
27
32
|
export function getFileCollectionVscdbContractPath() {
|
|
28
33
|
return join(getManagementDir(), FILE_COLLECTION_VSCDB_CONTRACT_BASENAME);
|
|
29
34
|
}
|
|
@@ -10,7 +10,7 @@ import { loadEndpointBase } from '../sender/endpoint_config.js';
|
|
|
10
10
|
import { tryResolveHardwareUuid } from './hardware_uuid.js';
|
|
11
11
|
import { CURSOR_SCALAR_ITEMTABLE_FIELDS, persistVscdbComposerContractFromPatternsResponse, readVscdbItemTableJson, } from '../readers/vscdb_reader.js';
|
|
12
12
|
import { sendConfigFile } from '../sender/batch_sender.js';
|
|
13
|
-
import { getFileCollectionPatterns } from '../../endpoint_client/registry_api.js';
|
|
13
|
+
import { buildApiUrl, getFileCollectionPatterns } from '../../endpoint_client/registry_api.js';
|
|
14
14
|
import { resolveRemediationConfigPath } from './remediation_config_path.js';
|
|
15
15
|
import { resolveSqlite3Binary } from './sqlite_binary.js';
|
|
16
16
|
/** Best-effort detail from execFileSync failures (stderr, exit code, errno). */
|
|
@@ -119,17 +119,9 @@ async function ensureInstructionsForUuids(endpointBase, machineUuid, want, overl
|
|
|
119
119
|
// ---------------------------------------------------------------------------
|
|
120
120
|
// API helpers
|
|
121
121
|
// ---------------------------------------------------------------------------
|
|
122
|
-
function resolveOrigin(endpointBase) {
|
|
123
|
-
try {
|
|
124
|
-
return new URL(endpointBase).origin;
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return endpointBase.replace(/\/+$/, '');
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
122
|
export async function fetchSync(endpointBase, machineUuid, activeUuids, timeoutMs = 8000) {
|
|
131
123
|
const uuidsParam = activeUuids.join(',');
|
|
132
|
-
const url = `${
|
|
124
|
+
const url = `${buildApiUrl(endpointBase, '/api/findings/remediations/sync/')}?machine_uuid=${encodeURIComponent(machineUuid)}&active_uuids=${encodeURIComponent(uuidsParam)}`;
|
|
133
125
|
const { statusCode, body } = await executeGet(url, timeoutMs);
|
|
134
126
|
if (statusCode !== 200 || !body) {
|
|
135
127
|
const line = `remediation_sync_get: url=${url} status=${statusCode} bytes=${body?.length ?? 0}`;
|
|
@@ -147,7 +139,7 @@ export async function fetchSync(endpointBase, machineUuid, activeUuids, timeoutM
|
|
|
147
139
|
}
|
|
148
140
|
}
|
|
149
141
|
async function fetchManifest(endpointBase, machineUuid, uuids, timeoutMs = 8000) {
|
|
150
|
-
const url = `${
|
|
142
|
+
const url = `${buildApiUrl(endpointBase, '/api/findings/remediations/manifest/')}?machine_uuid=${encodeURIComponent(machineUuid)}&uuids=${encodeURIComponent(uuids.join(','))}`;
|
|
151
143
|
const { statusCode, body } = await executeGet(url, timeoutMs);
|
|
152
144
|
if (statusCode !== 200 || !body) {
|
|
153
145
|
const line = `remediation_manifest_get: url=${url} status=${statusCode} bytes=${body?.length ?? 0}`;
|
|
@@ -370,8 +362,10 @@ function assertSafeSqliteIdentifiersForItemTable(table, keyColumn, valueColumn)
|
|
|
370
362
|
* Exact-match only: `spawn('sh', ['-c', cmd])` runs the whole string; substring checks would allow
|
|
371
363
|
* appending `; arbitrary shell` after a trusted prefix.
|
|
372
364
|
*/
|
|
373
|
-
const TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND = 'REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export REPO_ROOT
|
|
374
|
-
|
|
365
|
+
const TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND = 'REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export REPO_ROOT && ' +
|
|
366
|
+
'CURSOR_PROJECT="${CURSOR_PROJECT_DIR:-$REPO_ROOT}" && export CURSOR_PROJECT && ' +
|
|
367
|
+
'OPTIMUS_DEFERRED_LOG="${HOME}/opt-ai-sec/management/deferred_vscdb_restart.log" && mkdir -p "$(dirname "$OPTIMUS_DEFERRED_LOG")" && export OPTIMUS_DEFERRED_LOG && ' +
|
|
368
|
+
"nohup bash -c 'exec >>\"\$OPTIMUS_DEFERRED_LOG\" 2>&1; echo deferred_restart:begin ts=\$(date -u +%Y-%m-%dT%H:%M:%SZ) REPO_ROOT=\"\$REPO_ROOT\" CURSOR_PROJECT=\"\$CURSOR_PROJECT\"; sleep 2; if [ -f \"\$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\" ]; then echo deferred_restart:apply_via_monorepo_node; node \"\$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\"; APPLY_EC=\$?; else echo deferred_restart:apply_via_npx; cd \"\$REPO_ROOT\" && npx --yes -p log-llm-config apply-deferred-vscdb; APPLY_EC=\$?; fi; echo deferred_restart:apply_exit=\$APPLY_EC; if [ \$APPLY_EC -ne 0 ]; then echo deferred_restart:APPLY_FAILED_see_messages_above; fi; echo deferred_restart:open_cursor; open -a Cursor \"\$CURSOR_PROJECT\"; echo deferred_restart:open_exit=\$?; echo deferred_restart:end ts=\$(date -u +%Y-%m-%dT%H:%M:%SZ)' >/dev/null 2>&1 & killall -9 Cursor";
|
|
375
369
|
const TRUSTED_CURSOR_JSON_SETTINGS_RESTART_COMMAND = 'CURSOR_PROJECT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export CURSOR_PROJECT && nohup bash -c \'sleep 2 && open -a Cursor "$CURSOR_PROJECT"\' >/dev/null 2>&1 & killall -9 Cursor';
|
|
376
370
|
const TRUSTED_CLAUDE_RESTART_COMMAND = "nohup bash -c 'sleep 2 && open -a Claude' >/dev/null 2>&1 & pkill -x 'Claude'";
|
|
377
371
|
/**
|
|
@@ -729,6 +723,8 @@ function queueDeferredVscdbItem(item, postApplyUpload) {
|
|
|
729
723
|
*/
|
|
730
724
|
export async function applyDeferredVscdbFromDisk() {
|
|
731
725
|
const path = getDeferredVscdbApplyPath();
|
|
726
|
+
hookRunLog(`deferred_vscdb: applyDeferredVscdbFromDisk queue_path=${path} exists=${existsSync(path)}`);
|
|
727
|
+
complianceRunnerDiag(`deferred_vscdb: applyDeferredVscdbFromDisk start exists=${existsSync(path)}`);
|
|
732
728
|
if (!existsSync(path))
|
|
733
729
|
return true;
|
|
734
730
|
if (!assertSqlite3Available())
|
|
@@ -1130,7 +1126,7 @@ export function reportAutofixApplied(remediationUuid, result) {
|
|
|
1130
1126
|
return Promise.resolve();
|
|
1131
1127
|
}
|
|
1132
1128
|
const endpointBase = loadEndpointBase();
|
|
1133
|
-
const url =
|
|
1129
|
+
const url = buildApiUrl(endpointBase, '/endpoint_security/api/autofix-applied/');
|
|
1134
1130
|
const payload = { hardware_uuid: hardwareUuid, remediation_uuid: remediationUuid, result };
|
|
1135
1131
|
const signature = createSignature(payload, authKey.key);
|
|
1136
1132
|
const body = JSON.stringify({ ...payload, signature });
|
|
@@ -3,8 +3,13 @@
|
|
|
3
3
|
* Used by the compliance shell hook via execute_trusted_restarts CLI — single place for allowlist + spawn.
|
|
4
4
|
*/
|
|
5
5
|
import { spawn } from 'node:child_process';
|
|
6
|
-
import { hookRunLog } from './hook_logger.js';
|
|
6
|
+
import { appendComplianceRunnerLine, hookRunLog } from './hook_logger.js';
|
|
7
|
+
import { getDeferredVscdbRestartLogPath } from './management_storage.js';
|
|
7
8
|
import { isTrustedRestartCommandForAutofix } from './remediation_sync.js';
|
|
9
|
+
const FALLBACK_PATH = '/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin';
|
|
10
|
+
function isDeferredVscdbRestart(cmd) {
|
|
11
|
+
return cmd.includes('OPTIMUS_DEFERRED_LOG') || cmd.includes('apply_deferred_vscdb');
|
|
12
|
+
}
|
|
8
13
|
/** Spawn each trusted command detached (same pattern as former compliance_prompt_gate fireRestartCommands). */
|
|
9
14
|
export function executeTrustedRestartCommands(commands) {
|
|
10
15
|
for (const cmd of commands) {
|
|
@@ -12,11 +17,36 @@ export function executeTrustedRestartCommands(commands) {
|
|
|
12
17
|
if (!t)
|
|
13
18
|
continue;
|
|
14
19
|
if (!isTrustedRestartCommandForAutofix(cmd)) {
|
|
15
|
-
|
|
20
|
+
const msg = `rejected_not_allowlisted prefix=${t.slice(0, 200)}`;
|
|
21
|
+
hookRunLog(`execute_trusted_restarts: ${msg}`);
|
|
22
|
+
appendComplianceRunnerLine('RESTART', msg);
|
|
16
23
|
continue;
|
|
17
24
|
}
|
|
18
|
-
|
|
19
|
-
const
|
|
25
|
+
const deferred = isDeferredVscdbRestart(t);
|
|
26
|
+
const detailPath = getDeferredVscdbRestartLogPath();
|
|
27
|
+
if (deferred) {
|
|
28
|
+
hookRunLog(`execute_trusted_restarts: spawning deferred state.vscdb restart (killall Cursor, then apply + reopen). Step-by-step log → ${detailPath}`);
|
|
29
|
+
appendComplianceRunnerLine('RESTART', `spawn deferred_vscdb_restart sh -c (detail_log=${detailPath}) cwd_inherited_from_node`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
hookRunLog('execute_trusted_restarts: spawning trusted restart (see compliance_runner.log [RESTART])');
|
|
33
|
+
appendComplianceRunnerLine('RESTART', 'spawn trusted_restart sh -c (non-deferred)');
|
|
34
|
+
}
|
|
35
|
+
const child = spawn('sh', ['-c', t], {
|
|
36
|
+
detached: true,
|
|
37
|
+
stdio: 'ignore',
|
|
38
|
+
env: {
|
|
39
|
+
...process.env,
|
|
40
|
+
PATH: process.env.PATH && String(process.env.PATH).trim().length > 0
|
|
41
|
+
? process.env.PATH
|
|
42
|
+
: FALLBACK_PATH,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
child.on('error', (err) => {
|
|
46
|
+
const emsg = err instanceof Error ? err.message : String(err);
|
|
47
|
+
hookRunLog(`execute_trusted_restarts: spawn failed ${emsg}`);
|
|
48
|
+
appendComplianceRunnerLine('RESTART', `spawn_error ${emsg}`);
|
|
49
|
+
});
|
|
20
50
|
child.unref();
|
|
21
51
|
}
|
|
22
52
|
}
|