Documentation
¶
Index ¶
- func IsAtMost(candidate, ceiling Mode) bool
- func IsGroupBlockingMode(m Mode) bool
- func Rank(m Mode) int
- func ValidateForTransport(p *Policy, transport string) error
- type Mode
- type Policy
- func (p *Policy) BlockReason(name string, readOnly bool) string
- func (p *Policy) Clone() *Policy
- func (p *Policy) Describe() map[string]any
- func (p *Policy) IsAllowed(name string, readOnly bool) bool
- func (p *Policy) IsGroupAllowed(group string) bool
- func (p *Policy) SetTier1Tools(names map[string]bool)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsAtMost ¶ added in v1.2.2
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
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
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
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
func EffectiveCeiling ¶ added in v1.2.2
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
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 (*Policy) BlockReason ¶
BlockReason returns a human-readable explanation for why a tool is blocked.
func (*Policy) Describe ¶
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) IsGroupAllowed ¶
IsGroupAllowed reports whether tools in the given group are permitted.
func (*Policy) SetTier1Tools ¶
SetTier1Tools stores the set of Tier-1 tool names for later reference.