clinkx 1.1.0 → 1.1.2
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 +39 -1
- package/README.md +210 -177
- package/clinkx-workflows/dist/architecture-comparison/admission.d.ts +5 -0
- package/clinkx-workflows/dist/architecture-comparison/admission.js +50 -0
- package/clinkx-workflows/dist/architecture-comparison/admission.js.map +1 -0
- package/clinkx-workflows/dist/architecture-comparison/contract.d.ts +995 -0
- package/clinkx-workflows/dist/architecture-comparison/contract.js +149 -0
- package/clinkx-workflows/dist/architecture-comparison/contract.js.map +1 -0
- package/clinkx-workflows/dist/architecture-comparison/runtime.d.ts +29 -0
- package/clinkx-workflows/dist/architecture-comparison/runtime.js +387 -0
- package/clinkx-workflows/dist/architecture-comparison/runtime.js.map +1 -0
- package/clinkx-workflows/dist/contained-file.js +1 -1
- package/clinkx-workflows/dist/contained-file.js.map +1 -1
- package/clinkx-workflows/dist/council-execution-policy.d.ts +4 -2
- package/clinkx-workflows/dist/council-execution-policy.js +5 -1
- package/clinkx-workflows/dist/council-execution-policy.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/activity-contract.d.ts +72 -72
- package/clinkx-workflows/dist/dashboard/contracts.d.ts +1564 -122
- package/clinkx-workflows/dist/dashboard/contracts.js +4 -0
- package/clinkx-workflows/dist/dashboard/contracts.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/progress-report-contract.d.ts +12 -12
- package/clinkx-workflows/dist/dashboard/progress-report-status-overlay.d.ts +8 -8
- package/clinkx-workflows/dist/dashboard/scanner.d.ts +3 -0
- package/clinkx-workflows/dist/dashboard/scanner.js +27 -0
- package/clinkx-workflows/dist/dashboard/scanner.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/session-log-contract.d.ts +48 -48
- package/clinkx-workflows/dist/dashboard/session-log-redaction.d.ts +2 -0
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js +4 -0
- package/clinkx-workflows/dist/dashboard/session-log-redaction.js.map +1 -1
- package/clinkx-workflows/dist/dashboard/verified-repair-contract.d.ts +191 -0
- package/clinkx-workflows/dist/dashboard/verified-repair-contract.js +28 -0
- package/clinkx-workflows/dist/dashboard/verified-repair-contract.js.map +1 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/index-BdpmbPps.js +115 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/style-Im5i1iAs.css +1 -0
- package/clinkx-workflows/dist/dashboard-ui/index.html +2 -2
- package/clinkx-workflows/dist/engine.d.ts +6 -0
- package/clinkx-workflows/dist/engine.js +78 -7
- package/clinkx-workflows/dist/engine.js.map +1 -1
- package/clinkx-workflows/dist/index.d.ts +3 -0
- package/clinkx-workflows/dist/index.js +3 -2
- package/clinkx-workflows/dist/index.js.map +1 -1
- package/clinkx-workflows/dist/reducers/index.d.ts +9 -1
- package/clinkx-workflows/dist/reducers/index.js +22 -0
- package/clinkx-workflows/dist/reducers/index.js.map +1 -1
- package/clinkx-workflows/dist/state.js +17 -7
- package/clinkx-workflows/dist/state.js.map +1 -1
- package/clinkx-workflows/dist/validators/architecture-comparison.d.ts +2 -0
- package/clinkx-workflows/dist/validators/architecture-comparison.js +12 -0
- package/clinkx-workflows/dist/validators/architecture-comparison.js.map +1 -0
- package/clinkx-workflows/dist/validators/index.js +4 -0
- package/clinkx-workflows/dist/validators/index.js.map +1 -1
- package/clinkx-workflows/dist/validators/verified-repair.d.ts +2 -0
- package/clinkx-workflows/dist/validators/verified-repair.js +12 -0
- package/clinkx-workflows/dist/validators/verified-repair.js.map +1 -0
- package/clinkx-workflows/dist/verification-proof.d.ts +254 -0
- package/clinkx-workflows/dist/verification-proof.js +195 -0
- package/clinkx-workflows/dist/verification-proof.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/admission.d.ts +72 -0
- package/clinkx-workflows/dist/verified-repair/admission.js +63 -0
- package/clinkx-workflows/dist/verified-repair/admission.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/contract.d.ts +1910 -0
- package/clinkx-workflows/dist/verified-repair/contract.js +127 -0
- package/clinkx-workflows/dist/verified-repair/contract.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/host.d.ts +32 -0
- package/clinkx-workflows/dist/verified-repair/host.js +2 -0
- package/clinkx-workflows/dist/verified-repair/host.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/prompts.d.ts +12 -0
- package/clinkx-workflows/dist/verified-repair/prompts.js +58 -0
- package/clinkx-workflows/dist/verified-repair/prompts.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/result.d.ts +16 -0
- package/clinkx-workflows/dist/verified-repair/result.js +102 -0
- package/clinkx-workflows/dist/verified-repair/result.js.map +1 -0
- package/clinkx-workflows/dist/verified-repair/runtime.d.ts +28 -0
- package/clinkx-workflows/dist/verified-repair/runtime.js +186 -0
- package/clinkx-workflows/dist/verified-repair/runtime.js.map +1 -0
- package/clinkx-workflows/dist/workflow-tools.d.ts +3 -0
- package/clinkx-workflows/dist/workflow-tools.js +148 -14
- package/clinkx-workflows/dist/workflow-tools.js.map +1 -1
- package/clinkx-workflows/dist/workflow-verification-contract.d.ts +539 -0
- package/clinkx-workflows/dist/workflow-verification-contract.js +52 -0
- package/clinkx-workflows/dist/workflow-verification-contract.js.map +1 -0
- package/clinkx-workflows/dist/workflow-verification.d.ts +15 -0
- package/clinkx-workflows/dist/workflow-verification.js +218 -0
- package/clinkx-workflows/dist/workflow-verification.js.map +1 -0
- package/clinkx-workflows/templates/architecture-comparison/candidate.txt +29 -0
- package/clinkx-workflows/templates/architecture-comparison/judge.txt +31 -0
- package/clinkx-workflows/templates/verified-repair/investigate.txt +20 -0
- package/clinkx-workflows/templates/verified-repair/repair.txt +11 -0
- package/clinkx-workflows/templates/verified-repair/review.txt +18 -0
- package/clinkx-workflows/workflows/architecture-comparison.yaml +133 -0
- package/clinkx-workflows/workflows/verified-repair.yaml +104 -0
- package/dist/allowed-roots.js +4 -1
- package/dist/allowed-roots.js.map +1 -1
- package/dist/codex/app-server-client.d.ts +1 -0
- package/dist/codex/app-server-client.js +3 -2
- package/dist/codex/app-server-client.js.map +1 -1
- package/dist/context-builder/diagnostics.d.ts +1 -0
- package/dist/context-builder/diagnostics.js +1 -1
- package/dist/context-builder/diagnostics.js.map +1 -1
- package/dist/context-builder/discovery.d.ts +18 -1
- package/dist/context-builder/discovery.js +69 -1
- package/dist/context-builder/discovery.js.map +1 -1
- package/dist/context-builder/handler.js +8 -1
- package/dist/context-builder/handler.js.map +1 -1
- package/dist/context-builder/lifecycle-contract.d.ts +24 -24
- package/dist/context-builder/refine-handler.js +16 -1
- package/dist/context-builder/refine-handler.js.map +1 -1
- package/dist/context-builder/secrets.d.ts +11 -0
- package/dist/context-builder/secrets.js +81 -1
- package/dist/context-builder/secrets.js.map +1 -1
- package/dist/context-builder/versions.d.ts +5 -2
- package/dist/context-builder/versions.js +5 -2
- package/dist/context-builder/versions.js.map +1 -1
- package/dist/dashboard-cli.js +10 -3
- package/dist/dashboard-cli.js.map +1 -1
- package/dist/dashboard-gateway/main.js +8 -3
- package/dist/dashboard-gateway/main.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/project-verification/contract.d.ts +537 -0
- package/dist/project-verification/contract.js +40 -0
- package/dist/project-verification/contract.js.map +1 -0
- package/dist/project-verification/files.d.ts +23 -0
- package/dist/project-verification/files.js +80 -0
- package/dist/project-verification/files.js.map +1 -0
- package/dist/project-verification/process.d.ts +7 -0
- package/dist/project-verification/process.js +115 -0
- package/dist/project-verification/process.js.map +1 -0
- package/dist/project-verification/runner.d.ts +35 -0
- package/dist/project-verification/runner.js +185 -0
- package/dist/project-verification/runner.js.map +1 -0
- package/dist/project-verification/service.d.ts +37 -0
- package/dist/project-verification/service.js +151 -0
- package/dist/project-verification/service.js.map +1 -0
- package/dist/provider-doctor.d.ts +22 -0
- package/dist/provider-doctor.js +22 -0
- package/dist/provider-doctor.js.map +1 -0
- package/dist/server.js +29 -1
- package/dist/server.js.map +1 -1
- package/dist/verification-tools.d.ts +90 -0
- package/dist/verification-tools.js +120 -0
- package/dist/verification-tools.js.map +1 -0
- package/dist/verified-repair/files.d.ts +22 -0
- package/dist/verified-repair/files.js +114 -0
- package/dist/verified-repair/files.js.map +1 -0
- package/dist/verified-repair/host.d.ts +14 -0
- package/dist/verified-repair/host.js +612 -0
- package/dist/verified-repair/host.js.map +1 -0
- package/docs/configuration.md +493 -0
- package/docs/engineering-recipes.md +415 -0
- package/docs/security.md +293 -0
- package/docs/verification/README.md +59 -0
- package/docs/verification/dashboard-real-disk.md +436 -0
- package/docs/verification/project-checks.example.json +14 -0
- package/docs/verification/project-checks.md +444 -0
- package/docs/verification/workflow-handoff.md +113 -0
- package/package.json +13 -6
- package/scripts/provider-doctor-core.mjs +364 -0
- package/scripts/provider-doctor-probe.mjs +34 -0
- package/clinkx-workflows/dist/dashboard-ui/assets/index-JPHQVtn9.js +0 -106
- package/clinkx-workflows/dist/dashboard-ui/assets/style-DOMHk-j6.css +0 -1
package/docs/security.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# ClinkX Security Model
|
|
2
|
+
|
|
3
|
+
## Core Principle
|
|
4
|
+
|
|
5
|
+
**ClinkX validates what goes IN, not what the CLI does.**
|
|
6
|
+
|
|
7
|
+
ClinkX validates and constrains the *inputs* it accepts — file paths, arguments, environment variables. It does **not** sandbox the spawned CLI process. The subprocess runs with the full permissions of the user who started the ClinkX server.
|
|
8
|
+
|
|
9
|
+
## What ClinkX Secures (Input Validation)
|
|
10
|
+
|
|
11
|
+
### Allow-roots path validation
|
|
12
|
+
|
|
13
|
+
- `CLINKX_ALLOWED_ROOTS` (comma-separated, default: `process.cwd()`) defines which filesystem paths the tool will accept as `absolute_file_paths` or `images` inputs.
|
|
14
|
+
- All paths are resolved via `realpath` — symlink escapes are blocked.
|
|
15
|
+
- Startup refuses to run from filesystem root (`/` or drive root) unless `CLINKX_ALLOWED_ROOTS` is explicitly set.
|
|
16
|
+
|
|
17
|
+
### Context builder validation
|
|
18
|
+
|
|
19
|
+
- `context_builder` accepts only roots under the current allowed roots and verifies real paths before reading.
|
|
20
|
+
- Requests must include a bounded anchor: a `focus_paths` entry or nonblank `search_terms` entry. `include_globs` only narrows scanning when combined with those anchors and does not select context by itself. A root directory by itself is not enough.
|
|
21
|
+
- Symlink escapes, broad/symlinked runs directories, parent traversal, and artifact-only runs directories are rejected or omitted.
|
|
22
|
+
- High-confidence secret paths and content are omitted before preview, search, slice, bundle, or manifest artifacts are written **only when `allow_secrets:false`**. The secret filter is non-blocking and default-on (`allow_secrets:true`) — see "Context builder secret material" below.
|
|
23
|
+
- `context_builder` is the only context-curation/filesystem-bundle surface. The public MCP surface also exposes `clink` plus workflow orchestration tools (`list_workflows`, `resume_workflow`, `run_workflow`), but it does not expose primitive filesystem read, list, search, or delete tools.
|
|
24
|
+
|
|
25
|
+
### Context builder secret material (default-on)
|
|
26
|
+
|
|
27
|
+
The `context_builder` secret filter is **non-blocking and default-on**. Under the default (`allow_secrets:true`), secret material — API keys, SSH/private keys, tokens, and secret-bearing files such as `.env`, `.pem`, `id_rsa`, and `credentials.json` — is included **verbatim, BY DESIGN**:
|
|
28
|
+
|
|
29
|
+
- in curated bundles (`bundle.md` and the candidate slices),
|
|
30
|
+
- in the curator/finalizer delegate packets, and
|
|
31
|
+
- flowing onward to council member CLIs and their upstream providers.
|
|
32
|
+
|
|
33
|
+
Secrets are needed to probe, so this is intentional. The task/prompt-string guard (`assertNoHighConfidenceSecretsInTask`) is gated by the same flag, so with `allow_secrets:true` the `task` / `cb_task` string may carry secret material.
|
|
34
|
+
|
|
35
|
+
**On-disk persistence consequence.** When secrets are allowed, they are written durably to the runs directory (`CLINKX_CONTEXT_BUILDER_RUNS_DIR`) — `bundle.md`, `slices.jsonl`, `search.jsonl`, and `inputs.snapshot.json` (the task string). In workflows the curated bundle is copied into the workflow run directory, which is **retained on disk for async (`succeeded_async`) runs** so its result stays pollable. Treat these artifacts as secret-bearing and apply manual retention/cleanup accordingly.
|
|
36
|
+
|
|
37
|
+
**Escape hatch — restore fail-closed omission/redaction.** Set any of, in precedence order (highest wins):
|
|
38
|
+
|
|
39
|
+
1. per-call `allow_secrets:false` (standalone `context_builder` / `refine_context_run`),
|
|
40
|
+
2. workflow `cb_allow_secrets:false`,
|
|
41
|
+
3. env `CLINKX_CONTEXT_ALLOW_SECRETS=false` (environment-wide; honored by both standalone and workflow paths).
|
|
42
|
+
|
|
43
|
+
The effective default when none is set is `true`.
|
|
44
|
+
|
|
45
|
+
**Caveat — workflow task-secret guard requires the preflight runner.** In workflows, the persisted-task-text guard runs via the injected context-builder runner. Under the hard preflight bypass (`CLINKX_WORKFLOWS_CONTEXT_PREFLIGHT_ENABLED=false`) no runner is injected, so the guard is inert and `cb_allow_secrets:false` does **not** gate persisted task text (`inputs.snapshot.json`) in that mode — consistent with that switch being a total context_builder bypass (bundles/delegate off).
|
|
46
|
+
|
|
47
|
+
**What allowing secrets does NOT change.** Permitting secrets into bundles does **not** leak them into logs or child process environments. The following remain redacted/enforced regardless of `allow_secrets`:
|
|
48
|
+
|
|
49
|
+
- subprocess environment-variable scrubbing (`src/env.ts`),
|
|
50
|
+
- pino / stderr **log** redaction,
|
|
51
|
+
- Elaris remote-session redaction (`src/elaris/redact.ts`),
|
|
52
|
+
- path-traversal / allowed-root / absolute-path safety.
|
|
53
|
+
|
|
54
|
+
### Unsafe args
|
|
55
|
+
|
|
56
|
+
- `unsafe_args` from adapter config are always merged with `args` at runtime.
|
|
57
|
+
- Since clink spawns CLIs non-interactively, permission-bypass flags must be present for the subprocess to function.
|
|
58
|
+
|
|
59
|
+
### Environment sanitization
|
|
60
|
+
|
|
61
|
+
- Subprocess environment starts from a minimal baseline (`PATH`, `HOME`, `USER`, `LANG`, `TMPDIR`).
|
|
62
|
+
- Additional env from adapter config is merged via `env_allowlist`.
|
|
63
|
+
- Secrets are redacted in logs.
|
|
64
|
+
|
|
65
|
+
### Result contract safety
|
|
66
|
+
|
|
67
|
+
- Only allowlisted filenames (`RESULT.md`, `RESULT.json`) are read from run directories.
|
|
68
|
+
- Files must be regular files (not symlinks) — verified via `lstat`.
|
|
69
|
+
- File `realpath` must resolve within the run directory.
|
|
70
|
+
|
|
71
|
+
### Subprocess hardening
|
|
72
|
+
|
|
73
|
+
- `shell: false` — no shell interpretation of arguments.
|
|
74
|
+
- Bounded timeouts with SIGTERM → SIGKILL escalation.
|
|
75
|
+
- Output capture with byte limits: `CLINKX_MAX_CAPTURE_BYTES` controls retained head+tail ring buffer size (falls back to `CLINKX_MAX_OUTPUT_BYTES` if not set).
|
|
76
|
+
- Process-group kill on timeout/cancellation.
|
|
77
|
+
|
|
78
|
+
### Dashboard session logs
|
|
79
|
+
|
|
80
|
+
The dashboard session log is a local, private, observability-only record, not an
|
|
81
|
+
execution or authorization channel. Workflow-call, activity, and context-run
|
|
82
|
+
lanes accept normalized events only; arbitrary provider payloads are not a
|
|
83
|
+
journal input. Before any filesystem write, the redactor applies credential
|
|
84
|
+
patterns and absolute user-home path removal independently of `allow_secrets`
|
|
85
|
+
and the tool-arguments persistence gate.
|
|
86
|
+
|
|
87
|
+
Detector classes include normalized structured keys and credential suffixes;
|
|
88
|
+
credential assignments; Authorization/Proxy-Authorization with any scheme,
|
|
89
|
+
Cookie/Set-Cookie header lines, arrays, arguments, and name/value pairs;
|
|
90
|
+
shape-based credential flags; password-bearing URL
|
|
91
|
+
userinfo; vendor token prefixes and bounded three-segment JWTs; embedded JSON
|
|
92
|
+
with shell-escaped quotes or Unicode-escaped keys; private-key signals;
|
|
93
|
+
sensitive query values; and absolute user-home paths. Regardless of program,
|
|
94
|
+
`-u/--user/--proxy-user/--http-user/-a/--auth` operands are redacted only when
|
|
95
|
+
they contain a `user:secret` colon pair; `-b/--cookie` operands only when they
|
|
96
|
+
contain `name=value`; `--password/--http-password/--proxy-password/--passwd`
|
|
97
|
+
operands always. Attached `-pSECRET` is redacted only after an unquoted
|
|
98
|
+
mysql/mariadb token in the same command segment, unless the operand is
|
|
99
|
+
port-shaped. Sensitive `NAME=value` assignment words are redacted anywhere;
|
|
100
|
+
quoted command strings (such as `bash -lc '…'`) get one bounded nested pass.
|
|
101
|
+
The accepted trade-off is over-redaction of unrelated colon-pair operands such
|
|
102
|
+
as `docker run -u 1000:1000`, while `ssh -p 22`, `docker -p 8080:80`,
|
|
103
|
+
`tar -u archive`, and `wget -b URL` stay intact.
|
|
104
|
+
Tool output text uses the same text detectors. Derived
|
|
105
|
+
summaries use sanitized values before truncation; a recognized embedded
|
|
106
|
+
sensitive fragment that cannot be safely rewritten is withheld.
|
|
107
|
+
|
|
108
|
+
`CLINKX_SESSION_LOG_TOOL_ARGUMENTS_PERSISTENCE_ENABLED` defaults off and is read
|
|
109
|
+
once per producer at creation; only exact `true` enables arguments, derived
|
|
110
|
+
summaries, and `redaction.coverage: "pattern_best_effort"`. Coverage describes
|
|
111
|
+
the method; status/count report detected matches, not cleanliness. Readers
|
|
112
|
+
always accept the extended fields. Deploy capable backend/browser readers
|
|
113
|
+
before enabling producers, and keep them during rollback until extended
|
|
114
|
+
journals age out: disabling the flag does not scrub existing bytes or restore
|
|
115
|
+
old-reader compatibility. Native projection persists nothing and uses the same
|
|
116
|
+
sanitizer independently of this flag.
|
|
117
|
+
|
|
118
|
+
Pattern redaction is exposure reduction, not a proof that content is safe.
|
|
119
|
+
Prompts, assistant output, tool summaries, errors, and reasoning may still carry
|
|
120
|
+
sensitive project or personal data. Treat the session-log root and every copied
|
|
121
|
+
value as sensitive. The authenticated UI renders literal text and provides
|
|
122
|
+
chronological, sequence-authoritative Timeline and Conversation views; logs
|
|
123
|
+
never grant replay, approval, cancellation, or other control authority.
|
|
124
|
+
|
|
125
|
+
Every lane is fenced to the exact immutable parent generation and leaf identity.
|
|
126
|
+
Reads are bounded to 500 events per page and 100,000 events per lane. Workflow
|
|
127
|
+
and activity log availability follows parent retention. Context logs currently
|
|
128
|
+
follow the parent context-run/manual lifecycle because there is no independent
|
|
129
|
+
context-run pruner; operators must include them in context-run cleanup policy.
|
|
130
|
+
|
|
131
|
+
New parents persist a private `.session-log-generation` token so producers and
|
|
132
|
+
the dashboard resolve one journal across bind mounts even when their filesystem
|
|
133
|
+
device/inode identities differ. Dashboard-local generations remain the parent
|
|
134
|
+
authorization boundary; the portable token is read only after that check. A
|
|
135
|
+
missing sidecar is legacy same-filesystem behavior, while a malformed,
|
|
136
|
+
symlinked, or substituted sidecar fails closed without scanning journal
|
|
137
|
+
directories. Retention quarantines and reverifies the exact portable generation
|
|
138
|
+
before recursive deletion. As elsewhere in the local state tree, an actively
|
|
139
|
+
hostile process running as the same OS user is outside this filesystem boundary.
|
|
140
|
+
|
|
141
|
+
### Dashboard passkey state
|
|
142
|
+
|
|
143
|
+
Passkey mode stores only the WebAuthn user handle, public credential IDs and
|
|
144
|
+
keys, signature counters, transports, labels, and timestamps. It never stores a
|
|
145
|
+
private key or biometric. The credential document is a strict, versioned JSON
|
|
146
|
+
file under `CLINKX_WORKFLOWS_DASHBOARD_CREDENTIAL_DIR` (host default:
|
|
147
|
+
`${CLINKX_WORKFLOWS_STATE_DIR}/dashboard/webauthn`; container:
|
|
148
|
+
`/data/dashboard-credentials`); the directory and file must be mode `0700` and
|
|
149
|
+
`0600`, respectively.
|
|
150
|
+
|
|
151
|
+
Writes use a synced temporary file, atomic rename, and directory sync behind a
|
|
152
|
+
portable owner-token lease with heartbeat/stale-owner recovery and a bounded
|
|
153
|
+
synchronous publication fence. This is a single-host filesystem protocol, not
|
|
154
|
+
distributed locking or absolute CAS against a process paused beyond the lease.
|
|
155
|
+
If a post-rename callback or durability operation fails, one terminal
|
|
156
|
+
`dashboard_credential_store_post_publication_failure` diagnostic is emitted and
|
|
157
|
+
mutations stay disabled until an operator investigates and restarts/reopens the
|
|
158
|
+
store. Current healthchecks intentionally do not observe that latch.
|
|
159
|
+
|
|
160
|
+
Sessions, challenges, and the one-time first-enrollment code are bounded,
|
|
161
|
+
in-memory state and therefore expire on restart. Challenge capacity is
|
|
162
|
+
partitioned into 96 login and 32 registration entries with no live eviction;
|
|
163
|
+
verification capacity is 8. Saturation fails fast with HTTP 503 `auth_busy` and
|
|
164
|
+
`Retry-After: 1`.
|
|
165
|
+
|
|
166
|
+
Localhost cookies are not port-scoped by browsers. A successful local WebAuthn
|
|
167
|
+
login therefore creates a separate 32-byte random origin proof bound to the
|
|
168
|
+
in-memory session. The local login response returns that proof to the browser,
|
|
169
|
+
which keeps it in `sessionStorage` under the exact origin (including port) and
|
|
170
|
+
sends it as `X-ClinkX-Local-Origin-Proof` on passkey status, auth, and data
|
|
171
|
+
requests. Local authenticated access requires both the `HttpOnly` session cookie
|
|
172
|
+
and a constant-time-valid proof, so replaying a cookie from another localhost
|
|
173
|
+
port is insufficient even when `Origin` is absent. The proof is never a cookie,
|
|
174
|
+
server-persisted value, or log field. Logout, invalid/expired auth state, and
|
|
175
|
+
authenticated 401 responses clear it. Same-tab reload can restore it; a browsing
|
|
176
|
+
context without it must reauthenticate. Cloud passkey behavior remains
|
|
177
|
+
cookie-only and its login response remains `{"verified":true}`.
|
|
178
|
+
|
|
179
|
+
The first enrollment code is printed only when no credential exists. After the
|
|
180
|
+
first durable credential is registered, recovery requires an authenticated
|
|
181
|
+
session to add another passkey; losing every enrolled passkey requires backed-up
|
|
182
|
+
re-enrollment into deliberately empty state. Cloud deployment is limited
|
|
183
|
+
to one replica because session and challenge state are process-local and the
|
|
184
|
+
credential writer is single-owner. Credential state belongs on a narrow
|
|
185
|
+
independent read-write volume; operator progress-report status pins belong on
|
|
186
|
+
a second independent read-write volume. All other dashboard input mounts remain
|
|
187
|
+
read-only. Deployment preflight classifies strict-v1 absent/zero/nonzero state
|
|
188
|
+
only; store open remains the sole RP-ID authority.
|
|
189
|
+
|
|
190
|
+
Bearer mode remains a transitional rollback path until both a real local
|
|
191
|
+
platform-passkey ceremony and a live same-origin Traefik ceremony have passed.
|
|
192
|
+
The authenticated dashboard response path must not log enrollment codes,
|
|
193
|
+
session cookies, WebAuthn payloads, or Authorization headers, and an edge
|
|
194
|
+
`Permissions-Policy` must not disable `publickey-credentials-get` or
|
|
195
|
+
`publickey-credentials-create`.
|
|
196
|
+
|
|
197
|
+
## What ClinkX Does NOT Secure
|
|
198
|
+
|
|
199
|
+
### No sandbox
|
|
200
|
+
|
|
201
|
+
The spawned CLI process (e.g., `agy`, `codex`, `claude`, `grok`) runs with **full user permissions**. It can:
|
|
202
|
+
|
|
203
|
+
- Read/write any file the user can access
|
|
204
|
+
- Make network requests
|
|
205
|
+
- Execute other programs
|
|
206
|
+
- Modify system state
|
|
207
|
+
|
|
208
|
+
Allow-roots validation constrains which paths ClinkX *accepts as input* — it does not restrict what the CLI process can do once spawned.
|
|
209
|
+
|
|
210
|
+
The `agy` (Google Antigravity CLI) adapter runs **without `--sandbox`** — fully unsandboxed, exactly like the `codex`, `claude`, and `grok` adapters. Note that even agy's `--sandbox` flag would only enable **terminal restrictions**, not filesystem-write containment (on macOS it was verified to NOT contain filesystem writes), so it is not a security boundary either way. The shipped `agy` adapter always applies `--dangerously-skip-permissions` (its `unsafe_args` are merged unconditionally), which auto-approves all tool permission requests without prompting. Additionally, each agy headless run accumulates roughly six state files under `~/.gemini/antigravity-cli/`; this is minor disk growth to be aware of for long-lived servers.
|
|
211
|
+
|
|
212
|
+
The shipped `grok` adapter is the same class of unsandboxed CLI: `--always-approve` is in `args` (not `unsafe_args`), and there is no tool denylist. Local auth is OAuth via `~/.grok/auth.json` (`HOME` is in the sanitized baseline); `XAI_API_KEY` is the extra `env_allowlist` entry. The process inherits the user's `~/.grok` plus Claude-compat MCP the same way Claude inherits `~/.claude`. Recursion into a host-configured clinkx MCP is a host-config issue, not an adapter sandbox.
|
|
213
|
+
|
|
214
|
+
### No network restrictions
|
|
215
|
+
|
|
216
|
+
ClinkX does not proxy, filter, or restrict network access by the subprocess.
|
|
217
|
+
|
|
218
|
+
### No filesystem isolation
|
|
219
|
+
|
|
220
|
+
The subprocess shares the user's filesystem. The run directory is a convenience for result contracts, not a security boundary.
|
|
221
|
+
|
|
222
|
+
`context_builder` artifacts are also not a security boundary. They are durable files intended to be attached to later `clink` calls. Treat `manifest.json`, `bundle.md`, and candidate artifacts as local working artifacts with manual retention and cleanup expectations.
|
|
223
|
+
|
|
224
|
+
### Delegate mode is not a sandbox
|
|
225
|
+
|
|
226
|
+
When `context_builder` runs with `delegate.enabled:true`, curator and finalizer
|
|
227
|
+
providers are invoked through configured CLI adapters and the existing runner
|
|
228
|
+
boundary. ClinkX does not add filesystem, process, or network isolation for
|
|
229
|
+
those delegate calls.
|
|
230
|
+
|
|
231
|
+
Delegate provider output is treated as untrusted advice, not source authority:
|
|
232
|
+
|
|
233
|
+
- The server sends bounded local candidate packets, not arbitrary filesystem
|
|
234
|
+
access instructions.
|
|
235
|
+
- Providers must return one strict JSON object; truncation, salvage, prose,
|
|
236
|
+
fenced blocks, or malformed output are rejected.
|
|
237
|
+
- Accepted candidate IDs and ranges must map back to local discovery records.
|
|
238
|
+
- Source content is reconstructed locally from server-generated slices.
|
|
239
|
+
- Budgets and high-confidence secret checks are reapplied after delegate
|
|
240
|
+
selection.
|
|
241
|
+
- Raw curator/finalizer output is not persisted in receipts, manifests,
|
|
242
|
+
summaries, bundles, or candidate artifacts.
|
|
243
|
+
|
|
244
|
+
`failure_policy:"fallback"` publishes deterministic local selection as a
|
|
245
|
+
partial v2 run when delegate curation fails. `failure_policy:"fail"` returns an
|
|
246
|
+
error and does not publish `manifest.json`. Parent cancellation stops active
|
|
247
|
+
delegate work through the existing pipeline/runner cancellation path and does
|
|
248
|
+
not publish a successful run.
|
|
249
|
+
|
|
250
|
+
### What ClinkX cannot secure (practical limits)
|
|
251
|
+
|
|
252
|
+
- **CLI behavior**: If the CLI decides to read other files, execute programs, or make network requests, ClinkX does not (and cannot) prevent that in v1.
|
|
253
|
+
- **Prompt injection inside the CLI**: ClinkX can validate inputs to `clink`, but cannot guarantee the downstream model will obey your safety constraints.
|
|
254
|
+
- **External side-effects**: Any side-effects performed by the subprocess (disk writes, network calls) happen with the user’s permissions.
|
|
255
|
+
|
|
256
|
+
## Recommendations
|
|
257
|
+
|
|
258
|
+
1. **Run as a least-privilege user** when possible.
|
|
259
|
+
2. **Review adapter configs carefully** — `command`, `args`, and `unsafe_args` determine what gets executed.
|
|
260
|
+
3. **Set `CLINKX_ALLOWED_ROOTS` explicitly** in production to limit input surface.
|
|
261
|
+
4. **Review `unsafe_args` in your adapter configs** — they are always included at runtime.
|
|
262
|
+
5. **Treat the spawned CLI as fully trusted code** — because it runs with your permissions.
|
|
263
|
+
6. **Treat context_builder artifacts as local source-derived files** — review them before passing them to a powerful downstream CLI.
|
|
264
|
+
7. **Configure delegate providers deliberately** — there are no built-in curator or finalizer defaults, and delegate adapters run with the same process and filesystem caveats as `clink`.
|
|
265
|
+
|
|
266
|
+
## Troubleshooting
|
|
267
|
+
|
|
268
|
+
### “Path … is outside allowed roots”
|
|
269
|
+
|
|
270
|
+
- Set `CLINKX_ALLOWED_ROOTS` to include the workspace roots you want to allow.
|
|
271
|
+
- Paths are validated via `realpath` (symlink escapes are blocked).
|
|
272
|
+
|
|
273
|
+
### “FATAL: cwd resolves to filesystem root”
|
|
274
|
+
|
|
275
|
+
- Start the server from a non-root working directory, or set `CLINKX_ALLOWED_ROOTS` explicitly.
|
|
276
|
+
|
|
277
|
+
### “Adapter … requires a TTY”
|
|
278
|
+
|
|
279
|
+
- ClinkX v1 does not support PTY/TTY emulation. Use an adapter/CLI mode that can run non-interactively, or wait for a future version that adds PTY support.
|
|
280
|
+
|
|
281
|
+
### “Unknown cli_name …”
|
|
282
|
+
|
|
283
|
+
- Ensure your adapter JSON is discoverable (see `docs/configuration.md`) and names are unique.
|
|
284
|
+
|
|
285
|
+
### “Concurrency limit reached …”
|
|
286
|
+
|
|
287
|
+
- Increase `CLINKX_MAX_CONCURRENT`, or retry later. ClinkX fails fast (it does not queue requests).
|
|
288
|
+
|
|
289
|
+
### Timeouts / truncated output
|
|
290
|
+
|
|
291
|
+
- Increase adapter `timeout_seconds` or request `timeout_seconds`.
|
|
292
|
+
- If output is truncated at the capture layer, increase `CLINKX_MAX_CAPTURE_BYTES` (default 2MB, controls head+tail ring buffer retention). Falls back to `CLINKX_MAX_OUTPUT_BYTES` if not set.
|
|
293
|
+
- Set `CLINKX_STRICT_FIDELITY=true` to make capture-layer truncation a hard error for stdout-extracted (non-result-contract) calls.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Verification Procedures
|
|
2
|
+
|
|
3
|
+
The npm-installed ClinkX MCP server exposes provider readiness and project
|
|
4
|
+
verification tools. An MCP client can use them without shell access, a ClinkX
|
|
5
|
+
checkout, Git, a browser, or ClinkX development dependencies. Node 24 or newer
|
|
6
|
+
and the tools required by your own project checks must be installed on the MCP
|
|
7
|
+
server's host.
|
|
8
|
+
|
|
9
|
+
| MCP tool | Purpose | Guide |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `provider_doctor` | Separate provider configuration, executable, authentication, and startup readiness; authentication probes are explicit | [Provider readiness](../configuration.md#provider-readiness-doctor) |
|
|
12
|
+
| `verification_run` | Execute a reviewed project manifest and retain private evidence for the identified state | [Project checks](project-checks.md), [example manifest](project-checks.example.json) |
|
|
13
|
+
| `run_workflow` with `verified-repair` | Explicit scoped in-place repair with native and independent causal checks; owner acceptance stays separate | [Native repair setup](project-checks.md#native-verified-repair), [invocation](../engineering-recipes.md#built-in-native-verified-repair) |
|
|
14
|
+
| `verification_inspect` | Inspect retained evidence with the owner's original expectations digest; execute no project commands | [Project checks](project-checks.md) |
|
|
15
|
+
|
|
16
|
+
These guides and the example manifest ship in the npm package. The engineering
|
|
17
|
+
recipe invocation guide also ships; the built-in native workflows require no companion checkout. Manual recipe instructions use
|
|
18
|
+
the separately installed companion skill described in
|
|
19
|
+
[engineering recipes](../engineering-recipes.md).
|
|
20
|
+
|
|
21
|
+
## ClinkX source-checkout procedures
|
|
22
|
+
|
|
23
|
+
The following regression procedures exercise ClinkX's own runtime with controlled
|
|
24
|
+
fixtures. Their scripts and fixtures require a source checkout; their guides are
|
|
25
|
+
also included in the package. They do not replace the canonical check
|
|
26
|
+
(`npm run build:all && npm test`).
|
|
27
|
+
|
|
28
|
+
Each source procedure names one feature and states its prerequisites, exact commands,
|
|
29
|
+
the assertions it proves, the evidence to keep, cleanup, and known limits.
|
|
30
|
+
|
|
31
|
+
| Procedure | Feature | Surface exercised |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| [dashboard-real-disk.md](dashboard-real-disk.md) | Dashboard serves persisted run history and refreshes a same-generation state replacement | Real dashboard CLI, HTTP API, Chromium, files on disk |
|
|
34
|
+
| [workflow-handoff.md](workflow-handoff.md) | Workflow producers deliver the correct persisted bytes to a final consumer; absent producer evidence remains missing | Real YAML loader, MCP STDIO child, workflow engine, validators, artifact store, host coverage evaluator |
|
|
35
|
+
|
|
36
|
+
General rules:
|
|
37
|
+
|
|
38
|
+
- Build once, then run invocations that do not build.
|
|
39
|
+
- Give every invocation its own attempt directory under a private evidence
|
|
40
|
+
root outside the checkout (`chmod 700`).
|
|
41
|
+
- A zero exit status is not proof. Check the retained report for the exact
|
|
42
|
+
required test and its status.
|
|
43
|
+
- Raw reports, traces, and logs can contain credentials. Keep them private;
|
|
44
|
+
share only checked, token-free summaries.
|
|
45
|
+
|
|
46
|
+
## Maintaining the feature map
|
|
47
|
+
|
|
48
|
+
Each row above maps one feature to one procedure. When a procedure stops
|
|
49
|
+
passing, classify the cause before repairing it:
|
|
50
|
+
|
|
51
|
+
| Class | Meaning | Example | Repair in |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| Documentation drift | The product changed on purpose; the procedure or its selectors did not follow. | A UI redesign moved labels the spec asserted. | The procedure and spec. Keep the assertion's intent; record any check that can no longer be observed. |
|
|
54
|
+
| Harness defect | The fixture, config, or runner misreports the result. | A fixture that treats an unsolicited exit as a clean shutdown; a runner that kills the fixture before its cleanup. | The fixture or config, with a subprocess test or a repeated procedure run that fails without the repair. |
|
|
55
|
+
| Product regression | The feature itself no longer behaves as intended. | The inspector stops refreshing after a state replacement. | The product code, not the procedure. |
|
|
56
|
+
|
|
57
|
+
After any repair, repeat the affected procedure and keep the new attempt's
|
|
58
|
+
evidence. Do not weaken an assertion to make drift pass. Add a row here when a
|
|
59
|
+
new procedure is added, and remove a row only when its feature is removed.
|