wrap

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

Documentation

Index

Constants

View Source
const NamePrefix = "brig-"

NamePrefix is what every brig sandbox name begins with. It is how brig picks its own sandboxes out of a runtime that may be running other things, so it is the one part of the name that is not the caller's to drop -- see the BRIG_NAME check in Load. cmd/brig reads the same prefix back when it lists and resets.

Variables

View Source
var Stderr = &Notices{}

Stderr is the Notices for the process's own stderr, shared by every writer of it. See Notices.

Functions

func DropEphemeralHome added in v0.3.0

func DropEphemeralHome(vmName string) (string, error)

DropEphemeralHome deletes the guest home of vmName when brig created it, and returns the path it deleted, or "" when there was nothing to delete.

Call it only after the runtime has removed the sandbox, and before ForgetSandbox drops the record it reads.

func EphemeralHomeOf added in v0.3.0

func EphemeralHomeOf(vmName string) string

EphemeralHomeOf returns the guest home `brig rm` would delete with vmName, or "" when it would keep it or there is none on disk.

func ForgetSandbox

func ForgetSandbox(vmName string) (bool, error)

ForgetSandbox drops the entry of the session carrying a removed sandbox, so the next session to take that name starts from the ordinary resolution rather than inheriting a directory chosen for a different one.

It reports whether any entry named vmName, and the error of the rewrite that drops it. Remove and `brig rm --all` ignore that error, the way releaseGatewayIP drops its own: a removal that worked must not report a failure because a bookkeeping file could not be rewritten. rm of a sandbox the runtime does not have needs it, since forgetting the session is all that rm does.

func ForgetSlugClaim

func ForgetSlugClaim(vmName string)

ForgetSlugClaim drops a removed sandbox's claim, so the next session name that lands on it can take it. Errors are dropped the way Remove drops ForgetSandbox's: a removal that worked must not report a failure because a bookkeeping file could not be rewritten.

func GuestCwd

func GuestCwd(cwd, workspace, guestHome string) string

GuestCwd maps the host directory a command was invoked from into the guest, so running brig from a project inside the workspace starts the agent in the matching guest directory.

Outside the workspace there is nothing mounted to land in, so it falls back to the guest home. That includes a cwd inside the *unnamed* workspace while running a named session: this run mounts only its own workspace, so there is no guest directory matching the other path to start in.

func GuestProject

func GuestProject(dir string) string

GuestProject is where the host directory dir is mounted in the guest: /work/<basename>.

The basename rather than the whole path, so the agent's prompt and every path it prints name the project the way its owner does. Two projects with one basename cannot be mounted at once, and nothing tries to: one run mounts one project.

func InForeground added in v0.4.0

func InForeground(f *os.File) bool

InForeground reports whether brig is in the foreground process group of the terminal f is. A job in the background that reads from the terminal is stopped, so it must not ask anything there.

func IsTerminal

func IsTerminal(f *os.File) bool

IsTerminal reports whether a file is a terminal, which decides both whether a guest exec allocates a pseudo-terminal and whether there is anyone to answer a question.

It asks the terminal driver -- the same ioctl isatty(3) makes -- rather than asking the file whether it is a character device. Those are not the same question, and the difference is load-bearing: /dev/null is a character device, so `brig run < /dev/null` counted as a terminal, and the one check that stops a boot -- an image that claims to be ours and fails verification -- put its question to a file that answers nothing. It failed closed only by accident, because the read that followed hit EOF; a confirm() that took silence for consent would have failed open with nothing in the tests to say so. /dev/zero is the same mistake with a worse ending: an unbounded read that never returns.

brig does not take golang.org/x/term for this. The check is one ioctl per platform, and syscall declares everything it needs. termWidth and foreground are one ioctl each in the same way.

func MacOSVersion

func MacOSVersion() string

MacOSVersion reports the host's macOS product version like "15.6", or "" off macOS.

It is the very reading Load seeds Config.MacOSVersion with -- the same kern.osproductversion sysctl, no second way to ask -- exported so brig doctor can name the host without building a Config for the sake of one field. The per-platform macOSVersion behind it is where the sysctl and the "" off-macOS answer are documented.

func Marker

func Marker(dir string) (string, error)

Marker identifies this workspace by path and inode.

A share is bound at boot and cannot be changed on a live VM, so a long-lived sandbox can end up mounting something other than the workspace: point BRIG_WORKSPACE somewhere new while the VM is up, or rename or replace the directory underneath it, and the guest keeps the old binding -- which, once the original path is gone, surfaces as an EMPTY guest home. Everything then looks broken in a way that points nowhere near the mount: the agent asks for a login and a theme as though freshly installed.

Path alone is not enough to detect it, because a renamed and recreated directory reuses the path with a different inode, so the marker carries both.

func PruneSessions

func PruneSessions(live []string)

PruneSessions drops every entry whose sandbox is not in the list of what the runtime has.

`brig ls` is where this runs, because it is the one verb that asks the runtime what exists and so the one place brig learns that a sandbox went away without going through Remove -- removed with the runtime's own CLI, or lost with a runtime that was reinstalled. The cost of being wrong is small in the direction that matters: a list that came back short prunes an entry that was still good, and the session pays one restart for it.

Called with every instance the runtime lists rather than only brig's own, so that a sandbox brig would not recognise still counts as present.

func RefOfSandbox

func RefOfSandbox(vmName string) string

RefOfSandbox is the ref of whichever session is carrying this sandbox, or "" when none is.

The key rather than the value, which is the other thing `brig ls` has to recover from a sandbox name: the listing prints the ref every other verb takes, and a sandbox name is not one -- brig-claude-code-refactor cannot say which of its dashes separated the agent from the label, and that is the ambiguity this index was keyed by ref to remove.

Read on the same terms as WorkspaceOfSandbox: a sandbox carries one session, so the first entry naming it is the only one.

func SessionRefs

func SessionRefs() []string

SessionRefs returns the ref of every session the index holds, sorted.

The index is keyed by ref, so this is a read of what is already there. It exists for completion, which needs the labels an agent has without asking the runtime: detecting a runtime and listing its sandboxes is hundreds of milliseconds on a keystroke, and returns nothing at all on a host that has no runtime installed. The cost of reading the index instead is bounded -- a sandbox removed outside brig stays listed until the next `brig ls` prunes it or `brig rm <ref>` forgets it -- and a stale candidate is a name that fails when run, not a wrong action.

func ShellCommandError added in v0.4.0

func ShellCommandError(command []string) error

ShellCommandError refuses a script flag with no script after it, or with one that is empty or only whitespace. bash -lc exits 0 on an empty script, so a caller whose script variable was unset would read the run as a success. Shell and ShellAttached check it themselves; the CLI asks first so it can refuse before anything boots.

func TrustKey

func TrustKey(cwd, workspace, guestHome string) string

TrustKey is the guest directory the agent records trust against.

Not simply the directory the agent starts in: it resolves the key to the git repository root when the working directory sits inside one. Keying on the cwd therefore writes a key that is never read back -- started in myrepo/sub the agent asks for the entry under myrepo -- and the dialog stays up.

Only a repository the guest can see counts. The guest has nothing but the workspace mounted as its home, so a .git above the workspace is invisible in there and the guest keys on the directory itself. The walk stops at the workspace for exactly that reason.

func WorkspaceOfSandbox

func WorkspaceOfSandbox(vmName string) string

WorkspaceOfSandbox is the workspace recorded for whichever session is carrying this sandbox, or "" when none is.

The other direction of the same lookup, exported for the callers that have a sandbox name and no ref: `brig ls`, which reports the directory a running sandbox actually has rather than the one its name would derive. A sandbox carries one session, so the first entry naming it is the only one -- two refs pointing at one sandbox takes a BRIG_NAME that overrides the sandbox name of both, and a listing could not tell those apart whatever it did here.

Types

type Config

type Config struct {
	Profile profile.Profile
	Runtime runtime.Runtime

	// RawName is the session name as typed; Slug is its path-safe form. The
	// raw name reaches the agent as its display name, so what you typed is
	// what you see; only the paths use the slug.
	RawName string
	Slug    string

	Workspace string
	// EphemeralHome is set when brig chose Workspace because the run named
	// none. `brig rm` deletes such a home with the sandbox.
	EphemeralHome bool
	// RemovedHome is the home Remove deleted, or "" when it kept one.
	RemovedHome string
	// HomeErr is why Remove could not delete an ephemeral home, or nil.
	HomeErr error

	VMName string
	// HostConfig are host directories seeded into the workspace, empty unless
	// the run opted in. See hostProjections.
	HostConfig []hostSeed
	Image      string
	Pull       string
	Mem        int
	CPUs       int

	// ReadyTimeout is how long to wait for the guest agent after the runtime
	// reports the sandbox running. The two are not the same moment: the VMM
	// process is up several seconds before the in-guest agent binds its
	// listener.
	ReadyTimeout time.Duration

	// Env is what the guest sees, with BRIG_FORWARD_ENV already applied. See
	// envOverride for what that override does and does not reach. The
	// requirement list it may read from stays on Profile: one list, one place.
	Env []profile.EnvBinding
	// OpenStore returns the secret store, and is called only when the profile
	// declares secrets -- opening it unconditionally would raise a keychain
	// prompt for runs that read nothing. Replaced in tests.
	OpenStore func() (creds.SecretReader, error)
	// MacOSVersion reports the host's macOS version like "14.5", or "" off
	// macOS. A field so a test can pin the version the hypervisor preflight
	// sees without running on the OS in question; Load sets it to the real
	// host reader. See preflightHypervisor.
	MacOSVersion func() string

	GitConfig       bool
	GitHosts        []string
	GitIdentity     bool
	GitUser         string
	GitUserFromHost bool
	GitName         string
	GitEmail        string

	TrustWorkspace bool

	// Verify is how strictly the guest image is checked before boot, and
	// VerifyPolicy is what counts as ours.
	Verify       verify.Mode
	VerifyPolicy verify.Policy
	// RuntimePolicy is who signs the Linux runtime bundle's releases, whose
	// record vouches for the kernel and initrd the bundle carries. A zero
	// value is the bundle's own release workflow.
	RuntimePolicy verify.Policy
	// Network is the posture this run was resolved to, which is the one the
	// next boot gets. Held here so the envelope, the report and the spec
	// handed to the runtime cannot disagree about what a reader was told. A
	// sandbox already up can run with another; see networkLine.
	Network Network

	// Publish is every guest port this sandbox offers on the host: what
	// --publish asked for on this line, and what the sandbox was already
	// publishing. PublishAsked is the first half alone.
	//
	// A publication belongs to the sandbox rather than to one run of it, so a
	// later `brig run` with no --publish keeps what is already published. The
	// envelope names all of them on every run, which is what keeps that from
	// being a hole nobody was told about.
	Publish      []runtime.Publication
	PublishAsked []runtime.Publication
	// Egress is the merged rule set of every policy bound to this run, and
	// Policies the names it came from. Empty Egress.Default means no policy
	// applies, which is every run before one is attached.
	//
	// Resolved with the posture above rather than at boot, because a policy
	// decides the posture: see the note there.
	Egress   policy.Egress
	Policies []string
	// BootDigest is the registry digest verifyDigest resolved and checked, set
	// only on a runtime that boots by digest. EnsureRunning hands it to the
	// runtime so the object that boots is the object that verified; empty means
	// boot the tag as given, which is every hull run and any path that could not
	// resolve a digest.
	BootDigest string

	AllowRefs   bool
	AllowDenied bool
	// Cwd is the host directory the command was invoked from, and GuestCwd is
	// where that lands inside the guest.
	Cwd      string
	GuestCwd string

	// Project is the host directory this run was told to mount beside the
	// guest home, and GuestProject is where it lands in the guest. Both are
	// empty on a run that named none, which is what every path below reads to
	// tell the two shapes apart.
	//
	// A second mount rather than a redirection of the first, because the guest
	// home IS the agent's home: its dotfiles, its onboarding state, its
	// caches. Pointing that mount at a repository would put all of it in the
	// repository. So the home stays brig's own and the project arrives
	// alongside it, outside the home -- see GuestProject.
	//
	// Per run, not per session: the session's identity is its ref, which is
	// the agent and the label, which is the home. Two runs of one session on
	// two projects are the same session, so nothing here reaches the sandbox
	// name or the slug. See mountProject and sessionEntry.
	Project      string
	GuestProject string

	// ProjectReal is the project with every link resolved. It is what the
	// PROJECT row prints. Project is what the runtime is handed, and
	// mountProject says why the two reach the same directory.
	ProjectReal string

	// NoTerminal declares that this run has no terminal to put a question to,
	// whatever this process's own stdin happens to be. brigd sets it: started
	// from a shell its stdin is a terminal, but it is the daemon's terminal and
	// not the client's, so a question asked there is asked of nobody while the
	// caller waits for an answer that cannot arrive. See confirm.
	NoTerminal bool

	Out io.Writer
	Err io.Writer

	// Progress is where the run narrates what it is doing -- the line that says
	// a boot has started, and nothing that anybody has to act on.
	//
	// Separate from Err because a caller that collects what a run said and
	// hands it to somebody else has to be able to tell the two apart. brigd is
	// that caller: it returns Err to the client as the request's warnings, and
	// with the narration in there a boot that went perfectly came back carrying
	// "starting sandbox ..." as a warning about itself. On a terminal the
	// distinction does not arise, both being lines on the same stderr, which is
	// why it went unnoticed for as long as the CLI was the only caller.
	Progress io.Writer

	// Verbosity decides how much of the above is written. See the type: Err
	// carries warnings and goes quiet only under -q, and Progress carries
	// narration and stays empty until --verbose asks for it. Out is not
	// levelled -- it is the report `brig info` was asked for by name.
	Verbosity Verbosity
	// contains filtered or unexported fields
}

Config is everything a run needs, resolved once.

func Load

func Load(t profile.Profile, o Options, rt runtime.Runtime) (*Config, error)

Load resolves the configuration for one invocation.

func (*Config) BuildEnv

func (c *Config) BuildEnv() (creds.Set, error)

BuildEnv resolves everything the guest is handed for this invocation.

It is called once per command and never by Stop: stopping a sandbox needs nothing but the instance name, and opening the secret store for it would raise a keychain approval prompt for a command that needs no credential.

func (*Config) CanPublish added in v0.3.0

func (c *Config) CanPublish(add []runtime.Publication) error

CanPublish reports what this backend cannot honour about opening these ports on this sandbox, or nil.

`brig network publish` on a stopped sandbox writes a record and boots nothing. Without this the refusal arrives at the next `brig run`, against a publication the user typed yesterday and can no longer see. Asked here, the refusal names the backend while the port is still on the command line.

func (*Config) EnsureRunning

func (c *Config) EnsureRunning(set creds.Set) (err error)

EnsureRunning brings the sandbox up if it is not already, and makes sure the one that is up is mounting this workspace.

func (*Config) Exec

func (c *Config) Exec(set creds.Set, argv []string, tty bool) error

Exec hands the terminal to a command inside the sandbox. It does not return on success.

func (*Config) ExecAttached

func (c *Config) ExecAttached(set creds.Set, argv []string, tty bool) (int, error)

ExecAttached runs the command as a child of brig rather than replacing brig with it, and returns the command's exit status. It is the --json counterpart of Exec: brig stays alive across the exec so it can report the outcome, which Replace cannot. The spec is Exec's own, so the child inherits everything the handover would have carried.

func (*Config) Info

func (c *Config) Info(set creds.Set)

Info is `brig info`: the envelope, then everything `brig env` has always printed, both to stdout because here the report is the point. `brig env` is kept as a deprecated spelling that calls this and prints one line naming the new one.

func (*Config) InfoData

func (c *Config) InfoData(set creds.Set) InfoDocument

InfoData is `brig info` as data: the same facts (*Config).envelope and (*Config).Status assemble for the text report, gathered once here so the two forms cannot come to disagree about what a sandbox would receive. It is the payload behind the Info kind of the shared JSON envelope.

It is read from the same Config, creds.Set and resolved secrets the text report reads -- not re-derived -- so a row added there and a field added here stay in step. The one promise this shares with every other --json shape is the one jsonout.go states: a credential is named and sourced, never valued, not here and not in an error string. listSecrets below reads provenance without decrypting, the same no-value read the text report makes.

A method beside envelope and Status rather than a second gather, so the JSON and the text say the same thing for the same reason the block and the report already do.

func (*Config) KeptProject added in v0.3.0

func (c *Config) KeptProject() string

KeptProject returns the host directory this session names as its project: the one this run mounts, or the remembered one refused for a link on the way to it. It is empty when the session has no project.

func (*Config) Plan added in v0.4.0

func (c *Config) Plan() PlanDocument

Plan is `brig plan`: the permissions of a run of this Config, read without opening a secret.

It is built from the Config Load resolved, the same one `brig info` and a run read, so the three cannot disagree about the home, the network or the image. What it does not share with them is BuildEnv. BuildEnv reads every needed secret out of the store, fails on a missing one, and writes the git helper into the guest home. The plan lists the store instead, which reads names and no values, and it writes nothing. So a missing secret is a row marked unresolved and the command still answers.

It asks the checks EnsureRunning makes before it prepares anything, and says when one refuses. Without them a plan would show an enforced policy, or a network of the sandbox's own, for a run `brig run` refuses.

func (*Config) PrepareWorkspace

func (c *Config) PrepareWorkspace() error

PrepareWorkspace makes the host side of the sandbox ready. It runs whether or not a VM has to be started: the workspace lives on the host, and the marker written here is what the stale-share check reads back.

Everything below writes into a directory the sandbox has had read-write for however long it has been running, so the whole of it goes through one [workspaceRoot] rather than through paths joined onto c.Workspace. See rootio.go for what that buys.

func (*Config) PrintPlan added in v0.4.0

func (c *Config) PrintPlan(d PlanDocument)

PrintPlan writes the plan as aligned rows to Out, the form a person reads.

func (*Config) PrintPreRunEnvelope

func (c *Config) PrintPreRunEnvelope(set creds.Set)

PrintPreRunEnvelope writes the envelope before a run or create boots the sandbox, to stderr. Stderr rather than stdout so it never lands in the agent's own output or in the sandbox name a scripted create captures; the block is a notice, not the command's result. --quiet suppresses it entirely.

func (*Config) Remove

func (c *Config) Remove() error

Remove stops the sandbox and clears the instance holding its name. A guest home brig created goes with it, and RemovedHome names it. A home named with --home or BRIG_WORKSPACE stays on the host. The index entry goes too, so the next sandbox to take this name resolves its workspace the ordinary way instead of inheriting one chosen for a sandbox that no longer exists.

The home is deleted only when the runtime removed the sandbox, because a sandbox that is still there may still be using it. The index is pruned either way, which is how hull releases the gateway address it hands out: the entry describes a sandbox the user has asked to be rid of, and a removal that failed is reported on its own.

A home that could not be deleted is reported in HomeErr, not as the error: the sandbox is gone, and the next run of the session deletes what is left before it boots. See reapOrphanHome.

func (*Config) SetupGit

func (c *Config) SetupGit(set *creds.Set) error

SetupGit writes the managed git files into the workspace and adds the plumbing variables that make them work.

The workspace is a host directory mounted as the guest home, so this is written host-side. Both files are regenerated on every run so an upgrade takes effect, and are wired in by an [include] appended once to .gitconfig -- your own .gitconfig is never rewritten.

func (*Config) Shell

func (c *Config) Shell(set creds.Set, command []string) error

Shell opens a login shell in the sandbox, or runs one command in it.

func (*Config) ShellAttached

func (c *Config) ShellAttached(set creds.Set, command []string) (int, error)

ShellAttached is Shell down the child path, so a shell profile under --json behaves like an agent one: brig runs it as a child and reports its exit status rather than replacing itself with it.

func (*Config) Status

func (c *Config) Status(set creds.Set)

Status reports what this invocation would do, by name only -- never a value. It is the answer to "is the sandbox going to be authenticated, and as whom", asked without starting anything.

func (*Config) Stop

func (c *Config) Stop() error

Stop shuts the sandbox down and leaves it there.

The wrapper this was ported from removed the instance as well, because it had no other verb. Now that `brig rm` exists, stop is the reversible half: the sandbox keeps its name and its identity, and starting it again is a boot rather than a fresh creation. A sandbox that was not running is not a failure worth reporting -- the end state is the one that was asked for.

A sandbox that would not stop IS worth reporting, and used to be swallowed: `brig stop` discarded the runtime's error and exited 0, so a VM still running with a forwarded credential in it read as one that was gone. The end state is still what decides -- an instance that is no longer running when the runtime complains was already in the state that was asked for -- so the runtime is asked again before its error is believed, which is also what keeps "it was not running to begin with" from becoming a failure.

Only an answer clears a failed stop. A runtime that could not say whether the sandbox is still up has not established the end state, and treating that as "gone anyway" puts the swallow back: the user is told a VM holding a forwarded credential is down when nothing checked.

type Env

type Env struct {
	// contains filtered or unexported fields
}

Env is the settings lookup, resolved in one place so every knob follows the same rule.

A key is looked up per-agent first, then globally. Per-agent wins so one shell can carry different settings for two agents:

BRIG_CLAUDE_CODE_WORKSPACE  this agent only
BRIG_WORKSPACE              every agent

func NewEnv

func NewEnv(profileName string, get func(string) (string, bool)) Env

NewEnv builds the lookup for a profile.

func (Env) Bool

func (e Env) Bool(key string, fallback bool) bool

Bool reads a setting as an on/off switch. Anything but "0" is on, matching the shell idiom the wrapper used, so URUNC_CLAUDE_GIT_CONFIG=1 and =true both enable it and =0 is the only way off.

This is the reading for a tuning knob, where on is the ordinary case and a value the helper does not recognise is closer to on than to a failed run. StrictBool is the reading for a switch whose off position is the safe one.

func (Env) Fields

func (e Env) Fields(key string, fallback []string) []string

Fields reads a whitespace-separated list.

func (Env) Get

func (e Env) Get(key string) (string, bool)

Get returns the first setting present under any of the prefixes.

func (Env) Int

func (e Env) Int(key string, fallback int) int

Int reads a setting as a number, falling back on anything unparseable rather than failing the run over a typo in a tuning knob.

func (Env) SettingName added in v0.4.0

func (e Env) SettingName(key string) string

SettingName is setting without the value, for a message that quotes the value itself and would otherwise print it twice. It is also the variable to set to change what key reads: a per-agent variable that is present wins even when it is empty, so setting the global one under it changes nothing.

func (Env) StrictBool

func (e Env) StrictBool(key string, fallback bool) (bool, error)

StrictBool reads a security switch, where the safe position is off and a value the helper cannot read must stop the run rather than be guessed.

Bool treats anything but "0" as on. That is right for a tuning knob and wrong for a switch that forwards a denied credential or writes brig's own files into the workspace: under that rule BRIG_ALLOW_DENIED=false reads as on, so a user spelling "off" the way their shell does turns the guard off by turning it on -- the switch fails open for exactly the person trying to close it. Here both spellings a user reaches for are understood, case-insensitively, and anything outside either set is refused by name instead of falling open.

Absent or empty still falls back, so the switch keeps its default until the user says otherwise -- the same meaning Bool gives them.

func (Env) String

func (e Env) String(key, fallback string) string

String returns the setting or a fallback.

type InfoCredential

type InfoCredential struct {
	Name   string `json:"name"`
	Source string `json:"source,omitempty"`
}

InfoCredential is one credential this run hands the guest: its name, and where the value came from ("environment", "secret" or "file"). Never the value.

type InfoDeny

type InfoDeny struct {
	Off       bool     `json:"off"`
	Forwarded []string `json:"forwarded,omitempty"`
	Withheld  []string `json:"withheld,omitempty"`
}

InfoDeny is what the denylist did to this run, rather than the list recited: which of the denied names are being forwarded anyway (with the guard off), which are still withheld, and whether the guard is off at all. The same answer reportDeny gives, because the list on its own is a claim about the future that BRIG_ALLOW_DENIED can make false.

type InfoDocument

type InfoDocument struct {
	Session     string           `json:"session,omitempty"`
	Profile     string           `json:"profile"`
	Sandbox     string           `json:"sandbox"`
	Runtime     InfoRuntime      `json:"runtime"`
	Isolation   string           `json:"isolation"`
	Workspace   string           `json:"workspace"`
	Project     *InfoProject     `json:"project,omitempty"`
	Image       InfoImage        `json:"image"`
	Verify      InfoVerify       `json:"verify"`
	Network     string           `json:"network"`
	Credentials []InfoCredential `json:"credentials"`
	Deny        *InfoDeny        `json:"deny,omitempty"`
	Git         InfoGit          `json:"git"`
	// ArgvExposed is the values BRIG_ENV_ARGV would put on the runtime's command
	// line, by name. Empty -- and omitted -- when the hatch is off, which is the
	// default. The names are variable names, never values.
	ArgvExposed []string         `json:"argvExposed,omitempty"`
	GuestLogin  []InfoGuestLogin `json:"guestLogin,omitempty"`
	Identity    *InfoIdentity    `json:"identity,omitempty"`

	// ProjectRefused is why the project this session remembers was not
	// mounted, and so why Project is absent. It is omitted when nothing was
	// refused, so a script can tell a refusal from a run with --no-project.
	ProjectRefused string `json:"projectRefused,omitempty"`
}

InfoDocument is the Info payload. Every field is a fact the text report already prints; none carries a credential value.

type InfoGit

type InfoGit struct {
	Enabled bool     `json:"enabled"`
	User    string   `json:"user,omitempty"`
	Hosts   []string `json:"hosts,omitempty"`
}

InfoGit is the guest git-over-HTTPS setup: on or off, and when on, the user and the hosts it is written for.

type InfoGuestLogin

type InfoGuestLogin struct {
	Name    string `json:"name,omitempty"`
	Source  string `json:"source,omitempty"`
	Expired bool   `json:"expired,omitempty"`
}

InfoGuestLogin is where the guest's login comes from and whether it is still good: a name and a source, and Expired when its own expiry has passed. Built from provenance the store carries without decrypting, so it is a fact about where a credential came from and never the credential.

type InfoIdentity

type InfoIdentity struct {
	Cwd   string `json:"cwd"`
	Name  string `json:"name,omitempty"`
	Email string `json:"email,omitempty"`
}

InfoIdentity is the guest commit identity as resolved in the invoking directory, which per-directory includeIf rules make a property of where the command ran. Names and an email, never a signing key.

type InfoImage

type InfoImage struct {
	Ref  string `json:"ref"`
	Pull string `json:"pull"`
}

InfoImage is the guest image and the pull policy, the pair the IMAGE row prints.

type InfoProject

type InfoProject struct {
	// Host is the path as typed, which is what the runtime is handed. The
	// envelope's PROJECT row prints the directory it resolves to, and the two
	// differ only above the trusted split, as /tmp and /private/tmp do on
	// macOS. See mountProject.
	Host  string `json:"host"`
	Guest string `json:"guest"`
}

InfoProject is the second host directory a run mounts beside the guest home, and where it lands in the guest. Absent -- and omitted -- on a run that named no project.

type InfoRuntime

type InfoRuntime struct {
	Kind      string `json:"kind,omitempty"`
	Bin       string `json:"bin,omitempty"`
	Available bool   `json:"available"`
}

InfoRuntime is the runtime this run resolved to, and whether it is there at all. Available is false with Kind and Bin empty when no runtime is on PATH: `brig info` answers without one and marks the line unavailable rather than failing, so --json must carry the same complete object.

type InfoVerify

type InfoVerify struct {
	Mode   string `json:"mode"`
	Policy string `json:"policy"`
}

InfoVerify is whether the image is checked before boot and whose policy says so: the mode (off, warn, require) and "brig" for brig's own policy or "replaced" for one the BRIG_VERIFY_* variables overrode. The outcome is not here -- `brig info` reports before any boot, so there is nothing verified yet to report, the same reason the VERIFY row prints the mode and not the result.

type Network

type Network string

Network is the posture a sandbox runs with.

const (
	// NetShared is one network for sandboxes on the host. Whether they can
	// reach each other depends on the backend. See docs/security.md.
	NetShared Network = "shared"
	// NetIsolated is a network of this sandbox's own, so no other sandbox is
	// on it whatever the backend does with a shared one.
	NetIsolated Network = "isolated"
	// NetOffline is a sandbox with no route out. The agent runs, the workspace
	// is mounted, nothing leaves.
	NetOffline Network = "offline"
)

func AllNetworks

func AllNetworks() []Network

AllNetworks is every posture that exists. A list rather than a comment, so a test can walk it and catch a posture that gained a case in one switch and not the other.

func ParseNetworkStrict

func ParseNetworkStrict(s, source string) (Network, error)

ParseNetworkStrict reads a posture and refuses anything it does not recognise. source is how the value reached brig -- a flag, a setting, a profile field -- and it is named in the refusal, because being told about BRIG_NETWORK when you typed --network sends you looking for a variable you never set.

Strict for the same reason the security switches are: this decides whether a sandbox can reach the network at all, so a typo must stop the run rather than quietly pick a posture nobody asked for. The empty string is the unset case and keeps the default.

func (Network) Line

func (n Network) Line() string

Line is the posture as a reader is told it, with the consequence spelled out: "offline" on its own is a word, and what a reader needs is what it costs them.

Beside RuntimeNet deliberately. A posture has two vocabularies, the runtime's and the reader's, and keeping both on the type means a posture added later cannot pick up one translation and quietly miss the other.

The shared line describes the topology and stops there. Whether one sandbox can actually reach another on that network is a property of the backend, not of this setting, and it has changed under brig between runtime releases. A row claiming either answer is false somewhere, or false after the next release, so it claims what is true everywhere: these sandboxes are on one network rather than each on its own. The answer per backend, and when it was measured, is in docs/security.md and docs/manual-tests/sandbox-reachability.md.

func (Network) RuntimeNet

func (n Network) RuntimeNet() string

RuntimeNet is the word the runtime adapters take for this posture. The two vocabularies are deliberately separate: "offline" is what a person asks for, "none" is what a runtime is told.

type Notices added in v0.4.0

type Notices struct {
	// W is where the warnings go. nil is the process's stderr, read at each
	// write, so a test that swaps os.Stderr sees them.
	W io.Writer
	// NoTerminal says W has no person reading it, whatever it is. See
	// Config.NoTerminal.
	NoTerminal bool
	// contains filtered or unexported fields
}

Notices prints brig's own warnings to one writer: a line, or a block of a heading and rows under it.

Off a terminal every line carries brig's prefix, so a line copied out of a log or read back by brigd's client still says whose it is. On a terminal only a block's heading does: the rows sit under it as one unit, and a blank line parts a block from the warnings around it. A prefix on every row of a list is noise to a reader who can see where the block starts.

One Notices per writer, because the spacing depends on what the writer already shows. cmd/brig and a Config both write to stderr in one run, and both use Stderr for it, so a line from one after a block from the other is still parted from it.

func (*Notices) Ask added in v0.4.0

func (n *Notices) Ask(question string)

Ask puts a yes-or-no question after the warnings, parted from a block above it like any other line, and leaves the cursor after it for the answer.

func (*Notices) Error added in v0.4.0

func (n *Notices) Error(msg string)

Error prints the error a command ended with. Its lines stay as the error wrote them, with the prefix on the first alone, on a terminal or not: an error is quoted whole into bug reports and scripts, and its wording is its own. It only takes part in the spacing, so it does not run into a block.

func (*Notices) Say added in v0.4.0

func (n *Notices) Say(msg string)

Say prints msg: one line, or a block when msg has more than one. A block goes out in one write, so it does not interleave with a child's output.

type Options

type Options struct {
	Name      string // session name, as typed
	Image     string
	Workspace string
	// Project is the directory named as run's positional argument, to be
	// mounted beside the guest home. Relative is fine: it is resolved against
	// the directory the command was invoked from, because `brig run claude .`
	// is the line the positional exists for.
	Project string
	// NoProject asks for this run to have no project at all, and is the only
	// way to say so once a project is remembered: a positional names a
	// directory, and no directory names absence. Without it a session handed a
	// project keeps it for the rest of its life, since every later flagless
	// verb inherits it.
	NoProject bool
	Mem       int
	CPUs      int
	// Skills opts in to projecting the host's own agent config (skills,
	// plugins) read-only into the guest. Off unless asked for: it is the
	// user's real config, and handing it to a sandbox should be a decision.
	Skills bool
	// Network is the posture asked for on the command line, and beats both the
	// setting and the profile. Empty means nothing was asked for.
	Network string
	// Publish are the --publish values on the command line, unparsed. Each opens
	// a guest port on the host; see runtime.ParsePublication for the grammar.
	Publish []string
	// Verbosity is how much this invocation was asked to say: --verbose and
	// -q, which are read left of the verb. The zero value is the default
	// level, so a caller with no opinion -- brigd, and every test that builds
	// Options by hand -- gets what a person reads.
	Verbosity Verbosity
}

Options are the per-invocation overrides a command line can supply. Each one outranks the corresponding setting, which outranks the profile.

type PlanCredential added in v0.4.0

type PlanCredential struct {
	Name     string `json:"name"`
	Delivery string `json:"delivery"`
	Source   string `json:"source,omitempty"`
	Secret   string `json:"secret,omitempty"`
	Required bool   `json:"required"`
	State    string `json:"state"`
	Reason   string `json:"reason,omitempty"`
}

PlanCredential is one credential by name, delivery and source. It is creds.Planned with JSON names. Plan converts one to the other, so a field added to one and not the other fails to build.

type PlanDocument added in v0.4.0

type PlanDocument struct {
	Session string `json:"session,omitempty"`
	Profile string `json:"profile"`
	Sandbox string `json:"sandbox"`
	// Refused is why `brig run` refuses this run, from the checks it makes
	// before it prepares anything that a plan can ask without writing (see
	// Plan), and absent when none of them refuses. The plan still describes
	// the run, and the command still exits 0.
	Refused   *PlanRefusal `json:"refused,omitempty"`
	Runtime   PlanRuntime  `json:"runtime"`
	Isolation string       `json:"isolation"`
	Home      PlanMount    `json:"home"`
	Project   *PlanMount   `json:"project,omitempty"`
	// ProjectRefused is why the project this session remembers is not
	// mounted, as in the Info payload. Refused carries the same reason,
	// because the run stops on it.
	ProjectRefused string `json:"projectRefused,omitempty"`
	// Skills are the host directories --skills copies into the guest home.
	Skills []PlanMount `json:"skills"`
	Image  InfoImage   `json:"image"`
	Verify InfoVerify  `json:"verify"`
	// Network is the sentence the Info payload carries, and Posture the word
	// for the next boot, or unknown when the run refuses a sandbox whose
	// network brig cannot read.
	Network string   `json:"network"`
	Posture string   `json:"posture"`
	Ports   []string `json:"ports"`
	// Policies names every policy bound to this run. NoPolicy says none is,
	// so a reader does not have to infer it from an empty list.
	Policies    []string         `json:"policies"`
	NoPolicy    bool             `json:"noPolicy"`
	Egress      *PlanEgress      `json:"egress,omitempty"`
	Credentials []PlanCredential `json:"credentials"`
	// ArgvExposed names what the Info payload's field of the same name
	// names: the values BRIG_ENV_ARGV would put on the runtime's command
	// line. Sorted, where info keeps the order the run adds them in, because
	// the order of a profile's bindings is not a permission. Omitted when the
	// setting is off, which is the default.
	ArgvExposed []string   `json:"argvExposed,omitempty"`
	Limits      PlanLimits `json:"limits"`
	// Digest is sha256 over the compact encoding of this document with
	// Digest empty. See planDigest.
	Digest string `json:"digest"`
}

PlanDocument is the Plan payload. Every list in it is sorted and none is null, so two plans of the same run encode to the same bytes and the digest over them is stable.

type PlanEgress added in v0.4.0

type PlanEgress struct {
	Default string        `json:"default"`
	Allow   []policy.Rule `json:"allow"`
	Deny    []policy.Rule `json:"deny"`
}

PlanEgress is the merged rule set of every bound policy.

type PlanLimits added in v0.4.0

type PlanLimits struct {
	Mem  int `json:"mem"`
	CPUs int `json:"cpus"`
}

PlanLimits is what the guest is given: memory in MB and vCPUs.

type PlanMount added in v0.4.0

type PlanMount struct {
	Host  string `json:"host"`
	Guest string `json:"guest"`
	Mode  string `json:"mode"`
}

PlanMount is one host directory the guest reaches, where it lands and how.

type PlanRefusal added in v0.4.0

type PlanRefusal struct {
	// Reason is the refusal as `brig run` prints it.
	Reason string `json:"reason"`
}

PlanRefusal is a refusal `brig run` makes before it starts anything. It is an object rather than a string so that a field can be added beside Reason later, such as which class of refusal it is, without renaming this one.

type PlanRuntime added in v0.4.0

type PlanRuntime struct {
	InfoRuntime
	Backend string `json:"backend,omitempty"`
}

PlanRuntime is the runtime and the backend under it. Backend is the hypervisor the profile or BRIG_HYPERVISOR names, empty for the runtime's own default.

type Verbosity

type Verbosity int

Verbosity is how much a run says about itself.

The rule it encodes: by default, print what the user has to act on. A warning is an action and stays; brig's own narration and the runtime's own output are not, and wait to be asked for. Below the default is the form a script reads, where the output is identifiers and the errors that stopped them, and nothing in between.

Ordered rather than a set of modes, so every print site asks the same question -- is this worth saying at the level we are at -- with one comparison instead of a switch that has to be kept exhaustive.

const (
	// Quiet is identifiers and errors only, for a script. An error is never
	// printed at this level; it is returned, and the caller prints it.
	Quiet Verbosity = iota - 1
	// Normal is the default: warnings, the execution envelope, and one line
	// each end of a long operation. It is the zero value, so a Config built by
	// hand is at the level a person reads rather than silent.
	Normal
	// Verbose adds brig's own progress and the runtime's own output.
	Verbose
)

type VerifyRefusedError

type VerifyRefusedError struct{ Err error }

VerifyRefusedError marks a boot brig stopped because the guest image or the kernel it boots did not verify: a bad signature, a mismatch, or a "could not check" under BRIG_VERIFY=require, plus the interactive refusals of the same.

It carries the underlying message unchanged and only adds a class a caller can match, so a run refused for this reason gets an exit code of its own rather than folding into the general failure. EnsureRunning wraps the verify step's error in it, which is the one place both the image and the boot-asset checks pass through.

func (*VerifyRefusedError) Error

func (e *VerifyRefusedError) Error() string

func (*VerifyRefusedError) Unwrap

func (e *VerifyRefusedError) Unwrap() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL