Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import DisplayVersion from '@antfu/design/components/Display/DisplayVersion.vue'
import { computed } from 'vue'
import { getDeprecatedInfo, getVulnerability } from '../../state/payload'
import DisplayPackageName from './PackageName.vue'
import DisplayProvenanceBadge from './ProvenanceBadge.vue'
import DisplaySupplyChainBadge from './SupplyChainBadge.vue'

const props = defineProps<{
pkg: PackageNode
versionSize?: 'small' | 'normal'
versionPrefix?: string
showProvenance?: boolean
showSupplyChain?: boolean
}>()

const deprecation = computed(() => getDeprecatedInfo(props.pkg))
Expand Down Expand Up @@ -48,7 +48,7 @@ const vulnerability = computed(() => getVulnerability(props.pkg))
'text-sm': 'small' === versionSize,
}"
/>
<DisplayProvenanceBadge v-if="showProvenance" :pkg="props.pkg" class="ml-1 translate-y--0.1em" />
<DisplaySupplyChainBadge v-if="showSupplyChain" :pkg="props.pkg" class="ml-1 translate-y--0.1em" />
<slot />
</span>
</template>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script setup lang="ts">
import type { PackageNode } from 'node-modules-tools'
import { computed } from 'vue'
import { getNpmMeta } from '../../state/payload'
import { settings } from '../../state/settings'
import { getSupplyChainScore } from '../../utils/supply-chain'

const props = defineProps<{
pkg: PackageNode
class?: string
}>()

const meta = computed(() => getNpmMeta(props.pkg))

/**
* How many of the three supply-chain signals (provenance, trusted publisher,
* staged publish) this package has. `undefined` when there is no npm meta yet.
*/
const score = computed(() => meta.value ? getSupplyChainScore(meta.value) : undefined)

const isShown = computed(() => {
if (score.value === undefined)
return false
if (settings.value.showSupplyChainBadge === 'present')
return score.value > 0
if (settings.value.showSupplyChainBadge === 'absent')
return score.value === 0
return false
})

const TRUSTED_PUBLISHER = 'by a trusted publisher'
const description = computed(() => {
const m = meta.value
const state = m?.provenance
? `signed with provenance${m.trustedPublisher ? ` ${TRUSTED_PUBLISHER}` : ''}`
: m?.trustedPublisher
? `published ${TRUSTED_PUBLISHER}`
: 'not signed with provenance'
return `This package is ${state}${m?.staged ? ' (staged publish)' : ''}`
})

const icon = computed(() => {
switch (score.value) {
case 3:
return 'i-ph:seal-check-duotone text-green-400'
case 2:
return 'i-ph:circle-wavy-check-duotone text-teal-400'
case 1:
return 'i-ph:circle-wavy-check-duotone text-blue-400'
default:
return 'i-ph:circle-wavy-warning-duotone text-amber-400'
}
})
</script>

<template>
<span
v-if="isShown" v-tooltip="description"
:class="[props.class, icon]"
h-1.1em inline-flex align-middle
/>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defineProps<{
@click="selectedNode = pkg === selectedNode ? undefined : pkg"
>
<div flex="~ gap-2 items-center" text-left>
<DisplayPackageSpec :pkg :show-provenance="true" />
<DisplayPackageSpec :pkg :show-supply-chain="true" />
</div>
<div flex="~ wrap gap-2 items-center" text-sm>
<DisplayModuleType :pkg />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import IntegrationsPublintCounts from '../integrations/PublintCounts.vue'
import TreeDependencies from '../tree/Dependencies.vue'
import UiPercentageFileCategories from '../ui/PercentageFileCategories.vue'
import UiPercentageModuleType from '../ui/PercentageModuleType.vue'
import UiPercentageProvenance from '../ui/PercentageProvenance.vue'
import UiPercentageSupplyChain from '../ui/PercentageSupplyChain.vue'
import PanelMaintainerActionTypePill from './MaintainerActionTypePill.vue'
import PanelPackageDetailsInfo from './PackageDetailsInfo.vue'

Expand Down Expand Up @@ -466,9 +466,9 @@ const thirdPartyServices = computed(() => {
:flat="settings.deepDependenciesTree"
/>
<div op-fade text-sm mt2>
Dependency Provenance
Dependency Supply Chain
</div>
<UiPercentageProvenance
<UiPercentageSupplyChain
:pkg="pkg"
:flat="settings.deepDependenciesTree"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { NuxtLink } from '#components'
import { getBackend } from '../../backends'
import { selectedNode } from '../../state/current'
import { filters } from '../../state/filters'
import { getDeprecatedInfo, getNpmMeta, getNpmMetaLatest, getPublishTime, payloads } from '../../state/payload'
import { getDeprecatedInfo, getNpmMetaLatest, getPublishTime, payloads } from '../../state/payload'
import { settings } from '../../state/settings'
import DisplayAuthors from '../display/Authors.vue'
import DisplayDateBadge from '../display/DateBadge.vue'
import DisplayModuleType from '../display/ModuleType'
import DisplayNodeVersionRange from '../display/NodeVersionRange.vue'
import DisplayPackageName from '../display/PackageName.vue'
import DisplayProvenanceBadge from '../display/ProvenanceBadge.vue'
import DisplaySourceTypeBadge from '../display/SourceTypeBadge.vue'
import DisplaySupplyChainBadge from '../display/SupplyChainBadge.vue'
import DisplayVersionWithUpdates from '../display/VersionWithUpdates.vue'
import PanelPackageFunding from './PackageFunding.vue'

Expand All @@ -27,7 +27,6 @@ const props = defineProps<{
const backend = getBackend()
const router = useRouter()

const meta = computed(() => getNpmMeta(props.pkg))
const latestMeta = computed(() => getNpmMetaLatest(props.pkg))
const deprecation = computed(() => getDeprecatedInfo(props.pkg))
const resolved = computed(() => props.pkg.resolved)
Expand Down Expand Up @@ -55,12 +54,11 @@ function showDuplicatedGraph(pkgs: PackageNode[]) {
<div flex="~ col gap-2">
<DisplayPackageName
:name="pkg.name"
:provenance="meta?.provenance"
font-mono text-xl pr-8
:class="deprecation?.latest ? deprecation.type === 'future' ? 'text-orange line-through' : 'text-red line-through' : ''"
>
<template #after>
<DisplayProvenanceBadge :pkg class="ml-1" />
<DisplaySupplyChainBadge :pkg class="ml-1" />
</template>
</DisplayPackageName>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const showConfigDialog = ref(false)
<OptionItem :div="true" title="Show publish time badge" description="Show publish time badge on package list">
<FormCheckbox v-model="settings.showPublishTimeBadge" />
</OptionItem>
<OptionItem title="Provenance badge" description="Show provenance indicator on packages">
<OptionItem title="Supply chain badge" description="Show supply chain signals on packages">
<OptionSelectGroup
v-model="settings.showProvenanceBadge"
v-model="settings.showSupplyChainBadge"
:options="['present', 'absent', 'none']"
:titles="['Present', 'Absent', 'None']"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ withDefaults(
<slot name="before" />
<DisplayModuleType v-if="showModuleType" :pkg />
<DisplaySourceTypeBadge v-if="showSourceType" :pkg />
<DisplayPackageSpec :pkg show-provenance />
<DisplayPackageSpec :pkg show-supply-chain />
<slot name="after" />
</button>
</template>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<script setup lang="ts">
import type { PackageNode } from 'node-modules-tools'
import { computed } from 'vue'
import { getNpmMeta, payloads } from '../../state/payload'
import { getSupplyChainScore, SUPPLY_CHAIN_SIGNALS } from '../../utils/supply-chain'
import UiPercentage from './Percentage.vue'

const props = withDefaults(
defineProps<{
pkg?: PackageNode
packages?: PackageNode[]
flat?: boolean
rounded?: boolean
}>(),
{
flat: false,
rounded: true,
},
)

// Same green/teal/blue/gray ramp as the badge, best first.
const SCORE_COLORS = ['badge-color-gray', 'badge-color-blue', 'badge-color-teal', 'badge-color-green']

const nodes = computed(() => {
const pkgs = props.pkg
? [
props.pkg,
...props.flat
? payloads.available.flatDependencies(props.pkg)
: payloads.available.dependencies(props.pkg),
]
: props.packages ?? []

const scores = pkgs.map(p => getSupplyChainScore(getNpmMeta(p)))

return SCORE_COLORS
.map((className, score) => {
const value = scores.filter(s => s === score).length
return {
value,
name: `${score}/${SUPPLY_CHAIN_SIGNALS.length}`,
class: className,
title: `${value} dependencies with ${score} of ${SUPPLY_CHAIN_SIGNALS.length} supply chain signals: ${SUPPLY_CHAIN_SIGNALS.join(', ')}`,
}
})
.reverse()
.filter(n => n.value > 0)
})
</script>

<template>
<UiPercentage :nodes :rounded />
</template>
Loading
Loading