diff --git a/apps/hub/src/artifacts/approval-package.ts b/apps/hub/src/artifacts/approval-package.ts index 4cb646b0..0a8333f6 100644 --- a/apps/hub/src/artifacts/approval-package.ts +++ b/apps/hub/src/artifacts/approval-package.ts @@ -109,13 +109,14 @@ export function parseApprovalPackageBundle( return bundle; } -async function verifySourcePin( +export async function verifySourcePin( source: ApprovalPackageSource, readSource: StoredSourceReader, + path: string, ): Promise { if (EXCLUDED_PACKAGE_SOURCE_KINDS.has(source.kind)) throw new ProjectError(422, "excluded_package_source_kind", [ - { path: "manifest.sources", message: source.kind }, + { path, message: source.kind }, ]); const stored = await readSource(source.artifactId, source.version); if ( @@ -126,14 +127,14 @@ async function verifySourcePin( ) throw new ProjectError(422, "invalid_package_source", [ { - path: "manifest.sources", + path, message: `${source.artifactId}@${String(source.version)}`, }, ]); if (stored.approved === false) throw new ProjectError(422, "unapproved_package_source", [ { - path: "manifest.sources", + path, message: `${source.kind}@${String(source.version)}`, }, ]); @@ -199,7 +200,7 @@ export async function validateApprovalPackage( verifySealedAssignment(bundle, sealedAssignment); } for (const source of bundle.manifest.sources) - await verifySourcePin(source, readSource); + await verifySourcePin(source, readSource, "manifest.sources"); return bundle; } diff --git a/apps/hub/src/artifacts/approval-rounds.ts b/apps/hub/src/artifacts/approval-rounds.ts index 0f139cc3..90e60abb 100644 --- a/apps/hub/src/artifacts/approval-rounds.ts +++ b/apps/hub/src/artifacts/approval-rounds.ts @@ -52,7 +52,10 @@ import { parseJson, readJson } from "../lib/json.ts"; import { mailRunAsCaller } from "../mail/caller-mail.ts"; import { actorOf, authorizeProject } from "../projects/authorization.ts"; import { ProjectError } from "../projects/errors.ts"; -import { parseApprovalPackageBundle } from "./approval-package.ts"; +import { + EXCLUDED_PACKAGE_SOURCE_KINDS, + parseApprovalPackageBundle, +} from "./approval-package.ts"; export const APPROVAL_PACKAGE_KIND = "approval_package"; @@ -219,8 +222,7 @@ function extractSupportingDocuments( } } for (const source of bundle.manifest.sources) { - if (source.kind === "app" || source.kind === APPROVAL_PACKAGE_KIND) - continue; + if (EXCLUDED_PACKAGE_SOURCE_KINDS.has(source.kind)) continue; const path = `documents/${source.kind}.md`; if (docMap.has(path) || !isSafeRelativePath(path)) continue; const matched = projectDocuments.find( @@ -513,9 +515,7 @@ export function createPgApprovalRoundStore( const bundle = parseApprovalPackageBundle(stored.content); const projectDocuments: StoredPackageDocument[] = []; for (const source of bundle.manifest.sources) { - if (source.kind === "app" || source.kind === APPROVAL_PACKAGE_KIND) { - continue; - } + if (EXCLUDED_PACKAGE_SOURCE_KINDS.has(source.kind)) continue; const row = await getArtifact(db, source.artifactId); if (!row || row.tenantId !== actor.tenantId) { continue; diff --git a/apps/hub/src/artifacts/service.ts b/apps/hub/src/artifacts/service.ts index 94544eda..5641ce30 100644 --- a/apps/hub/src/artifacts/service.ts +++ b/apps/hub/src/artifacts/service.ts @@ -158,6 +158,7 @@ import { parseApprovalPackageBundle, readProjectPackageSource, validateApprovalPackage, + verifySourcePin, } from "./approval-package.ts"; import { createApprovalRoundService, @@ -2069,30 +2070,8 @@ export function createArtifactService( ); }, ); - for (const source of input.assignment.sources) { - const stored = await readSource(source.artifactId, source.version); - if ( - !stored || - stored.kind !== source.kind || - stored.version !== source.version || - stored.sha256 !== source.sha256 - ) { - throw new ProjectError(422, "invalid_package_source", [ - { - path: "assignment.sources", - message: `${source.artifactId}@${String(source.version)}`, - }, - ]); - } - if (stored.approved === false) { - throw new ProjectError(422, "unapproved_package_source", [ - { - path: "assignment.sources", - message: `${source.kind}@${String(source.version)}`, - }, - ]); - } - } + for (const source of input.assignment.sources) + await verifySourcePin(source, readSource, "assignment.sources"); const sealedAssignment = { ...input.assignment, sealed: true as const,