Repository navigation
feat(release): five-minute container quickstart via GHCR image - #61
Merged
Merged
Conversation
…er paths Two pre-existing bugs surfaced while verifying the suite in this environment: - repository_path_error silently accepted drive-letter paths like 'C:/evil.rs': Path::components treats them as normal components on Unix even though they are absolute on Windows. Reject them in the shared validator (admission scope, evidence v3, solver paths, RunWorkspace::resolve). - Spawned workspace commands could leave a __pycache__ behind; a solver rewrite landing in the same mtime second with the same byte length made timestamp+size invalidation treat stale bytecode as valid, so a later check observed pre-fix code (the v7 e2e python fixture flake). Commands now run with PYTHONDONTWRITEBYTECODE=1 so no bytecode cache can be written into the workspace between legs. Also bumps rustls 0.23.43 -> 0.23.45 (RUSTSEC-2026-0285) so the cargo-audit pre-commit hook passes.
A maintainer can now evaluate ContribAI end to end with only a container
runtime — no Rust toolchain, no config, no token, no writes:
docker run --rm ghcr.io/tang-vu/contribai:latest demo
- release.yml gains an image job after release: builds the locked
Dockerfile, smoke-tests the exact image with the same --version and
demo --json assertions the binaries get, pushes :<tag> and :latest to
GHCR, and attests the pushed digest. Job permissions are
least-privilege and actions stay SHA-pinned.
- .dockerignore keeps the build context to the locked workspace inputs.
- README leads Quick start with the zero-install path; QUICKSTART,
RELEASING, and the deployment guide document it and the one-time
owner step (make the GHCR package public).
- New CLI tests pin the read-only defaults: contribute needs --submit,
patrol needs --respond, and --dry-run parses independently.
- _typos.toml allowlists 'ratatui' so the existing typos hook stops
rewriting the crate name in docs.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The v7 e2e tests drive a real 'python -m pytest' red-to-green leg in the run workspace, but runner images do not ship the pytest module, so both legs exit non-zero and the run ends failed on all three OSes. Install it into the python on PATH (user site, with --break-system-packages only as the PEP 668 fallback for the ubuntu image). This is the pre-existing main CI failure.
Windows env names are case-insensitive and reported as e.g. 'Path', so an exact-match allowlist dropped PATH (and any mixed-case var) from spawned command environments there. Match case-insensitively and insert under the canonical allowlist spelling so the child always sees PATH. Caught by the windows CI leg's secrets_are_scrubbed_from_environment.
Match the CI fixture prerequisite in every release build job so the Python lifecycle tests can finish before the GHCR image job starts. Guard bootstrap ordering in the existing installer contract and document why pytest is required. Verified: missing-pytest lifecycle fails, installed-pytest lifecycle passes; 838 workspace tests pass (1 ignored doc test), release build, conformance, demo, formatting, installer contracts and negative mutations. Rust 1.88 Clippy reproduces the 290 unchanged baseline diagnostics. AI-assisted by OpenAI Codex. No release dispatch or package publication.
tang-vu
added a commit
that referenced
this pull request
Oct 5, 2026
Keep tree-sitter 0.26.11 and tree-sitter-language 0.1.7 because the proposed 0.27.0 and 0.1.8 releases require Rust 1.90. Preserve the other 13 grouped dependency updates. Verified Rust 1.88 locked all-target check, Rust 1.99 formatting and strict Clippy, release build, conformance, and 833 tests excluding the pre-existing path validation failure addressed in #61. AI-assisted implementation and verification; maintainer review remains required.
tang-vu
added a commit
that referenced
this pull request
Oct 7, 2026
Integrate main cea4725 while retaining the 13 dependency updates and Rust 1.88-compatible tree-sitter 0.26.11. Preserve main's PATH, path validation, bytecode, pytest prerequisite, and rustls security fixes. The resulting tree matches the independently reviewed local #61+#64 integration. Stable fmt, all-targets clippy, release build, and offline conformance passed locally; two Python e2e fixtures remain blocked by missing local pytest. Hosted CI must validate this exact branch head. AI-assisted by OpenAI Codex.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A maintainer can now evaluate ContribAI end-to-end in ~5 minutes with only a container runtime — no Rust toolchain, no config file, no GitHub token, no LLM key, and zero writes:
The
democommand exercises the real production pipeline offline (consent → permit → admission → evidence → protected-path fail-closed probe → human-review gate → no submission), so the 5-minute path demos the safety model, not a stripped-down toy.What changed
.github/workflows/release.yml— newimagejob afterrelease: builds the existing lockedDockerfile, smoke-tests the exact pushed image with the same--versionanddemo --jsonassertions the release binaries get (external_writes_enabled==false,submission=="not_attempted",candidate.evidence_valid,protected_path_probe.admission_allowed==false), pushes:<tag>+:latesttoghcr.io/tang-vu/contribai, and attests the pushed digest via the already-pinnedactions/attest. Least-privilege job permissions (contents: read,packages: write,id-token,attestations); plaindockerCLI so no new third-party actions.README.md/docs/QUICKSTART.md/docs/RELEASING.md/docs/deployment-guide.md— the quickstart now leads with thedocker runpath; RELEASING documents the new job and the one-time owner step (see below)..dockerignore(new) — build context trimmed to the locked workspace inputs the Dockerfile actually COPYs._typos.toml(new) — allowlistsratatui; the existing typos hook otherwise rewrites the crate name to "Ratatouille" in any commit touching the README.crates/contribai-rs/src/cli/mod.rs— three tests pinning the read-only CLI defaults:contributehassubmit:false,patrolhasrespond:false,--dry-runparses without--submit.crates/contribai-rs/src/exec/runner.rs— spawned workspace commands run withPYTHONDONTWRITEBYTECODE=1; the env allowlist now matches case-insensitively.crates/contribai-rs/src/core/admission.rs—repository_path_errornow rejects drive-letter paths (C:/...,d:...)..github/workflows/ci.yml— theTestjob installs pytest into the runner'spythonbeforecargo test(--user, with--break-system-packagesas the PEP 668 fallback for the ubuntu image).Cargo.lock—rustls 0.23.43→0.23.45,rustls-webpki 0.103.13→0.103.15(RUSTSEC-2026-0285).Pre-existing issues fixed along the way (main CI was red)
Every
CIrun onmainhas been failing: all threeTestjobs plusRustSec audit. Root causes found while verifying this branch — all fixed here, and this PR's CI is fully green:python -m pytestred-to-green leg, but runner images don't ship the module, so the run endedfailedon all three OSes. The new ci.yml step installs it.__pycache__that CPython's timestamp+size invalidation treats as valid, so a later check could observe pre-fix code. It failed closed (spurious repair — not a safety bypass).BoundedRunnernow setsPYTHONDONTWRITEBYTECODE=1for every spawned command; a regression test assertspytestruns leave no__pycache__.scrub_environmentmatched the allowlist case-sensitively, but Windows reportsPath, so spawned commands got no PATH on Windows. The allowlist match is now case-insensitive and inserts the canonical spelling.repository_path_errorletC:/evil.rsthrough becausePath::componentssees normal components on non-Windows hosts — silent acceptance in the shared validator used by admission scope, evidence v3, solver paths, andRunWorkspace::resolve. Now rejected; the existing traversal test that asserted this passes on Linux.cargo audit/ the RustSec job pass.What I did NOT change
--submit/--respond), permit binding, protected paths, fail-closed checks, human review, draft-PR-only, MCP read-only — all untouched.demostays offline.Owner action required (one-time)
After the next tagged release, the first GHCR push creates a private package. Set the
contribaipackage visibility to public once (Package settings under the owner's GitHub profile →ghcr.io/tang-vu/contribai→ Package settings → Change visibility), or external users can't pull. The Dockerfile'sorg.opencontainers.image.sourcelabel already links the package to this repo.Verification
cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings: cleancargo test --workspace --locked: 839 passed, 0 failedcargo build --workspace --release: cleannode scripts/check-installers.mjs,node scripts/check-site.mjs,node --check site/app.js: passdocker build+docker run ... --version+demo --jsonassertions + fulldemooutput: PASS locallyAI-assisted (Devin); the reviewer should confirm the workflow permissions and the GHCR visibility step.
Link to Devin session: https://app.devin.ai/sessions/868648d1623d4933b5da68d5ee560e02
Open in Devin Desktop: https://app.devin.ai/desktop/session/868648d1623d4933b5da68d5ee560e02?variant=devin
Requested by: @tang-vu