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

feat: Add GitHub Scanning app #663

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6a19e84
feat: create intial github secret scanner
muntaxir4 Nov 30, 2024
1b63829
feat: add GitHubScanner class
muntaxir4 Dec 1, 2024
7d29ef1
fix(platform): Resolve loading SVG blocking input field interaction (…
Allan2000-Git Dec 2, 2024
9da0798
feat(schema, api-client): Migrate workspace-membership schemas and ty…
muntaxir4 Dec 3, 2024
e619c72
feat(schema): Add User type inference from UserSchema (#574)
muntaxir4 Dec 3, 2024
f73dd7e
feat(platform): Added screen for CREATE NEW PROJECT (#540)
poswalsameer Dec 3, 2024
8302051
chore(web): Update dockerfile
rajdip-b Dec 3, 2024
ef29602
chore(release): 2.8.0 [skip ci]
semantic-release-bot Dec 3, 2024
f855323
docs: Updated alignment of pictures in API Testing page
rajdip-b Dec 4, 2024
cb0ed7c
docs: Updated alignment of pictures in API Testing page
rajdip-b Dec 4, 2024
9517f67
chore(schema): Add describe blocks in tests for each kind of schema (…
muntaxir4 Dec 5, 2024
cdbf1bc
fix(api): Enable global project access (#580)
muntaxir4 Dec 7, 2024
f83b952
feat(api): Add email template for inviting user to workspace (#480)
Allan2000-Git Dec 7, 2024
2605004
feat(api): Add logout endpoint to clear token cookie (#581)
ShreyamKundu Dec 8, 2024
f8f0505
feat(api): Add email template for sending OTP to the user (#582)
Allan2000-Git Dec 8, 2024
8029c29
fix(platform): Type error in navbar
rajdip-b Dec 8, 2024
901cbbc
fix(api): Empty name `""` accepted as a valid name while creating env…
zaheer-Khan3260 Dec 9, 2024
84d259e
feat(api): Add endpoint to fetch all workspace invitations for a user…
muntaxir4 Dec 13, 2024
17aacc7
refactor(web): Changed the text in the hero section of the web applic…
poswalsameer Dec 13, 2024
0edd8cf
feat(platofrm): Added online/offline status detection in the platform…
Allan2000-Git Dec 14, 2024
2ece96a
feat(cli): Add functionality to operate on Workspace Membership (#589)
muntaxir4 Dec 16, 2024
87fb1b3
fix(schema): Add versions field to project secrets and variables resp…
muntaxir4 Dec 16, 2024
e694af6
chore(ci): Update web deployment to push to ACR
rajdip-b Dec 17, 2024
1678b63
chore(ci): Fixed environment name
rajdip-b Dec 17, 2024
3309c4c
chore(ci): Push docker images of platform and API to ACR
rajdip-b Dec 17, 2024
84a574f
fix(docker): Update build script
rajdip-b Dec 17, 2024
cb17777
chore(platoform): Swapped all legacy API calls with `@keyshade/api-cl…
poswalsameer Dec 17, 2024
0430dfc
chore: Update platform build command
rajdip-b Dec 17, 2024
c29c4c4
chore(ci): Add internal package dependencies to existing workflows (#…
muntaxir4 Dec 19, 2024
6743c9b
feat: create intial github secret scanner
muntaxir4 Nov 30, 2024
5c6a621
feat: add GitHubScanner class
muntaxir4 Dec 1, 2024
c6241f1
Implement spawn-able github scan api
muntaxir4 Jan 5, 2025
8eb7ad6
github-scanner: migrate to next.js backend and add http streaming re…
muntaxir4 Jan 23, 2025
5b5bc24
refactor: rename github-scan to github-scanner and update functions t…
muntaxir4 Jan 25, 2025
e743f64
Merge remote-tracking branch 'develop' into feat/github-scan
muntaxir4 Jan 25, 2025
66471f6
update pnpm-lock and fix lints
muntaxir4 Jan 25, 2025
92550b7
resolve merge conflicts
muntaxir4 Jan 25, 2025
24ba9a9
Merge branch 'develop' into feat/github-scan
muntaxir4 Jan 25, 2025
4a138e7
update pnpm-lock file
muntaxir4 Jan 25, 2025
6dae818
fix unanwanted files
muntaxir4 Jan 25, 2025
021ca06
Merge branch 'develop' into feat/github-scan
kriptonian1 Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/github-scanner/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CLONING_DIR=
24 changes: 24 additions & 0 deletions apps/github-scanner/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
extends: ['custom/next'],
rules: {
//temporary disable all error causing rules
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'no-console': 'off',
'object-shorthand': 'off',
'react/jsx-sort-props': 'off',
'@typescript-eslint/no-misused-promises': 'off',
'no-useless-return': 'off',
'react/jsx-no-leaked-render': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'prefer-named-capture-group': 'off',
'turbo/no-undeclared-env-vars': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'no-await-in-loop': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-confusing-void-expression': 'off'
}
}
36 changes: 36 additions & 0 deletions apps/github-scanner/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
3 changes: 3 additions & 0 deletions apps/github-scanner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# GitHub Scan

This is a simple tool to scan GitHub repositories for secrets.
4 changes: 4 additions & 0 deletions apps/github-scanner/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
29 changes: 29 additions & 0 deletions apps/github-scanner/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "github-scanner",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 5173",
"build": "next build",
"start": "next start -p 5173",
"lint": "next lint --fix"
},
"dependencies": {
"@keyshade/secret-scan": "workspace:*",
"glob": "^11.0.0",
"next": "14.2.18",
"react": "^18",
"react-dom": "^18",
"simple-git": "^3.27.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.18",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
}
8 changes: 8 additions & 0 deletions apps/github-scanner/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};

export default config;
39 changes: 39 additions & 0 deletions apps/github-scanner/src/app/api/scan/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { NextRequest, NextResponse } from 'next/server'
import { GitHubScanner } from '@/util/scan-repo'

export function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const githubUrl = searchParams.get('github_url')

if (!githubUrl) {
return NextResponse.json(
{ error: 'Invalid or missing github_url parameter' },
{ status: 400 }
)
}

const stream = new ReadableStream({
async start(controller) {
try {
await GitHubScanner.scanRepo(githubUrl, {
write: (chunk) => controller.enqueue(chunk),
close: () => controller.close()
})
} catch (error) {
if (error instanceof Error) {
console.error('Failed to scan repository:', error)
controller.enqueue(JSON.stringify({ error: error.message }))
} else {
controller.enqueue(JSON.stringify({ error: 'Internal Server Error' }))
}
controller.close()
}
}
})

return new Response(stream, {
headers: {
'Content-Type': 'application/json'
}
})
}
Binary file added apps/github-scanner/src/app/favicon.ico
Binary file not shown.
Binary file not shown.
Binary file added apps/github-scanner/src/app/fonts/GeistVF.woff
Binary file not shown.
27 changes: 27 additions & 0 deletions apps/github-scanner/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--background: #ffffff;
--foreground: #171717;
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}

body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}

@layer utilities {
.text-balance {
text-wrap: balance;
}
}
35 changes: 35 additions & 0 deletions apps/github-scanner/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Metadata } from 'next'
import localFont from 'next/font/local'
import './globals.css'

const geistSans = localFont({
src: './fonts/GeistVF.woff',
variable: '--font-geist-sans',
weight: '100 900'
})
const geistMono = localFont({
src: './fonts/GeistMonoVF.woff',
variable: '--font-geist-mono',
weight: '100 900'
})

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app'
}

export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
)
}
12 changes: 12 additions & 0 deletions apps/github-scanner/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import RepoInput from '@/components/repo-input'

export default function Home() {
return (
<div className="m-4 grid min-h-screen items-center">
<div className="grid justify-items-center gap-8">
<h1 className="text-2xl dark:text-green-400">GitHub Scan</h1>
<RepoInput />
</div>
</div>
)
}
109 changes: 109 additions & 0 deletions apps/github-scanner/src/components/repo-input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
'use client'
import React, { useState } from 'react'
import { ScanResponse, ScanResult } from '@/util/types'

function RepoInput() {
const [url, setUrl] = useState('')
const [responseData, setResponseData] = useState<ScanResponse | null>(null)
const [streamData, setStreamData] = useState<ScanResult[]>([])

const handleOnSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
setResponseData({ loading: true })
setStreamData([]) // Clear previous stream data

try {
const response = await fetch(`/api/scan?github_url=${url}`)

const reader = response.body?.getReader()
if (!reader) {
throw new Error('Failed to get reader from response body')
}

const decoder = new TextDecoder()
let done = false

while (!done) {
const { value, done: readerDone } = await reader.read()
done = readerDone
const chunks = decoder
.decode(value, { stream: true })
.split('<%keyshade-delim%>')
.filter((s) => s.length > 0)
const res: ScanResult[] = []
for (const chunk of chunks) {
const parsed = JSON.parse(chunk)
if (parsed.error) {
setStreamData([])
setResponseData({ error: parsed.error, loading: false })
return
}
res.push(parsed.secret)
}
setStreamData((prev) => [...prev, ...res])
}

setResponseData({ loading: false })
} catch {
setStreamData([])
setResponseData({ error: 'Internal Error', loading: false })
}
}

return (
<>
<form
className="grid grid-cols-1 gap-2 sm:w-3/5 sm:grid-cols-6"
action=""
onSubmit={handleOnSubmit}
>
<input
value={url}
onChange={(e) => setUrl(e.target.value)}
type="url"
name="github_url"
id="github_url"
className="h-12 w-full rounded-xl bg-slate-600 p-2 placeholder:text-center sm:col-span-5"
placeholder="Enter a GitHub repo URL"
/>
{responseData?.loading ? (
<button
type="button"
disabled
className="h-8 rounded-xl bg-yellow-400 text-white sm:h-full sm:text-sm"
>
Scanning..
</button>
) : (
<button
type="submit"
className="h-8 rounded-xl bg-green-400 text-white sm:h-full sm:text-sm"
>
Submit
</button>
)}
</form>
{responseData?.error && (
<p className="text-center text-red-500">{responseData.error}</p>
)}
{streamData.length > 0 && (
<div className="mt-4 grid gap-4">
{streamData.map((item, index) => {
return (
<div key={index} className="grid gap-1 overflow-auto text-sm">
<p className="flex flex-wrap justify-center text-center text-sky-500">
{item.file}:{item.line}
</p>
<p className="flex flex-wrap justify-center text-center">
{item.content}
</p>
</div>
)
})}
</div>
)}
</>
)
}

export default RepoInput
Loading