@cairnkeep/cli 2.20.1 → 2.21.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/CHANGELOG.md +35 -0
- package/README.md +6 -3
- package/SECURITY.md +13 -0
- package/containers/entrypoint.sh +2 -1
- package/docs/README.md +2 -0
- package/docs/learning/CURRICULUM-MAP.md +4 -2
- package/docs/learning/FEATURE-GUIDE.md +6 -1
- package/docs/learning/README.md +1 -0
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +1 -1
- package/docs/learning/lessons/L02-installation.md +1 -1
- 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 +1 -1
- package/docs/learning/lessons/L23-guided-setup.md +1 -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 +3 -0
- package/docs/learning/lessons/L27-ecosystem-evidence.md +1 -1
- package/docs/learning/lessons/L28-security-assurance.md +104 -0
- package/docs/learning/video-scripts/V28-security-assurance.md +72 -0
- package/docs/operating.md +40 -5
- package/docs/privacy-and-data-flow.md +14 -0
- package/docs/releasing.md +9 -1
- package/docs/security-assurance.md +122 -0
- package/examples/eval/bundled-fake.json +1 -1
- package/mcp-memory-server/dist/artifact-schema.js +2 -7
- package/mcp-memory-server/dist/context-pack.js +152 -31
- package/mcp-memory-server/dist/eval-schema.js +13 -12
- package/mcp-memory-server/dist/http-security.js +104 -0
- package/mcp-memory-server/dist/index.js +50 -12
- package/mcp-memory-server/dist/okf.js +35 -9
- package/mcp-memory-server/dist/path-security.js +49 -0
- package/mcp-memory-server/dist/platform-security.js +154 -31
- package/mcp-memory-server/dist/project-environment.js +132 -0
- package/mcp-memory-server/dist/security-cli.js +46 -0
- package/mcp-memory-server/dist/security-doctor.js +211 -0
- package/mcp-memory-server/package.json +2 -1
- package/package.json +3 -2
- package/scripts/bootstrap.sh +1 -0
- package/scripts/cairn-cli.mjs +2 -0
- package/scripts/completion.sh +9 -3
- package/scripts/setup-reconcile.mjs +3 -0
- package/scripts/test-bootstrap-untracked.sh +2 -0
- package/scripts/test-cli-dispatch.sh +16 -1
- package/scripts/test-completion.sh +3 -0
- package/scripts/test-container-runner.sh +7 -0
- package/scripts/test-launcher-env-precedence.sh +30 -0
- package/scripts/test-learning-docs.sh +19 -0
- package/scripts/test-security-baseline.sh +4 -0
- package/scripts/verify-security-baseline.mjs +79 -0
- package/scripts/windows-platform.mjs +4 -2
- package/templates/start-claude.sh.template +3 -0
- package/templates/start-codex.sh.template +3 -0
- package/templates/start-kimi.sh.template +3 -0
- package/templates/start-omp.sh.template +3 -0
- package/templates/start-opencode.sh.template +3 -0
- package/templates/start-pi.sh.template +3 -0
- package/templates/start-qwen.sh.template +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ All notable user-facing changes are documented here. This project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.21.0] - 2026-10-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add `cairn security doctor [--project PATH] [--json]`, a read-only posture
|
|
13
|
+
check for private managed files, MCP authority, authenticated HTTP exposure,
|
|
14
|
+
Host allowlisting, token strength, and remote transport encryption.
|
|
15
|
+
- Add a maintained threat model and security-assurance learning lesson with
|
|
16
|
+
explicit assets, trust boundaries, residual risks, and verification evidence.
|
|
17
|
+
- Add CodeQL, pull-request dependency review, advisory OpenSSF Scorecard, and a
|
|
18
|
+
repository baseline gate that rejects unpinned external Actions and
|
|
19
|
+
`pull_request_target` workflows.
|
|
20
|
+
|
|
21
|
+
### Security
|
|
22
|
+
|
|
23
|
+
- Apply one portable-path contract across context packs, OKF, artifacts, and
|
|
24
|
+
evaluation paths, rejecting Windows drive/UNC paths, alternate separators,
|
|
25
|
+
ADS/device aliases and forbidden characters, traversal, invalid Unicode, and
|
|
26
|
+
case collisions while normalizing enumerated macOS filenames.
|
|
27
|
+
- Bound authenticated MCP HTTP request bodies to 8 MiB and set header, request,
|
|
28
|
+
and keep-alive timeouts; direct and container servers now share private
|
|
29
|
+
token-file resolution, strict decimal port parsing, canonical IPv4/DNS/IPv6
|
|
30
|
+
Host authorities, and empty hosts normalize to loopback.
|
|
31
|
+
- Bind relative HTTP token files to the selected project, verify project and
|
|
32
|
+
parent replacement boundaries, and parse private `.ai/.env` files through a
|
|
33
|
+
descriptor-bound 64 KiB limit.
|
|
34
|
+
- Require trusted POSIX ownership in addition to safe mode bits, preserve
|
|
35
|
+
explicit HTTP ports including 80/443, and apply the same raw/canonical
|
|
36
|
+
portable inventory to context-pack initialization, locking, and validation.
|
|
37
|
+
- Reject header-unsafe Bearer values, preserve ambient-over-project launcher
|
|
38
|
+
precedence, retain validated OKF bytes through import, and enforce portable
|
|
39
|
+
collisions at evaluation-bundle admission.
|
|
40
|
+
- Add deterministic adversarial path cases, token non-disclosure checks, and
|
|
41
|
+
HTTP authorization, Host, and request-limit regression coverage.
|
|
42
|
+
|
|
8
43
|
## [2.20.1] - 2026-10-06
|
|
9
44
|
|
|
10
45
|
### Maintenance
|
package/README.md
CHANGED
|
@@ -87,9 +87,11 @@ memory candidates; durable promotion and every networked or sensitive capture
|
|
|
87
87
|
path remain separately controlled. Ordinary uninstall retains durable data
|
|
88
88
|
unless an explicit purge is requested.
|
|
89
89
|
|
|
90
|
-
Start with [Privacy and data flow](docs/privacy-and-data-flow.md)
|
|
91
|
-
[Memory storage and deployment](docs/storage.md)
|
|
92
|
-
|
|
90
|
+
Start with [Privacy and data flow](docs/privacy-and-data-flow.md),
|
|
91
|
+
[Memory storage and deployment](docs/storage.md), and
|
|
92
|
+
[Security assurance and threat model](docs/security-assurance.md) before
|
|
93
|
+
enabling remote HTTP, embeddings, trajectories, artifacts, work evidence, or
|
|
94
|
+
context packs.
|
|
93
95
|
|
|
94
96
|
## Documentation
|
|
95
97
|
|
|
@@ -103,6 +105,7 @@ guides. In particular:
|
|
|
103
105
|
- [Operating guide](docs/operating.md)
|
|
104
106
|
- [Harness compatibility](docs/harness-compatibility.md)
|
|
105
107
|
- [Privacy and data flow](docs/privacy-and-data-flow.md)
|
|
108
|
+
- [Security assurance and threat model](docs/security-assurance.md)
|
|
106
109
|
- [Guided learning paths and video scripts](docs/learning/README.md)
|
|
107
110
|
|
|
108
111
|
The repository supports Linux, macOS, native Windows x64, WSL, Node.js 22/24/26,
|
package/SECURITY.md
CHANGED
|
@@ -35,3 +35,16 @@ Reports are especially useful for:
|
|
|
35
35
|
|
|
36
36
|
Configuration mistakes that deliberately disable documented safeguards are
|
|
37
37
|
normally outside scope unless the safe default is ineffective.
|
|
38
|
+
|
|
39
|
+
## Assurance model
|
|
40
|
+
|
|
41
|
+
The maintained [security assurance and threat model](docs/security-assurance.md)
|
|
42
|
+
documents assets, trust boundaries, implemented controls, verification gates,
|
|
43
|
+
and residual risks. Operators can run the read-only local posture check with:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
cairn security doctor --project .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This diagnostic complements dependency and repository scans; it is not a
|
|
50
|
+
certification, sandbox, secret manager, or multi-user access-control system.
|
package/containers/entrypoint.sh
CHANGED
|
@@ -17,6 +17,7 @@ load_secret() {
|
|
|
17
17
|
fi
|
|
18
18
|
value=$(cat "$file")
|
|
19
19
|
export "$name=$value"
|
|
20
|
+
unset "${name}_FILE"
|
|
20
21
|
fi
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -34,7 +35,7 @@ case "$mode" in
|
|
|
34
35
|
exec cairn memory-server "$@"
|
|
35
36
|
;;
|
|
36
37
|
http)
|
|
37
|
-
if [ -z "${CAIRN_MEMORY_HTTP_TOKEN:-}" ]; then
|
|
38
|
+
if [ -z "${CAIRN_MEMORY_HTTP_TOKEN:-}" ] && [ -z "${CAIRN_MEMORY_HTTP_TOKEN_FILE:-}" ]; then
|
|
38
39
|
echo "cairnkeep: HTTP mode requires CAIRN_MEMORY_HTTP_TOKEN or CAIRN_MEMORY_HTTP_TOKEN_FILE" >&2
|
|
39
40
|
exit 64
|
|
40
41
|
fi
|
package/docs/README.md
CHANGED
|
@@ -43,6 +43,8 @@ linked guides rather than the project landing page.
|
|
|
43
43
|
retention, backup, migration, and uninstall behavior.
|
|
44
44
|
- [Privacy and data flow](privacy-and-data-flow.md) maps what each opt-in feature
|
|
45
45
|
reads, stores, and may send over the network.
|
|
46
|
+
- [Security assurance and threat model](security-assurance.md) records assets,
|
|
47
|
+
trust boundaries, controls, residual risks, and the local posture check.
|
|
46
48
|
- [Git-linked work evidence](work-evidence.md) covers bounded local session-to-Git
|
|
47
49
|
provenance without prompt or reasoning capture.
|
|
48
50
|
- [Optional document knowledge](domain-knowledge.md) covers the separately
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Curriculum Coverage Map
|
|
2
2
|
|
|
3
|
-
**Baseline:** Cairnkeep 2.
|
|
3
|
+
**Baseline:** Cairnkeep 2.21.0
|
|
4
4
|
**Last reviewed:** 2026-10-06
|
|
5
5
|
|
|
6
6
|
This map prevents the course from drifting behind the product. It assigns each
|
|
@@ -43,6 +43,7 @@ been rehearsed.
|
|
|
43
43
|
| Bounded project playbooks, generic memory retrieval guidance, enforcement, and private receipts | L25 | L25 | Ready; balanced/local by default; invocation requires runtime evidence; actor identity unverified |
|
|
44
44
|
| Progressive pack retrieval, frozen benchmark, context-usage receipts, review-gated memory proposals, optional provider adapter | L26 | V26 | Ready; default flat search and AnythingLLM remain compatible; OpenViking and receipt mutation are explicitly gated |
|
|
45
45
|
| Branchable agent state, model-managed context, and learned decision-model comparisons | L27 | V27 | Ready; evidence runners are operator-invoked and no companion is a runtime dependency or authority |
|
|
46
|
+
| Threat model, local posture check, portable-path adversarial tests, and release security controls | L28 | V28 | Ready; diagnostic is read-only and evidence is not certification |
|
|
46
47
|
|
|
47
48
|
## Release Review
|
|
48
49
|
|
|
@@ -77,7 +78,7 @@ repository remains the canonical source for explanations and scripts.
|
|
|
77
78
|
| `course-11-windows` | L22 | Native PowerShell lifecycle, ACL inspection, and reversible uninstall |
|
|
78
79
|
| `course-12-guided-setup` | L23 | Deterministic setup, Pi local stdio, recovery, and backup-first uninstall |
|
|
79
80
|
| `course-13-playbooks` | L25 | Policy profiles, lifecycle decisions, enforcement, receipts, and ownership-safe instructions |
|
|
80
|
-
| Disposable source checkout | L26-
|
|
81
|
+
| Disposable source checkout | L26-L28 | Context retrieval, ecosystem evidence, and security assurance without modifying course projects |
|
|
81
82
|
|
|
82
83
|
## Command Ownership
|
|
83
84
|
|
|
@@ -95,6 +96,7 @@ against `cairn help` so a new command cannot bypass a curriculum decision.
|
|
|
95
96
|
| `cairn sync-kimi` | L02 |
|
|
96
97
|
| `cairn sync-omp` | L02 |
|
|
97
98
|
| `cairn doctor` | L03; advanced repair in L13-L14 |
|
|
99
|
+
| `cairn security` | L28 |
|
|
98
100
|
| `cairn playbook` | L25 |
|
|
99
101
|
| `cairn trajectory` | L13 |
|
|
100
102
|
| `cairn artifact` | L13 |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cairnkeep feature guide
|
|
2
2
|
|
|
3
|
-
**Baseline:** Cairnkeep 2.
|
|
3
|
+
**Baseline:** Cairnkeep 2.21.0
|
|
4
4
|
|
|
5
5
|
This is the step-back map for choosing and operating Cairnkeep features. The
|
|
6
6
|
[course labs](https://github.com/cairnkeep/cairnkeep-course-labs) provide one
|
|
@@ -27,6 +27,9 @@ locator and actual tool invocation must be verified from runtime evidence.
|
|
|
27
27
|
Version 2.20 adds OpenCode 2.0.24 plugin and compaction compatibility plus
|
|
28
28
|
operator-invoked ecosystem evidence runners; see
|
|
29
29
|
[L27](lessons/L27-ecosystem-evidence.md).
|
|
30
|
+
Version 2.21 adds the formal threat model, a read-only local security posture
|
|
31
|
+
check, portable-path adversarial coverage, bounded HTTP requests, and repository
|
|
32
|
+
supply-chain gates; see [L28](lessons/L28-security-assurance.md).
|
|
30
33
|
|
|
31
34
|
## The three-layer model
|
|
32
35
|
|
|
@@ -70,6 +73,7 @@ prerequisites for ordinary memory.
|
|
|
70
73
|
| Wiki and alignment | `/wiki-ingest`, `/wiki-query`, `/wiki-lint`, alignment files | Written only when invoked; reviewable `.planning/` artifacts | Re-run lint, inspect source citations, revert tracked changes normally | `course-02-memory` |
|
|
71
74
|
| Local code graph | `cairn graph build|query|status|diff|explain|path`; `/graphify` delegates | Default off; optional isolated `graphify` executable; incremental work under `graphify-out/`, published view under `.planning/graphs/` | Ignore both derived locations; check status and source before trusting a result; use `--force` only after intentional deletion; uninstall adapters separately | `course-08-graph` |
|
|
72
75
|
| Repository quality | `/repo-review`, `/security-audit` | On-demand workflow; findings are hypotheses until reproduced | Require file/line evidence and regression tests | `course-03-quality` |
|
|
76
|
+
| Security posture | `cairn security doctor [--project PATH] [--json]` | Read-only local configuration and permission inspection; no network; token values never emitted | Resolve failures, decide warnings explicitly, and re-run after exposure or authority changes | Disposable source checkout, L28 |
|
|
73
77
|
| Guided project setup | `cairn setup [PATH]` selectors; deterministic `--git`, `--harness`, `--memory`, and `--yes` flags | Arrow-key Git/memory choices and harness checkboxes in capable terminals; text fallback otherwise; reconciles only selected assets; private `.ai/cairnkeep.json`; machine sync is never automatic | Repeat deterministically, run doctor, or replay its recovery command; Git-less mode remains limited | `course-12-guided-setup` |
|
|
74
78
|
| Codex project memory | Select `--harness codex --memory local` | Writes `.codex/config.toml` plus POSIX/native Windows launchers; local stdio; user-wide configuration and trust remain untouched | Review the MCP table, accept Codex project trust, run doctor, and relaunch; uninstall is backup-first | `course-01-bootstrap` |
|
|
75
79
|
| Workflow playbooks and durable-context guidance | `cairn playbook check start|check|finish`; project `minimal`, `balanced`, or `strict` policy; managed `AGENTS.md` retrieval protocol | Balanced by default; private `.ai/playbooks.json`; one task-derived project search when applicable; optional receipts in `.agentfs/playbooks/`; checks are offline and execute nothing | Verify the actual memory tool event and maintained source, inspect status/digests, enforce truthful `must` evidence, inspect receipts, reset overrides, remove only the managed `AGENTS.md` block | `course-13-playbooks` |
|
|
@@ -108,6 +112,7 @@ prerequisites for ordinary memory.
|
|
|
108
112
|
| General meta-agent loop | Not shipped | Not applicable | Playbooks select bounded existing actions; no generic configuration loop, command language, or scheduler | `course-07-evaluation` |
|
|
109
113
|
| Pack retrieval and skills | `CAIRN_CONTEXT_PACKS=1`; HTTP needs separate consent; skills need exact-digest approval | Restart MCP server | `cairn pack skills`; revoke approval or disable pack; no automatic execution | `course-10-trust-context` |
|
|
110
114
|
| Ecosystem evidence runners | Explicit script invocation plus caller-supplied binaries/model configuration | None; disposable processes only | Temporary state is removed by default; inspect the JSON report and pinned evidence | Disposable source checkout, L27 |
|
|
115
|
+
| Security assurance | `cairn security doctor`; repository security workflows and offline gates | No restart for diagnostics; runtime HTTP bounds apply after server restart | Inspect failures/warnings, run security baseline and smoke gates, read residual risks | Disposable source checkout, L28 |
|
|
111
116
|
|
|
112
117
|
## Harness and maintenance checks
|
|
113
118
|
|
package/docs/learning/README.md
CHANGED
|
@@ -62,6 +62,7 @@ expanded only after their labs are executable.
|
|
|
62
62
|
| L25 | [Bounded workflow playbooks](lessons/L25-playbooks.md) | Ready | 35 min |
|
|
63
63
|
| L26 | [Context intelligence with explicit authority](lessons/L26-context-intelligence.md) | Ready | 45 min |
|
|
64
64
|
| L27 | [Evaluate context companions without moving authority](lessons/L27-ecosystem-evidence.md) | Ready | 30 min |
|
|
65
|
+
| L28 | [Verify Cairnkeep's security posture](lessons/L28-security-assurance.md) | Ready | 30 min |
|
|
65
66
|
|
|
66
67
|
The [curriculum coverage map](CURRICULUM-MAP.md) records where every public
|
|
67
68
|
feature is introduced, practised, and operated. It also marks design-only work
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# L28 - Verify Cairnkeep's security posture
|
|
2
|
+
|
|
3
|
+
**Status:** Ready
|
|
4
|
+
**Tested with:** Cairnkeep 2.21.0 and Node.js 22 or newer
|
|
5
|
+
|
|
6
|
+
## Outcome
|
|
7
|
+
|
|
8
|
+
You will distinguish repository assurance from local deployment posture, run a
|
|
9
|
+
read-only security diagnostic, deliberately reproduce a weak-token failure,
|
|
10
|
+
and choose least authority for a network-facing MCP client.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- Install Cairnkeep 2.21.0 or use a disposable source checkout.
|
|
15
|
+
- Complete [L20 - Least-authority MCP tool profiles](L20-mcp-tool-profiles.md).
|
|
16
|
+
- Use synthetic values only; never paste a real bearer token into a recording,
|
|
17
|
+
terminal transcript, or issue.
|
|
18
|
+
|
|
19
|
+
## Exercise
|
|
20
|
+
|
|
21
|
+
Create a disposable project and inspect the local-only posture:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
lab=$(mktemp -d)
|
|
25
|
+
mkdir -p "$lab/.ai"
|
|
26
|
+
chmod 700 "$lab/.ai"
|
|
27
|
+
cairn security doctor --project "$lab"
|
|
28
|
+
cairn security doctor --project "$lab" --json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
With HTTP disabled, the transport checks are `SKIP`. That is not missing
|
|
32
|
+
coverage: local stdio is the closed-by-default path.
|
|
33
|
+
|
|
34
|
+
Now model an unsafe deployment with a deliberately weak synthetic token:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
MCP_HTTP_PORT=7801 \
|
|
38
|
+
CAIRN_MEMORY_HTTP_TOKEN=short \
|
|
39
|
+
cairn security doctor --project "$lab" --json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The command exits non-zero and reports `http-token` as `FAIL`. Confirm that the
|
|
43
|
+
JSON does not contain `short`. Then model a bounded observation-only endpoint:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
MCP_HTTP_PORT=7801 \
|
|
47
|
+
MCP_HTTP_HOST=127.0.0.1 \
|
|
48
|
+
CAIRN_MEMORY_HTTP_TOKEN=synthetic-0123456789abcdef-0123456789abcdef \
|
|
49
|
+
CAIRN_MCP_TOOL_PROFILE=read-only \
|
|
50
|
+
cairn security doctor --project "$lab"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The diagnostic passes. This does not start the server, modify the project, or
|
|
54
|
+
prove that a reverse proxy supplies TLS; it checks only the effective local
|
|
55
|
+
configuration visible to this process.
|
|
56
|
+
|
|
57
|
+
Read [Security assurance and threat model](../../security-assurance.md), then
|
|
58
|
+
map each control to one boundary: project storage, MCP authority, remote
|
|
59
|
+
transport, context content, or release supply chain.
|
|
60
|
+
|
|
61
|
+
## Verification
|
|
62
|
+
|
|
63
|
+
From a source checkout, run the maintained offline gates:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npm run security:baseline
|
|
67
|
+
scripts/test-security-baseline.sh
|
|
68
|
+
npm --prefix mcp-memory-server run check:security-assurance
|
|
69
|
+
npm --prefix mcp-memory-server run check:http-guard
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The baseline rejects unpinned external Actions and `pull_request_target`. The
|
|
73
|
+
smoke tests cover token non-disclosure, request bounds, and deterministic
|
|
74
|
+
portable-path adversarial cases.
|
|
75
|
+
|
|
76
|
+
## Common failures
|
|
77
|
+
|
|
78
|
+
- A private `.ai` file is group/world accessible on POSIX: restore mode `0600`.
|
|
79
|
+
- HTTP is non-loopback without an explicit Host allowlist: set the public host
|
|
80
|
+
names and ports intentionally.
|
|
81
|
+
- A network client receives the `full` profile although it only observes:
|
|
82
|
+
choose `read-only` or a reviewed `custom` allowlist and restart the server.
|
|
83
|
+
- A remote URL uses plaintext HTTP: use HTTPS, unless it is an intentional
|
|
84
|
+
loopback-only hop.
|
|
85
|
+
|
|
86
|
+
## Privacy and trust boundary
|
|
87
|
+
|
|
88
|
+
The diagnostic reads configuration, file metadata, and only the length and
|
|
89
|
+
simple repetition of a configured token. It writes nothing and performs no
|
|
90
|
+
network request, but JSON includes the canonical project path. A passing report
|
|
91
|
+
is point-in-time evidence, not a certification or a substitute for TLS, host
|
|
92
|
+
hardening, secret management, or multi-user authorization.
|
|
93
|
+
|
|
94
|
+
## Recovery
|
|
95
|
+
|
|
96
|
+
Remove the disposable directory after inspecting the output:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
rm -rf -- "$lab"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For a real project, correct only the named file or environment setting. Do not
|
|
103
|
+
delete durable memory or regenerate credentials merely to silence a warning;
|
|
104
|
+
first decide whether the reported exposure is intentional.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# V28 - Security evidence you can inspect
|
|
2
|
+
|
|
3
|
+
Target length: 10–12 minutes. Audience: experienced developers operating an
|
|
4
|
+
agent-memory service locally or behind authenticated HTTP.
|
|
5
|
+
|
|
6
|
+
## Recording outline
|
|
7
|
+
|
|
8
|
+
### 0:00–1:20 — Threat model before tooling
|
|
9
|
+
|
|
10
|
+
Animate five boundaries: project storage, MCP authority, remote transport,
|
|
11
|
+
retrieved content, and release supply chain. State that Cairnkeep is not a
|
|
12
|
+
sandbox, secret manager, TLS terminator, or multi-user ACL.
|
|
13
|
+
|
|
14
|
+
### 1:20–3:20 — Safe local baseline
|
|
15
|
+
|
|
16
|
+
Type at human speed in a disposable directory:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
lab=$(mktemp -d)
|
|
20
|
+
mkdir -p "$lab/.ai"
|
|
21
|
+
chmod 700 "$lab/.ai"
|
|
22
|
+
cairn security doctor --project "$lab"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Pause on the skipped HTTP checks. Explain that disabled network exposure is the
|
|
26
|
+
expected secure default, not a missing test.
|
|
27
|
+
|
|
28
|
+
### 3:20–5:30 — Make one failure visible
|
|
29
|
+
|
|
30
|
+
Run the weak synthetic-token example from L28. Zoom into the non-zero exit and
|
|
31
|
+
the `http-token` failure, then search the JSON for the planted value to show it
|
|
32
|
+
was not emitted. Leave a two-second pause before remediation.
|
|
33
|
+
|
|
34
|
+
### 5:30–7:20 — Reduce authority
|
|
35
|
+
|
|
36
|
+
Re-run with a long synthetic token, loopback host, and
|
|
37
|
+
`CAIRN_MCP_TOOL_PROFILE=read-only`. Put the tool-catalog intersection on screen:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
feature gates ∩ capabilities ∩ MCP profile = exposed tools
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Stress that a profile removes authority; it never enables a feature.
|
|
44
|
+
|
|
45
|
+
### 7:20–9:20 — Show repository evidence
|
|
46
|
+
|
|
47
|
+
Use a split terminal for:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npm run security:baseline
|
|
51
|
+
npm --prefix mcp-memory-server run check:security-assurance
|
|
52
|
+
npm --prefix mcp-memory-server run check:http-guard
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Highlight full-SHA action pins, CodeQL, dependency review, token non-leakage,
|
|
56
|
+
portable Windows/POSIX path cases, and the HTTP 413 test. Do not show repository
|
|
57
|
+
secrets or live security-alert details.
|
|
58
|
+
|
|
59
|
+
### 9:20–10:30 — Read the residual risks
|
|
60
|
+
|
|
61
|
+
End on `docs/security-assurance.md`, not on a green checkmark. Call out the
|
|
62
|
+
same-account trust boundary, lack of per-user HTTP ACLs, unencrypted local
|
|
63
|
+
databases, and prompt-injection residual risk. The closing message is: evidence
|
|
64
|
+
narrows uncertainty; it does not abolish trust.
|
|
65
|
+
|
|
66
|
+
## Recording cautions
|
|
67
|
+
|
|
68
|
+
- Use only a temporary project and synthetic token.
|
|
69
|
+
- Keep commands, exit codes, and report states legible; cut dead time rather
|
|
70
|
+
than speeding narration.
|
|
71
|
+
- Do not imply that Scorecard, CodeQL, an SBOM, or provenance is a certification.
|
|
72
|
+
- Delete the exact temporary directory on screen at the end.
|
package/docs/operating.md
CHANGED
|
@@ -829,22 +829,57 @@ is guarded and **fails closed**:
|
|
|
829
829
|
|
|
830
830
|
| Variable | Purpose |
|
|
831
831
|
|---|---|
|
|
832
|
-
| `MCP_HTTP_PORT` | Enable HTTP mode
|
|
832
|
+
| `MCP_HTTP_PORT` | Enable HTTP mode with a canonical decimal port from 1 through 65535 (unset → stdio; signs, whitespace, prefixes, and suffixes are rejected) |
|
|
833
833
|
| `MCP_HTTP_HOST` | Bind address (default `127.0.0.1`) |
|
|
834
|
-
| `CAIRN_MEMORY_HTTP_TOKEN` | **Required** in HTTP mode — clients send `Authorization: Bearer <token>`; the server refuses to start without
|
|
834
|
+
| `CAIRN_MEMORY_HTTP_TOKEN` | **Required** in HTTP mode — clients send `Authorization: Bearer <token>`; the server refuses to start without a header-safe ASCII Bearer value |
|
|
835
|
+
| `CAIRN_MEMORY_HTTP_TOKEN_FILE` | Alternative private token file; set exactly one token source. Relative paths resolve from the server/project root. The direct server validates a private non-symlink file; the container entrypoint converts its mounted secret to the direct token and clears `_FILE` |
|
|
835
836
|
| `CAIRN_MEMORY_HTTP_ALLOWED_ORIGINS` | Comma-separated browser origins allowed via CORS (default: none — no cross-origin access) |
|
|
836
|
-
| `CAIRN_MEMORY_HTTP_ALLOWED_HOSTS` | Comma-separated
|
|
837
|
+
| `CAIRN_MEMORY_HTTP_ALLOWED_HOSTS` | Comma-separated `host:port` authorities allowed for DNS-rebinding protection (default: the bind host + `localhost` on the chosen port; bracket IPv6 literals) |
|
|
837
838
|
| `CAIRN_ARTIFACT_HTTP` | Additional consent for artifact tools (default off; requires `CAIRN_ARTIFACT_STORE`, a valid `X-Cairn-Project`, bearer auth, and the normal Host/CORS checks) |
|
|
838
839
|
|
|
839
840
|
Requests without a valid bearer token get `401`; requests with an unexpected
|
|
840
|
-
`Host` header get `403
|
|
841
|
-
|
|
841
|
+
`Host` header get `403`; request bodies over 8 MiB get `413`. The server also
|
|
842
|
+
bounds header size, header/request duration, and keep-alive time. Keep HTTP mode
|
|
843
|
+
bound to `127.0.0.1` unless you have a specific reason to expose it, and use a
|
|
844
|
+
random token of at least 32 bytes. HTTP mode has no
|
|
842
845
|
per-user ACL or tenant isolation. Clients may bind sessions to separate project
|
|
843
846
|
databases with validated `X-Cairn-Project` routing metadata, but that metadata
|
|
844
847
|
is not an authorization boundary. See [Memory storage and deployment](storage.md)
|
|
845
848
|
for the placement rules, client registration, TLS requirements, project headers,
|
|
846
849
|
and backup boundaries.
|
|
847
850
|
|
|
851
|
+
### Security posture check
|
|
852
|
+
|
|
853
|
+
`cairn security doctor [--project PATH] [--json]` performs a read-only local
|
|
854
|
+
posture check. It validates canonical project placement and its immediate
|
|
855
|
+
replacement boundary, permissions on private managed files, the effective MCP
|
|
856
|
+
profile, HTTP token strength and token-file
|
|
857
|
+
safety, explicit Host allowlisting for network bindings, least authority, and
|
|
858
|
+
remote URL encryption. It never prints a token value. A failed check exits 1;
|
|
859
|
+
warnings remain visible but nonfatal, and disabled optional surfaces are
|
|
860
|
+
reported as skipped.
|
|
861
|
+
|
|
862
|
+
The command safely parses literal `KEY=value`, single-quoted, or double-quoted
|
|
863
|
+
assignments from the selected project's private `.ai/.env` through a
|
|
864
|
+
descriptor-bound 64 KiB read; it never sources or executes that file. Ambient variables take precedence, matching launcher
|
|
865
|
+
override behavior. Shell expansion, command substitution, or another ambiguous
|
|
866
|
+
line fails the environment check instead of being evaluated. Relative token
|
|
867
|
+
files are resolved from the selected project, even when the command is invoked
|
|
868
|
+
from another directory. Unquoted values accept only letters, digits, and the
|
|
869
|
+
literal characters `_./:@%+,=-`; use single or double quotes for other literal
|
|
870
|
+
punctuation. POSIX file checks require ownership by the current account or the
|
|
871
|
+
trusted root account in addition to restrictive mode bits.
|
|
872
|
+
|
|
873
|
+
The generated POSIX launchers snapshot exported ambient variables before
|
|
874
|
+
sourcing `.ai/.env`, then restore those existing values. Project-only variables
|
|
875
|
+
are added, while an explicit process environment remains the highest-precedence
|
|
876
|
+
override, matching the Windows launchers and the posture report.
|
|
877
|
+
|
|
878
|
+
Run it after setup, after changing HTTP or MCP-profile configuration, and
|
|
879
|
+
before a security-sensitive deployment. It does not replace `cairn doctor`,
|
|
880
|
+
TLS, a secret manager, or a multi-user authorization layer. See
|
|
881
|
+
[Security assurance and threat model](security-assurance.md).
|
|
882
|
+
|
|
848
883
|
## Project playbooks
|
|
849
884
|
|
|
850
885
|
Guided setup and tracked bootstrap create private `.ai/playbooks.json` mode
|
|
@@ -156,6 +156,20 @@ Sanitized test replay uses synthetic tool arguments, results, stderr, and
|
|
|
156
156
|
project paths only; release evidence must not include credentials, private
|
|
157
157
|
endpoints, memory values, or identifying local paths.
|
|
158
158
|
|
|
159
|
+
`cairn security doctor` reads filesystem metadata for private project files and,
|
|
160
|
+
when HTTP is configured, the bearer token or configured token file only far
|
|
161
|
+
enough to check presence, byte length, repetition, header-safe syntax, and file safety. It emits no
|
|
162
|
+
token content, writes no state, and makes no network request. JSON output can
|
|
163
|
+
contain the canonical project path and should be treated as local diagnostic
|
|
164
|
+
data. The command parses literal assignments from `.ai/.env` without sourcing
|
|
165
|
+
the file, expanding variables, or executing commands; reads are descriptor-bound
|
|
166
|
+
and limited to 64 KiB, and the ambient environment retains precedence. Relative
|
|
167
|
+
token-file paths are anchored to the selected project rather than the caller's
|
|
168
|
+
working directory. The accepted literal grammar excludes unquoted shell
|
|
169
|
+
control, grouping, redirection, escape, expansion, tilde syntax, and control
|
|
170
|
+
bytes. Generated launchers restore existing ambient values after loading the
|
|
171
|
+
file, so the diagnostic and runtime use the same precedence.
|
|
172
|
+
|
|
159
173
|
## Evaluation adapter and report flow
|
|
160
174
|
|
|
161
175
|
`CAIRN_EVAL` is unset/off by default. With it off, `cairn eval` returns a fixed
|
package/docs/releasing.md
CHANGED
|
@@ -8,7 +8,8 @@ from a workstation.
|
|
|
8
8
|
1. Update the root `package.json` version and `CHANGELOG.md` on a pull request.
|
|
9
9
|
2. Run `npm ci`, `npm run check:public`, and
|
|
10
10
|
`npm --prefix mcp-memory-server test`.
|
|
11
|
-
3. Merge only after every required CI check passes.
|
|
11
|
+
3. Merge only after every required CI and security check passes. CodeQL and
|
|
12
|
+
dependency review are blocking; OpenSSF Scorecard is advisory evidence.
|
|
12
13
|
4. Publish a GitHub Release whose tag is exactly `v<package.json version>`.
|
|
13
14
|
5. After every platform and runtime job passes, CI builds one release candidate
|
|
14
15
|
keyed by the exact Git tree. It contains the npm tarball, reproducible
|
|
@@ -58,3 +59,10 @@ automatic. Confirm an unauthenticated pull after changing visibility.
|
|
|
58
59
|
|
|
59
60
|
Treat a published version as immutable. If a release is wrong, fix it in a new
|
|
60
61
|
version rather than moving its tag or replacing the npm package.
|
|
62
|
+
|
|
63
|
+
Repository Actions are restricted to the maintained allowlist and every
|
|
64
|
+
non-local action reference must use a full commit SHA. `npm run
|
|
65
|
+
security:baseline` enforces that contract, rejects `pull_request_target`, and
|
|
66
|
+
asserts that CodeQL, dependency review, and advisory Scorecard workflows remain
|
|
67
|
+
present. See [Security assurance and threat model](security-assurance.md) for
|
|
68
|
+
the wider threat model and residual risks.
|