From 2ca257dcd12d6d814341a06420dc146bfae97189 Mon Sep 17 00:00:00 2001 From: Ryan Wold Date: Tue, 26 Nov 2024 11:06:58 -0800 Subject: [PATCH 1/4] set short_uuid when the form is created * make set_uuid private * ensure unique uuids in db * add short_uuid to survey report --- app/controllers/admin/reporting_controller.rb | 4 +- app/models/form.rb | 39 +++++++------------ db/migrate/20241126184348_form_short_uuid.rb | 18 +++++++++ db/schema.rb | 6 ++- db/seeds.rb | 1 - 5 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 db/migrate/20241126184348_form_short_uuid.rb diff --git a/app/controllers/admin/reporting_controller.rb b/app/controllers/admin/reporting_controller.rb index 245040166..edd9d885c 100644 --- a/app/controllers/admin/reporting_controller.rb +++ b/app/controllers/admin/reporting_controller.rb @@ -10,7 +10,7 @@ def hisps def lifespan @form_lifespans = Submission.select('form_id, count(*) as num_submissions, (max(submissions.created_at) - min(submissions.created_at)) as lifespan').group(:form_id) - @forms = Form.select(:id, :name, :organization_id, :uuid).where('exists (select id, uuid from submissions where submissions.form_id = forms.id)') + @forms = Form.select(:id, :name, :organization_id, :uuid, :short_uuid).where('exists (select id from submissions where submissions.form_id = forms.id)') @orgs = Organization.order(:name) @org_summary = [] @orgs.each do |org| @@ -36,7 +36,7 @@ def lifespan end def no_submissions - @forms = Form.published.select(:id, :name, :organization_id, :uuid).where("not exists (select id, uuid from submissions where submissions.form_id = forms.id and submissions.created_at > current_date - interval '30' day)").order(:organization_id) + @forms = Form.published.select(:id, :name, :organization_id, :uuid, :short_uuid).where("not exists (select id, uuid from submissions where submissions.form_id = forms.id and submissions.created_at > current_date - interval '30' day)").order(:organization_id) @orgs = Organization.order(:name) @org_summary = [] @orgs.each do |org| diff --git a/app/models/form.rb b/app/models/form.rb index 212c9fc35..bcada6323 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -18,15 +18,17 @@ class Form < ApplicationRecord acts_as_taggable_on :tags validates :name, presence: true - validates :disclaimer_text, length: { in: 0..1000, allow_blank: true } + validates :uuid, presence: true + validates :short_uuid, presence: true validates :delivery_method, presence: true + validates :disclaimer_text, length: { in: 0..1000, allow_blank: true } validates :anticipated_delivery_count, numericality: true, allow_nil: true validate :omb_number_with_expiration_date validate :valid_form_kinds validate :target_for_delivery_method validate :ensure_modal_text - before_create :set_uuid + before_validation :set_uuid, on: :create after_create :create_first_form_section before_destroy :ensure_no_responses @@ -124,12 +126,6 @@ def suppress_submit_button (questions.size == 1 && questions.collect(&:question_type).include?('custom_text_display')) end - def self.find_by_short_uuid(short_uuid) - return nil unless short_uuid && short_uuid.length == 8 - - where('uuid LIKE ?', "#{short_uuid}%").first - end - def self.find_by_legacy_touchpoints_id(id) return nil unless id && id.length < 4 @@ -146,10 +142,6 @@ def to_param short_uuid end - def short_uuid - uuid[0..7] - end - def send_notifications? notification_emails.present? end @@ -158,14 +150,6 @@ def create_first_form_section form_sections.create(title: (I18n.t 'form.page_1'), position: 1) end - # def to_param - # short_uuid - # end - - def short_uuid - uuid[0..7] - end - # used to initially set tags (or reset them, if necessary) def set_submission_tags! submission_tags = submissions.collect(&:tags).uniq.sort_by { |i| i.name } @@ -228,19 +212,21 @@ def events def duplicate!(new_user:) new_form = dup + new_form.aasm_state = :created new_form.name = "Copy of #{name}" new_form.title = new_form.name new_form.survey_form_activations = 0 new_form.response_count = 0 new_form.questions_count = 0 new_form.last_response_created_at = nil - new_form.aasm_state = :created new_form.uuid = nil + new_form.short_uuid = nil new_form.legacy_touchpoint_id = nil new_form.legacy_touchpoint_uuid = nil - new_form.template = false + new_form.notification_emails = nil new_form.organization = new_user.organization new_form.legacy_form_embed = false + new_form.template = false new_form.save! # Manually remove the Form Section created with create_first_form_section @@ -286,10 +272,6 @@ def self.archive_expired! end end - def set_uuid - self.uuid = SecureRandom.uuid if uuid.blank? - end - def self.send_inactive_form_emails_since(days_ago) inactive_published_forms = find_inactive_forms_since(days_ago) @@ -764,6 +746,11 @@ def self.forms_whose_retention_period_has_passed private + def set_uuid + self.uuid ||= SecureRandom.uuid + self.short_uuid ||= self.uuid[0..7] + end + def set_submitted_at self.update(submitted_at: Time.current) end diff --git a/db/migrate/20241126184348_form_short_uuid.rb b/db/migrate/20241126184348_form_short_uuid.rb new file mode 100644 index 000000000..53ad2ef44 --- /dev/null +++ b/db/migrate/20241126184348_form_short_uuid.rb @@ -0,0 +1,18 @@ +class FormShortUuid < ActiveRecord::Migration[7.2] + def change + add_column :forms, :short_uuid, :string, limit: 8 + add_index :forms, :short_uuid, unique: true + + remove_index :forms, :uuid + add_index :forms, :uuid, unique: true + + remove_index :submissions, :uuid + add_index :submissions, :uuid, unique: true + + Form.all.each do |form| + form.update({ + short_uuid: form.uuid[0..7] + }) + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 5d3f31495..770d5877f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_11_12_222412) do +ActiveRecord::Schema[7.2].define(version: 2024_11_26_184348) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -309,12 +309,14 @@ t.boolean "legacy_form_embed", default: false t.datetime "archived_at" t.string "audience", default: "public", comment: "indicates whether a form is intended for a public or internal audience" + t.string "short_uuid", limit: 8 t.index ["legacy_touchpoint_id"], name: "index_forms_on_legacy_touchpoint_id" t.index ["legacy_touchpoint_uuid"], name: "index_forms_on_legacy_touchpoint_uuid" t.index ["organization_id"], name: "index_forms_on_organization_id" t.index ["service_id"], name: "index_forms_on_service_id" + t.index ["short_uuid"], name: "index_forms_on_short_uuid", unique: true t.index ["user_id"], name: "index_forms_on_user_id" - t.index ["uuid"], name: "index_forms_on_uuid" + t.index ["uuid"], name: "index_forms_on_uuid", unique: true end create_table "ivn_component_links", force: :cascade do |t| diff --git a/db/seeds.rb b/db/seeds.rb index 43b2759fd..f373094e5 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -613,7 +613,6 @@ def production_suitable_seeds fiscal_year: 2021, quarter: 2, rating: 'TRUE', - likert_or_thumb_question: "", number_of_interactions: 123_456, number_of_people_offered_the_survey: 9_876, likert_or_thumb_question: "thumbs_up_down", From 777656272a05f4b3c77ebe52ae630c1cb45d013a Mon Sep 17 00:00:00 2001 From: Ryan Wold Date: Thu, 5 Dec 2024 13:34:58 -0800 Subject: [PATCH 2/4] update gems --- Gemfile.lock | 118 ++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index eeac0e533..585859872 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -62,7 +62,7 @@ GEM erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - active_model_serializers (0.10.14) + active_model_serializers (0.10.15) actionpack (>= 4.1) activemodel (>= 4.1) case_transform (>= 0.2) @@ -102,10 +102,10 @@ GEM aes_key_wrap (1.1.0) ast (2.4.2) aws-eventstream (1.3.0) - aws-partitions (1.997.0) + aws-partitions (1.1018.0) aws-record (2.13.2) aws-sdk-dynamodb (~> 1, >= 1.85.0) - aws-sdk-core (3.211.0) + aws-sdk-core (3.214.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -113,7 +113,7 @@ GEM aws-sdk-dynamodb (1.126.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-kms (1.95.0) + aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) aws-sdk-rails (4.1.0) @@ -172,7 +172,7 @@ GEM brakeman (6.2.2) racc builder (3.3.0) - bullet (7.2.0) + bullet (8.0.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundler-audit (0.9.2) @@ -209,7 +209,7 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - date (3.3.4) + date (3.4.1) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) devise (4.9.4) @@ -224,20 +224,20 @@ GEM drb (2.2.1) dumb_delegator (1.0.0) erubi (1.13.0) - excon (1.0.0) + excon (1.2.2) factory_bot (6.5.0) activesupport (>= 5.0.0) factory_bot_rails (6.4.4) factory_bot (~> 6.5) railties (>= 5.0.0) - faraday (2.12.0) - faraday-net_http (>= 2.0, < 3.4) + faraday (2.12.1) + faraday-net_http (>= 2.0, < 3.5) json logger faraday-follow_redirects (0.3.0) faraday (>= 1, < 3) - faraday-net_http (3.3.0) - net-http + faraday-net_http (3.4.0) + net-http (>= 0.5.0) ffi (1.17.0-aarch64-linux-gnu) ffi (1.17.0-aarch64-linux-musl) ffi (1.17.0-arm-linux-gnu) @@ -278,7 +278,7 @@ GEM actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) - io-console (0.7.2) + io-console (0.8.0) irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) @@ -290,7 +290,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.7.4) + json (2.9.0) json-jwt (1.16.7) activesupport (>= 4.2) aes_key_wrap @@ -313,13 +313,13 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kramdown (2.4.0) - rexml + kramdown (2.5.1) + rexml (>= 3.3.9) language_server-protocol (3.17.0.3) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.1) + logger (1.6.2) logstop (0.3.1) loofah (2.23.1) crass (~> 1.0.2) @@ -335,17 +335,17 @@ GEM mime-types (3.6.0) logger mime-types-data (~> 3.2015) - mime-types-data (3.2024.1001) + mime-types-data (3.2024.1203) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.1) - msgpack (1.7.3) + minitest (5.25.4) + msgpack (1.7.5) multi_json (1.15.0) multi_xml (0.7.1) bigdecimal (~> 3.1) - net-http (0.4.1) + net-http (0.6.0) uri - net-imap (0.5.0) + net-imap (0.5.1) date net-protocol net-pop (0.1.2) @@ -354,19 +354,19 @@ GEM timeout net-smtp (0.5.0) net-protocol - newrelic_rpm (9.14.0) - nio4r (2.7.3) - nokogiri (1.16.7-aarch64-linux) + newrelic_rpm (9.16.1) + nio4r (2.7.4) + nokogiri (1.16.8-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.7-arm-linux) + nokogiri (1.16.8-arm-linux) racc (~> 1.4) - nokogiri (1.16.7-arm64-darwin) + nokogiri (1.16.8-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.7-x86-linux) + nokogiri (1.16.8-x86-linux) racc (~> 1.4) - nokogiri (1.16.7-x86_64-darwin) + nokogiri (1.16.8-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) + nokogiri (1.16.8-x86_64-linux) racc (~> 1.4) oauth2 (2.0.9) faraday (>= 0.17.3, < 3.0) @@ -389,37 +389,38 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) orm_adapter (0.5.0) - ostruct (0.6.0) + ostruct (0.6.1) paper_trail (15.2.0) activerecord (>= 6.1) request_store (~> 1.4) parallel (1.26.3) - parser (3.3.5.0) + parser (3.3.6.0) ast (~> 2.4.1) racc pg (1.5.9) - pry (0.14.2) + pry (0.15.0) coderay (~> 1.1) method_source (~> 1.0) - psych (5.1.2) + psych (5.2.1) + date stringio public_suffix (6.0.1) - puma (6.4.3) + puma (6.5.0) nio4r (~> 2.0) racc (1.8.1) rack (3.1.8) rack-cors (2.0.2) rack (>= 2.0.0) - rack-protection (4.0.0) + rack-protection (4.1.1) base64 (>= 0.1.0) + logger (>= 1.6.0) rack (>= 3.0.0, < 4) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) rack (>= 1.3) - rackup (2.1.0) + rackup (2.2.1) rack (>= 3) - webrick (~> 1.8) rails (7.2.1.2) actioncable (= 7.2.1.2) actionmailbox (= 7.2.1.2) @@ -447,9 +448,9 @@ GEM activesupport (>= 4.2) choice (~> 0.2.0) ruby-graphviz (~> 1.2) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.1) loofah (~> 2.21) - nokogiri (~> 1.14) + 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 (7.2.1.2) actionpack (= 7.2.1.2) activesupport (= 7.2.1.2) @@ -463,7 +464,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.7.0) + rdoc (6.8.1) psych (>= 4.0.0) redis (5.3.0) redis-client (>= 0.22.0) @@ -471,8 +472,8 @@ GEM connection_pool redis-namespace (1.11.0) redis (>= 4) - regexp_parser (2.9.2) - reline (0.5.10) + regexp_parser (2.9.3) + reline (0.5.12) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) @@ -497,20 +498,20 @@ GEM rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) - rspec-support (3.13.1) + rspec-support (3.13.2) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.67.0) + rubocop (1.69.1) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.32.2, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.36.2, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.36.2) parser (>= 3.3.1.0) rubocop-rails (2.27.0) activesupport (>= 4.2.0) @@ -536,14 +537,14 @@ GEM sprockets (> 3.0) sprockets-rails tilt - securerandom (0.3.1) - selenium-webdriver (4.25.0) + securerandom (0.4.0) + selenium-webdriver (4.27.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sidekiq (7.3.4) + sidekiq (7.3.6) connection_pool (>= 2.3.0) logger rack (>= 2.2.4) @@ -564,23 +565,25 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - ssrf_filter (1.1.2) + ssrf_filter (1.2.0) stimulus-rails (1.3.4) railties (>= 6.0.0) - stringio (3.1.1) + stringio (3.1.2) thor (1.3.2) thread_safe (0.3.6) tilt (2.4.0) - timeout (0.4.1) + timeout (0.4.2) turbo-rails (2.0.11) actionpack (>= 6.0.0) railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.6.0) + unicode-display_width (3.1.2) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) uniform_notifier (1.16.0) - uri (0.13.1) - useragent (0.16.10) + uri (1.0.2) + useragent (0.16.11) version_gem (1.1.4) virtus (2.0.0) axiom-types (~> 0.1) @@ -593,7 +596,6 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webrick (1.8.2) websocket (1.2.11) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) From 56681eb69fe104153137636fea6ebe4a70edfaa3 Mon Sep 17 00:00:00 2001 From: Ryan Wold Date: Thu, 5 Dec 2024 13:49:16 -0800 Subject: [PATCH 3/4] update gems --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 585859872..ef9f41a78 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -149,12 +149,12 @@ GEM rack-session (>= 1, < 3) aws-sigv4 (1.10.1) aws-eventstream (~> 1, >= 1.0.2) - axe-core-api (4.10.1) + axe-core-api (4.10.2) dumb_delegator ostruct virtus - axe-core-rspec (4.10.1) - axe-core-api (= 4.10.1) + axe-core-rspec (4.10.2) + axe-core-api (= 4.10.2) dumb_delegator ostruct virtus @@ -490,7 +490,7 @@ GEM rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (7.0.1) + rspec-rails (7.1.0) actionpack (>= 7.0) activesupport (>= 7.0) railties (>= 7.0) From f5c86a08514f8b6dcd1f4caf7b9f7afddcf7ab22 Mon Sep 17 00:00:00 2001 From: Ryan Wold Date: Thu, 5 Dec 2024 14:04:49 -0800 Subject: [PATCH 4/4] add security file --- SECURITY.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..dbca1179e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +## Supported Versions + +Only certain branches are supported with security updates. + +| Version (branch) | Supported | +| ---------------- | ----------- | +| main | :white_check_mark: | +| other | :x: | + +When using this code or reporting vulnerability please be sure to use supported branches and the most recent release. + +## Reporting a Vulnerability + +To report a security vulnerability, see https://www.gsa.gov/vulnerability-disclosure-policy for guidance.