Skip to main content

Module write_argv

Module write_argv 

Source
Expand description

Hardened argv construction for the git write verbs (ADR-108).

Every caller-supplied value that can reach std::process::Command::args for git.commit / git.branch / git.push passes through this module first. Nothing here ever touches a shell: Command::new("git") spawns the binary directly and .args([...]) passes each element as one literal, unparsed argv entry — there is no string interpolation anywhere in this crate’s write path for a caller-supplied value to escape.

This module owns exactly two responsibilities, both binding conditions of ADR-108’s Fork (b) resolution:

  1. Validation on every caller-supplied string before it can reach an argv array. Commit paths use Git’s internally-added :(literal) pathspec magic so valid filesystem names are not mistaken for caller-controlled pathspec syntax.
  2. A fixed subcommand + flag allowlist — the build_*_argv functions below are the only argv shapes the write handlers ever construct.

Force-push is rejected unconditionally by reject_force: no code path in this module can produce --force, -f, or --force-with-lease in a push argv, regardless of caller input or Gate policy (ADR-108 hard rule 1). This module is scoped for isolated, dedicated adversarial review per ADR-108’s binding requirement — keep new git-write argv construction here, not inlined into the handlers.

Enums§

GitArgError
Everything that can go wrong constructing a git write argv. Every variant carries enough context to build a caller-facing error without ever echoing back characters that were rejected specifically because they were suspicious (the raw value is still included for legitimate debugging – none of the rejected classes here are secret-shaped).

Constants§

MAX_AUTHOR_LEN
MAX_MESSAGE_LEN
MAX_PATH_LEN
MAX_REF_LEN
Maximum lengths, chosen generously above any real git identifier while still bounding argv/memory size against a malicious caller.
MAX_REMOTE_LEN

Functions§

build_add_argv
Builds the argv for the git add pre-stage step of git.commit when paths is non-empty. Fixed shape: ["add", "--", literal-pathspecs...].
build_branch_argv
Builds the argv for git branch: ["branch", "--", name] or ["branch", "--", name, from].
build_commit_argv
Builds the argv for git commit.
build_push_argv
Builds the argv for git push: ["push", "--", remote, branch]. Never carries a force flag – see reject_force, which handlers must call before reaching this function.
reject_force
ADR-108 hard rule 1: force-push is always denied, unconditionally, at the handler – not left to Gate policy. force: Some(true) (an explicit, loud request) is rejected; absent or Some(false) proceeds normally. There is no argv path anywhere in this module that can add a force flag.
validate_author
Validates the author argument. Bound into a single --author=<value> argv token (see build_commit_argv), so a leading dash inside value cannot itself become a new flag – rejected anyway, defensively, since a concatenated --author=--upload-pack=x value has no legitimate reason to start with -.
validate_commit_path
Validates one entry of git.commit’s paths argument as a bounded, repository-relative filename. Git parses path arguments as pathspecs even after --, so build_add_argv and build_commit_argv prepend the fixed, internally-constructed :(literal) signature after validation. Caller text such as :(top), *, ?, brackets, leading dashes, control characters, and Unicode therefore remains filename text rather than Git syntax. NUL is rejected because operating-system argv cannot represent it.
validate_message
Validates the commit message. Passed to git as a single argv element bound to -m’s value slot, so leading - is not an injection vector here (unlike ref/remote/path names, which can appear as bare positional argv entries) – only NUL bytes (illegal in a process argv on every target platform) and an unreasonable length are rejected.
validate_ref_name
Validates a branch/ref-shaped identifier: name (git.branch), from (git.branch’s optional start point), and branch (git.push’s target ref). Deliberately more restrictive than git’s own check-ref-format – this only needs to admit the identifiers a legitimate caller would ever pass, not the full ref grammar.
validate_remote_name
Validates the remote argument (git.push). Narrower than a ref name – remote names never contain /.
validate_repo_path
Validates the repo argument shared by all three write verbs: must be an absolute local path containing a .git entry (mirrors git.digest’s local-source validation in src/source.rs).