@openparachute/vault 0.4.0 → 0.4.4-rc.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -2
- package/core/src/core.test.ts +1295 -526
- package/core/src/mcp.ts +129 -428
- package/core/src/notes.ts +405 -32
- package/core/src/obsidian.ts +55 -177
- package/core/src/portable-md.test.ts +1001 -0
- package/core/src/portable-md.ts +1409 -0
- package/core/src/schema-defaults.ts +233 -171
- package/core/src/schema.ts +104 -32
- package/core/src/store.ts +103 -78
- package/core/src/tag-hierarchy.ts +36 -2
- package/core/src/types.ts +52 -42
- package/core/src/vault-projection.ts +309 -0
- package/package.json +2 -2
- package/src/auth-hub-jwt.test.ts +142 -13
- package/src/auth.ts +29 -0
- package/src/cli.ts +699 -141
- package/src/doctor.test.ts +7 -6
- package/src/hub-jwt.test.ts +16 -5
- package/src/hub-jwt.ts +9 -0
- package/src/mcp-http.ts +4 -2
- package/src/mcp-install-interactive.test.ts +883 -0
- package/src/mcp-install-interactive.ts +412 -0
- package/src/mcp-install.test.ts +957 -5
- package/src/mcp-install.ts +580 -13
- package/src/mcp-tools.ts +101 -90
- package/src/routes.ts +330 -207
- package/src/routing.test.ts +12 -12
- package/src/routing.ts +0 -2
- package/src/tokens-routes.test.ts +11 -4
- package/src/vault.test.ts +1052 -333
- package/core/src/note-schemas.ts +0 -232
package/src/doctor.test.ts
CHANGED
|
@@ -156,16 +156,16 @@ describe("vault doctor — extended checks", () => {
|
|
|
156
156
|
// Isolated HOME with no ~/.claude.json at all — the most common
|
|
157
157
|
// pre-`mcp-install` state for new users.
|
|
158
158
|
const res = runCli(["doctor"], dir, { HOME: dir });
|
|
159
|
-
expect(res.stdout).toMatch(/! MCP entry in
|
|
160
|
-
expect(res.stdout).toMatch(/does not exist|no
|
|
159
|
+
expect(res.stdout).toMatch(/! MCP entry in MCP client config/);
|
|
160
|
+
expect(res.stdout).toMatch(/does not exist|no parachute-vault entry/);
|
|
161
161
|
expect(res.stdout).toMatch(/mcp-install/);
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
test("warns when ~/.claude.json exists but has no parachute-vault entry", () => {
|
|
165
165
|
writeFileSync(join(dir, ".claude.json"), JSON.stringify({ mcpServers: {} }));
|
|
166
166
|
const res = runCli(["doctor"], dir, { HOME: dir });
|
|
167
|
-
expect(res.stdout).toMatch(/! MCP entry in
|
|
168
|
-
expect(res.stdout).toMatch(/no
|
|
167
|
+
expect(res.stdout).toMatch(/! MCP entry in MCP client config/);
|
|
168
|
+
expect(res.stdout).toMatch(/no parachute-vault entry/);
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
test("passes MCP entry + port-match checks when URL points at the configured port", () => {
|
|
@@ -174,7 +174,8 @@ describe("vault doctor — extended checks", () => {
|
|
|
174
174
|
writeFileSync(join(dir, "config.yaml"), "port: 4321\n");
|
|
175
175
|
writeClaudeJson(dir, "http://127.0.0.1:4321/vault/default/mcp");
|
|
176
176
|
const res = runCli(["doctor"], dir, { HOME: dir });
|
|
177
|
-
|
|
177
|
+
// Doctor now names the source file in the check label.
|
|
178
|
+
expect(res.stdout).toMatch(/✓ MCP entry in ~\/\.claude\.json \(parachute-vault\)/);
|
|
178
179
|
expect(res.stdout).toMatch(/✓ MCP URL port matches vault\s+\(port 4321\)/);
|
|
179
180
|
// Reachability will warn because nothing is bound to 4321 in the test
|
|
180
181
|
// env — this is the "entry present, port matches, daemon unreachable"
|
|
@@ -186,7 +187,7 @@ describe("vault doctor — extended checks", () => {
|
|
|
186
187
|
writeFileSync(join(dir, "config.yaml"), "port: 4321\n");
|
|
187
188
|
writeClaudeJson(dir, "http://127.0.0.1:9999/vault/default/mcp");
|
|
188
189
|
const res = runCli(["doctor"], dir, { HOME: dir });
|
|
189
|
-
expect(res.stdout).toMatch(/✓ MCP entry in ~\/\.claude\.json/);
|
|
190
|
+
expect(res.stdout).toMatch(/✓ MCP entry in ~\/\.claude\.json \(parachute-vault\)/);
|
|
190
191
|
expect(res.stdout).toMatch(/! MCP URL port matches vault/);
|
|
191
192
|
expect(res.stdout).toMatch(/MCP URL port 9999 ≠ vault port 4321/);
|
|
192
193
|
});
|
package/src/hub-jwt.test.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { describe, test, expect, beforeAll, afterAll, beforeEach } from "bun:test";
|
|
16
16
|
import { generateKeyPair, exportJWK, SignJWT } from "jose";
|
|
17
|
-
import { resetJwksCache, validateHubJwt, looksLikeJwt } from "./hub-jwt.ts";
|
|
17
|
+
import { resetJwksCache, resetRevocationCache, validateHubJwt, looksLikeJwt } from "./hub-jwt.ts";
|
|
18
18
|
|
|
19
19
|
interface Keypair {
|
|
20
20
|
privateKey: CryptoKey;
|
|
@@ -53,11 +53,19 @@ function startJwksFixture(): JwksFixture {
|
|
|
53
53
|
port: 0,
|
|
54
54
|
fetch(req) {
|
|
55
55
|
const url = new URL(req.url);
|
|
56
|
-
if (url.pathname !== "/.well-known/jwks.json") {
|
|
57
|
-
return new Response("not found", { status: 404 });
|
|
58
|
-
}
|
|
59
56
|
if (down) return new Response("upstream down", { status: 503 });
|
|
60
|
-
|
|
57
|
+
if (url.pathname === "/.well-known/jwks.json") {
|
|
58
|
+
return Response.json({ keys: keys.map((k) => k.publicJwk) });
|
|
59
|
+
}
|
|
60
|
+
// scope-guard 0.2+ consults `/.well-known/parachute-revocation.json` on
|
|
61
|
+
// every JWT validation (when the token has a jti). Serve an empty list
|
|
62
|
+
// by default so unrelated tests in this file aren't fail-closed by a
|
|
63
|
+
// 404 on that endpoint. The integration tests (`auth-hub-jwt.test.ts`)
|
|
64
|
+
// own the revoked-jti / fail-closed cases separately.
|
|
65
|
+
if (url.pathname === "/.well-known/parachute-revocation.json") {
|
|
66
|
+
return Response.json({ generated_at: new Date().toISOString(), jtis: [] });
|
|
67
|
+
}
|
|
68
|
+
return new Response("not found", { status: 404 });
|
|
61
69
|
},
|
|
62
70
|
});
|
|
63
71
|
return {
|
|
@@ -121,6 +129,9 @@ beforeEach(() => {
|
|
|
121
129
|
fixture.setUnreachable(false);
|
|
122
130
|
fixture.setKeys([kp]);
|
|
123
131
|
resetJwksCache();
|
|
132
|
+
// Drop the per-process revocation cache so each test starts cold against
|
|
133
|
+
// the fixture (an empty list by default; tests opt into populated lists).
|
|
134
|
+
resetRevocationCache();
|
|
124
135
|
});
|
|
125
136
|
|
|
126
137
|
describe("looksLikeJwt", () => {
|
package/src/hub-jwt.ts
CHANGED
|
@@ -75,5 +75,14 @@ export function resetJwksCache(): void {
|
|
|
75
75
|
guard.resetJwksCache();
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Reset the cached revocation list. Tests use this to start from a clean
|
|
80
|
+
* fail-closed state between cases; production callers shouldn't need it
|
|
81
|
+
* (the cache refreshes itself on TTL expiry).
|
|
82
|
+
*/
|
|
83
|
+
export function resetRevocationCache(): void {
|
|
84
|
+
guard.resetRevocationCache();
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
export { HubJwtError, looksLikeJwt };
|
|
79
88
|
export type { HubJwtClaims, ValidateHubJwtOptions };
|
package/src/mcp-http.ts
CHANGED
|
@@ -41,7 +41,6 @@ const TOOL_REQUIRED_VERB: Record<string, VaultVerb> = {
|
|
|
41
41
|
"query-notes": "read",
|
|
42
42
|
"list-tags": "read",
|
|
43
43
|
"find-path": "read",
|
|
44
|
-
"synthesize-notes": "read",
|
|
45
44
|
"vault-info": "read",
|
|
46
45
|
"create-note": "write",
|
|
47
46
|
"update-note": "write",
|
|
@@ -58,7 +57,10 @@ function requiredVerbForTool(toolName: string): VaultVerb {
|
|
|
58
57
|
|
|
59
58
|
/** Handle scoped MCP at /vault/{name}/mcp (single vault). */
|
|
60
59
|
export async function handleScopedMcp(req: Request, vaultName: string, auth: AuthResult): Promise<Response> {
|
|
61
|
-
|
|
60
|
+
// Auth flows through to getServerInstruction so the connect-time
|
|
61
|
+
// markdown brief is filtered by `scoped_tags` — symmetric with the
|
|
62
|
+
// JSON `vault-info` wrapper.
|
|
63
|
+
const instruction = await getServerInstruction(vaultName, auth);
|
|
62
64
|
return handleMcp(req, () => generateScopedMcpTools(vaultName, auth), `parachute-vault/${vaultName}`, vaultName, auth, instruction);
|
|
63
65
|
}
|
|
64
66
|
|