@valbuild/server 0.121.0 → 0.122.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.
@@ -75,51 +75,42 @@ export type ValToolDefinitionJson = Omit<ValToolDefinition, "inputSchema"> & {
75
75
  inputSchema: ReturnType<typeof z.toJSONSchema<z.ZodType>>;
76
76
  };
77
77
  /**
78
- * How the caller was established, and it is a union because there are two
79
- * genuinely different answers — with different consequences downstream.
78
+ * How the caller was established, and there is one acceptable answer: the host
79
+ * **checked a signature**.
80
80
  *
81
- * The distinction that matters is **who checked**. A PAT is forwarded to the
82
- * backend unchecked, because the app cannot resolve one; an access token is
83
- * verified by the app itself, against a public key it does not hold and
84
- * therefore cannot forge. The first is a credential being relayed. The second
85
- * is a signature that has already been checked.
81
+ * A union of one, deliberately. It carried a second variant — a personal access
82
+ * token relayed to the backend unchecked, on the reasoning that the app cannot
83
+ * resolve one and the backend can. The reasoning held; the shape did not. A
84
+ * credential the host cannot check is one it also cannot refuse, so accepting
85
+ * one made "a deployed endpoint that authenticates nobody" a supported
86
+ * configuration, and it let a host serve these tools without ever being told
87
+ * where callers should authorize. The discriminant stays so that adding a
88
+ * second *verified* kind stays a one-line change at every call site.
86
89
  */
87
90
  export type ValToolAuth = {
88
- type: "pat";
89
- /**
90
- * The caller's PAT. Never log this, never put it in a URL, and never let
91
- * it reach a tool result.
92
- *
93
- * Relayed to the backend as-is: this app is not the authority on what the
94
- * token may do, and the backend that is decides. Nothing is derived from
95
- * it here — see `docs/plans/mcp.md` D.2.
96
- */
97
- pat: string;
98
- } | {
99
91
  type: "verified-profile";
100
92
  /**
101
93
  * The profile the host **verified** — the `sub` of an access token whose
102
94
  * signature, issuer, audience and expiry were all checked against the
103
95
  * authorization server's published key.
104
96
  *
105
- * This field is the reason this type became a union, and an earlier
106
- * version of this file argued no identity field should exist at all. That
107
- * argument was about a specific case and stated too broadly: an id the
108
- * host *asserts* on the strength of a credential it cannot check is an
109
- * unverified claim dressed as a checked one, and that is still refused —
110
- * it is why the `pat` variant carries no profile. An id the host
111
- * *verified* cryptographically is a different thing, and it is the same
112
- * standing the Studio has when it re-signs a session it established
113
- * itself.
97
+ * This field is why an identity field exists at all, and an earlier version
98
+ * of this file argued none should. That argument was about a specific case
99
+ * and stated too broadly: an id the host *asserts* on the strength of a
100
+ * credential it cannot check is an unverified claim dressed as a checked one,
101
+ * and that is still refused — it is why a relayed token never carried a
102
+ * profile, and now cannot reach here at all. An id the host *verified*
103
+ * cryptographically is a different thing, and it is the same standing the
104
+ * Studio has when it re-signs a session it established itself.
114
105
  */
115
106
  profileId: AuthorId;
116
107
  /**
117
108
  * The token's granted scopes, as the authorization server issued them.
118
109
  *
119
- * Enforced here as well as by the backend, deliberately. Two checks on
120
- * one grant is not redundancy for its own sake: this one can refuse a
121
- * write before it is attempted, so a token that may only read never
122
- * reaches the code that builds a patch.
110
+ * Enforced here as well as by the backend, deliberately. Two checks on one
111
+ * grant is not redundancy for its own sake: this one can refuse a write
112
+ * before it is attempted, so a token that may only read never reaches the
113
+ * code that builds a patch.
123
114
  */
124
115
  scopes: string[];
125
116
  };
@@ -36,22 +36,25 @@ export declare function initHandlerOptions(route: string, opts: ValApiOptions, c
36
36
  /**
37
37
  * Build the data layer a {@link ValServerConfig} calls for.
38
38
  *
39
- * `auth` decides *whose* credential the http backend sees. Left out, it is the
40
- * app's own API key — which is what the Studio wants, because there the app has
41
- * already verified a session cookie and is acting on the user's behalf under its
42
- * own authority.
39
+ * The http backend always sees the app's own API key. That is what the Studio
40
+ * wants — there the app has already verified a session cookie and is acting on
41
+ * the user's behalf under its own authority — and it is now the only shape:
42
+ * every caller that reaches here has been authenticated by the app itself, so
43
+ * there is no request left on which the app is a pipe rather than an authority.
43
44
  *
44
- * A caller acting for a user it has *not* authenticated itself must pass that
45
- * user's personal access token instead, so the backend is the one that decides
46
- * what the caller may do. That is the whole of `docs/plans/mcp.md` D.2: the app
47
- * stops being an authority and goes back to being a pipe. Passing the app's API
48
- * key on such a request is the D.6 confused deputy, and it is worth being blunt
49
- * about why it is tempting — it works, and it works for every project the key
50
- * can reach, including the ones the caller cannot.
45
+ * This took a parameter for the other case: a caller acting for a user it had
46
+ * *not* authenticated passed that user's personal access token, and the backend
47
+ * decided what the caller could do. `ValOpsHttp` still accepts such a token —
48
+ * the CLI's `debug` command uses the developer's own from `val login` — but no
49
+ * server request builds one any more, because a request the app cannot
50
+ * authenticate is now refused instead of relayed.
51
+ *
52
+ * What has not changed is why the API key must never stand in for a credential
53
+ * that was merely *absent*: it works, and it works for every project the key
54
+ * can reach, including the ones the caller cannot. Callers are refused for a
55
+ * missing credential well before this point.
51
56
  */
52
- export declare function createValOps(valModules: ValModules, options: ValServerConfig, auth?: {
53
- pat: string;
54
- }): ValOpsFS | ValOpsHttp;
57
+ export declare function createValOps(valModules: ValModules, options: ValServerConfig): ValOpsFS | ValOpsHttp;
55
58
  /**
56
59
  * Hosts we send credentials to, and what each one puts at risk. They differ:
57
60
  * only `valBuildUrl` hands back the app token that becomes the session cookie,