Repository navigation
Conversation
…API, no .git (TIGER-364)
Phase 2 leads with the module's biggest risk: committing with no local git repo. Tiger_Git_Transport_Api
implements the commit path through the GitHub Git Data API:
1. read the branch head (ref) + its base tree
2. POST a blob per changed file (base64); a null-sha entry per deleted file
3. POST a new tree (on base_tree) then a new commit (parent = the old head)
4. fast-forward the branch ref (force:false) — a branch that moved under us is reported
NON_FAST_FORWARD, never clobbered
With the API transport there is no local index, so commit() writes to the remote in one flow and push()
is a verified no-op (committing IS pushing). Also implemented: branches(), createBranch() (refuses the
default branch). status/diff/switch/pull/tag/listReleases/fetchArchive throw NOT_IMPLEMENTED — the rest
of TIGER-364.
The HTTP layer is a seam (setHttp), the token is resolved per request via Tiger_Git_Credential (never
held), and every call is pinned to api.github.com. Errors map to stable, secret-free codes
(401->CREDENTIAL_INVALID, 403 rate->RATE_LIMITED, 404->INVALID_REF, 422 'fast forward'->NON_FAST_FORWARD).
Tests: 10 unit (29 across the Git suite) — the full four-step sequence + payloads asserted against canned
GitHub responses (no network), plus NON_FAST_FORWARD, missing-credential (no call made), nothing-to-commit,
empty-message, createBranch, branches, push no-op, and the NOT_IMPLEMENTED guards. CAPABILITIES.md regenerated.
Built on the Phase-1 substrate (PR #356); rebase onto main once that merges. A live-GitHub integration
test (real throwaway repo + token) is the Testing-column gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
The counterpart to ApiTransport, behind the same interface: git operations driven by the `git` binary over a real .git working tree, for a host that has git and can spawn a subprocess. Host-agnostic (works against any git remote, not just GitHub). Implemented: status (branch + porcelain changes + ahead/behind vs upstream), diff (numstat, size-capped), commit (stage -> -c author commit -> rev-parse; NOTHING_TO_COMMIT when empty), branches, createBranch (off HEAD, refuses the default), switchBranch (refuses a dirty tree -> DIRTY_TREE), push (origin, NO --force ever -> NON_FAST_FORWARD on rejection), pull (--ff-only), tag (annotated + pushed to origin). listReleases/fetchArchive are a provider-API concern (GitHub adapter routes them to ApiTransport) -> NOT_IMPLEMENTED. Safety, structural: git is invoked via proc_open with an ARGUMENT ARRAY (no shell string, no metacharacter interpretation); only a fixed subcommand set runs; every path is resolved under the module root first; ref/branch/tag names are validated (no leading '-', no '..'); a token is injected through an inline credential.helper that reads GIT_TOKEN from the ENV, so the secret is never in argv (ps-visible) nor written to .git/config. A command-runner seam (setRunner) allows stubbing. Tests: 12, proven END TO END against a real local repo + a bare file:// "remote", with a second clone used to force a genuine NON_FAST_FORWARD (push refused, never forced) and to verify push/tag actually reach the remote. Skipped where git is absent. Full Git suite 41 green; full unit suite 1172 green. CAPABILITIES.md regenerated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
|
Added ShellTransport (the git-binary path) on top of the ApiTransport commit spike. It implements far more of the interface (status/diff/commit/branches/createBranch/switchBranch/push/pull/tag), is host-agnostic, and is proven end-to-end against a real local repo + a bare |
…PI (TIGER-364) Tiger_Git_Provider_GitHub composes the two transports into one object a service uses without caring: it picks the WORKING transport for a connection (the git binary where the host allows it, the API otherwise) for the git ops, and ALWAYS routes the provider-API ops (listReleases/fetchArchive) to the API — because a GitHub release is not a git concept, so even a shell connection reaches it over the API. New Tiger_Git_Provider_Interface is the N-provider seam (GitLab/Bitbucket land later without touching the transports). Implements the two provider-API verbs on ApiTransport (their reason to exist): - listReleases() — newest first, drafts excluded. - fetchArchive() — GitHub's tarball 302 captured; the redirect host is confirmed against the allowlist before the CDN fetch, and our token is never forwarded to the signed codeload URL. send() now captures response headers for the capture. Remaining ApiTransport verbs (status/diff/switch/pull/tag over the API) stay NOT_IMPLEMENTED — the rest of TIGER-364. 10 new unit tests (routing proven with both seams; releases/archive incl. the 302 capture, host-allowlist refusal, bad-tag refusal). 68 Git, 1181 unit green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
|
GitHubAdapter landed (
Implemented the two provider-API verbs on
Still Tests: 10 new unit tests — routing proven with both seams (git-op→binary, api-op→API, release→API-even-on-shell), plus releases/archive incl. the 302 capture, the off-allowlist redirect refusal, and the bad-tag refusal. 68 Git, 1181 unit green; CAPABILITIES 244 classes. |
…ER-334) The TigerGit epic, landed as one squash of the reviewed stack (#356 foundation ← #357 transports+GitHubAdapter ← #358 services+UI+MCP+reconciler). Version a custom module in a private repo, cut a release through QA, and receive approved updates — with no local machine, no terminal, and (on shared hosting with exec disabled) no git binary. Two interchangeable transports (ShellTransport; ApiTransport with no .git), the GitHubAdapter that composes them, write-only encrypted credentials, an active-only-unique data model + audit log, the no-.git reconciler (status/diff/pull/switchBranch via a merge-base marker), the /api services (Repo/Release/Update; owner-only release capability, approved-only updates), an admin dashboard at /git/admin, and full MCP reach. Both live-GitHub gates passed (commit spike + reconciler) against real public and private repos. Ships as core 1.38.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
Epic TIGER-334 — Phase 2 (TIGER-364), the ApiTransport commit spike
Leads Phase 2 with the module's biggest technical risk: creating a commit with no local git repo. Proves
Tiger_Git_Transport_Api::commit()through the GitHub Git Data API:POSTa blob per changed file (base64); a null-sha entry per deleted filePOSTa new tree (onbase_tree) then a new commit (parent = the old head)force:false) — a branch that moved under us is reportedNON_FAST_FORWARD, never clobberedWith the API transport there's no local index, so
commit()writes straight to the remote branch in one flow andpush()is a verified no-op (committing is pushing). Also built:branches(),createBranch()(refuses the default branch).status/diff/switchBranch/pull/tag/listReleases/fetchArchivethrowNOT_IMPLEMENTED— the rest of TIGER-364.Safety / design
setHttp) → the whole flow is unit-tested against canned GitHub responses, no network.Tiger_Git_Credential(never held); every call pinned to api.github.com; redirects off.CREDENTIAL_INVALID, 403 rate→RATE_LIMITED, 404→INVALID_REF, 422 "fast forward"→NON_FAST_FORWARD.Tests
10 unit (29 across the Git suite): the four-step sequence and payloads asserted (blob = base64 file content; tree builds on
base_tree, deletion = null sha; commit parents the old head; ref updateforce:false), plusNON_FAST_FORWARD, missing-credential (no API call made), nothing-to-commit, empty-message,createBranch,branches, push no-op,NOT_IMPLEMENTED.Stacking + next
mainonce Tiger_Git Phase 1 foundation — interfaces, env detection, credentials, data model (TIGER-334) #356 merges.ShellTransport(git binary, host-agnostic), then the remaining ApiTransport verbs (status/diff/pull/tag/releases/archive).🤖 Generated with Claude Code
https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ