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
+
+
+ Component Definitions
+
+
+
+ Document title |
+ Description |
+
+
+
+ <% @documents.each do |d| %>
+
+ <%= link_to d.title, d.url, class: "usa-link usa-link--external", rel: "noreferrer", target: "_blank" %> |
+ <%= d.description %> |
+
+ <% end %>
+
+
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"