|
3 | 3 | package main |
4 | 4 |
|
5 | 5 | import ( |
6 | | - "archive/tar" |
7 | 6 | "bytes" |
8 | | - "compress/gzip" |
9 | 7 | "encoding/binary" |
10 | 8 | "errors" |
11 | 9 | "fmt" |
12 | 10 | "io" |
13 | | - "io/fs" |
14 | 11 | "net" |
15 | 12 | "os" |
16 | 13 | "os/exec" |
17 | | - "path/filepath" |
18 | 14 | "strconv" |
19 | 15 | "strings" |
20 | 16 | "sync" |
@@ -64,15 +60,6 @@ func handleConn(conn net.Conn) { |
64 | 60 | _ = vsockexec.EncodeResponse(conn, vsockexec.ExecResponse{ExitCode: 1, Error: err.Error()}) |
65 | 61 | return |
66 | 62 | } |
67 | | - if len(req.WorkspaceTarGz) > 0 { |
68 | | - if err := materializeWorkspace(req.WorkspaceTarGz, "/workspace", req.WorkspaceAccess); err != nil { |
69 | | - _ = vsockexec.EncodeResponse(conn, vsockexec.ExecResponse{ExitCode: 1, Error: err.Error()}) |
70 | | - return |
71 | | - } |
72 | | - if req.Dir == "" { |
73 | | - req.Dir = "/workspace" |
74 | | - } |
75 | | - } |
76 | 63 | if len(req.EntropySeed) > 0 { |
77 | 64 | _ = injectEntropy(req.EntropySeed) |
78 | 65 | } |
@@ -234,100 +221,6 @@ func buildCommandEnv(requestEnv []string) []string { |
234 | 221 | return out |
235 | 222 | } |
236 | 223 |
|
237 | | -func materializeWorkspace(tarGz []byte, destRoot, access string) error { |
238 | | - if err := os.RemoveAll(destRoot); err != nil { |
239 | | - return fmt.Errorf("reset workspace root: %w", err) |
240 | | - } |
241 | | - if err := os.MkdirAll(destRoot, 0o755); err != nil { |
242 | | - return fmt.Errorf("create workspace root: %w", err) |
243 | | - } |
244 | | - if err := extractTarGz(tarGz, destRoot); err != nil { |
245 | | - return fmt.Errorf("extract workspace: %w", err) |
246 | | - } |
247 | | - if strings.EqualFold(strings.TrimSpace(access), "ro") { |
248 | | - if err := makeTreeReadOnly(destRoot); err != nil { |
249 | | - return fmt.Errorf("mark workspace read-only: %w", err) |
250 | | - } |
251 | | - } |
252 | | - return nil |
253 | | -} |
254 | | - |
255 | | -func extractTarGz(content []byte, destRoot string) error { |
256 | | - gr, err := gzip.NewReader(bytes.NewReader(content)) |
257 | | - if err != nil { |
258 | | - return err |
259 | | - } |
260 | | - defer gr.Close() |
261 | | - |
262 | | - tr := tar.NewReader(gr) |
263 | | - root := filepath.Clean(destRoot) |
264 | | - prefix := root + string(os.PathSeparator) |
265 | | - for { |
266 | | - hdr, err := tr.Next() |
267 | | - if errors.Is(err, io.EOF) { |
268 | | - return nil |
269 | | - } |
270 | | - if err != nil { |
271 | | - return err |
272 | | - } |
273 | | - name := strings.TrimPrefix(filepath.Clean("/"+hdr.Name), "/") |
274 | | - if name == "." || name == "" { |
275 | | - continue |
276 | | - } |
277 | | - target := filepath.Join(root, name) |
278 | | - cleanTarget := filepath.Clean(target) |
279 | | - if cleanTarget != root && !strings.HasPrefix(cleanTarget, prefix) { |
280 | | - return fmt.Errorf("invalid archive path %q", hdr.Name) |
281 | | - } |
282 | | - |
283 | | - switch hdr.Typeflag { |
284 | | - case tar.TypeDir: |
285 | | - if err := os.MkdirAll(cleanTarget, fs.FileMode(hdr.Mode)); err != nil { |
286 | | - return err |
287 | | - } |
288 | | - case tar.TypeReg, tar.TypeRegA: |
289 | | - if err := os.MkdirAll(filepath.Dir(cleanTarget), 0o755); err != nil { |
290 | | - return err |
291 | | - } |
292 | | - f, err := os.OpenFile(cleanTarget, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fs.FileMode(hdr.Mode)) |
293 | | - if err != nil { |
294 | | - return err |
295 | | - } |
296 | | - if _, err := io.Copy(f, tr); err != nil { |
297 | | - _ = f.Close() |
298 | | - return err |
299 | | - } |
300 | | - if err := f.Close(); err != nil { |
301 | | - return err |
302 | | - } |
303 | | - case tar.TypeSymlink: |
304 | | - return fmt.Errorf("symlinks are not supported in workspace snapshots: %q", hdr.Name) |
305 | | - default: |
306 | | - // Skip unsupported entries (devices, fifos, etc.) in MVP. |
307 | | - } |
308 | | - } |
309 | | -} |
310 | | - |
311 | | -func makeTreeReadOnly(root string) error { |
312 | | - return filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { |
313 | | - if err != nil { |
314 | | - return err |
315 | | - } |
316 | | - if d.Type()&os.ModeSymlink != 0 { |
317 | | - return nil |
318 | | - } |
319 | | - info, err := d.Info() |
320 | | - if err != nil { |
321 | | - return err |
322 | | - } |
323 | | - mode := info.Mode().Perm() |
324 | | - if d.IsDir() { |
325 | | - return os.Chmod(path, mode&^0o222|0o555) |
326 | | - } |
327 | | - return os.Chmod(path, mode&^0o222|0o444) |
328 | | - }) |
329 | | -} |
330 | | - |
331 | 224 | func errorsIsClosed(err error) bool { |
332 | 225 | if err == nil { |
333 | 226 | return false |
|
0 commit comments