Documentation
¶
Overview ¶
Package remote adds an OPT-IN, TLS-only network bridge on top of zero's local daemon (internal/daemon). It lets a remote client drive the SAME daemon SessionManager/Pool over the network, behind bearer-token authentication and a protocol-version floor. The local Unix-socket daemon is unchanged and remains the default; nothing here activates unless `zero daemon serve-remote` is run.
Security (fail closed):
- TLS is mandatory; the bridge refuses to serve without a cert/key.
- A connection is authenticated BEFORE any control frame is dispatched; a failed/absent token closes the connection (after a small backoff) and no session frame is ever processed.
- Tokens are compared in constant time and are never logged.
- The control-frame size cap and version negotiation from internal/daemon are reused unchanged; oversize/old-version handshakes are rejected.
- A remote-driven session runs through the same daemon dispatch, so it stays under the same sandbox + risk model — remote never bypasses local controls.
Index ¶
- Constants
- Variables
- func DialRemote(cfg RemoteConfig) (*daemon.Client, error)
- func ServerTLSConfig(certFile, keyFile string) (*tls.Config, error)
- func TokenFromEnv() (string, error)
- type Attestation
- type Authenticator
- type Bridge
- type BridgeOptions
- type RemoteConfig
- type SessionLink
- type TokenAuthenticator
Constants ¶
const ( EnvToken = "ZERO_DAEMON_REMOTE_TOKEN" EnvTokenFile = "ZERO_DAEMON_REMOTE_TOKEN_FILE" )
Env vars the bridge reads for its bearer token.
const ( ModeSession = "session" ModeBundle = "bundle" )
Connection modes negotiated in the auth handshake. The default (empty) is a daemon session, preserving the original behavior; "bundle" requests a one-shot git-bundle upload instead of a session.
Variables ¶
ErrUnauthorized is returned when a token does not match.
Functions ¶
func DialRemote ¶
func DialRemote(cfg RemoteConfig) (*daemon.Client, error)
DialRemote establishes a verified TLS connection to a remote bridge, authenticates with the bearer token, and returns a daemon.Client ready for Run/Attach/Status — the same client the local socket uses, so remote and local share one protocol. The server certificate is always verified (never InsecureSkipVerify).
func ServerTLSConfig ¶
ServerTLSConfig builds a server TLS config from a cert/key pair, refusing if either is missing (TLS is mandatory for the remote bridge).
func TokenFromEnv ¶
TokenFromEnv resolves the bridge token from EnvToken, or a file named by EnvTokenFile. It never logs the token.
Types ¶
type Attestation ¶
Attestation is an optional post-token hook (e.g. workload attestation). The default is a no-op; a deployment can supply a stricter implementation.
type Authenticator ¶
Authenticator verifies a bearer token presented by a remote client.
type Bridge ¶
type Bridge struct {
// contains filtered or unexported fields
}
Bridge serves authenticated remote connections and drives the local daemon's control dispatch for each one.
func NewBridge ¶
func NewBridge(opts BridgeOptions) (*Bridge, error)
NewBridge validates options and builds a Bridge.
func (*Bridge) Close ¶
Close stops the listener started by ListenAndServeTLS, causing Serve to return. Safe to call before serving or more than once.
func (*Bridge) ListenAndServeTLS ¶
ListenAndServeTLS binds a TLS listener on addr and serves until the listener is closed (via Close). It refuses to serve without a TLS config (no plaintext remote bridge).
type BridgeOptions ¶
type BridgeOptions struct {
// Server is the local daemon to drive (required).
Server *daemon.Server
// Authenticator verifies bearer tokens (required).
Authenticator Authenticator
// Attestation is an optional post-token hook; nil => no-op.
Attestation Attestation
// MinVersion is the lowest control-protocol version accepted; 0 =>
// daemon.ProtoVersion.
MinVersion int
// MaxConnections bounds concurrent remote connections; 0 => default.
MaxConnections int
// HandshakeTimeout bounds the auth handshake; 0 => default.
HandshakeTimeout time.Duration
// AuthFailDelay slows brute-force attempts; <0 => none, 0 => default.
AuthFailDelay time.Duration
// BundleDir is the directory under which uploaded git bundles are extracted
// into per-link working trees. Empty disables bundle uploads entirely (a
// bundle-mode connection is then refused — opt-in, fail closed).
BundleDir string
// MaxBundleBytes caps a single uploaded bundle; 0 => default.
MaxBundleBytes int64
Log func(string)
}
BridgeOptions configures a Bridge.
type RemoteConfig ¶
type RemoteConfig struct {
// Address is host:port of the remote bridge (required).
Address string
// Token is the bearer token (required).
Token string
// CACertFile, when set, is the only CA trusted for the server cert (use for a
// self-signed bridge). Empty => system roots. InsecureSkipVerify is never used.
CACertFile string
// ServerName overrides the TLS/SNI verification name; empty => host of Address.
ServerName string
// Timeout bounds the dial + auth handshake; 0 => default.
Timeout time.Duration
}
RemoteConfig configures a remote dial.
type SessionLink ¶
type SessionLink struct {
// Address is host:port of the remote bridge.
Address string `json:"address"`
// ServerName overrides TLS/SNI verification; empty => host of Address.
ServerName string `json:"server_name,omitempty"`
// CACertFile is the CA trusted for the bridge cert (for a self-signed bridge).
CACertFile string `json:"ca_cert_file,omitempty"`
// LinkID is the per-link identifier (a single path component on the remote).
LinkID string `json:"link_id"`
// RemotePath is the extracted working tree on the remote; use it as --cwd for
// a remote run/attach against the linked repo.
RemotePath string `json:"remote_path"`
// BundleSHA256 is the hex SHA-256 of the uploaded bundle, for verification.
BundleSHA256 string `json:"bundle_sha256,omitempty"`
}
SessionLink records the association between a local repo and the remote working tree a bundle upload produced. It carries everything needed to reach the linked repo again — the bridge address, TLS verification details, the link id, and the extracted remote path — except the bearer token, which is always supplied separately (never persisted to the link file).
func LoadSessionLink ¶
func LoadSessionLink(path string) (*SessionLink, error)
LoadSessionLink reads and validates a link file written by Save.
func UploadRepoBundle ¶
func UploadRepoBundle(cfg RemoteConfig, repoDir, linkID string) (*SessionLink, error)
UploadRepoBundle creates a git bundle of repoDir's full history and uploads it to the remote bridge over an authenticated, bundle-mode TLS connection. The bridge extracts it into a per-link working tree and returns its path, captured in the returned SessionLink. repoDir must be a git work tree.
func (SessionLink) Save ¶
func (l SessionLink) Save(path string) error
Save writes the link to path as pretty JSON with 0600 permissions, atomically (write-temp-then-rename) so a reader never sees a partial file.
func (SessionLink) Validate ¶
func (l SessionLink) Validate() error
Validate checks the fields required to use a link.
type TokenAuthenticator ¶
type TokenAuthenticator struct {
// contains filtered or unexported fields
}
TokenAuthenticator compares a presented token against a fixed secret in constant time.
func NewTokenAuthenticator ¶
func NewTokenAuthenticator(token string) (*TokenAuthenticator, error)
NewTokenAuthenticator builds a token authenticator, refusing an empty secret (fail closed — a bridge must never accept everyone).
func (*TokenAuthenticator) Authenticate ¶
func (a *TokenAuthenticator) Authenticate(token string) error
Authenticate reports nil when token matches the configured secret.