execsession

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MPL-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package execsession manages short-lived, process-scoped permission grants that allow nested tfctl invocations to perform noninteractive deletes.

This is a safety rail, not a security boundary: the granting process and any nested tfctl run as the same OS user, so the value provided is a deliberate human opt-in that auto-reverts when the session ends. A hard guarantee that an agent cannot delete must come from the API token scope server-side.

Index

Constants

View Source
const (
	// ReasonNoSession indicates no session env var was set.
	ReasonNoSession = "no-session"
	// ReasonStale indicates the env var was set but the session file is gone.
	ReasonStale = "stale"
	// ReasonNotLive indicates the granting process is no longer alive.
	ReasonNotLive = "not-live"
	// ReasonClassNotGranted indicates the resource class was not permitted.
	ReasonClassNotGranted = "class-not-granted"
	// ReasonGranted indicates the delete is authorized.
	ReasonGranted = "granted"
)

Decision reason codes returned by Authorizer implementations.

View Source
const EnvVar = "TFCTL_EXEC_SESSION"

EnvVar is the environment variable a wrapper sets so nested tfctl invocations can discover the active exec session token.

Variables

This section is empty.

Functions

func AllowsDelete

func AllowsDelete(granted []string, class string) bool

AllowsDelete reports whether class is permitted by the granted set. Explicit class names always match. An empty/unknown class is always denied.

func ClassFromPath

func ClassFromPath(p string) string

ClassFromPath derives the resource class being deleted from a resolved API path. The heuristic returns the collection segment immediately preceding the final id segment. It returns "" when it cannot be determined (fewer than two meaningful segments), which callers treat as deny-by-default.

/organizations/tfc-demo-au       -> "organizations"
/workspaces/ws-abc               -> "workspaces"
/workspaces/ws-abc/vars/var-xyz  -> "vars"
/workspaces/ws/relationships/x   -> "x"   (link removal; reversible)
/workspaces                      -> ""    (collection only)

func DestroyableResourceTypes

func DestroyableResourceTypes() []string

DestroyableResourceTypes returns the suggested values for --allow-delete: every known destroyable resource class.

func NormalizeAllowDelete

func NormalizeAllowDelete(in []string) (out []string, warnings []string)

NormalizeAllowDelete lowercases, trims, and CSV-splits the raw --allow-delete values into a normalized, deduplicated list of types. Unknown types (not are returned as warnings but are still kept in the output, since the API surface is large.

Types

type Authorizer

type Authorizer interface {
	AuthorizeDelete(class string) (Decision, error)
}

Authorizer reports whether a noninteractive DELETE of a resource class is permitted by an active, live session. It is the seam the api command depends on so its behavior is testable.

type Decision

type Decision struct {
	// Allowed reports whether the delete may proceed without a prompt.
	Allowed bool
	// Token is the session token, surfaced for audit logging (empty if none).
	Token string
	// Reason is a machine-ish explanation; see the Reason* constants.
	Reason string
}

Decision is the outcome of an authorization check.

type EnvAuthorizer

type EnvAuthorizer struct {
	Store    *Store
	Getenv   func(string) string // default os.Getenv
	Liveness LivenessFn          // default probeLiveness
}

EnvAuthorizer is the runtime Authorizer. It reads the session token from the environment, loads the session, and verifies the granting process is still alive before checking the granted types.

func (*EnvAuthorizer) AuthorizeDelete

func (a *EnvAuthorizer) AuthorizeDelete(class string) (Decision, error)

AuthorizeDelete implements Authorizer.

type Handle

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

Handle is a live grant held by the wrapper process. Close releases the lock and removes the file.

func (*Handle) Close

func (h *Handle) Close() error

Close releases the advisory lock and removes the session file. It is safe to call once; subsequent calls are no-ops.

func (*Handle) Token

func (h *Handle) Token() string

Token returns the session token to expose to descendant processes.

type LivenessFn

type LivenessFn func(path string) (alive bool, err error)

LivenessFn reports whether the process that granted the session file at path is still alive. It is the seam that lets authorization be tested without real processes. It reports alive=true when the granting process still holds its shared lock on the file, and alive=false once that lock has been released (the process exited or was killed).

type Permissions

type Permissions struct {
	// AllowDelete holds normalized resource types.
	AllowDelete []string
}

Permissions is the set of capabilities granted to a session.

type Session

type Session struct {
	Version     int      `hcl:"version"`
	Token       string   `hcl:"token"`
	PID         int      `hcl:"pid"`
	CreatedAt   string   `hcl:"created_at"`
	AllowDelete []string `hcl:"allow_delete"`
}

Session is the on-disk record for an active grant.

type Store

type Store struct {
	// Dir is the directory session files live in. The default is the
	// <config-dir>/exec subdirectory resolved by profile.ConfigDir.
	Dir string
}

Store abstracts the directory holding session files so tests can use a temp dir.

func DefaultStore

func DefaultStore() (*Store, error)

DefaultStore returns a Store rooted at <config-dir>/exec, creating the directory with 0700 permissions if needed. The config dir is resolved by profile.ConfigDir, so it honors TFCTL_CONFIG_DIR and stays consistent with where the rest of tfctl reads its configuration.

func (*Store) Create

func (s *Store) Create(perms Permissions, pid int) (*Handle, error)

Create issues a new token, writes the session file with 0600 permissions, and acquires a shared advisory lock held open in the returned Handle. The lock is held for the process lifetime so authorizers can detect liveness.

func (*Store) Load

func (s *Store) Load(token string) (*Session, error)

Load reads and decodes the session for token. A missing or malformed token returns an error satisfying os.IsNotExist.

Jump to

Keyboard shortcuts

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