mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 07:09:07 +03:00
Add warn for service role keys
This commit is contained in:
1 parent
1a4e0243be
commit
e7facf9b8d
6 files changed
+143
-3
No files matched your search
@@ -22,7 +22,15 @@ import { withAuth } from 'hooks/misc/withAuth'
|
||||
import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import { cn, ResizableHandle, ResizablePanel, ResizablePanelGroup, Sheet, SheetContent } from 'ui'
|
||||
import {
|
||||
Alert_Shadcn_,
|
||||
cn,
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
Sheet,
|
||||
SheetContent,
|
||||
} from 'ui'
|
||||
import AppLayout from '../AppLayout/AppLayout'
|
||||
import EnableBranchingModal from '../AppLayout/EnableBranchingButton/EnableBranchingModal'
|
||||
import BuildingState from './BuildingState'
|
||||
@@ -43,6 +51,7 @@ import RestoreFailedState from './RestoreFailedState'
|
||||
import RestoringState from './RestoringState'
|
||||
import { UpgradingState } from './UpgradingState'
|
||||
import MobileSheetNav from 'ui-patterns/MobileSheetNav/MobileSheetNav'
|
||||
import { useServiceRoleKeyLeakQuery } from 'data/lint/service-role-key-leak-query'
|
||||
|
||||
// [Joshen] This is temporary while we unblock users from managing their project
|
||||
// if their project is not responding well for any reason. Eventually needs a bit of an overhaul
|
||||
@@ -121,6 +130,9 @@ const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<ProjectLayout
|
||||
|
||||
const [isClient, setIsClient] = useState(false)
|
||||
|
||||
const { data: serviceRoleKeyLeakData } = useServiceRoleKeyLeakQuery({ projectRef: projectRef })
|
||||
|
||||
console.log('serviceRoleKeyLeakData', serviceRoleKeyLeakData)
|
||||
useEffect(() => {
|
||||
setIsClient(true)
|
||||
}, [])
|
||||
@@ -224,6 +236,9 @@ const ProjectLayout = forwardRef<HTMLDivElement, PropsWithChildren<ProjectLayout
|
||||
</div>
|
||||
) : (
|
||||
<ContentWrapper isLoading={isLoading} isBlocking={isBlocking}>
|
||||
<Alert_Shadcn_ variant="destructive">
|
||||
Your `service_role` key has been leaked...warning / docs / etc
|
||||
</Alert_Shadcn_>
|
||||
<ResourceExhaustionWarningBanner />
|
||||
{children}
|
||||
</ContentWrapper>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export const lintKeys = {
|
||||
lint: (projectRef: string | undefined) => ['projects', projectRef, 'lint'] as const,
|
||||
serviceRoleKeyLeak: (projectRef: string | undefined) =>
|
||||
['projects', projectRef, 'service-role-key-leak'] as const,
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { UseQueryOptions, useQuery } from '@tanstack/react-query'
|
||||
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { BASE_PATH, PROJECT_STATUS } from 'lib/constants'
|
||||
import { ResponseError } from 'types'
|
||||
import { lintKeys } from './keys'
|
||||
|
||||
export type ServiceRoleKeyLeakVariables = {
|
||||
projectRef?: string
|
||||
}
|
||||
|
||||
// TODO: type this
|
||||
export type ServiceRoleKeyLeakResponse = any[]
|
||||
|
||||
export async function checkServiceRoleKeyLeak(
|
||||
{ projectRef }: ServiceRoleKeyLeakVariables,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
if (!projectRef) throw new Error('Project ref is required')
|
||||
|
||||
const res = await fetch(`${BASE_PATH}/api/check-service-role-key-leak`, {
|
||||
headers: {
|
||||
'x-project': projectRef,
|
||||
},
|
||||
signal,
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const error = await res.json()
|
||||
throw new Error(error.error?.message || 'Failed to fetch service role key leak data')
|
||||
}
|
||||
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export type ServiceRoleKeyLeakData = Awaited<ReturnType<typeof checkServiceRoleKeyLeak>>
|
||||
export type ServiceRoleKeyLeakError = ResponseError
|
||||
|
||||
export const useServiceRoleKeyLeakQuery = <TData = ServiceRoleKeyLeakData>(
|
||||
{ projectRef }: ServiceRoleKeyLeakVariables,
|
||||
{
|
||||
enabled = true,
|
||||
...options
|
||||
}: UseQueryOptions<ServiceRoleKeyLeakData, ServiceRoleKeyLeakError, TData> = {}
|
||||
) => {
|
||||
const project = useSelectedProject()
|
||||
const isActive = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
|
||||
|
||||
return useQuery<ServiceRoleKeyLeakData, ServiceRoleKeyLeakError, TData>(
|
||||
lintKeys.serviceRoleKeyLeak(projectRef),
|
||||
({ signal }) => checkServiceRoleKeyLeak({ projectRef }, signal),
|
||||
{
|
||||
enabled: enabled && typeof projectRef !== 'undefined' && isActive,
|
||||
...options,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -9,8 +9,18 @@ import { usageKeys } from './keys'
|
||||
export async function getResourceWarnings(signal?: AbortSignal) {
|
||||
const { data, error } = await get(`/platform/projects-resource-warnings`, { signal })
|
||||
if (error) handleError(error)
|
||||
|
||||
return data
|
||||
// for testing purposes, return a hardcoded array of resource warnings
|
||||
return [
|
||||
{
|
||||
project: 'aclodpjssdgdxbvmybdv', //replace with your ref to get an example warning
|
||||
is_readonly_mode_enabled: false,
|
||||
disk_io_exhaustion: null,
|
||||
disk_space_exhaustion: null,
|
||||
cpu_exhaustion: 'critical',
|
||||
memory_and_swap_exhaustion: null,
|
||||
},
|
||||
] as ResourceWarning[]
|
||||
//return data
|
||||
}
|
||||
|
||||
export type ResourceWarning = components['schemas']['ProjectResourceWarningsResponse']
|
||||
|
||||
@@ -16,6 +16,8 @@ const HOSTED_SUPPORTED_API_URLS = [
|
||||
'/ai/sql/cron',
|
||||
'/ai/docs',
|
||||
'/get-ip-address',
|
||||
'/get-ip-address',
|
||||
'/check-service-role-key-leak',
|
||||
]
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGet(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['GET'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
async function handleGet(req: NextApiRequest, res: NextApiResponse) {
|
||||
const projectRef = req.headers['x-project'] as string
|
||||
const project = 'bzembqluzmwrjuidwley'
|
||||
console.log('the ref', projectRef)
|
||||
|
||||
if (!project) {
|
||||
return res.status(400).json({ error: 'Project reference is required' })
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.logflare.app/api/endpoints/query/exposed%20service_role%20advisor%20hack?project=${project}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'X-API-KEY': process.env.LOGFLARE_API_KEY!,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Logflare API responded with status ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return res.json(data)
|
||||
} catch (error) {
|
||||
console.error('Error fetching service role key leak data:', error)
|
||||
return res.status(500).json({
|
||||
error:
|
||||
'There was an unknown error fetching the service role key leak data. Please try again.',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
export default wrapper
|
||||
Reference in new issue
Block a user