|
2 | 2 | (:require |
3 | 3 | [babashka.fs :as fs] |
4 | 4 | [babashka.process :as p] |
5 | | - [clojure.test :refer [deftest is testing are]] |
| 5 | + [clojure.test :refer [are deftest is testing]] |
6 | 6 | [eca.config :as config] |
7 | 7 | [eca.features.tools :as f.tools] |
8 | 8 | [eca.features.tools.shell :as f.tools.shell] |
|
28 | 28 | {:type :text |
29 | 29 | :text "Stderr:\nSome error"}]} |
30 | 30 | (with-redefs [fs/exists? (constantly true) |
31 | | - p/shell (constantly {:exit 1 :err "Some error"})] |
| 31 | + p/process (constantly (future {:exit 1 :err "Some error"}))] |
32 | 32 | ((get-in f.tools.shell/definitions ["eca_shell_command" :handler]) |
33 | 33 | {"command" "ls -lh"} |
34 | 34 | {:db {:workspace-folders [{:uri (h/file-uri "file:///project/foo") :name "foo"}]}}))))) |
|
38 | 38 | :contents [{:type :text |
39 | 39 | :text "Some text"}]} |
40 | 40 | (with-redefs [fs/exists? (constantly true) |
41 | | - p/shell (constantly {:exit 0 :out "Some text" :err "Other text"})] |
| 41 | + p/process (constantly (future {:exit 0 :out "Some text" :err "Other text"}))] |
42 | 42 | ((get-in f.tools.shell/definitions ["eca_shell_command" :handler]) |
43 | 43 | {"command" "ls -lh"} |
44 | 44 | {:db {:workspace-folders [{:uri (h/file-uri "file:///project/foo") :name "foo"}]}}))))) |
|
48 | 48 | :contents [{:type :text |
49 | 49 | :text "Some text"}]} |
50 | 50 | (with-redefs [fs/exists? (constantly true) |
51 | | - p/shell (constantly {:exit 0 :out "Some text" :err "Other text"})] |
| 51 | + p/process (constantly (future {:exit 0 :out "Some text" :err "Other text"}))] |
52 | 52 | ((get-in f.tools.shell/definitions ["eca_shell_command" :handler]) |
53 | 53 | {"command" "ls -lh" |
54 | 54 | "working_directory" (h/file-path "/project/foo/src")} |
55 | 55 | {:db {:workspace-folders [{:uri (h/file-uri "file:///project/foo") :name "foo"}]}}))))) |
56 | | -) |
| 56 | + (testing "command exceeds timeout" |
| 57 | + (is (match? |
| 58 | + {:error true |
| 59 | + :contents [{:type :text |
| 60 | + :text "Command timed out after 50 ms"}]} |
| 61 | + (with-redefs [fs/exists? (constantly true) |
| 62 | + p/process (constantly (future (Thread/sleep 100) {:exit 0 :err "ok"}))] |
| 63 | + ((get-in f.tools.shell/definitions ["eca_shell_command" :handler]) |
| 64 | + {"command" "ls -lh" |
| 65 | + "timeout" 50} |
| 66 | + {:db {:workspace-folders [{:uri (h/file-uri "file:///project/foo") :name "foo"}]}})))))) |
57 | 67 |
|
58 | 68 | (deftest shell-require-approval-fn-test |
59 | 69 | (let [approval-fn (get-in f.tools.shell/definitions ["eca_shell_command" :require-approval-fn]) |
|
84 | 94 | :contents [{:type :text |
85 | 95 | :text "Some output"}]} |
86 | 96 | (with-redefs [fs/exists? (constantly true) |
87 | | - p/shell (constantly {:exit 0 :out "Some output"})] |
| 97 | + p/process (constantly (future {:exit 0 :out "Some output"}))] |
88 | 98 | ((get-in f.tools.shell/definitions ["eca_shell_command" :handler]) |
89 | 99 | {"command" command} |
90 | 100 | {:db {:workspace-folders [{:uri (h/file-uri "file:///project/foo") :name "foo"}]} |
|
102 | 112 | (deftest plan-mode-approval-restrictions-test |
103 | 113 | (let [all-tools [{:name "eca_shell_command" :server "eca"}] |
104 | 114 | config config/initial-config] |
105 | | - |
| 115 | + |
106 | 116 | (testing "dangerous commands blocked in plan mode via approval" |
107 | | - (are [command] (= :deny |
108 | | - (f.tools/approval all-tools "eca_shell_command" |
109 | | - {"command" command} {} config "plan")) |
| 117 | + (are [command] (= :deny |
| 118 | + (f.tools/approval all-tools "eca_shell_command" |
| 119 | + {"command" command} {} config "plan")) |
110 | 120 | "echo 'test' > file.txt" |
111 | 121 | "cat file.txt > output.txt" |
112 | 122 | "ls >> log.txt" |
|
121 | 131 | "npm install package" |
122 | 132 | "python -c \"open('file.txt','w').write('test')\"" |
123 | 133 | "bash -c 'echo test > file.txt'")) |
124 | | - |
| 134 | + |
125 | 135 | (testing "non-dangerous commands default to ask in plan mode" |
126 | 136 | (are [command] (= :ask |
127 | | - (f.tools/approval all-tools "eca_shell_command" |
128 | | - {"command" command} {} config "plan")) |
| 137 | + (f.tools/approval all-tools "eca_shell_command" |
| 138 | + {"command" command} {} config "plan")) |
129 | 139 | "python --version" ; not matching dangerous patterns, defaults to ask |
130 | 140 | "node script.js" ; not matching dangerous patterns, defaults to ask |
131 | 141 | "clojure -M:test")) ; not matching dangerous patterns, defaults to ask |
132 | | - |
| 142 | + |
133 | 143 | (testing "safe commands not denied in plan mode" |
134 | 144 | (are [command] (not= :deny |
135 | | - (f.tools/approval all-tools "eca_shell_command" |
136 | | - {"command" command} {} config "plan")) |
| 145 | + (f.tools/approval all-tools "eca_shell_command" |
| 146 | + {"command" command} {} config "plan")) |
137 | 147 | "git status" |
138 | 148 | "ls -la" |
139 | 149 | "find . -name '*.clj'" |
|
143 | 153 | "pwd" |
144 | 154 | "date" |
145 | 155 | "env")) |
146 | | - |
| 156 | + |
147 | 157 | (testing "same commands work fine in agent mode (not denied)" |
148 | 158 | (are [command] (not= :deny |
149 | | - (f.tools/approval all-tools "eca_shell_command" |
150 | | - {"command" command} {} config "agent")) |
| 159 | + (f.tools/approval all-tools "eca_shell_command" |
| 160 | + {"command" command} {} config "agent")) |
151 | 161 | "echo 'test' > file.txt" |
152 | 162 | "rm file.txt" |
153 | 163 | "git add ." |
|
0 commit comments