Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"lru-cache": "^11.2.4",
"nanoid": "^3.1.20",
"nest-raven": "10.1.0",
"newrelic": "^13.19.2",
"newrelic": "13.18.0",
"nimma": "^0.6.0",
"passport": "0.7.0",
"passport-github2": "^0.1.12",
Expand Down
22 changes: 20 additions & 2 deletions apps/api/src/app/workflows-v2/e2e/test-http-endpoint.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { UserSession } from '@novu/testing';
import { expect } from 'chai';

/** Public HTTPS URL for outbound tests (localhost is blocked by SSRF validation). */
const HTTP_TEST_POST_URL = 'https://httpbin.org/post';

describe('Test HTTP Request Endpoint - /v2/workflows/steps/test-http-request (POST) #novu-v2', () => {
let session: UserSession;

Expand All @@ -9,10 +12,25 @@ describe('Test HTTP Request Endpoint - /v2/workflows/steps/test-http-request (PO
await session.initialize();
});

it('should resolve canonical raw JSON string body controls', async () => {
it('should reject localhost URLs blocked by SSRF validation', async () => {
const response = await session.testAgent.post('/v2/workflows/steps/test-http-request').send({
controlValues: {
url: `http://localhost:${process.env.PORT}/v1/health-check`,
method: 'GET',
},
});

expect(response.status).to.equal(201);
expect(response.body.data.statusCode).to.equal(400);
expect(response.body.data.body).to.deep.include({
error: 'Requests to "localhost" are not allowed.',
});
});

it('should resolve canonical raw JSON string body controls', async () => {
const response = await session.testAgent.post('/v2/workflows/steps/test-http-request').send({
controlValues: {
url: HTTP_TEST_POST_URL,
method: 'POST',
headers: [{ key: 'content-type', value: 'application/json' }],
body: JSON.stringify({
Expand Down Expand Up @@ -42,7 +60,7 @@ describe('Test HTTP Request Endpoint - /v2/workflows/steps/test-http-request (PO
it('should resolve legacy key-value array body controls', async () => {
const response = await session.testAgent.post('/v2/workflows/steps/test-http-request').send({
controlValues: {
url: `http://localhost:${process.env.PORT}/v1/health-check`,
url: HTTP_TEST_POST_URL,
method: 'POST',
headers: [{ key: 'content-type', value: 'application/json' }],
body: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
KeyValuePair,
resolveHttpRequestBody,
shouldIncludeBody,
validateUrlSsrf,
} from '@novu/application-generic';
import { createLiquidEngine } from '@novu/framework/internal';
import { Liquid } from 'liquidjs';
Expand Down Expand Up @@ -89,6 +90,25 @@ export class TestHttpEndpointUsecase {

const hasBody = shouldIncludeBody(resolvedBody, method);

const ssrfValidationError = await validateUrlSsrf(resolvedUrl);

if (ssrfValidationError) {
const durationMs = Math.round(performance.now() - startTime);

return {
statusCode: 400,
body: { error: ssrfValidationError },
headers: {},
durationMs,
resolvedRequest: {
url: resolvedUrl,
method,
headers: resolvedHeaders,
...(hasBody ? { body: resolvedBody } : {}),
},
};
}

const secretKey = await this.getDecryptedSecretKey.execute(
GetDecryptedSecretKeyCommand.create({ environmentId: command.user.environmentId })
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function SetupStep({
<StepIndicator status={status} index={index} />
</div>
<div className="flex gap-5">
<div className="flex min-w-0 flex-1 flex-col">
<div className="flex min-w-0 max-w-[400px] flex-1 flex-col">
<div className="flex flex-col gap-2">
{sectionLabel && (
<p className="text-text-soft font-code text-[12px] font-medium leading-4 tracking-[-0.24px]">
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/components/agents/slack-setup-guide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export function SlackSetupGuide({
description={
<span>
{
'Paste the App Credentials block from your Slack app — the App ID, Client ID, Client Secret and Signing Secret are filled automatically.'
'Paste the App Credentials block from your Slack app (You can also CMD+A and CMD+C the whole page!) — the App ID, Client ID, Client Secret and Signing Secret are filled automatically in the configure tab.'
}
</span>
}
Expand Down
2 changes: 1 addition & 1 deletion apps/inbound-mail/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"languagedetect": "^1.1.1",
"lodash": "^4.17.23",
"mailparser": "^0.6.0",
"newrelic": "^13.12.0",
"newrelic": "13.18.0",
"pino": "^8.17.2",
"rimraf": "^3.0.2",
"shelljs": "^0.8.5",
Expand Down
2 changes: 1 addition & 1 deletion apps/worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"lodash": "^4.18.0",
"lru-cache": "^11.2.4",
"nest-raven": "10.1.0",
"newrelic": "^13.19.2",
"newrelic": "13.18.0",
"reflect-metadata": "0.2.2",
"rimraf": "^3.0.2",
"rxjs": "7.8.2",
Expand Down
2 changes: 1 addition & 1 deletion apps/ws/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"jsonwebtoken": "9.0.3",
"lodash": "^4.18.0",
"nest-raven": "10.1.0",
"newrelic": "^13.19.2",
"newrelic": "13.18.0",
"reflect-metadata": "0.2.2",
"rimraf": "^3.0.2",
"rxjs": "7.8.2",
Expand Down
2 changes: 1 addition & 1 deletion libs/application-generic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@nestjs/terminus": "10.2.3",
"@nestjs/testing": "10.4.18",
"jsonwebtoken": "9.0.3",
"newrelic": "^13.19.2",
"newrelic": "13.18.0",
"reflect-metadata": "0.2.2"
},
"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@
"@clerk/shared@>=2.20.17 <2.22.1": "^2.22.1",
"@clerk/shared@>=3.0.0-canary.v20250225091530 <3.47.4": "^3.47.4",
"protobufjs@<7.5.5": "^7.5.5",
"protobufjs@>=8.0.0 <8.0.1": "^8.0.1"
"protobufjs@>=8.0.0 <8.0.1": "^8.0.1",
"newrelic": "13.18.0"
},
"onlyBuiltDependencies": [
"@clerk/shared",
Expand Down
2 changes: 1 addition & 1 deletion packages/framework/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@novu/framework",
"version": "2.10.1-alpha.4",
"version": "2.10.1-alpha.5",
"description": "The Code-First Notifications Workflow SDK.",
"main": "./dist/cjs/index.cjs",
"types": "./dist/cjs/index.d.cts",
Expand Down
2 changes: 1 addition & 1 deletion packages/novu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "novu",
"version": "2.8.1-rc.5",
"version": "2.8.1-rc.6",
"description": "Novu CLI. Run Novu Studio and sync workflows with Novu Cloud",
"main": "src/index.js",
"publishConfig": {
Expand Down
Loading
Loading