Skip to content

test(plugins): unblock TestResolveAndStage_NoInternalErrorsInHTTPErr (#1814) - #2166

Merged
HongmingWang-Rabbit merged 1 commit into
stagingfrom
test/unblock-resolveandstage-test
Apr 27, 2026
Merged

HongmingWang-Rabbit merged 1 commit into
stagingfrom
test/unblock-resolveandstage-test

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

Closes the second of two skipped tests in workspace_provision_test.go that were blocked on interface refactors. With this PR, both skipped tests called out by #1814 are unblocked and #1814 can close.

Bundled in this PR

Two tightly-coupled changes — the test cannot pass without the production fix; the production fix needs the interface to be exercised in tests:

1. Interface refactor (testability)

  • handlers.pluginSources interface with the 3 methods handler code calls: Register, Resolve, Schemes
  • Compile-time assertion var _ pluginSources = (*plugins.Registry)(nil) catches future method-signature drift at build time
  • PluginsHandler.sources narrowed from *plugins.Registry to the interface
  • Production wiring (NewPluginsHandler, WithSourceResolver) still passes *plugins.Registry, which satisfies the interface — zero behavior change

2. Production leak fix (#1206)

resolveAndStage's Fetch-failure path was interpolating err.Error() into the HTTP response body:

"error": fmt.Sprintf("failed to fetch plugin from %s: %v", source.Scheme, err)

Resolver errors routinely contain:

  • GitHub rate-limit text + request IDs (x-github-request-id=…)
  • Raw HTTP body fragments echoed by misbehaving upstreams
  • File-system paths from local-fs resolvers
  • Auth tokens IF an upstream echoed the request header

None has any business landing in a user's browser. Body now carries just failed to fetch plugin from <scheme>; the status code (404 / 504 / 502) already differentiates the failure shape. Full err detail stays in the server-side log.Printf one statement above.

Test

TestResolveAndStage_NoInternalErrorsInHTTPErr is now a 6-subtest table covering every error path inside resolveAndStage:

Path Source Status
empty source "" 400
invalid format "not a valid uri" 400
unknown scheme "weirdscheme://x" 400
local path-traversal "local://../etc/passwd" 400
unpinned github "github://owner/repo" 422
Fetch failure with leaky error "github://owner/repo#v1.0" 502

The Fetch-failure case plants 5 realistic leak markers in the synthetic resolver error: rate limit, x-github-request-id, auth_token, ghp_INTERNAL_DETAIL, /etc/passwd. The assertion fails if ANY appears in the response body. Each subtest checks status code + body-leak-marker scan independently.

Pre-fix the Fetch-failure subtest fails because the body contains all 5 markers verbatim. Post-fix it passes because the body is just "failed to fetch plugin from github".

Verification

  • ✓ 6/6 sub-tests pass
  • ✓ Full workspace-server go test ./... passes (interface refactor is non-breaking)
  • go build ./... clean

#1814 status after this lands

Both originally-skipped tests are unblocked:

🤖 Generated with Claude Code

…1814)

Closes the second of two skipped tests in workspace_provision_test.go
that were blocked on interface refactors. The Broadcaster + CP
provisioner halves landed in earlier #1814 cycles; this is the
plugin-source-registry half.

Refactor:
  - Add handlers.pluginSources interface with the 3 methods handler
    code actually calls (Register, Resolve, Schemes)
  - Compile-time assertion `var _ pluginSources = (*plugins.Registry)(nil)`
    catches future method-signature drift at build time
  - PluginsHandler.sources narrowed from *plugins.Registry to the
    interface; production wiring (NewPluginsHandler, WithSourceResolver)
    still passes *plugins.Registry — satisfies the interface

Production fix (#1206 leak):
  - resolveAndStage's Fetch-failure path was interpolating err.Error()
    into the HTTP response body via `failed to fetch plugin from %s: %v`.
    Resolver errors routinely contain rate-limit text, github request
    IDs, raw HTTP body fragments, and (for local resolvers) file system
    paths — none has any business landing in a user's browser.
  - Body now carries just `failed to fetch plugin from <scheme>`; the
    status code already differentiates the failure shape (404 not
    found, 504 timeout, 502 generic). Full err detail stays in the
    server-side log line one statement above.

Test:
  - 6 sub-tests covering every error path inside resolveAndStage:
    empty source, invalid format, unknown scheme, local
    path-traversal, unpinned github (PLUGIN_ALLOW_UNPINNED unset),
    Fetch failure with a leaky synthetic error
  - The Fetch-failure case plants 5 realistic leak markers in the
    resolver's error string (rate limit text, x-github-request-id,
    auth_token, ghp_-prefixed token, /etc/passwd path); the assertion
    fails if ANY appears in the response body
  - Table-driven so a future error path added to resolveAndStage gets
    one new row, not a copy-paste of the assertion logic

Verification:
  - 6/6 sub-tests pass
  - Full workspace-server test suite passes (interface refactor is
    non-breaking; production caller paths unchanged)
  - go build ./... clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@HongmingWang-Rabbit
HongmingWang-Rabbit added this pull request to the merge queue Apr 27, 2026
Merged via the queue into staging with commit 7cf77f2 Apr 27, 2026
15 checks passed
@molecule-ai
molecule-ai Bot deleted the test/unblock-resolveandstage-test branch May 20, 2026 06:22
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
…ivity + Delegation + A2A handlers (CHUNK 1 + CHUNK 2)' (#2166) from fix/2151-chunk1-activity-delegation-a2a-integration-tests into main
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
…tion tests (#2166 blocker #2)

**Step A — Go-level fail-closed**

Extract a shared `requireIntegrationDBURL(t)` helper into
`integration_helper_test.go` (build-tag: integration). The helper:
- Returns $INTEGRATION_DB_URL when present
- Calls `t.Fatalf` when the URL is empty AND any CI marker is set
  (`CI`, `GITHUB_ACTIONS`, or `GITEA_ACTIONS`), preventing a silent
  skip-to-green in CI
- Calls `t.Skip` when the URL is empty AND no CI marker is set,
  preserving the local-dev ergonomics

Update all three integration test files to use the shared helper:
- delegation_ledger_integration_test.go
- pending_uploads_integration_test.go
- workspace_create_name_integration_test.go

This closes the Go-level fail-open where a missing INTEGRATION_DB_URL
in CI would cause every integration test to skip and report PASS.

**Step C — Workflow bash preflight**

Add a `Preflight — INTEGRATION_DB_URL must be present` step in
`.gitea/workflows/handlers-postgres-integration.yml` immediately before
the `go test` invocation. If the postgres-start step failed to export
the variable, the preflight exits 1 with `::error::` so the job fails
loud before the test binary can even start.

**Step B — Workflow CoE mask**

ALREADY FIXED in current main: both `detect-changes` and `integration`
jobs have `continue-on-error: false` (lines 93 and 125). The context is
already listed in `audit-force-merge.yml` REQUIRED_CHECKS_JSON for
`main`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant