From 20e41ff764ac319b7f203a2a563de7a6a51a73ad Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Sun, 4 Aug 2024 23:59:03 -0400 Subject: [PATCH 01/11] 22|24 Initial layout, user updates, login/logout --- Gemfile.lock | 55 +++---- app/controllers/application_controller.rb | 30 ++++ app/controllers/dashboard_controller.rb | 5 + app/controllers/sessions_controller.rb | 11 +- app/models/application_record.rb | 17 +++ app/models/user.rb | 54 ++++++- app/views/dashboard/index.html.erb | 9 ++ app/views/layouts/_header.html.erb | 18 +++ app/views/layouts/application.html.erb | 1 + config/environments/development.rb | 2 +- config/routes.rb | 3 + db/structure.sql | 173 ++++++++++++++++++---- spec/models/user_spec.rb | 67 ++++++++- spec/spec_helper.rb | 1 + yarn.lock | 74 ++++----- 15 files changed, 419 insertions(+), 101 deletions(-) create mode 100644 app/controllers/dashboard_controller.rb create mode 100644 app/views/dashboard/index.html.erb create mode 100644 app/views/layouts/_header.html.erb diff --git a/Gemfile.lock b/Gemfile.lock index 969dceae..d8f1e2f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,8 +96,8 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - codeclimate-test-reporter (1.0.9) - simplecov (<= 0.13) + codeclimate-test-reporter (1.0.7) + simplecov concurrent-ruby (1.3.3) connection_pool (2.4.1) crack (1.0.0) @@ -111,18 +111,18 @@ GEM irb (~> 1.10) reline (>= 0.3.8) diff-lcs (1.5.1) - docile (1.1.5) + docile (1.4.1) drb (2.2.1) erubi (1.13.0) - faraday (2.10.0) + faraday (2.10.1) faraday-net_http (>= 2.0, < 3.2) logger - faraday-net_http (3.1.0) + faraday-net_http (3.1.1) net-http foreman (0.88.1) globalid (1.2.1) activesupport (>= 6.1) - hashdiff (1.1.0) + hashdiff (1.1.1) i18n (1.14.5) concurrent-ruby (~> 1.0) io-console (0.7.2) @@ -165,19 +165,23 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.6-aarch64-linux) + nokogiri (1.16.7-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.6-arm64-darwin) + nokogiri (1.16.7-arm-linux) racc (~> 1.4) - nokogiri (1.16.6-x86_64-darwin) + nokogiri (1.16.7-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.6-x86_64-linux) + nokogiri (1.16.7-x86-linux) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) parallel (1.25.1) parser (3.3.4.0) ast (~> 2.4.1) racc - pg (1.5.6) + pg (1.5.7) prism (0.30.0) propshaft (0.9.0) actionpack (>= 7.0.0) @@ -186,7 +190,7 @@ GEM railties (>= 7.0.0) psych (5.1.2) stringio - public_suffix (6.0.0) + public_suffix (6.0.1) puma (6.4.2) nio4r (~> 2.0) racc (1.8.1) @@ -286,7 +290,7 @@ GEM rubocop (~> 1.0) rubocop-rspec (3.0.3) rubocop (~> 1.61) - ruby-lsp (0.17.9) + ruby-lsp (0.17.10) language_server-protocol (~> 3.17.0) prism (>= 0.29.0, < 0.31) rbs (>= 3, < 4) @@ -299,12 +303,13 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - simplecov (0.13.0) - docile (~> 1.1.0) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - sorbet-runtime (0.5.11492) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + sorbet-runtime (0.5.11504) stimulus-rails (1.3.3) railties (>= 6.0.0) stringio (3.1.1) @@ -335,14 +340,14 @@ GEM websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.16) + zeitwerk (2.6.17) PLATFORMS aarch64-linux - arm64-darwin-21 - arm64-darwin-22 - arm64-darwin-23 - x86_64-darwin-22 + arm-linux + arm64-darwin + x86-linux + x86_64-darwin x86_64-linux DEPENDENCIES @@ -382,4 +387,4 @@ RUBY VERSION ruby 3.2.4p170 BUNDLED WITH - 2.4.6 + 2.5.9 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7944f9f9..46ac30fe 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,34 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base + helper_method :current_user, :logged_in? + + def current_user + if session[:userinfo] + user_token = session["userinfo"][0]["sub"] + @current_user ||= User.find_by(token: user_token) if user_token + end + end + + def logged_in? + !!current_user + end + + def sign_in(login_userinfo) + user = User.user_from_userinfo(login_userinfo) + + @current_user = user + session[:userinfo] = login_userinfo + end + + def sign_out + @current_user = nil + session.delete(:userinfo) + end + + def redirect_if_logged_in(path = "/dashboard") + if logged_in? + redirect_to path, notice: "You are already logged in." + end + end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb new file mode 100644 index 00000000..2d803889 --- /dev/null +++ b/app/controllers/dashboard_controller.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class DashboardController < ApplicationController + def index; end +end \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 8795a792..e64fade8 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -12,17 +12,16 @@ def create redirect_to(login_gov.authorization_url, allow_other_host: true) end - def delete + def destroy login_gov = LoginGov.new - # TODO: update user session status, clear out JWT # TODO: add session duration to the security log - # TODO: delete session locally and Phoenix - redirect_to(login_gov.logout_url) + sign_out + redirect_to(login_gov.logout_url, allow_other_host: true) end def result - # TODO: store the user_info in the session - # session[:user_info] = @login_userinfo + sign_in(@login_userinfo) + redirect_to dashboard_path end private diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 08dc5379..011fa12c 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -2,4 +2,21 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class + + before_create :set_inserted_at + before_save :set_updated_at + + self.record_timestamps = false + + attribute :inserted_at, :datetime, precision: 6 + attribute :updated_at, :datetime, precision: 6 + + private + def set_inserted_at + self.inserted_at ||= Time.current + end + + def set_updated_at + self.updated_at ||= Time.current + end end diff --git a/app/models/user.rb b/app/models/user.rb index 7bd1bd84..30c8840c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,7 +47,7 @@ class User < ApplicationRecord has_many :submission_documents, class_name: 'Submissions::Document', dependent: :destroy has_many :message_context_statuses, dependent: :destroy - attribute :role, :string, default: -> { self[:role] } + attribute :role, :string attribute :status, :string, default: 'pending' attribute :finalized, :boolean, default: true attribute :display, :boolean, default: true @@ -80,8 +80,54 @@ class User < ApplicationRecord attribute :renewal_request, :string - attribute :created_at, :datetime, precision: 6 - attribute :updated_at, :datetime, precision: 6 - validates :email, presence: true + + # Finds, creates, or updates user from userinfo + # Find in case of user with existing token matching userinfo["sub"] + # Create in case of no token or email matching in userinfo + # Update in case of matching email to userinfo["email"] but no token set + # TODO: Add relevant security log tracking here? + def self.user_from_userinfo(userinfo) + email = userinfo[0]["email"] + token = userinfo[0]["sub"] + + if user = find_by(token: token) + user + elsif user = find_by(email: email) + update_admin_added_user(user, userinfo) + else + default_role_and_status = default_role_and_status_for_email(email) + default_role = default_role_and_status[0] + default_status = default_role_and_status[1] + + user = create({ + email: email, + role: default_role, + token: token, + terms_of_use: nil, + privacy_guidelines: nil, + status: default_status + }) + end + end + + private + def self.update_admin_added_user(user, userinfo) + update(user.id, {token: userinfo[0]["sub"]}) + end + + def self.default_role_and_status_for_email(email) + if default_challenge_manager?(email) + ["challenge_manager", "pending"] + else + ["solver", "active"] + end + end + + def self.default_challenge_manager?(email) + escaped_gov_tld = Regexp.escape('.gov') + matching_gov_string = ".*#{escaped_gov_tld}$" + gov_regex = Regexp.new(matching_gov_string) + gov_regex.match?(email) + end end diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb new file mode 100644 index 00000000..576f6fed --- /dev/null +++ b/app/views/dashboard/index.html.erb @@ -0,0 +1,9 @@ +
+
+ <% if logged_in? %> + Logged In Dashboard Index + <% else %> + Logged Out Dashboard Index + <% end %> +
+
\ No newline at end of file diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb new file mode 100644 index 00000000..fdc90313 --- /dev/null +++ b/app/views/layouts/_header.html.erb @@ -0,0 +1,18 @@ +
+
+
+ +
+ +
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e00cfa64..a9dfbf59 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,6 +14,7 @@ + <%= render "layouts/header" %> <%= yield %> diff --git a/config/environments/development.rb b/config/environments/development.rb index 4ffc19a7..5220eed1 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -79,7 +79,7 @@ config.login_gov_oidc = { idp_host: "https://idp.int.identitysandbox.gov", login_redirect_uri: "http://localhost:3000/auth/result", - logout_redirect_uri: "https://www.challenge.gov/", + logout_redirect_uri: "http://localhost:3000/", acr_value: "http://idmanagement.gov/ns/assurance/loa/1", client_id: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:challenge_gov_platform_dev", private_key_password: nil, diff --git a/config/routes.rb b/config/routes.rb index 12c114e8..7a1763af 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,6 +5,9 @@ get 'auth/result', to: 'sessions#result' resource 'session', only: [:new, :create, :destroy] + get '/', to: "dashboard#index" + get '/dashboard', to: "dashboard#index" + # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Can be used by load balancers and uptime monitors to verify that the app is live. get "up" => "rails/health#show", as: :rails_health_check diff --git a/db/structure.sql b/db/structure.sql index 379e3719..b6ebe855 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -24,29 +24,6 @@ CREATE TYPE public.oban_job_state AS ENUM ( ); --- --- Name: oban_jobs_notify(); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION public.oban_jobs_notify() RETURNS trigger - LANGUAGE plpgsql - AS $$ -DECLARE - channel text; - notice json; -BEGIN - IF NEW.state = 'available' THEN - channel = 'public.oban_insert'; - notice = json_build_object('queue', NEW.queue); - - PERFORM pg_notify(channel, notice::text); - END IF; - - RETURN NULL; -END; -$$; - - SET default_tablespace = ''; SET default_table_access_method = heap; @@ -175,6 +152,37 @@ CREATE SEQUENCE public.certification_log_id_seq ALTER SEQUENCE public.certification_log_id_seq OWNED BY public.certification_log.id; +-- +-- Name: challenge_managers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.challenge_managers ( + id bigint NOT NULL, + challenge_id bigint, + user_id bigint, + revoked_at timestamp(0) without time zone +); + + +-- +-- Name: challenge_owners_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.challenge_owners_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: challenge_owners_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.challenge_owners_id_seq OWNED BY public.challenge_managers.id; + + -- -- Name: challenges; Type: TABLE; Schema: public; Owner: - -- @@ -505,7 +513,6 @@ CREATE TABLE public.oban_jobs ( cancelled_at timestamp without time zone, CONSTRAINT attempt_range CHECK (((attempt >= 0) AND (attempt <= max_attempts))), CONSTRAINT positive_max_attempts CHECK ((max_attempts > 0)), - CONSTRAINT priority_range CHECK (((priority >= 0) AND (priority <= 3))), CONSTRAINT queue_length CHECK (((char_length(queue) > 0) AND (char_length(queue) < 128))), CONSTRAINT worker_length CHECK (((char_length(worker) > 0) AND (char_length(worker) < 128))) ); @@ -515,7 +522,7 @@ CREATE TABLE public.oban_jobs ( -- Name: TABLE oban_jobs; Type: COMMENT; Schema: public; Owner: - -- -COMMENT ON TABLE public.oban_jobs IS '11'; +COMMENT ON TABLE public.oban_jobs IS '12'; -- @@ -1072,6 +1079,13 @@ ALTER TABLE ONLY public.agency_members ALTER COLUMN id SET DEFAULT nextval('publ ALTER TABLE ONLY public.certification_log ALTER COLUMN id SET DEFAULT nextval('public.certification_log_id_seq'::regclass); +-- +-- Name: challenge_managers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenge_managers ALTER COLUMN id SET DEFAULT nextval('public.challenge_owners_id_seq'::regclass); + + -- -- Name: challenges id; Type: DEFAULT; Schema: public; Owner: - -- @@ -1251,6 +1265,14 @@ ALTER TABLE ONLY public.certification_log ADD CONSTRAINT certification_log_pkey PRIMARY KEY (id); +-- +-- Name: challenge_managers challenge_owners_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenge_managers + ADD CONSTRAINT challenge_owners_pkey PRIMARY KEY (id); + + -- -- Name: challenges challenges_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1307,6 +1329,14 @@ ALTER TABLE ONLY public.non_federal_partners ADD CONSTRAINT non_federal_partners_pkey PRIMARY KEY (id); +-- +-- Name: oban_jobs non_negative_priority; Type: CHECK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE public.oban_jobs + ADD CONSTRAINT non_negative_priority CHECK ((priority >= 0)) NOT VALID; + + -- -- Name: oban_jobs oban_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1506,10 +1536,75 @@ CREATE UNIQUE INDEX winners_phase_id_index ON public.phase_winners USING btree ( -- --- Name: oban_jobs oban_notify; Type: TRIGGER; Schema: public; Owner: - +-- Name: agencies agencies_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.agencies + ADD CONSTRAINT agencies_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES public.agencies(id); + + +-- +-- Name: agency_members agency_members_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.agency_members + ADD CONSTRAINT agency_members_agency_id_fkey FOREIGN KEY (agency_id) REFERENCES public.agencies(id); + + +-- +-- Name: agency_members agency_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.agency_members + ADD CONSTRAINT agency_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: certification_log certification_log_approver_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.certification_log + ADD CONSTRAINT certification_log_approver_id_fkey FOREIGN KEY (approver_id) REFERENCES public.users(id); + + +-- +-- Name: certification_log certification_log_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- -CREATE TRIGGER oban_notify AFTER INSERT ON public.oban_jobs FOR EACH ROW EXECUTE FUNCTION public.oban_jobs_notify(); +ALTER TABLE ONLY public.certification_log + ADD CONSTRAINT certification_log_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: challenge_managers challenge_owners_challenge_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenge_managers + ADD CONSTRAINT challenge_owners_challenge_id_fkey FOREIGN KEY (challenge_id) REFERENCES public.challenges(id); + + +-- +-- Name: challenge_managers challenge_owners_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenge_managers + ADD CONSTRAINT challenge_owners_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: challenges challenges_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenges + ADD CONSTRAINT challenges_agency_id_fkey FOREIGN KEY (agency_id) REFERENCES public.agencies(id); + + +-- +-- Name: challenges challenges_sub_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.challenges + ADD CONSTRAINT challenges_sub_agency_id_fkey FOREIGN KEY (sub_agency_id) REFERENCES public.agencies(id); -- @@ -1520,6 +1615,14 @@ ALTER TABLE ONLY public.challenges ADD CONSTRAINT challenges_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id); +-- +-- Name: federal_partners federal_partners_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.federal_partners + ADD CONSTRAINT federal_partners_agency_id_fkey FOREIGN KEY (agency_id) REFERENCES public.agencies(id); + + -- -- Name: federal_partners federal_partners_challenge_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -1528,6 +1631,14 @@ ALTER TABLE ONLY public.federal_partners ADD CONSTRAINT federal_partners_challenge_id_fkey FOREIGN KEY (challenge_id) REFERENCES public.challenges(id); +-- +-- Name: federal_partners federal_partners_sub_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.federal_partners + ADD CONSTRAINT federal_partners_sub_agency_id_fkey FOREIGN KEY (sub_agency_id) REFERENCES public.agencies(id); + + -- -- Name: message_context_statuses message_context_statuses_message_context_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -1704,6 +1815,14 @@ ALTER TABLE ONLY public.timeline_events ADD CONSTRAINT timeline_events_challenge_id_fkey FOREIGN KEY (challenge_id) REFERENCES public.challenges(id); +-- +-- Name: users users_agency_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_agency_id_fkey FOREIGN KEY (agency_id) REFERENCES public.agencies(id); + + -- -- Name: phase_winners winners_phase_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index e1550e7a..a9ae61ce 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -34,7 +34,21 @@ # require 'rails_helper' -RSpec.describe User do +RSpec.describe User, type: :model do + let(:gov_userinfo) do + [{ + "email" => "test@example.gov", + "sub" => SecureRandom.uuid + }] + end + + let(:non_gov_userinfo) do + [{ + "email" => "test@example.com", + "sub" => SecureRandom.uuid + }] + end + describe 'validations' do it 'validates presence of email' do user = described_class.new(email: nil) @@ -49,4 +63,55 @@ expect(user.active_session).to be_falsey end end + + describe 'user_from_userinfo' do + it 'finds user if one matches token' do + email = gov_userinfo[0]["email"] + token = gov_userinfo[0]["sub"] + + user = described_class.create!(email: email, token: token) + + found_user = User.user_from_userinfo(gov_userinfo) + + expect(user).to eq(found_user) + end + + it 'creates pending challenge_manager user if no matching token or email and .gov email' do + email = gov_userinfo[0]["email"] + token = gov_userinfo[0]["sub"] + + created_user = User.user_from_userinfo(gov_userinfo) + + expect(created_user.email).to eq(email) + expect(created_user.token).to eq(token) + expect(created_user.role).to eq("challenge_manager") + expect(created_user.status).to eq("pending") + end + + it 'creates active solver user if no matching token or email and non .gov email' do + email = non_gov_userinfo[0]["email"] + token = non_gov_userinfo[0]["sub"] + + created_user = User.user_from_userinfo(non_gov_userinfo) + + expect(created_user.email).to eq(email) + expect(created_user.token).to eq(token) + expect(created_user.role).to eq("solver") + expect(created_user.status).to eq("active") + end + + it 'update user with token if matching email but no token set (from admin creation)' do + email = gov_userinfo[0]["email"] + token = gov_userinfo[0]["sub"] + + user = described_class.create!(email: email) + expect(user.token).to eq(nil) + + updated_user = User.user_from_userinfo(gov_userinfo) + + expect(updated_user.id).to eq(user.id) + expect(updated_user.email).to eq(email) + expect(updated_user.token).to eq(token) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f528642d..9a0bfd4a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ require 'simplecov' require 'webmock/rspec' +require 'securerandom' SimpleCov.command_name 'RSpec' diff --git a/yarn.lock b/yarn.lock index 75fed022..cb0ba9d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -173,11 +173,11 @@ integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg== "@types/node@*": - version "20.14.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.9.tgz#12e8e765ab27f8c421a1820c99f5f313a933b420" - integrity sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg== + version "22.1.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.1.0.tgz#6d6adc648b5e03f0e83c78dc788c2b037d0ad94b" + integrity sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw== dependencies: - undici-types "~5.26.4" + undici-types "~6.13.0" "@types/vinyl@^2.0.4": version "2.0.12" @@ -494,14 +494,14 @@ braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" browserslist@^4.21.10: - version "4.23.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.1.tgz#ce4af0534b3d37db5c1a4ca98b9080f985041e96" - integrity sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw== + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001629" - electron-to-chromium "^1.4.796" - node-releases "^2.0.14" - update-browserslist-db "^1.0.16" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" buffer-builder@^0.2.0: version "0.2.0" @@ -549,10 +549,10 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg== -caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001629: - version "1.0.30001637" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001637.tgz#d9fab531493d9ef46a8ff305e9812190ac463f21" - integrity sha512-1x0qRI1mD1o9e+7mBI7XtzFAP4XszbHaVWsMiGbSPLYekKTJF7K+FNk6AsXH4sUpc+qrsI3pVgf1Jdl/uGkuSQ== +caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001646: + version "1.0.30001646" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz#d472f2882259ba032dd73ee069ff01bfd059b25d" + integrity sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw== cheerio-select@^2.1.0: version "2.1.0" @@ -948,10 +948,10 @@ each-props@^1.3.2: is-plain-object "^2.0.1" object.defaults "^1.1.0" -electron-to-chromium@^1.4.796: - version "1.4.812" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.812.tgz#21b78709c5a13af5d5c688d135a22dcea7617acf" - integrity sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg== +electron-to-chromium@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz#cd477c830dd6fca41fbd5465c1ff6ce08ac22343" + integrity sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA== element-closest@^2.0.1: version "2.0.2" @@ -1629,9 +1629,9 @@ ignore@^5.2.0: integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== immutable@^4.0.0: - version "4.3.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.6.tgz#6a05f7858213238e587fb83586ffa3b4b27f0447" - integrity sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ== + version "4.3.7" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381" + integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== indent-string@^4.0.0: version "4.0.0" @@ -1706,9 +1706,9 @@ is-buffer@^1.1.5: integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-core-module@^2.13.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" - integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: hasown "^2.0.2" @@ -2138,10 +2138,10 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== normalize-package-data@^2.3.2: version "2.5.0" @@ -3177,10 +3177,10 @@ undertaker@^1.2.1: object.reduce "^1.0.0" undertaker-registry "^1.0.0" -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5" + integrity sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg== union-value@^1.0.0: version "1.0.1" @@ -3213,10 +3213,10 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.16: - version "1.0.16" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" - integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: escalade "^3.1.2" picocolors "^1.0.1" From 2b8dff4cea5a77999dd49c840c635cfcf20340f1 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Mon, 5 Aug 2024 00:07:03 -0400 Subject: [PATCH 02/11] 22|24 Rubocop autofixes --- Rakefile | 6 +++++- app/controllers/application_controller.rb | 14 ++++++------- app/controllers/dashboard_controller.rb | 2 +- app/models/application_record.rb | 3 ++- app/models/user.rb | 25 +++++++++++------------ spec/models/user_spec.rb | 4 ++-- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/Rakefile b/Rakefile index 84b021d0..786d01de 100644 --- a/Rakefile +++ b/Rakefile @@ -10,7 +10,11 @@ Rails.application.load_tasks namespace :cf do desc "Only run on the first application instance" task :on_first_instance do - instance_index = JSON.parse(ENV["VCAP_APPLICATION"])["instance_index"] rescue nil + instance_index = begin + JSON.parse(ENV.fetch("VCAP_APPLICATION", nil))["instance_index"] + rescue + nil + end exit(0) unless instance_index == 0 end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 46ac30fe..f53a6777 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,10 +4,10 @@ class ApplicationController < ActionController::Base helper_method :current_user, :logged_in? def current_user - if session[:userinfo] - user_token = session["userinfo"][0]["sub"] - @current_user ||= User.find_by(token: user_token) if user_token - end + return unless session[:userinfo] + + user_token = session["userinfo"][0]["sub"] + @current_user ||= User.find_by(token: user_token) if user_token end def logged_in? @@ -27,8 +27,8 @@ def sign_out end def redirect_if_logged_in(path = "/dashboard") - if logged_in? - redirect_to path, notice: "You are already logged in." - end + return unless logged_in? + + redirect_to path, notice: "You are already logged in." end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 2d803889..6049155d 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -2,4 +2,4 @@ class DashboardController < ApplicationController def index; end -end \ No newline at end of file +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 011fa12c..2dc662cc 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -3,8 +3,8 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class - before_create :set_inserted_at before_save :set_updated_at + before_create :set_inserted_at self.record_timestamps = false @@ -12,6 +12,7 @@ class ApplicationRecord < ActiveRecord::Base attribute :updated_at, :datetime, precision: 6 private + def set_inserted_at self.inserted_at ||= Time.current end diff --git a/app/models/user.rb b/app/models/user.rb index 30c8840c..9eeb9827 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,9 +91,9 @@ def self.user_from_userinfo(userinfo) email = userinfo[0]["email"] token = userinfo[0]["sub"] - if user = find_by(token: token) + if user = find_by(token:) user - elsif user = find_by(email: email) + elsif user = find_by(email:) update_admin_added_user(user, userinfo) else default_role_and_status = default_role_and_status_for_email(email) @@ -101,26 +101,25 @@ def self.user_from_userinfo(userinfo) default_status = default_role_and_status[1] user = create({ - email: email, - role: default_role, - token: token, - terms_of_use: nil, - privacy_guidelines: nil, - status: default_status - }) + email:, + role: default_role, + token:, + terms_of_use: nil, + privacy_guidelines: nil, + status: default_status + }) end end - private def self.update_admin_added_user(user, userinfo) - update(user.id, {token: userinfo[0]["sub"]}) + update(user.id, { token: userinfo[0]["sub"] }) end def self.default_role_and_status_for_email(email) if default_challenge_manager?(email) - ["challenge_manager", "pending"] + %w[challenge_manager pending] else - ["solver", "active"] + %w[solver active] end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a9ae61ce..95230d96 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -69,7 +69,7 @@ email = gov_userinfo[0]["email"] token = gov_userinfo[0]["sub"] - user = described_class.create!(email: email, token: token) + user = described_class.create!(email:, token:) found_user = User.user_from_userinfo(gov_userinfo) @@ -104,7 +104,7 @@ email = gov_userinfo[0]["email"] token = gov_userinfo[0]["sub"] - user = described_class.create!(email: email) + user = described_class.create!(email:) expect(user.token).to eq(nil) updated_user = User.user_from_userinfo(gov_userinfo) From 9ac306134937686dcd1e2c6bfa6f5ccc12b93ce8 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Mon, 5 Aug 2024 00:50:52 -0400 Subject: [PATCH 03/11] 22|24 Remaining Rubocop adjustments --- Rakefile | 4 +-- app/controllers/application_controller.rb | 2 +- app/models/user.rb | 35 ++++++++++++++--------- config/locales/en.yml | 1 + spec/models/user_spec.rb | 10 +++---- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Rakefile b/Rakefile index 786d01de..f925e9ee 100644 --- a/Rakefile +++ b/Rakefile @@ -9,12 +9,12 @@ Rails.application.load_tasks namespace :cf do desc "Only run on the first application instance" - task :on_first_instance do + task on_first_instance: :environment do instance_index = begin JSON.parse(ENV.fetch("VCAP_APPLICATION", nil))["instance_index"] rescue nil end - exit(0) unless instance_index == 0 + exit(0) unless instance_index.zero? end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f53a6777..34c3a93f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -29,6 +29,6 @@ def sign_out def redirect_if_logged_in(path = "/dashboard") return unless logged_in? - redirect_to path, notice: "You are already logged in." + redirect_to path, notice: I18n.t("already_logged_in_notice") end end diff --git a/app/models/user.rb b/app/models/user.rb index 9eeb9827..3e49593b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,23 +91,12 @@ def self.user_from_userinfo(userinfo) email = userinfo[0]["email"] token = userinfo[0]["sub"] - if user = find_by(token:) + if (user = find_by(token:)) user - elsif user = find_by(email:) + elsif (user = find_by(email:)) update_admin_added_user(user, userinfo) else - default_role_and_status = default_role_and_status_for_email(email) - default_role = default_role_and_status[0] - default_status = default_role_and_status[1] - - user = create({ - email:, - role: default_role, - token:, - terms_of_use: nil, - privacy_guidelines: nil, - status: default_status - }) + create_user_from_userinfo(userinfo) end end @@ -115,6 +104,24 @@ def self.update_admin_added_user(user, userinfo) update(user.id, { token: userinfo[0]["sub"] }) end + def self.create_user_from_userinfo(userinfo) + email = userinfo[0]["email"] + token = userinfo[0]["sub"] + + default_role_and_status = default_role_and_status_for_email(email) + default_role = default_role_and_status[0] + default_status = default_role_and_status[1] + + create({ + email:, + role: default_role, + token:, + terms_of_use: nil, + privacy_guidelines: nil, + status: default_status + }) + end + def self.default_role_and_status_for_email(email) if default_challenge_manager?(email) %w[challenge_manager pending] diff --git a/config/locales/en.yml b/config/locales/en.yml index e0a9572e..86bbf980 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -31,3 +31,4 @@ en: hello: "Hello world" please_try_again: "Please try again." login_error: "There was an issue with logging in. Please try again." + already_logged_in_notice: "You are already logged in." diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 95230d96..5c41693e 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -71,7 +71,7 @@ user = described_class.create!(email:, token:) - found_user = User.user_from_userinfo(gov_userinfo) + found_user = described_class.user_from_userinfo(gov_userinfo) expect(user).to eq(found_user) end @@ -80,7 +80,7 @@ email = gov_userinfo[0]["email"] token = gov_userinfo[0]["sub"] - created_user = User.user_from_userinfo(gov_userinfo) + created_user = described_class.user_from_userinfo(gov_userinfo) expect(created_user.email).to eq(email) expect(created_user.token).to eq(token) @@ -92,7 +92,7 @@ email = non_gov_userinfo[0]["email"] token = non_gov_userinfo[0]["sub"] - created_user = User.user_from_userinfo(non_gov_userinfo) + created_user = described_class.user_from_userinfo(non_gov_userinfo) expect(created_user.email).to eq(email) expect(created_user.token).to eq(token) @@ -105,9 +105,9 @@ token = gov_userinfo[0]["sub"] user = described_class.create!(email:) - expect(user.token).to eq(nil) + expect(user.token).to be_nil - updated_user = User.user_from_userinfo(gov_userinfo) + updated_user = described_class.user_from_userinfo(gov_userinfo) expect(updated_user.id).to eq(user.id) expect(updated_user.email).to eq(email) From f645e0e2913731c7fd002d2dec45ad729fe59e5e Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Mon, 5 Aug 2024 20:10:49 -0400 Subject: [PATCH 04/11] 22|24 Fix rubocop issues --- app/models/login_gov.rb | 1 - spec/models/user_spec.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/models/login_gov.rb b/app/models/login_gov.rb index ac88f861..7d4e398e 100644 --- a/app/models/login_gov.rb +++ b/app/models/login_gov.rb @@ -21,7 +21,6 @@ def initialize(msg, code:, body:) attr_reader :config def initialize(config = Rails.configuration.login_gov_oidc) - puts config.inspect @config = config.freeze.dup end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5c41693e..4de05d55 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -34,7 +34,7 @@ # require 'rails_helper' -RSpec.describe User, type: :model do +RSpec.describe User do let(:gov_userinfo) do [{ "email" => "test@example.gov", From 29608f646abb2c911406f9d485342ab9e98077e9 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Tue, 6 Aug 2024 11:41:42 -0400 Subject: [PATCH 05/11] 22|24 Fix failing tests --- spec/requests/sessions_request_spec.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/requests/sessions_request_spec.rb b/spec/requests/sessions_request_spec.rb index 0e752824..34220665 100644 --- a/spec/requests/sessions_request_spec.rb +++ b/spec/requests/sessions_request_spec.rb @@ -13,9 +13,9 @@ end it "delete session logs the user out" do - skip "not implemented" - delete "/session/:id" - assert_response :success + # skip "not implemented" + delete "/session" + assert_response :redirect end it "get /auth/result without params redirects to login" do @@ -34,9 +34,11 @@ code = "ABC123" login_gov = instance_double(LoginGov) allow(LoginGov).to receive(:new).and_return(login_gov) - allow(login_gov).to receive(:exchange_token_from_auth_result).with(code).and_return({ email: "test@example.com" }) + allow(login_gov).to receive(:exchange_token_from_auth_result).with(code).and_return( + [{ email: "test@example.com", sub: "sub" }] + ) get "/auth/result", params: { code: } - expect(response).to have_http_status(:ok) - expect(response).to render_template(:result) + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to("/dashboard") end end From 1715b88fd1577633c433066ed9731ed42d280e28 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Tue, 6 Aug 2024 11:42:44 -0400 Subject: [PATCH 06/11] 22|24 Revert tool-versions system change --- .tool-versions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.tool-versions b/.tool-versions index 70b96cf5..e87d7b95 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -ruby system -nodejs system -yarn system +ruby 3.2.4 +nodejs 20.15.1 +yarn 1.22.22 From 006c02ad1dd12ef77d15876fdc633717d809979e Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Tue, 6 Aug 2024 13:37:22 -0400 Subject: [PATCH 07/11] 22|24 Add back development.rb --- config/environments/development.rb | 78 ++++++++++++++++++++++++++ spec/requests/sessions_request_spec.rb | 1 - 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 config/environments/development.rb diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 00000000..cd4e78a2 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.enable_reloading = true + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable server timing + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + + # Highlight code that enqueued background job in logs. + config.active_job.verbose_enqueue_logs = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true + + # Raise error when a before_action's only/except options reference missing actions + config.action_controller.raise_on_missing_callback_actions = true +end \ No newline at end of file diff --git a/spec/requests/sessions_request_spec.rb b/spec/requests/sessions_request_spec.rb index 34220665..8466e041 100644 --- a/spec/requests/sessions_request_spec.rb +++ b/spec/requests/sessions_request_spec.rb @@ -13,7 +13,6 @@ end it "delete session logs the user out" do - # skip "not implemented" delete "/session" assert_response :redirect end From 830b6353d91e6cafc5fbc6916b5a1f6492405520 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Tue, 6 Aug 2024 14:10:32 -0400 Subject: [PATCH 08/11] Locked simplecov version for codeclimate error --- Gemfile | 2 +- Gemfile.lock | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 5024a7d0..d3e33ea2 100644 --- a/Gemfile +++ b/Gemfile @@ -90,6 +90,6 @@ group :test do gem "capybara" gem "selenium-webdriver" gem "rspec_junit_formatter" - gem "simplecov" + gem 'simplecov', '~> 0.17.0', require: false gem "rails-controller-testing" end diff --git a/Gemfile.lock b/Gemfile.lock index d8f1e2f8..b7752961 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,7 +84,7 @@ GEM base64 (0.2.0) bigdecimal (3.1.8) bindex (0.8.1) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) builder (3.3.0) capybara (3.40.0) @@ -276,7 +276,7 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.3) + rubocop-ast (1.32.0) parser (>= 3.3.1.0) rubocop-performance (1.21.1) rubocop (>= 1.48.1, < 2.0) @@ -288,9 +288,9 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - rubocop-rspec (3.0.3) + rubocop-rspec (3.0.4) rubocop (~> 1.61) - ruby-lsp (0.17.10) + ruby-lsp (0.17.11) language_server-protocol (~> 3.17.0) prism (>= 0.29.0, < 0.31) rbs (>= 3, < 4) @@ -303,13 +303,12 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - simplecov (0.22.0) + simplecov (0.17.1) docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - sorbet-runtime (0.5.11504) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + sorbet-runtime (0.5.11511) stimulus-rails (1.3.3) railties (>= 6.0.0) stringio (3.1.1) @@ -376,7 +375,7 @@ DEPENDENCIES rubocop-rspec ruby-lsp selenium-webdriver - simplecov + simplecov (~> 0.17.0) stimulus-rails turbo-rails tzinfo-data From 924e72d4666729488017d150370adafea8101cd5 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Fri, 9 Aug 2024 14:11:39 -0400 Subject: [PATCH 09/11] 22 PR feedback. Mil emails. Timestamp changes --- app/models/application_record.rb | 19 +++++--------- app/models/user.rb | 9 ++----- spec/models/user_spec.rb | 45 ++++++++++++++++++++++++++++++++ spec/rails_helper.rb | 2 ++ 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 2dc662cc..caea3da0 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -3,21 +3,14 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class - before_save :set_updated_at - before_create :set_inserted_at - - self.record_timestamps = false - attribute :inserted_at, :datetime, precision: 6 attribute :updated_at, :datetime, precision: 6 - private - - def set_inserted_at - self.inserted_at ||= Time.current - end - - def set_updated_at - self.updated_at ||= Time.current + private_class_method + # created_at timestamp is currently overridden to inserted_at due to shared Phoenix database + def self.timestamp_attributes_for_create + # only strings allowed here, symbols won't work, see below commit for more details + # https://github.com/rails/rails/commit/2b5dacb43dd92e98e1fd240a80c2a540ed380257 + super << 'inserted_at' end end diff --git a/app/models/user.rb b/app/models/user.rb index 3e49593b..eccb03a5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -108,9 +108,7 @@ def self.create_user_from_userinfo(userinfo) email = userinfo[0]["email"] token = userinfo[0]["sub"] - default_role_and_status = default_role_and_status_for_email(email) - default_role = default_role_and_status[0] - default_status = default_role_and_status[1] + default_role, default_status = default_role_and_status_for_email(email) create({ email:, @@ -131,9 +129,6 @@ def self.default_role_and_status_for_email(email) end def self.default_challenge_manager?(email) - escaped_gov_tld = Regexp.escape('.gov') - matching_gov_string = ".*#{escaped_gov_tld}$" - gov_regex = Regexp.new(matching_gov_string) - gov_regex.match?(email) + /\.(gov|mil)$/.match?(email) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4de05d55..46bd772f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -42,6 +42,13 @@ }] end + let(:mil_userinfo) do + [{ + "email" => "test@example.mil", + "sub" => SecureRandom.uuid + }] + end + let(:non_gov_userinfo) do [{ "email" => "test@example.com", @@ -64,6 +71,32 @@ end end + describe 'timestamps' do + it 'properly sets inserted_at and updated_at' do + email = gov_userinfo[0]["email"] + token = gov_userinfo[0]["sub"] + + user = described_class.create!(email:, token:) + + expect(user.inserted_at).not_to be_nil + expect(user.updated_at).not_to be_nil + + expect(user.inserted_at).to be_within(1.second).of(Time.current) + expect(user.updated_at).to be_within(1.second).of(Time.current) + + original_inserted_at = user.inserted_at + original_updated_at = user.updated_at + + travel_to 1.hour.from_now do + user.update!(email: 'new-email@example.com') + + expect(user.inserted_at).to eq(original_inserted_at) + expect(user.updated_at).to be > original_updated_at + expect(user.updated_at).to be_within(1.second).of(Time.current) + end + end + end + describe 'user_from_userinfo' do it 'finds user if one matches token' do email = gov_userinfo[0]["email"] @@ -88,6 +121,18 @@ expect(created_user.status).to eq("pending") end + it 'creates pending challenge_manager user if no matching token or email and .mil email' do + email = mil_userinfo[0]["email"] + token = mil_userinfo[0]["sub"] + + created_user = described_class.user_from_userinfo(mil_userinfo) + + expect(created_user.email).to eq(email) + expect(created_user.token).to eq(token) + expect(created_user.role).to eq("challenge_manager") + expect(created_user.status).to eq("pending") + end + it 'creates active solver user if no matching token or email and non .gov email' do email = non_gov_userinfo[0]["email"] token = non_gov_userinfo[0]["sub"] diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index ea28bc2b..0dad5f5b 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -66,4 +66,6 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") + + config.include ActiveSupport::Testing::TimeHelpers end From d46abdbae6115fa8c63f62a19479f2b4c43b87af Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Fri, 9 Aug 2024 14:15:45 -0400 Subject: [PATCH 10/11] 22 Fix trailing whitespace errors --- app/models/application_record.rb | 5 ++--- spec/models/user_spec.rb | 6 +++--- spec/rails_helper.rb | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index caea3da0..4e9fa68d 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -6,11 +6,10 @@ class ApplicationRecord < ActiveRecord::Base attribute :inserted_at, :datetime, precision: 6 attribute :updated_at, :datetime, precision: 6 - private_class_method # created_at timestamp is currently overridden to inserted_at due to shared Phoenix database def self.timestamp_attributes_for_create # only strings allowed here, symbols won't work, see below commit for more details - # https://github.com/rails/rails/commit/2b5dacb43dd92e98e1fd240a80c2a540ed380257 - super << 'inserted_at' + # https://github.com/rails/rails/commit/2b5dacb43dd92e98e1fd240a80c2a540ed380257 + super << 'inserted_at' end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 46bd772f..6beee664 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -80,16 +80,16 @@ expect(user.inserted_at).not_to be_nil expect(user.updated_at).not_to be_nil - + expect(user.inserted_at).to be_within(1.second).of(Time.current) - expect(user.updated_at).to be_within(1.second).of(Time.current) + expect(user.updated_at).to be_within(1.second).of(Time.current) original_inserted_at = user.inserted_at original_updated_at = user.updated_at travel_to 1.hour.from_now do user.update!(email: 'new-email@example.com') - + expect(user.inserted_at).to eq(original_inserted_at) expect(user.updated_at).to be > original_updated_at expect(user.updated_at).to be_within(1.second).of(Time.current) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 0dad5f5b..be870792 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -66,6 +66,6 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") - + config.include ActiveSupport::Testing::TimeHelpers end From b68d881684f4f1623605c3a27341fdddd7b50f07 Mon Sep 17 00:00:00 2001 From: Chris Preisinger Date: Fri, 9 Aug 2024 14:40:10 -0400 Subject: [PATCH 11/11] 22 Reverted structure.sql22 Reverted structure.sql --- db/structure.sql | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index b6ebe855..65453f93 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -98,18 +98,6 @@ CREATE SEQUENCE public.agency_members_id_seq ALTER SEQUENCE public.agency_members_id_seq OWNED BY public.agency_members.id; --- --- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.ar_internal_metadata ( - key character varying NOT NULL, - value character varying, - created_at timestamp(6) without time zone NOT NULL, - updated_at timestamp(6) without time zone NOT NULL -); - - -- -- Name: certification_log; Type: TABLE; Schema: public; Owner: - -- @@ -1249,14 +1237,6 @@ ALTER TABLE ONLY public.agency_members ADD CONSTRAINT agency_members_pkey PRIMARY KEY (id); --- --- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.ar_internal_metadata - ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); - - -- -- Name: certification_log certification_log_pkey; Type: CONSTRAINT; Schema: public; Owner: - --