Documentation
¶
Overview ¶
Package cockpit is the loopback daemon's Cockpit surface: the request guard every Cockpit route sits behind, the API mux, and the mounts that attach both to the dashboard listener (spec/features/cockpit).
Index ¶
- Constants
- func CanonicalHost(listenAddress string) string
- func Guard(canonical string, next http.Handler) http.Handler
- type Capability
- type LoginCode
- type MetadataHandler
- type Options
- type OwnerHandler
- type Principal
- type Server
- func (server *Server) HandleMetadata(name string, capability Capability, handler MetadataHandler)
- func (server *Server) HandleOwner(method, path string, capability Capability, handler OwnerHandler)
- func (server *Server) LoginCodeHandler() http.Handler
- func (server *Server) MintLoginCode() (LoginCode, error)
- func (server *Server) Mounts() map[string]http.Handler
- func (server *Server) MountsWith(others map[string]http.Handler) map[string]http.Handler
- type SessionStore
Constants ¶
const ( PagePrefix = web.MountPath APIPrefix = "/api/v1/cockpit/" )
PagePrefix and APIPrefix are the two subtrees Cockpit owns on the loopback listener (cockpit#req:cockpit-mount).
const ( PrincipalAnonymousLocal = "anonymous-local" PrincipalOwner = "owner" )
The two principals a request resolves to.
const ( LoginPath = PagePrefix + "session/login" LogoutPath = PagePrefix + "session/logout" )
LoginPath and LogoutPath are the two session routes under PagePrefix (cockpit#req:owner-session). The login code travels in LoginPath's "code" query parameter.
const LoginCodeRPCPath = "/wb.cockpit.v1/login-code"
LoginCodeRPCPath is the owner-channel route that mints a login code. The daemon registers it on the mux its unix socket serves, behind the owner token, and never on the loopback listener. The daemon's file bridge dispatches into that same mux but forwards only the DaemonService procedures it lists, so it refuses this path.
Variables ¶
This section is empty.
Functions ¶
func CanonicalHost ¶
CanonicalHost picks the one loopback name Cockpit's session cookie is scoped to from the daemon's listen address: "::1" when the listener is the IPv6 loopback address, otherwise "127.0.0.1" (including a listener named "localhost", or an address that does not parse).
func Guard ¶
Guard refuses a request whose Host header does not name a loopback host with status 421, before next runs: that is what stops a page that rebinds DNS to the loopback address. The port is not checked beyond being a number, so an SSH forward to another local port works.
canonical is the loopback name the daemon's listener has (see CanonicalHost). A GET or HEAD for a page on any other loopback name is redirected to the same path on http://<canonical>:<port>, using the port the browser reached; any other method there is refused with 421 so it is never replayed to another origin. An API request on an alias is served.
Types ¶
type Capability ¶
type Capability string
Capability is one permission a Cockpit route or action requires (cockpit#req:capability-vocabulary).
const ( CapabilityFleetRead Capability = "fleet.read" CapabilityMachineRead Capability = "machine.read" CapabilityRepoRead Capability = "repo.read" CapabilityWorktreeRead Capability = "worktree.read" CapabilityBranchRead Capability = "branch.read" CapabilityPRRead Capability = "pr.read" CapabilityAgentRead Capability = "agent.read" CapabilityRepoContentRead Capability = "repo.content.read" )
The capability vocabulary. A Feature that defines an action adds the action's capability.
type LoginCode ¶
LoginCode is a freshly minted login code and the moment it stops being exchangeable.
type MetadataHandler ¶
type MetadataHandler func(http.ResponseWriter, *http.Request, Principal)
MetadataHandler serves one metadata route for a resolved principal.
type Options ¶
type Options struct {
// CanonicalHost is the loopback name the listener has (see CanonicalHost).
CanonicalHost string
// Config is wb.yaml's cockpit: section, after defaults.
Config wbconfig.CockpitConfig
// Now is the clock login codes and sessions expire against; nil means
// time.Now.
Now func() time.Time
// Random is the source of login codes and session identifiers; nil means
// crypto/rand.
Random io.Reader
// Sessions holds the owner sessions; nil means a fresh in-memory store.
Sessions SessionStore
}
Options is what the daemon hands Cockpit at startup.
type OwnerHandler ¶
type OwnerHandler func(http.ResponseWriter, *http.Request)
OwnerHandler serves one owner route for a request with an owner session.
type Principal ¶
type Principal struct {
Name string `json:"principal"`
Capabilities []Capability `json:"capabilities"`
}
Principal is who a request acts as and what it may do.
func (Principal) Has ¶
func (principal Principal) Has(capability Capability) bool
Has reports whether the principal holds capability.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is Cockpit's state for one daemon run: its login codes, its owner sessions and its routes.
func (*Server) HandleMetadata ¶
func (server *Server) HandleMetadata(name string, capability Capability, handler MetadataHandler)
HandleMetadata registers the metadata GET route APIPrefix+name, which requires capability. A metadata route is the only kind the hosted origin may read (cockpit#req:cross-origin-allowance), so its handler must return nothing beyond the metadata field set, and registering one with a capability that is not a metadata capability panics. Routes are registered before Mounts is called.
func (*Server) HandleOwner ¶
func (server *Server) HandleOwner(method, path string, capability Capability, handler OwnerHandler)
HandleOwner registers an owner route — one that returns content or changes state — at path, under PagePrefix or APIPrefix, for one method. It requires an owner session holding capability; an empty capability requires the session alone. A route whose method is not GET changes state, and also requires the canonical origin and a JSON content type (cockpit#req:owner-routes). No owner route ever receives the cross-origin allowance. Routes are registered before Mounts is called.
func (*Server) LoginCodeHandler ¶
LoginCodeHandler serves LoginCodeRPCPath. The caller mounts it behind the owner token; it does no authentication of its own.
func (*Server) MintLoginCode ¶
MintLoginCode issues a single-use login code. Only the owner channel may reach it.
type SessionStore ¶
type SessionStore interface {
// Create starts a session at now and returns its identifier.
Create(now time.Time) (string, error)
// Valid reports whether id names a session that has not ended or expired
// at now.
Valid(id string, now time.Time) bool
// End ends the session id names, if any.
End(id string)
}
SessionStore holds owner sessions. The daemon's store is in memory, so every session ends when the daemon restarts; the interface is the seam a test replaces. An identifier is a secret: an implementation never logs it.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fleet is Cockpit's fleet read model: one versioned document of this machine's repositories, worktrees, branches, pull requests and agents, and of every other machine's published snapshot, kept current by a background snapshotter and served without a request ever running Git (cockpit#req:fleet-read-model, cockpit#req:no-fleet-scan-on-the-request-path).
|
Package fleet is Cockpit's fleet read model: one versioned document of this machine's repositories, worktrees, branches, pull requests and agents, and of every other machine's published snapshot, kept current by a background snapshotter and served without a request ever running Git (cockpit#req:fleet-read-model, cockpit#req:no-fleet-scan-on-the-request-path). |