From 760615710ec6aa23a1b4bdfc9ec66d4340b4d312 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Thu, 22 May 2025 09:43:38 -0400 Subject: [PATCH 01/14] Move testing from CircleCI to Github Actions --- .circleci/config.yml | 23 ---- .../actions/build-webpack-assets/action.yml | 26 +++++ .../actions/install-node-modules/action.yml | 28 +++++ .github/actions/migrate/action.yml | 28 +++++ .github/actions/setup-ruby-deps/action.yml | 28 +++++ .github/workflows/tests-and-coverage.yml | 108 ++++++++++++++++++ .gitignore | 7 +- Gemfile | 4 +- coverage/coverage_baseline.txt | 1 + spec/spec_helper.rb | 23 ++-- spec/support/capybara.rb | 1 + 11 files changed, 236 insertions(+), 41 deletions(-) create mode 100644 .github/actions/build-webpack-assets/action.yml create mode 100644 .github/actions/install-node-modules/action.yml create mode 100644 .github/actions/migrate/action.yml create mode 100644 .github/actions/setup-ruby-deps/action.yml create mode 100644 .github/workflows/tests-and-coverage.yml create mode 100644 coverage/coverage_baseline.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index 40167b88..de04bea2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,6 @@ executors: orbs: ruby: circleci/ruby@2.1.1 browser-tools: circleci/browser-tools@1.5.0 - coveralls: coveralls/coveralls@2.2.1 jobs: build: @@ -98,28 +97,6 @@ jobs: - run: bundle exec rails db:schema:load - run: bundle exec rails db:seed - # Run tests in parallel - - run: - name: Run Tests with Split by Timing Data - command: | - # Log the node index and total nodes - echo "Running tests on node $(circleci env subst '${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}')" - - # List the test files and split them by timings - TEST_FILES=$(find spec -type f -name "*_spec.rb" | circleci tests split --split-by=timings) - echo "Test files for this node: $TEST_FILES" - - # Run RSpec with the split test files - bundle exec rspec --format progress --format RspecJunitFormatter --out ~/treatment_database/test_results/rspec.xml $TEST_FILES - - # Store the test results (JUnit XML) for future runs - - store_test_results: - path: ~/treatment_database/test_results - - # Upload coverage results to Coveralls - - coveralls/upload: - parallel: true - workflows: version: 2 ci: diff --git a/.github/actions/build-webpack-assets/action.yml b/.github/actions/build-webpack-assets/action.yml new file mode 100644 index 00000000..20f12767 --- /dev/null +++ b/.github/actions/build-webpack-assets/action.yml @@ -0,0 +1,26 @@ +name: "Build Webpack Assets" +runs: + using: "composite" + steps: + # 1. Restore existing build cache + - name: Restore Webpack Build Cache + id: webpack-cache # give this step an ID + uses: actions/cache@v3 + with: + path: public/build + key: ${{ runner.os }}-webpack-build-${{ hashFiles('app/javascript/**/*','yarn.lock','package.json') }} + restore-keys: | + ${{ runner.os }}-webpack-build- + # 2. Build assets only on cache miss + - name: Build JavaScript & CSS Assets + if: steps.webpack-cache.outputs.cache-hit != 'true' + run: yarn build + shell: bash + + # 3. Save new build only on cache miss + - name: Save Webpack Build Cache + if: steps.webpack-cache.outputs.cache-hit != 'true' + uses: actions/cache@v3 + with: + path: public/build + key: ${{ runner.os }}-webpack-build-${{ hashFiles('app/javascript/**/*','yarn.lock','package.json') }} \ No newline at end of file diff --git a/.github/actions/install-node-modules/action.yml b/.github/actions/install-node-modules/action.yml new file mode 100644 index 00000000..56b06246 --- /dev/null +++ b/.github/actions/install-node-modules/action.yml @@ -0,0 +1,28 @@ +name: "Install Node Modules" +description: "Checks out code, sets up Node.js from .nvmrc with Yarn caching, and installs dependencies." +inputs: {} +runs: + using: "composite" + steps: + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Restore node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node-modules- + - name: Install Dependencies + run: yarn install --frozen-lockfile + shell: bash + + - name: Save node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} \ No newline at end of file diff --git a/.github/actions/migrate/action.yml b/.github/actions/migrate/action.yml new file mode 100644 index 00000000..56b06246 --- /dev/null +++ b/.github/actions/migrate/action.yml @@ -0,0 +1,28 @@ +name: "Install Node Modules" +description: "Checks out code, sets up Node.js from .nvmrc with Yarn caching, and installs dependencies." +inputs: {} +runs: + using: "composite" + steps: + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Restore node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node-modules- + - name: Install Dependencies + run: yarn install --frozen-lockfile + shell: bash + + - name: Save node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} \ No newline at end of file diff --git a/.github/actions/setup-ruby-deps/action.yml b/.github/actions/setup-ruby-deps/action.yml new file mode 100644 index 00000000..56b06246 --- /dev/null +++ b/.github/actions/setup-ruby-deps/action.yml @@ -0,0 +1,28 @@ +name: "Install Node Modules" +description: "Checks out code, sets up Node.js from .nvmrc with Yarn caching, and installs dependencies." +inputs: {} +runs: + using: "composite" + steps: + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + + - name: Restore node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node-modules- + - name: Install Dependencies + run: yarn install --frozen-lockfile + shell: bash + + - name: Save node_modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} \ No newline at end of file diff --git a/.github/workflows/tests-and-coverage.yml b/.github/workflows/tests-and-coverage.yml new file mode 100644 index 00000000..f2f86307 --- /dev/null +++ b/.github/workflows/tests-and-coverage.yml @@ -0,0 +1,108 @@ +name: Tests & Coverage + +on: + pull_request: + types: + - opened + - synchronize + - reopened + +jobs: + tests: + runs-on: ubuntu-latest + + # Job-level defaults + env: + RAILS_ENV: test + + # Cancel stale runs on the same PR + concurrency: + group: ${{ github.workflow }}-PR${{ github.event.number }} + cancel-in-progress: true + + steps: + - name: Check out code + uses: actions/checkout@v3 + + - name: Setup Chrome & capture paths + id: setup_chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: '133.0.6943.126' + install-chromedriver: true + install-dependencies: true + + - name: Export Chrome paths for CI + run: | + echo "CHROME_BIN=${{ steps.setup_chrome.outputs.chrome-path }}" >> $GITHUB_ENV + echo "CHROMEDRIVER_PATH=${{ steps.setup_chrome.outputs.chromedriver-path }}" >> $GITHUB_ENV + - name: Set up Ruby and Gems + uses: ./.github/actions/setup-ruby-deps + + - name: Install Node Modules + uses: ./.github/actions/install-node-modules + + - name: Build Webpack Assets + uses: ./.github/actions/build-webpack-assets + + - name: Run Database Migrations + uses: ./.github/actions/migrate + + - name: Run Tests with SimpleCov + run: | + bundle exec rspec \ + --format progress \ + --format RspecJunitFormatter \ + --out /tmp/test-results/rspec.xml + - name: Upload Coverage Artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage + + coverage: + needs: tests + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Checkout PR branch for baseline update + uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 + persist-credentials: true + + - name: Download Coverage Artifact + uses: actions/download-artifact@v4 + with: + name: coverage-report + path: . + + - name: Coverage Check + run: | + # Extract current coverage percentage + COVERAGE=$(grep -oE '[0-9]+\.[0-9]+%' coverage/index.html \ + | head -n1 \ + | tr -d '%') + echo "Current coverage: $COVERAGE%" + # Read the committed baseline + BASELINE=$(cat coverage/coverage_baseline.txt) + echo "Baseline coverage: $BASELINE%" + # Fail if coverage dropped + if (( $(echo "$COVERAGE < $BASELINE" | bc -l) )); then + echo "🚨 Coverage dropped: $COVERAGE% < $BASELINE%" + exit 1 + fi + # Bump baseline and push back to PR branch if coverage increased + if (( $(echo "$COVERAGE > $BASELINE" | bc -l) )); then + echo "$COVERAGE" > coverage/coverage_baseline.txt + git add coverage/coverage_baseline.txt + git config user.name "ci-bot" + git config user.email "ci-bot@example.com" + git commit -m "ci: update coverage baseline to $COVERAGE%" || true + git push origin HEAD:${{ github.head_ref }} || true + fi diff --git a/.gitignore b/.gitignore index 8d2948a8..45f80e86 100644 --- a/.gitignore +++ b/.gitignore @@ -36,8 +36,11 @@ # Ignore master key for decrypting credentials and more. /config/master.key -# Ignore the coverage folder -/coverage +# ignore everything in coverage +coverage/* + +# ...except the baseline file +!coverage/coverage_baseline.txt # Don't track .DS_Store on MacOS .DS_Store diff --git a/Gemfile b/Gemfile index 0890a39c..d4d70480 100644 --- a/Gemfile +++ b/Gemfile @@ -86,8 +86,6 @@ group :development, :test do gem 'coveralls_reborn' # Provides Ruby API for Coveralls.io code coverage reporting gem 'rubocop' # A Ruby static code analyzer and formatter gem 'rubocop-rails' # A RuboCop extension focused on enforcing Rails best practices - gem 'simplecov', require: false # Code coverage analysis tool for Ruby - gem 'simplecov-lcov', require: false # Formatter for SimpleCov that generates LCOV reports end group :development do @@ -108,6 +106,8 @@ group :test do gem 'rack-test' # Small, simple testing API for Rack apps gem 'rspec-rails', '~> 6.1.5' # RSpec for Rails 6+ gem 'shoulda-matchers', '~> 6.5' # Provides RSpec with additional matchers + gem 'simplecov', require: false # Code coverage analysis tool for Ruby + gem 'simplecov-lcov', require: false # Formatter for SimpleCov that generates LCOV reports end group :production do diff --git a/coverage/coverage_baseline.txt b/coverage/coverage_baseline.txt new file mode 100644 index 00000000..d0ada4a7 --- /dev/null +++ b/coverage/coverage_baseline.txt @@ -0,0 +1 @@ +99.54 \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f7ba496c..afe97eda 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,21 +5,16 @@ require 'coveralls' SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true -SimpleCov.start 'rails' do - add_filter '/spec/' # Exclude all files in the spec directory - add_filter '/lib/tasks/' # Exclude all files in the lib/tasks directory - add_filter '/lib/capistrano/' # Exclude all files in the lib/capistrano directory -end +SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::LcovFormatter, + Coveralls::SimpleCov::Formatter + ]) -SimpleCov.at_exit do - SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new( - [ - SimpleCov::Formatter::HTMLFormatter, - SimpleCov::Formatter::LcovFormatter, - Coveralls::SimpleCov::Formatter - ] - ) - SimpleCov.result.format! +SimpleCov.start 'rails' do + add_filter '/spec/' + add_filter '/lib/tasks/' + add_filter '/lib/capistrano/' end require 'byebug' diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 038b664f..0a901ad0 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'capybara/rspec' require 'selenium-webdriver' From a87786255b579de47e99079066a9b241cab586f7 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Thu, 22 May 2025 09:47:43 -0400 Subject: [PATCH 02/14] Add usage_notes.md for github actions --- .github/usage_notes.md | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/usage_notes.md diff --git a/.github/usage_notes.md b/.github/usage_notes.md new file mode 100644 index 00000000..5a5bd0be --- /dev/null +++ b/.github/usage_notes.md @@ -0,0 +1,58 @@ +# GitHub Actions Structure & Usage Notes + +This document explains how our repository's GitHub Actions are organized and why we've structured custom actions the +way we have. It should serve as a reference for setting up and maintaining our CI/CD workflows. + +## Folder Structure + +### Our repository includes two key directories for GitHub Actions: + +#### .github/workflows/ +- Contains the workflow YAML files. +- These files define our CI/CD pipelines and are triggered by GitHub events (e.g., pull requests). +- Each file in this folder represents an independent workflow that appears as a separate check on the PR screen. + +#### .github/actions/ +- Contains custom or composite actions that we reuse across multiple workflows. +- By modularizing common tasks (such as setting up Ruby and installing dependencies), we avoid code duplication and + ensure consistency across our checks (e.g., tests, RuboCop, Brakeman, bundler-audit). + +## Custom Composite Actions +### Why Use a Directory with an action.yml File? +For custom composite actions, GitHub Actions expects them to be structured as a directory that contains an action.yml file. + +For example, our Ruby dependencies setup is located at: +`.github/actions/setup-ruby-deps/action.yml`. +This is preferred over a standalone file like `.github/actions/setup-ruby-deps.yml` because: + +#### Standard Structure: +- GitHub recognizes a composite action by looking for an action.yml file inside a dedicated directory. +- This is the official and recommended approach. + +#### Modularity and Reusability: +- Organizing our custom actions into their own directories makes them easy to reuse and maintain. +- Each action can include additional resources (scripts, documentation, etc.) if needed. + +## Example: Setup Ruby and Dependencies Composite Action +The composite action in `.github/actions/setup-ruby-deps/action.yml` performs the following: + +1. Checks out the repository code. +2. Sets up Ruby using ruby/setup-ruby with bundler caching enabled. +3. Runs bundle install to install gem dependencies. + +This composite action can be used in multiple workflows (e.g., tests, RuboCop, Brakeman) to avoid duplicating these steps. + +## Usage in a Workflow +For example, our RuboCop workflow (`.github/workflows/rubocop.yml`) would use the composite action like this: +```aiignore +jobs: + rubocop: + runs-on: ubuntu-latest + steps: + - name: Setup Ruby and Dependencies + uses: ./.github/actions/setup-ruby-deps + - name: Run RuboCop + run: bundle exec rubocop + +``` +This ensures that the same setup process is consistently applied across our workflows. \ No newline at end of file From 6a6c3dd9a674eccd571d8070416777afe24119ba Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:04:00 -0400 Subject: [PATCH 03/14] Add ruby installation to setup-ruby-deps/action.yml --- .github/actions/setup-ruby-deps/action.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-ruby-deps/action.yml b/.github/actions/setup-ruby-deps/action.yml index 56b06246..6754c32a 100644 --- a/.github/actions/setup-ruby-deps/action.yml +++ b/.github/actions/setup-ruby-deps/action.yml @@ -1,9 +1,16 @@ -name: "Install Node Modules" -description: "Checks out code, sets up Node.js from .nvmrc with Yarn caching, and installs dependencies." +name: "Setup Ruby & Node" +description: "Sets up Ruby from .ruby-version with Bundler caching, and Node.js from .nvmrc with Yarn caching." + inputs: {} runs: using: "composite" steps: + - name: Set up Ruby from .ruby-version + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + - name: Set up Node.js uses: actions/setup-node@v3 with: @@ -25,4 +32,4 @@ runs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} \ No newline at end of file + key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} From 610ba0040f3dba4210a162b49e66b98bf115ff8c Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:11:16 -0400 Subject: [PATCH 04/14] Put correct file at .github/actions/migrate/action.yml --- .github/actions/migrate/action.yml | 33 ++++++++++-------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/.github/actions/migrate/action.yml b/.github/actions/migrate/action.yml index 56b06246..87605312 100644 --- a/.github/actions/migrate/action.yml +++ b/.github/actions/migrate/action.yml @@ -1,28 +1,17 @@ -name: "Install Node Modules" -description: "Checks out code, sets up Node.js from .nvmrc with Yarn caching, and installs dependencies." +name: "Run Database Migrations" +description: "Checks out code, sets up Ruby, and runs database migrations in the test environment." inputs: {} runs: using: "composite" steps: - - name: Set up Node.js - uses: actions/setup-node@v3 + - name: Checkout Code + uses: actions/checkout@v3 + - name: Set up Ruby with Bundler Cache + uses: ruby/setup-ruby@v1 with: - node-version-file: '.nvmrc' - cache: 'yarn' - - - name: Restore node_modules cache - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-node-modules- - - name: Install Dependencies - run: yarn install --frozen-lockfile + bundler-cache: true + - name: Run Migrations + run: RAILS_ENV=test bundle exec rails db:migrate + env: + RAILS_ENV: test shell: bash - - - name: Save node_modules cache - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }} \ No newline at end of file From e1e337f648e79a459bf723606527e48b105b06f6 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:22:47 -0400 Subject: [PATCH 05/14] Disable spring when running migrations --- .github/actions/migrate/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/migrate/action.yml b/.github/actions/migrate/action.yml index 87605312..3e8ed037 100644 --- a/.github/actions/migrate/action.yml +++ b/.github/actions/migrate/action.yml @@ -10,8 +10,8 @@ runs: uses: ruby/setup-ruby@v1 with: bundler-cache: true - - name: Run Migrations - run: RAILS_ENV=test bundle exec rails db:migrate + - name: Run Migrations (Spring disabled) + run: DISABLE_SPRING=1 bundle exec rails db:migrate env: RAILS_ENV: test shell: bash From df3e65e517d1a7431cf1a21b76ed8c93a024859c Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:30:28 -0400 Subject: [PATCH 06/14] Disable spring when running tests --- .github/workflows/tests-and-coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests-and-coverage.yml b/.github/workflows/tests-and-coverage.yml index f2f86307..a484d521 100644 --- a/.github/workflows/tests-and-coverage.yml +++ b/.github/workflows/tests-and-coverage.yml @@ -14,6 +14,7 @@ jobs: # Job-level defaults env: RAILS_ENV: test + DISABLE_SPRING: 1 # Cancel stale runs on the same PR concurrency: From 768d0c89c986089cceb99d9e62dbc285ace32490 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:42:03 -0400 Subject: [PATCH 07/14] Stop caching webpack assets and build every time --- .../actions/build-webpack-assets/action.yml | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/.github/actions/build-webpack-assets/action.yml b/.github/actions/build-webpack-assets/action.yml index 20f12767..c9e9e52b 100644 --- a/.github/actions/build-webpack-assets/action.yml +++ b/.github/actions/build-webpack-assets/action.yml @@ -1,26 +1,14 @@ name: "Build Webpack Assets" +description: "Runs Webpack build to generate JavaScript and CSS assets." runs: using: "composite" steps: - # 1. Restore existing build cache - - name: Restore Webpack Build Cache - id: webpack-cache # give this step an ID - uses: actions/cache@v3 - with: - path: public/build - key: ${{ runner.os }}-webpack-build-${{ hashFiles('app/javascript/**/*','yarn.lock','package.json') }} - restore-keys: | - ${{ runner.os }}-webpack-build- - # 2. Build assets only on cache miss - name: Build JavaScript & CSS Assets - if: steps.webpack-cache.outputs.cache-hit != 'true' run: yarn build shell: bash - # 3. Save new build only on cache miss - - name: Save Webpack Build Cache - if: steps.webpack-cache.outputs.cache-hit != 'true' - uses: actions/cache@v3 - with: - path: public/build - key: ${{ runner.os }}-webpack-build-${{ hashFiles('app/javascript/**/*','yarn.lock','package.json') }} \ No newline at end of file + - name: Confirm manifest.json was generated + run: | + echo "Checking for public/build/manifest.json..." + test -f public/build/manifest.json || { echo "❌ manifest.json missing"; exit 1; } + shell: bash From 8e9d3897cb7956b34e42580fccf423d2747c7867 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:48:49 -0400 Subject: [PATCH 08/14] Remove checking out code from the migrate action --- .github/actions/migrate/action.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/actions/migrate/action.yml b/.github/actions/migrate/action.yml index 3e8ed037..7efe91cd 100644 --- a/.github/actions/migrate/action.yml +++ b/.github/actions/migrate/action.yml @@ -1,11 +1,9 @@ name: "Run Database Migrations" -description: "Checks out code, sets up Ruby, and runs database migrations in the test environment." +description: "Sets up Ruby, and runs database migrations in the test environment." inputs: {} runs: using: "composite" steps: - - name: Checkout Code - uses: actions/checkout@v3 - name: Set up Ruby with Bundler Cache uses: ruby/setup-ruby@v1 with: From 0bf466032ed4759746289fb63d5856a545fae27d Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 10:56:23 -0400 Subject: [PATCH 09/14] Make spec/support/capybara.rb look for ENV['CHROME_BIN'] variable --- spec/support/capybara.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 0a901ad0..bec845cf 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -7,6 +7,13 @@ Capybara.register_driver :selenium_chrome_headless_sandboxless do |app| # Build Chrome options options = Selenium::WebDriver::Chrome::Options.new + + # Force use of pinned Chrome binary if present (e.g., from GitHub Actions) + chrome_bin = ENV['CHROME_BIN'] + if chrome_bin && File.exist?(chrome_bin) + options.binary = chrome_bin + end + options.add_argument('--headless') options.add_argument('--disable-gpu') options.add_argument('--no-sandbox') From 89a03aa56d1189ed1b4ae68dac0f220c9f633fb4 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 16:17:43 -0400 Subject: [PATCH 10/14] Restore spec_helper to qa version --- spec/spec_helper.rb | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index afe97eda..f7ba496c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,16 +5,21 @@ require 'coveralls' SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true -SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([ - SimpleCov::Formatter::HTMLFormatter, - SimpleCov::Formatter::LcovFormatter, - Coveralls::SimpleCov::Formatter - ]) - SimpleCov.start 'rails' do - add_filter '/spec/' - add_filter '/lib/tasks/' - add_filter '/lib/capistrano/' + add_filter '/spec/' # Exclude all files in the spec directory + add_filter '/lib/tasks/' # Exclude all files in the lib/tasks directory + add_filter '/lib/capistrano/' # Exclude all files in the lib/capistrano directory +end + +SimpleCov.at_exit do + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new( + [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::LcovFormatter, + Coveralls::SimpleCov::Formatter + ] + ) + SimpleCov.result.format! end require 'byebug' From 307406fbd724e20276f1565fb6a6d8cf71422c91 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Fri, 23 May 2025 16:20:36 -0400 Subject: [PATCH 11/14] Restore Gemfile to qa version --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index d4d70480..0890a39c 100644 --- a/Gemfile +++ b/Gemfile @@ -86,6 +86,8 @@ group :development, :test do gem 'coveralls_reborn' # Provides Ruby API for Coveralls.io code coverage reporting gem 'rubocop' # A Ruby static code analyzer and formatter gem 'rubocop-rails' # A RuboCop extension focused on enforcing Rails best practices + gem 'simplecov', require: false # Code coverage analysis tool for Ruby + gem 'simplecov-lcov', require: false # Formatter for SimpleCov that generates LCOV reports end group :development do @@ -106,8 +108,6 @@ group :test do gem 'rack-test' # Small, simple testing API for Rack apps gem 'rspec-rails', '~> 6.1.5' # RSpec for Rails 6+ gem 'shoulda-matchers', '~> 6.5' # Provides RSpec with additional matchers - gem 'simplecov', require: false # Code coverage analysis tool for Ruby - gem 'simplecov-lcov', require: false # Formatter for SimpleCov that generates LCOV reports end group :production do From aceaaaeb9f15be4580a0c55acacbbd133b79d6fe Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Tue, 27 May 2025 15:53:18 -0400 Subject: [PATCH 12/14] Add GitHub Actions workflow to run Brakeman and fail on high-severity warnings --- .github/workflows/brakeman.yml | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/brakeman.yml diff --git a/.github/workflows/brakeman.yml b/.github/workflows/brakeman.yml new file mode 100644 index 00000000..9578485a --- /dev/null +++ b/.github/workflows/brakeman.yml @@ -0,0 +1,46 @@ +name: Ensure Brakeman Passes + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + brakeman: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Ruby, Gems, and Install Dependencies + uses: ./.github/actions/setup-ruby-deps + + - name: Run Brakeman (Human-readable and JSON outputs) + run: | + mkdir -p tmp + bundle exec brakeman --no-exit-on-warn -o tmp/brakeman-output.json + env: + BRAKEMAN_FORMAT: json + + - name: Display Brakeman Report + run: | + echo "Brakeman Report (JSON):" + cat tmp/brakeman-output.json || echo "Brakeman report is missing or empty." + shell: bash + + - name: Upload Brakeman Report + uses: actions/upload-artifact@v4 + with: + name: brakeman-report + path: tmp/brakeman-output.json + + - name: Fail on High-Severity Issues + run: | + HIGH_SEVERITY_COUNT=$(jq '.warnings | map(select(.confidence == "High")) | length' tmp/brakeman-output.json) + echo "High severity issues: $HIGH_SEVERITY_COUNT" + if [ "$HIGH_SEVERITY_COUNT" -gt 0 ]; then + echo "Brakeman detected high-severity issues. Failing the job." + exit 1 + fi + env: + BRAKEMAN_FORMAT: json + shell: bash From 3ea660fa28b038e4c1e83cbf7aefea2656c3fd28 Mon Sep 17 00:00:00 2001 From: Janell-Huyck Date: Mon, 2 Jun 2025 12:08:17 -0400 Subject: [PATCH 13/14] Update Gemfile.lock after merging in qa --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 862db323..5ebb134b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -377,11 +377,11 @@ PLATFORMS aarch64-linux aarch64-linux-gnu aarch64-linux-musl - arm64-darwin-23 arm-linux arm-linux-gnu arm-linux-musl arm64-darwin + arm64-darwin-23 x86-linux x86-linux-gnu x86-linux-musl From 3ac49581266f3293a79cb26537fbee5426b115f1 Mon Sep 17 00:00:00 2001 From: Glen Horton Date: Mon, 2 Jun 2025 17:30:12 -0400 Subject: [PATCH 14/14] test 142 --- config/brakeman.ignore | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 config/brakeman.ignore diff --git a/config/brakeman.ignore b/config/brakeman.ignore deleted file mode 100644 index 6072b585..00000000 --- a/config/brakeman.ignore +++ /dev/null @@ -1,42 +0,0 @@ -{ - "ignored_warnings": [ - { - "warning_type": "Mass Assignment", - "warning_code": 105, - "fingerprint": "c885cc05df4d2146d8452ec9809d902182d4e29e7e239b442ecf37b1a8939939", - "check_name": "PermitAttributes", - "message": "Potentially dangerous key allowed for mass assignment", - "file": "app/controllers/users_controller.rb", - "line": 43, - "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", - "code": "params.require(:user).permit(:id, :display_name, :role, :account_active, :password, :password_confirmation)", - "render_path": null, - "location": { - "type": "method", - "class": "UsersController", - "method": "user_params" - }, - "user_input": ":role", - "confidence": "Medium", - "note": "" - }, - { - "warning_type": "Unmaintained Dependency", - "warning_code": 120, - "fingerprint": "d84924377155b41e094acae7404ec2e521629d86f97b0ff628e3d1b263f8101c", - "check_name": "EOLRails", - "message": "Support for Rails 5.2.8.1 ended on 2022-06-01", - "file": "Gemfile.lock", - "line": 185, - "link": "https://brakemanscanner.org/docs/warning_types/unmaintained_dependency/", - "code": null, - "render_path": null, - "location": null, - "user_input": null, - "confidence": "High", - "note": "" - } - ], - "updated": "2022-07-14 14:00:01 -0400", - "brakeman_version": "5.2.3" -}