-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
[Security solutions] Adds linter rule to forbid usage of no-non-null-assertion (TypeScript ! bang operator) #114375
[Security solutions] Adds linter rule to forbid usage of no-non-null-assertion (TypeScript ! bang operator) #114375
Conversation
export const TIMELINE = (id: string | undefined) => { | ||
if (id == null) { | ||
throw new TypeError('id should never be null or undefined'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Zero risk as this is just test code, but using a throw within the tests is preferred over upstream turning off typescript assertions.
@@ -57,7 +57,7 @@ const LOGIN_API_ENDPOINT = '/internal/security/login'; | |||
*/ | |||
export const getUrlWithRoute = (role: ROLES, route: string) => { | |||
const url = Cypress.config().baseUrl; | |||
const kibana = new URL(url!); | |||
const kibana = new URL(String(url)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Zero risk as this is just test code, but using a String(value)
will return value
, using a String(null)
will return the string value of null
and String(undefined)
will return the string undefined
. All of which will fail the test.
@@ -83,7 +83,7 @@ interface User { | |||
*/ | |||
export const constructUrlWithUser = (user: User, route: string) => { | |||
const url = Cypress.config().baseUrl; | |||
const kibana = new URL(url!); | |||
const kibana = new URL(String(url)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Zero risk as this is just test code, but using a String(value)
will return value
, using a String(null)
will return the string value of null
and String(undefined)
will return the string undefined
. All of which will fail the test.
@@ -94,7 +94,7 @@ export const BarChartBaseComponent = ({ | |||
yAccessors={yAccessors} | |||
timeZone={timeZone} | |||
splitSeriesAccessors={splitSeriesAccessors} | |||
data={series.value!} | |||
data={series.value ?? []} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: 🐛 Low risk fix here as we now pass an empty array if the series.value
is undefined
@@ -127,7 +127,7 @@ export const getColumnsWithTimestamp = ({ | |||
export const getExampleText = (example: string | number | null | undefined): string => | |||
!isEmpty(example) ? `Example: ${example}` : ''; | |||
|
|||
export const getIconFromType = (type: string | null) => { | |||
export const getIconFromType = (type: string | null | undefined) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk type fix where I change this to allow an undefined
so I could remove anywhere we turn off type assertions. This function should operate the same as before.
@@ -236,7 +236,7 @@ const EventsViewerComponent: React.FC<Props> = ({ | |||
useTimelineEvents({ | |||
docValueFields, | |||
fields, | |||
filterQuery: combinedQueries!.filterQuery, | |||
filterQuery: combinedQueries?.filterQuery, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: 🐛 Fix low risk, high impact here because if you look below this you see the code at line 246 which says:
skip: !canQueryTimeline || combinedQueries?.filterQuery === undefined, // When the filterQuery comes back as undefined, it means an error has been thrown and the request should be skipped
If this can be undefined then I would assume we want to allow it to be undefined here. Either way, this code written as is will BLOW UP if combinedQueries
is undefined. So I figured it's best to use ?
operator here.
@@ -300,7 +300,7 @@ const EventsViewerComponent: React.FC<Props> = ({ | |||
height={headerFilterGroup ? COMPACT_HEADER_HEIGHT : EVENTS_VIEWER_HEADER_HEIGHT} | |||
subtitle={utilityBar ? undefined : subtitle} | |||
title={globalFullScreen ? titleWithExitFullScreen : justTitle} | |||
isInspectDisabled={combinedQueries!.filterQuery === undefined} | |||
isInspectDisabled={combinedQueries?.filterQuery === undefined} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: 🐛 Low risk fix here because the !
will cause a failure if combinedQueries
is undefined
. This will ensure we are getting back an undefined
for sure instead of blowing up.
...s/security_solution/public/common/components/user_privileges/use_endpoint_privileges.test.ts
Outdated
Show resolved
Hide resolved
has('lastSuccess.timestamp', node) && node.lastSuccess!.timestamp != null ? ( | ||
<FormattedRelativePreferenceDate value={node.lastSuccess!.timestamp} /> | ||
has('lastSuccess.timestamp', node) && node.lastSuccess?.timestamp != null ? ( | ||
<FormattedRelativePreferenceDate value={node.lastSuccess?.timestamp} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk 🐛 fix here as the has
before this should guarantee it's there but the ?
allows us to remove the non-assertion operator. In reality we can probably use more ?
operator and remove more has
in these places but I figured this would be good enough for us.
has('lastFailure.timestamp', node) && node.lastFailure!.timestamp != null ? ( | ||
<FormattedRelativePreferenceDate value={node.lastFailure!.timestamp} /> | ||
has('lastFailure.timestamp', node) && node.lastFailure?.timestamp != null ? ( | ||
<FormattedRelativePreferenceDate value={node.lastFailure?.timestamp} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk 🐛 fix here as the has
before this should guarantee it's there but the ?
allows us to remove the non-assertion operator. In reality we can probably use more ?
operator and remove more has
in these places but I figured this would be good enough for us.
x-pack/plugins/security_solution/public/management/pages/event_filters/store/selectors.test.ts
Outdated
Show resolved
Hide resolved
...ion/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx
Outdated
Show resolved
Hide resolved
...ion/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx
Outdated
Show resolved
Hide resolved
...blic/management/pages/host_isolation_exceptions/view/host_isolation_exceptions_list.test.tsx
Outdated
Show resolved
Hide resolved
@@ -76,12 +76,12 @@ export const DraggableZeekElement = React.memo<{ | |||
and: [], | |||
enabled: true, | |||
id: escapeDataProviderId(`draggable-zeek-element-draggable-wrapper-${id}-${field}-${value}`), | |||
name: value!, | |||
name: String(value), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Small risk 🐛 fix. I don't think we expect null/undefined
but using String(null)
or String(undefined)
will display null
or undefined
but it won't blow things up. Using String(value)
if value is a string will return a value.
excluded: false, | ||
kqlQuery: '', | ||
queryMatch: { | ||
field, | ||
value: value!, | ||
value: String(value), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Small risk 🐛 fix. I don't think we expect null/undefined
but using String(null)
or String(undefined
will display null
or undefined
but it won't blow things up. Using String(value)
if value is a string will return a value.
@@ -97,7 +97,7 @@ export const DraggableZeekElement = React.memo<{ | |||
) : ( | |||
<EuiToolTip data-test-subj="badge-tooltip" content={field}> | |||
<Badge iconType="tag" color="hollow" title=""> | |||
{stringRenderer(value!)} | |||
{stringRenderer(String(value))} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Small risk 🐛 fix. I don't think we expect null/undefined
but using String(null)
or String(undefined
will display null
or undefined
but it won't blow things up. Using String(value)
if value is a string will return a value.
<UsernameWithAvatar | ||
key={user.updatedBy === null ? undefined : user.updatedBy} | ||
username={String(user.updatedBy)} | ||
/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Medium 🐛 fix. I don't think we expect user.updatedBy
to be null
but it can be either null | undefined
according to its type. To be safe here I decided to check explicitly against null
and then set it to undefined
if it is null. Otherwise I fall back on using the regular value which is user.updatedBy
.
The other way I could have fixed this was String(user.updatedBy)
but since undefined
can be valid key
I decided to implement the fix this way.
@@ -271,13 +271,13 @@ export const EventsTrData = styled.div.attrs(({ className = '' }) => ({ | |||
const TIMELINE_EVENT_DETAILS_OFFSET = 40; | |||
|
|||
interface WidthProp { | |||
width?: number; | |||
width: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk type fix here as it seems to want it to be required and no where is it optionally being set to undefined
or null
so the typing and code is better to just use the expected type here.
@@ -74,7 +75,7 @@ export class EndpointArtifactClient implements EndpointArtifactClientInterface { | |||
|
|||
async deleteArtifact(id: string) { | |||
// Ignoring the `id` not being in the type until we can refactor the types in endpoint. | |||
// @ts-ignore | |||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: zero risk as the @ts-ignore
wasn't needed here and now we only turn off the no-non-null-assertion
x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts
Outdated
Show resolved
Hide resolved
@@ -237,7 +237,7 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({ | |||
endDate: end, | |||
entityType, | |||
fields, | |||
filterQuery: combinedQueries!.filterQuery, | |||
filterQuery: combinedQueries?.filterQuery, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk 🐛 fix here since combinedQueries
can be undefined
and this is similar to the other areas of the code base we fixed the combinedQueries
since it can be undefined
and we don't want to blow up here.
@@ -217,7 +217,7 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({ | |||
entityType, | |||
excludeEcsData: true, | |||
fields, | |||
filterQuery: combinedQueries!.filterQuery, | |||
filterQuery: combinedQueries?.filterQuery, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: Low risk 🐛 fix here since combinedQueries
can be undefined
and this is similar to the other areas of the code base we fixed the combinedQueries
since it can be undefined
and we don't want to blow up here.
@elasticmachine merge upstream |
Is it possible to disable the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a great linting improvement 🙌 Thank you @FrankHassanabad!
I'm not familiar with most of the code that has been changed in this PR, so I'm not sure if it's legitimate for me to approve the PR, but it all looks good at first glance. I see that most of the !
in production code is left with the corresponding eslint-disable comments, so the logic should stay the same.
Specific areas of code for timelines, endpoint integration, etc should probably be reviewed closely by the corresponding owners.
Left 2 minor comments.
x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_event_type_signal.ts
Outdated
Show resolved
Hide resolved
…d/kibana into avoid-non-null-assertions
Yep, totally possible. I did it by adding this chunk you should see in the PR now:
And moving the rule into there. Also I removed all the additional workaround code in the tests to make them mostly the same as they were before except for where I could remove |
Thanks Frank! |
@elasticmachine merge upstream |
// This should be a very small set as most linter rules are useful for tests as well. | ||
files: [ | ||
'x-pack/plugins/security_solution/**/*.{ts,tsx}', | ||
'x-pack/plugins/timelines/**/*.{ts,tsx}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cnasikas @semd @jamster10 maybe we should do a follow up PR to add cases here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @jonathan-buttner! Let's do it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened an issue to track it here: #115152
], | ||
excludedFiles: [ | ||
'x-pack/plugins/security_solution/**/*.{test,mock,test_helper}.{ts,tsx}', | ||
'x-pack/plugins/timelines/**/*.{test,mock,test_helper}.{ts,tsx}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@FrankHassanabad @MadameSheema should we exclude cypress .spec
files? I'm fine with leaving them as linted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine leaving them as is.
…d/kibana into avoid-non-null-assertions
💚 Build SucceededMetrics [docs]Async chunks
History
To update your PR or re-run it, just comment with: |
…assertion (TypeScript ! bang operator) (elastic#114375) ## Summary Fixes: elastic#114535 **What this linter rule does:** * Sets the [@typescript-eslint/no-non-null-assertion](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-non-null-assertion.md) linter rule to become an error if seen. If you try to use the `!` operator you get an error and nice helper message that tries to encourage better practices such as this one: <img width="1635" alt="Screen Shot 2021-10-07 at 11 26 14 AM" src="https://user-images.githubusercontent.com/1151048/136474207-f38d3461-0af9-4cdc-885b-632cb49d8a24.png"> **Why are we deciding to set this linter rule?** * Recommended from Kibana [styleguide](https://github.com/elastic/kibana/blob/master/STYLEGUIDE.mdx#avoid-non-null-assertions) for ~2 years now and still recommended. * A lot of TypeScript has evolved and has operators such as `?` which can replace the `!` in most cases. Other cases can use a throw explicitly or other ways to manage this. * Some types can change instead of using this operator and we should just change the types. * TypeScript flows have improved and when we upgrade the linter will cause errors where we can remove the `!` operator which is 👍 better than leaving them when they're not needed anymore. * Newer programmers and team members sometimes mistake it for the `?` when it is not the same thing. * We have had past bugs and bugs recently because of these. * It's easier to use the linter to find bugs than to rely on manual tests. **How did Frank fix all the 403 areas in which the linter goes off?** * Anywhere I could remove the `!` operator without side effects or type script errors I just removed the `!` operator. * Anywhere in test code where I could replace the code with a `?` or a `throw` I went through that route. * Within the code areas (non test code) where I saw what looks like a simple bug that I could fix using a `?? []` or `?` operator or `String(value)` or fixing a simple type I would choose that route first. These areas I marked in the code review with the words `NOTE:` for anyone to look at. * Within all other areas of the code and tests where anything looked more involved I just disabled the linter for that particular line. When in doubt I chose this route. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
💚 Backport successful
This backport PR will be merged automatically after passing CI. |
…assertion (TypeScript ! bang operator) (#114375) (#115126) ## Summary Fixes: #114535 **What this linter rule does:** * Sets the [@typescript-eslint/no-non-null-assertion](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-non-null-assertion.md) linter rule to become an error if seen. If you try to use the `!` operator you get an error and nice helper message that tries to encourage better practices such as this one: <img width="1635" alt="Screen Shot 2021-10-07 at 11 26 14 AM" src="https://user-images.githubusercontent.com/1151048/136474207-f38d3461-0af9-4cdc-885b-632cb49d8a24.png"> **Why are we deciding to set this linter rule?** * Recommended from Kibana [styleguide](https://github.com/elastic/kibana/blob/master/STYLEGUIDE.mdx#avoid-non-null-assertions) for ~2 years now and still recommended. * A lot of TypeScript has evolved and has operators such as `?` which can replace the `!` in most cases. Other cases can use a throw explicitly or other ways to manage this. * Some types can change instead of using this operator and we should just change the types. * TypeScript flows have improved and when we upgrade the linter will cause errors where we can remove the `!` operator which is 👍 better than leaving them when they're not needed anymore. * Newer programmers and team members sometimes mistake it for the `?` when it is not the same thing. * We have had past bugs and bugs recently because of these. * It's easier to use the linter to find bugs than to rely on manual tests. **How did Frank fix all the 403 areas in which the linter goes off?** * Anywhere I could remove the `!` operator without side effects or type script errors I just removed the `!` operator. * Anywhere in test code where I could replace the code with a `?` or a `throw` I went through that route. * Within the code areas (non test code) where I saw what looks like a simple bug that I could fix using a `?? []` or `?` operator or `String(value)` or fixing a simple type I would choose that route first. These areas I marked in the code review with the words `NOTE:` for anyone to look at. * Within all other areas of the code and tests where anything looked more involved I just disabled the linter for that particular line. When in doubt I chose this route. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios Co-authored-by: Frank Hassanabad <frank.hassanabad@elastic.co>
…assertion (TypeScript ! bang operator) (elastic#114375) ## Summary Fixes: elastic#114535 **What this linter rule does:** * Sets the [@typescript-eslint/no-non-null-assertion](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-non-null-assertion.md) linter rule to become an error if seen. If you try to use the `!` operator you get an error and nice helper message that tries to encourage better practices such as this one: <img width="1635" alt="Screen Shot 2021-10-07 at 11 26 14 AM" src="https://user-images.githubusercontent.com/1151048/136474207-f38d3461-0af9-4cdc-885b-632cb49d8a24.png"> **Why are we deciding to set this linter rule?** * Recommended from Kibana [styleguide](https://github.com/elastic/kibana/blob/master/STYLEGUIDE.mdx#avoid-non-null-assertions) for ~2 years now and still recommended. * A lot of TypeScript has evolved and has operators such as `?` which can replace the `!` in most cases. Other cases can use a throw explicitly or other ways to manage this. * Some types can change instead of using this operator and we should just change the types. * TypeScript flows have improved and when we upgrade the linter will cause errors where we can remove the `!` operator which is 👍 better than leaving them when they're not needed anymore. * Newer programmers and team members sometimes mistake it for the `?` when it is not the same thing. * We have had past bugs and bugs recently because of these. * It's easier to use the linter to find bugs than to rely on manual tests. **How did Frank fix all the 403 areas in which the linter goes off?** * Anywhere I could remove the `!` operator without side effects or type script errors I just removed the `!` operator. * Anywhere in test code where I could replace the code with a `?` or a `throw` I went through that route. * Within the code areas (non test code) where I saw what looks like a simple bug that I could fix using a `?? []` or `?` operator or `String(value)` or fixing a simple type I would choose that route first. These areas I marked in the code review with the words `NOTE:` for anyone to look at. * Within all other areas of the code and tests where anything looked more involved I just disabled the linter for that particular line. When in doubt I chose this route. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
Summary
Fixes: #114535
What this linter rule does:
If you try to use the
!
operator you get an error and nice helper message that tries to encourage better practices such as this one:Why are we deciding to set this linter rule?
?
which can replace the!
in most cases. Other cases can use a throw explicitly or other ways to manage this.!
operator which is 👍 better than leaving them when they're not needed anymore.?
when it is not the same thing.How did Frank fix all the 403 areas in which the linter goes off?
!
operator without side effects or type script errors I just removed the!
operator.?
or athrow
I went through that route.?? []
or?
operator orString(value)
or fixing a simple type I would choose that route first. These areas I marked in the code review with the wordsNOTE:
for anyone to look at.Checklist