@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 +9 -5
- package/README.md +7 -6
- package/SELF_SERVICE_FAQ.md +3 -3
- package/dist/constraints.js +53 -1
- package/package.json +1 -1
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
|
-
-
|
|
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.
|
package/SELF_SERVICE_FAQ.md
CHANGED
|
@@ -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,
|
|
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
|
|
package/dist/constraints.js
CHANGED
|
@@ -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
|
|
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