@goplus/agentguard 1.0.14 → 1.1.3
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 +33 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +172 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud/client.d.ts +19 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +86 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +131 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/installers.d.ts +10 -0
- package/dist/installers.d.ts.map +1 -0
- package/dist/installers.js +137 -0
- package/dist/installers.js.map +1 -0
- package/dist/mcp-server.js +3 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/postinstall.d.ts +3 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +13 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/runtime/audit.d.ts +10 -0
- package/dist/runtime/audit.d.ts.map +1 -0
- package/dist/runtime/audit.js +94 -0
- package/dist/runtime/audit.js.map +1 -0
- package/dist/runtime/evaluator.d.ts +3 -0
- package/dist/runtime/evaluator.d.ts.map +1 -0
- package/dist/runtime/evaluator.js +197 -0
- package/dist/runtime/evaluator.js.map +1 -0
- package/dist/runtime/policy.d.ts +12 -0
- package/dist/runtime/policy.d.ts.map +1 -0
- package/dist/runtime/policy.js +81 -0
- package/dist/runtime/policy.js.map +1 -0
- package/dist/runtime/protect.d.ts +22 -0
- package/dist/runtime/protect.d.ts.map +1 -0
- package/dist/runtime/protect.js +172 -0
- package/dist/runtime/protect.js.map +1 -0
- package/dist/runtime/redaction.d.ts +6 -0
- package/dist/runtime/redaction.d.ts.map +1 -0
- package/dist/runtime/redaction.js +103 -0
- package/dist/runtime/redaction.js.map +1 -0
- package/dist/runtime/types.d.ts +62 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +3 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/scanner/rules/trojan.js +1 -1
- package/dist/scanner/rules/trojan.js.map +1 -1
- package/dist/tests/cloud-live.test.d.ts +2 -0
- package/dist/tests/cloud-live.test.d.ts.map +1 -0
- package/dist/tests/cloud-live.test.js +68 -0
- package/dist/tests/cloud-live.test.js.map +1 -0
- package/dist/tests/installer.test.d.ts +2 -0
- package/dist/tests/installer.test.d.ts.map +1 -0
- package/dist/tests/installer.test.js +32 -0
- package/dist/tests/installer.test.js.map +1 -0
- package/dist/tests/runtime-cloud.test.d.ts +2 -0
- package/dist/tests/runtime-cloud.test.d.ts.map +1 -0
- package/dist/tests/runtime-cloud.test.js +202 -0
- package/dist/tests/runtime-cloud.test.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/docs/SECURITY-POLICY.md +558 -0
- package/docs/architecture.md +54 -0
- package/docs/claude-code.md +41 -0
- package/docs/cloud-connect.md +73 -0
- package/docs/cloud-native-api.md +526 -0
- package/docs/codex.md +38 -0
- package/docs/goplus-api.md +38 -0
- package/docs/mcp-server.md +39 -0
- package/docs/openclaw.md +41 -0
- package/docs/privacy-boundary.md +37 -0
- package/docs/sdk.md +83 -0
- package/docs/trust-cli.md +58 -0
- package/examples/openclaw-docker/Dockerfile +10 -0
- package/examples/openclaw-docker/README.md +16 -0
- package/examples/openclaw-docker/docker-compose.yml +8 -0
- package/examples/openclaw-docker/plugin.ts +8 -0
- package/package.json +7 -2
- package/skills/agentguard/SKILL.md +157 -61
- package/skills/agentguard/{scripts/package.json → package.json} +2 -1
- package/skills/agentguard/patrol-checks.md +12 -2
- package/skills/agentguard/scan-rules.md +1 -1
- package/skills/agentguard/scripts/checkup-report.js +71 -30
|
@@ -75,6 +75,7 @@ Detailed commands, patterns, and thresholds for the 8 patrol checks. This docume
|
|
|
75
75
|
|
|
76
76
|
### Permission Checks
|
|
77
77
|
|
|
78
|
+
**macOS/Linux:**
|
|
78
79
|
```bash
|
|
79
80
|
# SSH directory — should be 700
|
|
80
81
|
stat -f "%Lp" ~/.ssh/ 2>/dev/null || stat -c "%a" ~/.ssh/ 2>/dev/null
|
|
@@ -82,10 +83,19 @@ stat -f "%Lp" ~/.ssh/ 2>/dev/null || stat -c "%a" ~/.ssh/ 2>/dev/null
|
|
|
82
83
|
stat -f "%Lp" ~/.gnupg/ 2>/dev/null || stat -c "%a" ~/.gnupg/ 2>/dev/null
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
**Windows (use icacls instead of stat):**
|
|
87
|
+
```powershell
|
|
88
|
+
icacls $env:USERPROFILE\.ssh 2>$null
|
|
89
|
+
icacls $env:USERPROFILE\.gnupg 2>$null
|
|
90
|
+
```
|
|
91
|
+
|
|
85
92
|
| Condition | Severity |
|
|
86
93
|
|-----------|----------|
|
|
87
|
-
| `~/.ssh/` permissions > 700 | HIGH |
|
|
88
|
-
| `~/.gnupg/` permissions > 700 | MEDIUM |
|
|
94
|
+
| macOS/Linux: `~/.ssh/` exists AND permissions > 700 | HIGH |
|
|
95
|
+
| macOS/Linux: `~/.gnupg/` exists AND permissions > 700 | MEDIUM |
|
|
96
|
+
| Windows: `~/.ssh/` exists AND ACL grants access to Everyone/Users/Authenticated Users | HIGH |
|
|
97
|
+
| Windows: `~/.gnupg/` exists AND ACL grants access to Everyone/Users/Authenticated Users | MEDIUM |
|
|
98
|
+
| Directory does not exist (stat/icacls returns empty) | N/A — not a finding |
|
|
89
99
|
|
|
90
100
|
---
|
|
91
101
|
|
|
@@ -292,7 +292,7 @@ Detects trojanized binary distribution patterns. Flags when 2+ of the following
|
|
|
292
292
|
- Version-like patterns (`x.0.0.0`)
|
|
293
293
|
- Values > 255 in any octet
|
|
294
294
|
|
|
295
|
-
## Rule 24: SOCIAL_ENGINEERING (
|
|
295
|
+
## Rule 24: SOCIAL_ENGINEERING (HIGH)
|
|
296
296
|
**Files**: `*.md`
|
|
297
297
|
|
|
298
298
|
| Pattern | Description |
|
|
@@ -15,9 +15,17 @@
|
|
|
15
15
|
import { writeFileSync, readFileSync, existsSync } from 'node:fs';
|
|
16
16
|
import { join, dirname } from 'node:path';
|
|
17
17
|
import { tmpdir, homedir } from 'node:os';
|
|
18
|
-
import
|
|
18
|
+
import open from 'open';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
20
|
|
|
21
|
+
const DIM_META = {
|
|
22
|
+
code_safety: { icon: 'find_in_page', name: 'Skill & Code Safety', zh: '技能与代码安全' },
|
|
23
|
+
credential_safety: { icon: 'key', name: 'Credential & Secrets', zh: '凭证与密钥安全' },
|
|
24
|
+
network_exposure: { icon: 'lan', name: 'Network & System', zh: '网络与系统暴露' },
|
|
25
|
+
runtime_protection: { icon: 'shield', name: 'Runtime Protection', zh: '运行时防护' },
|
|
26
|
+
web3_safety: { icon: 'token', name: 'Web3 Safety', zh: 'Web3 安全' },
|
|
27
|
+
};
|
|
28
|
+
|
|
21
29
|
// Try to load favicon from agentguard-server or fallback
|
|
22
30
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
31
|
let faviconB64 = '';
|
|
@@ -29,13 +37,27 @@ for (const p of iconPaths) {
|
|
|
29
37
|
if (existsSync(p)) { faviconB64 = readFileSync(p).toString('base64'); break; }
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
process.
|
|
34
|
-
|
|
35
|
-
process.
|
|
36
|
-
try {
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
// Support --file <path> argument to read JSON from file (cross-platform friendly)
|
|
41
|
+
const fileArgIdx = process.argv.indexOf('--file');
|
|
42
|
+
if (fileArgIdx !== -1 && process.argv[fileArgIdx + 1]) {
|
|
43
|
+
const filePath = process.argv[fileArgIdx + 1];
|
|
44
|
+
try {
|
|
45
|
+
const content = readFileSync(filePath, 'utf8');
|
|
46
|
+
generateReport(JSON.parse(content));
|
|
47
|
+
} catch (err) {
|
|
48
|
+
process.stderr.write(`Error reading ${filePath}: ${err.message}\n`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
// Fallback: read JSON from stdin (pipe)
|
|
53
|
+
let input = '';
|
|
54
|
+
process.stdin.setEncoding('utf8');
|
|
55
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
56
|
+
process.stdin.on('end', () => {
|
|
57
|
+
try { generateReport(JSON.parse(input)); }
|
|
58
|
+
catch (err) { process.stderr.write(`Error: ${err.message}\n`); process.exit(1); }
|
|
59
|
+
});
|
|
60
|
+
}
|
|
39
61
|
|
|
40
62
|
// ---------------------------------------------------------------------------
|
|
41
63
|
// Helpers
|
|
@@ -73,13 +95,7 @@ function getTier(score) {
|
|
|
73
95
|
])};
|
|
74
96
|
}
|
|
75
97
|
|
|
76
|
-
|
|
77
|
-
code_safety: { icon: 'find_in_page', name: 'Skill & Code Safety', zh: '技能与代码安全' },
|
|
78
|
-
credential_safety: { icon: 'key', name: 'Credential & Secrets', zh: '凭证与密钥安全' },
|
|
79
|
-
network_exposure: { icon: 'lan', name: 'Network & System', zh: '网络与系统暴露' },
|
|
80
|
-
runtime_protection: { icon: 'shield', name: 'Runtime Protection', zh: '运行时防护' },
|
|
81
|
-
web3_safety: { icon: 'token', name: 'Web3 Safety', zh: 'Web3 安全' },
|
|
82
|
-
};
|
|
98
|
+
|
|
83
99
|
|
|
84
100
|
function esc(s) { return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
|
|
85
101
|
|
|
@@ -730,7 +746,8 @@ function generateReport(data) {
|
|
|
730
746
|
autoRecs.push({ severity: 'LOW', text: 'Enable auto-scan on session start: export AGENTGUARD_AUTO_SCAN=1', zh: '启用会话启动时自动扫描:export AGENTGUARD_AUTO_SCAN=1' });
|
|
731
747
|
|
|
732
748
|
// Merge: user recs first, then auto recs (dedup by text similarity)
|
|
733
|
-
|
|
749
|
+
// Guard against malformed entries where text may be undefined (#37)
|
|
750
|
+
const allRecs = recommendations.filter(r => r && typeof r.text === 'string');
|
|
734
751
|
for (const ar of autoRecs) {
|
|
735
752
|
if (!allRecs.some(r => r.text.toLowerCase().includes(ar.text.slice(0, 30).toLowerCase()))) {
|
|
736
753
|
allRecs.push(ar);
|
|
@@ -747,11 +764,10 @@ function generateReport(data) {
|
|
|
747
764
|
const sc = sevColor(sev);
|
|
748
765
|
const zhText = r.zh || r.text;
|
|
749
766
|
return `
|
|
750
|
-
<div class="flex items-center gap-3 px-4 py-3 rounded-lg
|
|
767
|
+
<div class="flex items-center gap-3 px-4 py-3 rounded-lg">
|
|
751
768
|
<span class="w-5 text-xs font-headline font-bold text-[#849588]/60">${i+1}</span>
|
|
752
769
|
<span class="px-2 py-0.5 rounded text-[9px] font-bold uppercase tracking-wide text-white shrink-0" style="background:${sc}">${sev}</span>
|
|
753
770
|
<span class="text-sm text-[#b9cbbd] leading-snug rec-text" data-en="${esc(r.text)}" data-zh="${esc(zhText)}">${esc(r.text)}</span>
|
|
754
|
-
<span class="material-symbols-outlined text-sm text-[#849588]/0 group-hover:text-[#849588]/50 transition-colors ml-auto shrink-0">chevron_right</span>
|
|
755
771
|
</div>`;
|
|
756
772
|
}).join('')}</div>`
|
|
757
773
|
: '<div class="text-center py-12 text-[#849588]" data-i18n="no_recs">No recommendations.</div>';
|
|
@@ -759,12 +775,7 @@ function generateReport(data) {
|
|
|
759
775
|
// ── AI Analysis report ──
|
|
760
776
|
const analysisText = data.analysis || '';
|
|
761
777
|
const analysisHtml = analysisText
|
|
762
|
-
? `<div class="
|
|
763
|
-
<div class="bg-[#0a0e14] border border-[#3a4a3f]/10 rounded-xl p-5 text-sm text-[#b9cbbd] leading-relaxed whitespace-pre-line" id="analysisText">${esc(analysisText)}</div>
|
|
764
|
-
<button onclick="copyReport()" id="copyBtn" class="absolute top-3 right-3 flex items-center gap-1.5 px-3 py-1.5 bg-[#262a31] border border-[#3a4a3f]/30 rounded-lg text-[11px] font-semibold text-[#849588] hover:text-[#dfe2eb] hover:border-[#849588]/50 transition-all opacity-0 group-hover:opacity-100">
|
|
765
|
-
<span class="material-symbols-outlined text-sm" id="copyIcon">content_copy</span><span id="copyLabel" data-i18n="copy_report">Copy Report</span>
|
|
766
|
-
</button>
|
|
767
|
-
</div>`
|
|
778
|
+
? `<div class="bg-[#0a0e14] border border-[#3a4a3f]/10 rounded-xl p-5 text-sm text-[#b9cbbd] leading-relaxed whitespace-pre-line" id="analysisText">${esc(analysisText)}</div>`
|
|
768
779
|
: '';
|
|
769
780
|
|
|
770
781
|
// ── Health status label ──
|
|
@@ -919,6 +930,9 @@ body{background:#0a0e14;color:#dfe2eb;font-family:'Inter',sans-serif}
|
|
|
919
930
|
<p class="text-[10px] font-label uppercase tracking-[0.2em] text-[#849588] mb-1" data-i18n="sec_analysis">Security Analysis</p>
|
|
920
931
|
<h1 class="text-2xl font-headline font-bold text-[#f5fff5] tracking-tight flex items-center gap-3">
|
|
921
932
|
<span class="material-symbols-outlined" style="color:${tier.color}">analytics</span><span data-i18n="diag_report">Diagnostic Report</span>
|
|
933
|
+
<button onclick="copyReport()" id="copyBtn" class="flex items-center gap-1 px-2 py-1 bg-[#262a31] border border-[#3a4a3f]/30 rounded-lg text-[11px] font-semibold text-[#849588] hover:text-[#dfe2eb] hover:border-[#849588]/50 transition-all ml-1">
|
|
934
|
+
<span class="material-symbols-outlined text-sm" id="copyIcon">content_copy</span><span id="copyLabel" class="hidden sm:inline" data-i18n="copy_report">Copy Report</span>
|
|
935
|
+
</button>
|
|
922
936
|
</h1>
|
|
923
937
|
</div>
|
|
924
938
|
<div class="bg-[#262a31] border border-[#3a4a3f]/15 rounded-lg px-4 py-2 flex items-center gap-2">
|
|
@@ -1036,7 +1050,7 @@ body{background:#0a0e14;color:#dfe2eb;font-family:'Inter',sans-serif}
|
|
|
1036
1050
|
i18n.zh.quote=quotes_zh['${tier.grade}']||quotes_zh.B;
|
|
1037
1051
|
i18n.en.quote='"${tier.quote.replace(/'/g,"\\'")}\"';
|
|
1038
1052
|
|
|
1039
|
-
let curLang='en';
|
|
1053
|
+
let curLang=(${JSON.stringify(data.analysis||'')}).match(/[\u4e00-\u9fff]/) ? 'zh' : 'en';
|
|
1040
1054
|
window.toggleLang=function(){
|
|
1041
1055
|
curLang=curLang==='en'?'zh':'en';
|
|
1042
1056
|
document.getElementById('langLabel').textContent=curLang==='en'?'中文':'EN';
|
|
@@ -1054,6 +1068,22 @@ body{background:#0a0e14;color:#dfe2eb;font-family:'Inter',sans-serif}
|
|
|
1054
1068
|
});
|
|
1055
1069
|
};
|
|
1056
1070
|
|
|
1071
|
+
// Apply initial language on load (auto-detect Chinese from analysis content)
|
|
1072
|
+
if(curLang==='zh'){
|
|
1073
|
+
document.getElementById('langLabel').textContent='EN';
|
|
1074
|
+
document.querySelectorAll('[data-i18n]').forEach(el=>{
|
|
1075
|
+
const key=el.getAttribute('data-i18n');
|
|
1076
|
+
if(key==='findings_range'){
|
|
1077
|
+
const range=el.getAttribute('data-range'),total=el.getAttribute('data-total');
|
|
1078
|
+
el.textContent='发现 — '+range+' / 共 '+total;
|
|
1079
|
+
} else if(i18n.zh[key]!=null)el.textContent=i18n.zh[key];
|
|
1080
|
+
});
|
|
1081
|
+
document.querySelectorAll('.finding-dim,.finding-text,.clean-dims,.rec-text').forEach(el=>{
|
|
1082
|
+
const t=el.getAttribute('data-zh');
|
|
1083
|
+
if(t)el.textContent=t;
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1057
1087
|
// Dimension data for share card (must be before shareReport)
|
|
1058
1088
|
const _dims=${JSON.stringify(Object.fromEntries(Object.entries(DIM_META).map(([k])=>[k,dimensions[k]||{score:null,na:false}])))};
|
|
1059
1089
|
|
|
@@ -1334,11 +1364,22 @@ body{background:#0a0e14;color:#dfe2eb;font-family:'Inter',sans-serif}
|
|
|
1334
1364
|
|
|
1335
1365
|
const outPath = join(tmpdir(), `agentguard-checkup-${Date.now()}.html`);
|
|
1336
1366
|
writeFileSync(outPath, html, 'utf8');
|
|
1337
|
-
console.log(outPath);
|
|
1338
1367
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1368
|
+
// Skip browser open for headless/bot environments (Qclaw, OpenClaw, CI)
|
|
1369
|
+
const isHeadless = process.env.OPENCLAW_STATE_DIR || process.env.QCLAW || process.env.CI;
|
|
1370
|
+
|
|
1371
|
+
// Flush stdout before doing anything else — on Windows/Linux in non-TTY/pipe
|
|
1372
|
+
// mode, console.log() is non-blocking and process.exit() can terminate before
|
|
1373
|
+
// the buffer is flushed, causing the caller (Claude) to receive an empty path.
|
|
1374
|
+
// Flush stdout before doing anything else — on Windows/Linux in non-TTY/pipe
|
|
1375
|
+
// mode, console.log() is non-blocking and process.exit() can terminate before
|
|
1376
|
+
// the buffer is flushed, causing the caller (Claude) to receive an empty path.
|
|
1377
|
+
process.stdout.write(outPath + '\n', () => {
|
|
1378
|
+
if (!isHeadless) {
|
|
1379
|
+
open(outPath).catch(err => process.stderr.write(`Could not open browser: ${err.message}\n`));
|
|
1380
|
+
}
|
|
1381
|
+
// Hard exit after 3s — guards against exec child process hanging and
|
|
1382
|
+
// blocking Node from exiting naturally (e.g. xdg-open on misconfigured Linux).
|
|
1383
|
+
setTimeout(() => process.exit(0), 3000).unref();
|
|
1342
1384
|
});
|
|
1343
|
-
setTimeout(() => process.exit(0), 2000);
|
|
1344
1385
|
}
|