Documentation
¶
Overview ¶
approval_authorizer.go — the Protocol-side resolve authorizer.
Pre-111f the admin/console:fleet scope check lived INSIDE `internal/tools/approval` as a hard `internal/protocol/auth` import the one standing violation of the direction rule (runtime packages import protocol TYPES only, never protocol auth / methods / transports). The check moves here, one-way: the server package (the Runtime's network surface) adapts the Protocol's verified scope claims onto the approval package's injected `ResolveAuthorizer` seam. The approval package no longer knows the Protocol's auth vocabulary exists.
dev-only bootstrap endpoint.
BootstrapHandler is mounted at POST /v1/dev/bootstrap.json on harbor dev and harbor console only. It mints a fresh dev token and returns the full connection envelope so the Console Settings page can offer a one-click "Attach to local Runtime" button.
The endpoint is loopback-gated: only localhost peers receive a 200. Non-loopback peers get 403 regardless of headers. The gate reads r.RemoteAddr directly — no header-based spoofing vector exists.
The endpoint is never registered by harbor serve.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SearchAdminScopeFromAuth ¶ added in v1.3.0
SearchAdminScopeFromAuth is the production `search.ScopeChecker` — it consults the auth-attached scope set on ctx via `protocolauth.HasScope`.
The function is exported so the wiring (and tests that want the real shape) can inject it directly without re-implementing the closed-scope-set predicate.
pins the closed two-scope set `{admin, console:fleet}` — BOTH are cross-tenant fan-in entitlements. The §17.5 checkpoint (a checkpoint fix) corrected this predicate to honour `console:fleet` too: a Console fleet operator carrying only `console:fleet` is entitled to a cross-tenant search, exactly as it is entitled to a cross-tenant `events.subscribe`.
Types ¶
type BootstrapHandler ¶
type BootstrapHandler struct {
// contains filtered or unexported fields
}
BootstrapHandler serves POST /v1/dev/bootstrap.json.
func NewBootstrapHandler ¶
func NewBootstrapHandler( signer BootstrapSigner, id identity.Identity, scopes []string, baseURL string, logger *slog.Logger, ) *BootstrapHandler
NewBootstrapHandler returns a handler wired for the dev identity triple and scope set. baseURL is the absolute URL the bootstrapping Console should target (populated from the actual listener address).
func (*BootstrapHandler) ServeHTTP ¶
func (h *BootstrapHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
type BootstrapRequest ¶ added in v1.4.0
type BootstrapRequest struct {
// Tenant / User / Session override the minted token's identity
// triple. All three must be non-empty to take effect; a partial
// triple is rejected (identity is mandatory — CLAUDE.md §6). When
// all three are empty, the handler's default identity is used.
Tenant string `json:"tenant"`
User string `json:"user"`
Session string `json:"session"`
// Scopes overrides the minted token's verified scope set. A nil
// pointer (the field absent from the JSON) keeps the handler's
// default scopes; a non-nil pointer — INCLUDING an explicit empty
// array — replaces them, so `"scopes": []` mints a token with NO
// scopes (the non-admin case). Each entry SHOULD be a canonical
// auth.Scope string; unknown scopes are dropped from the verified
// set at validation time (auth.WithScopes), never elevated.
Scopes *[]string `json:"scopes"`
}
BootstrapRequest is the OPTIONAL request body the bootstrap endpoint accepts. An empty body (the common `-d '{}'` case) mints the handler's default admin dev token, preserving the one-click Console-attach flow. A body that names a full identity triple and/or a scope set mints a token for THAT principal instead — the dev-only path that makes a lesser-privileged (non-admin) token obtainable so the non-admin authorization contract is exercisable end-to-end (and the live negative-escalation smoke can run).
The override is gated by the same loopback boundary as the default mint: only a localhost peer ever reaches the signer, so a caller that can request a token for an arbitrary principal already controls the loopback dev surface. This is dev-only convenience — production (`harbor serve`) never mounts this endpoint.
type BootstrapResponse ¶
type BootstrapResponse struct {
BaseURL string `json:"base_url"`
Token string `json:"token"`
Identity bootstrapIdentity `json:"identity"`
Scopes []string `json:"scopes"`
ProtocolVersion string `json:"protocol_version"`
}
BootstrapResponse is the JSON envelope returned by the bootstrap endpoint. It carries every field the Console's attachConnection helper needs for a one-click attach.
type BootstrapSigner ¶
type BootstrapSigner interface {
SignDevToken(now time.Time, tenant, user, session string, scopes []string) (string, error)
}
BootstrapSigner is the minimal token-signing surface the bootstrap handler needs. The harbor dev cmd's devSigner satisfies it.
type ProtocolScopeAuthorizer ¶ added in v1.3.0
type ProtocolScopeAuthorizer struct {
// Next is the fallback authorizer consulted when ctx carries no
// qualifying Protocol scope. Nil = no fallback (strict).
Next approval.ResolveAuthorizer
}
ProtocolScopeAuthorizer is the wire-side approval.ResolveAuthorizer: a resolving ctx that carries the verified `admin` OR `console:fleet` Protocol scope claim (JWT validation → edge) is authorized — exactly the acceptance the pre-111f in-gate check enforced, so wire behaviour is unchanged. Everything else delegates to Next (production wires `approval.NewIdentityAuthorizer()`), which is how the in-process steering bridge resolves without the deleted protocol-scope self-elevation.
A nil Next is the strict wire-only posture: protocol scopes or nothing — fail closed with a wrapped approval.ErrResolveForbidden, byte-for-byte the pre-seam gate semantics.
Stateless; safe for concurrent use.
func NewProtocolScopeAuthorizer ¶ added in v1.3.0
func NewProtocolScopeAuthorizer(next approval.ResolveAuthorizer) ProtocolScopeAuthorizer
NewProtocolScopeAuthorizer constructs the wire-side authorizer with next as the non-Protocol fallback. Production gate assembly (`cmd/harbor`, `harbortest/devstack`) passes `approval.NewIdentityAuthorizer()` so both resolution paths work: Protocol-scoped callers keep today's admin/console:fleet acceptance; the runtime steering bridge resolves via the originating identity.
func (ProtocolScopeAuthorizer) AuthorizeResolve ¶ added in v1.3.0
func (a ProtocolScopeAuthorizer) AuthorizeResolve(ctx context.Context, pending approval.PendingInfo) error
AuthorizeResolve implements approval.ResolveAuthorizer.