-
Notifications
You must be signed in to change notification settings - Fork 21
[PROD] - Security, clean up & bug fixes #1368
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
Conversation
fix(PM-3141): allow only admins and reviewer to respond to appeals
fix(PM-2662): hide other submitters submissions if challenge is configured to hide it
…orecard-ui Cleanup old code for the review scorecard ui
…to hide submissions
fix(PM-2662): Show only users submission in review tab if challenge is configured to hide submissions
| ) | ||
| }, [challengeInfo]) | ||
|
|
||
| const isSubmissionsViewable = useMemo(() => { |
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.
[❗❗ correctness]
The isSubmissionsViewable function uses challengeInfo.metadata.some(...) which could potentially throw an error if challengeInfo.metadata is not an array. Consider adding a check to ensure challengeInfo.metadata is an array before calling .some().
| const filteredSubmissions = useMemo<BackendSubmission[]>( | ||
| () => { | ||
|
|
||
| const filterFunc = (submissions: BackendSubmission[]): BackendSubmission[] => submissions |
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.
[💡 maintainability]
The filterFunc is defined inside the useMemo hook but is used twice within the same scope. Consider defining filterFunc outside of useMemo to avoid redefining it unnecessarily, which could improve readability and maintainability.
| addAppeal, | ||
| isSavingAppeal, | ||
| }: ScorecardViewerContextValue = useScorecardViewerContext() | ||
| const { isAdmin, hasReviewerRole }: UseRolePermissionsResult = useRolePermissions() |
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.
[❗❗ security]
The useRolePermissions hook is used to determine role-based permissions. Ensure that this hook is correctly implemented and returns accurate role information, as incorrect role data could lead to unauthorized access or actions.
| reviewItem={props.reviewItem} | ||
| scorecardQuestion={props.question} | ||
| canRespondToAppeal={isReviewerRole} | ||
| canRespondToAppeal={isAdmin || hasReviewerRole} |
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.
[❗❗ correctness]
The condition isAdmin || hasReviewerRole is used to determine if a user can respond to an appeal. Ensure that this logic aligns with the intended business rules, as incorrect permission checks could lead to unauthorized actions.
| type='text' | ||
| className={classNames(props.className, styles.container)} | ||
| > | ||
| {/* @ts-expect-error: TS2786: DatePicker cannot be used as a JSX component */} |
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.
[maintainability]
Using @ts-expect-error to suppress TypeScript errors can hide potential issues. Investigate why DatePicker cannot be used as a JSX component and address the root cause instead of suppressing the error.
| readonly forceFocusStyle?: boolean | ||
| } | ||
|
|
||
| // @ts-expect-error: TS2322: Type mismatch for ForwardRefExoticComponent |
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.
[maintainability]
Using @ts-expect-error to suppress TypeScript errors can hide potential issues. Consider addressing the underlying type mismatch instead of suppressing it.
| } | ||
|
|
||
| const PageTitle: FC<PageTitleProps> = (props: PageTitleProps) => ( | ||
| // @ts-expect-error: TS2786: Helmet cannot be used as a JSX component |
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.
[maintainability]
Using @ts-expect-error to suppress TypeScript errors should be avoided if possible, as it can hide potential issues. Consider investigating the cause of the error TS2786 and resolving it, or documenting why this suppression is necessary and safe.
| portalRef?: MutableRefObject<HTMLElement>, | ||
| } | ||
|
|
||
| // @ts-expect-error: TS2322: Type mismatch for FC return type |
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.
[maintainability]
Using // @ts-expect-error to suppress TypeScript errors can hide potential issues. Investigate the root cause of the type mismatch and address it instead of suppressing the error. This will improve type safety and maintainability.
more security fixes - high -> dev
drop ssl serts
fix(PM-3141): Respond to appeals
| error: fetchAppealsError, | ||
| }: SWRResponse<AppealInfo[], Error> = useSWR<AppealInfo[], Error>( | ||
| `EnvironmentConfig.API.V6/appeals/resourceId/${resourceId}`, | ||
| `${EnvironmentConfig.API.V6}/appeals/resourceId/${resourceId}`, |
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.
[security]
The URL string is constructed using template literals, which is correct. However, ensure that resourceId is always a valid and sanitized string to prevent potential injection attacks or malformed URLs.
| try { | ||
| if (reviewId) { | ||
| // re-fetch review data | ||
| mutate(`EnvironmentConfig.API.V6/reviews/${reviewId}`) |
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.
[security]
The mutate function is used to revalidate the SWR cache for the review data. Ensure that reviewId is always a valid and sanitized string to prevent potential issues with cache keys.
| : `/${match[1]}/${match[2]}` | ||
|
|
||
| return `${basePath}/reviews/${submissionId}?reviewId=${encodedReviewId}` | ||
| return `${basePath}/reviews/${submissionId}?reviewId=${encodedReviewId}&respondToAppeals=true` |
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.
[❗❗ correctness]
Adding the respondToAppeals=true query parameter changes the behavior of the route. Ensure that this change is intentional and that all parts of the application that rely on this route are updated accordingly to handle the new parameter.
| const ReviewViewer: FC = () => { | ||
| const navigate = useAppNavigate() | ||
| const [searchParams] = useSearchParams() | ||
| const [respondToAppeals, setRespondToAppeals] = useState(searchParams.get('respondToAppeals') === 'true') |
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.
[performance]
Using useState with searchParams.get('respondToAppeals') directly ties the initial state to the URL parameter. Consider using useMemo to derive the initial state from searchParams to avoid unnecessary re-renders if searchParams changes but respondToAppeals does not.
| setRespondToAppeals(false) | ||
| } | ||
| }, [canEditScorecard, isManagerEdit]) | ||
| }, [canEditScorecard, isManagerEdit, respondToAppeals]) |
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.
[❗❗ correctness]
The dependency array for this useEffect includes respondToAppeals, which is being set to false inside the effect. This could lead to an infinite loop if not handled carefully. Ensure that the state update logic is correct and doesn't cause unnecessary re-renders.
fix(PM-3141): edit mode for copilot users
|
|
||
| useEffect(() => { | ||
| if (!canEditScorecard && isManagerEdit) { | ||
| if (!canEditScorecard && isManagerEdit && !respondToAppeals) { |
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.
[correctness]
The condition !respondToAppeals was added to the if statement. Ensure that this change aligns with the intended logic, as it alters when setIsManagerEdit(false) is called. Verify that this does not introduce any unintended behavior, especially if respondToAppeals is expected to influence the manager edit state.
fix(PM-2662): Show only current users winning submission in winners tab if challenge is private
| .toLowerCase() === 'true') | ||
| }, [challengeInfo]) | ||
|
|
||
| const canViewSubmissions = useMemo(() => { |
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.
[💡 readability]
The canViewSubmissions logic might be clearer if the isCompletedDesignChallenge and isSubmissionsViewable checks were combined into a single condition. This could improve readability by reducing the number of nested conditions.
| return true | ||
| }, [isCompletedDesignChallenge, isSubmissionsViewable, canViewAllSubmissions]) | ||
|
|
||
| const filterFunc = useCallback((submissions: ProjectResult[]): ProjectResult[] => submissions |
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.
[performance]
The filterFunc function uses useCallback, but its dependencies include canViewSubmissions and loginUserInfo?.userId, which are derived from context and could change. Ensure these dependencies are stable or consider using useMemo if the function doesn't need to be recreated.
fix(PM-2573): show only submissions with passed screening score
| })) as SubmissionRow[] | ||
| const rows = aggregatedSubmissionRows | ||
| .filter(aggregated => { | ||
| const reviews = aggregated.reviews ?? [] |
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.
[performance]
The filter function is used to find submissions with a specific review detail. However, it might be more efficient to use some instead of find within the filter callback to avoid unnecessary iterations once a match is found.
| return !!myReviewDetail?.reviewId | ||
| }) | ||
| .map(aggregated => ({ | ||
| ...(aggregated.submission ?? {}), |
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.
[💡 maintainability]
The spread operator is used twice on aggregated.submission. This is redundant and could be simplified to a single spread operation.
jmgasper
left a comment
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.
Added a few comments for clarification - nothing major.
| .toLowerCase() : '' | ||
| const status = challengeInfo.status ? String(challengeInfo.status) | ||
| .toLowerCase() : '' | ||
| return type === 'design' && ( |
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.
Do we need to check the challenge type here as well? This will match F2Fs in addition to challenges.
| reviewItem={props.reviewItem} | ||
| scorecardQuestion={props.question} | ||
| canRespondToAppeal={isReviewerRole} | ||
| canRespondToAppeal={isAdmin || hasReviewerRole} |
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.
What is this change for? Are we now allowing admins to respond to appeals? I'm not sure that's something we've done in the past?
| } | ||
| }, [challengeInfo?.type?.abbreviation, challengeInfo?.type?.name]) | ||
|
|
||
| const isCompletedDesignChallenge = useMemo(() => { |
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.
Should we move this out so that we aren't duplicating it multiple places? We added the same exact functionality in src/apps/review/src/lib/components/ChallengeDetailsContent/TabContentSubmissions.tsx
Master -> dev
Related JIRA Ticket:
What's in this PR?