diff --git a/.github/workflows/static_code_analysis.yml b/.github/workflows/static_code_analysis.yml new file mode 100644 index 00000000..55c2b7d6 --- /dev/null +++ b/.github/workflows/static_code_analysis.yml @@ -0,0 +1,69 @@ +--- +name: Static Code Analysis + +on: [pull_request] + +jobs: + brakeman: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + Bundle + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Run Brakeman analysis + run: bundle exec brakeman --parser-timeout 60 + + bundle-audit: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + Bundle + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Audit the bundle + # Ignore bootstrap version 3 warning: https://nhsd-jira.digital.nhs.uk/browse/NDRS2-1676 + run: bundle exec bundle-audit check --update --ignore CVE-2024-6484 + # run: bundle exec bundle-audit check --update + + notify: + # Run only on main, but regardless of whether tests past: + if: ${{ always() }} + # if: ${{ always() && github.ref == 'refs/heads/main' }} + + needs: + - brakeman + - bundle-audit + + runs-on: ubuntu-latest + + steps: + - uses: 8398a7/action-slack@v3 + with: + status: custom + fields: workflow,commit,author + custom_payload: | + { + channel: '${{ secrets.SLACK_CHANNEL }}', + username: 'GitHub CI', + icon_emoji: ':robot_face:', + attachments: [{ + text: '${{ github.event.commits[0].message }}', + fields: [ + { title: 'Author', value: '${{ github.actor }}', short: true }, + { title: 'Revision', value: '${{ github.sha }}', short: true } + ] + },{ + color: '${{ needs.brakeman.result }}' === 'success' ? 'good' : '${{ needs.brakeman.result }}' === 'failure' ? 'danger' : 'warning', + text: `Brakeman checks returned *${{ needs.brakeman.result }}*.` + },{ + color: '${{ needs.bundle-audit.result }}' === 'success' ? 'good' : '${{ needs.bundle-audit.result }}' === 'failure' ? 'danger' : 'warning', + text: `Bundle Audit checks returned *${{ needs.bundle-audit.result }}*.` + }] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 71973e5b..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,133 +0,0 @@ -name: Test - -on: [pull_request] - -jobs: - test: - strategy: - matrix: - ruby-version: - - '3.1.6' - # - '3.2' # Not yet tested on CentOS 7. Ideally move to rails 7.0 first - - name: Ruby ${{ matrix.ruby-version }} - - runs-on: ubuntu-latest - - services: - postgres: - image: postgres - env: - POSTGRES_USER: rails - POSTGRES_PASSWORD: rails_password - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - env: - DB_HOST: localhost - DB_PORT: 5432 - DB_USERNAME: rails - DB_PASSWORD: rails_password - - # Prep the whole stack in test-only mode: - RAILS_ENV: test - - steps: - - uses: actions/checkout@v2 - - name: Set up Ruby + Bundle - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - ruby-version: ${{ matrix.ruby-version }} - - name: Inject configuration - run: cp config/database.yml{.ci,} - - name: Prepare the database - run: bin/rails db:setup - - name: Precompile assets - # Since ruby/setup-ruby@v1 moved to Node.js v18 we need the extra options - # until we move to newer webpacker / stop using it. - # I've tried using a newer hash function in config/webpack/environment.js - # by adding the following line, but this didn't help with github actions - # # environment.config.set('output.hashFunction', 'sha256') - # https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported/73465262#73465262 - run: NODE_OPTIONS=--openssl-legacy-provider bin/rails yarn:install assets:clobber assets:precompile - - name: Run tests - run: bin/rails test - - brakeman: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Ruby + Bundle - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - - name: Run Brakeman analysis - run: bundle exec brakeman - - bundle-audit: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Ruby + Bundle - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - - name: Audit the bundle - # Ignore bootstrap version 3 warning: https://nhsd-jira.digital.nhs.uk/browse/NDRS2-1676 - run: bundle exec bundle-audit check --update --ignore CVE-2024-6484 - # run: bundle exec bundle-audit check --update - - # A utility job upon which Branch Protection can depend, - # thus remaining agnostic of the matrix. - test_matrix: - if: ${{ always() }} - runs-on: ubuntu-latest - name: Matrix - needs: test - steps: - - name: Check build matrix status - if: ${{ needs.test.result != 'success' }} - run: exit 1 - - notify: - # Run only on master, but regardless of whether tests past: - if: ${{ always() && github.ref == 'refs/heads/master' }} - - needs: - - test_matrix - - brakeman - - bundle-audit - - runs-on: ubuntu-latest - - steps: - - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,commit,author - custom_payload: | - { - channel: 'CSEPN7EES', - username: 'CI', - icon_emoji: ':hammer_and_wrench:', - attachments: [{ - color: '${{ needs.test.result }}' === 'success' ? 'good' : '${{ needs.test.result }}' === 'failure' ? 'danger' : 'warning', - text: `${process.env.AS_WORKFLOW} against \`${{ github.ref }}\` (${process.env.AS_COMMIT}) for ${{ github.actor }} resulted in *${{ needs.test.result }}*.` - },{ - color: '${{ needs.brakeman.result }}' === 'success' ? 'good' : '${{ needs.brakeman.result }}' === 'failure' ? 'danger' : 'warning', - text: `Brakeman checks returned *${{ needs.brakeman.result }}*.` - },{ - color: '${{ needs.bundle-audit.result }}' === 'success' ? 'good' : '${{ needs.bundle-audit.result }}' === 'failure' ? 'danger' : 'warning', - text: `Bundle Audit checks returned *${{ needs.bundle-audit.result }}*.` - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..a3984e3d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,154 @@ +--- +# This file is @generated by `bin/rails generate test_strategy test_strategy_timings.csv` +# Please edit the template and regenerate, rather than edit this file. + +name: Tests + +on: [pull_request] + +permissions: + contents: read + actions: read + +jobs: + remaining_test_matrix: + strategy: + fail-fast: false + matrix: + ruby-version: + - '3.1.6' + test-group: + - "[a-b]" + - "[c]" + - "[d-m]" + - "[n-z]" + + name: "Ruby ${{ matrix.ruby-version }} Tests (${{ matrix.test-group }})" + + runs-on: ubuntu-latest + + services: + postgres: + image: postgres + env: + POSTGRES_USER: rails + POSTGRES_PASSWORD: rails_password + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + --name postgres + ports: + - 5432:5432 + + env: + DB_HOST: localhost + DB_PORT: 5432 + DB_USERNAME: rails + DB_PASSWORD: rails_password + + # Prep the whole stack in test-only mode: + RAILS_ENV: test + + steps: + - uses: actions/checkout@v3 + - name: Set timezone to Europe/London + run: sudo timedatectl set-timezone Europe/London + - name: Use bundled npm files + run: printf 'disable-self-update-check true\nyarn-offline-mirror "./vendor/npm-packages-offline-cache"\nyarn-offline-mirror-pruning false\n' > .yarnrc + - name: Set up Ruby + Bundle + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: ${{ matrix.ruby-version }} + - name: Inject configuration + run: cp config/database.yml{.ci,} + - name: Prepare the database + run: bin/rails db:setup + - name: Precompile assets + # Since ruby/setup-ruby@v1 moved to Node.js v18 we need the extra options + # until we move to newer webpacker / stop using it. + # I've tried using a newer hash function in config/webpack/environment.js + # by adding the following line, but this didn't help with github actions + # # environment.config.set('output.hashFunction', 'sha256') + # https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported/73465262#73465262 + run: NODE_OPTIONS=--openssl-legacy-provider bin/rails yarn:install assets:clobber assets:precompile + - name: Run tests + run: PARALLEL_WORKERS=1 bin/rails test 'test/**/${{ matrix.test-group }}*_test.rb' + + # A utility job upon which Branch Protection can depend, + # thus remaining agnostic of the matrix. + remaining_tests: + if: ${{ always() }} + runs-on: ubuntu-latest + # name: Matrix + needs: remaining_test_matrix + steps: + - name: Check build matrix status + if: ${{ needs.remaining_test_matrix.result != 'success' }} + run: exit 1 + + notify: + # Run only on master, but regardless of whether tests past: + if: ${{ always() }} + # if: ${{ always() && github.ref == 'refs/heads/master' }} + + needs: + - remaining_tests + + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-node@v3 + # with: + # node-version: '16.x' + - id: slack-payload-generator + env: + COMMIT_MESSAGE: ${{ github.event.commits[0].message }} + run: |- + node -e " + const passed = '${{ needs.integration_tests.result }}' === 'success' && '${{ needs.models_tests.result }}' === 'success' && '${{ needs.remaining_tests.result }}' === 'success' + + const text = process.env.COMMIT_MESSAGE + + let attachments = [ + { + fallback: text, + text: text, + fields: [ + { title: 'Author', value: '${{ github.actor }}', short: true }, + { title: 'Revision', value: '${{ github.sha }}', short: true } + ] + // ts: @commit.author[:time].to_i + } + ] + + if (passed) { + attachments.push({ + color: 'good', + text: 'Tests passed' + }) + } else { + attachments.push({ + color: 'danger', + text: 'Test(s) failed' + }) + } + + let payload = { + channel: '${{ secrets.SLACK_CHANNEL }}', + username: 'GitHub CI', + icon_emoji: ':robot_face:', + attachments: attachments + } + + console.log('json=' + JSON.stringify(payload)) + " >> "$GITHUB_OUTPUT" + - uses: 8398a7/action-slack@v3 + with: + status: custom + fields: workflow,commit,author + custom_payload: ${{ steps.slack-payload-generator.outputs.json }} + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/config/application.rb b/config/application.rb index 073ba55b..135ca1f2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -13,7 +13,7 @@ module Mbis class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 6.1 + config.load_defaults 7.0 # Configuration for the application, engines, and railties goes here. # @@ -70,5 +70,18 @@ class Application < Rails::Application # TODO: Old Rails 6.0 default; disable this ActiveSupport.utc_to_local_returns_utc_offset_times = false + + # TODO: Old Rails 6.1 default; disable this + # Fails rails test test/models/concerns/workflow/model_test.rb:180 + config.active_support.executor_around_test_case = false + + # TODO: Old Rails 6.1 default; disable this + # Fixtures are incomplete, e.g. test/fixtures/memberships.yml needs to be defined + config.active_record.verify_foreign_keys_for_fixtures = false + + # Old Rails 6.1 default, required by devise_saml_authenticatable version 1.9.1 + # cf. https://github.com/apokalipto/devise_saml_authenticatable/issues/237 + # If we don't have this, the redirect when logging out from ADFS throws an application error. + Rails.application.config.action_controller.raise_on_open_redirects = false end end diff --git a/config/initializers/new_framework_defaults_7_0.rb b/config/initializers/new_framework_defaults_7_0.rb deleted file mode 100644 index 099df580..00000000 --- a/config/initializers/new_framework_defaults_7_0.rb +++ /dev/null @@ -1,145 +0,0 @@ -# rubocop:disable Layout/LineLength, Layout/EmptyLines -# Be sure to restart your server when you modify this file. -# -# This file eases your Rails 7.0 framework defaults upgrade. -# -# Uncomment each configuration one by one to switch to the new default. -# Once your application is ready to run with all new defaults, you can remove -# this file and set the `config.load_defaults` to `7.0`. -# -# Read the Guide for Upgrading Ruby on Rails for more info on each option. -# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html - -# `button_to` view helper will render `