supplychain

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package supplychain handles agent extension artifacts (skills, plugins, hooks, slash commands, agent definitions) as content-addressed trees (ADR-0028): reading them from the policy repo, fetching pinned remote sources (git commit, OCI digest), computing their digest, and the static scan run by `halo validate` and `halo release build`.

It has no internal dependencies so policy, release and halod can all use it.

Index

Constants

View Source
const (
	MaxFiles = 512
	MaxBytes = 8 << 20
)

Limits on one artifact. A skill or hook is a handful of small text files; anything near these is not one.

Variables

View Source
var (
	// CommitRe is a full git object id (SHA-1 or SHA-256 repositories).
	CommitRe = regexp.MustCompile(`^([0-9a-f]{40}|[0-9a-f]{64})$`)
	// OCIRefRe is a digest-pinned OCI reference: host/repo@sha256:<hex>.
	OCIRefRe = regexp.MustCompile(`^[a-z0-9]([a-z0-9.:-]*[a-z0-9])?(/[a-z0-9._-]+)+@sha256:[0-9a-f]{64}$`)
)
View Source
var Rules = []Rule{
	{"hidden-unicode", "zero-width, bidirectional-override or Unicode tag characters, which hide text from a reviewer but not from a model"},
	{"html-comment-instruction", "an HTML comment (invisible when Markdown renders) that carries an instruction: ignore previous instructions, do not tell the user, run curl/bash, ..."},
	{"permission-bypass", "a permission-bypass mode or flag (bypassPermissions, danger-full-access, --dangerously-skip-permissions, --yolo, ...): AGENTS.md invariant 1"},
	{"remote-exec", "fetch-and-execute: curl/wget piped to a shell or interpreter, sh -c \"$(curl ...)\", bash <(curl ...), iex (irm ...)"},
	{"credential-path", "a credential location: ~/.ssh, ~/.aws, gcloud credentials, .netrc, .git-credentials, docker or kube config, or reading a .env file"},
	{"exfil-url", "a URL on a request-capture, tunnel or paste service (webhook.site, ngrok, interact.sh, pastebin, Discord webhooks, ...) or a public raw-IP URL"},
	{"base64-blob", "a base64 run of 1024 characters or more (inline data: images excepted)"},
	{"executable-binary", "a native executable or Java class file (ELF, Mach-O, PE, CAFEBABE)"},
}

Rules is the documented ruleset, in report order.

Functions

func CRLFFiles

func CRLFFiles(t Tree) []string

CRLFFiles lists the files containing "\r\n", sorted. Digests are over the committed bytes: a Windows checkout with core.autocrlf=true hashes CRLF bytes that Linux CI and a remote git fetch never see.

func CRLFWarning

func CRLFWarning(files []string) string

CRLFWarning explains files (from CRLFFiles) and the .gitattributes fix.

func CheckPath

func CheckPath(p string) error

CheckPath reports whether p is a clean, relative, portable artifact path.

func DigestOf

func DigestOf(sums map[string]string) string

DigestOf is "sha256:<hex>" of Listing(sums).

func Listing

func Listing(sums map[string]string) []byte

Listing is the canonical text an artifact digest covers: one "<sha256 hex> <path>\n" line per file, sorted by path in byte order. It is exactly what `sha256sum` prints for the sorted file list, so the digest can be reproduced without Halos (see docs/adr/0028).

func SplitOCIRef

func SplitOCIRef(ref string) (repo, dgst string, err error)

SplitOCIRef splits a digest-pinned "host/repo@sha256:..." reference.

Types

type Finding

type Finding struct {
	Rule   string `json:"rule"`
	Path   string `json:"path"`
	Line   int    `json:"line,omitempty"`
	Detail string `json:"detail"`
}

Finding is one rule match. Line is 1-based (0 = whole file).

func Scan

func Scan(t Tree) []Finding

Scan runs every rule over every file of t. Findings are sorted by path, line and rule.

func (Finding) String

func (f Finding) String() string

type GitRunner

type GitRunner func(ctx context.Context, dir string, args ...string) ([]byte, error)

GitRunner runs git with args in dir; injectable for tests.

type Rule

type Rule struct {
	ID      string
	Summary string
}

Rule is one static check. The ruleset is deliberately small and conservative: each rule matches something an extension has no ordinary reason to contain, so a finding is worth a human look (ADR-0028).

type Tree

type Tree map[string][]byte

Tree is an artifact's content: slash-separated relative path -> bytes.

func FetchGit

func FetchGit(ctx context.Context, url, commit, sub string, run GitRunner) (Tree, error)

FetchGit fetches exactly commit from url (shallow) and reads sub ("" = the whole repository) from it. The checkout is verified to be commit, so a moved branch or tag can never stand in for the pin.

func FetchOCI

func FetchOCI(ctx context.Context, src oras.ReadOnlyTarget, dgst string) (Tree, error)

FetchOCI reads the artifact whose OCI manifest has digest dgst from src. Each layer is one file named by its org.opencontainers.image.title annotation, which is what `oras push <ref> <file>...` writes. Every blob is digest-verified as it is read. ponytail: directory layers (oras push of a directory, a tar+gzip blob) are refused; push the files instead.

func ReadPath

func ReadPath(root string) (Tree, error)

ReadPath reads a file (keyed by its base name) or a directory tree. .git directories are skipped; symlinks and other non-regular files are refused, so a checkout cannot point the artifact outside itself.

func (Tree) Check

func (t Tree) Check() error

Check enforces non-emptiness, path rules and size limits.

func (Tree) Digest

func (t Tree) Digest() string

Digest is the artifact digest: DigestOf(t.Sums()).

func (Tree) Sums

func (t Tree) Sums() map[string]string

Sums maps each path to the sha256 hex of its content.

Jump to

Keyboard shortcuts

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