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
- func AllowsDelete(granted []string, class string) bool
- func ClassFromPath(p string) string
- func DestroyableResourceTypes() []string
- func NormalizeAllowDelete(in []string) (out []string, warnings []string)
- type Authorizer
- type Decision
- type EnvAuthorizer
- type Handle
- type LivenessFn
- type Permissions
- type Session
- type Store
Constants ¶
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.
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 ¶
AllowsDelete reports whether class is permitted by the granted set. Explicit class names always match. An empty/unknown class is always denied.
func ClassFromPath ¶
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 ¶
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 ¶
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.
type LivenessFn ¶
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 ¶
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.