Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions lib/host-permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ type PermissionRule = {
action: PermissionAction
}

const findLastMatchingRule = (
rules: PermissionRule[],
predicate: (rule: PermissionRule) => boolean,
): PermissionRule | undefined => {
for (let index = rules.length - 1; index >= 0; index -= 1) {
const rule = rules[index]
if (rule && predicate(rule)) {
return rule
}
}

return undefined
}

const wildcardMatch = (value: string, pattern: string): boolean => {
const normalizedValue = value.replaceAll("\\", "/")
let escaped = pattern
Expand Down Expand Up @@ -55,7 +69,7 @@ const getPermissionRules = (permissionConfigs: PermissionConfig[]): PermissionRu
}

export const compressDisabledByOpencode = (...permissionConfigs: PermissionConfig[]): boolean => {
const match = getPermissionRules(permissionConfigs).findLast((rule) =>
const match = findLastMatchingRule(getPermissionRules(permissionConfigs), (rule) =>
wildcardMatch("compress", rule.permission),
)

Expand Down Expand Up @@ -83,5 +97,5 @@ export const hasExplicitToolPermission = (
permissionConfig: PermissionConfig,
tool: string,
): boolean => {
return permissionConfig ? Object.hasOwn(permissionConfig, tool) : false
return permissionConfig ? Object.prototype.hasOwnProperty.call(permissionConfig, tool) : false
}
31 changes: 31 additions & 0 deletions tests/host-permissions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,38 @@ test("pattern-specific denies do not disable the whole tool", () => {
)
})

test("compress permission resolution works without Array.findLast", () => {
const originalFindLast = Array.prototype.findLast

try {
delete (Array.prototype as Array<unknown> & { findLast?: unknown }).findLast

assert.equal(
compressDisabledByOpencode({
"*": "deny",
compress: "allow",
}),
false,
)
} finally {
Array.prototype.findLast = originalFindLast
}
})

test("explicit compress permissions are detected", () => {
assert.equal(hasExplicitToolPermission({ compress: "ask" }, "compress"), true)
assert.equal(hasExplicitToolPermission({ "*": "deny" }, "compress"), false)
})

test("explicit permission detection works without Object.hasOwn", () => {
const originalHasOwn = Object.hasOwn

try {
delete (Object as typeof Object & { hasOwn?: unknown }).hasOwn

assert.equal(hasExplicitToolPermission({ compress: "ask" }, "compress"), true)
assert.equal(hasExplicitToolPermission({ "*": "deny" }, "compress"), false)
} finally {
Object.hasOwn = originalHasOwn
}
})
Loading