shield-harness 0.1.0 → 0.3.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.
@@ -208,6 +208,84 @@ function printBasicGuide() {
208
208
  console.log(" 3. openshell sandbox start");
209
209
  }
210
210
 
211
+ // ---------------------------------------------------------------------------
212
+ // generate-policy command
213
+ // ---------------------------------------------------------------------------
214
+
215
+ const POLICY_PROFILES = ["standard", "strict"];
216
+ const DEFAULT_POLICY_OUTPUT = path.join(
217
+ ".claude",
218
+ "policies",
219
+ "openshell-generated.yaml",
220
+ );
221
+
222
+ /**
223
+ * Generate OpenShell policy YAML from permissions-spec.json.
224
+ * @param {string[]} args - CLI arguments (after "generate-policy")
225
+ */
226
+ function generatePolicy(args) {
227
+ // Parse --output
228
+ let output = DEFAULT_POLICY_OUTPUT;
229
+ const outputIdx = args.indexOf("--output");
230
+ if (outputIdx !== -1 && args[outputIdx + 1]) {
231
+ output = args[outputIdx + 1];
232
+ }
233
+
234
+ // Parse --profile
235
+ let profile = "standard";
236
+ const profileIdx = args.indexOf("--profile");
237
+ if (profileIdx !== -1 && args[profileIdx + 1]) {
238
+ profile = args[profileIdx + 1];
239
+ if (!POLICY_PROFILES.includes(profile)) {
240
+ console.error(`Unknown profile: ${profile}`);
241
+ console.error(`Available profiles: ${POLICY_PROFILES.join(", ")}`);
242
+ process.exit(1);
243
+ }
244
+ }
245
+
246
+ // Read permissions-spec.json
247
+ const specPath = path.join(process.cwd(), ".claude", "permissions-spec.json");
248
+ if (!fs.existsSync(specPath)) {
249
+ console.error("permissions-spec.json not found at: " + specPath);
250
+ console.error("Run 'npx shield-harness init' first.");
251
+ process.exit(1);
252
+ }
253
+
254
+ let spec;
255
+ try {
256
+ spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
257
+ } catch (err) {
258
+ console.error("Failed to parse permissions-spec.json: " + err.message);
259
+ process.exit(1);
260
+ }
261
+
262
+ // Generate YAML
263
+ let yaml;
264
+ try {
265
+ const {
266
+ generatePolicyYaml,
267
+ } = require("../.claude/hooks/lib/tier-policy-gen");
268
+ yaml = generatePolicyYaml(spec, { profile });
269
+ } catch (err) {
270
+ console.error("Failed to generate policy: " + err.message);
271
+ process.exit(1);
272
+ }
273
+
274
+ // Write output
275
+ const outputPath = path.resolve(process.cwd(), output);
276
+ const outputDir = path.dirname(outputPath);
277
+ if (!fs.existsSync(outputDir)) {
278
+ fs.mkdirSync(outputDir, { recursive: true });
279
+ }
280
+ fs.writeFileSync(outputPath, yaml);
281
+
282
+ console.log(`Policy generated successfully (profile: ${profile}).`);
283
+ console.log(` Output: ${output}`);
284
+ console.log("");
285
+ console.log("Usage:");
286
+ console.log(` openshell sandbox create --policy ${output} -- claude`);
287
+ }
288
+
211
289
  // ---------------------------------------------------------------------------
212
290
  // CLI
213
291
  // ---------------------------------------------------------------------------
@@ -227,12 +305,17 @@ if (command === "init") {
227
305
  }
228
306
  }
229
307
  init(profile);
308
+ } else if (command === "generate-policy") {
309
+ generatePolicy(args);
230
310
  } else {
231
311
  const pkg = require("../package.json");
232
312
  console.log(`Shield Harness v${pkg.version}`);
233
313
  console.log("");
234
314
  console.log("Usage:");
235
315
  console.log(" npx shield-harness init [--profile minimal|standard|strict]");
316
+ console.log(
317
+ " npx shield-harness generate-policy [--output <path>] [--profile standard|strict]",
318
+ );
236
319
  console.log("");
237
320
  console.log("Profiles:");
238
321
  console.log(" minimal — Minimal config, approval-free");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shield-harness",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Security harness for Claude Code — hooks-driven, zero-hassle defense",
5
5
  "bin": {
6
6
  "shield-harness": "./bin/shield-harness.js"
@@ -10,6 +10,7 @@
10
10
  ".claude/patterns/",
11
11
  ".claude/policies/",
12
12
  ".claude/rules/",
13
+ ".claude/permissions-spec.json",
13
14
  "bin/"
14
15
  ],
15
16
  "scripts": {
@@ -21,7 +22,12 @@
21
22
  "test:boundary": "node --test tests/data-boundary-evasion.test.js",
22
23
  "test:output": "node --test tests/output-security.test.js",
23
24
  "test:ocsf": "node --test tests/ocsf-mapper.test.js",
24
- "test:policy-compat": "node --test tests/policy-compat.test.js"
25
+ "test:policy-compat": "node --test tests/policy-compat.test.js",
26
+ "test:permissions": "node --test tests/permissions-alignment.test.js",
27
+ "test:openshell-detect": "node --test tests/openshell-detect.test.js",
28
+ "test:openshell-evidence": "node --test tests/openshell-evidence.test.js",
29
+ "test:tier-policy": "node --test tests/tier-policy-gen.test.js",
30
+ "test:policy-effectiveness": "node --test tests/policy-effectiveness.test.js"
25
31
  },
26
32
  "keywords": [
27
33
  "claude-code",