Help us shape the future of Go! Take the 2026 Go Developer Survey

policy

package
v0.17.2 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package policy evaluates host policy.

Policy is a floor, not an override (R-272), and is evaluated before grants — a policy that disables exec install-wide denies the owner too. It is a single versioned document rather than scattered columns, so applying policy to a running install is one transaction and one audit event (R-274).

Index

Constants

View Source
const (
	LoosenAllowlistAdd   = "allowlist_add"
	LoosenDenylistRemove = "denylist_remove"
	LoosenBlockPrivate   = "block_private_off"
)

Loosening kinds: the three ways an app can loosen the install's rules (R-182). Nothing else an app can write loosens.

View Source
const (
	InsecureWarn = "warn"
	InsecureStop = "stop"
)

What InsecureAction may say.

View Source
const AllowUploads = "upload"

AllowUploads is the allowlist entry that admits uploaded source.

An upload has no host and no path, so no host entry can name it. Without an entry of its own, a non-empty allowlist either lets every upload through — which makes "only github.com/acme" mean nothing to anyone with a CLI token — or refuses them all with no way to say otherwise.

View Source
const DefaultDeployApprovalExpiryHours = 7 * 24

DefaultDeployApprovalExpiryHours is how long a deploy request waits for approval when policy does not say (R-156): a week, so a request made on a Friday survives the weekend.

View Source
const DefaultInsecureGraceHours = 24

DefaultInsecureGraceHours is the grace an install gets when it turns stopping on without saying how long. A day: long enough for somebody to see the warning in a working week's morning, short enough to mean something.

Variables

This section is empty.

Functions

func CheckValue

func CheckValue(key string, value json.RawMessage) (json.RawMessage, error)

CheckValue reads value as the field key, as a startup setting is read, and returns it normalized. An error says why it does not read.

func Describe

func Describe(key string) string

Describe says what a policy field does, in the Policy screen's words.

func FieldType

func FieldType(key string) (string, bool)

FieldType is a policy field's type in words — "list", "true or false", "whole number" or "string" — and whether the field exists.

func Fields

func Fields() []string

Fields is every policy field's name, sorted.

func SameValue

func SameValue(key string, a, b json.RawMessage) bool

SameValue reports whether two encodings of the field key hold the same setting, treating absent as the zero value: a document that omits require_backup_before_destroy and one that sets it false say the same thing. An unknown key compares as the raw JSON.

func ValidateIdleDays

func ValidateIdleDays(stopName, deleteName string, stop, del int) error

ValidateIdleDays refuses idle days below zero, and a delete that would come no later than the stop, since both count from the same last activity (R-393). Shared with an app's own settings; the names are the ones the caller's reader typed (R-105).

Types

type Document

type Document struct {
	// SourceAllowlist restricts where apps may be created from (R-092). Empty
	// means no restriction — Pando ships permissive defaults (R-270).
	SourceAllowlist []string `json:"source_allowlist,omitempty"`

	// DisabledVerbs are denied install-wide, to everyone, including an app's
	// owner. R-085's "host policy may disable exec install-wide" is this list
	// containing app.exec.
	DisabledVerbs []string `json:"disabled_verbs,omitempty"`

	// AgentDisabledVerbs are denied to token principals only — the CLI token an
	// agent holds, and the MCP server acting through one (R-262).
	//
	// This is O-12's resolution. The tempting alternative is a list of tools
	// the MCP server refuses to expose, and it does not work: an agent holding
	// a token can call the REST API directly, so an MCP-layer exclusion is a
	// speed bump rather than a boundary. Expressed here, it is evaluated before
	// grants for every surface, which is the only place it means anything.
	//
	// Default-closed: Default() ships the exclusions design 04 §3 lists, and an
	// install can lift them by editing policy like any other rule.
	AgentDisabledVerbs []string `json:"agent_disabled_verbs,omitempty"`

	// AllowAnonymousGrants controls whether an app may be shared with everyone
	// (R-076). Pointer so that "unset" is distinguishable from "explicitly
	// false", which matters when a policy document is partially written.
	//
	// Superseded by PublicSharing, which says more; still read, so a policy
	// file or environment that sets it keeps meaning what it meant — false is
	// PublicSharingNone. PublicSharing wins when both are set.
	AllowAnonymousGrants *bool `json:"allow_anonymous_grants,omitempty"`

	// PublicSharing is how an app may be shared with everyone (R-076, R-075a):
	// at all, only behind a passcode, or not at all.
	PublicSharing PublicSharing `json:"public_sharing,omitempty"`

	// MinBuildIsolation and MinRuntimeIsolation are floors (R-024, R-114).
	// Separate because how isolated a build must be is a different question
	// from how isolated the running app must be.
	MinBuildIsolation   spec.IsolationClass `json:"min_build_isolation,omitempty"`
	MinRuntimeIsolation spec.IsolationClass `json:"min_runtime_isolation,omitempty"`

	// Egress (R-181 – R-185). The install's rules are a floor (R-183): an
	// app's own list narrows them, and only the loosening moves EgressFor
	// names — adding to an allowlist, removing from a denylist, turning
	// private-range blocking off — are subject to EgressLoosening.
	//
	// EgressMode is allow_all (empty), denylist or allowlist, and EgressList
	// is the list it reads. EgressBlockPrivate works with any mode.
	EgressMode         spec.EgressMode `json:"egress_mode,omitempty"`
	EgressList         []string        `json:"egress_list,omitempty"`
	EgressBlockPrivate bool            `json:"egress_block_private,omitempty"`

	// EgressLoosening is whether an app may loosen the rules above: by
	// somebody holding app.egress.loosen (empty, the default, R-270), only
	// after a deploy approval (R-154), or never.
	EgressLoosening EgressLoosening `json:"egress_loosening,omitempty"`

	// EgressAllowlist is the field before issue #79, when there was no mode
	// and an app's list replaced this one. Still read — a non-empty one with
	// no EgressMode is an allowlist — so a policy file that sets it keeps
	// meaning what its author wrote. Never enforced before, so an install that
	// set it starts being held to it; that is what the setting said.
	EgressAllowlist []string `json:"egress_allowlist,omitempty"`

	// Deploy approval (R-154 – R-159). Off unless something here, or the app's
	// own spec, turns it on.
	//
	// DeployApprovalRequired: every app's deploys need approval.
	// DeployApprovalApps: these apps' deploys do, whatever their owners say.
	// DeployApprovalCount: how many approvals a deploy needs; zero is one.
	// DeployApprovalExpiryHours: how long a request waits; zero is forever.
	// Default() ships seven days.
	DeployApprovalRequired    bool     `json:"deploy_approval_required,omitempty"`
	DeployApprovalApps        []string `json:"deploy_approval_apps,omitempty"`
	DeployApprovalCount       int      `json:"deploy_approval_count,omitempty"`
	DeployApprovalExpiryHours int      `json:"deploy_approval_expiry_hours,omitempty"`

	// RequireBackupBeforeDestroy: an admin sets "never destroy without backup"
	// once, and app owners cannot override downward (R-284).
	RequireBackupBeforeDestroy bool `json:"require_backup_before_destroy,omitempty"`

	// MaxTokenLifetimeDays caps how long a token may live; 0 means no cap.
	// R-061 allows policy to forbid non-expiring tokens.
	MaxTokenLifetimeDays int `json:"max_token_lifetime_days,omitempty"`

	// MaxLogDiskBytes is R-224: the total this install will commit to app logs
	// across every app. Zero means no aggregate limit.
	//
	// Enforced at plan time against the **sum of every app's cap**, not against
	// measured usage — which is O-16's resolution. Bounding what is committed
	// is the stronger guarantee: if every app's logs are capped and the caps
	// sum under the budget, the total cannot exceed it. Measuring usage would
	// mean acting after the disk was already filling, and the only remedy then
	// is recreating containers, which the reconciler may not do on a schedule
	// because an unrelated app turned chatty.
	MaxLogDiskBytes int64 `json:"max_log_disk_bytes,omitempty"`

	// MaxConcurrentDeploys is how many deploys each replica runs at once from
	// the deploy queue (issue #93). Zero means one per CPU, and at least two
	// (deploy.DefaultConcurrency). Per replica, because a build's cost lands
	// on the machine that runs it. Read every time the queue looks for work,
	// so a change applies without a restart; a deploy past the limit waits,
	// and says how many are ahead of it.
	MaxConcurrentDeploys int `json:"max_concurrent_deploys,omitempty"`

	// IdleStopDays and IdleDeleteDays stop, and later delete, an app nobody
	// has used for that many days, both counted from its last activity
	// (R-393 – R-398, issue #131). Zero is off, the default. An app may set
	// its own or turn either off (R-397), so these are defaults, not floors.
	IdleStopDays   int `json:"idle_stop_days,omitempty"`
	IdleDeleteDays int `json:"idle_delete_days,omitempty"`

	// StopOrphanedApps stops an app the moment none of its owners is active
	// (R-408). On unless set false: nil is on, so an install whose stored
	// policy predates the setting has it. Administrators are told either way
	// (R-409).
	StopOrphanedApps *bool `json:"stop_orphaned_apps,omitempty"`

	// Standby keeps a stopped copy of each app on another host, started when
	// its host is lost (R-419). On unless set false: nil is on [P]. An app's
	// spec may turn it on or off for itself (availability.standby). Only a
	// runtime with somewhere else to keep one has any (SupportsStandby).
	Standby *bool `json:"standby,omitempty"`

	// MaxAppsPerUser is how many apps a person may own unless their account or
	// a group of theirs says otherwise (R-244). Zero is unlimited.
	MaxAppsPerUser int `json:"max_apps_per_user,omitempty"`

	// AllowCPUOversubscription and AllowMemoryOversubscription let the apps
	// on a runtime together ask for more CPU, or more memory, than the runtime
	// reports having (R-242 as amended for issue #72). Both off by default: a
	// deploy that would oversubscribe is refused at plan time.
	//
	// Separate, because they fail differently. Too little CPU makes every app
	// slower; too little memory makes the kernel kill one. An install packing
	// many mostly-idle apps onto one host usually wants the first and not the
	// second.
	//
	// There is no disk counterpart and there will not be one: disk is not a
	// reservation the kernel shares out, and a full disk stops every app and
	// Pando with them.
	AllowCPUOversubscription    bool `json:"allow_cpu_oversubscription,omitempty"`
	AllowMemoryOversubscription bool `json:"allow_memory_oversubscription,omitempty"`

	// AllowFailoverOversubscription lets an app's standby be placed past the
	// CPU and memory the other hosts keep free for its host's loss (R-422).
	// Off by default: a standby goes only where, if its app's host were lost,
	// it would start, and an app with nowhere like that runs without one.
	// On, a host that takes over starts what fits, by each app's
	// availability.priority. Disk is still never oversubscribed (R-242): a
	// standby's copies are on its host's disk all the time.
	AllowFailoverOversubscription bool `json:"allow_failover_oversubscription,omitempty"`

	// Audit retention (R-347, R-348). The live audit log keeps
	// AuditRetentionMonths whole months; an older month is archived, the
	// archive read back and checked, and only then is the month removed.
	//
	// Zero is three months. Fewer than three is refused here, and the
	// database refuses it again: the floor is held by the function that
	// removes a month, so nothing the running server can write lowers it.
	// More is anyone's choice.
	//
	// AuditArchive is where an archive goes: keep (empty, the default) under
	// Pando's own directory, export to a backup destination — the default
	// one, or AuditArchiveDestination — or off, which archives nothing and so
	// removes nothing, the log growing as it did before retention existed.
	AuditRetentionMonths    int               `json:"audit_retention_months,omitempty"`
	AuditArchive            audit.ArchiveMode `json:"audit_archive,omitempty"`
	AuditArchiveDestination string            `json:"audit_archive_destination,omitempty"`

	// DisableAIScreening forbids AI screening of deployment plans install-wide
	// (R-336). Default false, like everything else here: Pando ships permissive
	// and configuration narrows (R-270).
	//
	// Worth an explicit setting rather than leaving it to whether an adapter is
	// configured, because the two are different decisions made by different
	// people. Screening sends repository contents to a provider (R-337), and an
	// administrator who has to say no to that should not have to do it by
	// deleting somebody else's adapter.
	DisableAIScreening bool `json:"disable_ai_screening,omitempty"`

	// DisableAnonymousUseAudit stops recording app.use for visitors who are
	// not signed in (R-227). Default false: anonymous use of a public app is
	// recorded like anyone's, once per browser session, because "who used this
	// app" after a leak includes the people nobody knew by name. An install
	// with a busy public site that does not want those rows turns it off.
	DisableAnonymousUseAudit bool `json:"disable_anonymous_use_audit,omitempty"`

	// DisableAnonymousDenialAudit stops recording authz.denied when somebody
	// not signed in reaches an app that is not shared with them (design 06
	// §6). Default false: every denial is audited, these included. Anyone can
	// cause one write per request without an account — a crawler walking a
	// private app's links does — so an install that does not want those rows
	// turns it off. A signed-in person or a token refused is always recorded.
	DisableAnonymousDenialAudit bool `json:"disable_anonymous_denial_audit,omitempty"`

	// The security score (R-314 – R-316, design 09 §5).
	//
	// MinSecurityScore is the floor a deploy has to clear, 0 to 100. Zero is
	// off, which is the shipped posture (R-270) — and so is an installation
	// with no scanner configured, where this is inert and the console says so
	// rather than silently blocking every deploy (R-317).
	MinSecurityScore int `json:"min_security_score,omitempty"`

	// InsecureAction is what happens to an app that is *already running* when
	// it falls below the floor: "warn" or "stop". Empty means warn.
	//
	// A policy change or a newly published CVE is not a reason to take
	// somebody's working service away without notice, so stopping is opt-in
	// and grace comes with it (R-315).
	InsecureAction string `json:"insecure_action,omitempty"`

	// InsecureGraceHours is how long an app has after it is first found below
	// the floor, before "stop" applies. Zero with InsecureAction "stop" means
	// the default below, not "immediately" — an accidental zero must not empty
	// a host.
	InsecureGraceHours int `json:"insecure_grace_hours,omitempty"`

	// IgnoreUnfixableFindings drops findings with no fix available from both
	// the score and the list.
	//
	// Off by default, so the number means "what is wrong with this app" rather
	// than "what could this app's owner do about it today" — and an upgrade
	// does not silently move every score. An installation that has decided it
	// only acts on what it can fix turns it on, and the two agree again: what
	// is counted is what is shown.
	IgnoreUnfixableFindings bool `json:"ignore_unfixable_findings,omitempty"`

	// DisablePasswordSignIn refuses sign-in with a local username and
	// password (issue #51), once people sign in through an external identity
	// provider. Refused while no external provider is on, so it cannot empty
	// the sign-in page. `pando admin enable-password-sign-in` is the way back
	// when every provider is unreachable, and needs shell access on the host.
	DisablePasswordSignIn bool `json:"disable_password_sign_in,omitempty"`

	// DisableJITProvisioning refuses making an account at a first external
	// sign-in, whatever each provider is set to. People then need an account
	// first — pushed by SCIM, or linked by an administrator.
	DisableJITProvisioning bool `json:"disable_jit_provisioning,omitempty"`

	// RequireLocalTwoFactor requires two-factor authentication on every local
	// account (R-405). An account without it can sign in with its password
	// and do nothing but set it up; one with it cannot turn it off. Accounts
	// from an identity provider are not affected: their provider decides.
	// `pando admin reset-two-factor` is the way back for someone who has lost
	// their authenticator and their recovery codes.
	RequireLocalTwoFactor bool `json:"require_local_two_factor,omitempty"`

	// DisableUpdateCheck stops Pando asking GitHub whether a newer release
	// exists (R-349). Default false — on — so an install learns about a
	// security release without anyone remembering to look; off sends no
	// request at all, for an air-gapped install or one that may not call out.
	DisableUpdateCheck bool `json:"disable_update_check,omitempty"`

	// AllowPrivateWebhooks lets an event subscription's webhook reach a
	// private, loopback or link-local address (R-372). Default false: anybody
	// who can see an app can subscribe to it, and a webhook that may point
	// anywhere is a way to make Pando send requests into its own network — to
	// a cloud metadata address, or to the database it runs on.
	AllowPrivateWebhooks bool `json:"allow_private_webhooks,omitempty"`

	// UpdateChannel is which releases the check offers (R-350): stable, the
	// default, or prerelease, which also offers release candidates.
	UpdateChannel UpdateChannel `json:"update_channel,omitempty"`

	// UpgradeInPlace lets Pando replace its own container with a newer
	// release (R-355). Off by default, against R-270 on purpose: a version
	// named in a Compose file or infrastructure-as-code is put back by its
	// next apply, so whoever owns that configuration turns this on — usually
	// there, as PANDO_POLICY_UPGRADE_IN_PLACE, which also locks it here.
	UpgradeInPlace bool `json:"upgrade_in_place,omitempty"`

	// AutoUpgradePatches upgrades to a new patch release of the running minor
	// line inside MaintenanceWindow, with nobody present (R-361). Needs
	// UpgradeInPlace and a window.
	AutoUpgradePatches bool `json:"auto_upgrade_patches,omitempty"`

	// MaintenanceWindow is when an automatic upgrade may start, in UTC:
	// weekdays, a start time and a length, as "sun,wed 02:00 2h" (R-361).
	// One string so that it reads the same in the config file, an
	// environment variable and the API.
	MaintenanceWindow string `json:"maintenance_window,omitempty"`
}

Document is the host policy (design 02 §2.5).

A single versioned document rather than scattered columns, so applying policy to a running install is one transaction and one audit event (R-274).

Policy is a floor, not an override (R-272): it can only deny. Nothing here grants anything, which is why it is evaluated before grants rather than mixed with them.

func Default

func Default() Document

Default is the permissive starting posture (R-270).

func (Document) ApprovalsNeeded

func (d Document) ApprovalsNeeded() int

ApprovalsNeeded is how many approvals a deploy needs, with the default of one applied.

func (Document) AuditRetention

func (d Document) AuditRetention() audit.Retention

AuditRetention is what the audit archiver reads (R-347).

func (Document) Channel

func (d Document) Channel() UpdateChannel

Channel is the update channel in force, stable when unset.

func (Document) DeployApprovalFor

func (d Document) DeployApprovalFor(appID string) bool

DeployApprovalFor reports whether host policy requires approval for an app's deploys: install-wide, or for this app by name. The app's own spec can require it too, which the approval service reads (R-154).

func (Document) EgressFor

func (d Document) EgressFor(app spec.Egress) EffectiveEgress

EgressFor resolves an app's egress against the installation (R-182).

Entries that do not parse are left out rather than failing here: the spec and the policy are each validated when written, and a plan shown to somebody should not fail on a list it was already told about.

func (Document) EgressInstallMode

func (d Document) EgressInstallMode() (spec.EgressMode, []string)

EgressInstallMode is the install's egress mode in force, reading the field from before issue #79 when the new one is unset.

func (Document) EgressLooseningRule

func (d Document) EgressLooseningRule() EgressLoosening

EgressLooseningRule is the rule in force, with the default applied.

func (Document) GraceHours

func (d Document) GraceHours() int

GraceHours is the grace in force, with the default applied.

func (Document) InstallEgress

func (d Document) InstallEgress() InstallEgress

InstallEgress is the installation's egress rules in force, with the defaults and the field from before issue #79 read the way EgressFor reads them, so what an owner is shown is what their app is held to.

func (Document) KeepsStandbys added in v0.17.0

func (d Document) KeepsStandbys() bool

KeepsStandbys reports whether apps keep a standby unless their spec says otherwise (R-419). On unless turned off.

func (Document) PublicSharingMode

func (d Document) PublicSharingMode() PublicSharing

PublicSharingMode is the rule in force, reading the older boolean when the new field is unset.

func (Document) StopsInsecureApps

func (d Document) StopsInsecureApps() bool

StopsInsecureApps reports whether policy says to stop them (R-316).

func (Document) StopsOrphanedApps added in v0.13.0

func (d Document) StopsOrphanedApps() bool

StopsOrphanedApps reports whether an app with no active owner is stopped (R-408). On unless turned off.

func (Document) TokenExpiry added in v0.13.0

func (d Document) TokenExpiry(now time.Time) *time.Time

TokenExpiry is when a token asked for without an expiry expires: never, unless policy caps how long a token may live (R-061), in which case the cap counted from now.

func (Document) ValidateAuditRetention

func (d Document) ValidateAuditRetention() error

ValidateAuditRetention refuses retention under the floor and a mode that is not one (R-348). Written for the administrator who typed it (R-105).

func (Document) ValidateEgress

func (d Document) ValidateEgress() error

ValidateEgress checks the install's egress settings can be read.

func (Document) ValidateRules

func (d Document) ValidateRules() error

ValidateRules checks the settings that would otherwise be saved and enforce nothing, or enforce something nobody meant: an egress mode or entry that does not parse, or an approval count below zero. Written for the administrator who typed it (R-105).

func (Document) ValidateUpgrades

func (d Document) ValidateUpgrades() error

ValidateUpgrades refuses automatic upgrades that could never run, or that have no window to run in (R-361).

type EffectiveEgress

type EffectiveEgress struct {
	// Mode and List are the install's rules with the app's additions and
	// removals applied.
	Mode spec.EgressMode `json:"mode"`
	List []EgressEntry   `json:"list"`

	// AppMode and AppList are the app's own list, applied on top. Empty when
	// the app has none.
	AppMode spec.EgressMode `json:"app_mode,omitempty"`
	AppList []string        `json:"app_list,omitempty"`

	BlockPrivate     bool   `json:"block_private"`
	BlockPrivateFrom string `json:"block_private_from,omitempty"` // install | app

	// Loosenings is every way this app is looser than the install, and Gate
	// is what policy says they need. Gate is empty when there are none.
	Loosenings []Loosening     `json:"loosenings,omitempty"`
	Gate       EgressLoosening `json:"gate,omitempty"`

	// Unused is the app's additions and removals that change nothing — adding
	// to an install with no list, removing an entry it does not have. Shown as
	// a warning (never a blocker): somebody wrote them expecting an effect.
	Unused []string `json:"unused,omitempty"`

	// Restricted is whether anything is refused at all. When it is not, the
	// app runs exactly as it would with no egress controls (R-186).
	Restricted bool `json:"restricted"`

	// Rules is what a runtime adapter enforces.
	Rules egress.Rules `json:"-"`
}

EffectiveEgress is the rules an app runs with, merged, with where each part came from (R-188). What the plan shows and what the runtime enforces are both read from here, so they cannot disagree.

func (EffectiveEgress) Forbidden

func (e EffectiveEgress) Forbidden() bool

Forbidden reports whether the app loosens rules that policy says may not be loosened. Refused at plan time (R-183).

func (EffectiveEgress) NeedsApproval

func (e EffectiveEgress) NeedsApproval() bool

NeedsApproval reports whether the app's loosenings make its deploy need approval (R-154).

type EgressEntry

type EgressEntry struct {
	Entry string `json:"entry"`
	From  string `json:"from"` // install | app
}

EgressEntry is one entry of the merged list, and whose it is.

type EgressLoosening

type EgressLoosening string

EgressLoosening is what an app needs to loosen the install's egress rules (R-183).

const (
	// EgressLooseningVerb: somebody holding app.egress.loosen may. The
	// default, because Pando ships permissive (R-270) and this is what an
	// install had before the setting existed.
	EgressLooseningVerb EgressLoosening = "verb"
	// EgressLooseningApproval: the deploy that carries it needs approval
	// (R-154). Anybody who may change the app's egress may propose one.
	EgressLooseningApproval EgressLoosening = "approval"
	// EgressLooseningForbidden: no app may, and a deploy that would is
	// refused at plan time.
	EgressLooseningForbidden EgressLoosening = "forbidden"
)

func (EgressLoosening) Valid

func (l EgressLoosening) Valid() error

Valid refuses a value that is none of the three. Empty is unset.

type Evaluator

type Evaluator struct {
	// contains filtered or unexported fields
}

Evaluator answers policy questions against the current document.

func New

func New(load func(ctx context.Context) (Document, error)) *Evaluator

New builds an evaluator over a document source.

The document is loaded per evaluation rather than cached, because R-274 says policy applies to a running install: a cached policy would keep denying, or keep allowing, for however long the cache lived.

func Static

func Static(d Document) *Evaluator

Static builds an evaluator over a fixed document, for tests and for an install that has not written one yet.

func (*Evaluator) Allows

func (e *Evaluator) Allows(ctx context.Context, p authz.Principal, verb authz.Verb, _ string) error

Allows implements authz.Policy: it reports whether a verb is permitted at all.

Evaluated before grants (design 06 §2, step 5). A policy that disables exec install-wide denies the owner too.

func (*Evaluator) AllowsAnonymousGrant

func (e *Evaluator) AllowsAnonymousGrant(ctx context.Context, withPasscode bool) error

AllowsAnonymousGrant checks R-076: whether an app may be shared with everyone, with a passcode or without one.

func (*Evaluator) AllowsScreening

func (e *Evaluator) AllowsScreening(ctx context.Context) string

AllowsScreening is host policy's veto over AI screening (R-336).

A reason rather than an error, and empty when it is allowed. This is not a failure — it is a posture, and it is shown in the review as one. An unreadable policy document denies: a screening that cannot be checked against policy is one that has not been checked, and the safe direction is the one that sends nothing anywhere.

func (*Evaluator) AllowsSource

func (e *Evaluator) AllowsSource(ctx context.Context, src spec.Source) error

AllowsSource checks the source allowlist (R-092).

Called before any clone or pull, so a blocked source produces zero disk writes. The check being here rather than inside the clone path is the whole point: by the time you are cloning, you have already written to disk.

An entry is a host (github.com), a host suffix (.corp.example), or a host and a path prefix (github.com/acme, ghcr.io/acme/web, 123456789012.dkr.ecr.us-east-1.amazonaws.com/team). A path prefix matches on whole segments, so github.com/acme does not admit github.com/acme-evil. Git URLs and image references are read the same way, which is how one list restricts "named orgs, named repos, a specific forge, or registry namespaces" alike. An upload is admitted only by the entry `upload`.

func (*Evaluator) AuditsAnonymousDenials

func (e *Evaluator) AuditsAnonymousDenials(ctx context.Context) bool

AuditsAnonymousDenials reports whether a data-plane denial of somebody not signed in is written to the audit log as authz.denied. A policy that cannot be read audits it, as RecordsAnonymousUse does.

func (*Evaluator) Document

func (e *Evaluator) Document(ctx context.Context) (Document, error)

Document returns the current policy.

func (*Evaluator) IsolationFloors

func (e *Evaluator) IsolationFloors(ctx context.Context) (build, runtime spec.IsolationClass, err error)

IsolationFloors returns the build and runtime floors (R-024, R-114).

func (*Evaluator) PublicSharing

func (e *Evaluator) PublicSharing(ctx context.Context) (PublicSharing, error)

PublicSharing is the host's rule for sharing with everyone, for the console to offer only what it allows.

func (*Evaluator) RecordsAnonymousUse

func (e *Evaluator) RecordsAnonymousUse(ctx context.Context) bool

RecordsAnonymousUse reports whether a visit by someone not signed in is written to the audit log as app.use (R-227). A policy that cannot be read records it: when unsure, keep the record.

func (*Evaluator) Snapshot

func (e *Evaluator) Snapshot(ctx context.Context) (authz.Policy, error)

Snapshot is an evaluator over the document as it is now, for answering several questions in one call from one read (authz.Snapshotter). Used for the length of that call and dropped: never kept across requests, because policy applies the moment it changes (R-274).

type Fixed

type Fixed struct {
	Key    string          `json:"key"`
	Value  json.RawMessage `json:"value"`
	Source Source          `json:"source"`
}

Fixed is one policy field set at startup.

type InstallEgress

type InstallEgress struct {
	Mode         spec.EgressMode `json:"mode"`
	List         []string        `json:"list"`
	BlockPrivate bool            `json:"block_private"`
	Loosening    EgressLoosening `json:"loosening"`
}

InstallEgress is the installation's egress rules as an app's owner edits against them (R-182): the mode and list in force, whether private addresses are blocked, and what loosening them needs (R-183).

type Loosening

type Loosening struct {
	Kind  string `json:"kind"`
	Entry string `json:"entry,omitempty"`
	// Message is written for the app's owner (R-105).
	Message string `json:"message"`
}

Loosening is one way an app's egress is looser than the install's.

func NewLoosenings

func NewLoosenings(prev, next EffectiveEgress) []Loosening

NewLoosenings is what next loosens that prev did not: the part of a change the loosening gate is asked about (R-183). A loosening already running was already allowed.

type Overlay

type Overlay struct {
	// contains filtered or unexported fields
}

Overlay is the policy fields set at startup.

func NewOverlay

func NewOverlay(settings []Setting) (*Overlay, error)

NewOverlay checks each setting against the policy document and returns the overlay. A setting that is not a policy field, or will not read as one, is an error that stops startup: a misspelt or malformed policy is a policy that silently does not apply, which is worse than not starting.

func (*Overlay) Apply

func (o *Overlay) Apply(doc Document) Document

Apply returns doc with the fixed fields laid over it. Nil-safe.

func (*Overlay) Changes

func (o *Overlay) Changes(incoming Document) (Fixed, bool)

Changes reports the first fixed field that incoming sets differently from its startup value, with that value's source. Fields left as the startup value — which is what GET /policy hands back — are not a change.

func (*Overlay) Fixed

func (o *Overlay) Fixed() []Fixed

Fixed lists the fields set at startup, sorted by name. Nil-safe.

func (*Overlay) Restore

func (o *Overlay) Restore(incoming, stored Document) Document

Restore returns incoming with every fixed field put back to what stored holds, so a save never writes a startup value into the stored document.

func (*Overlay) Wrap

func (o *Overlay) Wrap(s Store) Store

Wrap returns a store that reads the effective document — the stored one with the startup fields over it — and saves without writing a startup value into the stored one. Everything that reads policy goes through it, so no reader can see a stored value the startup config has replaced.

type PublicSharing

type PublicSharing string

PublicSharing is the host's rule for sharing an app with everyone.

const (
	// PublicSharingAllowed: public, with or without a passcode.
	PublicSharingAllowed PublicSharing = "allowed"
	// PublicSharingPasscodeOnly: public only behind a passcode.
	PublicSharingPasscodeOnly PublicSharing = "passcode_only"
	// PublicSharingNone: no app may be shared with everyone.
	PublicSharingNone PublicSharing = "none"
)

func (PublicSharing) Valid

func (p PublicSharing) Valid() error

Valid refuses a value that is none of the three. Empty is unset.

type Setting

type Setting struct {
	Key    string
	Value  any
	Source Source
}

Setting is one field as the config gives it: a string from the environment, or a typed value from the config file.

type Source

type Source struct {
	Kind string `json:"kind"`
	Name string `json:"name,omitempty"`
	Key  string `json:"key,omitempty"`
}

Source is where a fixed value was set, as the config package reports it.

type Store

type Store interface {
	Load(ctx context.Context) (Document, error)
	Save(ctx context.Context, doc Document, updatedBy string) error
}

Store is where the policy document is kept.

type UpdateChannel

type UpdateChannel string

UpdateChannel is which releases the update check offers (R-350).

const (
	// UpdateChannelStable offers releases only.
	UpdateChannelStable UpdateChannel = "stable"
	// UpdateChannelPrerelease also offers release candidates.
	UpdateChannelPrerelease UpdateChannel = "prerelease"
)

func (UpdateChannel) Valid

func (c UpdateChannel) Valid() error

Valid refuses a value that is neither. Empty is unset, which is stable.

type Window

type Window struct {
	Days   []time.Weekday
	Start  time.Duration // since midnight UTC
	Length time.Duration
}

Window is a parsed maintenance window (R-361): the weekdays it opens on, the UTC time it opens and how long it stays open. A window that runs past midnight belongs to the day it opened on.

func ParseWindow

func ParseWindow(s string) (Window, error)

ParseWindow reads "sun,wed 02:00 2h": weekdays by their first three letters, or "daily", a 24-hour UTC start time, and a whole number of hours from 1 to 24. Errors are written for the administrator who typed it (R-105).

func (Window) Open

func (w Window) Open(t time.Time) bool

Open reports whether t falls inside the window.

Jump to

Keyboard shortcuts

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