gitserver: Sunset Exec endpoint (#62774)

After we finally migrated all calls to Exec by proper API offerings,
we're finally not using this API anymore.
The previous PR deprecated this endpoint, and this one will fully remove
it. We can merge it early June when after the next release was cut.

As a result of this, gitserver no longer exposes a blanket exec endpoint
that could pose several risks from running dangerous commands to just
running commands that could cause resource exhaustion.

Closes https://github.com/sourcegraph/sourcegraph/issues/62099

Test plan:

This endpoint is unused, CI did not find any issues from removing it.
This commit is contained in:
Erik Seliger 2024-06-06 14:36:22 +02:00 committed by GitHub
parent 614375e538
commit 9183f528c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 687 additions and 2585 deletions

View File

@ -93,7 +93,7 @@ func (g *gitCLIBackend) NewCommand(ctx context.Context, optFns ...CommandOptionF
if !IsAllowedGitCmd(logger, opts.arguments) {
blockedCommandExecutedCounter.Inc()
return nil, ErrBadGitCommand
return nil, errBadGitCommand
}
if len(opts.arguments) == 0 {
@ -177,16 +177,16 @@ func (g *gitCLIBackend) NewCommand(ctx context.Context, optFns ...CommandOptionF
return cr, nil
}
// ErrBadGitCommand is returned from the git CLI backend if the arguments provided
// errBadGitCommand is returned from the git CLI backend if the arguments provided
// are not allowed.
var ErrBadGitCommand = errors.New("bad git command, not allowed")
var errBadGitCommand = errors.New("bad git command, not allowed")
func commandFailedError(ctx context.Context, err error, cmd wrexec.Cmder, stderr []byte) error {
func newCommandFailedError(ctx context.Context, err error, cmd wrexec.Cmder, stderr []byte) error {
if ctx.Err() != nil {
return ctx.Err()
}
return &CommandFailedError{
return &commandFailedError{
Inner: err,
args: cmd.Unwrap().Args,
Stderr: stderr,
@ -194,18 +194,18 @@ func commandFailedError(ctx context.Context, err error, cmd wrexec.Cmder, stderr
}
}
type CommandFailedError struct {
type commandFailedError struct {
Stderr []byte
ExitStatus int
Inner error
args []string
}
func (e *CommandFailedError) Unwrap() error {
func (e *commandFailedError) Unwrap() error {
return e.Inner
}
func (e *CommandFailedError) Error() string {
func (e *commandFailedError) Error() string {
return fmt.Sprintf("git command %v failed with status code %d (output: %q)", e.args, e.ExitStatus, e.Stderr)
}
@ -260,7 +260,7 @@ func (rc *cmdReader) waitCmd() error {
if checkMaybeCorruptRepo(rc.logger, rc.gitDir, rc.repoName, rc.stderr.String()) {
rc.err = common.ErrRepoCorrupted{Reason: rc.stderr.String()}
} else {
rc.err = commandFailedError(rc.ctx, rc.err, rc.cmd, rc.stderr.Bytes())
rc.err = newCommandFailedError(rc.ctx, rc.err, rc.cmd, rc.stderr.Bytes())
}
}

View File

@ -131,7 +131,7 @@ func (it *commitLogIterator) Next() (*git.GitCommitWithFiles, error) {
// If exit code is 128 and `fatal: bad object` is part of stderr, most likely we
// are referencing a commit that does not exist.
// We want to return a gitdomain.RevisionNotFoundError in that case.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 {
if (bytes.Contains(e.Stderr, []byte("fatal: your current branch")) && bytes.Contains(e.Stderr, []byte("does not have any commits yet"))) || bytes.Contains(e.Stderr, []byte("fatal: bad revision 'HEAD'")) {
return nil, io.EOF
@ -174,7 +174,7 @@ func (it *commitLogIterator) Next() (*git.GitCommitWithFiles, error) {
func (it *commitLogIterator) Close() error {
err := it.Closer.Close()
if err != nil {
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 {
if (bytes.Contains(e.Stderr, []byte("fatal: your current branch")) && bytes.Contains(e.Stderr, []byte("does not have any commits yet"))) || bytes.Contains(e.Stderr, []byte("fatal: bad revision 'HEAD'")) {
return nil

View File

@ -24,7 +24,7 @@ func (g *gitCLIBackend) Get(ctx context.Context, key string) (string, error) {
out, err := io.ReadAll(r)
if err != nil {
// Exit code 1 means the key is not set.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 1 {
return "", nil
}
@ -63,7 +63,7 @@ func (g *gitCLIBackend) Unset(ctx context.Context, key string) error {
_, err = io.Copy(io.Discard, r)
if err != nil {
// Exit code 5 means the key is not set.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 5 {
return nil
}

View File

@ -49,7 +49,7 @@ func (g *gitCLIBackend) ContributorCounts(ctx context.Context, opt git.Contribut
// If exit code is 128 and `fatal: bad object` is part of stderr, most likely we
// are referencing a range that does not exist.
// We want to return a gitdomain.RevisionNotFoundError in that case.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 && (bytes.Contains(e.Stderr, []byte("fatal: bad object")) ||
bytes.Contains(e.Stderr, []byte("fatal: bad revision"))) {
return nil, &gitdomain.RevisionNotFoundError{Repo: g.repoName, Spec: string(opt.Range)}

View File

@ -1,18 +1,12 @@
package gitcli
import (
"context"
"io"
"strconv"
"strings"
"github.com/sourcegraph/log"
)
func (g *gitCLIBackend) Exec(ctx context.Context, args ...string) (io.ReadCloser, error) {
return g.NewCommand(ctx, WithArguments(args...))
}
var (
// gitCmdAllowlist are commands and arguments that are allowed to execute and are
// checked by IsAllowedGitCmd

View File

@ -18,7 +18,7 @@ func (g *gitCLIBackend) SymbolicRefHead(ctx context.Context, short bool) (refNam
// TODO: implement refs_shorten_unambiguous_ref from git: https://sourcegraph.com/github.com/git/git/-/blob/refs.c?L1376,
// so QuickSymbolicRefHead can also be used when short=true.
if !short {
refName, err = QuickSymbolicRefHead(g.dir)
refName, err = quickSymbolicRefHead(g.dir)
if err == nil {
return refName, err
}
@ -46,7 +46,7 @@ func (g *gitCLIBackend) SymbolicRefHead(ctx context.Context, short bool) (refNam
}
func (g *gitCLIBackend) RevParseHead(ctx context.Context) (sha api.CommitID, err error) {
shaStr, err := QuickRevParseHead(g.dir)
shaStr, err := quickRevParseHead(g.dir)
if err == nil {
return api.CommitID(shaStr), nil
}
@ -78,9 +78,9 @@ func (g *gitCLIBackend) RevParseHead(ctx context.Context) (sha api.CommitID, err
const headFileRefPrefix = "ref: "
// QuickSymbolicRefHead best-effort mimics the execution of `git symbolic-ref HEAD`, but doesn't exec a child process.
// quickSymbolicRefHead best-effort mimics the execution of `git symbolic-ref HEAD`, but doesn't exec a child process.
// It just reads the .git/HEAD file from the bare git repository directory.
func QuickSymbolicRefHead(dir common.GitDir) (string, error) {
func quickSymbolicRefHead(dir common.GitDir) (string, error) {
// See if HEAD contains a commit hash and fail if so.
head, err := os.ReadFile(dir.Path("HEAD"))
if err != nil {
@ -99,9 +99,9 @@ func QuickSymbolicRefHead(dir common.GitDir) (string, error) {
return string(headRef), nil
}
// QuickRevParseHead best-effort mimics the execution of `git rev-parse HEAD`, but doesn't exec a child process.
// quickRevParseHead best-effort mimics the execution of `git rev-parse HEAD`, but doesn't exec a child process.
// It just reads the relevant files from the bare git repository directory.
func QuickRevParseHead(dir common.GitDir) (string, error) {
func quickRevParseHead(dir common.GitDir) (string, error) {
// See if HEAD contains a commit hash and return it if so.
head, err := os.ReadFile(dir.Path("HEAD"))
if err != nil {

View File

@ -129,14 +129,14 @@ func BenchmarkQuickRevParseHeadQuickSymbolicRefHead_packed_refs(b *testing.B) {
b.ResetTimer()
for range b.N {
rev, err := QuickRevParseHead(gitDir)
rev, err := quickRevParseHead(gitDir)
if err != nil {
b.Fatal(err)
}
if rev != masterRev {
b.Fatal("unexpected rev: ", rev)
}
ref, err := QuickSymbolicRefHead(gitDir)
ref, err := quickSymbolicRefHead(gitDir)
if err != nil {
b.Fatal(err)
}
@ -182,14 +182,14 @@ func BenchmarkQuickRevParseHeadQuickSymbolicRefHead_unpacked_refs(b *testing.B)
b.ResetTimer()
for range b.N {
rev, err := QuickRevParseHead(gitDir)
rev, err := quickRevParseHead(gitDir)
if err != nil {
b.Fatal(err)
}
if rev != masterRev {
b.Fatal("unexpected rev: ", rev)
}
ref, err := QuickSymbolicRefHead(gitDir)
ref, err := quickSymbolicRefHead(gitDir)
if err != nil {
b.Fatal(err)
}

View File

@ -24,7 +24,7 @@ func (g *gitCLIBackend) MergeBase(ctx context.Context, baseRevspec, headRevspec
stdout, err := io.ReadAll(out)
if err != nil {
// Exit code 1 and empty output most likely means that no common merge-base was found.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) {
if e.ExitStatus == 1 {
if len(e.Stderr) == 0 {

View File

@ -46,7 +46,7 @@ func (g *gitCLIBackend) getObjectType(ctx context.Context, objectID string) (git
stdout, err := io.ReadAll(r)
if err != nil {
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 && (bytes.Contains(e.Stderr, []byte("Not a valid object name")) ||
bytes.Contains(e.Stderr, []byte("git cat-file: could not get object info"))) {
return "", &gitdomain.RevisionNotFoundError{Repo: g.repoName, Spec: objectID}

View File

@ -50,7 +50,7 @@ func (g *gitCLIBackend) GetCommit(ctx context.Context, commit api.CommitID, incl
// If exit code is 128 and `fatal: bad object` is part of stderr, most likely we
// are referencing a commit that does not exist.
// We want to return a gitdomain.RevisionNotFoundError in that case.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 && bytes.Contains(e.Stderr, []byte("fatal: bad object")) {
return nil, &gitdomain.RevisionNotFoundError{Repo: g.repoName, Spec: string(commit)}
}
@ -175,7 +175,7 @@ func (g *gitCLIBackend) getBlobOID(ctx context.Context, commit api.CommitID, pat
// If exit code is 128 and `not a tree object` is part of stderr, most likely we
// are referencing a commit that does not exist.
// We want to return a gitdomain.RevisionNotFoundError in that case.
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 {
if bytes.Contains(e.Stderr, []byte("not a tree object")) || bytes.Contains(e.Stderr, []byte("Not a valid object name")) {
return "", &gitdomain.RevisionNotFoundError{Repo: g.repoName, Spec: string(commit)}
@ -225,7 +225,7 @@ func (g *gitCLIBackend) BehindAhead(ctx context.Context, left, right string) (*g
out, err := io.ReadAll(rc)
if err != nil {
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) {
switch {
case e.ExitStatus == 128 && bytes.Contains(e.Stderr, []byte("fatal: ambiguous argument")):
@ -262,7 +262,7 @@ func (g *gitCLIBackend) FirstEverCommit(ctx context.Context) (api.CommitID, erro
out, err := io.ReadAll(rc)
if err != nil {
var cmdFailedErr *CommandFailedError
var cmdFailedErr *commandFailedError
if errors.As(err, &cmdFailedErr) {
if cmdFailedErr.ExitStatus == 129 && bytes.Contains(cmdFailedErr.Stderr, []byte(revListUsageString)) {
// If the error is due to an empty repository, return a sentinel error.
@ -490,7 +490,7 @@ func (it *readDirIterator) Next() (fs.FileInfo, error) {
}
if err := it.sc.Err(); err != nil {
var cfe *CommandFailedError
var cfe *commandFailedError
if errors.As(err, &cfe) {
if bytes.Contains(cfe.Stderr, []byte("exists on disk, but not in")) {
return nil, &os.PathError{Op: "ls-tree", Path: filepath.ToSlash(it.path), Err: os.ErrNotExist}
@ -515,7 +515,7 @@ func (it *readDirIterator) Next() (fs.FileInfo, error) {
func (it *readDirIterator) Close() error {
if err := it.r.Close(); err != nil {
var cfe *CommandFailedError
var cfe *commandFailedError
if errors.As(err, &cfe) {
if bytes.Contains(cfe.Stderr, []byte("exists on disk, but not in")) {
return &os.PathError{Op: "ls-tree", Path: filepath.ToSlash(it.path), Err: os.ErrNotExist}

View File

@ -40,7 +40,7 @@ func (g *gitCLIBackend) revParse(ctx context.Context, spec string) (api.CommitID
stdout, err := io.ReadAll(r)
if err != nil {
var e *CommandFailedError
var e *commandFailedError
if errors.As(err, &e) && e.ExitStatus == 128 && (bytes.Contains(e.Stderr, []byte("bad revision")) ||
bytes.Contains(e.Stderr, []byte("unknown revision")) ||
bytes.Contains(e.Stderr, []byte("expected commit type"))) {

View File

@ -117,11 +117,6 @@ type GitBackend interface {
// Empty branches return an iterator that emits zero commits, not an error.
CommitLog(ctx context.Context, opt CommitLogOpts) (CommitLogIterator, error)
// Exec is a temporary helper to run arbitrary git commands from the exec endpoint.
// No new usages of it should be introduced and once the migration is done we will
// remove this method.
Exec(ctx context.Context, args ...string) (io.ReadCloser, error)
// FirstEverCommit returns the first commit ever made to the repository.
//
// If the repository is empty, a RevisionNotFoundError is returned (as the

View File

@ -570,9 +570,6 @@ type MockGitBackend struct {
// ContributorCountsFunc is an instance of a mock function object
// controlling the behavior of the method ContributorCounts.
ContributorCountsFunc *GitBackendContributorCountsFunc
// ExecFunc is an instance of a mock function object controlling the
// behavior of the method Exec.
ExecFunc *GitBackendExecFunc
// FirstEverCommitFunc is an instance of a mock function object
// controlling the behavior of the method FirstEverCommit.
FirstEverCommitFunc *GitBackendFirstEverCommitFunc
@ -659,11 +656,6 @@ func NewMockGitBackend() *MockGitBackend {
return
},
},
ExecFunc: &GitBackendExecFunc{
defaultHook: func(context.Context, ...string) (r0 io.ReadCloser, r1 error) {
return
},
},
FirstEverCommitFunc: &GitBackendFirstEverCommitFunc{
defaultHook: func(context.Context) (r0 api.CommitID, r1 error) {
return
@ -781,11 +773,6 @@ func NewStrictMockGitBackend() *MockGitBackend {
panic("unexpected invocation of MockGitBackend.ContributorCounts")
},
},
ExecFunc: &GitBackendExecFunc{
defaultHook: func(context.Context, ...string) (io.ReadCloser, error) {
panic("unexpected invocation of MockGitBackend.Exec")
},
},
FirstEverCommitFunc: &GitBackendFirstEverCommitFunc{
defaultHook: func(context.Context) (api.CommitID, error) {
panic("unexpected invocation of MockGitBackend.FirstEverCommit")
@ -889,9 +876,6 @@ func NewMockGitBackendFrom(i GitBackend) *MockGitBackend {
ContributorCountsFunc: &GitBackendContributorCountsFunc{
defaultHook: i.ContributorCounts,
},
ExecFunc: &GitBackendExecFunc{
defaultHook: i.Exec,
},
FirstEverCommitFunc: &GitBackendFirstEverCommitFunc{
defaultHook: i.FirstEverCommit,
},
@ -1704,120 +1688,6 @@ func (c GitBackendContributorCountsFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}
// GitBackendExecFunc describes the behavior when the Exec method of the
// parent MockGitBackend instance is invoked.
type GitBackendExecFunc struct {
defaultHook func(context.Context, ...string) (io.ReadCloser, error)
hooks []func(context.Context, ...string) (io.ReadCloser, error)
history []GitBackendExecFuncCall
mutex sync.Mutex
}
// Exec delegates to the next hook function in the queue and stores the
// parameter and result values of this invocation.
func (m *MockGitBackend) Exec(v0 context.Context, v1 ...string) (io.ReadCloser, error) {
r0, r1 := m.ExecFunc.nextHook()(v0, v1...)
m.ExecFunc.appendCall(GitBackendExecFuncCall{v0, v1, r0, r1})
return r0, r1
}
// SetDefaultHook sets function that is called when the Exec method of the
// parent MockGitBackend instance is invoked and the hook queue is empty.
func (f *GitBackendExecFunc) SetDefaultHook(hook func(context.Context, ...string) (io.ReadCloser, error)) {
f.defaultHook = hook
}
// PushHook adds a function to the end of hook queue. Each invocation of the
// Exec method of the parent MockGitBackend instance invokes the hook at the
// front of the queue and discards it. After the queue is empty, the default
// hook function is invoked for any future action.
func (f *GitBackendExecFunc) PushHook(hook func(context.Context, ...string) (io.ReadCloser, error)) {
f.mutex.Lock()
f.hooks = append(f.hooks, hook)
f.mutex.Unlock()
}
// SetDefaultReturn calls SetDefaultHook with a function that returns the
// given values.
func (f *GitBackendExecFunc) SetDefaultReturn(r0 io.ReadCloser, r1 error) {
f.SetDefaultHook(func(context.Context, ...string) (io.ReadCloser, error) {
return r0, r1
})
}
// PushReturn calls PushHook with a function that returns the given values.
func (f *GitBackendExecFunc) PushReturn(r0 io.ReadCloser, r1 error) {
f.PushHook(func(context.Context, ...string) (io.ReadCloser, error) {
return r0, r1
})
}
func (f *GitBackendExecFunc) nextHook() func(context.Context, ...string) (io.ReadCloser, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
if len(f.hooks) == 0 {
return f.defaultHook
}
hook := f.hooks[0]
f.hooks = f.hooks[1:]
return hook
}
func (f *GitBackendExecFunc) appendCall(r0 GitBackendExecFuncCall) {
f.mutex.Lock()
f.history = append(f.history, r0)
f.mutex.Unlock()
}
// History returns a sequence of GitBackendExecFuncCall objects describing
// the invocations of this function.
func (f *GitBackendExecFunc) History() []GitBackendExecFuncCall {
f.mutex.Lock()
history := make([]GitBackendExecFuncCall, len(f.history))
copy(history, f.history)
f.mutex.Unlock()
return history
}
// GitBackendExecFuncCall is an object that describes an invocation of
// method Exec on an instance of MockGitBackend.
type GitBackendExecFuncCall struct {
// Arg0 is the value of the 1st argument passed to this method
// invocation.
Arg0 context.Context
// Arg1 is a slice containing the values of the variadic arguments
// passed to this method invocation.
Arg1 []string
// Result0 is the value of the 1st result returned from this method
// invocation.
Result0 io.ReadCloser
// Result1 is the value of the 2nd result returned from this method
// invocation.
Result1 error
}
// Args returns an interface slice containing the arguments of this
// invocation. The variadic slice argument is flattened in this array such
// that one positional argument and three variadic arguments would result in
// a slice of four, not two.
func (c GitBackendExecFuncCall) Args() []interface{} {
trailing := []interface{}{}
for _, val := range c.Arg1 {
trailing = append(trailing, val)
}
return append([]interface{}{c.Arg0}, trailing...)
}
// Results returns an interface slice containing the results of this
// invocation.
func (c GitBackendExecFuncCall) Results() []interface{} {
return []interface{}{c.Result0, c.Result1}
}
// GitBackendFirstEverCommitFunc describes the behavior when the
// FirstEverCommit method of the parent MockGitBackend instance is invoked.
type GitBackendFirstEverCommitFunc struct {

View File

@ -210,30 +210,6 @@ func (b *observableBackend) ReadFile(ctx context.Context, commit api.CommitID, p
}, nil
}
func (b *observableBackend) Exec(ctx context.Context, args ...string) (_ io.ReadCloser, err error) {
ctx, errCollector, endObservation := b.operations.exec.WithErrors(ctx, &err, observation.Args{})
ctx, cancel := context.WithCancel(ctx)
endObservation.OnCancel(ctx, 1, observation.Args{})
concurrentOps.WithLabelValues("Exec").Inc()
r, err := b.backend.Exec(ctx, args...)
if err != nil {
concurrentOps.WithLabelValues("Exec").Dec()
cancel()
return nil, err
}
return &observableReadCloser{
inner: r,
endObservation: func(err error) {
concurrentOps.WithLabelValues("Exec").Dec()
errCollector.Collect(&err)
cancel()
},
}, nil
}
func (b *observableBackend) ArchiveReader(ctx context.Context, format ArchiveFormat, treeish string, paths []string) (_ io.ReadCloser, err error) {
ctx, errCollector, endObservation := b.operations.archiveReader.WithErrors(ctx, &err, observation.Args{})
ctx, cancel := context.WithCancel(ctx)
@ -545,7 +521,6 @@ type operations struct {
symbolicRefHead *observation.Operation
revParseHead *observation.Operation
readFile *observation.Operation
exec *observation.Operation
getCommit *observation.Operation
archiveReader *observation.Operation
resolveRevision *observation.Operation
@ -598,7 +573,6 @@ func newOperations(observationCtx *observation.Context) *operations {
symbolicRefHead: op("symbolic-ref-head"),
revParseHead: op("rev-parse-head"),
readFile: op("read-file"),
exec: op("exec"),
getCommit: op("get-commit"),
archiveReader: op("archive-reader"),
resolveRevision: op("resolve-revision"),

View File

@ -5,7 +5,6 @@ import (
"fmt"
"io"
"os"
"strings"
"time"
"go.opentelemetry.io/otel/attribute"
@ -16,7 +15,6 @@ import (
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/accesslog"
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/git"
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/git/gitcli"
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/gitserverfs"
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/perforce"
"github.com/sourcegraph/sourcegraph/internal/api"
@ -135,110 +133,6 @@ func (gs *grpcServer) DiskInfo(_ context.Context, _ *proto.DiskInfoRequest) (*pr
}, nil
}
func (gs *grpcServer) Exec(req *proto.ExecRequest, ss proto.GitserverService_ExecServer) error {
ctx := ss.Context()
// Log which actor is accessing the repo.
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
args := byteSlicesToStrings(req.GetArgs())
logAttrs := []log.Field{}
if len(args) > 0 {
logAttrs = append(logAttrs,
log.String("cmd", args[0]),
log.Strings("args", args[1:]),
)
}
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
accesslog.Record(ctx, req.GetRepo(), logAttrs...)
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
if req.GetRepo() == "" {
return status.New(codes.InvalidArgument, "repo must be specified").Err()
}
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
repoName := api.RepoName(req.GetRepo())
repoDir := gs.fs.RepoDir(repoName)
backend := gs.gitBackendSource(repoDir, repoName)
if err := gs.checkRepoExists(ctx, repoName); err != nil {
return err
}
w := streamio.NewWriter(func(p []byte) error {
return ss.Send(&proto.ExecResponse{
Data: p,
})
})
// Special-case `git rev-parse HEAD` requests. These are invoked by search queries for every repo in scope.
// For searches over large repo sets (> 1k), this leads to too many child process execs, which can lead
// to a persistent failure mode where every exec takes > 10s, which is disastrous for gitserver performance.
if len(args) == 2 && args[0] == "rev-parse" && args[1] == "HEAD" {
if resolved, err := gitcli.QuickRevParseHead(repoDir); err == nil && gitdomain.IsAbsoluteRevision(resolved) {
_, _ = w.Write([]byte(resolved))
return nil
}
}
// Special-case `git symbolic-ref HEAD` requests. These are invoked by resolvers determining the default branch of a repo.
// For searches over large repo sets (> 1k), this leads to too many child process execs, which can lead
// to a persistent failure mode where every exec takes > 10s, which is disastrous for gitserver performance.
if len(args) == 2 && args[0] == "symbolic-ref" && args[1] == "HEAD" {
if resolved, err := gitcli.QuickSymbolicRefHead(repoDir); err == nil {
_, _ = w.Write([]byte(resolved))
return nil
}
}
stdout, err := backend.Exec(ctx, args...)
if err != nil {
if errors.Is(err, gitcli.ErrBadGitCommand) {
return status.New(codes.InvalidArgument, "invalid command").Err()
}
if ctxErr := ctx.Err(); ctxErr != nil {
return status.FromContextError(ctxErr).Err()
}
return err
}
defer stdout.Close()
_, err = io.Copy(w, stdout)
if err != nil {
if ctxErr := ctx.Err(); ctxErr != nil {
return status.FromContextError(ctxErr).Err()
}
commandFailedErr := &gitcli.CommandFailedError{}
if errors.As(err, &commandFailedErr) {
gRPCStatus := codes.Unknown
if strings.Contains(commandFailedErr.Error(), "signal: killed") {
gRPCStatus = codes.Aborted
}
var errString string
if commandFailedErr.Unwrap() != nil {
errString = commandFailedErr.Unwrap().Error()
}
s, err := status.New(gRPCStatus, errString).WithDetails(&proto.ExecStatusPayload{
StatusCode: int32(commandFailedErr.ExitStatus),
Stderr: string(commandFailedErr.Stderr),
})
if err != nil {
gs.logger.Error("failed to marshal status", log.Error(err))
return err
}
return s.Err()
}
gs.svc.LogIfCorrupt(ctx, repoName, err)
return err
}
return nil
}
func (gs *grpcServer) Archive(req *proto.ArchiveRequest, ss proto.GitserverService_ArchiveServer) error {
ctx := ss.Context()

View File

@ -150,38 +150,6 @@ func (l *loggingGRPCServer) DiskInfo(ctx context.Context, request *proto.DiskInf
return l.base.DiskInfo(ctx, request)
}
func (l *loggingGRPCServer) Exec(request *proto.ExecRequest, server proto.GitserverService_ExecServer) (err error) {
start := time.Now()
defer func() {
elapsed := time.Since(start)
doLog(
l.logger,
proto.GitserverService_Exec_FullMethodName,
status.Code(err),
trace.Context(server.Context()).TraceID,
elapsed,
execRequestToLogFields(request)...)
}()
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
return l.base.Exec(request, server)
}
func execRequestToLogFields(req *proto.ExecRequest) []log.Field {
return []log.Field{
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
log.String("repo", req.GetRepo()),
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
log.String("ensureRevision", string(req.GetEnsureRevision())),
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
log.Strings("args", byteSlicesToStrings(req.GetArgs())),
// 🚨SECURITY: We don't log the stdin field because it could 1) contain sensitive data 2) be very large.
}
}
func (l *loggingGRPCServer) GetObject(ctx context.Context, request *proto.GetObjectRequest) (response *proto.GetObjectResponse, err error) {
start := time.Now()

View File

@ -1,14 +1,12 @@
package internal
import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/sourcegraph/sourcegraph/internal/actor"
@ -18,8 +16,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/time/rate"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/sourcegraph/log/logtest"
@ -29,13 +25,10 @@ import (
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/gitserverfs"
"github.com/sourcegraph/sourcegraph/cmd/gitserver/internal/vcssyncer"
"github.com/sourcegraph/sourcegraph/internal/api"
"github.com/sourcegraph/sourcegraph/internal/conf"
"github.com/sourcegraph/sourcegraph/internal/database"
"github.com/sourcegraph/sourcegraph/internal/database/dbmocks"
"github.com/sourcegraph/sourcegraph/internal/database/dbtest"
"github.com/sourcegraph/sourcegraph/internal/gitserver"
"github.com/sourcegraph/sourcegraph/internal/gitserver/connection"
v1 "github.com/sourcegraph/sourcegraph/internal/gitserver/v1"
"github.com/sourcegraph/sourcegraph/internal/limiter"
"github.com/sourcegraph/sourcegraph/internal/observation"
"github.com/sourcegraph/sourcegraph/internal/ratelimit"
@ -45,204 +38,6 @@ import (
"github.com/sourcegraph/sourcegraph/lib/errors"
)
type Test struct {
Name string
Request *v1.ExecRequest
ExpectedCode codes.Code
ExpectedBody string
ExpectedError string
ExpectedDetails []any
}
func TestExecRequest(t *testing.T) {
conf.Mock(&conf.Unified{})
t.Cleanup(func() { conf.Mock(nil) })
tests := []Test{
{
Name: "Command",
Request: &v1.ExecRequest{
Repo: "github.com/gorilla/mux",
Args: [][]byte{[]byte("diff-tree")},
},
ExpectedCode: codes.Unknown,
ExpectedBody: "teststdout",
ExpectedError: "teststderr",
ExpectedDetails: []any{&v1.ExecStatusPayload{
StatusCode: 42,
Stderr: "teststderr",
}},
},
{
Name: "Error",
Request: &v1.ExecRequest{
Repo: "github.com/gorilla/mux",
Args: [][]byte{[]byte("merge-base")},
},
ExpectedCode: codes.Unknown,
ExpectedError: "testerror",
ExpectedDetails: []any{&v1.ExecStatusPayload{
StatusCode: 1,
Stderr: "teststderr",
}},
},
{
Name: "EmptyInput",
Request: &v1.ExecRequest{
Repo: "github.com/gorilla/mux",
},
ExpectedCode: codes.InvalidArgument,
ExpectedError: "invalid command",
},
{
Name: "BadCommand",
Request: &v1.ExecRequest{
Repo: "github.com/gorilla/mux",
Args: [][]byte{[]byte("invalid-command")},
},
ExpectedCode: codes.InvalidArgument,
ExpectedError: "invalid command",
},
}
getRemoteURLFunc := func(ctx context.Context, name api.RepoName) (string, error) {
return "https://" + string(name) + ".git", nil
}
db := dbmocks.NewMockDB()
gr := dbmocks.NewMockGitserverRepoStore()
db.GitserverReposFunc.SetDefaultReturn(gr)
fs := gitserverfs.NewMockFSFrom(gitserverfs.New(&observation.TestContext, t.TempDir()))
require.NoError(t, fs.Initialize())
s := NewServer(&ServerOpts{
Logger: logtest.Scoped(t),
FS: fs,
GitBackendSource: func(dir common.GitDir, repoName api.RepoName) git.GitBackend {
backend := git.NewMockGitBackend()
backend.ExecFunc.SetDefaultHook(func(ctx context.Context, args ...string) (io.ReadCloser, error) {
if !gitcli.IsAllowedGitCmd(logtest.Scoped(t), args) {
return nil, gitcli.ErrBadGitCommand
}
switch args[0] {
case "diff-tree":
var stdout bytes.Buffer
stdout.Write([]byte("teststdout"))
return &errorReader{
ReadCloser: io.NopCloser(&stdout),
err: &gitcli.CommandFailedError{
Stderr: []byte("teststderr"),
ExitStatus: 42,
Inner: errors.New("teststderr"),
},
}, nil
case "merge-base":
return &errorReader{
ReadCloser: io.NopCloser(&bytes.Buffer{}),
err: &gitcli.CommandFailedError{
Stderr: []byte("teststderr"),
ExitStatus: 1,
Inner: errors.New("testerror"),
},
}, nil
}
return io.NopCloser(&bytes.Buffer{}), nil
})
return backend
},
GetRemoteURLFunc: getRemoteURLFunc,
GetVCSSyncer: func(ctx context.Context, name api.RepoName) (vcssyncer.VCSSyncer, error) {
getRemoteURLSource := func(ctx context.Context, name api.RepoName) (vcssyncer.RemoteURLSource, error) {
return vcssyncer.RemoteURLSourceFunc(func(ctx context.Context) (*vcs.URL, error) {
raw := "https://" + string(name) + ".git"
u, err := vcs.ParseURL(raw)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse URL %q", raw)
}
return u, nil
}), nil
}
return vcssyncer.NewGitRepoSyncer(logtest.Scoped(t), wrexec.NewNoOpRecordingCommandFactory(), getRemoteURLSource), nil
},
DB: db,
RecordingCommandFactory: wrexec.NewNoOpRecordingCommandFactory(),
Locker: NewRepositoryLocker(),
RPSLimiter: ratelimit.NewInstrumentedLimiter("GitserverTest", rate.NewLimiter(rate.Inf, 10)),
})
gs := NewGRPCServer(s, &GRPCServerConfig{
ExhaustiveRequestLoggingEnabled: true,
})
fs.RepoClonedFunc.SetDefaultHook(func(repo api.RepoName) (bool, error) {
if repo == "github.com/gorilla/mux" || repo == "my-mux" {
return true, nil
}
err := s.cloneRepo(context.Background(), repo, NewMockRepositoryLock())
require.NoError(t, err)
return false, nil
})
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
ss := gitserver.NewMockGitserverService_ExecServer()
ss.ContextFunc.SetDefaultReturn(context.Background())
var receivedData []byte
ss.SendFunc.SetDefaultHook(func(er *v1.ExecResponse) error {
receivedData = append(receivedData, er.GetData()...)
return nil
})
err := gs.Exec(test.Request, ss)
if test.ExpectedCode == codes.OK && err != nil {
t.Fatal(err)
}
if test.ExpectedCode != codes.OK {
if err == nil {
t.Fatal("expected error to be returned")
}
s, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, test.ExpectedCode, s.Code(), "wrong error code: expected %v, got %v %v", test.ExpectedCode, s.Code(), err)
if len(test.ExpectedDetails) > 0 {
if diff := cmp.Diff(test.ExpectedDetails, s.Details(), cmpopts.IgnoreUnexported(v1.ExecStatusPayload{}, v1.RepoNotFoundPayload{})); diff != "" {
t.Fatalf("unexpected error details (-want +got):\n%s", diff)
}
}
if strings.TrimSpace(s.Message()) != test.ExpectedError {
t.Errorf("wrong error body: expected %q, got %q", test.ExpectedError, s.Message())
}
}
if strings.TrimSpace(string(receivedData)) != test.ExpectedBody {
t.Errorf("wrong body: expected %q, got %q", test.ExpectedBody, string(receivedData))
}
})
}
}
type errorReader struct {
io.ReadCloser
err error
}
func (ec *errorReader) Read(p []byte) (int, error) {
n, err := ec.ReadCloser.Read(p)
if err == nil {
return n, nil
}
if err == io.EOF {
return n, ec.err
}
return n, err
}
// makeSingleCommitRepo make create a new repo with a single commit and returns
// the HEAD SHA
func makeSingleCommitRepo(cmd func(string, ...string) string) string {

View File

@ -32,13 +32,6 @@ func convertGRPCErrorToGitDomainError(err error) error {
for _, detail := range st.Details() {
switch payload := detail.(type) {
case *proto.ExecStatusPayload:
return &CommandStatusError{
Message: st.Message(),
Stderr: payload.GetStderr(),
StatusCode: payload.GetStatusCode(),
}
case *proto.RepoNotFoundPayload:
return &gitdomain.RepoNotExistError{
Repo: api.RepoName(payload.GetRepo()),
@ -105,24 +98,6 @@ func (r *errorTranslatingCreateCommitFromPatchBinaryClient) CloseAndRecv() (*pro
return res, convertGRPCErrorToGitDomainError(err)
}
func (r *errorTranslatingClient) Exec(ctx context.Context, in *proto.ExecRequest, opts ...grpc.CallOption) (proto.GitserverService_ExecClient, error) {
//lint:ignore SA1019 existing usage of deprecated functionality. We are just logging an existing field.
cc, err := r.base.Exec(ctx, in, opts...)
if err != nil {
return nil, convertGRPCErrorToGitDomainError(err)
}
return &errorTranslatingExecClient{cc}, nil
}
type errorTranslatingExecClient struct {
proto.GitserverService_ExecClient
}
func (r *errorTranslatingExecClient) Recv() (*proto.ExecResponse, error) {
res, err := r.GitserverService_ExecClient.Recv()
return res, convertGRPCErrorToGitDomainError(err)
}
func (r *errorTranslatingClient) DiskInfo(ctx context.Context, in *proto.DiskInfoRequest, opts ...grpc.CallOption) (*proto.DiskInfoResponse, error) {
res, err := r.base.DiskInfo(ctx, in, opts...)
return res, convertGRPCErrorToGitDomainError(err)

File diff suppressed because it is too large Load Diff

View File

@ -30,16 +30,6 @@ func (r *automaticRetryClient) CreateCommitFromPatchBinary(ctx context.Context,
// Idempotent methods.
func (r *automaticRetryClient) Exec(ctx context.Context, in *proto.ExecRequest, opts ...grpc.CallOption) (proto.GitserverService_ExecClient, error) {
// We specify the specific raw git commands that we allow in internal/gitserver/gitdomain/exec.go.
// For all of these commands, we know that they are either:
//
// - 1. non-destructive (making them safe to retry)
// - 2. not used in Exec directly, but instead only via a specific RPC (like CreateCommitFromPatchBinary) where the caller is responsible for retrying.
opts = append(defaults.RetryPolicy, opts...)
return r.base.Exec(ctx, in, opts...)
}
func (r *automaticRetryClient) DiskInfo(ctx context.Context, in *proto.DiskInfoRequest, opts ...grpc.CallOption) (*proto.DiskInfoResponse, error) {
opts = append(defaults.RetryPolicy, opts...)
return r.base.DiskInfo(ctx, in, opts...)

File diff suppressed because it is too large Load Diff

View File

@ -77,10 +77,6 @@ service GitserverService {
rpc DiskInfo(DiskInfoRequest) returns (DiskInfoResponse) {
option idempotency_level = NO_SIDE_EFFECTS;
}
rpc Exec(ExecRequest) returns (stream ExecResponse) {
option deprecated = true;
}
// GetObject returns the object with the given OID in the given repository.
//
// If the object is not found, an error with a RevisionNotFoundPayload is
@ -815,18 +811,6 @@ message CreateCommitFromPatchBinaryResponse {
string changelist_id = 3;
}
message ExecRequest {
string repo = 1 [deprecated = true];
bytes ensure_revision = 2 [deprecated = true];
repeated bytes args = 3 [deprecated = true];
bytes stdin = 4 [deprecated = true];
bool no_timeout = 5 [deprecated = true];
}
message ExecResponse {
bytes data = 1 [deprecated = true];
}
message RepoNotFoundPayload {
string repo = 1;
bool clone_in_progress = 2;
@ -844,11 +828,6 @@ message FileNotFoundPayload {
bytes path = 3;
}
message ExecStatusPayload {
int32 status_code = 1;
string stderr = 2;
}
message SearchRequest {
// repo is the name of the repo to be searched
string repo = 1;

View File

@ -196,7 +196,6 @@ var GitserverRepositoryService_ServiceDesc = grpc.ServiceDesc{
const (
GitserverService_CreateCommitFromPatchBinary_FullMethodName = "/gitserver.v1.GitserverService/CreateCommitFromPatchBinary"
GitserverService_DiskInfo_FullMethodName = "/gitserver.v1.GitserverService/DiskInfo"
GitserverService_Exec_FullMethodName = "/gitserver.v1.GitserverService/Exec"
GitserverService_GetObject_FullMethodName = "/gitserver.v1.GitserverService/GetObject"
GitserverService_IsRepoCloneable_FullMethodName = "/gitserver.v1.GitserverService/IsRepoCloneable"
GitserverService_ListGitolite_FullMethodName = "/gitserver.v1.GitserverService/ListGitolite"
@ -235,8 +234,6 @@ const (
type GitserverServiceClient interface {
CreateCommitFromPatchBinary(ctx context.Context, opts ...grpc.CallOption) (GitserverService_CreateCommitFromPatchBinaryClient, error)
DiskInfo(ctx context.Context, in *DiskInfoRequest, opts ...grpc.CallOption) (*DiskInfoResponse, error)
// Deprecated: Do not use.
Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (GitserverService_ExecClient, error)
// GetObject returns the object with the given OID in the given repository.
//
// If the object is not found, an error with a RevisionNotFoundPayload is
@ -495,39 +492,6 @@ func (c *gitserverServiceClient) DiskInfo(ctx context.Context, in *DiskInfoReque
return out, nil
}
// Deprecated: Do not use.
func (c *gitserverServiceClient) Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (GitserverService_ExecClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[1], GitserverService_Exec_FullMethodName, opts...)
if err != nil {
return nil, err
}
x := &gitserverServiceExecClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type GitserverService_ExecClient interface {
Recv() (*ExecResponse, error)
grpc.ClientStream
}
type gitserverServiceExecClient struct {
grpc.ClientStream
}
func (x *gitserverServiceExecClient) Recv() (*ExecResponse, error) {
m := new(ExecResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *gitserverServiceClient) GetObject(ctx context.Context, in *GetObjectRequest, opts ...grpc.CallOption) (*GetObjectResponse, error) {
out := new(GetObjectResponse)
err := c.cc.Invoke(ctx, GitserverService_GetObject_FullMethodName, in, out, opts...)
@ -556,7 +520,7 @@ func (c *gitserverServiceClient) ListGitolite(ctx context.Context, in *ListGitol
}
func (c *gitserverServiceClient) Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (GitserverService_SearchClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[2], GitserverService_Search_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[1], GitserverService_Search_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -588,7 +552,7 @@ func (x *gitserverServiceSearchClient) Recv() (*SearchResponse, error) {
}
func (c *gitserverServiceClient) Archive(ctx context.Context, in *ArchiveRequest, opts ...grpc.CallOption) (GitserverService_ArchiveClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[3], GitserverService_Archive_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[2], GitserverService_Archive_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -710,7 +674,7 @@ func (c *gitserverServiceClient) MergeBase(ctx context.Context, in *MergeBaseReq
}
func (c *gitserverServiceClient) Blame(ctx context.Context, in *BlameRequest, opts ...grpc.CallOption) (GitserverService_BlameClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[4], GitserverService_Blame_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[3], GitserverService_Blame_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -751,7 +715,7 @@ func (c *gitserverServiceClient) DefaultBranch(ctx context.Context, in *DefaultB
}
func (c *gitserverServiceClient) ReadFile(ctx context.Context, in *ReadFileRequest, opts ...grpc.CallOption) (GitserverService_ReadFileClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[5], GitserverService_ReadFile_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[4], GitserverService_ReadFile_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -801,7 +765,7 @@ func (c *gitserverServiceClient) ResolveRevision(ctx context.Context, in *Resolv
}
func (c *gitserverServiceClient) ListRefs(ctx context.Context, in *ListRefsRequest, opts ...grpc.CallOption) (GitserverService_ListRefsClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[6], GitserverService_ListRefs_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[5], GitserverService_ListRefs_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -842,7 +806,7 @@ func (c *gitserverServiceClient) RevAtTime(ctx context.Context, in *RevAtTimeReq
}
func (c *gitserverServiceClient) RawDiff(ctx context.Context, in *RawDiffRequest, opts ...grpc.CallOption) (GitserverService_RawDiffClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[7], GitserverService_RawDiff_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[6], GitserverService_RawDiff_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -901,7 +865,7 @@ func (c *gitserverServiceClient) BehindAhead(ctx context.Context, in *BehindAhea
}
func (c *gitserverServiceClient) ChangedFiles(ctx context.Context, in *ChangedFilesRequest, opts ...grpc.CallOption) (GitserverService_ChangedFilesClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[8], GitserverService_ChangedFiles_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[7], GitserverService_ChangedFiles_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -942,7 +906,7 @@ func (c *gitserverServiceClient) Stat(ctx context.Context, in *StatRequest, opts
}
func (c *gitserverServiceClient) ReadDir(ctx context.Context, in *ReadDirRequest, opts ...grpc.CallOption) (GitserverService_ReadDirClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[9], GitserverService_ReadDir_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[8], GitserverService_ReadDir_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -974,7 +938,7 @@ func (x *gitserverServiceReadDirClient) Recv() (*ReadDirResponse, error) {
}
func (c *gitserverServiceClient) CommitLog(ctx context.Context, in *CommitLogRequest, opts ...grpc.CallOption) (GitserverService_CommitLogClient, error) {
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[10], GitserverService_CommitLog_FullMethodName, opts...)
stream, err := c.cc.NewStream(ctx, &GitserverService_ServiceDesc.Streams[9], GitserverService_CommitLog_FullMethodName, opts...)
if err != nil {
return nil, err
}
@ -1011,8 +975,6 @@ func (x *gitserverServiceCommitLogClient) Recv() (*CommitLogResponse, error) {
type GitserverServiceServer interface {
CreateCommitFromPatchBinary(GitserverService_CreateCommitFromPatchBinaryServer) error
DiskInfo(context.Context, *DiskInfoRequest) (*DiskInfoResponse, error)
// Deprecated: Do not use.
Exec(*ExecRequest, GitserverService_ExecServer) error
// GetObject returns the object with the given OID in the given repository.
//
// If the object is not found, an error with a RevisionNotFoundPayload is
@ -1231,9 +1193,6 @@ func (UnimplementedGitserverServiceServer) CreateCommitFromPatchBinary(Gitserver
func (UnimplementedGitserverServiceServer) DiskInfo(context.Context, *DiskInfoRequest) (*DiskInfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DiskInfo not implemented")
}
func (UnimplementedGitserverServiceServer) Exec(*ExecRequest, GitserverService_ExecServer) error {
return status.Errorf(codes.Unimplemented, "method Exec not implemented")
}
func (UnimplementedGitserverServiceServer) GetObject(context.Context, *GetObjectRequest) (*GetObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetObject not implemented")
}
@ -1381,27 +1340,6 @@ func _GitserverService_DiskInfo_Handler(srv interface{}, ctx context.Context, de
return interceptor(ctx, in, info, handler)
}
func _GitserverService_Exec_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(ExecRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(GitserverServiceServer).Exec(m, &gitserverServiceExecServer{stream})
}
type GitserverService_ExecServer interface {
Send(*ExecResponse) error
grpc.ServerStream
}
type gitserverServiceExecServer struct {
grpc.ServerStream
}
func (x *gitserverServiceExecServer) Send(m *ExecResponse) error {
return x.ServerStream.SendMsg(m)
}
func _GitserverService_GetObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetObjectRequest)
if err := dec(in); err != nil {
@ -2071,11 +2009,6 @@ var GitserverService_ServiceDesc = grpc.ServiceDesc{
Handler: _GitserverService_CreateCommitFromPatchBinary_Handler,
ClientStreams: true,
},
{
StreamName: "Exec",
Handler: _GitserverService_Exec_Handler,
ServerStreams: true,
},
{
StreamName: "Search",
Handler: _GitserverService_Search_Handler,

View File

@ -135,7 +135,6 @@
path: github.com/sourcegraph/sourcegraph/internal/gitserver/v1
interfaces:
- GitserverServiceClient
- GitserverService_ExecServer
- GitserverService_ArchiveServer
- GitserverService_ArchiveClient
- GitserverService_BlameServer