Compile and prove the fastest trustworthy baseline for a GitHub repository.
Project description
gh-freshclone
gh-freshclone is a baseline compiler for unfamiliar public GitHub
repositories and local Git checkouts.
Before a human or coding agent starts editing, it answers:
What is the fastest trustworthy check for this exact commit, does it pass from a clean checkout, and what evidence produced that conclusion?
It compiles repository-owned manifests into an evidence-backed plan, executes the plan without host credentials in an OCI container, and writes a reusable JSON receipt. It distinguishes repository test failures from runner failures and missing environment capabilities.
Automatic detection covers root-level Python, Node.js/Bun/Deno, Rust, Go, Maven, Gradle, Ruby/Bundler, Composer/PHPUnit, CMake, Make/configure, and .NET projects. An operator can apply the same detector to one exact monorepo component, while a repository-owned configuration compiles fully custom steps. The package is alpha software.
Why it exists
- Readiness graders inspect files but generally do not prove a baseline.
- Local GitHub Actions runners reproduce workflows, not the smallest useful contributor baseline.
- Environment generators create an environment but do not record whether the baseline was green.
gh-freshclone is deliberately narrower. It resolves an immutable commit,
selects a profile, fingerprints dependency inputs, prepares dependencies with
network access, then runs the inferred test in a separate container under its
declared network policy. It records the exact image digest, runner version,
phase timings, diagnostics, and logs.
Its differentiated use case is the pre-edit external-repository check:
an OSS contributor or coding agent often cannot add a task contract to the
target repository and should not mutate it just to learn whether its current
baseline is green. gh-freshclone produces that evidence directly from a
remote exact commit, with zero target-repository configuration for supported
stacks.
This is not a general repo-readiness score, service orchestrator, toolchain
provisioner, or organization-policy platform. Contract-first readiness tools
are a better fit when the repository owner wants to model services,
environments, and long-lived workflows. gh-freshclone is the smaller
credential-free proof primitive that an external agent can call before making
its first edit.
Install
Prerequisites:
- Python 3.11 or newer and uv
- Git
- Docker, Podman, or Apple
container1.0.0+ on a supported Mac
Try the signed release without installing it or executing repository code:
uvx --from "gh-freshclone @ git+https://github.com/yhay81/gh-freshclone.git@v0.19.0" gh-freshclone plan pallets/itsdangerous
This resolves an immutable public commit and prints the baseline it would run.
Replace plan with doctor to verify local runner readiness, or with check
when you are ready to execute the baseline in an isolated container.
Until the package is registered on PyPI, install the signed release tag directly from GitHub:
uv tool install "gh-freshclone @ git+https://github.com/yhay81/gh-freshclone.git@v0.19.0"
gh-freshclone doctor
After publication to PyPI:
uv tool install gh-freshclone
gh-freshclone doctor
doctor verifies Git and runner-daemon readiness, not only whether the
executables are present. Public GitHub resolution uses credential-free HTTPS;
no GitHub token, API quota, or gh auth login is required. Use
doctor --json in automation.
During development:
uv sync --locked
uv run gh-freshclone doctor
The supported interface is the standalone gh-freshclone executable.
GitHub CLI extension packaging is not currently claimed.
Quick start
Inspect a plan without executing repository code:
gh-freshclone plan pallets/itsdangerous
gh-freshclone plan owner/repo --ref v1.2.3 --profile reproduce
gh-freshclone plan owner/repo --component apps/web
gh-freshclone plan https://github.com/owner/repo/pull/123
gh-freshclone plan . --json
Automatic planning reads the immutable Git tree, then hydrates only the
committed manifests and evidence files used by detection. It does not download
the repository's source and test bodies. check expands that same
credential-free checkout to the complete exact commit only after it has found
an executable baseline. With --component, planning hydrates only bounded
inputs below that directory and execution expands only that component from
the exact commit, avoiding unrelated monorepo I/O and host-incompatible paths.
A component-owned .gh-freshclone.toml can reference arbitrary files inside
that bounded component.
Read the upstream GitHub CI state for the same exact commit without executing repository code:
gh-freshclone github-status owner/repo
gh-freshclone github-status owner/repo --ref FULL_40_CHAR_SHA
gh-freshclone github-status https://github.com/owner/repo/pull/123 --json
Execute the default quick baseline:
gh-freshclone check pallets/itsdangerous
gh-freshclone check https://github.com/owner/repo/commit/FULL_40_CHAR_SHA
gh-freshclone check https://github.com/owner/repo/pull/123
gh-freshclone check . --runner docker --cpus 4 --memory 8g
gh-freshclone check owner/repo --component apps/web
gh-freshclone check owner/repo --test-network enabled
gh-freshclone check owner/repo --json
Profiles make the cost/coverage choice explicit:
| Profile | Purpose | Typical policy |
|---|---|---|
quick |
Fast trustworthy pre-edit signal | One compatible tox environment; primary test script |
reproduce |
Repository-default contributor baseline | Default tox/test command |
full |
Broad pre-submit confidence | All known scripts, features, or environments |
The component, profile, preparation and test commands, operator-selected
test-network policy, supporting manifest evidence, and dependency fingerprint
are part of the plan digest. Test containers stay offline by default even when
repository-owned configuration requests network. --test-network enabled is
the explicit operator opt-in that enables outbound access for every test step;
the effective policy is visible in plan, receipts, and results. Offline and
network-enabled PASS indexes are separate and cannot satisfy one another. A
PASS is reused only for the same commit, plan version, execution policy,
component, profile, runner, resources, and test-network policy. The index is
checked before a new clone, so a known PASS normally returns in well under a
second after commit resolution.
Use --no-cache when fresh execution evidence is required.
When automation already knows a full 40-character commit SHA, pass it with
--ref or paste a GitHub commit URL. Ref resolution then makes no network
request; materialization still verifies that the object exists before
execution. A pasted pull-request URL resolves its advertised head ref without
requiring GitHub API authentication.
github-status is the explicit GitHub REST API integration. It uses API
version 2026-03-10 to read the latest GitHub Checks and combined legacy
commit status for the resolved public commit. The command makes two
unauthenticated, read-only API requests, exposes the remaining API quota, does
not retry a rate-limit response, and never executes repository code. GitHub's
unauthenticated public-data limit is currently 60 requests per hour per source
IP. The mutable upstream CI observation is intentionally separate from plan,
receipt, and PASS-cache identity.
The ordinary plan and check paths continue to use credential-free Git
smart HTTP and do not require a GitHub API quota or token. See
the GitHub integration note for API
boundaries and Developer Program evidence.
GitHub Action
On a GitHub-hosted Ubuntu runner, the composite action installs the package from the same immutable action ref and writes the complete JSON result to an output path. It needs no checkout, GitHub token, secret, or write permission for a public remote target:
permissions: {}
jobs:
baseline:
runs-on: ubuntu-latest
steps:
- id: baseline
uses: yhay81/gh-freshclone@v0.19.0
with:
repository: pallets/itsdangerous
ref: 672971d66a2ef9f85151e53283113f33d642dabd
- name: Retain the proof even when the baseline fails
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0 # v7.0.1
with:
name: gh-freshclone-result
path: ${{ steps.baseline.outputs.result-path }}
Inputs also expose component, profile, runner, test-network,
no-cache, cpus, and memory. GitHub expressions enter the fixed Python
entrypoint only through environment variables; it invokes uvx without a
shell, places the repository after an option delimiter, and removes Git and
GitHub credential variables from the child environment. The action requires a
Linux job with Docker or Podman. Use the standalone CLI for Windows, macOS,
or Apple container.
What a result means
The result taxonomy is intentionally small:
| Status | Meaning |
|---|---|
PASS |
Every compiled step passed |
TEST_FAILURE |
The repository baseline executed and failed |
ENVIRONMENT_GAP |
Required executable, library, or permission is absent |
INFRA_FAILURE |
The OCI runner or image could not execute the plan |
For implicit environment failures, the tool does not rely on a test name alone. It extracts executable candidates from failing selectors, then probes the same content-addressed image. A diagnostic includes its confidence, evidence, and a package hint when known.
Example:
Result: ENVIRONMENT_GAP
python: environment_gap
Failing tests reference an executable absent from the image: less
(suggested package: less)
CLI exit codes are stable:
| Code | Meaning |
|---|---|
0 |
The check passed, the plan has executable steps, or diagnostics are healthy |
1 |
A baseline did not pass, no plan step was detected, or doctor found a missing prerequisite |
2 |
The request, repository, configuration, or runner could not be initialized |
After argument parsing, commands invoked with --json also return code-2
initialization failures as a JSON error envelope on standard output:
{
"api_version": 1,
"status": "error",
"error": {
"code": "initialization_error",
"message": "failed to pull image ..."
}
}
Reproducibility and performance
- GitHub targets are resolved to a full commit SHA using an isolated,
credential-free
git ls-remoterequest; exact SHA inputs skip this request. - Public targets materialize with a depth-one fetch of only that resolved ref or commit. A ref move falls back to the already-resolved SHA and fails closed if the immutable target is no longer available.
- Mutable image tags are refreshed from their registry and resolved to
repository@sha256:...; a stale local tag is never silently trusted. The digest is used for execution and stored in the receipt. An explicitly declared digest can run from verified local content without a registry round trip. - Lockfiles and relevant manifests form a dependency fingerprint.
- Before any container starts, the exact committed Git tree is streamed from
Git objects into one deterministic tar archive. Each prepare/test container
extracts that single read-only input instead of copying thousands of host
files through a VM bind mount. File modes, symlinks, and commit timestamps
are preserved; untracked files and modified working-tree content cannot
enter the archive. A small writable
.gitindex/ref layer points at the original checkout's read-only object database, retaining ordinary Git metadata without duplicating its packs. - Go reuses module and build caches but compiles
go test -count=1, so a fresh proof cannot silently reuse a previous successful test result. - Maven and Gradle reuse repository-, image-, and dependency-scoped
app-managed volumes. Dependencies are prepared with network access, then the
lifecycle is rerun from a fresh read-only checkout with Maven offline mode
or Gradle
--offlinein a network-disabled container. Managed volumes avoid host UID/permission coupling without granting broader container privileges. - Ruby/Bundler planning accepts only a generic-platform Bundler 4 lock with
complete SHA-256 identities, an exact Bundler version, the official
RubyGems source, repository-contained path gems, and a direct locked
ordinary test runner. Preparation constructs fixed RubyGems archive URLs
from safe lock tokens, downloads them in bounded parallel transfers, and
verifies every checksum without evaluating
Gemfile, gemspecs, Rakefiles, native extensions, or repository code. The network-disabled test container mounts those archives read-only, installs the exact Bundler into disposable state, performs a frozen local bundle install, and reruns RSpec or the Rake-backed Minitest/test-unit suite. - CMake planning requires a literal root CTest signal and refuses a declared
minimum newer than its pinned CMake runtime. It conservatively enables one
ordinary project test option when the committed
option(...)name and description identify it, while excluding CUDA, conformance, sanitizer, benchmark, and integration variants. - CMake 3.31.10 and Ninja 1.13.0 are installed into an exact-commit managed
volume during the network-enabled preparation phase of a common
multi-architecture Python/buildpack image. A configure-only preparation
populates declared FetchContent sources in that volume. A fresh
configuration, two-worker build, and CTest then run with
FETCHCONTENT_FULLY_DISCONNECTED=ONand no container network; compiled outputs are not reused.ctest --no-tests=errorprevents a zero-test build from becoming a false PASS. - Make planning reads only a root
GNUmakefileorMakefileand accepts a literal ordinarytest,tests, orchecktarget. If a rootconfigureexists, it must be a bounded UTF-8 sh/bash script. The fixed target runs in the official multi-architecture Buildpack Dependencies Bookworm image with no preparation phase, no credentials, and no container network; documentation, CI snippets, variable-expanded targets, and unknown configure entrypoints are never inferred. - Composer planning requires
composer.lock, a directphpunit/phpunitdeclaration, the matching locked package, and the defaultvendor/layout. It rejects locked Composer plugins instead of allowing package code to run during dependency acquisition. The official multi-architecture Composer image installs the exact lock with both plugins and scripts disabled. A second network-disabled container mounts that state read-only, copiesvendor/into its disposable workspace, explicitly disables Composer networking and redundant policy lookups, replays the no-change install lifecycle (including repository autoload/install hooks), and runs the lockedvendor/bin/phpunit. Hook and test writes cannot poison the next proof. Missing locked PHP extensions or an incompatible runtime are reported as an environment gap rather than a repository test failure. - .NET planning parses one committed root solution without evaluating MSBuild.
A declared supported SDK 8/9/10 selects Microsoft's official multi-arch SDK
image;
quickchooses one ordinary unit-test project and, when a literal matching TFM exists, only that framework. NuGet restore state and generatedobjinputs cross the phase boundary in an exact-commit managed volume. The network-disabled test container copies only those restore outputs into a fresh workspace, recompiles the source, and never reusesbinor test results. - Canonical CPU and memory limits are recorded in receipt v7 and participate
in receipt and PASS-index identity; a proof produced at
2 CPU / 4gis never reused for an8grequest. - Download caches are isolated by repository, runner, ecosystem, dependency fingerprint, and resolved image digest. Repository namespaces include a stable hash of the GitHub canonical name or local checkout path, so sanitized display-name collisions cannot share state.
- Preparation identity includes the dependency fingerprint, resolved image, preparation command, and working directory—not the test command. Changing a test selector does not redownload dependencies, while changing preparation still invalidates the cache.
- Python
.venv/tox state, Node.js/Bunnode_modules, and Maven/Gradle dependency state are kept in exact-commit, step-scoped volumes. A success marker allows a fresh proof to skip redundant dependency preparation without treating an interrupted preparation as reusable. - A failed preparation discards only its repo/commit/lockfile/image-scoped host cache or prepared volumes before the app performs one clean retry in the same check. This prevents storage-corrupted partial package-manager state from becoming a persistent false repository failure without creating an unbounded retry loop. A second preparation failure leaves the scoped cache clean and returns normally. Test-phase failures retain successfully prepared dependencies for fast deterministic reruns.
- A successful exact-commit materialization retains only its Git object
database, shallow boundary, and target metadata in the bounded host cache.
A later fresh proof creates a new Git repository with a generated safe
config, rejects links and alternate object stores, verifies retained objects
with
git fsck --full --strict, and proves the selected component has no missing objects while lazy fetching is disabled. Git config, hooks, credentials, worktrees, test outputs, and mutable refs are never cached. A source object database that cannot fit the shared 5 GiB host-cache budget is not retained. - Deno's
DENO_DIR, local vendor tree, andnode_modulesshare the same exact-commit volume across the networked preparation and offline test containers, including repositories with"vendor": true. - Bun baselines bootstrap a pinned Bun binary into the prepared volume of a
Node LTS image. Hybrid test scripts can therefore use
bun,node, andnpmwithout a project-maintained custom image. - When a Node/Bun package declares an entrypoint that is absent from the
checkout and also owns a known
buildscript, that build is compiled beforetest; committed entrypoints keep the faster test-only quick path. - PASS receipts use a versioned pre-clone index.
- Matching repository/commit/profile/runner probes take a cross-process lock; concurrent agents neither corrupt a shared prepared volume nor duplicate a known PASS build.
On a Windows 11 / Docker 29.6.1 development machine, the
pallets/itsdangerous quick profile improved from a 131.7-second full tox run
to 5.1–25.2 seconds of runner time across repeated measurements. Reusing its
PASS avoids cloning and container startup after immutable-ref resolution.
The credential-free default-branch path currently returns in a 0.611-second
median over 10 sequential runs. Supplying its exact SHA reduces the median to
0.176 seconds with a 0.204-second p95 for the installed CLI because no remote
ref request is needed. A dependency-light entry point returns --version in
53.490 ms median and 63.692 ms p95 instead of loading the execution engine.
Below CLI startup, the exact-SHA in-process cache contract measures 2.992 ms
median and 4.414 ms p95 over 30 Windows runs. The isolated
local-repository hot-path benchmark measures 60.720 ms median and 67.272 ms
p95 because local Git metadata and commit resolution use one process. CI
fails if the same clone-free path exceeds 250 ms p95 on its Linux runner.
These are development measurements, not cross-platform guarantees.
A public-repository trial across eight earlier automatic ecosystems, including
the defects discovered during real execution and measured cold/warm results,
is recorded in
docs/field-trial-2026-07-25.md.
On the final dual-build Java target, verified dependency reuse reduced an
otherwise fresh end-to-end Maven-plus-Gradle proof from 897.90 to 318.27
seconds while rerunning both offline lifecycles.
The CMake follow-up planned ten current public repositories and accepted eight
with root test evidence. A physical proof of
fmtlib/fmt@2a2d9edb257322bec0f7ac602fde3b382fe0082a compiled and passed all
21 CTest cases with the test container offline. The first end-to-end check took
175.09 seconds, including 9.97 seconds of fresh preparation and 156.65 seconds
of build/test runner time. Reusing that exact PASS returned in 0.42 seconds.
The .NET follow-up accepted all four single-solution repositories in its
manifest-only cohort: Polly, AutoMapper, Serilog, and FluentValidation.
AutoMapper/AutoMapper@dfa6dd587c5854b4beee5934beb39ba6e9569b84
restored in 44.578 seconds, then compiled and passed 1,217 unit tests in an
offline container; total runner time was 72.666 seconds. An intentionally
fresh repeat reused only verified restore state, recompiled and reran all
tests, and completed in 28.063 seconds. Serilog produced useful negative
evidence instead: its exact commit failed restore because its own
warning-as-error policy rejected five current high-severity NuGet advisories.
The Composer/PHPUnit follow-up accepted
mockery/mockery@3a80322e874fbdce4e87e739456fe48d48a527c8
without repository configuration. Fresh locked dependency preparation took
7.994 seconds; a separate offline container ran 705 tests with 1,105
assertions (10 skipped), and the complete proof took 23.963 seconds. An
intentionally fresh repeat verified the prepared-volume marker, replayed the
offline install hooks, reran PHPUnit, and completed in 16.661 seconds.
ramsey/uuid supplied the fail-closed control: its lock contains four
executable Composer plugins, so automatic planning rejected it and named the
plugins instead of running them while network access was available.
A fresh probe of public pull request
pallets/itsdangerous#428
resolved its advertised head commit without GitHub API authentication,
compiled one Python step, prepared dependencies, and passed the test in a
second network-disabled container. An earlier execution-policy-v13 cold proof took
9.327 seconds of runner time; an intentionally fresh second proof reused the
verified preparation and took 5.077 seconds while still rerunning all 297
tests offline. This is the same pasted-PR workflow exposed by the CLI, not a
fixture-only code path.
Run the performance contract against any committed local checkout:
uv run python -m benchmarks.cached_workflow . \
--runner docker --iterations 30 --max-p95-ms 250
uv run python -m benchmarks.cli_startup --max-p95-ms 250
The Python runner uses an exact-version
uv derived image, so
it avoids installing the package manager on every run.
Cache operations
Cache locations:
- macOS:
~/Library/Caches/gh-freshclone - Linux:
${XDG_CACHE_HOME:-~/.cache}/gh-freshclone - Windows:
%LOCALAPPDATA%\gh-freshclone
Set GH_FRESHCLONE_CACHE to override the host location.
gh-freshclone cache status
gh-freshclone cache status --json
gh-freshclone cache prune
gh-freshclone cache prune --max-gib 3 --max-volume-gib 2 \
--max-volumes 12 --max-age-days 14
gh-freshclone cache prune --max-evidence-gib 0.5 --max-evidence-entries 256
Automatic maintenance runs daily, and also after dependency, immutable-source,
or prepared-volume growth crosses its hard limit. Cache hits do not pay for
this extra measurement. Defaults are a shared 5 GiB and 128-entry budget for
host dependency and exact-source caches, 1 GiB and 512 receipt/log evidence
bundles, 24 prepared volumes with a 3 GiB measured-volume budget, and 30 days.
A cache hit refreshes its receipt or source LRU time. Docker and Podman volume
usage comes from runner metadata without mounting or executing cached content;
Apple container retains the count and age limits when byte accounting is
unavailable. Runner readiness, version,
image/volume metadata, volume creation, failure diagnostics, cache metadata,
and cleanup calls are limited to 15 seconds, so a stopped runner cannot turn
startup, doctor, cache status, or failure handling into an unbounded wait.
Independent version/readiness probes run concurrently while preserving runner
preference order, so the worst-case wait does not multiply by the number of
installed runners. Image downloads and repository prepare/test phases keep
their normal completion semantics.
Non-zero runs explicitly retry named container cleanup, and Docker/Podman
execution containers carry app ownership labels for diagnosis.
Before a cache-miss execution, the app preserves 2 GiB free on the filesystems
holding its cache and temporary checkout. It first removes only reclaimable
app-owned cache, tightening the measured prepared-volume budget further when
the normal limits are not enough; if the reserve is still unavailable, the
check stops before cloning with an actionable error. An existing immutable
PASS receipt remains usable because it needs neither a checkout nor a
container.
Evidence from incompatible receipt/execution-policy versions, dangling PASS
indexes, and interrupted-run logs are recovered by the same maintenance path.
It never invokes a global runner prune. Removal is limited to host paths below
the app cache root and named volumes recorded by this app with the strict
ghfc-* format. Per-resource OS locks protect every in-use dependency cache,
exact-source object cache, receipt/log bundle, and prepared volume from
automatic or manually invoked pruning, including from another process.
Unrelated repositories remain
parallel. Each step log is capped at 10 MiB while runner output continues to
be drained; a truncation marker and diagnostic tail remain available.
macOS, Windows, and Linux
Plan compilation works natively on all three platforms:
| Host | --runner auto preference |
|---|---|
| macOS | Apple container, Docker, Podman |
| Windows | Docker, Podman |
| Linux | Docker, Podman |
auto skips a stopped Docker/Podman daemon when another installed runner is
ready. If all daemons are stopped, an existing pre-clone PASS remains
available; a cache miss stops before cloning with an actionable readiness
error.
Apple container runs Linux containers
in lightweight virtual machines. Apple silicon with macOS 26 is the supported
configuration. Version 1.0.0 or newer is required because the runner contract
uses stable capability, read-only mount, named-volume, no-network, and
resource-limit flags. Apple container accepts whole-number CPU limits;
Docker and Podman also accept fractional values. Intel Macs and older macOS
releases can use Docker or Podman.
gh-freshclone check owner/repo --runner container
gh-freshclone check owner/repo --runner docker
Command construction, read-only input, prepared volumes, and --network none
are covered by the cross-platform contract suite. A manually dispatched
apple-container-e2e.yml workflow runs the complete prepare-then-offline-test
probe on a dedicated self-hosted runner labelled
gh-freshclone-apple-container. GitHub-hosted macOS runners cannot provide
this proof because nested virtualization is not
supported.
The ordinary CI workflow additionally runs the CMake, Make/configure, .NET,
Composer/PHPUnit, and Ruby/Bundler offline-boundary E2Es on native
GitHub-hosted ubuntu-24.04-arm runners. This continuously verifies the same
arm64 OCI images and dependency paths used by Apple silicon, while the
self-hosted workflow retains coverage of Apple container itself.
A physical Apple silicon run and cold/warm public-repository measurements are
recorded in
docs/field-trial-2026-07-25.md.
Security model
Repository tests execute untrusted code. gh-freshclone therefore:
- creates a fresh checkout pinned to an exact commit;
- excludes uncommitted and untracked local files;
- resolves public GitHub refs with a fixed HTTPS URL, isolated empty Git configuration, disabled prompts, and no API token;
- uses credential-free HTTPS for public GitHub clones and refuses known private repositories;
- disables system/global Git config, checkout templates, interactive credential helpers, system attributes, and host-configured filters during materialization;
- restores cached exact-source objects only into a newly initialized credential-free repository after strict Git object and component-closure validation, without retaining Git config, hooks, alternates, or refs;
- never forwards
GH_TOKEN,GITHUB_TOKEN, SSH agents, Git configuration, or the broad host environment; - gives each phase a disposable workspace extracted from one exact-commit
archive, with a compatibility fallback to the read-only
/inputcopy only when the committed tree cannot be represented portably; - mounts
/inputread-only with every supported runner; - mounts only repository-scoped dependency caches;
- runs dependency preparation with network access, exits that container, and starts a distinct test container with network disabled by default;
- never lets repository-owned configuration enable outbound test access by
itself; only the caller's
--test-network enabledopt-in can do so; - drops capabilities, restoring only
CHOWNandFOWNERfor package extraction; - enables
no-new-privilegeswith Docker and Podman; - limits CPU and memory on every runner, and process count on Docker/Podman;
- mounts
/tmpas a disposable tmpfs on every runner; - removes named test containers on normal completion, error, or interruption.
Only dependency preparation normally needs outbound network access. For a
suite that intentionally downloads assets during its test phase, inspect the
plan and pass --test-network enabled. A repository may request the same
policy in .gh-freshclone.toml, but that request remains offline until the
operator explicitly opts in. An OCI runtime remains a security boundary with
a non-zero attack surface. Do not add credential or broad host mounts for
untrusted repositories.
Detection policy
Commands come only from known manifest structures. README snippets and
arbitrary GitHub Actions run blocks are not executed.
Current evidence sources include:
- Python:
pyproject.toml,uv.lock, dependency groups/extras, tox and pytest; legacysetup.py/setup.cfgprojects and common requirements-file names are also compiled without executingsetup.pyon the host - Node.js:
packageManager, lockfiles, and known package scripts - Rust:
Cargo.tomlandrust-toolchain.toml - Go:
go.mod, using its explicittoolchainwhen present and a refreshed stable image otherwise - Maven:
pom.xml, an optional committedmvnw, and wrapper configuration;testis the default lifecycle andfullcompilesverify - Gradle: committed build files plus a committed
gradlew; wrapper compatibility and literal Java 17/21/25 toolchain declarations select a multi-architecture official Gradle image, while unwrapped builds are never auto-run - Ruby/Bundler:
Gemfile, an exact Bundler 4Gemfile.lockwith complete SHA-256 checksums and a genericrubyplatform, and a direct locked RSpec suite or Rake-backed Minitest/test-unit task; Git/plugin sources, custom gem servers, escaping path gems, checksum gaps, and transitive runners are reported rather than executed - Composer/PHPUnit:
composer.json, an exactcomposer.lock, a direct lockedphpunit/phpunitpackage, and an optionalphpunit.xml(.dist); custom vendor/bin layouts, locks missing the declared runner, transitive runners, and executable Composer plugin graphs are reported rather than guessed or executed - Make/configure: one root
GNUmakefileorMakefilewith a literaltest,tests, orcheckrule, plus an optional root sh/bashconfigure; the selected fixed command runs only in a network-disabled official buildpack container;quickprefers the conventionalchecktarget whilereproduce/fullprefertest, and a supported CMake plan takes precedence to avoid duplicate native builds - .NET: one root
.slnor.slnx, optionalglobal.json, and statically listed project paths;quickselects one ordinary unit-test project while rejecting benchmark, integration, performance, sample, and utility projects
Cargo members declared by a root workspace are covered by its
cargo test --workspace step. Other nested manifests are reported as not
auto-run rather than guessed. When an operator already knows the intended,
self-contained boundary, --component applies the same automatic detector
there without changing the target repository:
gh-freshclone plan dependabot/dependabot-core \
--ref 6c8bb8bd9cb7ec79c324bc550a992ab66201e76a \
--component npm_and_yarn/helpers
gh-freshclone check dependabot/dependabot-core \
--ref 6c8bb8bd9cb7ec79c324bc550a992ab66201e76a \
--component npm_and_yarn/helpers \
--test-network enabled
Component paths are non-empty portable POSIX paths, cannot traverse outside
the repository or enter .git, and must name a committed directory. The
selected component becomes part of every plan and cache identity. Planning
does not recursively guess components; the caller must supply the exact
boundary. Execution materializes and archives only that component, preserving
its repository-relative path and an exact detached HEAD. If a baseline
needs files outside that directory, select a wider component or use a
repository-owned root configuration.
A monorepo can instead opt into multiple explicit, reviewable steps with
.gh-freshclone.toml:
version = 1
[[steps]]
profiles = ["quick", "reproduce", "full"]
path = "services/api"
ecosystem = "python"
image = "ghcr.io/astral-sh/uv:0.11.32-python3.13-trixie"
prepare_command = "uv sync --frozen --group test"
command = "uv run --offline --no-sync --group test pytest -q"
test_network = "none"
dependency_files = ["uv.lock"]
[[steps]]
profiles = ["full"]
path = "apps/web"
ecosystem = "node"
image = "docker.io/library/node:24-bookworm"
prepare_command = "npm ci --no-audit --no-fund"
command = "npm test"
test_network = "none"
dependency_files = ["package-lock.json"]
The configuration is authoritative when present. Paths and dependency files
must remain below the repository, unknown fields fail closed, and plan still
does not execute commands. test_network = "enabled" is only a repository
request: the effective policy remains none unless the caller passes
--test-network enabled. This prevents an unfamiliar repository from granting
itself outbound access. The compiled plan records working_directory
separately, and the runner mounts each prepared environment at that exact
subdirectory rather than relying on a shell-only cd.
Agent and Tsumugi integration
The library API avoids scraping human CLI output:
from pathlib import Path
from gh_freshclone.api import (
compile_materialized_checkout,
probe_repository,
receipt_schema,
)
from gh_freshclone.integrations.tsumugi import outcome_to_tsumugi_flags
from gh_freshclone.model import Repository
outcome = probe_repository(
"dependabot/dependabot-core",
ref="6c8bb8bd9cb7ec79c324bc550a992ab66201e76a",
component="npm_and_yarn/helpers",
test_network="enabled",
profile="quick",
echo=False,
)
assert outcome.api_version == 1
print(
outcome.status,
outcome.receipt_path,
outcome.cached,
outcome.elapsed_seconds,
)
tsumugi_flags = outcome_to_tsumugi_flags(outcome)
# A host system can retain its own clone and sandbox lifecycle.
repository = Repository(
display_name="owner/repo",
commit_sha="0" * 40,
ref="main",
source_url=None,
github_repository="owner/repo",
local_path=None,
)
plan = compile_materialized_checkout(Path("/exact/checkout"), repository)
schema = receipt_schema()
compile_materialized_checkout only compiles manifests; it does not execute
repository code. The caller guarantees that the checkout matches the supplied
commit. This is the integration seam for Tsumugi: share the compiler and
evidence contract while Tsumugi retains its systemd sandbox, stall detection,
rate controls, and state database. outcome_to_tsumugi_flags maps status,
commands, commit, diagnostics, image identities, and cache evidence to
Tsumugi's existing test_cmd / baseline_* flag contract; it does not bypass
Tsumugi's quality gate or external-action controls.
check --json adds api_version, receipt_path, cached, and end-to-end
elapsed_seconds to the receipt shape. Receipt v7 is documented by the bundled
gh_freshclone/schemas/receipt-v7.schema.json; v6 remains bundled for existing
consumers. It records canonical CPU and memory limits, each step's working
directory, whether dependency preparation was reused, and whether immutable
source objects came from a git fsck-validated cache; resource limits also
scope PASS reuse. The Tsumugi adapter preserves nested working directories and
exposes limits and source provenance as baseline_resource_limits,
baseline_source_cache_hit, and baseline_source_validation.
Development
uv sync --locked
uv run pytest -q
uv run ruff check .
uv build
uv run python -m benchmarks.cached_workflow . --runner docker
uv run python -m benchmarks.cli_startup
CI runs unit and local-checkout integration tests on Windows, macOS, and Linux.
It also runs real Docker prepare/offline-test E2E, native arm64 CMake,
Make/configure, .NET, Composer/PHPUnit, and Ruby/Bundler boundary jobs, and the
cached-path performance contract. Native Apple container E2E is available
through the dedicated self-hosted workflow.
Release process
The tag-triggered release.yml workflow builds and smoke-tests the wheel and
sdist, records SHA-256 checksums and GitHub artifact attestations, and publishes
an independent GitHub release. PyPI publication runs only when the repository
variable PYPI_TRUSTED_PUBLISHING is exactly true and the pypi environment
is connected as a Trusted Publisher; it requires no long-lived publishing
token. A vX.Y.Z tag must exactly match the project version.
Before publishing, the workflow reruns tests, lint, the native Docker E2E, and
the performance contract. It builds with uv build --no-sources, smoke-tests
both the wheel and source distribution in isolated environments, writes
SHA-256 checksums, and transfers only that three-file release set to a separate
publish job. The source-running build job has read-only repository access and
no OIDC token; only the pypi environment job can attest, create a draft
GitHub release, and publish through PyPI Trusted Publishing. It rechecks the
transferred checksums and exposes the GitHub release only after the optional
PyPI step succeeds or is explicitly disabled. Release artifacts can then be
checked with:
gh attestation verify gh_freshclone-X.Y.Z-py3-none-any.whl \
--repo yhay81/gh-freshclone
See CHANGELOG.md for release contents.
Support
Use GitHub Issues for bug
reports and support. Successful checks, safe failures, performance
observations, and unsupported public repositories are welcome through the
structured Field report form; they are the product's zero-telemetry feedback
loop. Do not include access tokens, private repository content, or full logs
from private projects. Follow the
security policy
for vulnerability reports. See CONTRIBUTING.md for the
development gates and non-negotiable execution boundaries.
The support contact is
yusuke8h@gmail.com.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gh_freshclone-0.19.0.tar.gz.
File metadata
- Download URL: gh_freshclone-0.19.0.tar.gz
- Upload date:
- Size: 226.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a587a7059e377af5169805cf5bed7452412581a85d7d1e096e8145c5b76f261
|
|
| MD5 |
3f469c32c472a3fe34120a0b68e133a5
|
|
| BLAKE2b-256 |
e593005db29ae73390b37f162523506867d0b46683b7e47435a1985ab892dcb0
|
File details
Details for the file gh_freshclone-0.19.0-py3-none-any.whl.
File metadata
- Download URL: gh_freshclone-0.19.0-py3-none-any.whl
- Upload date:
- Size: 100.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cab82476bd125e1468846ddea7e7f3ff539227ca0269fcf690339490e8ecbc41
|
|
| MD5 |
330b368d6e58018815b5657b6e3153b0
|
|
| BLAKE2b-256 |
6548f1775a7a8ca14857fe27bb591bad810634d0f25b909096a7385f125a8a4a
|