diff --git a/.circleci/config.yml b/.circleci/config.yml index 553ef6c..7cba5e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,18 +16,6 @@ install_retry: &install_retry version: 2 jobs: - go.build: - <<: *defaults - steps: - - checkout - - *install_retry - - run: /tmp/retry -m 3 go mod download - - run: /tmp/retry -m 3 go mod vendor - - run: /tmp/retry -m 3 make install - - run: GO111MODULE=off /tmp/retry -m 3 go test -v ./... - - run: /tmp/retry -m 3 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.12.2 - - run: PATH=$PATH:$(pwd)/bin /tmp/retry -m 3 make lint - docker.integration: <<: *defaults steps: @@ -48,6 +36,4 @@ workflows: version: 2 build_and_integration: jobs: - - go.build - docker.integration - # requires: docker.build? diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..783facd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,88 @@ +name: CI +on: + push: + tags: + - v* + branches: + - master + pull_request: + +jobs: + docker-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Build the Docker image + run: docker build . --file Dockerfile + golangci-lint: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: lint + uses: golangci/golangci-lint-action@v0.1.7 + with: + version: v1.26 + github-token: ${{ secrets.GITHUB_TOKEN }} + tests-on-windows: + needs: golangci-lint # run after golangci-lint action to not produce duplicated errors + runs-on: windows-latest + strategy: + matrix: + golang: + #- 1.13 + - 1.14 + steps: + - uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.golang }} + - name: Run tests on Windows + run: make.exe unittest + continue-on-error: true + tests-on-mac: + needs: golangci-lint # run after golangci-lint action to not produce duplicated errors + runs-on: macos-latest + strategy: + matrix: + golang: + - 1.14 + steps: + - uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.golang }} + - uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ matrix.golang }}- + - name: Run tests on Unix-like operating systems + run: make unittest + tests-on-linux: + needs: golangci-lint # run after golangci-lint action to not produce duplicated errors + runs-on: ubuntu-latest + strategy: + matrix: + golang: + - 1.11 + - 1.12 + - 1.13 + - 1.14 + steps: + - uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.golang }} + - uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ matrix.golang }}- + - name: Run tests on Unix-like operating systems + run: make unittest diff --git a/.gitignore b/.gitignore index e3f3d55..b0e1bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +coverage.txt dist/ *~ *# diff --git a/Makefile b/Makefile index ca14bf4..4f3fd21 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,15 @@ -GIT_SHA ?= $(shell git rev-parse HEAD) -GIT_TAG ?= $(shell git describe --tags --always) -GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) -LDFLAGS ?= -X main.GitSha=$(GIT_SHA) -X main.GitTag=$(GIT_TAG) -X main.GitBranch=$(GIT_BRANCH) -VERSION ?= $(shell grep 'VERSION =' main.go | cut -d'"' -f2) +GOPKG ?= moul.io/sshportal +GOBINS ?= . +DOCKER_IMAGE ?= moul/sshportal + +VERSION ?= `git describe --tags --always` +VCS_REF ?= `git rev-parse --short HEAD` +GO_INSTALL_OPTS = -ldflags="-X main.GitSha=$(VCS_REF) -X main.GitTag=$(VERSION)" + +include rules.mk + +DB_VERSION ?= v$(shell grep -E 'ID: "[0-9]+",' pkg/bastion/dbinit.go | tail -n 1 | cut -d'"' -f2) AES_KEY ?= my-dummy-aes-key -GO ?= GO111MODULE=on go - -.PHONY: install -install: - $(GO) install -v -ldflags '$(LDFLAGS)' . - -.PHONY: docker.build -docker.build: - docker build -t moul/sshportal . .PHONY: integration integration: @@ -27,19 +24,10 @@ dev: -$(GO) get github.com/githubnemo/CompileDaemon CompileDaemon -exclude-dir=.git -exclude=".#*" -color=true -command="./sshportal server --debug --bind-address=:$(PORT) --aes-key=$(AES_KEY) $(EXTRA_RUN_OPTS)" . -.PHONY: test -test: - $(GO) test -i ./... - $(GO) test -v ./... - -.PHONY: lint -lint: - golangci-lint run --verbose ./... - .PHONY: backup backup: mkdir -p data/backups - cp sshportal.db data/backups/$(shell date +%s)-$(VERSION)-sshportal.sqlite + cp sshportal.db data/backups/$(shell date +%s)-$(DB_VERSION)-sshportal.sqlite doc: dot -Tsvg ./.assets/overview.dot > ./.assets/overview.svg diff --git a/go.sum b/go.sum index 3ad39f3..ec3287a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/anmitsu/go-shlex v0.0.0-20200502080107-070676123096 h1:ZruJGjP2kDYJM4UYAeWKJpWAnw4S0Xa9c5sVO3dp4B8= -github.com/anmitsu/go-shlex v0.0.0-20200502080107-070676123096/go.mod h1:yiw7E4c5EVh3s1/gBE3mE3ObvBGmvKsguqJmDKd2Vlc= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= @@ -26,8 +24,6 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/gliderlabs/ssh v0.3.0 h1:7GcKy4erEljCE/QeQ2jTVpu+3f3zkpZOxOJjFYkMqYU= github.com/gliderlabs/ssh v0.3.0/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= @@ -107,8 +103,6 @@ golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/main.go b/main.go index e649a3f..f5f20be 100644 --- a/main.go +++ b/main.go @@ -13,14 +13,10 @@ import ( ) var ( - // Version should be updated by hand at each release - Version = "1.10.0+dev" // GitTag will be overwritten automatically by the build system - GitTag string + GitTag = "n/a" // GitSha will be overwritten automatically by the build system - GitSha string - // GitBranch will be overwritten automatically by the build system - GitBranch string + GitSha = "n/a" ) func main() { @@ -29,7 +25,7 @@ func main() { app := cli.NewApp() app.Name = path.Base(os.Args[0]) app.Author = "Manfred Touron" - app.Version = Version + " (" + GitSha + ")" + app.Version = GitTag + " (" + GitSha + ")" app.Email = "https://moul.io/sshportal" app.Commands = []cli.Command{ { diff --git a/pkg/bastion/shell.go b/pkg/bastion/shell.go index 59104c4..2f00a96 100644 --- a/pkg/bastion/shell.go +++ b/pkg/bastion/shell.go @@ -41,7 +41,7 @@ const ( naMessage = "n/a" ) -func shell(s ssh.Session, version, gitSha, gitTag, gitBranch string) error { +func shell(s ssh.Session, version, gitSha, gitTag string) error { var ( sshCommand = s.Command() actx = s.Context().Value(authContextKey).(*authContext) @@ -1180,9 +1180,9 @@ GLOBAL OPTIONS: fmt.Fprintf(s, "User email: %s\n", myself.Email) fmt.Fprintf(s, "Version: %s\n", version) fmt.Fprintf(s, "GIT SHA: %s\n", gitSha) - fmt.Fprintf(s, "GIT Branch: %s\n", gitBranch) fmt.Fprintf(s, "GIT Tag: %s\n", gitTag) + // FIXME: gormigrate version // FIXME: add info about current server (network, cpu, ram, OS) // FIXME: add info about current user // FIXME: add active connections diff --git a/pkg/bastion/ssh.go b/pkg/bastion/ssh.go index fae64d1..23f87f8 100644 --- a/pkg/bastion/ssh.go +++ b/pkg/bastion/ssh.go @@ -212,6 +212,7 @@ func bastionClientConfig(ctx ssh.Context, host *dbmodels.Host) (*gossh.ClientCon switch action { case string(dbmodels.ACLActionAllow): + // do nothing case string(dbmodels.ACLActionDeny): return nil, fmt.Errorf("you don't have permission to that host") default: @@ -220,7 +221,7 @@ func bastionClientConfig(ctx ssh.Context, host *dbmodels.Host) (*gossh.ClientCon return clientConfig, nil } -func ShellHandler(s ssh.Session, version, gitSha, gitTag, gitBranch string) { +func ShellHandler(s ssh.Session, version, gitSha, gitTag string) { actx := s.Context().Value(authContextKey).(*authContext) if actx.userType() != userTypeHealthcheck { log.Printf("New connection(shell): sshUser=%q remote=%q local=%q command=%q dbUser=id:%d,email:%s", s.User(), s.RemoteAddr(), s.LocalAddr(), s.Command(), actx.user.ID, actx.user.Email) @@ -241,7 +242,7 @@ func ShellHandler(s ssh.Session, version, gitSha, gitTag, gitBranch string) { fmt.Fprintln(s, "OK") return case userTypeShell: - if err := shell(s, version, gitSha, gitTag, gitBranch); err != nil { + if err := shell(s, version, gitSha, gitTag); err != nil { fmt.Fprintf(s, "error: %v\n", err) _ = s.Exit(1) } diff --git a/rules.mk b/rules.mk new file mode 100644 index 0000000..9ff2c02 --- /dev/null +++ b/rules.mk @@ -0,0 +1,278 @@ +# +--------------------------------------------------------------+ +# | * * * moul.io/rules.mk | +# +--------------------------------------------------------------+ +# | | +# | ++ ______________________________________ | +# | ++++ / \ | +# | ++++ | | | +# | ++++++++++ | https://moul.io/rules.mk is a set | | +# | +++ | | of common Makefile rules that can | | +# | ++ | | be configured from the Makefile | | +# | + -== ==| | or with environment variables. | | +# | ( <*> <*> | | | +# | | | /| Manfred Touron | | +# | | _) / | manfred.life | | +# | | +++ / \______________________________________/ | +# | \ =+ / | +# | \ + | +# | |\++++++ | +# | | ++++ ||// | +# | ___| |___ _||/__ __| +# | / --- \ \| ||| __ _ ___ __ __/ /| +# |/ | | \ \ / / ' \/ _ \/ // / / | +# || | | | | | /_/_/_/\___/\_,_/_/ | +# +--------------------------------------------------------------+ + +all: help + +## +## Common helpers +## + +rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) + +## +## rules.mk +## +ifneq ($(wildcard rules.mk),) +.PHONY: rulesmk.bumpdeps +rulesmk.bumpdeps: + wget -O rules.mk https://raw.githubusercontent.com/moul/rules.mk/master/rules.mk +BUMPDEPS_STEPS += rulesmk.bumpdeps +endif + +## +## Maintainer +## + +ifneq ($(wildcard .git/HEAD),) +.PHONY: generate.authors +generate.authors: AUTHORS +AUTHORS: .git/ + echo "# This file lists all individuals having contributed content to the repository." > AUTHORS + echo "# For how it is generated, see 'https://github.com/moul/rules.mk'" >> AUTHORS + echo >> AUTHORS + git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf >> AUTHORS +GENERATE_STEPS += generate.authors +endif + +## +## Golang +## + +ifndef GOPKG +ifneq ($(wildcard go.mod),) +GOPKG = $(shell sed '/module/!d;s/^omdule\ //' go.mod) +endif +endif +ifdef GOPKG +GO ?= go +GOPATH ?= $(HOME)/go +GO_INSTALL_OPTS ?= +GO_TEST_OPTS ?= -test.timeout=30s +GOMOD_DIR ?= . +GOCOVERAGE_FILE ?= ./coverage.txt + +ifdef GOBINS +.PHONY: go.install +go.install: + @set -e; for dir in $(GOBINS); do ( set -xe; \ + cd $$dir; \ + $(GO) install $(GO_INSTALL_OPTS) .; \ + ); done +INSTALL_STEPS += go.install + +.PHONY: go.release +go.release: + goreleaser --snapshot --skip-publish --rm-dist + @echo -n "Do you want to release? [y/N] " && read ans && \ + if [ $${ans:-N} = y ]; then set -xe; goreleaser --rm-dist; fi +RELEASE_STEPS += go.release +endif + +.PHONY: go.unittest +go.unittest: + @echo "mode: atomic" > /tmp/gocoverage + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do (set -e; (set -xe; \ + cd $$dir; \ + $(GO) test $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race ./...); \ + if [ -f /tmp/profile.out ]; then \ + cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \ + rm -f /tmp/profile.out; \ + fi); done + @mv /tmp/gocoverage $(GOCOVERAGE_FILE) + +.PHONY: go.checkdoc +go.checkdoc: + go doc $(GOMOD_DIR) + +.PHONY: go.coverfunc +go.coverfunc: go.unittest + go tool cover -func=$(GOCOVERAGE_FILE) | grep -v .pb.go: | grep -v .pb.gw.go: + +.PHONY: go.lint +go.lint: + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \ + cd $$dir; \ + golangci-lint run --verbose ./...; \ + ); done + +.PHONY: go.tidy +go.tidy: + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \ + cd $$dir; \ + $(GO) mod tidy; \ + ); done + +.PHONY: go.build +go.build: + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \ + cd $$dir; \ + $(GO) build ./...; \ + ); done + +.PHONY: go.bump-deps +go.bumpdeps: + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \ + cd $$dir; \ + $(GO) get -u ./...; \ + ); done + +.PHONY: go.bump-deps +go.fmt: + if ! command -v goimports &>/dev/null; then GO111MODULE=off go get golang.org/x/tools/cmd/goimports; fi + @set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do ( set -xe; \ + cd $$dir; \ + goimports -w `go list -f '{{.Dir}}' ./...)` \ + ); done + +BUILD_STEPS += go.build +BUMPDEPS_STEPS += go.bumpdeps +TIDY_STEPS += go.tidy +LINT_STEPS += go.lint +UNITTEST_STEPS += go.unittest +FMT_STEPS += go.fmt +endif + +## +## Node +## + +ifndef NPM_PACKAGES +ifneq ($(wildcard package.json),) +NPM_PACKAGES = . +endif +endif +ifdef NPM_PACKAGES +.PHONY: npm.publish +npm.publish: + @echo -n "Do you want to npm publish? [y/N] " && read ans && \ + @if [ $${ans:-N} = y ]; then \ + set -e; for dir in $(NPM_PACKAGES); do ( set -xe; \ + cd $$dir; \ + npm publish --access=public; \ + ); done; \ + fi +RELEASE_STEPS += npm.publish +endif + +## +## Docker +## + +docker_build = docker build \ + --build-arg VCS_REF=`git rev-parse --short HEAD` \ + --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \ + --build-arg VERSION=`git describe --tags --always` \ + -t "$2" -f "$1" "$(dir $1)" + +ifndef DOCKERFILE_PATH +DOCKERFILE_PATH = ./Dockerfile +endif +ifndef DOCKER_IMAGE +ifneq ($(wildcard Dockerfile),) +DOCKER_IMAGE = $(notdir $(PWD)) +endif +endif +ifdef DOCKER_IMAGE +ifneq ($(DOCKER_IMAGE),none) +.PHONY: docker.build +docker.build: + $(call docker_build,$(DOCKERFILE_PATH),$(DOCKER_IMAGE)) + +BUILD_STEPS += docker.build +endif +endif + +## +## Common +## + +TEST_STEPS += $(UNITTEST_STEPS) +TEST_STEPS += $(LINT_STEPS) +TEST_STEPS += $(TIDY_STEPS) + +ifneq ($(strip $(TEST_STEPS)),) +.PHONY: test +test: $(PRE_TEST_STEPS) $(TEST_STEPS) +endif + +ifdef INSTALL_STEPS +.PHONY: install +install: $(PRE_INSTALL_STEPS) $(INSTALL_STEPS) +endif + +ifdef UNITTEST_STEPS +.PHONY: unittest +unittest: $(PRE_UNITTEST_STEPS) $(UNITTEST_STEPS) +endif + +ifdef LINT_STEPS +.PHONY: lint +lint: $(PRE_LINT_STEPS) $(FMT_STEPS) $(LINT_STEPS) +endif + +ifdef TIDY_STEPS +.PHONY: tidy +tidy: $(PRE_TIDY_STEPS) $(TIDY_STEPS) +endif + +ifdef BUILD_STEPS +.PHONY: build +build: $(PRE_BUILD_STEPS) $(BUILD_STEPS) +endif + +ifdef RELEASE_STEPS +.PHONY: release +release: $(PRE_RELEASE_STEPS) $(RELEASE_STEPS) +endif + +ifdef BUMPDEPS_STEPS +.PHONY: bumpdeps +bumpdeps: $(PRE_BUMDEPS_STEPS) $(BUMPDEPS_STEPS) +endif + +ifdef FMT_STEPS +.PHONY: fmt +fmt: $(PRE_FMT_STEPS) $(FMT_STEPS) +endif + +ifdef GENERATE_STEPS +.PHONY: generate +generate: $(PRE_GENERATE_STEPS) $(GENERATE_STEPS) +endif + +.PHONY: help +help:: + @echo "General commands:" + @[ "$(BUILD_STEPS)" != "" ] && echo " build" || true + @[ "$(BUMPDEPS_STEPS)" != "" ] && echo " bumpdeps" || true + @[ "$(FMT_STEPS)" != "" ] && echo " fmt" || true + @[ "$(GENERATE_STEPS)" != "" ] && echo " generate" || true + @[ "$(INSTALL_STEPS)" != "" ] && echo " install" || true + @[ "$(LINT_STEPS)" != "" ] && echo " lint" || true + @[ "$(RELEASE_STEPS)" != "" ] && echo " release" || true + @[ "$(TEST_STEPS)" != "" ] && echo " test" || true + @[ "$(TIDY_STEPS)" != "" ] && echo " tidy" || true + @[ "$(UNITTEST_STEPS)" != "" ] && echo " unittest" || true + @# FIXME: list other commands diff --git a/server.go b/server.go index c5f6784..471715b 100644 --- a/server.go +++ b/server.go @@ -89,8 +89,8 @@ func server(c *serverConfig) (err error) { // configure server srv := &ssh.Server{ Addr: c.bindAddr, - Handler: func(s ssh.Session) { bastion.ShellHandler(s, Version, GitSha, GitTag, GitBranch) }, // ssh.Server.Handler is the handler for the DefaultSessionHandler - Version: fmt.Sprintf("sshportal-%s", Version), + Handler: func(s ssh.Session) { bastion.ShellHandler(s, GitTag, GitSha, GitTag) }, // ssh.Server.Handler is the handler for the DefaultSessionHandler + Version: fmt.Sprintf("sshportal-%s", GitTag), ChannelHandlers: map[string]ssh.ChannelHandler{ "default": bastion.ChannelHandler, },