From 2199d803e4f80553448795f979836fe6aa3a353d Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 11 Jan 2019 16:34:21 +0100 Subject: Vendor gitlab-shell at 6c5b195353a632095d7f6 --- .../unreleased/vendor-gitlab-shell-20190111.yml | 5 + ruby/vendor/gitlab-shell/.codeclimate.yml | 19 + ruby/vendor/gitlab-shell/.gitignore | 18 + ruby/vendor/gitlab-shell/.gitlab-ci.yml | 142 ++++++ ruby/vendor/gitlab-shell/.rubocop.yml | 72 +++ ruby/vendor/gitlab-shell/.ruby-version | 1 + ruby/vendor/gitlab-shell/CHANGELOG | 481 ++++++++++++++++++ ruby/vendor/gitlab-shell/CONTRIBUTING.md | 51 ++ ruby/vendor/gitlab-shell/Gemfile | 11 + ruby/vendor/gitlab-shell/Gemfile.lock | 104 ++++ ruby/vendor/gitlab-shell/LICENSE | 25 + ruby/vendor/gitlab-shell/README.md | 5 + ruby/vendor/gitlab-shell/README.orig.md | 131 +++++ ruby/vendor/gitlab-shell/VERSION | 1 + ruby/vendor/gitlab-shell/bin/authorized_keys | 25 + ruby/vendor/gitlab-shell/bin/check | 42 ++ ruby/vendor/gitlab-shell/bin/compile | 17 + ruby/vendor/gitlab-shell/bin/create-hooks | 46 ++ ruby/vendor/gitlab-shell/bin/gitlab-keys | 27 + .../bin/gitlab-shell-authorized-keys-check | 42 ++ .../bin/gitlab-shell-authorized-principals-check | 36 ++ ruby/vendor/gitlab-shell/bin/gitlab-shell-ruby | 28 ++ ruby/vendor/gitlab-shell/bin/install | 33 ++ ruby/vendor/gitlab-shell/bin/test-logger | 10 + ruby/vendor/gitlab-shell/config.yml.example | 58 +++ ruby/vendor/gitlab-shell/hooks/post-receive | 22 + ruby/vendor/gitlab-shell/hooks/pre-receive | 32 ++ ruby/vendor/gitlab-shell/hooks/update | 18 + ruby/vendor/gitlab-shell/lib/action.rb | 4 + ruby/vendor/gitlab-shell/lib/action/custom.rb | 144 ++++++ ruby/vendor/gitlab-shell/lib/gitlab_access.rb | 43 ++ .../gitlab-shell/lib/gitlab_access_status.rb | 44 ++ ruby/vendor/gitlab-shell/lib/gitlab_config.rb | 56 +++ ruby/vendor/gitlab-shell/lib/gitlab_custom_hook.rb | 98 ++++ ruby/vendor/gitlab-shell/lib/gitlab_init.rb | 7 + ruby/vendor/gitlab-shell/lib/gitlab_keys.rb | 190 +++++++ .../gitlab-shell/lib/gitlab_lfs_authentication.rb | 30 ++ ruby/vendor/gitlab-shell/lib/gitlab_logger.rb | 120 +++++ ruby/vendor/gitlab-shell/lib/gitlab_metrics.rb | 59 +++ ruby/vendor/gitlab-shell/lib/gitlab_net.rb | 165 ++++++ ruby/vendor/gitlab-shell/lib/gitlab_net/errors.rb | 4 + .../vendor/gitlab-shell/lib/gitlab_post_receive.rb | 119 +++++ ruby/vendor/gitlab-shell/lib/gitlab_shell.rb | 270 ++++++++++ ruby/vendor/gitlab-shell/lib/hooks_utils.rb | 15 + ruby/vendor/gitlab-shell/lib/http_helper.rb | 125 +++++ ruby/vendor/gitlab-shell/lib/httpunix.rb | 54 ++ ruby/vendor/gitlab-shell/lib/object_dirs_helper.rb | 39 ++ .../vendor/gitlab-shell/spec/gitlab_access_spec.rb | 75 +++ .../vendor/gitlab-shell/spec/gitlab_config_spec.rb | 40 ++ .../gitlab-shell/spec/gitlab_custom_hook_spec.rb | 295 +++++++++++ ruby/vendor/gitlab-shell/spec/gitlab_keys_spec.rb | 372 ++++++++++++++ .../spec/gitlab_lfs_authentication_spec.rb | 37 ++ .../vendor/gitlab-shell/spec/gitlab_logger_spec.rb | 145 ++++++ .../gitlab-shell/spec/gitlab_metrics_spec.rb | 40 ++ ruby/vendor/gitlab-shell/spec/gitlab_net_spec.rb | 554 +++++++++++++++++++++ .../gitlab-shell/spec/gitlab_post_receive_spec.rb | 270 ++++++++++ .../gitlab_shell_authorized_keys_check_spec.rb | 117 +++++ ruby/vendor/gitlab-shell/spec/gitlab_shell_spec.rb | 477 ++++++++++++++++++ ruby/vendor/gitlab-shell/spec/hooks_utils_spec.rb | 28 ++ ruby/vendor/gitlab-shell/spec/httpunix_spec.rb | 58 +++ .../gitlab-shell/spec/object_dirs_helper_spec.rb | 95 ++++ ruby/vendor/gitlab-shell/spec/spec_helper.rb | 16 + .../gitlab-shell/spec/support/gl_id_test_hook | 2 + ruby/vendor/gitlab-shell/spec/support/hook_fail | 3 + ruby/vendor/gitlab-shell/spec/support/hook_ok | 3 + .../gitlab-shell/spec/support/http_unix_server.rb | 35 ++ ruby/vendor/gitlab-shell/spec/support/vcr.rb | 7 + ruby/vendor/gitlab-shell/spec/support/webmock.rb | 3 + .../spec/vcr_cassettes/allowed-pull.yml | 46 ++ ...llowed-push-project-not-found-404-text-html.yml | 46 ++ ...lowed-push-project-not-found-404-text-plain.yml | 46 ++ .../allowed-push-project-not-found-404.yml | 46 ++ .../allowed-push-project-not-found-text-html.yml | 46 ++ .../allowed-push-project-not-found-text-plain.yml | 46 ++ .../allowed-push-project-not-found.yml | 46 ++ .../spec/vcr_cassettes/allowed-push.yml | 46 ++ .../spec/vcr_cassettes/broadcast_message-none.yml | 46 ++ .../spec/vcr_cassettes/broadcast_message-ok.yml | 46 ++ .../gitlab-shell/spec/vcr_cassettes/check-ok.yml | 46 ++ .../vcr_cassettes/custom-action-not-ok-json.yml | 40 ++ .../custom-action-not-ok-not-json.yml | 40 ++ .../vcr_cassettes/custom-action-ok-not-json.yml | 51 ++ .../custom-action-ok-with-message.yml | 99 ++++ .../spec/vcr_cassettes/custom-action-ok.yml | 99 ++++ .../spec/vcr_cassettes/discover-ok.yml | 46 ++ .../spec/vcr_cassettes/http-pull-disabled.yml | 46 ++ .../spec/vcr_cassettes/http-push-disabled.yml | 46 ++ .../vcr_cassettes/lfs-authenticate-ok-download.yml | 46 ++ .../vcr_cassettes/lfs-authenticate-ok-upload.yml | 46 ++ .../spec/vcr_cassettes/notify-post-receive.yml | 46 ++ .../spec/vcr_cassettes/post-receive-not-found.yml | 42 ++ .../spec/vcr_cassettes/post-receive.yml | 46 ++ .../spec/vcr_cassettes/pre-receive-not-found.yml | 42 ++ .../spec/vcr_cassettes/pre-receive.yml | 46 ++ .../spec/vcr_cassettes/ssh-key-not-found.yml | 44 ++ .../spec/vcr_cassettes/ssh-key-not-implemented.yml | 44 ++ .../gitlab-shell/spec/vcr_cassettes/ssh-key-ok.yml | 47 ++ .../spec/vcr_cassettes/ssh-pull-disabled.yml | 46 ++ .../ssh-pull-project-denied-401-text-html.yml | 46 ++ .../ssh-pull-project-denied-401-text-plain.yml | 46 ++ .../vcr_cassettes/ssh-pull-project-denied-401.yml | 46 ++ .../ssh-pull-project-denied-with-user.yml | 46 ++ .../spec/vcr_cassettes/ssh-pull-project-denied.yml | 46 ++ .../spec/vcr_cassettes/ssh-push-disabled.yml | 46 ++ .../ssh-push-project-denied-401-text-html.yml | 46 ++ .../ssh-push-project-denied-401-text-plain.yml | 46 ++ .../vcr_cassettes/ssh-push-project-denied-401.yml | 46 ++ .../spec/vcr_cassettes/ssh-push-project-denied.yml | 46 ++ .../two-factor-recovery-codes-fail.yml | 46 ++ .../vcr_cassettes/two-factor-recovery-codes.yml | 46 ++ 110 files changed, 7780 insertions(+) create mode 100644 changelogs/unreleased/vendor-gitlab-shell-20190111.yml create mode 100644 ruby/vendor/gitlab-shell/.codeclimate.yml create mode 100644 ruby/vendor/gitlab-shell/.gitignore create mode 100644 ruby/vendor/gitlab-shell/.gitlab-ci.yml create mode 100644 ruby/vendor/gitlab-shell/.rubocop.yml create mode 100644 ruby/vendor/gitlab-shell/.ruby-version create mode 100644 ruby/vendor/gitlab-shell/CHANGELOG create mode 100644 ruby/vendor/gitlab-shell/CONTRIBUTING.md create mode 100644 ruby/vendor/gitlab-shell/Gemfile create mode 100644 ruby/vendor/gitlab-shell/Gemfile.lock create mode 100644 ruby/vendor/gitlab-shell/LICENSE create mode 100644 ruby/vendor/gitlab-shell/README.md create mode 100644 ruby/vendor/gitlab-shell/README.orig.md create mode 100644 ruby/vendor/gitlab-shell/VERSION create mode 100755 ruby/vendor/gitlab-shell/bin/authorized_keys create mode 100755 ruby/vendor/gitlab-shell/bin/check create mode 100755 ruby/vendor/gitlab-shell/bin/compile create mode 100755 ruby/vendor/gitlab-shell/bin/create-hooks create mode 100755 ruby/vendor/gitlab-shell/bin/gitlab-keys create mode 100755 ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-keys-check create mode 100755 ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-principals-check create mode 100755 ruby/vendor/gitlab-shell/bin/gitlab-shell-ruby create mode 100755 ruby/vendor/gitlab-shell/bin/install create mode 100755 ruby/vendor/gitlab-shell/bin/test-logger create mode 100644 ruby/vendor/gitlab-shell/config.yml.example create mode 100755 ruby/vendor/gitlab-shell/hooks/post-receive create mode 100755 ruby/vendor/gitlab-shell/hooks/pre-receive create mode 100755 ruby/vendor/gitlab-shell/hooks/update create mode 100644 ruby/vendor/gitlab-shell/lib/action.rb create mode 100644 ruby/vendor/gitlab-shell/lib/action/custom.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_access.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_access_status.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_config.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_custom_hook.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_init.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_keys.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_lfs_authentication.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_logger.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_metrics.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_net.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_net/errors.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_post_receive.rb create mode 100644 ruby/vendor/gitlab-shell/lib/gitlab_shell.rb create mode 100644 ruby/vendor/gitlab-shell/lib/hooks_utils.rb create mode 100644 ruby/vendor/gitlab-shell/lib/http_helper.rb create mode 100644 ruby/vendor/gitlab-shell/lib/httpunix.rb create mode 100644 ruby/vendor/gitlab-shell/lib/object_dirs_helper.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_access_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_config_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_custom_hook_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_keys_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_lfs_authentication_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_logger_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_metrics_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_net_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_post_receive_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_shell_authorized_keys_check_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/gitlab_shell_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/hooks_utils_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/httpunix_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/object_dirs_helper_spec.rb create mode 100644 ruby/vendor/gitlab-shell/spec/spec_helper.rb create mode 100755 ruby/vendor/gitlab-shell/spec/support/gl_id_test_hook create mode 100755 ruby/vendor/gitlab-shell/spec/support/hook_fail create mode 100755 ruby/vendor/gitlab-shell/spec/support/hook_ok create mode 100644 ruby/vendor/gitlab-shell/spec/support/http_unix_server.rb create mode 100644 ruby/vendor/gitlab-shell/spec/support/vcr.rb create mode 100644 ruby/vendor/gitlab-shell/spec/support/webmock.rb create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-pull.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-html.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-plain.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-html.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-plain.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-none.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-ok.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/check-ok.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-json.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-not-json.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-not-json.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-with-message.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/discover-ok.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-pull-disabled.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-push-disabled.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-download.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-upload.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/notify-post-receive.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive-not-found.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive-not-found.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-found.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-implemented.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-ok.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-disabled.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-html.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-plain.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-with-user.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-disabled.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-html.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-plain.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes-fail.yml create mode 100644 ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes.yml diff --git a/changelogs/unreleased/vendor-gitlab-shell-20190111.yml b/changelogs/unreleased/vendor-gitlab-shell-20190111.yml new file mode 100644 index 000000000..208ae4919 --- /dev/null +++ b/changelogs/unreleased/vendor-gitlab-shell-20190111.yml @@ -0,0 +1,5 @@ +--- +title: Vendor gitlab-shell at 6c5b195353a632095d7f6 +merge_request: 1037 +author: +type: other diff --git a/ruby/vendor/gitlab-shell/.codeclimate.yml b/ruby/vendor/gitlab-shell/.codeclimate.yml new file mode 100644 index 000000000..172b2e384 --- /dev/null +++ b/ruby/vendor/gitlab-shell/.codeclimate.yml @@ -0,0 +1,19 @@ +--- +engines: + bundler-audit: + enabled: true + duplication: + enabled: true + config: + languages: + - ruby + fixme: + enabled: true + rubocop: + enabled: true +exclude_paths: +- spec/ +- lib/vendor/ +- go/vendor/ +- tmp/ +- coverage/ diff --git a/ruby/vendor/gitlab-shell/.gitignore b/ruby/vendor/gitlab-shell/.gitignore new file mode 100644 index 000000000..4ea71fb3f --- /dev/null +++ b/ruby/vendor/gitlab-shell/.gitignore @@ -0,0 +1,18 @@ +config.yml +tmp/* +.idea +*.log +/*.log* +authorized_keys.lock +coverage/ +.gitlab_shell_secret +.bundle +tags +.bundle/ +custom_hooks +hooks/*.d +/go_build +/bin/gitlab-shell +/bin/gitaly-upload-pack +/bin/gitaly-receive-pack +/bin/gitaly-upload-archive diff --git a/ruby/vendor/gitlab-shell/.gitlab-ci.yml b/ruby/vendor/gitlab-shell/.gitlab-ci.yml new file mode 100644 index 000000000..72b886427 --- /dev/null +++ b/ruby/vendor/gitlab-shell/.gitlab-ci.yml @@ -0,0 +1,142 @@ +image: "ruby:2.3" + +variables: + INSTALL_BUNDLER_VERSION: "~> 2.0.1" + +before_script: + - export PATH=~/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin + - gem install --force --bindir /usr/local/bin bundler -v "$INSTALL_BUNDLER_VERSION" + - cp config.yml.example config.yml + - bundle install + +.rspec_definition: &rspec_definition + script: + # Skip the experimental Golang wrapper in the Ruby specs. These are now + # primarily regression tests for particular versions of Ruby. + # + # The full rspec suite is also run against each suppported golang version + - cp bin/gitlab-shell-ruby bin/gitlab-shell + - bundle exec rspec --color --tag ~go --format d spec + +rspec: + <<: *rspec_definition + tags: + - ruby + except: + - tags + +rubocop: + script: + - bundle exec rubocop + tags: + - ruby + except: + - tags + +#ruby 2.2 +rspec:ruby2.2: + image: ruby:2.2 + variables: + INSTALL_BUNDLER_VERSION: ~> 1.17.3 + <<: *rspec_definition + tags: + - ruby + except: + - tags + +#ruby 2.1 +rspec:ruby2.1: + image: ruby:2.1 + variables: + INSTALL_BUNDLER_VERSION: ~> 1.17.3 + <<: *rspec_definition + tags: + - ruby + except: + - tags + +.go: &go_definition + before_script: + - apt-get update -qq && apt-get install -y ruby ruby-dev + - ruby -v + - export PATH=~/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin + - gem install --bindir /usr/local/bin bundler + - cp config.yml.example config.yml + - bundle install + script: + - go version + - which go + - bin/compile + - support/go-test + - support/go-format check + # Run the full Ruby test suite in the "go" tests. As more functionality is + # migrated into these tests and out of Ruby, the amount of work here will + # reduce + - bundle exec rspec --color --format d spec + +go:1.9: + <<: *go_definition + image: golang:1.9 + +go:1.10: + <<: *go_definition + image: golang:1.10 + +go:1.11: + <<: *go_definition + image: golang:1.10 + +codequality: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + before_script: [] + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SOURCE_CODE="$PWD" + --volume "$PWD":/code + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code + artifacts: + paths: [codeclimate.json] + + +sast: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + before_script: [] + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}" + --volume "$PWD:/code" + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code + artifacts: + paths: [gl-sast-report.json] + +dependency_scanning: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + before_script: [] + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}" + --volume "$PWD:/code" + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code + artifacts: + paths: [gl-dependency-scanning-report.json] diff --git a/ruby/vendor/gitlab-shell/.rubocop.yml b/ruby/vendor/gitlab-shell/.rubocop.yml new file mode 100644 index 000000000..66b795173 --- /dev/null +++ b/ruby/vendor/gitlab-shell/.rubocop.yml @@ -0,0 +1,72 @@ +# Exclude some of GitLab files +AllCops: + Exclude: + - 'spec/**/*' + - 'vendor/**/*' + - 'tmp/**/*' + - 'bin/**/*' + - 'hooks/**/*' + - 'Guardfile' + +Layout/DotPosition: + Enabled: false + +Lint/AmbiguousBlockAssociation: + Enabled: false + +Metrics/LineLength: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/BlockLength: + Enabled: false + +Metrics/ParameterLists: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/PerceivedComplexity: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/StringLiterals: + Enabled: false + +Style/StringLiterals: + Enabled: false + +Style/GlobalVars: + Enabled: false + +Style/AccessorMethodName: + Enabled: false + +Style/GuardClause: + Enabled: false + +Style/RescueModifier: + Enabled: false + +Style/PercentLiteralDelimiters: + Enabled: false + +Style/IfUnlessModifier: + Enabled: false + +Style/RegexpLiteral: + Enabled: false + +Style/SpecialGlobalVars: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false diff --git a/ruby/vendor/gitlab-shell/.ruby-version b/ruby/vendor/gitlab-shell/.ruby-version new file mode 100644 index 000000000..00355e29d --- /dev/null +++ b/ruby/vendor/gitlab-shell/.ruby-version @@ -0,0 +1 @@ +2.3.7 diff --git a/ruby/vendor/gitlab-shell/CHANGELOG b/ruby/vendor/gitlab-shell/CHANGELOG new file mode 100644 index 000000000..592e99d5f --- /dev/null +++ b/ruby/vendor/gitlab-shell/CHANGELOG @@ -0,0 +1,481 @@ +v8.4.4 + - Pass push options along to gitlab-rails's post-receive endpoint + +v8.4.3 + - Remove circular dependency between HTTPHelper and GitlabNet !258 + +v8.4.2 + - Include LFS operation when requesting auth !254 + +v8.4.1 + - Surface error message sent along with API Service Unavailable error to user + +v8.4.0 + - Use Gitaly v2 auth scheme + +v8.3.3 + - Release v8.3.3 as v8.3.2 tag is incorrect + +v8.3.2 + - Ensure text/plain & text/html content types are handled !239 + - Fix newlines not appearing between new log entries !242 + +v8.3.1 + - No changes (version tag correction) + +v8.3.0 + - Add custom action (e.g. proxying SSH push) support + +v8.2.1 + - Fix HTTP status code handling for /api/v4/allowed API endpoint + +v8.2.0 + - Pass custom git_config_options to Gitaly !221 + - Add missing require statement in create-hooks !225 + +v8.1.1 + - Fix two regressions in SSH certificate support (!226) + +v8.1.0 + - Support Git v2 protocol (!217) + +v8.0.0 + - SSH certificate support (!207) + +v7.2.0 + - Update gitaly-proto to 0.109.0 (!216) + +v7.1.5 + - Fix a NoMethodError in the pre-receive hook (!206) + +v7.1.4 + - Don't truncate long strings in broadcast message (!202) + +v7.1.3 + - Use username instead of full name for identifying users (!204) + +v7.1.2 + - Add missing GitlabLogger#error method (!200) + +v7.1.1 + - Flush log file after every write (!199) + +v7.1.0 + - Migrate `git-upload-archive` to gitaly + +v7.0.0 + - Switch to structured logging (!193) + +v6.0.4 + - Don't delete GL_REPOSITORY environment variable from post-receive hook (!191) + +v6.0.3 + - Print new project information in post-receive + +v6.0.2 + - Use grpc-go 1.9.1 (!184) + - Update gitaly-proto and gitaly libs (!185) + +v6.0.1 + - Fix git push by removing a bad require in the pre-receive hook (!183) + +v6.0.0 + - Remove bin/gitlab_projects (!180) + - Remove direct redis integration (!181) + - Remove support unhiding of all references for Geo nodes (!179) + +v5.11.0 + - Introduce a more-complete implementation of bin/authorized_keys (!178) + +v5.10.3 + - Remove unused redis bin configuration + +v5.10.2 + - Print redirection message when pushing into renamed project + +v5.10.1 + - Use 'git clone --no-local' when creating a fork (!176) + +v5.10.0 + - Add a 'fork-repository' command that works with hashed storage (!174) + +v5.9.4 + - Add relative git object dir envvars to check access request + +v5.9.3 + - Expose GitLab username to hooks in `GL_USERNAME` environment variable + +v5.9.2 + - Fix pre-receive error when gitlab doesn't have /internal/pre_receive (!169) + +v5.9.1 + - Adds --force option to push branches + +v5.9.0 + - Support new /internal/pre-receive API endpoint for post-receive operations + - Support new /internal/post-receive API endpoint for post-receive operations + - Support `redis` field on /internal/check API endpoint + +v5.8.1 + - Support old versions of ruby without monotonic clock + +v5.8.0 + - Fix SSH support for Git for Windows v2.14 + +v5.7.0 + - Support unhiding of all refs via Gitaly + +v5.6.2 + - Bump redis-rb library to 3.3.3 + +v5.6.1 + - Fix setting permissions of SSH key tempfiles + - Fix a missing constant error when using SSH authentication + +v5.6.0 + - SSH authentication support + +v5.5.0 + - Support unhiding of all references for Geo nodes + +v5.4.0 + - Update Gitaly vendoring to use new RPC calls instead of old deprecated ones + +v5.3.1 + - Gracefully handle internal API errors when getting merge request URLs + +v5.3.0 + - Add ability to have git-receive-pack and git-upload-pack to go over Gitaly + +v5.2.1 + - Revert changes in v5.2.0 + +v5.2.0 + - Disable RubyGems to increase performance + +v5.1.1 + - Revert "Remove old `project` parameter, use `gl_repository` instead" + +v5.1.0 + - Add `gitlab-keys list-key-ids` subcommand for iterating over key IDs to find keys that should be deleted + +v5.0.6 + - Remove old `project` parameter, use `gl_repository` instead + - Use v4 of the GitLab REST API + +v5.0.5 + - Use gl_repository if present when enqueing Sidekiq PostReceive jobs + +v5.0.4 + - Handle GL_REPOSITORY env variable and use it in API calls and Sidekiq enqueuing + +v5.0.3 + - Use recursive lookup for git repositories in the bin/create-hooks script + +v5.0.2 + - Adds timeout option to push branches + +v5.0.1 + - Fetch repositories with `--quiet` option by default + +v5.0.0 + - Remove support for git-annex + +v4.1.1 + - Send (a selection of) git environment variables while making the API call to `/allowed`, !112 + +v4.1.0 + - Add support for global custom hooks and chained hook directories (Elan Ruusamäe, Dirk Hörner), !113, !111, !93, !89, #32 + - Clear up text with merge request after new branch push (Lisanne Fellinger) + +v4.0.3 + - Fetch repositories with `--prune` option by default + +v4.0.2 + - Fix gitlab_custom_hook dependencies + +v4.0.1 + - Add instrumentation to push hooks + +v4.0.0 + - Use full repository path for API calls + +v3.6.6 + - Re-use the default logger when logging metrics data + +v3.6.5 + - Test against ruby 2.3 + - Instrument GitLab Shell and log metrics data to a file + +v3.6.4 + - Fix rsync with ionice command building + - Fix short circuit logic between rsync with and without ionice for storage migrations + +v3.6.3 + - Re-exposing GL_ID to custom hooks + +v3.6.2 + - Enable GIT_TRACE/GIT_TRACE_PACKET/GIT_TRACE_PERFORMANCE by providing the git_trace_log_file config key + +v3.6.1 + - Set a low IO priority for storage moves to lower performance impact + +v3.6.0 + - Added full support for `git-lfs-authenticate` to properly handle LFS requests and pass them on to Workhorse + +v3.5.0 + - Add option to recover 2FA via SSH + +v3.4.0 + - Redis Sentinel support + +v3.3.3 + - Print URL for new or existing merge request after push + +v3.3.2 + - Improve authorized_keys check + +v3.3.1 + - Manage authorized_keys permissions continuously + +v3.3.0 + - Track ongoing push commands + - Add command to move repositories between repository storages + +v3.2.1 + - Allow gitlab-project's fork-project command to fork projects between different repository storages + +v3.2.0 + - Allow GitLab Shell to check for allowed access based on the used Git protocol + - Add an error message when using shell commands with incompatible GitLab versions + +v3.1.0 + - Refactor repository paths handling to allow multiple git mount points + +v3.0.1 + - Update PostReceive worker to provide enqueued_at time. + +v3.0.0 + - Remove rm-tag command (Robert Schilling) + - Remove create-branch and rm-branch commands (Robert Schilling) + - Update PostReceive worker so it logs a unique JID in Sidekiq + - Remove update-head command + - Use Redis Ruby client instead of shelling out to redis-cli + +v2.7.2 + - Do not prune objects during 'git gc' + +v2.7.1 + - Add new command to list tags from a remote repo + - Add the ability to fetch remote repo with or without tags + +v2.7.0 + - Add support for ssh AuthorizedKeysCommand query by key + +v2.6.13 + - Add push-branches command + - Add delete-remote-branches command + +v2.6.12 + - Fix git-annex issue not working using custom SSH port repositories + +v2.6.11 + - Increase HTTP timeout and log request durations + - Workaround for a Webrick issue on Ruby 2.2 + - New optional `--force` parameter for `gitlab-projects fetch-remote` + +v2.6.10 + - Add git gc for housekeeping + +v2.6.9 + - Remove trailing slashes from gitlab_url + +v2.6.8 + - Revert git-lfs-authenticate command from white list + +v2.6.7 + - Exit with non-zero status when import-repository fails + - Add fetch-remote command + +v2.6.6 + - Do not clean LANG environment variable for the git hooks when working through the SSH-protocol + - Add git-lfs-authenticate command to white list (this command is used by git-lfs for SSO authentication through SSH-protocol) + - Handle git-annex and gcryptsetup + +v2.6.5 + - Handle broken symlinks in create-hooks + +v2.6.4 + - Remove keys from authorized_keys in-place + - Increase batch_add_keys lock timeout to 300 seconds + - If git-annex is enabled set GIT_ANNEX_SHELL_LIMITED variable + +v2.6.3 + - Prevent keys with a very specific comment from accidentally being deleted. + +v2.6.2 + - Include ecdsa keys in `gitlab_keys list-keys`. + - Refactor logic around GL_ID + +v2.6.1 + - Write errors to stderr to get git to abort and show them as such. + +v2.6.0 + - Prevent character encoding issues by sending received changes as raw data. + +v2.5.4 + - Remove recursive commands from bin/install + +v2.5.3 + - Improve git-annex integration + +v2.5.2 + - Safer line sub for git-annex command + +v2.5.1 + - Expect broadcast message to return empty JSON if no message now + +v2.5.0 + - Support git-annex tool (disabled by default) + - Add rubocop (Ruby static code analyzer) for development + +v2.4.3 + - Print broadcast message if one is available + +v2.4.2 + - Pass git changes list as string instead of array + +v2.4.1 + - Access token masking in url before loging + +v2.4.0 + - Show error message when git push is rejected + +v2.2.0 + - Support for custom hooks (Drew Blessing and Jose Kahan) + +v2.1.0 + - Use secret token with GitLab internal API. Requires GitLab 7.5 or higher + +v2.0.1 + - Send post-receive changes to redis as a string instead of array + +v2.0.0 + - Works with GitLab v7.3+ + - Replace raise with abort when checking path to prevent path exposure + - Handle invalid number of arguments on remote commands + - Replace update hook with pre-receive and post-receive hooks. + - Symlink the whole hooks directory + - Ignore missing repositories in create-hooks + - Connect to Redis via sockets by default + +v1.9.7 + - Increased test coverage + - By default use direct unicorn connection (localhost:8080) + - Fix wrong repo path send to GitLab by GitlabUpdate hook + +v1.9.6 + - Explicitly require 'timeout' from the standard library + +v1.9.5 + - Put authorized_keys.lock in the same directory as authorized_keys + - Use lock file when add new entries to authorized_keys + +v1.9.4 + - Use lock file when modify authorized_keys + +v1.9.3 + - Ignore force push detection for new branch or branch remove push + +v1.9.2 + - Add support for force push detection + +v1.9.1 + - Update hook sends branch and tag name + +v1.9.0 + - Call api in update hook for both ssdh and http push. Requires GitLab 6.7+ + - Pass oldrev and newrev to api.allowed? + +v1.8.5 + - Add `gitlab-keys batch-add-keys` subcommand for authorized_keys rebuilds + +v1.8.4 + - Dont do import if repository exists + +v1.8.3 + - Add timeout option for repository import + +v1.8.2 + - Fix broken 1.8.1 + +v1.8.1 + - Restrict Environment Variables + - Add bin/create-hooks command + - More safe shell execution + +v1.8.0 + - Fix return values in GitlabKeys + +v1.7.9 + - Fix escape of repository path for custom ssh port + +v1.7.8 + - Escape repository path to prevent relative links (CVE-2013-4583) + +v1.7.7 + - Separate options from arguments with -- (CVE-2013-4582) + - Bypass shell and use stdlib JSON for GitlabUpdate (CVE-2013-4581) + +v1.7.6 + - Fix gitlab-projects update-head for improted repo when branch exists but not listed in refs/head + +v1.7.5 + - Remove keys from authorized_keys using ruby instead of shell + +v1.7.4 + - More protection against shell injection (CVE-2013-4546) + +v1.7.3 + - Use Kernel#open to append lines to authorized_keys (CVE-2013-4490) + +v1.7.2 + - More safe command execution + +v1.7.1 + - Fixed issue when developers are able to push to protected branches that contain a '/' in the branch name. + +v1.7.0 + - Clean authorized_keys file with `gitlab-keys clear` + +v1.6.0 + - Create branch/tag functionality + - Remove branch/tag functionality + +v1.5.0 + - Logger + - Ability to specify ca_file/ca_path + - Update-head command for project + - Better regexp for key_id inside shell + +v1.4.0 + - Regex used in rm-key command was too lax + +v1.3.0 + - Fork-project command + - Custom redis configuration + - Interpret login with deploy key as anonymous one + +v1.2.0 + - Return non-zero result if gitlab-projects and gitlab-keys execution was not successful + - http_settings configuration option added + +v1.1.0 + - added mv-project feature + - increased test coverage + +v1.0.4 + - requires gitlab c9ca15e + - don't use post-receive file any more. Make all updates in update + - fixed issue with invalid GL_USER + - use GL_ID instead of GL_USER diff --git a/ruby/vendor/gitlab-shell/CONTRIBUTING.md b/ruby/vendor/gitlab-shell/CONTRIBUTING.md new file mode 100644 index 000000000..32b7d2348 --- /dev/null +++ b/ruby/vendor/gitlab-shell/CONTRIBUTING.md @@ -0,0 +1,51 @@ +## Contributing + +Thank you for your interest in contributing to this GitLab project! We welcome +all contributions. By participating in this project, you agree to abide by the +[code of conduct](#code-of-conduct). + +## Developer Certificate of Origin + License + +By contributing to GitLab B.V., You accept and agree to the following terms and +conditions for Your present and future Contributions submitted to GitLab B.V. +Except for the license granted herein to GitLab B.V. and recipients of software +distributed by GitLab B.V., You reserve all right, title, and interest in and to +Your Contributions. All Contributions are subject to the following DCO + License +terms. + +[DCO + License](https://gitlab.com/gitlab-org/dco/blob/master/README.md) + +_This notice should stay as the first item in the CONTRIBUTING.md file._ + +## Code of conduct + +As contributors and maintainers of this project, we pledge to respect all people +who contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, or religion. + +Examples of unacceptable behavior by participants include the use of sexual +language or imagery, derogatory comments or personal attacks, trolling, public +or private harassment, insults, or other unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct. Project maintainers who do not follow the +Code of Conduct may be removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior can be +reported by emailing contact@gitlab.com. + +This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0, +available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/). + +[contributor-covenant]: http://contributor-covenant.org +[individual-agreement]: https://docs.gitlab.com/ee/legal/individual_contributor_license_agreement.html +[corporate-agreement]: https://docs.gitlab.com/ee/legal/corporate_contributor_license_agreement.html diff --git a/ruby/vendor/gitlab-shell/Gemfile b/ruby/vendor/gitlab-shell/Gemfile new file mode 100644 index 000000000..4166d5071 --- /dev/null +++ b/ruby/vendor/gitlab-shell/Gemfile @@ -0,0 +1,11 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'listen', '~> 0.5.0' + gem 'rspec', '~> 3.8.0' + gem 'rspec-parameterized', '~> 0.4.0' + gem 'rubocop', '0.49.1', require: false + gem 'simplecov', '~> 0.9.0', require: false + gem 'vcr', '~> 4.0.0' + gem 'webmock', '~> 3.4.0' +end diff --git a/ruby/vendor/gitlab-shell/Gemfile.lock b/ruby/vendor/gitlab-shell/Gemfile.lock new file mode 100644 index 000000000..f23d7817c --- /dev/null +++ b/ruby/vendor/gitlab-shell/Gemfile.lock @@ -0,0 +1,104 @@ +GEM + remote: https://rubygems.org/ + specs: + abstract_type (0.0.7) + adamantium (0.2.0) + ice_nine (~> 0.11.0) + memoizable (~> 0.4.0) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + ast (2.4.0) + binding_of_caller (0.8.0) + debug_inspector (>= 0.0.1) + coderay (1.1.2) + concord (0.1.5) + adamantium (~> 0.2.0) + equalizer (~> 0.0.9) + crack (0.4.3) + safe_yaml (~> 1.0.0) + debug_inspector (0.0.3) + diff-lcs (1.3) + docile (1.1.5) + equalizer (0.0.11) + hashdiff (0.3.7) + ice_nine (0.11.2) + listen (0.5.3) + memoizable (0.4.2) + thread_safe (~> 0.3, >= 0.3.1) + multi_json (1.13.1) + parallel (1.12.1) + parser (2.5.1.2) + ast (~> 2.4.0) + powerpack (0.1.2) + proc_to_ast (0.1.0) + coderay + parser + unparser + procto (0.0.3) + public_suffix (3.0.3) + rainbow (2.2.2) + rake + rake (12.3.1) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-parameterized (0.4.0) + binding_of_caller + parser + proc_to_ast + rspec (>= 2.13, < 4) + unparser + rspec-support (3.8.0) + rubocop (0.49.1) + parallel (~> 1.10) + parser (>= 2.3.3.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + ruby-progressbar (1.9.0) + safe_yaml (1.0.4) + simplecov (0.9.2) + docile (~> 1.1.0) + multi_json (~> 1.0) + simplecov-html (~> 0.9.0) + simplecov-html (0.9.0) + thread_safe (0.3.6) + unicode-display_width (1.4.0) + unparser (0.2.8) + abstract_type (~> 0.0.7) + adamantium (~> 0.2.0) + concord (~> 0.1.5) + diff-lcs (~> 1.3) + equalizer (~> 0.0.9) + parser (>= 2.3.1.2, < 2.6) + procto (~> 0.0.2) + vcr (4.0.0) + webmock (3.4.2) + addressable (>= 2.3.6) + crack (>= 0.3.2) + hashdiff + +PLATFORMS + ruby + +DEPENDENCIES + listen (~> 0.5.0) + rspec (~> 3.8.0) + rspec-parameterized (~> 0.4.0) + rubocop (= 0.49.1) + simplecov (~> 0.9.0) + vcr (~> 4.0.0) + webmock (~> 3.4.0) + +BUNDLED WITH + 1.16.3 diff --git a/ruby/vendor/gitlab-shell/LICENSE b/ruby/vendor/gitlab-shell/LICENSE new file mode 100644 index 000000000..06c55d0ae --- /dev/null +++ b/ruby/vendor/gitlab-shell/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2011-2018 GitLab B.V. + +With regard to the GitLab Software: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +For all third party components incorporated into the GitLab Software, those +components are licensed under the original license provided by the owner of the +applicable component. diff --git a/ruby/vendor/gitlab-shell/README.md b/ruby/vendor/gitlab-shell/README.md new file mode 100644 index 000000000..c562fc44c --- /dev/null +++ b/ruby/vendor/gitlab-shell/README.md @@ -0,0 +1,5 @@ +# gitlab-shell + +Vendored from https://gitlab.com/gitlab-org/gitlab-shell at [6c5b195353a632095d7f672d28b9985fd879b077](https://gitlab.com/gitlab-org/gitlab-shell/commit/6c5b195353a632095d7f672d28b9985fd879b077). + +Original README: [README.orig.md](README.orig.md). diff --git a/ruby/vendor/gitlab-shell/README.orig.md b/ruby/vendor/gitlab-shell/README.orig.md new file mode 100644 index 000000000..55f7c61e9 --- /dev/null +++ b/ruby/vendor/gitlab-shell/README.orig.md @@ -0,0 +1,131 @@ +# GitLab Shell + +## GitLab Shell handles git SSH sessions for GitLab + +GitLab Shell handles git SSH sessions for GitLab and modifies the list of authorized keys. +GitLab Shell is not a Unix shell nor a replacement for Bash or Zsh. + +When you access the GitLab server over SSH then GitLab Shell will: + +1. Limits you to predefined git commands (git push, git pull). +1. Call the GitLab Rails API to check if you are authorized, and what Gitaly server your repository is on +1. Copy data back and forth between the SSH client and the Gitaly server + +If you access a GitLab server over HTTP(S) you end up in [gitlab-workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse). + +An overview of the four cases described above: + +1. git pull over ssh -> gitlab-shell -> API call to gitlab-rails (Authorization) -> accept or decline -> establish Gitaly session +1. git push over ssh -> gitlab-shell (git command is not executed yet) -> establish Gitaly session -> (in Gitaly) gitlab-shell pre-receive hook -> API call to gitlab-rails (authorization) -> accept or decline push + +## Git hooks + +For historical reasons the gitlab-shell repository also contains the +Git hooks that allow GitLab to validate Git pushes (e.g. "is this user +allowed to push to this protected branch"). These hooks also trigger +events in GitLab (e.g. to start a CI pipeline after a push). In +GitLab's current architecture (Q4 2018) these hooks belong to Gitaly +more than gitlab-shell. We [are moving them to the Gitaly +repository](https://gitlab.com/gitlab-org/gitaly/issues/1226). + +## Code status + +[![pipeline status](https://gitlab.com/gitlab-org/gitlab-shell/badges/master/pipeline.svg)](https://gitlab.com/gitlab-org/gitlab-shell/commits/master) +[![coverage report](https://gitlab.com/gitlab-org/gitlab-shell/badges/master/coverage.svg)](https://gitlab.com/gitlab-org/gitlab-shell/commits/master) +[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlab-shell.svg)](https://codeclimate.com/github/gitlabhq/gitlab-shell) + +## Requirements + +**GitLab shell will always use your system ruby (normally located at /usr/bin/ruby) and will not use the ruby your installed with a ruby version manager (such as RVM).** +It requires ruby 2.0 or higher. +Please uninstall any old ruby versions from your system: + +``` +sudo apt-get remove ruby1.8 +``` + +Download Ruby and compile it with: + +``` +mkdir /tmp/ruby && cd /tmp/ruby +curl -L --progress http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.gz | tar xz +cd ruby-2.1.5 +./configure --disable-install-rdoc +make +sudo make install +``` + +To install gitlab-shell you also need a Go compiler version 1.8 or newer. https://golang.org/dl/ + +## Setup + + ./bin/install + ./bin/compile + +## Check + + ./bin/check + +## Keys + +Add key: + + ./bin/gitlab-keys add-key key-782 "ssh-rsa AAAAx321..." + +Remove key: + + ./bin/gitlab-keys rm-key key-23 "ssh-rsa AAAAx321..." + +List all keys: + + ./bin/gitlab-keys list-keys + + +Remove all keys from authorized_keys file: + + ./bin/gitlab-keys clear + +## Git LFS remark + +Starting with GitLab 8.12, GitLab supports Git LFS authentication through ssh. + +## Releasing a new version + +GitLab Shell is versioned by git tags, and the version used by the Rails +application is stored in +[`GITLAB_SHELL_VERSION`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/GITLAB_SHELL_VERSION). + +For each version, there is a raw version and a tag version: + +- The **raw version** is the version number. For instance, `15.2.8`. +- The **tag version** is the raw version prefixed with `v`. For instance, `v15.2.8`. + +To release a new version of GitLab Shell and have that version available to the +Rails application: + +1. Update the [`CHANGELOG`](CHANGELOG) with the **tag version** and the + [`VERSION`](VERSION) file with the **raw version**. +2. Add a new git tag with the **tag version**. +3. Update `GITLAB_SHELL_VERSION` in the Rails application to the **raw + version**. (Note: this can be done as a separate MR to that, or in and MR + that will make use of the latest GitLab Shell changes.) + +## Updating VCR fixtures + +In order to generate new VCR fixtures you need to have a local GitLab instance +running and have next data: + +1. gitlab-org/gitlab-test project. +2. SSH key with access to the project and ID 1 that belongs to Administrator. +3. SSH key without access to the project and ID 2. + +You also need to modify `secret` variable at `spec/gitlab_net_spec.rb` so tests +can connect to your local instance. + +## Contributing + +See [CONTRIBUTING.md](./CONTRIBUTING.md). + +## License + +See [LICENSE](./LICENSE). diff --git a/ruby/vendor/gitlab-shell/VERSION b/ruby/vendor/gitlab-shell/VERSION new file mode 100644 index 000000000..2eb8a04cb --- /dev/null +++ b/ruby/vendor/gitlab-shell/VERSION @@ -0,0 +1 @@ +8.4.4 \ No newline at end of file diff --git a/ruby/vendor/gitlab-shell/bin/authorized_keys b/ruby/vendor/gitlab-shell/bin/authorized_keys new file mode 100755 index 000000000..ca0164607 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/authorized_keys @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby + +# +# GitLab shell authorized_keys. Query GitLab API to get the authorized command for a given ssh key fingerprint +# +# Ex. +# /bin/authorized_keys BASE64-KEY +# +# Returns +# command="/bin/gitlab-shell key-#",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQA... +# + +key = ARGV[0] +abort "# No key provided" if key.nil? || key.empty? + +require_relative "../lib/gitlab_init" +require_relative "../lib/gitlab_net" +require_relative "../lib/gitlab_keys" + +authorized_key = GitlabNet.new.authorized_key(key) +if authorized_key.nil? + puts "# No key was found for #{key}" +else + puts GitlabKeys.key_line("key-#{authorized_key['id']}", authorized_key["key"]) +end diff --git a/ruby/vendor/gitlab-shell/bin/check b/ruby/vendor/gitlab-shell/bin/check new file mode 100755 index 000000000..d2224a641 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/check @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +require_relative '../lib/gitlab_init' +require_relative '../lib/gitlab_net' + +# +# GitLab shell check task +# + +print "Check GitLab API access: " +begin + resp = GitlabNet.new.check + + if resp.code != "200" + abort "FAILED. code: #{resp.code}" + end + + puts 'OK' + + check_values = JSON.parse(resp.body) + + print 'Redis available via internal API: ' + if check_values['redis'] + puts 'OK' + else + abort 'FAILED' + end +rescue GitlabNet::ApiUnreachableError + abort "FAILED: Failed to connect to internal API" +end + +config = GitlabConfig.new + +abort("ERROR: missing option in config.yml") unless config.auth_file + +print "\nAccess to #{config.auth_file}: " +if system(File.dirname(__FILE__) + '/gitlab-keys', 'check-permissions') + print 'OK' +else + abort "FAILED" +end +puts "\n" diff --git a/ruby/vendor/gitlab-shell/bin/compile b/ruby/vendor/gitlab-shell/bin/compile new file mode 100755 index 000000000..fc5fb6c65 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/compile @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +require 'fileutils' + +require_relative '../support/go_build' +include GoBuild + +def main + create_fresh_build_dir + + run!(GO_ENV, %W[go install #{GO_PACKAGE}/cmd/...]) + executables = Dir[File.join(BUILD_DIR, 'bin', '*')] + FileUtils.chmod(0755, executables) + FileUtils.cp(executables, File.join(ROOT_PATH, 'bin')) +end + +main diff --git a/ruby/vendor/gitlab-shell/bin/create-hooks b/ruby/vendor/gitlab-shell/bin/create-hooks new file mode 100755 index 000000000..1adc80984 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/create-hooks @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby + +# Recreate GitLab hooks in the Git repositories managed by GitLab. +# +# This script is used when restoring a GitLab backup. + +require_relative '../lib/gitlab_init' +require File.join(ROOT_PATH, 'lib', 'gitlab_metrics') +require 'fileutils' + +def create_hooks(path) + global_hooks_directory = File.join(ROOT_PATH, 'hooks') + local_hooks_directory = File.join(path, 'hooks') + real_local_hooks_directory = :not_found + + begin + real_local_hooks_directory = File.realpath(local_hooks_directory) + rescue Errno::ENOENT + # real_local_hooks_directory == :not_found + end + + if real_local_hooks_directory != File.realpath(global_hooks_directory) + if File.exist?(local_hooks_directory) + $logger.info "Moving existing hooks directory and symlinking global hooks directory for #{path}." + FileUtils.mv(local_hooks_directory, "#{local_hooks_directory}.old.#{Time.now.to_i}") + end + FileUtils.ln_sf(global_hooks_directory, local_hooks_directory) + else + $logger.info "Hooks already exist for #{path}." + true + end +end + +repository_storage_paths = ARGV + +repository_storage_paths.each do |repo_path| + Dir["#{repo_path.chomp('/')}/**/*.git"].each do |repo| + begin + GitlabMetrics.measure('command-create-hooks') do + create_hooks(repo) + end + rescue Errno::ENOENT + # The user must have deleted their repository. Ignore. + end + end +end diff --git a/ruby/vendor/gitlab-shell/bin/gitlab-keys b/ruby/vendor/gitlab-shell/bin/gitlab-keys new file mode 100755 index 000000000..9eb19503e --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/gitlab-keys @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby + +require_relative '../lib/gitlab_init' + +# +# GitLab Keys shell. Add/remove keys from ~/.ssh/authorized_keys +# +# Ex. +# /bin/gitlab-keys add-key key-782 "ssh-rsa AAAAx321..." +# +# printf "key-782\tssh-rsa AAAAx321...\n" | /bin/gitlab-keys batch-add-keys +# +# /bin/gitlab-keys rm-key key-23 "ssh-rsa AAAAx321..." +# +# /bin/gitlab-keys list-keys +# +# /bin/gitlab-keys clear +# + +require File.join(ROOT_PATH, 'lib', 'gitlab_keys') + +# Return non-zero if command execution was not successful +if GitlabKeys.new.exec + exit 0 +else + exit 1 +end diff --git a/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-keys-check b/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-keys-check new file mode 100755 index 000000000..2ea1a7488 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-keys-check @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby + +# +# GitLab shell authorized_keys helper. Query GitLab API to get the authorized +# command for a given ssh key fingerprint +# +# Ex. +# bin/gitlab-shell-authorized-keys-check +# +# Returns +# command="/bin/gitlab-shell key-#",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAA... +# +# Expects to be called by the SSH daemon, via configuration like: +# AuthorizedKeysCommandUser git +# AuthorizedKeysCommand /bin/gitlab-shell-authorized-keys-check git %u %k + +abort "# Wrong number of arguments. #{ARGV.size}. Usage: +# gitlab-shell-authorized-keys-check " unless ARGV.size == 3 + +expected_username = ARGV[0] +abort '# No username provided' if expected_username.nil? || expected_username == '' + +actual_username = ARGV[1] +abort '# No username provided' if actual_username.nil? || actual_username == '' + +# Only check access if the requested username matches the configured username. +# Normally, these would both be 'git', but it can be configured by the user +exit 0 unless expected_username == actual_username + +key = ARGV[2] +abort "# No key provided" if key.nil? || key == '' + +require_relative '../lib/gitlab_init' +require_relative '../lib/gitlab_net' +require_relative '../lib/gitlab_keys' + +authorized_key = GitlabNet.new.authorized_key(key) +if authorized_key.nil? + puts "# No key was found for #{key}" +else + puts GitlabKeys.key_line("key-#{authorized_key['id']}", authorized_key['key']) +end diff --git a/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-principals-check b/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-principals-check new file mode 100755 index 000000000..aa6d427c3 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/gitlab-shell-authorized-principals-check @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +# +# GitLab shell authorized principals helper. Emits the same sort of +# command="..." line as gitlab-shell-authorized-principals-check, with +# the right options. +# +# Ex. +# bin/gitlab-shell-authorized-keys-check [...] +# +# Returns one line per principal passed in, e.g.: +# command="/bin/gitlab-shell username-{KEY_ID}",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty {PRINCIPAL} +# [command="/bin/gitlab-shell username-{KEY_ID}",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty {PRINCIPAL2}] +# +# Expects to be called by the SSH daemon, via configuration like: +# AuthorizedPrincipalsCommandUser root +# AuthorizedPrincipalsCommand /bin/gitlab-shell-authorized-principals-check git %i sshUsers + +abort "# Wrong number of arguments. #{ARGV.size}. Usage: +# gitlab-shell-authorized-principals-check [...]" unless ARGV.size >= 2 + +key_id = ARGV[0] +abort '# No key_id provided' if key_id.nil? || key_id == '' + +principals = ARGV[1..-1] +principals.each { |principal| + abort '# An invalid principal was provided' if principal.nil? || principal == '' +} + +require_relative '../lib/gitlab_init' +require_relative '../lib/gitlab_net' +require_relative '../lib/gitlab_keys' + +principals.each { |principal| + puts GitlabKeys.principal_line("username-#{key_id}", principal.dup) +} diff --git a/ruby/vendor/gitlab-shell/bin/gitlab-shell-ruby b/ruby/vendor/gitlab-shell/bin/gitlab-shell-ruby new file mode 100755 index 000000000..8d43cf14a --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/gitlab-shell-ruby @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby + +unless ENV['SSH_CONNECTION'] + puts "Only ssh allowed" + exit +end + +original_cmd = ENV.delete('SSH_ORIGINAL_COMMAND') + +require_relative '../lib/gitlab_init' + +# +# +# GitLab shell, invoked from ~/.ssh/authorized_keys or from an +# AuthorizedPrincipalsCommand in the key-less SSH CERT mode. +# +# +require File.join(ROOT_PATH, 'lib', 'gitlab_shell') + +# We must match e.g. "key-12345" anywhere on the command-line. See +# https://gitlab.com/gitlab-org/gitlab-shell/issues/145 +who = /\b(?:(?:key)-[0-9]+|username-\S+)\b/.match(ARGV.join(' ')).to_s + +if GitlabShell.new(who).exec(original_cmd) + exit 0 +else + exit 1 +end diff --git a/ruby/vendor/gitlab-shell/bin/install b/ruby/vendor/gitlab-shell/bin/install new file mode 100755 index 000000000..e9c165458 --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/install @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby + +require_relative '../lib/gitlab_init' + +# +# GitLab shell, invoked from ~/.ssh/authorized_keys +# + +config = GitlabConfig.new +key_dir = File.dirname("#{config.auth_file}") +repository_storage_paths = ARGV + +commands = [ + %W(mkdir -p #{key_dir}), + %W(chmod 700 #{key_dir}), +] + +repository_storage_paths.each do |repository_storage_path| + commands << %W(mkdir -p #{repository_storage_path}) + commands << %W(chmod ug+rwX,o-rwx #{repository_storage_path}) +end + +commands.each do |cmd| + print "#{cmd.join(' ')}: " + if system(*cmd) + puts 'OK' + else + puts 'Failed' + abort "#{$PROGRAM_NAME} failed" + end +end + +exit diff --git a/ruby/vendor/gitlab-shell/bin/test-logger b/ruby/vendor/gitlab-shell/bin/test-logger new file mode 100755 index 000000000..11b2a558a --- /dev/null +++ b/ruby/vendor/gitlab-shell/bin/test-logger @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +# The purpose of this executable is to test that gitlab-shell logging +# works correctly in combination with Kernel.exec. + +require_relative '../lib/gitlab_init' +require_relative '../lib/gitlab_logger' + +$logger.info(ARGV.first) +Kernel.exec('true') diff --git a/ruby/vendor/gitlab-shell/config.yml.example b/ruby/vendor/gitlab-shell/config.yml.example new file mode 100644 index 000000000..3d3e58062 --- /dev/null +++ b/ruby/vendor/gitlab-shell/config.yml.example @@ -0,0 +1,58 @@ +# +# If you change this file in a Merge Request, please also create +# a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests +# + +# GitLab user. git by default +user: git + +# URL to GitLab instance, used for API calls. Default: http://localhost:8080. +# For relative URL support read http://doc.gitlab.com/ce/install/relative_url.html +# You only have to change the default if you have configured Unicorn +# to listen on a custom port, or if you have configured Unicorn to +# only listen on a Unix domain socket. For Unix domain sockets use +# "http+unix://", e.g. +# "http+unix://%2Fpath%2Fto%2Fsocket" +gitlab_url: "http://localhost:8080" + +# See installation.md#using-https for additional HTTPS configuration details. +http_settings: +# read_timeout: 300 +# user: someone +# password: somepass +# ca_file: /etc/ssl/cert.pem +# ca_path: /etc/pki/tls/certs + self_signed_cert: false + +# File used as authorized_keys for gitlab user +auth_file: "/home/git/.ssh/authorized_keys" + +# File that contains the secret key for verifying access to GitLab. +# Default is .gitlab_shell_secret in the gitlab-shell directory. +# secret_file: "/home/git/gitlab-shell/.gitlab_shell_secret" + +# Parent directory for global custom hook directories (pre-receive.d, update.d, post-receive.d) +# Default is hooks in the gitlab-shell directory. +# custom_hooks_dir: "/home/git/gitlab-shell/hooks" + +# Log file. +# Default is gitlab-shell.log in the root directory. +# log_file: "/home/git/gitlab-shell/gitlab-shell.log" + +# Log level. INFO by default +log_level: INFO + +# Log format. 'text' by default +# log_format: json + +# Audit usernames. +# Set to true to see real usernames in the logs instead of key ids, which is easier to follow, but +# incurs an extra API call on every gitlab-shell command. +audit_usernames: false + +# Migration to Go: anything listed here has two implementations. Use these flags +# to try the new implementations out, or to revert to the old behaviour if there +# problems arise. +migration: + enabled: false + features: [] diff --git a/ruby/vendor/gitlab-shell/hooks/post-receive b/ruby/vendor/gitlab-shell/hooks/post-receive new file mode 100755 index 000000000..2b6538f03 --- /dev/null +++ b/ruby/vendor/gitlab-shell/hooks/post-receive @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +# This file was placed here by GitLab. It makes sure that your pushed commits +# will be processed properly. + +refs = $stdin.read +key_id = ENV.delete('GL_ID') +gl_repository = ENV['GL_REPOSITORY'] +repo_path = Dir.pwd + +require_relative '../lib/gitlab_custom_hook' +require_relative '../lib/hooks_utils' +require_relative '../lib/gitlab_post_receive' + +push_options = HooksUtils.get_push_options + +if GitlabPostReceive.new(gl_repository, repo_path, key_id, refs, push_options).exec && + GitlabCustomHook.new(repo_path, key_id).post_receive(refs) + exit 0 +else + exit 1 +end diff --git a/ruby/vendor/gitlab-shell/hooks/pre-receive b/ruby/vendor/gitlab-shell/hooks/pre-receive new file mode 100755 index 000000000..6ce587951 --- /dev/null +++ b/ruby/vendor/gitlab-shell/hooks/pre-receive @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby + +# This file was placed here by GitLab. It makes sure that your pushed commits +# will be processed properly. + +refs = $stdin.read +key_id = ENV.delete('GL_ID') +protocol = ENV.delete('GL_PROTOCOL') +repo_path = Dir.pwd +gl_repository = ENV['GL_REPOSITORY'] + +def increase_reference_counter(gl_repository, repo_path) + result = GitlabNet.new.pre_receive(gl_repository) + + result && result['reference_counter_increased'] +end + +require_relative '../lib/gitlab_custom_hook' +require_relative '../lib/gitlab_access' +require_relative '../lib/gitlab_net' + +# It's important that on pre-receive `increase_reference_counter` gets executed +# last so that it only runs if everything else succeeded. On post-receive on the +# other hand, we run GitlabPostReceive first because the push is already done +# and we don't want to skip it if the custom hook fails. +if GitlabAccess.new(gl_repository, repo_path, key_id, refs, protocol).exec && + GitlabCustomHook.new(repo_path, key_id).pre_receive(refs) && + increase_reference_counter(gl_repository, repo_path) + exit 0 +else + exit 1 +end diff --git a/ruby/vendor/gitlab-shell/hooks/update b/ruby/vendor/gitlab-shell/hooks/update new file mode 100755 index 000000000..4c2fc08b0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/hooks/update @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +# This file was placed here by GitLab. It makes sure that your pushed commits +# will be processed properly. + +ref_name = ARGV[0] +old_value = ARGV[1] +new_value = ARGV[2] +repo_path = Dir.pwd +key_id = ENV.delete('GL_ID') + +require_relative '../lib/gitlab_custom_hook' + +if GitlabCustomHook.new(repo_path, key_id).update(ref_name, old_value, new_value) + exit 0 +else + exit 1 +end diff --git a/ruby/vendor/gitlab-shell/lib/action.rb b/ruby/vendor/gitlab-shell/lib/action.rb new file mode 100644 index 000000000..28c1c146f --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/action.rb @@ -0,0 +1,4 @@ +require_relative 'action/custom' + +module Action +end diff --git a/ruby/vendor/gitlab-shell/lib/action/custom.rb b/ruby/vendor/gitlab-shell/lib/action/custom.rb new file mode 100644 index 000000000..a2f3d59c8 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/action/custom.rb @@ -0,0 +1,144 @@ +require 'base64' + +require_relative '../http_helper' + +module Action + class Custom + include HTTPHelper + + class BaseError < StandardError; end + class MissingPayloadError < BaseError; end + class MissingAPIEndpointsError < BaseError; end + class MissingDataError < BaseError; end + class UnsuccessfulError < BaseError; end + + NO_MESSAGE_TEXT = 'No message'.freeze + DEFAULT_HEADERS = { 'Content-Type' => CONTENT_TYPE_JSON }.freeze + + def initialize(gl_id, payload) + @gl_id = gl_id + @payload = payload + end + + def execute + validate! + inform_client(info_message) if info_message + process_api_endpoints! + end + + private + + attr_reader :gl_id, :payload + + def process_api_endpoints! + output = '' + resp = nil + + data_with_gl_id = data.merge('gl_id' => gl_id) + + api_endpoints.each do |endpoint| + url = "#{base_url}#{endpoint}" + json = { 'data' => data_with_gl_id, 'output' => output } + + resp = post(url, {}, headers: DEFAULT_HEADERS, options: { json: json }) + + # Net::HTTPSuccess is the parent of Net::HTTPOK, Net::HTTPCreated etc. + case resp + when Net::HTTPSuccess, Net::HTTPMultipleChoices + true + else + raise_unsuccessful!(resp) + end + + begin + body = JSON.parse(resp.body) + rescue JSON::ParserError + raise UnsuccessfulError, 'Response was not valid JSON' + end + + print_flush(body['result']) + + # In the context of the git push sequence of events, it's necessary to read + # stdin in order to capture output to pass onto subsequent commands + output = read_stdin + end + + resp + end + + def base_url + config.gitlab_url + end + + def data + @data ||= payload['data'] + end + + def api_endpoints + data['api_endpoints'] + end + + def info_message + data['info_message'] + end + + def config + @config ||= GitlabConfig.new + end + + def api + @api ||= GitlabNet.new + end + + def read_stdin + Base64.encode64($stdin.read) + end + + def print_flush(str) + return false unless str + $stdout.print(Base64.decode64(str)) + $stdout.flush + end + + def inform_client(str) + $stderr.puts(format_gitlab_output(str)) + end + + def format_gitlab_output(str) + str.split("\n").map { |line| "> GitLab: #{line}" }.join("\n") + end + + def validate! + validate_payload! + validate_data! + validate_api_endpoints! + end + + def validate_payload! + raise MissingPayloadError if !payload.is_a?(Hash) || payload.empty? + end + + def validate_data! + raise MissingDataError unless data.is_a?(Hash) + end + + def validate_api_endpoints! + raise MissingAPIEndpointsError if !api_endpoints.is_a?(Array) || + api_endpoints.empty? + end + + def raise_unsuccessful!(result) + message = "#{exception_message_for(result.body)} (#{result.code})" + raise UnsuccessfulError, format_gitlab_output(message) + end + + def exception_message_for(body) + body = JSON.parse(body) + return body['message'] unless body['message'].to_s.empty? + + body['result'].to_s.empty? ? NO_MESSAGE_TEXT : Base64.decode64(body['result']) + rescue JSON::ParserError + NO_MESSAGE_TEXT + end + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_access.rb b/ruby/vendor/gitlab-shell/lib/gitlab_access.rb new file mode 100644 index 000000000..72abd14d9 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_access.rb @@ -0,0 +1,43 @@ +require_relative 'gitlab_init' +require_relative 'gitlab_net' +require_relative 'gitlab_access_status' +require_relative 'gitlab_metrics' +require_relative 'object_dirs_helper' +require 'json' + +class GitlabAccess + class AccessDeniedError < StandardError; end + + attr_reader :config, :gl_repository, :repo_path, :changes, :protocol + + def initialize(gl_repository, repo_path, actor, changes, protocol) + @config = GitlabConfig.new + @gl_repository = gl_repository + @repo_path = repo_path.strip + @actor = actor + @changes = changes.lines + @protocol = protocol + end + + def exec + status = GitlabMetrics.measure('check-access:git-receive-pack') do + api.check_access('git-receive-pack', @gl_repository, @repo_path, @actor, @changes, @protocol, env: ObjectDirsHelper.all_attributes.to_json) + end + + raise AccessDeniedError, status.message unless status.allowed? + + true + rescue GitlabNet::ApiUnreachableError + $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" + false + rescue AccessDeniedError => ex + $stderr.puts "GitLab: #{ex.message}" + false + end + + protected + + def api + GitlabNet.new + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_access_status.rb b/ruby/vendor/gitlab-shell/lib/gitlab_access_status.rb new file mode 100644 index 000000000..dd6562ece --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_access_status.rb @@ -0,0 +1,44 @@ +require 'json' + +class GitAccessStatus + HTTP_MULTIPLE_CHOICES = '300'.freeze + + attr_reader :message, :gl_repository, :gl_id, :gl_username, :gitaly, :git_protocol, :git_config_options, :payload + + def initialize(status, status_code, message, gl_repository: nil, gl_id: nil, + gl_username: nil, gitaly: nil, git_protocol: nil, + git_config_options: nil, payload: nil) + @status = status + @status_code = status_code + @message = message + @gl_repository = gl_repository + @gl_id = gl_id + @gl_username = gl_username + @git_config_options = git_config_options + @gitaly = gitaly + @git_protocol = git_protocol + @payload = payload + end + + def self.create_from_json(json, status_code) + values = JSON.parse(json) + new(values["status"], + status_code, + values["message"], + gl_repository: values["gl_repository"], + gl_id: values["gl_id"], + gl_username: values["gl_username"], + git_config_options: values["git_config_options"], + gitaly: values["gitaly"], + git_protocol: values["git_protocol"], + payload: values["payload"]) + end + + def allowed? + @status + end + + def custom_action? + @status_code == HTTP_MULTIPLE_CHOICES + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_config.rb b/ruby/vendor/gitlab-shell/lib/gitlab_config.rb new file mode 100644 index 000000000..85aa88991 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_config.rb @@ -0,0 +1,56 @@ +require 'yaml' + +class GitlabConfig + attr_reader :config + + def initialize + @config = YAML.load_file(File.join(ROOT_PATH, 'config.yml')) + end + + def home + ENV['HOME'] + end + + def auth_file + @config['auth_file'] ||= File.join(home, ".ssh/authorized_keys") + end + + def secret_file + @config['secret_file'] ||= File.join(ROOT_PATH, '.gitlab_shell_secret') + end + + # Pass a default value because this is called from a repo's context; in which + # case, the repo's hooks directory should be the default. + # + def custom_hooks_dir(default: nil) + @config['custom_hooks_dir'] || default + end + + def gitlab_url + (@config['gitlab_url'] ||= "http://localhost:8080").sub(%r{/*$}, '') + end + + def http_settings + @config['http_settings'] ||= {} + end + + def log_file + @config['log_file'] ||= File.join(ROOT_PATH, 'gitlab-shell.log') + end + + def log_level + @config['log_level'] ||= 'INFO' + end + + def log_format + @config['log_format'] ||= 'text' + end + + def audit_usernames + @config['audit_usernames'] ||= false + end + + def metrics_log_file + @config['metrics_log_file'] ||= File.join(ROOT_PATH, 'gitlab-shell-metrics.log') + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_custom_hook.rb b/ruby/vendor/gitlab-shell/lib/gitlab_custom_hook.rb new file mode 100644 index 000000000..67096dfe7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_custom_hook.rb @@ -0,0 +1,98 @@ +require 'open3' +require_relative 'gitlab_init' +require_relative 'gitlab_metrics' + +class GitlabCustomHook + attr_reader :vars, :config + + def initialize(repo_path, key_id) + @repo_path = repo_path + @vars = { 'GL_ID' => key_id } + @config = GitlabConfig.new + end + + def pre_receive(changes) + GitlabMetrics.measure("pre-receive-hook") do + find_hooks('pre-receive').all? do |hook| + call_receive_hook(hook, changes) + end + end + end + + def post_receive(changes) + GitlabMetrics.measure("post-receive-hook") do + find_hooks('post-receive').all? do |hook| + call_receive_hook(hook, changes) + end + end + end + + def update(ref_name, old_value, new_value) + GitlabMetrics.measure("update-hook") do + find_hooks('update').all? do |hook| + system(vars, hook, ref_name, old_value, new_value) + end + end + end + + private + + def call_receive_hook(hook, changes) + # Prepare the hook subprocess. Attach a pipe to its stdin, and merge + # both its stdout and stderr into our own stdout. + stdin_reader, stdin_writer = IO.pipe + hook_pid = spawn(vars, hook, in: stdin_reader, err: :out) + stdin_reader.close + + # Submit changes to the hook via its stdin. + begin + IO.copy_stream(StringIO.new(changes), stdin_writer) + rescue Errno::EPIPE # rubocop:disable Lint/HandleExceptions + # It is not an error if the hook does not consume all of its input. + end + + # Close the pipe to let the hook know there is no further input. + stdin_writer.close + + Process.wait(hook_pid) + $?.success? + end + + # lookup hook files in this order: + # + # 1. .git/custom_hooks/ - per project hook + # 2. .git/custom_hooks/.d/* - per project hooks + # 3. .git/hooks/.d/* - global hooks + # + def find_hooks(hook_name) + hook_files = [] + + # .git/custom_hooks/ + project_custom_hook_file = File.join(@repo_path, 'custom_hooks', hook_name) + hook_files.push(project_custom_hook_file) if File.executable?(project_custom_hook_file) + + # .git/custom_hooks/.d/* + project_custom_hooks_dir = File.join(@repo_path, 'custom_hooks', "#{hook_name}.d") + hook_files += match_hook_files(project_custom_hooks_dir) + + # .git/hooks/.d/* OR /.d/* + global_custom_hooks_parent = config.custom_hooks_dir(default: File.join(@repo_path, 'hooks')) + global_custom_hooks_dir = File.join(global_custom_hooks_parent, "#{hook_name}.d") + hook_files += match_hook_files(global_custom_hooks_dir) + + hook_files + end + + # match files from path: + # 1. file must be executable + # 2. file must not match backup file + # + # the resulting list is sorted + def match_hook_files(path) + return [] unless Dir.exist?(path) + + Dir["#{path}/*"].select do |f| + !f.end_with?('~') && File.executable?(f) + end.sort + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_init.rb b/ruby/vendor/gitlab-shell/lib/gitlab_init.rb new file mode 100644 index 000000000..0e1458a7b --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_init.rb @@ -0,0 +1,7 @@ +ROOT_PATH = ENV.fetch('GITLAB_SHELL_DIR', File.expand_path('..', __dir__)) + +# We are transitioning parts of gitlab-shell into the gitaly project. In +# gitaly, GITALY_EMBEDDED will be true. +GITALY_EMBEDDED = true + +require_relative 'gitlab_config' diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_keys.rb b/ruby/vendor/gitlab-shell/lib/gitlab_keys.rb new file mode 100644 index 000000000..0600a1877 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_keys.rb @@ -0,0 +1,190 @@ +require 'timeout' + +require_relative 'gitlab_config' +require_relative 'gitlab_logger' +require_relative 'gitlab_metrics' + +class GitlabKeys # rubocop:disable Metrics/ClassLength + class KeyError < StandardError; end + + attr_accessor :auth_file, :key + + def self.command(whatever) + "#{ROOT_PATH}/bin/gitlab-shell #{whatever}" + end + + def self.command_key(key_id) + unless /\A[a-z0-9-]+\z/ =~ key_id + raise KeyError, "Invalid key_id: #{key_id.inspect}" + end + + command(key_id) + end + + def self.whatever_line(command, trailer) + "command=\"#{command}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty #{trailer}" + end + + def self.key_line(key_id, public_key) + public_key.chomp! + + if public_key.include?("\n") + raise KeyError, "Invalid public_key: #{public_key.inspect}" + end + + whatever_line(command_key(key_id), public_key) + end + + def self.principal_line(username_key_id, principal) + principal.chomp! + + if principal.include?("\n") + raise KeyError, "Invalid principal: #{principal.inspect}" + end + + whatever_line(command_key(username_key_id), principal) + end + + def initialize + @command = ARGV.shift + @key_id = ARGV.shift + key = ARGV.shift + @key = key.dup if key + @auth_file = GitlabConfig.new.auth_file + end + + def exec + GitlabMetrics.measure("command-#{@command}") do + case @command + when 'add-key' + add_key + when 'batch-add-keys' + batch_add_keys + when 'rm-key' + rm_key + when 'list-keys' + list_keys + when 'list-key-ids' + list_key_ids + when 'clear' + clear + when 'check-permissions' + check_permissions + else + $logger.warn('Attempt to execute invalid gitlab-keys command', command: @command.inspect) + puts 'not allowed' + false + end + end + end + + protected + + def add_key + lock do + $logger.info('Adding key', key_id: @key_id, public_key: @key) + auth_line = self.class.key_line(@key_id, @key) + open_auth_file('a') { |file| file.puts(auth_line) } + end + true + end + + def list_keys + $logger.info 'Listing all keys' + keys = '' + File.readlines(auth_file).each do |line| + # key_id & public_key + # command=".../bin/gitlab-shell key-741" ... ssh-rsa AAAAB3NzaDAxx2E\n + # ^^^^^^^ ^^^^^^^^^^^^^^^ + matches = /^command=\".+?\s+(.+?)\".+?(?:ssh|ecdsa)-.*?\s(.+)\s*.*\n*$/.match(line) + keys << "#{matches[1]} #{matches[2]}\n" unless matches.nil? + end + keys + end + + def list_key_ids + $logger.info 'Listing all key IDs' + open_auth_file('r') do |f| + f.each_line do |line| + matchd = line.match(/key-(\d+)/) + next unless matchd + puts matchd[1] + end + end + end + + def batch_add_keys + lock(300) do # Allow 300 seconds (5 minutes) for batch_add_keys + open_auth_file('a') do |file| + stdin.each_line do |input| + tokens = input.strip.split("\t") + abort("#{$0}: invalid input #{input.inspect}") unless tokens.count == 2 + key_id, public_key = tokens + $logger.info('Adding key', key_id: key_id, public_key: public_key) + file.puts(self.class.key_line(key_id, public_key)) + end + end + end + true + end + + def stdin + $stdin + end + + def rm_key + lock do + $logger.info('Removing key', key_id: @key_id) + open_auth_file('r+') do |f| + while line = f.gets # rubocop:disable Lint/AssignmentInCondition + next unless line.start_with?("command=\"#{self.class.command_key(@key_id)}\"") + f.seek(-line.length, IO::SEEK_CUR) + # Overwrite the line with #'s. Because the 'line' variable contains + # a terminating '\n', we write line.length - 1 '#' characters. + f.write('#' * (line.length - 1)) + end + end + end + true + end + + def clear + open_auth_file('w') { |file| file.puts '# Managed by gitlab-shell' } + true + end + + def check_permissions + open_auth_file(File::RDWR | File::CREAT) { true } + rescue => ex + puts "error: could not open #{auth_file}: #{ex}" + if File.exist?(auth_file) + system('ls', '-l', auth_file) + else + # Maybe the parent directory is not writable? + system('ls', '-ld', File.dirname(auth_file)) + end + false + end + + def lock(timeout = 10) + File.open(lock_file, "w+") do |f| + begin + f.flock File::LOCK_EX + Timeout.timeout(timeout) { yield } + ensure + f.flock File::LOCK_UN + end + end + end + + def lock_file + @lock_file ||= auth_file + '.lock' + end + + def open_auth_file(mode) + open(auth_file, mode, 0o600) do |file| + file.chmod(0o600) + yield file + end + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_lfs_authentication.rb b/ruby/vendor/gitlab-shell/lib/gitlab_lfs_authentication.rb new file mode 100644 index 000000000..ccd6d69f0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_lfs_authentication.rb @@ -0,0 +1,30 @@ +require 'base64' +require 'json' + +class GitlabLfsAuthentication + attr_accessor :username, :lfs_token, :repository_http_path + + def initialize(username, lfs_token, repository_http_path) + @username = username + @lfs_token = lfs_token + @repository_http_path = repository_http_path + end + + def self.build_from_json(json) + values = JSON.parse(json) + new(values['username'], values['lfs_token'], values['repository_http_path']) + rescue + nil + end + + def authentication_payload + authorization = { + header: { + Authorization: "Basic #{Base64.strict_encode64("#{username}:#{lfs_token}")}" + }, + href: "#{repository_http_path}/info/lfs/" + } + + JSON.generate(authorization) + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_logger.rb b/ruby/vendor/gitlab-shell/lib/gitlab_logger.rb new file mode 100644 index 000000000..67f6030dd --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_logger.rb @@ -0,0 +1,120 @@ +require 'json' +require 'logger' +require 'time' + +require_relative 'gitlab_config' + +def convert_log_level(log_level) + Logger.const_get(log_level.upcase) +rescue NameError + $stderr.puts "WARNING: Unrecognized log level #{log_level.inspect}." + $stderr.puts "WARNING: Falling back to INFO." + Logger::INFO +end + +class GitlabLogger + # Emulate the quoting logic of logrus + # https://github.com/sirupsen/logrus/blob/v1.0.5/text_formatter.go#L143-L156 + SHOULD_QUOTE = /[^a-zA-Z0-9\-._\/@^+]/ + + LEVELS = { + Logger::INFO => 'info'.freeze, + Logger::DEBUG => 'debug'.freeze, + Logger::WARN => 'warn'.freeze, + Logger::ERROR => 'error'.freeze + }.freeze + + def initialize(level, path, log_format) + @level = level + + @log_file = File.open(path, 'ab') + # By default Ruby will buffer writes. This is a problem when we exec + # into a new command before Ruby flushed its buffers. Setting 'sync' to + # true disables Ruby's buffering. + @log_file.sync = true + + @log_format = log_format + end + + def info(message, data = {}) + log_at(Logger::INFO, message, data) + end + + def debug(message, data = {}) + log_at(Logger::DEBUG, message, data) + end + + def warn(message, data = {}) + log_at(Logger::WARN, message, data) + end + + def error(message, data = {}) + log_at(Logger::ERROR, message, data) + end + + private + + attr_reader :log_file, :log_format + + def log_at(level, message, data) + return unless @level <= level + + data[:pid] = pid + data[:level] = LEVELS[level] + data[:msg] = message + + # Use RFC3339 to match logrus in the Go parts of gitlab-shell + data[:time] = time_now.to_datetime.rfc3339 + + case log_format + when 'json' + # Don't use IO#puts because of https://bugs.ruby-lang.org/issues/14042 + log_file.print("#{format_json(data)}\n") + else + log_file.print("#{format_text(data)}\n") + end + end + + def pid + Process.pid + end + + def time_now + Time.now + end + + def format_text(data) + # We start the line with these fields to match the behavior of logrus + result = [ + format_key_value(:time, data.delete(:time)), + format_key_value(:level, data.delete(:level)), + format_key_value(:msg, data.delete(:msg)) + ] + + data.sort.each { |k, v| result << format_key_value(k, v) } + result.join(' ') + end + + def format_key_value(key, value) + value_string = value.to_s + value_string = value_string.inspect if SHOULD_QUOTE =~ value_string + + "#{key}=#{value_string}" + end + + def format_json(data) + data.each do |key, value| + next unless value.is_a?(String) + + value = value.dup.force_encoding('utf-8') + value = value.inspect unless value.valid_encoding? + data[key] = value.freeze + end + + data.to_json + end +end + +config = GitlabConfig.new + +$logger = GitlabLogger.new(convert_log_level(config.log_level), config.log_file, config.log_format) diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_metrics.rb b/ruby/vendor/gitlab-shell/lib/gitlab_metrics.rb new file mode 100644 index 000000000..917a48918 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_metrics.rb @@ -0,0 +1,59 @@ +require_relative 'gitlab_config' +require_relative 'gitlab_logger' + +module GitlabMetrics + module System + # THREAD_CPUTIME is not supported on OS X + if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID) + def self.cpu_time + Process. + clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond) + end + else + def self.cpu_time + Process. + clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond) + end + end + + # Returns the current monotonic clock time in a given precision. + # + # Returns the time as a Fixnum. + def self.monotonic_time + if defined?(Process::CLOCK_MONOTONIC) + Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + else + Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond) + end + end + end + + def self.logger + $logger + end + + # Measures the execution time of a block. + # + # Example: + # + # GitlabMetrics.measure(:find_by_username_duration) do + # User.find_by_username(some_username) + # end + # + # name - The name of the field to store the execution time in. + # + # Returns the value yielded by the supplied block. + def self.measure(name) + start_real = System.monotonic_time + start_cpu = System.cpu_time + + retval = yield + + real_time = System.monotonic_time - start_real + cpu_time = System.cpu_time - start_cpu + + logger.debug('metrics', name: name, wall_time: real_time, cpu_time: cpu_time) + + retval + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_net.rb b/ruby/vendor/gitlab-shell/lib/gitlab_net.rb new file mode 100644 index 000000000..a84ba84ee --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_net.rb @@ -0,0 +1,165 @@ +require 'net/http' +require 'openssl' +require 'json' + +require_relative 'gitlab_config' +require_relative 'gitlab_access' +require_relative 'gitlab_lfs_authentication' +require_relative 'http_helper' + +class GitlabNet # rubocop:disable Metrics/ClassLength + include HTTPHelper + + CHECK_TIMEOUT = 5 + API_INACCESSIBLE_MESSAGE = 'API is not accessible'.freeze + + def check_access(cmd, gl_repository, repo, who, changes, protocol, env: {}) + changes = changes.join("\n") unless changes.is_a?(String) + + params = { + action: cmd, + changes: changes, + gl_repository: gl_repository, + project: sanitize_path(repo), + protocol: protocol, + env: env + } + + who_sym, _, who_v = self.class.parse_who(who) + params[who_sym] = who_v + + url = "#{internal_api_endpoint}/allowed" + resp = post(url, params) + + case resp + when Net::HTTPSuccess, Net::HTTPMultipleChoices, Net::HTTPUnauthorized, + Net::HTTPNotFound, Net::HTTPServiceUnavailable + if resp.content_type == CONTENT_TYPE_JSON + return GitAccessStatus.create_from_json(resp.body, resp.code) + end + end + + GitAccessStatus.new(false, resp.code, API_INACCESSIBLE_MESSAGE) + end + + def discover(who) + _, who_k, who_v = self.class.parse_who(who) + + resp = get("#{internal_api_endpoint}/discover?#{who_k}=#{who_v}") + + JSON.parse(resp.body) rescue nil + end + + def lfs_authenticate(gl_id, repo, operation) + id_sym, _, id = self.class.parse_who(gl_id) + params = { project: sanitize_path(repo), operation: operation } + + case id_sym + when :key_id + params[:key_id] = id + when :user_id + params[:user_id] = id + else + raise ArgumentError, "lfs_authenticate() got unsupported GL_ID='#{gl_id}'!" + end + + resp = post("#{internal_api_endpoint}/lfs_authenticate", params) + + GitlabLfsAuthentication.build_from_json(resp.body) if resp.code == '200' + end + + def broadcast_message + resp = get("#{internal_api_endpoint}/broadcast_message") + JSON.parse(resp.body) rescue {} + end + + def merge_request_urls(gl_repository, repo_path, changes) + changes = changes.join("\n") unless changes.is_a?(String) + changes = changes.encode('UTF-8', 'ASCII', invalid: :replace, replace: '') + url = "#{internal_api_endpoint}/merge_request_urls?project=#{URI.escape(repo_path)}&changes=#{URI.escape(changes)}" + url += "&gl_repository=#{URI.escape(gl_repository)}" if gl_repository + resp = get(url) + + if resp.code == '200' + JSON.parse(resp.body) + else + [] + end + rescue + [] + end + + def check + get("#{internal_api_endpoint}/check", options: { read_timeout: CHECK_TIMEOUT }) + end + + def authorized_key(key) + resp = get("#{internal_api_endpoint}/authorized_keys?key=#{URI.escape(key, '+/=')}") + JSON.parse(resp.body) if resp.code == "200" + rescue + nil + end + + def two_factor_recovery_codes(gl_id) + id_sym, _, id = self.class.parse_who(gl_id) + + resp = post("#{internal_api_endpoint}/two_factor_recovery_codes", id_sym => id) + + JSON.parse(resp.body) if resp.code == '200' + rescue + {} + end + + def notify_post_receive(gl_repository, repo_path) + params = { gl_repository: gl_repository, project: repo_path } + resp = post("#{internal_api_endpoint}/notify_post_receive", params) + + resp.code == '200' + rescue + false + end + + def post_receive(gl_repository, identifier, changes, push_options) + params = { + gl_repository: gl_repository, + identifier: identifier, + changes: changes, + :"push_options[]" => push_options, # rubocop:disable Style/HashSyntax + } + resp = post("#{internal_api_endpoint}/post_receive", params) + + raise NotFound if resp.code == '404' + + JSON.parse(resp.body) if resp.code == '200' + end + + def pre_receive(gl_repository) + resp = post("#{internal_api_endpoint}/pre_receive", gl_repository: gl_repository) + + raise NotFound if resp.code == '404' + + JSON.parse(resp.body) if resp.code == '200' + end + + def self.parse_who(who) + if who.start_with?("key-") + value = who.gsub("key-", "") + raise ArgumentError, "who='#{who}' is invalid!" unless value =~ /\A[0-9]+\z/ + [:key_id, 'key_id', value] + elsif who.start_with?("user-") + value = who.gsub("user-", "") + raise ArgumentError, "who='#{who}' is invalid!" unless value =~ /\A[0-9]+\z/ + [:user_id, 'user_id', value] + elsif who.start_with?("username-") + [:username, 'username', who.gsub("username-", "")] + else + raise ArgumentError, "who='#{who}' is invalid!" + end + end + + protected + + def sanitize_path(repo) + repo.delete("'") + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_net/errors.rb b/ruby/vendor/gitlab-shell/lib/gitlab_net/errors.rb new file mode 100644 index 000000000..f32b3d826 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_net/errors.rb @@ -0,0 +1,4 @@ +class GitlabNet + class ApiUnreachableError < StandardError; end + class NotFound < StandardError; end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_post_receive.rb b/ruby/vendor/gitlab-shell/lib/gitlab_post_receive.rb new file mode 100644 index 000000000..2d412b91b --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_post_receive.rb @@ -0,0 +1,119 @@ +require_relative 'gitlab_init' +require_relative 'gitlab_net' +require_relative 'gitlab_metrics' +require 'json' +require 'base64' +require 'securerandom' + +class GitlabPostReceive + attr_reader :config, :gl_repository, :repo_path, :changes, :jid + + def initialize(gl_repository, repo_path, actor, changes, push_options) + @config = GitlabConfig.new + @gl_repository = gl_repository + @repo_path = repo_path.strip + @actor = actor + @changes = changes + @push_options = push_options + @jid = SecureRandom.hex(12) + end + + def exec + response = GitlabMetrics.measure("post-receive") do + api.post_receive(gl_repository, @actor, changes, @push_options) + end + + return false unless response + print_broadcast_message(response['broadcast_message']) if response['broadcast_message'] + print_merge_request_links(response['merge_request_urls']) if response['merge_request_urls'] + puts response['redirected_message'] if response['redirected_message'] + puts response['project_created_message'] if response['project_created_message'] + + response['reference_counter_decreased'] + rescue GitlabNet::ApiUnreachableError + false + end + + protected + + def api + @api ||= GitlabNet.new + end + + def print_merge_request_links(merge_request_urls) + return if merge_request_urls.empty? + puts + merge_request_urls.each { |mr| print_merge_request_link(mr) } + end + + def print_merge_request_link(merge_request) + message = + if merge_request["new_merge_request"] + "To create a merge request for #{merge_request['branch_name']}, visit:" + else + "View merge request for #{merge_request['branch_name']}:" + end + + puts message + puts((" " * 2) + merge_request["url"]) + puts + end + + def print_broadcast_message(message) + # A standard terminal window is (at least) 80 characters wide. + total_width = 80 + + # Git prefixes remote messages with "remote: ", so this width is subtracted + # from the width available to us. + total_width -= "remote: ".length # rubocop:disable Performance/FixedSize + + # Our centered text shouldn't start or end right at the edge of the window, + # so we add some horizontal padding: 2 chars on either side. + text_width = total_width - 2 * 2 + + # Automatically wrap message at text_width (= 68) characters: + # Splits the message up into the longest possible chunks matching + # "". + + msg_start_idx = 0 + lines = [] + while msg_start_idx < message.length + parsed_line = parse_broadcast_msg(message[msg_start_idx..-1], text_width) + msg_start_idx += parsed_line.length + lines.push(parsed_line.strip) + end + + puts + puts "=" * total_width + puts + + lines.each do |line| + line.strip! + + # Center the line by calculating the left padding measured in characters. + line_padding = [(total_width - line.length) / 2, 0].max + puts((" " * line_padding) + line) + end + + puts + puts "=" * total_width + end + + private + + def parse_broadcast_msg(msg, text_length) + msg ||= "" + # just return msg if shorter than or equal to text length + return msg if msg.length <= text_length + + # search for word break shorter than text length + truncate_to_space = msg.match(/\A(.{,#{text_length}})(?=\s|$)(\s*)/).to_s + + if truncate_to_space.empty? + # search for word break longer than text length + truncate_to_space = msg.match(/\A\S+/).to_s + end + + truncate_to_space + end +end diff --git a/ruby/vendor/gitlab-shell/lib/gitlab_shell.rb b/ruby/vendor/gitlab-shell/lib/gitlab_shell.rb new file mode 100644 index 000000000..c1bb97627 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/gitlab_shell.rb @@ -0,0 +1,270 @@ +# frozen_string_literal: true + +require 'shellwords' +require 'pathname' + +require_relative 'gitlab_net' +require_relative 'gitlab_metrics' +require_relative 'action' + +class GitlabShell # rubocop:disable Metrics/ClassLength + class AccessDeniedError < StandardError; end + class DisallowedCommandError < StandardError; end + class InvalidRepositoryPathError < StandardError; end + + GIT_UPLOAD_PACK_COMMAND = 'git-upload-pack' + GIT_RECEIVE_PACK_COMMAND = 'git-receive-pack' + GIT_UPLOAD_ARCHIVE_COMMAND = 'git-upload-archive' + GIT_LFS_AUTHENTICATE_COMMAND = 'git-lfs-authenticate' + + GITALY_COMMANDS = { + GIT_UPLOAD_PACK_COMMAND => File.join(ROOT_PATH, 'bin', 'gitaly-upload-pack'), + GIT_UPLOAD_ARCHIVE_COMMAND => File.join(ROOT_PATH, 'bin', 'gitaly-upload-archive'), + GIT_RECEIVE_PACK_COMMAND => File.join(ROOT_PATH, 'bin', 'gitaly-receive-pack') + }.freeze + + GIT_COMMANDS = (GITALY_COMMANDS.keys + [GIT_LFS_AUTHENTICATE_COMMAND]).freeze + TWO_FACTOR_RECOVERY_COMMAND = '2fa_recovery_codes' + GL_PROTOCOL = 'ssh' + + attr_accessor :gl_id, :gl_repository, :repo_name, :command, :git_access, :git_protocol + + def initialize(who) + who_sym, = GitlabNet.parse_who(who) + if who_sym == :username + @who = who + else + @gl_id = who + end + @config = GitlabConfig.new + end + + # The origin_cmd variable contains UNTRUSTED input. If the user ran + # ssh git@gitlab.example.com 'evil command', then origin_cmd contains + # 'evil command'. + def exec(origin_cmd) + unless origin_cmd + puts "Welcome to GitLab, #{username}!" + return true + end + + args = Shellwords.shellwords(origin_cmd) + args = parse_cmd(args) + + access_status = nil + + if GIT_COMMANDS.include?(args.first) + access_status = GitlabMetrics.measure('verify-access') { verify_access } + + @gl_repository = access_status.gl_repository + @git_protocol = ENV['GIT_PROTOCOL'] + @gitaly = access_status.gitaly + @username = access_status.gl_username + @git_config_options = access_status.git_config_options + @gl_id = access_status.gl_id if defined?(@who) + elsif !defined?(@gl_id) + # We're processing an API command like 2fa_recovery_codes, but + # don't have a @gl_id yet, that means we're in the "username" + # mode and need to materialize it, calling the "user" method + # will do that and call the /discover method. + user + end + + if @command == GIT_RECEIVE_PACK_COMMAND && access_status.custom_action? + # If the response from /api/v4/allowed is a HTTP 300, we need to perform + # a Custom Action and therefore should return and not call process_cmd() + # + return process_custom_action(access_status) + end + + process_cmd(args) + + true + rescue GitlabNet::ApiUnreachableError + $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" + false + rescue AccessDeniedError => ex + $logger.warn('Access denied', command: origin_cmd, user: log_username) + $stderr.puts "GitLab: #{ex.message}" + false + rescue DisallowedCommandError + $logger.warn('Denied disallowed command', command: origin_cmd, user: log_username) + $stderr.puts "GitLab: Disallowed command" + false + rescue InvalidRepositoryPathError + $stderr.puts "GitLab: Invalid repository path" + false + rescue Action::Custom::BaseError => ex + $logger.warn('Custom action error', exception: ex.class, message: ex.message, + command: origin_cmd, user: log_username) + $stderr.puts ex.message + false + end + + protected + + def parse_cmd(args) + # Handle Git for Windows 2.14 using "git upload-pack" instead of git-upload-pack + if args.length == 3 && args.first == 'git' + @command = "git-#{args[1]}" + args = [@command, args.last] + else + @command = args.first + end + + @git_access = @command + + return args if TWO_FACTOR_RECOVERY_COMMAND == @command + + raise DisallowedCommandError unless GIT_COMMANDS.include?(@command) + + case @command + when GIT_LFS_AUTHENTICATE_COMMAND + raise DisallowedCommandError unless args.count >= 2 + @repo_name = args[1] + case args[2] + when 'download' + @git_access = GIT_UPLOAD_PACK_COMMAND + when 'upload' + @git_access = GIT_RECEIVE_PACK_COMMAND + else + raise DisallowedCommandError + end + else + raise DisallowedCommandError unless args.count == 2 + @repo_name = args.last + end + + args + end + + def verify_access + status = api.check_access(@git_access, nil, @repo_name, @who || @gl_id, '_any', GL_PROTOCOL) + + raise AccessDeniedError, status.message unless status.allowed? + + status + end + + def process_custom_action(access_status) + Action::Custom.new(@gl_id, access_status.payload).execute + end + + def process_cmd(args) + return api_2fa_recovery_codes if TWO_FACTOR_RECOVERY_COMMAND == @command + + if @command == GIT_LFS_AUTHENTICATE_COMMAND + GitlabMetrics.measure('lfs-authenticate') do + operation = args[2] + $logger.info('Processing LFS authentication', operation: operation, user: log_username) + lfs_authenticate(operation) + end + return + end + + # TODO: instead of building from pieces here in gitlab-shell, build the + # entire gitaly_request in gitlab-ce and pass on as-is here. + args = JSON.dump( + 'repository' => @gitaly['repository'], + 'gl_repository' => @gl_repository, + 'gl_id' => @gl_id, + 'gl_username' => @username, + 'git_config_options' => @git_config_options, + 'git_protocol' => @git_protocol + ) + + gitaly_address = @gitaly['address'] + executable = GITALY_COMMANDS.fetch(@command) + gitaly_bin = File.basename(executable) + args_string = [gitaly_bin, gitaly_address, args].join(' ') + $logger.info('executing git command', command: args_string, user: log_username) + + exec_cmd(executable, gitaly_address: gitaly_address, token: @gitaly['token'], json_args: args) + end + + # This method is not covered by Rspec because it ends the current Ruby process. + def exec_cmd(executable, gitaly_address:, token:, json_args:) + env = { 'GITALY_TOKEN' => token } + + args = [executable, gitaly_address, json_args] + # We use 'chdir: ROOT_PATH' to let the next executable know where config.yml is. + Kernel.exec(env, *args, unsetenv_others: true, chdir: ROOT_PATH) + end + + def api + GitlabNet.new + end + + def user + return @user if defined?(@user) + + begin + if defined?(@who) + @user = api.discover(@who) + @gl_id = "user-#{@user['id']}" if @user && @user.key?('id') + else + @user = api.discover(@gl_id) + end + rescue GitlabNet::ApiUnreachableError + @user = nil + end + end + + def username_from_discover + return nil unless user && user['username'] + + "@#{user['username']}" + end + + def username + @username ||= username_from_discover || 'Anonymous' + end + + # User identifier to be used in log messages. + def log_username + @config.audit_usernames ? username : "user with id #{@gl_id}" + end + + def lfs_authenticate(operation) + lfs_access = api.lfs_authenticate(@gl_id, @repo_name, operation) + + return unless lfs_access + + puts lfs_access.authentication_payload + end + + private + + def continue?(question) + puts "#{question} (yes/no)" + STDOUT.flush # Make sure the question gets output before we wait for input + continue = STDIN.gets.chomp + puts '' # Add a buffer in the output + continue == 'yes' + end + + def api_2fa_recovery_codes + continue = continue?( + "Are you sure you want to generate new two-factor recovery codes?\n" \ + "Any existing recovery codes you saved will be invalidated." + ) + + unless continue + puts 'New recovery codes have *not* been generated. Existing codes will remain valid.' + return + end + + resp = api.two_factor_recovery_codes(@gl_id) + if resp['success'] + codes = resp['recovery_codes'].join("\n") + puts "Your two-factor authentication recovery codes are:\n\n" \ + "#{codes}\n\n" \ + "During 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." + else + puts "An error occurred while trying to generate new recovery codes.\n" \ + "#{resp['message']}" + end + end +end diff --git a/ruby/vendor/gitlab-shell/lib/hooks_utils.rb b/ruby/vendor/gitlab-shell/lib/hooks_utils.rb new file mode 100644 index 000000000..b11317c8d --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/hooks_utils.rb @@ -0,0 +1,15 @@ +module HooksUtils + module_function + + # Gets an array of Git push options from the environment + def get_push_options + count = ENV['GIT_PUSH_OPTION_COUNT'].to_i + result = [] + + count.times do |i| + result.push(ENV["GIT_PUSH_OPTION_#{i}"]) + end + + result + end +end diff --git a/ruby/vendor/gitlab-shell/lib/http_helper.rb b/ruby/vendor/gitlab-shell/lib/http_helper.rb new file mode 100644 index 000000000..c6a4bb845 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/http_helper.rb @@ -0,0 +1,125 @@ +require_relative 'httpunix' +require_relative 'gitlab_logger' +require_relative 'gitlab_net/errors' + +module HTTPHelper + READ_TIMEOUT = 300 + CONTENT_TYPE_JSON = 'application/json'.freeze + + protected + + def config + @config ||= GitlabConfig.new + end + + def base_api_endpoint + "#{config.gitlab_url}/api/v4" + end + + def internal_api_endpoint + "#{base_api_endpoint}/internal" + end + + def http_client_for(uri, options = {}) + http = if uri.is_a?(URI::HTTPUNIX) + Net::HTTPUNIX.new(uri.hostname) + else + Net::HTTP.new(uri.host, uri.port) + end + + http.read_timeout = options[:read_timeout] || read_timeout + + if uri.is_a?(URI::HTTPS) + http.use_ssl = true + http.cert_store = cert_store + http.verify_mode = OpenSSL::SSL::VERIFY_NONE if config.http_settings['self_signed_cert'] + end + + http + end + + def http_request_for(method, uri, params: {}, headers: {}, options: {}) + request_klass = method == :get ? Net::HTTP::Get : Net::HTTP::Post + request = request_klass.new(uri.request_uri, headers) + + user = config.http_settings['user'] + password = config.http_settings['password'] + request.basic_auth(user, password) if user && password + + if options[:json] + request.body = options[:json].merge(secret_token: secret_token).to_json + else + request.set_form_data(params.merge(secret_token: secret_token)) + end + + if uri.is_a?(URI::HTTPUNIX) + # The HTTPUNIX HTTP client does not set a correct Host header. This can + # lead to 400 Bad Request responses. + request['Host'] = 'localhost' + end + + request + end + + def request(method, url, params: {}, headers: {}, options: {}) + $logger.debug('Performing request', method: method.to_s.upcase, url: url) + + uri = URI.parse(url) + http = http_client_for(uri, options) + request = http_request_for(method, uri, + params: params, + headers: headers, + options: options) + + begin + start_time = Time.new + response = http.start { http.request(request) } + rescue => e + $logger.warn('Failed to connect', method: method.to_s.upcase, url: url, error: e) + raise GitlabNet::ApiUnreachableError + ensure + fields = { method: method.to_s.upcase, url: url, duration: Time.new - start_time, gitaly_embedded: GITALY_EMBEDDED } + $logger.info('finished HTTP request', fields) + end + + case response + when Net::HTTPSuccess, Net::HTTPMultipleChoices + $logger.debug('Received response', code: response.code, body: response.body) + else + $logger.error('Call failed', method: method.to_s.upcase, url: url, code: response.code, body: response.body) + end + + response + end + + def get(url, headers: {}, options: {}) + request(:get, url, headers: headers, options: options) + end + + def post(url, params, headers: {}, options: {}) + request(:post, url, params: params, headers: headers, options: options) + end + + def cert_store + @cert_store ||= begin + store = OpenSSL::X509::Store.new + store.set_default_paths + + ca_file = config.http_settings['ca_file'] + store.add_file(ca_file) if ca_file + + ca_path = config.http_settings['ca_path'] + store.add_path(ca_path) if ca_path + + store + end + end + + def secret_token + @secret_token ||= File.read config.secret_file + end + + def read_timeout + config.http_settings['read_timeout'] || READ_TIMEOUT + end +end diff --git a/ruby/vendor/gitlab-shell/lib/httpunix.rb b/ruby/vendor/gitlab-shell/lib/httpunix.rb new file mode 100644 index 000000000..7d00f71d5 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/httpunix.rb @@ -0,0 +1,54 @@ +# support for http+unix://... connection scheme +# +# The URI scheme has the same structure as the similar one for python requests. See: +# http://fixall.online/theres-no-need-to-reinvent-the-wheelhttpsgithubcommsabramorequests-unixsocketurl/241810/ +# https://github.com/msabramo/requests-unixsocket + +require 'uri' +require 'net/http' + +module URI + class HTTPUNIX < HTTP + def hostname + # decode %XX from path to file + v = host + URI.decode(v) + end + + # port is not allowed in URI + DEFAULT_PORT = nil + def set_port(v) + return v unless v + raise InvalidURIError, "http+unix:// cannot contain port" + end + end + @@schemes['HTTP+UNIX'] = HTTPUNIX +end + +# Based on: +# - http://stackoverflow.com/questions/15637226/ruby-1-9-3-simple-get-request-to-unicorn-through-socket +# - Net::HTTP::connect +module Net + class HTTPUNIX < HTTP + def initialize(socketpath, port = nil) + super(socketpath, port) + @port = nil # HTTP will set it to default - override back -> set DEFAULT_PORT + end + + # override to prevent ":" being appended to HTTP_HOST + def addr_port + address + end + + def connect + D "opening connection to #{address} ..." + s = UNIXSocket.new(address) + D "opened" + @socket = BufferedIO.new(s) + @socket.read_timeout = @read_timeout + @socket.continue_timeout = @continue_timeout + @socket.debug_output = @debug_output + on_connect + end + end +end diff --git a/ruby/vendor/gitlab-shell/lib/object_dirs_helper.rb b/ruby/vendor/gitlab-shell/lib/object_dirs_helper.rb new file mode 100644 index 000000000..e175a0392 --- /dev/null +++ b/ruby/vendor/gitlab-shell/lib/object_dirs_helper.rb @@ -0,0 +1,39 @@ +require 'pathname' + +class ObjectDirsHelper + class << self + def all_attributes + { + "GIT_ALTERNATE_OBJECT_DIRECTORIES" => absolute_alt_object_dirs, + "GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE" => relative_alt_object_dirs, + "GIT_OBJECT_DIRECTORY" => absolute_object_dir, + "GIT_OBJECT_DIRECTORY_RELATIVE" => relative_object_dir + } + end + + def absolute_object_dir + ENV['GIT_OBJECT_DIRECTORY'] + end + + def relative_object_dir + relative_path(absolute_object_dir) + end + + def absolute_alt_object_dirs + ENV['GIT_ALTERNATE_OBJECT_DIRECTORIES'].to_s.split(File::PATH_SEPARATOR) + end + + def relative_alt_object_dirs + absolute_alt_object_dirs.map { |dir| relative_path(dir) }.compact + end + + private + + def relative_path(absolute_path) + return if absolute_path.nil? + + repo_dir = Dir.pwd + Pathname.new(absolute_path).relative_path_from(Pathname.new(repo_dir)).to_s + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_access_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_access_spec.rb new file mode 100644 index 000000000..92268e2e7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_access_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' +require 'gitlab_access' + +describe GitlabAccess do + let(:repository_path) { "/home/git/repositories" } + let(:repo_name) { 'dzaporozhets/gitlab-ci' } + let(:repo_path) { File.join(repository_path, repo_name) + ".git" } + let(:api) do + double(GitlabNet).tap do |api| + allow(api).to receive(:check_access).and_return(GitAccessStatus.new(true, + '200', + 'ok', + gl_repository: 'project-1', + gl_id: 'user-123', + gl_username: 'testuser', + git_config_options: ['receive.MaxInputSize=10000'], + gitaly: nil, + git_protocol: 'version=2')) + end + end + subject do + GitlabAccess.new(nil, repo_path, 'key-123', 'wow', 'ssh').tap do |access| + allow(access).to receive(:exec_cmd).and_return(:exec_called) + allow(access).to receive(:api).and_return(api) + end + end + + before do + allow_any_instance_of(GitlabConfig).to receive(:repos_path).and_return(repository_path) + end + + describe :initialize do + it { expect(subject.repo_path).to eq(repo_path) } + it { expect(subject.changes).to eq(['wow']) } + it { expect(subject.protocol).to eq('ssh') } + end + + describe "#exec" do + context "access is granted" do + it "returns true" do + expect(subject.exec).to be_truthy + end + end + + context "access is denied" do + before do + allow(api).to receive(:check_access).and_return(GitAccessStatus.new( + false, + '401', + 'denied', + gl_repository: nil, + gl_id: nil, + gl_username: nil, + git_config_options: nil, + gitaly: nil, + git_protocol: nil + )) + end + + it "returns false" do + expect(subject.exec).to be_falsey + end + end + + context "API connection fails" do + before do + allow(api).to receive(:check_access).and_raise(GitlabNet::ApiUnreachableError) + end + + it "returns false" do + expect(subject.exec).to be_falsey + end + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_config_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_config_spec.rb new file mode 100644 index 000000000..d12b657be --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_config_spec.rb @@ -0,0 +1,40 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_config' + +describe GitlabConfig do + let(:config) { GitlabConfig.new } + let(:config_data) { {} } + + before { expect(YAML).to receive(:load_file).and_return(config_data) } + + describe '#gitlab_url' do + let(:url) { 'http://test.com' } + + subject { config.gitlab_url } + + before { config_data['gitlab_url'] = url } + + it { is_expected.not_to be_empty } + it { is_expected.to eq(url) } + + context 'remove trailing slashes' do + before { config_data['gitlab_url'] = url + '//' } + + it { is_expected.to eq(url) } + end + end + + describe '#audit_usernames' do + subject { config.audit_usernames } + + it("returns false by default") { is_expected.to eq(false) } + end + + describe '#log_format' do + subject { config.log_format } + + it 'returns "text" by default' do + is_expected.to eq('text') + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_custom_hook_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_custom_hook_spec.rb new file mode 100644 index 000000000..540cd2b0a --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_custom_hook_spec.rb @@ -0,0 +1,295 @@ +# coding: utf-8 +require 'spec_helper' +require 'gitlab_custom_hook' + +describe GitlabCustomHook do + let(:original_root_path) { ROOT_PATH } + let(:tmp_repo_path) { File.join(original_root_path, 'tmp', 'repo.git') } + let(:tmp_root_path) { File.join(original_root_path, 'tmp') } + let(:global_custom_hooks_path) { global_hook_path('custom_global_hooks') } + let(:hook_ok) { File.join(original_root_path, 'spec', 'support', 'hook_ok') } + let(:hook_fail) { File.join(original_root_path, 'spec', 'support', 'hook_fail') } + let(:hook_gl_id) { File.join(original_root_path, 'spec', 'support', 'gl_id_test_hook') } + + let(:vars) { { "GL_ID" => "key_1" } } + let(:old_value) { "old-value" } + let(:new_value) { "new-value" } + let(:ref_name) { "name/of/ref" } + let(:changes) { "#{old_value} #{new_value} #{ref_name}\n" } + + let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } + + def hook_path(path) + File.join(tmp_repo_path, path.split('/')) + end + + def global_hook_path(path) + File.join(tmp_root_path, path.split('/')) + end + + def create_hook(path, which) + FileUtils.ln_sf(which, hook_path(path)) + end + + # global hooks multiplexed + def create_global_hooks_d(which, hook_name = 'hook') + create_hook('hooks/pre-receive.d/' + hook_name, which) + create_hook('hooks/update.d/' + hook_name, which) + create_hook('hooks/post-receive.d/' + hook_name, which) + end + + # repo hooks + def create_repo_hooks(which) + create_hook('custom_hooks/pre-receive', which) + create_hook('custom_hooks/update', which) + create_hook('custom_hooks/post-receive', which) + end + + # repo hooks multiplexed + def create_repo_hooks_d(which, hook_name = 'hook') + create_hook('custom_hooks/pre-receive.d/' + hook_name, which) + create_hook('custom_hooks/update.d/' + hook_name, which) + create_hook('custom_hooks/post-receive.d/' + hook_name, which) + end + + def cleanup_hook_setup + FileUtils.rm_rf(File.join(tmp_repo_path)) + FileUtils.rm_rf(File.join(global_custom_hooks_path)) + FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) + FileUtils.rm_f(File.join(tmp_root_path, 'config.yml')) + end + + def expect_call_receive_hook(path) + expect(gitlab_custom_hook) + .to receive(:call_receive_hook) + .with(hook_path(path), changes) + .and_call_original + end + + def expect_call_update_hook(path) + expect(gitlab_custom_hook) + .to receive(:system) + .with(vars, hook_path(path), ref_name, old_value, new_value) + .and_call_original + end + + # setup paths + # .git/hooks/ - symlink to gitlab-shell/hooks global dir + # .git/hooks/ - executed by git itself, this is gitlab-shell/hooks/ + # .git/hooks/.d/* - global hooks: all executable files (minus editor backup files) + # .git/custom_hooks/ - per project hook (this is already existing behavior) + # .git/custom_hooks/.d/* - per project hooks + # + # custom hooks are invoked in such way that first failure prevents other scripts being ran + # as global scripts are ran first, failing global skips repo hooks + + before do + cleanup_hook_setup + + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks')) + + ['pre-receive', 'update', 'post-receive'].each do |hook| + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', "#{hook}.d")) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', "#{hook}.d")) + end + + FileUtils.symlink(File.join(tmp_root_path, 'hooks'), File.join(tmp_repo_path, 'hooks')) + FileUtils.symlink(File.join(ROOT_PATH, 'config.yml.example'), File.join(tmp_root_path, 'config.yml')) + + stub_const('ROOT_PATH', tmp_root_path) + end + + after do + cleanup_hook_setup + end + + context 'with gl_id_test_hook as repo hook' do + before do + create_repo_hooks(hook_gl_id) + end + + context 'pre_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + end + end + + context 'post_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context 'update hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + end + end + end + + context 'with gl_id_test_hook as global hook' do + before do + create_global_hooks_d(hook_gl_id) + end + + context 'pre_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + end + end + + context 'post_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context 'update hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + end + end + end + + context "having no hooks" do + it "returns true" do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context "having only successful repo hooks" do + before do + create_repo_hooks(hook_ok) + end + + it "returns true" do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context "having both successful repo and global hooks" do + before do + create_repo_hooks(hook_ok) + create_global_hooks_d(hook_ok) + end + + it "returns true" do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context "having failing repo and successful global hooks" do + before do + create_repo_hooks_d(hook_fail) + create_global_hooks_d(hook_ok) + end + + it "returns false" do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) + expect(gitlab_custom_hook.post_receive(changes)).to eq(false) + end + + it "only executes the global hook" do + expect_call_receive_hook("custom_hooks/pre-receive.d/hook") + expect_call_update_hook("custom_hooks/update.d/hook") + expect_call_receive_hook("custom_hooks/post-receive.d/hook") + + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) + end + end + + context "having successful repo but failing global hooks" do + before do + create_repo_hooks_d(hook_ok) + create_global_hooks_d(hook_fail) + end + + it "returns false" do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) + expect(gitlab_custom_hook.post_receive(changes)).to eq(false) + end + + it "executes the relevant hooks" do + expect_call_receive_hook("hooks/pre-receive.d/hook") + expect_call_receive_hook("custom_hooks/pre-receive.d/hook") + expect_call_update_hook("hooks/update.d/hook") + expect_call_update_hook("custom_hooks/update.d/hook") + expect_call_receive_hook("hooks/post-receive.d/hook") + expect_call_receive_hook("custom_hooks/post-receive.d/hook") + + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) + end + end + + context "executing hooks in expected order" do + before do + create_repo_hooks_d(hook_ok, '01-test') + create_repo_hooks_d(hook_ok, '02-test') + create_global_hooks_d(hook_ok, '03-test') + create_global_hooks_d(hook_ok, '04-test') + end + + it "executes hooks in order" do + expect_call_receive_hook("custom_hooks/pre-receive.d/01-test").ordered + expect_call_receive_hook("custom_hooks/pre-receive.d/02-test").ordered + expect_call_receive_hook("hooks/pre-receive.d/03-test").ordered + expect_call_receive_hook("hooks/pre-receive.d/04-test").ordered + + expect_call_update_hook("custom_hooks/update.d/01-test").ordered + expect_call_update_hook("custom_hooks/update.d/02-test").ordered + expect_call_update_hook("hooks/update.d/03-test").ordered + expect_call_update_hook("hooks/update.d/04-test").ordered + + expect_call_receive_hook("custom_hooks/post-receive.d/01-test").ordered + expect_call_receive_hook("custom_hooks/post-receive.d/02-test").ordered + expect_call_receive_hook("hooks/post-receive.d/03-test").ordered + expect_call_receive_hook("hooks/post-receive.d/04-test").ordered + + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) + end + end + + context "when the custom_hooks_dir config option is set" do + before do + allow(gitlab_custom_hook.config).to receive(:custom_hooks_dir).and_return(global_custom_hooks_path) + + FileUtils.mkdir_p(File.join(global_custom_hooks_path, "pre-receive.d")) + FileUtils.ln_sf(hook_ok, File.join(global_custom_hooks_path, "pre-receive.d", "hook")) + + create_global_hooks_d(hook_fail) + end + + it "finds hooks in that directory" do + expect(gitlab_custom_hook) + .to receive(:call_receive_hook) + .with(global_hook_path("custom_global_hooks/pre-receive.d/hook"), changes) + .and_call_original + + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + end + + it "does not execute hooks in the default location" do + expect(gitlab_custom_hook) + .not_to receive(:call_receive_hook) + .with("hooks/pre-receive.d/hook", changes) + .and_call_original + + gitlab_custom_hook.pre_receive(changes) + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_keys_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_keys_spec.rb new file mode 100644 index 000000000..f86d00d06 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_keys_spec.rb @@ -0,0 +1,372 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_keys' +require 'stringio' + +describe GitlabKeys do + before do + $logger = double('logger').as_null_object + end + + describe '.command' do + it 'the internal "command" utility function' do + command = "#{ROOT_PATH}/bin/gitlab-shell does-not-validate" + expect(described_class.command('does-not-validate')).to eq(command) + end + + it 'does not raise a KeyError on invalid input' do + command = "#{ROOT_PATH}/bin/gitlab-shell foo\nbar\nbaz\n" + expect(described_class.command("foo\nbar\nbaz\n")).to eq(command) + end + end + + describe '.command_key' do + it 'returns the "command" part of the key line' do + command = "#{ROOT_PATH}/bin/gitlab-shell key-123" + expect(described_class.command_key('key-123')).to eq(command) + end + + it 'raises KeyError on invalid input' do + expect { described_class.command_key("\nssh-rsa AAA") }.to raise_error(described_class::KeyError) + end + end + + describe '.key_line' do + let(:line) { %(command="#{ROOT_PATH}/bin/gitlab-shell key-741",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaDAxx2E) } + + it 'returns the key line' do + expect(described_class.key_line('key-741', 'ssh-rsa AAAAB3NzaDAxx2E')).to eq(line) + end + + it 'silently removes a trailing newline' do + expect(described_class.key_line('key-741', "ssh-rsa AAAAB3NzaDAxx2E\n")).to eq(line) + end + + it 'raises KeyError on invalid input' do + expect { described_class.key_line('key-741', "ssh-rsa AAA\nssh-rsa AAA") }.to raise_error(described_class::KeyError) + end + end + + describe '.principal_line' do + let(:line) { %(command="#{ROOT_PATH}/bin/gitlab-shell username-someuser",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty sshUsers) } + + it 'returns the key line' do + expect(described_class.principal_line('username-someuser', 'sshUsers')).to eq(line) + end + + it 'silently removes a trailing newline' do + expect(described_class.principal_line('username-someuser', "sshUsers\n")).to eq(line) + end + + it 'raises KeyError on invalid input' do + expect { described_class.principal_line('username-someuser', "sshUsers\nloginUsers") }.to raise_error(described_class::KeyError) + end + end + + describe :initialize do + let(:gitlab_keys) { build_gitlab_keys('add-key', 'key-741', 'ssh-rsa AAAAB3NzaDAxx2E') } + + it { expect(gitlab_keys.key).to eq('ssh-rsa AAAAB3NzaDAxx2E') } + it { expect(gitlab_keys.instance_variable_get(:@command)).to eq('add-key') } + it { expect(gitlab_keys.instance_variable_get(:@key_id)).to eq('key-741') } + end + + describe :add_key do + let(:gitlab_keys) { build_gitlab_keys('add-key', 'key-741', 'ssh-rsa AAAAB3NzaDAxx2E') } + + it "adds a line at the end of the file" do + create_authorized_keys_fixture + gitlab_keys.send :add_key + auth_line = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-741\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaDAxx2E" + expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{auth_line}\n") + end + + context "without file writing" do + before { allow(gitlab_keys).to receive(:open) } + before { create_authorized_keys_fixture } + + it "should log an add-key event" do + expect($logger).to receive(:info).with("Adding key", {:key_id=>"key-741", :public_key=>"ssh-rsa AAAAB3NzaDAxx2E"}) + gitlab_keys.send :add_key + end + + it "should return true" do + expect(gitlab_keys.send(:add_key)).to be_truthy + end + end + end + + describe :list_keys do + let(:gitlab_keys) do + build_gitlab_keys('add-key', 'key-741', 'ssh-rsa AAAAB3NzaDAxx2E') + end + + it 'adds a key and lists it' do + create_authorized_keys_fixture + gitlab_keys.send :add_key + auth_line1 = 'key-741 AAAAB3NzaDAxx2E' + expect(gitlab_keys.send(:list_keys)).to eq("#{auth_line1}\n") + end + end + + describe :list_key_ids do + let(:gitlab_keys) { build_gitlab_keys('list-key-ids') } + before do + create_authorized_keys_fixture( + existing_content: + "key-1\tssh-dsa AAA\nkey-2\tssh-rsa BBB\nkey-3\tssh-rsa CCC\nkey-9000\tssh-rsa DDD\n" + ) + end + + it 'outputs the key IDs, separated by newlines' do + expect { gitlab_keys.send(:list_key_ids) }.to output("1\n2\n3\n9000\n").to_stdout + end + end + + describe :batch_add_keys do + let(:gitlab_keys) { build_gitlab_keys('batch-add-keys') } + let(:fake_stdin) { StringIO.new("key-12\tssh-dsa ASDFASGADG\nkey-123\tssh-rsa GFDGDFSGSDFG\n", 'r') } + before do + create_authorized_keys_fixture + allow(gitlab_keys).to receive(:stdin).and_return(fake_stdin) + end + + it "adds lines at the end of the file" do + gitlab_keys.send :batch_add_keys + auth_line1 = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-12\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-dsa ASDFASGADG" + auth_line2 = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-123\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa GFDGDFSGSDFG" + expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{auth_line1}\n#{auth_line2}\n") + end + + context "with invalid input" do + let(:fake_stdin) { StringIO.new("key-12\tssh-dsa ASDFASGADG\nkey-123\tssh-rsa GFDGDFSGSDFG\nfoo\tbar\tbaz\n", 'r') } + + it "aborts" do + expect(gitlab_keys).to receive(:abort) + gitlab_keys.send :batch_add_keys + end + end + + context "without file writing" do + before do + expect(gitlab_keys).to receive(:open).and_yield(double(:file, puts: nil, chmod: nil)) + end + + it "should log an add-key event" do + expect($logger).to receive(:info).with("Adding key", key_id: 'key-12', public_key: "ssh-dsa ASDFASGADG") + expect($logger).to receive(:info).with("Adding key", key_id: 'key-123', public_key: "ssh-rsa GFDGDFSGSDFG") + gitlab_keys.send :batch_add_keys + end + + it "should return true" do + expect(gitlab_keys.send(:batch_add_keys)).to be_truthy + end + end + end + + describe :stdin do + let(:gitlab_keys) { build_gitlab_keys } + subject { gitlab_keys.send :stdin } + before { $stdin = 1 } + + it { is_expected.to equal(1) } + end + + describe :rm_key do + let(:gitlab_keys) { build_gitlab_keys('rm-key', 'key-741', 'ssh-rsa AAAAB3NzaDAxx2E') } + + it "removes the right line" do + create_authorized_keys_fixture + other_line = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-742\",options ssh-rsa AAAAB3NzaDAxx2E" + delete_line = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-741\",options ssh-rsa AAAAB3NzaDAxx2E" + open(tmp_authorized_keys_path, 'a') do |auth_file| + auth_file.puts delete_line + auth_file.puts other_line + end + gitlab_keys.send :rm_key + erased_line = delete_line.gsub(/./, '#') + expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{erased_line}\n#{other_line}\n") + end + + context "without file writing" do + before do + allow(gitlab_keys).to receive(:open) + allow(gitlab_keys).to receive(:lock).and_yield + end + + it "should log an rm-key event" do + expect($logger).to receive(:info).with("Removing key", key_id: "key-741") + gitlab_keys.send :rm_key + end + + it "should return true" do + expect(gitlab_keys.send(:rm_key)).to be_truthy + end + end + + context 'without key content' do + let(:gitlab_keys) { build_gitlab_keys('rm-key', 'key-741') } + + it "removes the right line by key ID" do + create_authorized_keys_fixture + other_line = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-742\",options ssh-rsa AAAAB3NzaDAxx2E" + delete_line = "command=\"#{ROOT_PATH}/bin/gitlab-shell key-741\",options ssh-rsa AAAAB3NzaDAxx2E" + open(tmp_authorized_keys_path, 'a') do |auth_file| + auth_file.puts delete_line + auth_file.puts other_line + end + gitlab_keys.send :rm_key + erased_line = delete_line.gsub(/./, '#') + expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{erased_line}\n#{other_line}\n") + end + end + end + + describe :clear do + let(:gitlab_keys) { build_gitlab_keys('clear') } + + it "should return true" do + allow(gitlab_keys).to receive(:open) + expect(gitlab_keys.send(:clear)).to be_truthy + end + end + + describe :check_permissions do + let(:gitlab_keys) { build_gitlab_keys('check-permissions') } + + it 'returns true when the file can be opened' do + create_authorized_keys_fixture + expect(gitlab_keys.exec).to eq(true) + end + + it 'returns false if opening raises an exception' do + expect(gitlab_keys).to receive(:open_auth_file).and_raise("imaginary error") + expect(gitlab_keys.exec).to eq(false) + end + + it 'creates the keys file if it does not exist' do + create_authorized_keys_fixture + FileUtils.rm(tmp_authorized_keys_path) + expect(gitlab_keys.exec).to eq(true) + expect(File.exist?(tmp_authorized_keys_path)).to eq(true) + end + end + + describe :exec do + it 'add-key arg should execute add_key method' do + gitlab_keys = build_gitlab_keys('add-key') + expect(gitlab_keys).to receive(:add_key) + gitlab_keys.exec + end + + it 'batch-add-keys arg should execute batch_add_keys method' do + gitlab_keys = build_gitlab_keys('batch-add-keys') + expect(gitlab_keys).to receive(:batch_add_keys) + gitlab_keys.exec + end + + it 'rm-key arg should execute rm_key method' do + gitlab_keys = build_gitlab_keys('rm-key') + expect(gitlab_keys).to receive(:rm_key) + gitlab_keys.exec + end + + it 'clear arg should execute clear method' do + gitlab_keys = build_gitlab_keys('clear') + expect(gitlab_keys).to receive(:clear) + gitlab_keys.exec + end + + it 'check-permissions arg should execute check_permissions method' do + gitlab_keys = build_gitlab_keys('check-permissions') + expect(gitlab_keys).to receive(:check_permissions) + gitlab_keys.exec + end + + it 'should puts message if unknown command arg' do + gitlab_keys = build_gitlab_keys('change-key') + expect(gitlab_keys).to receive(:puts).with('not allowed') + gitlab_keys.exec + end + + it 'should log a warning on unknown commands' do + gitlab_keys = build_gitlab_keys('nooope') + allow(gitlab_keys).to receive(:puts).and_return(nil) + expect($logger).to receive(:warn).with("Attempt to execute invalid gitlab-keys command", command: '"nooope"') + gitlab_keys.exec + end + end + + describe :lock do + before do + allow_any_instance_of(GitlabKeys).to receive(:lock_file).and_return(tmp_lock_file_path) + end + + it "should raise exception if operation lasts more then timeout" do + key = GitlabKeys.new + expect do + key.send :lock, 1 do + sleep 2 + end + end.to raise_error(Timeout::Error, 'execution expired') + end + + it "should actually lock file" do + $global = "" + key = GitlabKeys.new + + thr1 = Thread.new do + key.send :lock do + # Put bigger sleep here to test if main thread will + # wait for lock file released before executing code + sleep 1 + $global << "foo" + end + end + + # make sure main thread start lock command after + # thread above + sleep 0.5 + + key.send :lock do + $global << "bar" + end + + thr1.join + expect($global).to eq("foobar") + end + end + + def build_gitlab_keys(*args) + argv(*args) + GitlabKeys.new + end + + def argv(*args) + args.each_with_index do |arg, i| + ARGV[i] = arg.freeze + end + end + + def create_authorized_keys_fixture(existing_content: 'existing content') + FileUtils.mkdir_p(File.dirname(tmp_authorized_keys_path)) + open(tmp_authorized_keys_path, 'w') { |file| file.puts(existing_content) } + allow(gitlab_keys).to receive(:auth_file).and_return(tmp_authorized_keys_path) + end + + def tmp_authorized_keys_path + File.join(ROOT_PATH, 'tmp', 'authorized_keys') + end + + def tmp_lock_file_path + tmp_authorized_keys_path + '.lock' + end + + def capture_stdout(&blk) + old = $stdout + $stdout = fake = StringIO.new + blk.call + fake.string + ensure + $stdout = old + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_lfs_authentication_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_lfs_authentication_spec.rb new file mode 100644 index 000000000..81b53a7bf --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_lfs_authentication_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' +require 'gitlab_lfs_authentication' +require 'json' + +describe GitlabLfsAuthentication do + subject do + GitlabLfsAuthentication.build_from_json( + JSON.generate( + { + username: 'dzaporozhets', + lfs_token: 'wsnys8Zm8Jn7zyhHTAAK', + repository_http_path: 'http://gitlab.dev/repo' + } + ) + ) + end + + describe '#build_from_json' do + it { expect(subject.username).to eq('dzaporozhets') } + it { expect(subject.lfs_token).to eq('wsnys8Zm8Jn7zyhHTAAK') } + it { expect(subject.repository_http_path).to eq('http://gitlab.dev/repo') } + end + + describe '#authentication_payload' do + result = "{\"header\":{\"Authorization\":\"Basic ZHphcG9yb3poZXRzOndzbnlzOFptOEpuN3p5aEhUQUFL\"},\"href\":\"http://gitlab.dev/repo/info/lfs/\"}" + + it { expect(subject.authentication_payload).to eq(result) } + + it 'should be a proper JSON' do + payload = subject.authentication_payload + json_payload = JSON.parse(payload) + + expect(json_payload['header']['Authorization']).to eq('Basic ZHphcG9yb3poZXRzOndzbnlzOFptOEpuN3p5aEhUQUFL') + expect(json_payload['href']).to eq('http://gitlab.dev/repo/info/lfs/') + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_logger_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_logger_spec.rb new file mode 100644 index 000000000..a9cd3fb0c --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_logger_spec.rb @@ -0,0 +1,145 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_logger' +require 'securerandom' + +describe :convert_log_level do + subject { convert_log_level :extreme } + + it "converts invalid log level to Logger::INFO" do + expect($stderr).to receive(:puts).at_least(:once) + is_expected.to eq(Logger::INFO) + end +end + +describe GitlabLogger do + subject { described_class.new(level, '/dev/null', format) } + let(:format) { 'text' } + let(:output) { StringIO.new } + let(:level) { Logger::INFO } + let(:time) { Time.at(123_456_789).utc } # '1973-11-29T21:33:09+00:00' + let(:pid) { 1234 } + + before do + allow(subject).to receive(:log_file).and_return(output) + allow(subject).to receive(:time_now).and_return(time) + allow(subject).to receive(:pid).and_return(pid) + end + + def first_line + output.string.lines.first.chomp + end + + describe 'field sorting' do + it 'sorts fields, except time, level, msg' do + # Intentionally put 'foo' before 'baz' to see the effect of sorting + subject.info('hello world', foo: 'bar', baz: 'qux') + + expect(first_line).to eq('time="1973-11-29T21:33:09+00:00" level=info msg="hello world" baz=qux foo=bar pid=1234') + end + end + + describe '#error' do + context 'when the log level is too high' do + let(:level) { Logger::FATAL } + + it 'does nothing' do + subject.info('hello world') + + expect(output.string).to eq('') + end + end + + it 'logs data' do + subject.error('hello world', foo: 'bar') + + expect(first_line).to eq('time="1973-11-29T21:33:09+00:00" level=error msg="hello world" foo=bar pid=1234') + end + end + + describe '#info' do + context 'when the log level is too high' do + let(:level) { Logger::ERROR } + + it 'does nothing' do + subject.info('hello world') + + expect(output.string).to eq('') + end + end + + it 'logs data' do + subject.info('hello world', foo: 'bar') + + expect(first_line).to eq('time="1973-11-29T21:33:09+00:00" level=info msg="hello world" foo=bar pid=1234') + end + end + + describe '#warn' do + context 'when the log level is too high' do + let(:level) { Logger::ERROR } + + it 'does nothing' do + subject.warn('hello world') + + expect(output.string).to eq('') + end + end + + it 'logs data' do + subject.warn('hello world', foo: 'bar') + + expect(first_line).to eq('time="1973-11-29T21:33:09+00:00" level=warn msg="hello world" foo=bar pid=1234') + end + end + + describe '#debug' do + it 'does nothing' do + subject.debug('hello world') + + expect(output.string).to eq('') + end + + context 'when the log level is low enough' do + let(:level) { Logger::DEBUG } + + it 'logs data' do + subject.debug('hello world', foo: 'bar') + + expect(first_line).to eq('time="1973-11-29T21:33:09+00:00" level=debug msg="hello world" foo=bar pid=1234') + end + end + end + + describe 'json logging' do + let(:format) { 'json' } + + it 'writes valid JSON data' do + subject.info('hello world', foo: 'bar') + + expect(JSON.parse(first_line)).to eq( + 'foo' => 'bar', + 'level' => 'info', + 'msg' => 'hello world', + 'pid' => 1234, + 'time' => '1973-11-29T21:33:09+00:00' + ) + end + + it 'handles non-UTF8 string values' do + subject.info("hello\x80world") + + expect(JSON.parse(first_line)).to include('msg' => '"hello\x80world"') + end + end + + describe 'log flushing' do + it 'logs get written even when calling Kernel.exec' do + msg = SecureRandom.hex(12) + test_logger_status = system('bin/test-logger', msg) + expect(test_logger_status).to eq(true) + + grep_status = system('grep', '-q', '-e', msg, GitlabConfig.new.log_file) + expect(grep_status).to eq(true) + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_metrics_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_metrics_spec.rb new file mode 100644 index 000000000..00e94b590 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_metrics_spec.rb @@ -0,0 +1,40 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_metrics' + +describe GitlabMetrics do + describe '.measure' do + before do + $logger = double('logger').as_null_object + end + + it 'returns the return value of the block' do + val = described_class.measure('foo') { 10 } + + expect(val).to eq(10) + end + + it 'writes the metrics data to a log file' do + expect($logger).to receive(:debug). + with('metrics', a_metrics_log_message('foo')) + + described_class.measure('foo') { 10 } + end + + it 'calls proper measure methods' do + expect(described_class::System).to receive(:monotonic_time).twice.and_call_original + expect(described_class::System).to receive(:cpu_time).twice.and_call_original + + described_class.measure('foo') { 10 } + end + end +end + +RSpec::Matchers.define :a_metrics_log_message do |x| + match do |actual| + [ + actual.fetch(:name) == x, + actual.fetch(:wall_time).is_a?(Numeric), + actual.fetch(:cpu_time).is_a?(Numeric), + ].all? + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_net_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_net_spec.rb new file mode 100644 index 000000000..c6245d4e3 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_net_spec.rb @@ -0,0 +1,554 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_net' +require_relative '../lib/gitlab_access_status' + +describe GitlabNet, vcr: true do + using RSpec::Parameterized::TableSyntax + + let(:gitlab_net) { described_class.new } + let(:changes) { ['0000000000000000000000000000000000000000 92d0970eefd7acb6d548878925ce2208cfe2d2ec refs/heads/branch4'] } + let(:base_api_endpoint) { 'http://localhost:3000/api/v4' } + let(:internal_api_endpoint) { 'http://localhost:3000/api/v4/internal' } + let(:project) { 'gitlab-org/gitlab-test.git' } + let(:key) { 'key-1' } + let(:key2) { 'key-2' } + let(:secret) { "0a3938d9d95d807e94d937af3a4fbbea\n" } + + before do + $logger = double('logger').as_null_object + allow(gitlab_net).to receive(:base_api_endpoint).and_return(base_api_endpoint) + allow(gitlab_net).to receive(:secret_token).and_return(secret) + end + + describe '#check' do + it 'should return 200 code for gitlab check' do + VCR.use_cassette("check-ok") do + result = gitlab_net.check + expect(result.code).to eq('200') + end + end + + it 'adds the secret_token to request' do + VCR.use_cassette("check-ok") do + expect_any_instance_of(Net::HTTP::Get).to receive(:set_form_data).with(hash_including(secret_token: secret)) + gitlab_net.check + end + end + + it "raises an exception if the connection fails" do + allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(StandardError) + expect { gitlab_net.check }.to raise_error(GitlabNet::ApiUnreachableError) + end + end + + describe '#discover' do + it 'should return user has based on key id' do + VCR.use_cassette("discover-ok") do + user = gitlab_net.discover(key) + expect(user['name']).to eq('Administrator') + expect(user['username']).to eq('root') + end + end + + it 'adds the secret_token to request' do + VCR.use_cassette("discover-ok") do + expect_any_instance_of(Net::HTTP::Get).to receive(:set_form_data).with(hash_including(secret_token: secret)) + gitlab_net.discover(key) + end + end + + it "raises an exception if the connection fails" do + VCR.use_cassette("discover-ok") do + allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(StandardError) + expect { gitlab_net.discover(key) }.to raise_error(GitlabNet::ApiUnreachableError) + end + end + end + + describe '#lfs_authenticate' do + context 'lfs authentication succeeded' do + let(:repository_http_path) { URI.join(internal_api_endpoint.sub('/api/v4', ''), project).to_s } + + context 'for download operation' do + it 'should return the correct data' do + VCR.use_cassette('lfs-authenticate-ok-download') do + lfs_access = gitlab_net.lfs_authenticate(key, project, 'download') + expect(lfs_access.username).to eq('root') + expect(lfs_access.lfs_token).to eq('Hyzhyde_wLUeyUQsR3tHGTG8eNocVQm4ssioTEsBSdb6KwCSzQ') + expect(lfs_access.repository_http_path).to eq(repository_http_path) + end + end + end + + context 'for upload operation' do + it 'should return the correct data' do + VCR.use_cassette('lfs-authenticate-ok-upload') do + lfs_access = gitlab_net.lfs_authenticate(key, project, 'upload') + expect(lfs_access.username).to eq('root') + expect(lfs_access.lfs_token).to eq('Hyzhyde_wLUeyUQsR3tHGTG8eNocVQm4ssioTEsBSdb6KwCSzQ') + expect(lfs_access.repository_http_path).to eq(repository_http_path) + end + end + end + end + end + + describe '#broadcast_message' do + context "broadcast message exists" do + it 'should return message' do + VCR.use_cassette("broadcast_message-ok") do + result = gitlab_net.broadcast_message + expect(result["message"]).to eq("Message") + end + end + end + + context "broadcast message doesn't exist" do + it 'should return nil' do + VCR.use_cassette("broadcast_message-none") do + result = gitlab_net.broadcast_message + expect(result).to eq({}) + end + end + end + end + + describe '#merge_request_urls' do + let(:gl_repository) { "project-1" } + let(:changes) { "123456 789012 refs/heads/test\n654321 210987 refs/tags/tag" } + let(:encoded_changes) { "123456%20789012%20refs/heads/test%0A654321%20210987%20refs/tags/tag" } + + it "sends the given arguments as encoded URL parameters" do + expect(gitlab_net).to receive(:get).with("#{internal_api_endpoint}/merge_request_urls?project=#{project}&changes=#{encoded_changes}&gl_repository=#{gl_repository}") + + gitlab_net.merge_request_urls(gl_repository, project, changes) + end + + it "omits the gl_repository parameter if it's nil" do + expect(gitlab_net).to receive(:get).with("#{internal_api_endpoint}/merge_request_urls?project=#{project}&changes=#{encoded_changes}") + + gitlab_net.merge_request_urls(nil, project, changes) + end + + it "returns an empty array when the result cannot be parsed as JSON" do + response = double(:response, code: '200', body: '') + allow(gitlab_net).to receive(:get).and_return(response) + + expect(gitlab_net.merge_request_urls(gl_repository, project, changes)).to eq([]) + end + + it "returns an empty array when the result's status is not 200" do + response = double(:response, code: '500', body: '[{}]') + allow(gitlab_net).to receive(:get).and_return(response) + + expect(gitlab_net.merge_request_urls(gl_repository, project, changes)).to eq([]) + end + end + + describe '#pre_receive' do + let(:gl_repository) { "project-1" } + let(:params) { { gl_repository: gl_repository } } + + subject { gitlab_net.pre_receive(gl_repository) } + + it 'sends the correct parameters and returns the request body parsed' do + expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data) + .with(hash_including(params)) + + VCR.use_cassette("pre-receive") { subject } + end + + it 'calls /internal/pre-receive' do + VCR.use_cassette("pre-receive") do + expect(subject['reference_counter_increased']).to be(true) + end + end + + it 'throws a NotFound error when pre-receive is not available' do + VCR.use_cassette("pre-receive-not-found") do + expect { subject }.to raise_error(GitlabNet::NotFound) + end + end + end + + describe '#post_receive' do + let(:gl_repository) { "project-1" } + let(:changes) { "123456 789012 refs/heads/test\n654321 210987 refs/tags/tag" } + let(:push_options) { ["ci-skip", "something unexpected"] } + let(:params) do + { gl_repository: gl_repository, identifier: key, changes: changes, :"push_options[]" => push_options } + end + let(:merge_request_urls) do + [{ + "branch_name" => "test", + "url" => "http://localhost:3000/gitlab-org/gitlab-test/merge_requests/7", + "new_merge_request" => false + }] + end + + subject { gitlab_net.post_receive(gl_repository, key, changes, push_options) } + + it 'sends the correct parameters' do + expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data).with(hash_including(params)) + + + VCR.use_cassette("post-receive") do + subject + end + end + + it 'calls /internal/post-receive' do + VCR.use_cassette("post-receive") do + expect(subject['merge_request_urls']).to eq(merge_request_urls) + expect(subject['broadcast_message']).to eq('Message') + expect(subject['reference_counter_decreased']).to eq(true) + end + end + + it 'throws a NotFound error when post-receive is not available' do + VCR.use_cassette("post-receive-not-found") do + expect { subject }.to raise_error(GitlabNet::NotFound) + end + end + end + + describe '#authorized_key' do + let (:ssh_key) { "rsa-key" } + + it "should return nil when the resource is not implemented" do + VCR.use_cassette("ssh-key-not-implemented") do + result = gitlab_net.authorized_key("whatever") + expect(result).to be_nil + end + end + + it "should return nil when the fingerprint is not found" do + VCR.use_cassette("ssh-key-not-found") do + result = gitlab_net.authorized_key("whatever") + expect(result).to be_nil + end + end + + it "should return a ssh key with a valid fingerprint" do + VCR.use_cassette("ssh-key-ok") do + result = gitlab_net.authorized_key(ssh_key) + expect(result).to eq({ + "can_push" => false, + "created_at" => "2017-06-21T09:50:07.150Z", + "id" => 99, + "key" => "ssh-rsa rsa-key dummy@gitlab.com", + "title" => "untitled" + }) + end + end + end + + describe '#two_factor_recovery_codes' do + it 'returns two factor recovery codes' do + VCR.use_cassette('two-factor-recovery-codes') do + result = gitlab_net.two_factor_recovery_codes(key) + expect(result['success']).to be_truthy + expect(result['recovery_codes']).to eq(['f67c514de60c4953','41278385fc00c1e0']) + end + end + + it 'returns false when recovery codes cannot be generated' do + VCR.use_cassette('two-factor-recovery-codes-fail') do + result = gitlab_net.two_factor_recovery_codes('key-777') + expect(result['success']).to be_falsey + expect(result['message']).to eq('Could not find the given key') + end + end + end + + describe '#notify_post_receive' do + let(:gl_repository) { 'project-1' } + let(:repo_path) { '/path/to/my/repo.git' } + let(:params) do + { gl_repository: gl_repository, project: repo_path } + end + + it 'sets the arguments as form parameters' do + VCR.use_cassette('notify-post-receive') do + expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data).with(hash_including(params)) + gitlab_net.notify_post_receive(gl_repository, repo_path) + end + end + + it 'returns true if notification was succesful' do + VCR.use_cassette('notify-post-receive') do + expect(gitlab_net.notify_post_receive(gl_repository, repo_path)).to be_truthy + end + end + end + + describe '#check_access' do + context 'ssh key with access nil, to project' do + it 'should allow push access for host' do + VCR.use_cassette("allowed-push") do + access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + expect(access.allowed?).to be_truthy + end + end + + context 'but project not found' do + where(:desc, :cassette, :message) do + 'deny push access for host' | 'allowed-push-project-not-found' | 'The project you were looking for could not be found.' + 'deny push access for host (when text/html)' | 'allowed-push-project-not-found-text-html' | 'API is not accessible' + 'deny push access for host (when text/plain)' | 'allowed-push-project-not-found-text-plain' | 'API is not accessible' + 'deny push access for host (when 404 is returned)' | 'allowed-push-project-not-found-404' | 'The project you were looking for could not be found.' + 'deny push access for host (when 404 is returned with text/html)' | 'allowed-push-project-not-found-404-text-html' | 'API is not accessible' + 'deny push access for host (when 404 is returned with text/plain)' | 'allowed-push-project-not-found-404-text-plain' | 'API is not accessible' + end + + with_them do + it 'should deny push access for host' do + VCR.use_cassette(cassette) do + access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + expect(access.allowed?).to be_falsey + expect(access.message).to eql(message) + end + end + end + end + + it 'adds the secret_token to the request' do + VCR.use_cassette("allowed-push") do + expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data).with(hash_including(secret_token: secret)) + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + end + end + + it 'should allow pull access for host' do + VCR.use_cassette("allowed-pull") do + access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh') + expect(access.allowed?).to be_truthy + end + end + end + + context 'ssh access has been disabled' do + it 'should deny pull access for host' do + VCR.use_cassette('ssh-pull-disabled') do + access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh') + expect(access.allowed?).to be_falsey + expect(access.message).to eq 'Git access over SSH is not allowed' + end + end + + it 'should deny push access for host' do + VCR.use_cassette('ssh-push-disabled') do + access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + expect(access.allowed?).to be_falsey + expect(access.message).to eq 'Git access over SSH is not allowed' + end + end + end + + context 'http access has been disabled' do + it 'should deny pull access for host' do + VCR.use_cassette('http-pull-disabled') do + access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') + expect(access.allowed?).to be_falsey + expect(access.message).to eq 'Pulling over HTTP is not allowed.' + end + end + + it 'should deny push access for host' do + VCR.use_cassette("http-push-disabled") do + access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'http') + expect(access.allowed?).to be_falsey + expect(access.message).to eq 'Pushing over HTTP is not allowed.' + end + end + end + + context 'ssh key without access to project' do + where(:desc, :cassette, :message) do + 'deny push access for host' | 'ssh-push-project-denied' | 'Git access over SSH is not allowed' + 'deny push access for host (when 401 is returned)' | 'ssh-push-project-denied-401' | 'Git access over SSH is not allowed' + 'deny push access for host (when 401 is returned with text/html)' | 'ssh-push-project-denied-401-text-html' | 'API is not accessible' + 'deny push access for host (when 401 is returned with text/plain)' | 'ssh-push-project-denied-401-text-plain' | 'API is not accessible' + 'deny pull access for host' | 'ssh-pull-project-denied' | 'Git access over SSH is not allowed' + 'deny pull access for host (when 401 is returned)' | 'ssh-pull-project-denied-401' | 'Git access over SSH is not allowed' + 'deny pull access for host (when 401 is returned with text/html)' | 'ssh-pull-project-denied-401-text-html' | 'API is not accessible' + 'deny pull access for host (when 401 is returned with text/plain)' | 'ssh-pull-project-denied-401-text-plain' | 'API is not accessible' + end + + with_them do + it 'should deny push access for host' do + VCR.use_cassette(cassette) do + access = gitlab_net.check_access('git-receive-pack', nil, project, key2, changes, 'ssh') + expect(access.allowed?).to be_falsey + expect(access.message).to eql(message) + end + end + end + + it 'should deny pull access for host (with user)' do + VCR.use_cassette("ssh-pull-project-denied-with-user") do + access = gitlab_net.check_access('git-upload-pack', nil, project, 'user-2', changes, 'ssh') + expect(access.allowed?).to be_falsey + expect(access.message).to eql('Git access over SSH is not allowed') + end + end + end + + it 'handles non 200 status codes' do + resp = double(:resp, code: 501) + + allow(gitlab_net).to receive(:post).and_return(resp) + + access = gitlab_net.check_access('git-upload-pack', nil, project, 'user-2', changes, 'ssh') + expect(access).not_to be_allowed + end + + it "raises an exception if the connection fails" do + allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(StandardError) + expect { + gitlab_net.check_access('git-upload-pack', nil, project, 'user-1', changes, 'ssh') + }.to raise_error(GitlabNet::ApiUnreachableError) + end + end + + describe '#base_api_endpoint' do + let(:net) { described_class.new } + + subject { net.send :base_api_endpoint } + + it { is_expected.to include(net.send(:config).gitlab_url) } + it("uses API version 4") { is_expected.to end_with("api/v4") } + end + + describe '#internal_api_endpoint' do + let(:net) { described_class.new } + + subject { net.send :internal_api_endpoint } + + it { is_expected.to include(net.send(:config).gitlab_url) } + it("uses API version 4") { is_expected.to end_with("api/v4/internal") } + end + + describe '#http_client_for' do + subject { gitlab_net.send :http_client_for, URI('https://localhost/') } + + before do + allow(gitlab_net).to receive :cert_store + allow(gitlab_net.send(:config)).to receive(:http_settings) { {'self_signed_cert' => true} } + end + + it { expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE) } + end + + describe '#http_request_for' do + context 'with stub' do + let(:get) { double(Net::HTTP::Get) } + let(:user) { 'user' } + let(:password) { 'password' } + let(:url) { URI 'http://localhost/' } + let(:params) { { 'key1' => 'value1' } } + let(:headers) { { 'Content-Type' => 'application/json'} } + let(:options) { { json: { 'key2' => 'value2' } } } + + context 'with no params, options or headers' do + subject { gitlab_net.send :http_request_for, :get, url } + + before do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('user') { user } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('password') { password } + expect(Net::HTTP::Get).to receive(:new).with('/', {}).and_return(get) + expect(get).to receive(:basic_auth).with(user, password).once + expect(get).to receive(:set_form_data).with(hash_including(secret_token: secret)).once + end + + it { is_expected.not_to be_nil } + end + + context 'with params' do + subject { gitlab_net.send :http_request_for, :get, url, params: params, headers: headers } + + before do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('user') { user } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('password') { password } + expect(Net::HTTP::Get).to receive(:new).with('/', headers).and_return(get) + expect(get).to receive(:basic_auth).with(user, password).once + expect(get).to receive(:set_form_data).with({ 'key1' => 'value1', secret_token: secret }).once + end + + it { is_expected.not_to be_nil } + end + + context 'with headers' do + subject { gitlab_net.send :http_request_for, :get, url, headers: headers } + + before do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('user') { user } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('password') { password } + expect(Net::HTTP::Get).to receive(:new).with('/', headers).and_return(get) + expect(get).to receive(:basic_auth).with(user, password).once + expect(get).to receive(:set_form_data).with(hash_including(secret_token: secret)).once + end + + it { is_expected.not_to be_nil } + end + + context 'with options' do + context 'with json' do + subject { gitlab_net.send :http_request_for, :get, url, options: options } + + before do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('user') { user } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('password') { password } + expect(Net::HTTP::Get).to receive(:new).with('/', {}).and_return(get) + expect(get).to receive(:basic_auth).with(user, password).once + expect(get).to receive(:body=).with({ 'key2' => 'value2', secret_token: secret }.to_json).once + expect(get).not_to receive(:set_form_data) + end + + it { is_expected.not_to be_nil } + end + end + end + + context 'Unix socket' do + it 'sets the Host header to "localhost"' do + gitlab_net = described_class.new + expect(gitlab_net).to receive(:secret_token).and_return(secret) + + request = gitlab_net.send(:http_request_for, :get, URI('http+unix://%2Ffoo')) + + expect(request['Host']).to eq('localhost') + end + end + end + + describe '#cert_store' do + let(:store) do + double(OpenSSL::X509::Store).tap do |store| + allow(OpenSSL::X509::Store).to receive(:new) { store } + end + end + + before :each do + expect(store).to receive(:set_default_paths).once + end + + after do + gitlab_net.send :cert_store + end + + it "calls add_file with http_settings['ca_file']" do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('ca_file') { 'test_file' } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('ca_path') { nil } + expect(store).to receive(:add_file).with('test_file') + expect(store).not_to receive(:add_path) + end + + it "calls add_path with http_settings['ca_path']" do + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('ca_file') { nil } + allow(gitlab_net.send(:config).http_settings).to receive(:[]).with('ca_path') { 'test_path' } + expect(store).not_to receive(:add_file) + expect(store).to receive(:add_path).with('test_path') + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_post_receive_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_post_receive_spec.rb new file mode 100644 index 000000000..3cae6319e --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_post_receive_spec.rb @@ -0,0 +1,270 @@ +# coding: utf-8 +require 'spec_helper' +require 'gitlab_post_receive' + +describe GitlabPostReceive do + let(:repository_path) { "/home/git/repositories" } + let(:repo_name) { 'dzaporozhets/gitlab-ci' } + let(:actor) { 'key-123' } + let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" } + let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") } + let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) } + let(:repo_path) { File.join(repository_path, repo_name) + ".git" } + let(:gl_repository) { "project-1" } + let(:push_options) { [] } + let(:gitlab_post_receive) { GitlabPostReceive.new(gl_repository, repo_path, actor, wrongly_encoded_changes, push_options) } + let(:broadcast_message) { "test " * 10 + "message " * 10 } + let(:enqueued_at) { Time.new(2016, 6, 23, 6, 59) } + let(:new_merge_request_urls) do + [{ + 'branch_name' => 'new_branch', + 'url' => 'http://localhost/dzaporozhets/gitlab-ci/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch', + 'new_merge_request' => true + }] + end + let(:existing_merge_request_urls) do + [{ + 'branch_name' => 'feature_branch', + 'url' => 'http://localhost/dzaporozhets/gitlab-ci/merge_requests/1', + 'new_merge_request' => false + }] + end + + before do + $logger = double('logger').as_null_object # Global vars are bad + allow_any_instance_of(GitlabConfig).to receive(:repos_path).and_return(repository_path) + end + + describe "#exec" do + let(:response) { { 'reference_counter_decreased' => true } } + + it 'calls the api to notify the execution of the hook' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + + expect(gitlab_post_receive.exec).to eq(true) + end + + context 'merge request urls and broadcast messages' do + let(:response) do + { + 'reference_counter_decreased' => true, + 'merge_request_urls' => new_merge_request_urls, + 'broadcast_message' => broadcast_message + } + end + + it 'prints the merge request urls and broadcast message' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + assert_broadcast_message_printed(gitlab_post_receive) + assert_new_mr_printed(gitlab_post_receive) + + expect(gitlab_post_receive.exec).to eq(true) + end + + context 'when contains long url string at end' do + let(:broadcast_message) { "test " * 10 + "message " * 10 + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" } + + it 'doesnt truncate url' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + assert_broadcast_message_printed_keep_long_url_end(gitlab_post_receive) + assert_new_mr_printed(gitlab_post_receive) + + expect(gitlab_post_receive.exec).to eq(true) + end + end + + context 'when contains long url string at start' do + let(:broadcast_message) { "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url " + "test " * 10 + "message " * 11} + + it 'doesnt truncate url' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + assert_broadcast_message_printed_keep_long_url_start(gitlab_post_receive) + assert_new_mr_printed(gitlab_post_receive) + + expect(gitlab_post_receive.exec).to eq(true) + end + end + + context 'when contains long url string in middle' do + let(:broadcast_message) { "test " * 11 + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url " + "message " * 11} + + it 'doesnt truncate url' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + assert_broadcast_message_printed_keep_long_url_middle(gitlab_post_receive) + assert_new_mr_printed(gitlab_post_receive) + + expect(gitlab_post_receive.exec).to eq(true) + end + end + + end + + context 'when redirected message available' do + let(:message) { "This is a redirected message" } + let(:response) do + { + 'reference_counter_decreased' => true, + 'redirected_message' => message + } + end + + it 'prints redirected message' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + assert_redirected_message_printed(gitlab_post_receive) + expect(gitlab_post_receive.exec).to eq(true) + end + + context 'when project created message is available' do + let(:message) { "This is a created project message" } + let(:response) do + { + 'reference_counter_decreased' => true, + 'project_created_message' => message + } + end + + it 'prints project created message' do + expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) + + assert_project_created_message_printed(gitlab_post_receive) + + expect(gitlab_post_receive.exec).to be true + end + end + end + end + + private + + def assert_new_mr_printed(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "To create a merge request for new_branch, visit:" + ).ordered + expect(gitlab_post_receive).to receive(:puts).with( + " http://localhost/dzaporozhets/gitlab-ci/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + end + + def assert_existing_mr_printed(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "View merge request for feature_branch:" + ).ordered + expect(gitlab_post_receive).to receive(:puts).with( + " http://localhost/dzaporozhets/gitlab-ci/merge_requests/1" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + end + + def assert_broadcast_message_printed(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " test test test test test test test test test test message message" + ).ordered + expect(gitlab_post_receive).to receive(:puts).with( + " message message message message message message message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + end + + def assert_redirected_message_printed(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).with("This is a redirected message") + end + + def assert_project_created_message_printed(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).with("This is a created project message") + end + + def assert_broadcast_message_printed_keep_long_url_end(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " test test test test test test test test test test message message" + ).ordered + expect(gitlab_post_receive).to receive(:puts).with( + " message message message message message message message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + end + + def assert_broadcast_message_printed_keep_long_url_start(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " test test test test test test test test test test message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " message message message message message message message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + end + + def assert_broadcast_message_printed_keep_long_url_middle(gitlab_post_receive) + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + expect(gitlab_post_receive).to receive(:puts).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " test test test test test test test test test test test" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " message message message message message message message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).with( + " message message message" + ).ordered + + expect(gitlab_post_receive).to receive(:puts).ordered + expect(gitlab_post_receive).to receive(:puts).with( + "========================================================================" + ).ordered + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_shell_authorized_keys_check_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_shell_authorized_keys_check_spec.rb new file mode 100644 index 000000000..baaa56049 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_shell_authorized_keys_check_spec.rb @@ -0,0 +1,117 @@ +require_relative 'spec_helper' + +describe 'bin/gitlab-shell-authorized-keys-check' do + def original_root_path + ROOT_PATH + end + + # All this test boilerplate is mostly copy/pasted between + # gitlab_shell_gitlab_shell_spec.rb and + # gitlab_shell_authorized_keys_check_spec.rb + def tmp_root_path + @tmp_root_path ||= File.realpath(Dir.mktmpdir) + end + + def config_path + File.join(tmp_root_path, 'config.yml') + end + + def tmp_socket_path + # This has to be a relative path shorter than 100 bytes due to + # limitations in how Unix sockets work. + 'tmp/gitlab-shell-authorized-keys-check-socket' + end + + before(:all) do + FileUtils.mkdir_p(File.dirname(tmp_socket_path)) + FileUtils.touch(File.join(tmp_root_path, '.gitlab_shell_secret')) + + @server = HTTPUNIXServer.new(BindAddress: tmp_socket_path) + @server.mount_proc('/api/v4/internal/authorized_keys') do |req, res| + if req.query['key'] == 'known-rsa-key' + res.status = 200 + res.content_type = 'application/json' + res.body = '{"key":"known-rsa-key", "id": 1}' + else + res.status = 404 + end + end + + @webrick_thread = Thread.new { @server.start } + + sleep(0.1) while @webrick_thread.alive? && @server.status != :Running + raise "Couldn't start stub GitlabNet server" unless @server.status == :Running + + File.open(config_path, 'w') do |f| + f.write("---\ngitlab_url: http+unix://#{CGI.escape(tmp_socket_path)}\n") + end + + copy_dirs = ['bin', 'lib'] + FileUtils.rm_rf(copy_dirs.map { |d| File.join(tmp_root_path, d) }) + FileUtils.cp_r(copy_dirs, tmp_root_path) + end + + after(:all) do + @server.shutdown if @server + @webrick_thread.join if @webrick_thread + FileUtils.rm_rf(tmp_root_path) + end + + let(:gitlab_shell_path) { File.join(tmp_root_path, 'bin', 'gitlab-shell') } + let(:authorized_keys_check_path) { File.join(tmp_root_path, 'bin', 'gitlab-shell-authorized-keys-check') } + + it 'succeeds when a valid key is given' do + output, status = run! + + expect(output).to eq("command=\"#{gitlab_shell_path} key-1\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty known-rsa-key\n") + expect(status).to be_success + end + + it 'returns nothing when an unknown key is given' do + output, status = run!(key: 'unknown-key') + + expect(output).to eq("# No key was found for unknown-key\n") + expect(status).to be_success + end + + it' fails when not enough arguments are given' do + output, status = run!(key: nil) + + expect(output).to eq('') + expect(status).not_to be_success + end + + it' fails when too many arguments are given' do + output, status = run!(key: ['a', 'b']) + + expect(output).to eq('') + expect(status).not_to be_success + end + + it 'skips when run as the wrong user' do + output, status = run!(expected_user: 'unknown-user') + + expect(output).to eq('') + expect(status).to be_success + end + + it 'skips when the wrong users connects' do + output, status = run!(actual_user: 'unknown-user') + + expect(output).to eq('') + expect(status).to be_success + end + + def run!(expected_user: 'git', actual_user: 'git', key: 'known-rsa-key') + cmd = [ + authorized_keys_check_path, + expected_user, + actual_user, + key + ].flatten.compact + + output = IO.popen(cmd, &:read) + + [output, $?] + end +end diff --git a/ruby/vendor/gitlab-shell/spec/gitlab_shell_spec.rb b/ruby/vendor/gitlab-shell/spec/gitlab_shell_spec.rb new file mode 100644 index 000000000..eef572e13 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/gitlab_shell_spec.rb @@ -0,0 +1,477 @@ +require_relative 'spec_helper' +require_relative '../lib/gitlab_shell' +require_relative '../lib/gitlab_access_status' + +describe GitlabShell do + before do + $logger = double('logger').as_null_object + FileUtils.mkdir_p(tmp_repos_path) + end + + after do + FileUtils.rm_rf(tmp_repos_path) + end + + subject do + ARGV[0] = gl_id + GitlabShell.new(gl_id).tap do |shell| + allow(shell).to receive(:exec_cmd).and_return(:exec_called) + allow(shell).to receive(:api).and_return(api) + end + end + + let(:git_config_options) { ['receive.MaxInputSize=10000'] } + + let(:gitaly_check_access) do + GitAccessStatus.new( + true, + '200', + 'ok', + gl_repository: gl_repository, + gl_id: gl_id, + gl_username: gl_username, + git_config_options: git_config_options, + gitaly: { 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default'} , 'address' => 'unix:gitaly.socket' }, + git_protocol: git_protocol + ) + end + + let(:api) do + double(GitlabNet).tap do |api| + allow(api).to receive(:discover).and_return({ 'name' => 'John Doe', 'username' => 'testuser' }) + allow(api).to receive(:check_access).and_return(GitAccessStatus.new( + true, + '200', + 'ok', + gl_repository: gl_repository, + gl_id: gl_id, + gl_username: gl_username, + git_config_options: nil, + gitaly: nil, + git_protocol: git_protocol)) + allow(api).to receive(:two_factor_recovery_codes).and_return({ + 'success' => true, + 'recovery_codes' => %w[f67c514de60c4953 41278385fc00c1e0] + }) + end + end + + let(:gl_id) { "key-#{rand(100) + 100}" } + let(:ssh_cmd) { nil } + let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') } + + let(:repo_name) { 'gitlab-ci.git' } + let(:gl_repository) { 'project-1' } + let(:gl_id) { 'user-1' } + let(:gl_username) { 'testuser' } + let(:git_config_options) { ['receive.MaxInputSize=10000'] } + let(:git_protocol) { 'version=2' } + + before do + allow_any_instance_of(GitlabConfig).to receive(:audit_usernames).and_return(false) + end + + describe '#initialize' do + let(:ssh_cmd) { 'git-receive-pack' } + + it { expect(subject.gl_id).to eq gl_id } + end + + describe '#parse_cmd' do + describe 'git' do + context 'w/o namespace' do + let(:ssh_args) { %w(git-upload-pack gitlab-ci.git) } + + before do + subject.send :parse_cmd, ssh_args + end + + it 'has the correct attributes' do + expect(subject.repo_name).to eq 'gitlab-ci.git' + expect(subject.command).to eq 'git-upload-pack' + end + end + + context 'namespace' do + let(:repo_name) { 'dmitriy.zaporozhets/gitlab-ci.git' } + let(:ssh_args) { %w(git-upload-pack dmitriy.zaporozhets/gitlab-ci.git) } + + before do + subject.send :parse_cmd, ssh_args + end + + it 'has the correct attributes' do + expect(subject.repo_name).to eq 'dmitriy.zaporozhets/gitlab-ci.git' + expect(subject.command).to eq 'git-upload-pack' + end + end + + context 'with an invalid number of arguments' do + let(:ssh_args) { %w(foobar) } + + it "should raise an DisallowedCommandError" do + expect { subject.send :parse_cmd, ssh_args }.to raise_error(GitlabShell::DisallowedCommandError) + end + end + + context 'with an API command' do + before do + subject.send :parse_cmd, ssh_args + end + + context 'when generating recovery codes' do + let(:ssh_args) { %w(2fa_recovery_codes) } + + it 'sets the correct command' do + expect(subject.command).to eq('2fa_recovery_codes') + end + + it 'does not set repo name' do + expect(subject.repo_name).to be_nil + end + end + end + end + + describe 'git-lfs' do + let(:repo_name) { 'dzaporozhets/gitlab.git' } + let(:ssh_args) { %w(git-lfs-authenticate dzaporozhets/gitlab.git download) } + + before do + subject.send :parse_cmd, ssh_args + end + + it 'has the correct attributes' do + expect(subject.repo_name).to eq 'dzaporozhets/gitlab.git' + expect(subject.command).to eq 'git-lfs-authenticate' + expect(subject.git_access).to eq 'git-upload-pack' + end + end + + describe 'git-lfs old clients' do + let(:repo_name) { 'dzaporozhets/gitlab.git' } + let(:ssh_args) { %w(git-lfs-authenticate dzaporozhets/gitlab.git download long_oid) } + + before do + subject.send :parse_cmd, ssh_args + end + + it 'has the correct attributes' do + expect(subject.repo_name).to eq 'dzaporozhets/gitlab.git' + expect(subject.command).to eq 'git-lfs-authenticate' + expect(subject.git_access).to eq 'git-upload-pack' + end + end + end + + describe '#exec' do + let(:gitaly_message) do + JSON.dump( + 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' }, + 'gl_repository' => gl_repository, + 'gl_id' => gl_id, + 'gl_username' => gl_username, + 'git_config_options' => git_config_options, + 'git_protocol' => git_protocol + ) + end + + before do + allow(ENV).to receive(:[]).with('GIT_PROTOCOL').and_return(git_protocol) + end + + shared_examples_for 'upload-pack' do |command| + let(:ssh_cmd) { "#{command} gitlab-ci.git" } + after { subject.exec(ssh_cmd) } + + it "should process the command" do + expect(subject).to receive(:process_cmd).with(%w(git-upload-pack gitlab-ci.git)) + end + + it "should execute the command" do + expect(subject).to receive(:exec_cmd).with('git-upload-pack') + end + + it "should log the command execution" do + message = "executing git command" + user_string = "user with id #{gl_id}" + expect($logger).to receive(:info).with(message, command: "git-upload-pack", user: user_string) + end + + it "should use usernames if configured to do so" do + allow_any_instance_of(GitlabConfig).to receive(:audit_usernames).and_return(true) + expect($logger).to receive(:info).with("executing git command", hash_including(user: 'testuser')) + end + end + + context 'gitaly-upload-pack' do + let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } + + before do + allow(api).to receive(:check_access).and_return(gitaly_check_access) + end + + after { subject.exec(ssh_cmd) } + + it "should process the command" do + expect(subject).to receive(:process_cmd).with(%w(git-upload-pack gitlab-ci.git)) + end + + it "should execute the command" do + expect(subject).to receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-upload-pack"), gitaly_address: 'unix:gitaly.socket', json_args: gitaly_message, token: nil) + end + + it "should log the command execution" do + message = "executing git command" + user_string = "user with id #{gl_id}" + + expect($logger).to receive(:info).with(message, command: "gitaly-upload-pack unix:gitaly.socket #{gitaly_message}", user: user_string) + end + + it "should use usernames if configured to do so" do + allow_any_instance_of(GitlabConfig).to receive(:audit_usernames).and_return(true) + expect($logger).to receive(:info).with("executing git command", hash_including(user: 'testuser')) + end + end + + context 'git-receive-pack' do + let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } + + before do + allow(api).to receive(:check_access).and_return(gitaly_check_access) + end + + after { subject.exec(ssh_cmd) } + + it "should process the command" do + expect(subject).to receive(:process_cmd).with(%w(git-receive-pack gitlab-ci.git)) + end + + it "should execute the command" do + expect(subject).to receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-receive-pack"), gitaly_address: 'unix:gitaly.socket', json_args: gitaly_message, token: nil) + end + + it "should log the command execution" do + message = "executing git command" + user_string = "user with id #{gl_id}" + expect($logger).to receive(:info).with(message, command: "gitaly-receive-pack unix:gitaly.socket #{gitaly_message}", user: user_string) + end + + context 'with a custom action' do + let(:fake_payload) { { 'api_endpoints' => [ '/fake/api/endpoint' ], 'data' => {} } } + let(:custom_action_gitlab_access_status) do + GitAccessStatus.new( + true, + '300', + 'Multiple Choices', + payload: fake_payload + ) + end + let(:action_custom) { double(Action::Custom) } + + before do + allow(api).to receive(:check_access).and_return(custom_action_gitlab_access_status) + end + + it "should not process the command" do + expect(subject).to_not receive(:process_cmd).with(%w(git-receive-pack gitlab-ci.git)) + expect(Action::Custom).to receive(:new).with(gl_id, fake_payload).and_return(action_custom) + expect(action_custom).to receive(:execute) + end + end + end + + context 'gitaly-receive-pack' do + let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } + before do + allow(api).to receive(:check_access).and_return(gitaly_check_access) + end + after { subject.exec(ssh_cmd) } + + it "should process the command" do + expect(subject).to receive(:process_cmd).with(%w(git-receive-pack gitlab-ci.git)) + end + + it "should execute the command" do + expect(subject).to receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-receive-pack"), gitaly_address: 'unix:gitaly.socket', json_args: gitaly_message, token: nil) + end + + it "should log the command execution" do + message = "executing git command" + user_string = "user with id #{gl_id}" + expect($logger).to receive(:info).with(message, command: "gitaly-receive-pack unix:gitaly.socket #{gitaly_message}", user: user_string) + end + + it "should use usernames if configured to do so" do + allow_any_instance_of(GitlabConfig).to receive(:audit_usernames).and_return(true) + expect($logger).to receive(:info).with("executing git command", hash_including(user: 'testuser')) + end + end + + shared_examples_for 'upload-archive' do |command| + let(:ssh_cmd) { "#{command} gitlab-ci.git" } + let(:exec_cmd_log_params) { exec_cmd_params } + + after { subject.exec(ssh_cmd) } + + it "should process the command" do + expect(subject).to receive(:process_cmd).with(%w(git-upload-archive gitlab-ci.git)) + end + + it "should execute the command" do + expect(subject).to receive(:exec_cmd).with(*exec_cmd_params) + end + + it "should log the command execution" do + message = "executing git command" + user_string = "user with id #{gl_id}" + expect($logger).to receive(:info).with(message, command: exec_cmd_log_params.join(' '), user: user_string) + end + + it "should use usernames if configured to do so" do + allow_any_instance_of(GitlabConfig).to receive(:audit_usernames).and_return(true) + expect($logger).to receive(:info).with("executing git command", hash_including(user: 'testuser')) + end + end + + context 'gitaly-upload-archive' do + before do + allow(api).to receive(:check_access).and_return(gitaly_check_access) + end + + it_behaves_like 'upload-archive', 'git-upload-archive' do + let(:gitaly_executable) { "gitaly-upload-archive" } + let(:exec_cmd_params) do + [ + File.join(ROOT_PATH, "bin", gitaly_executable), + { gitaly_address: 'unix:gitaly.socket', json_args: gitaly_message, token: nil } + ] + end + let(:exec_cmd_log_params) do + [gitaly_executable, 'unix:gitaly.socket', gitaly_message] + end + end + end + + context 'arbitrary command' do + let(:ssh_cmd) { 'arbitrary command' } + after { subject.exec(ssh_cmd) } + + it "should not process the command" do + expect(subject).not_to receive(:process_cmd) + end + + it "should not execute the command" do + expect(subject).not_to receive(:exec_cmd) + end + + it "should log the attempt" do + message = 'Denied disallowed command' + user_string = "user with id #{gl_id}" + expect($logger).to receive(:warn).with(message, command: 'arbitrary command', user: user_string) + end + end + + context 'no command' do + after { subject.exec(nil) } + + it "should call api.discover" do + expect(api).to receive(:discover).with(gl_id) + end + end + + context "failed connection" do + let(:ssh_cmd) { 'git-upload-pack gitlab-ci.git' } + + before do + allow(api).to receive(:check_access).and_raise(GitlabNet::ApiUnreachableError) + end + after { subject.exec(ssh_cmd) } + + it "should not process the command" do + expect(subject).not_to receive(:process_cmd) + end + + it "should not execute the command" do + expect(subject).not_to receive(:exec_cmd) + end + end + + context 'with an API command' do + before do + allow(subject).to receive(:continue?).and_return(true) + end + + context 'when generating recovery codes' do + let(:ssh_cmd) { '2fa_recovery_codes' } + after do + subject.exec(ssh_cmd) + end + + it 'does not call verify_access' do + expect(subject).not_to receive(:verify_access) + end + + it 'calls the corresponding method' do + expect(subject).to receive(:api_2fa_recovery_codes) + end + + it 'outputs recovery codes' do + expect($stdout).to receive(:puts) + .with(/f67c514de60c4953\n41278385fc00c1e0/) + end + + context 'when the process is unsuccessful' do + it 'displays the error to the user' do + allow(api).to receive(:two_factor_recovery_codes).and_return({ + 'success' => false, + 'message' => 'Could not find the given key' + }) + + expect($stdout).to receive(:puts) + .with(/Could not find the given key/) + end + end + end + end + end + + describe '#validate_access' do + let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } + + describe 'check access with api' do + before do + allow(api).to receive(:check_access).and_return( + GitAccessStatus.new( + false, + 'denied', + gl_repository: nil, + gl_id: nil, + gl_username: nil, + git_config_options: nil, + gitaly: nil, + git_protocol: nil)) + end + + after { subject.exec(ssh_cmd) } + + it "should call api.check_access" do + expect(api).to receive(:check_access).with('git-upload-pack', nil, 'gitlab-ci.git', gl_id, '_any', 'ssh') + end + + it "should disallow access and log the attempt if check_access returns false status" do + message = 'Access denied' + user_string = "user with id #{gl_id}" + + expect($logger).to receive(:warn).with(message, command: 'git-upload-pack gitlab-ci.git', user: user_string) + end + end + end + + describe '#api' do + let(:shell) { GitlabShell.new(gl_id) } + subject { shell.send :api } + + it { is_expected.to be_a(GitlabNet) } + end +end diff --git a/ruby/vendor/gitlab-shell/spec/hooks_utils_spec.rb b/ruby/vendor/gitlab-shell/spec/hooks_utils_spec.rb new file mode 100644 index 000000000..2113239a4 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/hooks_utils_spec.rb @@ -0,0 +1,28 @@ +require_relative 'spec_helper' +require_relative '../lib/hooks_utils.rb' + +describe :get_push_options do + context "when GIT_PUSH_OPTION_COUNT is not set" do + it { expect(HooksUtils.get_push_options).to eq([]) } + end + + context "when one option is given" do + before do + ENV['GIT_PUSH_OPTION_COUNT'] = '1' + ENV['GIT_PUSH_OPTION_0'] = 'aaa' + end + + it { expect(HooksUtils.get_push_options).to eq(['aaa']) } + end + + context "when multiple options are given" do + before do + ENV['GIT_PUSH_OPTION_COUNT'] = '3' + ENV['GIT_PUSH_OPTION_0'] = 'aaa' + ENV['GIT_PUSH_OPTION_1'] = 'bbb' + ENV['GIT_PUSH_OPTION_2'] = 'ccc' + end + + it { expect(HooksUtils.get_push_options).to eq(['aaa', 'bbb', 'ccc']) } + end +end diff --git a/ruby/vendor/gitlab-shell/spec/httpunix_spec.rb b/ruby/vendor/gitlab-shell/spec/httpunix_spec.rb new file mode 100644 index 000000000..719a85594 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/httpunix_spec.rb @@ -0,0 +1,58 @@ +require_relative 'spec_helper' +require_relative '../lib/httpunix' + +describe URI::HTTPUNIX do + describe :parse do + uri = URI::parse('http+unix://%2Fpath%2Fto%2Fsocket/img.jpg') + subject { uri } + + it { is_expected.to be_an_instance_of(URI::HTTPUNIX) } + + it 'has the correct attributes' do + expect(subject.scheme).to eq('http+unix') + expect(subject.hostname).to eq('/path/to/socket') + expect(subject.path).to eq('/img.jpg') + end + end +end + +describe Net::HTTPUNIX do + def tmp_socket_path + # This has to be a relative path shorter than 100 bytes due to + # limitations in how Unix sockets work. + 'tmp/test-socket' + end + + before(:all) do + # "hello world" over unix socket server in background thread + FileUtils.mkdir_p(File.dirname(tmp_socket_path)) + @server = HTTPUNIXServer.new(BindAddress: tmp_socket_path) + @server.mount_proc '/' do |req, resp| + resp.body = "Hello World (at #{req.path})" + end + + @webrick_thread = Thread.new { @server.start } + + sleep(0.1) while @webrick_thread.alive? && @server.status != :Running + raise "Couldn't start HTTPUNIXServer" unless @server.status == :Running + end + + after(:all) do + @server.shutdown if @server + @webrick_thread.join if @webrick_thread + end + + it "talks via HTTP ok" do + VCR.turned_off do + begin + WebMock.allow_net_connect! + http = Net::HTTPUNIX.new(tmp_socket_path) + expect(http.get('/').body).to eq('Hello World (at /)') + expect(http.get('/path').body).to eq('Hello World (at /path)') + + ensure + WebMock.disable_net_connect! + end + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/object_dirs_helper_spec.rb b/ruby/vendor/gitlab-shell/spec/object_dirs_helper_spec.rb new file mode 100644 index 000000000..c2d0db7f7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/object_dirs_helper_spec.rb @@ -0,0 +1,95 @@ +require_relative 'spec_helper' +require_relative '../lib/object_dirs_helper' + +describe ObjectDirsHelper do + before do + allow(Dir).to receive(:pwd).and_return('/home/git/repositories/foo/bar.git') + end + + describe '.all_attributes' do + it do + expect(described_class.all_attributes.keys).to include(*%w[ + GIT_OBJECT_DIRECTORY + GIT_OBJECT_DIRECTORY_RELATIVE + GIT_ALTERNATE_OBJECT_DIRECTORIES + GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE + ]) + end + end + + describe '.absolute_object_dir' do + subject { described_class.absolute_object_dir } + + context 'when GIT_OBJECT_DIRECTORY is set' do + let(:dir) { '/home/git/repositories/foo/bar.git/./objects' } + + before do + allow(ENV).to receive(:[]).with('GIT_OBJECT_DIRECTORY').and_return(dir) + end + + it { expect(subject).to eq(dir) } + end + + context 'when GIT_OBJECT_DIRECTORY is not set' do + it { expect(subject).to be_nil } + end + end + + describe '.absolute_alt_object_dirs' do + subject { described_class.absolute_alt_object_dirs } + + context 'when GIT_ALTERNATE_OBJECT_DIRECTORIES is set' do + let(:dirs) { [ + '/home/git/repositories/foo/bar.git/./incoming-UKU6Gl', + '/home/git/repositories/foo/bar.git/./incoming-AcU7Qr' + ] } + + before do + allow(ENV).to receive(:[]).with('GIT_ALTERNATE_OBJECT_DIRECTORIES').and_return(dirs.join(File::PATH_SEPARATOR)) + end + + it { expect(subject).to eq(dirs) } + end + + context 'when GIT_ALTERNATE_OBJECT_DIRECTORIES is not set' do + it { expect(subject).to eq([]) } + end + end + + describe '.relative_alt_object_dirs' do + subject { described_class.relative_alt_object_dirs } + + context 'when GIT_ALTERNATE_OBJECT_DIRECTORIES is set' do + let(:dirs) { [ + '/home/git/repositories/foo/bar.git/./objects/incoming-UKU6Gl', + '/home/git/repositories/foo/bar.git/./objects/incoming-AcU7Qr' + ] } + + before do + allow(ENV).to receive(:[]).with('GIT_ALTERNATE_OBJECT_DIRECTORIES').and_return(dirs.join(File::PATH_SEPARATOR)) + end + + it { expect(subject).to eq(['objects/incoming-UKU6Gl', 'objects/incoming-AcU7Qr']) } + end + + context 'when GIT_ALTERNATE_OBJECT_DIRECTORIES is not set' do + it { expect(subject).to eq([]) } + end + end + + describe '.relative_object_dir' do + subject { described_class.relative_object_dir } + + context 'when GIT_OBJECT_DIRECTORY is set' do + before do + allow(ENV).to receive(:[]).with('GIT_OBJECT_DIRECTORY').and_return('/home/git/repositories/foo/bar.git/./objects') + end + + it { expect(subject).to eq('objects') } + end + + context 'when GIT_OBJECT_DIRECTORY is not set' do + it { expect(subject).to be_nil } + end + end +end diff --git a/ruby/vendor/gitlab-shell/spec/spec_helper.rb b/ruby/vendor/gitlab-shell/spec/spec_helper.rb new file mode 100644 index 000000000..dfdf44984 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/spec_helper.rb @@ -0,0 +1,16 @@ +require 'rspec-parameterized' +require 'simplecov' +SimpleCov.start + +require 'gitlab_init' + +Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f } + +RSpec.configure do |config| + config.run_all_when_everything_filtered = true + config.filter_run :focus + + config.before(:each) do + stub_const('ROOT_PATH', File.expand_path('..', __dir__)) + end +end diff --git a/ruby/vendor/gitlab-shell/spec/support/gl_id_test_hook b/ruby/vendor/gitlab-shell/spec/support/gl_id_test_hook new file mode 100755 index 000000000..bf5874da9 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/gl_id_test_hook @@ -0,0 +1,2 @@ +#!/bin/sh +printenv GL_ID | grep -q '^key_1$' diff --git a/ruby/vendor/gitlab-shell/spec/support/hook_fail b/ruby/vendor/gitlab-shell/spec/support/hook_fail new file mode 100755 index 000000000..4420796f8 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/hook_fail @@ -0,0 +1,3 @@ +#!/bin/bash +#echo "fail: $0" +exit 1 diff --git a/ruby/vendor/gitlab-shell/spec/support/hook_ok b/ruby/vendor/gitlab-shell/spec/support/hook_ok new file mode 100755 index 000000000..eb1e3bc7f --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/hook_ok @@ -0,0 +1,3 @@ +#!/bin/bash +#echo "ok: $0" +exit 0 diff --git a/ruby/vendor/gitlab-shell/spec/support/http_unix_server.rb b/ruby/vendor/gitlab-shell/spec/support/http_unix_server.rb new file mode 100644 index 000000000..113df57bc --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/http_unix_server.rb @@ -0,0 +1,35 @@ +require 'webrick' + +# like WEBrick::HTTPServer, but listens on UNIX socket +class HTTPUNIXServer < WEBrick::HTTPServer + def initialize(config = {}) + null_log = WEBrick::Log.new(IO::NULL, 7) + + super(config.merge(Logger: null_log, AccessLog: null_log)) + end + + def listen(address, port) + socket = Socket.unix_server_socket(address) + socket.autoclose = false + server = UNIXServer.for_fd(socket.fileno) + socket.close + @listeners << server + end + + # Workaround: + # https://bugs.ruby-lang.org/issues/10956 + # Affecting Ruby 2.2 + # Fix for 2.2 is at https://github.com/ruby/ruby/commit/ab0a64e1 + # However, this doesn't work with 2.1. The following should work for both: + def start(&block) + @shutdown_pipe = IO.pipe + shutdown_pipe = @shutdown_pipe + super(&block) + end + + def cleanup_shutdown_pipe(shutdown_pipe) + @shutdown_pipe = nil + return if !shutdown_pipe + super(shutdown_pipe) + end +end diff --git a/ruby/vendor/gitlab-shell/spec/support/vcr.rb b/ruby/vendor/gitlab-shell/spec/support/vcr.rb new file mode 100644 index 000000000..a47cb9702 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/vcr.rb @@ -0,0 +1,7 @@ +require 'vcr' + +VCR.configure do |c| + c.cassette_library_dir = 'spec/vcr_cassettes' + c.hook_into :webmock + c.configure_rspec_metadata! +end diff --git a/ruby/vendor/gitlab-shell/spec/support/webmock.rb b/ruby/vendor/gitlab-shell/spec/support/webmock.rb new file mode 100644 index 000000000..ed4fe6d6a --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/support/webmock.rb @@ -0,0 +1,3 @@ +require 'webmock/rspec' + +WebMock.disable_net_connect!(allow_localhost: true) diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-pull.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-pull.yml new file mode 100644 index 000000000..b07347655 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-pull.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 67ab4954-19e6-42ce-aae6-55c8ae5a365e + X-Runtime: + - '0.230871' + body: + encoding: UTF-8 + string: '{"status":true,"gl_repository":"project-3","repository_path":"/Users/dzaporozhets/Projects/gitlab-development-kit/repositories/gitlab-org/gitlab-test.git"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-html.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-html.yml new file mode 100644 index 000000000..4adb08802 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-html.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - text/html + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: '

The project you were looking for could not be found.

' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-plain.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-plain.yml new file mode 100644 index 000000000..a84b7d2d7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404-text-plain.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - text/plain + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: 'The project you were looking for could not be found.' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404.yml new file mode 100644 index 000000000..e531fcbbe --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-404.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: '{"status":false,"message":"The project you were looking for could not be found."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-html.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-html.yml new file mode 100644 index 000000000..b2738fea7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-html.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - text/html + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: '

The project you were looking for could not be found.

' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-plain.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-plain.yml new file mode 100644 index 000000000..34532cee2 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found-text-plain.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - text/plain + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: 'The project you were looking for could not be found.' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found.yml new file mode 100644 index 000000000..f25fa7eaa --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push-project-not-found.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: '{"status":false,"message":"The project you were looking for could not be found."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push.yml new file mode 100644 index 000000000..1636fd507 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/allowed-push.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f + X-Runtime: + - '0.289759' + body: + encoding: UTF-8 + string: '{"status":true,"gl_repository":"project-3","repository_path":"/Users/dzaporozhets/Projects/gitlab-development-kit/repositories/gitlab-org/gitlab-test.git"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-none.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-none.yml new file mode 100644 index 000000000..8162343c2 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-none.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/broadcast_message + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '2' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:50 GMT + Etag: + - W/"99914b932bd37a50b983c5e7c90ae93b" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - d31271ab-e21f-4349-a4c3-54f238c075c3 + X-Runtime: + - '0.254031' + body: + encoding: UTF-8 + string: "{}" + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:50 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-ok.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-ok.yml new file mode 100644 index 000000000..a309c7ed3 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/broadcast_message-ok.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/broadcast_message + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '153' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:29:13 GMT + Etag: + - W/"ce6de457fcc884f50125e81a10f165ce" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - ebaaf2c2-112e-4b3c-9182-e8714cd2a29c + X-Runtime: + - '0.276085' + body: + encoding: UTF-8 + string: '{"message":"Message","starts_at":"2017-06-21T12:28:00.000Z","ends_at":"2017-06-21T12:35:00.000Z","color":"#e75e40","font":"#ffffff","id":1,"active":true}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:29:13 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/check-ok.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/check-ok.yml new file mode 100644 index 000000000..f8ba853ee --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/check-ok.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/check + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '72' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:49 GMT + Etag: + - W/"e1b00c927355c31ffb83b0800821cdbd" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 19d8b75c-45d1-4b8b-9e47-2fda86f98187 + X-Runtime: + - '0.245482' + body: + encoding: UTF-8 + string: '{"api_version":"v4","gitlab_version":"9.3.0-pre","gitlab_rev":"8f537e5"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:49 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-json.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-json.yml new file mode 100644 index 000000000..e50719ddf --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-json.yml @@ -0,0 +1,40 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/fake/info_refs_bad + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-11"},"output":"","secret_token":"0a3938d9d95d807e94d937af3a4fbbea\n"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 403 + message: Forbidden + headers: + Date: + - Fri, 20 Jul 2018 06:54:21 GMT + Connection: + - close + Content-Type: + - application/json + X-Request-Id: + - ea0644ac-e1ad-45f6-aa72-cc7910274318 + X-Runtime: + - '1.236672' + body: + encoding: UTF-8 + string: '{"message":"You cannot perform write operations on a read-only instance"}' + http_version: + recorded_at: Fri, 20 Jul 2018 06:54:21 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-not-json.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-not-json.yml new file mode 100644 index 000000000..b60a93a6c --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-not-ok-not-json.yml @@ -0,0 +1,40 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/fake/info_refs_bad + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-11"},"output":"","secret_token":"0a3938d9d95d807e94d937af3a4fbbea\n"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 403 + message: Forbidden + headers: + Date: + - Fri, 20 Jul 2018 06:54:21 GMT + Connection: + - close + Content-Type: + - application/json + X-Request-Id: + - ea0644ac-e1ad-45f6-aa72-cc7910274318 + X-Runtime: + - '1.236672' + body: + encoding: UTF-8 + string: '""' + http_version: + recorded_at: Fri, 20 Jul 2018 06:54:21 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-not-json.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-not-json.yml new file mode 100644 index 000000000..3bfb39057 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-not-json.yml @@ -0,0 +1,51 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/fake/info_refs + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-1"},"output":"","secret_token":"0a3938d9d95d807e94d937af3a4fbbea"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 20 Jul 2018 06:18:58 GMT + Connection: + - close + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Content-Type: + - application/json + Content-Length: + - '172' + Vary: + - Origin + Etag: + - W/"7d01e1e3dbcbe7cca9607461352f8244" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 03afa234-b6be-49ab-9392-4aa35c5dee25 + X-Runtime: + - '1.436040' + body: + encoding: UTF-8 + string: '""' + http_version: + recorded_at: Fri, 20 Jul 2018 06:18:58 GMT diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-with-message.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-with-message.yml new file mode 100644 index 000000000..9d44a37d2 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok-with-message.yml @@ -0,0 +1,99 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/fake/info_refs + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-1"},"output":"","secret_token":"0a3938d9d95d807e94d937af3a4fbbea"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 20 Jul 2018 06:18:58 GMT + Connection: + - close + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Content-Type: + - application/json + Content-Length: + - '172' + Vary: + - Origin + Etag: + - W/"7d01e1e3dbcbe7cca9607461352f8244" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 03afa234-b6be-49ab-9392-4aa35c5dee25 + X-Runtime: + - '1.436040' + body: + encoding: UTF-8 + string: '{"result":"aW5mb19yZWZzLXJlc3VsdA==\n"}' + http_version: + recorded_at: Fri, 20 Jul 2018 06:18:58 GMT +- request: + method: post + uri: http://localhost:3000/api/v4/fake/push + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-1"},"output":"info_refs-result","secret_token":"0a3938d9d95d807e94d937af3a4fbbea"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 201 + message: Created + headers: + Date: + - Fri, 20 Jul 2018 06:19:08 GMT + Connection: + - close + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Content-Type: + - application/json + Content-Length: + - '13' + Vary: + - Origin + Cache-Control: + - no-cache + X-Request-Id: + - 0c6894ac-7f8e-4cdb-871f-4cb64d3731ca + X-Runtime: + - '0.786754' + body: + encoding: UTF-8 + string: '{"result":"cHVzaC1yZXN1bHQ=\n"}' + http_version: + recorded_at: Fri, 20 Jul 2018 06:19:08 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok.yml new file mode 100644 index 000000000..9d44a37d2 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/custom-action-ok.yml @@ -0,0 +1,99 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/fake/info_refs + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-1"},"output":"","secret_token":"0a3938d9d95d807e94d937af3a4fbbea"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 20 Jul 2018 06:18:58 GMT + Connection: + - close + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Content-Type: + - application/json + Content-Length: + - '172' + Vary: + - Origin + Etag: + - W/"7d01e1e3dbcbe7cca9607461352f8244" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 03afa234-b6be-49ab-9392-4aa35c5dee25 + X-Runtime: + - '1.436040' + body: + encoding: UTF-8 + string: '{"result":"aW5mb19yZWZzLXJlc3VsdA==\n"}' + http_version: + recorded_at: Fri, 20 Jul 2018 06:18:58 GMT +- request: + method: post + uri: http://localhost:3000/api/v4/fake/push + body: + encoding: UTF-8 + string: '{"data":{"gl_username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git","gl_id":"key-1"},"output":"info_refs-result","secret_token":"0a3938d9d95d807e94d937af3a4fbbea"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - localhost + response: + status: + code: 201 + message: Created + headers: + Date: + - Fri, 20 Jul 2018 06:19:08 GMT + Connection: + - close + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Content-Type: + - application/json + Content-Length: + - '13' + Vary: + - Origin + Cache-Control: + - no-cache + X-Request-Id: + - 0c6894ac-7f8e-4cdb-871f-4cb64d3731ca + X-Runtime: + - '0.786754' + body: + encoding: UTF-8 + string: '{"result":"cHVzaC1yZXN1bHQ=\n"}' + http_version: + recorded_at: Fri, 20 Jul 2018 06:19:08 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/discover-ok.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/discover-ok.yml new file mode 100644 index 000000000..0f17363eb --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/discover-ok.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/discover?key_id=1 + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '42' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:49 GMT + Etag: + - W/"63b4ab301951bea83c4fc398eba8e307" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - dc11b8d4-1972-417b-8305-2c35c849405c + X-Runtime: + - '0.230170' + body: + encoding: UTF-8 + string: '{"name":"Administrator","username":"root"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:49 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-pull-disabled.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-pull-disabled.yml new file mode 100644 index 000000000..23ef3e53c --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-pull-disabled.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=http&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '62' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:32:01 GMT + Etag: + - W/"71e09fcf8a60a03cd1acc22806386ead" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 70bdecc9-0078-4a4b-aa6b-cac1b2578886 + X-Runtime: + - '0.324202' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Pulling over HTTP is not allowed."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:32:01 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-push-disabled.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-push-disabled.yml new file mode 100644 index 000000000..676e5b8b4 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/http-push-disabled.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=http&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '62' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:32:01 GMT + Etag: + - W/"7f14e23ac07cc8b0a53c567fcf9432fd" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 573f3584-87c6-41cb-a5bf-5e7ee76d4250 + X-Runtime: + - '0.266135' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Pushing over HTTP is not allowed."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:32:01 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-download.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-download.yml new file mode 100644 index 000000000..e832c9067 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-download.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/lfs_authenticate + body: + encoding: US-ASCII + string: project=gitlab-org%2Fgitlab-test.git&key_id=1&operation=download&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '158' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:50 GMT + Etag: + - W/"0a8ccf1603566e521c169d5e43c86cd2" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - d82d6071-1868-4a37-b026-65ab37f96f2f + X-Runtime: + - '0.331056' + body: + encoding: UTF-8 + string: '{"username":"root","lfs_token":"Hyzhyde_wLUeyUQsR3tHGTG8eNocVQm4ssioTEsBSdb6KwCSzQ","repository_http_path":"http://localhost:3000/gitlab-org/gitlab-test.git"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:50 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-upload.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-upload.yml new file mode 100644 index 000000000..e4fa33569 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/lfs-authenticate-ok-upload.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/lfs_authenticate + body: + encoding: US-ASCII + string: project=gitlab-org%2Fgitlab-test.git&key_id=1&operation=upload&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '158' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:50 GMT + Etag: + - W/"0a8ccf1603566e521c169d5e43c86cd2" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - d82d6071-1868-4a37-b026-65ab37f96f2f + X-Runtime: + - '0.331056' + body: + encoding: UTF-8 + string: '{"username":"root","lfs_token":"Hyzhyde_wLUeyUQsR3tHGTG8eNocVQm4ssioTEsBSdb6KwCSzQ","repository_http_path":"http://localhost:3000/gitlab-org/gitlab-test.git"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:50 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/notify-post-receive.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/notify-post-receive.yml new file mode 100644 index 000000000..255f41516 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/notify-post-receive.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/notify_post_receive + body: + encoding: US-ASCII + string: gl_repository=project-1&project=%2Fpath%2Fto%2Fmy%2Frepo.git&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '3' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:47:48 GMT + Etag: + - W/"3644a684f98ea8fe223c713b77189a77" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 407b184d-d6cf-43db-93fa-3f2d97112948 + X-Runtime: + - '6.626186' + body: + encoding: UTF-8 + string: '200' + http_version: + recorded_at: Wed, 21 Jun 2017 12:47:48 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive-not-found.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive-not-found.yml new file mode 100644 index 000000000..e89095d19 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive-not-found.yml @@ -0,0 +1,42 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/post_receive + body: + encoding: US-ASCII + string: gl_repository=project-1&identifier=key-1&changes=123456+789012+refs%2Fheads%2Ftest%0A654321+210987+refs%2Ftags%2Ftag&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - no-cache + Content-Length: + - '25' + Content-Type: + - application/json + Date: + - Wed, 30 Aug 2017 22:24:37 GMT + Vary: + - Origin + X-Request-Id: + - bbfdb1ed-99dc-4246-a606-3074ffd5d87b + X-Runtime: + - '0.459681' + body: + encoding: UTF-8 + string: '{"error":"404 Not Found"}' + http_version: + recorded_at: Wed, 30 Aug 2017 22:24:37 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive.yml new file mode 100644 index 000000000..c29f86539 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/post-receive.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/post_receive + body: + encoding: US-ASCII + string: gl_repository=project-1&identifier=key-1&changes=123456+789012+refs%2Fheads%2Ftest%0A654321+210987+refs%2Ftags%2Ftag&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '208' + Content-Type: + - application/json + Date: + - Wed, 30 Aug 2017 22:08:28 GMT + Etag: + - W/"1757d1411091b751684cde10119e0942" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - f7d422a7-c1a3-49d1-9b81-7fc48c954767 + X-Runtime: + - '0.687283' + body: + encoding: UTF-8 + string: '{"merge_request_urls":[{"branch_name":"test","url":"http://localhost:3000/gitlab-org/gitlab-test/merge_requests/7","new_merge_request":false}],"broadcast_message":"Message","reference_counter_decreased":true}' + http_version: + recorded_at: Wed, 30 Aug 2017 22:08:28 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive-not-found.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive-not-found.yml new file mode 100644 index 000000000..5eed672c7 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive-not-found.yml @@ -0,0 +1,42 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/pre_receive + body: + encoding: US-ASCII + string: gl_repository=project-1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - no-cache + Content-Length: + - '25' + Content-Type: + - application/json + Date: + - Thu, 31 Aug 2017 16:41:13 GMT + Vary: + - Origin + X-Request-Id: + - 0b845e9a-5417-488d-bc5a-07d8c585b2da + X-Runtime: + - '0.295361' + body: + encoding: UTF-8 + string: '{"error":"404 Not Found"}' + http_version: + recorded_at: Thu, 31 Aug 2017 16:41:13 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive.yml new file mode 100644 index 000000000..6072d0ca0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/pre-receive.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/pre_receive + body: + encoding: US-ASCII + string: gl_repository=project-1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '36' + Content-Type: + - application/json + Date: + - Thu, 31 Aug 2017 20:17:41 GMT + Etag: + - W/"7d4df85c493bd3d421351aa791a8fbf6" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - f0c84103-8dc0-48ea-a142-62554f6bca3d + X-Runtime: + - '0.612997' + body: + encoding: UTF-8 + string: '{"reference_counter_increased":true}' + http_version: + recorded_at: Thu, 31 Aug 2017 20:17:41 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-found.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-found.yml new file mode 100644 index 000000000..fdff8fcbe --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-found.yml @@ -0,0 +1,44 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/authorized_keys?key=whatever + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - no-cache + Content-Length: + - '31' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:15:09 GMT + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c829f804-616e-4046-9b70-cc6a2a559166 + X-Runtime: + - '0.281120' + body: + encoding: UTF-8 + string: '{"message":"404 Key Not Found"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:15:09 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-implemented.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-implemented.yml new file mode 100644 index 000000000..c883dfaf4 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-not-implemented.yml @@ -0,0 +1,44 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/authorized_keys?key=whatever + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 404 + message: Not Found + headers: + Cache-Control: + - no-cache + Content-Length: + - '31' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:15:09 GMT + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 4bcc3073-f32d-4e07-994e-5eb476b23d41 + X-Runtime: + - '0.448808' + body: + encoding: UTF-8 + string: '{"message":"404 Key Not Found"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:15:09 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-ok.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-ok.yml new file mode 100644 index 000000000..358f78800 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-key-ok.yml @@ -0,0 +1,47 @@ +--- +http_interactions: +- request: + method: get + uri: http://localhost:3000/api/v4/internal/authorized_keys?key=rsa-key + body: + encoding: US-ASCII + string: secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '686' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:16:41 GMT + Etag: + - W/"18dfce1367306a2dda6aaf8b1e7795a8" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 839ab67c-7b72-44e0-916e-ca4f68c25604 + X-Runtime: + - '9.070282' + body: + encoding: UTF-8 + string: '{"id":99,"title":"untitled","key":"ssh-rsa rsa-key + dummy@gitlab.com","created_at":"2017-06-21T09:50:07.150Z","can_push":false}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:16:41 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-disabled.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-disabled.yml new file mode 100644 index 000000000..55ce261b5 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-disabled.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:23:57 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 096ae253-c6fe-4360-b4d4-48f4b5435ca6 + X-Runtime: + - '6.377187' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:23:57 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-html.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-html.yml new file mode 100644 index 000000000..d3341080f --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-html.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - text/html + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8ce54f29-9ed0-46e5-aedb-37edaa3d52da + X-Runtime: + - '0.228256' + body: + encoding: UTF-8 + string: '

Git access over SSH is not allowed

' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-plain.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-plain.yml new file mode 100644 index 000000000..e07249390 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401-text-plain.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - text/plain + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8ce54f29-9ed0-46e5-aedb-37edaa3d52da + X-Runtime: + - '0.228256' + body: + encoding: UTF-8 + string: 'Git access over SSH is not allowed' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401.yml new file mode 100644 index 000000000..4a9305a6d --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-401.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8ce54f29-9ed0-46e5-aedb-37edaa3d52da + X-Runtime: + - '0.228256' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-with-user.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-with-user.yml new file mode 100644 index 000000000..b461b5b24 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied-with-user.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&user_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:05 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 3b242d73-d860-48ac-8fef-80e2d0d3daca + X-Runtime: + - '0.342469' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:05 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied.yml new file mode 100644 index 000000000..5107d15e0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-pull-project-denied.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8ce54f29-9ed0-46e5-aedb-37edaa3d52da + X-Runtime: + - '0.228256' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-disabled.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-disabled.yml new file mode 100644 index 000000000..c0617919f --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-disabled.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:23:57 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 93620e06-fda9-4be5-855e-300f5d62fa3c + X-Runtime: + - '0.207159' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:23:57 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-html.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-html.yml new file mode 100644 index 000000000..08dea914f --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-html.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - text/html + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c843a5a3-fc08-46eb-aa45-caceae515638 + X-Runtime: + - '7.359835' + body: + encoding: UTF-8 + string: '

Git access over SSH is not allowed

' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-plain.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-plain.yml new file mode 100644 index 000000000..46d9a1d0b --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401-text-plain.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - text/plain + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c843a5a3-fc08-46eb-aa45-caceae515638 + X-Runtime: + - '7.359835' + body: + encoding: UTF-8 + string: 'Git access over SSH is not allowed' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401.yml new file mode 100644 index 000000000..77248e2aa --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied-401.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c843a5a3-fc08-46eb-aa45-caceae515638 + X-Runtime: + - '7.359835' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied.yml new file mode 100644 index 000000000..c16e608e0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/ssh-push-project-denied.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c843a5a3-fc08-46eb-aa45-caceae515638 + X-Runtime: + - '7.359835' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes-fail.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes-fail.yml new file mode 100644 index 000000000..ab9b55158 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes-fail.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/two_factor_recovery_codes + body: + encoding: US-ASCII + string: key_id=777&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '58' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:33:42 GMT + Etag: + - W/"2642e3904bef8fa05ab8e0ca78c19047" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 7f8f2587-f6a2-445a-97a2-36fb9ea8f2d2 + X-Runtime: + - '0.196409' + body: + encoding: UTF-8 + string: '{"success":false,"message":"Could not find the given key"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:33:42 GMT +recorded_with: VCR 2.4.0 diff --git a/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes.yml b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes.yml new file mode 100644 index 000000000..20eba0bc0 --- /dev/null +++ b/ruby/vendor/gitlab-shell/spec/vcr_cassettes/two-factor-recovery-codes.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/two_factor_recovery_codes + body: + encoding: US-ASCII + string: key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '225' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:31:42 GMT + Etag: + - W/"087adad20960d665d59e7e4ca02efd28" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - a0e1c950-83a7-4fed-afb0-bfb01d104795 + X-Runtime: + - '1.378088' + body: + encoding: UTF-8 + string: '{"success":true,"recovery_codes":["f67c514de60c4953","41278385fc00c1e0"]}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:31:42 GMT +recorded_with: VCR 2.4.0 -- cgit v1.2.3 From 83a0c7b826280c7d9d09d0c5826a67c82cfd3016 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 11 Jan 2019 16:49:01 +0100 Subject: Add vendored gitlab-shell to rspec --- Makefile | 4 ++++ _support/makegen.go | 10 +++++++++- ruby/.gitignore | 1 + ruby/Gemfile | 6 ++++++ ruby/Gemfile.lock | 26 +++++++++++++++++++++++++- 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 ruby/.gitignore diff --git a/Makefile b/Makefile index a19054faa..5e79ab055 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,10 @@ test: prepare-build rspec: prepare-build cd $(BUILD_DIR) && $(MAKE) $@ +.PHONY: rspec-gitlab-shell +rspec-gitlab-shell: prepare-build + cd $(BUILD_DIR) && $(MAKE) $@ + .PHONY: verify verify: prepare-build cd $(BUILD_DIR) && $(MAKE) $@ diff --git a/_support/makegen.go b/_support/makegen.go index 3bd410f81..e8e7de6ba 100644 --- a/_support/makegen.go +++ b/_support/makegen.go @@ -310,7 +310,7 @@ binaries: assemble prepare-tests: {{ .TestRepo }} {{ .GitTestRepo }} ../.ruby-bundle .PHONY: test -test: test-go rspec +test: test-go rspec rspec-gitlab-shell .PHONY: test-go test-go: prepare-tests @@ -324,6 +324,14 @@ race-go: prepare-tests rspec: assemble-go prepare-tests cd {{ .GitalyRubyDir }} && bundle exec rspec +.PHONY: rspec-gitlab-shell +rspec-gitlab-shell: {{ .GitlabShellDir }}/config.yml assemble-go prepare-tests + # rspec in {{ .GitlabShellRelDir }} + @cd {{ .GitalyRubyDir }} && bundle exec bin/ruby-cd {{ .GitlabShellDir }} rspec + +{{ .GitlabShellDir }}/config.yml: {{ .GitlabShellDir }}/config.yml.example + cp $< $@ + .PHONY: verify verify: lint check-formatting staticcheck govendor-status notice-up-to-date govendor-tagged rubocop diff --git a/ruby/.gitignore b/ruby/.gitignore new file mode 100644 index 000000000..3b6ee585f --- /dev/null +++ b/ruby/.gitignore @@ -0,0 +1 @@ +/coverage diff --git a/ruby/Gemfile b/ruby/Gemfile index e17ac114a..690195249 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -27,4 +27,10 @@ group :development, :test do gem 'rspec-parameterized', require: false gem 'timecop', require: false gem 'factory_bot', require: false + + # gitlab-shell spec gems + gem 'listen', '~> 0.5.0' + gem 'simplecov', '~> 0.9.0', require: false + gem 'vcr', '~> 4.0.0' + gem 'webmock', '~> 3.4.0' end diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index 7418309d7..4132df771 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -10,6 +10,8 @@ GEM adamantium (0.2.0) ice_nine (~> 0.11.0) memoizable (~> 0.4.0) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) ast (2.4.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) @@ -19,9 +21,12 @@ GEM adamantium (~> 0.2.0) equalizer (~> 0.0.9) concurrent-ruby (1.1.3) + crack (0.4.3) + safe_yaml (~> 1.0.0) crass (1.0.4) debug_inspector (0.0.3) diff-lcs (1.3) + docile (1.1.5) equalizer (0.0.11) escape_utils (1.2.1) factory_bot (4.11.1) @@ -63,12 +68,14 @@ GEM grpc (1.15.0) google-protobuf (~> 3.1) googleapis-common-protos-types (~> 1.0.0) + hashdiff (0.3.8) i18n (1.1.1) concurrent-ruby (~> 1.0) ice_nine (0.11.2) json (2.1.0) licensee (8.9.2) rugged (~> 0.24) + listen (0.5.3) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) mime-types (3.2.2) @@ -76,6 +83,7 @@ GEM mime-types-data (3.2018.0812) mini_portile2 (2.3.0) minitest (5.11.3) + multi_json (1.13.1) multipart-post (2.0.0) nokogiri (1.8.5) mini_portile2 (~> 2.3.0) @@ -91,6 +99,7 @@ GEM parser unparser procto (0.0.3) + public_suffix (3.0.3) rainbow (3.0.0) rdoc (4.3.0) rouge (3.3.0) @@ -122,12 +131,18 @@ GEM unicode-display_width (~> 1.0, >= 1.0.1) ruby-progressbar (1.10.0) rugged (0.27.5) + safe_yaml (1.0.4) sanitize (4.6.6) crass (~> 1.0.2) nokogiri (>= 1.4.4) nokogumbo (~> 1.4) sentry-raven (2.7.4) faraday (>= 0.7.6, < 1.0) + simplecov (0.9.2) + docile (~> 1.1.0) + multi_json (~> 1.0) + simplecov-html (~> 0.9.0) + simplecov-html (0.9.0) stringex (2.8.4) thread_safe (0.3.6) timecop (0.9.1) @@ -142,6 +157,11 @@ GEM equalizer (~> 0.0.9) parser (>= 2.3.1.2, < 2.6) procto (~> 0.0.2) + vcr (4.0.0) + webmock (3.4.2) + addressable (>= 2.3.6) + crack (>= 0.3.2) + hashdiff PLATFORMS ruby @@ -159,13 +179,17 @@ DEPENDENCIES google-protobuf (~> 3.6) grpc (~> 1.15.0) licensee (~> 8.9.0) + listen (~> 0.5.0) rdoc (~> 4.2) rspec rspec-parameterized rubocop (~> 0.50) rugged (~> 0.27) sentry-raven (~> 2.7.2) + simplecov (~> 0.9.0) timecop + vcr (~> 4.0.0) + webmock (~> 3.4.0) BUNDLED WITH - 1.17.1 + 1.17.2 -- cgit v1.2.3