rails_template_18f 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +4 -1
  5. data/README.md +16 -19
  6. data/exe/rails_template_18f +60 -0
  7. data/lib/generators/rails_template18f/active_storage/active_storage_generator.rb +135 -0
  8. data/lib/generators/rails_template18f/active_storage/templates/app/jobs/file_scan_job.rb +33 -0
  9. data/lib/generators/rails_template18f/active_storage/templates/app/models/file_upload.rb +25 -0
  10. data/lib/generators/rails_template18f/active_storage/templates/doc/adr/clamav.md.tt +30 -0
  11. data/lib/generators/rails_template18f/active_storage/templates/spec/jobs/file_scan_job_spec.rb +35 -0
  12. data/lib/generators/rails_template18f/active_storage/templates/spec/models/file_upload_spec.rb +38 -0
  13. data/lib/generators/rails_template18f/circleci/circleci_generator.rb +26 -10
  14. data/lib/generators/rails_template18f/cloud_gov_config/cloud_gov_config_generator.rb +28 -0
  15. data/lib/generators/rails_template18f/cloud_gov_config/templates/app/models/cloud_gov_config.rb +15 -0
  16. data/lib/generators/rails_template18f/cloud_gov_config/templates/spec/models/cloud_gov_config_spec.rb +44 -0
  17. data/lib/generators/rails_template18f/dap/dap_generator.rb +72 -0
  18. data/lib/generators/rails_template18f/github_actions/github_actions_generator.rb +27 -11
  19. data/lib/generators/rails_template18f/i18n/i18n_generator.rb +107 -0
  20. data/{templates → lib/generators/rails_template18f/i18n/templates}/config/locales/en.yml.tt +3 -3
  21. data/{templates → lib/generators/rails_template18f/i18n/templates}/config/locales/es.yml +3 -3
  22. data/{templates → lib/generators/rails_template18f/i18n/templates}/config/locales/fr.yml +3 -6
  23. data/{templates → lib/generators/rails_template18f/i18n/templates}/config/locales/zh.yml +0 -0
  24. data/lib/generators/rails_template18f/i18n_js/i18n_js_generator.rb +60 -0
  25. data/lib/generators/rails_template18f/i18n_js/templates/lib/tasks/i18n.rake +9 -0
  26. data/lib/generators/rails_template18f/newrelic/newrelic_generator.rb +79 -0
  27. data/{templates/config/newrelic.yml → lib/generators/rails_template18f/newrelic/templates/config/newrelic.yml.tt} +7 -7
  28. data/lib/generators/rails_template18f/sidekiq/sidekiq_generator.rb +70 -0
  29. data/lib/generators/rails_template18f/sidekiq/templates/config/initializers/redis.rb +14 -0
  30. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/README.md.tt +0 -0
  31. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/bootstrap/import.sh +0 -0
  32. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/bootstrap/main.tf.tt +3 -3
  33. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/bootstrap/providers.tf +0 -0
  34. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/bootstrap/run.sh.tt +1 -1
  35. data/lib/generators/rails_template18f/terraform/templates/terraform/bootstrap/teardown_creds.sh.tt +5 -0
  36. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/bootstrap/variables.tf +0 -0
  37. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/create_space_deployer.sh +0 -0
  38. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/destroy_space_deployer.sh +0 -0
  39. data/lib/generators/rails_template18f/terraform/templates/terraform/production/main.tf.tt +82 -0
  40. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/production/providers.tf.tt +0 -0
  41. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/production/variables.tf +0 -0
  42. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/clamav/main.tf.tt +50 -0
  43. data/{templates/terraform/shared/database → lib/generators/rails_template18f/terraform/templates/terraform/shared/clamav}/providers.tf +0 -0
  44. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/clamav/variables.tf +47 -0
  45. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/database/main.tf.tt +0 -0
  46. data/{templates/terraform/shared/domain → lib/generators/rails_template18f/terraform/templates/terraform/shared/database}/providers.tf +0 -0
  47. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/database/variables.tf +0 -0
  48. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/domain/main.tf.tt +1 -1
  49. data/{templates/terraform/shared/s3 → lib/generators/rails_template18f/terraform/templates/terraform/shared/domain}/providers.tf +0 -0
  50. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/domain/variables.tf +0 -0
  51. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/redis/main.tf.tt +23 -0
  52. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/redis/providers.tf +16 -0
  53. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/redis/variables.tf +42 -0
  54. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/s3/main.tf +0 -0
  55. data/lib/generators/rails_template18f/terraform/templates/terraform/shared/s3/providers.tf +16 -0
  56. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/shared/s3/variables.tf +0 -0
  57. data/lib/generators/rails_template18f/terraform/templates/terraform/staging/main.tf.tt +62 -0
  58. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/staging/providers.tf.tt +0 -0
  59. data/{templates → lib/generators/rails_template18f/terraform/templates}/terraform/staging/variables.tf +0 -0
  60. data/lib/generators/rails_template18f/terraform/terraform_generator.rb +84 -0
  61. data/lib/rails_template18f/app_updater.rb +19 -0
  62. data/lib/rails_template18f/generators/base.rb +53 -0
  63. data/lib/rails_template18f/generators/cloud_gov_options.rb +53 -0
  64. data/lib/rails_template18f/generators/pipeline_options.rb +18 -0
  65. data/lib/rails_template18f/generators.rb +11 -0
  66. data/lib/rails_template18f/version.rb +1 -1
  67. data/lib/rails_template_18f.rb +1 -4
  68. data/rails-template-18f.gemspec +1 -0
  69. data/template.rb +84 -148
  70. data/templates/README.md.tt +7 -44
  71. data/templates/config/deployment/staging.yml +1 -1
  72. data/templates/config/environments/ci.rb +0 -1
  73. data/templates/doc/compliance/apps/application.boundary.md.tt +4 -31
  74. data/templates/githooks/{pre-commit.tt → pre-commit} +0 -15
  75. data/templates/manifest.yml.tt +1 -2
  76. metadata +77 -34
  77. data/lib/rails_template18f/terraform_options.rb +0 -68
  78. data/templates/terraform/bootstrap/teardown_creds.sh.tt +0 -5
  79. data/templates/terraform/production/main.tf.tt +0 -50
  80. data/templates/terraform/staging/main.tf.tt +0 -30
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_helper"
4
+
5
+ RSpec.describe CloudGovConfig, type: :model do
6
+ subject { described_class }
7
+
8
+ describe ".dig" do
9
+ context "VCAP_SERVICES is blank" do
10
+ it "returns nil" do
11
+ expect(subject.dig(:s3, :credentials, :bucket)).to be_nil
12
+ end
13
+ end
14
+
15
+ context "VCAP_SERVICES is set" do
16
+ let(:bucket_name) { "bucket-name" }
17
+ let(:vcap) {
18
+ {
19
+ s3: [
20
+ {
21
+ credentials: {
22
+ bucket: bucket_name
23
+ }
24
+ }
25
+ ]
26
+ }
27
+ }
28
+
29
+ around do |example|
30
+ ClimateControl.modify VCAP_SERVICES: vcap.to_json do
31
+ example.run
32
+ end
33
+ end
34
+
35
+ it "can find a path" do
36
+ expect(subject.dig(:s3, :credentials, :bucket)).to eq bucket_name
37
+ end
38
+
39
+ it "returns nil for a missing path" do
40
+ expect(subject.dig(:s3, :credentials, :other)).to be_nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RailsTemplate18f
6
+ module Generators
7
+ class DapGenerator < ::Rails::Generators::Base
8
+ include Base
9
+
10
+ class_option :agency_code, default: "GSA", desc: "Agency code to track DAP metrics"
11
+
12
+ desc <<~DESC
13
+ Description:
14
+ Install JS snippet for Digital Analytics Program (DAP)
15
+ DESC
16
+
17
+ def update_content_security_policy
18
+ csp_file = "config/initializers/content_security_policy.rb"
19
+ gsub_file csp_file, /(policy.img_src .*)$/, '\1, "https://www.google-analytics.com"'
20
+ gsub_file csp_file, /(policy.script_src .*)$/, '\1, "https://dap.digitalgov.gov", "https://www.google-analytics.com"'
21
+ if file_content(csp_file).match?(/policy.connect_src/)
22
+ gsub_file csp_file, /(policy.connect_src .*)$/, '\1, "https://dap.digitalgov.gov", "https://www.google-analytics.com"'
23
+ else
24
+ gsub_file csp_file, /((#?)(\s+)policy.script_src .*)$/, "\\1\n\\2\\3policy.connect_src :self, \"https://dap.digitalgov.gov\", \"https://www.google-analytics.com\""
25
+ end
26
+ end
27
+
28
+ def install_js_snippet
29
+ insert_into_file "app/views/layouts/application.html.erb", <<EODAP, before: /^\s+<\/head>/
30
+
31
+ <% if Rails.env.production? %>
32
+ <!-- We participate in the US government's analytics program. See the data at analytics.usa.gov. -->
33
+ <%= javascript_include_tag "https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=#{options[:agency_code]}", async: true, id:"_fed_an_ua_tag" %>
34
+ <% end %>
35
+ EODAP
36
+ end
37
+
38
+ def update_readme
39
+ insertion_regex = /^## Documentation$/
40
+ if file_content("README.md").match?(insertion_regex)
41
+ insert_into_file "README.md", readme, before: insertion_regex
42
+ else
43
+ append_to_file "README.md", readme
44
+ end
45
+ end
46
+
47
+ def update_boundary_diagram
48
+ boundary_filename = "doc/compliance/apps/application.boundary.md"
49
+ insert_into_file boundary_filename, <<EOB, after: "Boundary(gsa_saas, \"GSA-authorized SaaS\") {\n"
50
+ System_Ext(dap, "DAP", "Analytics collection")
51
+ EOB
52
+ insert_into_file boundary_filename, <<~EOB, before: "@enduml"
53
+ Rel(browser, dap, "reports usage", "https (443)")
54
+ Rel(developer, dap, "View traffic statistics", "https GET (443)")
55
+ EOB
56
+ end
57
+
58
+ no_tasks do
59
+ def readme
60
+ <<~EOM
61
+ ## Analytics
62
+
63
+ Digital Analytics Program (DAP) code has been included for the Production environment, associated with #{options[:agency_code]}.
64
+
65
+ If #{app_name.titleize} is for another agency, update the agency line in `app/views/layouts/application.html.erb`
66
+
67
+ EOM
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rails/generators"
4
+
3
5
  module RailsTemplate18f
4
6
  module Generators
5
7
  class GithubActionsGenerator < ::Rails::Generators::Base
6
- include ::Rails::Generators::AppName
7
- include RailsTemplate18f::TerraformOptions
8
+ include Base
9
+ include PipelineOptions
8
10
 
9
11
  class_option :node_version, desc: "Node version to test against in actions"
10
12
 
@@ -13,10 +15,6 @@ module RailsTemplate18f
13
15
  Install Github Actions workflow files
14
16
  DESC
15
17
 
16
- def self.source_root
17
- @source_root ||= File.expand_path("templates", __dir__)
18
- end
19
-
20
18
  def install_actions
21
19
  directory "github", ".github"
22
20
  if !terraform?
@@ -26,10 +24,28 @@ module RailsTemplate18f
26
24
  end
27
25
 
28
26
  def update_readme
29
- insert_into_file "README.md", readme_cicd, after: "## CI/CD\n"
30
- insert_into_file "README.md", readme_staging_deploy, after: "#### Staging\n"
31
- insert_into_file "README.md", readme_prod_deploy, after: "#### Production\n"
32
- insert_into_file "README.md", readme_credentials, after: "#### Credentials and other Secrets\n"
27
+ if file_content("README.md").match?(/^## CI\/CD$/)
28
+ insert_into_file "README.md", readme_cicd, after: "## CI/CD\n"
29
+ insert_into_file "README.md", readme_staging_deploy, after: "#### Staging\n"
30
+ insert_into_file "README.md", readme_prod_deploy, after: "#### Production\n"
31
+ insert_into_file "README.md", readme_credentials, after: "#### Credentials and other Secrets\n"
32
+ else
33
+ append_to_file "README.md", <<~EOM
34
+ ## CI/CD
35
+ #{readme_cicd}
36
+
37
+ ### Deployment
38
+
39
+ #### Staging
40
+ #{readme_staging_deploy}
41
+
42
+ #### Production
43
+ #{readme_prod_deploy}
44
+
45
+ #### Credentials and other Secrets
46
+ #{readme_credentials}
47
+ EOM
48
+ end
33
49
  end
34
50
 
35
51
  def update_boundary_diagram
@@ -48,7 +64,7 @@ EOB
48
64
  readme_filename = "terraform/README.md"
49
65
  insert_into_file readme_filename, " |- .force-action-apply\n", after: " |- secrets.auto.tfvars\n"
50
66
  insert_into_file readme_filename, <<~EOM, after: /- `secrets.auto.tfvars`.*$/
51
- - `.force-action-apply` is a file that can be updated to force GitHub Actions to run `terraform apply` during the deploy phase
67
+ \n- `.force-action-apply` is a file that can be updated to force GitHub Actions to run `terraform apply` during the deploy phase
52
68
  EOM
53
69
  end
54
70
 
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "bundler"
5
+
6
+ module RailsTemplate18f
7
+ module Generators
8
+ class I18nGenerator < ::Rails::Generators::Base
9
+ include Base
10
+
11
+ class_option :languages, default: "es,fr,zh", desc: "Comma separated list of supported language short codes"
12
+
13
+ desc <<~DESC
14
+ Description:
15
+ Install translation framework and configuration for given languages.
16
+ Always installs configuration for English
17
+ DESC
18
+
19
+ def install_helper_gem_and_tasks
20
+ return if file_content("Gemfile").match?(/gem "i18n-tasks"/)
21
+ gem_group :development, :test do
22
+ gem "i18n-tasks", "~> 0.9"
23
+ end
24
+ Bundler.with_original_env do
25
+ in_root do
26
+ run "bundle install"
27
+ run "cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/"
28
+ run "cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/"
29
+ end
30
+ end
31
+ insert_into_file "config/i18n-tasks.yml", "\n#{indent("- app/assets/builds", 4)}", after: "exclude:"
32
+ uncomment_lines "config/i18n-tasks.yml", "ignore_missing:"
33
+ insert_into_file "config/i18n-tasks.yml", indent(<<~EOM), after: "ignore_missing:\n"
34
+ - 'shared.languages.*'
35
+ - 'shared.header.{title,close,demo_banner,menu}'
36
+ EOM
37
+ end
38
+
39
+ def install_translations
40
+ inside "config/locales" do
41
+ template "en.yml"
42
+ languages.each do |lang|
43
+ copy_file "#{lang}.yml"
44
+ end
45
+ end
46
+ end
47
+
48
+ def configure_i18n
49
+ application "config.i18n.fallbacks = [:en]"
50
+ available_regex = /^(\s*config.i18n.available_locales).*$/
51
+ if file_content("config/application.rb").match?(available_regex)
52
+ gsub_file "config/application.rb", available_regex, "\\1 = #{supported_languages}"
53
+ else
54
+ application "config.i18n.available_locales = #{supported_languages}"
55
+ end
56
+ end
57
+
58
+ def install_nav_helper
59
+ inject_into_module "app/helpers/application_helper.rb", "ApplicationHelper", indent(<<~'EOH')
60
+ def format_active_locale(locale_string)
61
+ link_classes = "usa-nav__link"
62
+ if locale_string.to_sym == I18n.locale
63
+ link_classes = "#{link_classes} usa-current"
64
+ end
65
+ link_to t("shared.languages.#{locale_string}"), root_path(locale: locale_string), class: link_classes
66
+ end
67
+ EOH
68
+ end
69
+
70
+ def install_around_action
71
+ return if languages.empty?
72
+ inject_into_class "app/controllers/application_controller.rb", "ApplicationController", indent(<<~EOM)
73
+ around_action :switch_locale
74
+
75
+ def switch_locale(&action)
76
+ locale = params[:locale] || I18n.default_locale
77
+ I18n.with_locale(locale, &action)
78
+ end
79
+ EOM
80
+ end
81
+
82
+ def install_route
83
+ return if languages.empty?
84
+ return if file_content("config/routes.rb").match?(/scope "\(:locale\)"/)
85
+ regex = /(^.+\.routes\.draw do\s*$)\n(.*)^end$/m
86
+ gsub_file "config/routes.rb", regex, <<~'EOR'
87
+ \1
88
+ scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
89
+ # Your application routes go here
90
+ \2
91
+ end
92
+ end
93
+ EOR
94
+ end
95
+
96
+ private
97
+
98
+ def supported_languages
99
+ @supported_languages ||= [:en, *languages]
100
+ end
101
+
102
+ def languages
103
+ @languages ||= options[:languages].split(",").map(&:to_sym)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -12,11 +12,11 @@ en:
12
12
  secure_heading: Secure .gov websites use HTTPS
13
13
  us_flag: U.S. Flag
14
14
  header:
15
- title: <%= app_name.titleize %>
16
- menu: Menu
17
15
  close: Close
18
- primary: Primary navigation
19
16
  demo_banner: TEST SITE - Do not use real personal information (demo purposes only) - TEST SITE
17
+ menu: Menu
18
+ primary: Primary navigation
19
+ title: <%= app_name.titleize %>
20
20
  languages:
21
21
  en: English
22
22
  es: Español
@@ -12,8 +12,8 @@ es:
12
12
  secure_heading: Los sitios web seguros .gov usan HTTPS
13
13
  us_flag: Bandera de Estados Unidos
14
14
  header:
15
- menu: Menú
16
15
  close: Cerrar
17
- primary: Navegacion primaria
18
16
  demo_banner: SITIO DE PRUEBA - No utilice información personal real (sólo para propósitos de demostración) - SITIO DE PRUEBA
19
- skip_link: Salte al contenido principal
17
+ menu: Menú
18
+ primary: Navegacion primaria
19
+ skip_link: Salte al contenido principal
@@ -8,15 +8,12 @@ fr:
8
8
  lock: Verrou
9
9
  locked_padlock: Verrou fermé
10
10
  official_site: Un site web officiel du gouvernement des États-Unis
11
- secure_description_html: Un <strong>verrou</strong> (%{lock_icon}) ou
12
- <strong>https://</strong> signifie que vous êtes connecté en toute
13
- sécurité au site Web .gov. Partagez des informations sensibles
14
- uniquement sur des sites Web officiels et sécurisés.
11
+ secure_description_html: Un <strong>verrou</strong> (%{lock_icon}) ou <strong>https://</strong> signifie que vous êtes connecté en toute sécurité au site Web .gov. Partagez des informations sensibles uniquement sur des sites Web officiels et sécurisés.
15
12
  secure_heading: Les sites Web sécurisés .gov utilisent HTTPS
16
13
  us_flag: Drapeau américain
17
14
  header:
18
- menu: Menu
19
15
  close: Fermer
20
- primary: Navigation primaire
21
16
  demo_banner: SITE DE TEST - N’utilisez pas de véritables données personnelles (il s’agit d’une démonstration seulement) - SITE DE TEST
17
+ menu: Menu
18
+ primary: Navigation primaire
22
19
  skip_link: Passer au contenu principal
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "bundler"
5
+
6
+ module RailsTemplate18f
7
+ module Generators
8
+ class I18nJsGenerator < ::Rails::Generators::Base
9
+ include Base
10
+
11
+ desc <<~DESC
12
+ Description:
13
+ Install and configure i18n-js gem to provide translations to JS code.
14
+
15
+ By default, will only export translations with keys that match `*.js.*`
16
+ DESC
17
+
18
+ def install_gem_and_tasks
19
+ return if file_content("Gemfile").match?(/gem "i18n-js"/)
20
+ gem "i18n-js", "~> 3.9"
21
+ Bundler.with_original_env do
22
+ in_root do
23
+ run "bundle install"
24
+ run "yarn add i18n-js"
25
+ generate "i18n:js:config"
26
+ end
27
+ end
28
+ append_to_file "config/i18n-js.yml", <<~EOYAML
29
+ # remove `only` to include all translations
30
+ translations:
31
+ - file: "app/assets/builds/translations.js"
32
+ only: "*.js.*"
33
+ EOYAML
34
+ end
35
+
36
+ def configure_asset_pipeline
37
+ copy_file "lib/tasks/i18n.rake"
38
+ environment "config.middleware.use I18n::JS::Middleware", env: :development
39
+ insert_into_file "app/views/layouts/application.html.erb", indent(<<~EOHTML, 4), after: /<%= stylesheet_link_tag "application".*$\n/
40
+ <%= javascript_include_tag "i18n", "data-turbo-track": "reload" %>
41
+ <%= javascript_include_tag "translations", "data-turbo-track": "reload" %>
42
+ EOHTML
43
+ append_to_file "app/assets/config/manifest.js", <<~EOJS
44
+ //= link i18n.js
45
+ //= link translations.js
46
+ EOJS
47
+ end
48
+
49
+ def ignore_generated_file
50
+ unless skip_git?
51
+ append_to_file ".gitignore", <<~EOM
52
+
53
+ # Generated by i18n-js
54
+ /public/javascripts/i18n.js
55
+ EOM
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ # export translations as part of asset precompile
2
+
3
+ Rake::Task["assets:precompile"].enhance(["i18n:js:export"])
4
+
5
+ if Rake::Task.task_defined?("test:prepare")
6
+ Rake::Task["test:prepare"].enhance(["i18n:js:export"])
7
+ elsif Rake::Task.task_defined?("db:test:prepare")
8
+ Rake::Task["db:test:prepare"].enhance(["i18n:js:export"])
9
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RailsTemplate18f
6
+ module Generators
7
+ class NewrelicGenerator < ::Rails::Generators::Base
8
+ include Base
9
+
10
+ desc <<~DESC
11
+ Description:
12
+ Install NewRelic config for FedRAMP collection
13
+ DESC
14
+
15
+ def update_content_security_policy
16
+ csp_file = "config/initializers/content_security_policy.rb"
17
+ gsub_file csp_file, /(policy.script_src .*)$/, '\1, "https://js-agent.newrelic.com", "https://*.nr-data.net"'
18
+ if file_content(csp_file).match?(/policy.connect_src/)
19
+ gsub_file csp_file, /(policy.connect_src .*)$/, '\1, "https://*.nr-data.net"'
20
+ else
21
+ gsub_file csp_file, /((#?)(\s+)policy.script_src .*)$/, "\\1\n\\2\\3policy.connect_src :self, \"https://*.nr-data.net\""
22
+ end
23
+ end
24
+
25
+ def install_gem
26
+ gem "newrelic_rpm", "~> 8.4"
27
+ end
28
+
29
+ def install_config
30
+ template "config/newrelic.yml"
31
+ end
32
+
33
+ def update_cloud_gov_manifest
34
+ insert_into_file "manifest.yml", " NEW_RELIC_LOG: stdout\n", before: /^\s+processes:/
35
+ end
36
+
37
+ def update_readme
38
+ insertion_regex = /^## Documentation$/
39
+ if file_content("README.md").match?(insertion_regex)
40
+ insert_into_file "README.md", readme, before: insertion_regex
41
+ else
42
+ append_to_file "README.md", readme
43
+ end
44
+ end
45
+
46
+ def update_boundary_diagram
47
+ boundary_filename = "doc/compliance/apps/application.boundary.md"
48
+ insert_into_file boundary_filename, <<EOB, after: "Boundary(gsa_saas, \"GSA-authorized SaaS\") {\n"
49
+ System_Ext(newrelic, "New Relic", "Monitoring SaaS")
50
+ EOB
51
+ insert_into_file boundary_filename, <<~EOB, before: "@enduml"
52
+ Rel(app, newrelic, "reports telemetry (ruby agent)", "tcp (443)")
53
+ Rel(browser, newrelic, "reports ux metrics (javascript agent)", "https (443)")
54
+ Rel(developer, newrelic, "Manage performance", "https (443)")
55
+ EOB
56
+ end
57
+
58
+ no_tasks do
59
+ def readme
60
+ <<~EOM
61
+ ## Monitoring with New Relic
62
+
63
+ The [New Relic Ruby agent](https://docs.newrelic.com/docs/apm/agents/ruby-agent/getting-started/introduction-new-relic-ruby) has been installed for monitoring this application.
64
+
65
+ The config lives at `config/newrelic.yml`, and points to a [FEDRAMP version of the New Relic service as its host](https://docs.newrelic.com/docs/security/security-privacy/compliance/fedramp-compliant-endpoints/). To access the metrics dashboard, you will need to be connected to VPN.
66
+
67
+ ### Getting started
68
+
69
+ To get started sending metrics via New Relic APM:
70
+ 1. Add your New Relic license key to the Rails credentials with key `new_relic_key`.
71
+ 1. Optionally, update `app_name` entries in `config/newrelic.yml` with what is registered for your application in New Relic
72
+ 1. Comment out the `agent_enabled: false` line in `config/newrelic.yml`
73
+ 1. Add the [Javascript snippet provided by New Relic](https://docs.newrelic.com/docs/browser/browser-monitoring/installation/install-browser-monitoring-agent) into `application.html.erb`. It is recommended to vary this based on environment (i.e. include one snippet for staging and another for production).
74
+ EOM
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -10,14 +10,14 @@
10
10
 
11
11
  common: &default_settings
12
12
  # Required license key associated with your New Relic account.
13
- license_key: <%= Rails.application.credentials.new_relic_key %>
13
+ license_key: <%%= Rails.application.credentials.new_relic_key %>
14
14
  # FEDRAMP-specific New Relic host
15
15
  # https://docs.newrelic.com/docs/security/security-privacy/compliance/fedramp-compliant-endpoints/
16
16
  host: 'gov-collector.newrelic.com'
17
17
 
18
18
  # Your application name. Renaming here affects where data displays in New
19
19
  # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications
20
- app_name: <APPNAME>
20
+ app_name: <%= app_name.titleize %>
21
21
 
22
22
  monitor_mode: true
23
23
 
@@ -30,8 +30,8 @@ common: &default_settings
30
30
 
31
31
  # This line disables agent regardless of other settings.
32
32
  # To enable the New Relic agent:
33
- # 1) Replace <APPNAME> in this file with the application name you want to show in New Relic
34
- # 2) add the New Relic license keys to the appropriate encrypted credentials file(s)
33
+ # 1) add the New Relic license keys to the appropriate encrypted credentials file(s)
34
+ # 2) Optionally, update app_name entries in this file with the application name you want to show in New Relic
35
35
  # 3) Comment out the line below
36
36
  agent_enabled: false
37
37
 
@@ -44,7 +44,7 @@ common: &default_settings
44
44
  # If your application has other named environments, configure them here.
45
45
  development:
46
46
  <<: *default_settings
47
- app_name: <APPNAME> (Development)
47
+ app_name: <%= app_name.titleize %> (Development)
48
48
 
49
49
  test:
50
50
  <<: *default_settings
@@ -58,8 +58,8 @@ ci:
58
58
 
59
59
  staging:
60
60
  <<: *default_settings
61
- app_name: <APPNAME> (Staging)
61
+ app_name: <%= app_name.titleize %> (Staging)
62
62
 
63
63
  production:
64
64
  <<: *default_settings
65
- app_name: <APPNAME> (Production)
65
+ app_name: <%= app_name.titleize %> (Production)
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module RailsTemplate18f
6
+ module Generators
7
+ class SidekiqGenerator < ::Rails::Generators::Base
8
+ include Base
9
+
10
+ desc <<~DESC
11
+ Description:
12
+ Install Sidekiq and configure it as the ActiveJob backend
13
+ DESC
14
+
15
+ def install_gem
16
+ gem "sidekiq", "~> 6.4"
17
+ end
18
+
19
+ def configure_server_runner
20
+ append_to_file "Procfile.dev", "worker: bundle exec sidekiq\n"
21
+ insert_into_file "manifest.yml", indent(<<~EOYAML), after: /processes:$\n/
22
+ - type: worker
23
+ instances: ((worker_instances))
24
+ memory: ((worker_memory))
25
+ command: bundle exec sidekiq
26
+ EOYAML
27
+ insert_into_file "manifest.yml", "\n - #{app_name}-redis-((env))", after: "services:"
28
+ inside "config/deployment" do
29
+ append_to_file "staging.yml", <<~EOYAML
30
+ worker_instances: 1
31
+ worker_memory: 256M
32
+ EOYAML
33
+ append_to_file "production.yml", <<~EOYAML
34
+ worker_instances: 1
35
+ worker_memory: 512M
36
+ EOYAML
37
+ end
38
+ end
39
+
40
+ def configure_active_job
41
+ generate "rails_template18f:cloud_gov_config"
42
+ copy_file "config/initializers/redis.rb"
43
+ application "config.active_job.queue_adapter = :sidekiq"
44
+ end
45
+
46
+ def configure_sidekiq_ui
47
+ prepend_to_file "config/routes.rb", "require \"sidekiq/web\"\n\n"
48
+ route <<~EOR
49
+ if Rails.env.development?
50
+ mount Sidekiq::Web => "/sidekiq"
51
+ end
52
+ EOR
53
+ end
54
+
55
+ def update_boundary_diagram
56
+ boundary_filename = "doc/compliance/apps/application.boundary.md"
57
+
58
+ insert_into_file boundary_filename, indent(<<~EOB, 16), after: /ContainerDb\(app_db.*$\n/
59
+ Container(worker, "<&layers> Sidekiq workers", "Ruby #{ruby_version}, Sidekiq", "Perform background work and data processing")
60
+ ContainerDb(redis, "Redis Database", "AWS ElastiCache (Redis)", "Background job queue")
61
+ EOB
62
+ insert_into_file boundary_filename, <<~EOB, before: "@enduml"
63
+ Rel(app, redis, "enqueue job parameters", "redis")
64
+ Rel(worker, redis, "dequeues job parameters", "redis")
65
+ Rel(worker, app_db, "reads/writes primary data", "psql (5432)")
66
+ EOB
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.to_prepare do
4
+ redis_url = CloudGovConfig.dig "aws-elasticache-redis", "credentials", "uri"
5
+ if redis_url.present?
6
+ Sidekiq.configure_server do |config|
7
+ config.redis = {url: redis_url, ssl: true}
8
+ end
9
+
10
+ Sidekiq.configure_client do |config|
11
+ config.redis = {url: redis_url, ssl: true}
12
+ end
13
+ end
14
+ end
@@ -9,9 +9,9 @@ module "s3" {
9
9
  cf_api_url = local.cf_api_url
10
10
  cf_user = var.cf_user
11
11
  cf_password = var.cf_password
12
- cf_org_name = "<%= @cloud_gov_organization %>"
13
- cf_space_name = "<%= @cloud_gov_production_space %>"
14
- s3_service_name = local.s3_service_name<% if @cloud_gov_organization == "sandbox-gsa" %>
12
+ cf_org_name = "<%= cloud_gov_organization %>"
13
+ cf_space_name = "<%= cloud_gov_production_space %>"
14
+ s3_service_name = local.s3_service_name<% if cloud_gov_organization == "sandbox-gsa" %>
15
15
  s3_plan_name = "basic-sandbox"<% end %>
16
16
  }
17
17
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  if [[ ! -f "secrets.auto.tfvars" ]]; then
4
- ../create_space_deployer.sh <%= @cloud_gov_production_space %> config-bootstrap-deployer > secrets.auto.tfvars
4
+ ../create_space_deployer.sh <%= cloud_gov_production_space %> config-bootstrap-deployer > secrets.auto.tfvars
5
5
  fi
6
6
 
7
7
  if [[ $# -gt 0 ]]; then
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ../destroy_space_deployer.sh <%= cloud_gov_production_space %> config-bootstrap-deployer
4
+
5
+ rm secrets.auto.tfvars