diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fd708e40..7ea8ab3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,6 +88,8 @@ install: - *yarn_install - bundle exec rake assets:precompile + + # Build a container image async, and don't block CI tests # Cache intermediate images for 1 week (168 hours) build-dashboard-image: @@ -121,11 +123,11 @@ build-dashboard-image: /kaniko/executor --context "${CI_PROJECT_DIR}" --dockerfile "${CI_PROJECT_DIR}/idp_dashboard.Dockerfile" - --destination "${ECR_REGISTRY}/identity-dashboard/review:${CI_COMMIT_SHA}" - ${BRANCH_TAGGING_STRING} + --destination "identity-dashboard/review-testing:${CI_COMMIT_SHA}" --cache-repo="${ECR_REGISTRY}/identity-dashboard/review/cache" --cache-ttl=168h --cache=true + --no-push --compressed-caching=false --build-arg "http_proxy=${http_proxy}" --build-arg "https_proxy=${https_proxy}" --build-arg "no_proxy=${no_proxy}" @@ -150,354 +152,34 @@ lint: reports: junit: rubocop.xml -review-app: - stage: review - allow_failure: true - needs: - - job: build-dashboard-image - resource_group: $CI_ENVIRONMENT_SLUG-review-app-dashboard.review-app.identitysandbox.gov - image: - name: dtzar/helm-kubectl:latest - script: - - kubectl config get-contexts - - export CONTEXT=$(kubectl config get-contexts | grep -v CURRENT | awk '{print $1}' | head -1) - - kubectl config use-context "$CONTEXT" - - |- - export IDP_ENV=$(cat <- - helm upgrade --install --namespace review-apps - --debug - --set idp.image.repository="${ECR_REGISTRY}/identity-idp/review" - --set idp.image.tag="${IDP_IMAGE_TAG}" - --set idp.image.pullPolicy="Always" - --set worker.image.repository="${ECR_REGISTRY}/identity-idp/review" - --set worker.image.tag="${IDP_WORKER_IMAGE_TAG}" - --set worker.image.pullPolicy="Always" - --set pivcac.image.repository="${ECR_REGISTRY}/identity-pivcac/review" - --set pivcac.image.tag="${PKI_IMAGE_TAG}" - --set pivcac.image.pullPolicy="Always" - --set dashboard.image.repository="${ECR_REGISTRY}/identity-dashboard/review" - --set dashboard.image.tag="${CI_COMMIT_SHA}" - --set-json dashboard.env="$DASHBOARD_ENV" - --set-json dashboard.enabled=true - --set-json idp.env="$IDP_ENV" - --set-json worker.env="$WORKER_ENV" - --set-json pivcac.env="$PIVCAC_ENV" - --set-json idp.ingress.hosts="[{\"host\": \"$CI_ENVIRONMENT_SLUG.review-app.identitysandbox.gov\", \"paths\": [{\"path\": \"/\", \"pathType\": \"Prefix\"}]}]" - --set-json pivcac.ingress.hosts="[{\"host\": \"$CI_ENVIRONMENT_SLUG-review-app.pivcac.identitysandbox.gov\", \"paths\": [{\"path\": \"/\", \"pathType\": \"Prefix\"}]}]" - --set-json dashboard.ingress.hosts="[{\"host\": \"$CI_ENVIRONMENT_SLUG-review-app-dashboard.review-app.identitysandbox.gov\", \"paths\": [{\"path\": \"/\", \"pathType\": \"Prefix\"}]}]" - $CI_ENVIRONMENT_SLUG ./identity-idp-helm-chart - - echo "DNS may take a while to propagate, so be patient if it doesn't show up right away" - - echo "To access the rails console, first run 'aws-vault exec sandbox-power -- aws eks update-kubeconfig --name review_app'" - - echo "Then run aws-vault exec sandbox-power -- kubectl exec -it service/$CI_ENVIRONMENT_SLUG-login-chart-idp -n review-apps -- /app/bin/rails console" - - echo "Address of IDP review app:" - - echo https://$CI_ENVIRONMENT_SLUG.review-app.identitysandbox.gov - - echo "Address of PIVCAC review app:" - - echo https://$CI_ENVIRONMENT_SLUG-review-app.pivcac.identitysandbox.gov - - echo "Address of Dashboard review app:" - - echo https://$CI_ENVIRONMENT_SLUG-review-app-dashboard.review-app.identitysandbox.gov - environment: - name: review/$CI_COMMIT_REF_NAME - url: https://$CI_ENVIRONMENT_SLUG-review-app-dashboard.review-app.identitysandbox.gov - on_stop: stop-review-app - auto_stop_in: 2 days - rules: - - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - - if: $CI_PIPELINE_SOURCE != "merge_request_event" - when: never - -stop-review-app: - resource_group: $CI_ENVIRONMENT_SLUG-review-app.dashboard.identitysandbox.gov - script: - - export CONTEXT=$(kubectl config get-contexts | grep -v CURRENT | awk '{print $1}' | head -1) - - kubectl config use-context "$CONTEXT" - - helm uninstall --namespace review-apps $CI_ENVIRONMENT_SLUG - stage: review - image: - name: dtzar/helm-kubectl:latest - needs: - - job: review-app - environment: - name: review/$CI_COMMIT_REF_NAME - action: stop - when: manual - rules: - - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - - if: $CI_PIPELINE_SOURCE != "merge_request_event" - when: never -include: - - template: Jobs/SAST.gitlab-ci.yml - - template: Jobs/Dependency-Scanning.gitlab-ci.yml - - template: Security/Secret-Detection.gitlab-ci.yml - -secret_detection: - stage: scan - allow_failure: false - variables: - SECRET_DETECTION_EXCLUDED_PATHS: 'keys.example,config/artifacts.example,public/acuant/*/opencv.min.js,tmp/0.0.0.0-3000.key' - SECRET_DETECTION_REPORT_FILE: 'gl-secret-detection-report.json' - rules: - - if: $SECRET_DETECTION_DISABLED - when: never - - if: '$CI_COMMIT_BRANCH || $CI_COMMIT_TAG' - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main" - variables: - SECRET_DETECTION_LOG_OPTIONS: origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}..HEAD - - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "main" && $CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME == "main" - variables: - SECRET_DETECTION_LOG_OPTIONS: origin/${CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME}..HEAD - before_script: - - apk add --no-cache jq - - git fetch origin --quiet - script: - - | - if [ -z "$SECRET_DETECTION_LOG_OPTIONS" ]; then - /analyzer run - if [ -f "$SECRET_DETECTION_REPORT_FILE" ]; then - # check if '{ "vulnerabilities": [], ..' is empty in the report file if it exists - if [ "$(jq ".vulnerabilities | length" $SECRET_DETECTION_REPORT_FILE)" -gt 0 ]; then - echo "Vulnerabilities detected. Please analyze the artifact $SECRET_DETECTION_REPORT_FILE produced by the 'secret-detection' job." - exit 80 - fi - else - echo "Artifact $SECRET_DETECTION_REPORT_FILE does not exist. The 'secret-detection' job likely didn't create one. Hence, no evaluation can be performed." - fi - else - echo "Skipping because this is not a PR or is not targeting main" - exit 0 - fi - -# Export the automated ECR scan results into a format Gitlab can use -# Report schema https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/container-scanning-report-format.json -ecr-scan: - stage: scan +specs: + stage: test + needs: [] interruptible: true - allow_failure: true - rules: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - - if: $CI_PIPELINE_SOURCE != "merge_request_event" - when: never + variables: + BRANCH_TAGGING_STRING: '' tags: - build-pool - needs: - - job: build-dashboard-image image: - name: amazon/aws-cli - entrypoint: [""] - before_script: - - curl -LO https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64 - - chmod +x jq-linux64 - - mv jq-linux64 /usr/local/bin/jq + name: gcr.io/kaniko-project/executor:debug + entrypoint: [''] script: - - > - while true; do - SCAN_STATUS=$(aws ecr describe-image-scan-findings --repository-name identity-dashboard/review --image-id imageTag=$CI_COMMIT_SHA --query 'imageScanStatus.status' --output text || true) - if echo "$SCAN_STATUS" | grep -q "ACTIVE"; then - echo "Scan Complete" - break - elif echo "$SCAN_STATUS" | grep -q "FAILED"; then - echo "ECR scan failed" - exit 1 - else - echo "Waiting for ECR scan to complete" - sleep 15 - fi - done - - SCAN_FINDINGS=$(aws ecr describe-image-scan-findings --repository-name identity-dashboard/review --image-id imageTag=$CI_COMMIT_SHA) - - echo $SCAN_FINDINGS - - > - echo $SCAN_FINDINGS | - jq -r 'if (.imageScanFindings.enhancedFindings | length > 0) then - { - "version": "15.0.4", - "scan": { - "start_time": (.imageScanFindings.imageScanCompletedAt | sub("\\.[0-9]+"; "") | strptime("%Y-%m-%dT%H:%M:%S%z") | strftime("%Y-%m-%dT%H:%M:%S")), - "end_time": (.imageScanFindings.imageScanCompletedAt | sub("\\.[0-9]+"; "") | strptime("%Y-%m-%dT%H:%M:%S%z") | strftime("%Y-%m-%dT%H:%M:%S")), - "scanner": { - "id": "clair", - "name": "Amazon ECR Image Scan", - "version": "1.0.0", - "vendor": { - "name": "Amazon Web Services" - } - }, - "analyzer": { - "id": "clair", - "name": "Amazon ECR Image Scan", - "version": "1.0.0", - "vendor": { - "name": "Amazon Web Services" - } - }, - "status": "success", - "type": "container_scanning" - }, - "vulnerabilities": [ - .imageScanFindings.enhancedFindings[] | - { - "id": .packageVulnerabilityDetails.vulnerabilityId, - "name": .title, - "description": .description, - "severity": (if .severity == "HIGH" then "High" - elif .severity == "MEDIUM" then "Medium" - elif .severity == "LOW" then "Low" - elif .severity == "CRITICAL" then "Critical" - elif .severity == "INFORMATIONAL" then "Info" - elif .severity == "UNTRIAGED" then "Info" - else "Unknown" end), - "solution": .remediation.recommendation.text, - "identifiers": [ - { - "type": "cve", - "name": .packageVulnerabilityDetails.vulnerabilityId, - "url": .packageVulnerabilityDetails.sourceUrl, - "value": .packageVulnerabilityDetails.vulnerabilityId - } - ], - "links": [ - { - "name": .packageVulnerabilityDetails.vulnerabilityId, - "url": .packageVulnerabilityDetails.sourceUrl - } - ], - "location": { - "dependency": { - "package": { - "name": .packageVulnerabilityDetails.vulnerablePackages[0].name - }, - "version": .packageVulnerabilityDetails.vulnerablePackages[0].version - }, - "operating_system": .resources[0].details.awsEcrContainerImage.platform, - "image": .resources[0].id - } - } - ] - } - else - { - "version": "15.0.4", - "scan": { - "start_time": (now | strftime("%Y-%m-%dT%H:%M:%S")), - "end_time": (now | strftime("%Y-%m-%dT%H:%M:%S")), - "scanner": { - "id": "clair", - "name": "Amazon ECR Image Scan", - "version": "1.0.0", - "vendor": { - "name": "Amazon Web Services" - } - }, - "analyzer": { - "id": "clair", - "name": "Amazon ECR Image Scan", - "version": "1.0.0", - "vendor": { - "name": "Amazon Web Services" - } - }, - "status": "success", - "type": "container_scanning" - }, - "vulnerabilities": [] - } - end' > gl-container-scanning-report.json - artifacts: - paths: - - gl-container-scanning-report.json - reports: - container_scanning: gl-container-scanning-report.json \ No newline at end of file + - mkdir -p /kaniko/.docker + - |- + KANIKOCFG="\"credsStore\":\"ecr-login\"" + if [ "x${http_proxy}" != "x" -o "x${https_proxy}" != "x" ]; then + KANIKOCFG="${KANIKOCFG}, \"proxies\": { \"default\": { \"httpProxy\": \"${http_proxy}\", \"httpsProxy\": \"${https_proxy}\", \"noProxy\": \"${no_proxy}\"}}" + fi + KANIKOCFG="{ ${KANIKOCFG} }" + echo "${KANIKOCFG}" > /kaniko/.docker/config.json + - >- + /kaniko/executor + --context "${CI_PROJECT_DIR}" + --dockerfile "${CI_PROJECT_DIR}/idp_dashboard_testing.Dockerfile" + --destination ${BRANCH_TAGGING_STRING} + --cache-repo="${ECR_REGISTRY}/identity-dashboard/review/cache" + --cache-ttl=168h + --cache=true + --compressed-caching=false + --build-arg "http_proxy=${http_proxy}" --build-arg "https_proxy=${https_proxy}" --build-arg "no_proxy=${no_proxy}" diff --git a/idp_dashboard_testing.Dockerfile b/idp_dashboard_testing.Dockerfile new file mode 100644 index 00000000..af63c15b --- /dev/null +++ b/idp_dashboard_testing.Dockerfile @@ -0,0 +1,142 @@ +FROM cimg/ruby:3.2.2-browsers + + + +# Set environment variables +ENV RAILS_ROOT /dashboard +ENV RAILS_ENV production +ENV NODE_ENV production +ENV RAILS_SERVE_STATIC_FILES true +ENV RAILS_LOG_TO_STDOUT true +ENV LOGIN_CONFIG_FILE $RAILS_ROOT/tmp/application.yml +ENV RAILS_LOG_LEVEL debug +ENV BUNDLE_PATH /usr/local/bundle +ENV PIDFILE /tmp/server.pid +ENV YARN_VERSION 1.22.19 +ENV NODE_VERSION 18.16.1 +ENV BUNDLER_VERSION 2.4.4 + +ENV POSTGRES_SSLMODE prefer +ENV POSTGRES_DB dashboard +ENV POSTGRES_HOST localhost +ENV POSTGRES_USERNAME postgres +ENV POSTGRES_PASSWORD password +ENV POSTGRES_SSLCERT /usr/local/share/aws/rds-combined-ca-bundle.pem +ENV NEW_RELIC_ENABLED false + + +ENV SMPT_HOST changeme +ENV SMPT_PASSWORD changeme +ENV SMPT_PORT 2025 +ENV SMPT_USERNAME changeme + +ENV DASHBOARD_API_TOKEN changeme + +ENV IDP_SP_URL http://localhost:3000 +ENV IDP_URL http://localhost:3000 + +ENV LOGO_UPLOAD_ENABLED false +ENV POST_LOGOUT_URL http://localhost:3000 +ENV SAML_SP_ISSUER http://localhost:3001 +ENV SMPT_ADDRESS changeme +ENV SMPT_DOMAIN changeme +ENV MAILER_DOMAIN https://dashboard.login.gov +ENV LOGIN_DOMAIN identitysandbox.gov + +ENV NEW_RELIC_LICENSE_KEY changeme + +# Prevent documentation installation +RUN echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/00_nodoc && \ + echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/00_nodoc && \ + echo 'path-exclude=/usr/share/groff/*' >> /etc/dpkg/dpkg.cfg.d/00_nodoc && \ + echo 'path-exclude=/usr/share/info/*' >> /etc/dpkg/dpkg.cfg.d/00_nodoc && \ + echo 'path-exclude=/usr/share/lintian/*' >> /etc/dpkg/dpkg.cfg.d/00_nodoc && \ + echo 'path-exclude=/usr/share/linda/*' >> /etc/dpkg/dpkg.cfg.d/00_nodoc + +# Create a new user and set up the working directory +RUN addgroup --gid 1000 app && \ + adduser --uid 1000 --gid 1000 --disabled-password --gecos "" app && \ + mkdir -p $RAILS_ROOT && \ + mkdir -p $BUNDLE_PATH && \ + chown -R app:app $RAILS_ROOT && \ + chown -R app:app $BUNDLE_PATH + +RUN browser-tools/install-browser-tools + + + +RUN curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter &&\ + chmod +x ./cc-test-reporter \ + +RUN curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ + && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ + && rm "node-v$NODE_VERSION-linux-x64.tar.xz" \ + && ln -s /usr/local/bin/node /usr/local/bin/nodejsv + +# Install Yarn +#RUN curl -sSk https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn-archive-keyring.gpg >/dev/null +#RUN echo "deb [signed-by=/usr/share/keyrings/yarn-archive-keyring.gpg] https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list +#RUN apt-get update && apt-get install -y yarn=1.22.5-1 +RUN curl -fsSLO --compressed "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn_1.22.19_all.deb" \ + && dpkg --install "yarn_1.22.19_all.deb" \ + && rm "yarn_1.22.19_all.deb" + +RUN mkdir -p /usr/local/share/aws \ + && cd /usr/local/share/aws \ + && curl -fsSLk https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem --output rds-combined-ca-bundle.pem +WORKDIR $RAILS_ROOT + +# Set user +USER app + + + +COPY .ruby-version $RAILS_ROOT/.ruby-version +COPY Gemfile $RAILS_ROOT/Gemfile +COPY Gemfile.lock $RAILS_ROOT/Gemfile.lock + +COPY --chown=app:app ./app ./app +COPY --chown=app:app ./bin ./bin +COPY --chown=app:app ./config ./config +COPY --chown=app:app ./db ./db +COPY --chown=app:app ./lib ./lib +COPY --chown=app:app ./public ./public +COPY --chown=app:app ./spec ./spec +COPY --chown=app:app ./config.ru ./config.ru +COPY --chown=app:app ./Rakefile ./Rakefile +COPY --chown=app:app ./Rakefile ./Rakefile +COPY --chown=app:app ./Procfile ./Procfile +COPY --chown=app:app ./babel.config.js ./babel.config.js +COPY --chown=app:app ./webpack.config.js ./webpack.config.js +COPY --chown=app:app ./.browserslistrc ./.browserslistrc + +COPY --chown=app:app ./config/application.yml.default.docker $RAILS_ROOT/config/application.yml +COPY --chown=app:app ./config/newrelic.yml.docker $RAILS_ROOT/config/newrelic.yml +COPY --chown=app:app ./config/database.yml.docker $RAILS_ROOT/config/database.yml + +RUN bundle config unset deployment +RUN bundle config build.nokogiri --use-system-libraries +RUN bundle config set --local deployment 'true' +RUN bundle config set --local path $BUNDLE_PATH +RUN bundle config set --local without 'deploy development test' +RUN bundle install +RUN bundle binstubs --all + +COPY package.json $RAILS_ROOT/package.json +COPY yarn.lock $RAILS_ROOT/yarn.lock +RUN yarn install --cache-folder .cache/yarn + + +# Generate and place SSL certificates for puma +RUN mkdir -p $RAILS_ROOT/keys +RUN openssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 1825 \ + -keyout $RAILS_ROOT/keys/localhost.key \ + -out $RAILS_ROOT/keys/localhost.crt \ + -subj "/C=US/ST=Fake/L=Fakerton/O=Dis/CN=localhost" + +# Create PID folder in /tmp for server pid +RUN mkdir -m 666 /tmp/pids + +# Precompile assets +RUN bundle exec rake assets:precompile --trace + \ No newline at end of file