diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index a5fd0638e..000000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-version: 2
-
-jobs:
- deploy-staging:
- docker:
- - image: mehradm/awbworg:v1
- auth:
- username: $DOCKERHUB_USERNAME
- password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
- resource_class: small
- working_directory: ~/repo
- steps:
- - checkout
-
- - add_ssh_keys:
- fingerprints:
- - "15:bf:72:7f:c7:2c:1c:65:3f:83:32:7f:34:85:fc:ba"
-
- - run: cap staging deploy
-
- deploy-production:
- docker:
- - image: mehradm/awbworg:v1
-
- steps:
- - checkout
- - run: ruby -v
-
-workflows:
- version: 2
- deploy_staging_branch: # The name of our workflow is "build_and_test"
- jobs: # The list of jobs we run as part of this workflow.
- - deploy-staging:
- context: docker-hub-creds
- filters:
- branches:
- only: staging
- deploy_production_branch: # The name of our workflow is "build_and_test"
- jobs: # The list of jobs we run as part of this workflow.
- - deploy-production:
- context: docker-hub-creds
- filters:
- branches:
- only: production
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..e5903e0b8
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+- package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: weekly
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/ci.yml
similarity index 81%
rename from .github/workflows/build-and-test.yml
rename to .github/workflows/ci.yml
index d9a3c8263..e66d8531f 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/ci.yml
@@ -8,6 +8,24 @@ on:
- reopened
jobs:
+ scan_ruby:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Scan for common Rails security vulnerabilities using static analysis
+ run: bin/brakeman --no-pager
+
+ - name: Scan for known security vulnerabilities in gems used
+ run: bin/bundler-audit
+
build-and-test:
runs-on: ubuntu-latest
diff --git a/.github/workflows/sanity-check-main.yml b/.github/workflows/sanity-check-main.yml
index 436f725cf..79916cea1 100644
--- a/.github/workflows/sanity-check-main.yml
+++ b/.github/workflows/sanity-check-main.yml
@@ -11,6 +11,18 @@ jobs:
publish-badge:
runs-on: ubuntu-latest
+
+ services:
+ mysql:
+ image: mysql:8.0
+ env:
+ MYSQL_ROOT_PASSWORD: ''
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
+ MYSQL_DATABASE: awbw_test
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
steps:
- uses: actions/checkout@v4
@@ -18,6 +30,22 @@ jobs:
with:
bundler-cache: true
+ - name: Setup database
+ run: |
+ bundle exec rake db:create db:schema:load
+ env:
+ RAILS_ENV: test
+ # AWS credentials
+ AWS_REGION: ${{ vars.AWS_REGION }}
+ AWS_S3_BUCKET: ${{ vars.AWS_S3_BUCKET }}
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ # SMTP settings
+ SMTP_SERVER: ${{ secrets.SMTP_SERVER }}
+ SMTP_PORT: ${{ secrets.SMTP_PORT }}
+ SMTP_USERNAME: ${{ secrets.SMTP_USERNAME }}
+ SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
+
- name: Run RSpec (SimpleCov JSON + summary via at_exit)
env:
RAILS_ENV: test
diff --git a/Gemfile b/Gemfile
index d51f5e3cd..bff616835 100644
--- a/Gemfile
+++ b/Gemfile
@@ -66,6 +66,8 @@ gem "json", ">= 2.6", "< 3" # or simply: gem "json", "~> 2.7"
group :development, :test do
gem 'better_errors'
+ gem "brakeman", require: false
+ gem "bundler-audit", require: false
gem 'capybara', '~> 3.36'
gem 'dotenv-rails'
gem 'faker'
diff --git a/Gemfile.lock b/Gemfile.lock
index 66edf31f2..7efd810c7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -109,7 +109,12 @@ GEM
bourbon (4.2.3)
sass (~> 3.4)
thor
+ brakeman (7.1.0)
+ racc
builder (3.3.0)
+ bundler-audit (0.9.2)
+ bundler (>= 1.2.0, < 3)
+ thor (~> 1.0)
capybara (3.40.0)
addressable
matrix
@@ -470,6 +475,8 @@ DEPENDENCIES
bootstrap-sass
bootstrap-will_paginate
bourbon (~> 4.2.2)
+ brakeman
+ bundler-audit
capybara (~> 3.36)
ckeditor (~> 4.3.0)
cocoon (~> 1.2.6)
diff --git a/app/views/resources/latest_news.html.erb b/app/views/resources/latest_news.html.erb
index 92b63728e..4b3db6d9d 100644
--- a/app/views/resources/latest_news.html.erb
+++ b/app/views/resources/latest_news.html.erb
@@ -8,7 +8,6 @@
<% end %>
-<% end %>
@@ -53,5 +52,5 @@
-
+LALALALA
diff --git a/bin/brakeman b/bin/brakeman
new file mode 100755
index 000000000..ace1c9ba0
--- /dev/null
+++ b/bin/brakeman
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+require "rubygems"
+require "bundler/setup"
+
+ARGV.unshift("--ensure-latest")
+
+load Gem.bin_path("brakeman", "brakeman")
diff --git a/bin/bundler-audit b/bin/bundler-audit
new file mode 100755
index 000000000..e2ef22690
--- /dev/null
+++ b/bin/bundler-audit
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+require_relative "../config/boot"
+require "bundler/audit/cli"
+
+ARGV.concat %w[ --config config/bundler-audit.yml ] if ARGV.empty? || ARGV.include?("check")
+Bundler::Audit::CLI.start
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
new file mode 100644
index 000000000..3076ad9d9
--- /dev/null
+++ b/config/brakeman.ignore
@@ -0,0 +1,196 @@
+{
+ "ignored_warnings": [
+ {
+ "warning_type": "SQL Injection",
+ "warning_code": 0,
+ "fingerprint": "23223b1e5030a4476088aea976cf673e2a30ece4dda7f63e1abd01a2fd8f939e",
+ "check_name": "SQL",
+ "message": "Possible SQL injection",
+ "file": "app/models/workshop.rb",
+ "line": 517,
+ "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
+ "code": "all.order(:title).search_by_categories(params[:categories]).order(:title).search_by_sectors(params[:sectors]).order(:title).order(:led_count => :desc).where(:windows_type_id => params[:type].to_i).order(:title).find_by_sql(\"SELECT *, MATCH ( #{\"title, full_name, objective, materials, introduction, demonstration, opening_circle, warm_up, creation, closing, notes, tips, misc1, misc2\"} ) AGAINST ( '*#{params[:query]}*' IN BOOLEAN MODE ) AS all_score,\\n MATCH ( title ) AGAINST ( '*#{params[:query]}*' IN BOOLEAN MODE ) AS title_score\\n\\n FROM workshops WHERE MATCH ( #{\"title, full_name, objective, materials, introduction, demonstration, opening_circle, warm_up, creation, closing, notes, tips, misc1, misc2\"} )\\n AGAINST ( '*#{params[:query]}*' IN BOOLEAN MODE ) #{\"AND windows_type_id = #{params[:type]}\"} AND inactive is false ORDER BY title_score DESC;\")",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "Workshop",
+ "method": "Workshop.search"
+ },
+ "user_input": "params[:query]",
+ "confidence": "Weak",
+ "cwe_id": [
+ 89
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Mass Assignment",
+ "warning_code": 70,
+ "fingerprint": "3143e4690dfdaf7bb904980f061cc9764ede5382bad4602edabaa4b6a56c07b5",
+ "check_name": "MassAssignment",
+ "message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
+ "file": "app/controllers/monthly_reports_controller.rb",
+ "line": 243,
+ "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
+ "code": "params[:quotes].permit!",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "MonthlyReportsController",
+ "method": "quotes_params"
+ },
+ "user_input": null,
+ "confidence": "Medium",
+ "cwe_id": [
+ 915
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Remote Code Execution",
+ "warning_code": 24,
+ "fingerprint": "59ffdfd50cdef491cfd47d69eaa3edc1d3a291661c75c5f1b10c7afa173581af",
+ "check_name": "UnsafeReflection",
+ "message": "Unsafe reflection method `constantize` called on parameter value",
+ "file": "app/controllers/api/v1/resources_controller.rb",
+ "line": 3,
+ "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
+ "code": "params[:type].constantize",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "Api::V1::ResourcesController",
+ "method": "index"
+ },
+ "user_input": "params[:type]",
+ "confidence": "High",
+ "cwe_id": [
+ 470
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Mass Assignment",
+ "warning_code": 70,
+ "fingerprint": "801ab5e957972d9cafe31dcbb1f53ca2416781cc09e5b8bd0fe62f05eeeda6c7",
+ "check_name": "MassAssignment",
+ "message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
+ "file": "app/controllers/workshop_logs_controller.rb",
+ "line": 142,
+ "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
+ "code": "params[:quotes].permit!",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "WorkshopLogsController",
+ "method": "quotes_params"
+ },
+ "user_input": null,
+ "confidence": "Medium",
+ "cwe_id": [
+ 915
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Mass Assignment",
+ "warning_code": 70,
+ "fingerprint": "abea946803acd0f0fe12c3bcd54e9b5b04d04f78ff6672e38a6cb8db02e3b5eb",
+ "check_name": "MassAssignment",
+ "message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
+ "file": "app/controllers/reports_controller.rb",
+ "line": 270,
+ "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
+ "code": "params[:quotes].permit!",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "ReportsController",
+ "method": "quotes_params"
+ },
+ "user_input": null,
+ "confidence": "Medium",
+ "cwe_id": [
+ 915
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Cross-Site Scripting",
+ "warning_code": 2,
+ "fingerprint": "b10de889c20028842db9a1821e6214044ff9adf7cd90f2ee6621a66c9c03a162",
+ "check_name": "CrossSiteScripting",
+ "message": "Unescaped model attribute",
+ "file": "app/views/workshop_variations/show.html.erb",
+ "line": 16,
+ "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
+ "code": "WorkshopVariation.find(params[:id]).decorate.display_code",
+ "render_path": [
+ {
+ "type": "controller",
+ "class": "WorkshopVariationsController",
+ "method": "show",
+ "line": 10,
+ "file": "app/controllers/workshop_variations_controller.rb",
+ "rendered": {
+ "name": "workshop_variations/show",
+ "file": "app/views/workshop_variations/show.html.erb"
+ }
+ }
+ ],
+ "location": {
+ "type": "template",
+ "template": "workshop_variations/show"
+ },
+ "user_input": null,
+ "confidence": "High",
+ "cwe_id": [
+ 79
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Mass Assignment",
+ "warning_code": 70,
+ "fingerprint": "d241d7e5a92d236ee0b2642ccdbde49e42dbb34989232d7c0d35cdabebb4e9b8",
+ "check_name": "MassAssignment",
+ "message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
+ "file": "app/controllers/workshop_logs_controller.rb",
+ "line": 146,
+ "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
+ "code": "params[:files].permit!",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "WorkshopLogsController",
+ "method": "files_params"
+ },
+ "user_input": null,
+ "confidence": "Medium",
+ "cwe_id": [
+ 915
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Unmaintained Dependency",
+ "warning_code": 120,
+ "fingerprint": "d84924377155b41e094acae7404ec2e521629d86f97b0ff628e3d1b263f8101c",
+ "check_name": "EOLRails",
+ "message": "Support for Rails 6.1.7.10 ended on 2024-10-01",
+ "file": "Gemfile.lock",
+ "line": 319,
+ "link": "https://brakemanscanner.org/docs/warning_types/unmaintained_dependency/",
+ "code": null,
+ "render_path": null,
+ "location": null,
+ "user_input": null,
+ "confidence": "High",
+ "cwe_id": [
+ 1104
+ ],
+ "note": ""
+ }
+ ],
+ "brakeman_version": "7.1.0"
+}
diff --git a/config/bundler-audit.yml b/config/bundler-audit.yml
new file mode 100644
index 000000000..6034773d2
--- /dev/null
+++ b/config/bundler-audit.yml
@@ -0,0 +1,10 @@
+---
+ignore:
+ - CVE-2024-54133
+ - CVE-2024-39308
+ - CVE-2025-55193
+ - CVE-2025-24293
+ - CVE-2021-41182
+ - CVE-2021-41183
+ - CVE-2021-41184
+ - CVE-2022-31160