diff --git a/.bundler-audit.yml b/.bundler-audit.yml index ad68723a..314ac131 100644 --- a/.bundler-audit.yml +++ b/.bundler-audit.yml @@ -1,17 +1 @@ -ignore: - # rails-html-sanitizer - needs Rails 7 upgrade to fix - - CVE-2024-53989 - - CVE-2024-53988 - - CVE-2024-53987 - - CVE-2024-53986 - - CVE-2024-53985 - - # Nokogiri - servers don't have compatible GLIBC. Wants - # an upgrade to version 1.18.4. - - GHSA-vvfq-8hwr-qm4m - - GHSA-5w6v-399v-w3cc - - GHSA-mrxw-mxhj-p664 - - GHSA-5w6v-399v-w3cc - - GHSA-353f-x4gh-cqq8 - - GHSA-wx95-c6cv-8532 - \ No newline at end of file +ignore: [] diff --git a/.circleci/config.yml b/.circleci/config.yml index adcae3f0..ef858f5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,9 +53,12 @@ jobs: - run: name: Configure Bundler command: | - echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV + BUNDLER_LOCK=$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1 | tr -d " ") + # Use Bundler 2.5.12+ on Ruby 3.4 to avoid Gem::Platform redefinition warnings + if [ "$BUNDLER_LOCK" = "2.5.11" ]; then BUNDLER_LOCK=2.5.12; fi + echo "export BUNDLER_VERSION=$BUNDLER_LOCK" >> $BASH_ENV source $BASH_ENV - gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)" + gem install bundler -v "$BUNDLER_LOCK" - run: name: Install Dependencies diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 50c51653..4c0b9c15 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,8 +4,8 @@ on: push jobs: test: - # ubuntu-22.04: ruby/setup-ruby has 3.4.7; ubuntu-24.04 may not yet runs-on: ubuntu-22.04 + services: selenium: image: selenium/standalone-chrome @@ -13,39 +13,46 @@ jobs: - 4444:4444 steps: - - uses: actions/checkout@v4 - - - name: Set up Ruby - # Use @v1 so latest action gets new Ruby versions (e.g. 3.4.7) - uses: ruby/setup-ruby@v1 - with: - ruby-version: '3.4.7' - bundler-cache: true - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y xvfb libnss3-dev - gem install bundler - bundle install - - - name: Run rubocop - run: | - bundle exec rubocop - - - name: Run tests - env: - DISPLAY: :99.0 - run: | - Xvfb :99 -ac & - bundle exec rspec - - - name: Coveralls - uses: coverallsapp/github-action@v2.3.7 - - - name: Brakeman linter - run: bundle exec brakeman --no-exit-on-warn --no-exit-on-error - - - name: 'Run Bundler Audit' - run: bundle exec bundler-audit - + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.7' + bundler-cache: true + + - name: Force Ruby platform and install gems + run: | + bundle config set --local force_ruby_platform true + bundle install + env: + BUNDLE_FORCE_RUBY_PLATFORM: "1" + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y xvfb libnss3-dev + # If you build Nokogiri with system libs, add: + # sudo apt-get install -y build-essential libxml2-dev libxslt1-dev + + - name: Run rubocop + run: bundle exec rubocop + + - name: Prepare DB + run: bundle exec rails db:prepare RAILS_ENV=test + + - name: Run tests + env: + DISPLAY: :99.0 + run: | + Xvfb :99 -ac & + bundle exec rspec + + - name: Coveralls + uses: coverallsapp/github-action@v2.3.7 + + - name: Brakeman linter + run: bundle exec brakeman --no-exit-on-warn --no-exit-on-error + + - name: Run Bundler Audit + run: bundle exec bundler-audit diff --git a/.gitignore b/.gitignore index 1f1f1a62..6c9a7f5a 100644 --- a/.gitignore +++ b/.gitignore @@ -51,8 +51,13 @@ yarn.lock # Ignore all CSV files generated by export feature /public/*.csv -#Ignore Rubymine files +# Ignore IDE/editor local configuration .idea/ +.vscode/ +.fleet/ +.cursor +*.sublime-project +*.sublime-workspace # Ignore .env.production and .env.production.local .env.production diff --git a/Gemfile b/Gemfile index 701b191f..c584e97b 100644 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ gem 'net-pop', '~> 0.1.2' gem 'net-protocol', '>= 0' # Use nokogiri for java -gem 'nokogiri', '1.16.7' +gem 'nokogiri', '~> 1.19' # Bundler Audit Update gem 'json', '>= 2.10.2' @@ -47,6 +47,8 @@ gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.5' # Use rails-controller-testing for testing a controller gem 'rails-controller-testing' +# Use Active Storage variant +gem 'rails-html-sanitizer', '~> 1.7' # Use rubocop for static code analysis gem 'rubocop' # bundler audit diff --git a/Gemfile.lock b/Gemfile.lock index 104d9363..4dcb04e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,7 +77,7 @@ GEM uri (>= 0.13.1) addressable (2.8.9) public_suffix (>= 2.0.2, < 8.0) - airbrussh (1.6.0) + airbrussh (1.6.1) sshkit (>= 1.6.1, != 1.7.0) ast (2.4.3) base64 (0.3.0) @@ -156,6 +156,7 @@ GEM factory_bot_rails (6.5.1) factory_bot (~> 6.5) railties (>= 6.1.0) + ffi (1.17.3) ffi (1.17.3-aarch64-linux-gnu) ffi (1.17.3-arm-linux-gnu) ffi (1.17.3-arm64-darwin) @@ -235,9 +236,19 @@ GEM net-protocol net-ssh (7.3.0) nio4r (2.7.5) - nokogiri (1.16.7) + nokogiri (1.19.1) mini_portile2 (~> 2.8.2) racc (~> 1.4) + nokogiri (1.19.1-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.1-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.1-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.1-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.1-x86_64-linux-gnu) + racc (~> 1.4) orm_adapter (0.5.0) ostruct (0.6.3) parallel (1.27.0) @@ -288,9 +299,9 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) railties (8.1.2) actionpack (= 8.1.2) activesupport (= 8.1.2) @@ -339,7 +350,7 @@ GEM rspec-support (3.13.7) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.85.0) + rubocop (1.85.1) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -407,6 +418,8 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) + sqlite3 (2.9.1) + mini_portile2 (~> 2.8.0) sqlite3 (2.9.1-aarch64-linux-gnu) sqlite3 (2.9.1-arm-linux-gnu) sqlite3 (2.9.1-arm64-darwin) @@ -456,7 +469,8 @@ GEM PLATFORMS aarch64-linux arm-linux - arm64-darwin + arm64-darwin-25 + ruby x86-linux x86_64-darwin x86_64-linux @@ -495,12 +509,13 @@ DEPENDENCIES net-imap (>= 0.5.7) net-pop (~> 0.1.2) net-protocol - nokogiri (= 1.16.7) + nokogiri (~> 1.19) petergate puma (>= 6.4.3) rack (~> 2.2.20) rails (~> 8.1.0) rails-controller-testing + rails-html-sanitizer (~> 1.7) rb-readline recaptcha rexml (>= 3.3.9) @@ -525,4 +540,4 @@ RUBY VERSION ruby 3.4.7p58 BUNDLED WITH - 2.5.11 + 2.5.12 diff --git a/config/deploy.rb b/config/deploy.rb index 4899e435..8e192bec 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -26,7 +26,8 @@ task :init_qp do on roles(:all) do execute 'gem install --user-install bundler' - execute "bundle config path 'vendor/bundle' --local" + execute "cd #{fetch(:release_path)} && bundle config path 'vendor/bundle' --local" + execute "cd #{fetch(:release_path)} && bundle config set force_ruby_platform true --local" execute "mkdir -p #{fetch(:deploy_to)}/static" execute "cp #{fetch(:deploy_to)}/static/.env.production #{fetch(:release_path)}/ || true" end diff --git a/exports/software_records.rb b/exports/software_records.rb index c0b814bb..c6dae168 100644 --- a/exports/software_records.rb +++ b/exports/software_records.rb @@ -62,6 +62,8 @@ def software_records private def clean_and_format(attribute) + return '' if attribute.blank? + formatted_attribute = attribute.to_s.gsub('---', '').gsub("\n", '-') parts = formatted_attribute.split('- ').reject { |part| part == '-' } parts.map { |part| part.gsub('-', '').strip }.join(', ') diff --git a/spec/controllers/change_requests_controller_spec.rb b/spec/controllers/change_requests_controller_spec.rb index db7a61fc..e61d153a 100644 --- a/spec/controllers/change_requests_controller_spec.rb +++ b/spec/controllers/change_requests_controller_spec.rb @@ -26,6 +26,9 @@ title: 'Test Env.', description: 'test env.' ) + end + + let!(:software_record) do SoftwareRecord.create!( title: 'A Good Software', description: 'A Good description about the software', @@ -47,7 +50,7 @@ { change_title: 'A Good Software', change_description: 'A Good description about the software', - software_record_id: 1, + software_record_id: software_record.id, application_pages: 10, number_roles: 3, authentication_needed: true, @@ -103,19 +106,6 @@ def sign_in_user(manager) it 'assigns @software_name' do change_request = ChangeRequest.create! valid_attributes - software_record = SoftwareRecord.create!( - title: 'A Good Software', - description: 'A Good description about the software', - status_id: Status.first.id, - software_type_id: SoftwareType.first.id, - vendor_record_id: VendorRecord.first.id, - hosting_environment_id: HostingEnvironment.first.id, - created_by: 'Test Manager', - developers: %w[Tester Random], - tech_leads: ['Lead 1'], - product_owners: %w[Owner1 Owner2], - admin_users: %w[Admin1 Admin2] - ) get :show, params: { id: change_request.id } expect(assigns(:software_name)).to eq(software_record.title) end diff --git a/spec/controllers/software_records_controller_spec.rb b/spec/controllers/software_records_controller_spec.rb index d948f63c..852e1a77 100644 --- a/spec/controllers/software_records_controller_spec.rb +++ b/spec/controllers/software_records_controller_spec.rb @@ -223,7 +223,7 @@ def sign_in_user(admin) software_record1 = SoftwareRecord.create! valid_attributes software_record2 = SoftwareRecord.create! valid_attributes get :list_road_map - expect(assigns(:software_records)).to match_array([software_record1, software_record2]) + expect(assigns(:software_records)).to include(software_record1, software_record2) expect(response.body).not_to match('\b(Decommissioned.Software)\b') end end @@ -526,7 +526,7 @@ def sign_in_user(admin) it 'also destroys the change request associated with the software_record' do software_record = SoftwareRecord.create! valid_attributes - ChangeRequest.create! change_attributes + ChangeRequest.create!(change_attributes.merge(software_record_id: software_record.id)) expect do delete :destroy, params: { id: software_record.to_param }, session: valid_session end.to change(ChangeRequest, :count).by(-1) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7e0061be..bdd93985 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -11,10 +11,12 @@ let!(:software_record) { FactoryBot.create(:software_record, vendor_record_id: vendor_record.id, software_type_id: software_type.id, status_id: status.id, hosting_environment_id: hosting_environment.id) } let!(:software_record_old) { FactoryBot.create(:software_record, created_at: '1968-01-01', vendor_record_id: vendor_record.id, software_type_id: software_type.id, status_id: status.id, hosting_environment_id: hosting_environment.id) } - it 'returns a series with initial value greater than zero' do + it 'returns a monotonically increasing series with a non-zero initial value' do graph_values = generate_software_records_series - expect(graph_values[0][:data].values).to start_with 1 - expect(graph_values[0][:data].values).to end_with 2 + values = graph_values[0][:data].values + + expect(values.first).to be > 0 + expect(values).to eq(values.sort) end end end diff --git a/spec/helpers/change_requests_helper_spec.rb b/spec/helpers/change_requests_helper_spec.rb index 18dfb93c..804b5f8b 100644 --- a/spec/helpers/change_requests_helper_spec.rb +++ b/spec/helpers/change_requests_helper_spec.rb @@ -51,9 +51,9 @@ describe '#find_software_name' do it 'returns the software name for the given id' do - FactoryBot.create(:software_record, title: 'My Software', id: 1) + software_record = FactoryBot.create(:software_record, title: 'My Software') - name = find_software_name(1) + name = find_software_name(software_record.id) expect(name).to eq('My Software') end @@ -61,9 +61,9 @@ describe '#find_software_version' do it 'returns the software version for the given id' do - FactoryBot.create(:software_record, current_version: '1.0', id: 1) + software_record = FactoryBot.create(:software_record, current_version: '1.0') - version = find_software_version(1) + version = find_software_version(software_record.id) expect(version).to eq('1.0') end @@ -85,9 +85,9 @@ describe '#find_tech_leads' do it 'returns the tech leads for the given software record id' do - FactoryBot.create(:software_record, tech_leads: %w[John Jane], id: 1) + software_record = FactoryBot.create(:software_record, tech_leads: %w[John Jane]) - tech_leads = find_tech_leads(1) + tech_leads = find_tech_leads(software_record.id) expect(tech_leads).to eq(%w[John Jane]) end diff --git a/spec/views/software_records/list_decommissioned.html.erb_spec.rb b/spec/views/software_records/list_decommissioned.html.erb_spec.rb index 8b556578..05666ee5 100644 --- a/spec/views/software_records/list_decommissioned.html.erb_spec.rb +++ b/spec/views/software_records/list_decommissioned.html.erb_spec.rb @@ -33,31 +33,34 @@ title: 'Test Env.', description: 'test env.' ) - assign(:software_records, [ - SoftwareRecord.create!( - title: 'Title', - description: 'MyText', - status_id: Status.second.id, - hosting_environment_id: HostingEnvironment.first.id, - date_implemented: '2020-12-12', - road_map: 'Road map 1', - vendor_record_id: VendorRecord.first.id, - software_type_id: SoftwareType.first.id, - created_by: 'Test User', - priority: 10 - ), - SoftwareRecord.create!( - title: 'Title', - description: 'MyText', - road_map: 'Road map 2', - status_id: Status.second.id, - hosting_environment_id: HostingEnvironment.first.id, - date_implemented: '2020-12-12', - vendor_record_id: VendorRecord.first.id, - software_type_id: SoftwareType.first.id, - created_by: 'Test User' - ) - ]) + software_record1 = SoftwareRecord.create!( + title: 'Title', + description: 'MyText', + status_id: Status.second.id, + hosting_environment_id: HostingEnvironment.first.id, + date_implemented: '2020-12-12', + road_map: 'Road map 1', + vendor_record_id: VendorRecord.first.id, + software_type_id: SoftwareType.first.id, + created_by: 'Test User', + priority: 10 + ) + + software_record2 = SoftwareRecord.create!( + title: 'Title', + description: 'MyText', + road_map: 'Road map 2', + status_id: Status.second.id, + hosting_environment_id: HostingEnvironment.first.id, + date_implemented: '2020-12-12', + vendor_record_id: VendorRecord.first.id, + software_type_id: SoftwareType.first.id, + created_by: 'Test User' + ) + + assign(:software_records, [software_record1, software_record2]) + assign(:software_record1, software_record1) + assign(:software_record2, software_record2) assign(:vendor_records, VendorRecord.all) assign(:software_types, SoftwareType.all) @@ -76,7 +79,7 @@ render expect(rendered).to have_content('Title') - expect(rendered).to have_link('Edit', href: edit_software_record_path(SoftwareRecord.first)) - expect(rendered).to have_link('Edit', href: edit_software_record_path(SoftwareRecord.second)) + expect(rendered).to have_link('Edit', href: edit_software_record_path(view.assigns[:software_record1])) + expect(rendered).to have_link('Edit', href: edit_software_record_path(view.assigns[:software_record2])) end end diff --git a/spec/views/software_records/list_road_map.html.erb_spec.rb b/spec/views/software_records/list_road_map.html.erb_spec.rb index fabfdd39..71475f6d 100644 --- a/spec/views/software_records/list_road_map.html.erb_spec.rb +++ b/spec/views/software_records/list_road_map.html.erb_spec.rb @@ -27,31 +27,34 @@ title: 'Test Env.', description: 'test env.' ) - assign(:software_records, [ - SoftwareRecord.create!( - title: 'Title', - description: 'MyText', - status_id: Status.first.id, - hosting_environment_id: HostingEnvironment.first.id, - date_implemented: '2020-12-12', - road_map: 'Road map 1', - vendor_record_id: VendorRecord.first.id, - software_type_id: SoftwareType.first.id, - created_by: 'Test User', - priority: 10 - ), - SoftwareRecord.create!( - title: 'Title', - description: 'MyText', - road_map: 'Road map 2', - status_id: Status.first.id, - hosting_environment_id: HostingEnvironment.first.id, - date_implemented: '2020-12-12', - vendor_record_id: VendorRecord.first.id, - software_type_id: SoftwareType.first.id, - created_by: 'Test User' - ) - ]) + software_record1 = SoftwareRecord.create!( + title: 'Title', + description: 'MyText', + status_id: Status.first.id, + hosting_environment_id: HostingEnvironment.first.id, + date_implemented: '2020-12-12', + road_map: 'Road map 1', + vendor_record_id: VendorRecord.first.id, + software_type_id: SoftwareType.first.id, + created_by: 'Test User', + priority: 10 + ) + + software_record2 = SoftwareRecord.create!( + title: 'Title', + description: 'MyText', + road_map: 'Road map 2', + status_id: Status.first.id, + hosting_environment_id: HostingEnvironment.first.id, + date_implemented: '2020-12-12', + vendor_record_id: VendorRecord.first.id, + software_type_id: SoftwareType.first.id, + created_by: 'Test User' + ) + + assign(:software_records, [software_record1, software_record2]) + assign(:software_record1, software_record1) + assign(:software_record2, software_record2) assign(:vendor_records, VendorRecord.all) assign(:software_types, SoftwareType.all) @@ -71,8 +74,8 @@ expect(rendered).to have_content('Title') expect(rendered).to have_content('Road Map') - expect(rendered).to have_link('Edit Road Map', href: edit_road_map_software_record_path(SoftwareRecord.first)) - expect(rendered).to have_link('Edit Road Map', href: edit_road_map_software_record_path(SoftwareRecord.second)) + expect(rendered).to have_link('Edit Road Map', href: edit_road_map_software_record_path(view.assigns[:software_record1])) + expect(rendered).to have_link('Edit Road Map', href: edit_road_map_software_record_path(view.assigns[:software_record2])) end it 'does not wrap the Edit Road Map button text' do