From 2be2ed47cf0bc0992772c3da523185eff5ffeafc Mon Sep 17 00:00:00 2001 From: Mikhael Rakauskas Date: Tue, 5 Aug 2025 14:25:29 -0400 Subject: [PATCH] staging infrastructure support --- .dockerignore | 1 - .env.development | 6 + .env.staging | 9 ++ Dockerfile | 7 +- bin/start_staging | 224 ++++++++++++++++++++++++++++++ config/database.yml | 43 +++--- config/dotenv.rb | 12 +- config/environments/staging.rb | 164 ++++++++++++++++++++++ config/rds-combined-ca-bundle.pem | 124 +++++++++++++++++ config/secrets.yml | 3 + config/shakapacker.yml | 4 + config/storage.yml | 15 -- 12 files changed, 566 insertions(+), 46 deletions(-) create mode 100644 .env.development create mode 100644 .env.staging create mode 100755 bin/start_staging create mode 100644 config/environments/staging.rb create mode 100644 config/rds-combined-ca-bundle.pem diff --git a/.dockerignore b/.dockerignore index 69198e47..5dfe9eb5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -28,4 +28,3 @@ /attachments /docuseal .DS_Store -.env diff --git a/.env.development b/.env.development new file mode 100644 index 00000000..be97e459 --- /dev/null +++ b/.env.development @@ -0,0 +1,6 @@ +DB_HOST=host.docker.internal +DB_PASSWORD=postgres +DB_PORT=5432 +DB_USERNAME=postgres +REDIS_URL=redis://host.docker.internal:6379/7 +PORT=3000 diff --git a/.env.staging b/.env.staging new file mode 100644 index 00000000..86c04a40 --- /dev/null +++ b/.env.staging @@ -0,0 +1,9 @@ +DB_HOST= +DB_POOL=25 +DB_PORT=5432 +DB_SSLCERT= +DB_SSLMODE=verify-full +REDIS_URL= +PORT=3000 +S3_ATTACHMENTS_BUCKET= +ACTIVE_STORAGE_PUBLIC=true diff --git a/Dockerfile b/Dockerfile index a5a8f855..2bb17055 100644 --- a/Dockerfile +++ b/Dockerfile @@ -78,6 +78,8 @@ COPY ./public ./public COPY ./tmp ./tmp COPY LICENSE README.md Rakefile config.ru .version ./ COPY .version ./public/version +COPY ./.env.staging ./.env.staging +COPY ./config/rds-combined-ca-bundle.pem /config/rds-combined-ca-bundle.pem COPY --from=download /fonts/GoNotoKurrent-Regular.ttf /fonts/GoNotoKurrent-Bold.ttf /fonts/DancingScript-Regular.otf /fonts/OFL.txt /fonts COPY --from=download /fonts/FreeSans.ttf /usr/share/fonts/freefont @@ -85,6 +87,9 @@ COPY --from=download /pdfium-linux/lib/libpdfium.so /usr/lib/libpdfium.so COPY --from=download /pdfium-linux/licenses/pdfium.txt /usr/lib/libpdfium-LICENSE.txt COPY --from=webpack /app/public/packs ./public/packs +# Install AWS CLI and jq for secrets management +RUN apk add --no-cache curl jemalloc vips sqlite postgresql-client aws-cli jq bind-tools + RUN ln -s /fonts /app/public/fonts RUN bundle exec bootsnap precompile --gemfile app/ lib/ @@ -92,4 +97,4 @@ WORKDIR /data/docuseal ENV WORKDIR=/data/docuseal EXPOSE 3000 -CMD ["/app/bin/bundle", "exec", "puma", "-C", "/app/config/puma.rb", "--dir", "/app"] +CMD ["/app/bin/bundle", "exec", "puma", "-C", "/app/config/puma.rb", "--dir", "/app"] \ No newline at end of file diff --git a/bin/start_staging b/bin/start_staging new file mode 100755 index 00000000..fa9abbd6 --- /dev/null +++ b/bin/start_staging @@ -0,0 +1,224 @@ +#!/bin/sh -e + +echo "=== CP Docuseal Staging Startup ===" + +# Enable jemalloc for reduced memory usage and latency. +if [ -z "${LD_PRELOAD+x}" ]; then + LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit) + export LD_PRELOAD +fi + +check_aws_setup() { + if [ -z "$AWS_REGION" ]; then + echo "ERROR: AWS_REGION environment variable is not set" + exit 1 + fi + + if ! command -v aws &> /dev/null; then + echo "ERROR: AWS CLI is not installed. Please install it to proceed." + exit 1 + fi +} + +# Function to fetch secrets from AWS Secrets Manager +fetch_db_credentials() { + echo "Fetching database credentials from AWS Secrets Manager..." + + if [ -z "$DB_SECRETS_NAME" ]; then + echo "ERROR: DB_SECRETS_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret + echo "Retrieving secret: $DB_SECRETS_NAME" + SECRET_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$DB_SECRETS_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ]; then + echo "ERROR: Failed to retrieve secrets from AWS Secrets Manager" + exit 1 + fi + + # Parse JSON and export environment variables + export DB_USERNAME=$(echo "$SECRET_JSON" | jq -r '.username') + export DB_PASSWORD=$(echo "$SECRET_JSON" | jq -r '.password') + + # Validate that we got the credentials + if [ "$DB_USERNAME" = "null" ] || [ "$DB_PASSWORD" = "null" ] || [ -z "$DB_USERNAME" ] || [ -z "$DB_PASSWORD" ]; then + echo "ERROR: Failed to parse database credentials from secrets" + echo "Expected JSON format: {\"username\": \"...\", \"password\": \"...\"}" + exit 1 + fi + + # Write credentials to .env.staging file + echo "Writing database credentials to .env.staging..." + + # Remove existing DB_USERNAME and DB_PASSWORD lines if they exist + if [ -f "./.env.staging" ]; then + echo "Removing existing DB_USERNAME and DB_PASSWORD from .env.staging" + grep -v "^DB_USERNAME=" ./.env.staging > ./.env.staging.tmp || true + grep -v "^DB_PASSWORD=" ./.env.staging.tmp > ./.env.staging || true + rm -f ./.env.staging.tmp + fi + + # Append the new credentials + echo "DB_USERNAME=$DB_USERNAME" >> ./.env.staging + echo "DB_PASSWORD=$DB_PASSWORD" >> ./.env.staging + + echo "✓ Database credentials successfully retrieved and written to .env.staging" +} + +# Function to fetch encryption key from AWS Secrets Manager and write to config/master.key +fetch_encryption_key() { + echo "Fetching encryption key from AWS Secrets Manager..." + + ENCRYPTION_SECRET_NAME="cpdocuseal/encryption_key" + if [ -z "$AWS_REGION" ]; then + echo "ERROR: AWS_REGION environment variable is not set" + exit 1 + fi + + # Fetch the secret value (assume it's a plain string, not JSON) + ENCRYPTION_KEY=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$ENCRYPTION_SECRET_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ] || [ -z "$ENCRYPTION_KEY" ] || [ "$ENCRYPTION_KEY" = "null" ]; then + echo "ERROR: Failed to retrieve encryption key from AWS Secrets Manager" + exit 1 + fi + + # Write the key to config/master.key + echo -n "$ENCRYPTION_KEY" > config/master.key + chmod 600 config/master.key + echo "✓ Encryption key written to config/master.key" +} + +fetch_env_variables() { + echo "Fetching environment variables from AWS Secrets Manager..." + + if [ -z "$CP_VARIABLES_NAME" ]; then + echo "ERROR: CP_VARIABLES_NAME environment variable is not set" + exit 1 + fi + + # Fetch the secret + echo "Retrieving secret: $CP_VARIABLES_NAME" + SECRET_JSON=$(aws secretsmanager get-secret-value \ + --region "$AWS_REGION" \ + --secret-id "$CP_VARIABLES_NAME" \ + --query SecretString \ + --output text) + + if [ $? -ne 0 ]; then + echo "ERROR: Failed to retrieve secrets from AWS Secrets Manager" + exit 1 + fi + + export DB_HOST=$(echo "$SECRET_JSON" | jq -r '.host') + export REDIS_URL=$(echo "$SECRET_JSON" | jq -r '.redis_url') + export S3_ATTACHMENTS_BUCKET=$(echo "$SECRET_JSON" | jq -r '.s3_attachments_bucket') + export DB_SSLCERT=$(echo "$SECRET_JSON" | jq -r '.ssl_cert_location') + + # Validate that we got the values + if [ "$DB_HOST" = "null" ] || [ "$REDIS_URL" = "null" ] || [ "$S3_ATTACHMENTS_BUCKET" = "null" ] || [ "$DB_SSLCERT" = "null" ] || [ -z "$DB_HOST" ] || [ -z "$REDIS_URL" ] || [ -z "$S3_ATTACHMENTS_BUCKET" ] || [ -z "$DB_SSLCERT" ]; then + echo "ERROR: Failed to parse variables from secrets" + echo "Expected JSON format: {\"key\": \"...\", ...}" + exit 1 + fi + + # Write variables to .env.staging file + echo "Writing environment variables to .env.staging..." + + # Remove existing DB_HOST, REDIS_URL, and S3_ATTACHMENTS_BUCKET lines if they exist + if [ -f "./.env.staging" ]; then + echo "Removing existing variables from .env.staging" + grep -v "^DB_HOST=" ./.env.staging > ./.env.staging.tmp || true + grep -v "^REDIS_URL=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^S3_ATTACHMENTS_BUCKET=" ./.env.staging.tmp > ./.env.staging || true + grep -v "^DB_SSLCERT=" ./.env.staging.tmp > ./.env.staging || true + rm -f ./.env.staging.tmp + fi + + # Append the new credentials + echo "DB_HOST=$DB_HOST" >> ./.env.staging + echo "REDIS_URL=$REDIS_URL" >> ./.env.staging + echo "S3_ATTACHMENTS_BUCKET=$S3_ATTACHMENTS_BUCKET" >> ./.env.staging + echo "DB_SSLCERT=$DB_SSLCERT" >> ./.env.staging + + echo "✓ Environment variables successfully retrieved and written to .env.staging" +} + +# Function to setup database +setup_database() { + echo "Running database migrations..." + ./bin/rails db:migrate + + if [ $? -eq 0 ]; then + echo "✓ Database migrations completed successfully" + else + echo "ERROR: Database migrations failed" + exit 1 + fi +} + +set_environment() { + if [ -f "./.env.staging" ]; then + echo "Setting environment variables from .env.staging" + set -a + . ./.env.staging + set +a + fi +} + +# Main execution +main() { + local command=${1:-api} + + cd ../../app/ + + set_environment + + check_aws_setup + + echo "Starting CP Docuseal in staging mode..." + echo "Command: $command" + echo "Rails Environment: ${RAILS_ENV:-staging}" + + # Fetch database credentials from Secrets Manager + fetch_db_credentials + + # Fetch encryption key and write to config/master.key + fetch_encryption_key + + # Fetch other environment variables from Secrets Manager + fetch_env_variables + + # Load updated environment variables + set_environment + + # Setup and migrate database (only for API command) + if [ "$command" = "api" ]; then + setup_database + echo "=== Startup Complete - Starting Rails Server ===" + echo "Database Host: ${DB_HOST:-not set}" + echo "Database Port: ${DB_PORT:-not set}" + # Start the Rails server + exec ./bin/rails server -b 0.0.0.0 -p "${PORT:-3000}" + elif [ "$command" = "sidekiq" ]; then + echo "=== Startup Complete - Starting Sidekiq ===" + # Start Sidekiq + exec bundle exec sidekiq -q default + else + echo "ERROR: Unknown command '$command'. Use 'api' or 'sidekiq'" + exit 1 + fi +} + +# Execute main function with all arguments +main "$@" diff --git a/config/database.yml b/config/database.yml index ec5eb459..0c804623 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,7 +1,6 @@ default: &default adapter: postgresql encoding: unicode - pool: <%= ENV.fetch('RAILS_MAX_THREADS', 15).to_i + ENV.fetch('SIDEKIQ_THREADS', 5).to_i %> development: adapter: postgresql @@ -22,27 +21,25 @@ test: host: localhost production: -<% if !ENV['DATABASE_HOST'].to_s.empty? %> <<: *default - host: <%= ENV['DATABASE_HOST'] %> - port: <%= ENV['DATABASE_PORT'] %> - username: <%= ENV['DATABASE_USER'] %> - password: <%= ENV['DATABASE_PASSWORD'] %> - database: <%= ENV['DATABASE_NAME'] %> - <% if !ENV['DATABASE_SEARCH_PATH'].to_s.empty? %> - search_path: <%= ENV['DATABASE_SEARCH_PATH'] %> - <% end %> -<% elsif ENV['DATABASE_URL'].to_s.empty? %> - adapter: sqlite3 - database: <%= ENV['WORKDIR'] || '.' %>/db.sqlite3 - pool: <%= ENV.fetch('RAILS_MAX_THREADS', 15).to_i + ENV.fetch('SIDEKIQ_THREADS', 5).to_i %> - timeout: 5000 -<% elsif ENV['DATABASE_URL'].match?(/\Apostgres/) %> + host: <%= ENV['DB_HOST'] %> + port: <%= ENV['DB_PORT'] %> + pool: <%= ENV['DB_POOL'] || 25 %> + username: <%= ENV['DB_USERNAME'] %> + password: <%= ENV['DB_PASSWORD'] %> + database: <%= ENV['DB_NAME'] %> + sslmode: <%= ENV['DB_SSLMODE'] %> + sslrootcert: <%= ENV['DB_SSLCERT'] %> + +staging: <<: *default - url: <%= ENV['DATABASE_URL'] %> -<% elsif ENV['DATABASE_URL'].match?(/\Amysql/) %> - adapter: mysql2 - encoding: utf8mb4 - pool: <%= ENV.fetch('RAILS_MAX_THREADS', 15).to_i + ENV.fetch('SIDEKIQ_THREADS', 5).to_i %> - url: <%= ENV['DATABASE_URL'] %> -<% end %> + host: <%= ENV['DB_HOST'] %> + port: <%= ENV['DB_PORT'] %> + pool: <%= ENV['DB_POOL'] || 25 %> + username: <%= ENV['DB_USERNAME'] %> + password: <%= ENV['DB_PASSWORD'] %> + database: <%= ENV['DB_NAME'] %> + sslmode: <%= ENV['DB_SSLMODE'] %> + sslrootcert: <%= ENV['DB_SSLCERT'] %> + variables: + statement_timeout: 120000 diff --git a/config/dotenv.rb b/config/dotenv.rb index 319785e7..110119c0 100644 --- a/config/dotenv.rb +++ b/config/dotenv.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -if ENV['RAILS_ENV'] == 'production' +if ENV['RAILS_ENV'] == 'production' || ENV['RAILS_ENV'] == 'staging' if !ENV['AWS_SECRET_MANAGER_ID'].to_s.empty? require 'aws-sdk-secretsmanager' @@ -43,11 +43,11 @@ if ENV['DATABASE_URL'].to_s.split('@').last.to_s.split('/').first.to_s.include?( url = Addressable::URI.parse(ENV.fetch('DATABASE_URL', '')) - ENV['DATABASE_HOST'] = url.host - ENV['DATABASE_PORT'] = (url.port || 5432).to_s - ENV['DATABASE_USER'] = url.user - ENV['DATABASE_PASSWORD'] = url.password - ENV['DATABASE_NAME'] = url.path.to_s.delete_prefix('/') + ENV['DB_HOST'] = url.host + ENV['DB_PORT'] = (url.port || 5432).to_s + ENV['DB_USERNAME'] = url.user + ENV['DB_PASSWORD'] = url.password + ENV['DB_NAME'] = url.path.to_s.delete_prefix('/') ENV.delete('DATABASE_URL') end diff --git a/config/environments/staging.rb b/config/environments/staging.rb new file mode 100644 index 00000000..02a18963 --- /dev/null +++ b/config/environments/staging.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +require 'active_support/core_ext/integer/time' +require 'active_support/core_ext/string' + +Rails.backtrace_cleaner.remove_silencers! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.enable_reloading = false + + config.public_file_server.headers = { + 'cache-control' => 'public, s-maxage=31536000, max-age=15552000', + 'Expires' => 1.year.from_now.to_fs(:rfc822) + } + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + config.active_job.queue_adapter = :sidekiq + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = true + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :aws_s3 + + config.active_storage.resolve_model_to_route = :rails_storage_proxy if ENV['ACTIVE_STORAGE_PUBLIC'] != 'true' + config.active_storage.service_urls_expire_in = ENV.fetch('PRESIGNED_URLS_EXPIRE_MINUTES', '240').to_i.minutes + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + config.assume_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] != 'false' + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + config.force_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] != 'false' + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [:request_id] + + config.cache_store = :memory_store + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + config.action_mailer.raise_delivery_errors = false + + if ENV['SMTP_ADDRESS'] + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { + address: ENV.fetch('SMTP_ADDRESS', nil), + port: ENV.fetch('SMTP_PORT', 587), + domain: ENV.fetch('SMTP_DOMAIN', nil), + user_name: ENV.fetch('SMTP_USERNAME', nil), + password: ENV.fetch('SMTP_PASSWORD', nil), + authentication: ENV.fetch('SMTP_PASSWORD', nil).present? ? ENV.fetch('SMTP_AUTHENTICATION', 'plain') : nil, + enable_starttls_auto: ENV['SMTP_ENABLE_STARTTLS_AUTO'] != 'false' + }.compact + end + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + logger = ActiveSupport::Logger.new($stdout) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + + encryption_secret = ENV['ENCRYPTION_SECRET'].presence || Digest::SHA256.hexdigest(ENV['SECRET_KEY_BASE'].to_s) + + config.active_record.encryption = { + primary_key: encryption_secret.first(32), + deterministic_key: encryption_secret.last(32), + key_derivation_salt: Digest::SHA256.hexdigest(encryption_secret) + } + + ActiveRecord::Encryption.configure(**config.active_record.encryption) + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + config.lograge.enabled = true + config.lograge.base_controller_class = ['ActionController::API', 'ActionController::Base'] + + config.lograge.formatter = ->(data) { data.except(:path, :location).to_json } + + config.lograge.custom_payload do |controller| + params = + begin + controller.request.try(:params) || {} + rescue StandardError + {} + end + + resource = controller.instance_variable_get(:@submitter) || + controller.instance_variable_get(:@submission) || + controller.instance_variable_get(:@template) || + controller.instance_variable_get(:@record) + + current_user = controller.instance_variable_get(:@current_user) + + { + host: controller.request.host, + fwd: controller.request.remote_ip, + params: { + id: params[:id], + template_id: params[:template_id], + submission_id: params[:submission_id], + submitter_id: params[:submitter_id], + sig: (params[:signed_uuid] || params[:signed_id]).to_s.split('--').first, + slug: (params[:slug] || + params[:submitter_slug] || + params[:submission_slug] || + params[:submit_form_slug] || + params[:template_slug]).to_s.first(5) + }.compact_blank, + uid: current_user.try(:id), + aid: current_user.try(:account_id), + rid: resource.try(:id), + raid: resource.try(:account_id) + } + end + + config.host_authorization = { exclude: ->(request) { request.path == "/up" } } + [ + /.*\.careerplug\.org\Z/, + /.*\.careerplug\.com\Z/, + /.*\.cpstaging\d\.click\Z/, + /.*\.cpstaging\d+\.name\Z/ + ].each { |hrexp| config.hosts << hrexp } +end diff --git a/config/rds-combined-ca-bundle.pem b/config/rds-combined-ca-bundle.pem new file mode 100644 index 00000000..881d0946 --- /dev/null +++ b/config/rds-combined-ca-bundle.pem @@ -0,0 +1,124 @@ +-----BEGIN CERTIFICATE----- +MIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD +VQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi +MCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h +em9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw +ODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV +BAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv +biBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV +BAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ +oWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY +0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I +6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9 +O08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9 +McZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa +pmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN +AQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV +ynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc +NUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu +cbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY +0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/ +zPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBzCCAu+gAwIBAgICJVUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT +MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK +DBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT +MSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTkxODE2 +NTNaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz +aGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT +ZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h +em9uIFJEUyB1cy1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM3i/k2u6cqbMdcISGRvh+m+L0yaSIoOXjtpNEoIftAipTUYoMhL +InXGlQBVA4shkekxp1N7HXe1Y/iMaPEyb3n+16pf3vdjKl7kaSkIhjdUz3oVUEYt +i8Z/XeJJ9H2aEGuiZh3kHixQcZczn8cg3dA9aeeyLSEnTkl/npzLf//669Ammyhs +XcAo58yvT0D4E0D/EEHf2N7HRX7j/TlyWvw/39SW0usiCrHPKDLxByLojxLdHzso +QIp/S04m+eWn6rmD+uUiRteN1hI5ncQiA3wo4G37mHnUEKo6TtTUh+sd/ku6a8HK +glMBcgqudDI90s1OpuIAWmuWpY//8xEG2YECAwEAAaNmMGQwDgYDVR0PAQH/BAQD +AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPqhoWZcrVY9mU7tuemR +RBnQIj1jMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3 +DQEBCwUAA4IBAQB6zOLZ+YINEs72heHIWlPZ8c6WY8MDU+Be5w1M+BK2kpcVhCUK +PJO4nMXpgamEX8DIiaO7emsunwJzMSvavSPRnxXXTKIc0i/g1EbiDjnYX9d85DkC +E1LaAUCmCZBVi9fIe0H2r9whIh4uLWZA41oMnJx/MOmo3XyMfQoWcqaSFlMqfZM4 +0rNoB/tdHLNuV4eIdaw2mlHxdWDtF4oH+HFm+2cVBUVC1jXKrFv/euRVtsTT+A6i +h2XBHKxQ1Y4HgAn0jACP2QSPEmuoQEIa57bEKEcZsBR8SDY6ZdTd2HLRIApcCOSF +MRM8CKLeF658I0XgF8D5EsYoKPsA+74Z+jDH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/zCCAuegAwIBAgIRAPVSMfFitmM5PhmbaOFoGfUwDQYJKoZIhvcNAQELBQAw +gZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ +bmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn +QW1hem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH +DAdTZWF0dGxlMCAXDTIxMDUyNTIyMzQ1N1oYDzIwNjEwNTI1MjMzNDU3WjCBlzEL +MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x +EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6 +b24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl +YXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDu9H7TBeGoDzMr +dxN6H8COntJX4IR6dbyhnj5qMD4xl/IWvp50lt0VpmMd+z2PNZzx8RazeGC5IniV +5nrLg0AKWRQ2A/lGGXbUrGXCSe09brMQCxWBSIYe1WZZ1iU1IJ/6Bp4D2YEHpXrW +bPkOq5x3YPcsoitgm1Xh8ygz6vb7PsvJvPbvRMnkDg5IqEThapPjmKb8ZJWyEFEE +QRrkCIRueB1EqQtJw0fvP4PKDlCJAKBEs/y049FoOqYpT3pRy0WKqPhWve+hScMd +6obq8kxTFy1IHACjHc51nrGII5Bt76/MpTWhnJIJrCnq1/Uc3Qs8IVeb+sLaFC8K +DI69Sw6bAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE7PCopt +lyOgtXX0Y1lObBUxuKaCMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC +AQEAFj+bX8gLmMNefr5jRJfHjrL3iuZCjf7YEZgn89pS4z8408mjj9z6Q5D1H7yS +jNETVV8QaJip1qyhh5gRzRaArgGAYvi2/r0zPsy+Tgf7v1KGL5Lh8NT8iCEGGXwF +g3Ir+Nl3e+9XUp0eyyzBIjHtjLBm6yy8rGk9p6OtFDQnKF5OxwbAgip42CD75r/q +p421maEDDvvRFR4D+99JZxgAYDBGqRRceUoe16qDzbMvlz0A9paCZFclxeftAxv6 +QlR5rItMz/XdzpBJUpYhdzM0gCzAzdQuVO5tjJxmXhkSMcDP+8Q+Uv6FA9k2VpUV +E/O5jgpqUJJ2Hc/5rs9VkAPXeA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +0Ws= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICrjCCAjSgAwIBAgIRAPAlEk8VJPmEzVRRaWvTh2AwCgYIKoZIzj0EAwMwgZYx +CzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu +MRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h +em9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl +YXR0bGUwIBcNMjEwNTI1MjI0MTU1WhgPMjEyMTA1MjUyMzQxNTVaMIGWMQswCQYD +VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG +A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS +RFMgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx5xjrup8II4HOJw15NTnS3H5yMrQGlbj +EDA5MMGnE9DmHp5dACIxmPXPMe/99nO7wNdl7G71OYPCgEvWm0FhdvVUeTb3LVnV +BnaXt32Ek7/oxGk1T+Df03C+W0vmuJ+wo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G +A1UdDgQWBBTGXmqBWN/1tkSea4pNw0oHrjk2UDAOBgNVHQ8BAf8EBAMCAYYwCgYI +KoZIzj0EAwMDaAAwZQIxAIqqZWCSrIkZ7zsv/FygtAusW6yvlL935YAWYPVXU30m +jkMFLM+/RJ9GMvnO8jHfCgIwB+whlkcItzE9CRQ6CsMo/d5cEHDUu/QW6jSIh9BR +OGh9pTYPVkUbBiKPA7lVVhre +-----END CERTIFICATE----- diff --git a/config/secrets.yml b/config/secrets.yml index 66854c24..6938d16c 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -6,3 +6,6 @@ test: production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> + +staging: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/config/shakapacker.yml b/config/shakapacker.yml index 7131405b..7a70c711 100644 --- a/config/shakapacker.yml +++ b/config/shakapacker.yml @@ -41,6 +41,10 @@ test: compile: true public_output_path: packs-test +staging: + <<: *default + compile: false + production: <<: *default compile: false diff --git a/config/storage.yml b/config/storage.yml index e6fca35e..c6fe78fd 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -13,21 +13,6 @@ aws_s3: upload: cache_control: 'public, max-age=31536000' -google: - service: GCS - credentials: <%= ENV['GCS_CREDENTIALS'] || '{}' %> - project: <%= ENV['GCS_PROJECT'] %> - bucket: <%= ENV['GCS_BUCKET'] %> - public: <%= ENV['ACTIVE_STORAGE_PUBLIC'] == 'true' %> - cache_control: "public, max-age=31536000" - -azure: - service: AzureStorage - storage_account_name: <%= ENV['AZURE_STORAGE_ACCOUNT_NAME'] %> - storage_access_key: <%= ENV['AZURE_STORAGE_ACCESS_KEY'] %> - container: <%= ENV['AZURE_CONTAINER'] %> - public: <%= ENV['ACTIVE_STORAGE_PUBLIC'] == 'true' %> - test: service: Disk root: <%= Rails.root.join("tmp/storage") %>