Skip to content

test: enable Azure AD with e2e tests #614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 49 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
01f7c3c
test: have e2e tests use env vars to run
mcmcgrath13 Apr 2, 2025
82d566d
fix: setup and teardown
mcmcgrath13 Apr 2, 2025
c4ac9e6
fix: side nav link fetching for tests
mcmcgrath13 Apr 3, 2025
f281c53
test: fix unit tests for new testid
mcmcgrath13 Apr 3, 2025
711972e
ci: fix upload naming
mcmcgrath13 Apr 3, 2025
92ef05e
fix: archive names
mcmcgrath13 Apr 3, 2025
12c15dc
ci: testing replacements
mcmcgrath13 Apr 3, 2025
d61d6df
Merge branch 'main' into mcm/test-e2e-azure-ad
mcmcgrath13 Apr 3, 2025
2bbc0a7
ci: fix matrix
mcmcgrath13 Apr 3, 2025
9ff48b7
ci: sed
mcmcgrath13 Apr 3, 2025
3754720
ci: fix var
mcmcgrath13 Apr 3, 2025
c2f9d17
fix: auth usage
mcmcgrath13 Apr 3, 2025
a5742e4
fix: remove only
mcmcgrath13 Apr 7, 2025
5aeb689
fix: un-narrow test command
mcmcgrath13 Apr 7, 2025
ffbcadd
fix: update util waitfor
mcmcgrath13 Apr 7, 2025
f16ba22
ci: always upload reports
mcmcgrath13 Apr 7, 2025
eddaa97
fix: make auth utils work
mcmcgrath13 Apr 7, 2025
4361694
ci: fix report saving logic
mcmcgrath13 Apr 8, 2025
648f48d
fix: merge in main
mcmcgrath13 May 1, 2025
3a55564
fix: merge cleanup
mcmcgrath13 May 1, 2025
06893ad
fix: not working - scratch
mcmcgrath13 May 2, 2025
23ccf19
fix: merge in main
mcmcgrath13 Jul 7, 2025
d47d41b
fix: merge cruft
mcmcgrath13 Jul 7, 2025
70eb0ba
fix: more merge cruft
mcmcgrath13 Jul 7, 2025
20176c6
Merge branch 'main' of https://github.com/CDCgov/dibbs-ecr-viewer int…
mcmcgrath13 Jul 8, 2025
aa2f4f9
Merge branch 'main' of https://github.com/CDCgov/dibbs-ecr-viewer int…
mcmcgrath13 Jul 11, 2025
aded678
fix: log in to account for user type, split out user env vars
mcmcgrath13 Jul 11, 2025
129d979
test: fix unit tests
mcmcgrath13 Jul 11, 2025
46ecb07
fix: getting the token
mcmcgrath13 Jul 11, 2025
655a57c
fix: don't migrate without db, debug token
mcmcgrath13 Jul 11, 2025
73c1946
test: fix e2e test running
mcmcgrath13 Jul 11, 2025
eb63c9f
ci: password
mcmcgrath13 Jul 11, 2025
6515a1b
test: fix migration login, use gcp
mcmcgrath13 Jul 11, 2025
bc2ac64
ci: remove explicit integrated tests running
mcmcgrath13 Jul 11, 2025
156ab0b
ci: passwrod again
mcmcgrath13 Jul 11, 2025
df8978c
test: more generification and typos
mcmcgrath13 Jul 11, 2025
6009379
fix: seed script auth
mcmcgrath13 Jul 11, 2025
07cfd39
fix: users need to be emails, not user names
mcmcgrath13 Jul 11, 2025
1b6f2c3
test: fix expected message
mcmcgrath13 Jul 11, 2025
ccfca33
test: fix expected status
mcmcgrath13 Jul 14, 2025
b0e6c21
test: fix migration e2e run condition and token getting
mcmcgrath13 Jul 14, 2025
4dd83f5
test: fix commands
mcmcgrath13 Jul 14, 2025
18f47ab
test: try to login less
mcmcgrath13 Jul 14, 2025
bbcf4b5
test: save cookies after expect
mcmcgrath13 Jul 14, 2025
c8f8c3c
test: cleanup
mcmcgrath13 Jul 14, 2025
4a90317
test: try to deflake side nav tests
mcmcgrath13 Jul 14, 2025
ac3d435
test: log in via IDP, skip tests that don't make sense for non-integr…
mcmcgrath13 Jul 14, 2025
692499a
fix: cleanup
mcmcgrath13 Jul 14, 2025
e418e40
Merge branch 'main' into mcm/test-e2e-azure-ad
mcmcgrath13 Jul 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 31 additions & 64 deletions .github/workflows/container-ecr-viewer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,24 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max

convert-data:
e2e-tests:
strategy:
fail-fast: false
matrix:
include:
- config: AWS_SQLSERVER_NON_INTEGRATED
- config: AWS_SQLSERVER_DUAL
azure_ad: true
schema: extended
endpoint: process-ecr
- config: GCP_PG_DUAL
azure_ad: false
schema: core
endpoint: process-zip
- config: AWS_INTEGRATED
azure_ad: false
endpoint: process-zip
- config: AZURE_PG_NON_INTEGRATED
azure_ad: true
schema: core
endpoint: process-ecr
runs-on: ubuntu-latest
Expand Down Expand Up @@ -116,26 +125,23 @@ jobs:
run: |
echo "METADATA_DATABASE_SCHEMA=${{ matrix.schema }}" >> .env.local

- name: Set UPLOAD_URL to ${{ matrix.endpoint }}
- name: Set up Azure AD
if: ${{ matrix.azure_ad }}
working-directory: ./containers/${{env.CONTAINER}}
run: |
echo "UPLOAD_URL=http://host.docker.internal:3000/ecr-viewer/api/${{ matrix.endpoint }}" >> .env.local
sed -i 's/AUTH_PROVIDER=.*$/AUTH_PROVIDER=ad/' .env.local
sed -i 's/AUTH_CLIENT_ID=.*$/AUTH_CLIENT_ID=${{ secrets.AZURE_AD_CLIENT_ID }}/' .env.local
sed -i 's/AUTH_CLIENT_SECRET=.*$/AUTH_CLIENT_SECRET=${{ secrets.AZURE_AD_CLIENT_SECRET }}/' .env.local
sed -i 's/AUTH_ISSUER=.*$/AUTH_ISSUER=${{ secrets.AZURE_AD_ISSUER }}/' .env.local
sed -i 's/AUTH_ADMIN_USER=.*$/AUTH_ADMIN_USER=${{ secrets.AZURE_ADMIN_USER }}/' .env.local
sed -i 's/AUTH_ADMIN_PASSWORD=.*$/AUTH_ADMIN_PASSWORD=${{ secrets.AZURE_ADMIN_PASSWORD }}/' .env.local
sed -i 's/AUTH_STANDARD_USER=.*$/AUTH_STANDARD_USER=${{ secrets.AZURE_STANDARD_USER }}/' .env.local
sed -i 's/AUTH_STANDARD_PASSWORD=.*$/AUTH_STANDARD_PASSWORD=${{ secrets.AZURE_STANDARD_PASSWORD }}/' .env.local

- name: Run seed data conversion
run: npm run convert-seed-data
- name: Set UPLOAD_URL to ${{ matrix.endpoint }}
working-directory: ./containers/${{env.CONTAINER}}

e2e-tests:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{env.NODE_VERSION}}
run: |
echo "UPLOAD_URL=http://host.docker.internal:3000/ecr-viewer/api/${{ matrix.endpoint }}" >> .env.local

- name: Install dependencies
working-directory: ./containers/${{env.CONTAINER}}
Expand All @@ -145,12 +151,6 @@ jobs:
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e:install

- name: Set up env vars
working-directory: ./containers/${{env.CONTAINER}}
run: |
npm run setup-local-env
../../setup-env.sh ../orchestration/.env ../orchestration/.env.sample

- name: Run local docker and wait for it to be ready
working-directory: ./containers/${{env.CONTAINER}}
run: npm run local-docker:silent && ./tests/e2e/waitForUrl.sh localhost:3000/ecr-viewer/api/health-check localhost:8071/health/ready
Expand All @@ -175,7 +175,7 @@ jobs:
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-migrations
name: playwright-report-migrations-${{ matrix.config }}
path: containers/${{env.CONTAINER}}/playwright-report/
retention-days: 5

Expand All @@ -193,7 +193,7 @@ jobs:
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e:seed-user-prog

- name: Run Playwright tests - Non-Integrated
- name: Run Playwright tests
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e

Expand All @@ -209,55 +209,22 @@ jobs:
working-directory: ./containers/${{env.CONTAINER}}
run: docker compose --profile "*" down

- name: Upload playwright report - Non-Integrated
- name: Upload playwright report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
name: playwright-report-${{ matrix.config }}
path: containers/${{env.CONTAINER}}/playwright-report/
retention-days: 5

- name: Upload Lighthouse report
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: lighthouse-report
name: lighthouse-report-${{ matrix.config }}
path: containers/${{env.CONTAINER}}/lighthouse/
retention-days: 5

- name: Set CONFIG_NAME to AWS_INTEGRATED
working-directory: ./containers/${{env.CONTAINER}}
run: |
sed -i 's/AWS_SQLSERVER_DUAL/AWS_INTEGRATED/' .env.local

- name: Run local docker and wait for it to be ready
working-directory: ./containers/${{env.CONTAINER}}
run: npm run local-docker:silent && ./tests/e2e/waitForUrl.sh localhost:3000/ecr-viewer/api/health-check

- name: Run Playwright tests - Integrated
working-directory: ./containers/${{env.CONTAINER}}
run: npm run test:e2e:integrated

- name: Get docker logs
if: ${{ !cancelled() }}
working-directory: ./containers/${{env.CONTAINER}}/tests/e2e
shell: bash
run: |
echo "Saving $CONTAINER logs"
docker compose --profile "*" logs --timestamps &>> e2e-run.log

- name: Docker down
working-directory: ./containers/${{env.CONTAINER}}
run: docker compose --profile "*" down

- name: Upload playwright report - integrated
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-integrated
path: containers/${{env.CONTAINER}}/playwright-report/
retention-days: 5

- name: Get docker logs
if: ${{ !cancelled() }}
working-directory: ./containers/${{env.CONTAINER}}/tests/e2e
Expand All @@ -267,10 +234,10 @@ jobs:
docker compose --profile "*" logs --timestamps &>> e2e-run.log

- name: Archive docker logs
if: ${{ !cancelled() }}
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: logs
name: logs-${{ matrix.config }}
path: ./containers/${{env.CONTAINER}}/tests/e2e/e2e-run.log
retention-days: 5

Expand Down
6 changes: 4 additions & 2 deletions containers/ecr-viewer/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ AUTH_CLIENT_ID=ecr-viewer
AUTH_CLIENT_SECRET=P7e6LOwZXhJq1MCo0GSRAQFqBOYDuaBx
AUTH_ISSUER=http://localhost:8070/realms/master
# For local testing only
AUTH_USER=ecr-viewer-admin
AUTH_PASSWORD=pw
[email protected]
AUTH_ADMIN_PASSWORD=pw
[email protected]
AUTH_STANDARD_PASSWORD=pw
# AUTH_SESSION_DURATION_MIN=3

# INTEGRATED AUTH - For testing use only
Expand Down
2 changes: 1 addition & 1 deletion containers/ecr-viewer/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
},
"overrides": [
{
"files": ["*.test*", "**/tests/**/*"],
"files": ["./tests/**/*"],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"jsdoc/require-jsdoc": "off"
Expand Down
7 changes: 3 additions & 4 deletions containers/ecr-viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@
"test:integration:pg": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'METADATA_DATABASE_TYPE=postgres TEST_TYPE=integration TZ=America/New_York jest --runInBand --detectOpenHandles'",
"test:integration:sqlserver": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'METADATA_DATABASE_TYPE=sqlserver TEST_TYPE=integration TZ=America/New_York jest --runInBand --detectOpenHandles'",
"test:e2e:install": "playwright install --with-deps",
"test:e2e": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'playwright test ./tests/e2e/dual'",
"test:e2e:migrations": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'playwright test ./tests/e2e/migrations.spec.ts --project chromium'",
"test:e2e:integrated": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'playwright test ./tests/e2e/integrated'",
"test:e2e:seed-user-prog": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'playwright test ./tests/e2e/seed.spec.ts --project chromium'",
"test:e2e": "npx @dotenvx/dotenvx run -f .env.local -- playwright test --project chromium --project firefox --project webkit",
"test:e2e:migrations": "npx @dotenvx/dotenvx run -f .env.local -- playwright test --project migrations",
"test:e2e:seed-user-prog": "npx @dotenvx/dotenvx run -f .env.local -- playwright test --project seed",
"clear-local": "docker compose -f ./seed-scripts/docker-compose-seed.yaml --profile \"*\" down -v",
"convert-seed-data": "npx @dotenvx/dotenvx run -f .env.local -- sh -c 'docker compose -f ./seed-scripts/docker-compose-seed.yaml --profile ${CONFIG_NAME} --profile ecr-viewer up --abort-on-container-exit ${CONVERT_FLAGS}'",
"convert-seed-data:build": "CONVERT_FLAGS=--build npm run convert-seed-data"
Expand Down
30 changes: 27 additions & 3 deletions containers/ecr-viewer/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { defineConfig, devices } from "@playwright/test";

// for main e2e tests, pick the test dir based on the config
const testDir =
process.env.CONFIG_NAME?.endsWith("DUAL") ||
process.env.CONFIG_NAME?.endsWith("NON_INTEGRATED")
? "./tests/e2e/dual"
: "./tests/e2e/integrated";

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests/e2e",
testDir: "./tests/e2e", // base test dir
globalSetup: require.resolve("./tests/e2e/global-setup"),
globalTeardown: require.resolve("./tests/e2e/global-teardown"),
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
Expand All @@ -30,18 +39,33 @@ export default defineConfig({
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
testDir,
},

{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
testIgnore: /lighthouse.spec.ts/,
testIgnore: [/lighthouse.spec.ts/],
testDir,
},

{
name: "webkit",
use: { ...devices["Desktop Safari"] },
testIgnore: /lighthouse.spec.ts/,
testIgnore: [/lighthouse.spec.ts/],
testDir,
},

{
name: "migrations",
use: { ...devices["Desktop Chrome"] },
testMatch: [/migrations.spec.ts/],
},

{
name: "seed",
use: { ...devices["Desktop Chrome"] },
testMatch: [/seed.spec.ts/],
},
],
webServer: {
Expand Down
52 changes: 38 additions & 14 deletions containers/ecr-viewer/seed-scripts/create-seed-data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import grequests
import requests as rqsts
from azure.identity import DefaultAzureCredential

MIGRATION_URL = "http://host.docker.internal:3000/ecr-viewer/api/migrate-db"
BASEDIR = os.path.dirname(os.path.abspath(__file__))
Expand Down Expand Up @@ -43,25 +44,48 @@ def _process_files():
subfolders = subfolders_raw.split(",")

print("Requesting API token...")
token_req = rqsts.post(
f"{os.getenv('AUTH_ISSUER').replace('localhost', 'host.docker.internal')}/protocol/openid-connect/token",
data={
"client_id": os.getenv("AUTH_CLIENT_ID"),
"client_secret": os.getenv("AUTH_CLIENT_SECRET"),
"username": os.getenv("AUTH_USER"),
"password": os.getenv("AUTH_PASSWORD"),
"grant_type": "password",
"scope": "openid email profile",
},
)
assert token_req.status_code == 200, f"{token_req.json()}"
token = token_req.json()["access_token"]
config_name = os.getenv("CONFIG_NAME")
if config_name.endswith("INTEGRATED") and not config_name.endswith(
"NON_INTEGRATED"
):
print("using integrated auth")
token = os.getenv("DUMMY_NBS_JWT")
elif os.getenv("AUTH_PROVIDER") == "keycloak":
print("using keycloak auth")
token_req = rqsts.post(
f"{os.getenv('AUTH_ISSUER').replace('localhost', 'host.docker.internal')}/protocol/openid-connect/token",
data={
"client_id": os.getenv("AUTH_CLIENT_ID"),
"client_secret": os.getenv("AUTH_CLIENT_SECRET"),
"username": os.getenv("AUTH_ADMIN_USER"),
"password": os.getenv("AUTH_ADMIN_PASSWORD"),
"grant_type": "password",
"scope": "openid email profile",
},
)
assert token_req.status_code == 200, f"{token_req.json()}"
token = token_req.json()["access_token"]
elif os.getenv("AUTH_PROVIDER") == "ad":
print("using ad auth")
os.environ["AZURE_CLIENT_ID"] = os.getenv("AUTH_CLIENT_ID")
os.environ["AZURE_TENANT_ID"] = os.getenv("AUTH_ISSUER")
os.environ["AZURE_CLIENT_SECRET"] = os.getenv("AUTH_CLIENT_SECRET")
default_credential = DefaultAzureCredential()
token = default_credential.get_token(
f"{os.getenv('AUTH_CLIENT_ID')}/.default"
).token
else:
raise "Unknown auth setup"

headers = {"Authorization": f"Bearer {token}"}

print("Requesting db migration...")
rs = rqsts.post(
MIGRATION_URL,
data={"migration_secret": "test", "init_admin_email": "[email protected]"},
data={
"migration_secret": "test",
"init_admin_email": os.getenv("AUTH_ADMIN_USER"),
},
headers=headers,
)
assert rs.status_code == 200, f"{rs.json()}"
Expand Down
6 changes: 4 additions & 2 deletions containers/ecr-viewer/seed-scripts/docker-compose-seed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ services:
- CONFIG_NAME
- SEED_DATA_DIRECTORIES=${SEED_DATA_DIRECTORIES:-star-wars}
- UPLOAD_URL=${UPLOAD_URL:-http://host.docker.internal:3000/ecr-viewer/api/process-ecr}
- AUTH_PROVIDER
- AUTH_CLIENT_ID
- AUTH_CLIENT_SECRET
- AUTH_ISSUER
- AUTH_USER
- AUTH_PASSWORD
- AUTH_ADMIN_USER
- AUTH_ADMIN_PASSWORD
- DUMMY_NBS_JWT
extra_hosts:
- host.docker.internal:host-gateway
1 change: 1 addition & 0 deletions containers/ecr-viewer/seed-scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
azure-identity
grequests
requests
gevent>=23.9
8 changes: 8 additions & 0 deletions containers/ecr-viewer/src/app/api/migrate-db/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";

import { dbDialect } from "@/app/data/metadataDb/utils/db-config";
import { createInitialAdminUser } from "@/app/services/userService";

import { migrateDown, migrateUp } from "./migrate";
Expand Down Expand Up @@ -38,6 +39,13 @@ interface MigrationResponse {
export async function POST(
request: NextRequest,
): Promise<NextResponse<MigrationResponse>> {
if (!dbDialect()) {
return NextResponse.json(
{ message: "No database set up to migrate" },
{ status: 200 }, // success in the sense there's nothing to do
);
}

if (!process.env.METADATA_DATABASE_MIGRATION_SECRET) {
console.error("No migration secret found!");
return NextResponse.json(
Expand Down
2 changes: 1 addition & 1 deletion containers/ecr-viewer/src/app/utils/auth-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface UserSession {
}

/**
* Server side helper for whether this user is logged in. For client side, see `useLoggedInUser`.
* Server side helper for whether this user is logged in. For client side, see `useIsLoggedInUser`.
* A user can have access to an ecr page without being a logged in user if
* they are authenticated via an NBS jwt.
* @returns whether the user is logged in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ const SideNav: React.FC = () => {
key={section.id}
href={"#" + section.id}
className={activeSection === section.id ? "usa-current" : ""}
data-testid="sidenav-link"
>
{section.title}
</a>
Expand Down
Loading
Loading