fix(core): merge authenticated provider allowlists
This commit is contained in:
+29
-13
@@ -141,7 +141,7 @@ export const layer = (options?: Options) => Layer.effect(
|
||||
Effect.logWarning("failed to discover wellknown config", { error }).pipe(Effect.as([] as const)),
|
||||
),
|
||||
)
|
||||
return yield* Effect.forEach(entries, (entry) =>
|
||||
const resolved = yield* Effect.forEach(entries, (entry) =>
|
||||
Effect.gen(function* () {
|
||||
const auth = entry.manifest.auth
|
||||
if (!auth) return []
|
||||
@@ -151,20 +151,29 @@ export const layer = (options?: Options) => Layer.effect(
|
||||
if (!credential || credential.value.type !== "key") return []
|
||||
const variables = { [auth.env]: credential.value.key }
|
||||
const configs = yield* wellknown.resolve(entry, variables).pipe(Effect.orDie)
|
||||
return yield* Effect.forEach(configs, (config) =>
|
||||
ConfigVariable.substitute({
|
||||
type: "virtual",
|
||||
source: entry.origin,
|
||||
dir: entry.origin,
|
||||
text: JSON.stringify(config),
|
||||
env: variables,
|
||||
}).pipe(
|
||||
Effect.flatMap((text) => parseInfo(text, entry.origin)),
|
||||
Effect.map((info) => (info ? new Document({ type: "document", info }) : undefined)),
|
||||
),
|
||||
).pipe(Effect.map((documents) => documents.filter((document) => document !== undefined)))
|
||||
return configs.map((config) => ({ config, source: entry.origin, variables }))
|
||||
}),
|
||||
).pipe(Effect.map((documents) => documents.flat()))
|
||||
// V1 merged authenticated configs before applying this allowlist. Give every
|
||||
// migrated document the union so one source's wildcard deny cannot hide another.
|
||||
const enabledProviders = Array.from(
|
||||
new Set(resolved.flatMap((item) => legacyEnabledProviders(item.config) ?? [])),
|
||||
)
|
||||
return yield* Effect.forEach(resolved, (item) => {
|
||||
const config = legacyEnabledProviders(item.config)
|
||||
? { ...item.config, enabled_providers: enabledProviders }
|
||||
: item.config
|
||||
return ConfigVariable.substitute({
|
||||
type: "virtual",
|
||||
source: item.source,
|
||||
dir: item.source,
|
||||
text: JSON.stringify(config),
|
||||
env: item.variables,
|
||||
}).pipe(
|
||||
Effect.flatMap((text) => parseInfo(text, item.source)),
|
||||
Effect.map((info) => (info ? new Document({ type: "document", info }) : undefined)),
|
||||
)
|
||||
}).pipe(Effect.map((documents) => documents.filter((document) => document !== undefined)))
|
||||
})
|
||||
|
||||
const loadDirectory = Effect.fnUntraced(function* (directory: AbsolutePath) {
|
||||
@@ -360,6 +369,13 @@ export const layer = (options?: Options) => Layer.effect(
|
||||
}),
|
||||
)
|
||||
|
||||
function legacyEnabledProviders(config: WellKnown.Config) {
|
||||
if (typeof config !== "object" || config === null) return
|
||||
if (!Array.isArray(config.enabled_providers)) return
|
||||
if (!config.enabled_providers.every((provider): provider is string => typeof provider === "string")) return
|
||||
return config.enabled_providers
|
||||
}
|
||||
|
||||
export function configured(options?: Options) {
|
||||
return makeLocationNode({
|
||||
service: Service,
|
||||
|
||||
@@ -307,7 +307,7 @@ describe("Config", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("loads authenticated wellknown config before user configuration", () =>
|
||||
it.live("loads and merges authenticated wellknown config before user configuration", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) =>
|
||||
@@ -322,6 +322,7 @@ describe("Config", () => {
|
||||
})
|
||||
|
||||
const integrationID = Integration.ID.make("https://example.com")
|
||||
const supplementalID = Integration.ID.make("https://models.example.com")
|
||||
let key = "secret"
|
||||
const credentialNode = makeGlobalNode({
|
||||
service: Credential.Service,
|
||||
@@ -329,13 +330,16 @@ describe("Config", () => {
|
||||
Credential.Service,
|
||||
Credential.Service.of({
|
||||
all: () => Effect.die("unused Credential.all"),
|
||||
list: () =>
|
||||
list: (requested) =>
|
||||
Effect.succeed([
|
||||
new Credential.Info({
|
||||
id: Credential.ID.create(),
|
||||
integrationID,
|
||||
integrationID: requested,
|
||||
label: "default",
|
||||
value: Credential.Key.make({ type: "key", key }),
|
||||
value: Credential.Key.make({
|
||||
type: "key",
|
||||
key: requested === integrationID ? key : "supplemental",
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
get: () => Effect.die("unused Credential.get"),
|
||||
@@ -351,17 +355,28 @@ describe("Config", () => {
|
||||
integrationID,
|
||||
manifest: { auth: { command: ["login"], env: "TOKEN" } },
|
||||
}
|
||||
const supplemental: WellKnown.Entry = {
|
||||
origin: "https://models.example.com",
|
||||
integrationID: supplementalID,
|
||||
manifest: { auth: { command: ["login"], env: "TOKEN" } },
|
||||
}
|
||||
const wellknownNode = makeGlobalNode({
|
||||
service: WellKnown.Service,
|
||||
layer: Layer.succeed(
|
||||
WellKnown.Service,
|
||||
WellKnown.Service.of({
|
||||
entries: () => Effect.succeed([entry]),
|
||||
snapshot: () => [entry],
|
||||
entries: () => Effect.succeed([entry, supplemental]),
|
||||
snapshot: () => [entry, supplemental],
|
||||
refresh: () => Effect.succeed(false),
|
||||
add: () => Effect.die("unused Wellknown.add"),
|
||||
remove: () => Effect.die("unused Wellknown.remove"),
|
||||
resolve: (_entry, variables) => Effect.succeed([{ shell: variables.TOKEN }]),
|
||||
resolve: (resolved, variables) =>
|
||||
Effect.succeed([
|
||||
{
|
||||
shell: variables.TOKEN,
|
||||
enabled_providers: [resolved.integrationID === integrationID ? "primary" : "fable"],
|
||||
},
|
||||
]),
|
||||
}),
|
||||
),
|
||||
deps: [],
|
||||
@@ -376,7 +391,24 @@ describe("Config", () => {
|
||||
initial.flatMap((entry) =>
|
||||
entry.type === "document" && entry.info.shell ? [entry.info.shell] : [],
|
||||
),
|
||||
).toEqual(["secret", "global", "project"])
|
||||
).toEqual(["secret", "supplemental", "global", "project"])
|
||||
expect(
|
||||
initial
|
||||
.filter((entry): entry is Document => entry.type === "document" && entry.info.shell !== undefined)
|
||||
.slice(0, 2)
|
||||
.map((entry) => entry.info.experimental?.policies),
|
||||
).toEqual([
|
||||
[
|
||||
{ action: "provider.use", resource: "*", effect: "deny" },
|
||||
{ action: "provider.use", resource: "primary", effect: "allow" },
|
||||
{ action: "provider.use", resource: "fable", effect: "allow" },
|
||||
],
|
||||
[
|
||||
{ action: "provider.use", resource: "*", effect: "deny" },
|
||||
{ action: "provider.use", resource: "primary", effect: "allow" },
|
||||
{ action: "provider.use", resource: "fable", effect: "allow" },
|
||||
],
|
||||
])
|
||||
const updated = yield* bus
|
||||
.subscribe(Event.Updated)
|
||||
.pipe(Stream.take(1), Stream.runCollect, Effect.forkScoped)
|
||||
@@ -390,7 +422,7 @@ describe("Config", () => {
|
||||
refreshed.flatMap((entry) =>
|
||||
entry.type === "document" && entry.info.shell ? [entry.info.shell] : [],
|
||||
),
|
||||
).toEqual(["next", "global", "project"])
|
||||
).toEqual(["next", "supplemental", "global", "project"])
|
||||
}).pipe(
|
||||
Effect.provide(testLayer(project, global, project, undefined, undefined, credentialNode, wellknownNode)),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user