Documentation
¶
Overview ¶
Package sandbox provides sandbox/bwrap: the single source of truth for the tenant sandbox view. The same view config drives two enforcement mechanisms:
- WrapArgv: subprocess isolation — translates the view into a bwrap argv prefix around bash / ACP subprocesses (each call runs in its own mount namespace, keeping 127.0.0.1 / the Pod network stack);
- CheckRead / CheckWrite: in-process enforcement — for the filesystem/sandbox decorator and other in-process tools that bwrap cannot confine.
View: tmpfs masks the tenant-root parent (neighbor tenants invisible) → bind back this tenant root (rw); global root read-only with secretFiles masked; minimal system ro-binds; no --unshare-net.
Index ¶
Constants ¶
const ( ModeOff = "off" // no wrapping, no checks — equivalent to no sandbox ModeAuto = "auto" // enable when bwrap is usable, warn and degrade otherwise (local dev only) ModeBwrap = "bwrap" // force enable; missing deps fail closed per FailIfUnavailable (default) )
Sandbox modes.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Config ¶
type Config struct {
Mode string `json:"mode"`
// Env marks the deployment environment: "prod"/"production" upgrades
// mode=auto to fail-closed bwrap, so a misconfig cannot silently run
// unsandboxed in production. Explicit config, no implicit env detection.
Env string `json:"env"`
// RoBinds are extra read-only binds (public read-only paths shared by all
// tenants; source and target are the same path). Host absolute paths or
// workspace refs (e.g. "global:share_dir", resolved per call per tenant).
RoBinds []string `json:"roBinds"`
// RwBinds are extra read-write binds (public writable paths shared by all
// tenants; beware concurrent write conflicts). Host absolute paths or
// workspace refs (missing dirs are created).
RwBinds []string `json:"rwBinds"`
// HidePaths are masked: directories become invisible and read-only,
// files are masked empty. Host absolute paths or workspace refs. Applied
// after all binds, so they can mask sensitive subpaths of system binds or
// the global root. Resolution fails closed (a failed mask means a leak).
HidePaths []string `json:"hidePaths"`
// SecretFiles are sensitive files under the global root masked empty
// (relative to the global root), default ["secrets.enc.json"].
// Applied after the global ro-bind and ro/rwBinds.
SecretFiles []string `json:"secretFiles"`
// SystemBinds overrides the default minimal system read-only bind list;
// empty uses the built-in default (/usr /bin /lib /lib64 /opt plus
// DNS/cert files under /etc).
SystemBinds []string `json:"systemBinds"`
// TmpBase is the base dir on a host tmpfs (default /dev/shm/shellbwrap):
// each tenant gets a subdir bound rw as in-sandbox /tmp. /dev/shm has its
// own size cap (usually half of RAM), preventing tmpfs writes from eating
// node memory. The explicit value "tmpfs" falls back to bwrap's own
// --tmpfs /tmp (no size limit, not recommended). Must be exclusive per
// runner instance on a shared host: startup removes leftover contents.
TmpBase string `json:"tmpBase"`
}
Config configures sandbox/bwrap: the tenant view fields (roBinds/rwBinds/ hidePaths/secretFiles — shared by subprocess wrapping and in-process enforcement) plus the bwrap-mechanism knobs (mode/systemBinds/tmpBase/ probe-failure policy).
func (*Config) SetDefaults ¶
func (c *Config) SetDefaults()
SetDefaults implements pluginkit.Defaulter.
type Sandbox ¶
type Sandbox struct {
// contains filtered or unexported fields
}
Sandbox is the tenant sandbox view; tenant identity is resolved from ctx on every call.
func (*Sandbox) CheckRead ¶
CheckRead decides per the current tenant view whether an in-process read is allowed (used by the filesystem/sandbox decorator and other in-process tools — bwrap cannot confine Go code). path is a host absolute path. When the sandbox is disabled everything is allowed (confinement falls back to the tool layer, e.g. filesystem/local root).
The read model mirrors the bwrap view's allowlist: inside the sandbox only {tenantRoot, globalRoot, roBinds, rwBinds, systemBinds} exist and everything else is invisible; accordingly an in-process read is allowed only under {tenantRoot, globalRoot, roBinds, rwBinds} (system binds are a subprocess mechanism detail — fs tools have no legitimate need to read /usr; add an explicit roBind if one ever does). Deny rules:
- masked paths: matching hidePaths (incl. subpaths) or secretFiles;
- everything outside the allowlist (incl. neighbor tenants and any unrelated host path).
func (*Sandbox) CheckWrite ¶
CheckWrite decides per the current tenant view whether an in-process write is allowed. path is a host absolute path. Aligned with the bwrap view's read-only floor: only the tenant root and rwBinds are writable; everything else (global root, roBinds, system paths, unbound paths) is denied — the in-process equivalent of EROFS inside the sandbox.
func (*Sandbox) Enabled ¶
Enabled reports whether the sandbox is active (false in off mode or after an auto-mode probe fallback). When false, WrapArgv passes through and CheckRead/CheckWrite allow everything (confinement falls back to the tool layer).
func (*Sandbox) WrapArgv ¶
WrapArgv renders bwrap args for the current tenant and wraps the inner command (e.g. ["bash","-lc",cmd] or an ACP agent command). When the sandbox is disabled, inner is returned unchanged.
View: tmpfs masks the tenant-root parent (neighbor tenants invisible) → bind back this tenant root (rw); global root read-only with secretFiles masked; minimal system ro-binds; no --unshare-net (127.0.0.1 / Pod network stack preserved).