fix: add security checks and tests for code review
Security: - Add authorization checks to list_packages, update_package, delete_package endpoints - Add MAX_TOTAL_ARTIFACTS limit (1000) to prevent memory exhaustion during dependency resolution - Add TooManyArtifactsError exception for proper error handling UI: - Display reverse dependency errors in PackagePage - Add warning display for failed dependency fetches in DependencyGraph Tests: - Add unit tests for metadata extraction (deb, wheel, tarball, jar) - Add unit tests for rate limit configuration - Add unit tests for PyPI registry client
This commit is contained in:
@@ -227,6 +227,21 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.graph-warning {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
border-top: 1px solid rgba(245, 158, 11, 0.3);
|
||||
color: var(--warning-color, #f59e0b);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.graph-warning svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Missing Dependencies */
|
||||
.missing-dependencies {
|
||||
border-top: 1px solid var(--border-primary);
|
||||
|
||||
@@ -106,6 +106,7 @@ function DependencyGraph({ projectName, packageName, tagName, onClose }: Depende
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [warning, setWarning] = useState<string | null>(null);
|
||||
const [resolution, setResolution] = useState<DependencyResolutionResponse | null>(null);
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState<NodeData>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
@@ -127,16 +128,24 @@ function DependencyGraph({ projectName, packageName, tagName, onClose }: Depende
|
||||
|
||||
// Fetch dependencies for each artifact
|
||||
const depsMap = new Map<string, Dependency[]>();
|
||||
const failedFetches: string[] = [];
|
||||
|
||||
for (const artifact of resolutionData.resolved) {
|
||||
try {
|
||||
const deps = await getArtifactDependencies(artifact.artifact_id);
|
||||
depsMap.set(artifact.artifact_id, deps.dependencies);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.warn(`Failed to fetch dependencies for ${artifact.package}:`, err);
|
||||
failedFetches.push(artifact.package);
|
||||
depsMap.set(artifact.artifact_id, []);
|
||||
}
|
||||
}
|
||||
|
||||
// Report warning if some fetches failed
|
||||
if (failedFetches.length > 0) {
|
||||
setWarning(`Could not load dependency details for: ${failedFetches.slice(0, 3).join(', ')}${failedFetches.length > 3 ? ` and ${failedFetches.length - 3} more` : ''}`);
|
||||
}
|
||||
|
||||
// Find the root artifact
|
||||
const rootArtifact = resolutionData.resolved.find(
|
||||
a => a.project === resolutionData.requested.project &&
|
||||
@@ -324,6 +333,17 @@ function DependencyGraph({ projectName, packageName, tagName, onClose }: Depende
|
||||
)}
|
||||
</div>
|
||||
|
||||
{warning && (
|
||||
<div className="graph-warning">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
|
||||
<line x1="12" y1="9" x2="12" y2="13"></line>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||
</svg>
|
||||
<span>{warning}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{resolution && resolution.missing && resolution.missing.length > 0 && (
|
||||
<div className="missing-dependencies">
|
||||
<h3>Not Cached ({resolution.missing.length})</h3>
|
||||
|
||||
@@ -78,7 +78,7 @@ function PackagePage() {
|
||||
// Reverse dependencies state
|
||||
const [reverseDeps, setReverseDeps] = useState<DependentInfo[]>([]);
|
||||
const [reverseDepsLoading, setReverseDepsLoading] = useState(false);
|
||||
const [_reverseDepsError, setReverseDepsError] = useState<string | null>(null);
|
||||
const [reverseDepsError, setReverseDepsError] = useState<string | null>(null);
|
||||
const [reverseDepsPage, setReverseDepsPage] = useState(1);
|
||||
const [reverseDepsTotal, setReverseDepsTotal] = useState(0);
|
||||
const [reverseDepsHasMore, setReverseDepsHasMore] = useState(false);
|
||||
@@ -647,10 +647,13 @@ function PackagePage() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Used By (Reverse Dependencies) Section - only show if there are reverse deps */}
|
||||
{reverseDeps.length > 0 && (
|
||||
{/* Used By (Reverse Dependencies) Section - only show if there are reverse deps or error */}
|
||||
{(reverseDeps.length > 0 || reverseDepsError) && (
|
||||
<div className="used-by-section card">
|
||||
<h3>Used By</h3>
|
||||
{reverseDepsError && (
|
||||
<div className="error-message">{reverseDepsError}</div>
|
||||
)}
|
||||
<div className="reverse-deps-list">
|
||||
<div className="deps-summary">
|
||||
{reverseDepsTotal} {reverseDepsTotal === 1 ? 'package depends' : 'packages depend'} on this:
|
||||
|
||||
Reference in New Issue
Block a user