@optimuslabs/harness-map-staging 1.5.24 → 1.5.26
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/approved_tenant_gate.js +302 -0
- package/dist/compliance_prompt_gate.js +315 -156
- package/dist/log_config_files/collection/claude_desktop_orgs_collector.js +173 -0
- package/dist/log_config_files/collection/codex_token_usage_collector.js +1 -1
- package/dist/log_config_files/collection/config_collector.js +1 -0
- package/dist/log_config_files/collection/cursor_token_usage_collector.js +127 -91
- package/dist/log_config_files/runtime/main_runner.js +79 -149
- package/dist/log_config_files/runtime/management_storage.js +46 -2
- package/dist/log_config_files/runtime/remediation_sync.js +156 -109
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { homedir } from 'node:os';
|
|
|
4
4
|
import { executeBody } from '../../endpoint_client/http_transport.js';
|
|
5
5
|
import { parseJsonWithJsoncFallback, parseTomlText, stringifyToml } from '../readers/file_readers.js';
|
|
6
6
|
import { complianceRunnerDiag, hookRunLog, logRemediationApplyFailure } from './hook_logger.js';
|
|
7
|
-
import { atomicWriteJson, getDeferredVscdbApplyPath, getFileCollectionVscdbContractPath, getRemediationInstructionsPath, readRemediationInstructionsFile, writeRemediationInstructionsFile, } from './management_storage.js';
|
|
7
|
+
import { atomicWriteJson, getDeferredVscdbApplyPath, getFileCollectionVscdbContractPath, getRemediationInstructionsPath, readRemediationInstructionsFile, writeApprovedTenants, writeUnapprovedEmailDomains, writeAllowedEmailDomains, writeApprovedAgents, writeRemediationInstructionsFile, } from './management_storage.js';
|
|
8
8
|
import { readStoredAuthKey } from '../auth/auth_key_store.js';
|
|
9
9
|
import { ensureAuthentication } from '../auth/auth_flow.js';
|
|
10
10
|
import { createSignature } from '../sender/signing.js';
|
|
@@ -1600,123 +1600,172 @@ export function reportAutofixApplied(remediationUuid, result, details) {
|
|
|
1600
1600
|
// ---------------------------------------------------------------------------
|
|
1601
1601
|
// Main entry point
|
|
1602
1602
|
// ---------------------------------------------------------------------------
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1603
|
+
const errorText = (err) => (err instanceof Error ? err.message : String(err));
|
|
1604
|
+
/** The strings in a synced list, lowercased; anything else in it is dropped. */
|
|
1605
|
+
function lowercaseStrings(list) {
|
|
1606
|
+
return list.filter((v) => typeof v === 'string').map((v) => v.toLowerCase());
|
|
1607
|
+
}
|
|
1608
|
+
async function ensureVscdbContract(endpointBase) {
|
|
1607
1609
|
try {
|
|
1608
|
-
if (
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1610
|
+
if (existsSync(getFileCollectionVscdbContractPath()))
|
|
1611
|
+
return;
|
|
1612
|
+
const pr = await getFileCollectionPatterns(endpointBase);
|
|
1613
|
+
if (pr)
|
|
1614
|
+
persistVscdbComposerContractFromPatternsResponse(pr);
|
|
1613
1615
|
}
|
|
1614
1616
|
catch {
|
|
1615
1617
|
/* contract also written on full log-config run */
|
|
1616
1618
|
}
|
|
1619
|
+
}
|
|
1620
|
+
/** The server's sync answer, or null (logged) when the request failed or came back empty. */
|
|
1621
|
+
async function fetchSyncResult(endpointBase, machineUuid, activeUuids) {
|
|
1617
1622
|
let syncResult;
|
|
1618
1623
|
try {
|
|
1619
1624
|
syncResult = await fetchSync(endpointBase, machineUuid, activeUuids);
|
|
1620
1625
|
}
|
|
1621
1626
|
catch (err) {
|
|
1622
|
-
const msg = `remediation_sync_error: ${
|
|
1627
|
+
const msg = `remediation_sync_error: ${errorText(err)}`;
|
|
1623
1628
|
hookRunLog(msg);
|
|
1624
1629
|
complianceRunnerDiag(msg);
|
|
1625
|
-
return;
|
|
1630
|
+
return null;
|
|
1626
1631
|
}
|
|
1627
1632
|
if (!syncResult) {
|
|
1628
1633
|
hookRunLog(`remediation_sync: no response from server, skipping`);
|
|
1629
1634
|
complianceRunnerDiag('remediation_sync: no response from server (non-200 or empty body), skipping');
|
|
1630
|
-
return;
|
|
1631
1635
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1636
|
+
return syncResult;
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Kept locally so the prompt gate checks the signed-in tenant without a round trip; a failed
|
|
1640
|
+
* sync never gets here and leaves the last lists in place.
|
|
1641
|
+
*/
|
|
1642
|
+
function storeApprovals(syncResult) {
|
|
1643
|
+
const approvedTenants = syncResult.approved_tenants;
|
|
1644
|
+
if (approvedTenants && typeof approvedTenants === 'object' && !Array.isArray(approvedTenants)) {
|
|
1645
|
+
writeApprovedTenants(approvedTenants);
|
|
1646
|
+
}
|
|
1647
|
+
const unapprovedDomains = syncResult.unapproved_email_domains;
|
|
1648
|
+
if (Array.isArray(unapprovedDomains))
|
|
1649
|
+
writeUnapprovedEmailDomains(lowercaseStrings(unapprovedDomains));
|
|
1650
|
+
const approvedAgents = syncResult.approved_agents;
|
|
1651
|
+
if (Array.isArray(approvedAgents))
|
|
1652
|
+
writeApprovedAgents(lowercaseStrings(approvedAgents));
|
|
1653
|
+
const allowedDomains = syncResult.allowed_email_domains;
|
|
1654
|
+
if (Array.isArray(allowedDomains))
|
|
1655
|
+
writeAllowedEmailDomains(lowercaseStrings(allowedDomains));
|
|
1656
|
+
}
|
|
1657
|
+
async function reconcileInstructions(endpointBase, machineUuid, want) {
|
|
1658
|
+
try {
|
|
1659
|
+
await ensureInstructionsForUuids(endpointBase, machineUuid, want, null);
|
|
1660
|
+
}
|
|
1661
|
+
catch (err) {
|
|
1662
|
+
hookRunLog(`remediation_instructions_reconcile_error: ${errorText(err)}`);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
/** Server says nothing changed: still repair a local file that is missing rows, incomplete or stale. */
|
|
1666
|
+
async function reconcileUnchanged(endpointBase, machineUuid, remediations, activeUuids) {
|
|
1667
|
+
hookRunLog(`remediation_sync: unchanged enforced=${activeUuids.length}`);
|
|
1668
|
+
complianceRunnerDiag(`remediation_sync: server status=unchanged local_uuids=${activeUuids.length} — no new rows to fetch; if a deploy should exist, verify Finding.machine matches this hardware_uuid`);
|
|
1669
|
+
const want = new Set(activeUuids);
|
|
1670
|
+
if (activeUuids.length === 0) {
|
|
1671
|
+
if (remediations.length > 0)
|
|
1672
|
+
await reconcileInstructions(endpointBase, machineUuid, new Set());
|
|
1660
1673
|
return;
|
|
1661
1674
|
}
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
let manifest
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
}
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1675
|
+
const have = new Map(remediations.map((r) => [r.uuid, r]));
|
|
1676
|
+
const needBackfill = activeUuids.some((u) => !have.has(u));
|
|
1677
|
+
const haveIncomplete = remediations.some((r) => want.has(r.uuid) && needsManifestRefetch(r));
|
|
1678
|
+
const haveOrphan = remediations.some((r) => !want.has(r.uuid));
|
|
1679
|
+
if (needBackfill || haveIncomplete || haveOrphan || !existsSync(getRemediationInstructionsPath())) {
|
|
1680
|
+
await reconcileInstructions(endpointBase, machineUuid, want);
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
function writeSortedInstructions(remediations) {
|
|
1684
|
+
remediations.sort((a, b) => a.uuid.localeCompare(b.uuid));
|
|
1685
|
+
writeInstructions({ remediations });
|
|
1686
|
+
}
|
|
1687
|
+
/** The manifest rows for the added UUIDs; null (logged) when it could not be fetched. */
|
|
1688
|
+
async function fetchAddedManifest(endpointBase, machineUuid, added) {
|
|
1689
|
+
let manifest;
|
|
1690
|
+
try {
|
|
1691
|
+
manifest = await fetchManifest(endpointBase, machineUuid, added);
|
|
1692
|
+
}
|
|
1693
|
+
catch (err) {
|
|
1694
|
+
const msg = `remediation_manifest_error: ${errorText(err)}`;
|
|
1695
|
+
hookRunLog(msg);
|
|
1696
|
+
complianceRunnerDiag(msg);
|
|
1697
|
+
return null;
|
|
1698
|
+
}
|
|
1699
|
+
if (!manifest) {
|
|
1700
|
+
hookRunLog(`remediation_sync: manifest fetch failed, skipping`);
|
|
1701
|
+
complianceRunnerDiag('remediation_sync: manifest fetch failed (null), skipping — remediation_instructions.json not updated');
|
|
1702
|
+
}
|
|
1703
|
+
return manifest;
|
|
1704
|
+
}
|
|
1705
|
+
function upsertInstruction(remediations, existingUuids, instruction) {
|
|
1706
|
+
if (!existingUuids.has(instruction.uuid)) {
|
|
1707
|
+
remediations.push(instruction);
|
|
1708
|
+
existingUuids.add(instruction.uuid);
|
|
1709
|
+
return;
|
|
1700
1710
|
}
|
|
1711
|
+
// Enforced remediations are always in `added`; overwrite local copy with fresh server data.
|
|
1712
|
+
const idx = remediations.findIndex((r) => r.uuid === instruction.uuid);
|
|
1713
|
+
if (idx >= 0)
|
|
1714
|
+
remediations[idx] = instruction;
|
|
1715
|
+
}
|
|
1716
|
+
/** Put the manifest's added rows into `remediations` (replacing a local copy); returns the rows put in. */
|
|
1717
|
+
function mergeAddedInstructions(remediations, manifest, added) {
|
|
1701
1718
|
const existingUuids = new Set(remediations.map((r) => r.uuid));
|
|
1702
1719
|
const addedSet = new Set(added);
|
|
1703
1720
|
const overlay = [];
|
|
1704
|
-
for (const instruction of manifest
|
|
1721
|
+
for (const instruction of manifest) {
|
|
1705
1722
|
if (!addedSet.has(instruction.uuid))
|
|
1706
1723
|
continue;
|
|
1707
|
-
|
|
1708
|
-
// Enforced remediations are always in `added`; overwrite local copy with fresh server data.
|
|
1709
|
-
const idx = remediations.findIndex((r) => r.uuid === instruction.uuid);
|
|
1710
|
-
if (idx >= 0)
|
|
1711
|
-
remediations[idx] = instruction;
|
|
1712
|
-
}
|
|
1713
|
-
else {
|
|
1714
|
-
remediations.push(instruction);
|
|
1715
|
-
existingUuids.add(instruction.uuid);
|
|
1716
|
-
}
|
|
1724
|
+
upsertInstruction(remediations, existingUuids, instruction);
|
|
1717
1725
|
overlay.push(instruction);
|
|
1718
1726
|
hookRunLog(`remediation_instructions_saved: uuid=${instruction.uuid} path=${instruction.config_file_path}`);
|
|
1719
1727
|
}
|
|
1728
|
+
return overlay;
|
|
1729
|
+
}
|
|
1730
|
+
/** Write the merged instructions, fetch anything still missing, and report the new UUID set. */
|
|
1731
|
+
async function persistSyncedInstructions(endpointBase, machineUuid, remediations, overlay, removedCount) {
|
|
1732
|
+
writeSortedInstructions(remediations);
|
|
1733
|
+
complianceRunnerDiag(`remediation_sync: wrote ${getRemediationInstructionsPath()} rows=${remediations.length} (added_from_manifest=${overlay.length} removed=${removedCount})`);
|
|
1734
|
+
const finalWant = new Set(remediations.map((r) => r.uuid));
|
|
1735
|
+
try {
|
|
1736
|
+
await ensureInstructionsForUuids(endpointBase, machineUuid, finalWant, overlay.length > 0 ? overlay : null);
|
|
1737
|
+
}
|
|
1738
|
+
catch (err) {
|
|
1739
|
+
hookRunLog(`remediation_instructions_persist_error: ${errorText(err)}`);
|
|
1740
|
+
}
|
|
1741
|
+
// Post-sync heartbeat: report the updated UUID set so the server has a before/after pair.
|
|
1742
|
+
const finalUuids = remediations.map((r) => r.uuid);
|
|
1743
|
+
try {
|
|
1744
|
+
await fetchSync(endpointBase, machineUuid, finalUuids);
|
|
1745
|
+
hookRunLog(`remediation_sync: post-sync heartbeat reported uuids=${finalUuids.length}`);
|
|
1746
|
+
}
|
|
1747
|
+
catch {
|
|
1748
|
+
// Non-critical — skip silently.
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
/** Server sent added/removed UUIDs: drop the removed, fetch and merge the added, then persist. */
|
|
1752
|
+
async function applySyncUpdate(endpointBase, machineUuid, local, syncResult) {
|
|
1753
|
+
const { added, removed } = syncResult;
|
|
1754
|
+
hookRunLog(`remediation_sync: status=updated added=${added.length} removed=${removed.length}`);
|
|
1755
|
+
complianceRunnerDiag(`remediation_sync: server status=updated added=${JSON.stringify(added)} removed=${JSON.stringify(removed)}`);
|
|
1756
|
+
const removedSet = new Set(removed);
|
|
1757
|
+
const retiredInstructions = local.filter((r) => removedSet.has(r.uuid));
|
|
1758
|
+
for (const r of retiredInstructions)
|
|
1759
|
+
hookRunLog(`remediation_remove: uuid=${r.uuid} path=${r.config_file_path}`);
|
|
1760
|
+
const removedCount = retiredInstructions.length;
|
|
1761
|
+
const remediations = local.filter((r) => !removedSet.has(r.uuid));
|
|
1762
|
+
const manifest = added.length > 0 ? await fetchAddedManifest(endpointBase, machineUuid, added) : [];
|
|
1763
|
+
if (!manifest) {
|
|
1764
|
+
if (removedCount > 0)
|
|
1765
|
+
writeSortedInstructions(remediations);
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
const overlay = mergeAddedInstructions(remediations, manifest, added);
|
|
1720
1769
|
transferQuarantineForRetiredUuids(removed, added, retiredInstructions, overlay);
|
|
1721
1770
|
const addedCount = overlay.length;
|
|
1722
1771
|
if (added.length > 0 && addedCount === 0) {
|
|
@@ -1725,26 +1774,24 @@ export async function syncRemediations(endpointBase, machineUuid) {
|
|
|
1725
1774
|
complianceRunnerDiag(`${msg} — remediation_instructions.json not written`);
|
|
1726
1775
|
}
|
|
1727
1776
|
if (removedCount > 0 || addedCount > 0) {
|
|
1728
|
-
|
|
1729
|
-
writeInstructions({ remediations });
|
|
1730
|
-
complianceRunnerDiag(`remediation_sync: wrote ${getRemediationInstructionsPath()} rows=${remediations.length} (added_from_manifest=${addedCount} removed=${removedCount})`);
|
|
1731
|
-
const finalWant = new Set(remediations.map((r) => r.uuid));
|
|
1732
|
-
try {
|
|
1733
|
-
await ensureInstructionsForUuids(endpointBase, machineUuid, finalWant, overlay.length > 0 ? overlay : null);
|
|
1734
|
-
}
|
|
1735
|
-
catch (err) {
|
|
1736
|
-
hookRunLog(`remediation_instructions_persist_error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1737
|
-
}
|
|
1738
|
-
// Post-sync heartbeat: report the updated UUID set so the server has a before/after pair.
|
|
1739
|
-
const finalUuids = remediations.map((r) => r.uuid);
|
|
1740
|
-
try {
|
|
1741
|
-
await fetchSync(endpointBase, machineUuid, finalUuids);
|
|
1742
|
-
hookRunLog(`remediation_sync: post-sync heartbeat reported uuids=${finalUuids.length}`);
|
|
1743
|
-
}
|
|
1744
|
-
catch {
|
|
1745
|
-
// Non-critical — skip silently.
|
|
1746
|
-
}
|
|
1777
|
+
await persistSyncedInstructions(endpointBase, machineUuid, remediations, overlay, removedCount);
|
|
1747
1778
|
}
|
|
1748
1779
|
hookRunLog(`remediation_sync: saved=${addedCount} removed=${removedCount}`);
|
|
1749
1780
|
complianceRunnerDiag(`remediation_sync: done saved=${addedCount} removed=${removedCount}`);
|
|
1750
1781
|
}
|
|
1782
|
+
export async function syncRemediations(endpointBase, machineUuid) {
|
|
1783
|
+
const remediations = readInstructions().remediations;
|
|
1784
|
+
const activeUuids = remediations.map((r) => r.uuid);
|
|
1785
|
+
complianceRunnerDiag(`remediation_sync: begin endpoint=${endpointBase} machine_uuid=${machineUuid} local_rows=${remediations.length}`);
|
|
1786
|
+
await ensureVscdbContract(endpointBase);
|
|
1787
|
+
const syncResult = await fetchSyncResult(endpointBase, machineUuid, activeUuids);
|
|
1788
|
+
if (!syncResult)
|
|
1789
|
+
return;
|
|
1790
|
+
applyClearApplyTrackingUuids(syncResult.clear_apply_tracking_uuids);
|
|
1791
|
+
storeApprovals(syncResult);
|
|
1792
|
+
if (syncResult.status === 'unchanged') {
|
|
1793
|
+
await reconcileUnchanged(endpointBase, machineUuid, remediations, activeUuids);
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
await applySyncUpdate(endpointBase, machineUuid, remediations, syncResult);
|
|
1797
|
+
}
|