fix: avoid truncate permission import cycle (#18292)
parent
e71a21e0a8
commit
7866dbcfcc
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Wildcard } from "@/util/wildcard"
|
||||||
|
|
||||||
|
type Rule = {
|
||||||
|
permission: string
|
||||||
|
pattern: string
|
||||||
|
action: "allow" | "deny" | "ask"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function evaluate(permission: string, pattern: string, ...rulesets: Rule[][]): Rule {
|
||||||
|
const rules = rulesets.flat()
|
||||||
|
const match = rules.findLast(
|
||||||
|
(rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern),
|
||||||
|
)
|
||||||
|
return match ?? { action: "ask", permission, pattern: "*" }
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import { Wildcard } from "@/util/wildcard"
|
||||||
import { Deferred, Effect, Layer, Schema, ServiceMap } from "effect"
|
import { Deferred, Effect, Layer, Schema, ServiceMap } from "effect"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
|
import { evaluate as evalRule } from "./evaluate"
|
||||||
import { PermissionID } from "./schema"
|
import { PermissionID } from "./schema"
|
||||||
|
|
||||||
export namespace PermissionNext {
|
export namespace PermissionNext {
|
||||||
|
|
@ -125,12 +126,8 @@ export namespace PermissionNext {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function evaluate(permission: string, pattern: string, ...rulesets: Ruleset[]): Rule {
|
export function evaluate(permission: string, pattern: string, ...rulesets: Ruleset[]): Rule {
|
||||||
const rules = rulesets.flat()
|
log.info("evaluate", { permission, pattern, ruleset: rulesets.flat() })
|
||||||
log.info("evaluate", { permission, pattern, ruleset: rules })
|
return evalRule(permission, pattern, ...rulesets)
|
||||||
const match = rules.findLast(
|
|
||||||
(rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern),
|
|
||||||
)
|
|
||||||
return match ?? { action: "ask", permission, pattern: "*" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/PermissionNext") {}
|
export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/PermissionNext") {}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Cause, Duration, Effect, Layer, Schedule, ServiceMap } from "effect"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import type { Agent } from "../agent/agent"
|
import type { Agent } from "../agent/agent"
|
||||||
import { AppFileSystem } from "@/filesystem"
|
import { AppFileSystem } from "@/filesystem"
|
||||||
import { PermissionNext } from "../permission"
|
import { evaluate } from "@/permission/evaluate"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { ToolID } from "./schema"
|
import { ToolID } from "./schema"
|
||||||
|
|
@ -28,7 +28,7 @@ export namespace TruncateEffect {
|
||||||
|
|
||||||
function hasTaskTool(agent?: Agent.Info) {
|
function hasTaskTool(agent?: Agent.Info) {
|
||||||
if (!agent?.permission) return false
|
if (!agent?.permission) return false
|
||||||
return PermissionNext.evaluate("task", "*", agent.permission).action !== "deny"
|
return evaluate("task", "*", agent.permission).action !== "deny"
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@ import { Effect, FileSystem, Layer } from "effect"
|
||||||
import { Truncate } from "../../src/tool/truncate"
|
import { Truncate } from "../../src/tool/truncate"
|
||||||
import { TruncateEffect } from "../../src/tool/truncate-effect"
|
import { TruncateEffect } from "../../src/tool/truncate-effect"
|
||||||
import { Identifier } from "../../src/id/id"
|
import { Identifier } from "../../src/id/id"
|
||||||
|
import { Process } from "../../src/util/process"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
import { writeFileStringScoped } from "../lib/filesystem"
|
import { writeFileStringScoped } from "../lib/filesystem"
|
||||||
|
|
||||||
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
|
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
|
||||||
|
const ROOT = path.resolve(import.meta.dir, "..", "..")
|
||||||
|
|
||||||
describe("Truncate", () => {
|
describe("Truncate", () => {
|
||||||
describe("output", () => {
|
describe("output", () => {
|
||||||
|
|
@ -125,6 +127,14 @@ describe("Truncate", () => {
|
||||||
if (result.truncated) throw new Error("expected not truncated")
|
if (result.truncated) throw new Error("expected not truncated")
|
||||||
expect("outputPath" in result).toBe(false)
|
expect("outputPath" in result).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("loads truncate effect in a fresh process", async () => {
|
||||||
|
const out = await Process.run([process.execPath, "run", path.join(ROOT, "src", "tool", "truncate-effect.ts")], {
|
||||||
|
cwd: ROOT,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(out.code).toBe(0)
|
||||||
|
}, 20000)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("cleanup", () => {
|
describe("cleanup", () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue