Skip to content

Commit ffd9772

Browse files
committed
Merge branch 'development' of https://github.com/DMontgomery40/plugin-vulnerability-scanner into development
2 parents 3c7c2a2 + 81342ac commit ffd9772

File tree

5 files changed

+193
-21
lines changed

5 files changed

+193
-21
lines changed

.github/workflows/deploy.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,28 @@ on:
44
push:
55
branches:
66
- main
7+
- development
78

89
jobs:
9-
deploy:
10+
build-and-deploy:
1011
runs-on: ubuntu-latest
11-
permissions:
12-
contents: write
1312
steps:
14-
- uses: actions/checkout@v3
15-
16-
- name: Set up Node
13+
- name: Checkout
14+
uses: actions/checkout@v3
15+
16+
- name: Setup Node.js
1717
uses: actions/setup-node@v3
1818
with:
1919
node-version: '18'
20-
21-
- name: Install dependencies
20+
21+
- name: Install Dependencies
2222
run: npm install
23-
23+
2424
- name: Build
2525
run: npm run build
26-
26+
2727
- name: Deploy to GitHub Pages
28-
uses: peaceiris/actions-gh-pages@v3
28+
uses: JamesIves/github-pages-deploy-action@v4
2929
with:
30-
github_token: ${{ secrets.GITHUB_TOKEN }}
31-
publish_dir: ./dist
32-
force_orphan: true
30+
branch: gh-pages
31+
folder: dist # Vite builds to the dist folder by default
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
2+
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
3+
4+
on:
5+
# Runs on pushes targeting the default branch
6+
push:
7+
branches: ["development"]
8+
9+
# Allows you to run this workflow manually from the Actions tab
10+
workflow_dispatch:
11+
12+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13+
permissions:
14+
contents: read
15+
pages: write
16+
id-token: write
17+
18+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20+
concurrency:
21+
group: "pages"
22+
cancel-in-progress: false
23+
24+
jobs:
25+
# Build job
26+
build:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@v4
31+
- name: Setup Pages
32+
uses: actions/configure-pages@v5
33+
- name: Build with Jekyll
34+
uses: actions/jekyll-build-pages@v1
35+
with:
36+
source: ./
37+
destination: ./_site
38+
- name: Upload artifact
39+
uses: actions/upload-pages-artifact@v3
40+
41+
# Deployment job
42+
deploy:
43+
environment:
44+
name: github-pages
45+
url: ${{ steps.deployment.outputs.page_url }}
46+
runs-on: ubuntu-latest
47+
needs: build
48+
steps:
49+
- name: Deploy to GitHub Pages
50+
id: deployment
51+
uses: actions/deploy-pages@v4

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
</head>
88
<body>
99
<div id="root"></div>
10-
<script type="module" src="/src/main.jsx"></script>
10+
<script type="module" src="./main.jsx"></script>
1111
</body>
1212
</html>

src/lib/scanner.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import _ from 'lodash';
2+
<<<<<<< HEAD
23
import { VULNERABILITY_PATTERNS as patterns } from './patterns/index.js';
34
import { getScannerForFile, PACKAGE_FILE_PATTERNS } from './scanners/index.js';
45
import { repoCache } from './cache.js';
@@ -18,6 +19,11 @@ const recommendations = {
1819
dynamicRequire: 'Use static imports and proper dependency management',
1920
unsafeDeserialization: 'Validate and sanitize data before deserialization'
2021
};
22+
=======
23+
import { corePatterns, enhancedPatterns, recommendations } from './patterns';
24+
import { getScannerForFile, PACKAGE_FILE_PATTERNS } from './scanners';
25+
import { repoCache } from './cache';
26+
>>>>>>> 81342ac2800f95e58c70d0204d4e1fd9b4d976ed
2127

2228
class VulnerabilityScanner {
2329
constructor(config = {}) {
@@ -28,8 +34,16 @@ class VulnerabilityScanner {
2834
...config
2935
};
3036

37+
<<<<<<< HEAD
3138
// Use all patterns
3239
this.vulnerabilityPatterns = patterns;
40+
=======
41+
// Combine patterns based on configuration
42+
this.vulnerabilityPatterns = {
43+
...corePatterns,
44+
...(this.config.enableNewPatterns ? enhancedPatterns : {})
45+
};
46+
>>>>>>> 81342ac2800f95e58c70d0204d4e1fd9b4d976ed
3347

3448
// Track rate limit information
3549
this.rateLimitInfo = null;
@@ -42,6 +56,7 @@ class VulnerabilityScanner {
4256

4357
if (token) {
4458
headers.Authorization = `token ${token}`;
59+
<<<<<<< HEAD
4560
}
4661

4762
const response = await fetch(url, { headers });
@@ -140,8 +155,31 @@ class VulnerabilityScanner {
140155
} catch (error) {
141156
console.error(`Error fetching directory ${item.path}:`, error.message);
142157
}
158+
=======
159+
}
160+
161+
const response = await fetch(url, { headers });
162+
163+
// Extract rate limit information from headers
164+
this.rateLimitInfo = {
165+
limit: parseInt(response.headers.get('x-ratelimit-limit') || '60'),
166+
remaining: parseInt(response.headers.get('x-ratelimit-remaining') || '0'),
167+
reset: parseInt(response.headers.get('x-ratelimit-reset') || '0')
168+
};
169+
170+
if (!response.ok) {
171+
if (response.status === 403 && this.rateLimitInfo.remaining === 0) {
172+
const resetDate = new Date(this.rateLimitInfo.reset * 1000);
173+
throw new Error(`GitHub API rate limit exceeded. Resets at ${resetDate.toLocaleString()}`);
174+
}
175+
if (response.status === 404) {
176+
throw new Error('Repository or file not found. Check the URL and ensure you have access.');
177+
>>>>>>> 81342ac2800f95e58c70d0204d4e1fd9b4d976ed
143178
}
179+
throw new Error(`GitHub API error: ${response.statusText}`);
144180
}
181+
182+
return response;
145183
}
146184

147185
async scanFile(fileContent, filePath) {
@@ -202,6 +240,83 @@ class VulnerabilityScanner {
202240
}, []);
203241
}
204242

243+
async fetchRepositoryFiles(url, token = null) {
244+
const githubRegex = /github\.com\/([^/]+)\/([^/]+)(?:\/tree\/[^/]+)?\/?(.*)/;
245+
const match = url.match(githubRegex);
246+
if (!match) {
247+
throw new Error('Invalid GitHub URL format');
248+
}
249+
250+
// Check cache first
251+
const cachedData = repoCache.get(url, token);
252+
if (cachedData) {
253+
return {
254+
files: cachedData.files,
255+
rateLimit: this.rateLimitInfo,
256+
fromCache: true
257+
};
258+
}
259+
260+
const [, owner, repo, path] = match;
261+
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`;
262+
263+
try {
264+
const response = await this.fetchWithAuth(apiUrl, token);
265+
const data = await response.json();
266+
const files = [];
267+
268+
await this.fetchFiles(files, data, owner, repo, token);
269+
270+
// Cache the results
271+
repoCache.set(url, token, { files });
272+
273+
return {
274+
files,
275+
rateLimit: this.rateLimitInfo,
276+
fromCache: false
277+
};
278+
} catch (error) {
279+
throw new Error(error.message);
280+
}
281+
}
282+
283+
async fetchFiles(files, items, owner, repo, token) {
284+
for (const item of items) {
285+
// Check if we're running low on rate limit
286+
if (this.rateLimitInfo && this.rateLimitInfo.remaining < 5) {
287+
const resetDate = new Date(this.rateLimitInfo.reset * 1000);
288+
console.warn(`Warning: Rate limit running low. Resets at ${resetDate.toLocaleString()}`);
289+
}
290+
291+
const supportedExtensions = Object.keys(PACKAGE_FILE_PATTERNS)
292+
.concat(['.json', '.py', '.css', '.html', '.config', '.conf', '.sh', '.patch',
293+
'.yaml', '.yml', 'Dockerfile', '.ini', '.js', '.jsx', '.ts', '.tsx']);
294+
295+
if (item.type === 'file' &&
296+
(supportedExtensions.some(ext => item.name.toLowerCase().endsWith(ext.toLowerCase())) ||
297+
supportedExtensions.some(ext => item.name.toLowerCase() === ext.toLowerCase()))) {
298+
try {
299+
const response = await this.fetchWithAuth(item.download_url, token);
300+
const content = await response.text();
301+
files.push({
302+
path: item.path,
303+
content: content
304+
});
305+
} catch (error) {
306+
console.error(`Error fetching ${item.path}:`, error.message);
307+
}
308+
} else if (item.type === 'dir') {
309+
try {
310+
const response = await this.fetchWithAuth(item._links.self, token);
311+
const data = await response.json();
312+
await this.fetchFiles(files, data, owner, repo, token);
313+
} catch (error) {
314+
console.error(`Error fetching directory ${item.path}:`, error.message);
315+
}
316+
}
317+
}
318+
}
319+
205320
generateReport(findings) {
206321
// Separate findings by scanner type
207322
const generalFindings = findings.filter(f => f.scannerType === 'general');

vite.config.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { defineConfig } from 'vite';
2-
import react from '@vitejs/plugin-react';
3-
import path from 'path';
1+
import { defineConfig } from 'vite'
2+
import react from '@vitejs/plugin-react'
3+
import path from 'path'
44

5-
// https://vitejs.dev/config/
65
export default defineConfig({
76
plugins: [react()],
8-
base: '/plugin-vulnerability-scanner/', // This is correct for GitHub Pages
7+
base: '/plugin-vulnerability-scanner/',
98
resolve: {
109
alias: {
1110
'@': path.resolve(__dirname, './src')
@@ -17,5 +16,13 @@ export default defineConfig({
1716
sourcemap: true,
1817
minify: 'terser',
1918
emptyOutDir: true,
19+
rollupOptions: {
20+
input: {
21+
main: path.resolve(__dirname, 'index.html'),
22+
},
23+
output: {
24+
manualChunks: undefined
25+
}
26+
}
2027
}
21-
});
28+
})

0 commit comments

Comments
 (0)