An empty required repo identifier built a trailing-empty path segment
(`/api/v1/repos/{owner}/`) and leaked gitea's bare 404. parseArgs now
validates, via reflection, that `repo`/`name` string args are non-empty and
returns a typed ErrValidation naming the field. Optional identifiers (e.g.
code_search's owner-wide fan-out `repo`) opt out with `,omitempty`. `owner` is
already enforced by the allowlist check.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1.2 KiB
Go
33 lines
1.2 KiB
Go
package tools_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"gitea.d-ma.be/mathias/gitea-mcp/internal/allowlist"
|
|
"gitea.d-ma.be/mathias/gitea-mcp/internal/gitea"
|
|
"gitea.d-ma.be/mathias/gitea-mcp/internal/tools"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// #37: an empty required repo identifier must fail fast at the tool layer with a
|
|
// typed ErrValidation naming the field, rather than building a trailing-empty
|
|
// path segment (`/api/v1/repos/{owner}/`) that leaks gitea's bare 404.
|
|
func TestEmptyRepoRejectedAsValidation(t *testing.T) {
|
|
c := gitea.NewClient("http://unused", "")
|
|
a := allowlist.New([]string{"mathias"})
|
|
|
|
_, err := tools.NewRepoGet(c, a).Call(context.Background(), json.RawMessage(`{"owner":"mathias","repo":""}`))
|
|
require.Error(t, err)
|
|
assert.ErrorIs(t, err, gitea.ErrValidation)
|
|
assert.Contains(t, err.Error(), "repo")
|
|
|
|
// same for an empty `name` on a create tool (name = required new-repo name)
|
|
_, err = tools.NewRepoCreate(c, a).Call(context.Background(), json.RawMessage(`{"owner":"mathias","name":""}`))
|
|
require.Error(t, err)
|
|
assert.ErrorIs(t, err, gitea.ErrValidation)
|
|
assert.Contains(t, err.Error(), "name")
|
|
}
|