rails_template_18f 2.1.0 → 2.2.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile.lock +5 -3
  4. data/lib/generators/rails_template18f/active_storage/active_storage_generator.rb +4 -3
  5. data/lib/generators/rails_template18f/auditree/auditree_generator.rb +36 -6
  6. data/lib/generators/rails_template18f/auditree/templates/gitlab/auditree.yml.tt +48 -0
  7. data/lib/generators/rails_template18f/cloud_gov_config/cloud_gov_config_generator.rb +0 -8
  8. data/lib/generators/rails_template18f/cloud_gov_config/templates/app/models/cloud_gov_config.rb +6 -15
  9. data/lib/generators/rails_template18f/cloud_gov_config/templates/spec/models/cloud_gov_config_spec.rb +13 -19
  10. data/lib/generators/rails_template18f/github_actions/github_actions_generator.rb +0 -4
  11. data/lib/generators/rails_template18f/gitlab_ci/gitlab_ci_generator.rb +0 -9
  12. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/rails.yml +2 -2
  13. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab/terraform.yml +8 -3
  14. data/lib/generators/rails_template18f/gitlab_ci/templates/gitlab-ci.yml.tt +2 -1
  15. data/lib/generators/rails_template18f/oscal/oscal_generator.rb +15 -1
  16. data/lib/generators/rails_template18f/oscal/templates/bin/trestle.tt +10 -1
  17. data/lib/generators/rails_template18f/oscal/templates/gitlab/trestle.yml.tt +29 -0
  18. data/lib/generators/rails_template18f/public_egress/public_egress_generator.rb +1 -1
  19. data/lib/generators/rails_template18f/sidekiq/templates/config/initializers/redis.rb +1 -1
  20. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/apply.sh +25 -0
  21. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/main.tf.tt +98 -0
  22. data/lib/generators/rails_template18f/terraform/templates/gitlab_bootstrap/setup_shadowenv.sh +59 -0
  23. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/templates/backend_config.tftpl +6 -0
  24. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/templates/bot_secrets.tftpl +5 -0
  25. data/lib/generators/rails_template18f/terraform/templates/s3_bootstrap/common/users.auto.tfvars +5 -0
  26. data/lib/generators/rails_template18f/terraform/templates/{full_bootstrap → s3_bootstrap/full}/main.tf.tt +2 -9
  27. data/lib/generators/rails_template18f/terraform/templates/{sandbox_bootstrap → s3_bootstrap/sandbox}/main.tf.tt +2 -2
  28. data/lib/generators/rails_template18f/terraform/templates/terraform/.shadowenv.d/.gitignore +3 -0
  29. data/lib/generators/rails_template18f/terraform/templates/terraform/README.md.tt +38 -26
  30. data/lib/generators/rails_template18f/terraform/templates/terraform/app.tf.tt +1 -0
  31. data/lib/generators/rails_template18f/terraform/templates/terraform/main.tf.tt +3 -3
  32. data/lib/generators/rails_template18f/terraform/templates/terraform/providers.tf.tt +2 -8
  33. data/lib/generators/rails_template18f/terraform/templates/terraform/staging.tfvars.tt +5 -5
  34. data/lib/generators/rails_template18f/terraform/templates/terraform/terraform.sh.tt +40 -15
  35. data/lib/generators/rails_template18f/terraform/templates/terraform/variables.tf.tt +6 -6
  36. data/lib/generators/rails_template18f/terraform/terraform_generator.rb +78 -5
  37. data/lib/rails_template18f/version.rb +1 -1
  38. data/template.rb +32 -15
  39. metadata +21 -13
  40. data/lib/generators/rails_template18f/terraform/templates/terraform/bootstrap/templates/backend_config.tftpl +0 -8
  41. /data/lib/generators/rails_template18f/{github_actions → oscal}/templates/github/workflows/assemble-ssp.yml.tt +0 -0
  42. /data/lib/generators/rails_template18f/{github_actions → oscal}/templates/github/workflows/validate-ssp.yml +0 -0
  43. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap/templates → gitlab_bootstrap}/bot_secrets.tftpl +0 -0
  44. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap → gitlab_bootstrap}/users.auto.tfvars +0 -0
  45. /data/lib/generators/rails_template18f/terraform/templates/{terraform/bootstrap → s3_bootstrap/common}/apply.sh +0 -0
  46. /data/lib/generators/rails_template18f/terraform/templates/{full_bootstrap → s3_bootstrap/full}/imports.tf.tftpl +0 -0
  47. /data/lib/generators/rails_template18f/terraform/templates/{sandbox_bootstrap → s3_bootstrap/sandbox}/imports.tf.tftpl +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c98e855c8844d55ba478f2fe9a0bac27cea41e417e7f76b2be22f97c5363963c
4
- data.tar.gz: 5eeb6079ee3d68350ee473aec5156fd54f2f47d837a1230ac62080b223960220
3
+ metadata.gz: bab13c0d757c29b86c139635bed3f016cc486d38299b7aa90533d888b6995d69
4
+ data.tar.gz: 447e73554b32dd86782cf52c4cda2699f55c4e0706c05f813e82515a2e61912f
5
5
  SHA512:
6
- metadata.gz: 24df2ba12417ab9754e851406fc9c77b21c23b21206f7760dd0ba23d0793f25b3fad5c8a57fbf2c5f9743cb8e0edd2bbe6a89b4f8603342f9ec893f3a28bdb34
7
- data.tar.gz: 681823d0918b7ddacde8372051d85f8636954b92aa97467655b89e7d5ac3580768b31d1b7e12d27cd8d2a296c92769ae065b578dbb1b143aa8dbb15e9927fcde
6
+ metadata.gz: cad79214c9110e3fb33968b8c6d1fc98477c6c979bc58724e9b88f57985456ca7d404515dd004891dade32d4e95183f1a90c12d4d05ee87753f52867f9efde94
7
+ data.tar.gz: ecb278387c12d47fc9bc611f26c0787fa7c4c2dda43fa14ce8f176bfb4cf9d0d2c6b04718ab0faa3569b4f5897e9d65cdc0b0944972c64648e8e401d9b341881
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.2.0] - 2025-06-27
4
+
5
+ - Prevent non-compliant hostnames by replacing underscores with dashes
6
+ - use shadowenv for configuring terraform backend secrets
7
+ - use GitLab http backend for terraform state storage whenever configuring both terraform and GitLab CI
8
+ - Create GitLabCI jobs for oscal and auditree generators
9
+ - fixes for deploying to the sandbox-gsa cloug.gov org
10
+
3
11
  ## [2.1.0] - 2025-04-29
4
12
 
5
13
  - Terraform generator updates to remove the old cloudfoundy-community provider and reduce the need for cloud.gov service accounts
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_template_18f (2.1.0)
4
+ rails_template_18f (2.2.0)
5
5
  activesupport (~> 8.0.1)
6
6
  colorize (~> 1.1)
7
7
  railties (~> 8.0.1)
@@ -85,8 +85,9 @@ GEM
85
85
  date
86
86
  stringio
87
87
  racc (1.8.1)
88
- rack (3.1.12)
89
- rack-session (2.0.0)
88
+ rack (3.1.16)
89
+ rack-session (2.1.1)
90
+ base64 (>= 0.1.0)
90
91
  rack (>= 3.0.0)
91
92
  rack-test (2.2.0)
92
93
  rack (>= 1.3)
@@ -177,6 +178,7 @@ GEM
177
178
 
178
179
  PLATFORMS
179
180
  arm64-darwin-23
181
+ arm64-darwin-24
180
182
  x86_64-darwin-20
181
183
  x86_64-darwin-21
182
184
  x86_64-linux
@@ -20,12 +20,13 @@ module RailsTemplate18f
20
20
  environment "config.active_storage.service = :local", env: "ci"
21
21
  append_to_file "config/storage.yml", <<~EOYAML
22
22
 
23
+ <% cgc = CloudGovConfig.new %>
23
24
  amazon:
24
25
  service: S3
25
- access_key_id: <%= CloudGovConfig.dig(:s3, :credentials, :access_key_id) %>
26
- secret_access_key: <%= CloudGovConfig.dig(:s3, :credentials, :secret_access_key) %>
26
+ access_key_id: <%= cgc.dig(:s3, :credentials, :access_key_id) %>
27
+ secret_access_key: <%= cgc.dig(:s3, :credentials, :secret_access_key) %>
27
28
  region: us-gov-west-1
28
- bucket: <%= CloudGovConfig.dig(:s3, :credentials, :bucket) %>
29
+ bucket: <%= cgc.dig(:s3, :credentials, :bucket) %>
29
30
  EOYAML
30
31
  end
31
32
 
@@ -41,7 +41,7 @@ module RailsTemplate18f
41
41
  plant-helper -f /tmp/rspec.json -c assessment-plans -d "RSpec run assessment plan"
42
42
  -t 31536000 -l #{auditree_evidence_locker}
43
43
 
44
- - name: Plan assessment results in evidence locker
44
+ - name: Plant assessment results in evidence locker
45
45
  uses: ./.github/actions/auditree-cmd
46
46
  env:
47
47
  GITHUB_TOKEN: ${{ secrets.AUDITREE_GITHUB_TOKEN }}
@@ -54,6 +54,19 @@ PLANT_HELPER_STEPS
54
54
  end
55
55
  end
56
56
 
57
+ def copy_gitlab_actions
58
+ if file_exists? ".gitlab-ci.yml"
59
+ directory "gitlab", ".gitlab"
60
+ insert_into_file ".gitlab-ci.yml", " - local: \".gitlab/auditree.yml\"\n", after: /^include:\n/
61
+ insert_into_file ".gitlab-ci.yml", " AUDITREE_VERSION: #{docker_auditree_tag}\n", after: /^variables:\n/
62
+ insert_into_file ".gitlab-ci.yml", <<EOY, after: /^\s+- bundle exec rspec\n/
63
+ artifacts:
64
+ paths:
65
+ - tmp/oscal/**/*
66
+ EOY
67
+ end
68
+ end
69
+
57
70
  def update_readme
58
71
  if file_content("README.md").match?("## Documentation")
59
72
  insert_into_file "README.md", readme_contents, after: "## Documentation\n"
@@ -74,7 +87,7 @@ PLANT_HELPER_STEPS
74
87
  end
75
88
 
76
89
  def auditree_evidence_locker
77
- options[:evidence_locker].present? ? options[:evidence_locker] : "https://github.com/GSA-TTS/TKTK_#{app_name}_evidence"
90
+ options[:evidence_locker].present? ? options[:evidence_locker] : "REPLACE_THIS_WITH_YOUR_EVIDENCE_LOCKER_REPO"
78
91
  end
79
92
 
80
93
  def git_email
@@ -98,10 +111,9 @@ PLANT_HELPER_STEPS
98
111
  1. Docker desktop must be running
99
112
  1. Initialize the config file with `bin/auditree init`
100
113
  1. Create an evidence locker repository with a default or blank README
101
- 1. Create a github personal access token to interact with the code repo and evidence locker and set as `AUDITREE_GITHUB_TOKEN` secret within your Github Actions secrets.
102
- 1. Update `config/auditree.template.json` with the repo addresses for your locker and code repos
103
- #{(options[:evidence_locker].blank? && file_exists?(".github/workflows/rspec.yml")) ? "1. Update `.github/workflows/rspec.yml` with the locker repository URL" : ""}
104
- 1. Copy the `devtools_cloud_gov` component definition into the project with the latest docker-trestle
114
+ 1. Update `config/auditree.template.json` with the repo address for your locker
115
+ #{ci_readme_contents.chomp}
116
+ 1. Copy the `devtools_cloud_gov` component definition into the project with the latest docker-trestle after [setting up docker-trestle](#initial-trestle-setup)
105
117
 
106
118
  #### Ongoing use
107
119
 
@@ -109,6 +121,24 @@ PLANT_HELPER_STEPS
109
121
  auditree and using new checks.
110
122
  README
111
123
  end
124
+
125
+ def ci_readme_contents
126
+ if file_exists? ".gitlab-ci.yml"
127
+ <<~README
128
+ 1. Remove the `repo_integrity` section of `config/auditree.template.json`
129
+ 1. Create a gitlab personal access token with `write_repository` scope to interact with the code repo and evidence locker and set as `AUDITREE_GITLAB_TOKEN` secret within your CI/CD variables.
130
+ #{options[:evidence_locker].blank? ? "1. Update `.gitlab/auditree.yml` with the locker repository URL" : ""}
131
+ README
132
+ elsif file_exists? ".github/workflows"
133
+ <<~README
134
+ 1. Update `config/auditree.template.json` with the repo address for your code repos
135
+ 1. Create a github personal access token to interact with the code repo and evidence locker and set as `AUDITREE_GITHUB_TOKEN` secret within your Github Actions secrets.
136
+ #{options[:evidence_locker].blank? ? "1. Update `.github/workflows/rspec.yml` with the locker repository URL" : ""}
137
+ README
138
+ else
139
+ ""
140
+ end
141
+ end
112
142
  end
113
143
  end
114
144
  end
@@ -0,0 +1,48 @@
1
+ .auditree:setup:
2
+ inherit:
3
+ default: false
4
+ image: "ghcr.io/gsa-tts/auditree:${AUDITREE_VERSION}"
5
+ variables:
6
+ CDEF: "${CI_PROJECT_DIR}/doc/compliance/oscal/component-definitions/devtools_cloud_gov/component-definition.json"
7
+ AUDITREE_CONFIG: "${CI_PROJECT_DIR}/config/auditree.template.json"
8
+ before_script:
9
+ - git config --global user.name "$GITLAB_USER_NAME"
10
+ - git config --global user.email "$GITLAB_USER_EMAIL"
11
+ - cf api api.fr.cloud.gov
12
+ - cd $HOME
13
+ - export GITLAB_TOKEN="auditree-gitlab-token:${AUDITREE_GITLAB_TOKEN}"
14
+
15
+ auditree:
16
+ extends: .auditree:setup
17
+ stage: scan
18
+ script:
19
+ - fetch -c "$CDEF" -t "$AUDITREE_CONFIG"
20
+ - check -c "$CDEF" -t "$AUDITREE_CONFIG" -o "$CI_PROJECT_DIR"
21
+ artifacts:
22
+ paths:
23
+ - auditree.json
24
+ rules:
25
+ - if: $CI_PIPELINE_SOURCE == "schedule"
26
+
27
+ rspec:plant:
28
+ extends: .auditree:setup
29
+ stage: test
30
+ needs: ["rspec"]
31
+ variables:
32
+ PLAN_FILE: "${CI_PROJECT_DIR}/tmp/oscal/assessment-plans/rspec/assessment-plan.json"
33
+ RESULT_FILE: "${CI_PROJECT_DIR}/tmp/oscal/assessment-results/rspec/assessment-results.json"
34
+ script:
35
+ - |
36
+ if [ -f "$PLAN_FILE" ]; then
37
+ plant-helper -f "$PLAN_FILE" -c assessment-plans -d "RSpec run assessment plan" -t 31536000 -l "<%= auditree_evidence_locker %>"
38
+ else
39
+ echo "No plan file, skipping plant"
40
+ fi
41
+ - |
42
+ if [ -f "$RESULT_FILE" ]; then
43
+ plant-helper -f "$RESULT_FILE" -c assessment-results -d "RSpec run assessment results" -t 31536000 -l "<%= auditree_evidence_locker %>"
44
+ else
45
+ echo "No result file, skipping plant"
46
+ fi
47
+ rules:
48
+ - if: $CI_PIPELINE_SOURCE != "schedule"
@@ -12,14 +12,6 @@ module RailsTemplate18f
12
12
  Install a helper class to retrieve configuration from ENV["VCAP_SERVICES"]
13
13
  DESC
14
14
 
15
- def install_climate_control
16
- return if gem_installed?("climate_control")
17
- gem_group :test do
18
- gem "climate_control", "~> 1.2"
19
- end
20
- bundle_install
21
- end
22
-
23
15
  def install_model_and_test
24
16
  copy_file "app/models/cloud_gov_config.rb"
25
17
  copy_file "spec/models/cloud_gov_config_spec.rb"
@@ -1,23 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class CloudGovConfig
4
- ENV_VARIABLE = "VCAP_SERVICES"
4
+ attr_reader :vcap_services
5
5
 
6
- def self.dig(*path)
7
- return nil if ENV[ENV_VARIABLE].blank?
8
- first, *rest = path
9
- vcap_services[first]&.first&.dig(*rest)
10
- end
11
-
12
- def self.vcap_services
13
- if Rails.env.test?
14
- parse_env
15
- else
16
- @vcap_services ||= parse_env
17
- end
6
+ def initialize(env = ENV["VCAP_SERVICES"])
7
+ @vcap_services = env.blank? ? {} : JSON.parse(env).with_indifferent_access
18
8
  end
19
9
 
20
- private_class_method def self.parse_env
21
- JSON.parse(ENV[ENV_VARIABLE]).with_indifferent_access
10
+ def dig(*path)
11
+ first, *rest = path
12
+ vcap_services[first]&.first&.dig(*rest)
22
13
  end
23
14
  end
@@ -3,35 +3,29 @@
3
3
  require "rails_helper"
4
4
 
5
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
6
+ describe "#dig" do
7
+ [nil, "", "{}"].each do |blank|
8
+ context "VCAP_SERVICES is #{blank.inspect}" do
9
+ subject { described_class.new blank }
10
+ it "returns nil" do
11
+ expect(subject.dig(:s3, :credentials, :bucket)).to be_nil
12
+ end
12
13
  end
13
14
  end
14
15
 
15
16
  context "VCAP_SERVICES is set" do
17
+ subject { described_class.new vcap }
16
18
  let(:bucket_name) { "bucket-name" }
17
19
  let(:vcap) {
18
20
  {
19
- s3: [
20
- {
21
- credentials: {
22
- bucket: bucket_name
23
- }
21
+ s3: [{
22
+ credentials: {
23
+ bucket: bucket_name
24
24
  }
25
- ]
26
- }
25
+ }]
26
+ }.to_json
27
27
  }
28
28
 
29
- around do |example|
30
- ClimateControl.modify VCAP_SERVICES: vcap.to_json do
31
- example.run
32
- end
33
- end
34
-
35
29
  it "can find a path" do
36
30
  expect(subject.dig(:s3, :credentials, :bucket)).to eq bucket_name
37
31
  end
@@ -17,10 +17,6 @@ module RailsTemplate18f
17
17
 
18
18
  def install_actions
19
19
  directory "github", ".github"
20
- if !oscal_dir_exists?
21
- remove_file ".github/workflows/validate-ssp.yml"
22
- remove_file ".github/workflows/assemble-ssp.yml"
23
- end
24
20
  if !terraform_manage_spaces?
25
21
  remove_file ".github/workflows/terraform-production.yml"
26
22
  remove_file ".github/workflows/deploy-production.yml"
@@ -79,7 +79,6 @@ EOB
79
79
  | `CF_USERNAME` | cloud.gov SpaceDeployer username |
80
80
  | `CF_PASSWORD` | cloud.gov SpaceDeployer password |
81
81
  | `RAILS_MASTER_KEY` | `config/master.key` |
82
- #{terraform_secret_values}
83
82
  EOM
84
83
  end
85
84
 
@@ -96,7 +95,6 @@ EOB
96
95
  | `CF_USERNAME` | cloud.gov SpaceDeployer username |
97
96
  | `CF_PASSWORD` | cloud.gov SpaceDeployer password |
98
97
  | `PRODUCTION_RAILS_MASTER_KEY` | `config/credentials/production.key`. Should be marked as `Protected`. |
99
- #{terraform_secret_values}
100
98
  EOM
101
99
  else
102
100
  "Production deploys are not supported in the sandbox organization."
@@ -114,13 +112,6 @@ EOB
114
112
 
115
113
  private
116
114
 
117
- def terraform_secret_values
118
- <<~EOM
119
- | `TERRAFORM_PUBLIC_BACKEND_CONFIG` | File-type variable containing all entries from secrets.backend.tfvars _except_ `secret_key`. Marked as `Visible` |
120
- | `TERRAFORM_SECRET_BACKEND_CONFIG` | File-type variable containing the `secret_key` line from secrets.backend.tfvars. Masked and hidden. |
121
- EOM
122
- end
123
-
124
115
  def postgres_version
125
116
  options[:postgres_version]
126
117
  end
@@ -30,7 +30,7 @@ include:
30
30
  alias: pg
31
31
  before_script:
32
32
  - !reference [.setup-ruby]
33
- - export DATABASE_URL="postgres://postgres:${POSTGRES_PASSWORD}@${CI_SERVICE_pg}:5432/${POSTGRES_DB}"
33
+ - export DATABASE_URL="postgres://postgres:${POSTGRES_PASSWORD}@${WSR_SERVICE_HOST_pg}:5432/${POSTGRES_DB}"
34
34
  - bin/rails db:prepare
35
35
 
36
36
  .run-server:
@@ -47,7 +47,7 @@ include:
47
47
  - sleep 5
48
48
 
49
49
  .owasp:setup:
50
- stage: test
50
+ stage: scan
51
51
  extends: .run-server
52
52
  image: "rcahearngsa/owasp-ruby:${RUBY_VERSION}"
53
53
  variables:
@@ -8,11 +8,16 @@
8
8
  entrypoint: ["sh"]
9
9
  variables:
10
10
  CF_API_URL: https://api.fr.cloud.gov
11
- TERRAFORM_BACKEND_KEY: terraform.tfstate.staging
11
+ TF_STATE_NAME: staging
12
+ TF_HTTP_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE_NAME}
13
+ TF_HTTP_LOCK_ADDRESS: ${TF_HTTP_ADDRESS}/lock
14
+ TF_HTTP_UNLOCK_ADDRESS: ${TF_HTTP_ADDRESS}/lock
15
+ TF_HTTP_USERNAME: gitlab-ci-token
16
+ TF_HTTP_PASSWORD: ${CI_JOB_TOKEN}
12
17
  dependencies: []
13
18
  before_script:
14
19
  - cd terraform
15
- - terraform init -backend-config=$TERRAFORM_PUBLIC_BACKEND_CONFIG -backend-config=$TERRAFORM_SECRET_BACKEND_CONFIG -backend-config="key=$TERRAFORM_BACKEND_KEY"
20
+ - terraform init
16
21
  rules:
17
22
  - if: $CI_PIPELINE_SOURCE != "schedule"
18
23
 
@@ -25,4 +30,4 @@
25
30
  dependencies: null
26
31
  variables:
27
32
  CF_USER: $CF_USERNAME
28
- TERRAFORM_BACKEND_KEY: terraform.tfstate.production
33
+ TF_STATE_NAME: "production"
@@ -10,6 +10,7 @@ workflow:
10
10
  stages:
11
11
  - build
12
12
  - test
13
+ - scan
13
14
  - deploy
14
15
 
15
16
  variables:
@@ -80,7 +81,7 @@ rspec:
80
81
  - if: $CI_PIPELINE_SOURCE != "schedule"
81
82
 
82
83
  pa11y_scan:
83
- stage: test
84
+ stage: scan
84
85
  extends: .run-server
85
86
  script:
86
87
  - !reference [.install-puppet-deps]
@@ -49,6 +49,16 @@ module RailsTemplate18f
49
49
  end
50
50
  end
51
51
 
52
+ def copy_gitlab_ci
53
+ if use_gitlab_ci?
54
+ directory "gitlab", ".gitlab"
55
+ if file_exists? ".gitlab-ci.yml"
56
+ insert_into_file ".gitlab-ci.yml", " - local: \".gitlab/trestle.yml\"\n", after: /^include:\n/
57
+ insert_into_file ".gitlab-ci.yml", " TRESTLE_VERSION: #{docker_trestle_tag}\n", after: /^variables:\n/
58
+ end
59
+ end
60
+ end
61
+
52
62
  def update_readme
53
63
  if file_content("README.md").match?("## Documentation")
54
64
  insert_into_file "README.md", readme_contents, after: "## Documentation\n"
@@ -85,13 +95,17 @@ module RailsTemplate18f
85
95
  end
86
96
 
87
97
  def docker_trestle_tag
88
- options[:tag].present? ? options[:tag] : "20240912"
98
+ options[:tag].present? ? options[:tag] : "20250603"
89
99
  end
90
100
 
91
101
  def use_github_actions?
92
102
  options[:ci] == "github" || file_exists?(".github/workflows")
93
103
  end
94
104
 
105
+ def use_gitlab_ci?
106
+ options[:ci] == "gitlab" || file_exists?(".gitlab-ci.yml")
107
+ end
108
+
95
109
  def readme_contents
96
110
  content = <<~README
97
111
 
@@ -2,8 +2,17 @@
2
2
 
3
3
  trestle_tag="<%= docker_trestle_tag %>"
4
4
 
5
+ if [ "$1" = "-h" ]; then
6
+ echo """
7
+ Usage: $0 [-h] [CMD [CMD ARGS]]
8
+
9
+ CMD defaults to 'bash'
10
+ """
11
+ exit 0
12
+ fi
13
+
5
14
  command="bash"
6
- if [ "$1" != "" ]; then
15
+ if [ -n "$1" ]; then
7
16
  command=$1
8
17
  shift 1
9
18
  fi
@@ -0,0 +1,29 @@
1
+ .trestle:setup:
2
+ inherit:
3
+ default: false
4
+ image: "ghcr.io/gsa-tts/trestle:${TRESTLE_VERSION}"
5
+ before_script:
6
+ - cd doc/compliance/oscal
7
+ - export PATH="/app/bin:$PATH"
8
+
9
+ validate_ssp:
10
+ extends: .trestle:setup
11
+ stage: test
12
+ script:
13
+ - validate-ssp-json
14
+ rules:
15
+ - if: $CI_PIPELINE_SOURCE != "schedule"
16
+
17
+ assemble_ssp:
18
+ extends: .trestle:setup
19
+ stage: deploy
20
+ script:
21
+ - trestle assemble -n <%= app_name %> system-security-plan
22
+ - render-ssp
23
+ artifacts:
24
+ expose_as: "<%= app_name %> SSPP"
25
+ paths:
26
+ - doc/compliance/oscal/dist/system-security-plans/<%= app_name %>.json
27
+ - doc/compliance/oscal/ssp-render/<%= app_name %>_ssp.md
28
+ rules:
29
+ - if: $CI_PIPELINE_SOURCE != "schedule"
@@ -103,7 +103,7 @@ EOB
103
103
 
104
104
  cf_org_name = local.cf_org_name
105
105
  cf_space_name = "${var.cf_space_name}-egress"
106
- allow_ssh = var.allow_space_ssh
106
+ allow_ssh = var.allow_ssh
107
107
  deployers = local.space_deployers
108
108
  developers = var.space_developers
109
109
  auditors = var.space_auditors
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Rails.application.config.to_prepare do
4
- redis_url = CloudGovConfig.dig "aws-elasticache-redis", "credentials", "uri"
4
+ redis_url = CloudGovConfig.new.dig "aws-elasticache-redis", "credentials", "uri"
5
5
  if redis_url.present?
6
6
  Sidekiq.configure_server do |config|
7
7
  config.redis = {url: redis_url, ssl: true}
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if ! command -v terraform &> /dev/null
4
+ then
5
+ echo "terraform must be installed before running this script"
6
+ exit 1
7
+ fi
8
+
9
+ if [ -z "$GITLAB_PROJECT_ID" ] || [ -z "$GITLAB_HOSTNAME" ]; then
10
+ echo "GITLAB_PROJECT_ID or GITLAB_HOSTNAME has not been set. Run ./setup_shadowenv.sh first"
11
+ exit 1
12
+ fi
13
+
14
+ set -e
15
+
16
+ # ensure we're logged in via cli
17
+ cf spaces &> /dev/null || cf login -a api.fr.cloud.gov --sso
18
+
19
+ tf_state_address="https://$GITLAB_HOSTNAME/api/v4/projects/$GITLAB_PROJECT_ID/terraform/state/bootstrap"
20
+ terraform init \
21
+ -backend-config="address=$tf_state_address" \
22
+ -backend-config="lock_address=$tf_state_address/lock" \
23
+ -backend-config="unlock_address=$tf_state_address/lock"
24
+
25
+ terraform apply "$@"
@@ -0,0 +1,98 @@
1
+ terraform {
2
+ required_version = "~> 1.10"
3
+ required_providers {
4
+ cloudfoundry = {
5
+ source = "cloudfoundry/cloudfoundry"
6
+ version = "~> 1.7"
7
+ }
8
+ }
9
+ backend "http" {
10
+ lock_method = "POST"
11
+ unlock_method = "DELETE"
12
+ retry_wait_min = 5
13
+ }
14
+ }
15
+ # empty config will let terraform borrow cf-cli's auth
16
+ provider "cloudfoundry" {}
17
+
18
+ locals {
19
+ org_name = "<%= cloud_gov_organization %>"
20
+ space_name = "<%= terraform_manage_spaces? ? "#{ cloud_gov_production_space }-mgmt" : cloud_gov_staging_space %>"
21
+ }
22
+
23
+ data "cloudfoundry_org" "org" {
24
+ name = local.org_name
25
+ }
26
+ <% if terraform_manage_spaces? %>
27
+ variable "terraform_users" {
28
+ type = set(string)
29
+ description = "The list of developer emails and service account usernames who should be granted access to retrieve state bucket credentials"
30
+
31
+ validation {
32
+ condition = length(var.terraform_users) > 0
33
+ error_message = "terraform_users must include at least the current user calling apply.sh"
34
+ }
35
+ }
36
+
37
+ module "mgmt_space" {
38
+ source = "github.com/gsa-tts/terraform-cloudgov//cg_space?ref=v2.3.0"
39
+
40
+ cf_org_name = local.org_name
41
+ cf_space_name = local.space_name
42
+ developers = var.terraform_users
43
+ }
44
+ <% else %>
45
+ data "cloudfoundry_space" "space" {
46
+ name = local.space_name
47
+ org = data.cloudfoundry_org.org.id
48
+ }
49
+ <% end %>
50
+ data "cloudfoundry_service_plans" "cg_service_account" {
51
+ name = "<%= terraform_manage_spaces? ? "space-auditor" : "space-deployer" %>"
52
+ service_offering_name = "cloud-gov-service-account"
53
+ }
54
+ locals {
55
+ sa_service_name = "<%= app_name %>-cicd-deployer"
56
+ sa_key_name = "cicd-deployer-access-key"
57
+ sa_bot_credentials = jsondecode(data.cloudfoundry_service_credential_binding.runner_sa_key.credential_bindings.0.credential_binding).credentials
58
+ sa_cf_username = nonsensitive(local.sa_bot_credentials.username)
59
+ sa_cf_password = local.sa_bot_credentials.password
60
+ }
61
+ resource "cloudfoundry_service_instance" "runner_service_account" {
62
+ name = local.sa_service_name
63
+ type = "managed"
64
+ service_plan = data.cloudfoundry_service_plans.cg_service_account.service_plans.0.id<% if terraform_manage_spaces? %>
65
+ space = module.mgmt_space.space_id
66
+ depends_on = [module.mgmt_space]<% else %>
67
+ space = data.cloudfoundry_space.space.id<% end %>
68
+ }
69
+ resource "cloudfoundry_service_credential_binding" "runner_sa_key" {
70
+ name = local.sa_key_name
71
+ service_instance = cloudfoundry_service_instance.runner_service_account.id
72
+ type = "key"
73
+ }
74
+ data "cloudfoundry_service_credential_binding" "runner_sa_key" {
75
+ name = local.sa_key_name
76
+ service_instance = cloudfoundry_service_instance.runner_service_account.id
77
+ depends_on = [cloudfoundry_service_credential_binding.runner_sa_key]
78
+ }<% if terraform_manage_spaces? %>
79
+ data "cloudfoundry_user" "sa_user" {
80
+ name = local.sa_cf_username
81
+ }
82
+ resource "cloudfoundry_org_role" "sa_org_manager" {
83
+ user = data.cloudfoundry_user.sa_user.users.0.id
84
+ type = "organization_manager"
85
+ org = data.cloudfoundry_org.org.id
86
+ }<% end %>
87
+
88
+ resource "local_sensitive_file" "bot_secrets_file" {
89
+ filename = "${path.module}/secrets.cicd.tfvars"
90
+ file_permission = "0600"
91
+
92
+ content = templatefile("${path.module}/bot_secrets.tftpl", {
93
+ service_name = local.sa_service_name,
94
+ key_name = local.sa_key_name,
95
+ username = local.sa_cf_username,
96
+ password = local.sa_cf_password
97
+ })
98
+ }