Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Profiles and Access Dimensions

Define filesystem, network, command, home, and isolation authority in an immutable sandbox Profile.

developer

sandbox.Profile is the normalized authority description. Construct it with sandbox.NewProfile(ProfileConfig), not by trying to fill internal fields. Construction canonicalizes roots, rejects contradictory additional roots, validates every enum, derives required guarantees, and computes a deterministic fingerprint. The returned profile is immutable.

The dimensions

FieldValuesMeaning
WorkspaceRead, WorkspaceWriteDeny, Gated, AllowAuthority under WorkspaceRoot. Read and write are independent axes.
HostRead, HostWriteDeny, Gated, AllowThe rest of the host filesystem, subject to platform compilation.
NetworkDeny, Gated, AllowEgress authority. Target-scoped grants can narrow a gated request.
CommandDeny, Gated, AllowWhether command admission is refused, requires a grant, or can proceed.
AdditionalRoots[]RootAccessExtra canonical roots with their own read/write pair.
HomeIsolatedHome, RealHomeThe child HOME. Isolated homes are owned below the ExecutorSet scratch child.
IsolationSandboxed, UnconfinedWhether the OS boundary is required. Unconfined needs an explicit acknowledgement.

The access enum is deliberately ordered as Deny < Gated < Allow. That ordering is used by restriction to take the narrower value. It is not a claim that Gated itself is an operating-system restriction. It is an application admission state.

Construct a profile

package example

import (
	"fmt"

	"github.com/looprig/sandbox"
)

func profileFor(workspace, cache string) (*sandbox.Profile, error) {
	profile, err := sandbox.NewProfile(sandbox.ProfileConfig{
		WorkspaceRoot:  workspace,
		WorkspaceRead:  sandbox.Allow,
		WorkspaceWrite: sandbox.Gated,
		HostRead:       sandbox.Deny,
		HostWrite:      sandbox.Deny,
		Network:        sandbox.Gated,
		Command:        sandbox.Gated,
		Home:           sandbox.IsolatedHome,
		Isolation:      sandbox.Sandboxed,
		AdditionalRoots: []sandbox.RootAccess{
			{Path: cache, Read: sandbox.Allow, Write: sandbox.Deny},
		},
	})
	if err != nil {
		return nil, fmt.Errorf("profile: %w", err)
	}

	read, err := profile.AccessFor("filesystem.read", workspace)
	if err != nil {
		return nil, err
	}
	fmt.Println("workspace read authority", read == uint8(sandbox.Allow))
	return profile, nil
}

AccessFor accepts the stable access vocabulary command.execute, network, filesystem.read, and filesystem.write. Filesystem scopes are absolute paths, tree:<configured-root> for a configured recursive root, or host:* for the host axis. A tree scope that is not a configured root returns Deny; malformed scopes return ErrInvalidProfile.

Unconfined is explicit

An Unconfined profile is not a fallback when a host lacks a backend. It requires AckUnconfined: true, Allow on filesystem and network axes, and Allow for every additional root. The null backend is selected only for that acknowledged shape. A Sandboxed profile remains a required OS boundary and fails with ErrSandboxUnavailable or another typed setup error if the host cannot compile it.

The Home choice is independent from the authority axes. RealHome gives the child the real user home, while IsolatedHome gives each Executor key a separate directory and adds it to the compiled writable policy. See filesystem and environment for the practical implications.

Source

Proof

← back to documentation