From 4600b0ddf3d8f4bf964d02dc953e9e7db60576ed Mon Sep 17 00:00:00 2001 From: Philipp Schoenbach Date: Fri, 30 Jan 2026 00:51:11 +0100 Subject: [PATCH] clean branch for PR --- src/components/package-inspector/Hero.tsx | 26 +++++ .../PackageInspectorPage.tsx | 57 ++++++++++ .../package-inspector/SearchResultCard.tsx | 43 ++++++++ .../package-inspector/mock-data.json | 102 ++++++++++++++++++ src/components/ui/Searchbar.tsx | 50 +++++++++ src/pages/_meta.ts | 40 ++----- src/pages/package-inspector.mdx | 7 ++ src/pages/package-inspector/[...purl].tsx | 1 + src/pages/package-inspector/_meta.ts | 1 + 9 files changed, 295 insertions(+), 32 deletions(-) create mode 100644 src/components/package-inspector/Hero.tsx create mode 100644 src/components/package-inspector/PackageInspectorPage.tsx create mode 100644 src/components/package-inspector/SearchResultCard.tsx create mode 100644 src/components/package-inspector/mock-data.json create mode 100644 src/components/ui/Searchbar.tsx create mode 100644 src/pages/package-inspector.mdx create mode 100644 src/pages/package-inspector/[...purl].tsx create mode 100644 src/pages/package-inspector/_meta.ts diff --git a/src/components/package-inspector/Hero.tsx b/src/components/package-inspector/Hero.tsx new file mode 100644 index 0000000..8ab4824 --- /dev/null +++ b/src/components/package-inspector/Hero.tsx @@ -0,0 +1,26 @@ +import { Container } from '@/components/top-level-pages/container' +import { Shield } from 'lucide-react' + +export function PackageInspectorHero() { + return ( +
+
+ +
+
+ + Powered by DevGuard +
+

+ Package Inspector +

+

+ Analyze the security state of open-source packages. Get + insights on maintenance, vulnerabilities, and supply + chain risks. +

+
+
+
+ ) +} diff --git a/src/components/package-inspector/PackageInspectorPage.tsx b/src/components/package-inspector/PackageInspectorPage.tsx new file mode 100644 index 0000000..7fdcedc --- /dev/null +++ b/src/components/package-inspector/PackageInspectorPage.tsx @@ -0,0 +1,57 @@ +import { useState } from 'react' +import { Searchbar } from '@/components/ui/Searchbar' +import { SearchResultCard } from './SearchResultCard' +import { PackageInspectorHero } from './Hero' +import mockData from './mock-data.json' + +export function PackageInspectorPage() { + const [searchQuery, setSearchQuery] = useState('') + + const [isLoading, setIsLoading] = useState(false) + + const [results, setResults] = useState([]) + + const [hasSearched, setHasSearched] = useState(false) + + const handleSearch = async () => { + if (!searchQuery.trim()) return + + setIsLoading(true) + setHasSearched(true) + + // TODO: replace with real API call when backend is ready + // simulate delay to test search button working and return mock data + await new Promise((resolve) => setTimeout(resolve, 1000)) + setResults([mockData]) + setIsLoading(false) + } + + return ( + <> + +
+ + + {hasSearched && ( +
+ {results.map((result) => ( + + ))} +
+ )} +
+ + ) +} diff --git a/src/components/package-inspector/SearchResultCard.tsx b/src/components/package-inspector/SearchResultCard.tsx new file mode 100644 index 0000000..4a0e9e2 --- /dev/null +++ b/src/components/package-inspector/SearchResultCard.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import Link from 'next/link' +import { Package } from 'lucide-react' + +interface SearchResultCardProps { + name: string + description?: string + version: string + purl: string +} + +export function SearchResultCard({ + name, + description, + version, + purl, +}: SearchResultCardProps) { + const encodedPurl = encodeURIComponent(purl) + + return ( + +
+ +
+
+
+ + {name} + + v{version} +
+ {description && ( +

+ {description} +

+ )} +
+ + ) +} diff --git a/src/components/package-inspector/mock-data.json b/src/components/package-inspector/mock-data.json new file mode 100644 index 0000000..3cf483c --- /dev/null +++ b/src/components/package-inspector/mock-data.json @@ -0,0 +1,102 @@ +{ + "purl": "pkg:npm/event-stream@3.3.6", + "ecosystem": "npm", + "name": "event-stream", + "version": "3.3.6", + + "project": { + "projectKey": "github.com/dominictarr/event-stream", + "starsCount": 1400, + "forksCount": 220, + "openIssuesCount": 12, + "homepage": "https://github.com/dominictarr/event-stream", + "license": "MIT", + "description": "Toolkit to make creating and working with streams easy", + + "scoreCard": { + "checks": [ + { + "name": "Maintained", + "score": 2, + "reason": "No commit activity in the last 12 months" + }, + { + "name": "Code-Review", + "score": 3, + "reason": "Most commits are directly pushed to main without review" + }, + { + "name": "Signed-Releases", + "score": 0, + "reason": "No signed tags or releases detected" + }, + { + "name": "Signed-Commits", + "score": 1, + "reason": "Only a small subset of commits are signed" + }, + { + "name": "Branch-Protection", + "score": 0, + "reason": "Main branch allows force-pushes and direct commits" + }, + { + "name": "CI-Tests", + "score": 4, + "reason": "Basic CI exists but coverage is minimal" + }, + { + "name": "Fuzzing", + "score": 0, + "reason": "No fuzzing configuration detected" + }, + { + "name": "Dependency-Update-Tool", + "score": 2, + "reason": "Dependabot is configured but updates are often ignored" + }, + { + "name": "Security-Policy", + "score": 0, + "reason": "SECURITY.md not found" + }, + { + "name": "Vulnerabilities", + "score": 3, + "reason": "Known historical vulnerabilities with no documented remediation" + }, + { + "name": "Packaging", + "score": 1, + "reason": "Package includes postinstall scripts without sandboxing" + }, + { + "name": "Binary-Artifacts", + "score": 0, + "reason": "Prebuilt binaries committed to the repository" + } + ], + "metadata": { + "tool": "openssf-scorecard", + "toolVersion": "5.0.0", + "generatedAt": "2024-09-30T11:22:00Z" + } + }, + + "scoreCardScore": 2.8, + "updatedAt": "2024-11-01T14:00:00Z" + }, + + "maliciousPackage": { + "id": "MAL-2024-000123", + "summary": "Malicious package targeting CI environments", + "details": "The package executes a post-install script that exfiltrates environment variables and SSH keys.", + "published": "2024-10-12T08:15:30Z", + "modified": "2024-11-01T14:42:10Z", + "affectedComponent": { + "id": "mac-001", + "versionRange": "<=3.3.6", + "firstObserved": "2024-10-10T09:00:00Z" + } + } +} \ No newline at end of file diff --git a/src/components/ui/Searchbar.tsx b/src/components/ui/Searchbar.tsx new file mode 100644 index 0000000..12db516 --- /dev/null +++ b/src/components/ui/Searchbar.tsx @@ -0,0 +1,50 @@ +import { Button } from './button' +import { Search } from 'lucide-react' + +interface SearchbarProps { + value: string + onChange: (value: string) => void + onSubmit: () => void + isLoading?: boolean + placeholder?: string + // TODO: make button name customizable +} + +export function Searchbar({ + value, + onChange, + onSubmit, + isLoading = false, + placeholder, +}: SearchbarProps) { + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault() + onSubmit() + } + + return ( +
+
+
+
+ + onChange(e.target.value)} + className="w-full rounded-xl border border-gray-300 bg-white py-4 pl-12 pr-32 text-gray-900 placeholder-gray-500 focus:border-primary focus:outline-none focus:ring-primary dark:border-gray-800 dark:bg-gray-950 dark:text-white dark:focus:border-primary" + placeholder={placeholder} + /> + +
+
+
+
+ ) +} diff --git a/src/pages/_meta.ts b/src/pages/_meta.ts index ce5c0af..652b3c9 100644 --- a/src/pages/_meta.ts +++ b/src/pages/_meta.ts @@ -1,22 +1,9 @@ export default { - index: { - theme: { - layout: 'raw', - }, - display: 'hidden', - }, - pricing: { - theme: { - layout: 'raw', - }, - display: 'hidden', - }, - 'terms-of-use': { - display: 'hidden', - }, - 'privacy-policy': { - display: 'hidden', - }, + index: { theme: { layout: 'raw' }, display: 'hidden' }, + pricing: { theme: { layout: 'raw' }, display: 'hidden' }, + 'package-inspector': { theme: { layout: 'raw' }, display: 'hidden' }, + 'terms-of-use': { display: 'hidden' }, + 'privacy-policy': { display: 'hidden' }, introduction: { title: 'Introduction' }, 'getting-started': { title: 'Getting Started' }, 'how-to-guides': { title: 'How-to Guides' }, @@ -24,23 +11,12 @@ export default { explanations: { title: 'Explanations' }, reference: { title: 'Reference' }, contributing: { title: 'Contributing' }, - other: { - title: 'Other', - }, - 'header-pricing': { - title: 'Pricing', - type: 'page', - href: '/pricing', - }, + other: { title: 'Other' }, + 'header-pricing': { title: 'Pricing', type: 'page', href: '/pricing' }, 'header-docs': { title: 'Documentation', type: 'page', href: '/introduction', }, - '404': { - theme: { - layout: 'raw', - }, - display: 'hidden', - }, + '404': { theme: { layout: 'raw' }, display: 'hidden' }, } diff --git a/src/pages/package-inspector.mdx b/src/pages/package-inspector.mdx new file mode 100644 index 0000000..d59785a --- /dev/null +++ b/src/pages/package-inspector.mdx @@ -0,0 +1,7 @@ +--- +title: Package Inspector +description: Analyze the security state of open-source packages. Get insights on maintenance, vulnerabilities, and supply chain risks. +--- +import { PackageInspectorPage } from '@/components/package-inspector/PackageInspectorPage' + + \ No newline at end of file diff --git a/src/pages/package-inspector/[...purl].tsx b/src/pages/package-inspector/[...purl].tsx new file mode 100644 index 0000000..1f11af3 --- /dev/null +++ b/src/pages/package-inspector/[...purl].tsx @@ -0,0 +1 @@ +//results page coming soon diff --git a/src/pages/package-inspector/_meta.ts b/src/pages/package-inspector/_meta.ts new file mode 100644 index 0000000..b1ce79b --- /dev/null +++ b/src/pages/package-inspector/_meta.ts @@ -0,0 +1 @@ +export default { theme: { layout: 'raw' }, display: 'hidden' }