summaryrefslogtreecommitdiff
path: root/example/simple-example.lua
blob: 6f35400397a737998ea2931461170ca6e46f0df7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
-- example/simple-example.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Simple example
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--

supple = require'supple'

-- Code string to run in the untrusted environment
subcode = [[
local t = ...
local tot = 0
for i = 1, #t do
  tot = tot + t[i]()
end
t.tot = tot
return tot, -t
]]

-- Generate a function to return 'n'
local function give_n(n)
      return function() return n end
end

-- A useful table for the test
local tab = {
      give_n(4),
      give_n(8),
      give_n(12),
}

-- A metatable which defines -tab to equal 'JEFF'
local mt = {
   __unm = function () return "JEFF" end
}

setmetatable(tab, mt)

local tests, passed = 0, 0

local function lprint(expect, result, ...)
   tests = tests + 1
   luxio.write(1, ("[%d]\r"):format(tests))
   local foo = {n=select("#",...),...}
   if expect and not result then
      print "Want OK, got FAIL"
   elseif (not expect) and result then
      print "Want FAIL, got OK"
   end
   if expect ~= result then
      for i = 1, foo.n do
	 if type(foo[i]) == "table" then
	    print("{")
	    for k, v in pairs(foo[i]) do
	       print("",k,v)
	    end
	    print("}")
	 else
	    print(foo[i])
	 end
      end
      print()
   else
      passed = passed + 1
   end
end

local function lprint_ok(...)
   return lprint(true, ...)
end

local function lprint_fail(...)
   return lprint(false, ...)
end

-- Finally, run the subcode
lprint_ok(supple.host.run(subcode, "@test-code", tab))
assert(tab.tot == 24)

-- Now run a supple command which we expect to error out.
lprint_fail(supple.host.run("unknown()", "@test-code"))

-- And now, one where we pass an error from host to sandbox and back
lprint_fail(supple.host.run("local f = ... f()", "@test-code", function() unknown() end))

-- And now, one where we pass an error from sandbox to host to sandbox and back
lprint_fail(supple.host.run("local f = ... f(function() unknown() end)", "@test-code", function(ff) ff() end))

-- Next , a reasonable traceback via named functions on each end...

local errsrc = [[
      function raises()
	 does_not_exist()
      end
      
      function passes()
	 raises()
      end

      function chains(f)
	 f(passes)
      end

      local callme = ...

      callme(chains)
]]

function loopback(f)
   f(loopback)
end

lprint_fail(supple.host.run(errsrc, "@error-code", loopback))

-- Now we try the sandboxing limits

local long_run = [[
      local s = ""
      for i = 1, 10000 do
	 s = s .. "FISHFISHFISHFISHFISH"
      end
      return #s
]]

supple.host.set_limits { count = 100 }
lprint_fail(supple.host.run(long_run, "@long-code"))
supple.host.set_limits { memory = 1000 }
lprint_fail(supple.host.run(long_run, "@big-code"))


-- next we demonstrate that ipairs works on proxied tables

local summing = [[
      local t = ...
      local tot = 0
      for i, v in ipairs(t) do
	 tot = tot + v
      end
      return tot
]]

lprint_ok(supple.host.run(summing, "@summing", { 10, 14, 3 }))

-- next we demonstrate that next works on proxied tables

local isempty = [[
      local t = ...
      return next(t) == nil
]]

lprint_ok(supple.host.run(isempty, "@isempty", {}))
lprint_ok(supple.host.run(isempty, "@isempty", {"bar"}))

-- And now that pairs works on proxied tables

local keys = [[
      local t = ...
      local ret = {}
      for k, v in pairs(t) do
	 ret[#ret+1] = k
      end
      ret.ret = ret
      return ret
]]

lprint_ok(supple.host.run(keys, "@keys", { foo="bar", baz="meta" }))

-- Next demonstrate that using supple.host.loadstring works to allow
-- globals set in the parent to be seen/changed

local function loader(n)
   return supple.host.loadstring(([[return { print=print, name = %q }]]):format(n), "@" .. n)
end

local getname = [[
      local f = ...
      local mod = (f("Jeff"))()
      return mod.print and "PRINT" or mod.name
]]

-- Expect to see 'PRINT'
lprint_ok(supple.host.run(getname, "@getname", loader))

-- Attempt to do a test which shows the same issue as seen with gitano-web

local updates = {
   ["refs/heads/master"] = {
      oldsha = "0123456789abcdef0123456789abcdef01234567",
      newsha = "76543210fedcba9876543210fedcba9876543210",
   }
}

local update_code = [[
      local repo, updates = ...
      local hadmaster = false
      local foundrefs = {}
      if updates["refs/heads/master"] then
	 hadmaster = true
      end
      for ref, data in pairs(updates) do
	 foundrefs[ref] = { data.oldsha, data.newsha }
      end
      return hadmaster, foundrefs
]]

for i = 1, 1000 do
   lprint_ok(supple.host.run(update_code, "@update-hook", "REPO", updates))
   if passed ~= tests then
      os.exit(1)
   end
end

print(("[%d/%d OK]"):format(passed, tests))

-- Dump the final trace, just for edification
--print(supple.track.stop())