consolecall

package
v1.76.9 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package consolecall is the plumbing for the console's provider operations once they live in the provider's module (docs/decisions/0071, v1.76 D-v176-1 b): the console authenticates a person, snapshots who they are, and asks the module to do the work as that snapshot.

A call is a proto-JSON envelope, `{caller:{actor,roles,workspaces}, msg}`, over modcall. The module trusts the snapshot because only the caller class `console` may reach a console method: Handle registers with `Allow("console")` and nothing else, and Violations says which methods of a server do not. The transport names the class, never the envelope, so a payload cannot claim to be the console.

A refusal the person should read is a Problem in the reply, not a transport error: transport errors carry a code and no detail, since the caller is another trust domain.

Index

Constants

View Source
const (
	ModuleGitHub = "github"
	ModuleSlack  = "slack"
	ModuleGoogle = "google"
)

The modules a console operation can reach.

View Source
const (
	SourcePerson   = "person"
	SourceWorkload = "workload"
	SourceRecovery = "recovery"
)

The values of Caller.Source.

View Source
const (
	MaxDirectories  = 256
	MaxSourceGroups = 4000
	MaxAddressFacts = 2000
)

The bounds of the facts of one call.

View Source
const Class = "console"

Class is the caller class of the console, the only one a console method answers.

View Source
const ListMaxBytes = 2 << 20

ListMaxBytes is the bound of a method that lists: above modcall.DefaultMaxBytes, well under modcall.HardMaxBytes.

View Source
const MethodPrefix = "console."

MethodPrefix starts the name of every console method, so a lint can tell them from the module's other methods.

Variables

View Source
var ErrFacts = errors.New("the directory facts are not valid")

ErrFacts is a facts field that is not well formed.

Functions

func Handle

func Handle[Req, Resp proto.Message](
	s *modcall.Server, method string, fn func(ctx context.Context, caller Caller, req Req) (Resp, error), opts ...modcall.Option,
)

Handle registers a console method on a module's server. It answers the caller class Class and no other, whatever opts say about who may call: an modcall.Allow among them is overridden. A *Problem the function returns is told to the console as the reply's Problem; any other error is the transport's, with no detail.

func HandleJSON

func HandleJSON[Req, Resp any](
	s *modcall.Server, method string, fn func(ctx context.Context, caller Caller, req Req) (Resp, error), opts ...modcall.Option,
)

HandleJSON registers a console method over Go values. It answers Class and no other, as Handle does.

func List

func List() modcall.Option

List is the option of a method that lists: its bound is ListMaxBytes.

func Proxy

func Proxy[Req, Resp proto.Message](ctx context.Context, c modcall.Caller, module, method string, caller Caller, req Req) (Resp, error)

Proxy calls one console method of a module as caller and returns its reply. A Problem the module told comes back as a *Problem error; any other failure is the transport's modcall.Error.

func ProxyJSON

func ProxyJSON[Req, Resp any](ctx context.Context, c modcall.Caller, module, method string, caller Caller, req Req) (Resp, error)

ProxyJSON calls a console method registered by HandleJSON.

func Violations

func Violations(s *modcall.Server) []string

Violations lists the methods of s that break the console rule: a method named like a console method that answers anyone but Class, and a method that answers Class together with another class. A console method must answer the console alone because it trusts the caller snapshot; another class could send any snapshot it liked.

func WithFacts

func WithFacts(ctx context.Context, f *DirectoryFacts) context.Context

WithFacts puts the facts a call carries in its context: the console's proxy sends them from it, and a module's handler reads them from it.

Types

type Caller

type Caller struct {
	// Actor is who to write down: the address, else the subject.
	Actor string `json:"actor"`
	// Roles are the installation-wide roles held (the role and the roles it
	// implies are not expanded: [access.Role.Implies] does that).
	Roles []string `json:"roles,omitempty"`
	// Workspaces are the roles held over one directory workspace each.
	Workspaces map[string]string `json:"workspaces,omitempty"`
	// Source says how the actor was established, so the trail names a workload
	// or a recovery as what it is: "person" for an address, "workload", or
	// "recovery"; empty for anyone else.
	Source string `json:"source,omitempty"`
	// Origin is the console's own address, where the provider sends the browser
	// back (the redirect of an install). The console asserts it like the rest
	// of the snapshot; a method that needs none ignores it.
	Origin string `json:"origin,omitempty"`
}

Caller is the snapshot of who the console authorized, taken once per request. The module acts on it and re-checks nothing against the person's session.

func Snapshot

func Snapshot(id access.Identity) Caller

Snapshot takes the caller of an authorized identity.

func (Caller) Identity

func (c Caller) Identity() access.Identity

Identity is the snapshot as an identity for the module's own authorization: the strongest installation-wide role in Roles, and Workspaces as scopes.

type Callers

type Callers struct {
	GitHub, Slack, Google modcall.Caller
}

Callers is how the console reaches each provider module: one modcall.Caller each, sending as the class Class.

func (Callers) OrLocal

func (c Callers) OrLocal(l modcall.Local) Callers

OrLocal fills each caller that is nil with the in-process servers, as the console. A deployment that has not split a module out calls it there.

type Directory

type Directory struct {
	ID      string   `json:"id"`
	Primary string   `json:"primary,omitempty"`
	Served  []string `json:"served,omitempty"`
	// Authoritative is the served domains the directory answers for with
	// confidence, sorted: what an owner is labelled with.
	Authoritative []string `json:"authoritative,omitempty"`
}

Directory is one connected directory as an owner is chosen and shown.

type DirectoryFacts

type DirectoryFacts struct {
	// Directories are every connected directory: for choosing and showing an
	// owner.
	Directories []Directory `json:"directories,omitempty"`
	// Sources are the directories' groups as a picker lists them, with
	// SourcesError saying why they could not be read.
	Sources      []SourceDirectory `json:"sources,omitempty"`
	SourcesError string            `json:"sources_error,omitempty"`
	// Groups and Users are, by lowercase address, what the call's own addresses
	// are: whether a source is a group of a connected directory, and whether a
	// listed person is an active user of one.
	Groups map[string]GroupFact `json:"groups,omitempty"`
	Users  map[string]UserFact  `json:"users,omitempty"`
}

DirectoryFacts are what a module may know of the connected directories for one call. A module reads no directory of its own (it holds no grant on the Google module's snapshot): the console, which already reads that snapshot, resolves what the method needs and sends it in the envelope. The module takes it as the console's word, like the caller snapshot, and refuses a field that is not well formed (DirectoryFacts.Validate).

Only what the methods ask is here, and each part is bounded.

func FactsFrom

func FactsFrom(ctx context.Context) *DirectoryFacts

FactsFrom is the facts a call carries, nil when it carries none.

func (*DirectoryFacts) IDs

func (f *DirectoryFacts) IDs() []string

IDs are the connected directories' ids, sorted.

func (*DirectoryFacts) Validate

func (f *DirectoryFacts) Validate() error

Validate refuses a field that is oversized, names a directory twice or none, or says an address belongs to a directory the field does not list. A forged field can still lie within these rules, as the caller snapshot can: only the console class can send it.

type Envelope

type Envelope struct {
	Caller Caller          `json:"caller"`
	Msg    json.RawMessage `json:"msg,omitempty"`
	// Directory is what the console resolved of the connected directories for
	// this call ([DirectoryFacts]); nil when the method needs none.
	Directory *DirectoryFacts `json:"directory,omitempty"`
}

Envelope is a request on the wire: the caller and one proto message as proto-JSON.

func Wrap

func Wrap(c Caller, msg proto.Message) (Envelope, error)

Wrap is the envelope of a request.

func (Envelope) Unwrap

func (e Envelope) Unwrap(msg proto.Message) error

Unwrap reads the message of an envelope into msg. Unknown fields are refused: a console and a module of the same release agree on the message.

type GroupFact

type GroupFact struct {
	Found     bool   `json:"found,omitempty"`
	Workspace string `json:"workspace,omitempty"`
	Err       string `json:"err,omitempty"`
}

GroupFact is whether an address is a group of a connected directory, and of which. Err is the hub's own words when the address is not one.

type Problem

type Problem struct {
	// Code is the Connect code the console answers with, by its name
	// ("failed_precondition"); empty is a failed precondition.
	Code string `json:"code,omitempty"`
	// Status is the HTTP status of the page the console renders for a provider
	// callback that cannot finish. Zero is 409.
	Status int `json:"status,omitempty"`
	// Summary is one line.
	Summary string `json:"summary"`
	// Detail is what went wrong, safe to show the signed-in person.
	Detail string `json:"detail,omitempty"`
	// Hints are what to try.
	Hints []string `json:"hints,omitempty"`
}

Problem is a refusal or a failure a person should read, told as data.

func (*Problem) Error

func (p *Problem) Error() string

Error implements error, so a handler can return a Problem.

type Reply

type Reply struct {
	Msg     json.RawMessage `json:"msg,omitempty"`
	Problem *Problem        `json:"problem,omitempty"`
}

Reply is the answer on the wire: a proto message, or a Problem.

type SourceDirectory

type SourceDirectory struct {
	Workspace string        `json:"workspace"`
	Domains   []string      `json:"domains,omitempty"`
	Groups    []SourceGroup `json:"groups,omitempty"`
}

SourceDirectory is a connected directory and its groups, as a picker lists them.

type SourceGroup

type SourceGroup struct {
	Email   string `json:"email"`
	Members int    `json:"members,omitempty"`
}

SourceGroup is one group of a directory.

type UserFact

type UserFact struct {
	InDomain      bool   `json:"in_domain,omitempty"`
	Authoritative bool   `json:"authoritative,omitempty"`
	Found         bool   `json:"found,omitempty"`
	Suspended     bool   `json:"suspended,omitempty"`
	Workspace     string `json:"workspace,omitempty"`
	Err           string `json:"err,omitempty"`
}

UserFact is whether an address is an account a connected directory holds. InDomain is whether the address is in a domain a connected directory serves (Workspace says which), and Authoritative whether the directory can vouch for the rest just now.

Jump to

Keyboard shortcuts

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