fix(core): prefer specific permission rules
This commit is contained in:
parent
a568f616c9
commit
5530bbe0ac
5 changed files with 100 additions and 61 deletions
|
|
@ -19,15 +19,7 @@ export type Ruleset = typeof Ruleset.Type
|
|||
const EDIT_TOOLS = ["edit", "write", "apply_patch"]
|
||||
|
||||
export function evaluate(permission: string, pattern: string, ...rulesets: Ruleset[]): Rule {
|
||||
return (
|
||||
rulesets
|
||||
.flat()
|
||||
.findLast((rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern)) ?? {
|
||||
action: "ask",
|
||||
permission,
|
||||
pattern: "*",
|
||||
}
|
||||
)
|
||||
return select(permission, pattern, rulesets.flat())?.rule ?? { action: "ask", permission, pattern: "*" }
|
||||
}
|
||||
|
||||
export function merge(...rulesets: Ruleset[]): Ruleset {
|
||||
|
|
@ -38,8 +30,52 @@ export function disabled(tools: string[], ruleset: Ruleset): Set<string> {
|
|||
return new Set(
|
||||
tools.filter((tool) => {
|
||||
const permission = EDIT_TOOLS.includes(tool) ? "edit" : tool
|
||||
const rule = ruleset.findLast((rule) => Wildcard.match(permission, rule.permission))
|
||||
return rule?.pattern === "*" && rule.action === "deny"
|
||||
if (
|
||||
ruleset.some(
|
||||
(rule) => Wildcard.match(permission, rule.permission) && rule.pattern !== "*" && rule.action !== "deny",
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return evaluate(permission, "*", ruleset).action === "deny"
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function select(permission: string, pattern: string, ruleset: Ruleset) {
|
||||
return ruleset.reduce<Selected | undefined>((best, rule, index) => {
|
||||
if (!Wildcard.match(permission, rule.permission) || !Wildcard.match(pattern, rule.pattern)) return best
|
||||
const next = { rule, index, permission: specificity(rule.permission), pattern: specificity(rule.pattern) }
|
||||
if (!best) return next
|
||||
return compare(next, best) >= 0 ? next : best
|
||||
}, undefined)
|
||||
}
|
||||
|
||||
type Selected = {
|
||||
rule: Rule
|
||||
index: number
|
||||
permission: Specificity
|
||||
pattern: Specificity
|
||||
}
|
||||
|
||||
type Specificity = {
|
||||
wildcard: number
|
||||
literal: number
|
||||
}
|
||||
|
||||
function specificity(pattern: string): Specificity {
|
||||
return {
|
||||
wildcard: [...pattern.matchAll(/[?*]/g)].length,
|
||||
literal: pattern.replace(/[?*]/g, "").length,
|
||||
}
|
||||
}
|
||||
|
||||
function compare(a: Selected, b: Selected) {
|
||||
return (
|
||||
b.permission.wildcard - a.permission.wildcard ||
|
||||
a.permission.literal - b.permission.literal ||
|
||||
b.pattern.wildcard - a.pattern.wildcard ||
|
||||
a.pattern.literal - b.pattern.literal ||
|
||||
a.index - b.index
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue