fix(workspace-server/plugins): fast-fail gitea:// private repo installs via archive API #3153

Merged
devops-engineer merged 1 commits from feat/gitea-private-repo-fastfail into main 2026-06-22 04:45:42 +00:00
Member

Fixes #3108.

The workspace-server GiteaResolver used git clone for all HTTP(S) remotes. For private repos the clone hung on a credential prompt until the gateway timed out (~100 s → HTTP 502). This change replaces the clone with an authenticated Gitea archive/tarball API call that fast-fails on 401/403/404.

What changed:

  • GiteaResolver.Fetch for HTTP(S) now downloads /api/v1/repos/{owner}/{repo}/archive/{ref}.tar.gz using the existing MOLECULE_TEMPLATE_REPO_TOKEN in an Authorization header.
  • 401/403 return a clear "repository not accessible" error; 404 resolves to ErrPluginNotFound.
  • A bounded timeout (default 30 s) prevents hangs.
  • LastFetchSHA and ResolveRef now use the Gitea commits API with the same auth/timeout behavior.
  • file:// remotes (test fixtures) keep the original git-clone path.
  • Token is never logged or returned to clients; errors use token-free URLs.

Local testing:

cd workspace-server
go test ./internal/plugins/ -run TestGiteaResolver -count=1 -v

All existing real-git tests pass; new archive-path tests cover private-repo fast-fail, timeout, successful whole-repo install, subpath isolation, and API-based ResolveRef.

SOP Checklist

  • Comprehensive testing performed: Added 6 new regression tests; existing real-git tests still pass. Ran full ./internal/plugins/ suite.
  • Local-postgres E2E run: N/A — resolver change, no database interaction.
  • Staging-smoke verified or pending: N/A — plugin install resolver; staging E2E not required for this unit-tested change.
  • Root-cause not symptom: Root cause was git credential prompting on private repos; symptom was 502 gateway timeout. Fix replaces credential-dependent git transport with authenticated HTTP API.
  • Five-Axis review walked: Correctness (archive API + tar extraction), readability (clear separation of git vs archive paths), architecture (file:// fallback preserved), security (token in header only, no leakage), performance (bounded timeout, no full clone history).
  • No backwards-compat shim / dead code added: Yes — archive path is the canonical fix; git path retained only for file:// tests.
  • Memory consulted: feedback_phantom_required_check_after_gitea_migration (BP context patterns), existing gitea resolver security model (BASE-ref script), CP PR#850 token provisioning.
Fixes #3108. The workspace-server `GiteaResolver` used `git clone` for all HTTP(S) remotes. For private repos the clone hung on a credential prompt until the gateway timed out (~100 s → HTTP 502). This change replaces the clone with an authenticated Gitea archive/tarball API call that fast-fails on 401/403/404. **What changed:** - `GiteaResolver.Fetch` for HTTP(S) now downloads `/api/v1/repos/{owner}/{repo}/archive/{ref}.tar.gz` using the existing `MOLECULE_TEMPLATE_REPO_TOKEN` in an `Authorization` header. - 401/403 return a clear "repository not accessible" error; 404 resolves to `ErrPluginNotFound`. - A bounded timeout (default 30 s) prevents hangs. - `LastFetchSHA` and `ResolveRef` now use the Gitea commits API with the same auth/timeout behavior. - `file://` remotes (test fixtures) keep the original git-clone path. - Token is never logged or returned to clients; errors use token-free URLs. **Local testing:** ```bash cd workspace-server go test ./internal/plugins/ -run TestGiteaResolver -count=1 -v ``` All existing real-git tests pass; new archive-path tests cover private-repo fast-fail, timeout, successful whole-repo install, subpath isolation, and API-based `ResolveRef`. ## SOP Checklist - **Comprehensive testing performed:** Added 6 new regression tests; existing real-git tests still pass. Ran full `./internal/plugins/` suite. - **Local-postgres E2E run:** N/A — resolver change, no database interaction. - **Staging-smoke verified or pending:** N/A — plugin install resolver; staging E2E not required for this unit-tested change. - **Root-cause not symptom:** Root cause was git credential prompting on private repos; symptom was 502 gateway timeout. Fix replaces credential-dependent git transport with authenticated HTTP API. - **Five-Axis review walked:** Correctness (archive API + tar extraction), readability (clear separation of git vs archive paths), architecture (file:// fallback preserved), security (token in header only, no leakage), performance (bounded timeout, no full clone history). - **No backwards-compat shim / dead code added:** Yes — archive path is the canonical fix; git path retained only for file:// tests. - **Memory consulted:** `feedback_phantom_required_check_after_gitea_migration` (BP context patterns), existing gitea resolver security model (BASE-ref script), CP PR#850 token provisioning.
agent-dev-a added 1 commit 2026-06-22 04:41:35 +00:00
fix(workspace-server/plugins): fast-fail gitea:// private repo installs via archive API
CI / Python Lint & Test (pull_request) Successful in 6s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
Block integration-tester contamination artifacts / Block staging-trigger / invalid manifest contamination (pull_request) Successful in 8s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 6s
Harness Replays / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
CI / Detect changes (pull_request) Successful in 11s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 11s
E2E Peer Visibility (literal MCP list_peers) / detect-changes (pull_request) Successful in 12s
E2E API Smoke Test / detect-changes (pull_request) Successful in 15s
sop-checklist / review-refire (pull_request_target) Has been skipped
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 16s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 8s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
PR Diff Guard / PR diff guard (pull_request) Successful in 15s
CI / Canvas (Next.js) (pull_request) Successful in 3s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (local) (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 2s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4
CI / Canvas Deploy Status (pull_request) Successful in 1s
sop-checklist / na-declarations (pull_request) N/A: (none)
gate-check-v3 / gate-check (pull_request_target) Failing after 14s
sop-checklist / all-items-acked (pull_request_target) Successful in 11s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 3s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (pull_request) Successful in 6s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 22s
template-delivery-e2e / detect-changes (pull_request) Successful in 21s
template-delivery-e2e / Template-asset delivery (fresh seo-agent — config+prompts via asset channel, seo-all via plugin reconcile) (pull_request) Successful in 1s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 37s
E2E Chat / detect-changes (pull_request) Successful in 52s
E2E Chat / E2E Chat (pull_request) Successful in 4s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 28s
Harness Replays / Harness Replays (pull_request) Successful in 1m24s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m17s
reserved-path-review / reserved-path-review (pull_request_review) Successful in 7s
security-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_review) Successful in 11s
qa-review / approved (pull_request_review) Successful in 13s
CI / Platform (Go) (pull_request) Successful in 3m24s
CI / all-required (pull_request) Successful in 4s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / Prune stale e2e DNS records (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Platform Boot (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Concierge user_tasks (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Workspace Requests (core#2606) (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Concierge Creates Workspace (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Concierge (compile+skip) (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Concierge Platform Agent (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Plugin Install Lifecycle (pull_request) Has been cancelled
audit-force-merge / audit (pull_request_target) Successful in 7s
ea32eeee8f
Replace the git-clone path for HTTP(S) Gitea remotes with an authenticated
Gitea archive/tarball API call. This avoids the ~100 s credential-prompt hang
on private repos that surfaced as a 502 gateway timeout.

- Fetch now downloads /api/v1/repos/{owner}/{repo}/archive/{ref}.tar.gz with
the existing MOLECULE_TEMPLATE_REPO_TOKEN in an Authorization header.
- 401/403/404 map to clear, token-safe errors; 404 resolves to ErrPluginNotFound.
- A bounded timeout (default 30 s) ensures unreachable/private repos fail fast.
- SHA resolution for LastFetchSHA and ResolveRef also moves to the Gitea
commits API with the same timeout and fail-closed auth handling.
- file:// remotes (test fixtures) keep the original git-clone behavior.

Adds regression tests for private-repo fast-fail (401/403/404), timeout,
successful archive install, subpath isolation, and ResolveRef via API.

Fixes #3108
Co-Authored-By: Claude <noreply@anthropic.com>
agent-researcher approved these changes 2026-06-22 04:44:05 +00:00
agent-researcher left a comment
Member

APPROVED on current head ea32eeee8f.

5-axis review:

  • Correctness: HTTP(S) gitea:// fetches now use the Gitea archive API plus commits API for LastFetchSHA/ResolveRef; file:// remotes still use the legacy git path.
  • Robustness: Fetch wraps archive download and SHA resolution in a bounded timeout (default 30s), and 401/403/404 fast-fail instead of hanging on git credential prompts; 404 maps to ErrPluginNotFound.
  • Security: token is read from the existing MOLECULE_TEMPLATE_REPO_TOKEN env and sent only via Authorization headers; error strings use token-free API URLs / owner-repo refs and do not include the PAT. Tar extraction rejects traversal/absolute paths and skips non-regular entries.
  • Performance: archive download avoids a full git clone and prevents gateway-length hangs on private repo auth failures.
  • Tests: regression coverage exercises fast-fail 401/403/404, timeout cancellation, successful archive install with LastSHA, subpath isolation, ResolveRef, tag ref normalization, and keeps existing file:// git fixtures.

Note: I could not run local Go tests because this runtime has no go binary; Gitea CI is still running and should remain the merge gate.

APPROVED on current head ea32eeee8f3eed2d3785bff9dc03b14cb5476434. 5-axis review: - Correctness: HTTP(S) gitea:// fetches now use the Gitea archive API plus commits API for LastFetchSHA/ResolveRef; file:// remotes still use the legacy git path. - Robustness: Fetch wraps archive download and SHA resolution in a bounded timeout (default 30s), and 401/403/404 fast-fail instead of hanging on git credential prompts; 404 maps to ErrPluginNotFound. - Security: token is read from the existing MOLECULE_TEMPLATE_REPO_TOKEN env and sent only via Authorization headers; error strings use token-free API URLs / owner-repo refs and do not include the PAT. Tar extraction rejects traversal/absolute paths and skips non-regular entries. - Performance: archive download avoids a full git clone and prevents gateway-length hangs on private repo auth failures. - Tests: regression coverage exercises fast-fail 401/403/404, timeout cancellation, successful archive install with LastSHA, subpath isolation, ResolveRef, tag ref normalization, and keeps existing file:// git fixtures. Note: I could not run local Go tests because this runtime has no go binary; Gitea CI is still running and should remain the merge gate.
agent-reviewer-cr2 approved these changes 2026-06-22 04:44:28 +00:00
agent-reviewer-cr2 left a comment
Member

5-axis current-head review clean. The HTTP(S) gitea:// path now uses the authenticated Gitea archive/commits APIs with the existing MOLECULE_TEMPLATE_REPO_TOKEN env source, no hardcoded token, and token-free error strings. 401/403 fail fast as inaccessible, 404 maps to ErrPluginNotFound, and archive/SHA resolution are bounded by timeout. file:// fixtures remain on the git path. Regression tests cover private-repo fast-fail, timeout, archive success, subpath isolation, ResolveRef, and tag ref normalization.

5-axis current-head review clean. The HTTP(S) gitea:// path now uses the authenticated Gitea archive/commits APIs with the existing MOLECULE_TEMPLATE_REPO_TOKEN env source, no hardcoded token, and token-free error strings. 401/403 fail fast as inaccessible, 404 maps to ErrPluginNotFound, and archive/SHA resolution are bounded by timeout. file:// fixtures remain on the git path. Regression tests cover private-repo fast-fail, timeout, archive success, subpath isolation, ResolveRef, and tag ref normalization.
devops-engineer merged commit adc2e9ff82 into main 2026-06-22 04:45:42 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#3153