Skip to content

Commit f65da1e

Browse files
castor-agentclaude
andcommitted
chore: merge main (v0.14.0) back to dev
Brings tenant isolation fix, security advisory, and guardrail changes from v0.14.0 into dev. Conflict resolution: took main for all conflicted files (security patches in src/actions.ts, src/server.ts, src/services/relationships.ts, src/shared/action_schemas.ts, tests/security/tenant_isolation_matrix.test.ts, and docs/security/). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2 parents 2778ff2 + 94a6b25 commit f65da1e

5,334 files changed

Lines changed: 189041 additions & 241714 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
2. **Foundation documents** from `docs/foundation/` in this order:
1212
- `core_identity.md` — What Neotoma is and is not (State Layer scope)
1313
- `philosophy.md` — Core principles and architectural invariants
14-
- `layered_architecture.md` — State Layer, Strategy Layer, Execution Layer
14+
- `layered_architecture.md` — State Layer (Neotoma) and Operational Layer(s) above it
1515
- `product_principles.md` — Product design principles
1616
- `agent_instructions_rules.mdc` — Repository-wide agent instructions and validation checklist
1717
3. **Task-specific docs** as indicated by the index (e.g. subsystems, architecture, testing)

.claude/rules/agent_instructions_sync_rules.md

Lines changed: 26 additions & 244 deletions
Large diffs are not rendered by default.

.claude/rules/change_guardrails_rules.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ For each change type, follow the linked canonical doc. The matrix lists only the
4646
| New CLI runtime override (env var + flag) | `docs/developer/cli_reference.md` § Runtime overrides | `src/cli/index.ts` `preAction` hook, env-var precedence table in cli_reference |
4747
| Error response / envelope change | `docs/subsystems/errors.md` | `openapi.yaml` schema, server builders, contract / unit tests |
4848
| User-scoped endpoint / user-id handling | `docs/subsystems/auth.md` § User-ID Resolution | `getAuthenticatedUserId` usage; `openapi.yaml` query params; never parallel resolution paths |
49+
| Auth middleware / proxy trust / local-dev shortcuts (the v0.11.1 class) | `docs/security/threat_model.md` + `.cursor/skills/release/SKILL.md` § Step 3.5 | `src/actions.ts` (exported: `isLocalRequest`; internal: `forwardedForValues`, `isProductionEnvironment`); `src/services/root_landing/**` mirrors; `protected_routes_manifest.json` regenerated via `npm run security:manifest:write`; `npm run security:lint` clean; `tests/security/auth_topology_matrix.test.ts` updated when the topology surface changes; supplement `Security hardening` section + `docs/security/advisories/` entry on regression |
4950
| MCP ↔ CLI agent-instruction parity | `docs/developer/agent_instructions_sync_rules.mdc` | Mirrored edits in both instruction files + anchor-table row |
5051

5152
**Data model & core semantics**
@@ -89,6 +90,12 @@ These rules sit between subsystems. Each canonical doc covers its own surface; o
8990
13. A PR that causes previously-accepted input to start returning an `ERR_*` MUST populate a structured `hint` at the validation seam in the same change (`docs/subsystems/errors.md` § Tightening-change hint obligation) and update an entry in `tests/contract/legacy_payloads/` (flip `outcome` to `rejected`, populate `hint_match`, add a line to `CHANGES.md`).
9091
14. Tightening request-shape validation — closing an `additionalProperties`, adding a required field, narrowing a type, removing an enum value — is a breaking change and MUST be named in the release supplement's "Breaking changes" section (`docs/developer/github_release_process.md` § Validation tightening is breaking), regardless of whether the tightened shape was previously declared in `openapi.yaml`.
9192
15. Every release supplement MUST contain an explicit "Breaking changes" section. Use the literal line `No breaking changes.` when none exist; never omit the section (`.cursor/skills/release/SKILL.md` § Step 3).
93+
16. Authority over loopback / proxy / `X-Forwarded-For` trust lives in `src/actions.ts` (`isLocalRequest`, `forwardedForValues`, `isProductionEnvironment`) and the matching helpers in `src/services/root_landing/**`. Any new code that needs to know "is this request local?" MUST consume those exports — not a bare `req.socket.remoteAddress` check, not a `Host` header read, not an inlined fork (`docs/security/threat_model.md`). Treat the v0.11.1 advisory shape as a regression class, not a one-off.
94+
17. Every new Express route MUST land in `scripts/security/protected_routes_manifest.json` (auth-required) or in the runtime allow-list with a stated `reason`. Run `npm run security:manifest:write` in the same change; CI's `security_gates` job runs `--check` and rejects drift.
95+
18. Every release that the diff classifier (`scripts/security/classify_diff.js`) labels `sensitive=true` MUST land with a filled `docs/releases/in_progress/<TAG>/security_review.md` and a supplement `Security hardening` section linking it. `none` provider mode is acceptable, manual fill is mandatory.
96+
19. Every new **destructive or data-mutating operation** (DB migration, encryption migration, repair command, bulk-rewrite over user data) MUST ship with a real round-trip integration test that operates on a real file, not in-memory stubs. The test MUST cover: identity (forward→inverse leaves the data unchanged), dry-run non-mutation, idempotency on re-run, and NULL preservation. See `docs/testing/testing_standard.md` § Destructive operations.
97+
20. Every new **external-file-shape parser** (harness transcripts, SQLite imports, third-party config formats) MUST ship with a test that exercises the actual parsing path against a fixture file in the supported format. Detection-only tests (asserting `detectSource` returns the right tag) are not coverage of parsing.
98+
21. Every new **HTTP server runtime-config knob** (timeouts, connection behavior, header policy) MUST ship with a test that asserts the *runtime* behavior — a response header value, a socket lifetime, an observable connection property — not just the source string. A constant declared in code with no runtime assertion regresses silently.
9299

93100
### MUST NOT
94101

@@ -106,6 +113,9 @@ These rules sit between subsystems. Each canonical doc covers its own surface; o
106113
12. Create untyped relationships or cycles in hierarchical relationship types (`docs/subsystems/relationships.md`).
107114
13. Tighten validation of a previously-tolerated request shape without (a) a structured `hint`, (b) a legacy-payload fixture flipped to `rejected`, and (c) a line in the release supplement's "Breaking changes" section. Silent tightenings are the specific regression mode the legacy-payload corpus and the OpenAPI breaking-change diff gate exist to catch.
108115
14. Omit the "Breaking changes" section from a release supplement, even for patch releases with no breaking changes. Write `No breaking changes.` explicitly.
116+
15. Read `req.socket.remoteAddress`, `req.headers["x-forwarded-for"]`, `req.headers["host"]`, or `req.header("host")` directly outside `src/actions.ts` and `src/services/root_landing/**`. Use the canonical helpers; the static rule `forwarded-for-trust` (gate G2) is gating, not advisory.
117+
16. Reference `LOCAL_DEV_USER_ID` outside `src/cli/**`, `src/services/local_auth.ts`, and `tests/**`. Widening the local-dev surface is the same class as the v0.11.1 Inspector auth-bypass; gate any exception behind `assertExplicitlyTrusted("…")` and a written rationale in `docs/security/threat_model.md`.
118+
17. Register a new public Express route without either `auth.requireUser()` / `assertGuestWriteAllowed()` middleware OR an entry in the runtime unauth allow-list of `protected_routes_manifest.json` with a stated `reason`. Silent additions are the exact regression mode the manifest sync gate exists to catch.
109119

110120
### SHOULD
111121

@@ -124,7 +134,7 @@ Before opening a PR that touches any surface in the Touchpoint Matrix, confirm:
124134
- [ ] `src/shared/contract_mappings.ts` updated for any new `operationId`, MCP tool, or CLI command.
125135
- [ ] `npm test -- tests/contract/` passes.
126136
- [ ] New top-level CLI commands listed in `tests/cli/cli_command_coverage_guard.test.ts`.
127-
- [ ] MCP and CLI agent-instruction parity confirmed via `neotoma cli-instructions check`.
137+
- [ ] MCP and CLI agent-instruction parity confirmed via `neotoma cli config --yes`.
128138
- [ ] Runtime overrides follow `flag > env > default` and appear in the cli_reference Runtime overrides table.
129139
- [ ] New env vars are `NEOTOMA_`-prefixed and read in `preAction`.
130140
- [ ] Error hints emitted as structured `hint` / `details` fields, not concatenated into `message`.
@@ -139,6 +149,14 @@ Before opening a PR that touches any surface in the Touchpoint Matrix, confirm:
139149
- [ ] Mutating ops honor `idempotency_key`; ingestion writes are transactional.
140150
- [ ] No new PII in logs, metric labels, event payloads, or error messages.
141151
- [ ] Renamed files are `snake_case` and `foundation_config.yaml` + `.claude/rules/` symlinks are updated.
152+
- [ ] `npm run security:classify-diff` recorded; if `sensitive=true`, `npm run security:lint` is clean, `npm run security:manifest:check` passes, `npm run test:security:auth-matrix` passes, and `docs/releases/in_progress/<TAG>/security_review.md` exists with a sign-off verdict.
153+
- [ ] New Express routes registered in `protected_routes_manifest.json` (or runtime unauth allow-list with a `reason`); manifest regenerated via `npm run security:manifest:write` when needed.
154+
- [ ] No bare `req.socket.remoteAddress`, `X-Forwarded-For`, or `Host` reads outside `src/actions.ts` / `src/services/root_landing/**`; auth-local fallbacks (`!auth && isLocalRequest`) gated through `assertExplicitlyTrusted`.
155+
- [ ] **User-facing-surface coverage**: any new CLI command, new CLI flag, new destructive/data-mutating operation, new external-file-shape parser, or new HTTP runtime-config knob has a test that exercises the **user-observable behavior end-to-end**, not just a helper function. A test file with the right name that only covers an internal helper is not coverage. Required regression tests by surface class:
156+
- Destructive operations (DB migrations, encryption migrations, repair commands): real round-trip test against a real file — encrypt→decrypt identity, dry-run non-mutation, idempotency on re-run, NULL preservation.
157+
- External-file-shape parsers (harness transcripts, SQLite imports, third-party config): at least one fixture per supported format that exercises the actual parser path, not just `detectSource`.
158+
- Discovery / detection / parser pairs: a roundtrip test asserting paths emitted by discovery are parseable by the parser.
159+
- HTTP runtime config (timeouts, headers, keep-alive): a test that asserts the *runtime* behavior (response header, socket lifetime), not just the source string.
142160

143161
## Canonical doc index
144162

@@ -147,11 +165,14 @@ Load the canonical doc for the surface your change touches, not this rule, for s
147165
**Foundation & architecture**
148166

149167
- `docs/NEOTOMA_MANIFEST.md` — root invariants: State Layer, determinism, immutability, schema-first, no PII, no synthetic data.
150-
- `docs/foundation/layered_architecture.md` — State / Strategy / Execution Layer boundaries.
168+
- `docs/foundation/layered_architecture.md` — State Layer / Operational Layer boundaries.
151169
- `docs/architecture/architectural_decisions.md` — three-layer truth model and registry evolution.
152170
- `docs/architecture/determinism.md` — deterministic data layer vs bounded-convergence agents.
153171
- `docs/architecture/idempotence_pattern.md` — LLM stochasticity bounded by post-hoc canonicalization / hashing.
154172
- `docs/foundation/schema_agnostic_design_rules.md` — schema-driven behavior, no per-type branches.
173+
- `docs/security/threat_model.md` — channels the pre-release security gates cover (alternate-path auth, proxy trust, local-dev shortcuts, unauth public route, guest-access widening).
174+
- `docs/security/advisories/` — disclosed advisories, indexed by `README.md`; the seed entry `2026-05-11-inspector-auth-bypass.md` documents the v0.11.1 regression class the gates were designed against.
175+
- `.cursor/skills/release/SKILL.md` § Step 3.5 — Track 1 security gates (pre-release review lane); Track 2 (advisory + rollout via subscriptions / peer / guest) follows.
155176

156177
**API & contract**
157178

.claude/rules/feature_unit_detection.md

Lines changed: 0 additions & 132 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../docs/developer/cli_agent_instructions.md
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
description: "Keep the automated test catalog and testing docs in sync with test-file, test-command, and CI-lane changes."
3+
globs:
4+
- "tests/**/*.ts"
5+
- "tests/**/*.tsx"
6+
- "src/**/*.test.ts"
7+
- "src/**/*.test.tsx"
8+
- "src/**/__tests__/**/*.ts"
9+
- "src/**/__tests__/**/*.tsx"
10+
- "frontend/src/**/*.test.ts"
11+
- "frontend/src/**/*.test.tsx"
12+
- "playwright/tests/**/*.spec.ts"
13+
- "package.json"
14+
- ".github/workflows/ci_test_lanes.yml"
15+
- "docs/testing/**"
16+
alwaysApply: false
17+
---
18+
19+
<!-- Source: docs/testing/test_catalog_maintenance_rules.mdc -->
20+
21+
22+
# Test Catalog Maintenance
23+
24+
- `docs/testing/automated_test_catalog.md` is the canonical automated-test inventory.
25+
- When automated test files are added, removed, moved, or renamed, run `npm run generate:test-catalog` in the same change.
26+
- When test commands, CI lanes, or default-vs-optional test modes change, update `docs/testing/automated_test_catalog.md` and `docs/testing/testing_standard.md` in the same change.
27+
- Before finishing, run `npm run validate:test-catalog`.
28+
- Do not hand-edit generated inventory entries in the catalog; update the generator or regenerate the file instead.

.claude/settings.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
{
22
"$schema": "https://json.schemastore.org/claude-code-settings.json",
33
"env": {},
4-
"hooks": {}
4+
"hooks": {
5+
"Stop": [
6+
{
7+
"matcher": "",
8+
"hooks": [
9+
{
10+
"type": "command",
11+
"command": "cd /Users/markmhendrickson/repos/neotoma && npm run mirror:plans 2>&1 | tail -5"
12+
}
13+
]
14+
}
15+
]
16+
}
517
}

.claude/settings.local.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
"WebFetch(domain:x.com)",
1414
"WebFetch(domain:chatgptguide.ai)",
1515
"WebFetch(domain:www.reddit.com)",
16-
"WebFetch(domain:old.reddit.com)"
16+
"WebFetch(domain:old.reddit.com)",
17+
"mcp__mcpsrv_neotoma_dev__retrieve_entity_by_identifier",
18+
"mcp__mcpsrv_neotoma_dev__get_session_identity",
19+
"Bash(mkdir -p /Users/markmhendrickson/repos/neotoma/.claude/skills/shadcn)",
20+
"mcp__mcpsrv_neotoma__get_authenticated_user"
1721
]
1822
},
1923
"enableAllProjectMcpServers": true,

0 commit comments

Comments
 (0)