@denial-web/clawguard 0.1.0 → 0.1.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # ClawGuard
2
2
 
3
- Independent governance and security scanner for OpenClaw-style skills and MCP tool configs.
3
+ Security gate and governance scanner for OpenClaw-style skills, ClawHub installs, MCP configs, and agent tools.
4
4
 
5
5
  ClawGuard helps developers answer one simple question before enabling a skill:
6
6
 
@@ -8,6 +8,8 @@ ClawGuard helps developers answer one simple question before enabling a skill:
8
8
 
9
9
  This project is compatible with OpenClaw-style skill directories, but it is not affiliated with OpenClaw.
10
10
 
11
+ ClawGuard is user-triggered today: run it before install, in CI, or as a local review step. It does not yet automatically intercept OpenClaw or ClawHub installs.
12
+
11
13
  ## Demo Preview
12
14
 
13
15
  [Watch the repeatable demo video](docs/assets/clawguard-demo.mp4), or regenerate it locally with `npm run demo:capture`.
@@ -41,7 +43,15 @@ Run ClawGuard directly from npm:
41
43
  npx @denial-web/clawguard scan ./path/to/skill
42
44
  ```
43
45
 
44
- Or run the local checkout:
46
+ Use gate mode before installing or trusting a skill:
47
+
48
+ ```bash
49
+ npx @denial-web/clawguard gate ./path/to/skill --policy governed
50
+ ```
51
+
52
+ Gate mode exits with `0` for allow, `1` for warn/review/sandbox decisions, and `2` for block.
53
+
54
+ When testing the published package, run `npx` from outside this repository. From inside the ClawGuard source checkout, use the local commands instead:
45
55
 
46
56
  ```bash
47
57
  npm test
@@ -172,6 +182,7 @@ Findings:
172
182
  ## Roadmap
173
183
 
174
184
  - `clawguard scan <path>` CLI
185
+ - `clawguard gate <path>` policy gate
175
186
  - OpenClaw `SKILL.md` metadata mismatch checks
176
187
  - `.clawguard.json` policy/config support
177
188
  - MCP/plugin config scanning
@@ -1,6 +1,6 @@
1
1
  # ClawGuard Architecture
2
2
 
3
- ClawGuard is an independent static governance layer for OpenClaw-style skills, ClawHub packages, and MCP/tool configs. It should stay compatible with OpenClaw without pretending to be OpenClaw.
3
+ ClawGuard is an independent static governance gate for OpenClaw-style skills, ClawHub packages, and MCP/tool configs. It should stay compatible with OpenClaw without pretending to be OpenClaw.
4
4
 
5
5
  ## Mission
6
6
 
@@ -18,11 +18,12 @@ The product should be small, explainable, and useful in three moments:
18
18
 
19
19
  1. CLI
20
20
 
21
- Current surface: `clawguard scan <path>`.
21
+ Current surfaces: `clawguard scan <path>` and `clawguard gate <path>`.
22
22
 
23
23
  Target surface:
24
24
 
25
25
  - `clawguard scan <path>`
26
+ - `clawguard gate <path>`
26
27
  - `clawguard scan-skill <skill-dir>`
27
28
  - `clawguard scan-workspace <workspace-dir>`
28
29
  - `clawguard scan-mcp <config-path>`
@@ -47,7 +48,15 @@ The product should be small, explainable, and useful in three moments:
47
48
 
48
49
  6. Install gate
49
50
 
50
- Optional wrapper or integration pattern around OpenClaw/ClawHub install/update flows. It should scan a downloaded bundle before the user enables it.
51
+ Current surface: `clawguard gate <path>`.
52
+
53
+ Gate mode maps scan results into allow, warn, sandbox, or block decisions and exits with install-wrapper friendly codes:
54
+
55
+ - `0`: allow
56
+ - `1`: warn, manual review, sandbox required, or dual approval
57
+ - `2`: block
58
+
59
+ Future surface: wrapper or integration pattern around OpenClaw/ClawHub install/update flows. It should scan a downloaded bundle before the user enables it.
51
60
 
52
61
  ## Trust Boundaries
53
62
 
@@ -99,14 +99,22 @@ Build:
99
99
  - Decisions: allow, warn, manual review, sandbox required, dual approval, block.
100
100
  - `.clawguard.json` config.
101
101
  - Suppressions with reason and optional expiry.
102
+ - Install gate command with policy exit codes.
102
103
  - Policy check command for saved reports.
103
104
 
104
105
  Success demo:
105
106
 
106
107
  ```bash
108
+ clawguard gate ./skills/my-skill --policy governed
107
109
  clawguard scan ./skills --policy governed --fail-on-policy
108
110
  ```
109
111
 
112
+ Gate exit codes:
113
+
114
+ - `0`: allow
115
+ - `1`: warn, manual review, sandbox required, or dual approval
116
+ - `2`: block
117
+
110
118
  ## Phase 4: Reports and CI
111
119
 
112
120
  Goal: make ClawGuard easy to adopt by maintainers.
@@ -25,8 +25,8 @@ Use this before sharing ClawGuard publicly.
25
25
 
26
26
  ## GitHub Repository
27
27
 
28
- - [ ] Repo description: `Governance and security scanner for OpenClaw skills, ClawHub installs, MCP configs, and skill dependencies.`
29
- - [ ] Topics: `openclaw`, `clawhub`, `mcp`, `security`, `ai-agents`, `scanner`, `governance`, `supply-chain`.
28
+ - [x] Repo description: `Governance and security scanner for OpenClaw skills, ClawHub installs, MCP configs, and skill dependencies.`
29
+ - [x] Topics: `openclaw`, `clawhub`, `mcp`, `security`, `ai-agents`, `scanner`, `governance`, `supply-chain`.
30
30
  - [x] License is visible.
31
31
  - [x] Security policy is visible.
32
32
  - [x] GitHub Action example is documented.
@@ -60,5 +60,4 @@ Include:
60
60
 
61
61
  - Record a short GIF or video using [docs/DEMO_SCRIPT.md](DEMO_SCRIPT.md).
62
62
  - Regenerate demo assets with `npm run demo:capture` after visual UI changes.
63
- - Apply the repository description and topics in GitHub after the repo is created.
64
63
  - Validate against real installed skill folders once a public skill archive or local ClawHub install is available.
@@ -23,7 +23,7 @@ Provider: GitHub Actions
23
23
  Organization or user: denial-web
24
24
  Repository: clawguard
25
25
  Workflow filename: publish.yml
26
- Environment name: leave blank
26
+ Environment name: blank
27
27
  ```
28
28
 
29
29
  After the trusted publisher is connected, publish from GitHub Actions:
@@ -62,5 +62,13 @@ The release event will trigger `.github/workflows/publish.yml`.
62
62
  After publishing, test the package from npm:
63
63
 
64
64
  ```bash
65
+ cd /private/tmp
65
66
  npx @denial-web/clawguard scan examples/risky-skill
66
67
  ```
68
+
69
+ When testing from outside the repository, point the scan command at a real skill path. For example:
70
+
71
+ ```bash
72
+ cd /private/tmp
73
+ npx @denial-web/clawguard scan /Users/hy/CascadeProjects/ClawGuard/examples/risky-skill
74
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@denial-web/clawguard",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Explainable security scanner for OpenClaw-style skills and MCP tool configs.",
5
5
  "type": "module",
6
6
  "repository": {
package/src/cli.js CHANGED
@@ -27,7 +27,7 @@ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
27
27
 
28
28
  const command = args[0];
29
29
 
30
- if (!["scan", "scan-workspace"].includes(command)) {
30
+ if (!["scan", "scan-workspace", "gate"].includes(command)) {
31
31
  console.error(`Unknown command: ${command}`);
32
32
  printHelp();
33
33
  process.exit(1);
@@ -54,15 +54,21 @@ try {
54
54
  await writeReportFile(options.htmlPath, createHtmlReport(result));
55
55
  }
56
56
 
57
- if (options.json) {
57
+ if (command === "gate") {
58
+ if (options.json) {
59
+ console.log(JSON.stringify(createGateResult(result), null, 2));
60
+ } else {
61
+ printGateResult(result, options);
62
+ }
63
+ } else if (options.json) {
58
64
  console.log(JSON.stringify(result, null, 2));
59
65
  } else {
60
66
  printHumanResult(result, options);
61
67
  }
62
68
 
63
- process.exit(shouldFail(result, options) ? 2 : 0);
69
+ process.exit(command === "gate" ? gateExitCode(result.policy.decision) : shouldFail(result, options) ? 2 : 0);
64
70
  } catch (error) {
65
- console.error(`Scan failed: ${error.message}`);
71
+ console.error(`${command === "gate" ? "Gate" : "Scan"} failed: ${error.message}`);
66
72
  process.exit(1);
67
73
  }
68
74
 
@@ -71,6 +77,7 @@ function printHelp() {
71
77
 
72
78
  Usage:
73
79
  clawguard scan <path> [--json] [--policy <preset>] [--fail-on <level>]
80
+ clawguard gate <path> [--json] [--policy <preset>]
74
81
  clawguard scan-workspace <path> [--json] [--policy <preset>]
75
82
  npm run scan -- <path>
76
83
 
@@ -90,7 +97,14 @@ Options:
90
97
  --max-file-size <size> Skip individual files larger than this size. Examples: 512kb, 1mb.
91
98
  Default: 1mb.
92
99
 
100
+ Gate exit codes:
101
+ 0 = allow
102
+ 1 = warn, manual review, sandbox required, or dual approval
103
+ 2 = block
104
+
93
105
  Examples:
106
+ npx @denial-web/clawguard gate ./skills/my-skill
107
+ npx @denial-web/clawguard gate ./skills/my-skill --policy governed
94
108
  npm run scan -- examples/risky-skill
95
109
  npm run scan -- examples/metadata-mismatch-skill --policy governed --fail-on-policy
96
110
  npm run scan -- examples/metadata-mismatch-skill --html clawguard.html
@@ -171,6 +185,87 @@ function printHumanResult(result, options) {
171
185
  }
172
186
  }
173
187
 
188
+ function printGateResult(result, options) {
189
+ const decision = result.policy.decision;
190
+ console.log(`ClawGuard gate: ${result.target}`);
191
+ console.log(`Decision: ${formatDecision(decision)}`);
192
+ console.log(`Risk: ${result.level.toUpperCase()} (${result.score}/100)`);
193
+ console.log(`Policy: ${result.policy.preset}`);
194
+ console.log(`Exit code: ${gateExitCode(decision)}`);
195
+ console.log(`Reason: ${result.policy.reason}`);
196
+
197
+ if (result.configPath) {
198
+ console.log(`Config: ${result.configPath}`);
199
+ }
200
+
201
+ if (result.policy.requiredActions.length > 0) {
202
+ console.log(`Required actions: ${result.policy.requiredActions.join(", ")}`);
203
+ }
204
+
205
+ if (result.findings.length > 0) {
206
+ console.log(`Findings: ${result.findings.length}`);
207
+ const topFindings = result.findings.slice(0, 5);
208
+ for (const finding of topFindings) {
209
+ console.log(`- [${finding.severity.toUpperCase()}] ${finding.title}`);
210
+ console.log(` ${finding.file}:${finding.line}`);
211
+ }
212
+
213
+ if (result.findings.length > topFindings.length) {
214
+ console.log(`- ${result.findings.length - topFindings.length} more finding(s). Run scan for full details.`);
215
+ }
216
+ }
217
+
218
+ if (decision === "allow") {
219
+ console.log("\nGate result: safe to continue under the selected policy.");
220
+ } else if (decision === "block") {
221
+ console.log("\nGate result: block install or trust until reviewed.");
222
+ } else {
223
+ console.log("\nGate result: pause before install or trust.");
224
+ }
225
+ }
226
+
227
+ function createGateResult(result) {
228
+ return {
229
+ target: result.target,
230
+ decision: result.policy.decision,
231
+ exitCode: gateExitCode(result.policy.decision),
232
+ risk: {
233
+ level: result.level,
234
+ score: result.score
235
+ },
236
+ policy: {
237
+ preset: result.policy.preset,
238
+ reason: result.policy.reason,
239
+ requiredActions: result.policy.requiredActions
240
+ },
241
+ summary: result.summary,
242
+ findings: result.findings.map((finding) => ({
243
+ ruleId: finding.ruleId,
244
+ severity: finding.severity,
245
+ title: finding.title,
246
+ file: finding.file,
247
+ line: finding.line,
248
+ recommendation: finding.recommendation
249
+ }))
250
+ };
251
+ }
252
+
253
+ function formatDecision(decision) {
254
+ return decision.replaceAll("_", " ").toUpperCase();
255
+ }
256
+
257
+ function gateExitCode(decision) {
258
+ if (decision === "allow") {
259
+ return 0;
260
+ }
261
+
262
+ if (decision === "block") {
263
+ return 2;
264
+ }
265
+
266
+ return 1;
267
+ }
268
+
174
269
  function parseOptions(values) {
175
270
  const options = {
176
271
  json: false,
@@ -1 +0,0 @@
1
- export const safe = true;