Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,23 @@ tagged.

## Unreleased

_Nothing yet._
### Added

- **`env ( … )` gains aliases, defaults, and literals.** Entries now use
shell / docker-compose parameter-expansion syntax: `NAME = ${HOST}` aliases
a differently-named host variable, `${HOST:-default}` / `${HOST-default}`
supply a fallback, `${HOST:?message}` / `${HOST?message}` make a variable
required (failing sandbox creation with a message when missing), and a bare
or quoted right-hand side (`EDITOR = vim`) sets a literal constant. Bare
`NAME` passthrough is unchanged.

### Fixed

- **Forwarded `env ( … )` vars now reach the agent user.** The generated
`/etc/profile.d/99-clawk-env.sh` was written `0600 root:root`, so the
agent's login shells silently skipped it and the variables never arrived.
It is now `0644`, matching the working OAuth-token export
(clawkwork/clawk#4).

## v0.2.0

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ sandbox my-project (
)
network ( allow api.example.com )
forwards ( 3000 )
env ( DATABASE_URL ) # names only; values come from your shell
env ( DATABASE_URL ) # forward a host var; values come from your shell
# also: GH=${OTHER_NAME}, LOG=${LOG:-info} defaults, API=${API:?required}
on create ( "go mod download" )
agent (
instructions "Ask before running destructive commands."
Expand Down
28 changes: 24 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ sandbox my-project (
)

env (
GITHUB_TOKEN
GITHUB_TOKEN # forward host $GITHUB_TOKEN as-is
GH_TOKEN = ${ACME_GH_TOKEN} # alias: read a differently-named host var
LOG_LEVEL = ${LOG_LEVEL:-info} # default when unset or empty
API_KEY = ${API_KEY:?set it} # required — fails create if missing
EDITOR = vim # literal constant
)

on create (
Expand Down Expand Up @@ -106,10 +110,26 @@ sandbox my-project (
plus `use <policy>…` chains — see
[Networking](networking.md#policies-and-use-chains).
- `forwards ( … )` — port forwards (`PORT` or `HOST:GUEST`).
- `env ( … )` — host env-var **names** to forward in. Values come from your
shell at boot; the file never stores secrets. Names must be
- `env ( … )` — environment variables to export inside the VM. Secret
*values* come from your shell at boot and are never written to disk on the
host; only names, defaults, and literals live in the file. Each entry uses
shell / docker-compose parameter-expansion syntax:
- `NAME` — forward the identically-named host variable.
- `NAME = ${HOST}` — alias: forward host `$HOST` under a different guest
name.
- `NAME = ${HOST:-default}` — use `default` when `$HOST` is unset **or**
empty; `${HOST-default}` falls back only when it is unset.
- `NAME = ${HOST:?message}` — require `$HOST`; a missing value fails
sandbox creation with `message` (`${HOST?message}` treats only unset,
not empty, as missing).
- `NAME = value` / `NAME = "value with spaces"` — a literal constant, no
host lookup.

Host variables are referenced only through `${…}`; a bare or quoted
right-hand side is always a literal. Names (both sides) must be
shell-variable shaped (letters, digits, `_`; not starting with a digit) —
lowercase names like `http_proxy` are fine.
lowercase names like `http_proxy` are fine. Whitespace around `=` is
optional.
- `on create ( … )` / `on up ( … )` — shell hooks. `create` runs once after
the first boot; `up` runs on every boot. Each command runs inside the
guest via `bash -lc` as a login shell: variable expansion, globs, and
Expand Down
14 changes: 8 additions & 6 deletions internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,14 @@ type Sandbox struct {
// instead of hitting an in-guest version error mid-boot. Zero means
// the record predates the field: ABI 1.
GuestABI int `json:"guest_abi,omitempty"`
// RequiredEnv holds the names (not values) of host env vars this
// sandbox wants exported inside the VM. Declared in clawk.mod via
// `env ( NAME ... )`. Values are read from the host shell at
// sandbox-create time and written to /etc/profile.d/99-clawk-env.sh
// in the guest — never persisted to disk on the host alongside the
// name so we don't check secrets into the sandbox state file.
// RequiredEnv holds the env entries this sandbox wants exported inside
// the VM, declared in clawk.mod via `env ( … )`. Each string is a
// canonical envspec entry — a bare name like "GITHUB_TOKEN" (passthrough),
// an alias/default like "GH=${ACME_GH_TOKEN:-}" or a literal like
// "EDITOR=vim". Only names and defaults/literals are stored: secret
// *values* are read from the host shell at sandbox-create/up time and
// written to /etc/profile.d/99-clawk-env.sh in the guest, never persisted
// to the sandbox state file. See internal/envspec.
RequiredEnv []string `json:"required_env,omitempty"`
// NestedVirt opts the VM into hardware-assisted nested
// virtualization so the guest can run its own VMs (Docker with KVM,
Expand Down
Loading
Loading