Skip to content
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

chore: added credentials to javascript transformations #3408

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
732fbf4
chore: added credentials to javascript transformations
kanishkkatara May 23, 2024
e6a3dbb
chore: added tests
kanishkkatara May 23, 2024
a7e4ba4
chore: change in credentials structure
kanishkkatara May 24, 2024
5111ce9
chore: changes in test transform API
kanishkkatara May 30, 2024
c280d81
fix: credential param
kanishkkatara May 30, 2024
3137964
fix: test
kanishkkatara May 31, 2024
7eb537c
fix: credential error handling
kanishkkatara Jun 3, 2024
a57da89
chore: added tests
kanishkkatara Jun 3, 2024
1fd068b
chore: added errors in credentials
kanishkkatara Jun 3, 2024
8808508
chore: added credentials at event level for python transformations
kanishkkatara Jun 4, 2024
ce2d62d
Merge branch 'develop' into feature/dat-1207-javascript-transformatio…
kanishkkatara Jun 11, 2024
546a937
chore: added check for multiple arguments
kanishkkatara Jun 12, 2024
bb94c81
chore: change in lodash import
kanishkkatara Jun 12, 2024
a80d403
chore: changes in transformation error handling
kanishkkatara Jun 17, 2024
67e9277
fix: fixes in javascript transformation
kanishkkatara Jun 18, 2024
e7a59f9
chore: added tests for transform batch and code version 0
kanishkkatara Jun 18, 2024
46cd341
fix: pr comments
kanishkkatara Jun 18, 2024
819f508
fix: undefined tests
kanishkkatara Jun 18, 2024
fa3619c
Merge branch 'develop' into feature/dat-1207-javascript-transformatio…
kanishkkatara Jun 18, 2024
e6c5098
fix: credentials payload fix
kanishkkatara Jun 18, 2024
3db810c
fix: tests names, credentialsMap refactor
kanishkkatara Jun 19, 2024
7b0ea80
refactor: change in credentials function validation code
kanishkkatara Jun 19, 2024
2a17453
Merge branch 'develop' into feature/dat-1207-javascript-transformatio…
kanishkkatara Jun 19, 2024
d655fd1
Merge branch 'develop' into feature/dat-1207-javascript-transformatio…
kanishkkatara Jun 19, 2024
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
3 changes: 2 additions & 1 deletion src/controllers/userTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ export class UserTransformController {
'(User transform - router:/transformation/test ):: Request to transformer',
ctx.request.body,
);
const { events, trRevCode, libraryVersionIDs = [] } = ctx.request.body as any;
const { events, trRevCode, libraryVersionIDs = [], credentials = [] } = ctx.request.body as any;
const response = await UserTransformService.testTransformRoutine(
events,
trRevCode,
libraryVersionIDs,
credentials,
);
ctx.body = response.body;
ControllerUtility.postProcess(ctx, response.status);
Expand Down
15 changes: 13 additions & 2 deletions src/services/userTransform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import groupBy from 'lodash/groupBy';
import isEmpty from 'lodash/isEmpty';
import { isNil } from 'lodash';
import { userTransformHandler } from '../routerUtils';
import {
UserTransformationLibrary,
Expand Down Expand Up @@ -203,7 +204,7 @@
} as UserTransformationServiceResponse;
}

public static async testTransformRoutine(events, trRevCode, libraryVersionIDs) {
public static async testTransformRoutine(events, trRevCode, libraryVersionIDs, credentials) {

Check warning on line 207 in src/services/userTransform.ts

View check run for this annotation

Codecov / codecov/patch

src/services/userTransform.ts#L207

Added line #L207 was not covered by tests
const response: FixMe = {};
try {
if (!trRevCode || !trRevCode.code || !trRevCode.codeVersion) {
Expand All @@ -213,11 +214,21 @@
throw new Error('Invalid request. Missing events');
}

const updatedEvents = events.map((ev) => {

Check warning on line 217 in src/services/userTransform.ts

View check run for this annotation

Codecov / codecov/patch

src/services/userTransform.ts#L217

Added line #L217 was not covered by tests
if (isNil(ev.credentials)) {
return {

Check warning on line 219 in src/services/userTransform.ts

View check run for this annotation

Codecov / codecov/patch

src/services/userTransform.ts#L219

Added line #L219 was not covered by tests
...ev,
credentials,
};
}
return ev;

Check warning on line 224 in src/services/userTransform.ts

View check run for this annotation

Codecov / codecov/patch

src/services/userTransform.ts#L224

Added line #L224 was not covered by tests
});

logger.debug(`[CT] Test Input Events: ${JSON.stringify(events)}`);
// eslint-disable-next-line no-param-reassign
trRevCode.versionId = 'testVersionId';
response.body = await userTransformHandler()(
events,
updatedEvents,
trRevCode.versionId,
libraryVersionIDs,
trRevCode,
Expand Down
8 changes: 8 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,20 @@ type UserTransformationLibrary = {
VersionID: string;
};

type Credential = {
id: string;
key: string;
value: string;
isSecret: boolean;
};

type ProcessorTransformationRequest = {
request?: object;
message: object;
metadata: Metadata;
destination: Destination;
libraries?: UserTransformationLibrary[];
credentials?: Credential[];
};

type RouterTransformationRequestData = {
Expand Down
7 changes: 7 additions & 0 deletions src/util/customTransformer-v1.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,17 @@ async function userTransformHandlerV1(
return { transformedEvents: events };
}

const credentialsMap = {};
(events[0]?.credentials || []).forEach((cred) => {
credentialsMap[cred.key] = cred.value;
});
const isolatevmFactory = await getFactory(
userTransformation.code,
libraryVersionIds,
userTransformation.versionId,
userTransformation.id,
userTransformation.workspaceId,
credentialsMap,
userTransformation.secrets || {},
testMode,
);
Expand Down
2 changes: 0 additions & 2 deletions src/util/customTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const { parserForImport } = require('./parser');
const stats = require('./stats');
const { fetchWithDnsWrapper } = require('./utils');
const { getMetadata, getTransformationMetadata } = require('../v0/util');

const ISOLATE_VM_MEMORY = parseInt(process.env.ISOLATE_VM_MEMORY || '128', 10);
const GEOLOCATION_TIMEOUT_IN_MS = parseInt(process.env.GEOLOCATION_TIMEOUT_IN_MS || '1000', 10);

Expand Down Expand Up @@ -286,7 +285,6 @@ async function userTransformHandler(
events.forEach((ev) => {
eventsMetadata[ev.message.messageId] = ev.metadata;
});

let userTransformedEvents = [];
let result;
if (res.codeVersion && res.codeVersion === '1') {
Expand Down
58 changes: 53 additions & 5 deletions src/util/ivmFactory.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const ivm = require('isolated-vm');
const fetch = require('node-fetch');
const _ = require('lodash');
const { isNil, isObject, camelCase } = require('lodash');

const { getLibraryCodeV1, getRudderLibByImportName } = require('./customTransforrmationsStore-v1');
const { extractStackTraceUptoLastSubstringMatch } = require('./utils');
Expand Down Expand Up @@ -30,7 +30,16 @@
return module;
}

async function createIvm(code, libraryVersionIds, versionId, secrets, testMode) {
async function createIvm(
code,
libraryVersionIds,
versionId,
transformationId,
workspaceId,
credentials,
secrets,
testMode,
) {
const createIvmStartTime = new Date();
const logs = [];
const libraries = await Promise.all(
Expand All @@ -51,7 +60,7 @@

// TODO: Check if this should this be &&
libraries.forEach((library) => {
const libHandleName = _.camelCase(library.name);
const libHandleName = camelCase(library.name);
if (extractedLibraries.includes(libHandleName)) {
librariesMap[libHandleName] = library.code;
}
Expand Down Expand Up @@ -243,6 +252,20 @@
}),
);

await jail.set('_credential', function (key) {
if (isNil(credentials) || !isObject(credentials)) {
logger.error(

Check warning on line 257 in src/util/ivmFactory.js

View check run for this annotation

Codecov / codecov/patch

src/util/ivmFactory.js#L257

Added line #L257 was not covered by tests
`Error fetching credentials map for transformationID: ${transformationId} and workspaceId: ${workspaceId}`,
);
stats.increment('credential_error_total', { transformationId, workspaceId });
return undefined;

Check warning on line 261 in src/util/ivmFactory.js

View check run for this annotation

Codecov / codecov/patch

src/util/ivmFactory.js#L260-L261

Added lines #L260 - L261 were not covered by tests
}
if (key === null || key === undefined) {
throw new TypeError('Key should be valid and defined');
}
return credentials[key];
});

await jail.set('_rsSecrets', function (...args) {
if (args.length == 0 || !secrets || !secrets[args[0]]) return 'ERROR';
return secrets[args[0]];
Expand Down Expand Up @@ -321,6 +344,13 @@
]);
};

let credential = _credential;
delete _credential;
global.credential = function(...args) {
const key = args[0];
return credential(new ivm.ExternalCopy(key).copyInto());
};

return new ivm.Reference(function forwardMainPromise(
fnRef,
resolve,
Expand Down Expand Up @@ -411,10 +441,28 @@
return evaluateModule(isolate, context, code);
}

async function getFactory(code, libraryVersionIds, versionId, secrets, testMode) {
async function getFactory(
code,
libraryVersionIds,
transformationId,
workspaceId,
versionId,
credentials,
secrets,
testMode,
) {
const factory = {
create: async () => {
return createIvm(code, libraryVersionIds, versionId, secrets, testMode);
return createIvm(
code,
libraryVersionIds,
versionId,
transformationId,
workspaceId,
credentials,
secrets,
testMode,
);
},
destroy: async (client) => {
client.fnRef.release();
Expand Down
6 changes: 6 additions & 0 deletions src/util/prometheus.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,12 @@ class Prometheus {
'sourceId',
],
},
{
name: 'credential_error_total',
help: 'Error in fetching credentials count',
type: 'counter',
labelNames: ['transformationId', 'workspaceId'],
},

// Gauges
{
Expand Down
67 changes: 67 additions & 0 deletions test/__tests__/data/user_transformation_input_credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[
{
"message": {
"channel": "web",
"context": {
"app": {
"build": "1.0.0",
"name": "RudderLabs JavaScript SDK",
"namespace": "com.rudderlabs.javascript",
"version": "1.0.0"
},
"traits": {
"email": "[email protected]",
"anonymousId": "12345"
},
"library": {
"name": "RudderLabs JavaScript SDK",
"version": "1.0.0"
},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36",
"locale": "en-US",
"ip": "0.0.0.0",
"os": {
"name": "",
"version": ""
},
"screen": {
"density": 2
}
},
"type": "track",
"messageId": "ec5481b6-a926-4d2e-b293-0b3a77c4d3be",
"originalTimestamp": "2019-10-14T11:15:18.300Z",
"anonymousId": "00000000000000000000000000",
"userId": "12345",
"event": "test track event GA3",
"properties": {
"user_actual_role": "system_admin, system_user",
"user_actual_id": 12345
},
"integrations": {
"All": true
},
"sentAt": "2019-10-14T11:15:53.296Z"
},
"destination": {
"Config": {
"trackingID": "UA-149602794-1"
},
"Enabled": true
},
"credentials": [
{
"id": "id1",
"key": "key1",
"value": "value1",
"isSecret": false
},
{
"id": "id2",
"key": "key2",
"value": "value2",
"isSecret": true
}
]
}
]
1 change: 1 addition & 0 deletions test/__tests__/user_transformation.integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ describe("Function invocation & creation tests", () => {
versionId,
[],
trRevCode,
[],
true
);
expect(response).toEqual(outputEvents);
Expand Down
Loading
Loading