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

Added new rule to detect assertions where statusCode is in the parameter #97

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

jpolavar
Copy link
Contributor

@jpolavar jpolavar commented Nov 25, 2024

Closes #96

Tested with internal services

@jpolavar jpolavar added the MINOR label Nov 25, 2024
@jpolavar jpolavar self-assigned this Nov 25, 2024
Copy link
Contributor

@le-cong le-cong left a comment

Choose a reason for hiding this comment

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

just a few things, also does it make sense to check number literal values such as 200/409/etc. because they are also frequently used in status code assertion? ideally they should be replaced by StatusCodes.OK/etc. from http-status-codes package.
maybe it should be a separated rules? i'm not sure ...


export const ruleId = 'no-status-code-assert';
const NO_STATUS_CODE_ASSERT = 'NO_STATUS_CODE_ASSERT';
const keywords = ['status', 'code', 'StatusCodes', 'statusCode'];
Copy link
Contributor

Choose a reason for hiding this comment

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

status/code are widely used in none response status code related assertions, e.g. things like account.status/message.code can be incorrectly labelled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@le-cong refactored to just check for StatusCodes for all assertions in parameters else if it is BinaryExpression check on either side.

*/
const hasStatusCodeOrValue = (arg: TSESTree.Node): boolean => {
const checkName = (name?: string): boolean =>
name !== undefined && keywords.some((keyword) => name.toLowerCase().includes(keyword));
Copy link
Contributor

Choose a reason for hiding this comment

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

the usage of name.toLowerCase() seems contradict with the keyword const values which contains upper case values.

@jpolavar jpolavar requested a review from le-cong December 20, 2024 05:27
Copy link
Contributor

@le-cong le-cong left a comment

Choose a reason for hiding this comment

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

just a few minor items

node.object.name === 'assert' &&
node.property.type === AST_NODE_TYPES.Identifier;

//Checks if a given AST node is an identifier with the name 'assert'.
Copy link
Contributor

Choose a reason for hiding this comment

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

remove?


const isAssertCallWithStatusCode = (callee: TSESTree.Node, args: TSESTree.Node[]): boolean =>
(isAssertIdentifier(callee) || isAssertMemberExpression(callee)) &&
args.some((arg) => hasStatusCodeOrValue(arg) && arg.type !== AST_NODE_TYPES.Identifier);
Copy link
Contributor

Choose a reason for hiding this comment

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

the arg.type check seems unnecessary given the fact that hasStatusCodeOrValue function is already testing some specific conditions in its switch statements.

switch (arg.type) {
case AST_NODE_TYPES.Literal:
if (typeof arg.value === 'number') {
return isStatusCodeLiteral(arg.value);
Copy link
Contributor

Choose a reason for hiding this comment

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

this branch doesn't have test coverage, either add test case or remove this logic and leave it for a separated rule to detect the direct usage of numeric value instead of http-status-codes for response status code?

Copy link
Contributor Author

@jpolavar jpolavar Dec 23, 2024

Choose a reason for hiding this comment

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

oh we are just focusing on statusCodes, we can remove this

@jpolavar jpolavar requested a review from le-cong December 23, 2024 19:09
## Fail

```js
assert(statusCode === 200);
Copy link
Contributor

Choose a reason for hiding this comment

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

update to reflect the latest implementation?

Copy link
Contributor Author

@jpolavar jpolavar Dec 24, 2024

Choose a reason for hiding this comment

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

@carlansley should we have rule to auto fix the prod code with statusCode if we have numbers?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I can answer that, can we add a little more description to the issue/PR about what this entire rule is needed for? I'm sure this was discussed at some point but tbh I don't recall what the original problem was.

Copy link
Contributor Author

@jpolavar jpolavar Dec 24, 2024

Choose a reason for hiding this comment

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

We need to monitor for assertion failures in production and also improve how assertions are used in production code. Currently, assertions are being used for status checks, which isn’t ideal. A good first step is to implement an ESLint rule that will detect when assertions are made using a statusCode as one of the parameters. This will help identify and clean up improper use of assertions in the code. notify service could look for assertion errors, but we need to clean up usage of assertions for status checks.

As we are checking for statusCode, should we have another rule to auto fix the prod code with statusCode if we have numbers some thing like
assert(statusCode === 200);
would be assert(statusCode === StatusCodes.OK);

Copy link
Contributor

Choose a reason for hiding this comment

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

is there a mistake in the documentation wrt what is "pass" and what is "fail"? That was what confused me initially.

Copy link
Contributor Author

@jpolavar jpolavar Dec 24, 2024

Choose a reason for hiding this comment

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

But initially it was like

Fail

assert(statusCode === 200);
assert.equal(statusCode, 200);

Pass

assert(response.status === 200);
assert.equal(response.status, 200);

Updated the rule to handle just statusCodes.

Fail

assert(statusCode === StatusCodes.OK);
assert.equal(statusCode, StatusCodes.OK);

Pass

assert(response.status === 200);
assert.equal(response.status, 200);

Pass wouldn't report as StatusCodes aren't used. This was the reason if we need to have another rule to auto fix all the numbers to statusCodes?

@jpolavar jpolavar requested a review from le-cong December 23, 2024 20:04
@carlansley carlansley requested a review from ramaghanta January 2, 2025 21:31
Comment on lines 13 to 14
assert(response.status === 200);
assert.equal(response.status, 200);

Choose a reason for hiding this comment

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

shouldn't these be failures as well? In a nutshell, we want to disallow the usage of assert to check for the desired response status, whether by using status or statusCode, in production code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

status/code are widely used in none response status code related assertions, e.g. things like account.status/message.code can be incorrectly labelled. Should we check .status, .code in the params of assert instead

Choose a reason for hiding this comment

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

not sure I understand, but all I'm saying is, just like how you're disallowing assert.ok(response.statusCode === StatusCodes.OK), we should also disallow assert.ok(response.status === StatusCodes.OK)

Copy link
Contributor Author

@jpolavar jpolavar Jan 6, 2025

Choose a reason for hiding this comment

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

assert.ok(response.status === StatusCodes.OK) is disallowed and would be reported as error but assert.equal(response.status, 200); is allowed since the rule check is going by StatusCodes. We can add that to disallow

Copy link
Contributor

Choose a reason for hiding this comment

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

created #109 to address the usage of magic number instead of StatusCodes.xxx

Choose a reason for hiding this comment

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

@le-cong, why do we need a separate rule? if 200/201/400/500 etc., are used, it will fail with a no-magic-numbers correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

good point, the only thing is that no-magic-number rule is turned off for test codes, thought we might want to be consistent with status code handling all across targeting a specific subset of numbers. thoughts?

Choose a reason for hiding this comment

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

no-magic-number is turned off for https://github.com/checkdigit/eslint-config/blob/main/index.mjs#L208. So, the only HTTP response status codes that will be allowed would be 256 and 512, which are uncommon and I can't think of any services that use these.

Copy link
Contributor

Choose a reason for hiding this comment

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

L208 is for default setting including production code, but it's overridden by the next section in https://github.com/checkdigit/eslint-config/blob/5eea1c576703f1ba1663bd6bb73542d19ccbce5d/index.mjs#L438, which disables this rule completely for test codes.

Choose a reason for hiding this comment

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

got it. the new GitHub issue you created makes sense to me then

@jpolavar jpolavar requested a review from ramaghanta January 6, 2025 23:13
Copy link

@ramaghanta ramaghanta left a comment

Choose a reason for hiding this comment

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

lftm

Copy link
Contributor

@carlansley carlansley left a comment

Choose a reason for hiding this comment

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

lftm, but main needs to be merged in

Copy link

github-actions bot commented Jan 8, 2025

❌ PR review status - not all reviewers have approved - 2 approved - 1 outstanding

@jpolavar jpolavar requested a review from carlansley January 8, 2025 21:55
Copy link

github-actions bot commented Jan 8, 2025

Coverage after merging no-status-assert-rule into main will be

85.05%▴ +0.40%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   file-path-comment.ts100%100%100%100%
   get-documentation-url.ts100%100%100%100%
   index.ts0%0%0%0%1, 1, 10, 100–109, 11, 110–119, 12, 120–129, 13, 130–139, 14, 140–145, 15–19, 2, 20–29, 3, 30–39, 4, 40–49, 5, 50–59, 6, 60–69, 7, 70–79, 8, 80–89, 9, 90–99
   invalid-json-stringify.ts100%100%100%100%
   no-card-numbers.ts95.11%89.29%100%96.03%134–139, 144–146
   no-duplicated-imports.ts100%100%100%100%
   no-enum.ts100%100%100%100%
   no-legacy-service-typing.ts100%100%100%100%
   no-promise-instance-method.ts100%100%100%100%
   no-random-v4-uuid.ts100%100%100%100%
   no-serve-runtime.ts100%100%100%100%
   no-side-effects.ts99.54%97.83%100%100%132
   no-status-code-assert.ts100%100%100%100%
   no-test-import.ts100%100%100%100%
   no-uuid.ts95.16%85.71%100%96.23%100–101, 89–91, 99
   no-wallaby-comment.ts97.50%85%100%100%43–44, 58
   object-literal-response.ts100%100%100%100%
   regular-expression-comment.ts95.51%89.47%100%97.06%35–37, 54
   require-assert-predicate-rejects-throws.ts100%100%100%100%
   require-fixed-services-import.ts100%100%100%100%
   require-resolve-full-response.ts83.69%78.33%100%84.72%105–107, 109–111, 113–115, 122–124, 127, 129, 129–131, 147–149, 199–210, 46, 65, 65–67, 81–83, 94–99
   require-strict-assert.ts98.40%92%100%100%44–45
   require-ts-extension-imports-exports.ts100%100%100%100%
   require-type-out-of-type-only-imports.ts100%100%100%100%
   tester.test.ts100%100%100%100%
   ts-tester.test.ts100%100%100%100%
src/library
   format.ts0%0%0%0%1, 1, 10–19, 2, 20, 3–9
   tree.ts0%0%0%0%1, 1, 10–19, 2, 20–29, 3, 30–39, 4, 40–49, 5, 50–59, 6, 60–69, 7, 70–79, 8, 80–89, 9, 90–97
   ts-tree.ts46.09%46.15%37.50%46.73%100–107, 27–29, 29–30, 33, 33–35, 35–37, 42–43, 46–47, 56–74, 77–96, 99
   variable.ts0%0%0%0%1, 1–5

Copy link

github-actions bot commented Jan 8, 2025

Beta Published - Install Command: npm install @checkdigit/[email protected]

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

Successfully merging this pull request may close these issues.

Add rule to detect assertions where statusCode is in the parameter
4 participants