Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:

- name: Setup Bun
uses: oven-sh/setup-bun@22457c87c1b161cf7dde222c3e82b2b5f8d2bed2
with:
no-cache: true

- name: Install dependencies
run: bun install
Expand Down
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ export const scanner: Bun.Security.Scanner = {
for (const alert of artifact.alerts) {
const description = ['']

if (alert.type === 'didYouMean') {
if (alert.type === 'didYouMean' && alert.props?.alternatePackage) {
description.push(`This package could be a typo-squatting attempt of another package (${alert.props.alternatePackage}).`)
}

if (alert.props.description) {
if (alert.props?.description) {
description.push(alert.props.description)
}

if (alert.props.note) {
if (alert.props?.note) {
description.push(alert.props.note)
}

Expand Down
4 changes: 2 additions & 2 deletions src/modes/authenticated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function (apiKey: string): ScannerImplementation {
return createScanner({
maxSending: 30,
maxBatchLength: 1,
fetchStrategy: async (purls, artifacts) => {
fetchStrategy: async (purls) => {
const body = JSON.stringify({
components: purls.map(purl => ({ purl }))
} satisfies SocketBatchEndpointBody)
Expand All @@ -33,7 +33,7 @@ export default function (apiKey: string): ScannerImplementation {

const data = await res.text()

artifacts.push(...data.split('\n').filter(Boolean).map(line => JSON.parse(line)))
return data.split('\n').filter(Boolean).map(line => JSON.parse(line))
}
})
}
8 changes: 5 additions & 3 deletions src/modes/unauthenticated.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { ScannerImplementation } from '../types'
import type { ScannerImplementation, SocketArtifact } from '../types'
import { createScanner } from '../scanner-factory'
import { userAgent } from './user-agent'

export default function (): ScannerImplementation {
return createScanner({
maxSending: 20,
maxBatchLength: 50,
fetchStrategy: async (purls, artifacts) => {
fetchStrategy: async (purls) => {
const urls = purls.map(purl => `https://firewall-api.socket.dev/purl/${encodeURIComponent(purl)}`)
const results: SocketArtifact[] = []
await Promise.all(urls.map(async url => {
const res = await fetch(url, {
headers: {
Expand All @@ -18,8 +19,9 @@ export default function (): ScannerImplementation {
throw new Error(`Socket Security Scanner: Received ${res.status} from server`)
}
const data = await res.text()
artifacts.push(...data.split('\n').filter(Boolean).map(line => JSON.parse(line)))
results.push(...data.split('\n').filter(Boolean).map(line => JSON.parse(line)))
}))
return results
}
})
}
14 changes: 8 additions & 6 deletions src/scanner-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,38 @@ import type { SocketArtifact, ScannerImplementation } from './types'
type ScannerConfig = {
maxSending: number
maxBatchLength: number
fetchStrategy: (purls: string[], artifacts: SocketArtifact[]) => Promise<void>
fetchStrategy: (purls: string[]) => Promise<SocketArtifact[]>
}

export function createScanner({ maxSending, maxBatchLength, fetchStrategy }: ScannerConfig): ScannerImplementation {
return async function*(packages) {
let artifacts: SocketArtifact[] = []
let batch: Bun.Security.Package[] = []
let in_flight = 0
let inFlight = 0

const pending: Set<Promise<void>> = new Set()

async function startFlight() {
const purls = batch.map(p => `pkg:npm/${p.name}@${p.version}`)
batch = []
in_flight += purls.length
inFlight += purls.length

if (in_flight >= maxSending) {
if (inFlight >= maxSending) {
if (pending.size !== 0) {
await Promise.race([...pending])
} else {
// bug if we get here
}
}

const flight = fetchStrategy(purls, artifacts)
const flight = fetchStrategy(purls).then(results => {
artifacts.push(...results)
})

pending.add(flight)

flight.finally(() => {
in_flight -= purls.length
inFlight -= purls.length
pending.delete(flight)
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type SocketArtifact = {
alerts: {
action: 'error' | 'warn'
type: string,
props: {
props?: {
note?: string,
didYouMean?: string,
} & Record<string, any>
Expand Down
Loading
Loading