policy

package
v1.2.5 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsAtMost added in v1.2.2

func IsAtMost(candidate, ceiling Mode) bool

IsAtMost reports whether candidate is at most as broad as ceiling. An empty ceiling means "no explicit constraint" (the helper still rejects unknown candidates). EffectiveTenantMode layers the implicit "process mode as ceiling" semantics on top.

func IsGroupBlockingMode added in v1.2.2

func IsGroupBlockingMode(m Mode) bool

IsGroupBlockingMode reports whether the given mode nullifies AllowedGroups (i.e. IsGroupAllowed returns false before consulting the allowlist). tenantRuntime uses this to decide whether to honour or silently drop tenant AllowGroups. Unknown / empty modes fail closed and are treated as blocking.

func Rank added in v1.2.2

func Rank(m Mode) int

Rank reflects posture breadth, not current IsAllowed equivalence. The ceiling contract surface (see ADR 0021) lives on this total ordering; standard and full are deliberately split so future divergence between them cannot silently widen deployments whose ceiling is pinned at standard.

read_only         = 0  (narrowest)
time_tracking_safe = 1
safe_core         = 2
standard          = 3
full              = 4  (broadest)

Unknown modes return -1 so every comparison against a real ceiling rejects them (fail closed).

func ValidateForTransport added in v1.2.2

func ValidateForTransport(p *Policy, transport string) error

ValidateForTransport returns an error when the policy's process mode exceeds the explicit ceiling under a transport that consumes control-plane tenant records (currently only streamable_http).

The MCP_TENANT_POLICY_CEILING env var is documented as streamable-HTTP only (internal/config/spec.go AppliesTo). Transports that do not consume control-plane TenantRecord overrides — stdio, legacy http, grpc — would treat the ceiling as a no-op at runtime, so failing startup for "policy > ceiling" on those transports would reject a configuration that has no actual effect. ValidateForTransport scopes the cross-check to where it is load-bearing.

EffectiveTenantMode / tenantpolicy.Derive keep their independent defense-in-depth checks for actual per-session derivation. See ADR 0021.

Types

type Mode

type Mode string
const (
	ReadOnly         Mode = "read_only"
	TimeTrackingSafe Mode = "time_tracking_safe"
	SafeCore         Mode = "safe_core"
	Standard         Mode = "standard"
	Full             Mode = "full"
)

func EffectiveCeiling added in v1.2.2

func EffectiveCeiling(mode, ceiling Mode) Mode

EffectiveCeiling returns the actual per-tenant ceiling the runtime enforces, which is the narrower of the process mode and the configured ceiling (when both are known). EffectiveTenantMode caps tenant overrides at this value, so it is what operators should see in clockify_policy_info's effective_ceiling field.

Behaviour:

  • Unknown mode → "" (defensive; signals "no usable cap").
  • Empty ceiling → mode (implicit ceiling = process mode).
  • Unknown ceiling → "" (defensive).
  • Otherwise → min(mode, ceiling) by Rank.

PR #99 review final diagnostic fix: previously Describe reported the configured ceiling verbatim, which hid the case CLOCKIFY_POLICY=time_tracking_safe + MCP_TENANT_POLICY_CEILING= standard (live cap = time_tracking_safe, not standard).

func EffectiveTenantMode added in v1.2.2

func EffectiveTenantMode(processMode, tenantMode, ceiling Mode) (Mode, error)

EffectiveTenantMode returns the effective per-tenant policy mode given the process mode, the tenant's requested mode (may be empty to inherit), and an optional explicit ceiling from MCP_TENANT_POLICY_CEILING.

Invariants (see ADR 0021):

  • processMode must be a known mode (read_only / time_tracking_safe / safe_core / standard / full). Unknown processMode fails closed.
  • When ceiling is set, ceiling must be a known mode AND processMode must satisfy processMode <= ceiling. A processMode broader than the explicit ceiling is a configuration error and fails closed before the tenant override is considered. This catches the hosted-profile misconfiguration where an operator overrode CLOCKIFY_POLICY=standard while the profile pinned MCP_TENANT_POLICY_CEILING=time_tracking_safe.
  • Empty tenantMode inherits processMode (subject to the processMode<=ceiling invariant above).
  • Unknown tenantMode fails closed.
  • After the processMode<=ceiling invariant, the effective ceiling for the tenant override is processMode itself (it is the tighter of the two). tenantMode > processMode fails closed with an explicit error rather than silent clamp.

type Policy

type Policy struct {
	Mode Mode
	// Ceiling is the maximum mode a control-plane tenant record may
	// select via TenantRecord.PolicyMode. Empty = implicit ceiling
	// (= process Mode itself; see EffectiveTenantMode). See ADR 0021.
	Ceiling        Mode
	DeniedTools    map[string]bool
	DeniedGroups   map[string]bool
	AllowedGroups  map[string]bool // nil = not set (all allowed per mode)
	Tier1ToolNames map[string]bool // populated after registry construction
	// TenantAllowGroupsIgnored is set on per-tenant clones when the
	// tenant carried AllowGroups under a group-blocking effective mode
	// (read_only / time_tracking_safe / safe_core) and the list was
	// silently dropped. Surfaced via Describe() for clockify_policy_info.
	TenantAllowGroupsIgnored bool
}

func FromEnv

func FromEnv() (*Policy, error)

func (*Policy) BlockReason

func (p *Policy) BlockReason(name string, readOnly bool) string

BlockReason returns a human-readable explanation for why a tool is blocked.

func (*Policy) Clone

func (p *Policy) Clone() *Policy

func (*Policy) Describe

func (p *Policy) Describe() map[string]any

Describe returns a map describing the current policy configuration.

Ceiling fields (ADR 0021):

  • configured_ceiling: literal MCP_TENANT_POLICY_CEILING value, or "" if unset.
  • effective_ceiling: the actual per-tenant cap the runtime enforces — `min(processMode, configured_ceiling)` per EffectiveCeiling. When configured_ceiling is empty, the process mode acts as the implicit ceiling so this equals the process mode. When configured_ceiling is broader than the process mode (a legitimate "I want headroom in this profile but the process is narrower today" shape), the process mode is what gets reported because EffectiveTenantMode caps tenants at min(processMode, ceiling) — see PR #99 review final diagnostic fix.
  • ceiling_source: "explicit" when configured_ceiling is set; "implicit_process_mode" when the process mode is acting as the ceiling.

The deprecated single "ceiling" key is removed — it conflated configured-vs-effective and silently hid the implicit-ceiling case (PR #99 review).

func (*Policy) IsAllowed

func (p *Policy) IsAllowed(name string, readOnly bool) bool

func (*Policy) IsGroupAllowed

func (p *Policy) IsGroupAllowed(group string) bool

IsGroupAllowed reports whether tools in the given group are permitted.

func (*Policy) SetTier1Tools

func (p *Policy) SetTier1Tools(names map[string]bool)

SetTier1Tools stores the set of Tier-1 tool names for later reference.

Jump to

Keyboard shortcuts

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