Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: CDCgov/dibbs-query-connector
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a434a66cfbc012c629e2c86bf46fa6e8eece5d5f
Choose a base ref
..
head repository: CDCgov/dibbs-query-connector
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 30cfc4bf4ea7a65a199017e9e464581a1eb2519a
Choose a head ref
Showing with 1,274 additions and 62 deletions.
  1. +2 −1 query-connector/.gitignore
  2. +11 −4 query-connector/Dockerfile
  3. +28 −0 query-connector/Dockerfile.jwks-seeder
  4. +2 −0 query-connector/README.md
  5. +2 −1 query-connector/__mocks__/next-auth/react.js
  6. +38 −0 query-connector/__mocks__/tabbable.js
  7. +9 −0 query-connector/docker-compose-dev.yaml
  8. +0 −1 query-connector/e2e/query_building.spec.ts
  9. +1 −1 query-connector/e2e/user_management.spec.ts
  10. +1 −0 query-connector/flyway/sql/V08_01__drop_user_management_table.sql
  11. +37 −0 query-connector/generate_jwks.sh
  12. +81 −0 query-connector/keycloak/dev.json
  13. +81 −0 query-connector/keycloak/localhost.json
  14. +10 −0 query-connector/package-lock.json
  15. +2 −1 query-connector/package.json
  16. +1 −1 query-connector/setup-scripts/e2e_tests.sh
  17. +25 −0 query-connector/src/app/(pages)/.well-known/jwks.json/route.ts
  18. +150 −0 query-connector/src/app/(pages)/auditLogs/AuditLogs.test.tsx
  19. +147 −0 query-connector/src/app/(pages)/auditLogs/auditLogs.module.scss
  20. +326 −0 query-connector/src/app/(pages)/auditLogs/page.tsx
  21. +3 −3 ...connector/src/app/(pages)/queryBuilding/buildFromTemplates/conditionTemplateSelection.module.scss
  22. +1 −1 query-connector/src/app/(pages)/userManagement/components/userPermissions/userPermissionsTable.tsx
  23. +0 −10 query-connector/src/app/backend/user-management.ts
  24. +8 −0 query-connector/src/app/layout.tsx
  25. +8 −0 query-connector/src/app/shared/page-routes.ts
  26. +95 −0 query-connector/src/app/ui/components/sessionTimeout/sessionTimeout.test.tsx
  27. +124 −0 query-connector/src/app/ui/components/sessionTimeout/sessionTimeout.tsx
  28. +3 −1 query-connector/src/app/ui/designSystem/drawer/Drawer.tsx
  29. +4 −4 query-connector/src/app/ui/designSystem/drawer/drawer.module.scss
  30. +11 −0 query-connector/src/app/ui/designSystem/modal/Modal.tsx
  31. +2 −2 query-connector/src/app/ui/designSystem/table/table.module.scss
  32. +37 −0 query-connector/src/app/ui/styles/custom-styles.scss
  33. +11 −0 query-connector/start.sh
  34. +13 −31 query-connector/vs_dump.sql
3 changes: 2 additions & 1 deletion query-connector/.gitignore
Original file line number Diff line number Diff line change
@@ -8,4 +8,5 @@ certificates
/playwright/.cache/
/coverage
report.json
.tool-versions
.tool-versions
keys/
15 changes: 11 additions & 4 deletions query-connector/Dockerfile
Original file line number Diff line number Diff line change
@@ -3,8 +3,7 @@ FROM node:22-alpine AS base
FROM base AS installer

RUN apk update
RUN apk add --no-cache libc6-compat
RUN apk add --no-cache bash curl
RUN apk add --no-cache libc6-compat bash curl git go

WORKDIR /app
COPY . .
@@ -24,11 +23,16 @@ ENV NEXT_TELEMETRY_DISABLED=1
RUN npm ci
RUN npm run build

# Download jwksetinfer tool
RUN git clone https://github.com/MicahParks/jwkset.git \
&& cd jwkset/cmd/jwksetinfer \
&& go build

# Final stage for running the app
FROM base AS runner
WORKDIR /app

RUN apk add --no-cache bash openjdk17-jre
RUN apk add --no-cache bash openjdk17-jre openssl uuidgen jq

# Copy Flyway from the installer stage
COPY --from=installer /flyway /flyway
@@ -50,11 +54,13 @@ COPY --from=installer /app/package.json .
COPY --from=installer /app/flyway/conf/flyway.conf ../flyway/conf/flyway.conf
COPY --from=installer /app/flyway/sql ../flyway/sql
COPY --from=installer /app/src/app/assets ./.next/server/app/assets
COPY --from=installer /app/jwkset/cmd/jwksetinfer/jwksetinfer /usr/local/bin/jwksetinfer

# Automatically leverage output traces to reduce image size
COPY --from=installer --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=installer --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=installer --chown=nextjs:nodejs /app/public ./public
COPY --from=installer --chown=nextjs:nodejs /app/start.sh ./start.sh
RUN ls -R
# Set environment variables for Flyway and Node.js telemetry
ENV NEXT_TELEMETRY_DISABLED=1
@@ -64,4 +70,5 @@ ENV JAVA_HOME=/usr/lib/jvm/default-jvm
# Add the OpenJDK to the PATH so the java command is available for Flways
ENV PATH=$JAVA_HOME/bin:$PATH

CMD ["sh", "-c","flyway -configFiles=../flyway/conf/flyway.conf -schemas=public -connectRetries=60 migrate && echo done with flyway && node server.js"]
ENTRYPOINT ["/bin/bash"]
CMD ["/app/start.sh"]
28 changes: 28 additions & 0 deletions query-connector/Dockerfile.jwks-seeder
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM alpine:latest

# Install required packages
RUN apk update && apk add --no-cache \
bash \
openssl \
uuidgen \
jq \
git \
go

# Set up work directory
WORKDIR /app

# Download and build jwksetinfer tool
RUN git clone https://github.com/MicahParks/jwkset.git && \
cd jwkset/cmd/jwksetinfer && \
go build && \
mv jwksetinfer /usr/local/bin/ && \
chmod +x /usr/local/bin/jwksetinfer && \
cd / && \
rm -rf /app/jwkset

# Set entrypoint to bash to keep container running or execute scripts
ENTRYPOINT ["/bin/bash"]

# Default command (can be overridden in docker-compose)
CMD ["/app/generate_jwks.sh"]
2 changes: 2 additions & 0 deletions query-connector/README.md
Original file line number Diff line number Diff line change
@@ -130,6 +130,8 @@ Playwright provides a number of different ways of executing end to end tests. Fr
`npm run test:playwright:ui`
Runs the end-to-end tests locally by spawning the Playwright UI mode. This will start a dev server off localhost:3000, so make sure you don't have another app instance running off that port.

You'll need to have a token for Aidbox set under AIDBOX_LICENSE in your .env for the Aidbox seeder to run correctly. You can sign up for a dev license at https://aidbox.app and use that in your local setup.

`npm run test:playwright`
Runs the end-to-end tests.

3 changes: 2 additions & 1 deletion query-connector/__mocks__/next-auth/react.js
Original file line number Diff line number Diff line change
@@ -4,11 +4,12 @@ const useSession = jest
.fn()
.mockReturnValue({ data: undefined, status: "loading" });

const signOut = jest.fn();
/**
*
* @param root0
* @param root0.children
*/
const SessionProvider = ({ children }) => <>{children}</>;

export { useSession, SessionProvider };
export { useSession, signOut, SessionProvider };
38 changes: 38 additions & 0 deletions query-connector/__mocks__/tabbable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* eslint-disable jsdoc/require-returns, jsdoc/require-param-description */
// __mocks__/tabbable.js

const lib = jest.requireActual("tabbable");

const tabbable = {
...lib,
/**
*
* @param node
* @param options
*/
tabbable: (node, options) =>
lib.tabbable(node, { ...options, displayCheck: "none" }),
/**
*
* @param node
* @param options
*/
focusable: (node, options) =>
lib.focusable(node, { ...options, displayCheck: "none" }),
/**
*
* @param node
* @param options
*/
isFocusable: (node, options) =>
lib.isFocusable(node, { ...options, displayCheck: "none" }),
/**
*
* @param node
* @param options
*/
isTabbable: (node, options) =>
lib.isTabbable(node, { ...options, displayCheck: "none" }),
};

module.exports = tabbable;
9 changes: 9 additions & 0 deletions query-connector/docker-compose-dev.yaml
Original file line number Diff line number Diff line change
@@ -101,5 +101,14 @@ services:
flyway:
condition: service_completed_successfully

# JWKS key generator
jwks-generator:
build:
context: .
dockerfile: Dockerfile.jwks-seeder
volumes:
- "./keys:/app/keys"
- "./generate_jwks.sh:/app/generate_jwks.sh"

volumes:
aidbox_pg_data:
1 change: 0 additions & 1 deletion query-connector/e2e/query_building.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @ts-check

import { test, expect } from "@playwright/test";
import { TEST_URL } from "../playwright-setup";

2 changes: 1 addition & 1 deletion query-connector/e2e/user_management.spec.ts
Original file line number Diff line number Diff line change
@@ -15,6 +15,6 @@ test.describe("User management", () => {
await expect(page.getByRole("button", { name: "Users" })).toHaveClass(
/tabGroup_tab__active__/,
);
await expect(page.getByText("No users found")).toBeVisible();
await expect(page.getByText("Mario, Mario")).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS user_management;
37 changes: 37 additions & 0 deletions query-connector/generate_jwks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash

# Check if keys/jwks.json exists
if [ -f keys/jwks.json ]; then
echo "JWKS already exists. Skipping key generation."
exit 0
fi

mkdir -p keys

# Generate ECDSA key pair and JWKS for SMART on FHIR
set -e
if [ ! -f keys/ec384-private.pem ]; then
echo "Generating new ECDSA key pair..."

# Generate ECDSA P-384 key pair
openssl ecparam -name secp384r1 -genkey -noout -out keys/ec384-private.pem
openssl ec -in keys/ec384-private.pem -pubout -out keys/ec384-public.pem

# Generate JWKS
jwksetinfer keys/ec384-private.pem >keys/jwks.json

# Generate a UUID and replace kid in jwks.json using jq
KID=$(uuidgen)
jq --arg KID "$KID" '.keys[0].kid = $KID' keys/jwks.json >keys/jwks.json.tmp

# Add algorithm to jwks.json
jq '.keys[0].alg = "ES384"' keys/jwks.json.tmp >keys/jwks.json

# Fix permissions
chmod 600 keys/ec384-private.pem
chmod 644 keys/ec384-public.pem keys/jwks.json

echo "Key generation complete."
else
echo "Using existing keys."
fi
81 changes: 81 additions & 0 deletions query-connector/keycloak/dev.json
Original file line number Diff line number Diff line change
@@ -472,6 +472,87 @@
"webAuthnPolicyPasswordlessAcceptableAaguids": [],
"webAuthnPolicyPasswordlessExtraOrigins": [],
"users": [
{
"id": "3295c949-ddd4-484c-b1ac-904484e72d7f",
"username": "mario",
"firstName": "Mario",
"lastName": "Mario",
"emailVerified": true,
"createdTimestamp": 1742398946534,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "5ba5f7ee-b1ce-4969-814e-0c4b2dc5f3ec",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398959892,
"secretData": "{\"value\":\"vHe/0T6rE+6tPtQaeWpbv0qMZJBqkiW4Dj9YtDsRS2g=\",\"salt\":\"+1StaWt5e8GT3b+sycysyw==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "ab29205c-5a84-49ed-8f60-5b7c2cd1575c",
"username": "peach",
"firstName": "Princess",
"lastName": "Peach",
"emailVerified": true,
"createdTimestamp": 1742398897969,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "3368ea8a-96ae-463f-ac94-f7d6063b1000",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398909496,
"secretData": "{\"value\":\"WrWIzPPGQQD3OJhaH5UbhVbCBOlXuUx9wkzLKtjO2p8=\",\"salt\":\"OObODYLOFzabgRoCis3GkA==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "fe1c1448-e555-4bcc-a0d7-13970503a705",
"username": "toad",
"firstName": "Captain",
"lastName": "Toad",
"emailVerified": true,
"createdTimestamp": 1742398923041,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "f6451e2e-e1da-4439-a3ae-09fa27207fa0",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398933723,
"secretData": "{\"value\":\"qcsrP+smMu2563eL7mEIeYTwUA68bK31YJy+ohOek8g=\",\"salt\":\"mlmPcb4YSPOA53lVzIKWWQ==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "1c3b6114-3c12-4ef7-95ba-a0091f506ed6",
"username": "qc-admin",
81 changes: 81 additions & 0 deletions query-connector/keycloak/localhost.json
Original file line number Diff line number Diff line change
@@ -472,6 +472,87 @@
"webAuthnPolicyPasswordlessAcceptableAaguids": [],
"webAuthnPolicyPasswordlessExtraOrigins": [],
"users": [
{
"id": "3295c949-ddd4-484c-b1ac-904484e72d7f",
"username": "mario",
"firstName": "Mario",
"lastName": "Mario",
"emailVerified": true,
"createdTimestamp": 1742398946534,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "5ba5f7ee-b1ce-4969-814e-0c4b2dc5f3ec",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398959892,
"secretData": "{\"value\":\"vHe/0T6rE+6tPtQaeWpbv0qMZJBqkiW4Dj9YtDsRS2g=\",\"salt\":\"+1StaWt5e8GT3b+sycysyw==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "ab29205c-5a84-49ed-8f60-5b7c2cd1575c",
"username": "peach",
"firstName": "Princess",
"lastName": "Peach",
"emailVerified": true,
"createdTimestamp": 1742398897969,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "3368ea8a-96ae-463f-ac94-f7d6063b1000",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398909496,
"secretData": "{\"value\":\"WrWIzPPGQQD3OJhaH5UbhVbCBOlXuUx9wkzLKtjO2p8=\",\"salt\":\"OObODYLOFzabgRoCis3GkA==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "fe1c1448-e555-4bcc-a0d7-13970503a705",
"username": "toad",
"firstName": "Captain",
"lastName": "Toad",
"emailVerified": true,
"createdTimestamp": 1742398923041,
"enabled": true,
"totp": false,
"credentials": [
{
"id": "f6451e2e-e1da-4439-a3ae-09fa27207fa0",
"type": "password",
"userLabel": "My password",
"createdDate": 1742398933723,
"secretData": "{\"value\":\"qcsrP+smMu2563eL7mEIeYTwUA68bK31YJy+ohOek8g=\",\"salt\":\"mlmPcb4YSPOA53lVzIKWWQ==\",\"additionalParameters\":{}}",
"credentialData": "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}"
}
],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": [
"default-roles-master"
],
"notBefore": 0,
"groups": []
},
{
"id": "1c3b6114-3c12-4ef7-95ba-a0091f506ed6",
"username": "qc-admin",
Loading