diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 0000000..48a8a58 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_GEM__PUSH_KEY: "rubygems_ted_com" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 45bcfb1..e08b951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.bundle/ log/*.log pkg/ spec/dummy/db/*.sqlite3 @@ -7,3 +6,4 @@ spec/dummy/log/*.log spec/dummy/public/assets/* spec/dummy/tmp/ spec/dummy/.sass-cache +.byebug_history diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000..71fe5c6 --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +front_end_builds diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..a603bb5 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.7.5 diff --git a/.travis.yml b/.travis.yml index e983b8a..543634c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,18 @@ language: ruby -# Reset lockfile for different rails versions -before_install: "rm Gemfile.lock" install: bundle install script: - bundle exec rake db:create - bundle exec rake db:schema:load - bundle exec rake spec rvm: - - 1.9.3 - - 2.0.0 - - 2.1.0 - - 2.2.0 + - 2.2.2 + - 2.3.0 + - 2.4.0 + - 2.5.0 env: - - "RAILS_VERSION=3.2.0" - - "RAILS_VERSION=4.0.0" - - "RAILS_VERSION=4.1.0" - - "RAILS_VERSION=4.2.0" + - "RAILS_VERSION=5.0.0" + - "RAILS_VERSION=5.1.0" + - "RAILS_VERSION=5.2.0" matrix: exclude: - rvm: 1.9.3 @@ -24,3 +21,28 @@ matrix: env: "RAILS_VERSION=4.2.0" - rvm: 2.2.0 env: "RAILS_VERSION=3.2.0" + - rvm: 2.2.2 + env: "RAILS_VERSION=5.0.0" + - rvm: 2.2.2 + env: "RAILS_VERSION=5.1.0" + - rvm: 2.2.2 + env: "RAILS_VERSION=5.2.0" + include: + - rvm: 2.3.0 + env: "RAILS_VERSION=5.0.0" + - rvm: 2.3.0 + env: "RAILS_VERSION=5.1.0" + - rvm: 2.3.0 + env: "RAILS_VERSION=5.2.0" + - rvm: 2.4.0 + env: "RAILS_VERSION=5.0.0" + - rvm: 2.4.0 + env: "RAILS_VERSION=5.1.0" + - rvm: 2.4.0 + env: "RAILS_VERSION=5.2.0" + - rvm: 2.5.0 + env: "RAILS_VERSION=5.0.0" + - rvm: 2.5.0 + env: "RAILS_VERSION=5.1.0" + - rvm: 2.5.0 + env: "RAILS_VERSION=5.2.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b2fe59..7f45462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # What's new +### 1.0.5 (May 11, 2020) +* Version 1.0.5 may be used with Rails version 6 only. +* Update rspec syntax to work with more modern versions +* Bump Ruby version to 2.7.5 + +### 1.0.4 (May 11, 2021) +* changed rails dependency to '>= 5.0' + +### 1.0.3 (November 19th, 2020) +* remove crossdomain.xml see https://www.openbugbounty.org/reports/1519953/ + +### 1.0.2 (January 9th, 2020) +* This version fixes a bug with FrontEndBuilds::AppsController#index where it would not show the `/frontends`. + - This bug was introduced in 1.0.0 (rails 5 updates). + - The controller should return "10 builds for each app", instead it was + returning "10 builds for all apps". This and issue when one of your apps has + a really old "live build" that is older than your 10 most recent (for any app) + +### 1.0.1 (May 6th, 2019) +* `FrontEndBuilds::App.live_build` is now optional. This resolves issues with Rails 5 clients that have `Rails.application.config.active_record.belongs_to_required_by_default` enabled. + +### 1.0.0 (January 31, 2019) +* Support for Rails 5 +* Dropping support for < Rails 5 +* Support for OpenSSL Ver 2 +* If a user uses a key that is not RSA an exception will now be raised + ## Upgrading To upgrade ``front_end_builds`` just set the appropriate version in your @@ -23,6 +50,3 @@ Check the log below to see all the new features. to verify the build. To set this up login to your admin area and add a public key, for example your SSH pubkey. Make sure you update your ``ember-cli-front-end-builds`` to use version `0.1.0` as well. - - - diff --git a/Gemfile b/Gemfile index e1fd10d..6bdd6de 100644 --- a/Gemfile +++ b/Gemfile @@ -8,16 +8,16 @@ rails = case rails_version when 'master' { :github => 'rails/rails'} when 'default' - '~> 4.2.0' + '~> 6' else "~> #{rails_version}" end gem 'rails', rails -# These no longer ship with ruby 2.2.0, but are needed for -# Rails 3 and 4.0.0 -if RUBY_VERSION == "2.2.0" - gem 'test-unit' - gem 'minitest' +gem 'bigdecimal', '1.4.2' + + # these are here so travis will work +group :test, :development do + gem 'sqlite3' end diff --git a/Gemfile.lock b/Gemfile.lock index 18896bc..c403664 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,198 +1,250 @@ PATH remote: . specs: - front_end_builds (0.2.1) + front_end_builds (1.0.5) + rails (> 5, < 7) GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) + actioncable (6.1.5) + actionpack (= 6.1.5) + activesupport (= 6.1.5) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.5) + actionpack (= 6.1.5) + activejob (= 6.1.5) + activerecord (= 6.1.5) + activestorage (= 6.1.5) + activesupport (= 6.1.5) + mail (>= 2.7.1) + actionmailer (6.1.5) + actionpack (= 6.1.5) + actionview (= 6.1.5) + activejob (= 6.1.5) + activesupport (= 6.1.5) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.4) - actionview (= 4.2.4) - activesupport (= 4.2.4) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.4) - activesupport (= 4.2.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.5) + actionview (= 6.1.5) + activesupport (= 6.1.5) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.5) + actionpack (= 6.1.5) + activerecord (= 6.1.5) + activestorage (= 6.1.5) + activesupport (= 6.1.5) + nokogiri (>= 1.8.5) + actionview (6.1.5) + activesupport (= 6.1.5) builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.4) - activesupport (= 4.2.4) - globalid (>= 0.3.0) - activemodel (4.2.4) - activesupport (= 4.2.4) - builder (~> 3.1) - activerecord (4.2.4) - activemodel (= 4.2.4) - activesupport (= 4.2.4) - arel (~> 6.0) - activesupport (4.2.4) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.3.6) - arel (6.0.3) - binding_of_caller (0.7.2) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.5) + activesupport (= 6.1.5) + globalid (>= 0.3.6) + activemodel (6.1.5) + activesupport (= 6.1.5) + activerecord (6.1.5) + activemodel (= 6.1.5) + activesupport (= 6.1.5) + activestorage (6.1.5) + actionpack (= 6.1.5) + activejob (= 6.1.5) + activerecord (= 6.1.5) + activesupport (= 6.1.5) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.5) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + ast (2.4.2) + bigdecimal (1.4.2) + binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) - builder (3.2.2) - coderay (1.1.0) - crack (0.4.2) - safe_yaml (~> 1.0.0) - debug_inspector (0.0.2) - diff-lcs (1.2.5) - erubis (2.7.0) - factory_girl (4.5.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) - railties (>= 3.0.0) - ffi (1.9.14) - formatador (0.2.5) - globalid (0.3.6) - activesupport (>= 4.1.0) - guard (2.14.0) - formatador (>= 0.2.4) - listen (>= 2.7, < 4.0) - lumberjack (~> 1.0) - nenv (~> 0.1) - notiffany (~> 0.0) - pry (>= 0.9.12) - shellany (~> 0.0) - thor (>= 0.18.1) - guard-compat (1.2.1) - guard-rspec (4.7.3) - guard (~> 2.1) - guard-compat (~> 1.1) - rspec (>= 2.99.0, < 4.0) - i18n (0.7.0) - json (1.8.3) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - loofah (2.0.3) + builder (3.2.4) + bundler-audit (0.9.0.1) + bundler (>= 1.2.0, < 3) + thor (~> 1.0) + byebug (11.1.3) + coderay (1.1.3) + concurrent-ruby (1.1.10) + crack (0.4.5) + rexml + crass (1.0.6) + database_cleaner (2.0.1) + database_cleaner-active_record (~> 2.0.0) + database_cleaner-active_record (2.0.1) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) + debug_inspector (1.1.0) + diff-lcs (1.5.0) + erubi (1.10.0) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + factory_bot_rails (6.2.0) + factory_bot (~> 6.2.0) + railties (>= 5.0.0) + globalid (1.0.0) + activesupport (>= 5.0) + hashdiff (1.0.1) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + loofah (2.15.0) + crass (~> 1.0.2) nokogiri (>= 1.5.9) - lumberjack (1.0.10) - mail (2.6.3) - mime-types (>= 1.16, < 3) - method_source (0.8.2) - mime-types (2.6.2) - mini_portile (0.6.2) - minitest (5.8.2) - nenv (0.3.0) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - notiffany (0.1.1) - nenv (~> 0.1) - shellany (~> 0.0) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - pry-stack_explorer (0.4.9.1) - binding_of_caller (>= 0.7) - pry (>= 0.9.11) - rack (1.6.4) - rack-test (0.6.3) - rack (>= 1.0) - rails (4.2.4) - actionmailer (= 4.2.4) - actionpack (= 4.2.4) - actionview (= 4.2.4) - activejob (= 4.2.4) - activemodel (= 4.2.4) - activerecord (= 4.2.4) - activesupport (= 4.2.4) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.4) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.7) - activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6.0) - rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.2) - loofah (~> 2.0) - railties (4.2.4) - actionpack (= 4.2.4) - activesupport (= 4.2.4) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.4.2) - rb-fsevent (0.9.7) - rb-inotify (0.9.7) - ffi (>= 0.5.0) - rspec (3.1.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-core (3.1.7) - rspec-support (~> 3.1.0) - rspec-expectations (3.1.2) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + mini_portile2 (2.6.1) + minitest (5.15.0) + nio4r (2.5.8) + nokogiri (1.12.5) + mini_portile2 (~> 2.6.1) + racc (~> 1.4) + nokogiri (1.12.5-x86_64-darwin) + racc (~> 1.4) + parallel (1.22.0) + parser (3.1.1.0) + ast (~> 2.4.1) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-stack_explorer (0.4.13) + binding_of_caller (~> 0.7) + pry (~> 0.13) + public_suffix (4.0.6) + racc (1.6.0) + rack (2.2.3) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (6.1.5) + actioncable (= 6.1.5) + actionmailbox (= 6.1.5) + actionmailer (= 6.1.5) + actionpack (= 6.1.5) + actiontext (= 6.1.5) + actionview (= 6.1.5) + activejob (= 6.1.5) + activemodel (= 6.1.5) + activerecord (= 6.1.5) + activestorage (= 6.1.5) + activesupport (= 6.1.5) + bundler (>= 1.15.0) + railties (= 6.1.5) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (6.1.5) + actionpack (= 6.1.5) + activesupport (= 6.1.5) + method_source + rake (>= 12.2) + thor (~> 1.0) + rainbow (3.1.1) + rake (13.0.6) + rb-readline (0.5.5) + regexp_parser (2.2.1) + rexml (3.2.5) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.11.0) + rspec-its (1.3.0) + rspec-core (>= 3.0.0) + rspec-expectations (>= 3.0.0) + rspec-mocks (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.1.0) - rspec-its (1.0.1) - rspec-core (>= 2.99.0.beta1) - rspec-expectations (>= 2.99.0.beta1) - rspec-mocks (3.1.3) - rspec-support (~> 3.1.0) - rspec-rails (3.1.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-support (~> 3.1.0) - rspec-support (3.1.2) - ruby_dep (1.4.0) - safe_yaml (1.0.4) - shellany (0.0.1) + rspec-support (~> 3.11.0) + rspec-rails (5.1.1) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.11.0) + rubocop (1.26.1) + parallel (~> 1.10) + parser (>= 3.1.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.16.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.16.0) + parser (>= 3.1.1.0) + rubocop-rspec (2.9.0) + rubocop (~> 1.19) + ruby-progressbar (1.11.0) shoulda-matchers (2.7.0) activesupport (>= 3.0.0) - slop (3.6.0) - sprockets (3.4.0) + sprockets (3.7.2) + concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (2.3.3) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.10) - thor (0.19.1) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - webmock (1.20.3) - addressable (>= 2.3.6) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.4.2) + thor (1.2.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + unicode-display_width (2.1.0) + webmock (3.14.0) + addressable (>= 2.8.0) crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) PLATFORMS ruby + x86_64-darwin-21 DEPENDENCIES - factory_girl_rails + bigdecimal (= 1.4.2) + bundler (>= 1.15.0) + bundler-audit + byebug + database_cleaner + factory_bot_rails front_end_builds! guard-rspec pry pry-stack_explorer - rails (~> 4.2.0) + rails (~> 6) + rb-readline rspec-its - rspec-rails (= 3.1.0) + rspec-rails + rubocop + rubocop-rspec shoulda-matchers (= 2.7.0) + sprockets (= 3.7.2) + sprockets-rails (= 3.2.1) sqlite3 webmock BUNDLED WITH - 1.12.5 + 2.3.8 diff --git a/README.md b/README.md index 74ad84f..1da7c9a 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,29 @@ +# Deprecation Notice + +TED has shifted to React and will no longer maintain this application/library. If you wish to continue using this application/library, please create a pull request and repo ownership can be transferred. This repository will be archived at the end of 2022. + [![Build Status](https://travis-ci.org/tedconf/front_end_builds.svg)](https://travis-ci.org/tedconf/front_end_builds) [![Code Climate](https://codeclimate.com/github/tedconf/front_end_builds/badges/gpa.svg)](https://codeclimate.com/github/tedconf/front_end_builds) [![Gem Version](https://badge.fury.io/rb/front_end_builds.svg)](http://badge.fury.io/rb/front_end_builds) # FrontEndBuilds -Front-End Builds lets you easily serve remotely-hosted static (JS) applications from your Rails apps. +Front-End Builds (FEB) lets you easily serve remotely-hosted static (JS) applications from your Rails apps. For example, you can host a Rails backend on Heroku, an Ember.js frontend on S3, and use FEB to connect the two. ![](https://camo.githubusercontent.com/175c23176da269c03c5d3f51a8feef3bdb50fc8a/687474703a2f2f63762d73637265656e73686f74732e73332e616d617a6f6e6177732e636f6d2f41646d696e5f323031352d30332d31305f30302d35312d32352e706e67) ![](https://camo.githubusercontent.com/979b56c0651251f4cf428ff354990ee167aeaf63/687474703a2f2f63762d73637265656e73686f74732e73332e616d617a6f6e6177732e636f6d2f41646d696e5f323031352d30332d31305f30302d35302d35382e706e67) Benefits: - - JS app can be deployed without redeploying your Rails app - - Easily smoke test SHAs, branches and releases in your production environment with query params: - http://your-app.com/my-ember-app?branch=new-feature + +- JS app can be deployed without redeploying your Rails app +- Easily smoke test SHAs, branches and releases in your production environment with query params: + http://your-app.com/my-ember-app?branch=new-feature Features: - - Admin interface lets you easily view, rollback and activate different app versions -The motivation for this gem came from [Luke Melia's RailsConf2014 talk](http://www.confreaks.com/videos/3324-railsconf-lightning-fast-deployment-of-your-rails-backed-javascript-app). +- Admin interface lets you easily view, rollback and activate different app versions +The motivation for this gem came from [Luke Melia's RailsConf2014 talk](http://www.confreaks.com/videos/3324-railsconf-lightning-fast-deployment-of-your-rails-backed-javascript-app). ## Installation @@ -38,6 +43,7 @@ Front-End Builds brings some migrations along with it. To run, execute ``` rake front_end_builds:install:migrations +rake db:migrate ``` ## Usage @@ -66,7 +72,7 @@ end mount protected_app, at: '/frontends' ``` -This will use basic HTTP auth to secure access to your admin ui. Just set the ENV variable, and use it to gain access. +This will use basic HTTP auth to secure access to your admin ui. Just set the ENV variable in production, and use it to gain access. If you're deploying to Heroku, use [Config Vars](https://devcenter.heroku.com/articles/config-vars). Now, to create a new app, first add a `front_end` route pointing to your app in `routes.rb`: @@ -79,13 +85,11 @@ end ``` Visit the admin (at whatever URL you mounted the engine above), create a -new app named `app-name`, and you'll receive instructions on how to +new app named `app-name`, and you'll receive instructions on how to start pushing builds. Note: -If you're using this engine to serve an ember app at the Root, be sure -to put all other Rails routes above the `front_end` route - as this take priority -over all routes below it! +If you're using this engine to serve an ember app at the Root, be sure to put all other Rails routes above the `front_end` route - as this takes priority over all routes below it! ```rb Rails.application.routes.draw do @@ -95,21 +99,32 @@ Rails.application.routes.draw do end ``` -## Configurations Options +At this point you should be able to test the setup in dev by running -Should you wish to allow deploys from an approved branch only, you may set the following environment variables +``` +bin/rails server +``` -`FRONT_END_BUILDS_RESTRICT_DEPLOYS=TRUE` and set the approved branch `FRONT_END_BUILDS_PRODUCTION_BRANCH=the_name_of_your_approved_branch` +Visit `/frontends` to access the Admin interface, and visit the `front_end` route, which will initially return 404 Not found since you haven't configured and deployed any front-end builds yet. -This can be troublesome if you're deploying from TravisCI as builds are always tagged `HEAD`, you can resolve this by adjusting your `.travis.yml`. +## A note on SSH Keys -```yml -install: -- git checkout ${TRAVIS_BRANCH} -``` +At this time only RSA keys are supported for authentication. You can't generate the keys using ssh-add you'll need the use [something like this](https://www.scottbrady91.com/openssl/creating-rsa-keys-using-openssl) -This basically just ensures that the branch name is available to `ember-cli-front-end-builds` to tag the deploy. +### Example Next Steps with Heroku and Ember.js +A common configuration is to deploy your FEB-enabled Rails app to Heroku, and deploy your Ember.js frontend to S3: + +1. Deploy your Rails app to Heroku +2. Configure your frontend app with [ember-cli-deploy-front-end-builds-pack](https://github.com/tedconf/ember-cli-deploy-front-end-builds-pack) +3. Access your Rails app's FEB Admin interface, add an app, and configure a public SSH key that corresponds to the private key you plan on using to sign your Ember.js builds +4. Deploy your frontend app. If all goes well, it should build the Ember app, push the static assets to S3, then POST to your Rails app. You'll see the build in the Admin interface, and should be able to access your frontend at the `front_end` route you specified. + +## Configurations Options + +Should you wish to allow deploys from an approved branch only, you may set the following environment variables + +`FRONT_END_BUILDS_RESTRICT_DEPLOYS=TRUE` and set the approved branch `FRONT_END_BUILDS_PRODUCTION_BRANCH=the_name_of_your_approved_branch` ## Development @@ -136,9 +151,15 @@ rspec ember test ``` +## Build status + +[This gem is built on Travis-CI.](https://travis-ci.org/tedconf/front_end_builds) + +![](https://travis-ci.org/tedconf/front_end_builds.svg?branch=master) + ## TODO -* Create docs site -* Auto live setting -* make posts idempotent (i think they are), but dont insert a new row if +- Create docs site +- Auto live setting +- make posts idempotent (i think they are), but dont insert a new row if it already exists. diff --git a/Rakefile b/Rakefile index 0c56eb8..d879ad3 100644 --- a/Rakefile +++ b/Rakefile @@ -25,7 +25,7 @@ end namespace :admin do task :build do Dir.chdir('admin') do - sh 'ember build --environment=production' + sh 'ember build production' end # Copy the dist to public diff --git a/admin/public/crossdomain.xml b/admin/public/crossdomain.xml deleted file mode 100644 index 29a035d..0000000 --- a/admin/public/crossdomain.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/app/controllers/front_end_builds/admin_controller.rb b/app/controllers/front_end_builds/admin_controller.rb index 7bab2e8..5d5deb8 100644 --- a/app/controllers/front_end_builds/admin_controller.rb +++ b/app/controllers/front_end_builds/admin_controller.rb @@ -15,7 +15,7 @@ def index html = html.sub('BASEURL/', baseURL) html = html.sub("baseURL: ''", "baseURL: '#{baseURL}'") - render text: html + render plain: html end end diff --git a/app/controllers/front_end_builds/application_controller.rb b/app/controllers/front_end_builds/application_controller.rb index 12e9290..df19446 100644 --- a/app/controllers/front_end_builds/application_controller.rb +++ b/app/controllers/front_end_builds/application_controller.rb @@ -1,11 +1,6 @@ module FrontEndBuilds class ApplicationController < ActionController::Base - def use_params(param_method) - v = Rails::VERSION::MAJOR - send("#{param_method}_rails_#{v}") - end - # Public: A quick helper to create a respond_to block for # returning json to the client. Used because `respond_with` # is no longer included in Rails. @@ -20,6 +15,5 @@ def respond_with_json(object, options = {}) def error!(errors, status = :unprocessable_entity) respond_with_json({ errors: errors }, status: status) end - end end diff --git a/app/controllers/front_end_builds/apps_controller.rb b/app/controllers/front_end_builds/apps_controller.rb index 49ecad6..fe7d971 100644 --- a/app/controllers/front_end_builds/apps_controller.rb +++ b/app/controllers/front_end_builds/apps_controller.rb @@ -2,10 +2,15 @@ module FrontEndBuilds class AppsController < ApplicationController - before_filter :set_app , :only => [:show, :destroy, :update] + before_action :set_app , :only => [:show, :destroy, :update] def index - apps = App.includes(:recent_builds) + # this should be the most recent 10 builds for each app + + # DO NOT use `App.includes(:recent_builds)` + # b/c it mucks up the grouping logic and only gives the most + # recent 10 for ALL apps not 10 per app + apps = App.all respond_with_json({ apps: apps.map(&:serialize), @@ -23,7 +28,7 @@ def show end def create - @app = FrontEndBuilds::App.new( use_params(:app_create_params) ) + @app = FrontEndBuilds::App.new( app_create_params ) if @app.save respond_with_json( @@ -39,7 +44,7 @@ def create end def update - if @app.update_attributes( use_params(:app_update_params) ) + if @app.update( app_update_params ) respond_with_json( { app: @app.serialize }, @@ -61,7 +66,7 @@ def destroy ) else respond_with_json( - {errors: @app.errors}, + { errors: @app.errors }, status: :unprocessable_entity ) end @@ -73,31 +78,18 @@ def set_app @app = FrontEndBuilds::App.find(params[:id]) end - def app_create_params_rails_3 - params[:app].slice(:name) - end - - def app_create_params_rails_4 + def app_create_params params.require(:app).permit( :name ) end - def app_update_params_rails_3 - params[:app].slice( - :name, - :require_manual_activation, - :live_build_id - ) - end - - def app_update_params_rails_4 + def app_update_params params.require(:app).permit( :name, :require_manual_activation, :live_build_id ) end - end end diff --git a/app/controllers/front_end_builds/bests_controller.rb b/app/controllers/front_end_builds/bests_controller.rb index aeaf544..95008bd 100644 --- a/app/controllers/front_end_builds/bests_controller.rb +++ b/app/controllers/front_end_builds/bests_controller.rb @@ -11,17 +11,17 @@ module FrontEndBuilds class BestsController < ApplicationController include Rails.application.routes.url_helpers - before_filter :find_front_end, only: [:show] + before_action :find_front_end, only: [:show] def show if @front_end respond_to do |format| - format.html { render text: @front_end.with_head_tag(meta_tags) } + format.html { render plain: @front_end.with_head_tag(meta_tags) } format.json { render json: { version: @front_end.id } } end else # TODO install instructions, user needs to push build - render text: "not found", status: 404 + render plain: "not found", status: 404 end end @@ -33,10 +33,10 @@ def meta_tags csrf_param: request_forgery_protection_token, csrf_token: form_authenticity_token, front_end_build_version: @front_end.id, - front_end_build_params: use_params(:build_search_params).to_query, + front_end_build_params: build_search_params.to_h.to_query, front_end_build_url: front_end_builds_best_path( - use_params(:build_search_params).merge(format: :json) - ) + build_search_params.merge(format: :json) + ) } tags @@ -48,14 +48,10 @@ def meta_tags end def find_front_end - @front_end = FrontEndBuilds::Build.find_best(use_params(:build_search_params)) + @front_end = FrontEndBuilds::Build.find_best(build_search_params) end - def build_search_params_rails_3 - params.slice(:app_name, :id, :branch, :sha, :job) - end - - def build_search_params_rails_4 + def build_search_params params.permit(:app_name, :id, :branch, :sha, :job) end end diff --git a/app/controllers/front_end_builds/builds_controller.rb b/app/controllers/front_end_builds/builds_controller.rb index 4a4d365..aa1adc1 100644 --- a/app/controllers/front_end_builds/builds_controller.rb +++ b/app/controllers/front_end_builds/builds_controller.rb @@ -2,7 +2,7 @@ module FrontEndBuilds class BuildsController < ApplicationController - before_filter :set_app!, only: [:create] + before_action :set_app!, only: [:create] def index builds = FrontEndBuilds::Build.where(app_id: params[:app_id]) @@ -12,7 +12,7 @@ def index end def create - build = @app.builds.new(use_params(:build_create_params)) + build = @app.builds.new(build_create_params) if build.verify && build.save build.setup! @@ -22,7 +22,7 @@ def create build.errors[:base] << 'No access - invalid SSH key' if !build.verify render( - text: 'Could not create the build: ' + build.errors.full_messages.to_s, + plain: 'Could not create the build: ' + build.errors.full_messages.to_s, status: :unprocessable_entity ) end @@ -45,7 +45,7 @@ def set_app! if @app.nil? render( - text: "No app named #{params[:app_name]}.", + plain: "No app named #{params[:app_name]}.", status: :unprocessable_entity ) @@ -64,11 +64,7 @@ def _create_params ] end - def build_create_params_rails_3 - params.slice(*_create_params) - end - - def build_create_params_rails_4 + def build_create_params params.permit(*_create_params) end end diff --git a/app/controllers/front_end_builds/host_apps_controller.rb b/app/controllers/front_end_builds/host_apps_controller.rb index 4ed3ad7..5c8509f 100644 --- a/app/controllers/front_end_builds/host_apps_controller.rb +++ b/app/controllers/front_end_builds/host_apps_controller.rb @@ -6,7 +6,7 @@ def show respond_with_json({ host_app: { id: params[:id], - name: Rails.application.class.parent_name + name: Rails.application.class.module_parent_name.underscore } }) end diff --git a/app/controllers/front_end_builds/pubkeys_controller.rb b/app/controllers/front_end_builds/pubkeys_controller.rb index 8047289..d622b83 100644 --- a/app/controllers/front_end_builds/pubkeys_controller.rb +++ b/app/controllers/front_end_builds/pubkeys_controller.rb @@ -8,8 +8,7 @@ def index end def create - pubkey = FrontEndBuilds::Pubkey - .new( use_params(:pubkey_create_params) ) + pubkey = FrontEndBuilds::Pubkey.new(pubkey_create_params) if pubkey.save respond_with_json( @@ -36,11 +35,7 @@ def destroy private - def pubkey_create_params_rails_3 - params[:pubkey].slice(:name, :pubkey) - end - - def pubkey_create_params_rails_4 + def pubkey_create_params params.require(:pubkey).permit( :name, :pubkey diff --git a/app/models/front_end_builds/app.rb b/app/models/front_end_builds/app.rb index bed84d5..a14cf59 100644 --- a/app/models/front_end_builds/app.rb +++ b/app/models/front_end_builds/app.rb @@ -6,7 +6,7 @@ class App < ActiveRecord::Base :live_build_id end - belongs_to :live_build, class_name: 'FrontEndBuilds::Build' + belongs_to :live_build, class_name: 'FrontEndBuilds::Build', optional: true has_many :builds, class_name: 'FrontEndBuilds::Build' if ActiveRecord::VERSION::MAJOR < 4 diff --git a/db/migrate/20141010162405_create_front_end_builds_builds.rb b/db/migrate/20141010162405_create_front_end_builds_builds.rb index 552e2ed..1dc405f 100644 --- a/db/migrate/20141010162405_create_front_end_builds_builds.rb +++ b/db/migrate/20141010162405_create_front_end_builds_builds.rb @@ -1,4 +1,4 @@ -class CreateFrontEndBuildsBuilds < ActiveRecord::Migration +class CreateFrontEndBuildsBuilds < ActiveRecord::Migration[4.2] def change create_table :front_end_builds_builds do |t| t.references :app diff --git a/db/migrate/20141010165726_create_front_end_builds_apps.rb b/db/migrate/20141010165726_create_front_end_builds_apps.rb index ee7e204..a7c91e9 100644 --- a/db/migrate/20141010165726_create_front_end_builds_apps.rb +++ b/db/migrate/20141010165726_create_front_end_builds_apps.rb @@ -1,4 +1,4 @@ -class CreateFrontEndBuildsApps < ActiveRecord::Migration +class CreateFrontEndBuildsApps < ActiveRecord::Migration[4.2] def change create_table :front_end_builds_apps do |t| t.string :name, limit: 191 diff --git a/db/migrate/20141105222855_add_endpoint_to_front_end_builds_build.rb b/db/migrate/20141105222855_add_endpoint_to_front_end_builds_build.rb index d560bb9..c1e0f4a 100644 --- a/db/migrate/20141105222855_add_endpoint_to_front_end_builds_build.rb +++ b/db/migrate/20141105222855_add_endpoint_to_front_end_builds_build.rb @@ -1,4 +1,4 @@ -class AddEndpointToFrontEndBuildsBuild < ActiveRecord::Migration +class AddEndpointToFrontEndBuildsBuild < ActiveRecord::Migration[4.2] def change add_column :front_end_builds_builds, :endpoint, :string, limit: 2038 end diff --git a/db/migrate/20150114202950_require_manual_activation.rb b/db/migrate/20150114202950_require_manual_activation.rb index fd626e2..74f1f58 100644 --- a/db/migrate/20150114202950_require_manual_activation.rb +++ b/db/migrate/20150114202950_require_manual_activation.rb @@ -1,4 +1,4 @@ -class RequireManualActivation < ActiveRecord::Migration +class RequireManualActivation < ActiveRecord::Migration[4.2] def change add_column :front_end_builds_apps, :require_manual_activation, diff --git a/db/migrate/20150124215337_create_front_end_builds_pubkeys.rb b/db/migrate/20150124215337_create_front_end_builds_pubkeys.rb index 40d2ed3..1ff6f21 100644 --- a/db/migrate/20150124215337_create_front_end_builds_pubkeys.rb +++ b/db/migrate/20150124215337_create_front_end_builds_pubkeys.rb @@ -1,4 +1,4 @@ -class CreateFrontEndBuildsPubkeys < ActiveRecord::Migration +class CreateFrontEndBuildsPubkeys < ActiveRecord::Migration[4.2] def change create_table :front_end_builds_pubkeys do |t| t.string :name, null: false, limit: 191 diff --git a/db/migrate/20150124221024_add_pubkey_to_build.rb b/db/migrate/20150124221024_add_pubkey_to_build.rb index e71fc9d..06f3742 100644 --- a/db/migrate/20150124221024_add_pubkey_to_build.rb +++ b/db/migrate/20150124221024_add_pubkey_to_build.rb @@ -1,4 +1,4 @@ -class AddPubkeyToBuild < ActiveRecord::Migration +class AddPubkeyToBuild < ActiveRecord::Migration[4.2] def change # Track what public deployed each build add_column :front_end_builds_builds, :pubkey_id, :integer diff --git a/db/migrate/20150126123348_add_build_ref_to_apps.rb b/db/migrate/20150126123348_add_build_ref_to_apps.rb index 499c3c7..ff064a9 100644 --- a/db/migrate/20150126123348_add_build_ref_to_apps.rb +++ b/db/migrate/20150126123348_add_build_ref_to_apps.rb @@ -1,4 +1,4 @@ -class AddBuildRefToApps < ActiveRecord::Migration +class AddBuildRefToApps < ActiveRecord::Migration[4.2] def change add_column :front_end_builds_apps, :live_build_id, :integer end diff --git a/db/migrate/20150224040537_remove_api_key_from_apps.rb b/db/migrate/20150224040537_remove_api_key_from_apps.rb index 39e19d1..48402b1 100644 --- a/db/migrate/20150224040537_remove_api_key_from_apps.rb +++ b/db/migrate/20150224040537_remove_api_key_from_apps.rb @@ -1,4 +1,4 @@ -class RemoveApiKeyFromApps < ActiveRecord::Migration +class RemoveApiKeyFromApps < ActiveRecord::Migration[4.2] def change remove_column :front_end_builds_apps, :api_key end diff --git a/front_end_builds.gemspec b/front_end_builds.gemspec index 74e287b..b80befe 100644 --- a/front_end_builds.gemspec +++ b/front_end_builds.gemspec @@ -5,10 +5,19 @@ require "front_end_builds/version" # Describe your gem and declare its dependencies: Gem::Specification.new do |s| + # Prevent pushing this gem to RubyGems.org. + # allow pushing only to our private gem server. + if s.respond_to?(:metadata) + s.metadata['allowed_push_host'] = 'https://rubygems.ted.com/private' + else + raise 'RubyGems 2.0 or newer is required to protect against ' \ + 'public gem pushes.' + end + s.name = "front_end_builds" s.version = FrontEndBuilds::VERSION - s.authors = ["Ryan Toronto", "Sam Selikoff"] - s.email = ["rt@ted.com", "sam@ted.com"] + s.authors = ["Ryan Toronto", "Sam Selikoff", "John Hirbour"] + s.email = ["rt@ted.com", "sam@ted.com", "gohn@ted.com"] s.homepage = "http://github.com/tedconf/front_end_builds" s.summary = "Summary of FrontEndBuilds." s.description = "Rails engine to manage front end builds and deployments" @@ -17,13 +26,31 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib,public}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] s.test_files = Dir["test/**/*"] - s.add_development_dependency "sqlite3" - s.add_development_dependency 'rspec-rails', '3.1.0' - s.add_development_dependency 'rspec-its' - s.add_development_dependency 'factory_girl_rails' + # Use Rails 6 + s.add_dependency 'rails', '> 5', '< 7' + + # Ideally we'd use this https://github.com/bensie/sshkey + # for ssh key bits, but it doesn't support OpenSSL v2.x + + # sort this by alpha + s.add_development_dependency 'bundler', '>=1.15.0' + s.add_development_dependency 'bundler-audit' + s.add_development_dependency 'byebug' + s.add_development_dependency 'database_cleaner' + s.add_development_dependency 'factory_bot_rails' s.add_development_dependency 'pry' s.add_development_dependency 'pry-stack_explorer' + s.add_development_dependency 'rb-readline' + s.add_development_dependency 'rspec-rails' + s.add_development_dependency 'rspec-its' + s.add_development_dependency 'rubocop' + s.add_development_dependency 'rubocop-rspec' s.add_development_dependency 'shoulda-matchers', '2.7.0' + # These 2 are needed so that the rails app version matches + # otherwise bundle gives you sprockets 4 + s.add_development_dependency 'sprockets', '3.7.2' + s.add_development_dependency 'sprockets-rails', '3.2.1' + s.add_development_dependency "sqlite3" s.add_development_dependency 'webmock' s.add_development_dependency 'guard-rspec' end diff --git a/lib/front_end_builds/engine.rb b/lib/front_end_builds/engine.rb index fd6a686..ed4b0e2 100644 --- a/lib/front_end_builds/engine.rb +++ b/lib/front_end_builds/engine.rb @@ -6,7 +6,7 @@ class Engine < ::Rails::Engine config.generators do |g| g.test_framework :rspec, fixture: false - g.fixture_replacement :factory_girl, dir: 'spec/factories' + g.fixture_replacement :factory_bot, dir: 'spec/factories' g.assets false g.helper false end diff --git a/lib/front_end_builds/utils/ssh_pubkey_convert.rb b/lib/front_end_builds/utils/ssh_pubkey_convert.rb index 567ba6b..a35aada 100644 --- a/lib/front_end_builds/utils/ssh_pubkey_convert.rb +++ b/lib/front_end_builds/utils/ssh_pubkey_convert.rb @@ -3,6 +3,9 @@ # # https://github.com/mytestbed/omf/blob/master/omf_common/lib/omf_common/auth/ssh_pub_key_convert.rb # +# Support for DSA keys was removed from this code as the FEB app doesn't support DSA keys +# See PubKey#verify +# module FrontEndBuilds module Utils @@ -66,33 +69,21 @@ def self.convert(keystring) (nstr, bytes) = unpack_string(bytes, n) key = OpenSSL::PKey::RSA.new - n = OpenSSL::BN.new(nstr, 2) - e = OpenSSL::BN.new(estr, 2) - if key.respond_to? :set_key - key.set_key(n, e, nil) + + # support SSL 2 + if Gem::Version.new(OpenSSL::VERSION) < Gem::Version.new('2.0.0') + key.n = OpenSSL::BN.new(nstr, 2) + key.e = OpenSSL::BN.new(estr, 2) else - key.n = n - key.e = e + # params are n, e, d + key.set_key(OpenSSL::BN.new(nstr, 2), OpenSSL::BN.new(estr, 2), nil) end - key - elsif keytype == 'ssh-dss' - (n, bytes) = unpack_u32(bytes) - (pstr, bytes) = unpack_string(bytes, n) - (n, bytes) = unpack_u32(bytes) - (qstr, bytes) = unpack_string(bytes, n) - (n, bytes) = unpack_u32(bytes) - (gstr, bytes) = unpack_string(bytes, n) - (n, bytes) = unpack_u32(bytes) - (pkstr, bytes) = unpack_string(bytes, n) - key = OpenSSL::PKey::DSA.new - key.p = OpenSSL::BN.new(pstr, 2) - key.q = OpenSSL::BN.new(qstr, 2) - key.g = OpenSSL::BN.new(gstr, 2) - key.pub_key = OpenSSL::BN.new(pkstr, 2) key else - nil + # anything non-RSA is not supported + # this part edited by TED + raise "Unsupported key type: #{keytype}" end end end diff --git a/lib/front_end_builds/version.rb b/lib/front_end_builds/version.rb index 9d3d19b..447b90a 100644 --- a/lib/front_end_builds/version.rb +++ b/lib/front_end_builds/version.rb @@ -1,3 +1,3 @@ module FrontEndBuilds - VERSION = "0.2.1" + VERSION = '1.0.5' end diff --git a/public/front_end_builds/crossdomain.xml b/public/front_end_builds/crossdomain.xml deleted file mode 100644 index 29a035d..0000000 --- a/public/front_end_builds/crossdomain.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/spec/controllers/front_end_builds/apps_controller_spec.rb b/spec/controllers/front_end_builds/apps_controller_spec.rb index d6e618d..6adb2ee 100644 --- a/spec/controllers/front_end_builds/apps_controller_spec.rb +++ b/spec/controllers/front_end_builds/apps_controller_spec.rb @@ -4,25 +4,55 @@ module FrontEndBuilds RSpec.describe AppsController, :type => :controller do routes { FrontEndBuilds::Engine.routes } - let(:app) { FactoryGirl.create :front_end_builds_app, name: 'dummy' } - let!(:builds) { FactoryGirl.create_list :front_end_builds_build, 2, app: app } - let!(:live_build) { FactoryGirl.create :front_end_builds_build, :live, :fetched, app: app } + let(:app) { create(:front_end_builds_app, name: 'dummy') } + let!(:builds) { create_list(:front_end_builds_build, 2, app: app) } + let!(:live_build) { create(:front_end_builds_build, :live, :fetched, app: app) } describe 'index' do it "should find all apps" do get :index, format: :json - expect(response).to be_success + expect(response.successful?).to be true expect(json['apps'].length).to eq(1) expect(json['builds'].length).to eq(3) end + + # This specs query composition b/c it changed slightly between rails 4 and rails 5 + # in regards to includes + describe "testing query composition", focus: true do + # getting rid of the ones from the outer describe + before(:each) do + App.delete_all + Build.delete_all + end + + let(:app1) { create(:front_end_builds_app, name: 'dummy') } + let(:app2) { create(:front_end_builds_app, name: 'dummy2') } + let!(:app1_builds) { create_list(:front_end_builds_build, 1, app: app1) } + let!(:app2_builds) { create_list(:front_end_builds_build, 10, app: app2) } + + it "Finds the correct builds_ids for EACH app" do + get :index, format: :json + + expect(response.successful?).to be true + expect(json['apps'].length).to eq(2) + app1_json = json['apps'].select{|x| x['id'] == app1.id}.first + app2_json = json['apps'].select{|x| x['id'] == app2.id}.first + + # make sure the oldest app (by created_by) shows up + # this rows ends up missing if include(:recent_builds) is in the Arel + expect(app1_json['build_ids']).to match(app1_builds.map(&:id)) + + expect(app2_json['build_ids']).to match( app2.recent_builds.map(&:id)) + end + end end describe 'show' do it "should find the requested app" do - get :show, id: app.id, format: :json + get :show, params: { id: app.id }, format: :json - expect(response).to be_success + expect(response.successful?).to be true expect(json['app']['id']).to eq(app.id) expect(json['builds'].length).to eq(3) expect(json['app']['live_build_id']).to eq(app.live_build.id) @@ -31,12 +61,14 @@ module FrontEndBuilds describe 'create' do it "should create a new app" do - post :create, app: { - name: 'my-new-app' + post :create, params: { + app: { + name: 'my-new-app' + } }, format: :json - expect(response).to be_success + expect(response.successful?).to be true app = FrontEndBuilds::App.where(name: 'my-new-app').limit(1).first expect(json['app']['id']).to eq(app.id) @@ -44,20 +76,22 @@ module FrontEndBuilds end describe 'update' do - let(:app) { FactoryGirl.create :front_end_builds_app, name: 'forsaken' } - let!(:live_build) { FactoryGirl.create :front_end_builds_build, :live, :fetched, app: app } - let!(:new_build) { FactoryGirl.create :front_end_builds_build, :fetched, app: app } - let(:prohibited_build) { FactoryGirl.create(:front_end_builds_build, :fetched, app: app, branch: 'experimental')} + let(:app) { create :front_end_builds_app, name: 'forsaken' } + let!(:live_build) { create :front_end_builds_build, :live, :fetched, app: app } + let!(:new_build) { create :front_end_builds_build, :fetched, app: app } + let(:prohibited_build) { create :front_end_builds_build, :fetched, app: app, branch: 'experimental' } it "should edit an existing app" do post :update, - id: app.id, - app: { - live_build_id: new_build.id + params: { + id: app.id, + app: { + live_build_id: new_build.id + } }, format: :json - expect(response).to be_success + expect(response.successful?).to be true app.reload @@ -83,23 +117,25 @@ module FrontEndBuilds end describe 'destroy' do - let(:deletable_app) { FactoryGirl.create :front_end_builds_app, name: 'forsaken' } + let(:deletable_app) { create :front_end_builds_app, name: 'forsaken' } context 'a valid app' do before(:each) do post :destroy, - id: deletable_app.id, + params: { + id: deletable_app.id + }, format: :json end context 'the response' do subject { response } - it { should be_success } + it { expect(subject.successful?).to be true } end context 'the data' do subject { json['app']['id'] } - it { should_not be_nil } + it { expect(subject).to be_truthy } end context 'the record' do diff --git a/spec/controllers/front_end_builds/bests_controller_spec.rb b/spec/controllers/front_end_builds/bests_controller_spec.rb index b2d433f..0e0f7a5 100644 --- a/spec/controllers/front_end_builds/bests_controller_spec.rb +++ b/spec/controllers/front_end_builds/bests_controller_spec.rb @@ -2,11 +2,11 @@ module FrontEndBuilds RSpec.describe BestsController, :type => :controller do - let(:app) { FactoryGirl.create :front_end_builds_app, name: 'dummy' } + let(:app) { create :front_end_builds_app, name: 'dummy' } describe "show" do let!(:latest) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha1', job: 'number1', @@ -17,7 +17,7 @@ module FrontEndBuilds end let!(:live) do - FactoryGirl.create :front_end_builds_build, :live, + create :front_end_builds_build, :live, app: app, sha: 'sha2', job: 'number2', @@ -28,7 +28,7 @@ module FrontEndBuilds end let!(:older) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha3', job: 'number3', @@ -39,33 +39,33 @@ module FrontEndBuilds end it "should find the live build" do - get :show, app_name: app.name - expect(response).to be_success + get :show, params: { app_name: app.name } + expect(response.successful?).to be true expect(response.body).to match(live.html) end it "should find the build by job" do - get :show, app_name: app.name, job: 'number3' - expect(response).to be_success + get :show, params: { app_name: app.name, job: 'number3' } + expect(response.successful?).to be true expect(response.body).to match(older.html) end it "should find the build by build_id" do - get :show, id: older.id - expect(response).to be_success + get :show, params: { id: older.id } + expect(response.successful?).to be true expect(response.body).to match(older.html) end it "should find the build by branch" do - get :show, app_name: app.name, branch: 'master' - expect(response).to be_success + get :show, params: { app_name: app.name, branch: 'master' } + expect(response.successful?).to be true expect(response.body).to match(latest.html) end context "meta tags" do before(:each) do - get :show, app_name: app.name, branch: 'master' - expect(response).to be_success + get :show, params: { app_name: app.name, branch: 'master' } + expect(response.successful?).to be true end subject { response.body } @@ -77,13 +77,13 @@ module FrontEndBuilds end it "should be 404 when nothing is found" do - get :show, app_name: 'does-not-exist', branch: 'master' - expect(response).to_not be_success + get :show, params: { app_name: 'does-not-exist', branch: 'master' } + expect(response.successful?).to_not be true expect(response.status).to eq(404) end it "should be able to get the version of the best build" do - get :show, app_name: app.name, branch: 'master', format: :json + get :show, params: { app_name: app.name, branch: 'master', format: :json } expect(json['version']).to eq(latest.id) end diff --git a/spec/controllers/front_end_builds/builds_controller_spec.rb b/spec/controllers/front_end_builds/builds_controller_spec.rb index 042ec37..7bb54db 100644 --- a/spec/controllers/front_end_builds/builds_controller_spec.rb +++ b/spec/controllers/front_end_builds/builds_controller_spec.rb @@ -2,34 +2,34 @@ module FrontEndBuilds RSpec.describe BuildsController, :type => :controller do - let(:app) { FactoryGirl.create :front_end_builds_app, name: 'dummy' } + let(:app) { create :front_end_builds_app, name: 'dummy' } describe "index" do routes { FrontEndBuilds::Engine.routes } it "should list all the builds for an app" do - FactoryGirl.create_list(:front_end_builds_build, 3, app: app) + create_list(:front_end_builds_build, 3, app: app) - get :index, app_id: app.id, format: :json - expect(response).to be_success + get :index, params: { app_id: app.id }, format: :json + expect(response.successful?).to be true expect(json['builds'].length).to eq(3) end it 'should be scoped to the requested app' do - build1 = FactoryGirl.create(:front_end_builds_build, app: app) - FactoryGirl.create(:front_end_builds_build) + build1 = create(:front_end_builds_build, app: app) + create(:front_end_builds_build) - get :index, app_id: app.id, format: :json - expect(response).to be_success + get :index, params: { app_id: app.id }, format: :json + expect(response.successful?).to be true expect(json['builds'].length).to eq(1) expect(json['builds'].first['id']).to eq(build1.id) end it "should not list any builds if the app is not present" do - FactoryGirl.create_list(:front_end_builds_build, 3) + create_list(:front_end_builds_build, 3) get :index, format: :json - expect(response).to be_success + expect(response.successful?).to be true expect(json['builds'].length).to eq(0) end end @@ -37,11 +37,11 @@ module FrontEndBuilds describe "show" do routes { FrontEndBuilds::Engine.routes } - let(:build) { FactoryGirl.create :front_end_builds_build } + let(:build) { create :front_end_builds_build } it "should load the app" do - get :show, id: build.id, format: :json - expect(response).to be_success + get :show, params: { id: build.id }, format: :json + expect(response.successful?).to be true expect(json['build']['id']).to eq(build.id) end end @@ -50,14 +50,14 @@ module FrontEndBuilds let(:endpoint) { 'http://www.ted.com/testing/build' } before(:each) do - FactoryGirl.create :front_end_builds_build, :live, + create :front_end_builds_build, :live, app: app, endpoint: 'http://www.ted.com/testing/build', created_at: 1.day.ago, fetched: true, html: 'the old build' - FactoryGirl.create(:front_end_builds_pubkey, :fixture_pubkey) + create(:front_end_builds_pubkey, :fixture_pubkey) stub_request(:get, endpoint) .to_return(body: 'fetched html') @@ -66,7 +66,7 @@ module FrontEndBuilds it "should create the new build, and make it live" do expect(app.live_build.html).to eq('the old build') - post :create, { + post :create, params: { app_name: app.name, branch: 'master', sha: 'some-sha', @@ -75,14 +75,14 @@ module FrontEndBuilds signature: create_signature("#{app.name}-#{endpoint}") } - expect(response).to be_success + expect(response.successful?).to be true expect(app.reload.live_build.html).to eq('fetched html') end it "should not make a new build live if it's non-master" do expect(app.live_build.html).to eq('the old build') - post :create, { + post :create, params: { app_name: app.name, branch: 'some-feature', sha: 'some-sha', @@ -91,14 +91,14 @@ module FrontEndBuilds signature: create_signature("#{app.name}-#{endpoint}") } - expect(response).to be_success + expect(response.successful?).to be true expect(app.reload.live_build.html).to eq('the old build') end it "should not active a build if the app requires manual activiation" do - app.update_attributes(require_manual_activation: true) + app.update(require_manual_activation: true) - post :create, { + post :create, params: { app_name: app.name, branch: 'master', sha: 'some-sha', @@ -107,14 +107,14 @@ module FrontEndBuilds signature: create_signature("#{app.name}-#{endpoint}") } - expect(response).to be_success + expect(response.successful?).to be true expect(app.live_build.html).to eq('the old build') end it 'should error if the app cannot be found' do - app.update_attributes(require_manual_activation: true) + app.update(require_manual_activation: true) - post :create, { + post :create, params: { app_name: 'this-does-not-exist', branch: 'master', sha: 'some-sha', @@ -123,7 +123,7 @@ module FrontEndBuilds signature: create_signature("unknown-#{endpoint}") } - expect(response).to_not be_success + expect(response.successful?).to_not be true expect(response.body).to eq('No app named this-does-not-exist.') end @@ -132,7 +132,7 @@ module FrontEndBuilds digest = OpenSSL::Digest::SHA256.new signature = pkey.sign(digest, "#{app.name}-#{endpoint}") - post :create, { + post :create, params: { app_name: app.name, branch: 'master', sha: 'some-sha', @@ -141,22 +141,22 @@ module FrontEndBuilds signature: Base64.encode64(signature) } - expect(response).to_not be_success + expect(response.successful?).to_not be true expect(response.body).to match("No access - invalid SSH key") end it "should error if not all fields are present" do - post :create, { + post :create, params: { app_name: app.name, endpoint: endpoint, signature: create_signature("#{app.name}-#{endpoint}") } - expect(response).to_not be_success + expect(response.successful?).to_not be true expect(response.body).to match("Sha can't be blank") end it 'should let the html be submitted' do - post :create, { + post :create, params: { app_name: app.name, branch: 'master', sha: 'some-sha', @@ -165,7 +165,7 @@ module FrontEndBuilds signature: create_signature('hello world') } - expect(response).to be_success + expect(response.successful?).to be true expect(app.live_build.html).to eq('the old build') end end diff --git a/spec/controllers/front_end_builds/host_apps_controller_spec.rb b/spec/controllers/front_end_builds/host_apps_controller_spec.rb index 9df01c5..3a3b017 100644 --- a/spec/controllers/front_end_builds/host_apps_controller_spec.rb +++ b/spec/controllers/front_end_builds/host_apps_controller_spec.rb @@ -6,11 +6,11 @@ module FrontEndBuilds describe 'show' do it 'should fetch info about the host application (rails)' do - get :show, id: 'current', format: :json + get :show, params: { id: 'current' }, format: :json - expect(response).to be_success + expect(response.successful?).to be true expect(json['host_app']['id']).to eq('current') - expect(json['host_app']['name']).to eq('Dummy') + expect(json['host_app']['name']).to eq('dummy') end end diff --git a/spec/controllers/front_end_builds/pubkeys_controller_spec.rb b/spec/controllers/front_end_builds/pubkeys_controller_spec.rb index 395a744..a4e5d8d 100644 --- a/spec/controllers/front_end_builds/pubkeys_controller_spec.rb +++ b/spec/controllers/front_end_builds/pubkeys_controller_spec.rb @@ -5,12 +5,12 @@ module FrontEndBuilds routes { FrontEndBuilds::Engine.routes } describe 'index' do - let!(:keys) { FactoryGirl.create_list(:front_end_builds_pubkey, 3) } + let!(:keys) { create_list(:front_end_builds_pubkey, 3) } it 'should list all pubkeys' do get :index, format: :json - expect(response).to be_success + expect(response.successful?).to be true expect(json['pubkeys'].size).to eq(3) end end @@ -18,13 +18,15 @@ module FrontEndBuilds describe 'create' do it 'should create a new pubkey' do post :create, - pubkey: { - name: 'my-new-key', - pubkey: 'asdfasdf' + params: { + pubkey: { + name: 'my-new-key', + pubkey: 'asdfasdf' + } }, format: :json - expect(response).to be_success + expect(response.successful?).to be true key = FrontEndBuilds::Pubkey .where(name: 'my-new-key') @@ -36,23 +38,25 @@ module FrontEndBuilds it 'should not create a new pubkey without a pubkey' do post :create, - pubkey: { - name: 'my-new-key' + params: { + pubkey: { + name: 'my-new-key' + } }, format: :json - expect(response).to_not be_success + expect(response.successful?).to_not be true expect(json['errors']['pubkey'].size).to eq(1) end end describe 'destroy' do - let(:pubkey) { FactoryGirl.create(:front_end_builds_pubkey) } + let(:pubkey) { create(:front_end_builds_pubkey) } it 'should remove a pubkey' do - delete :destroy, id: pubkey.id, format: :json + delete :destroy, params: { id: pubkey.id }, format: :json - expect(response).to be_success + expect(response.successful?).to be true lookup_pubkey = FrontEndBuilds::Pubkey .where(id: pubkey.id) diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml index 1c1a37c..60fb357 100644 --- a/spec/dummy/config/database.yml +++ b/spec/dummy/config/database.yml @@ -1,4 +1,4 @@ -# SQLite version 3.x +#talkstar SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index 363ab3e..4d0f642 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -14,12 +14,9 @@ config.eager_load = false # Configure static asset server for tests with Cache-Control for performance. - if Rails::VERSION::MAJOR >= 4 && Rails::VERSION::MINOR > 1 - config.serve_static_files = true - else - config.serve_static_assets = true - end - config.static_cache_control = 'public, max-age=3600' + config.public_file_server.enabled = true + + config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' } # Show full error reports and disable caching. config.consider_all_requests_local = true diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index 3df7fa9..df7afc3 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -1,55 +1,52 @@ -# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150224040537) do +ActiveRecord::Schema.define(version: 2015_02_24_040537) do create_table "front_end_builds_apps", force: :cascade do |t| - t.string "name" + t.string "name", limit: 191 t.datetime "created_at" t.datetime "updated_at" - t.boolean "require_manual_activation", default: false - t.integer "live_build_id" + t.boolean "require_manual_activation", default: false + t.integer "live_build_id" + t.index ["name"], name: "index_front_end_builds_apps_on_name" end - add_index "front_end_builds_apps", ["name"], name: "index_front_end_builds_apps_on_name" - create_table "front_end_builds_builds", force: :cascade do |t| - t.integer "app_id" - t.string "sha" - t.string "job" - t.string "branch" - t.text "html" - t.boolean "fetched", default: false - t.boolean "active", default: false + t.integer "app_id" + t.string "sha", limit: 191 + t.string "job", limit: 191 + t.string "branch", limit: 191 + t.text "html" + t.boolean "fetched", default: false + t.boolean "active", default: false t.datetime "created_at" t.datetime "updated_at" - t.string "endpoint", limit: 2038 - t.integer "pubkey_id" - t.text "signature" + t.string "endpoint", limit: 2038 + t.integer "pubkey_id" + t.text "signature" + t.index ["active"], name: "index_front_end_builds_builds_on_active" + t.index ["app_id", "branch"], name: "index_front_end_builds_builds_on_app_id_and_branch" + t.index ["app_id", "job"], name: "index_front_end_builds_builds_on_app_id_and_job" + t.index ["app_id", "sha"], name: "index_front_end_builds_builds_on_app_id_and_sha" + t.index ["created_at"], name: "index_front_end_builds_builds_on_created_at" + t.index ["fetched"], name: "index_front_end_builds_builds_on_fetched" end - add_index "front_end_builds_builds", ["active"], name: "index_front_end_builds_builds_on_active" - add_index "front_end_builds_builds", ["app_id", "branch"], name: "index_front_end_builds_builds_on_app_id_and_branch" - add_index "front_end_builds_builds", ["app_id", "job"], name: "index_front_end_builds_builds_on_app_id_and_job" - add_index "front_end_builds_builds", ["app_id", "sha"], name: "index_front_end_builds_builds_on_app_id_and_sha" - add_index "front_end_builds_builds", ["created_at"], name: "index_front_end_builds_builds_on_created_at" - add_index "front_end_builds_builds", ["fetched"], name: "index_front_end_builds_builds_on_fetched" - create_table "front_end_builds_pubkeys", force: :cascade do |t| - t.string "name", limit: 191, null: false - t.text "pubkey", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name", limit: 191, null: false + t.text "pubkey", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end end diff --git a/spec/factories/front_end_builds_apps.rb b/spec/factories/front_end_builds_apps.rb index c2756b3..c94ba35 100644 --- a/spec/factories/front_end_builds_apps.rb +++ b/spec/factories/front_end_builds_apps.rb @@ -1,6 +1,6 @@ -# Read about factories at https://github.com/thoughtbot/factory_girl +# Read about factories at https://github.com/thoughtbot/factory_bot -FactoryGirl.define do +FactoryBot.define do factory :front_end_builds_app, :class => 'FrontEndBuilds::App' do sequence(:name) { |n| "application-#{n}" } end diff --git a/spec/factories/front_end_builds_builds.rb b/spec/factories/front_end_builds_builds.rb index c440108..cc5b155 100644 --- a/spec/factories/front_end_builds_builds.rb +++ b/spec/factories/front_end_builds_builds.rb @@ -1,21 +1,23 @@ -# Read about factories at https://github.com/thoughtbot/factory_girl +# Read about factories at https://github.com/thoughtbot/factory_bot -FactoryGirl.define do +FactoryBot.define do factory :front_end_builds_build, :class => 'FrontEndBuilds::Build' do sequence(:sha) { |n| "sha#{n}" } sequence(:job) { |n| n } sequence(:endpoint) { |n| "http://ted.bucket.ted.com/#{n}/index.html" } - branch "master" - signature "some signature" - html "hello world" + branch { "master" } + signature { "some signature" } + html { "hello world" } association :app, factory: :front_end_builds_app trait :fetched do - fetched true + fetched { true } end trait :live do - after :create, &:activate! + after(:create) do |p| + p.activate! + end end trait :signed do diff --git a/spec/factories/front_end_builds_pubkeys.rb b/spec/factories/front_end_builds_pubkeys.rb index 9437243..ebd932e 100644 --- a/spec/factories/front_end_builds_pubkeys.rb +++ b/spec/factories/front_end_builds_pubkeys.rb @@ -1,6 +1,6 @@ -FactoryGirl.define do +FactoryBot.define do factory :front_end_builds_pubkey, :class => 'FrontEndBuilds::Pubkey' do - name 'ryan' + name { 'ryan' } sequence(:pubkey) { |i| "ssh-rsa pubkey#{i}#{i}#{i} test@ted.com" } trait :fixture_pubkey do diff --git a/spec/fixtures/README.md b/spec/fixtures/README.md new file mode 100644 index 0000000..be9c9be --- /dev/null +++ b/spec/fixtures/README.md @@ -0,0 +1,5 @@ +the keys in this dir are used for testing ssh key to open ssl pkey conversions. + +ecdsa keys are not supported at this time, the key in this dir is for testing error raising. + +Ideally we'd use something like the sshkey gem, but it doesn't currently support OpenSSL 2 diff --git a/spec/fixtures/id_dsa b/spec/fixtures/id_dsa new file mode 100644 index 0000000..a4cd5ae --- /dev/null +++ b/spec/fixtures/id_dsa @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBugIBAAKBgQCKMPZ4FvbvJosU1OtQ+TOptTrr+KE58jbZtWjcqXokSyVLDeHx +UqgGTOJMsfBkf1baJ4XzxixdSxYLgmWQLIdldl4p/W/DU+dAGRKr+uN2X1d1lx37 +ZBofJZsfl2BNtvlMlgH+VUhyefUpn/XNDr6yEfKDaWHamIWwgc3qZr6bYwIVALAe +RZEeFQKDxAtcoAMsXcEOHLsdAoGAV6EXR/2RqlUYpjk/ZB+lkPCjFVLCrQfKJ8pi +M+yGYIfrCKQ/xusMgRkLSLqhGuQlWljhCJIHbz3PTTP67kFBz2svWekSP7g5q48Z +nl/BzrojBmZljf+k+nuqKF2ZkitilU8l4nlPjZGeXDK6xVVzR3KZml883OsvPiIA +H9W/YX8CgYAPxU0kAZKbBGGo2p+T9KjOK27dXJG5fh+3nOZBzk91GRBK+2QR1jSd ++ovliKChyH1CFWGbEEcjKrJ3emD3NdBUaAmy0+Am1ET9Rxn6uhVoit9woBOFfALt +zeLewsjxPOo2+S/nHP1Pjom1hR4Uqx8VEfm8jwltOQNPa5zwCwuWgQIUO6jwfKlA +N8v2vgs82zH2MxY/7MA= +-----END DSA PRIVATE KEY----- diff --git a/spec/fixtures/id_dsa.pub b/spec/fixtures/id_dsa.pub new file mode 100644 index 0000000..55a7f1d --- /dev/null +++ b/spec/fixtures/id_dsa.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAIow9ngW9u8mixTU61D5M6m1Ouv4oTnyNtm1aNypeiRLJUsN4fFSqAZM4kyx8GR/VtonhfPGLF1LFguCZZAsh2V2Xin9b8NT50AZEqv643ZfV3WXHftkGh8lmx+XYE22+UyWAf5VSHJ59Smf9c0OvrIR8oNpYdqYhbCBzepmvptjAAAAFQCwHkWRHhUCg8QLXKADLF3BDhy7HQAAAIBXoRdH/ZGqVRimOT9kH6WQ8KMVUsKtB8onymIz7IZgh+sIpD/G6wyBGQtIuqEa5CVaWOEIkgdvPc9NM/ruQUHPay9Z6RI/uDmrjxmeX8HOuiMGZmWN/6T6e6ooXZmSK2KVTyXieU+NkZ5cMrrFVXNHcpmaXzzc6y8+IgAf1b9hfwAAAIAPxU0kAZKbBGGo2p+T9KjOK27dXJG5fh+3nOZBzk91GRBK+2QR1jSd+ovliKChyH1CFWGbEEcjKrJ3emD3NdBUaAmy0+Am1ET9Rxn6uhVoit9woBOFfALtzeLewsjxPOo2+S/nHP1Pjom1hR4Uqx8VEfm8jwltOQNPa5zwCwuWgQ== test key diff --git a/spec/fixtures/id_dsa_as_open_ssl_pkey b/spec/fixtures/id_dsa_as_open_ssl_pkey new file mode 100644 index 0000000..8fb46df --- /dev/null +++ b/spec/fixtures/id_dsa_as_open_ssl_pkey @@ -0,0 +1,12 @@ +-----BEGIN PUBLIC KEY----- +MIIBtjCCASsGByqGSM44BAEwggEeAoGBAIow9ngW9u8mixTU61D5M6m1Ouv4oTny +Ntm1aNypeiRLJUsN4fFSqAZM4kyx8GR/VtonhfPGLF1LFguCZZAsh2V2Xin9b8NT +50AZEqv643ZfV3WXHftkGh8lmx+XYE22+UyWAf5VSHJ59Smf9c0OvrIR8oNpYdqY +hbCBzepmvptjAhUAsB5FkR4VAoPEC1ygAyxdwQ4cux0CgYBXoRdH/ZGqVRimOT9k +H6WQ8KMVUsKtB8onymIz7IZgh+sIpD/G6wyBGQtIuqEa5CVaWOEIkgdvPc9NM/ru +QUHPay9Z6RI/uDmrjxmeX8HOuiMGZmWN/6T6e6ooXZmSK2KVTyXieU+NkZ5cMrrF +VXNHcpmaXzzc6y8+IgAf1b9hfwOBhAACgYAPxU0kAZKbBGGo2p+T9KjOK27dXJG5 +fh+3nOZBzk91GRBK+2QR1jSd+ovliKChyH1CFWGbEEcjKrJ3emD3NdBUaAmy0+Am +1ET9Rxn6uhVoit9woBOFfALtzeLewsjxPOo2+S/nHP1Pjom1hR4Uqx8VEfm8jwlt +OQNPa5zwCwuWgQ== +-----END PUBLIC KEY----- diff --git a/spec/fixtures/id_ecdsa b/spec/fixtures/id_ecdsa new file mode 100644 index 0000000..bc348f5 --- /dev/null +++ b/spec/fixtures/id_ecdsa @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIBKpqV9kSisBTT15Ln8rExnQSaCGLvfU95iqZLR+KHmpoAoGCCqGSM49 +AwEHoUQDQgAEbZm3tQoVqG1ADReN+0/AEYlwGxT8juJ0azJwvmFAZquIrybjIfId +6c3qqHFYc2Ldsz0GZQlIqhsJFcuWhsyd3w== +-----END EC PRIVATE KEY----- diff --git a/spec/fixtures/id_ecdsa.pub b/spec/fixtures/id_ecdsa.pub new file mode 100644 index 0000000..efcc877 --- /dev/null +++ b/spec/fixtures/id_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBG2Zt7UKFahtQA0XjftPwBGJcBsU/I7idGsycL5hQGariK8m4yHyHenN6qhxWHNi3bM9BmUJSKobCRXLlobMnd8= test key diff --git a/spec/fixtures/id_rsa_as_open_ssl_pkey b/spec/fixtures/id_rsa_as_open_ssl_pkey new file mode 100644 index 0000000..6addd0f --- /dev/null +++ b/spec/fixtures/id_rsa_as_open_ssl_pkey @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4c7SGwMHroke/tg3BCd3 +iSxJpGXd6UZiq5D8XMbwogxrkLQV1+SNLsGSszwCf17ISRZaVzOQ7OB15p4Dy3f0 +V/XDOK6wT0aFnuiBqwdnsO0davI63WuAnGb7DEWQBlBz2V/GZ+L5HiBaykWxQ0WI +e6dpbIE6ozSgjGQ+Xs3iR1XazhytBf7O3bYRUI4qndWfSXgeIlOX+RjCXxSWExgG +0pu1YwMj17h6SPeqWT9NpS6tS7luxlCx9sr6QXpHKlKT9fQ44m07J8mfriG86SkG +XEUVogKCEkd1G8FhqfArbZwJydLnXUpZ3hWQ8crA5q9DwZGh2Mp+ANH8X/UxTkrl +gwIDAQAB +-----END PUBLIC KEY----- diff --git a/spec/lib/front_end_builds/utils/ssh_pubkey_convert_spec.rb b/spec/lib/front_end_builds/utils/ssh_pubkey_convert_spec.rb new file mode 100644 index 0000000..b404ea8 --- /dev/null +++ b/spec/lib/front_end_builds/utils/ssh_pubkey_convert_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' +require 'front_end_builds/utils/ssh_pubkey_convert' + +require'byebug' +module FrontEndBuilds + module Utils + RSpec.describe SSHPubKeyConvert do + describe '.convert' do + context "RSA Key" do + let(:public_key) { "spec/fixtures/id_rsa.pub" } + let(:output_pkey) { "spec/fixtures/id_rsa_as_open_ssl_pkey" } + + it "converts a RSA keys to a pkey as expected" do + key_contents = File.read(public_key) + expected_output = File.read(output_pkey).chomp + conversion_output = FrontEndBuilds::Utils::SSHPubKeyConvert.convert(key_contents).to_s.chomp + expect(conversion_output).to eq(expected_output) + end + end + + context "DSA Key" do + let(:public_key) { "spec/fixtures/id_dsa.pub" } + + it "throws an error if passed an id_ecdsa key" do + key_contents = File.read(public_key) + expect { + FrontEndBuilds::Utils::SSHPubKeyConvert.convert(key_contents).to_s.chomp + }.to raise_error('Unsupported key type: ssh-dss') + end + end + + context "ECDSA Key" do + let(:public_key) { "spec/fixtures/id_ecdsa.pub" } + + it "throws an error if passed an id_ecdsa key" do + key_contents = File.read(public_key) + expect { + FrontEndBuilds::Utils::SSHPubKeyConvert.convert(key_contents).to_s.chomp + }.to raise_error('Unsupported key type: ecdsa-sha2-nistp256') + end + end + end + end + end +end diff --git a/spec/models/front_end_builds/app_spec.rb b/spec/models/front_end_builds/app_spec.rb index 087dfc7..f57c321 100644 --- a/spec/models/front_end_builds/app_spec.rb +++ b/spec/models/front_end_builds/app_spec.rb @@ -2,7 +2,7 @@ module FrontEndBuilds describe App, :type => :model do - let(:app) { FactoryGirl.create(:front_end_builds_app) } + let(:app) { create(:front_end_builds_app) } it { should have_many(:builds) } it { should belong_to(:live_build) } @@ -10,7 +10,7 @@ module FrontEndBuilds describe '#recent_builds' do it 'should only show the 10 most recent builds' do - FactoryGirl.create_list(:front_end_builds_build, 11, { + create_list(:front_end_builds_build, 11, { app: app }) @@ -18,12 +18,12 @@ module FrontEndBuilds end it 'should order the builds with the most recent at top' do - older = FactoryGirl.create(:front_end_builds_build, { + older = create(:front_end_builds_build, { app: app, created_at: 2.days.ago }) - recent = FactoryGirl.create(:front_end_builds_build, { + recent = create(:front_end_builds_build, { app: app, created_at: 1.day.ago }) @@ -47,7 +47,7 @@ module FrontEndBuilds describe '#get_url' do it 'should lookup the url in the Apps url hash' do App.register_url('testing', '/testing') - app = FactoryGirl.create(:front_end_builds_app, name: 'testing') + app = create(:front_end_builds_app, name: 'testing') expect(app.get_url).to eq('/testing') end end diff --git a/spec/models/front_end_builds/build_spec.rb b/spec/models/front_end_builds/build_spec.rb index 27e761d..406a7ba 100644 --- a/spec/models/front_end_builds/build_spec.rb +++ b/spec/models/front_end_builds/build_spec.rb @@ -11,10 +11,10 @@ module FrontEndBuilds it { should validate_presence_of(:branch) } describe :find_best do - let(:app) { FactoryGirl.create :front_end_builds_app } + let(:app) { create :front_end_builds_app } let!(:latest) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha1', job: 'number1', @@ -24,7 +24,7 @@ module FrontEndBuilds end let!(:live_build) do - FactoryGirl.create :front_end_builds_build, :live, + create :front_end_builds_build, :live, app: app, sha: 'sha2', job: 'number2', @@ -34,7 +34,7 @@ module FrontEndBuilds end let!(:older) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha3', job: 'number3', @@ -45,7 +45,7 @@ module FrontEndBuilds context "with no query" do before(:each) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha4', branch: 'nonmaster', @@ -64,7 +64,7 @@ module FrontEndBuilds context "when finding the branch" do before(:each) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha3', branch: 'master', @@ -88,7 +88,7 @@ module FrontEndBuilds context "when finding unfetched build" do before(:each) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha3', branch: 'master', @@ -102,7 +102,7 @@ module FrontEndBuilds context "when finding another app" do before(:each) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, sha: 'sha4', branch: 'master', fetched: true, @@ -120,11 +120,11 @@ module FrontEndBuilds end describe '#verify' do - let(:app) { FactoryGirl.create(:front_end_builds_app, name: 'app') } + let(:app) { create(:front_end_builds_app, name: 'app') } let(:endpoint) { 'http://some.external.url.ted.com/index.html' } let(:build) do - FactoryGirl.build(:front_end_builds_build, { + FactoryBot.build(:front_end_builds_build, { app: app, endpoint: endpoint, signature: create_signature("#{app.name}-#{endpoint}") @@ -136,7 +136,7 @@ module FrontEndBuilds end it 'should be true if the signature can be verifed by a pubkey' do - FactoryGirl.create(:front_end_builds_pubkey, { + create(:front_end_builds_pubkey, { pubkey: ssh_pubkey }) @@ -149,11 +149,11 @@ module FrontEndBuilds end describe '#matching_pubkey' do - let(:app) { FactoryGirl.create(:front_end_builds_app, name: 'app') } + let(:app) { create(:front_end_builds_app, name: 'app') } let(:endpoint) { 'http://some.external.url.ted.com/index.html' } let(:build) do - FactoryGirl.build(:front_end_builds_build, { + FactoryBot.build(:front_end_builds_build, { app: app, endpoint: endpoint, signature: create_signature("#{app.name}-#{endpoint}") @@ -165,7 +165,7 @@ module FrontEndBuilds end it 'should have a pubkey if the signature can be verifed by a pubkey' do - pubkey = FactoryGirl.create(:front_end_builds_pubkey, { + pubkey = create(:front_end_builds_pubkey, { pubkey: ssh_pubkey }) @@ -178,9 +178,9 @@ module FrontEndBuilds end describe :live? do - let(:app) { FactoryGirl.create(:front_end_builds_app) } + let(:app) { create(:front_end_builds_app) } let!(:latest) do - FactoryGirl.create :front_end_builds_build, :live, + create :front_end_builds_build, :live, app: app, sha: 'sha1', job: 'number1', @@ -190,7 +190,7 @@ module FrontEndBuilds end let!(:older) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, sha: 'sha2', job: 'number2', @@ -209,14 +209,14 @@ module FrontEndBuilds end describe :master? do - let(:app) { FactoryGirl.create(:front_end_builds_app) } + let(:app) { create(:front_end_builds_app) } let(:build1) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, branch: 'master' end let(:build2) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, app: app, branch: 'feature' end @@ -232,7 +232,7 @@ module FrontEndBuilds describe '#setup!' do let(:build) do - FactoryGirl.create(:front_end_builds_build) + create(:front_end_builds_build) end before(:each) do @@ -252,7 +252,7 @@ module FrontEndBuilds it 'should not fetch if the build already has html' do expect(build).to_not receive(:fetch!) - build.update_attributes(html: 'got it') + build.update(html: 'got it') build.setup! end @@ -282,7 +282,7 @@ module FrontEndBuilds describe :fetch! do let(:app) do - FactoryGirl.create(:front_end_builds_app) + create(:front_end_builds_app) end before(:each) do @@ -295,7 +295,7 @@ module FrontEndBuilds end it "should fetch and load the html" do - build = FactoryGirl.create(:front_end_builds_build, + build = create(:front_end_builds_build, app: app, job: 'job1', sha: 'sha1', @@ -310,7 +310,7 @@ module FrontEndBuilds end it "should not fetch if it has already been fetched" do - build = FactoryGirl.create :front_end_builds_build, + build = create :front_end_builds_build, html: 'unchanged', fetched: true @@ -323,7 +323,7 @@ module FrontEndBuilds describe :with_head_tag do let(:build) do - FactoryGirl.create :front_end_builds_build, + create :front_end_builds_build, html: '' end diff --git a/spec/models/front_end_builds/pubkey_spec.rb b/spec/models/front_end_builds/pubkey_spec.rb index 63a5e55..9712db3 100644 --- a/spec/models/front_end_builds/pubkey_spec.rb +++ b/spec/models/front_end_builds/pubkey_spec.rb @@ -9,7 +9,7 @@ module FrontEndBuilds end let(:pubkey) do - FactoryGirl.create(:front_end_builds_pubkey, { + create(:front_end_builds_pubkey, { pubkey: ssh_public_key }) end @@ -24,7 +24,7 @@ module FrontEndBuilds end it 'should be unknown if it cannot figure out the pubkey' do - pubkey = FactoryGirl.create(:front_end_builds_pubkey, { + pubkey = create(:front_end_builds_pubkey, { pubkey: 'badinfo' }) @@ -45,7 +45,7 @@ module FrontEndBuilds end it 'should be false if the type of unknown' do - pubkey = FactoryGirl.create(:front_end_builds_pubkey, { + pubkey = create(:front_end_builds_pubkey, { pubkey: 'ssh-UNKNOWN badkeybutwhocares' }) @@ -53,7 +53,7 @@ module FrontEndBuilds end it 'should be false if the key has no base64 encoded part' do - pubkey = FactoryGirl.create(:front_end_builds_pubkey, { + pubkey = create(:front_end_builds_pubkey, { pubkey: 'someotherkeyformat' }) @@ -71,23 +71,23 @@ module FrontEndBuilds end it 'should raise an error if it cannot convert' do - pubkey = FactoryGirl.create(:front_end_builds_pubkey, { + pubkey = create(:front_end_builds_pubkey, { pubkey: 'badkey' }) - expect { pubkey.to_rsa_pkey }.to raise_error + expect { pubkey.to_rsa_pkey }.to raise_error( ArgumentError, "Invalid SSH public key 'badkey'" ) end end describe '#verify' do let(:app) do - FactoryGirl.create(:front_end_builds_app, name: 'app') + create(:front_end_builds_app, name: 'app') end let(:endpoint) { 'http://some.external.url.ted.com/index.html' } let(:build) do - FactoryGirl.build(:front_end_builds_build, { + FactoryBot.build(:front_end_builds_build, { app: app, endpoint: endpoint }) @@ -99,7 +99,7 @@ module FrontEndBuilds end it 'should verify the signature + html for a build without an endpoint' do - build = FactoryGirl.create(:front_end_builds_build, { + build = create(:front_end_builds_build, { app: app, html: 'some html', endpoint: nil, @@ -115,7 +115,7 @@ module FrontEndBuilds end it 'should not verify a bad html signature for a build' do - build = FactoryGirl.create(:front_end_builds_build, { + build = create(:front_end_builds_build, { app: app, html: 'some html', endpoint: nil, @@ -127,19 +127,19 @@ module FrontEndBuilds end describe '#last_build' do - let(:pubkey) { FactoryGirl.create(:front_end_builds_pubkey) } + let(:pubkey) { create(:front_end_builds_pubkey) } it 'should be nil if this pubkey was never used in a build' do expect(pubkey.last_build).to be_nil end it 'should be the most recently created build' do - build = FactoryGirl.create(:front_end_builds_build, { + build = create(:front_end_builds_build, { pubkey: pubkey, created_at: 2.hours.ago }) - FactoryGirl.create(:front_end_builds_build, { + create(:front_end_builds_build, { pubkey: pubkey, created_at: 3.hours.ago }) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5e91200..0bee98f 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -4,9 +4,10 @@ require 'rspec/rails' require 'rspec/its' -require 'factory_girl_rails' +require 'factory_bot_rails' require 'shoulda/matchers' require 'webmock/rspec' +require 'database_cleaner' Rails.backtrace_cleaner.remove_silencers! @@ -24,4 +25,8 @@ config.include JsonParser, type: :controller config.include JsonParser, type: :request config.include CreateSignature + + # make create & build available directly. + # FactoryBot.create(:foo) -> create(:foo) + config.include FactoryBot::Syntax::Methods end diff --git a/spec/requests/admin_api_requests_spec.rb b/spec/requests/admin_api_requests_spec.rb index c8b67b0..12021c6 100644 --- a/spec/requests/admin_api_requests_spec.rb +++ b/spec/requests/admin_api_requests_spec.rb @@ -1,13 +1,15 @@ +require 'rails_helper' + describe 'The API for the admin section should work', type: :request do it 'should load the admin' do get '/frontend-config' - expect(response).to be_success + expect(response.successful?).to be true expect(response.body).to match('Admin') end it "should respond to the admin's API requests" do get '/frontend-config/api/host_apps/current.json' - expect(response).to be_success - expect(json['host_app']['name']).to eq('Dummy') + expect(response.successful?).to be true + expect(json['host_app']['name']).to eq('dummy') end end diff --git a/spec/requests/admin_assets_spec.rb b/spec/requests/admin_assets_spec.rb index 14df71b..d075761 100644 --- a/spec/requests/admin_assets_spec.rb +++ b/spec/requests/admin_assets_spec.rb @@ -14,7 +14,7 @@ it 'should return the js file' do get admin_javascript_url - expect(response).to be_success + expect(response.successful?).to be true expect(response.body[0..1000]).to eq(admin_javascript_content[0..1000]) end end diff --git a/spec/requests/api_requests_spec.rb b/spec/requests/api_requests_spec.rb index cf3a896..ef8179a 100644 --- a/spec/requests/api_requests_spec.rb +++ b/spec/requests/api_requests_spec.rb @@ -1,8 +1,8 @@ describe 'It should not intercept API requests', type: :request do - let(:front_end_app) { FactoryGirl.create :front_end_builds_app, name: "dummy" } + let(:front_end_app) { create :front_end_builds_app, name: "dummy" } let!(:build) do - FactoryGirl.create(:front_end_builds_build, :live, + create(:front_end_builds_build, :live, app: front_end_app, fetched: true, active: true @@ -11,12 +11,12 @@ it "should get the build" do get "/dummy" - expect(response).to be_success + expect(response.successful?).to be true end it "should allow api requests to come through" do get "/items/1.json" - expect(response).to be_success + expect(response.successful?).to be true expect(JSON.parse(response.body)['it']).to eq('worked') end end diff --git a/spec/requests/build_spec.rb b/spec/requests/build_spec.rb index 9db4fee..f1bf46a 100644 --- a/spec/requests/build_spec.rb +++ b/spec/requests/build_spec.rb @@ -1,47 +1,51 @@ require 'rails_helper' describe "Front end builds API", type: :request do - let!(:front_end_app) { FactoryGirl.create :front_end_builds_app, name: "dummy" } + let!(:front_end_app) { create :front_end_builds_app, name: "dummy" } let(:endpoint) { "http://www.ted.com/builds/1" } before(:each) do stub_request(:get, endpoint) .to_return(body: 'your app!') - FactoryGirl.create(:front_end_builds_pubkey, :fixture_pubkey) + create(:front_end_builds_pubkey, :fixture_pubkey) end it "creates a new build and then uses it" do post "/dummy", - branch: "master", - sha: "a1b2c3", - job: "jenkins-build-1", - endpoint: endpoint, - signature: create_signature("dummy-#{endpoint}") + params: { + branch: "master", + sha: "a1b2c3", + job: "jenkins-build-1", + endpoint: endpoint, + signature: create_signature("dummy-#{endpoint}") + } - expect(response).to be_success + expect(response.successful?).to be true # Index loads get "/dummy" - expect(response).to be_success + expect(response.successful?).to be true expect(response.body).to match(/your app!$/) # Deep routes load get "/dummy/posts/1" - expect(response).to be_success + expect(response.successful?).to be true expect(response.body).to match(/your app!$/) end it "should be able to create a build from a generic endpoint" do post "/front_end_builds/builds", - app_name: 'dummy', - branch: "master", - sha: "a1b2c3", - job: "jenkins-build-1", - endpoint: endpoint, - signature: create_signature("dummy-#{endpoint}") - - expect(response).to be_success + params: { + app_name: 'dummy', + branch: "master", + sha: "a1b2c3", + job: "jenkins-build-1", + endpoint: endpoint, + signature: create_signature("dummy-#{endpoint}") + } + + expect(response.successful?).to be true expect(front_end_app.builds.length).to eq(1) expect(front_end_app.builds.first.html).to eq('your app!') end diff --git a/spec/requests/new_build_version_spec.rb b/spec/requests/new_build_version_spec.rb index 4f186f0..4c2dfa4 100644 --- a/spec/requests/new_build_version_spec.rb +++ b/spec/requests/new_build_version_spec.rb @@ -1,18 +1,19 @@ require 'rails_helper' describe "Front end builds new version", type: :request do - let(:front_end_app) { FactoryGirl.create :front_end_builds_app, name: "dummy" } + let(:front_end_app) { create :front_end_builds_app, name: "dummy" } let(:version_url) { "/front_end_builds/best?app_name=dummy&branch=master" } let(:endpoint) { "http://www.ted.com/builds/1" } + let(:headers) { { 'ACCEPT' => 'application/json' } } before(:each) do - FactoryGirl.create( + create( :front_end_builds_build, :fetched, app: front_end_app, ) - FactoryGirl.create(:front_end_builds_pubkey, :fixture_pubkey) + create(:front_end_builds_pubkey, :fixture_pubkey) stub_request(:get, endpoint) .to_return(body: 'your app!') @@ -20,25 +21,27 @@ it "gets a different version when a new build is created" do # get the current version - get version_url, format: :json - expect(response).to be_success - expect(json['version']).to_not be_nil + get version_url, headers: headers + expect(response.successful?).to be true + expect(json['version']).to_not be nil original_version = json['version'] post "/dummy", - branch: "master", - sha: "a1b2c3", - job: "jenkins-build-1", - endpoint: endpoint, - signature: create_signature("dummy-#{endpoint}") + params: { + branch: "master", + sha: "a1b2c3", + job: "jenkins-build-1", + endpoint: endpoint, + signature: create_signature("dummy-#{endpoint}") + } - expect(response).to be_success + expect(response.successful?).to be true # now we should get a new version - get version_url, format: :json - expect(response).to be_success - expect(json['version']).to_not be_nil + get version_url, headers: headers + expect(response.successful?).to be true + expect(json['version']).to_not be nil new_version = json['version'] diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb new file mode 100644 index 0000000..32f1a29 --- /dev/null +++ b/spec/support/database_cleaner.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +RSpec.configure do |config| + config.before(:suite) do + DatabaseCleaner.strategy = :transaction + DatabaseCleaner.clean_with(:truncation) + end + + config.around(:each) do |example| + DatabaseCleaner.cleaning do + example.run + end + end +end