diff --git a/.github/actions/run-server/action.yml b/.github/actions/run-server/action.yml index 0672abd..6b17c95 100644 --- a/.github/actions/run-server/action.yml +++ b/.github/actions/run-server/action.yml @@ -11,6 +11,14 @@ inputs: runs: using: "composite" steps: + - name: Seed data + shell: bash + env: + RAILS_ENV: ${{ inputs.rails_env }} + DATABASE_URL: ${{ inputs.database_url }} + SECRET_KEY_BASE: not-actually-secret + run: bundle exec rails db:seed + - name: "Start server in background" shell: bash env: diff --git a/Gemfile b/Gemfile index 2b3084f..e35f09b 100644 --- a/Gemfile +++ b/Gemfile @@ -70,4 +70,5 @@ gem "sidekiq", "~> 7.2" group :test do gem "climate_control", "~> 1.0" + gem "shoulda-matchers", "~> 6.2" end diff --git a/Gemfile.lock b/Gemfile.lock index 2bc7399..15da52c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -281,6 +281,8 @@ GEM rexml ruby-progressbar (1.13.0) secure_headers (6.5.0) + shoulda-matchers (6.2.0) + activesupport (>= 5.2.0) sidekiq (7.2.4) concurrent-ruby (< 2) connection_pool (>= 2.3.0) @@ -351,6 +353,7 @@ DEPENDENCIES rails_template_18f! rspec-rails (~> 6.1) secure_headers (~> 6.3) + shoulda-matchers (~> 6.2) sidekiq (~> 7.2) sprockets-rails standard (~> 1.36) diff --git a/app/assets/stylesheets/uswds-components.scss b/app/assets/stylesheets/uswds-components.scss index 814d66a..7b6bd21 100644 --- a/app/assets/stylesheets/uswds-components.scss +++ b/app/assets/stylesheets/uswds-components.scss @@ -7,6 +7,7 @@ @forward "usa-section"; @forward "usa-language-selector"; // add additional packages here as you use them +@forward "usa-table"; // or replace these all with // @forward "uswds"; diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 45f463e..7ddfee6 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -1,4 +1,5 @@ class PagesController < ApplicationController def home + @documents = Document.all end end diff --git a/app/models/document.rb b/app/models/document.rb new file mode 100644 index 0000000..399e858 --- /dev/null +++ b/app/models/document.rb @@ -0,0 +1,14 @@ +class Document < ApplicationRecord + validates_presence_of :title, :url + + validate :url_is_https + + private + + def url_is_https + parsed = URI(url) + errors.add(:url, "must begin with https") unless parsed.scheme == "https" + rescue ArgumentError + errors.add(:url, "must begin with https") + end +end diff --git a/app/views/pages/home.html.erb b/app/views/pages/home.html.erb index 3453cf2..0f4198d 100644 --- a/app/views/pages/home.html.erb +++ b/app/views/pages/home.html.erb @@ -1,2 +1,20 @@ -

Pages#home

-

Find me in app/views/pages/home.html.erb

+

Published Compliance Documents

+ + + + + + + + + + <% @documents.each do |d| %> + + + + + <% end %> + +
+ Component Definitions +
Document titleDescription
<%= link_to d.title, d.url, class: "usa-link usa-link--external", rel: "noreferrer", target: "_blank" %><%= d.description %>
diff --git a/config/brakeman.ignore b/config/brakeman.ignore new file mode 100644 index 0000000..3d66779 --- /dev/null +++ b/config/brakeman.ignore @@ -0,0 +1,40 @@ +{ + "ignored_warnings": [ + { + "warning_type": "Cross-Site Scripting", + "warning_code": 4, + "fingerprint": "d0e9d6fdde0767b697aa5a6acefada357aadb15e48d55ce07a17ed87db41e8a6", + "check_name": "LinkToHref", + "message": "Potentially unsafe model attribute in `link_to` href", + "file": "app/views/pages/home.html.erb", + "line": 15, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", + "code": "link_to(Document.new.title, Document.new.url, :class => \"usa-link usa-link--external\", :rel => \"noreferrer\", :target => \"_blank\")", + "render_path": [ + { + "type": "controller", + "class": "PagesController", + "method": "home", + "line": 4, + "file": "app/controllers/pages_controller.rb", + "rendered": { + "name": "pages/home", + "file": "app/views/pages/home.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "pages/home" + }, + "user_input": "Document.new.url", + "confidence": "Weak", + "cwe_id": [ + 79 + ], + "note": "Document#url is validated to only begin with https" + } + ], + "updated": "2024-06-25 17:59:19 -0400", + "brakeman_version": "6.1.2" +} diff --git a/db/migrate/20240625213001_create_documents.rb b/db/migrate/20240625213001_create_documents.rb new file mode 100644 index 0000000..73151c9 --- /dev/null +++ b/db/migrate/20240625213001_create_documents.rb @@ -0,0 +1,11 @@ +class CreateDocuments < ActiveRecord::Migration[7.1] + def change + create_table :documents do |t| + t.string :title, null: false + t.text :description, null: false, default: "" + t.string :url, null: false + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f913998..974639e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,16 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 0) do +ActiveRecord::Schema[7.1].define(version: 2024_06_25_213001) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "documents", force: :cascade do |t| + t.string "title", null: false + t.text "description", default: "", null: false + t.string "url", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end diff --git a/db/seeds.rb b/db/seeds.rb index 4fbd6ed..58d01ce 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,3 +7,5 @@ # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| # MovieGenre.find_or_create_by!(name: genre_name) # end + +Document.find_or_create_by(title: "Cloud.gov LATO CRM", description: "OSCAL 1.1.2 Component Definition defining the CRM for a cloud.gov-hosted system persuing a GSA LATO", url: "https://raw.githubusercontent.com/GSA-TTS/docker-trestle/main/templates/component-definitions/cloud_gov/component-definition.json") diff --git a/doc/compliance/rendered/apps/data.logical.pdf b/doc/compliance/rendered/apps/data.logical.pdf new file mode 100644 index 0000000..abd63ce Binary files /dev/null and b/doc/compliance/rendered/apps/data.logical.pdf differ diff --git a/spec/models/document_spec.rb b/spec/models/document_spec.rb new file mode 100644 index 0000000..6ce45ca --- /dev/null +++ b/spec/models/document_spec.rb @@ -0,0 +1,10 @@ +require "rails_helper" + +RSpec.describe Document, type: :model do + describe "validations" do + it { should validate_presence_of :title } + it { should validate_presence_of :url } + it { should allow_value("https://raw.githubusercontent.com/GSA-TTS/docker-trestle/main/templates/component-definitions/cloud_gov/component-definition.json").for :url } + it { should_not allow_value("javascript:alert('oops')").for :url } + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index db6d989..3c22cf5 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -20,7 +20,7 @@ # directory. Alternatively, in the individual `*_spec.rb` files, manually # require only the support files necessary. # -# Rails.root.glob('spec/support/**/*.rb').sort.each { |f| require f } +Rails.root.glob("spec/support/**/*.rb").sort.each { |f| require f } # Checks for pending migrations and applies them before tests are run. # If you are not using ActiveRecord, you can remove these lines. diff --git a/spec/support/shoulda.rb b/spec/support/shoulda.rb new file mode 100644 index 0000000..7d045f3 --- /dev/null +++ b/spec/support/shoulda.rb @@ -0,0 +1,6 @@ +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end diff --git a/spec/views/pages/home.html.erb_spec.rb b/spec/views/pages/home.html.erb_spec.rb index 6ce2e2a..a66279d 100644 --- a/spec/views/pages/home.html.erb_spec.rb +++ b/spec/views/pages/home.html.erb_spec.rb @@ -1,6 +1,8 @@ require "rails_helper" RSpec.describe "pages/home.html.erb", type: :view do + before { assign(:documents, Document.all) } + it "displays the gov banner" do render template: "pages/home", layout: "layouts/application" expect(rendered).to match "An official website of the United States government"