fullcourtdefense-cli 1.7.3 → 1.7.5
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.
|
@@ -511,6 +511,7 @@ async function upload(servers, host, clientCoverage, apiUrl, auth, connectorName
|
|
|
511
511
|
} : undefined,
|
|
512
512
|
secrets: extras?.secrets?.findings.slice(0, 100).map(sanitizeSecretForUpload),
|
|
513
513
|
agentFiles: extras?.agentFiles?.slice(0, 100).map(sanitizeAgentFileForUpload),
|
|
514
|
+
scanScope: extras?.scanScope,
|
|
514
515
|
servers: servers.map(s => ({
|
|
515
516
|
serverName: s.serverName,
|
|
516
517
|
command: s.command,
|
|
@@ -626,12 +627,19 @@ async function discoverCommand(args, config) {
|
|
|
626
627
|
console.log('Removed daily desktop discovery schedule.');
|
|
627
628
|
return;
|
|
628
629
|
}
|
|
629
|
-
if (args.schedule === 'daily') {
|
|
630
|
+
if (args.schedule === 'daily' || args.schedule === 'logon') {
|
|
630
631
|
const hour = args.scheduleHour ? Number.parseInt(args.scheduleHour, 10) : 9;
|
|
631
|
-
|
|
632
|
+
const surface = surfaces.size === 4 ? 'all' : Array.from(surfaces).join(',');
|
|
633
|
+
(0, discoverSchedule_1.installDailyDiscoverSchedule)({
|
|
634
|
+
userEmail: args.userEmail,
|
|
635
|
+
hour: Number.isFinite(hour) ? hour : 9,
|
|
636
|
+
surface,
|
|
637
|
+
trigger: args.schedule,
|
|
638
|
+
});
|
|
632
639
|
if (!silent) {
|
|
633
|
-
|
|
634
|
-
console.log(
|
|
640
|
+
const when = args.schedule === 'logon' ? 'at logon' : `daily at ${String(Number.isFinite(hour) ? hour : 9).padStart(2, '0')}:00`;
|
|
641
|
+
console.log(`Desktop discovery scheduled ${when} (runs discover --surface ${surface} --upload --silent${args.userEmail ? ` --user-email ${args.userEmail}` : ''}).`);
|
|
642
|
+
console.log('Uses login Shield credentials or an explicit org API key.');
|
|
635
643
|
}
|
|
636
644
|
return;
|
|
637
645
|
}
|
|
@@ -684,7 +692,30 @@ async function discoverCommand(args, config) {
|
|
|
684
692
|
}, null, 2));
|
|
685
693
|
return;
|
|
686
694
|
}
|
|
687
|
-
const
|
|
695
|
+
const home = os.homedir();
|
|
696
|
+
const uploadExtras = {
|
|
697
|
+
secrets,
|
|
698
|
+
agentFiles,
|
|
699
|
+
posture,
|
|
700
|
+
scanScope: {
|
|
701
|
+
surfaces: [...surfaces],
|
|
702
|
+
workingDirectory: cwd,
|
|
703
|
+
mcpConfigPaths: scanned.map(s => ({ ...s, exists: fs.existsSync(s.path) })),
|
|
704
|
+
included: [
|
|
705
|
+
`Current command folder: ${cwd}`,
|
|
706
|
+
'Known MCP/AI client config files for Cursor, Claude, Codex, Gemini, Windsurf, and VS Code',
|
|
707
|
+
`User-level AI rules, skills, hooks, and instruction files under ${home}`,
|
|
708
|
+
`Credential stores and shell history under ${home}`,
|
|
709
|
+
`Environment files under ${cwd}, ${path.join(home, 'dev')}, ${path.join(home, 'repos')}, ${path.join(home, 'projects')}, ${path.join(home, 'Documents')}, and ${path.join(home, 'code')}`,
|
|
710
|
+
],
|
|
711
|
+
excluded: [
|
|
712
|
+
'Unrelated project folders outside the listed roots',
|
|
713
|
+
'Large/generated dependency and build folders such as node_modules, .git, dist, build, vendor, caches, and temp folders',
|
|
714
|
+
'Full disk contents, browser profiles, email/chat archives, binary files, and operating-system folders',
|
|
715
|
+
],
|
|
716
|
+
note: 'Desktop posture is a targeted AI-development exposure scan, not a full-device forensic scan. Run the command from the project folder you want represented.',
|
|
717
|
+
},
|
|
718
|
+
};
|
|
688
719
|
async function maybeUpload() {
|
|
689
720
|
if (args.upload !== 'true')
|
|
690
721
|
return;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface ScheduleArgs {
|
|
2
2
|
userEmail?: string;
|
|
3
3
|
hour?: number;
|
|
4
|
+
surface?: string;
|
|
5
|
+
trigger?: 'daily' | 'logon';
|
|
4
6
|
}
|
|
5
7
|
export declare function installDailyDiscoverSchedule(args?: ScheduleArgs): void;
|
|
6
8
|
export declare function uninstallDailyDiscoverSchedule(): void;
|
|
@@ -40,33 +40,56 @@ const fs = __importStar(require("fs"));
|
|
|
40
40
|
const os = __importStar(require("os"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const TASK_NAME = 'FullCourtDefenseDesktopDiscover';
|
|
43
|
-
|
|
43
|
+
const STARTUP_LAUNCHER = 'FullCourtDefenseDesktopDiscover.cmd';
|
|
44
|
+
function windowsStartupLauncherPath() {
|
|
45
|
+
const appData = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
|
|
46
|
+
return path.join(appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', STARTUP_LAUNCHER);
|
|
47
|
+
}
|
|
48
|
+
function discoverCommandLine(userEmail, surface) {
|
|
44
49
|
const node = process.execPath;
|
|
45
50
|
const script = path.resolve(process.argv[1] || path.join(__dirname, '..', 'index.js'));
|
|
46
51
|
const q = (value) => (/\s/.test(value) ? `"${value}"` : value);
|
|
47
52
|
const parts = [q(node), q(script), 'discover', '--upload', '--silent'];
|
|
53
|
+
if (surface)
|
|
54
|
+
parts.push('--surface', q(surface));
|
|
48
55
|
if (userEmail)
|
|
49
56
|
parts.push('--user-email', q(userEmail));
|
|
50
57
|
return parts.join(' ');
|
|
51
58
|
}
|
|
52
|
-
function installWindowsSchedule(hour, userEmail) {
|
|
53
|
-
const tr = discoverCommandLine(userEmail);
|
|
54
|
-
const st = `${String(hour).padStart(2, '0')}:00`;
|
|
59
|
+
function installWindowsSchedule(hour, userEmail, surface, trigger = 'daily') {
|
|
60
|
+
const tr = discoverCommandLine(userEmail, surface);
|
|
55
61
|
try {
|
|
56
62
|
(0, child_process_1.execSync)(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: 'ignore' });
|
|
57
63
|
}
|
|
58
64
|
catch {
|
|
59
65
|
// task may not exist
|
|
60
66
|
}
|
|
61
|
-
|
|
67
|
+
const schedule = trigger === 'logon'
|
|
68
|
+
? '/SC ONLOGON'
|
|
69
|
+
: `/SC DAILY /ST ${String(hour).padStart(2, '0')}:00`;
|
|
70
|
+
try {
|
|
71
|
+
(0, child_process_1.execSync)(`schtasks /Create /F /TN "${TASK_NAME}" ${schedule} /RL LIMITED /TR "${tr.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (trigger !== 'logon')
|
|
75
|
+
throw error;
|
|
76
|
+
const launcher = windowsStartupLauncherPath();
|
|
77
|
+
fs.mkdirSync(path.dirname(launcher), { recursive: true });
|
|
78
|
+
fs.writeFileSync(launcher, `@echo off\r\n${tr} > "%USERPROFILE%\\.fullcourtdefense-discover.log" 2>&1\r\n`, 'utf8');
|
|
79
|
+
console.log(`Task Scheduler denied access; installed user logon launcher instead: ${launcher}`);
|
|
80
|
+
}
|
|
62
81
|
}
|
|
63
|
-
function installMacSchedule(hour, userEmail) {
|
|
82
|
+
function installMacSchedule(hour, userEmail, surface, trigger = 'daily') {
|
|
64
83
|
const label = 'ai.fullcourtdefense.discover';
|
|
65
84
|
const plistDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
|
|
66
85
|
const plistPath = path.join(plistDir, `${label}.plist`);
|
|
67
86
|
fs.mkdirSync(plistDir, { recursive: true });
|
|
68
|
-
const cmd = discoverCommandLine(userEmail).split(/\s+/);
|
|
87
|
+
const cmd = discoverCommandLine(userEmail, surface).split(/\s+/);
|
|
69
88
|
const program = cmd.shift() || process.execPath;
|
|
89
|
+
const triggerXml = trigger === 'logon'
|
|
90
|
+
? '<key>RunAtLoad</key><true/>'
|
|
91
|
+
: `<key>StartCalendarInterval</key>
|
|
92
|
+
<dict><key>Hour</key><integer>${hour}</integer><key>Minute</key><integer>0</integer></dict>`;
|
|
70
93
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
71
94
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
72
95
|
<plist version="1.0">
|
|
@@ -74,8 +97,7 @@ function installMacSchedule(hour, userEmail) {
|
|
|
74
97
|
<key>Label</key><string>${label}</string>
|
|
75
98
|
<key>ProgramArguments</key>
|
|
76
99
|
<array>${[program, ...cmd].map(part => `<string>${part.replace(/&/g, '&').replace(/</g, '<')}</string>`).join('')}</array>
|
|
77
|
-
|
|
78
|
-
<dict><key>Hour</key><integer>${hour}</integer><key>Minute</key><integer>0</integer></dict>
|
|
100
|
+
${triggerXml}
|
|
79
101
|
<key>StandardOutPath</key><string>${path.join(os.homedir(), '.fullcourtdefense-discover.log')}</string>
|
|
80
102
|
<key>StandardErrorPath</key><string>${path.join(os.homedir(), '.fullcourtdefense-discover.err.log')}</string>
|
|
81
103
|
</dict>
|
|
@@ -84,8 +106,9 @@ function installMacSchedule(hour, userEmail) {
|
|
|
84
106
|
(0, child_process_1.spawnSync)('launchctl', ['unload', plistPath], { stdio: 'ignore' });
|
|
85
107
|
(0, child_process_1.spawnSync)('launchctl', ['load', plistPath], { stdio: 'inherit' });
|
|
86
108
|
}
|
|
87
|
-
function installLinuxCron(hour, userEmail) {
|
|
88
|
-
const
|
|
109
|
+
function installLinuxCron(hour, userEmail, surface, trigger = 'daily') {
|
|
110
|
+
const schedule = trigger === 'logon' ? '@reboot' : `0 ${hour} * * *`;
|
|
111
|
+
const line = `${schedule} ${discoverCommandLine(userEmail, surface)} >> ${path.join(os.homedir(), '.fullcourtdefense-discover.log')} 2>&1`;
|
|
89
112
|
const marker = '# fullcourtdefense-discover';
|
|
90
113
|
let crontab = '';
|
|
91
114
|
try {
|
|
@@ -101,16 +124,30 @@ function installLinuxCron(hour, userEmail) {
|
|
|
101
124
|
}
|
|
102
125
|
function installDailyDiscoverSchedule(args = {}) {
|
|
103
126
|
const hour = Number.isFinite(args.hour) ? Math.min(23, Math.max(0, args.hour)) : 9;
|
|
127
|
+
const trigger = args.trigger || 'daily';
|
|
104
128
|
if (process.platform === 'win32')
|
|
105
|
-
installWindowsSchedule(hour, args.userEmail);
|
|
129
|
+
installWindowsSchedule(hour, args.userEmail, args.surface, trigger);
|
|
106
130
|
else if (process.platform === 'darwin')
|
|
107
|
-
installMacSchedule(hour, args.userEmail);
|
|
131
|
+
installMacSchedule(hour, args.userEmail, args.surface, trigger);
|
|
108
132
|
else
|
|
109
|
-
installLinuxCron(hour, args.userEmail);
|
|
133
|
+
installLinuxCron(hour, args.userEmail, args.surface, trigger);
|
|
110
134
|
}
|
|
111
135
|
function uninstallDailyDiscoverSchedule() {
|
|
112
136
|
if (process.platform === 'win32') {
|
|
113
|
-
|
|
137
|
+
try {
|
|
138
|
+
(0, child_process_1.execSync)(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: 'inherit' });
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Scheduled Task may not exist or may be inaccessible.
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const launcher = windowsStartupLauncherPath();
|
|
145
|
+
if (fs.existsSync(launcher))
|
|
146
|
+
fs.unlinkSync(launcher);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// ignore
|
|
150
|
+
}
|
|
114
151
|
return;
|
|
115
152
|
}
|
|
116
153
|
if (process.platform === 'darwin') {
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,7 @@ function printHelp() {
|
|
|
124
124
|
scan Runs the scan. Use --local for inside-organization scans.
|
|
125
125
|
discover Finds MCP servers, local secrets, agent rules/skills, and machine
|
|
126
126
|
blast radius on this laptop. Use --surface all --upload for AI Fleet.
|
|
127
|
+
Use --schedule logon to upload inventory/posture at machine login.
|
|
127
128
|
install-cursor-hook
|
|
128
129
|
Installs a Cursor hook so EVERY agent action on this machine is
|
|
129
130
|
checked against your org's Action Policies — in any repo/folder.
|
|
@@ -305,6 +306,7 @@ function printHelp() {
|
|
|
305
306
|
$ fullcourtdefense login --token <fleet-enrollment-token>
|
|
306
307
|
$ fullcourtdefense install-all
|
|
307
308
|
$ fullcourtdefense install-all --auto-protect true --upload
|
|
309
|
+
$ fullcourtdefense discover --surface all --upload --schedule logon
|
|
308
310
|
$ fullcourtdefense install-mcp-gateway --clients cursor,codex --mcp-command npm --mcp-args "run mcp"
|
|
309
311
|
$ fullcourtdefense install-codex-mcp-gateway --mcp-command npm --mcp-args "run mcp"
|
|
310
312
|
$ fullcourtdefense scan --system-prompt ./prompts/system.md --fail-threshold 80
|
package/dist/version.json
CHANGED