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

feat(cli): [nan-1106] import relative files in syncs/actions #2273

Merged

Conversation

khaliqgant
Copy link
Member

@khaliqgant khaliqgant commented Jun 5, 2024

Describe your changes

Use tsup to import relative files in syncs. The error reporting with tsup isn't as nice as ts-node so the tsup transpiles only and ts-node is still used to type check and report nice errors. The result is actually faster than previous. tsup doesn't transpile if there are any compilation errors.

Note that an additional vite.cli.config file was added which doesn't use threads because it was interfering with tsup

Edge Cases Handled

  • If the main file imports another file which in turn imports another file then all imported files should be typed checked and checked to make sure nango calls are used correctly
  • If a library is imported like crypto we shouldn't try and type check that file
  • If a tsconfig.json file exists in their repo it isn't used and the one we want to use in the nango cli directory is instead used
  • Limit possible import files to be in the nango-integrations directory
  • Update to download the entire nango-integrations directory instead of just the particular file (v2)
  • Verify that changing the transpiled code doesn't produce different results the ts-node transpilation

Issue ticket number and link

NAN-1106

Checklist before requesting a review (skip if just adding/editing APIs & templates)

  • I added tests, otherwise the reason is:
  • I added observability, otherwise the reason is:
  • I added analytics, otherwise the reason is:

Copy link

linear bot commented Jun 5, 2024

@khaliqgant khaliqgant changed the title feat(cli: [nan-1106] import relative files in syncs/actions feat(cli): [nan-1106] import relative files in syncs/actions Jun 5, 2024
@khaliqgant khaliqgant requested review from TBonnin and bodinsamuel and removed request for TBonnin June 6, 2024 09:39
Copy link
Collaborator

@bodinsamuel bodinsamuel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this error when running node ../nango/packages/cli/dist/index.js compile

Error compiling "/Users/samuelbodin/code/nango-integrations/unauthenticated/syncs/trackDeletes.ts":
SyntaxError: Unexpected token '', "��z��" is not valid JSON
    at JSON.parse (<anonymous>)
    at new AnyMap (/Users/samuelbodin/code/nango/node_modules/@jridgewell/src/any-map.ts:20:37)
    at mapSourcePosition (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:387:14)
    at wrapCallSite (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:592:20)
    at Function.prepareStackTrace (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:671:41)
    at prepareStackTraceCallback (node:internal/errors:145:29)
    at getStackString (node:internal/util/inspect:1240:16)
    at formatError (node:internal/util/inspect:1369:15)
    at formatRaw (node:internal/util/inspect:985:14)
    at formatValue (node:internal/util/inspect:840:10)

packages/cli/lib/tests/helpers.ts Outdated Show resolved Hide resolved
vite.cli.config.ts Outdated Show resolved Hide resolved
@khaliqgant
Copy link
Member Author

I have this error when running node ../nango/packages/cli/dist/index.js compile

Error compiling "/Users/samuelbodin/code/nango-integrations/unauthenticated/syncs/trackDeletes.ts":
SyntaxError: Unexpected token '', "��z��" is not valid JSON
    at JSON.parse (<anonymous>)
    at new AnyMap (/Users/samuelbodin/code/nango/node_modules/@jridgewell/src/any-map.ts:20:37)
    at mapSourcePosition (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:387:14)
    at wrapCallSite (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:592:20)
    at Function.prepareStackTrace (/Users/samuelbodin/code/nango/node_modules/@cspotcode/source-map-support/source-map-support.js:671:41)
    at prepareStackTraceCallback (node:internal/errors:145:29)
    at getStackString (node:internal/util/inspect:1240:16)
    at formatError (node:internal/util/inspect:1369:15)
    at formatRaw (node:internal/util/inspect:985:14)
    at formatValue (node:internal/util/inspect:840:10)

Can you try this again? Should be resolved.

Copy link
Collaborator

@TBonnin TBonnin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is an inverted condition with the nango-integrations directory detection but other than that it seems to work as expected. I haven't tested very involved or big import though

Question about your PR notes:

Update to download the entire nango-integrations directory instead of just the particular file (v2)
why will we need to do that?

const code = fs.readFileSync(filePath, 'utf-8');
const ast = parser.parse(code, { sourceType: 'module', plugins: ['typescript'] });
const importedFiles: string[] = [];
const traverseFn = (traverse as any).default || traverse;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it is unrelated to this PR but I've always wondered why does this .default thing is doing and why we are not using traverse directly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think during tests traverse wasn't available for some reason


const cwd = process.cwd().split('/').pop();
const fullPath = path.resolve(importedFilePathWithExtension);
if (cwd === 'nango-integrations' && fullPath.includes(process.cwd())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't it be the negative? ie: if fullPath doesn't includes nango-integration then show error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this was the last thing I added last night without testing thoroughly. Updated and added a test case to support it + improved the error message

@khaliqgant
Copy link
Member Author

I think there is an inverted condition with the nango-integrations directory detection but other than that it seems to work as expected. I haven't tested very involved or big import though

Question about your PR notes:

Update to download the entire nango-integrations directory instead of just the particular file (v2)
why will we need to do that?

So a user could download all the code including helper files.

Copy link
Collaborator

@bodinsamuel bodinsamuel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great 👏🏻
I have a question about unintended side-effects, it's now possible to load any npm package inside the build, I don't think it's okay even if it's handy?

@khaliqgant
Copy link
Member Author

Works great 👏🏻 I have a question about unintended side-effects, it's now possible to load any npm package inside the build, I don't think it's okay even if it's handy?

Thanks for catching this! Should be resolved by 1980321

Copy link
Collaborator

@bodinsamuel bodinsamuel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, it now catches the most obvious incorrect import, and execute appropriately.
It's still possible to import node_modules by using relative path (i.e: import {attemptifyAsync} from '../../node_modules/stubborn-fs/src/attemptify';). It's a bit harder to catch, especially that stuff could live outside node_modules.

Side note:

  • You can't import .js file, I'm sure it's not really an issue but it displays the wrong error message in that case. (and it reduces the possibility to import packages)
  • Because they can import stuff, they'll need a package.json, so we need to check wether the zod/node version is matching what we are using otherwise the types will be wrong and/or expected execution will be slightly different

packages/cli/lib/services/compile.service.ts Outdated Show resolved Hide resolved
@khaliqgant
Copy link
Member Author

Nice, it now catches the most obvious incorrect import, and execute appropriately. It's still possible to import node_modules by using relative path (i.e: import {attemptifyAsync} from '../../node_modules/stubborn-fs/src/attemptify';). It's a bit harder to catch, especially that stuff could live outside node_modules.

Yeah, hard to catch these edge cases.

Side note:

  • You can't import .js file, I'm sure it's not really an issue but it displays the wrong error message in that case. (and it reduces the possibility to import packages)

Something to revisit in future iterations perhaps.

  • Because they can import stuff, they'll need a package.json, so we need to check wether the zod/node version is matching what we are using otherwise the types will be wrong and/or expected execution will be slightly different

Yeah, we should publish in our documentation what versions of things we're using to make sure it aligns

@khaliqgant khaliqgant merged commit 5a2d16c into master Jun 7, 2024
21 checks passed
@khaliqgant khaliqgant deleted the khaliq/nan-1106-import-relative-files-with-cc-or-rollup branch June 7, 2024 13:46
@bburns
Copy link
Contributor

bburns commented Jun 12, 2024

Nice, it now catches the most obvious incorrect import, and execute appropriately. It's still possible to import node_modules by using relative path (i.e: import {attemptifyAsync} from '../../node_modules/stubborn-fs/src/attemptify';). It's a bit harder to catch, especially that stuff could live outside node_modules.

Yeah, hard to catch these edge cases.

Some example code for avoiding path traversal attacks -

const root = '/var/www/'
exports.validatePath = user_input => {
  if (user_input.indexOf('\0') !== -1) {
    return 'Access denied'
  }
  if (!/^[a-z0-9]+$/.test(user_input)) {
    return 'Access denied'
  }
  const path = require('path')
  const safe_input = path.normalize(user_input).replace(/^(\.\.(\/|\\|$))+/, '')
  const path_string = path.join(root, safe_input)
  if (path_string.indexOf(root) !== 0) {
    return 'Access denied'
  }
  return path_string
}

From https://www.stackhawk.com/blog/node-js-path-traversal-guide-examples-and-prevention/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants