Repository navigation
ci: add llm reviewer #236
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
ci: add llm reviewer #236
Changes from all commits
15eb3de
218ecc8
6bd613d
9c7eca3
519ce50
77d5cd6
3549d1c
25cb137
c07a80b
50e9a3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| name: Code Review | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
|
||
| on: | ||
| pull_request: | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened] | ||
| pull_request_review_comment: | ||
| types: [created] | ||
|
|
||
| concurrency: | ||
| group: ${{ github.repository }}-${{ github.event.number || github.head_ref || | ||
| github.sha }}-${{ github.workflow }}-${{ github.event_name == | ||
| 'pull_request_review_comment' && 'pr_comment' || 'pr' }} | ||
| cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }} | ||
|
Comment on lines
+14
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The concurrency group name is quite complex and may lead to issues with workflow naming. Consider simplifying the group name to avoid potential conflicts. - concurrency:
- group: ${{ github.repository }}-${{ github.event.number || github.head_ref ||
- github.sha }}-${{ github.workflow }}-${{ github.event_name ==
- 'pull_request_review_comment' && 'pr_comment' || 'pr' }}
+ concurrency:
+ group: ${{ github.repository }}-${{ github.workflow }}-${{ github.event_name }} |
||
|
|
||
| jobs: | ||
| review: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: coderabbitai/ai-pr-reviewer@latest | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pinning to - - uses: coderabbitai/ai-pr-reviewer@latest
+ - uses: coderabbitai/ai-pr-reviewer@<commit-sha> |
||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| with: | ||
|
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a good practice to validate the secrets before using them. You can add a step to check if the secrets are set before running the + - name: Validate secrets
+ run: |
+ if [ -z "$GITHUB_TOKEN" ]; then
+ echo "GITHUB_TOKEN is not set"
+ exit 1
+ fi
+ if [ -z "$OPENAI_API_KEY" ]; then
+ echo "OPENAI_API_KEY is not set"
+ exit 1
+ fi
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Review all files There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is a thorough review of the Security: Performance: Logic: Error Handling: Maintainability: Best Practices: Here's an updated version of the workflow incorporating the suggested changes: name: Code Review
permissions:
contents: read
pull-requests: write
on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened]
pull_request_review_comment:
types: [created]
concurrency:
group: ${{ github.repository }}-${{ github.event.number || github.head_ref || github.sha }}-${{ github.workflow }}-${{ github.event_name == 'pull_request_review_comment' && 'pr_comment' || 'pr' }}
cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }}
jobs:
review:
runs-on: ubuntu-latest
steps:
- name: Validate secrets
run: |
if [ -z "$GITHUB_TOKEN" ]; then
echo "GITHUB_TOKEN is not set"
exit 1
fi
if [ -z "$OPENAI_API_KEY" ]; then
echo "OPENAI_API_KEY is not set"
exit 1
fi
- uses: coderabbitai/ai-pr-reviewer@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
with:
debug: true
review_simple_changes: false
review_comment_lgtm: false
openai_base_url: "https://openrouter.ai/api/v1"
openai_light_model: "openai/gpt-5-nano"
openai_heavy_model: "meta-llama/llama-3-70b-instruct"Let me know if you have any further questions or concerns! |
||
| debug: true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n .github/workflows/code-review.yml | head -40Repository: vitonsky/deepink Length of output: 1318 🌐 Web query:
💡 Result: The
Example: - uses: coderabbitai/ai-pr-reviewer@latest
with:
debug: 'true'Sources: [1] [2] [3] Disable Line 29 should default to 🤖 Prompt for AI Agents |
||
| review_simple_changes: false | ||
| review_comment_lgtm: false | ||
| openai_base_url: "https://openrouter.ai/api/v1" | ||
| openai_light_model: "openai/gpt-5-nano" | ||
| openai_heavy_model: "meta-llama/llama-3-70b-instruct" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,12 @@ | ||
| import React, { createContext, FC, useEffect, useMemo, useState } from 'react'; | ||
| import { isEqual } from 'lodash'; | ||
| import { Box } from '@chakra-ui/react'; | ||
| import { FileController } from '@core/features/files/FileController'; | ||
| import { StateFile } from '@core/features/files/StateFile'; | ||
| import { LexemesRegistry } from '@core/features/notes/controller/LexemesRegistry'; | ||
| import { WorkspacesController } from '@core/features/workspaces/WorkspacesController'; | ||
| import { StatusBarProvider } from '@features/MainScreen/StatusBar/StatusBarProvider'; | ||
| import { SplashScreen } from '@features/SplashScreen'; | ||
| import { GLOBAL_COMMANDS } from '@hooks/commands'; | ||
| import { useShortcutsBinding } from '@hooks/commands/shortcuts/useShortcutsBinding'; | ||
| import { useCommandCallback } from '@hooks/commands/useCommandCallback'; | ||
|
|
@@ -14,9 +16,8 @@ import { | |
| createWorkspaceObject, | ||
| defaultVaultConfig, | ||
| ProfileConfigScheme, | ||
| selectIsActiveWorkspaceReady, | ||
| selectWorkspacesInfo, | ||
| WorkspaceConfigScheme, | ||
| WorkspaceData, | ||
| workspacesApi, | ||
| } from '@state/redux/profiles/profiles'; | ||
| import { createContextGetterHook } from '@utils/react/createContextGetterHook'; | ||
|
|
@@ -77,20 +78,6 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls }) | |
| ]).then(async ([workspaces, config, state]) => { | ||
| const [defaultWorkspace] = workspaces; | ||
|
|
||
| const workspaceConfigs = await Promise.all( | ||
| workspaces.map(async (workspace) => { | ||
| const config = await new StateFile( | ||
| new FileController( | ||
| `workspaces/${workspace.id}/config.json`, | ||
| controls.profile.files, | ||
| ), | ||
| WorkspaceConfigScheme, | ||
| ).get(); | ||
|
|
||
| return [workspace.id, config] as const; | ||
| }), | ||
| ).then((entries) => Object.fromEntries(entries)); | ||
|
|
||
| if (!defaultWorkspace) return; | ||
|
|
||
| dispatch( | ||
|
|
@@ -99,19 +86,10 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls }) | |
| profile: { | ||
| activeWorkspace: null, | ||
| workspaces: Object.fromEntries( | ||
| workspaces.map((workspace) => { | ||
| const workspaceObject = createWorkspaceObject(workspace); | ||
| return [ | ||
| workspace.id, | ||
| { | ||
| ...workspaceObject, | ||
| config: { | ||
| ...workspaceObject.config, | ||
| ...workspaceConfigs[workspace.id], | ||
| }, | ||
| } satisfies WorkspaceData, | ||
| ]; | ||
| }), | ||
| workspaces.map((workspace) => [ | ||
| workspace.id, | ||
| createWorkspaceObject(workspace), | ||
| ]), | ||
| ), | ||
| config: { | ||
| ...defaultVaultConfig, | ||
|
|
@@ -158,28 +136,39 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls }) | |
| enabled: controls.profile.profile.isEncrypted, | ||
| }); | ||
|
|
||
| const isActiveWorkspaceReady = useAppSelector( | ||
| selectIsActiveWorkspaceReady({ profileId }), | ||
| ); | ||
|
Comment on lines
+139
to
+141
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Memoize the selector to prevent unnecessary re-renders.
🔧 Proposed fix- const isActiveWorkspaceReady = useAppSelector(
- selectIsActiveWorkspaceReady({ profileId }),
- );
+ const isActiveWorkspaceReady = useAppSelector(
+ useMemo(() => selectIsActiveWorkspaceReady({ profileId }), [profileId]),
+ );🤖 Prompt for AI Agents |
||
|
|
||
| return ( | ||
| <ProfileControlsContext.Provider value={controls}> | ||
| {!isActiveWorkspaceReady && <SplashScreen />} | ||
| {workspaces.length > 0 && <ProfileServices />} | ||
| {workspaces.map((workspace) => | ||
| workspace.touched ? ( | ||
| <WorkspaceContext.Provider | ||
| key={workspace.id} | ||
| value={{ profileId: profileId, workspaceId: workspace.id }} | ||
| > | ||
| <StatusBarProvider> | ||
| <Workspace profile={currentProfile} /> | ||
| <ProfileStatusBar /> | ||
| {isDevMode && ( | ||
| <ToggleSQLConsole | ||
| isVisible={isDBConsoleVisible} | ||
| onVisibilityChange={setIsDBConsoleVisible} | ||
| /> | ||
| )} | ||
| </StatusBarProvider> | ||
| </WorkspaceContext.Provider> | ||
| ) : null, | ||
| )} | ||
| <Box | ||
| width="100%" | ||
| height="100vh" | ||
| display={isActiveWorkspaceReady ? 'flex' : 'none'} | ||
| > | ||
| {workspaces.map((workspace) => | ||
| workspace.touched ? ( | ||
| <WorkspaceContext.Provider | ||
| key={workspace.id} | ||
| value={{ profileId: profileId, workspaceId: workspace.id }} | ||
| > | ||
| <StatusBarProvider> | ||
| <Workspace profile={currentProfile} /> | ||
| <ProfileStatusBar /> | ||
| {isDevMode && ( | ||
| <ToggleSQLConsole | ||
| isVisible={isDBConsoleVisible} | ||
| onVisibilityChange={setIsDBConsoleVisible} | ||
| /> | ||
| )} | ||
| </StatusBarProvider> | ||
| </WorkspaceContext.Provider> | ||
| ) : null, | ||
| )} | ||
| </Box> | ||
| {isDevMode && ( | ||
| <SQLConsole | ||
| isVisible={isDBConsoleVisible} | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,131 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| import React, { useMemo, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { FaUser } from 'react-icons/fa6'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { Button, Divider, HStack, Text } from '@chakra-ui/react'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { NestedList } from '@components/NestedList'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { TELEMETRY_EVENT_NAME } from '@core/features/telemetry'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { telemetry } from '@electron/requests/telemetry/renderer'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { getRandomItem } from '@utils/collections/getRandomItem'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| import { ProfileCreator } from './ProfileCreator'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { ProfileLoginForm } from './ProfileLoginForm'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { ProfilesForm } from './ProfilesForm'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { ProfilesListApi } from './useProfilesList'; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { OnPickProfile } from './useVaultOpener'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export type VaultScreenManagerProps = { | ||||||||||||||||||||||||||||||||||||||||||||||
| profiles: ProfilesListApi; | ||||||||||||||||||||||||||||||||||||||||||||||
| currentProfile: string | null; | ||||||||||||||||||||||||||||||||||||||||||||||
| onChooseProfile: (id: string | null) => void; | ||||||||||||||||||||||||||||||||||||||||||||||
| onOpenProfile: OnPickProfile; | ||||||||||||||||||||||||||||||||||||||||||||||
| onLoginStart?: () => void; | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export const defaultVaultNames = [ | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Creative drafts', | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Second brain', | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Digital garden', | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Creative space', | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Mind space', | ||||||||||||||||||||||||||||||||||||||||||||||
| 'Idea lab', | ||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export const VaultScreenManager = ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| currentProfile, | ||||||||||||||||||||||||||||||||||||||||||||||
| profiles, | ||||||||||||||||||||||||||||||||||||||||||||||
| onOpenProfile, | ||||||||||||||||||||||||||||||||||||||||||||||
| onChooseProfile, | ||||||||||||||||||||||||||||||||||||||||||||||
| onLoginStart, | ||||||||||||||||||||||||||||||||||||||||||||||
| }: VaultScreenManagerProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const currentVaultObject = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||
| () => profiles.profiles?.find((profile) => profile.id === currentProfile) ?? null, | ||||||||||||||||||||||||||||||||||||||||||||||
| [currentProfile, profiles.profiles], | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const [screen, setScreen] = useState<'create' | 'choose'>('choose'); | ||||||||||||||||||||||||||||||||||||||||||||||
| const hasNoVaults = profiles.profiles.length === 0; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (currentVaultObject) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <ProfileLoginForm | ||||||||||||||||||||||||||||||||||||||||||||||
| profile={currentVaultObject} | ||||||||||||||||||||||||||||||||||||||||||||||
| onLogin={async (...arg) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (onLoginStart) onLoginStart(); | ||||||||||||||||||||||||||||||||||||||||||||||
| return await onOpenProfile(...arg); | ||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||
| onPickAnotherProfile={() => onChooseProfile(null)} | ||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (screen === 'create' || hasNoVaults) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <ProfileCreator | ||||||||||||||||||||||||||||||||||||||||||||||
| onCreateProfile={(profile) => | ||||||||||||||||||||||||||||||||||||||||||||||
| profiles.createProfile(profile).then((newProfile) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| onOpenProfile(newProfile, profile.password ?? undefined).then( | ||||||||||||||||||||||||||||||||||||||||||||||
| console.warn, | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+63
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle vault-open result after profile creation instead of warning blindly. Current flow ignores Proposed fix <ProfileCreator
- onCreateProfile={(profile) =>
- profiles.createProfile(profile).then((newProfile) => {
- onOpenProfile(newProfile, profile.password ?? undefined).then(
- console.warn,
- );
- })
- }
+ onCreateProfile={async (profile) => {
+ try {
+ const newProfile = await profiles.createProfile(profile);
+ const result = await onOpenProfile(
+ newProfile,
+ profile.password ?? undefined,
+ );
+
+ if (result.status === 'error') {
+ return result.message ?? 'Cannot open the created profile';
+ }
+ } catch (error) {
+ console.error(error);
+ return 'Cannot create profile';
+ }
+ }}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| onCancel={hasNoVaults ? undefined : () => setScreen('choose')} | ||||||||||||||||||||||||||||||||||||||||||||||
| defaultProfileName={ | ||||||||||||||||||||||||||||||||||||||||||||||
| hasNoVaults ? getRandomItem(defaultVaultNames) : undefined | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <ProfilesForm | ||||||||||||||||||||||||||||||||||||||||||||||
| title="Choose the profile" | ||||||||||||||||||||||||||||||||||||||||||||||
| controls={ | ||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||
| variant="accent" | ||||||||||||||||||||||||||||||||||||||||||||||
| size="lg" | ||||||||||||||||||||||||||||||||||||||||||||||
| w="100%" | ||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setScreen('create')} | ||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||
| Create new profile | ||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||
| <NestedList | ||||||||||||||||||||||||||||||||||||||||||||||
| divider={<Divider margin="0px !important" />} | ||||||||||||||||||||||||||||||||||||||||||||||
| sx={{ | ||||||||||||||||||||||||||||||||||||||||||||||
| w: '100%', | ||||||||||||||||||||||||||||||||||||||||||||||
| borderRadius: '4px', | ||||||||||||||||||||||||||||||||||||||||||||||
| maxHeight: '230px', | ||||||||||||||||||||||||||||||||||||||||||||||
| overflow: 'auto', | ||||||||||||||||||||||||||||||||||||||||||||||
| border: '1px solid', | ||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||
| items={profiles.profiles.map((profile) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||
| id: profile.id, | ||||||||||||||||||||||||||||||||||||||||||||||
| content: ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <HStack | ||||||||||||||||||||||||||||||||||||||||||||||
| as="button" | ||||||||||||||||||||||||||||||||||||||||||||||
| key={profile.id} | ||||||||||||||||||||||||||||||||||||||||||||||
| sx={{ | ||||||||||||||||||||||||||||||||||||||||||||||
| padding: '.8rem 1rem', | ||||||||||||||||||||||||||||||||||||||||||||||
| w: '100%', | ||||||||||||||||||||||||||||||||||||||||||||||
| cursor: 'pointer', | ||||||||||||||||||||||||||||||||||||||||||||||
| gap: '.8rem', | ||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| onChooseProfile(profile.id); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (profile.encryption === null) { | ||||||||||||||||||||||||||||||||||||||||||||||
| onOpenProfile(profile); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED); | ||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+113
to
+121
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle errors when opening unencrypted profiles. For unencrypted profiles, Proposed fix onClick={() => {
onChooseProfile(profile.id);
if (profile.encryption === null) {
- onOpenProfile(profile);
+ onOpenProfile(profile).catch((error) => {
+ console.error('Failed to open profile', error);
+ });
}
telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED);
}}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||
| <FaUser /> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Text>{profile.name}</Text> | ||||||||||||||||||||||||||||||||||||||||||||||
| </HStack> | ||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||
| }))} | ||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||
| </ProfilesForm> | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
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.
The workflow has both
pull_request(line 8, no type filter) andpull_request_target(line 9, with type filters) triggers. This is problematic:pull_requestwill trigger on all PR events (opened, synchronize, reopened, etc.) without restrictionpull_request_targetruns in the context of the base repository with access to secrets — using it alongsidepull_requestfor the same job is redundant and potentially dangerous, aspull_request_targetcan expose secrets to code from forked PRsIf this repo doesn't need to handle forks, use only
pull_request. If fork support is needed, use onlypull_request_target(with caution).