import { describe, expect, it } from "@effect/vitest";import { ConnectionId, ScopeId, SecretId } from "@executor-js/sdk"; import { effectiveBindingForScope, missingCredentialLabels, type BindingRowForCredentialStatus, type SourceForCredentialStatus,} from "./credential-status"; const userScope = ScopeId.make("user");const orgScope = ScopeId.make("org");const scopeRanks = new Map([ [userScope, 0], [orgScope, 1],]); const source: SourceForCredentialStatus = { config: { headers: { Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " }, }, oauth2: { securitySchemeName: "oauth2", flow: "clientCredentials", clientIdSlot: "oauth2:oauth2:client-id", clientSecretSlot: "oauth2:oauth2:client-secret", connectionSlot: "oauth2:oauth2:connection", }, },}; const bindings = ( scopeId: ScopeId, slots: readonly string[],): readonly BindingRowForCredentialStatus[] => slots.map((slot) => ({ slot, scopeId, value: slot === "oauth2:oauth2:connection" ? { kind: "connection", connectionId: ConnectionId.make(`${scopeId}-connection`), } : { kind: "secret", secretId: SecretId.make(`${scopeId}-${slot}`), }, })); const allSlots = [ "header:authorization", "oauth2:oauth2:client-id", "oauth2:oauth2:client-secret", "oauth2:oauth2:connection",] as const; describe("OpenAPI credential status", () => { it("treats personal bindings as satisfying the user's credential status for an org source", () => { expect( missingCredentialLabels(source, bindings(userScope, allSlots), userScope, scopeRanks, { liveConnectionIds: [ConnectionId.make("user-connection")], }), ).toEqual([]); }); it("falls back to shared org bindings when the user has no personal override", () => { expect( missingCredentialLabels(source, bindings(orgScope, allSlots), userScope, scopeRanks, { liveConnectionIds: [ConnectionId.make("org-connection")], }), ).toEqual([]); }); it("treats a stale connection binding as missing OAuth credentials", () => { expect( missingCredentialLabels(source, bindings(userScope, allSlots), userScope, scopeRanks, { liveConnectionIds: [], }), ).toEqual(["OAuth client connection"]); }); it("does not treat personal bindings as satisfying org-level credential status", () => { expect( missingCredentialLabels(source, bindings(userScope, allSlots), orgScope, scopeRanks), ).toEqual(["Authorization", "Client ID", "Client Secret", "OAuth client connection"]); }); it("prefers the personal binding over a shared org binding", () => { const binding = effectiveBindingForScope( [ ...bindings(orgScope, ["oauth2:oauth2:connection"]), ...bindings(userScope, ["oauth2:oauth2:connection"]), ], "oauth2:oauth2:connection", userScope, scopeRanks, ); expect(binding?.scopeId).toEqual(userScope); });});
import { describe, expect, it } from "@effect/vitest";
import { ConnectionId, ScopeId, SecretId } from "@executor-js/sdk";
import {
effectiveBindingForScope,
missingCredentialLabels,
type BindingRowForCredentialStatus,
type SourceForCredentialStatus,
} from "./credential-status";
const userScope = ScopeId.make("user");
const orgScope = ScopeId.make("org");
const scopeRanks = new Map([
[userScope, 0],
[orgScope, 1],
]);
const source: SourceForCredentialStatus = {
config: {
headers: {
Authorization: { kind: "binding", slot: "header:authorization", prefix: "Bearer " },
},
oauth2: {
securitySchemeName: "oauth2",
flow: "clientCredentials",
clientIdSlot: "oauth2:oauth2:client-id",
clientSecretSlot: "oauth2:oauth2:client-secret",
connectionSlot: "oauth2:oauth2:connection",
},
},
};
const bindings = (
scopeId: ScopeId,
slots: readonly string[],
): readonly BindingRowForCredentialStatus[] =>
slots.map((slot) => ({
slot,
scopeId,
value:
slot === "oauth2:oauth2:connection"
? {
kind: "connection",
connectionId: ConnectionId.make(`${scopeId}-connection`),
}
: {
kind: "secret",
secretId: SecretId.make(`${scopeId}-${slot}`),
},
}));
const allSlots = [
"header:authorization",
"oauth2:oauth2:client-id",
"oauth2:oauth2:client-secret",
"oauth2:oauth2:connection",
] as const;
describe("OpenAPI credential status", () => {
it("treats personal bindings as satisfying the user's credential status for an org source", () => {
expect(
missingCredentialLabels(source, bindings(userScope, allSlots), userScope, scopeRanks, {
liveConnectionIds: [ConnectionId.make("user-connection")],
}),
).toEqual([]);
});
it("falls back to shared org bindings when the user has no personal override", () => {
expect(
missingCredentialLabels(source, bindings(orgScope, allSlots), userScope, scopeRanks, {
liveConnectionIds: [ConnectionId.make("org-connection")],
}),
).toEqual([]);
});
it("treats a stale connection binding as missing OAuth credentials", () => {
expect(
missingCredentialLabels(source, bindings(userScope, allSlots), userScope, scopeRanks, {
liveConnectionIds: [],
}),
).toEqual(["OAuth client connection"]);
});
it("does not treat personal bindings as satisfying org-level credential status", () => {
expect(
missingCredentialLabels(source, bindings(userScope, allSlots), orgScope, scopeRanks),
).toEqual(["Authorization", "Client ID", "Client Secret", "OAuth client connection"]);
});
it("prefers the personal binding over a shared org binding", () => {
const binding = effectiveBindingForScope(
[
...bindings(orgScope, ["oauth2:oauth2:connection"]),
...bindings(userScope, ["oauth2:oauth2:connection"]),
],
"oauth2:oauth2:connection",
userScope,
scopeRanks,
);
expect(binding?.scopeId).toEqual(userScope);
});
});