@optimuslabs/harness-map-staging 1.5.16
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/README.md +46 -0
- package/dist/apply_deferred_vscdb.js +38 -0
- package/dist/bootstrap_constants.js +15 -0
- package/dist/cli/bash_script_generator.js +95 -0
- package/dist/cli.js +144 -0
- package/dist/cli_invocation_match.js +30 -0
- package/dist/compliance_check_runner.js +57 -0
- package/dist/compliance_prompt_gate.js +396 -0
- package/dist/dialog_prefs_cli.js +109 -0
- package/dist/endpoint_client/compress_payload.js +25 -0
- package/dist/endpoint_client/http_transport.js +90 -0
- package/dist/endpoint_client/index.js +3 -0
- package/dist/endpoint_client/registry_api.js +41 -0
- package/dist/endpoint_client/startup_api.js +44 -0
- package/dist/endpoint_client/types.js +4 -0
- package/dist/execute_trusted_restarts.js +60 -0
- package/dist/log_config_files/auth/auth_flow.js +22 -0
- package/dist/log_config_files/auth/auth_key_store.js +14 -0
- package/dist/log_config_files/collection/claude_desktop_extensions_collector.js +248 -0
- package/dist/log_config_files/collection/claude_known_projects_collector.js +42 -0
- package/dist/log_config_files/collection/claude_token_usage_collector.js +203 -0
- package/dist/log_config_files/collection/codex_token_usage_collector.js +342 -0
- package/dist/log_config_files/collection/config_collector.js +245 -0
- package/dist/log_config_files/collection/copilot_token_usage_collector.js +167 -0
- package/dist/log_config_files/collection/cowork_desktop_version_collector.js +60 -0
- package/dist/log_config_files/collection/cowork_session_whitelist.js +89 -0
- package/dist/log_config_files/collection/cursor_project_mcp_collector.js +230 -0
- package/dist/log_config_files/collection/cursor_project_workspace_activity.js +73 -0
- package/dist/log_config_files/collection/cursor_token_usage_collector.js +192 -0
- package/dist/log_config_files/collection/directory_collector.js +126 -0
- package/dist/log_config_files/collection/enrichment_helpers.js +53 -0
- package/dist/log_config_files/collection/ensure_cursor_user_settings_snapshot.js +50 -0
- package/dist/log_config_files/collection/file_type_rules.js +47 -0
- package/dist/log_config_files/collection/grok_cli_version_collector.js +53 -0
- package/dist/log_config_files/collection/hermes_token_usage_collector.js +241 -0
- package/dist/log_config_files/collection/mcp_tool_collector.js +106 -0
- package/dist/log_config_files/collection/metadata_merge.js +43 -0
- package/dist/log_config_files/collection/openclaw_helpers.js +55 -0
- package/dist/log_config_files/collection/openclaw_token_usage_collector.js +223 -0
- package/dist/log_config_files/collection/opencode_token_usage_collector.js +177 -0
- package/dist/log_config_files/collection/pi_token_usage_collector.js +239 -0
- package/dist/log_config_files/collection/plugin_collector.js +223 -0
- package/dist/log_config_files/collection/plugin_version_helpers.js +37 -0
- package/dist/log_config_files/collection/skills_cli_collector.js +162 -0
- package/dist/log_config_files/index.js +19 -0
- package/dist/log_config_files/paths/path_constants_helpers.js +71 -0
- package/dist/log_config_files/paths/pattern_resolver.js +326 -0
- package/dist/log_config_files/readers/composer_shadow_merge.js +67 -0
- package/dist/log_config_files/readers/cursor_shadow_merge_ruleset.js +46 -0
- package/dist/log_config_files/readers/file_readers.js +196 -0
- package/dist/log_config_files/readers/vscdb_config_builder.js +148 -0
- package/dist/log_config_files/readers/vscdb_reactive_storage.js +62 -0
- package/dist/log_config_files/readers/vscdb_reader.js +337 -0
- package/dist/log_config_files/runtime/client_event_reporter.js +347 -0
- package/dist/log_config_files/runtime/compliance_check.js +1013 -0
- package/dist/log_config_files/runtime/compliance_session_log.js +378 -0
- package/dist/log_config_files/runtime/dialog_preferences.js +31 -0
- package/dist/log_config_files/runtime/hardware_uuid.js +36 -0
- package/dist/log_config_files/runtime/hook_logger.js +267 -0
- package/dist/log_config_files/runtime/hook_type_for_request.js +30 -0
- package/dist/log_config_files/runtime/log_metadata.js +122 -0
- package/dist/log_config_files/runtime/main_runner.js +376 -0
- package/dist/log_config_files/runtime/management_storage.js +144 -0
- package/dist/log_config_files/runtime/ops_target_path.js +18 -0
- package/dist/log_config_files/runtime/remediation_apply_tracking.js +152 -0
- package/dist/log_config_files/runtime/remediation_config_path.js +140 -0
- package/dist/log_config_files/runtime/remediation_sync.js +1705 -0
- package/dist/log_config_files/runtime/secret_regex_scan.js +126 -0
- package/dist/log_config_files/runtime/sqlite_binary.js +124 -0
- package/dist/log_config_files/runtime/trusted_restarts.js +113 -0
- package/dist/log_config_files/runtime/workspace_repo.js +170 -0
- package/dist/log_config_files/runtime/worktree_absent.js +50 -0
- package/dist/log_config_files/runtime/worktree_scanner.js +137 -0
- package/dist/log_config_files/sender/batch_sender.js +283 -0
- package/dist/log_config_files/sender/endpoint_config.js +24 -0
- package/dist/log_config_files/sender/signing.js +1 -0
- package/dist/log_sensitive_paths_audit.js +89 -0
- package/dist/log_uuid/auth_key_store.js +37 -0
- package/dist/log_uuid/hardware_uuid.js +35 -0
- package/dist/log_uuid/index.js +11 -0
- package/dist/log_uuid/log_uuid_helper.js +30 -0
- package/dist/log_uuid/startup_sender.js +131 -0
- package/dist/log_uuid/user_profile.js +192 -0
- package/dist/remediation_change_preview.js +182 -0
- package/dist/tofu.js +22 -0
- package/dist/tofu_environment.js +36 -0
- package/dist/types/config_file_types.js +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createSignature as createSharedSignature } from '../tofu.js';
|
|
2
|
+
import { classifyEndpointResponse, postStartupPayload } from '../endpoint_client/index.js';
|
|
3
|
+
import { flushBufferedClientEvents, getStoryId, reportFunctionalFailureAwait, reportFunctionalRun, } from '../log_config_files/runtime/client_event_reporter.js';
|
|
4
|
+
import { resolveHardwareUuid } from './hardware_uuid.js';
|
|
5
|
+
import { writeAuthKey, readStoredAuthKey, loadEndpointBase, buildStartupEndpointUrl } from './auth_key_store.js';
|
|
6
|
+
import { resolveUserProfile } from './user_profile.js';
|
|
7
|
+
import { resolveWorkspaceRepo } from '../log_config_files/runtime/workspace_repo.js';
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
const canonicalizeValue = (value) => {
|
|
12
|
+
if (Array.isArray(value))
|
|
13
|
+
return value.map(canonicalizeValue);
|
|
14
|
+
if (value && typeof value === 'object') {
|
|
15
|
+
const result = {};
|
|
16
|
+
for (const key of Object.keys(value).sort())
|
|
17
|
+
result[key] = canonicalizeValue(value[key]);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
};
|
|
22
|
+
const canonicalStringify = (value) => JSON.stringify(canonicalizeValue(value));
|
|
23
|
+
const createSignature = (payloadSummary, keyHex) => {
|
|
24
|
+
// Keep this adapter for backward compatibility of public exports in log_uuid.
|
|
25
|
+
return createSharedSignature(payloadSummary, keyHex);
|
|
26
|
+
};
|
|
27
|
+
const readOrganizationUuid = () => {
|
|
28
|
+
const envValue = (process.env.OPTIMUS_ORGANIZATION_UUID || '').trim();
|
|
29
|
+
if (envValue)
|
|
30
|
+
return envValue;
|
|
31
|
+
try {
|
|
32
|
+
return fs.readFileSync(path.join(os.homedir(), '.optimuslabs', 'management', 'org', 'organization-uuid.txt'), 'utf8').trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const parseHookManifest = () => {
|
|
39
|
+
const raw = (process.env.OPTIMUS_HOOK_MANIFEST || '').trim();
|
|
40
|
+
if (!raw)
|
|
41
|
+
return {};
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(raw);
|
|
44
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// malformed — skip
|
|
49
|
+
}
|
|
50
|
+
return {};
|
|
51
|
+
};
|
|
52
|
+
const getMetadata = () => ({
|
|
53
|
+
github_username: process.env.GITHUB_USER || process.env.GH_USER || '',
|
|
54
|
+
org_identifier: process.env.GITHUB_ORG || '',
|
|
55
|
+
organization_uuid: readOrganizationUuid(),
|
|
56
|
+
repo_identifier: resolveWorkspaceRepo(),
|
|
57
|
+
branch: process.env.GITHUB_REF_NAME || process.env.BRANCH_NAME || '',
|
|
58
|
+
commit_sha: process.env.GITHUB_SHA || '',
|
|
59
|
+
agent_name: process.env.OPTIMUS_AGENT || '',
|
|
60
|
+
user_profile: { ...resolveUserProfile() },
|
|
61
|
+
hook_manifest: parseHookManifest(),
|
|
62
|
+
});
|
|
63
|
+
function buildRequestBody(hardwareUuid, timestamp) {
|
|
64
|
+
const payloadSummary = { timestamp, directory: process.cwd(), hardware_uuid: hardwareUuid };
|
|
65
|
+
const requestBody = { hardware_uuid: hardwareUuid, payload: payloadSummary, metadata: getMetadata(), scan_timestamp: timestamp };
|
|
66
|
+
const storedKey = readStoredAuthKey();
|
|
67
|
+
if (storedKey?.key && storedKey.hardware_uuid === hardwareUuid) {
|
|
68
|
+
requestBody.signature = createSignature(payloadSummary, storedKey.key);
|
|
69
|
+
if (storedKey.key_id)
|
|
70
|
+
requestBody.key_id = storedKey.key_id;
|
|
71
|
+
console.log('Using stored auth key to sign startup payload.');
|
|
72
|
+
}
|
|
73
|
+
else if (storedKey && storedKey.hardware_uuid !== hardwareUuid) {
|
|
74
|
+
console.warn('Stored auth key hardware UUID mismatch; requesting new key from server.');
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.log('No stored auth key found; requesting new key from server.');
|
|
78
|
+
}
|
|
79
|
+
return requestBody;
|
|
80
|
+
}
|
|
81
|
+
const maybeSendToEndpoint = async (hardwareUuid, timestamp, options = {}) => {
|
|
82
|
+
const startupEndpointUrl = buildStartupEndpointUrl(loadEndpointBase());
|
|
83
|
+
const requestBody = buildRequestBody(hardwareUuid, timestamp);
|
|
84
|
+
try {
|
|
85
|
+
const response = await postStartupPayload(startupEndpointUrl, requestBody);
|
|
86
|
+
const result = classifyEndpointResponse(response);
|
|
87
|
+
console.log(result.message);
|
|
88
|
+
if (result.branch === 'key_issued' && result.key) {
|
|
89
|
+
writeAuthKey(result.key, result.keyId, hardwareUuid);
|
|
90
|
+
const manifest = parseHookManifest();
|
|
91
|
+
if (options.allowKeyIssuedRetry !== false &&
|
|
92
|
+
Object.keys(manifest).length > 0) {
|
|
93
|
+
return maybeSendToEndpoint(hardwareUuid, new Date().toISOString(), {
|
|
94
|
+
allowKeyIssuedRetry: false,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result.branch !== 'error';
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error(`Failed to contact endpoint: ${error.message}`);
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const main = async () => {
|
|
106
|
+
getStoryId();
|
|
107
|
+
void flushBufferedClientEvents();
|
|
108
|
+
const timestamp = new Date().toISOString();
|
|
109
|
+
try {
|
|
110
|
+
const hardwareUuid = resolveHardwareUuid();
|
|
111
|
+
const ok = await maybeSendToEndpoint(hardwareUuid, timestamp);
|
|
112
|
+
if (ok) {
|
|
113
|
+
await reportFunctionalRun({
|
|
114
|
+
unit: 'auth_version',
|
|
115
|
+
command: 'log_uuid',
|
|
116
|
+
outcome: 'ok',
|
|
117
|
+
hook_name: 'start_every_prompt',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
await reportFunctionalFailureAwait('auth_version', 'log_uuid', new Error('startup payload request failed'));
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
await reportFunctionalFailureAwait('auth_version', 'log_uuid', error instanceof Error ? error : new Error(String(error)));
|
|
127
|
+
console.error(`Unable to log hardware UUID: ${error.message}`);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
export { canonicalizeValue, canonicalStringify, createSignature, getMetadata, maybeSendToEndpoint, main };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { readCommandOutput, resolveHardwareUuid } from './hardware_uuid.js';
|
|
7
|
+
const safeJsonParse = (raw) => {
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(raw);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const readCursorCachedEmailFromVscdb = () => {
|
|
16
|
+
const dbPath = path.join(os.homedir(), 'Library/Application Support/Cursor/User/globalStorage/state.vscdb');
|
|
17
|
+
if (!fs.existsSync(dbPath))
|
|
18
|
+
return '';
|
|
19
|
+
try {
|
|
20
|
+
const out = execFileSync('sqlite3', [dbPath, "select value from ItemTable where key='cursorAuth/cachedEmail';"], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/** Fallback: `storage.json` key path `cursor.auth.email` (design_notes). */
|
|
28
|
+
const readCursorCachedEmailFromStorageJson = () => {
|
|
29
|
+
const fp = path.join(os.homedir(), 'Library/Application Support/Cursor/User/globalStorage/storage.json');
|
|
30
|
+
if (!fs.existsSync(fp))
|
|
31
|
+
return '';
|
|
32
|
+
try {
|
|
33
|
+
const parsed = safeJsonParse(fs.readFileSync(fp, { encoding: 'utf8' }));
|
|
34
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
35
|
+
return '';
|
|
36
|
+
const root = parsed;
|
|
37
|
+
const cursor = root.cursor;
|
|
38
|
+
if (!cursor || typeof cursor !== 'object' || Array.isArray(cursor))
|
|
39
|
+
return '';
|
|
40
|
+
const auth = cursor.auth;
|
|
41
|
+
if (!auth || typeof auth !== 'object' || Array.isArray(auth))
|
|
42
|
+
return '';
|
|
43
|
+
const email = auth.email;
|
|
44
|
+
return typeof email === 'string' ? email.trim() : '';
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const readCursorCachedEmail = () => readCursorCachedEmailFromVscdb() || readCursorCachedEmailFromStorageJson();
|
|
51
|
+
const readClaudeAuthEmailFromCli = () => {
|
|
52
|
+
try {
|
|
53
|
+
const out = execFileSync('claude', ['auth', 'status'], {
|
|
54
|
+
encoding: 'utf8',
|
|
55
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
56
|
+
}).trim();
|
|
57
|
+
if (!out)
|
|
58
|
+
return '';
|
|
59
|
+
const parsed = safeJsonParse(out);
|
|
60
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
61
|
+
const email = parsed.email;
|
|
62
|
+
return typeof email === 'string' ? email.trim() : '';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
return '';
|
|
69
|
+
};
|
|
70
|
+
/** Fallback: optional Claude config files under ~/.claude/ (design_notes). */
|
|
71
|
+
const readClaudeEmailFromHomeFiles = () => {
|
|
72
|
+
const candidates = [
|
|
73
|
+
path.join(os.homedir(), '.claude/.credentials.json'),
|
|
74
|
+
path.join(os.homedir(), '.claude/.claude.json'),
|
|
75
|
+
];
|
|
76
|
+
for (const fp of candidates) {
|
|
77
|
+
if (!fs.existsSync(fp))
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
const parsed = safeJsonParse(fs.readFileSync(fp, { encoding: 'utf8' }));
|
|
81
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
82
|
+
continue;
|
|
83
|
+
const email = parsed.email;
|
|
84
|
+
if (typeof email === 'string' && email.includes('@'))
|
|
85
|
+
return email.trim();
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* try next */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return '';
|
|
92
|
+
};
|
|
93
|
+
const readClaudeAuthEmail = () => readClaudeAuthEmailFromCli().trim() || readClaudeEmailFromHomeFiles();
|
|
94
|
+
const readMachineName = () => {
|
|
95
|
+
const fromEnv = process.env.OPTIMUS_MACHINE_NAME?.trim();
|
|
96
|
+
if (fromEnv)
|
|
97
|
+
return fromEnv;
|
|
98
|
+
// macOS: human-readable computer name set in System Settings
|
|
99
|
+
if (process.platform === 'darwin') {
|
|
100
|
+
const name = readCommandOutput('scutil --get ComputerName');
|
|
101
|
+
if (name)
|
|
102
|
+
return name;
|
|
103
|
+
}
|
|
104
|
+
// Fallback: OS hostname
|
|
105
|
+
return os.hostname();
|
|
106
|
+
};
|
|
107
|
+
const readMacUsername = () => {
|
|
108
|
+
const fromEnv = process.env.OPTIMUS_MAC_USERNAME?.trim() ||
|
|
109
|
+
process.env.USER?.trim() ||
|
|
110
|
+
process.env.LOGNAME?.trim() ||
|
|
111
|
+
'';
|
|
112
|
+
if (fromEnv)
|
|
113
|
+
return fromEnv;
|
|
114
|
+
return readCommandOutput('id -un');
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Matches design_notes order: `gh api user` (login), then CI-style env, then `git config user.name`.
|
|
118
|
+
* `metadata.github_username` in startup_sender still uses env only; this field is the richer probe.
|
|
119
|
+
*/
|
|
120
|
+
const readGithubUsername = () => {
|
|
121
|
+
try {
|
|
122
|
+
const out = execFileSync('gh', ['api', 'user', '--jq', '.login'], {
|
|
123
|
+
encoding: 'utf8',
|
|
124
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
125
|
+
maxBuffer: 1024 * 1024,
|
|
126
|
+
// CI often has `gh` installed; without a cap it can block on auth/network and hang callers.
|
|
127
|
+
timeout: 3500,
|
|
128
|
+
}).trim();
|
|
129
|
+
if (out)
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* gh missing or not authenticated */
|
|
134
|
+
}
|
|
135
|
+
return (process.env.GITHUB_USER?.trim() ||
|
|
136
|
+
process.env.GH_USER?.trim() ||
|
|
137
|
+
readCommandOutput('git config user.name'));
|
|
138
|
+
};
|
|
139
|
+
const readUserProfileFromEnvOrFile = () => {
|
|
140
|
+
const inline = process.env.OPTIMUS_USER_PROFILE_JSON?.trim();
|
|
141
|
+
if (inline) {
|
|
142
|
+
const parsed = safeJsonParse(inline);
|
|
143
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
const filePath = process.env.OPTIMUS_USER_PROFILE_FILE?.trim();
|
|
147
|
+
if (filePath && fs.existsSync(filePath)) {
|
|
148
|
+
const parsed = safeJsonParse(fs.readFileSync(filePath, { encoding: 'utf8' }));
|
|
149
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
};
|
|
154
|
+
const isPlausibleUuid = (s) => /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/i.test(s.trim());
|
|
155
|
+
/**
|
|
156
|
+
* macOS Open Directory **GeneratedUID** for the console user (same concept as Directory Utility).
|
|
157
|
+
* See `dscl . -read /Users/<shortname> GeneratedUID`. Not the hardware UUID (that is `machineuuid`).
|
|
158
|
+
*
|
|
159
|
+
* `OPTIMUS_MAC_GENERATED_UID` overrides for tests or locked-down environments where `dscl` is unavailable.
|
|
160
|
+
*/
|
|
161
|
+
const readMacAccountGeneratedUid = () => {
|
|
162
|
+
const env = process.env.OPTIMUS_MAC_GENERATED_UID?.trim();
|
|
163
|
+
if (env && isPlausibleUuid(env))
|
|
164
|
+
return env.trim().toLowerCase();
|
|
165
|
+
if (process.platform !== 'darwin')
|
|
166
|
+
return '';
|
|
167
|
+
const user = readMacUsername();
|
|
168
|
+
if (!user || !/^[a-zA-Z0-9._-]+$/.test(user))
|
|
169
|
+
return '';
|
|
170
|
+
try {
|
|
171
|
+
const out = execFileSync('dscl', ['.', '-read', `/Users/${user}`, 'GeneratedUID'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
172
|
+
const m = out.match(/GeneratedUID:\s*([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})/);
|
|
173
|
+
if (m?.[1] && isPlausibleUuid(m[1]))
|
|
174
|
+
return m[1].toLowerCase();
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
return '';
|
|
180
|
+
};
|
|
181
|
+
const buildDefaultUserProfile = () => ({
|
|
182
|
+
generateduuid: readMacAccountGeneratedUid() || crypto.randomUUID(),
|
|
183
|
+
machineuuid: resolveHardwareUuid(),
|
|
184
|
+
mac_username: readMacUsername(),
|
|
185
|
+
machine_name: readMachineName(),
|
|
186
|
+
github_username: readGithubUsername(),
|
|
187
|
+
claude_email: readClaudeAuthEmail(),
|
|
188
|
+
cursor_email: readCursorCachedEmail(),
|
|
189
|
+
});
|
|
190
|
+
/** Best-effort local user profile object for startup metadata. */
|
|
191
|
+
const resolveUserProfile = () => readUserProfileFromEnvOrFile() ?? buildDefaultUserProfile();
|
|
192
|
+
export { resolveUserProfile };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { readRemediationInstructionsFile } from './log_config_files/runtime/management_storage.js';
|
|
2
|
+
import { remediationFixSpec } from './log_config_files/runtime/remediation_sync.js';
|
|
3
|
+
export const MAX_PREVIEW_LINES = 5;
|
|
4
|
+
export const MAX_PREVIEW_LINE_CHARS = 72;
|
|
5
|
+
function truncateLine(text, max = MAX_PREVIEW_LINE_CHARS) {
|
|
6
|
+
const trimmed = text.trim();
|
|
7
|
+
if (trimmed.length <= max)
|
|
8
|
+
return trimmed;
|
|
9
|
+
return `${trimmed.slice(0, max - 1)}…`;
|
|
10
|
+
}
|
|
11
|
+
function formatScalar(value) {
|
|
12
|
+
if (value === null)
|
|
13
|
+
return 'null';
|
|
14
|
+
if (value === undefined)
|
|
15
|
+
return 'undefined';
|
|
16
|
+
if (typeof value === 'string')
|
|
17
|
+
return `"${value}"`;
|
|
18
|
+
if (typeof value === 'boolean' || typeof value === 'number')
|
|
19
|
+
return String(value);
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
if (value.length === 0)
|
|
22
|
+
return '[]';
|
|
23
|
+
const parts = value.slice(0, 2).map((entry) => formatScalar(entry));
|
|
24
|
+
if (value.length > 2)
|
|
25
|
+
return `${parts.join(', ')} …+${value.length - 2}`;
|
|
26
|
+
return parts.join(', ');
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === 'object') {
|
|
29
|
+
const record = value;
|
|
30
|
+
if (typeof record.serverName === 'string')
|
|
31
|
+
return `"${record.serverName}"`;
|
|
32
|
+
const keys = Object.keys(record);
|
|
33
|
+
if (keys.length === 1 && keys[0])
|
|
34
|
+
return formatScalar(record[keys[0]]);
|
|
35
|
+
if (keys.length <= 3)
|
|
36
|
+
return `{${keys.join(', ')}}`;
|
|
37
|
+
return `{${keys.slice(0, 2).join(', ')}, …}`;
|
|
38
|
+
}
|
|
39
|
+
return String(value);
|
|
40
|
+
}
|
|
41
|
+
function formatListDeltaItems(items) {
|
|
42
|
+
if (items.length === 0)
|
|
43
|
+
return '—';
|
|
44
|
+
const shown = items.slice(0, 2).map((entry) => formatScalar(entry));
|
|
45
|
+
if (items.length > 2)
|
|
46
|
+
return `${shown.join(', ')} …+${items.length - 2}`;
|
|
47
|
+
return shown.join(', ');
|
|
48
|
+
}
|
|
49
|
+
function leafFromSettingPath(settingPath, opKey) {
|
|
50
|
+
const path = settingPath.trim();
|
|
51
|
+
if (!path)
|
|
52
|
+
return opKey;
|
|
53
|
+
if (path.endsWith(`.${opKey}`))
|
|
54
|
+
return opKey;
|
|
55
|
+
const last = path.split('.').pop();
|
|
56
|
+
return last && last.length > 0 ? last : opKey;
|
|
57
|
+
}
|
|
58
|
+
function linesFromOps(check) {
|
|
59
|
+
const lines = [];
|
|
60
|
+
const settingPath = check.setting_path ?? '';
|
|
61
|
+
const ops = check.ops;
|
|
62
|
+
if (!ops || typeof ops !== 'object')
|
|
63
|
+
return lines;
|
|
64
|
+
const setOps = ops.set;
|
|
65
|
+
if (setOps && typeof setOps === 'object') {
|
|
66
|
+
for (const [key, value] of Object.entries(setOps)) {
|
|
67
|
+
const leaf = Object.keys(setOps).length === 1 ? leafFromSettingPath(settingPath, key) : key;
|
|
68
|
+
lines.push(`Set ${leaf} → ${formatScalar(value)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const addOps = ops.add;
|
|
72
|
+
if (addOps && typeof addOps === 'object') {
|
|
73
|
+
for (const [key, items] of Object.entries(addOps)) {
|
|
74
|
+
if (!Array.isArray(items))
|
|
75
|
+
continue;
|
|
76
|
+
lines.push(`Add to ${key}: ${formatListDeltaItems(items)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const removeOps = ops.remove;
|
|
80
|
+
if (removeOps && typeof removeOps === 'object') {
|
|
81
|
+
for (const [key, items] of Object.entries(removeOps)) {
|
|
82
|
+
if (Array.isArray(items)) {
|
|
83
|
+
lines.push(`Remove from ${key}: ${formatListDeltaItems(items)}`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (items && typeof items === 'object') {
|
|
87
|
+
lines.push(`Remove from ${key}: ${formatListDeltaItems(Object.keys(items))}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
93
|
+
function linesFromSqliteOp(check) {
|
|
94
|
+
const sqliteOp = check.sqlite_op;
|
|
95
|
+
if (!sqliteOp || typeof sqliteOp !== 'object')
|
|
96
|
+
return [];
|
|
97
|
+
const lines = [];
|
|
98
|
+
const settingPath = check.setting_path ?? '';
|
|
99
|
+
const updates = sqliteOp.updates;
|
|
100
|
+
if (updates && typeof updates === 'object') {
|
|
101
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
102
|
+
lines.push(`Set ${leafFromSettingPath(settingPath, key)} → ${formatScalar(value)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const unionAdd = sqliteOp.array_union_add;
|
|
106
|
+
if (Array.isArray(unionAdd) && unionAdd.length > 0) {
|
|
107
|
+
const target = sqliteOp.target_key ?? 'list';
|
|
108
|
+
lines.push(`Add to ${target}: ${formatListDeltaItems(unionAdd)}`);
|
|
109
|
+
}
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
112
|
+
function linesFromCheck(check) {
|
|
113
|
+
const fromOps = linesFromOps(check);
|
|
114
|
+
if (fromOps.length > 0)
|
|
115
|
+
return fromOps;
|
|
116
|
+
return linesFromSqliteOp(check);
|
|
117
|
+
}
|
|
118
|
+
function linesFromFixSpec(spec) {
|
|
119
|
+
if (!spec)
|
|
120
|
+
return [];
|
|
121
|
+
if (Array.isArray(spec.checks) && spec.checks.length > 0) {
|
|
122
|
+
return spec.checks.flatMap((check) => linesFromCheck(check));
|
|
123
|
+
}
|
|
124
|
+
if (spec.setting_path || spec.ops) {
|
|
125
|
+
return linesFromCheck({ setting_path: spec.setting_path, ops: spec.ops });
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
/** Basename for macOS dialog copy (vscdb paths shortened). */
|
|
130
|
+
export function previewFileLabel(configFilePath) {
|
|
131
|
+
if (!configFilePath?.trim())
|
|
132
|
+
return 'config file';
|
|
133
|
+
const normalized = configFilePath.replace(/\\/g, '/');
|
|
134
|
+
const hashIdx = normalized.indexOf('#');
|
|
135
|
+
const pathPart = hashIdx >= 0 ? normalized.slice(0, hashIdx) : normalized;
|
|
136
|
+
const fragment = hashIdx >= 0 ? normalized.slice(hashIdx + 1) : '';
|
|
137
|
+
const segments = pathPart.split('/').filter(Boolean);
|
|
138
|
+
const base = segments[segments.length - 1] ?? pathPart;
|
|
139
|
+
if (base.endsWith('.vscdb') || base === 'state.vscdb') {
|
|
140
|
+
if (fragment && fragment !== 'composerState') {
|
|
141
|
+
const short = fragment.length > 28
|
|
142
|
+
? fragment.includes('/')
|
|
143
|
+
? (fragment.split('/').pop() ?? fragment)
|
|
144
|
+
: fragment
|
|
145
|
+
: fragment;
|
|
146
|
+
return `state.vscdb (${short})`;
|
|
147
|
+
}
|
|
148
|
+
return 'state.vscdb';
|
|
149
|
+
}
|
|
150
|
+
return base || 'config file';
|
|
151
|
+
}
|
|
152
|
+
export function collectRemediationPreviewLines(appliedViolations, remediations, maxLines = MAX_PREVIEW_LINES) {
|
|
153
|
+
const byUuid = new Map(remediations.map((row) => [row.uuid, row]));
|
|
154
|
+
const fileLabels = new Set();
|
|
155
|
+
const allLines = [];
|
|
156
|
+
for (const violation of appliedViolations) {
|
|
157
|
+
const instruction = byUuid.get(violation.uuid);
|
|
158
|
+
const spec = instruction ? remediationFixSpec(instruction) : null;
|
|
159
|
+
fileLabels.add(previewFileLabel(instruction?.config_file_path ?? violation.config_file_path ?? ''));
|
|
160
|
+
allLines.push(...linesFromFixSpec(spec));
|
|
161
|
+
}
|
|
162
|
+
const lines = allLines.slice(0, maxLines);
|
|
163
|
+
const hiddenCount = Math.max(0, allLines.length - lines.length);
|
|
164
|
+
return { fileLabels: [...fileLabels], lines, hiddenCount };
|
|
165
|
+
}
|
|
166
|
+
export function formatRemediationChangePreviewSection(appliedViolations, remediations) {
|
|
167
|
+
const { fileLabels, lines, hiddenCount } = collectRemediationPreviewLines(appliedViolations, remediations);
|
|
168
|
+
if (lines.length === 0)
|
|
169
|
+
return '';
|
|
170
|
+
const filePart = fileLabels.length === 1
|
|
171
|
+
? `Changes in ${fileLabels[0]}:`
|
|
172
|
+
: `Changes in ${fileLabels.slice(0, 2).join(', ')}${fileLabels.length > 2 ? ', …' : ''}:`;
|
|
173
|
+
const body = lines.map((line) => ` • ${truncateLine(line)}`).join('\n');
|
|
174
|
+
const tail = hiddenCount > 0
|
|
175
|
+
? `\n … and ${hiddenCount} more change${hiddenCount === 1 ? '' : 's'}`
|
|
176
|
+
: '';
|
|
177
|
+
return `${filePart}\n${body}${tail}`;
|
|
178
|
+
}
|
|
179
|
+
export function formatRemediationChangePreviewForApplied(appliedViolations) {
|
|
180
|
+
const { remediations } = readRemediationInstructionsFile();
|
|
181
|
+
return formatRemediationChangePreviewSection(appliedViolations, remediations);
|
|
182
|
+
}
|
package/dist/tofu.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tofu shim — centralises all imports from @optimuslabs/tofu-staging.
|
|
3
|
+
*
|
|
4
|
+
* Reads ~/.optimuslabs/management/optimus_dev.env at startup:
|
|
5
|
+
* - No file / unreadable → staging (ignores OPTIMUS_ENVIRONMENT).
|
|
6
|
+
* - File present → environment= line in file, then OPTIMUS_ENVIRONMENT, then staging.
|
|
7
|
+
* - environment=development + local dist present → loads sibling optimus-tofu dist
|
|
8
|
+
* - staging / production / npx installs → published @optimuslabs/tofu-staging npm package
|
|
9
|
+
*
|
|
10
|
+
* All other source files import from this module, never directly from
|
|
11
|
+
* "@optimuslabs/tofu-staging", so the conditional lives in exactly one place.
|
|
12
|
+
*/
|
|
13
|
+
import path from "path";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { shouldUseLocalTofuDist } from "./tofu_environment.js";
|
|
16
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const localTofuPath = path.join(__dirname, "../../optimus-tofu/dist/index.js");
|
|
18
|
+
const useLocalTofu = shouldUseLocalTofuDist(localTofuPath);
|
|
19
|
+
const tofu = (useLocalTofu
|
|
20
|
+
? await import(localTofuPath)
|
|
21
|
+
: await import("@optimuslabs/tofu-staging"));
|
|
22
|
+
export const { loadEndpointBase, normalizeBaseUrl, buildStartupEndpointUrl, createSignature, persistAuthKey, readStoredAuthKey, ensureAuthentication, getEndpointSource, canonicalizePayload, getAuthKeyPath, } = tofu;
|
|
@@ -0,0 +1,36 @@
|
|
|
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, '.optimuslabs', 'management', 'optimus_dev.env');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Staging package: default staging when no management file (promotion rewrites to production).
|
|
12
|
+
* File present → environment= line in file, then OPTIMUS_ENVIRONMENT, then staging.
|
|
13
|
+
*/
|
|
14
|
+
export function readEnvironment() {
|
|
15
|
+
const envPath = managementEnvPath();
|
|
16
|
+
if (!envPath) {
|
|
17
|
+
return 'staging';
|
|
18
|
+
}
|
|
19
|
+
let content;
|
|
20
|
+
try {
|
|
21
|
+
content = readFileSync(envPath, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return 'staging';
|
|
25
|
+
}
|
|
26
|
+
const match = content?.match(/^(?:environment|ENVIRONMENT|OPTIMUS_ENVIRONMENT)\s*=\s*(.+)/m);
|
|
27
|
+
if (match)
|
|
28
|
+
return match[1].trim().toLowerCase();
|
|
29
|
+
const fromEnv = process.env.OPTIMUS_ENVIRONMENT?.trim().toLowerCase();
|
|
30
|
+
if (fromEnv)
|
|
31
|
+
return fromEnv;
|
|
32
|
+
return 'staging';
|
|
33
|
+
}
|
|
34
|
+
export function shouldUseLocalTofuDist(localTofuPath) {
|
|
35
|
+
return readEnvironment() === 'development' && existsSync(localTofuPath);
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@optimuslabs/harness-map-staging",
|
|
3
|
+
"version": "1.5.16",
|
|
4
|
+
"description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"log-llm-config-staging": "dist/cli.js",
|
|
8
|
+
"log_uuid-staging": "dist/log_uuid/index.js",
|
|
9
|
+
"log_config_files-staging": "dist/log_config_files/index.js",
|
|
10
|
+
"log_sensitive_paths_audit-staging": "dist/log_sensitive_paths_audit.js",
|
|
11
|
+
"apply-deferred-vscdb-staging": "dist/apply_deferred_vscdb.js",
|
|
12
|
+
"execute-trusted-restarts-staging": "dist/execute_trusted_restarts.js",
|
|
13
|
+
"compliance_prompt_gate-staging": "dist/compliance_prompt_gate.js",
|
|
14
|
+
"compliance_check_runner-staging": "dist/compliance_check_runner.js",
|
|
15
|
+
"dialog_prefs-staging": "dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.json && node ../../../scripts/ensure-bin-executable.mjs",
|
|
19
|
+
"dev": "ts-node src/cli.ts",
|
|
20
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
21
|
+
"prepare": "npm run build",
|
|
22
|
+
"pretest": "npm run build",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mcp",
|
|
28
|
+
"config",
|
|
29
|
+
"logging",
|
|
30
|
+
"npx"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "UNLICENSED",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/optimuslabs-io/optimus-secure-fdn.git",
|
|
37
|
+
"directory": "npx_packages/staging/optimuslabs/log-llm-config"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/optimuslabs-io/optimus-secure-fdn/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/optimuslabs-io/optimus-secure-fdn/tree/main/npx_packages/staging/optimuslabs/log-llm-config#readme",
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/**/*",
|
|
45
|
+
"README.md"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^24.10.1",
|
|
52
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
53
|
+
"@vitest/ui": "^4.1.8",
|
|
54
|
+
"ts-node": "^10.9.2",
|
|
55
|
+
"typescript": "^5.4.5",
|
|
56
|
+
"vitest": "^4.1.8"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"axios": "^1.18.1",
|
|
60
|
+
"canonicalize": "^2.1.0",
|
|
61
|
+
"@optimuslabs/tofu-staging": "^0.1.18",
|
|
62
|
+
"smol-toml": "^1.7.1"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
}
|
|
67
|
+
}
|