mirror of
https://github.com/moul/sshportal.git
synced 2025-01-11 18:08:42 +08:00
Merge pull request #28 from moul/dev/moul/ci-integration
Run integration tests on CI
This commit is contained in:
commit
d6ea80dab1
13 changed files with 196 additions and 134 deletions
|
@ -1,11 +1,12 @@
|
|||
defaults: &defaults
|
||||
working_directory: /go/src/github.com/moul/sshportal
|
||||
docker:
|
||||
- image: circleci/golang:1.8
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.8
|
||||
# - image: circleci/mysql:9.4
|
||||
|
||||
working_directory: /go/src/github.com/moul/sshportal
|
||||
go.build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- run: make install
|
||||
|
@ -14,4 +15,26 @@ jobs:
|
|||
# - run: make integration
|
||||
- run: go get -u github.com/alecthomas/gometalinter
|
||||
- run: gometalinter --install
|
||||
- run: make lint
|
||||
- run: make lint
|
||||
docker.integration:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Docker Compose
|
||||
command: |
|
||||
umask 022
|
||||
curl -L https://github.com/docker/compose/releases/download/1.11.2/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
|
||||
- setup_remote_docker:
|
||||
docker_layer_caching: true
|
||||
- run: docker build -t moul/sshportal .
|
||||
- run: make integration
|
||||
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_integration:
|
||||
jobs:
|
||||
- go.build
|
||||
- docker.integration
|
||||
# requires: docker.build?
|
||||
|
|
|
@ -2,8 +2,13 @@
|
|||
|
||||
## master (unreleased)
|
||||
|
||||
Breaking changes:
|
||||
* Use `sshportal server` instead of `sshportal` to start a new server (nothing to change if using the docker image)
|
||||
|
||||
Changes:
|
||||
* Fix connection failure when sending too many environment variables (fix [#22](https://github.com/moul/sshportal/issues/22))
|
||||
* Fix panic when entering empty command (fix [#13](https://github.com/moul/sshportal/issues/13))
|
||||
* Add `config backup --ignore-events` option
|
||||
|
||||
## v1.6.0 (2017-12-12)
|
||||
|
||||
|
|
|
@ -8,3 +8,5 @@ RUN make _docker_install
|
|||
FROM scratch
|
||||
COPY --from=builder /go/bin/sshportal /bin/sshportal
|
||||
ENTRYPOINT ["/bin/sshportal"]
|
||||
CMD ["server"]
|
||||
EXPOSE 2222
|
||||
|
|
3
Makefile
3
Makefile
|
@ -3,7 +3,6 @@ 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)
|
||||
PORT ?= 2222
|
||||
AES_KEY ?= my-dummy-aes-key
|
||||
|
||||
.PHONY: install
|
||||
|
@ -16,7 +15,7 @@ docker.build:
|
|||
|
||||
.PHONY: integration
|
||||
integration:
|
||||
PORT="$(PORT)" bash ./examples/integration/test.sh
|
||||
cd ./examples/integration && make
|
||||
|
||||
.PHONY: _docker_install
|
||||
_docker_install:
|
||||
|
|
4
examples/integration/Dockerfile
Normal file
4
examples/integration/Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
|||
FROM occitech/ssh-client
|
||||
COPY . /integration
|
||||
ENTRYPOINT ["/bin/sh", "-c"]
|
||||
CMD ["/integration/_client.sh"]
|
6
examples/integration/Makefile
Normal file
6
examples/integration/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
run:
|
||||
docker-compose down
|
||||
docker-compose up -d sshportal
|
||||
docker-compose build client
|
||||
docker-compose run client /integration/_client.sh
|
||||
docker-compose down
|
56
examples/integration/_client.sh
Executable file
56
examples/integration/_client.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
cp /integration/client_test_rsa ~/.ssh/id_rsa
|
||||
chmod -R 700 ~/.ssh
|
||||
cat >~/.ssh/config <<EOF
|
||||
Host sshportal
|
||||
UserKnownHostsFile /dev/null
|
||||
StrictHostKeyChecking no
|
||||
Port 2222
|
||||
HostName sshportal
|
||||
EOF
|
||||
|
||||
#ping -c 1 sshportal
|
||||
sleep 3
|
||||
|
||||
set -x
|
||||
|
||||
# login
|
||||
ssh sshportal -l invite:integration
|
||||
|
||||
# hostgroup/usergroup/acl
|
||||
ssh sshportal -l admin hostgroup create
|
||||
ssh sshportal -l admin hostgroup create --name=hg1
|
||||
ssh sshportal -l admin hostgroup create --name=hg2 --comment=test
|
||||
ssh sshportal -l admin usergroup inspect hg1 hg2
|
||||
ssh sshportal -l admin hostgroup ls
|
||||
|
||||
ssh sshportal -l admin usergroup create
|
||||
ssh sshportal -l admin usergroup create --name=ug1
|
||||
ssh sshportal -l admin usergroup create --name=ug2 --comment=test
|
||||
ssh sshportal -l admin usergroup inspect ug1 ug2
|
||||
ssh sshportal -l admin usergroup ls
|
||||
|
||||
ssh sshportal -l admin acl create --ug=ug1 --ug=ug2 --hg=hg1 --hg=hg2 --comment=test --action=allow --weight=42
|
||||
ssh sshportal -l admin acl inspect 2
|
||||
ssh sshportal -l admin acl ls
|
||||
|
||||
# basic host create
|
||||
ssh sshportal -l admin host create bob@example.org:1234
|
||||
ssh sshportal -l admin host create test42
|
||||
ssh sshportal -l admin host create --name=testtest --comment=test --password=test test@test.test
|
||||
ssh sshportal -l admin host create --group=hg1 --group=hg2 hostwithgroups.org
|
||||
ssh sshportal -l admin host inspect example test42 testtest hostwithgroups
|
||||
ssh sshportal -l admin host ls
|
||||
|
||||
# backup/restore
|
||||
ssh sshportal -l admin config backup --indent --ignore-events > backup-1
|
||||
ssh sshportal -l admin config restore --confirm < backup-1
|
||||
ssh sshportal -l admin config backup --indent --ignore-events > backup-2
|
||||
(
|
||||
cat backup-1 | grep -v '"date":' | grep -v 'tedAt":' > backup-1.clean
|
||||
cat backup-2 | grep -v '"date":' | grep -v 'tedAt":' > backup-2.clean
|
||||
set -xe
|
||||
diff backup-1.clean backup-2.clean
|
||||
)
|
27
examples/integration/client_test_rsa
Normal file
27
examples/integration/client_test_rsa
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAxV0ds/oMuOw9QVLFgxaM0Js2IdJKiYLnmKq96IuZ/wMqMea3
|
||||
qi1UfNBPUQ2CojwbJGTea8cA9J1Et+a6v1mL66YG8zyxmhdlKHm2KOMnUXSfWPNg
|
||||
ZArXH7Uj4Nx1k/O1ujfQFAsYTx63kMqwq1lM9JrExLSdp/8D/zQAyF68c82w8UZH
|
||||
aIpLZJkM/fgh0VJWiw65NYAzuIkJNBgZR8rEBQU7V3lCqFGcSJ88MoqIdVGy0I4b
|
||||
GGpO9VppDTf+uYGYDthhXlV0nHM45neWL5hzFK6oqbLFLpsaUOY7C3kKv+8+B3lX
|
||||
p3OfGVoFy7u3evro+yRQEMQ+myS5UBIHaI3qOwIDAQABAoIBABM7/vASV3kSNOoP
|
||||
2gXrha+y4LStHOyH4HBFe5qVOF3c/hi85ntkTY6YcpJwoaGUAAUs+2w/ib1NMmxF
|
||||
xT9ux68gkB7WdGyTCR3HttQHR0at+fWeSm+Vit+hNKzub1sK7lQGqnW5mxXi5Xrr
|
||||
9gnM+y3/g1u0SoUb2lTdyZG9gdo7LnLElzRinraEqTJUowXkqzAhGf1A+Kgp2fkb
|
||||
/+QP1oiK8QeOFOsITD2UwIVCBRwRl5TjjwfLQ4El6oAWNjcL1ZfSmQLiXZ7U8Smk
|
||||
Cd+BI+6ZDLA43fBUGDjbg4+2dt2JoKNkS0FfqhCW+Z2A0+ClJ8pwuMqRz8XXaOYr
|
||||
ONCqOPECgYEA/qyWxSUjEWMvN3tC/mZPEbwHP3m7mbR1KGwhZylWVCmEF7kVC6il
|
||||
/ICQZUI9ekyGJZ/SKZKwxDe7oeV+vFsus/9FWC5wrp45Xm4kEUwsBr4bWvuNpVOq
|
||||
jrKecY8NgPZS1X6Uc5BbpiE9/VF2gCdYVVCDXP1NfO2MDhkniXJQUEMCgYEAxmQl
|
||||
3s/vih9rXllPZcWHafjnFcGU1AIiJD1c+8lAqwCZzm0Bt0Ex4s1t3lp0ew6YBVXN
|
||||
yGy+BORxOC9FQGTlKZNk/S705+8iAVNc9Sy7XbgN3GY3eat7XYbNpGbQrjiyZ+7I
|
||||
pdEnoHWQD4NFXHaVsXaVHcBFUovXKoes2PODeqkCgYEAoN/3Ucv2zgoAjqSfmkKY
|
||||
mhRT48YLOroi9AjyRM95CCs9lRrGb5n2WH4COOTSHwpuByBhSv+uCBVIwqlNGMDk
|
||||
zLFpZZ3YcoXiqYMb541dlljKwPt8673hVMkCi6uZFSkFBHY0YpgDPPtsxDOMjsHL
|
||||
7ACzKq+cHlmUimdbcViz4S8CgYEAr2+sVYaHixsRtVNA9PxiLQIgR4rx8zEXw/hH
|
||||
m5hyiUV0vaiDlewfEzMab0CKNK/JGx6vZQdUWbsxq7+Re8o9JDDlY0b854T+CzIO
|
||||
x/iQj+XMzBPQBtXvt9sXSsRo0Uft7B6qbIeyhSCxDibFVWjAIzh70N1P8BkdYsyr
|
||||
uwZMRFECgYEA5QuutlFLI7hMPdBQvsEhjdVwKAj7LvpNemgxDpEoMiQWWm51XzcP
|
||||
IZjlCwl1UvIE0MxowtvNr5lQuGRN8/88Dajpq+W6eeTSCKi67nn0VZh13cQLKvoX
|
||||
DRZ6nfC3iLnEYKK+KN/I3NY7JcSjHmW6V8WtrCYAi2D5Ns05XJAG6t8=
|
||||
-----END RSA PRIVATE KEY-----
|
18
examples/integration/docker-compose.yml
Normal file
18
examples/integration/docker-compose.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
version: '3.0'
|
||||
|
||||
services:
|
||||
sshportal:
|
||||
image: moul/sshportal
|
||||
environment:
|
||||
- SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN=integration
|
||||
command: server --debug
|
||||
ports:
|
||||
- 2222
|
||||
|
||||
client:
|
||||
build: .
|
||||
depends_on:
|
||||
- sshportal
|
||||
#volumes:
|
||||
# - .:/integration
|
||||
tty: true
|
|
@ -1,87 +0,0 @@
|
|||
#!/bin/sh -e
|
||||
# Setup a new sshportal and performs some checks
|
||||
|
||||
PORT=${PORT:-2222}
|
||||
SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN=integration
|
||||
|
||||
# tempdir
|
||||
WORK_DIR=`mktemp -d`
|
||||
if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then
|
||||
echo "Could not create temp dir"
|
||||
exit 1
|
||||
fi
|
||||
cd "${WORK_DIR}"
|
||||
|
||||
# pre cleanup
|
||||
docker_cleanup() {
|
||||
( set -x
|
||||
docker rm -f -v sshportal-integration 2>/dev/null >/dev/null || true
|
||||
)
|
||||
}
|
||||
tempdir_cleanup() {
|
||||
rm -rf "${WORK_DIR}"
|
||||
}
|
||||
docker_cleanup
|
||||
trap tempdir_cleanup EXIT
|
||||
|
||||
# start server
|
||||
( set -xe;
|
||||
docker run \
|
||||
-d \
|
||||
-e SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN=${SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN} \
|
||||
--name=sshportal-integration \
|
||||
-p${PORT}:2222 \
|
||||
moul/sshportal --debug
|
||||
)
|
||||
while ! nc -z localhost ${PORT}; do
|
||||
sleep 1
|
||||
done
|
||||
sleep 3
|
||||
|
||||
# integration suite
|
||||
xssh() {
|
||||
set -e
|
||||
echo "+ ssh {sshportal} $@" >&2
|
||||
ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no localhost -p ${PORT} $@
|
||||
}
|
||||
# login
|
||||
xssh -l invite:integration
|
||||
|
||||
# hostgroup/usergroup/acl
|
||||
xssh -l admin hostgroup create
|
||||
xssh -l admin hostgroup create --name=hg1
|
||||
xssh -l admin hostgroup create --name=hg2 --comment=test
|
||||
xssh -l admin usergroup inspect hg1 hg2
|
||||
xssh -l admin hostgroup ls
|
||||
|
||||
xssh -l admin usergroup create
|
||||
xssh -l admin usergroup create --name=ug1
|
||||
xssh -l admin usergroup create --name=ug2 --comment=test
|
||||
xssh -l admin usergroup inspect ug1 ug2
|
||||
xssh -l admin usergroup ls
|
||||
|
||||
xssh -l admin acl create --ug=ug1 --ug=ug2 --hg=hg1 --hg=hg2 --comment=test --action=allow --weight=42
|
||||
xssh -l admin acl inspect 2
|
||||
xssh -l admin acl ls
|
||||
|
||||
# basic host create
|
||||
xssh -l admin host create bob@example.org:1234
|
||||
xssh -l admin host create test42
|
||||
xssh -l admin host create --name=testtest --comment=test --password=test test@test.test
|
||||
xssh -l admin host create --group=hg1 --group=hg2 hostwithgroups.org
|
||||
xssh -l admin host inspect example test42 testtest hostwithgroups
|
||||
xssh -l admin host ls
|
||||
|
||||
# backup/restore
|
||||
xssh -l admin config backup --indent > backup-1
|
||||
xssh -l admin config restore --confirm < backup-1
|
||||
xssh -l admin config backup --indent > backup-2
|
||||
(
|
||||
cat backup-1 | grep -v '"date":' > backup-1.clean
|
||||
cat backup-2 | grep -v '"date":' > backup-2.clean
|
||||
set -xe
|
||||
diff backup-1.clean backup-2.clean
|
||||
)
|
||||
|
||||
# post cleanup
|
||||
#cleanup
|
|
@ -9,7 +9,7 @@ services:
|
|||
condition: service_healthy
|
||||
links:
|
||||
- mysql
|
||||
command: --db-driver=mysql --debug --db-conn="root:root@tcp(mysql:3306)/db?charset=utf8&parseTime=true&loc=Local"
|
||||
command: server --db-driver=mysql --debug --db-conn="root:root@tcp(mysql:3306)/db?charset=utf8&parseTime=true&loc=Local"
|
||||
ports:
|
||||
- 2222:2222
|
||||
|
||||
|
|
76
main.go
76
main.go
|
@ -45,43 +45,49 @@ func main() {
|
|||
app.Author = "Manfred Touron"
|
||||
app.Version = Version + " (" + GitSha + ")"
|
||||
app.Email = "https://github.com/moul/sshportal"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "bind-address, b",
|
||||
EnvVar: "SSHPORTAL_BIND",
|
||||
Value: ":2222",
|
||||
Usage: "SSH server bind address",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "db-driver",
|
||||
Value: "sqlite3",
|
||||
Usage: "GORM driver (sqlite3)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "db-conn",
|
||||
Value: "./sshportal.db",
|
||||
Usage: "GORM connection string",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "debug, D",
|
||||
Usage: "Display debug information",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config-user",
|
||||
Usage: "SSH user that spawns a configuration shell",
|
||||
Value: "admin",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "healthcheck-user",
|
||||
Usage: "SSH user that returns healthcheck status without checking the SSH key",
|
||||
Value: "healthcheck",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "aes-key",
|
||||
Usage: "Encrypt sensitive data in database (length: 16, 24 or 32)",
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "server",
|
||||
Usage: "Start sshportal server",
|
||||
Action: server,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "bind-address, b",
|
||||
EnvVar: "SSHPORTAL_BIND",
|
||||
Value: ":2222",
|
||||
Usage: "SSH server bind address",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "db-driver",
|
||||
Value: "sqlite3",
|
||||
Usage: "GORM driver (sqlite3)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "db-conn",
|
||||
Value: "./sshportal.db",
|
||||
Usage: "GORM connection string",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "debug, D",
|
||||
Usage: "Display debug information",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config-user",
|
||||
Usage: "SSH user that spawns a configuration shell",
|
||||
Value: "admin",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "healthcheck-user",
|
||||
Usage: "SSH user that returns healthcheck status without checking the SSH key",
|
||||
Value: "healthcheck",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "aes-key",
|
||||
Usage: "Encrypt sensitive data in database (length: 16, 24 or 32)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Action = server
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Fatalf("error: %v", err)
|
||||
}
|
||||
|
|
7
shell.go
7
shell.go
|
@ -299,6 +299,7 @@ GLOBAL OPTIONS:
|
|||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{Name: "indent", Usage: "uses indented JSON"},
|
||||
cli.BoolFlag{Name: "decrypt", Usage: "decrypt sensitive data"},
|
||||
cli.BoolFlag{Name: "ignore-events", Usage: "do not backup events data"},
|
||||
},
|
||||
Description: "ssh admin@portal config backup > sshportal.bkp",
|
||||
Action: func(c *cli.Context) error {
|
||||
|
@ -360,8 +361,10 @@ GLOBAL OPTIONS:
|
|||
if err := SessionsPreload(db).Find(&config.Sessions).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := EventsPreload(db).Find(&config.Events).Error; err != nil {
|
||||
return err
|
||||
if !c.Bool("ignore-events") {
|
||||
if err := EventsPreload(db).Find(&config.Events).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
config.Date = time.Now()
|
||||
enc := json.NewEncoder(s)
|
||||
|
|
Loading…
Reference in a new issue