fullcourtdefense-cli 1.17.0 → 1.18.0
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/commands/daemon.js
CHANGED
|
@@ -658,10 +658,13 @@ async function runDaemon(args, config) {
|
|
|
658
658
|
const watched = refreshWatchTargets();
|
|
659
659
|
log(`Watching ${watched} config file(s) across ${watchers.size} director${watchers.size === 1 ? 'y' : 'ies'}.`);
|
|
660
660
|
await pollBundle();
|
|
661
|
-
await heartbeat();
|
|
662
661
|
// One protective pass at startup so a machine that drifted while the daemon
|
|
663
|
-
// was down converges immediately.
|
|
662
|
+
// was down converges immediately. Runs BEFORE the first heartbeat: upgrades
|
|
663
|
+
// legitimately leave stale hook/wrap paths behind, and heartbeating first
|
|
664
|
+
// would report a false "damaged" state (and fire admin integrity alerts)
|
|
665
|
+
// for a condition the very next line repairs.
|
|
664
666
|
await reprotect(['startup pass']);
|
|
667
|
+
await heartbeat();
|
|
665
668
|
// Fresh machines have never uploaded an inventory (MSI/onboard defers the
|
|
666
669
|
// initial discovery to keep setup fast), so the dashboard shows "Never" for
|
|
667
670
|
// discovery + posture until the daily scheduled job fires — up to 24h later.
|
|
@@ -35,7 +35,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.discoverCommand = discoverCommand;
|
|
37
37
|
exports.runDiscoverUpload = runDiscoverUpload;
|
|
38
|
-
const crypto = __importStar(require("crypto"));
|
|
39
38
|
const fs = __importStar(require("fs"));
|
|
40
39
|
const os = __importStar(require("os"));
|
|
41
40
|
const path = __importStar(require("path"));
|
|
@@ -52,6 +51,7 @@ const discoverBlastRadius_1 = require("./discoverBlastRadius");
|
|
|
52
51
|
const discoverSecrets_1 = require("./discoverSecrets");
|
|
53
52
|
const windowsAudit_1 = require("./windowsAudit");
|
|
54
53
|
const discoveryMarker_1 = require("../discoveryMarker");
|
|
54
|
+
const machineIdentity_1 = require("../machineIdentity");
|
|
55
55
|
const DEFAULT_API_URL = 'https://api.fullcourtdefense.ai';
|
|
56
56
|
function parseSurfaces(args) {
|
|
57
57
|
const raw = (args.surface || args.type || 'mcp').toLowerCase().trim();
|
|
@@ -93,9 +93,17 @@ function redactCommandArgs(args) {
|
|
|
93
93
|
}
|
|
94
94
|
return out;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* The SAME stable hardware id used at enrollment (MachineGuid / IOPlatformUUID
|
|
98
|
+
* / machine-id, sha256 → 32 hex chars). Discovery uploads MUST carry this id:
|
|
99
|
+
* the fleet console attaches scan evidence to the enrolled machine strictly by
|
|
100
|
+
* machineId, so a divergent id here makes the machine page show "Never
|
|
101
|
+
* scanned" while the data sits under a ghost host record. (Pre-1.18 releases
|
|
102
|
+
* hashed hostname+username into a 16-char fingerprint — the backend still
|
|
103
|
+
* recognizes those as legacy and matches them by hostname.)
|
|
104
|
+
*/
|
|
96
105
|
function machineFingerprint() {
|
|
97
|
-
|
|
98
|
-
return crypto.createHash('sha256').update(seed).digest('hex').slice(0, 16);
|
|
106
|
+
return (0, machineIdentity_1.getMachineIdentity)().machineId;
|
|
99
107
|
}
|
|
100
108
|
/** Detect ephemeral CI runners so they are never listed as user machines in the fleet. */
|
|
101
109
|
function isCiEnvironment() {
|
|
@@ -613,6 +621,8 @@ function proxyStatusLabel(status) {
|
|
|
613
621
|
return 'Proxied';
|
|
614
622
|
if (status === 'direct')
|
|
615
623
|
return 'Direct — needs gateway';
|
|
624
|
+
if (status === 'reference')
|
|
625
|
+
return 'Reference config — not loaded by any AI client';
|
|
616
626
|
return 'Unknown';
|
|
617
627
|
}
|
|
618
628
|
function sanitizeSecretForUpload(finding) {
|
|
@@ -1036,7 +1046,9 @@ async function discoverCommand(args, config) {
|
|
|
1036
1046
|
console.log('');
|
|
1037
1047
|
if (clientCoverage.length > 0) {
|
|
1038
1048
|
for (const row of clientCoverage) {
|
|
1039
|
-
const gateway =
|
|
1049
|
+
const gateway = (0, discoverProxy_1.isReferenceConfigSource)(row.client)
|
|
1050
|
+
? `${COLOR.gray}reference only — not loaded by any AI client${COLOR.reset}`
|
|
1051
|
+
: row.mcpGatewayInstalled ? `${COLOR.green}gateway ✓${COLOR.reset}` : `${COLOR.red}no gateway${COLOR.reset}`;
|
|
1040
1052
|
console.log(` ${COLOR.dim}•${COLOR.reset} ${row.client} — ${row.mcpServerCount} MCP · ${gateway}`);
|
|
1041
1053
|
}
|
|
1042
1054
|
console.log('');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export type DesktopProxyStatus = 'fcd_gateway' | 'proxied' | 'direct' | 'unknown';
|
|
1
|
+
export type DesktopProxyStatus = 'fcd_gateway' | 'proxied' | 'direct' | 'reference' | 'unknown';
|
|
2
|
+
export declare function isReferenceConfigSource(source: string): boolean;
|
|
2
3
|
export declare const FCD_GATEWAY_SERVER_NAMES: Set<string>;
|
|
3
4
|
export declare const FCD_HOOK_MARKER = "--fcd-managed true";
|
|
4
5
|
export declare const FCD_HOOK_TAG = "fullcourtdefense";
|
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.FCD_HOOK_TAG = exports.FCD_HOOK_MARKER = exports.FCD_GATEWAY_SERVER_NAMES = void 0;
|
|
37
|
+
exports.isReferenceConfigSource = isReferenceConfigSource;
|
|
37
38
|
exports.isFcdGatewayServer = isFcdGatewayServer;
|
|
38
39
|
exports.extractGatewayDownstream = extractGatewayDownstream;
|
|
39
40
|
exports.buildGatewayWrapIndex = buildGatewayWrapIndex;
|
|
@@ -44,6 +45,18 @@ exports.buildClientCoverage = buildClientCoverage;
|
|
|
44
45
|
const fs = __importStar(require("fs"));
|
|
45
46
|
const os = __importStar(require("os"));
|
|
46
47
|
const path = __importStar(require("path"));
|
|
48
|
+
/**
|
|
49
|
+
* Config sources that no AI client actually loads. A plain `mcp.json` at a
|
|
50
|
+
* repo root is documentation/sample material — Cursor, Claude Code, VS Code,
|
|
51
|
+
* Windsurf, etc. all read their own dot-folder configs, never this file.
|
|
52
|
+
* Servers found there are inventory-worthy (they show what a repo references)
|
|
53
|
+
* but are not live attack surface, so they classify as 'reference' instead of
|
|
54
|
+
* 'direct' and must never count toward the machine's exposed status.
|
|
55
|
+
*/
|
|
56
|
+
const REFERENCE_CONFIG_SOURCES = new Set(['Repo (mcp.json)']);
|
|
57
|
+
function isReferenceConfigSource(source) {
|
|
58
|
+
return REFERENCE_CONFIG_SOURCES.has(source);
|
|
59
|
+
}
|
|
47
60
|
exports.FCD_GATEWAY_SERVER_NAMES = new Set([
|
|
48
61
|
'agentguard-gateway',
|
|
49
62
|
'fullcourtdefense-gateway',
|
|
@@ -157,6 +170,8 @@ function buildGatewayWrapIndex(servers) {
|
|
|
157
170
|
return wrapsByConfig;
|
|
158
171
|
}
|
|
159
172
|
function classifyProxyStatus(server, wrapsByConfig) {
|
|
173
|
+
if (isReferenceConfigSource(server.source))
|
|
174
|
+
return 'reference';
|
|
160
175
|
if (isFcdGatewayServer(server))
|
|
161
176
|
return 'fcd_gateway';
|
|
162
177
|
const wrapped = wrapsByConfig.get(server.configPath.toLowerCase());
|
package/dist/version.json
CHANGED