chore(eslint-plugin): rule against invalid paths#28828
Conversation
paulhcsun
left a comment
There was a problem hiding this comment.
Looks good, just one minor comment.
| } | ||
|
|
||
| if (isPathJoinFuncCall(node)) { | ||
| // Confirm path does not have unnecessary '..' |
There was a problem hiding this comment.
First: is this check against oscillating worth the squeeze? (Or is this just to make the subsequent checks easier? If so, I can dig that. Might want to write that down.)
Second: can this not be simplified in the following way:
..may only occur in the path prefix.- So any
..whose index is after the first non-..is incorrect:
const components = confirmFirstArgumentIsDirnameAndRemove(node.arguments);
const firstDownDir = components.findIndex((p) => p !== '..');
if (components.some((p, i) => p === '..' && i > firstDownDir) {
// ERROR: Oscillating paths
return;
}Then we can observe that package.json may only exist in the very last directory that we ended up with by doing ..: if it occurs anywhere earlier that's an error:
// Note the - 1 to exclude the last directory from the check
// Exclude the case where there are no '..' at all in the path -- those are never invalid
if (firstDownDir > 0) {
for (let i = 0; i < firstDownDir - 1; i++) {
const pjFile = path.join(...[path.dirname(currentFile), ...components.slice(0, i), 'package.json']);
if (existsSync(pjFile)) {
// ERROR: this path will end up going out of the package.json directory
return;
}
}
}There was a problem hiding this comment.
Take a moment to reason through this table to see how this works:
// components | firstDownDir | closest invalid package.json
['x'] 0 /* N/A */
['..', 'x'] 1 'package.json'
['..', '..', 'x'] 2 '../package.json'There was a problem hiding this comment.
Oh you should also add a check that / doesn't occur anywhere inside any of the components, otherwise our checks are going to fail:
path.join(__dirname, '../../../..', 'banana')
Is bad style but works, and anything that accidentally works will occur in our code base 😅. We need to guard against it.
| let forward = false; // Determines if the path is officially going forward | ||
| let validPath = true; | ||
| for (let i=1; i<node.arguments.length; i++) { | ||
| const path = node.arguments[i].value; |
There was a problem hiding this comment.
Are we confirming anywhere that the first argument to path.join() is __dirname ? I can't find it
There was a problem hiding this comment.
Yes, in isPathJoinFuncCall:
function isPathJoinFuncCall(node: any): boolean {
return (
node.callee?.property?.name === 'join' &&
node.arguments.length > 1 &&
node.arguments[0].name &&
node.arguments[0].name === '__dirname'
)
}There was a problem hiding this comment.
I assume that we don't have any rule that says path.join must have __dirname as the first argument, but rereading your comment suggests that that may be indeed what you are suggesting
There was a problem hiding this comment.
No, but just saying that we don't need to do any checks on path.joins where the first argument ISN'T __dirname.
| // Note i + 1 here to include the current '..' in the path, since Array.slice excludes the end index. | ||
| const pjFile = path.join(...[path.dirname(currentFile), ...args.slice(0, i + 1), 'package.json']); |
There was a problem hiding this comment.
I think this is the correct implementation of your algo @rix0rrr
There was a problem hiding this comment.
Yeah, you are right. Good catch!
I suppose we could also do i in [1..firstDownDir) as opposed to [0..firstDownDir - 1), and that would have avoided this i + 1.
tools/@aws-cdk/eslint-plugin/test/rules/fixtures/no-invalid-path/variable-path.ts
Outdated
Show resolved
Hide resolved
rix0rrr
left a comment
There was a problem hiding this comment.
Conditionally approved! I'll leave you to decide what to do with the i + 1/i - 1 business
| // Note i + 1 here to include the current '..' in the path, since Array.slice excludes the end index. | ||
| const pjFile = path.join(...[path.dirname(currentFile), ...args.slice(0, i + 1), 'package.json']); |
There was a problem hiding this comment.
Yeah, you are right. Good catch!
I suppose we could also do i in [1..firstDownDir) as opposed to [0..firstDownDir - 1), and that would have avoided this i + 1.
|
@Mergifyio update |
✅ Branch has been successfully updated |
packages/@aws-cdk/app-staging-synthesizer-alpha/test/app-staging-synthesizer.test.ts
Outdated
Show resolved
Hide resolved
…ng-synthesizer.test.ts
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
This is a follow up to #28658, #28772, and #28760. We had to fix multiple places where that file path extended beyond the package itself into other areas of the local repository (that would not be available after packaging). This caused myriad issues at synth time with `file not found` errors. This PR introduces a linter rule with the following specifications: - no inefficient paths, i.e. no going backwards multiple times. Ex. `path.join(__dirname, '..', 'folder', '..', 'another-folder')`. This should and can be easily simplified - no paths that go backwards past a `package.json` file. This should catch the instances we faced next time. The `yarn lint` command on `aws-cdk-lib` took 51.47s seconds without this new rule and 53.32s seconds with the rule enabled. The difference of ~2 seconds shouldn't be a hindrance in this case but I am happy to look for additional efficiencies in the rule I've written. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
This is a follow up to #28658, #28772, and #28760. We had to fix multiple places where that file path extended beyond the package itself into other areas of the local repository (that would not be available after packaging). This caused myriad issues at synth time with `file not found` errors. This PR introduces a linter rule with the following specifications: - no inefficient paths, i.e. no going backwards multiple times. Ex. `path.join(__dirname, '..', 'folder', '..', 'another-folder')`. This should and can be easily simplified - no paths that go backwards past a `package.json` file. This should catch the instances we faced next time. The `yarn lint` command on `aws-cdk-lib` took 51.47s seconds without this new rule and 53.32s seconds with the rule enabled. The difference of ~2 seconds shouldn't be a hindrance in this case but I am happy to look for additional efficiencies in the rule I've written. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
This is a follow up to #28658, #28772, and #28760. We had to fix multiple places where that file path extended beyond the package itself into other areas of the local repository (that would not be available after packaging). This caused myriad issues at synth time with
file not founderrors.This PR introduces a linter rule with the following specifications:
path.join(__dirname, '..', 'folder', '..', 'another-folder'). This should and can be easily simplifiedpackage.jsonfile. This should catch the instances we faced next time.The
yarn lintcommand onaws-cdk-libtook 51.47s seconds without this new rule and 53.32s seconds with the rule enabled. The difference of ~2 seconds shouldn't be a hindrance in this case but I am happy to look for additional efficiencies in the rule I've written.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license