log-llm-config 1.3.7 → 1.3.8
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.
|
@@ -2,9 +2,9 @@ import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { OPT_AI_SEC_MANAGEMENT_REL } from './bootstrap_constants.js';
|
|
5
|
-
import {
|
|
5
|
+
import { hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
|
|
6
6
|
import { runComplianceCheck } from './log_config_files/runtime/compliance_check.js';
|
|
7
|
-
/** Append-only log for compliance runner lifecycle; hook_log.txt
|
|
7
|
+
/** Append-only log for compliance runner lifecycle; hook_log.txt uses a fresh session from the gate then this section. */
|
|
8
8
|
function runnerFileLog(message) {
|
|
9
9
|
try {
|
|
10
10
|
const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
|
|
@@ -18,7 +18,7 @@ function runnerFileLog(message) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
(async () => {
|
|
21
|
-
|
|
21
|
+
hookLogAppendSection('compliance_check_runner (background sync + check)');
|
|
22
22
|
runnerFileLog('compliance_check_runner: start');
|
|
23
23
|
try {
|
|
24
24
|
await runComplianceCheck();
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
* and remediation_instructions.json via applyAutofixViolations / enforceRemediation.
|
|
7
7
|
*
|
|
8
8
|
* Prompt gate: compliance_prompt_gate runs runLocalRemediationComplianceCheck then applyAutofixViolations.
|
|
9
|
-
* Background: compliance_check_runner runs syncRemediations (network)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Background: compliance_check_runner runs syncRemediations (network) then the same local check.
|
|
10
|
+
* Apply (autofix) is intentionally left to the gate on the next prompt — the background pass only
|
|
11
|
+
* downloads the latest manifest so the gate has fresh data to act on.
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, readFileSync
|
|
13
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
14
14
|
import { readVscdbItemTableJson } from '../readers/vscdb_reader.js';
|
|
15
|
-
import {
|
|
16
|
-
import { executeTrustedRestartCommands } from './trusted_restarts.js';
|
|
15
|
+
import { readRemediationInstructionsFile, writeRemediationInstructionsFile } from './management_storage.js';
|
|
17
16
|
import { complianceRunnerDiag, hookRunLog } from './hook_logger.js';
|
|
18
17
|
import { loadEndpointBase } from '../sender/endpoint_config.js';
|
|
19
18
|
import { resolveHardwareUuid, tryResolveHardwareUuid } from './hardware_uuid.js';
|
|
@@ -434,22 +433,10 @@ export function pruneSatisfiedOneTimeRemediations() {
|
|
|
434
433
|
}
|
|
435
434
|
return { removed, reportPromises };
|
|
436
435
|
}
|
|
437
|
-
/** Same staleness window as compliance_prompt_gate: avoid applying very old local manifests. */
|
|
438
|
-
const MANIFEST_STALE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
439
|
-
function getManifestStalenessMs() {
|
|
440
|
-
try {
|
|
441
|
-
const p = getRemediationInstructionsPath();
|
|
442
|
-
if (!existsSync(p))
|
|
443
|
-
return null;
|
|
444
|
-
return Date.now() - statSync(p).mtimeMs;
|
|
445
|
-
}
|
|
446
|
-
catch {
|
|
447
|
-
return null;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
436
|
/**
|
|
451
|
-
* Background refresh: server sync
|
|
452
|
-
*
|
|
437
|
+
* Background refresh: server sync for latest instructions, then the same local evaluation as the hook.
|
|
438
|
+
* Apply (autofix) is intentionally deferred to the gate on the next prompt — this pass only downloads
|
|
439
|
+
* a fresh manifest so the gate has up-to-date data when it runs.
|
|
453
440
|
*/
|
|
454
441
|
export async function runComplianceCheck() {
|
|
455
442
|
try {
|
|
@@ -464,31 +451,5 @@ export async function runComplianceCheck() {
|
|
|
464
451
|
if (pruned.removed > 0) {
|
|
465
452
|
await Promise.allSettled(pruned.reportPromises);
|
|
466
453
|
}
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
const staleMs = getManifestStalenessMs();
|
|
470
|
-
if (staleMs !== null && staleMs > MANIFEST_STALE_MS) {
|
|
471
|
-
const staleDays = Math.floor(staleMs / (24 * 60 * 60 * 1000));
|
|
472
|
-
hookRunLog(`compliance_check_runner: skip autofix — local remediation manifest is stale (${staleDays} days old)`);
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
const { fixed, restartCommands, failedViolations, reportPromises } = applyAutofixViolations(status.violations);
|
|
476
|
-
if (fixed === 0) {
|
|
477
|
-
if (failedViolations.length > 0) {
|
|
478
|
-
hookRunLog(`compliance_check_runner: autofix failed for ${failedViolations.length} violation(s) (see autofix logs above)`);
|
|
479
|
-
}
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
await Promise.allSettled(reportPromises);
|
|
483
|
-
if (failedViolations.length > 0) {
|
|
484
|
-
hookRunLog(`compliance_check_runner: autofix partial failure — ${failedViolations.length} violation(s) still unresolved`);
|
|
485
|
-
}
|
|
486
|
-
if (restartCommands.length > 0) {
|
|
487
|
-
hookRunLog(`compliance_check_runner: executing ${restartCommands.length} trusted restart command(s)`);
|
|
488
|
-
executeTrustedRestartCommands(restartCommands);
|
|
489
|
-
}
|
|
490
|
-
const pruned = pruneSatisfiedOneTimeRemediations();
|
|
491
|
-
if (pruned.removed > 0) {
|
|
492
|
-
await Promise.allSettled(pruned.reportPromises);
|
|
493
454
|
}
|
|
494
455
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, appendFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, appendFileSync, writeFileSync, statSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { OPT_AI_SEC_MANAGEMENT_REL } from '../../bootstrap_constants.js';
|
|
4
4
|
const HOOK_LOG_FILENAME = 'hook_log.txt';
|
|
5
5
|
const COMPLIANCE_RUNNER_LOG_FILENAME = 'compliance_runner.log';
|
|
6
|
+
/** Hard cap so a single upload/sync session cannot grow hook_log.txt without bound. */
|
|
7
|
+
const MAX_HOOK_LOG_BYTES = 2 * 1024 * 1024;
|
|
6
8
|
function getHookLogPath() {
|
|
7
9
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
8
10
|
if (!homeDir)
|
|
@@ -33,7 +35,24 @@ function complianceRunnerDiag(message) {
|
|
|
33
35
|
// best-effort
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
function ensureHookLogUnderCap() {
|
|
39
|
+
const logPath = getHookLogPath();
|
|
40
|
+
if (!logPath || !existsSync(logPath))
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
if (statSync(logPath).size <= MAX_HOOK_LOG_BYTES)
|
|
44
|
+
return;
|
|
45
|
+
const ts = new Date().toISOString();
|
|
46
|
+
writeFileSync(logPath, `${'='.repeat(72)}\n${ts} hook_log.txt truncated (exceeded ${MAX_HOOK_LOG_BYTES} bytes)\n${'='.repeat(72)}\n`, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// best-effort
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start a new hook_log.txt session (replaces the file). Use once per logical run
|
|
54
|
+
* (e.g. compliance_prompt_gate, log_config_files upload via hookLogReplace).
|
|
55
|
+
*/
|
|
37
56
|
function hookLogSessionBanner(label) {
|
|
38
57
|
const logPath = getHookLogPath();
|
|
39
58
|
if (!logPath)
|
|
@@ -44,15 +63,34 @@ function hookLogSessionBanner(label) {
|
|
|
44
63
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
45
64
|
const ts = new Date().toISOString();
|
|
46
65
|
const banner = `\n${'='.repeat(72)}\n${ts} session: ${label}\n${'='.repeat(72)}\n`;
|
|
47
|
-
|
|
66
|
+
writeFileSync(logPath, banner, 'utf8');
|
|
48
67
|
}
|
|
49
68
|
catch {
|
|
50
69
|
// best-effort
|
|
51
70
|
}
|
|
52
71
|
}
|
|
53
72
|
/**
|
|
54
|
-
*
|
|
73
|
+
* Append a subsection after an existing session (e.g. compliance_check_runner after the gate)
|
|
74
|
+
* without replacing hook_log.txt.
|
|
55
75
|
*/
|
|
76
|
+
function hookLogAppendSection(label) {
|
|
77
|
+
const logPath = getHookLogPath();
|
|
78
|
+
if (!logPath)
|
|
79
|
+
return;
|
|
80
|
+
try {
|
|
81
|
+
ensureHookLogUnderCap();
|
|
82
|
+
const dir = path.dirname(logPath);
|
|
83
|
+
if (!existsSync(dir))
|
|
84
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
85
|
+
const ts = new Date().toISOString();
|
|
86
|
+
const banner = `\n${'-'.repeat(72)}\n${ts} section: ${label}\n${'-'.repeat(72)}\n`;
|
|
87
|
+
appendFileSync(logPath, banner, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// best-effort
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Begins a log_config_files upload session (replaces hook_log.txt, same as hookLogSessionBanner). */
|
|
56
94
|
function hookLogReplace() {
|
|
57
95
|
hookLogSessionBanner('log_config_files (config upload)');
|
|
58
96
|
}
|
|
@@ -62,6 +100,7 @@ function hookRunLog(message) {
|
|
|
62
100
|
if (!logPath)
|
|
63
101
|
return;
|
|
64
102
|
try {
|
|
103
|
+
ensureHookLogUnderCap();
|
|
65
104
|
const ts = new Date().toISOString();
|
|
66
105
|
appendFileSync(logPath, `${ts} ${message}\n`, 'utf8');
|
|
67
106
|
}
|
|
@@ -75,10 +114,11 @@ function hookLogLine(message) {
|
|
|
75
114
|
if (!logPath)
|
|
76
115
|
return;
|
|
77
116
|
try {
|
|
117
|
+
ensureHookLogUnderCap();
|
|
78
118
|
appendFileSync(logPath, `${message}\n`, 'utf8');
|
|
79
119
|
}
|
|
80
120
|
catch {
|
|
81
121
|
// best-effort
|
|
82
122
|
}
|
|
83
123
|
}
|
|
84
|
-
export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookRunLog, hookLogLine, complianceRunnerDiag, };
|
|
124
|
+
export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, };
|