A virtual jailed shell environment for Go apps backed by a virtual filesystem.
xeiaso.net/blog/2026/dancing-mad-sandboxing/
shell
agents
terrible-idea
sandbox
1package s3fs
2
3import (
4 "io/fs"
5 "os"
6 "time"
7
8 "github.com/aws/aws-sdk-go-v2/aws"
9 "github.com/aws/aws-sdk-go-v2/service/s3"
10 "tangled.org/xeiaso.net/kefka/s3fs/unixmeta"
11)
12
13// FileStat is the value returned by s3FileInfo.Sys() when the Unix-metadata
14// feature is enabled. It carries the raw numeric owner and group so consumers
15// can resolve them to names however they like.
16type FileStat struct {
17 UID, GID uint32
18}
19
20// s3FileInfo implements os.FileInfo
21type s3FileInfo struct {
22 name string
23 size int64
24 mode os.FileMode
25 modTime time.Time
26 sys *FileStat
27}
28
29func newFileInfo(name string, size int64, modTime time.Time) os.FileInfo {
30 return s3FileInfo{
31 name: name,
32 size: size,
33 mode: 0666,
34 modTime: modTime,
35 }
36}
37
38func newDirInfo(name string) os.FileInfo {
39 return s3FileInfo{
40 name: name,
41 mode: fs.ModeDir,
42 modTime: time.Time{},
43 }
44}
45
46// newFileInfoFromHead builds a FileInfo from a HeadObject response. When cfg is
47// nil the Unix-metadata feature is off and the result matches newFileInfo;
48// otherwise the x-amz-meta-* attributes are decoded, falling back to the
49// session defaults for any header that is missing.
50func newFileInfoFromHead(name string, head *s3.HeadObjectOutput, cfg *unixMetaConfig) os.FileInfo {
51 size := aws.ToInt64(head.ContentLength)
52 modTime := aws.ToTime(head.LastModified)
53 if cfg == nil {
54 return newFileInfo(name, size, modTime)
55 }
56
57 attrs := unixmeta.Decode(head.Metadata, unixmeta.Attrs{
58 UID: cfg.uid,
59 GID: cfg.gid,
60 Mode: 0o666 &^ cfg.umask,
61 Mtime: modTime,
62 })
63
64 return s3FileInfo{
65 name: name,
66 size: size,
67 mode: attrs.Mode,
68 modTime: attrs.Mtime,
69 sys: &FileStat{UID: attrs.UID, GID: attrs.GID},
70 }
71}
72
73func (fi s3FileInfo) Name() string {
74 return fi.name
75}
76
77func (fi s3FileInfo) Size() int64 {
78 return fi.size
79}
80
81func (fi s3FileInfo) Mode() os.FileMode {
82 return fi.mode
83}
84
85func (fi s3FileInfo) IsDir() bool {
86 return fi.mode.IsDir()
87}
88
89func (fi s3FileInfo) Sys() any {
90 if fi.sys == nil {
91 return nil
92 }
93 return fi.sys
94}
95
96func (fi s3FileInfo) ModTime() time.Time {
97 return fi.modTime
98}