trustdex 0.7.0 → 0.9.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.
- package/README.ko.md +71 -8
- package/README.md +75 -8
- package/bin/trustdex.mjs +204 -11
- package/docs/ARCHITECTURE.ko.md +10 -2
- package/docs/ARCHITECTURE.md +15 -4
- package/docs/CLAUDE.ko.md +47 -2
- package/docs/CLAUDE.md +54 -5
- package/docs/CODEX.ko.md +49 -5
- package/docs/CODEX.md +59 -11
- package/docs/DEFENSIVE_USE_CASE.ko.md +8 -2
- package/docs/DEFENSIVE_USE_CASE.md +11 -3
- package/docs/EVALUATION.ko.md +29 -1
- package/docs/EVALUATION.md +29 -1
- package/docs/ROADMAP.ko.md +7 -4
- package/docs/ROADMAP.md +7 -4
- package/docs/THREAT_MODEL.ko.md +7 -1
- package/docs/THREAT_MODEL.md +7 -1
- package/examples/adversarial/README.ko.md +2 -0
- package/examples/adversarial/README.md +2 -0
- package/examples/adversarial/bindings/README.ko.md +24 -0
- package/examples/adversarial/bindings/README.md +25 -0
- package/examples/adversarial/bindings/claude.mcp.json +12 -0
- package/examples/adversarial/bindings/claude.settings.json +9 -0
- package/examples/adversarial/bindings/codex.toml +9 -0
- package/examples/adversarial/bindings/expected.json +15 -0
- package/examples/adversarial/bindings/trust-store.json +15 -0
- package/package.json +3 -3
- package/schemas/permission-posture-diff-v2.schema.json +37 -0
- package/schemas/permission-posture-v2.schema.json +117 -0
- package/schemas/tool-permission-bindings-diff-v1.schema.json +70 -0
- package/schemas/tool-permission-bindings-v1.schema.json +94 -0
- package/src/bindings.mjs +354 -0
- package/src/claude-settings.mjs +130 -0
- package/src/codex-settings.mjs +81 -3
- package/src/posture.mjs +69 -8
package/README.ko.md
CHANGED
|
@@ -70,6 +70,7 @@ TrustDex는 이름, 스타 수 또는 브랜딩만으로 "공식" 여부를 추
|
|
|
70
70
|
- 지원하지 않는 Codex MCP 키와 하위 섹션을 발견하면 안전하게 실패
|
|
71
71
|
- 사용자가 제공한 패키지 바이트를 npm SRI 또는 MCP Registry SHA-256 메타데이터와 대조해 검증
|
|
72
72
|
- 무결성 기반 신뢰 증거를 설정된 패키지 버전에 연결하고 불일치 차단
|
|
73
|
+
- 각 Claude/Codex MCP 소스의 결정·출처 상태를 도구 이름이나 규칙 값 없이 자동 도구 권한과 연결
|
|
73
74
|
|
|
74
75
|
## 호환성
|
|
75
76
|
|
|
@@ -82,8 +83,8 @@ Node.js 20 이상이 필요합니다.
|
|
|
82
83
|
npm에서 직접 실행:
|
|
83
84
|
|
|
84
85
|
```bash
|
|
85
|
-
npx trustdex@0.
|
|
86
|
-
npx trustdex@0.
|
|
86
|
+
npx trustdex@0.9.0 --help
|
|
87
|
+
npx trustdex@0.9.0 inspect ./mcp.json --pack strict --policy ./trustdex.policy.json
|
|
87
88
|
```
|
|
88
89
|
|
|
89
90
|
또는 소스 체크아웃에서 작업:
|
|
@@ -179,7 +180,17 @@ node ./bin/trustdex.mjs inspect-codex-settings \
|
|
|
179
180
|
--pack strict
|
|
180
181
|
```
|
|
181
182
|
|
|
182
|
-
이 명령은 승인 정책, 샌드박스 종류, 네트워크 접근, 추가 쓰기 가능 루트 개수, 웹 검색 모드 및 명시적인 서브에이전트 활성화를 보고합니다. 쓰기 가능 경로나 관련 없는 설정의 값은 보관하지
|
|
183
|
+
이 명령은 승인 정책, 샌드박스 종류, 네트워크 접근, 추가 쓰기 가능 루트 개수, 웹 검색 모드 및 명시적인 서브에이전트 활성화를 보고합니다. 쓰기 가능 경로나 관련 없는 설정의 값은 보관하지 않습니다. 문서화된 병합 우선순위를 검사하려면 활성 소스를 명시적으로 제공하세요. `--project`는 저장소 루트에서 현재 디렉터리 방향으로 반복합니다.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
node ./bin/trustdex.mjs inspect-codex-settings-stack \
|
|
187
|
+
--system ./review/system.toml \
|
|
188
|
+
--user ./review/user.toml \
|
|
189
|
+
--project ./review/root-project.toml \
|
|
190
|
+
--project ./review/closest-project.toml \
|
|
191
|
+
--cli ./review/cli-overrides.toml \
|
|
192
|
+
--pack strict
|
|
193
|
+
```
|
|
183
194
|
|
|
184
195
|
단계별 게이트 워크플로와 이 프로젝트가 자체 검토 과정에서 Codex를 사용하는 방법은 [Codex에서 TrustDex 사용하기](docs/CODEX.ko.md)를 참고하세요.
|
|
185
196
|
|
|
@@ -193,7 +204,7 @@ node ./bin/trustdex.mjs gate-claude ./.mcp.json --pack strict --out .trustdex/cl
|
|
|
193
204
|
claude --strict-mcp-config --mcp-config .trustdex/claude-mcp.json
|
|
194
205
|
```
|
|
195
206
|
|
|
196
|
-
Claude를 시작하기 전에 게이트의 결과를 확인하세요. 기본적으로 `ALLOW` 항목만 노출되며, `ASK` 항목에는 검토가 필요합니다. 어댑터는 검사할 수 없는 설정을 조용히 신뢰하지 않고 거부합니다. 이 명령은 npm 0.5.0 이상과 소스 체크아웃에서 사용할 수 있습니다. 게시된 CLI를 실행하려면 `node ./bin/trustdex.mjs` 대신 `npx trustdex@0.
|
|
207
|
+
Claude를 시작하기 전에 게이트의 결과를 확인하세요. 기본적으로 `ALLOW` 항목만 노출되며, `ASK` 항목에는 검토가 필요합니다. 어댑터는 검사할 수 없는 설정을 조용히 신뢰하지 않고 거부합니다. 이 명령은 npm 0.5.0 이상과 소스 체크아웃에서 사용할 수 있습니다. 게시된 CLI를 실행하려면 `node ./bin/trustdex.mjs` 대신 `npx trustdex@0.9.0`을 사용하세요.
|
|
197
208
|
|
|
198
209
|
지원되는 설정, PowerShell 오류 처리, 서명된 검토 및 Claude Desktop 워크플로는 [Claude에서 TrustDex 사용하기](docs/CLAUDE.ko.md)를 참고하세요.
|
|
199
210
|
|
|
@@ -205,7 +216,19 @@ node ./bin/trustdex.mjs inspect-claude-settings \
|
|
|
205
216
|
--pack strict
|
|
206
217
|
```
|
|
207
218
|
|
|
208
|
-
이 명령은 구조적인 기능 증거만 보고합니다. 권한 지정자, 디렉터리 값, 훅 명령, 도메인, 자격 증명 도우미 값 또는 환경 값을 출력하거나 지문에 포함하지 않습니다.
|
|
219
|
+
이 명령은 구조적인 기능 증거만 보고합니다. 권한 지정자, 디렉터리 값, 훅 명령, 도메인, 자격 증명 도우미 값 또는 환경 값을 출력하거나 지문에 포함하지 않습니다. 문서화된 파일 우선순위와 목록 병합을 계산하려면 소스를 명시적으로 제공하세요.
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
node ./bin/trustdex.mjs inspect-claude-settings-stack \
|
|
223
|
+
--user ./review/user.settings.json \
|
|
224
|
+
--project ./.claude/settings.json \
|
|
225
|
+
--local ./.claude/settings.local.json \
|
|
226
|
+
--session ./review/session.settings.json \
|
|
227
|
+
--managed ./review/managed-settings.json \
|
|
228
|
+
--pack strict
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
스택 검사는 여전히 정적 검토 도구이며 런타임 샌드박스가 아닙니다. 파일, 환경 변수 재정의 또는 조직 정책을 자동으로 찾지 않으며, 전달된 소스만 평가합니다.
|
|
209
232
|
|
|
210
233
|
## 권한 상태 드리프트
|
|
211
234
|
|
|
@@ -223,6 +246,13 @@ node ./bin/trustdex.mjs snapshot-codex-settings \
|
|
|
223
246
|
--pack strict \
|
|
224
247
|
--out .trustdex/codex-posture.json
|
|
225
248
|
|
|
249
|
+
node ./bin/trustdex.mjs snapshot-claude-settings-stack \
|
|
250
|
+
--user ./review/user.settings.json \
|
|
251
|
+
--project ./.claude/settings.json \
|
|
252
|
+
--managed ./review/managed-settings.json \
|
|
253
|
+
--pack strict \
|
|
254
|
+
--out .trustdex/claude-stack-posture.json
|
|
255
|
+
|
|
226
256
|
node ./bin/trustdex.mjs diff-permissions \
|
|
227
257
|
.trustdex/approved-posture.json \
|
|
228
258
|
.trustdex/current-posture.json \
|
|
@@ -240,9 +270,42 @@ node ./bin/trustdex.mjs diff-permissions \
|
|
|
240
270
|
기계 소비자는 `--json` 출력을
|
|
241
271
|
[`schemas/permission-posture-v1.schema.json`](schemas/permission-posture-v1.schema.json)과
|
|
242
272
|
[`schemas/permission-posture-diff-v1.schema.json`](schemas/permission-posture-diff-v1.schema.json)으로
|
|
243
|
-
검증할 수 있습니다.
|
|
273
|
+
검증할 수 있습니다. 병합 소스 스냅샷과 차이는
|
|
274
|
+
[`schemas/permission-posture-v2.schema.json`](schemas/permission-posture-v2.schema.json)과
|
|
275
|
+
[`schemas/permission-posture-diff-v2.schema.json`](schemas/permission-posture-diff-v2.schema.json)을
|
|
276
|
+
사용합니다. 스키마가 바뀌면 새로운 정수 `schemaVersion`을 사용하며 기존
|
|
244
277
|
필드의 의미를 조용히 바꾸지 않습니다.
|
|
245
278
|
|
|
279
|
+
## 도구 출처와 자동 권한 연결
|
|
280
|
+
|
|
281
|
+
MCP 소스와 해당 소스에 부여된 자동 권한을 하나의 값 없는 기록으로 검토합니다.
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
node ./bin/trustdex.mjs snapshot-claude-bindings ./.mcp.json \
|
|
285
|
+
--settings ./.claude/settings.json \
|
|
286
|
+
--trust-store ./trust-store.json \
|
|
287
|
+
--out .trustdex/claude-bindings.json
|
|
288
|
+
|
|
289
|
+
node ./bin/trustdex.mjs snapshot-codex-bindings ~/.codex/config.toml \
|
|
290
|
+
--trust-store ./trust-store.json \
|
|
291
|
+
--out .trustdex/codex-bindings.json
|
|
292
|
+
|
|
293
|
+
node ./bin/trustdex.mjs diff-bindings \
|
|
294
|
+
.trustdex/approved-bindings.json \
|
|
295
|
+
.trustdex/current-bindings.json \
|
|
296
|
+
--json
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Claude에서는 `--settings` 대신 스택 소스 플래그를 사용할 수 있습니다. 범위가
|
|
300
|
+
제한된 권한은 MCP 소스가 `ALLOW`일 때만 `bound`가 될 수 있습니다. 와일드카드/전체
|
|
301
|
+
도구 권한, ASK 소스, 출처 변경, 일치하지 않는 규칙 및 모호한 서버 이름 일치는
|
|
302
|
+
재검토 또는 차단 대상입니다. Codex의 `default_tools_approval_mode = "approve"`는
|
|
303
|
+
전체 도구 권한으로 취급합니다. 보고서는 서버 이름과 구조적 개수만 보관하고
|
|
304
|
+
엔드포인트 경로, 권한 지정자 및 도구 이름은 제외합니다.
|
|
305
|
+
[`schemas/tool-permission-bindings-v1.schema.json`](schemas/tool-permission-bindings-v1.schema.json)과
|
|
306
|
+
[`schemas/tool-permission-bindings-diff-v1.schema.json`](schemas/tool-permission-bindings-diff-v1.schema.json)으로
|
|
307
|
+
검증할 수 있습니다. 이는 검토 증거이며 런타임 권한 강제 기능이 아닙니다.
|
|
308
|
+
|
|
246
309
|
## 온라인 출처 관찰
|
|
247
310
|
|
|
248
311
|
일반 검사는 계속 로컬에서만 수행됩니다. 다음 명령은 명시적으로 실행할 때만 네트워크 조회를 수행합니다.
|
|
@@ -388,7 +451,7 @@ node ./bin/trustdex.mjs verify .trustdex/trust-record.json \
|
|
|
388
451
|
```yaml
|
|
389
452
|
- uses: actions/checkout@v4
|
|
390
453
|
|
|
391
|
-
- uses: grigent/trustdex@v0.
|
|
454
|
+
- uses: grigent/trustdex@v0.9.0
|
|
392
455
|
with:
|
|
393
456
|
config: ./mcp.json
|
|
394
457
|
pack: official-first
|
|
@@ -410,7 +473,7 @@ node ./bin/trustdex.mjs verify .trustdex/trust-record.json \
|
|
|
410
473
|
|
|
411
474
|
## 로드맵
|
|
412
475
|
|
|
413
|
-
공개 로드맵은 [docs/ROADMAP.ko.md](docs/ROADMAP.ko.md)에서 관리합니다. 단기 작업은
|
|
476
|
+
공개 로드맵은 [docs/ROADMAP.ko.md](docs/ROADMAP.ko.md)에서 관리합니다. 단기 작업은 실제 런타임 증거, 추가 에이전트 런타임 어댑터, 재현 가능한 통제 및 실제 파일럿 피드백에 중점을 둡니다. 로드맵 항목은 계획이며 약속이 아닙니다.
|
|
414
477
|
|
|
415
478
|
## 보안
|
|
416
479
|
|
package/README.md
CHANGED
|
@@ -70,6 +70,7 @@ TrustDex deliberately does not infer "official" status from names, stars, or bra
|
|
|
70
70
|
- fail closed on unsupported Codex MCP keys and subsections
|
|
71
71
|
- verify user-supplied package bytes against npm SRI or MCP Registry SHA-256 metadata
|
|
72
72
|
- bind integrity-backed trust evidence to the configured package version and block mismatches
|
|
73
|
+
- bind each Claude/Codex MCP source decision and provenance state to its automatic tool grant without retaining tool names or rule values
|
|
73
74
|
|
|
74
75
|
## Compatibility
|
|
75
76
|
|
|
@@ -82,8 +83,8 @@ Requires Node.js 20+.
|
|
|
82
83
|
Run directly from npm:
|
|
83
84
|
|
|
84
85
|
```bash
|
|
85
|
-
npx trustdex@0.
|
|
86
|
-
npx trustdex@0.
|
|
86
|
+
npx trustdex@0.9.0 --help
|
|
87
|
+
npx trustdex@0.9.0 inspect ./mcp.json --pack strict --policy ./trustdex.policy.json
|
|
87
88
|
```
|
|
88
89
|
|
|
89
90
|
Or work from a source checkout:
|
|
@@ -181,8 +182,19 @@ node ./bin/trustdex.mjs inspect-codex-settings \
|
|
|
181
182
|
|
|
182
183
|
This reports approval policy, sandbox class, network access, additional writable-root
|
|
183
184
|
count, web-search mode, and explicit subagent enablement. It does not retain writable
|
|
184
|
-
paths or values from unrelated settings
|
|
185
|
-
|
|
185
|
+
paths or values from unrelated settings. To inspect the documented merged precedence,
|
|
186
|
+
provide each active source explicitly; repeat `--project` from repository root toward
|
|
187
|
+
the current directory:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
node ./bin/trustdex.mjs inspect-codex-settings-stack \
|
|
191
|
+
--system ./review/system.toml \
|
|
192
|
+
--user ./review/user.toml \
|
|
193
|
+
--project ./review/root-project.toml \
|
|
194
|
+
--project ./review/closest-project.toml \
|
|
195
|
+
--cli ./review/cli-overrides.toml \
|
|
196
|
+
--pack strict
|
|
197
|
+
```
|
|
186
198
|
|
|
187
199
|
See [Using TrustDex with Codex](docs/CODEX.md) for a step-by-step gating workflow and for how this project uses Codex in its own review process.
|
|
188
200
|
|
|
@@ -201,7 +213,7 @@ claude --strict-mcp-config --mcp-config .trustdex/claude-mcp.json
|
|
|
201
213
|
Check the gate's result before starting Claude. Only `ALLOW` entries are exposed by
|
|
202
214
|
default; `ASK` entries require review. The adapter rejects settings it cannot
|
|
203
215
|
inspect instead of silently trusting them. These commands are available in npm 0.5.0 and later, and from a source checkout.
|
|
204
|
-
Use `npx trustdex@0.
|
|
216
|
+
Use `npx trustdex@0.9.0` in place of `node ./bin/trustdex.mjs` to run the published CLI.
|
|
205
217
|
|
|
206
218
|
See [Using TrustDex with Claude](docs/CLAUDE.md) for supported settings, PowerShell
|
|
207
219
|
error handling, signed review, and the Claude Desktop workflow.
|
|
@@ -217,7 +229,22 @@ node ./bin/trustdex.mjs inspect-claude-settings \
|
|
|
217
229
|
|
|
218
230
|
The command reports structural capability evidence only. It does not print or fingerprint
|
|
219
231
|
permission specifiers, directory values, hook commands, domains, credential-helper values,
|
|
220
|
-
or environment values.
|
|
232
|
+
or environment values. To calculate the documented file precedence and list merging, pass
|
|
233
|
+
the sources explicitly:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
node ./bin/trustdex.mjs inspect-claude-settings-stack \
|
|
237
|
+
--user ./review/user.settings.json \
|
|
238
|
+
--project ./.claude/settings.json \
|
|
239
|
+
--local ./.claude/settings.local.json \
|
|
240
|
+
--session ./review/session.settings.json \
|
|
241
|
+
--managed ./review/managed-settings.json \
|
|
242
|
+
--pack strict
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The stack inspector remains a static review aid, not a runtime sandbox. It does not discover
|
|
246
|
+
files, environment overrides, or organization policy automatically; only supplied sources
|
|
247
|
+
are evaluated.
|
|
221
248
|
|
|
222
249
|
## Permission posture drift
|
|
223
250
|
|
|
@@ -235,6 +262,13 @@ node ./bin/trustdex.mjs snapshot-codex-settings \
|
|
|
235
262
|
--pack strict \
|
|
236
263
|
--out .trustdex/codex-posture.json
|
|
237
264
|
|
|
265
|
+
node ./bin/trustdex.mjs snapshot-claude-settings-stack \
|
|
266
|
+
--user ./review/user.settings.json \
|
|
267
|
+
--project ./.claude/settings.json \
|
|
268
|
+
--managed ./review/managed-settings.json \
|
|
269
|
+
--pack strict \
|
|
270
|
+
--out .trustdex/claude-stack-posture.json
|
|
271
|
+
|
|
238
272
|
node ./bin/trustdex.mjs diff-permissions \
|
|
239
273
|
.trustdex/approved-posture.json \
|
|
240
274
|
.trustdex/current-posture.json \
|
|
@@ -253,8 +287,41 @@ enforcement.
|
|
|
253
287
|
Machine consumers can validate `--json` output against
|
|
254
288
|
[`schemas/permission-posture-v1.schema.json`](schemas/permission-posture-v1.schema.json)
|
|
255
289
|
and [`schemas/permission-posture-diff-v1.schema.json`](schemas/permission-posture-diff-v1.schema.json).
|
|
290
|
+
Merged-source snapshots and their diffs use
|
|
291
|
+
[`schemas/permission-posture-v2.schema.json`](schemas/permission-posture-v2.schema.json)
|
|
292
|
+
and [`schemas/permission-posture-diff-v2.schema.json`](schemas/permission-posture-diff-v2.schema.json).
|
|
256
293
|
Schema changes require a new integer `schemaVersion`; fields are not silently repurposed.
|
|
257
294
|
|
|
295
|
+
## Tool provenance and automatic permission bindings
|
|
296
|
+
|
|
297
|
+
Review an MCP source and the automatic permission granted to it as one value-free record:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
node ./bin/trustdex.mjs snapshot-claude-bindings ./.mcp.json \
|
|
301
|
+
--settings ./.claude/settings.json \
|
|
302
|
+
--trust-store ./trust-store.json \
|
|
303
|
+
--out .trustdex/claude-bindings.json
|
|
304
|
+
|
|
305
|
+
node ./bin/trustdex.mjs snapshot-codex-bindings ~/.codex/config.toml \
|
|
306
|
+
--trust-store ./trust-store.json \
|
|
307
|
+
--out .trustdex/codex-bindings.json
|
|
308
|
+
|
|
309
|
+
node ./bin/trustdex.mjs diff-bindings \
|
|
310
|
+
.trustdex/approved-bindings.json \
|
|
311
|
+
.trustdex/current-bindings.json \
|
|
312
|
+
--json
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Claude stack source flags can replace `--settings`. A scoped grant can be `bound` only
|
|
316
|
+
when its MCP source is `ALLOW`; wildcard/all-tool grants, ASK sources, changed
|
|
317
|
+
provenance, unmatched rules, and ambiguous server-name matches require review or are
|
|
318
|
+
blocked. Codex `default_tools_approval_mode = "approve"` is treated as an all-tool
|
|
319
|
+
grant. Reports retain server names and structural counts, but omit endpoint paths,
|
|
320
|
+
permission specifiers, and tool names. Validate them with
|
|
321
|
+
[`schemas/tool-permission-bindings-v1.schema.json`](schemas/tool-permission-bindings-v1.schema.json)
|
|
322
|
+
and [`schemas/tool-permission-bindings-diff-v1.schema.json`](schemas/tool-permission-bindings-diff-v1.schema.json).
|
|
323
|
+
This is review evidence, not runtime permission enforcement.
|
|
324
|
+
|
|
258
325
|
## Online provenance observations
|
|
259
326
|
|
|
260
327
|
Normal inspection remains local-only. These commands perform an explicit network lookup only when invoked:
|
|
@@ -400,7 +467,7 @@ The private key should never be committed.
|
|
|
400
467
|
```yaml
|
|
401
468
|
- uses: actions/checkout@v4
|
|
402
469
|
|
|
403
|
-
- uses: grigent/trustdex@v0.
|
|
470
|
+
- uses: grigent/trustdex@v0.9.0
|
|
404
471
|
with:
|
|
405
472
|
config: ./mcp.json
|
|
406
473
|
pack: official-first
|
|
@@ -422,7 +489,7 @@ For production CI, pin the action to a reviewed commit SHA rather than a moving
|
|
|
422
489
|
|
|
423
490
|
## Roadmap
|
|
424
491
|
|
|
425
|
-
The public roadmap is maintained in [docs/ROADMAP.md](docs/ROADMAP.md). Near-term work focuses on
|
|
492
|
+
The public roadmap is maintained in [docs/ROADMAP.md](docs/ROADMAP.md). Near-term work focuses on effective-runtime evidence, additional agent-runtime adapters, reproducible controls, and real-world pilot feedback. Roadmap items are intentions, not promises.
|
|
426
493
|
|
|
427
494
|
## Security
|
|
428
495
|
|
package/bin/trustdex.mjs
CHANGED
|
@@ -6,9 +6,13 @@ import process from 'node:process';
|
|
|
6
6
|
|
|
7
7
|
import { inspectMcpConfig } from '../src/inspect.mjs';
|
|
8
8
|
import { parseCodexMcpToml, gateCodexToml } from '../src/codex-config.mjs';
|
|
9
|
-
import { inspectCodexSettingsText } from '../src/codex-settings.mjs';
|
|
9
|
+
import { inspectCodexSettingsStack, inspectCodexSettingsText } from '../src/codex-settings.mjs';
|
|
10
10
|
import { parseClaudeMcpConfig } from '../src/claude-config.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
inspectClaudeMcpPermissionBindings,
|
|
13
|
+
inspectClaudeSettings,
|
|
14
|
+
inspectClaudeSettingsStack
|
|
15
|
+
} from '../src/claude-settings.mjs';
|
|
12
16
|
import { inspectSkillText, inspectPluginManifest } from '../src/extensions.mjs';
|
|
13
17
|
import { evaluateAll } from '../src/policy.mjs';
|
|
14
18
|
import { getPolicyPack, mergePolicy } from '../src/policy-packs.mjs';
|
|
@@ -27,6 +31,11 @@ import {
|
|
|
27
31
|
createPermissionPostureSnapshot,
|
|
28
32
|
diffPermissionPostureSnapshots
|
|
29
33
|
} from '../src/posture.mjs';
|
|
34
|
+
import {
|
|
35
|
+
codexAutomaticGrantProjection,
|
|
36
|
+
createToolPermissionBindingSnapshot,
|
|
37
|
+
diffToolPermissionBindingSnapshots
|
|
38
|
+
} from '../src/bindings.mjs';
|
|
30
39
|
import { gateMcpConfig } from '../src/gate.mjs';
|
|
31
40
|
import { assessReview } from '../src/review.mjs';
|
|
32
41
|
import {
|
|
@@ -51,6 +60,9 @@ Usage:
|
|
|
51
60
|
[--trust-store trust-store.json] [--json]
|
|
52
61
|
trustdex inspect-codex-settings <config.toml> [--pack ...] [--policy policy.json] [--json]
|
|
53
62
|
trustdex snapshot-codex-settings <config.toml> --out posture.json [--pack ...]
|
|
63
|
+
trustdex inspect-codex-settings-stack [--system file] [--managed file] [--user file]
|
|
64
|
+
[--profile file] [--project file ...] [--cli file] [--json]
|
|
65
|
+
trustdex snapshot-codex-settings-stack [same source flags] --out posture.json
|
|
54
66
|
|
|
55
67
|
trustdex gate <mcp.json> --out gated.json [--pack ...] [--policy policy.json]
|
|
56
68
|
[--trust-store trust-store.json] [--include-ask] [--json]
|
|
@@ -60,6 +72,13 @@ Usage:
|
|
|
60
72
|
trustdex inspect-claude <.mcp.json> [--pack ...] [--policy policy.json] [--json]
|
|
61
73
|
trustdex inspect-claude-settings <settings.json> [--pack ...] [--policy policy.json] [--json]
|
|
62
74
|
trustdex snapshot-claude-settings <settings.json> --out posture.json [--pack ...]
|
|
75
|
+
trustdex inspect-claude-settings-stack [--user file] [--project file] [--local file]
|
|
76
|
+
[--session file] [--managed file] [--json]
|
|
77
|
+
trustdex snapshot-claude-settings-stack [same source flags] --out posture.json
|
|
78
|
+
trustdex snapshot-claude-bindings <.mcp.json> --settings file --out bindings.json
|
|
79
|
+
[--trust-store trust-store.json] [--pack ...]
|
|
80
|
+
trustdex snapshot-claude-bindings <.mcp.json> [Claude stack source flags]
|
|
81
|
+
--out bindings.json [--trust-store trust-store.json] [--pack ...]
|
|
63
82
|
trustdex gate-claude <.mcp.json> --out gated.json [--pack ...] [--policy policy.json]
|
|
64
83
|
trustdex snapshot-claude <.mcp.json> --out snapshot.json [--pack ...]
|
|
65
84
|
trustdex approve-claude <.mcp.json> --private key.pem --dir review [--pack ...]
|
|
@@ -86,6 +105,9 @@ Usage:
|
|
|
86
105
|
|
|
87
106
|
trustdex diff <before.json> <after.json> [--json]
|
|
88
107
|
trustdex diff-permissions <before.json> <after.json> [--json]
|
|
108
|
+
trustdex snapshot-codex-bindings <config.toml> --out bindings.json
|
|
109
|
+
[--trust-store trust-store.json] [--pack ...]
|
|
110
|
+
trustdex diff-bindings <before.json> <after.json> [--json]
|
|
89
111
|
trustdex policy <strict|official-first|development>
|
|
90
112
|
|
|
91
113
|
trustdex keygen --private trustdex-private.pem --public trustdex-public.pem
|
|
@@ -122,6 +144,17 @@ function getFlag(args, name) {
|
|
|
122
144
|
return index >= 0 ? args[index + 1] : null;
|
|
123
145
|
}
|
|
124
146
|
|
|
147
|
+
function getFlags(args, name) {
|
|
148
|
+
const values = [];
|
|
149
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
150
|
+
if (args[index] !== name) continue;
|
|
151
|
+
const value = args[index + 1];
|
|
152
|
+
if (!value || value.startsWith('--')) throw new Error(`${name} requires a file path.`);
|
|
153
|
+
values.push(value);
|
|
154
|
+
}
|
|
155
|
+
return values;
|
|
156
|
+
}
|
|
157
|
+
|
|
125
158
|
function hasFlag(args, name) {
|
|
126
159
|
return args.includes(name);
|
|
127
160
|
}
|
|
@@ -164,8 +197,8 @@ function setInspectExitCode(results) {
|
|
|
164
197
|
else if (results.some((result) => result.action === 'ask')) process.exitCode = 1;
|
|
165
198
|
}
|
|
166
199
|
|
|
167
|
-
async function evaluateMcp(configPath, args) {
|
|
168
|
-
const isClaude = args[0].endsWith('-claude');
|
|
200
|
+
async function evaluateMcp(configPath, args, options = {}) {
|
|
201
|
+
const isClaude = options.claude === true || args[0].endsWith('-claude');
|
|
169
202
|
let config;
|
|
170
203
|
try { config = await readJson(configPath); } catch (error) {
|
|
171
204
|
if (isClaude && error instanceof SyntaxError) throw new Error('Invalid Claude MCP JSON.');
|
|
@@ -225,6 +258,68 @@ async function evaluateCodexSettings(configPath, args) {
|
|
|
225
258
|
return { policy, result };
|
|
226
259
|
}
|
|
227
260
|
|
|
261
|
+
async function evaluateClaudeSettingsStack(args) {
|
|
262
|
+
const layers = [];
|
|
263
|
+
for (const scope of ['user', 'project', 'local', 'session', 'managed']) {
|
|
264
|
+
for (const file of getFlags(args, `--${scope}`)) {
|
|
265
|
+
let settings;
|
|
266
|
+
try { settings = await readJson(file); } catch (error) {
|
|
267
|
+
if (error instanceof SyntaxError) throw new Error(`Invalid Claude ${scope} settings JSON.`);
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
layers.push({ scope, settings });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!layers.length) throw new Error('Claude settings stack requires at least one source flag.');
|
|
274
|
+
const policy = await loadPolicy(args);
|
|
275
|
+
const [result] = evaluateAll([inspectClaudeSettingsStack(layers)], policy);
|
|
276
|
+
return { policy, result };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function evaluateCodexSettingsStack(args) {
|
|
280
|
+
const layers = [];
|
|
281
|
+
for (const scope of ['system', 'managed', 'user', 'profile', 'project', 'cli']) {
|
|
282
|
+
for (const file of getFlags(args, `--${scope}`)) {
|
|
283
|
+
layers.push({ scope, text: await fs.readFile(file, 'utf8') });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (!layers.length) throw new Error('Codex settings stack requires at least one source flag.');
|
|
287
|
+
const policy = await loadPolicy(args);
|
|
288
|
+
const [result] = evaluateAll([inspectCodexSettingsStack(layers)], policy);
|
|
289
|
+
return { policy, result };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function loadClaudeBindingLayers(args) {
|
|
293
|
+
const single = getFlags(args, '--settings');
|
|
294
|
+
const stackScopes = ['user', 'project', 'local', 'session', 'managed'];
|
|
295
|
+
const hasStack = stackScopes.some((scope) => getFlags(args, `--${scope}`).length);
|
|
296
|
+
if (single.length > 1 || (single.length && hasStack)) {
|
|
297
|
+
throw new Error('Claude bindings accept one --settings file or stack source flags, not both.');
|
|
298
|
+
}
|
|
299
|
+
if (single.length) {
|
|
300
|
+
let settings;
|
|
301
|
+
try { settings = await readJson(single[0]); } catch (error) {
|
|
302
|
+
if (error instanceof SyntaxError) throw new Error('Invalid Claude settings JSON.');
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
return [{ scope: 'session', settings }];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const layers = [];
|
|
309
|
+
for (const scope of stackScopes) {
|
|
310
|
+
for (const file of getFlags(args, `--${scope}`)) {
|
|
311
|
+
let settings;
|
|
312
|
+
try { settings = await readJson(file); } catch (error) {
|
|
313
|
+
if (error instanceof SyntaxError) throw new Error(`Invalid Claude ${scope} settings JSON.`);
|
|
314
|
+
throw error;
|
|
315
|
+
}
|
|
316
|
+
layers.push({ scope, settings });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (!layers.length) throw new Error('Claude bindings require --settings or stack source flags.');
|
|
320
|
+
return layers;
|
|
321
|
+
}
|
|
322
|
+
|
|
228
323
|
function printObservation(observation, asJson) {
|
|
229
324
|
if (asJson) {
|
|
230
325
|
console.log(JSON.stringify(observation, null, 2));
|
|
@@ -268,6 +363,23 @@ function printPermissionPostureDiff(diff) {
|
|
|
268
363
|
}
|
|
269
364
|
}
|
|
270
365
|
|
|
366
|
+
function printBindingDiff(diff) {
|
|
367
|
+
if (diff.status === 'unchanged') {
|
|
368
|
+
console.log('UNCHANGED: tool permission bindings match the baseline.');
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
console.log(diff.status === 'restricted'
|
|
372
|
+
? 'RESTRICTED: automatic tool permissions became more restrictive.'
|
|
373
|
+
: 'NEEDS_REVIEW: tool provenance or automatic permissions changed.');
|
|
374
|
+
for (const change of diff.changes) {
|
|
375
|
+
const subject = change.name ? `${change.name}.` : '';
|
|
376
|
+
const details = change.before !== null || change.after !== null
|
|
377
|
+
? ` (${String(change.before)} -> ${String(change.after)})`
|
|
378
|
+
: '';
|
|
379
|
+
console.log(`${change.impact.toUpperCase()} ${change.type}: ${subject}${change.field}${details}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
271
383
|
async function main() {
|
|
272
384
|
const args = process.argv.slice(2);
|
|
273
385
|
const command = args[0];
|
|
@@ -320,6 +432,13 @@ async function main() {
|
|
|
320
432
|
return;
|
|
321
433
|
}
|
|
322
434
|
|
|
435
|
+
if (command === 'inspect-claude-settings-stack') {
|
|
436
|
+
const { result } = await evaluateClaudeSettingsStack(args);
|
|
437
|
+
printResults([result], hasFlag(args, '--json'));
|
|
438
|
+
setInspectExitCode([result]);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
323
442
|
if (command === 'inspect-codex') {
|
|
324
443
|
const configPath = args[1];
|
|
325
444
|
if (!configPath) throw new Error('inspect-codex requires a path to Codex config.toml.');
|
|
@@ -338,21 +457,79 @@ async function main() {
|
|
|
338
457
|
return;
|
|
339
458
|
}
|
|
340
459
|
|
|
341
|
-
if (command === '
|
|
342
|
-
const
|
|
460
|
+
if (command === 'inspect-codex-settings-stack') {
|
|
461
|
+
const { result } = await evaluateCodexSettingsStack(args);
|
|
462
|
+
printResults([result], hasFlag(args, '--json'));
|
|
463
|
+
setInspectExitCode([result]);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (['snapshot-claude-settings', 'snapshot-codex-settings',
|
|
468
|
+
'snapshot-claude-settings-stack', 'snapshot-codex-settings-stack'].includes(command)) {
|
|
469
|
+
const isStack = command.endsWith('-stack');
|
|
470
|
+
const configPath = isStack ? null : args[1];
|
|
343
471
|
const out = getFlag(args, '--out');
|
|
344
|
-
if (!configPath || !out) {
|
|
345
|
-
throw new Error(
|
|
472
|
+
if ((!isStack && !configPath) || !out) {
|
|
473
|
+
throw new Error(isStack
|
|
474
|
+
? `${command} requires source flags and --out <posture.json>.`
|
|
475
|
+
: `${command} requires a settings path and --out <posture.json>.`);
|
|
346
476
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
477
|
+
let evaluated;
|
|
478
|
+
if (command === 'snapshot-claude-settings') evaluated = await evaluateClaudeSettings(configPath, args);
|
|
479
|
+
else if (command === 'snapshot-codex-settings') evaluated = await evaluateCodexSettings(configPath, args);
|
|
480
|
+
else if (command === 'snapshot-claude-settings-stack') evaluated = await evaluateClaudeSettingsStack(args);
|
|
481
|
+
else evaluated = await evaluateCodexSettingsStack(args);
|
|
482
|
+
const { policy, result } = evaluated;
|
|
350
483
|
const snapshot = createPermissionPostureSnapshot(result, policy);
|
|
351
484
|
await writeFileSafe(out, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
352
485
|
console.log(`Wrote ${out}\nDigest: ${snapshot.digest}`);
|
|
353
486
|
return;
|
|
354
487
|
}
|
|
355
488
|
|
|
489
|
+
if (command === 'snapshot-claude-bindings') {
|
|
490
|
+
const configPath = args[1];
|
|
491
|
+
const out = getFlag(args, '--out');
|
|
492
|
+
if (!configPath || !out) {
|
|
493
|
+
throw new Error('snapshot-claude-bindings requires <.mcp.json>, settings sources, and --out <bindings.json>.');
|
|
494
|
+
}
|
|
495
|
+
const { policy, store, results } = await evaluateMcp(configPath, args, { claude: true });
|
|
496
|
+
const projection = inspectClaudeMcpPermissionBindings(
|
|
497
|
+
await loadClaudeBindingLayers(args),
|
|
498
|
+
results.map((result) => result.name)
|
|
499
|
+
);
|
|
500
|
+
const snapshot = createToolPermissionBindingSnapshot({
|
|
501
|
+
runtime: 'claude',
|
|
502
|
+
results,
|
|
503
|
+
grants: projection.grants,
|
|
504
|
+
policy,
|
|
505
|
+
trustStore: store,
|
|
506
|
+
unboundAutomaticGrantCount: projection.unboundAllowRuleCount,
|
|
507
|
+
ambiguousAutomaticGrantCount: projection.ambiguousAllowRuleCount
|
|
508
|
+
});
|
|
509
|
+
await writeFileSafe(out, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
510
|
+
console.log(`Wrote ${out}\nStatus: ${snapshot.status}\nDigest: ${snapshot.digest}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (command === 'snapshot-codex-bindings') {
|
|
515
|
+
const configPath = args[1];
|
|
516
|
+
const out = getFlag(args, '--out');
|
|
517
|
+
if (!configPath || !out) {
|
|
518
|
+
throw new Error('snapshot-codex-bindings requires <config.toml> and --out <bindings.json>.');
|
|
519
|
+
}
|
|
520
|
+
const { policy, store, results } = await evaluateCodex(configPath, args);
|
|
521
|
+
const snapshot = createToolPermissionBindingSnapshot({
|
|
522
|
+
runtime: 'codex',
|
|
523
|
+
results,
|
|
524
|
+
grants: codexAutomaticGrantProjection(results),
|
|
525
|
+
policy,
|
|
526
|
+
trustStore: store
|
|
527
|
+
});
|
|
528
|
+
await writeFileSafe(out, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
529
|
+
console.log(`Wrote ${out}\nStatus: ${snapshot.status}\nDigest: ${snapshot.digest}`);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
|
|
356
533
|
if (command === 'diff-permissions') {
|
|
357
534
|
const beforePath = args[1];
|
|
358
535
|
const afterPath = args[2];
|
|
@@ -369,6 +546,22 @@ async function main() {
|
|
|
369
546
|
return;
|
|
370
547
|
}
|
|
371
548
|
|
|
549
|
+
if (command === 'diff-bindings') {
|
|
550
|
+
const beforePath = args[1];
|
|
551
|
+
const afterPath = args[2];
|
|
552
|
+
if (!beforePath || !afterPath) {
|
|
553
|
+
throw new Error('diff-bindings requires <before.json> <after.json>.');
|
|
554
|
+
}
|
|
555
|
+
const diff = diffToolPermissionBindingSnapshots(
|
|
556
|
+
await readJson(beforePath),
|
|
557
|
+
await readJson(afterPath)
|
|
558
|
+
);
|
|
559
|
+
if (hasFlag(args, '--json')) console.log(JSON.stringify(diff, null, 2));
|
|
560
|
+
else printBindingDiff(diff);
|
|
561
|
+
if (diff.status === 'needs-review') process.exitCode = 1;
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
372
565
|
if (command === 'gate-codex') {
|
|
373
566
|
const configPath = args[1];
|
|
374
567
|
const out = getFlag(args, '--out');
|
package/docs/ARCHITECTURE.ko.md
CHANGED
|
@@ -13,7 +13,7 @@ TrustDex는 관찰, 정책, 게이트 및 검토 증거를 분리하는 의존
|
|
|
13
13
|
3. 선택적인 신뢰 저장소 주장이 명시적인 출처 증거를 연결합니다.
|
|
14
14
|
4. 정책 엔진이 ALLOW, ASK 또는 BLOCK을 생성합니다.
|
|
15
15
|
5. 게이트가 승인된 설정만 출력합니다.
|
|
16
|
-
6. MCP 스냅샷, 권한 상태 스냅샷 및 서명된 신뢰 기록을 통해 이후 드리프트를 검토할 수 있습니다.
|
|
16
|
+
6. MCP 스냅샷, 권한 상태 스냅샷, 출처–권한 결합 스냅샷 및 서명된 신뢰 기록을 통해 이후 드리프트를 검토할 수 있습니다.
|
|
17
17
|
|
|
18
18
|
게이트가 강제 적용 경계입니다. 보고서만으로는 에이전트가 검토되지 않은 확장을 불러오는 것을 막을 수 없습니다.
|
|
19
19
|
|
|
@@ -32,6 +32,7 @@ TrustDex는 관찰, 정책, 게이트 및 검토 증거를 분리하는 의존
|
|
|
32
32
|
| `src/gate.mjs` | 승인된 MCP 항목만 출력 |
|
|
33
33
|
| `src/snapshot.mjs` | 결정론적 신뢰 관련 상태 및 드리프트 |
|
|
34
34
|
| `src/posture.mjs` | 값이 제거된 Claude/Codex 권한 상태 스냅샷 및 자율성 확대 분류 |
|
|
35
|
+
| `src/bindings.mjs` | 값이 제거된 MCP 소스/출처와 자동 도구 권한의 연결 및 드리프트 분류 |
|
|
35
36
|
| `src/trust-record.mjs` | Ed25519 검토 기록 서명 및 검증 |
|
|
36
37
|
| `src/review.mjs` | 서명된 기준선 비교 |
|
|
37
38
|
|
|
@@ -41,13 +42,20 @@ TrustDex는 관찰, 정책, 게이트 및 검토 증거를 분리하는 의존
|
|
|
41
42
|
- 비밀 값은 출력하거나 스냅샷에 저장해서는 안 됩니다.
|
|
42
43
|
- 권한 규칙 값, 쓰기 가능 루트 경로, 훅/도우미 본문 및 관련 없는 설정 값은 에이전트 설정 보고서에 보관해서는 안 됩니다.
|
|
43
44
|
- 권한 상태 스냅샷은 소스 경로와 설정 값을 제외해야 하며, 새 자율성 또는 정책 의미 변경은 검토를 요구해야 합니다.
|
|
45
|
+
- 결합 스냅샷은 권한 지정자와 도구 이름을 제외해야 하며, ASK/BLOCK 소스의 자동 권한, 와일드카드 확대, 출처 변경 또는 모호하거나 연결되지 않은 규칙을 안전한 연결로 표시해서는 안 됩니다.
|
|
44
46
|
- 알 수 없는 증거가 신뢰로 바뀌어서는 안 됩니다.
|
|
45
47
|
- 차단 신호의 심각도를 출처 정보로 낮춰서는 안 됩니다.
|
|
46
48
|
- 지원하지 않는 보안 관련 구문은 안전하게 실패해야 합니다.
|
|
47
49
|
- 네트워크 조회는 명시적으로 수행하며, 관찰은 승인이 아닙니다.
|
|
48
50
|
- ALLOW는 정책 결과이지 안전 인증이 아닙니다.
|
|
49
51
|
|
|
50
|
-
설정 검사는
|
|
52
|
+
설정 검사는 권고 기능입니다. 소스 파일 하나 또는 명시적으로 전달된 Claude/Codex 소스 스택을 읽고 지원되는 보안 필드에 대해 문서화된 우선순위를 계산할 수 있습니다. 활성 파일, 프로필, 환경 변수 재정의, 요구사항 또는 서버 전달 정책을 자동으로 찾지 않으며 보고된 정책이 실제로 활성화되었다는 것도 증명하지 않습니다. MCP 게이트는 구현된 강제 적용 경계로 유지되고, 에이전트 작업은 운영체제 및 런타임 샌드박스가 강제합니다.
|
|
53
|
+
|
|
54
|
+
결합 스냅샷은 MCP 검사/정책 결과와 명시적으로 전달된 런타임 설정에서 파싱한
|
|
55
|
+
자동 도구 권한이라는 두 정적 투영을 합성합니다. 실제 설정을 자동으로 찾거나 도구
|
|
56
|
+
호출을 가로채지 않습니다. `bound`는 관찰된 범위 제한 권한이 전달된 증거 아래에서
|
|
57
|
+
ALLOW 소스를 가리킨다는 뜻이며, 도구 구현이 안전하거나 런타임이 해당 파일을
|
|
58
|
+
로드했다는 뜻이 아닙니다.
|
|
51
59
|
|
|
52
60
|
## 의존성 정책
|
|
53
61
|
|