Skip to content

Commit

Permalink
Merge branch 'next' into nv-5432-fix-typeerror-related-to-subscriberi…
Browse files Browse the repository at this point in the history
…dtrim-function
  • Loading branch information
BiswaViraj authored Feb 27, 2025
2 parents f263e14 + e6c66cf commit 99f61a6
Show file tree
Hide file tree
Showing 444 changed files with 8,863 additions and 3,629 deletions.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"EQAs",
"analagous",
"addrs",
"Tiering",
"subscriberpayloaddto",
"adresses",
"APIJSON",
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/docker/build-api/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ runs:
docker tag novu-api $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker run --network=host --name api -dit --env NODE_ENV=test $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker run --network=host appropriate/curl --retry 10 --retry-delay 5 --retry-connrefused http://127.0.0.1:1337/v1/health-check | grep 'ok'
docker run --network=host appropriate/curl --retry 10 --retry-delay 5 --retry-connrefused http://127.0.0.1:1336/v1/health-check | grep 'ok'
echo "IMAGE=$REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/dev-deploy-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

jobs:
test_api:
uses: ./.github/workflows/reusable-api-e2e.yml
with:
ee: true
job-name: 'novu/api-ee'
secrets: inherit
# test_api:
# uses: ./.github/workflows/reusable-api-e2e.yml
# with:
# ee: true
# job-name: 'novu/api-ee'
# secrets: inherit

deploy_dev_api:
runs-on: ubuntu-latest
needs: test_api
# needs: test_api
timeout-minutes: 80
environment: Development
permissions:
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,14 +256,14 @@ jobs:
# with:
# ee: true

# test_e2e_dashboard:
# name: E2E test Dashboard app
# needs: [get-affected]
# if: ${{ contains(fromJson(needs.get-affected.outputs.test-e2e), '@novu/dashboard') }}
# uses: ./.github/workflows/reusable-dashboard-e2e.yml
# secrets: inherit
# with:
# ee: true
test_e2e_dashboard:
name: E2E test Dashboard app
needs: [get-affected]
if: ${{ contains(fromJson(needs.get-affected.outputs.test-e2e), '@novu/dashboard') }}
uses: ./.github/workflows/reusable-dashboard-e2e.yml
secrets: inherit
with:
ee: true

test_e2e_widget:
name: E2E test Widget
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prod-deploy-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
docker tag novu-api $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker run --network=host --name api -dit --env NODE_ENV=test $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker run --network=host appropriate/curl --retry 10 --retry-delay 5 --retry-connrefused http://127.0.0.1:1337/v1/health-check | grep 'ok'
docker run --network=host appropriate/curl --retry 10 --retry-delay 5 --retry-connrefused http://127.0.0.1:1336/v1/health-check | grep 'ok'
docker push $REGISTRY/$REPOSITORY:prod
docker push $REGISTRY/$REPOSITORY:latest
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/reusable-api-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ jobs:
if: ${{ needs.check_submodule_token.outputs.has_token == 'true' && inputs.ee }}
env:
LAUNCH_DARKLY_SDK_KEY: ${{ secrets.LAUNCH_DARKLY_SDK_KEY }}
CI_EE_TEST: true
CLERK_ENABLED: true
CLERK_ISSUER_URL: ${{ vars.CLERK_ISSUER_URL }}
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
CLERK_WEBHOOK_SECRET: ${{ secrets.CLERK_WEBHOOK_SECRET }}
CLERK_LONG_LIVED_TOKEN: ${{ secrets.CLERK_LONG_LIVED_TOKEN }}
run: |
pnpm --filter @novu/api-service test:e2e:novu-v2
Expand Down
67 changes: 47 additions & 20 deletions .github/workflows/reusable-dashboard-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ jobs:
fail-fast: false
matrix:
# run 4 copies of the current job in parallel
containers: [1, 2, 3, 4]
total: [4]
containers: [1]
total: [1]

# The type of runner that the job will run on
runs-on: ubuntu-latest
Expand Down Expand Up @@ -68,6 +68,30 @@ jobs:
with:
submodules: true

- name: Create .env file for the Dashboard app
working-directory: apps/dashboard
run: |
touch .env
echo VITE_LAUNCH_DARKLY_CLIENT_SIDE_ID=${{ secrets.LAUNCH_DARKLY_CLIENT_SIDE_ID }} >> .env
echo VITE_API_HOSTNAME=http://127.0.0.1:1336 >> .env
echo VITE_WEBSOCKET_HOSTNAME=http://127.0.0.1:1340 >> .env
echo VITE_LEGACY_DASHBOARD_URL=http://127.0.0.1:4200 >> .env
echo VITE_CLERK_PUBLISHABLE_KEY=${{ secrets.CLERK_E2E_PUBLISHABLE_KEY }} >> .env
- name: Create .env file for the Playwright
working-directory: apps/dashboard
run: |
touch .env.playwright
echo NOVU_ENTERPRISE=true >> .env.playwright
echo NEW_RELIC_ENABLED=false >> .env.playwright
echo NEW_RELIC_APP_NAME=Novu >> .env.playwright
echo MONGO_URL=mongodb://127.0.0.1:27017/novu-test >> .env.playwright
echo API_URL=http://127.0.0.1:1336 >> .env.playwright
echo CLERK_ENABLED=true >> .env.playwright
echo CLERK_PUBLISHABLE_KEY=${{ secrets.CLERK_E2E_PUBLISHABLE_KEY }} >> .env.playwright
echo CLERK_SECRET_KEY=${{ secrets.CLERK_E2E_SECRET_KEY }} >> .env.playwright
echo NODE_ENV=test >> .env.playwright
- uses: mansagroup/nrwl-nx-action@v3
with:
targets: build
Expand All @@ -77,30 +101,33 @@ jobs:
- uses: ./.github/actions/start-localstack
- uses: ./.github/actions/setup-redis-cluster

- uses: ./.github/actions/run-backend
with:
cypress_github_oauth_client_id: ${{ secrets.CYPRESS_GITHUB_OAUTH_CLIENT_ID }}
cypress_github_oauth_client_secret: ${{ secrets.CYPRESS_GITHUB_OAUTH_CLIENT_SECRET }}
launch_darkly_sdk_key: ${{ secrets.LAUNCH_DARKLY_SDK_KEY }}
ci_ee_test: ${{ steps.determine_run_type.outputs.enterprise_run }}
- name: Start API in TEST
env:
CI_EE_TEST: true
CLERK_ENABLED: true
CLERK_ISSUER_URL: https://neat-mole-83.clerk.accounts.dev
CLERK_SECRET_KEY: ${{ secrets.CLERK_E2E_SECRET_KEY }}
run: |
cd apps/api && pnpm start:test &
- name: Start Worker
shell: bash
env:
NODE_ENV: 'test'
PORT: '1342'
CI_EE_TEST: true
run: cd apps/worker && pnpm start:test &

- name: Wait on API and Worker
shell: bash
run: wait-on --timeout=180000 http://127.0.0.1:1336/v1/health-check http://127.0.0.1:1342/v1/health-check

- name: Start WS
run: |
cd apps/ws && pnpm start:test &
- name: Start Novu Dashboard
working-directory: apps/dashboard
env:
REACT_APP_API_URL: http://127.0.0.1:1336
REACT_APP_WS_URL: http://127.0.0.1:1340
REACT_APP_WEBHOOK_URL: http://127.0.0.1:1341
# Disable LaunchDarkly client-side SDK in the test environment to reduce E2E flakiness
REACT_APP_LAUNCH_DARKLY_CLIENT_SIDE_ID: ''
NOVU_ENTERPRISE: ${{ steps.determine_run_type.outputs.enterprise_run }}
run: pnpm start:static:build &

- name: Wait on Services
run: wait-on --timeout=180000 http://127.0.0.1:1340/v1/health-check http://127.0.0.1:4201/
run: wait-on --timeout=180000 http://127.0.0.1:1340/v1/health-check

- name: Install Playwright
working-directory: apps/dashboard
Expand Down
9 changes: 1 addition & 8 deletions .idea/runConfigurations/RUN_LOCAL_ENV.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .source
9 changes: 2 additions & 7 deletions apps/api/e2e/setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { testServer, TestingQueueService, JobsService } from '@novu/testing';
import { JobsService, TestingQueueService, testServer } from '@novu/testing';
import sinon from 'sinon';
import chai from 'chai';
import mongoose from 'mongoose';
Expand Down Expand Up @@ -67,12 +67,7 @@ afterEach(async function () {
sinon.restore();

try {
await Promise.race([
cleanup(),
timeoutPromise(TIMEOUT).then(() => {
console.warn('Cleanup operation timed out after 5000ms - continuing with tests');
}),
]);
await Promise.race([cleanup(), timeoutPromise(TIMEOUT).then(() => {})]);
} catch (error) {
console.error('Error during cleanup:', error);
}
Expand Down
6 changes: 3 additions & 3 deletions apps/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@novu/api-service",
"version": "2.1.7",
"version": "2.1.13",
"description": "description",
"author": "",
"private": "true",
Expand All @@ -15,15 +15,15 @@
"docker:build:depot": "pnpm --silent --workspace-root pnpm-context -- apps/api/Dockerfile | depot build --build-arg PACKAGE_PATH=apps/api - -t novu-api --load",
"start": "pnpm start:dev",
"start:dev": "nest start --watch",
"start:test": "cross-env NODE_ENV=test PORT=1336 nest start --watch",
"start:test": "cross-env NODE_ENV=test nest start --watch",
"start:debug": "nest start --debug",
"start:prod": "node dist/main.js",
"build:metadata": "cross-env ts-node scripts/generate-metadata.ts",
"lint": "eslint src",
"lint:fix": "pnpm lint -- --fix",
"lint:openapi": "spectral lint http://127.0.0.1:${PORT:-3000}/openapi.yaml",
"pretest": "pnpm build:metadata",
"generate:swagger": "cross-env NODE_ENV=test PORT=1336 ts-node exportOpenAPIJSON.ts",
"generate:swagger": "cross-env NODE_ENV=test ts-node exportOpenAPIJSON.ts",
"generate:sdk": " (cd ../../libs/internal-sdk && speakeasy run --skip-compile --minimal --skip-versioning) && (cd ../../libs/internal-sdk && pnpm build) ",
"test": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test mocha --timeout 5000 --require ts-node/register --exit 'src/**/*.spec.ts'",
"test:e2e:novu-v1": "cross-env TS_NODE_COMPILER_OPTIONS='{\"strictNullChecks\": false}' NODE_ENV=test mocha --timeout 5000 --grep '#novu-v1' --require ts-node/register --exit --file e2e/setup.ts src/**/*.e2e{,-ee}.ts ",
Expand Down
1 change: 0 additions & 1 deletion apps/api/src/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ GLOBAL_CONTEXT_PATH=
API_CONTEXT_PATH=
DISABLE_USER_REGISTRATION=false

NEST_STARTER_MAIL=[email protected]
CLIENT_SUCCESS_AUTH_REDIRECT=https://dashboard.novu-staging.co/auth/login

REDIS_PORT=6379
Expand Down
1 change: 0 additions & 1 deletion apps/api/src/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ API_CONTEXT_PATH=
DISABLE_USER_REGISTRATION=false

WIDGET_BASE_URL=https://widget.novu.co
NEST_STARTER_MAIL=[email protected]

REDIS_PORT=6379
REDIS_PREFIX=
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ REDIS_CLUSTER_KEY_PREFIX=
SYNC_PATH=http://127.0.0.1:3001
API_ROOT_URL=http://127.0.0.1:3000
DISABLE_USER_REGISTRATION=false
PORT=1337
PORT=1336
JWT_SECRET=ASD#asda23DFEFSFHG%fg
NODE_ENV=test
SENDGRID_API_KEY=SG.123123
Expand Down Expand Up @@ -147,7 +147,7 @@ ZwIDAQAB
-----END PUBLIC KEY-----"

TUNNEL_BASE_ADDRESS=example.com
API_ROOT_URL=http://localhost:1337
API_ROOT_URL=http://localhost:1336
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
PLAIN_IDENTITY_VERIFICATION_SECRET_KEY='PLAIN_IDENTITY_VERIFICATION_SECRET_KEY'
NOVU_INTERNAL_SECRET_KEY=test
114 changes: 114 additions & 0 deletions apps/api/src/app/auth/e2e/clerk.strategy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/* eslint-disable global-require */
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import { EnvironmentRepository } from '@novu/dal';
import sinon from 'sinon';
import { ApiAuthSchemeEnum, UserSessionData } from '@novu/shared';
import { HttpRequestHeaderKeysEnum } from '@novu/application-generic';
import { UnauthorizedException } from '@nestjs/common';

describe('ClerkStrategy', () => {
let eeAuth: any;

try {
eeAuth = require('@novu/ee-auth');
} catch (error) {
return;
}

const { ClerkStrategy, LinkEntitiesService, ClerkJwtPayload } = eeAuth;

let strategy: typeof ClerkStrategy;
let mockEnvironmentRepository: { findOne: sinon.SinonStub };
let mockLinkEntitiesService: { linkInternalExternalEntities: sinon.SinonStub };

const mockRequest = {
headers: {
[HttpRequestHeaderKeysEnum.NOVU_ENVIRONMENT_ID.toLowerCase()]: 'env-123',
},
};

const mockPayload: Partial<typeof ClerkJwtPayload> = {
_id: 'clerk-user-123',
org_id: 'clerk-org-123',
firstName: 'John',
lastName: 'Doe',
profilePicture: 'https://example.com/profile.png',
email: '[email protected]',
org_role: 'org:admin',
externalId: undefined,
externalOrgId: undefined,
};

beforeEach(async () => {
mockEnvironmentRepository = {
findOne: sinon.stub().resolves({ _id: 'env-123' }),
};

mockLinkEntitiesService = {
linkInternalExternalEntities: sinon.stub().resolves({
internalUserId: 'internal-user-123',
internalOrgId: 'internal-org-123',
}),
};

const moduleRef = await Test.createTestingModule({
providers: [
ClerkStrategy,
{ provide: EnvironmentRepository, useValue: mockEnvironmentRepository },
{ provide: LinkEntitiesService, useValue: mockLinkEntitiesService },
],
}).compile();

strategy = moduleRef.get<typeof ClerkStrategy>(ClerkStrategy);
});

describe('validate', () => {
it('should transform Clerk payload into valid user session', async () => {
const result: UserSessionData = await strategy.validate(mockRequest, mockPayload);

expect(result).to.deep.include({
_id: 'internal-user-123',
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
organizationId: 'internal-org-123',
roles: ['admin'],
environmentId: 'env-123',
scheme: ApiAuthSchemeEnum.BEARER,
});
});

it('should call linkInternalExternalEntities with correct parameters', async () => {
await strategy.validate(mockRequest, mockPayload);

expect(mockLinkEntitiesService.linkInternalExternalEntities.calledOnceWith(mockRequest, mockPayload)).to.be.true;
});

it('should verify environment access', async () => {
await strategy.validate(mockRequest, mockPayload);

expect(
mockEnvironmentRepository.findOne.calledOnceWith(
{
_id: 'env-123',
_organizationId: 'internal-org-123',
},
'_id'
)
).to.be.true;
});

it('should throw UnauthorizedException when environment is not found', async () => {
mockEnvironmentRepository.findOne.resolves(null);

try {
await strategy.validate(mockRequest, mockPayload);
expect.fail('Should have thrown an error');
} catch (err) {
expect(err).to.be.instanceOf(UnauthorizedException);
expect(err.message).to.equal('Cannot find environment');
}
});
});
});
Loading

0 comments on commit 99f61a6

Please sign in to comment.