summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAiden Cline <[email protected]>2025-10-23 13:35:09 -0500
committerGitHub <[email protected]>2025-10-23 13:35:09 -0500
commit9b5fe10df6d2326040612d3ad7d682e2fd8fc24b (patch)
tree41138d2777425fe3a951bb126151047dd7de812f
parentb5f336c0eab41e21be0d4313463b3ca4c8561784 (diff)
downloadopencode-9b5fe10df6d2326040612d3ad7d682e2fd8fc24b.tar.gz
opencode-9b5fe10df6d2326040612d3ad7d682e2fd8fc24b.zip
add flag wildcard parsing support for bash tool (#3390)
-rw-r--r--packages/opencode/src/tool/bash.ts2
-rw-r--r--packages/opencode/src/util/wildcard.ts26
2 files changed, 27 insertions, 1 deletions
diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts
index 2e456c8b3..d56b4690b 100644
--- a/packages/opencode/src/tool/bash.ts
+++ b/packages/opencode/src/tool/bash.ts
@@ -97,7 +97,7 @@ export const BashTool = Tool.define("bash", {
// always allow cd if it passes above check
if (command[0] !== "cd") {
- const action = Wildcard.all(node.text, permissions)
+ const action = Wildcard.allStructured({ head: command[0], tail: command.slice(1) }, permissions)
if (action === "deny") {
throw new Error(
`The user has specifically restricted access to this command, you are not allowed to execute it. Here is the configuration: ${JSON.stringify(permissions)}`,
diff --git a/packages/opencode/src/util/wildcard.ts b/packages/opencode/src/util/wildcard.ts
index d329501f2..9b595a0a9 100644
--- a/packages/opencode/src/util/wildcard.ts
+++ b/packages/opencode/src/util/wildcard.ts
@@ -25,4 +25,30 @@ export namespace Wildcard {
}
return result
}
+
+ export function allStructured(input: { head: string; tail: string[] }, patterns: Record<string, any>) {
+ const sorted = pipe(patterns, Object.entries, sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"]))
+ let result = undefined
+ for (const [pattern, value] of sorted) {
+ const parts = pattern.split(/\s+/)
+ if (!match(input.head, parts[0])) continue
+ if (parts.length === 1 || matchSequence(input.tail, parts.slice(1))) {
+ result = value
+ continue
+ }
+ }
+ return result
+ }
+
+ function matchSequence(items: string[], patterns: string[]): boolean {
+ if (patterns.length === 0) return true
+ const [pattern, ...rest] = patterns
+ if (pattern === "*") return matchSequence(items, rest)
+ for (let i = 0; i < items.length; i++) {
+ if (match(items[i], pattern) && matchSequence(items.slice(i + 1), rest)) {
+ return true
+ }
+ }
+ return false
+ }
}