diff --git a/.dockerignore b/.dockerignore index 91fc136..bd44397 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,5 +8,4 @@ Gemfile.lock Rakefile *.md *.yml -scripts env diff --git a/CHANGELOG.md b/CHANGELOG.md index 1145ae8..fe6cd96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,18 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased](https://github.com/passbolt/passbolt_docker/compare/v2.7.1...HEAD) +## [Unreleased](https://github.com/passbolt/passbolt_docker/compare/v2.8.1...HEAD) + +## [2.8.1](https://github.com/passbolt/passbolt_docker/compare/v2.7.1...v2.8.1) - 2019-04-01 + +### Added + +- Documentation for new env variable APP_BASE to use passbolt in a subfolder +- Added wait-for.sh to the docker image as part of [#123](https://github.com/passbolt/passbolt_docker/pull/123) + +### Fixed + +- Now passbolt checks for the mysql status outside of the docker image [#97](https://github.com/passbolt/passbolt_docker/issues/97) ## [2.7.1](https://github.com/passbolt/passbolt_docker/compare/v2.7.0...v2.7.1) - 2019-02-13 diff --git a/Dockerfile b/Dockerfile index f447add..ef679f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM php:7.2-fpm LABEL maintainer="diego@passbolt.com" -ARG PASSBOLT_VERSION="2.7.1" +ARG PASSBOLT_VERSION="2.8.1" ARG PASSBOLT_URL="https://github.com/passbolt/passbolt_api/archive/v${PASSBOLT_VERSION}.tar.gz" ARG PHP_EXTENSIONS="gd \ @@ -78,6 +78,7 @@ RUN apt-get update \ COPY conf/passbolt.conf /etc/nginx/conf.d/default.conf COPY conf/supervisor/*.conf /etc/supervisor/conf.d/ COPY bin/docker-entrypoint.sh /docker-entrypoint.sh +COPY scripts/wait-for.sh /usr/bin/wait-for.sh EXPOSE 80 443 diff --git a/README.md b/README.md index bccb848..8917fcf 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Passbolt docker image provides several environment variables to configure differ | Variable name | Description | Default value | | ----------------------------------- | -------------------------------- | ------------------- | +| APP_BASE | it allows people to specify the base subdir the application is running in | null | | APP_FULL_BASE_URL | Passbolt base url | false | | DATASOURCES_DEFAULT_HOST | Database hostname | localhost | | DATASOURCES_DEFAULT_PORT | Database port | 3306 | diff --git a/bin/docker-entrypoint.sh b/bin/docker-entrypoint.sh index 28e95d4..70b225d 100755 --- a/bin/docker-entrypoint.sh +++ b/bin/docker-entrypoint.sh @@ -70,29 +70,18 @@ gen_ssl_cert() { } install() { - tables=$(mysql \ - -u "${DATASOURCES_DEFAULT_USERNAME:-passbolt}" \ - -h "${DATASOURCES_DEFAULT_HOST:-localhost}" \ - -P "${DATASOURCES_DEFAULT_PORT:-3306}" \ - -BN -e "SHOW TABLES FROM ${DATASOURCES_DEFAULT_DATABASE:-passbolt}" \ - -p"${DATASOURCES_DEFAULT_PASSWORD:-P4ssb0lt}" |wc -l) - app_config="/var/www/passbolt/config/app.php" + local app_config="/var/www/passbolt/config/app.php" if [ ! -f "$app_config" ]; then su -c 'cp /var/www/passbolt/config/app.default.php /var/www/passbolt/config/app.php' -s /bin/bash www-data fi - if [ -z "${PASSBOLT_GPG_SERVER_KEY_FINGERPRINT+xxx}" ]; then + if [ -z "${PASSBOLT_GPG_SERVER_KEY_FINGERPRINT+xxx}" ] && [ ! -f '/var/www/passbolt/config/passbolt.php' ]; then gpg_auto_fingerprint="$(su -c "gpg --list-keys --with-colons ${PASSBOLT_KEY_EMAIL:-passbolt@yourdomain.com} |grep fpr |head -1| cut -f10 -d:" -ls /bin/bash www-data)" export PASSBOLT_GPG_SERVER_KEY_FINGERPRINT=$gpg_auto_fingerprint fi - if [ "$tables" -eq 0 ]; then - su -c '/var/www/passbolt/bin/cake passbolt install --no-admin' -s /bin/bash www-data - else - su -c '/var/www/passbolt/bin/cake passbolt migrate' -s /bin/bash www-data - echo "Enjoy! ☮" - fi + su -c '/var/www/passbolt/bin/cake passbolt install --no-admin' -s /bin/bash www-data || su -c '/var/www/passbolt/bin/cake passbolt migrate' -s /bin/bash www-data && echo "Enjoy! ☮" } email_cron_job() { diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 0ff4ac0..d0818de 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -21,7 +21,6 @@ services: volumes: - gpg_volume:/var/www/passbolt/config/gpg - images_volume:/var/www/passbolt/webroot/img/public/images - - ./scripts/wait-for.sh:/usr/bin/wait-for.sh command: ["/usr/bin/wait-for.sh", "db:3306", "--", "/docker-entrypoint.sh"] ports: - 80:80 diff --git a/docker-compose-pro.yml b/docker-compose-pro.yml index d3077ff..31f8759 100644 --- a/docker-compose-pro.yml +++ b/docker-compose-pro.yml @@ -10,7 +10,7 @@ services: - "127.0.0.1:3306:3306" passbolt: - image: passbolt/passbolt:2.7.1-pro-debian + image: passbolt/passbolt:2.8.1-pro-debian tty: true depends_on: - db @@ -20,7 +20,6 @@ services: - gpg_volume:/var/www/passbolt/config/gpg - images_volume:/var/www/passbolt/webroot/img/public - ./license:/var/www/passbolt/config/license - - ./scripts/wait-for.sh:/usr/bin/wait-for.sh tmpfs: - /run command: ["/usr/bin/wait-for.sh", "db:3306", "--", "/docker-entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index a225b86..27eed0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,7 +10,7 @@ services: - "127.0.0.1:3306:3306" passbolt: - image: passbolt/passbolt:2.7.1-debian + image: passbolt/passbolt:2.8.1-debian tty: true depends_on: - db @@ -19,7 +19,6 @@ services: volumes: - gpg_volume:/var/www/passbolt/config/gpg - images_volume:/var/www/passbolt/webroot/img/public - - ./scripts/wait-for.sh:/usr/bin/wait-for.sh tmpfs: - /run command: ["/usr/bin/wait-for.sh", "db:3306", "--", "/docker-entrypoint.sh"] diff --git a/spec/docker_image/image_spec.rb b/spec/docker_image/image_spec.rb index 2152e53..1620270 100644 --- a/spec/docker_image/image_spec.rb +++ b/spec/docker_image/image_spec.rb @@ -34,6 +34,7 @@ describe 'Dockerfile' do 'curl', 'gd', 'intl', 'json', 'mcrypt', 'mysqlnd', 'xsl', 'phar', 'posix', 'xml', 'zlib', 'ctype', 'pdo', 'gnupg', 'pdo_mysql' ] } + let(:wait_for) { '/usr/bin/wait-for.sh' } describe 'passbolt required php extensions' do it 'has php extensions installed' do @@ -61,6 +62,12 @@ describe 'Dockerfile' do end end + describe 'wait-for' do + it 'is installed' do + expect(file(wait_for)).to exist and be_executable + end + end + describe 'passbolt directory structure' do it 'must exist and be directories' do expect(file(passbolt_home)).to be_a_directory diff --git a/spec/docker_runtime_no_envs/runtime_no_envs_spec.rb b/spec/docker_runtime_no_envs/runtime_no_envs_spec.rb new file mode 100644 index 0000000..3672732 --- /dev/null +++ b/spec/docker_runtime_no_envs/runtime_no_envs_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +describe 'passbolt_api service' do + + before(:all) do + @mysql_image = Docker::Image.create('fromImage' => 'mariadb:latest') + @mysql = Docker::Container.create( + 'Env' => [ + 'MYSQL_ROOT_PASSWORD=test', + 'MYSQL_DATABASE=passbolt', + 'MYSQL_USER=passbolt', + 'MYSQL_PASSWORD=±!@#$%^&*()_+=-}{|:;<>?' + ], + "Healthcheck" => { + "Test": [ + "CMD-SHELL", + "mysqladmin ping --silent" + ] + }, + 'Image' => @mysql_image.id) + @mysql.start + + while @mysql.json['State']['Health']['Status'] != 'healthy' + sleep 1 + end + + @image = Docker::Image.build_from_dir(ROOT_DOCKERFILES) + + @container = Docker::Container.create( + 'Env' => [ + "DATASOURCES_DEFAULT_HOST=#{@mysql.json['NetworkSettings']['IPAddress']}", + ], + 'Binds' => [ "#{FIXTURES_PATH + '/passbolt.php'}:/var/www/passbolt/config/passbolt.php" ], + 'Image' => @image.id) + + @container.start + @container.logs(stdout: true) + + set :docker_container, @container.id + sleep 17 + end + + after(:all) do + @mysql.kill + @container.kill + end + + let(:passbolt_host) { @container.json['NetworkSettings']['IPAddress'] } + let(:uri) { "/healthcheck/status.json" } + let(:curl) { "curl -sk -o /dev/null -w '%{http_code}' -H 'Host: passbolt.local' https://#{passbolt_host}/#{uri}" } + + describe 'php service' do + it 'is running supervised' do + expect(service('php-fpm')).to be_running.under('supervisor') + end + + it 'has its port open' do + expect(@container.json['Config']['ExposedPorts']).to have_key('9000/tcp') + end + end + + describe 'email cron' do + it 'is running supervised' do + expect(service('cron')).to be_running.under('supervisor') + end + end + + describe 'web service' do + it 'is running supervised' do + expect(service('nginx')).to be_running.under('supervisor') + end + + it 'is listening on port 80' do + expect(@container.json['Config']['ExposedPorts']).to have_key('80/tcp') + end + + it 'is listening on port 443' do + expect(@container.json['Config']['ExposedPorts']).to have_key('443/tcp') + end + end + + describe 'passbolt status' do + it 'returns 200' do + expect(command(curl).stdout).to eq '200' + end + end + + describe 'passbolt serverkey unaccessible' do + let(:uri) { '/config/gpg/serverkey.asc' } + it "returns 404" do + expect(command(curl).stdout).to eq '404' + end + end + + describe 'passbolt serverkey private unaccessible' do + let(:uri) { '/config/gpg/serverkey_private.asc' } + it 'returns 404' do + expect(command(curl).stdout).to eq '404' + end + end + + describe 'passbolt conf unaccessible' do + let(:uri) { '/config/app.php' } + it 'returns 404' do + expect(command(curl).stdout).to eq '404' + end + end + describe 'passbolt tmp folder is unaccessible' do + let(:uri) { '/tmp/cache/database/empty' } + it 'returns 404' do + expect(command(curl).stdout).to eq '404' + end + end + + describe 'hide information' do + let(:curl) { "curl -Isk -H 'Host: passbolt.local' https://#{passbolt_host}/" } + it 'hides php version' do + expect(command("#{curl} | grep 'X-Powered-By: PHP'").stdout).to be_empty + end + + it 'hides nginx version' do + expect(command("#{curl} | grep 'Server:'").stdout.strip).to match(/^Server:\s+nginx$/) + end + end + +end diff --git a/spec/fixtures/passbolt.php b/spec/fixtures/passbolt.php new file mode 100644 index 0000000..88d159a --- /dev/null +++ b/spec/fixtures/passbolt.php @@ -0,0 +1,142 @@ + [ + // A base URL to use for absolute links. + // The url where the passbolt instance will be reachable to your end users. + // This information is need to render images in emails for example + 'fullBaseUrl' => 'https://passbolt.local', + ], + + // Database configuration. + 'Datasources' => [ + 'default' => [ + //'host' => 'db', + //'port' => 'non_standard_port_number', + 'username' => 'passbolt', + 'password' => '±!@#$%^&*()_+=-}{|:;<>?', + 'database' => 'passbolt', + ], + ], + + // Email configuration. + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => 'user', + 'password' => 'secret', + // Is this a secure connection? true if yes, null if no. + 'tls' => null, + //'timeout' => 30, + //'client' => null, + //'url' => null, + ], + ], + 'Email' => [ + 'default' => [ + // Defines the default name and email of the sender of the emails. + 'from' => ['passbolt@your_organization.com' => 'Passbolt'], + //'charset' => 'utf-8', + //'headerCharset' => 'utf-8', + ], + ], + + /** + * DEFAULT PASSBOLT CONFIGURATION + * + * This is the default configuration. + * It enforces the use of ssl, and does not provide a default OpenPGP key. + * If your objective is to try passbolt quickly for evaluation purpose, and security is not important + * you can use the demo config example provided in the next section below. + */ + 'passbolt' => [ + // GPG Configuration. + // The keyring must to be owned and accessible by the webserver user. + // Example: www-data user on Debian + 'gpg' => [ + // Tell GPG where to find the keyring. + // If putenv is set to false, gnupg will use the default path ~/.gnupg. + // For example : + // - Apache on Centos it would be in '/usr/share/httpd/.gnupg' + // - Apache on Debian it would be in '/var/www/.gnupg' + // - Nginx on Centos it would be in '/var/lib/nginx/.gnupg' + // - etc. + 'keyring' => '/home/www-data/.gnupg', + // + // Replace GNUPGHOME with above value even if it is set. + //'putenv' => false, + + // Main server key. + 'serverKey' => [ + // Server private key fingerprint. + 'fingerprint' => '2FC8945833C51946E937F9FED47B0811573EE67E', + 'public' => CONFIG . DS . 'gpg' . DS . 'unsecure.key', + 'private' => CONFIG . DS . 'gpg' . DS . 'unsecure_private.key', + ], + ], + ], + +/** + * DEMO CONFIGURATION EXAMPLE + * + * Uncomment the lines below if you want to try passbolt quickly. + * and if you are not concerned about the security of your installation. + * (Don't forget to comment the default config above). + */ +// 'debug' => true, +// 'passbolt' => [ +// 'registration' => [ +// 'public' => true +// ], +// 'ssl' => [ +// 'force' => false, +// ], +// 'gpg' => [ +// 'serverKey' => [ +// 'fingerprint' => '2FC8945833C51946E937F9FED47B0811573EE67E', +// 'public' => CONFIG . DS . 'gpg' . DS . 'unsecure.key', +// 'private' => CONFIG . DS . 'gpg' . DS . 'unsecure_private.key', +// ], +// ], +// ] + +]; diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9620baa..39299aa 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,7 @@ require 'serverspec' require 'docker' ROOT_DOCKERFILES = File.expand_path('../../', __FILE__) +FIXTURES_PATH = File::expand_path("fixtures", File::dirname(__FILE__)) set :backend, :docker Docker.options[:read_timeout] = 3600