fix: stop dropping oauth.onInsufficientScope when extracting the client secret (#2018)

Copilot round 4 (one suppressed finding, and a real bug).

`extractSecretsFromStored` rebuilt the stripped `oauth` object from an
allow-list of the non-secret fields. That list had gone stale: it never named
`onInsufficientScope`, so a server carrying both a client secret and a
non-default SEP-2350 policy silently lost the policy on save, falling back to
`reauthorize`. This predates #2018 — the PR only extended the same list with
`authorizationParams` — but the list is the defect, so fix the class rather
than add a third entry to it.

The stripped entry now subtracts the one secret instead of enumerating what to
keep, so any field added to `oauth` later is preserved by construction.

Regression test verified to fail against the allow-list version:
`expected { clientId: 'cid' } to deeply equal { clientId: 'cid', onInsufficientScope: 'throw' }`.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-15 21:54:16 -04:00
commit d95a6e629c

View file

@ -925,6 +925,27 @@ describe("extractSecretsFromStored", () => {
expect(stripped.oauth).toEqual({ enterpriseManaged: true });
});
// The stripped entry now subtracts the secret instead of enumerating the
// fields to keep, so a field added to `oauth` later survives by construction.
// `onInsufficientScope` is the case the old allow-list had already lost.
it("preserves oauth.onInsufficientScope when lifting clientSecret to keychain", () => {
const stored: StoredMCPServer = {
type: "streamable-http",
url: "https://x.test",
oauth: {
clientId: "cid",
clientSecret: "shh",
onInsufficientScope: "throw",
},
};
const { stripped, secrets } = extractSecretsFromStored(stored);
expect(secrets).toEqual({ [SECRET_FIELD_OAUTH_CLIENT_SECRET]: "shh" });
expect(stripped.oauth).toEqual({
clientId: "cid",
onInsufficientScope: "throw",
});
});
it("preserves oauth.authorizationParams when lifting clientSecret to keychain", () => {
const stored: StoredMCPServer = {
type: "streamable-http",