mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-15 04:27:20 +03:00
fix(core): import legacy auth.json only into the user's database file (#63716)
This commit is contained in:
committed by
GitHub
Unverified
parent
de63679df0
commit
f2687cc30a
@@ -30,7 +30,9 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/st
|
||||
// releasing a shared semaphore resumes the waiting object's fiber inside the
|
||||
// releasing object's I/O context, where its first storage call is rejected as
|
||||
// cross-object I/O.
|
||||
const databaseLayer = (lock: Effect.Effect<Semaphore.Semaphore>) =>
|
||||
// Only a database file the user opens imports their legacy auth.json; in-memory and injected databases belong to
|
||||
// embedders and tests, which must not pick up the user's credentials.
|
||||
const databaseLayer = (lock: Effect.Effect<Semaphore.Semaphore>, legacyCredentials = false) =>
|
||||
Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
@@ -48,7 +50,7 @@ const databaseLayer = (lock: Effect.Effect<Semaphore.Semaphore>) =>
|
||||
// Durable Object SQLite always enforces foreign keys and rejects the pragma.
|
||||
if (supportsForeignKeyToggle && !durableObject) yield* db.run("PRAGMA foreign_keys = ON")
|
||||
const semaphore = yield* lock
|
||||
yield* semaphore.withPermit(DatabaseMigration.apply(db))
|
||||
yield* semaphore.withPermit(DatabaseMigration.apply(db, { legacyCredentials }))
|
||||
|
||||
return { db }
|
||||
}).pipe(Effect.orDie),
|
||||
@@ -70,9 +72,10 @@ export function layer(options: Options = { path: ":memory:" }) {
|
||||
return Layer.unwrap(
|
||||
Effect.gen(function* () {
|
||||
const provide = (filename: string) =>
|
||||
databaseLayer(filename === ":memory:" ? Semaphore.make(1) : Effect.succeed(lockFor(filename))).pipe(
|
||||
Layer.provide(sqliteLayer({ filename })),
|
||||
)
|
||||
(filename === ":memory:"
|
||||
? databaseLayer(Semaphore.make(1))
|
||||
: databaseLayer(Effect.succeed(lockFor(filename)), true)
|
||||
).pipe(Layer.provide(sqliteLayer({ filename })))
|
||||
const filename = options.path ?? ":memory:"
|
||||
if (filename === ":memory:") return provide(filename)
|
||||
const file = isAbsolute(filename) ? filename : join((yield* Global.Service).data, filename)
|
||||
|
||||
@@ -21,7 +21,7 @@ export type Migration = {
|
||||
|
||||
// Not serialized here: the Database layer holds a lock scoped to the database
|
||||
// it is bootstrapping, since two instances over one file must not race.
|
||||
export function apply(db: Database) {
|
||||
export function apply(db: Database, options = { legacyCredentials: true }) {
|
||||
return Effect.gen(function* () {
|
||||
// OpenCode owns the unprefixed table namespace. Embedders sharing this
|
||||
// database may own underscore-prefixed tables, which bootstrap ignores.
|
||||
@@ -36,7 +36,7 @@ export function apply(db: Database) {
|
||||
yield* db.transaction((tx) =>
|
||||
Effect.gen(function* () {
|
||||
yield* schema.up(tx)
|
||||
yield* legacyCredentials.up(tx)
|
||||
if (options.legacyCredentials) yield* legacyCredentials.up(tx)
|
||||
yield* tx.run(
|
||||
sql`CREATE TABLE ${sql.identifier("migration")} (id TEXT PRIMARY KEY, time_completed INTEGER NOT NULL)`,
|
||||
)
|
||||
|
||||
@@ -553,6 +553,22 @@ describe("DatabaseMigration", () => {
|
||||
)
|
||||
})
|
||||
|
||||
test("leaves legacy credentials out of in-memory databases", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
await Bun.write(
|
||||
path.join(tmp.path, "auth.json"),
|
||||
JSON.stringify({ openai: { type: "oauth", refresh: "refresh", access: "access", expires: 123 } }),
|
||||
)
|
||||
|
||||
const rows = await Effect.runPromise(
|
||||
Database.Service.use((database) => database.db.all(sql`SELECT id FROM credential`)).pipe(
|
||||
Effect.provide(Database.layer({ path: ":memory:" })),
|
||||
Effect.provideService(Global.Service, Global.make({ data: tmp.path })),
|
||||
),
|
||||
)
|
||||
expect(rows).toEqual([])
|
||||
})
|
||||
|
||||
test("bootstraps a fresh database when the legacy credential file is malformed", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
await Bun.write(path.join(tmp.path, "auth.json"), "not json")
|
||||
|
||||
Reference in New Issue
Block a user