log-llm-config-staging 1.3.72 → 1.3.73
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/cli.js +1 -1
- package/dist/compliance_prompt_gate.js +21 -1
- package/dist/log_config_files/runtime/compliance_check.js +3 -2
- package/dist/log_config_files/runtime/main_runner.js +2 -2
- package/dist/log_config_files/sender/batch_sender.js +18 -3
- package/dist/log_uuid/startup_sender.js +1 -1
- package/dist/tofu.js +2 -29
- package/dist/tofu_environment.js +32 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -94,7 +94,7 @@ function parseAndSetLogUuidEnvVars() {
|
|
|
94
94
|
if (userArg)
|
|
95
95
|
process.env.GITHUB_USER = userArg;
|
|
96
96
|
if (repoArg)
|
|
97
|
-
process.env.
|
|
97
|
+
process.env.OPTIMUS_WORKSPACE_REPO = repoArg;
|
|
98
98
|
if (branchArg)
|
|
99
99
|
process.env.GITHUB_REF_NAME = branchArg;
|
|
100
100
|
if (agentArg)
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { applyAutofixViolations, normalizeAgentToken, pruneSatisfiedOneTimeRemediations, runLocalRemediationComplianceCheck, } from './log_config_files/runtime/compliance_check.js';
|
|
10
10
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
11
|
-
import { getRemediationInstructionsPath } from './log_config_files/runtime/management_storage.js';
|
|
11
|
+
import { getRemediationInstructionsPath, readRemediationInstructionsFile } from './log_config_files/runtime/management_storage.js';
|
|
12
12
|
import { hookLogSessionBanner, hookRunLog, logRemediationApplyFailure } from './log_config_files/runtime/hook_logger.js';
|
|
13
13
|
import { isThisCliModule } from './cli_invocation_match.js';
|
|
14
14
|
import { ensureAuthentication } from './log_config_files/auth/auth_flow.js';
|
|
15
15
|
import { sendConfigFile } from './log_config_files/sender/batch_sender.js';
|
|
16
16
|
import { tryResolveHardwareUuid } from './log_config_files/runtime/hardware_uuid.js';
|
|
17
|
+
import { syncRemediations } from './log_config_files/runtime/remediation_sync.js';
|
|
18
|
+
import { loadEndpointBase } from './log_config_files/sender/endpoint_config.js';
|
|
17
19
|
const MANIFEST_STALE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18
20
|
function parseIde() {
|
|
19
21
|
const eq = process.argv.find((a) => a.startsWith('--ide='));
|
|
@@ -135,6 +137,24 @@ export async function runCompliancePromptGate() {
|
|
|
135
137
|
const ide = parseIde();
|
|
136
138
|
const agent = parseAgent(ide);
|
|
137
139
|
hookLogSessionBanner('compliance_prompt_gate (before submit)');
|
|
140
|
+
// Sync before checking so server-side changes (enforce/unenforce) propagate on every prompt
|
|
141
|
+
// without waiting for the background runner. Race against a 3 s timeout so a slow or
|
|
142
|
+
// unavailable server never delays the gate significantly.
|
|
143
|
+
const hw = tryResolveHardwareUuid();
|
|
144
|
+
if (hw) {
|
|
145
|
+
const { remediations } = readRemediationInstructionsFile();
|
|
146
|
+
if (Array.isArray(remediations) && remediations.length > 0) {
|
|
147
|
+
try {
|
|
148
|
+
await Promise.race([
|
|
149
|
+
syncRemediations(loadEndpointBase(), hw),
|
|
150
|
+
new Promise((resolve) => setTimeout(resolve, 3000)),
|
|
151
|
+
]);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Network or auth failure — fall back to local file state.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
138
158
|
const status = runLocalRemediationComplianceCheck(agent);
|
|
139
159
|
// Secondary-satisfied: primary checks failed but settings.json (or equiv) has the fix.
|
|
140
160
|
// Upload those files fire-and-forget so the backend can resolve the finding immediately.
|
|
@@ -20,7 +20,7 @@ import { complianceRunnerDiag, hookRunLog, logRemediationApplyFailure } from './
|
|
|
20
20
|
import { loadEndpointBase } from '../sender/endpoint_config.js';
|
|
21
21
|
import { resolveHardwareUuid, tryResolveHardwareUuid } from './hardware_uuid.js';
|
|
22
22
|
import { buildDeferredCursorRestartCommand, discoverAllWorkspaceVscdbs, enforceRemediation, fetchSync, isTrustedRestartCommandForAutofix, remediationFixSpec, reportAutofixApplied, syncRemediations, } from './remediation_sync.js';
|
|
23
|
-
import { sendConfigFile } from '../sender/batch_sender.js';
|
|
23
|
+
import { sendConfigFile, resolveRepoFromPath } from '../sender/batch_sender.js';
|
|
24
24
|
import { ensureAuthentication } from '../auth/auth_flow.js';
|
|
25
25
|
/** Normalize manifest/env/CLI agent tokens to a known Agent, or '' if unrecognized. */
|
|
26
26
|
export function normalizeAgentToken(raw) {
|
|
@@ -525,10 +525,11 @@ export function applyAutofixViolations(violations, agent = 'cursor') {
|
|
|
525
525
|
if (fileType) {
|
|
526
526
|
const hw = tryResolveHardwareUuid();
|
|
527
527
|
if (hw) {
|
|
528
|
+
const repoIdentifier = resolveRepoFromPath(configPathForDisk);
|
|
528
529
|
// Do not rely on the bulk uploader (start-every-prompt throttles at 1800s).
|
|
529
530
|
// Always attempt to upload the single remediated file immediately.
|
|
530
531
|
reportPromises.push(ensureAuthentication(hw)
|
|
531
|
-
.then((authKey) => sendConfigFile({ file_type: fileType, file_path: configPathForDisk, raw_content: updatedContent }, hw, authKey))
|
|
532
|
+
.then((authKey) => sendConfigFile({ file_type: fileType, file_path: configPathForDisk, raw_content: updatedContent }, hw, authKey, repoIdentifier))
|
|
532
533
|
.then((sentOk) => {
|
|
533
534
|
hookRunLog(`autofix: uploaded remediated file uuid=${inst.uuid} path=${configPathForDisk} ok=${sentOk}`);
|
|
534
535
|
})
|
|
@@ -84,7 +84,7 @@ async function addSensitivePathsAudit(endpointBase, configFiles) {
|
|
|
84
84
|
async function sendAllConfigFiles(configFiles, hardwareUuid, authKey) {
|
|
85
85
|
const hookTypeRaw = (process.env.OPTIMUS_HOOK_TYPE || 'claude').toLowerCase();
|
|
86
86
|
const hookType = hookTypeRaw === 'cursor' ? 'cursor' : 'claude';
|
|
87
|
-
const workspaceRepo = process.env.OPTIMUS_WORKSPACE_REPO ||
|
|
87
|
+
const workspaceRepo = process.env.OPTIMUS_WORKSPACE_REPO || '';
|
|
88
88
|
const manifest = configFiles.map((c) => canonicalCursorUserStateVscdbPath(c.file_path));
|
|
89
89
|
const hookRequestId = await sendHookRequestCreate(hardwareUuid, authKey, hookType, workspaceRepo);
|
|
90
90
|
hookRunLog(`hook-request id=${hookRequestId ?? 'none'}`);
|
|
@@ -118,7 +118,7 @@ async function main() {
|
|
|
118
118
|
const endpointBase = loadEndpointBase();
|
|
119
119
|
hookRunLog(`start endpoint=${endpointBase} hardware_uuid=${hardwareUuid}`);
|
|
120
120
|
hookRunLog(`endpoint_source=${getEndpointSource()} cwd=${process.cwd()}`);
|
|
121
|
-
hookRunLog(`env: OPTIMUS_HOOK_TYPE=${process.env.OPTIMUS_HOOK_TYPE ? 'set' : 'unset'}
|
|
121
|
+
hookRunLog(`env: OPTIMUS_HOOK_TYPE=${process.env.OPTIMUS_HOOK_TYPE ? 'set' : 'unset'} OPTIMUS_WORKSPACE_REPO=${process.env.OPTIMUS_WORKSPACE_REPO ? 'set' : 'unset'} OPTIMUS_ENDPOINT=${process.env.OPTIMUS_ENDPOINT ? 'set' : 'unset'}`);
|
|
122
122
|
let authKey;
|
|
123
123
|
try {
|
|
124
124
|
authKey = await ensureAuthentication(hardwareUuid);
|
|
@@ -6,9 +6,24 @@ import { canonicalCursorUserStateVscdbPath } from '../runtime/remediation_config
|
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
+
import { execFileSync } from 'node:child_process';
|
|
9
10
|
/** Chunk size per batch request. */
|
|
10
11
|
export const BATCH_CHUNK_SIZE = 20;
|
|
11
12
|
const MAX_BATCH_SIZE_BYTES = 500 * 1024; // 500KB
|
|
13
|
+
function resolveWorkspaceRepo() {
|
|
14
|
+
return process.env.OPTIMUS_WORKSPACE_REPO || '';
|
|
15
|
+
}
|
|
16
|
+
export function resolveRepoFromPath(filePath) {
|
|
17
|
+
try {
|
|
18
|
+
const dir = path.dirname(filePath);
|
|
19
|
+
return execFileSync('git', ['remote', '-v'], { cwd: dir, timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] })
|
|
20
|
+
.toString()
|
|
21
|
+
.trim();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return resolveWorkspaceRepo();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
12
27
|
function resolveApiBase(endpoint) {
|
|
13
28
|
try {
|
|
14
29
|
return new URL(endpoint).origin;
|
|
@@ -86,7 +101,7 @@ function splitChunk(chunks, chunkIndex) {
|
|
|
86
101
|
async function sendConfigFilesBatch(configFiles, hardwareUuid, authKey, hookRequestId, ingestSessionId) {
|
|
87
102
|
const endpoint = loadEndpointBase();
|
|
88
103
|
const apiUrl = `${resolveApiBase(endpoint)}/endpoint_security/log-config-files/`;
|
|
89
|
-
const metadata = { org_identifier: process.env.GITHUB_ORG || process.env.GH_ORG || '', organization_uuid: readOrganizationUuid(), repo_identifier:
|
|
104
|
+
const metadata = { org_identifier: process.env.GITHUB_ORG || process.env.GH_ORG || '', organization_uuid: readOrganizationUuid(), repo_identifier: resolveWorkspaceRepo() };
|
|
90
105
|
const basePayloadSize = JSON.stringify({ hardware_uuid: hardwareUuid, metadata }).length + 800;
|
|
91
106
|
const chunks = buildBatchChunks(configFiles, basePayloadSize);
|
|
92
107
|
const totals = { accepted: 0, failed: 0 };
|
|
@@ -169,13 +184,13 @@ async function sendIngestSessionFinish(hardwareUuid, authKey, ingestSessionId) {
|
|
|
169
184
|
return false;
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
|
-
async function sendConfigFile(configFile, hardwareUuid, authKey) {
|
|
187
|
+
async function sendConfigFile(configFile, hardwareUuid, authKey, repoIdentifier) {
|
|
173
188
|
const endpoint = loadEndpointBase();
|
|
174
189
|
const apiUrl = `${resolveApiBase(endpoint)}/endpoint_security/log-config-file/`;
|
|
175
190
|
const uploadPath = canonicalCursorUserStateVscdbPath(configFile.file_path);
|
|
176
191
|
const payload = { hardware_uuid: hardwareUuid, file_type: configFile.file_type, file_path: uploadPath, raw_content: configFile.raw_content };
|
|
177
192
|
const signature = createSignature(payload, authKey.key);
|
|
178
|
-
const body = { ...payload, signature, key_id: authKey.key_id || '', metadata: { org_identifier: process.env.GITHUB_ORG || process.env.GH_ORG || '', organization_uuid: readOrganizationUuid(), repo_identifier:
|
|
193
|
+
const body = { ...payload, signature, key_id: authKey.key_id || '', metadata: { org_identifier: process.env.GITHUB_ORG || process.env.GH_ORG || '', organization_uuid: readOrganizationUuid(), repo_identifier: repoIdentifier ?? resolveWorkspaceRepo() } };
|
|
179
194
|
try {
|
|
180
195
|
const response = await postStartupPayload(apiUrl, body);
|
|
181
196
|
if (response.status !== 'accepted') {
|
|
@@ -51,7 +51,7 @@ const getMetadata = () => ({
|
|
|
51
51
|
github_username: process.env.GITHUB_USER || process.env.GH_USER || '',
|
|
52
52
|
org_identifier: process.env.GITHUB_ORG || '',
|
|
53
53
|
organization_uuid: readOrganizationUuid(),
|
|
54
|
-
repo_identifier: process.env.
|
|
54
|
+
repo_identifier: process.env.OPTIMUS_WORKSPACE_REPO || '',
|
|
55
55
|
branch: process.env.GITHUB_REF_NAME || process.env.BRANCH_NAME || '',
|
|
56
56
|
commit_sha: process.env.GITHUB_SHA || '',
|
|
57
57
|
agent_name: process.env.OPTIMUS_AGENT || '',
|
package/dist/tofu.js
CHANGED
|
@@ -10,39 +10,12 @@
|
|
|
10
10
|
* All other source files import from this module, never directly from
|
|
11
11
|
* "optimus-tofu-staging", so the conditional lives in exactly one place.
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, readFileSync } from "fs";
|
|
14
|
-
import { homedir } from "os";
|
|
15
13
|
import path from "path";
|
|
16
14
|
import { fileURLToPath } from "url";
|
|
17
|
-
|
|
18
|
-
const home = homedir();
|
|
19
|
-
if (!home)
|
|
20
|
-
return null;
|
|
21
|
-
return path.join(home, "opt-ai-sec", "management", "optimus_dev.env");
|
|
22
|
-
}
|
|
23
|
-
function readEnvironment() {
|
|
24
|
-
const envPath = managementEnvPath();
|
|
25
|
-
if (!envPath) {
|
|
26
|
-
return "staging";
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const content = readFileSync(envPath, "utf8");
|
|
30
|
-
const match = content.match(/^(?:environment|ENVIRONMENT|OPTIMUS_ENVIRONMENT)\s*=\s*(.+)/m);
|
|
31
|
-
if (match)
|
|
32
|
-
return match[1].trim().toLowerCase();
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
// No management file: this staging package defaults to staging (promotion rewrites to production).
|
|
36
|
-
return "staging";
|
|
37
|
-
}
|
|
38
|
-
const fromEnv = process.env.OPTIMUS_ENVIRONMENT?.trim().toLowerCase();
|
|
39
|
-
if (fromEnv)
|
|
40
|
-
return fromEnv;
|
|
41
|
-
return "staging";
|
|
42
|
-
}
|
|
15
|
+
import { shouldUseLocalTofuDist } from "./tofu_environment.js";
|
|
43
16
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
44
17
|
const localTofuPath = path.join(__dirname, "../../optimus-tofu/dist/index.js");
|
|
45
|
-
const useLocalTofu =
|
|
18
|
+
const useLocalTofu = shouldUseLocalTofuDist(localTofuPath);
|
|
46
19
|
const tofu = (useLocalTofu
|
|
47
20
|
? await import(localTofuPath)
|
|
48
21
|
: await import("optimus-tofu-staging"));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export function managementEnvPath() {
|
|
5
|
+
const home = homedir();
|
|
6
|
+
if (!home)
|
|
7
|
+
return null;
|
|
8
|
+
return path.join(home, 'opt-ai-sec', 'management', 'optimus_dev.env');
|
|
9
|
+
}
|
|
10
|
+
/** Resolve optimus environment label (file wins over shell OPTIMUS_ENVIRONMENT). */
|
|
11
|
+
export function readEnvironment() {
|
|
12
|
+
const envPath = managementEnvPath();
|
|
13
|
+
if (!envPath) {
|
|
14
|
+
return 'staging';
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const content = readFileSync(envPath, 'utf8');
|
|
18
|
+
const match = content.match(/^(?:environment|ENVIRONMENT|OPTIMUS_ENVIRONMENT)\s*=\s*(.+)/m);
|
|
19
|
+
if (match)
|
|
20
|
+
return match[1].trim().toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return 'staging';
|
|
24
|
+
}
|
|
25
|
+
const fromEnv = process.env.OPTIMUS_ENVIRONMENT?.trim().toLowerCase();
|
|
26
|
+
if (fromEnv)
|
|
27
|
+
return fromEnv;
|
|
28
|
+
return 'staging';
|
|
29
|
+
}
|
|
30
|
+
export function shouldUseLocalTofuDist(localTofuPath) {
|
|
31
|
+
return readEnvironment() === 'development' && existsSync(localTofuPath);
|
|
32
|
+
}
|