@darkelogix/openclaw-trusted-mode 1.0.0 → 1.0.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/CHANGELOG.md CHANGED
@@ -9,8 +9,8 @@ Terminology and acronyms: [`GLOSSARY.md`](./GLOSSARY.md).
9
9
  - `CLI`: Command Line Interface
10
10
  - `CI`: Continuous Integration
11
11
 
12
- ## Unreleased
13
- - Add governed release artifacts (`SECURITY.md`, `RELEASE_v1.0.0.md`, compatibility matrix).
12
+ ## Unreleased
13
+ - Add governed release artifacts (`SECURITY.md`, `RELEASE_v1.0.0.md`, compatibility matrix).
14
14
  - Add Trusted Mode Check attestation status contract (`ENFORCED_OK`, `LOCKDOWN_ONLY`, `UNSAFE`) with JSON output.
15
15
  - Add CI gates for release artifact and changelog version discipline.
16
16
  - Add runtime certification gating (`CERTIFIED_ENFORCED` vs `LOCKDOWN_ONLY`/`UNSUPPORTED`) in plugin.
@@ -25,9 +25,13 @@ Terminology and acronyms: [`GLOSSARY.md`](./GLOSSARY.md).
25
25
  - Add generated `SECURITY_RELEASE_INDEX.md` artifact and workflow integration for release evidence traceability.
26
26
  - Add enterprise hardening options in plugin config (`toolPolicyMode`, `allowedTools`, `requireTenantId`, `allowedTenantIds`) with fail-closed validation behavior.
27
27
  - Add plugin schema/runtime contract check (`verify-plugin-schema-contract`) and CI enforcement.
28
- - Add consolidated release evidence bundling command (`bundle-release-evidence`) and release workflow artifact publication.
29
- - Add enterprise TCTP/EVTP validation matrix runner (`npm run test-pack-matrix`) against live PDP.
30
- - Add release documentation for deterministic certification proof (`decision_proof`) vs timestamped operational `outcome_event`.
28
+ - Add consolidated release evidence bundling command (`bundle-release-evidence`) and release workflow artifact publication.
29
+ - Add enterprise TCTP/EVTP validation matrix runner (`npm run test-pack-matrix`) against live PDP.
30
+ - Add release documentation for deterministic certification proof (`decision_proof`) vs timestamped operational `outcome_event`.
31
+
32
+ ## v1.0.1
33
+ - normalize constrained paths before prefix enforcement so `/tmp-evil`, traversal segments, and Windows path-prefix collisions do not bypass policy
34
+ - add regression coverage for path normalization and descendant-boundary checks
31
35
 
32
36
  ## v1.0.0
33
37
  - Add Trusted Mode Check CLI (Node) with mock PDP for CI.
package/README.md CHANGED
@@ -57,12 +57,13 @@ For governed release declaration, see [`RELEASE_v1.0.0.md`](./RELEASE_v1.0.0.md)
57
57
 
58
58
  ## What it does
59
59
 
60
- - Free standalone mode defaults to local hardening with a minimal allowlist:
61
- - `read_file`
62
- - `list_files`
63
- - `search_files`
64
- - Blocks high-risk tools such as `exec`, file writes/edits, and deletes unless you deliberately widen the policy.
65
- - Sends tool call context to a Policy Decision Point (PDP) endpoint.
60
+ - Free standalone mode defaults to local hardening with a minimal allowlist:
61
+ - `read_file`
62
+ - `list_files`
63
+ - `search_files`
64
+ - Blocks high-risk tools such as `exec`, file writes/edits, and deletes unless you deliberately widen the policy.
65
+ - Normalizes constrained paths before enforcing allowed prefixes so traversal and lookalike prefixes do not slip through.
66
+ - Sends tool call context to a Policy Decision Point (PDP) endpoint.
66
67
  - Denies execution when PDP returns a deny decision.
67
68
  - Optionally enforces returned constraints.
68
69
  - Supports fail-closed (default) or fail-open behavior.
@@ -69,9 +69,9 @@ If not loaded:
69
69
 
70
70
  If you are using standalone free mode, check these first:
71
71
 
72
- 1. Confirm `toolPolicyMode` is `ALLOWLIST_ONLY`.
73
- 2. Confirm the blocked tool is not present in `allowedTools`.
74
- 3. For shell execution, verify the runtime tool name is `exec`.
72
+ 1. Confirm `toolPolicyMode` is `ALLOWLIST_ONLY`.
73
+ 2. Confirm the blocked tool is not present in `allowedTools`.
74
+ 3. For shell execution, the runtime commonly emits `exec`; current SDE governance canonicalizes `exec`, `execute_shell`, and `run_shell_command` to the same shell policy, but verifying the observed tool id is still useful for troubleshooting.
75
75
 
76
76
  Run SDE smoke test:
77
77
 
@@ -1,6 +1,58 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.enforceConstraints = enforceConstraints;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ function normalizePathValue(value) {
9
+ const trimmed = String(value || '').trim();
10
+ if (!trimmed)
11
+ return null;
12
+ const windows = /^[a-zA-Z]:[\\/]/.test(trimmed) || trimmed.includes('\\');
13
+ const pathApi = windows ? node_path_1.default.win32 : node_path_1.default.posix;
14
+ const separator = windows ? '\\' : '/';
15
+ const root = pathApi.parse(trimmed).root;
16
+ let normalized = pathApi.normalize(trimmed);
17
+ if (windows)
18
+ normalized = normalized.replace(/\//g, '\\');
19
+ while (normalized.length > root.length &&
20
+ (normalized.endsWith('/') || normalized.endsWith('\\'))) {
21
+ normalized = normalized.slice(0, -1);
22
+ }
23
+ return {
24
+ normalized: normalized || root || separator,
25
+ root,
26
+ separator,
27
+ windows,
28
+ };
29
+ }
30
+ function isPathWithinPrefix(value, prefix) {
31
+ const normalizedValue = normalizePathValue(value);
32
+ const normalizedPrefix = normalizePathValue(prefix);
33
+ if (!normalizedValue || !normalizedPrefix)
34
+ return false;
35
+ if (normalizedValue.windows !== normalizedPrefix.windows)
36
+ return false;
37
+ const left = normalizedValue.windows
38
+ ? normalizedValue.normalized.toLowerCase()
39
+ : normalizedValue.normalized;
40
+ const right = normalizedPrefix.windows
41
+ ? normalizedPrefix.normalized.toLowerCase()
42
+ : normalizedPrefix.normalized;
43
+ if (left === right)
44
+ return true;
45
+ if (right === normalizedPrefix.root) {
46
+ return left.startsWith(right);
47
+ }
48
+ return left.startsWith(`${right}${normalizedPrefix.separator}`);
49
+ }
50
+ function matchesAllowedPrefix(key, value, prefix) {
51
+ if (key.toLowerCase().includes('path')) {
52
+ return isPathWithinPrefix(value, prefix);
53
+ }
54
+ return value.startsWith(prefix);
55
+ }
4
56
  function enforceConstraints(params, constraints) {
5
57
  if (!Array.isArray(constraints)) {
6
58
  throw new Error(`[Trusted Mode ERROR] Invalid constraints format`);
@@ -15,7 +67,7 @@ function enforceConstraints(params, constraints) {
15
67
  const value = params?.[key];
16
68
  if (typeof value !== 'string')
17
69
  continue;
18
- const ok = allowedPrefixes.some((prefix) => value.startsWith(prefix));
70
+ const ok = allowedPrefixes.some((prefix) => typeof prefix === 'string' && matchesAllowedPrefix(key, value, prefix));
19
71
  if (!ok) {
20
72
  throw new Error(`[Trusted Mode BLOCKED] Constraint violation for "${key}" (allowed prefixes: ${allowedPrefixes.join(', ')})`);
21
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkelogix/openclaw-trusted-mode",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "MIT-licensed OpenClaw Trusted Mode plugin with standalone hardening and optional SDE-backed governance",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",