diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..cb6b2c84b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,79 @@ + + +*A note to PR reviewers: it may be helpful to review our +[code review documentation](https://github.com/GSA/notifications-api/blob/main/docs/all.md#code-reviews) +to know what to keep in mind while reviewing pull requests.* + +## Description + +Please enter a clear description about your proposed changes and what the +expected outcome(s) is/are from there. If there are complex implementation +details within the changes, this is a great place to explain those details using +plain language. + +This should include: + +- Links to issues that this PR addresses +- Screenshots or screen captures of any visible changes, especially for UI work +- Dependency changes + +If there are any caveats, known issues, follow-up items, etc., make a quick note +of them here as well, though more details are probably warranted in the issue +itself in this case. + +## TODO (optional) + +If you're opening a draft PR, it might be helpful to list any outstanding work, +especially if you're asking folks to take a look before it's ready for full +review. In this case, create a small checklist with the outstanding items: + +- [ ] TODO item 1 +- [ ] TODO item 2 +- [ ] TODO item ... + +## Security Considerations + +Please think about the security compliance aspect of your changes and what the +potential impacts might be. + +**NOTE: Please be mindful of sharing sensitive information here! If you're not +sure of what to write, please ask the team first before writing anything here.** + +Relevant details could include (and are not limited to) the following: + +- Handling secrets/credential management (or specifically calling out that there + is nothing to handle) +- Any adjustments to the flow of data in and out the system, or even within it +- Connecting or disconnecting any external services to the application +- Handling of any sensitive information, such as PII +- Handling of information within log statements or other application monitoring + services/hooks +- The inclusion of a new external dependency or the removal of an existing one +- ... (anything else relevant from a security compliance perspective) + +There are some cases where there are no security considerations to be had, e.g., +updating our documentation with publicly available information. In those cases +it is fine to simply put something like this: + +- None; this is a documentation update with publicly available information. diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 99ef30c3b..53af0de2d 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,12 +7,12 @@ permissions: env: NOTIFY_ENVIRONMENT: test - NEW_RELIC_CONFIG_FILE: newrelic.ini - NEW_RELIC_ENVIRONMENT: test FLASK_APP: application.py WERKZEUG_DEBUG_PIN: off REDIS_ENABLED: 0 NODE_VERSION: 16.15.1 + AWS_US_TOLL_FREE_NUMBER: "+18556438890" + ADMIN_BASE_URL: http://localhost:6012 jobs: build: @@ -44,29 +44,97 @@ jobs: run: npm test - name: Run py tests with coverage run: poetry run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10 --ignore=tests/end_to_end tests/ - # - name: Run E2E tests - # run: poetry run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end - # env: - # NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }} - # NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} - # NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} - # NOTIFY_E2E_TEST_URI: ${{ secrets.NOTIFY_E2E_TEST_URI }} - name: Check coverage threshold run: poetry run coverage report --fail-under=90 - # - name: Health check - # run: | - # response=$(curl -url ${{secrets.NOTIFY_E2E_TEST_URI}}_status) - # if grep -q "ok" <<< "$response"; then - # echo "Health check passed" - # else - # echo "Health check failed" - # exit 1 - # fi - # env: - # NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }} - # NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} - # NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} - # NOTIFY_E2E_TEST_URI: ${{ secrets.NOTIFY_E2E_TEST_URI }} + + end-to-end-tests: + permissions: + checks: write + pull-requests: write + contents: write + runs-on: ubuntu-latest + services: + postgres: + image: postgres + env: + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_DB: test_notification_api + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 5432 on service container to the host + - 5432:5432 + redis: + image: redis + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 6379 on service container to the host + - 6379:6379 + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup-project + - uses: jwalton/gh-find-current-pr@v1 + id: findPr + - name: Clone API + uses: actions/checkout@v3 + with: + repository: GSA/notifications-api + path: 'notifications-api' + - name: Install API dependencies + working-directory: 'notifications-api' + run: make bootstrap + env: + DATABASE_URL: postgresql://user:password@localhost:5432/test_notification_api + SQLALCHEMY_DATABASE_TEST_URI: postgresql://user:password@localhost:5432/test_notification_api + REDIS_URL: redis://localhost:6379 + NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} + NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} + NOTIFY_ENVIRONMENT: development + - name: Run API server + working-directory: 'notifications-api' + run: make run-procfile & + env: + DATABASE_URL: postgresql://user:password@localhost:5432/test_notification_api + SQLALCHEMY_DATABASE_TEST_URI: postgresql://user:password@localhost:5432/test_notification_api + REDIS_URL: redis://localhost:6379 + NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} + NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} + NOTIFY_ENVIRONMENT: development + - name: Run Admin server + run: make run-flask & + env: + # API_HOST_NAME: https://notify-api-staging.app.cloud.gov + API_HOST_NAME: http://localhost:6011 + DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }} + SECRET_KEY: ${{ secrets.SECRET_KEY }} + ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }} + ADMIN_CLIENT_USERNAME: notify-admin + NOTIFY_ENVIRONMENT: e2etest + NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }} + NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} + NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} + NOTIFY_E2E_TEST_URI: http://localhost:6012 + - name: Run E2E tests + # Run the E2E tests against the code found in this PR. + # run: poetry run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end + # --browser webkit doesn't work at this time. + run: make e2e-test + # Debugging for now to troubleshoot a connectivity issue to the local servers + # run: curl --request GET --url "http://localhost:6012" + env: + NOTIFY_ENVIRONMENT: e2etest + NOTIFY_E2E_AUTH_STATE_PATH: ${{ secrets.NOTIFY_E2E_AUTH_STATE_PATH }} + NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }} + NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }} + NOTIFY_E2E_TEST_URI: http://localhost:6012 validate-new-relic-config: runs-on: ubuntu-latest @@ -76,6 +144,7 @@ jobs: - uses: ./.github/actions/setup-project - name: Validate NewRelic config env: + NEW_RELIC_CONFIG_FILE: newrelic.ini NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }} # Need to set a NEW_RELIC_ENVIRONMENT with monitor_mode: true NEW_RELIC_ENVIRONMENT: staging diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml index e1d76775a..bf9757493 100644 --- a/.github/workflows/deploy-demo.yml +++ b/.github/workflows/deploy-demo.yml @@ -56,12 +56,12 @@ jobs: NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }} LOGIN_PEM: ${{ secrets.LOGIN_PEM }} LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov" - LOGIN_DOT_GOV_USER_INFO_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/userinfo" - LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/token" - LOGIN_DOT_GOV_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-demo.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?" + LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo" + LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token" + LOGIN_DOT_GOV_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-demo.app.cloud.gov/sign-out" + LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?" LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-demo.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://idp.int.identitysandbox.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" + LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" with: cf_username: ${{ secrets.CLOUDGOV_USERNAME }} cf_password: ${{ secrets.CLOUDGOV_PASSWORD }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 767acae72..915994d58 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -62,12 +62,12 @@ jobs: NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }} LOGIN_PEM: ${{ secrets.LOGIN_PEM }} LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov" - LOGIN_DOT_GOV_USER_INFO_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/userinfo" - LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/token" - LOGIN_DOT_GOV_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-staging.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?" + LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo" + LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token" + LOGIN_DOT_GOV_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-staging.app.cloud.gov/sign-out" + LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?" LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-staging.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://idp.int.identitysandbox.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" + LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" with: cf_username: ${{ secrets.CLOUDGOV_USERNAME }} cf_password: ${{ secrets.CLOUDGOV_PASSWORD }} diff --git a/Makefile b/Makefile index 8f950dbf6..aa9b404af 100644 --- a/Makefile +++ b/Makefile @@ -80,8 +80,8 @@ dead-code: .PHONY: e2e-test e2e-test: export NEW_RELIC_ENVIRONMENT=test -e2e-test: ## Run end-to-end integration tests - poetry run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end +e2e-test: ## Run end-to-end integration tests; note that --browser webkit isn't currently working + poetry run pytest -v --browser chromium --browser firefox tests/end_to_end .PHONY: js-lint js-lint: ## Run javascript linting scanners diff --git a/app/__init__.py b/app/__init__.py index 3f008f7a1..47a3c15e4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -381,6 +381,10 @@ def load_service_before_request(): request_ctx.service = Service( service_api_client.get_service(service_id)["data"] ) + stats = service_api_client.get_service_statistics( + service_id, limit_days=7 + ) + request_ctx.service.stats = stats except HTTPError as exc: # if service id isn't real, then 404 rather than 500ing later because we expect service to be set if exc.status_code == 404: diff --git a/app/assets/javascripts/collapsibleCheckboxes.js b/app/assets/javascripts/collapsibleCheckboxes.js index f67cad80a..696d7e1c1 100644 --- a/app/assets/javascripts/collapsibleCheckboxes.js +++ b/app/assets/javascripts/collapsibleCheckboxes.js @@ -65,7 +65,7 @@ return $(`