-
-
Notifications
You must be signed in to change notification settings - Fork 271
feat: add provenance to end of README and provenance badge #436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
91d3b99
c9cc109
c19f8ef
4b142f4
64f9601
cc60590
0927569
2c99239
e6bb3e2
723ee08
d9408b5
9c1c0fd
86530fc
1df3da5
0ce8e20
4fe71b7
558f331
0c65073
dc02155
b5d0e08
aa5c739
0490129
73169c0
b9fd47e
f95b9cb
121ebeb
8b37de5
4df6684
49152ff
23582b9
c5e939e
a7b1e22
fed4af5
b632fe3
7c1e4de
2e6a643
1495782
880b091
392c73e
fa236e6
697a85b
38f4d00
2c32786
c77a400
4f22aea
43bb79a
1175730
81a644c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| <script setup lang="ts"> | ||
| import type { ProvenanceDetails } from '#shared/types' | ||
|
|
||
| defineProps<{ | ||
| details: ProvenanceDetails | ||
| }>() | ||
| </script> | ||
|
|
||
| <template> | ||
| <section aria-labelledby="provenance-heading" class="scroll-mt-20"> | ||
| <h2 id="provenance-heading" class="group text-xs text-fg-subtle uppercase tracking-wider mb-3"> | ||
| <a | ||
| href="#provenance" | ||
| class="inline-flex items-center gap-1.5 text-fg-subtle hover:text-fg-muted transition-colors duration-200 no-underline" | ||
| > | ||
| {{ $t('package.provenance_section.title') }} | ||
| <span | ||
| class="i-carbon-link w-3 h-3 block opacity-0 group-hover:opacity-100 transition-opacity duration-200" | ||
| aria-hidden="true" | ||
| /> | ||
| </a> | ||
| </h2> | ||
|
|
||
| <div class="space-y-3 border border-border rounded-lg p-5"> | ||
| <p class="flex items-center gap-2 text-sm text-fg m-0"> | ||
| <span class="i-lucide-shield-check w-4 h-4 shrink-0 text-emerald-500" aria-hidden="true" /> | ||
| <i18n-t keypath="package.provenance_section.built_and_signed_on" tag="span"> | ||
| <template #provider> | ||
| <strong>{{ details.providerLabel }}</strong> | ||
| </template> | ||
| </i18n-t> | ||
| </p> | ||
| <a | ||
| v-if="details.buildSummaryUrl" | ||
| :href="details.buildSummaryUrl" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="link text-sm text-fg-muted block mt-1" | ||
| > | ||
| {{ $t('package.provenance_section.view_build_summary') }} | ||
| </a> | ||
|
|
||
| <dl class="m-0 mt-4 flex justify-between"> | ||
| <div v-if="details.sourceCommitUrl" class="flex flex-col gap-0.5"> | ||
| <dt class="font-mono text-xs text-fg-muted m-0"> | ||
| {{ $t('package.provenance_section.source_commit') }} | ||
| </dt> | ||
| <dd class="m-0"> | ||
| <a | ||
| :href="details.sourceCommitUrl" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="link font-mono text-sm break-all" | ||
| > | ||
| {{ | ||
| details.sourceCommitSha | ||
| ? `${details.sourceCommitSha.slice(0, 12)}` | ||
| : details.sourceCommitUrl | ||
| }} | ||
| </a> | ||
| </dd> | ||
| </div> | ||
| <div v-if="details.buildFileUrl" class="flex flex-col gap-0.5"> | ||
| <dt class="font-mono text-xs text-fg-muted m-0"> | ||
| {{ $t('package.provenance_section.build_file') }} | ||
| </dt> | ||
| <dd class="m-0"> | ||
| <a | ||
| :href="details.buildFileUrl" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="link font-mono text-sm break-all" | ||
| > | ||
| {{ details.buildFilePath ?? details.buildFileUrl }} | ||
| </a> | ||
| </dd> | ||
| </div> | ||
| <div v-if="details.publicLedgerUrl" class="flex flex-col gap-0.5"> | ||
| <dt class="font-mono text-xs text-fg-muted m-0"> | ||
| {{ $t('package.provenance_section.public_ledger') }} | ||
| </dt> | ||
| <dd class="m-0"> | ||
| <a | ||
| :href="details.publicLedgerUrl" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="link text-sm" | ||
| > | ||
| {{ $t('package.provenance_section.transparency_log_entry') }} | ||
| </a> | ||
| </dd> | ||
| </div> | ||
| </dl> | ||
| </div> | ||
| </section> | ||
| </template> | ||
AscaL marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NpmVersionDist, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PackumentVersion, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProvenanceDetails, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ReadmeResponse, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SkillsListResponse, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '#shared/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -158,6 +159,39 @@ const { data: vulnTree, status: vulnTreeStatus } = useDependencyAnalysis( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => resolvedVersion.value ?? '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: provenanceData, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| status: provenanceStatus, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| execute: fetchProvenance, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = useLazyFetch<ProvenanceDetails | null>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const v = displayVersion.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!v || !hasProvenance(v)) return '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return `/api/registry/provenance/${packageName.value}/v/${v.version}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: () => null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| server: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| immediate: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (import.meta.client) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| watch( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displayVersion, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (v && hasProvenance(v) && provenanceStatus.value === 'idle') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetchProvenance() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { immediate: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const provenanceBadgeMounted = shallowRef(false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onMounted(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provenanceBadgeMounted.value = true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Keep latestVersion for comparison (to show "(latest)" badge) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const latestVersion = computed(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!pkg.value) return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -523,16 +557,26 @@ defineOgImageComponent('Package', { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span v-else>v{{ resolvedVersion }}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-if="hasProvenance(displayVersion)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :href="`https://www.npmjs.com/package/${pkg.name}/v/${resolvedVersion}#provenance`" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target="_blank" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rel="noopener noreferrer" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="inline-flex items-center justify-center gap-1.5 text-fg-muted hover:text-fg transition-colors duration-200 min-w-6 min-h-6" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :title="$t('package.verified_provenance')" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="i-lucide-shield-check w-3.5 h-3.5 shrink-0" aria-hidden="true" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </a> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <template v-if="hasProvenance(displayVersion) && provenanceBadgeMounted"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <TooltipApp | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :text=" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provenanceData && provenanceStatus !== 'pending' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? $t('package.provenance_section.built_and_signed_on', { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provider: provenanceData.providerLabel, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : $t('package.verified_provenance') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| position="bottom" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| href="#provenance" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :aria-label="$t('package.provenance_section.view_more_details')" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="inline-flex items-center justify-center gap-1.5 text-fg-muted hover:text-emerald-500 transition-colors duration-200 min-w-6 min-h-6" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="i-lucide-shield-check w-3.5 h-3.5 shrink-0" aria-hidden="true" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </a> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </TooltipApp> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </template> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
560
to
579
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: head -n 600 app/pages/package/[...package].vue | tail -n 100Repository: npmx-dev/npmx.dev Length of output: 4689 🏁 Script executed: wc -l app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 100 🏁 Script executed: rg "provenanceStatus|provenanceData" app/pages/package/[...package].vue -A 2 -B 2Repository: npmx-dev/npmx.dev Length of output: 868 🏁 Script executed: rg "fetchProvenance|useLazyFetch" app/pages/package/[...package].vue -A 5 -B 2Repository: npmx-dev/npmx.dev Length of output: 1703 🏁 Script executed: rg "catch|error" app/pages/package/[...package].vue | grep -i provenanceRepository: npmx-dev/npmx.dev Length of output: 43 🏁 Script executed: web_search
Nuxt useLazyFetch status states documentationRepository: npmx-dev/npmx.dev Length of output: 154 🌐 Web query:
💡 Result: In Nuxt,
(These are the same Sources: [1] Nuxt 🏁 Script executed: rg "provenanceData\s*=" app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 43 🏁 Script executed: rg "provenanceData" app/pages/package/[...package].vue | head -20Repository: npmx-dev/npmx.dev Length of output: 292 🏁 Script executed: sed -n '200,250p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 1688 🏁 Script executed: rg -B 20 "status: provenanceStatus" app/pages/package/[...package].vue | head -40Repository: npmx-dev/npmx.dev Length of output: 644 🏁 Script executed: rg "provenanceData|fetchProvenance" app/pages/package/[...package].vue -A 10 | grep -A 10 -B 5 "error\|catch\|reset"Repository: npmx-dev/npmx.dev Length of output: 43 🏁 Script executed: sed -n '290,330p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 1191 🏁 Script executed: rg -n "const {" app/pages/package/[...package].vue | grep -i provenanceRepository: npmx-dev/npmx.dev Length of output: 138 🏁 Script executed: sed -n '320,360p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 1484 🏁 Script executed: rg -n "useLazyFetch.*Provenance\|data: provenanceData" app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 43 🏁 Script executed: sed -n '360,400p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 1306 🏁 Script executed: grep -n "provenanceData\|provenanceStatus\|fetchProvenance" app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 461 🏁 Script executed: sed -n '160,185p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 596 🏁 Script executed: sed -n '555,570p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 851 🏁 Script executed: sed -n '1130,1150p' app/pages/package/[...package].vueRepository: npmx-dev/npmx.dev Length of output: 766 Use explicit success status to avoid showing stale provider labels after failed fetches. The current condition - provenanceData && provenanceStatus !== 'pending'
+ provenanceStatus === 'success' && provenanceData📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-if="requestedVersion && latestVersion && resolvedVersion !== latestVersion.version" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="text-fg-subtle text-sm shrink-0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1084,8 +1128,37 @@ defineOgImageComponent('Package', { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >{{ $t('package.readme.view_on_github') }}</a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </section> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <section | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-if="hasProvenance(displayVersion) && provenanceBadgeMounted" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id="provenance" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="scroll-mt-20" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-if="provenanceStatus === 'pending'" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="mt-8 flex items-center gap-2 text-fg-subtle text-sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="i-carbon-circle-dash w-4 h-4 motion-safe:animate-spin" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| aria-hidden="true" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span>{{ $t('package.provenance_section.title') }}…</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <PackageProvenanceSection | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-else-if="provenanceData" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :details="provenanceData" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="mt-8" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <!-- Error state: provenance exists but details failed to load --> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-else-if="provenanceStatus === 'error'" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="mt-8 flex items-center gap-2 text-fg-subtle text-sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span class="i-carbon:warning w-4 h-4" aria-hidden="true" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span>{{ $t('package.provenance_section.error_loading') }}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </section> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </section> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="area-sidebar"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <!-- Sidebar --> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="sticky top-34 space-y-6 sm:space-y-8 min-w-0 overflow-hidden xl:(top-22) pt-1"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for the question, but is this file AI generated?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No issue, yes it is for the most part, beside some minor changes I made
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh.. I'm rewriting this code currently
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR still needs changes and reviews, so it's better not to merge it for now
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, what's the issue?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still working on this
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It is described here - #436 (review) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import * as v from 'valibot' | ||
| import { PackageRouteParamsSchema } from '#shared/schemas/package' | ||
| import type { NpmVersionDist } from '#shared/types' | ||
| import { CACHE_MAX_AGE_ONE_HOUR, ERROR_PROVENANCE_FETCH_FAILED } from '#shared/utils/constants' | ||
| import { | ||
| parseAttestationToProvenanceDetails, | ||
| type NpmAttestationsResponse, | ||
| } from '#server/utils/provenance' | ||
|
|
||
| /** | ||
| * GET /api/registry/provenance/:name/v/:version | ||
| * | ||
| * Returns parsed provenance details for a package version (build summary, source commit, build file, public ledger). | ||
| * Version is required. Returns null when the version has no attestations or parsing fails. | ||
| */ | ||
| export default defineCachedEventHandler( | ||
| async event => { | ||
| const pkgParamSegments = getRouterParam(event, 'pkg')?.split('/') ?? [] | ||
|
|
||
| const { rawPackageName, rawVersion } = parsePackageParams(pkgParamSegments) | ||
|
|
||
| if (!rawVersion) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| message: 'Version is required for provenance.', | ||
| }) | ||
| } | ||
|
|
||
| try { | ||
| const parsed = v.parse(PackageRouteParamsSchema, { | ||
| packageName: rawPackageName, | ||
| version: rawVersion, | ||
| }) as { packageName: string; version: string } | ||
| const { packageName, version } = parsed | ||
|
|
||
| const packument = await fetchNpmPackage(packageName) | ||
| const versionData = packument.versions[version] | ||
| if (!versionData) { | ||
| throw createError({ | ||
| statusCode: 404, | ||
| message: `Version ${version} not found for package ${packageName}.`, | ||
| }) | ||
| } | ||
| const dist = versionData.dist as NpmVersionDist | undefined | ||
| const attestationsUrl = dist?.attestations?.url | ||
|
|
||
| if (!attestationsUrl) { | ||
| return null | ||
| } | ||
|
|
||
| const response = await $fetch<NpmAttestationsResponse>(attestationsUrl) | ||
| const details = parseAttestationToProvenanceDetails(response) | ||
| return details | ||
| } catch (error: unknown) { | ||
| handleApiError(error, { | ||
| statusCode: 502, | ||
| message: ERROR_PROVENANCE_FETCH_FAILED, | ||
| }) | ||
| } | ||
| }, | ||
| { | ||
| maxAge: CACHE_MAX_AGE_ONE_HOUR, | ||
| swr: true, | ||
| getKey: event => { | ||
| const pkg = getRouterParam(event, 'pkg') ?? '' | ||
| return `provenance:v1:${pkg.replace(/\/+$/, '').trim()}` | ||
| }, | ||
| }, | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.