As we reevaluate how to best support and maintain Staging Ref in the future, we encourage development teams using this environment to highlight their use cases in the following issue: https://gitlab.com/gitlab-com/gl-infra/software-delivery/framework/software-delivery-framework-issue-tracker/-/issues/36.

Skip to content
Snippets Groups Projects
Commit e638fdaa authored by Archish's avatar Archish
Browse files

Merge branch 'main' of gitlab.com:gitlab-community/gitlab-shell into 789-personalaccesstoken-lint

parents a014db05 c2d73ce0
No related branches found
No related tags found
No related merge requests found
Showing
with 218 additions and 148 deletions
ruby 3.3.4
golang 1.23.0
ruby 3.3.5
golang 1.23.1
// Package command handles command creation and initialization in GitLab Shell.
package command
import (
Loading
Loading
@@ -9,6 +10,7 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
)
// New creates a new command based on provided arguments, config, and I/O.
func New(arguments []string, config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
args, err := Parse(arguments)
if err != nil {
Loading
Loading
@@ -22,6 +24,7 @@ func New(arguments []string, config *config.Config, readWriter *readwriter.ReadW
return nil, disallowedcommand.Error
}
// Parse parses command-line arguments into a CommandArgs structure.
func Parse(arguments []string) (*commandargs.AuthorizedPrincipals, error) {
args := &commandargs.AuthorizedPrincipals{Arguments: arguments}
Loading
Loading
// Package main is the entry point for the GitLab Shell authorized principals check command.
package main
import (
Loading
Loading
@@ -21,6 +22,10 @@ var (
)
func main() {
os.Exit(run())
}
func run() int {
command.CheckForVersionFlag(os.Args, Version, BuildTime)
readWriter := &readwriter.ReadWriter{
Loading
Loading
@@ -31,32 +36,33 @@ func main() {
executable, err := executable.New(executable.AuthorizedPrincipalsCheck)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
_, _ = fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
return 1
}
config, err := config.NewFromDirExternal(executable.RootDir)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to read config, exiting")
os.Exit(1)
_, _ = fmt.Fprintln(readWriter.ErrOut, "Failed to read config, exiting")
return 1
}
logCloser := logger.Configure(config)
defer logCloser.Close()
defer logCloser.Close() //nolint:errcheck
cmd, err := cmd.New(os.Args[1:], config, readWriter)
if err != nil {
// For now this could happen if `SSH_CONNECTION` is not set on
// the environment
fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
os.Exit(1)
_, _ = fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
return 1
}
ctx, finished := command.Setup(executable.Name, config)
defer finished()
if ctx, err = cmd.Execute(ctx); err != nil {
if _, err = cmd.Execute(ctx); err != nil {
console.DisplayWarningMessage(err.Error(), readWriter.ErrOut)
os.Exit(1)
return 1
}
return 0
}
// Package main is the entry point for the GitLab Shell health check command.
package main
import (
Loading
Loading
@@ -20,6 +21,10 @@ var (
)
func main() {
os.Exit(run())
}
func run() int {
command.CheckForVersionFlag(os.Args, Version, BuildTime)
readWriter := &readwriter.ReadWriter{
Loading
Loading
@@ -28,32 +33,38 @@ func main() {
ErrOut: os.Stderr,
}
exitOnError := func(err error, message string) int {
if err != nil {
_, _ = fmt.Fprintf(readWriter.ErrOut, "%s: %v\n", message, err)
return 1
}
return 0
}
executable, err := executable.New(executable.Healthcheck)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
if code := exitOnError(err, "Failed to determine executable, exiting"); code != 0 {
return code
}
config, err := config.NewFromDirExternal(executable.RootDir)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to read config, exiting")
os.Exit(1)
if code := exitOnError(err, "Failed to read config, exiting"); code != 0 {
return code
}
logCloser := logger.Configure(config)
defer logCloser.Close()
defer logCloser.Close() //nolint:errcheck
cmd, err := checkCmd.New(config, readWriter)
if err != nil {
fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
os.Exit(1)
if code := exitOnError(err, "Failed to create command"); code != 0 {
return code
}
ctx, finished := command.Setup(executable.Name, config)
defer finished()
if ctx, err = cmd.Execute(ctx); err != nil {
fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
os.Exit(1)
if _, err = cmd.Execute(ctx); err != nil {
_, _ = fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
return 1
}
return 0
}
Loading
Loading
@@ -15,14 +15,14 @@ require (
github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b
github.com/otiai10/copy v1.14.0
github.com/pires/go-proxyproto v0.7.0
github.com/prometheus/client_golang v1.20.2
github.com/prometheus/client_golang v1.20.3
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
gitlab.com/gitlab-org/gitaly/v16 v16.11.8
gitlab.com/gitlab-org/labkit v1.21.0
golang.org/x/crypto v0.26.0
golang.org/x/crypto v0.27.0
golang.org/x/sync v0.8.0
google.golang.org/grpc v1.65.0
google.golang.org/grpc v1.66.0
google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v3 v3.0.1
)
Loading
Loading
@@ -98,15 +98,15 @@ require (
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/api v0.169.0 // indirect
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
gopkg.in/DataDog/dd-trace-go.v1 v1.32.0 // indirect
)
Loading
Loading
Loading
Loading
@@ -324,8 +324,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
Loading
Loading
@@ -422,8 +422,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Loading
Loading
@@ -587,11 +587,11 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Loading
Loading
@@ -600,8 +600,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Loading
Loading
@@ -759,10 +759,10 @@ google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKr
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s=
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
Loading
Loading
@@ -788,8 +788,8 @@ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
Loading
Loading
// Package authorizedkeys handles fetching and printing authorized SSH keys.
package authorizedkeys
import (
Loading
Loading
@@ -12,12 +13,14 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/keyline"
)
// Command contains the configuration, arguments, and I/O interfaces.
type Command struct {
Config *config.Config
Args *commandargs.AuthorizedKeys
ReadWriter *readwriter.ReadWriter
}
// Execute runs the command to fetch and print the authorized SSH key.
func (c *Command) Execute(ctx context.Context) (context.Context, error) {
// Do and return nothing when the expected and actual user don't match.
// This can happen when the user in sshd_config doesn't match the user
Loading
Loading
@@ -38,7 +41,7 @@ func (c *Command) Execute(ctx context.Context) (context.Context, error) {
func (c *Command) printKeyLine(ctx context.Context) error {
response, err := c.getAuthorizedKey(ctx)
if err != nil {
fmt.Fprintln(c.ReadWriter.Out, fmt.Sprintf("# No key was found for %s", c.Args.Key))
_, _ = fmt.Fprintf(c.ReadWriter.Out, "# No key was found for %s\n", c.Args.Key)
return nil
}
Loading
Loading
@@ -47,7 +50,7 @@ func (c *Command) printKeyLine(ctx context.Context) error {
return err
}
fmt.Fprintln(c.ReadWriter.Out, keyLine.ToString())
_, _ = fmt.Fprintln(c.ReadWriter.Out, keyLine.ToString())
return nil
}
Loading
Loading
// Package authorizedprincipals handles printing authorized principals in GitLab Shell.
package authorizedprincipals
import (
Loading
Loading
@@ -10,12 +11,14 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/keyline"
)
// Command contains the configuration, arguments, and I/O interfaces.
type Command struct {
Config *config.Config
Args *commandargs.AuthorizedPrincipals
ReadWriter *readwriter.ReadWriter
}
// Execute runs the command to print authorized principals.
func (c *Command) Execute(ctx context.Context) (context.Context, error) {
if err := c.printPrincipalLines(); err != nil {
return ctx, err
Loading
Loading
@@ -42,7 +45,7 @@ func (c *Command) printPrincipalLine(principal string) error {
return err
}
fmt.Fprintln(c.ReadWriter.Out, principalKeyLine.ToString())
_, _ = fmt.Fprintln(c.ReadWriter.Out, principalKeyLine.ToString())
return nil
}
// Package githttp provides functionality to handle Git operations over HTTP(S) and SSH,
// including executing Git commands like git-upload-pack and converting responses to the
// expected format for SSH protocols. It integrates with GitLab's internal components
// for secure access verification and data transfer.
package githttp
import (
"bytes"
"context"
"fmt"
"io"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/commandargs"
Loading
Loading
@@ -17,8 +19,9 @@ import (
const pullService = "git-upload-pack"
var uploadPackHttpPrefix = []byte("001e# service=git-upload-pack\n0000")
var uploadPackHTTPPrefix = []byte("001e# service=git-upload-pack\n0000")
// PullCommand handles the execution of a Git pull operation over HTTP(S) or SSH
type PullCommand struct {
Config *config.Config
ReadWriter *readwriter.ReadWriter
Loading
Loading
@@ -36,6 +39,12 @@ type PullCommand struct {
// 5. Perform /git-upload-pack request and send this data
// 6. Return the output to the user
// ForInfoRefs returns the necessary Pull specifics for client.InfoRefs()
func (c *PullCommand) ForInfoRefs() (*readwriter.ReadWriter, string, []byte) {
return c.ReadWriter, pullService, uploadPackHTTPPrefix
}
// Execute runs the pull command by determining the appropriate method (HTTP/SSH)
func (c *PullCommand) Execute(ctx context.Context) error {
data := c.Response.Payload.Data
client := &git.Client{URL: data.PrimaryRepo, Headers: data.RequestHeaders}
Loading
Loading
@@ -48,39 +57,19 @@ func (c *PullCommand) Execute(ctx context.Context) error {
return c.requestSSHUploadPack(ctx, client)
}
if err := c.requestInfoRefs(ctx, client); err != nil {
if err := requestInfoRefs(ctx, client, c); err != nil {
return err
}
return c.requestUploadPack(ctx, client, data.GeoProxyFetchDirectToPrimaryWithOptions)
}
func (c *PullCommand) requestInfoRefs(ctx context.Context, client *git.Client) error {
response, err := client.InfoRefs(ctx, pullService)
if err != nil {
return err
}
defer response.Body.Close()
// Read the first bytes that contain 001e# service=git-upload-pack\n0000 string
// to convert HTTP(S) Git response to the one expected by SSH
p := make([]byte, len(uploadPackHttpPrefix))
_, err = response.Body.Read(p)
if err != nil || !bytes.Equal(p, uploadPackHttpPrefix) {
return fmt.Errorf("Unexpected git-upload-pack response")
}
_, err = io.Copy(c.ReadWriter.Out, response.Body)
return err
}
func (c *PullCommand) requestSSHUploadPack(ctx context.Context, client *git.Client) error {
response, err := client.SSHUploadPack(ctx, io.NopCloser(c.ReadWriter.In))
if err != nil {
return err
}
defer response.Body.Close()
defer response.Body.Close() //nolint:errcheck
_, err = io.Copy(c.ReadWriter.Out, response.Body)
Loading
Loading
@@ -95,7 +84,7 @@ func (c *PullCommand) requestUploadPack(ctx context.Context, client *git.Client,
if err != nil {
return err
}
defer response.Body.Close()
defer response.Body.Close() //nolint:errcheck
_, err = io.Copy(c.ReadWriter.Out, response.Body)
Loading
Loading
@@ -108,18 +97,27 @@ func (c *PullCommand) readFromStdin(pw *io.PipeWriter, geoProxyFetchDirectToPrim
for scanner.Scan() {
line := scanner.Bytes()
pw.Write(line)
_, err := pw.Write(line)
if err != nil {
log.WithError(err).Error("failed to write line")
}
if pktline.IsDone(line) {
break
}
if pktline.IsFlush(line) && geoProxyFetchDirectToPrimaryWithOptions {
pw.Write(pktline.PktDone())
_, err := pw.Write(pktline.PktDone())
if err != nil {
log.WithError(err).Error("failed to write packet done line")
}
break
}
}
pw.Close()
err := pw.Close()
if err != nil {
log.WithError(err).Error("failed to close writer")
}
}
Loading
Loading
@@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
Loading
Loading
@@ -104,7 +105,7 @@ func TestPullExecuteWithFailedInfoRefs(t *testing.T) {
desc: "unexpected response",
statusCode: http.StatusOK,
responseContent: "unexpected response",
expectedErr: "Unexpected git-upload-pack response",
expectedErr: "unexpected git-upload-pack response",
},
}
Loading
Loading
@@ -114,7 +115,7 @@ func TestPullExecuteWithFailedInfoRefs(t *testing.T) {
{
Path: "/info/refs",
Handler: func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "git-upload-pack", r.URL.Query().Get("service"))
assert.Equal(t, "git-upload-pack", r.URL.Query().Get("service"))
w.WriteHeader(tc.statusCode)
w.Write([]byte(tc.responseContent))
Loading
Loading
@@ -167,7 +168,7 @@ func setupPull(t *testing.T, uploadPackStatusCode int) string {
{
Path: "/info/refs",
Handler: func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "git-upload-pack", r.URL.Query().Get("service"))
assert.Equal(t, "git-upload-pack", r.URL.Query().Get("service"))
w.Write([]byte(infoRefs))
},
Loading
Loading
@@ -176,10 +177,10 @@ func setupPull(t *testing.T, uploadPackStatusCode int) string {
Path: "/git-upload-pack",
Handler: func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.NoError(t, err)
defer r.Body.Close()
require.True(t, strings.HasSuffix(string(body), "0009done\n"))
assert.True(t, strings.HasSuffix(string(body), "0009done\n"))
w.WriteHeader(uploadPackStatusCode)
},
Loading
Loading
@@ -195,12 +196,12 @@ func setupSSHPull(t *testing.T, uploadPackStatusCode int) string {
Path: "/ssh-upload-pack",
Handler: func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.NoError(t, err)
defer r.Body.Close()
require.True(t, strings.HasSuffix(string(body), "0009done\n"))
require.Equal(t, "version=2", r.Header.Get("Git-Protocol"))
require.Equal(t, "token", r.Header.Get("Authorization"))
assert.True(t, strings.HasSuffix(string(body), "0009done\n"))
assert.Equal(t, "version=2", r.Header.Get("Git-Protocol"))
assert.Equal(t, "token", r.Header.Get("Authorization"))
w.Write([]byte("upload-pack-response"))
w.WriteHeader(uploadPackStatusCode)
Loading
Loading
package githttp
import (
"bytes"
"context"
"fmt"
"io"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/commandargs"
Loading
Loading
@@ -15,10 +13,12 @@ import (
"gitlab.com/gitlab-org/labkit/log"
)
const service = "git-receive-pack"
const pushService = "git-receive-pack"
var receivePackHttpPrefix = []byte("001f# service=git-receive-pack\n0000")
var receivePackHTTPPrefix = []byte("001f# service=git-receive-pack\n0000")
// PushCommand handles the execution of a Git push operation,
// including configuration, input/output handling, and access verification.
type PushCommand struct {
Config *config.Config
ReadWriter *readwriter.ReadWriter
Loading
Loading
@@ -35,6 +35,13 @@ type PushCommand struct {
// 4. Read the send-pack data provided by user via SSH (stdinReader)
// 5. Perform /git-receive-pack request and send this data
// 6. Return the output to the user
// ForInfoRefs returns the necessary Push specifics for client.InfoRefs()
func (c *PushCommand) ForInfoRefs() (*readwriter.ReadWriter, string, []byte) {
return c.ReadWriter, pushService, receivePackHTTPPrefix
}
// Execute runs the push command by determining the appropriate method (HTTP/SSH)
func (c *PushCommand) Execute(ctx context.Context) error {
data := c.Response.Payload.Data
client := &git.Client{URL: data.PrimaryRepo, Headers: data.RequestHeaders}
Loading
Loading
@@ -47,39 +54,19 @@ func (c *PushCommand) Execute(ctx context.Context) error {
return c.requestSSHReceivePack(ctx, client)
}
if err := c.requestInfoRefs(ctx, client); err != nil {
if err := requestInfoRefs(ctx, client, c); err != nil {
return err
}
return c.requestReceivePack(ctx, client)
}
func (c *PushCommand) requestInfoRefs(ctx context.Context, client *git.Client) error {
response, err := client.InfoRefs(ctx, service)
if err != nil {
return err
}
defer response.Body.Close()
// Read the first bytes that contain 001f# service=git-receive-pack\n0000 string
// to convert HTTP(S) Git response to the one expected by SSH
p := make([]byte, len(receivePackHttpPrefix))
_, err = response.Body.Read(p)
if err != nil || !bytes.Equal(p, receivePackHttpPrefix) {
return fmt.Errorf("Unexpected git-receive-pack response")
}
_, err = io.Copy(c.ReadWriter.Out, response.Body)
return err
}
func (c *PushCommand) requestSSHReceivePack(ctx context.Context, client *git.Client) error {
response, err := client.SSHReceivePack(ctx, io.NopCloser(c.ReadWriter.In))
if err != nil {
return err
}
defer response.Body.Close()
defer response.Body.Close() //nolint:errcheck
_, err = io.Copy(c.ReadWriter.Out, response.Body)
Loading
Loading
@@ -94,7 +81,7 @@ func (c *PushCommand) requestReceivePack(ctx context.Context, client *git.Client
if err != nil {
return err
}
defer response.Body.Close()
defer response.Body.Close() //nolint:errcheck
_, err = io.Copy(c.ReadWriter.Out, response.Body)
Loading
Loading
@@ -107,7 +94,10 @@ func (c *PushCommand) readFromStdin(pw *io.PipeWriter) {
scanner := pktline.NewScanner(c.ReadWriter.In)
for scanner.Scan() {
line := scanner.Bytes()
pw.Write(line)
_, err := pw.Write(line)
if err != nil {
log.WithError(err).Error("failed to write line")
}
if pktline.IsFlush(line) {
break
Loading
Loading
@@ -119,8 +109,14 @@ func (c *PushCommand) readFromStdin(pw *io.PipeWriter) {
}
if needsPackData {
io.Copy(pw, c.ReadWriter.In)
_, err := io.Copy(pw, c.ReadWriter.In)
if err != nil {
log.WithError(err).Error("failed to copy")
}
}
pw.Close()
err := pw.Close()
if err != nil {
log.WithError(err).Error("failed to close writer")
}
}
Loading
Loading
@@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
Loading
Loading
@@ -40,7 +41,7 @@ func TestExecute(t *testing.T) {
}
require.NoError(t, cmd.Execute(context.Background()))
require.Equal(t, infoRefsWithoutPrefix, output.String())
assert.Equal(t, infoRefsWithoutPrefix, output.String())
}
func TestExecuteWithFailedInfoRefs(t *testing.T) {
Loading
Loading
@@ -63,7 +64,7 @@ func TestExecuteWithFailedInfoRefs(t *testing.T) {
desc: "unexpected response",
statusCode: http.StatusOK,
responseContent: "unexpected response",
expectedErr: "Unexpected git-receive-pack response",
expectedErr: "unexpected git-receive-pack response",
},
}
Loading
Loading
@@ -73,7 +74,7 @@ func TestExecuteWithFailedInfoRefs(t *testing.T) {
{
Path: "/info/refs",
Handler: func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "git-receive-pack", r.URL.Query().Get("service"))
assert.Equal(t, "git-receive-pack", r.URL.Query().Get("service"))
w.WriteHeader(tc.statusCode)
w.Write([]byte(tc.responseContent))
Loading
Loading
@@ -94,7 +95,7 @@ func TestExecuteWithFailedInfoRefs(t *testing.T) {
err := cmd.Execute(context.Background())
require.Error(t, err)
require.Equal(t, tc.expectedErr, err.Error())
assert.Equal(t, tc.expectedErr, err.Error())
})
}
}
Loading
Loading
@@ -115,7 +116,7 @@ func TestExecuteWithFailedReceivePack(t *testing.T) {
err := cmd.Execute(context.Background())
require.Error(t, err)
require.Equal(t, "Remote repository is unavailable", err.Error())
assert.Equal(t, "Remote repository is unavailable", err.Error())
}
func TestPushExecuteWithSSHReceivePack(t *testing.T) {
Loading
Loading
@@ -144,7 +145,7 @@ func TestPushExecuteWithSSHReceivePack(t *testing.T) {
}
require.NoError(t, cmd.Execute(context.Background()))
require.Equal(t, "receive-pack-response", output.String())
assert.Equal(t, "receive-pack-response", output.String())
}
func setup(t *testing.T, receivePackStatusCode int) (string, io.Reader) {
Loading
Loading
@@ -164,7 +165,7 @@ func setup(t *testing.T, receivePackStatusCode int) (string, io.Reader) {
{
Path: "/info/refs",
Handler: func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "git-receive-pack", r.URL.Query().Get("service"))
assert.Equal(t, "git-receive-pack", r.URL.Query().Get("service"))
w.Write([]byte(infoRefs))
},
Loading
Loading
@@ -173,10 +174,10 @@ func setup(t *testing.T, receivePackStatusCode int) (string, io.Reader) {
Path: "/git-receive-pack",
Handler: func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.NoError(t, err)
defer r.Body.Close()
require.Equal(t, receivePackPrefix+flush+receivePackData, string(body))
assert.Equal(t, receivePackPrefix+flush+receivePackData, string(body))
w.WriteHeader(receivePackStatusCode)
},
},
Loading
Loading
@@ -191,12 +192,12 @@ func setupSSHPush(t *testing.T, uploadPackStatusCode int) string {
Path: "/ssh-receive-pack",
Handler: func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.NoError(t, err)
defer r.Body.Close()
require.True(t, strings.HasSuffix(string(body), "0009done\n"))
require.Equal(t, "version=2", r.Header.Get("Git-Protocol"))
require.Equal(t, "token", r.Header.Get("Authorization"))
assert.True(t, strings.HasSuffix(string(body), "0009done\n"))
assert.Equal(t, "version=2", r.Header.Get("Git-Protocol"))
assert.Equal(t, "token", r.Header.Get("Authorization"))
w.WriteHeader(uploadPackStatusCode)
w.Write([]byte("receive-pack-response"))
Loading
Loading
package githttp
import (
"bytes"
"context"
"fmt"
"io"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet/git"
)
type gitHTTPCommand interface {
ForInfoRefs() (*readwriter.ReadWriter, string, []byte)
}
// requestInfoRefs performs an HTTP request to the /info/refs endpoint for the specified Git service,
// verifies the response prefix, and writes the result to the output stream.
func requestInfoRefs(ctx context.Context, client *git.Client, command gitHTTPCommand) error {
readWriter, serviceName, httpPrefix := command.ForInfoRefs()
response, err := client.InfoRefs(ctx, serviceName)
if err != nil {
return err
}
defer response.Body.Close() //nolint:errcheck
// Read the first bytes that contain for
// push - 001f# service=git-receive-pack\n0000 string
// pull - 001e# service=git-upload-pack\n0000 string
// to convert HTTP(S) Git response to the one expected by SSH
p := make([]byte, len(httpPrefix))
_, err = response.Body.Read(p)
if err != nil || !bytes.Equal(p, httpPrefix) {
return fmt.Errorf("unexpected %s response", serviceName)
}
_, err = io.Copy(readWriter.Out, response.Body)
return err
}
Loading
Loading
@@ -34,7 +34,7 @@ func buildTestHandlers(code int, rsp *healthcheck.Response) []testserver.TestReq
return []testserver.TestRequestHandler{
{
Path: "/api/v4/internal/check",
Handler: func(w http.ResponseWriter, r *http.Request) {
Handler: func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(code)
if rsp != nil {
json.NewEncoder(w).Encode(rsp)
Loading
Loading
// Package accessverifier handles the verification of access permission.
package accessverifier
import (
Loading
Loading
@@ -11,14 +12,17 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet/accessverifier"
)
// Response is an alias for accessverifier.Response, representing the result of an access verification.
type Response = accessverifier.Response
// Command handles access verification commands.
type Command struct {
Config *config.Config
Args *commandargs.Shell
ReadWriter *readwriter.ReadWriter
}
// Verify checks access permissions and returns a response.
func (c *Command) Verify(ctx context.Context, action commandargs.CommandType, repo string) (*Response, error) {
client, err := accessverifier.NewClient(c.Config)
if err != nil {
Loading
Loading
Loading
Loading
@@ -8,6 +8,7 @@ import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
Loading
Loading
@@ -28,23 +29,23 @@ func setup(t *testing.T) (*Command, *bytes.Buffer, *bytes.Buffer) {
Path: "/api/v4/internal/allowed",
Handler: func(w http.ResponseWriter, r *http.Request) {
b, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.NoError(t, err)
var requestBody *accessverifier.Request
err = json.Unmarshal(b, &requestBody)
require.NoError(t, err)
assert.NoError(t, err)
if requestBody.KeyID == "1" {
body := map[string]interface{}{
"gl_console_messages": []string{"console", "message"},
}
require.NoError(t, json.NewEncoder(w).Encode(body))
assert.NoError(t, json.NewEncoder(w).Encode(body))
} else {
body := map[string]interface{}{
"status": false,
"message": "missing user",
}
require.NoError(t, json.NewEncoder(w).Encode(body))
assert.NoError(t, json.NewEncoder(w).Encode(body))
}
},
},
Loading
Loading
Loading
Loading
@@ -34,7 +34,7 @@ func (c *Command) Execute(ctx context.Context) (context.Context, error) {
c.displayRecoveryCodes(ctx)
} else {
ctxlog.Debug("twofactorrecover: execute: User chose not to continue")
fmt.Fprintln(c.ReadWriter.Out, "\nNew recovery codes have *not* been generated. Existing codes will remain valid.")
_, _ = fmt.Fprintln(c.ReadWriter.Out, "\nNew recovery codes have *not* been generated. Existing codes will remain valid.")
}
return ctx, nil
Loading
Loading
@@ -44,7 +44,7 @@ func (c *Command) getUserAnswer(ctx context.Context) string {
question :=
"Are you sure you want to generate new two-factor recovery codes?\n" +
"Any existing recovery codes you saved will be invalidated. (yes/no)"
fmt.Fprintln(c.ReadWriter.Out, question)
_, _ = fmt.Fprintln(c.ReadWriter.Out, question)
var answer string
if _, err := fmt.Fscanln(io.LimitReader(c.ReadWriter.In, readerLimit), &answer); err != nil {
Loading
Loading
@@ -67,10 +67,10 @@ func (c *Command) displayRecoveryCodes(ctx context.Context) {
"\n\nDuring sign in, use one of the codes above when prompted for\n" +
"your two-factor code. Then, visit your Profile Settings and add\n" +
"a new device so you do not lose access to your account again.\n"
fmt.Fprint(c.ReadWriter.Out, messageWithCodes)
_, _ = fmt.Fprint(c.ReadWriter.Out, messageWithCodes)
} else {
ctxlog.WithError(err).Error("twofactorrecover: displayRecoveryCodes: failed to generate recovery codes")
fmt.Fprintf(c.ReadWriter.Out, "\nAn error occurred while trying to generate new recovery codes.\n%v\n", err)
_, _ = fmt.Fprintf(c.ReadWriter.Out, "\nAn error occurred while trying to generate new recovery codes.\n%v\n", err)
}
}
Loading
Loading
Loading
Loading
@@ -9,6 +9,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
Loading
Loading
@@ -28,7 +29,7 @@ func setup(t *testing.T) {
b, err := io.ReadAll(r.Body)
defer r.Body.Close()
require.NoError(t, err)
assert.NoError(t, err)
var requestBody *twofactorrecover.RequestBody
json.Unmarshal(b, &requestBody)
Loading
Loading
Loading
Loading
@@ -37,7 +37,7 @@ func (c *Command) Execute(ctx context.Context) (context.Context, error) {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
fmt.Fprint(c.ReadWriter.Out, prompt)
_, _ = fmt.Fprint(c.ReadWriter.Out, prompt)
resultCh := make(chan string)
go func() {
Loading
Loading
@@ -68,7 +68,7 @@ func (c *Command) Execute(ctx context.Context) (context.Context, error) {
}
log.WithContextFields(ctx, log.Fields{"message": message}).Info("Two factor verify command finished")
fmt.Fprintf(c.ReadWriter.Out, "\n%v\n", message)
_, _ = fmt.Fprintf(c.ReadWriter.Out, "\n%v\n", message)
return ctx, nil
}
Loading
Loading
Loading
Loading
@@ -8,6 +8,7 @@ import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
Loading
Loading
@@ -35,10 +36,10 @@ func setup(t *testing.T) []testserver.TestRequestHandler {
b, err := io.ReadAll(r.Body)
defer r.Body.Close()
require.NoError(t, err)
assert.NoError(t, err)
var requestBody *twofactorverify.RequestBody
require.NoError(t, json.Unmarshal(b, &requestBody))
assert.NoError(t, json.Unmarshal(b, &requestBody))
switch requestBody.KeyID {
case "verify_via_otp", "verify_via_otp_with_push_error":
Loading
Loading
@@ -53,7 +54,7 @@ func setup(t *testing.T) []testserver.TestRequestHandler {
"success": false,
"message": "error message",
}
require.NoError(t, json.NewEncoder(w).Encode(body))
assert.NoError(t, json.NewEncoder(w).Encode(body))
case "broken":
w.WriteHeader(http.StatusInternalServerError)
}
Loading
Loading
@@ -65,10 +66,10 @@ func setup(t *testing.T) []testserver.TestRequestHandler {
b, err := io.ReadAll(r.Body)
defer r.Body.Close()
require.NoError(t, err)
assert.NoError(t, err)
var requestBody *twofactorverify.RequestBody
require.NoError(t, json.Unmarshal(b, &requestBody))
assert.NoError(t, json.Unmarshal(b, &requestBody))
switch requestBody.KeyID {
case "verify_via_push":
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment