scriptexec

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package scriptexec is the one place sloprail decides whether a declared script may be run: it must be executed DIRECTLY, so it must be executable and carry a shebang naming a standard interpreter. There is no `sh <file>` fallback — a file without a shebang would otherwise run under whatever shell happens to start it, and a bash script run by dash fails in ways that read as a refusal of the guarded action.

A declared script that fails Verify is REPORTED (declaration.Loaded.Degraded: `sr-file declarations`, the next session hook) and REFUSED at run time, naming the file and the fix; its rule stays loaded and enforced. For a context's `enter` that means the event that triggered it is refused (a Pre* event denied, a Post* one refused at the Stop), and every Stop is refused while an enter or exit cannot run: an enter that cannot run is not a decline, it never reads as approval. Dropping the rule instead would disarm it on a `chmod -x`, which is not a write and so never reaches a hook.

Only declared SCRIPT paths are affected (a check's `script`/`prepare`, a rule's `subjects`, a context's `enter`/`exit`, a judge mock, an sr-test `test.sh`), never an inline command. A declared script string is a path plus plain arguments, exec'd directly (see Argv), never `sh -c`.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotExecutable  = errors.New("script is not executable")
	ErrNoShebang      = errors.New("script has no shebang")
	ErrBadInterpreter = errors.New("script's shebang names a non-standard interpreter")
	ErrShellSyntax    = errors.New("declared script is not a path plus plain arguments")
)

The ways a script can be unrunnable. Compare with errors.Is.

Functions

func Argv

func Argv(dir, script string) ([]string, error)

Argv splits a declared script string into the argv it is exec'd with, or says why it cannot be.

A declared script is a PATH plus plain ARGUMENTS, split on blanks and exec'd directly, never through a shell: `./staged.sh check` is fine, `./a.sh && ./b.sh`, `./x.sh | y`, `"my dir/x.sh"`, `$HOME/x.sh`, `./x.sh >out`, `./x.sh *` are not (a shell would run them, but only the first word could be verified, and the rest would run unchecked). Every character of a word must be a letter, a digit or one of `_ . / - + = : , @ %`; anything else is shell syntax and is refused, naming the character. The first word is resolved against dir unless absolute; a bare first word (no `/`) is a program on PATH, left to the exec to find. sr:invariant checks/check-that-cannot-answer-refuses

func Command

func Command(ctx context.Context, path string, args ...string) (*exec.Cmd, error)

Command verifies path and returns a command that execs it directly (no shell, no interpreter fallback) with args. A relative path is resolved against the process's working directory, once, here: the file verified is the file exec'd, whatever Dir the caller then sets on the command (Go would otherwise resolve a relative Path against cmd.Dir, a different place).

func Path

func Path(dir, script string) string

Path resolves the script file a declared script string names (see Argv): its first word, relative to dir unless absolute. "" when the string is empty or names a program on PATH.

func Verify

func Verify(path string) error

Verify reports why the file at path cannot be exec'd directly, or nil. A path that does not exist is an error from os.Stat, not one of the sentinels.

func VerifyDeclared

func VerifyDeclared(dir, script string) error

VerifyDeclared is Verify for a declared script string resolved against dir: the string must be a path plus plain arguments (Argv), and the file it names must pass Verify. A declaration naming a file that does not exist is nil here: absence is reported where it is run (a clear "not found"), and a bare word is a program on PATH, not a script of ours. Everything that EXISTS must pass Verify.

Verify then exec is not atomic, and cannot be: the kernel's own exec is the last word. A file swapped in between is still exec'd directly, never through a shell, so one that lost its shebang or execute bit fails to start (refused by the caller), never runs as `sh <file>`.

Types

This section is empty.

Jump to

Keyboard shortcuts

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