@cairnkeep/cli 2.22.2 → 2.22.4
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 +67 -1
- package/containers/healthcheck.mjs +27 -33
- package/containers/quadlet/cairnkeep.container +1 -1
- package/docs/containers.md +12 -0
- package/docs/domain-knowledge.md +15 -0
- package/docs/learning/CURRICULUM-MAP.md +1 -1
- package/docs/learning/FEATURE-GUIDE.md +1 -1
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +2 -2
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/learning/lessons/L19-validated-skill-improvement.md +1 -1
- package/docs/learning/lessons/L20-mcp-tool-profiles.md +1 -1
- package/docs/learning/lessons/L21-context-packs.md +1 -1
- package/docs/learning/lessons/L22-native-windows.md +2 -2
- package/docs/learning/lessons/L23-guided-setup.md +8 -1
- package/docs/learning/lessons/L24-okf-exchange.md +1 -1
- package/docs/learning/lessons/L25-playbooks.md +1 -1
- package/docs/learning/lessons/L26-context-intelligence.md +1 -1
- package/docs/learning/lessons/L27-ecosystem-evidence.md +1 -1
- package/docs/learning/lessons/L28-security-assurance.md +52 -2
- package/docs/learning/video-scripts/V28-security-assurance.md +45 -0
- package/docs/native-windows.md +10 -0
- package/docs/operating.md +19 -1
- package/docs/privacy-and-data-flow.md +6 -0
- package/docs/releasing.md +3 -2
- package/docs/security-assurance.md +67 -0
- package/examples/eval/bundled-fake.json +1 -1
- package/mcp-memory-server/dist/capability-registry.js +2 -15
- package/mcp-memory-server/dist/context-pack-retrieval.js +6 -6
- package/mcp-memory-server/dist/domain-retrieval-provider.js +100 -45
- package/mcp-memory-server/dist/eval-plan.js +15 -22
- package/mcp-memory-server/dist/eval-runner.js +17 -10
- package/mcp-memory-server/dist/eval-workspace.js +82 -23
- package/mcp-memory-server/dist/failure-signature.js +29 -8
- package/mcp-memory-server/dist/graph-cli.js +25 -10
- package/mcp-memory-server/dist/okf.js +4 -9
- package/mcp-memory-server/dist/playbook-receipt.js +3 -17
- package/mcp-memory-server/dist/skill-store.js +10 -26
- package/mcp-memory-server/dist/stable-file.js +85 -0
- package/mcp-memory-server/dist/work-evidence-store.js +7 -5
- package/omp/extensions/cairnkeep-capture.ts +29 -17
- package/package.json +1 -1
- package/scripts/lib/opencode-v2-plugin-harness.mjs +20 -3
- package/scripts/lib/stable-file.mjs +75 -0
- package/scripts/playbook-instructions.mjs +42 -20
- package/scripts/setup-core.mjs +5 -36
- package/scripts/setup-reconcile.mjs +32 -32
- package/scripts/setup.mjs +25 -34
- package/scripts/test-ci-sharding.sh +5 -0
- package/scripts/test-container-health.mjs +56 -0
- package/scripts/test-container.sh +8 -1
- package/scripts/test-learning-docs.sh +8 -0
- package/scripts/test-omp-staged-security.mjs +110 -0
- package/scripts/test-runtime-file-security.mjs +311 -0
- package/scripts/test-setup-diagnosis.mjs +97 -0
- package/scripts/test-windows-native.mjs +5 -0
- package/scripts/verify-omp-capture.mjs +1 -0
- package/scripts/windows-platform.mjs +54 -22
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,71 @@ All notable user-facing changes are documented here. This project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.22.4] - 2026-10-07
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
|
|
12
|
+
- Remove ambiguous nested path expressions from failure signatures. Crafted
|
|
13
|
+
slash-heavy messages no longer cause exponential backtracking; existing v1
|
|
14
|
+
fixture signatures remain byte-equivalent. Add timeout-isolated regression
|
|
15
|
+
inputs and a reproducible generated corpus.
|
|
16
|
+
- Bind capability compatibility configuration, skill artifacts/targets/backups
|
|
17
|
+
and work-evidence reads to inspected descriptors with fixed byte bounds,
|
|
18
|
+
identity rechecks and strict UTF-8. Reject replacement, growth and special-file
|
|
19
|
+
substitution; preserve private-ledger permissions and ordinary project-file
|
|
20
|
+
modes. Keep schemas, feature defaults and explicit approval gates unchanged.
|
|
21
|
+
Update security guidance and the learning/video supplement; historical
|
|
22
|
+
analysis findings remain subject to individual triage.
|
|
23
|
+
- Bind evaluation inputs/note snapshots, OKF import/export, graph artifacts,
|
|
24
|
+
playbook receipts and progressive-context cache reads to bounded inspected
|
|
25
|
+
descriptors. Reject replacement and growth before accepting content; publish
|
|
26
|
+
snapshots from the validated bytes instead of reopening source paths.
|
|
27
|
+
Rebuild unsafe derived caches deterministically without changing pack
|
|
28
|
+
enablement or skill approval. Add public-reader regression controls and
|
|
29
|
+
update security, learning and video guidance.
|
|
30
|
+
- Bound setup policy/state/ownership and instruction-file reads to 1 MiB;
|
|
31
|
+
bound OMP staged candidates to 8 KiB and exclude linked or oversized files.
|
|
32
|
+
Recheck observed setup/instruction targets before publication; preserve
|
|
33
|
+
caller edits detected after inspection, original instruction modes and
|
|
34
|
+
failed-operation state. Keep private approvals and machine sync explicit.
|
|
35
|
+
On Windows, use content ownership rather than POSIX executable-mode bits
|
|
36
|
+
when reconciling generated files; keep private-state ACL enforcement.
|
|
37
|
+
- Publish evaluation overlays and Windows managed files through exclusive
|
|
38
|
+
descriptor-written temporary files. Reject substituted targets, clean only
|
|
39
|
+
owned temporary files, and never unlink live Windows data to retry a denied
|
|
40
|
+
replacement. Bound compressed and expanded memory imports to 512 MiB.
|
|
41
|
+
- Keep container health checks on a validated numeric loopback port, using the
|
|
42
|
+
server's bounded credential resolver. Refuse provider URL credentials and
|
|
43
|
+
redirects, bound AnythingLLM query responses to 8 MiB, and sanitize provider
|
|
44
|
+
HTTP, network and stream failures without including response bodies.
|
|
45
|
+
Reject workspace dot segments, including shorthand OpenViking traversal.
|
|
46
|
+
Preserve default retrieval providers and successful response shapes.
|
|
47
|
+
|
|
48
|
+
### CI
|
|
49
|
+
|
|
50
|
+
- Preserve the bundled evaluation task set's canonical LF bytes in native
|
|
51
|
+
Windows source checkouts. Add a real Git CRLF-conversion regression control;
|
|
52
|
+
keep the installed-package exact-byte integrity check unchanged.
|
|
53
|
+
- Canonicalize bounded-read fixture paths before injecting file changes, covering
|
|
54
|
+
Windows short temporary-directory names and a real POSIX alias control.
|
|
55
|
+
- Run focused bounded-input controls before the longer Windows smoke shards on
|
|
56
|
+
all supported Node versions; retain every complete-catalog and install gate.
|
|
57
|
+
- Wait for completed OpenCode V2 fixture capture before reading its database,
|
|
58
|
+
under a bounded event-stream completion deadline. A deterministic delayed
|
|
59
|
+
completion control rejects the old file-existence readiness assumption;
|
|
60
|
+
production capture behavior is unchanged.
|
|
61
|
+
|
|
62
|
+
## [2.22.3] - 2026-10-07
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- Diagnose preserved custom setup files separately from generated-file
|
|
67
|
+
ownership. A complete scaffold no longer fails merely because setup skipped
|
|
68
|
+
caller-owned files or its ownership map is empty. Keep missing/unsafe asset,
|
|
69
|
+
launcher-executable and recorded digest/mode checks; never adopt, rewrite or
|
|
70
|
+
remove custom files during diagnosis. Add cross-platform regression controls
|
|
71
|
+
and clarify operating and guided-setup learning documentation.
|
|
72
|
+
|
|
8
73
|
## [2.22.2] - 2026-10-07
|
|
9
74
|
|
|
10
75
|
### Security
|
|
@@ -716,7 +781,8 @@ stored memories.
|
|
|
716
781
|
- Preserve executable permissions and Bash 3.2 portability on macOS.
|
|
717
782
|
- Add backup-first uninstall and SQLite-safe memory export/import guidance.
|
|
718
783
|
|
|
719
|
-
[Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.
|
|
784
|
+
[Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.22.4...HEAD
|
|
785
|
+
[2.22.4]: https://github.com/cairnkeep/cairnkeep/compare/v2.22.3...v2.22.4
|
|
720
786
|
[2.20.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.19.1...v2.20.0
|
|
721
787
|
[2.19.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.19.0...v2.19.1
|
|
722
788
|
[2.19.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.18.0...v2.19.0
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
if (!port) {
|
|
5
|
-
process.exit(0);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
let token = process.env.CAIRN_MEMORY_HTTP_TOKEN?.trim();
|
|
9
|
-
const tokenFile = process.env.CAIRN_MEMORY_HTTP_TOKEN_FILE?.trim();
|
|
10
|
-
if (!token && tokenFile) {
|
|
11
|
-
try {
|
|
12
|
-
token = readFileSync(tokenFile, "utf8").trim();
|
|
13
|
-
} catch {
|
|
14
|
-
process.exit(1);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
if (!token) {
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { parseHttpPort, resolveHttpToken } from "../mcp-memory-server/dist/http-security.js";
|
|
20
4
|
|
|
21
5
|
const body = {
|
|
22
6
|
jsonrpc: "2.0",
|
|
@@ -29,18 +13,28 @@ const body = {
|
|
|
29
13
|
},
|
|
30
14
|
};
|
|
31
15
|
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
16
|
+
export async function containerHealthcheck(env = process.env) {
|
|
17
|
+
const port = parseHttpPort(env.MCP_HTTP_PORT);
|
|
18
|
+
if (!port.enabled) return "error" in port ? 1 : 0;
|
|
19
|
+
const token = resolveHttpToken(env);
|
|
20
|
+
if (!token.ok) return 1;
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`http://127.0.0.1:${port.port}/mcp`, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: {
|
|
25
|
+
Authorization: `Bearer ${token.token}`,
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
Accept: "application/json, text/event-stream",
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(body),
|
|
30
|
+
redirect: "manual",
|
|
31
|
+
signal: AbortSignal.timeout(4000),
|
|
32
|
+
});
|
|
33
|
+
await response.body?.cancel();
|
|
34
|
+
return response.ok ? 0 : 1;
|
|
35
|
+
} catch { return 1; }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (process.argv[1] && pathToFileURL(realpathSync(process.argv[1])).href === import.meta.url) {
|
|
39
|
+
process.exitCode = await containerHealthcheck();
|
|
46
40
|
}
|
|
@@ -9,7 +9,7 @@ ContainerName=cairnkeep
|
|
|
9
9
|
Exec=http
|
|
10
10
|
UserNS=keep-id:uid=10001,gid=10001
|
|
11
11
|
Volume=cairnkeep-data.volume:/data:Z
|
|
12
|
-
Secret=cairnkeep-http-token,type=mount,target=http-token
|
|
12
|
+
Secret=cairnkeep-http-token,type=mount,target=http-token,uid=10001,gid=10001,mode=0400
|
|
13
13
|
Environment=MCP_HTTP_HOST=0.0.0.0
|
|
14
14
|
Environment=MCP_HTTP_PORT=7801
|
|
15
15
|
Environment=CAIRN_MEMORY_HTTP_ALLOWED_HOSTS=localhost:7801,127.0.0.1:7801
|
package/docs/containers.md
CHANGED
|
@@ -80,6 +80,18 @@ cairn-container http \
|
|
|
80
80
|
|
|
81
81
|
The container always adds its own loopback address for health checks.
|
|
82
82
|
|
|
83
|
+
The health-check security follow-up validates `MCP_HTTP_PORT` with the server's
|
|
84
|
+
numeric port parser and uses its bounded private token resolver. Invalid
|
|
85
|
+
configuration fails without issuing a request; probes target only
|
|
86
|
+
`127.0.0.1` and refuse redirects. The existing
|
|
87
|
+
`/usr/local/lib/cairnkeep/container-healthcheck.mjs` command remains available
|
|
88
|
+
as an alias to the packaged probe. Stdio mode requires no HTTP probe.
|
|
89
|
+
File-based probes require a private token readable by the container user;
|
|
90
|
+
world-readable secret mounts fail closed. The Quadlet example explicitly mounts
|
|
91
|
+
its secret as UID/GID 10001 with mode `0400`. For other engines, verify the
|
|
92
|
+
effective in-container ownership and mode rather than relying on a secret
|
|
93
|
+
declaration that the engine may not honor.
|
|
94
|
+
|
|
83
95
|
One HTTP server and bearer token form one trust domain. They are not a
|
|
84
96
|
multi-tenant authorization boundary; see [Memory storage and
|
|
85
97
|
deployment](storage.md).
|
package/docs/domain-knowledge.md
CHANGED
|
@@ -32,6 +32,17 @@ work exactly the same without them.
|
|
|
32
32
|
| `CAIRN_ANYTHINGLLM_PROJECTS_FILE` | Optional config path for the bundled sync script. Default `${XDG_CONFIG_HOME:-~/.config}/cairnkeep/anythingllm-projects.json`. |
|
|
33
33
|
| `CAIRN_ANYTHINGLLM_STATE_FILE` | Optional state path for the bundled sync script. Default `${XDG_STATE_HOME:-~/.local/state}/cairnkeep/anythingllm-sync.json`. |
|
|
34
34
|
|
|
35
|
+
The query security follow-up validates HTTP(S) URLs and rejects embedded
|
|
36
|
+
credentials, query strings and fragments before fetching. Redirects are not
|
|
37
|
+
followed, and workspace names cannot be empty or URL dot segments. Responses
|
|
38
|
+
are streamed under an 8 MiB cap and must be UTF-8 JSON
|
|
39
|
+
objects; successful answer-field selection is unchanged. Failed requests
|
|
40
|
+
report only a controlled failure class or HTTP status, never a provider error
|
|
41
|
+
body or raw network/stream diagnostic. The existing two-minute query deadline
|
|
42
|
+
remains. Configure HTTPS outside loopback: remote plaintext HTTP remains
|
|
43
|
+
accepted for compatibility, not as a recommendation. Document synchronization
|
|
44
|
+
uses a separate script and does not inherit these query-specific guarantees.
|
|
45
|
+
|
|
35
46
|
The workspaces the tools target come from the project's **memory config** — the
|
|
36
47
|
first of `.agent/memory.json`, `.opencode/memory.json`, `.claude/memory.json`, or
|
|
37
48
|
`memory.json` that exists:
|
|
@@ -117,6 +128,10 @@ CAIRN_OPENVIKING_BASE_URL=http://127.0.0.1:1933
|
|
|
117
128
|
|
|
118
129
|
Plain HTTP is limited to loopback. Use HTTPS for any other host. Credentials in
|
|
119
130
|
the URL, redirects, invalid response shapes, and oversized bodies are rejected.
|
|
131
|
+
The response cap is 1 MiB. Network and stream failures are payload-free in the
|
|
132
|
+
security follow-up, including failures during response cleanup.
|
|
133
|
+
Shorthand workspace names and explicit `viking://resources` URIs share the
|
|
134
|
+
same decoded traversal checks before any request is sent.
|
|
120
135
|
Authenticated remote MCP use requires the additional explicit consent setting
|
|
121
136
|
`CAIRN_OPENVIKING_MCP_HTTP=1`.
|
|
122
137
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 15 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.22.
|
|
6
|
+
**Tested with:** Cairnkeep 2.22.4
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ ephemeral; the named course volume is persistent.
|
|
|
26
26
|
1. Pull the public image:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
podman pull ghcr.io/cairnkeep/cairnkeep:2.22.
|
|
29
|
+
podman pull ghcr.io/cairnkeep/cairnkeep:2.22.4
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
2. Start the stdio server with a read-only root filesystem and no Linux
|
|
@@ -38,7 +38,7 @@ ephemeral; the named course volume is persistent.
|
|
|
38
38
|
--read-only --cap-drop=all --security-opt=no-new-privileges \
|
|
39
39
|
--tmpfs=/tmp:rw,noexec,nosuid,size=64m,mode=1777 \
|
|
40
40
|
--volume cairnkeep-course-data:/data:Z,U \
|
|
41
|
-
ghcr.io/cairnkeep/cairnkeep:2.22.
|
|
41
|
+
ghcr.io/cairnkeep/cairnkeep:2.22.4 stdio
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
3. The process waits quietly for MCP input. Press `Ctrl-C` after confirming it
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 25 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.22.
|
|
6
|
+
**Tested with:** Cairnkeep 2.22.4 and Node.js 22 or newer
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -47,7 +47,7 @@ sync. Codex project trust remains an explicit operator decision.
|
|
|
47
47
|
2. Install Cairnkeep:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
npm install --global @cairnkeep/cli@2.22.
|
|
50
|
+
npm install --global @cairnkeep/cli@2.22.4
|
|
51
51
|
cairn --version
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Operator
|
|
5
5
|
**Time:** 30 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.22.
|
|
6
|
+
**Tested with:** Cairnkeep 2.22.4, Windows x64, and Node.js 22 or newer
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ perform a reversible uninstall without relying on WSL or Git Bash.
|
|
|
16
16
|
From PowerShell:
|
|
17
17
|
|
|
18
18
|
```powershell
|
|
19
|
-
npm install --global @cairnkeep/cli@2.22.
|
|
19
|
+
npm install --global @cairnkeep/cli@2.22.4
|
|
20
20
|
cairn version
|
|
21
21
|
|
|
22
22
|
$Lab = Join-Path $env:TEMP 'Cairnkeep Windows Lab'
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart and Operator
|
|
5
5
|
**Time:** 35 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.22.
|
|
6
|
+
**Tested with:** Cairnkeep 2.22.4; Pi 0.84.1; Node.js 22, 24, and 26
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -54,6 +54,13 @@ records the selected Pi harness in private `.ai/cairnkeep.json`, and reports
|
|
|
54
54
|
created, updated, unchanged, and skipped assets. Repeating the same `cairn
|
|
55
55
|
setup` command should report the managed files as unchanged.
|
|
56
56
|
|
|
57
|
+
When an existing project has customized launchers or scaffold files, setup
|
|
58
|
+
preserves and skips them. Its private asset map tracks ownership, not a full
|
|
59
|
+
inventory. Doctor accepts safely present custom files without adopting them,
|
|
60
|
+
but still rejects missing files, links, non-executable POSIX launchers and
|
|
61
|
+
changes to recorded owned assets. Do not replace a custom file just to satisfy
|
|
62
|
+
a generated digest. Diagnosis does not change file contents or ownership.
|
|
63
|
+
|
|
57
64
|
Project setup never changes the Pi installation. Apply and check machine assets
|
|
58
65
|
explicitly, then diagnose the project again:
|
|
59
66
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# L28 - Verify Cairnkeep's security posture
|
|
2
2
|
|
|
3
3
|
**Status:** Ready
|
|
4
|
-
**Tested with:** Cairnkeep 2.22.
|
|
4
|
+
**Tested with:** Cairnkeep 2.22.4 and Node.js 22 or newer
|
|
5
5
|
|
|
6
6
|
## Outcome
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@ and choose least authority for a network-facing MCP client.
|
|
|
11
11
|
|
|
12
12
|
## Prerequisites
|
|
13
13
|
|
|
14
|
-
- Install Cairnkeep 2.22.
|
|
14
|
+
- Install Cairnkeep 2.22.4 or use a disposable source checkout.
|
|
15
15
|
- Complete [L20 - Least-authority MCP tool profiles](L20-mcp-tool-profiles.md).
|
|
16
16
|
- Use synthetic values only; never paste a real bearer token into a recording,
|
|
17
17
|
terminal transcript, or issue.
|
|
@@ -68,6 +68,14 @@ scripts/test-security-baseline.sh
|
|
|
68
68
|
npm --prefix mcp-memory-server run check:security-assurance
|
|
69
69
|
npm --prefix mcp-memory-server run check:http-guard
|
|
70
70
|
node mcp-memory-server/scripts/smoke-context-pack-state.mjs
|
|
71
|
+
node mcp-memory-server/scripts/smoke-note-signatures.mjs
|
|
72
|
+
node mcp-memory-server/scripts/smoke-runtime-file-reads.mjs
|
|
73
|
+
node mcp-memory-server/scripts/smoke-bounded-input-reads.mjs
|
|
74
|
+
node mcp-memory-server/scripts/smoke-workspace-file-security.mjs
|
|
75
|
+
node mcp-memory-server/scripts/smoke-outbound-security.mjs
|
|
76
|
+
node scripts/test-runtime-file-security.mjs
|
|
77
|
+
node scripts/test-omp-staged-security.mjs
|
|
78
|
+
node scripts/test-container-health.mjs
|
|
71
79
|
```
|
|
72
80
|
|
|
73
81
|
The baseline rejects unpinned external Actions, `pull_request_target` and
|
|
@@ -91,6 +99,48 @@ under bounded reads. A resolved review thread or green CodeQL job does not mean
|
|
|
91
99
|
all historical alerts are fixed: inspect current findings and test the actual
|
|
92
100
|
boundary without dismissing results merely to improve an advisory score.
|
|
93
101
|
|
|
102
|
+
In a checkout containing the runtime-security follow-up, the signature control
|
|
103
|
+
keeps existing v1 fingerprints byte-equivalent and isolates crafted path inputs
|
|
104
|
+
behind a five-second child-process timeout. The runtime file-read control
|
|
105
|
+
substitutes valid capability configuration, skill targets/ledgers/backups and
|
|
106
|
+
work-evidence records after inspection. Readers reject those replacements,
|
|
107
|
+
bound growth, reject special files without waiting for a writer and close their
|
|
108
|
+
descriptors. Ordinary project configuration may remain `0644`; private evidence
|
|
109
|
+
and approval ledgers still require private ownership/ACLs. Build the server
|
|
110
|
+
before running source-checkout controls. The generated parser corpus is
|
|
111
|
+
reproducible regression coverage, not integrated coverage-guided fuzzing.
|
|
112
|
+
|
|
113
|
+
The bounded-input follow-up extends descriptor-bound reads to evaluation,
|
|
114
|
+
OKF import/export, graph artifacts, private playbook receipts and derived
|
|
115
|
+
progressive-context caches. Compare a replaced valid file with same-inode
|
|
116
|
+
growth: rejecting oversized content after `readFile` has allocated it is not
|
|
117
|
+
a bounded read. Note snapshots publish the bytes that were inspected and
|
|
118
|
+
hashed, not a later reopened file. Unsafe derived caches can be rebuilt from
|
|
119
|
+
immutable content; read-only doctor reports them without deletion. Cache
|
|
120
|
+
rebuilding never changes project enablement or skill approval. This exercise
|
|
121
|
+
does not certify directory-wide transactions against other same-account
|
|
122
|
+
processes.
|
|
123
|
+
|
|
124
|
+
The publication follow-up extends the exercise to setup, instruction files,
|
|
125
|
+
evaluation overlays and native Windows managed writes. Inspect a concurrent
|
|
126
|
+
caller edit: rechecking the observed target before publication must preserve
|
|
127
|
+
it. A denied Windows replacement must retain the live database, not unlink it
|
|
128
|
+
to retry. A substituted overlay symlink must leave its outside sentinel intact.
|
|
129
|
+
Exclusive descriptor-written temporaries retain modes and clean only their own
|
|
130
|
+
files. These are point-in-time safeguards, not all-project transactions or
|
|
131
|
+
protection against another hostile process using your account. Native Windows
|
|
132
|
+
and container/package verification remain required before shipping.
|
|
133
|
+
|
|
134
|
+
The OMP control reads only synthetic staged candidates, never invokes a model,
|
|
135
|
+
and shows that linked, growing or over-8-KiB content cannot become wakeup
|
|
136
|
+
evidence or `/cairn-staged` output. It does not approve or persist a candidate.
|
|
137
|
+
The outbound and health controls stub network calls: provider redirects and
|
|
138
|
+
oversized bodies fail, private error sentinels never appear in diagnostics,
|
|
139
|
+
and a malformed health port never becomes a network destination. Successful
|
|
140
|
+
retrieval still sends a query to the explicitly configured external provider.
|
|
141
|
+
AnythingLLM responses have an 8 MiB cap; OpenViking retains its 1 MiB cap and
|
|
142
|
+
separate consent gates. Prefer HTTPS outside loopback.
|
|
143
|
+
|
|
94
144
|
## Common failures
|
|
95
145
|
|
|
96
146
|
- A private `.ai` file is group/world accessible on POSIX: restore mode `0600`.
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
Target length: 10–12 minutes. Audience: experienced developers operating an
|
|
4
4
|
agent-memory service locally or behind authenticated HTTP.
|
|
5
5
|
|
|
6
|
+
The source-checkout security follow-up blocks below are optional supplemental
|
|
7
|
+
clips, not part of the original 10–12-minute timing. Record them as a separate
|
|
8
|
+
segment after their branch passes the complete release gates; do not present
|
|
9
|
+
unreleased controls as installed-package behavior.
|
|
10
|
+
|
|
6
11
|
## Recording outline
|
|
7
12
|
|
|
8
13
|
### 0:00–1:20 — Threat model before tooling
|
|
@@ -69,6 +74,46 @@ rejection, bounded growth and cleanup; use no real private pointer/approval
|
|
|
69
74
|
data. Distinguish resolved old review comments from current analysis findings,
|
|
70
75
|
and do not imply a green CI run certifies an empty security backlog.
|
|
71
76
|
|
|
77
|
+
For the runtime-security follow-up, show
|
|
78
|
+
`node mcp-memory-server/scripts/smoke-note-signatures.mjs` and
|
|
79
|
+
`node mcp-memory-server/scripts/smoke-runtime-file-reads.mjs` from a built source
|
|
80
|
+
checkout. Explain that a tiny crafted path used to stall signature parsing,
|
|
81
|
+
while the fixed parser preserves the existing v1 fixture fingerprints. The
|
|
82
|
+
child-process timeout makes a regression fail instead of freezing the demo.
|
|
83
|
+
Then show valid-file replacement rejection through capability, skill and
|
|
84
|
+
work-evidence readers. Explain fixed byte bounds and descriptor cleanup, and
|
|
85
|
+
distinguish private ledger permissions from ordinary project-file modes. Do not
|
|
86
|
+
call the generated corpus coverage-guided fuzzing or claim that this patch
|
|
87
|
+
resolves every historical analysis alert. Use only the synthetic fixtures.
|
|
88
|
+
|
|
89
|
+
In a checkout with the bounded-input follow-up, run
|
|
90
|
+
`node mcp-memory-server/scripts/smoke-bounded-input-reads.mjs`. Zoom into
|
|
91
|
+
valid-file substitution and same-inode growth through evaluation, OKF, graph,
|
|
92
|
+
receipt and cache entry points. Contrast a byte cap checked after allocation
|
|
93
|
+
with a fixed descriptor-read allocation. Show that note snapshots publish the
|
|
94
|
+
validated bytes and rejected derived cache data is rebuilt, while read-only
|
|
95
|
+
doctor never deletes it. Explain that this does not enable a pack or approve a
|
|
96
|
+
skill, make directory-wide publication transactional, or substitute for native
|
|
97
|
+
Windows verification. Keep a pause between the failure and remediation.
|
|
98
|
+
|
|
99
|
+
For the publication follow-up, show
|
|
100
|
+
`node scripts/test-runtime-file-security.mjs` beside
|
|
101
|
+
`node mcp-memory-server/scripts/smoke-workspace-file-security.mjs`. Pause on the
|
|
102
|
+
concurrent caller edit and denied-replacement controls: the previous content
|
|
103
|
+
must survive. Contrast a direct path write with an exclusive, flushed temporary
|
|
104
|
+
file followed by publication. State that immediate parent/target checks are
|
|
105
|
+
not directory-wide transactions or a same-account sandbox. Native Windows
|
|
106
|
+
verification is still required; POSIX fixture execution is not proof of it.
|
|
107
|
+
|
|
108
|
+
Run `node scripts/test-omp-staged-security.mjs` and explain the 8 KiB candidate
|
|
109
|
+
bound, symlink exclusion and unchanged agent-review requirement. Then show
|
|
110
|
+
`node mcp-memory-server/scripts/smoke-outbound-security.mjs` and
|
|
111
|
+
`node scripts/test-container-health.mjs`: synthetic provider errors must stay
|
|
112
|
+
out of diagnostics, redirects are refused, response bytes are bounded, and
|
|
113
|
+
the health probe cannot turn an unvalidated port into an outside destination.
|
|
114
|
+
These controls stub network calls; never show real credentials or imply that
|
|
115
|
+
the exercise contacted a provider. Leave a reading pause after each result.
|
|
116
|
+
|
|
72
117
|
Briefly open `.github/workflows/publish.yml` beside the permission table in
|
|
73
118
|
`docs/releasing.md`. Contrast the read-only preparation job with the necessary
|
|
74
119
|
npm and OCI publication grants. Explain that explicit maps deny unspecified
|
package/docs/native-windows.md
CHANGED
|
@@ -125,6 +125,16 @@ access, or background synchronization.
|
|
|
125
125
|
uses `sqlite3.exe` `.backup` for a consistent snapshot of each live WAL database
|
|
126
126
|
and then writes the same portable `.tgz` format used on Unix.
|
|
127
127
|
|
|
128
|
+
The archive/publication security follow-up binds compressed input to one
|
|
129
|
+
descriptor with a 512 MiB cap; decompressed tar output is independently capped
|
|
130
|
+
at 512 MiB. Managed writes use exclusive descriptor-written temporary files,
|
|
131
|
+
flush them and recheck the immediate parent/target before publication. Sharing
|
|
132
|
+
violations get bounded retries with at most 250 ms total backoff. A denied
|
|
133
|
+
replacement never unlinks the live destination; its prior contents survive.
|
|
134
|
+
These checks do not make a multi-database import transactional, and a post-write
|
|
135
|
+
ACL failure is not a rollback. Keep the pre-import backup and diagnose the
|
|
136
|
+
failure before retrying.
|
|
137
|
+
|
|
128
138
|
## Scheduling and process cleanup
|
|
129
139
|
|
|
130
140
|
`cairn audit-timer` registers the opt-in `Cairnkeep Memory Audit` task through
|
package/docs/operating.md
CHANGED
|
@@ -94,6 +94,22 @@ returns the same schema-v1 result. The private mode-`0600`
|
|
|
94
94
|
selected harnesses, and digests/modes/template identifiers for setup-owned
|
|
95
95
|
assets. It contains no credentials, endpoints, or absolute paths.
|
|
96
96
|
|
|
97
|
+
The asset map records ownership, not every file in the project. Existing custom
|
|
98
|
+
files that setup skips remain caller-owned. Doctor checks that every required
|
|
99
|
+
selected asset is a regular file under non-symlinked scaffold directories and
|
|
100
|
+
that POSIX launchers are executable, without adopting or rewriting custom files.
|
|
101
|
+
An empty ownership map is valid when all required assets were already present.
|
|
102
|
+
|
|
103
|
+
In the security follow-up, policy/state/owned-asset and `AGENTS.md` reads are
|
|
104
|
+
descriptor-bound and capped at 1 MiB. A changed, linked, oversized or invalid
|
|
105
|
+
UTF-8 input fails closed instead of being accepted through a later path read.
|
|
106
|
+
Publication rechecks observed targets and preserves concurrent caller edits
|
|
107
|
+
detected before replacement. Instruction reconciliation retains the original
|
|
108
|
+
file mode; unsafe instruction files are not rewritten. These checks are not an
|
|
109
|
+
all-project transaction or a sandbox against another process using your account.
|
|
110
|
+
Correct the reported input and rerun the printed recovery command; do not
|
|
111
|
+
delete caller-owned files or the ownership record to bypass a failure.
|
|
112
|
+
|
|
97
113
|
Setup never installs or refreshes machine-level harness assets. Its
|
|
98
114
|
`machine_sync.automatic` field is always false, and the human output labels each
|
|
99
115
|
reported command as not run automatically. The JSON result's
|
|
@@ -1072,7 +1088,9 @@ Unsupported schema, SQLite failure, invalid full records, or digest corruption
|
|
|
1072
1088
|
fails untouched with guidance to preserve the database before manual recovery.
|
|
1073
1089
|
|
|
1074
1090
|
When `.ai/cairnkeep.json` exists, doctor also validates its private state,
|
|
1075
|
-
selected assets, digests
|
|
1091
|
+
selected assets, and the digests and modes of recorded setup-owned files.
|
|
1092
|
+
Preserved caller-owned files need safe presence, not a generated-file digest;
|
|
1093
|
+
doctor never claims ownership of them. It reports `limited` for explicit
|
|
1076
1094
|
`--git none`, fails an incomplete or drifted setup with the recorded
|
|
1077
1095
|
deterministic `cairn setup` recovery command, and checks the Pi machine
|
|
1078
1096
|
extension when Pi was selected. `cairn sync-pi --apply` repairs that
|
|
@@ -683,6 +683,12 @@ skill readable; Cairnkeep never copies it into a harness or executes it.
|
|
|
683
683
|
- The OpenViking adapter is query-only. It sends the requested workspace target
|
|
684
684
|
and query to the configured endpoint, but performs no synchronization, watch,
|
|
685
685
|
commit, update, or deletion. Non-loopback endpoints must use HTTPS.
|
|
686
|
+
- In the query security follow-up, AnythingLLM and OpenViking do not follow
|
|
687
|
+
redirects, bound response bytes and suppress provider error bodies and raw
|
|
688
|
+
network/stream diagnostics. Successful requests still send the selected
|
|
689
|
+
query to the configured provider. AnythingLLM retains remote HTTP support
|
|
690
|
+
for compatibility; choose HTTPS outside loopback. Synchronization scripts
|
|
691
|
+
have their own authority and do not inherit query-only guarantees.
|
|
686
692
|
|
|
687
693
|
Pack digests and proposal digests protect integrity and stale-state detection;
|
|
688
694
|
they do not authenticate a publisher or make extracted statements true.
|
package/docs/releasing.md
CHANGED
|
@@ -47,8 +47,9 @@ does not require republishing the npm package.
|
|
|
47
47
|
anonymous pull before announcing the release.
|
|
48
48
|
|
|
49
49
|
The native-Windows lanes retain stable check names for branch protection. Each
|
|
50
|
-
lane exercises the Windows CLI and packed global install on its Node version
|
|
51
|
-
|
|
50
|
+
lane exercises the Windows CLI and packed global install on its Node version.
|
|
51
|
+
Focused bounded-input controls run first so platform-specific failures surface
|
|
52
|
+
before the longer smoke shards. The complete memory-server smoke catalog is deterministically balanced
|
|
52
53
|
across the three lanes. The Linux Node 22/24/26 matrix independently runs the
|
|
53
54
|
complete catalog on every supported runtime. This preserves coverage while
|
|
54
55
|
removing three serial copies of the slow Windows suite from the critical path.
|