resolve

package
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package resolve loads the definitions behind local `uses:` references.

Analysis that stops at the file boundary misses a whole class of problem: a workflow passes attacker-controlled data into a local composite action or reusable workflow, and the execution happens inside that other file. The calling workflow looks clean because it only passes a parameter, and the callee looks clean because it only uses its own declared input.

Only repository-local references are resolved. A remote reference (`owner/repo/action@ref`) would require fetching the other repository, which is a network operation with its own trust questions; those are covered by the supply chain rules instead.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsLocal

func IsLocal(uses string) bool

IsLocal reports whether a `uses:` value refers to something in this repository.

func RepoRootFor

func RepoRootFor(workflowPath string) string

RepoRootFor derives the repository root from a workflow file path.

Workflows are discovered under <root>/.github/workflows, so the root is recovered by trimming that suffix. An empty string is returned when the path does not have that shape, in which case no local resolution is attempted.

Types

type Definition

type Definition struct {
	Kind Kind
	// Path is the file on disk, for reporting.
	Path string
	// RelPath is the path relative to the repository root.
	RelPath string
	Content []byte

	// Inputs are the input names the definition declares.
	Inputs map[string]bool

	// Steps are the composite action's steps. Empty for reusable workflows.
	Steps []parser.Step
	// Jobs are the reusable workflow's jobs. Empty for composite actions.
	Jobs map[string]parser.Job
}

Definition is a resolved local `uses:` target.

func (*Definition) ExecutedInputs

func (d *Definition) ExecutedInputs() []InputUse

ExecutedInputs returns the declared inputs that reach an execution sink inside the definition.

A definition that merely echoes an input into a file, or passes it to an action that does not execute it, is not reported: the point is to identify inputs whose value becomes code.

type InputUse

type InputUse struct {
	// Input is the declared input name that is used.
	Input string
	// StepName identifies the step inside the definition.
	StepName string
	// SinkKind describes how the value is used, e.g. "run script".
	SinkKind string
	// Line is the line within the definition file, for reporting.
	Line int
	// Snippet is the offending line.
	Snippet string
}

InputUse records a place inside a resolved definition where a declared input reaches an execution sink.

type Kind

type Kind int

Kind distinguishes the two things a local `uses:` can point at.

const (
	// KindCompositeAction is an action.yml with `runs.using: composite`.
	KindCompositeAction Kind = iota
	// KindReusableWorkflow is a workflow invoked as `jobs.<id>.uses`.
	KindReusableWorkflow
)

type Repo

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

Repo resolves local references relative to a repository root.

Definitions are cached because the same action is commonly used by many workflows in a repository, and a scan would otherwise re-read and re-parse it for each one.

func NewRepo

func NewRepo(root string) *Repo

NewRepo creates a resolver rooted at the given directory.

func (*Repo) ResolveUses

func (r *Repo) ResolveUses(uses string) (*Definition, bool)

ResolveUses loads the definition a local `uses:` value points at.

Returns false when the reference is remote, missing, unparseable, or an action that is not composite. A JavaScript or Docker action has no steps to analyse from source, so it is deliberately not resolved.

Jump to

Keyboard shortcuts

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