1 ## oils_failures_allowed: 10
2
3 # Not disallowed:
4 # setglobal, mutating arguments with setvar
5
6 #### eval() is a pure function
7 shopt --set ysh:upgrade
8
9 var pure = ^(
10 const a = 1
11 const b = 2
12 )
13
14 var d = eval(pure, to_dict=true)
15 pp test_ (d)
16
17 var impure = ^(seq 3 | wc -l)
18
19 try {
20 call eval(impure)
21 }
22 #= _error
23 echo impure code=$[_error.code]
24
25 # Can run impure code after pure code
26 call io->eval(impure)
27
28 ## STDOUT:
29 (Dict) {"a":1,"b":2}
30 impure code=5
31 3
32 ## END
33
34 #### evalExpr() is a pure function
35 shopt --set ysh:upgrade
36
37 var x = 42
38 var pure = ^[x + 1]
39 echo pure=$[evalExpr(pure)]
40
41 var impure = ^[x + $(echo 3)]
42 try {
43 echo impure code=$[evalExpr(impure)]
44 }
45 echo impure code=$[_error.code]
46
47 # Can run impure code after pure code
48 echo impure=$[io->evalExpr(impure)]
49
50 ## STDOUT:
51 pure=43
52 impure code=5
53 impure=45
54 ## END
55
56 #### Idiom to handle purity errors from untrusted config files
57
58 echo "TODO: what's the idiom?"
59
60 # trap PURE ? Is this like trap ERR?
61 # You can handle these errors
62 #
63 # OILS_CRASH_DUMP_DIR=?
64 #
65 # Or do you need 2 more flags?
66 #
67 # --eval-pure-str 'try { source user-config.ysh }'
68 # --eval-str
69 #
70 # That is a bit annoying?
71 #
72 # --eval pure:foo.hay
73 # --eval-str 'pure:echo hi'
74 # --eval any:foo.hay
75 # --eval-str 'any:echo hi'
76
77 ## STDOUT:
78 ## END
79
80 #### Executor: can run user-defined Procs
81 shopt --set ysh:upgrade
82
83 var g = []
84
85 proc p-outside {
86 # note: append builtin would be nice
87 call g->append('p-outside')
88 }
89
90 # The Hay file can call any procs? That seems wrong actually
91 # We want to hide some of them
92
93 var cmd = ^(
94 p-outside
95
96 proc p-inside {
97 call g->append('p-inside')
98 }
99 p-inside
100 )
101
102 call eval(cmd)
103
104 pp test_ (g)
105
106 ## STDOUT:
107 (List) ["p-outside","p-inside"]
108 ## END
109
110 #### Executor: can run Hay (while Hay is hard-coded)
111
112 shopt --set ysh:upgrade
113
114 hay define Package/INSTALL
115
116 var cmd = ^(
117 Package foo {
118 version = '1.1'
119 INSTALL { echo hi }
120 }
121 )
122
123 call eval(cmd)
124
125 json write (_hay().children[0].attrs)
126
127 ## STDOUT:
128 {
129 "version": "1.1"
130 }
131 ## END
132
133
134 #### Executor: External Commands not allowed
135
136 var cmd = ^(seq 3)
137
138 call io->eval(cmd)
139
140 call eval(cmd)
141
142 ## status: 127
143 ## STDOUT:
144 1
145 2
146 3
147 ## END
148
149
150 #### Command subs, pipelines not allowed with --eval-pure
151
152 echo >command-sub.sh 'x=$(echo command sub)'
153 echo >command-sub.ysh 'var x = $(echo command sub)'
154
155 $SH --eval command-sub.sh -c 'echo $x'
156 $SH --eval-pure command-sub.sh -c 'echo command-sub.sh=$?'
157 $SH --eval-pure command-sub.ysh -c 'echo command-sub.ysh=$?'
158
159 echo
160
161 echo >pipeline.sh 'seq 3 | wc -l'
162
163 $SH --eval pipeline.sh -c 'echo eval'
164 $SH --eval-pure pipeline.sh -c 'echo pipeline.sh=$?'
165
166
167 ## status: 0
168 ## STDOUT:
169 command sub
170 command-sub.sh=5
171 command-sub.ysh=5
172
173 3
174 eval
175 pipeline.sh=5
176 ## END
177
178 #### Process subs, subshells not allowed with eval()
179 shopt --set ysh:upgrade
180
181 var cmd = ^( cat <(echo 1) <(echo 2) )
182 call io->eval(cmd)
183
184 try {
185 call eval(cmd)
186 }
187 echo code=$[_error.code] message=$[_error.message]
188 echo
189
190 var cmd = ^(( echo subshell ) )
191 call io->eval(cmd)
192
193 try {
194 call eval(cmd)
195 }
196 echo code=$[_error.code] message=$[_error.message]
197
198 ## STDOUT:
199 1
200 2
201 code=5 message=Process subs aren't allowed in pure mode (OILS-ERR-204)
202
203 subshell
204 code=5 message=Subshells aren't allowed in pure mode (OILS-ERR-204)
205 ## END
206
207 #### Background job &
208 shopt --set ysh:upgrade
209
210 var cmd = ^( sleep 0.01 & wait )
211 call io->eval(cmd)
212
213 try {
214 call eval(cmd)
215 }
216 echo code=$[_error.code] message=$[_error.message]
217
218 var cmd = ^( seq 3 | wc -l )
219 call io->eval(cmd)
220
221 try {
222 call eval(cmd)
223 }
224 echo code=$[_error.code] message=$[_error.message]
225
226 ## STDOUT:
227 code=5 message=Background jobs aren't allowed in pure mode (OILS-ERR-204)
228 3
229 code=5 message=Pipelines aren't allowed in pure mode (OILS-ERR-204)
230 ## END
231
232 #### Redirects
233 shopt --set ysh:upgrade
234
235 hay define Package
236 var cmd = ^( Package foo > out.txt )
237 call io->eval(cmd)
238 rm -v out.txt
239
240 try {
241 call eval(cmd)
242 }
243 # not created, but there's also no error?
244 # oh it's because of the PureExecutor
245
246 ## STDOUT:
247 TODO
248 ## END
249
250 #### Are any builtins allowed? true, false
251 shopt --set ysh:upgrade
252
253
254 # what other builtins should be allowed?
255 # - set and shopt could be dangerous?
256 # - set -- 1 2 3 may be OK
257 # - test -n is safe, but test --file is not
258 # - YSH mostly won't need it
259 # - not part of YSH
260 # - unset
261 # - printf -v (otherwise printf does I/O)
262 # - shift - use ARGV
263 # - getopts
264 # - alias
265 # Other:
266 # - type - some of this does I/O
267 #
268 # If we only consider YSH, everything has a trivial replacement, e.g. true and
269 # false. false can be assert [false]
270
271 var cmd = ^(
272 true
273 echo true
274 builtin true
275 echo builtin true
276 command true
277 echo command true
278
279 builtin false
280 echo builtin false
281 )
282
283 call io->eval(cmd)
284 call eval(cmd)
285 echo
286
287 ## STDOUT:
288 true
289 builtin true
290 command true
291 ## END
292
293 #### Are source or use builtins allowed?
294 shopt --set ysh:upgrade
295
296 # Problem: they cna "steal" information with directory traversal attacks?
297 # maybe only allow them in the same dirs
298 #
299 # Or maybe have a $PATH - $OILS_LIB_PATH
300 # and it can only be set by the caller, via command line flag?
301 #
302 # ysh --oils-path dir1:dir2 --eval
303 #
304 # use foo.ysh # relative to the path
305
306 var cmd = ^(
307 source foo.ysh
308 use foo.ysh
309 )
310
311 call eval (cmd)
312
313 ## STDOUT:
314 ## END
315
316 #### Can log to stderr in pure mode
317 shopt --set ysh:upgrade
318
319 var cmd = ^(
320 var name = 'world'
321
322 # I think this should be allowed
323 # And maybe log can be customized with:
324 # - xtrace unification? hierarchy
325 # - timestamps
326
327 log "hi $name"
328 )
329
330 call io->eval(cmd)
331 call eval (cmd)
332
333 ## STDOUT:
334 ## END
335
336
337 #### io and vm are not allowed
338
339 var cmd = ^(
340 = vm.getFrame(-1)
341 = vm.id({})
342
343 = io.stdin
344 )
345
346 call io->eval(cmd)
347 call eval (cmd)
348
349 ## STDOUT:
350 ## END
351
352 #### Can't make an alias of io->eval and call it, etc.
353 shopt --set ysh:upgrade
354
355 # The --eval-pure could be make an alias, and then "trick" the post-amble into
356 # calling it.
357
358 var f = io->eval
359
360 var cmd = ^(echo hi)
361
362 call f(cmd)
363
364 ## STDOUT:
365 ## END
366
367 #### Globbing not allowed
368
369 # TODO: should be @[io.glob('*.txt')]
370 # That is a bit verbose
371 var cmd = ^(
372 echo *.txt
373 )
374
375 call io->eval(cmd)
376 call eval(cmd)
377
378 ## STDOUT:
379 ## END
380
381 #### $RANDOM $SECONDS
382 shopt --set ysh:upgrade
383
384 var cmd = ^(
385 echo not-implemented=$RANDOM
386 echo $SECONDS
387 )
388
389 call io->eval(cmd)
390 call eval(cmd)
391
392 ## STDOUT:
393 ## END
394
395 #### Purely-evaluated code can't set traps for later
396
397 # this follows from 'no builtins', but probably good to test
398
399 var cmd = ^(
400 trap 'echo INT' INT
401 )
402
403 call io->eval(cmd)
404 call eval(cmd)
405
406 ## STDOUT:
407 ## END