Explorar o código

fix: permissions wildcarding so that for ex: 'ls *' includes ls * AND 'ls' to prevent having to double state commands or use 'ls*'

Aiden Cline hai 1 mes
pai
achega
62702fbd11

+ 12 - 10
packages/opencode/src/util/wildcard.ts

@@ -2,16 +2,18 @@ import { sortBy, pipe } from "remeda"
 
 export namespace Wildcard {
   export function match(str: string, pattern: string) {
-    const regex = new RegExp(
-      "^" +
-        pattern
-          .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
-          .replace(/\*/g, ".*") // * becomes .*
-          .replace(/\?/g, ".") + // ? becomes .
-        "$",
-      "s", // s flag enables multiline matching
-    )
-    return regex.test(str)
+    let escaped = pattern
+      .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape special regex chars
+      .replace(/\*/g, ".*") // * becomes .*
+      .replace(/\?/g, ".") // ? becomes .
+
+    // If pattern ends with " *" (space + wildcard), make the trailing part optional
+    // This allows "ls *" to match both "ls" and "ls -la"
+    if (escaped.endsWith(" .*")) {
+      escaped = escaped.slice(0, -3) + "( .*)?"
+    }
+
+    return new RegExp("^" + escaped + "$", "s").test(str)
   }
 
   export function all(input: string, patterns: Record<string, any>) {

+ 20 - 0
packages/opencode/test/util/wildcard.test.ts

@@ -7,6 +7,26 @@ test("match handles glob tokens", () => {
   expect(Wildcard.match("foo+bar", "foo+bar")).toBe(true)
 })
 
+test("match with trailing space+wildcard matches command with or without args", () => {
+  // "ls *" should match "ls" (no args) and "ls -la" (with args)
+  expect(Wildcard.match("ls", "ls *")).toBe(true)
+  expect(Wildcard.match("ls -la", "ls *")).toBe(true)
+  expect(Wildcard.match("ls foo bar", "ls *")).toBe(true)
+
+  // "ls*" (no space) should NOT match "ls" alone — wait, it should because .* matches empty
+  // but it WILL match "lstmeval" which is the dangerous case users should avoid
+  expect(Wildcard.match("ls", "ls*")).toBe(true)
+  expect(Wildcard.match("lstmeval", "ls*")).toBe(true)
+
+  // "ls *" (with space) should NOT match "lstmeval"
+  expect(Wildcard.match("lstmeval", "ls *")).toBe(false)
+
+  // multi-word commands
+  expect(Wildcard.match("git status", "git *")).toBe(true)
+  expect(Wildcard.match("git", "git *")).toBe(true)
+  expect(Wildcard.match("git commit -m foo", "git *")).toBe(true)
+})
+
 test("all picks the most specific pattern", () => {
   const rules = {
     "*": "deny",