debugger

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package debugger: see session.go for the package doc.

Package debugger: see session.go for the package doc.

Package debugger: see session.go for the package doc.

Package debugger is actl's frontend-agnostic core (see CLAUDE.md §5). It owns the barrier-driven pause loop and the halt/pass policy; it imports no frontend, prints nothing, and owns no terminal. The TUI, a future DAP server, and the headless/agent driver are all peers that consume this API:

commands in  — Step / Continue / Abort / SetBreakpoint
events out   — PauseEvent on Pauses(), completion on Done()

It drives act through the soft-fork StepBarrier hook (third_party/act): act keeps the job container alive between step execs, so blocking inside the barrier yields a live workspace + env to inspect.

Package debugger: see session.go for the package doc.

Index

Constants

View Source
const (
	GCPAuthAction   = "google-github-actions/auth"
	AWSAuthAction   = "aws-actions/configure-aws-credentials"
	AzureAuthAction = "azure/login"
)

Auth action refs intercepted for identity handling (§4). Exported so a host-side pre-scan (cmd/actl) can keep cloud-CLI invocation lazy without re-spelling the literals.

Variables

View Source
var ErrAborted = errors.New("debugger: run aborted by user")

ErrAborted is the run error when the front-end aborts via Abort.

Functions

func StepUses added in v0.1.1

func StepUses(st *model.Step, action string) bool

StepUses reports whether step st uses action, matching both the bare ref ("owner/repo") and a pinned version ("owner/repo@v2"). The one place actl decides what "this step uses X" means.

Types

type AWSIdentity

type AWSIdentity struct {
	AccessKeyID     string // → AWS_ACCESS_KEY_ID
	SecretAccessKey string // → AWS_SECRET_ACCESS_KEY
	SessionToken    string // → AWS_SESSION_TOKEN (empty for long-lived creds)
	Account         string // local caller identity (arn), for the transparency line (best-effort)
}

AWSIdentity is the host-resolved ambient AWS credentials for the opt-in ambient fallback (CLAUDE.md §4), the AWS analog of GCPIdentity. The default is bring-a-credential (static keys, see Options.AWSAccessKeyID/AWSSecretAccessKey); ambient is used only with -aws-ambient. Unlike GCP these are env-only — no file is mounted — so the core just injects them at the step's position. Discovery is a host concern (cmd/actl).

type AuthMode added in v0.2.0

type AuthMode int

AuthMode describes how a cloud's federated auth steps were handled locally — the identity strategy is bring-a-credential by default, with ambient personal login only as an opt-in fallback (CLAUDE.md §4). One value per cloud, for the transparency line.

const (
	AuthNone        AuthMode = iota // the job has no auth step for this cloud
	AuthDeclared                    // only secret/key-mode steps — left to run as declared (faithful, untouched)
	AuthSubstituted                 // federated steps rewritten to a brought scoped credential (the default path)
	AuthAmbient                     // federated steps satisfied by the dev's ambient personal login (opt-in fallback)
	AuthUnsatisfied                 // federated steps neutralized — no credential available, cloud calls will fail
)

type ConfigSummary

type ConfigSummary struct {
	Secrets []string // secret names (sorted), values withheld
	Vars    []string // var names (sorted)
	Env     []string // env names (sorted)
}

ConfigSummary is a redacted view of the secrets/vars/env supplied to the run: the names that loaded, never their values, so a transparency line (and any screenshot of it) leaks nothing sensitive.

type DockerUnavailableError

type DockerUnavailableError struct{ Cause error }

DockerUnavailableError is returned by New when the Docker daemon can't be reached. act execs every step into a real job container, so a running daemon is a hard prerequisite; surfacing it up front (with a friendly message) beats act's cryptic mid-run failure. Cause is the underlying connection/ping error.

func (*DockerUnavailableError) Error

func (e *DockerUnavailableError) Error() string

func (*DockerUnavailableError) Unwrap

func (e *DockerUnavailableError) Unwrap() error

type EnvOverlay

type EnvOverlay struct {
	Secrets map[string]string
	Vars    map[string]string
}

EnvOverlay is a per-`environment:` overlay of secrets/vars applied when the debugged job targets that deployment environment (GHA scopes secrets/vars by `environment:`). The host (cmd/actl) resolves each environment's secret-file/inline-vars into these flat maps; the core merges the matching one over the flat defaults (CLI overrides still win — see New).

type EnvSummary

type EnvSummary struct {
	Name    string // the job's `environment:` (deployment environment), "" if none
	Secrets int    // overlay secret keys merged in
	Vars    int    // overlay var keys merged in
}

EnvSummary describes the per-`environment:` overlay applied for the debugged job, for a transparency line: the environment the job targets and how many secrets/vars its overlay contributed. Name is empty when the job targets no environment; Name set with zero counts means the job targets an environment for which no overlay was configured (the flat defaults are used as-is). Values are never retained here.

type EventSummary

type EventSummary struct {
	EventName string // the planned event (github.event_name)
	Path      string // user-supplied event JSON path, if any (else synthesized "{}")
	Synthetic bool   // payload was synthesized (no -event-file)
}

EventSummary describes the github.event payload backing the run, for a transparency line.

type GCPIdentity

type GCPIdentity struct {
	CredentialFile string // host path to the ADC json, bind-mounted ro into the container
	AccessToken    string // ambient ADC access token → CLOUDSDK_AUTH_ACCESS_TOKEN
	Account        string // local identity, for the transparency line (best-effort, may be empty)
}

GCPIdentity is the host-resolved ambient GCP credentials the CLI passes in for the opt-in ambient fallback (CLAUDE.md §4). The default identity path is bring-a-credential (a service-account key, see Options.GCPKeyJSON); ambient is used only when the dev opts in with -gcp-ambient. Locally there is no GitHub OIDC issuer, so a federated `google-github-actions/auth` (WIF) can't mint a token; ambient intercepts that step and injects the dev's already-present credentials. The core never shells out to gcloud — discovery/minting is a host concern (cmd/actl); the core only consumes the data.

type GitHubContextSummary

type GitHubContextSummary struct {
	Repository string   // github.repository (resolved from local git or overridden)
	Ref        string   // github.ref
	Sha        string   // github.sha (short, for display)
	Actor      string   // github.actor ("" → act's "nektos/act" placeholder)
	Overridden []string // which of repository/ref/sha/actor came from a flag
}

GitHubContextSummary is the resolved github.* runtime context for a transparency line: the values act will expose (repository/ref/sha/actor), which the user overrode, and a note that run ids are placeholders locally.

type IdentitySummary added in v0.2.0

type IdentitySummary struct {
	Cloud    string   // "GCP" / "AWS" / "Azure" — names the line
	Mode     AuthMode // how the federated steps were handled
	Steps    []string // intercepted federated auth step labels
	Targets  []string // federation target per federated step (as declared in the workflow)
	Declared []string // secret/key-mode step labels left to run untouched
	Account  string   // the identity we run as (brought principal, or ambient account)
	Region   string   // AWS only: the declared aws-region honored ("" otherwise)
	// Ambient-only detail (Mode == AuthAmbient), for the GCP/AWS ambient line:
	File  bool // an ambient credential file was mounted into the container (GCP)
	Token bool // an ambient access token was injected (GCP)
}

IdentitySummary is a redacted view of one cloud's identity handling for a transparency line: which federated auth steps were intercepted, the federation target each would have used in real CI, which mode satisfied them (substituted brought credential / ambient / none), and the identity we run as. No credential material is retained here. Shared by GCP, AWS, and Azure (CLAUDE.md §4).

type InputsSummary

type InputsSummary struct {
	Provided map[string]string // inputs.* the user supplied
	Defaults []string          // declared inputs not supplied (act fills their default)
	Declared bool              // the workflow declares inputs for this event
}

InputsSummary lists the workflow's declared dispatch/call inputs and which were supplied vs. left to their declared default, for a transparency line. Values are the user's own CLI inputs (not secrets), so they're shown.

type JobListing

type JobListing struct {
	ID          string
	Name        string
	Environment string   // deployment environment (`environment:`), "" if none
	Matrix      []string // combination labels ("k=v, …") when the job has more than one; nil otherwise
	Steps       []StepListing
}

JobListing is one job in a Listing.

type Listing

type Listing struct {
	WorkflowPath string
	Event        string
	Jobs         []JobListing
}

Listing is a Docker-free inventory of a workflow's jobs and steps, produced by List for `actl -list` so the user can see what they'd debug (jobs, their environment and matrix combinations, and each job's steps) without starting a container.

func List

func List(opts Options) (*Listing, error)

List parses and plans the workflow and returns its jobs and steps without touching Docker — the read-only counterpart to New, sharing the same parsePlan prefix. It does not select a single job (it lists them all), so a multi-job or matrix workflow is reported in full rather than prompting.

type MultipleJobsError

type MultipleJobsError struct{ Jobs []string }

MultipleJobsError is returned by New when the workflow has more than one job and Options.JobID did not pick one. It lists the available job ids so a frontend can prompt for a choice.

func (*MultipleJobsError) Error

func (e *MultipleJobsError) Error() string

type MultipleMatrixError

type MultipleMatrixError struct {
	Job    string
	Combos []string // candidate combinations as "k=v, k2=v2" labels, sorted
}

MultipleMatrixError is returned by New when the selected job is a matrix job and the supplied -matrix selection does not pin it to a single combination (debugging one job means debugging one combination). It lists the candidates that remain so a frontend can prompt; the same shape as MultipleJobsError.

func (*MultipleMatrixError) Error

func (e *MultipleMatrixError) Error() string

type NeedsInput

type NeedsInput struct {
	Outputs map[string]string
	Result  string
}

NeedsInput seeds an upstream job's contribution to the needs context when a downstream job is debugged in isolation (the upstream job is not run). Outputs holds only the keys the user provided; Result defaults to "success" if empty.

type NeedsSummary

type NeedsSummary struct {
	Job     string
	Live    bool
	Result  string
	Assumed bool
	Outputs map[string]string
}

NeedsSummary describes how one of the selected job's needs was satisfied locally, for a transparency line. With Live (the --with-deps mode) the upstream job runs for real and the seeded fields are unused; otherwise Result is the effective value (Assumed when defaulted) and Outputs holds the seeded keys.

type Options

type Options struct {
	WorkflowPath    string                     // path to the workflow file
	EventName       string                     // event to plan for (default "push")
	JobID           string                     // which job to debug; required only if the event plans more than one
	Matrix          map[string]map[string]bool // matrix combination to pin (act's Config.Matrix shape: key→value→true); required only if the job's matrix has more than one combination
	WithDeps        bool                       // run the job's upstream needs for real (to completion) before debugging it, instead of isolating
	Image           string                     // docker image mapped to ubuntu-latest when Images is empty (default catthehacker); back-compat sugar for Images
	Images          map[string]string          // runner label → docker image (act's -P/Platforms map); empty falls back to {ubuntu-latest: Image}
	Workdir         string                     // workspace bind-mounted into the container so local 'uses: ./' actions resolve; empty = an isolated empty temp dir (steps can't write to your tree). NOTE: a set workdir is mounted, so steps can write to it
	Source          string                     // working tree a default actions/checkout copies into the workspace (no host mutation); empty = current dir. Ignored when Workdir is set
	Secrets         map[string]string          // secrets.* base (flat defaults, e.g. from secret-file); the env overlay and SecretOverrides layer on top
	Vars            map[string]string          // vars.* base (flat defaults); the env overlay and VarOverrides layer on top
	Env             map[string]string          // extra env for containers
	Environments    map[string]EnvOverlay      // per-`environment:` secrets/vars overlays, keyed by environment name; the one matching the debugged job's `environment:` is merged over Secrets/Vars
	SecretOverrides map[string]string          // secrets.* applied last (after the env overlay) so an explicit CLI -secret wins; nil for library callers
	VarOverrides    map[string]string          // vars.* applied last (after the env overlay) so an explicit CLI -var wins; nil for library callers
	// Cloud identity (CLAUDE.md §4). The default is bring-a-credential: a scoped
	// non-personal credential rewrites a federated auth step to its secret/key mode so
	// the real action runs. Ambient personal login is an opt-in fallback (GCP/AWS only;
	// Azure has none) — non-nil GCP/AWS means -…-ambient was set and the creds resolved.
	GCPKeyJSON         string                // service-account key JSON content → rewrites a federated google-github-actions/auth to credentials_json mode
	AzureCredsJSON     string                // service-principal creds JSON content → rewrites a federated azure/login to creds mode
	AWSAccessKeyID     string                // brought static access key id → rewrites a federated aws-actions/configure-aws-credentials to static-key mode
	AWSSecretAccessKey string                // brought static secret access key (paired with AWSAccessKeyID)
	GCP                *GCPIdentity          // ambient GCP creds for the opt-in fallback (nil unless -gcp-ambient)
	AWS                *AWSIdentity          // ambient AWS creds for the opt-in fallback (nil unless -aws-ambient)
	Needs              map[string]NeedsInput // seeded needs.<job>.* for isolated debugging, keyed by upstream job id (ignored with WithDeps)
	BreakOnError       bool                  // in Continue mode, halt after a step that errored
	Breakpoints        []int                 // zero-based step indices to halt before, in Continue mode
	BreakpointNames    []string              // step names to halt before, resolved to indices against the job's steps in New (a name with no matching step is an error)

	// Runtime context GitHub injects in real CI that a clean local runner lacks
	// — all seed-and-be-honest surfaces (CLAUDE.md §4), each with a transparency line.
	GitHubToken string            // GITHUB_TOKEN → github.token (and mirrored into secrets.GITHUB_TOKEN); empty falls back to Secrets["GITHUB_TOKEN"]
	Inputs      map[string]string // workflow_dispatch/workflow_call inputs.* (user values; act applies declared defaults + typing on top)
	EventPath   string            // path to a github.event payload JSON; empty = "{}" (plus any Inputs)
	Repository  string            // override github.repository (env GITHUB_REPOSITORY); empty = act derives from local git
	Ref         string            // override github.ref (env GITHUB_REF); empty = act derives from local git
	Sha         string            // override github.sha (env SHA_REF, act's read key); empty = act derives from local git
	Actor       string            // override github.actor (Config.Actor); empty = act's "nektos/act" placeholder
	// GitHubOverrides names the github.* fields the user set explicitly by flag (any of
	// "repository"/"ref"/"sha"/"actor"), so the transparency line marks those as overrides.
	// The values above may also be filled from local git for an honest display — only an
	// entry here means the user overrode it, not merely that the value is non-empty.
	GitHubOverrides []string
}

Options configures a debug Session. Only WorkflowPath is required.

type PauseEvent

type PauseEvent struct {
	When  When        // before or after the step's main executor
	Index int         // zero-based step index within the job
	Step  *model.Step // the step at this boundary
	Err   error       // for When==After: the step's error, or nil
}

PauseEvent is emitted when the run halts at a step boundary.

type ProgressEvent added in v0.1.1

type ProgressEvent struct {
	Index int         // zero-based step index now starting
	Step  *model.Step // the step at this boundary
}

ProgressEvent is emitted as the run passes a step's "before" boundary without halting (Continue mode, no breakpoint), so a frontend can follow execution — the step-list highlight tracks the running step even when no pause fires. It's purely advisory: the send is non-blocking and may be dropped under load, and the authoritative state is still PauseEvent/Done. Emitted only for the debugged job.

type ServicesSummary

type ServicesSummary struct {
	Names []string // service container names (sorted)
}

ServicesSummary lists the names of the job's `services:` containers, for a transparency line. act starts these natively when the job runs; actl only surfaces that they will start. Empty when the job declares no services.

type Session

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

Session is one debug run of a single job. Construct with New, then Start.

func New

func New(opts Options) (*Session, error)

New parses the workflow, plans the chosen job, and wires the pause barrier. It does not start execution; call Start. v0.1 debugs a single job: if the event plans more than one, Options.JobID must pick one (else a MultipleJobsError lists the choices).

func (*Session) AWSSummary

func (s *Session) AWSSummary() IdentitySummary

AWSSummary returns the redacted view of the AWS identity handling, for a transparency line. Its Steps/Declared are empty when the job has no aws-actions/configure-aws-credentials step.

func (*Session) Abort

func (s *Session) Abort()

Abort resumes with an order to stop the job (the run ends with ErrAborted).

func (*Session) AzureSummary added in v0.2.0

func (s *Session) AzureSummary() IdentitySummary

AzureSummary returns the redacted view of the Azure identity handling, for a transparency line. Azure has no ambient fallback (CLAUDE.md §4). Its Steps/Declared are empty when the job has no azure/login step.

func (*Session) CanRerun

func (s *Session) CanRerun() bool

CanRerun reports whether Rerun is available — only after a step's main has run (rerunning before it would double-execute on resume).

func (*Session) CheckoutSource

func (s *Session) CheckoutSource() string

CheckoutSource is the host working tree copied into the workspace at checkout time; empty when there's nothing to copy (e.g. a -workdir mount already holds the code, or there were no intercepted checkouts).

func (*Session) CheckoutSteps

func (s *Session) CheckoutSteps() []string

CheckoutSteps returns the labels of default `actions/checkout` steps that were intercepted (rewritten to no-ops), for a transparency line. Empty when none.

func (*Session) ConfigSummary

func (s *Session) ConfigSummary() ConfigSummary

ConfigSummary returns the redacted names of the secrets/vars/env supplied to the run (values withheld), for a transparency line.

func (*Session) ContainerName

func (s *Session) ContainerName() string

ContainerName is the docker name of the live job container at the current pause (empty while running or if no container is in use). A frontend can drop an interactive shell into it; the core stays out of the terminal (CLAUDE.md §5).

func (*Session) Continue

func (s *Session) Continue()

Continue resumes and runs until a breakpoint, a break-on-error stop, or the end of the job.

func (*Session) CurrentRun

func (s *Session) CurrentRun() string

CurrentRun returns the paused step's `run:` script (empty for a `uses:` step or while running) — for pre-filling an editor before Rerun.

func (*Session) Done

func (s *Session) Done() <-chan struct{}

Done is closed when the run has finished (successfully, with an error, or aborted). Read Err afterwards.

func (*Session) Env

func (s *Session) Env() map[string]string

Env returns a copy of the job's environment captured at the current pause, or nil while the run is executing. Inspection is only meaningful while paused.

func (*Session) EnvSummary

func (s *Session) EnvSummary() EnvSummary

EnvSummary returns the per-`environment:` overlay applied for the debugged job (the environment it targets and how many secrets/vars its overlay contributed), for a transparency line. Its Name is empty when the job targets no environment.

func (*Session) Err

func (s *Session) Err() error

Err returns the run result. Only valid once Done is closed.

func (*Session) EventSummary

func (s *Session) EventSummary() EventSummary

EventSummary reports the github.event payload backing the run, for a transparency line.

func (*Session) GCPSummary

func (s *Session) GCPSummary() IdentitySummary

GCPSummary returns the redacted view of the GCP identity handling (which auth steps were intercepted, the federation target, and how they were satisfied), for a transparency line. Its Steps/Declared are empty when the job has no auth step.

func (*Session) GitHubContextSummary

func (s *Session) GitHubContextSummary() GitHubContextSummary

GitHubContextSummary reports the resolved github.* runtime context (repository/ ref/sha/actor and any overrides), for a transparency line.

func (*Session) InputsSummary

func (s *Session) InputsSummary() InputsSummary

InputsSummary reports the workflow's declared inputs and which were supplied vs defaulted, for a transparency line. Declared is false when the event takes no inputs.

func (*Session) JobID

func (s *Session) JobID() string

JobID is the id of the job being debugged.

func (*Session) LocalUsesSteps

func (s *Session) LocalUsesSteps() []string

LocalUsesSteps returns the labels of steps that reference a local action (`uses: ./…`) — these need a real workspace (run with a workdir set).

func (*Session) Logs

func (s *Session) Logs() <-chan string

Logs delivers act's output line by line (job + step logs, with secrets masked). Drain it concurrently; it is buffered but a frontend should keep reading.

func (*Session) NeedsSummary

func (s *Session) NeedsSummary() []NeedsSummary

NeedsSummary reports how the selected job's needs were satisfied (seeded in isolation, or live with --with-deps), for a transparency line. Empty when the job has no needs.

func (*Session) Pauses

func (s *Session) Pauses() <-chan PauseEvent

Pauses delivers a PauseEvent each time the run halts. The run stays blocked until a control method (Step/Continue/Abort) is called.

func (*Session) Progress added in v0.1.1

func (s *Session) Progress() <-chan ProgressEvent

Progress delivers an advisory ProgressEvent as each step starts while the run is passing through (Continue mode), letting a frontend track the running step without a halt. The channel is buffered and lossy — the run never blocks on it — so it's a hint, not a guarantee; Pauses/Done remain authoritative. Optional to consume.

func (*Session) Rerun

func (s *Session) Rerun() error

Rerun re-executes the paused step's main in the live container, picking up any SetRun/SetEnv edits. It blocks until the step finishes; output arrives on Logs(). Only valid while paused after a step has run.

func (*Session) ServicesSummary

func (s *Session) ServicesSummary() ServicesSummary

ServicesSummary returns the names of the job's `services:` containers (which act starts natively when the job runs), for a transparency line. Empty when none.

func (*Session) SetBreakpoint

func (s *Session) SetBreakpoint(index int, on bool)

SetBreakpoint toggles a halt before the step at the given zero-based index (consulted in Continue mode). Safe to call before Start or while paused.

func (*Session) SetEnv

func (s *Session) SetEnv(key, value string)

SetEnv sets or overrides a job env var in memory. The next Rerun (and later steps) see it. No-op while running.

func (*Session) SetRun

func (s *Session) SetRun(script string)

SetRun replaces the paused step's `run:` script in memory (the file on disk is untouched). The next Rerun picks it up. No-op while running.

func (*Session) Start

func (s *Session) Start(ctx context.Context)

Start launches the run in the background. The run halts at the first barrier (before the first step) per the default Step mode; drive it via the control methods and Pauses. Done is closed when the run finishes.

func (*Session) Step

func (s *Session) Step()

Step resumes and halts again at the next barrier.

func (*Session) Steps

func (s *Session) Steps() []*model.Step

Steps returns the job's steps in declaration order (for rendering a step list before the run starts).

func (*Session) TokenSummary

func (s *Session) TokenSummary() TokenSummary

TokenSummary reports how github.token was satisfied (set from a flag/secret, or absent), for a transparency line.

func (*Session) WithDeps

func (s *Session) WithDeps() bool

WithDeps reports whether the job's upstream needs run for real before it.

func (*Session) Workspace

func (s *Session) Workspace() string

Workspace returns the bind-mounted workspace path, or empty when isolated. When non-empty, steps run in the container can write to this path on the host.

func (*Session) WorkspaceIsolated

func (s *Session) WorkspaceIsolated() bool

WorkspaceIsolated reports whether the run uses an empty temp workspace (no user repo), in which case local `uses: ./…` actions and checkout can't resolve.

type StepListing

type StepListing struct {
	Index int
	Label string // step display label (name / uses / run)
	Kind  string // run / docker / local / remote / reusable
}

StepListing is one step in a JobListing.

type TokenSummary

type TokenSummary struct {
	Present bool   // github.token (and secrets.GITHUB_TOKEN) was set
	Source  string // "flag", "secret", or "" when absent
}

TokenSummary is a redacted view of the GITHUB_TOKEN substitution for a transparency line: whether github.token was set and where it came from, never the token itself.

type When

type When int

When marks which side of a step's main executor a pause occurred on. It mirrors the fork's runner.BarrierWhen but keeps act's type out of frontend code.

const (
	Before When = iota // before the step's main executor ran
	After              // after the step's main executor returned
)

func (When) String

func (w When) String() string

Jump to

Keyboard shortcuts

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