wire

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package wire is the hand-written ConnectRPC layer for the gpgsmith daemon: the typed client wrapper used by CLI/UI/TUI frontends, the per-service handler implementations the daemon mounts on its HTTP server, and the proto↔kernel type conversion that keeps protobuf types from leaking out of this package into the rest of the codebase.

The package is named "wire" rather than "rpc" because Go's standard library already has "net/rpc" and golangci-lint's revive var-naming rule flags the shadowed name.

Layering:

pkg/gen/gpgsmith/v1                       generated message + service stubs (untouched)
pkg/gen/gpgsmith/v1/gpgsmithv1connect     generated client/server interfaces (untouched)
pkg/wire                                  THIS PACKAGE — handlers, client, mapping
pkg/daemon                                implements wire.Backend with real sessions
pkg/cli/gpgsmith                          uses wire.Client to talk to the daemon

The wire package depends on the kernel (pkg/gpgsmith, pkg/vault, pkg/gpg, pkg/audit) for the value types it converts to/from proto, but does NOT depend on the daemon runtime — that direction would create a cycle. The daemon imports wire and provides a Backend implementation; wire never reaches into the daemon.

Index

Constants

View Source
const (
	// SessionHeader is the HTTP header used to bind an RPC to a specific
	// daemon-side session. The value is an opaque token returned by
	// OpenVault / ResumeVault / CreateVault.
	SessionHeader = "Gpgsmith-Session"

	// SessionTokenListHeader is stamped by the daemon onto
	// DaemonService.ListSessions responses. Its value is a
	// comma-separated list of "<token>=<vault_name>" pairs. Used by
	// local CLI callers to auto-bind GPGSMITH_SESSION when exactly one
	// session is open.
	SessionTokenListHeader = "Gpgsmith-Session-Tokens"

	// SessionEnvVar is the environment variable CLI frontends read to
	// populate the SessionHeader on outbound requests.
	SessionEnvVar = "GPGSMITH_SESSION"

	// SessionVaultNameEnvVar is an informational env var the CLI
	// exports alongside GPGSMITH_SESSION inside a wrapped subshell, so
	// the user's PS1 and scripts can reference the vault name without
	// calling the daemon.
	SessionVaultNameEnvVar = "GPGSMITH_VAULT_NAME"
)

Variables

This section is empty.

Functions

func ContextWithSessionToken added in v0.5.0

func ContextWithSessionToken(ctx context.Context, token string) context.Context

ContextWithSessionToken returns ctx with the given token stored under the private session context key. Exported for tests that want to exercise handlers without going through an HTTP round-trip.

func TokenFromContext added in v0.5.0

func TokenFromContext(ctx context.Context) (string, bool)

TokenFromContext returns the session token stamped onto ctx by the server-side interceptor, if any.

func WithEnvSessionInterceptor added in v0.5.0

func WithEnvSessionInterceptor() connect.ClientOption

WithEnvSessionInterceptor returns a connect.ClientOption that installs the env-var session interceptor. Used by NewUnixSocketClient.

func WithServerSessionInterceptor added in v0.5.0

func WithServerSessionInterceptor() connect.HandlerOption

WithServerSessionInterceptor returns a connect.HandlerOption that installs the server-side session header → context interceptor.

Types

type Backend

type Backend interface {
	DaemonStatus(ctx context.Context) (DaemonStatus, error)
	DaemonShutdown(ctx context.Context, gracefulTimeoutSeconds int) error
	ListSessions(ctx context.Context) ([]SessionInfo, error)
	// ListSessionTokens returns the open sessions together with
	// their opaque tokens. It is only used by local CLI callers
	// to auto-bind GPGSMITH_SESSION when exactly one session is
	// open. The tokens are transported via the
	// Gpgsmith-Session-Tokens response header — we intentionally
	// keep them out of SessionInfo/proto so non-local callers
	// (e.g. the web UI shim) never see them by accident.
	ListSessionTokens(ctx context.Context) ([]SessionTokenEntry, error)

	ListVaults(ctx context.Context) (entries []vault.Entry, defaultName string, err error)
	StatusVaults(ctx context.Context) (open []SessionInfo, recoverable []ResumeOption, err error)
	OpenVault(ctx context.Context, name, passphrase string, source gpgsmith.LockSource) (result OpenResult, token string, err error)
	ResumeVault(ctx context.Context, name, passphrase string, source gpgsmith.LockSource, resume bool) (info SessionInfo, token string, err error)
	SealVault(ctx context.Context, token, message string) (vault.Snapshot, error)
	DiscardVault(ctx context.Context, token string) error
	Snapshots(ctx context.Context, name string) ([]vault.Snapshot, error)
	ImportVault(ctx context.Context, sourcePath, passphrase, targetName string) (vault.Snapshot, error)
	CreateVault(ctx context.Context, name, path, passphrase string) (snap vault.Snapshot, session SessionInfo, token string, err error)
	ExportVault(ctx context.Context, name, passphrase, targetDir string) (snapshotName string, err error)
	TrustVault(ctx context.Context, name, fingerprint string) error

	CreateMasterKey(ctx context.Context, token string, opts CreateKeyOpts) (masterFP string, subkeys []gpg.SubKey, err error)
	GenerateSubkeys(ctx context.Context, token string) ([]gpg.SubKey, error)
	ListKeys(ctx context.Context, token string) ([]gpg.SubKey, error)
	RevokeSubkey(ctx context.Context, token, keyID string) error
	ExportKey(ctx context.Context, token string) (target string, err error)
	SSHPubKey(ctx context.Context, token string) (path string, err error)
	KeyStatus(ctx context.Context, token string) (keys []gpg.SubKey, card *gpg.CardInfo, err error)

	ListIdentities(ctx context.Context, token string) ([]gpg.UID, error)
	AddIdentity(ctx context.Context, token, uid string) error
	RevokeIdentity(ctx context.Context, token, uid string) error
	PrimaryIdentity(ctx context.Context, token, uid string) error

	ProvisionCard(ctx context.Context, token string, opts ProvisionCardOpts) (card gpg.YubiKeyEntry, sshPubkeyPath string, err error)
	RotateCard(ctx context.Context, token, label string) (gpg.YubiKeyEntry, error)
	RevokeCard(ctx context.Context, token, label string) error
	CardInventory(ctx context.Context, token string) ([]gpg.YubiKeyEntry, error)
	DiscoverCard(ctx context.Context, token, label, description string) (card gpg.YubiKeyEntry, alreadyKnown bool, err error)

	ListPublishServers(ctx context.Context, token string) ([]gpg.ServerEntry, error)
	AddPublishServer(ctx context.Context, token, alias, url string) error
	RemovePublishServer(ctx context.Context, token, alias string) error
	EnablePublishServer(ctx context.Context, token, alias string) error
	DisablePublishServer(ctx context.Context, token, alias string) error
	Publish(ctx context.Context, token string, aliases []string) ([]PublishResult, error)
	LookupPublished(ctx context.Context, token string) ([]LookupResult, error)

	ShowAudit(ctx context.Context, token string, last int) ([]audit.Entry, error)

	// ===== EventService =====
	//
	// SubscribeEvents returns a channel of events. If token is
	// non-empty and matches an open session, only that vault's events
	// are forwarded; if token is empty, the subscriber receives events
	// for all vaults. The channel is closed when the passed context is
	// canceled. The Backend is responsible for fan-out.
	SubscribeEvents(ctx context.Context, token string) (<-chan Event, error)
}

Backend is the contract that the wire handlers call into. It exposes the gpgsmith kernel surface in a session-aware, daemon-style API: every session-bearing method takes an opaque session token to identify which open Session to operate on. The Backend implementation (typically *daemon.Daemon) is responsible for looking up the Session in its in-memory token-keyed map, returning a useful error if no session exists for the token, and routing the call to the appropriate kernel function.

Methods are grouped by the protobuf service they back, in the same order services appear in proto/gpgsmith/v1/.

All Backend methods are safe to call from multiple goroutines concurrently. Concurrency control of mutating operations on a single vault is the Backend's responsibility (typically a per-Session mutex).

type Client

Client is the typed gpgsmith ConnectRPC client. It bundles all eight generated service clients into one struct so callers (CLI commands, web UI shim, TUI) only have one thing to import and one connection lifetime to manage.

A Client is constructed via:

  • NewUnixSocketClient(socketPath) for talking to a daemon over Unix domain socket
  • NewHTTPClient(httpClient, baseURL) for talking to any Connect endpoint

The exposed sub-clients (Daemon, Vault, Key, ...) are the generated interfaces. Calls take typed proto messages; the Connect transport handles (de)serialization. Callers in pkg/cli/gpgsmith and pkg/webui/gpgsmith translate between proto types and CLI/HTML data on their side of the wire.

func NewHTTPClient

func NewHTTPClient(hc *http.Client, baseURL string, opts ...connect.ClientOption) *Client

NewHTTPClient builds a Client around an arbitrary http.Client and base URL. Used by tests (httptest.Server provides both) and could be used by other transports in the future.

func NewUnixSocketClient

func NewUnixSocketClient(socketPath string) *Client

NewUnixSocketClient builds a Client that talks to a Connect server over a Unix domain socket at the given path. This is the production configuration the CLI uses to talk to the daemon.

The HTTP base URL is "http://unix" — a synthetic placeholder; Connect uses the http.Client's transport for the actual dial, so the host portion is never resolved. The path portion of every Connect request is the gRPC method path generated by buf+protoc-gen-connect-go.

func (*Client) Close

func (c *Client) Close()

Close releases idle HTTP connections. Safe to call multiple times.

type CreateKeyOpts

type CreateKeyOpts struct {
	Name         string
	Email        string
	Algo         string
	Expiry       string
	SubkeyAlgo   string
	SubkeyExpiry string
}

CreateKeyOpts mirrors the kernel master-key generation parameters.

type DaemonStatus

type DaemonStatus struct {
	PID            int
	Version        string
	Commit         string
	SocketPath     string
	StartedAt      time.Time
	ActiveSessions int
}

DaemonStatus is the response shape for DaemonService.Status, in kernel-flavored Go form. The mapping layer translates this to/from the proto type.

type Event

type Event struct {
	At        time.Time
	VaultName string
	JobID     string
	Kind      EventKind
	Message   string
	Data      map[string]string
}

Event is one item in the daemon's pub/sub stream.

type EventKind

type EventKind int

EventKind enumerates the daemon's event types. Mirrors the proto EventKind enum.

const (
	EventKindUnspecified  EventKind = iota // zero value; proto field was unset
	EventKindJobStarted                    // a job (key gen, card op, ...) started
	EventKindJobProgress                   // job has progressed; check Message/Data
	EventKindJobPrompt                     // job needs user input ("touch your YubiKey")
	EventKindJobCompleted                  // job finished successfully
	EventKindJobFailed                     // job finished with an error
	EventKindStateChanged                  // a session's state changed (open/seal/discard)
	EventKindSessionEnded                  // a session was ended (any reason)
)

EventKind enumeration values. The order matches the proto EventKind enum so the mapping layer is a 1:1 switch.

type LookupResult

type LookupResult struct {
	URL    string
	Status string
}

LookupResult is the per-server outcome of a lookup operation.

type OpenResult

type OpenResult struct {
	Session         *SessionInfo
	ResumeAvailable *ResumeOption
}

OpenResult is the return value from Backend.OpenVault. Either Session is set (open succeeded with no resume question) or ResumeAvailable is set (caller must call ResumeVault to choose).

type ProvisionCardOpts

type ProvisionCardOpts struct {
	Label       string
	Description string
	SameKeys    bool
	UniqueKeys  bool
}

ProvisionCardOpts mirrors the card provisioning parameters.

type PublishResult

type PublishResult struct {
	Alias   string
	Success bool
	Error   string
}

PublishResult is the per-target outcome of a publish operation.

type ResumeOption

type ResumeOption struct {
	CanonicalBase string
	Hostname      string
	Source        gpgsmith.LockSource
	StartedAt     time.Time
	LastHeartbeat time.Time
	Status        string
	Divergent     bool
}

ResumeOption describes a recoverable .session-<host> ephemeral that the daemon discovered when listing a vault.

type Server

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

Server bundles the gpgsmith ConnectRPC service handlers into a single http.Handler ready to be served over a Unix socket (by the daemon) or a localhost TCP listener (by the web UI shim, if it ever wants to expose the same surface to the browser via Connect-Web).

Construct via NewServer(backend); call Handler() to get the http.Handler suitable for http.Server.

func NewServer

func NewServer(backend Backend) *Server

NewServer wires every gpgsmith Connect service handler into a single http.ServeMux. Each handler delegates to the supplied Backend.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the http.Handler that serves all gpgsmith Connect services. The daemon mounts this on its Unix socket; tests can mount it on an httptest.Server for round-trip integration tests.

type SessionInfo

type SessionInfo struct {
	VaultName      string
	VaultPath      string
	Source         gpgsmith.LockSource
	Hostname       string
	StartedAt      time.Time
	LastActiveAt   time.Time
	SourceSnapshot string
	MasterFP       string
	Generation     uint64
	Status         string
}

SessionInfo describes one currently-open session held by the daemon, in kernel-flavored Go form.

type SessionTokenEntry added in v0.5.0

type SessionTokenEntry struct {
	Token     string
	VaultName string
}

SessionTokenEntry pairs an opaque session token with its vault name. Used only by ListSessionTokens for local CLI auto-binding.

func DecodeSessionTokens added in v0.5.0

func DecodeSessionTokens(header string) []SessionTokenEntry

DecodeSessionTokens parses the Gpgsmith-Session-Tokens response header value back into (token, vaultName) pairs. Exported for the CLI's auto-bind path.

Jump to

Keyboard shortcuts

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