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
- func ContextWithSessionToken(ctx context.Context, token string) context.Context
- func TokenFromContext(ctx context.Context) (string, bool)
- func WithEnvSessionInterceptor() connect.ClientOption
- func WithServerSessionInterceptor() connect.HandlerOption
- type Backend
- type Client
- type CreateKeyOpts
- type DaemonStatus
- type Event
- type EventKind
- type LookupResult
- type OpenResult
- type ProvisionCardOpts
- type PublishResult
- type ResumeOption
- type Server
- type SessionInfo
- type SessionTokenEntry
Constants ¶
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
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
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 ¶
type Client struct {
Daemon gpgsmithv1connect.DaemonServiceClient
Vault gpgsmithv1connect.VaultServiceClient
Key gpgsmithv1connect.KeyServiceClient
Identity gpgsmithv1connect.IdentityServiceClient
Card gpgsmithv1connect.CardServiceClient
Server gpgsmithv1connect.ServerServiceClient
Audit gpgsmithv1connect.AuditServiceClient
Event gpgsmithv1connect.EventServiceClient
// contains filtered or unexported fields
}
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 ¶
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 ¶
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.
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 ¶
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 ¶
ProvisionCardOpts mirrors the card provisioning parameters.
type PublishResult ¶
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.
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
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.