Harden public Clip revision reads

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-07-09 18:47:25 +00:00
1 parent bf6d6ed6e3
commit fed84a8547
2 files changed
+29 -5

No files matched your search

+22 -2
View File
@@ -212,7 +212,7 @@ describeEmbeddedPostgres("clipService", () => {
expect(revisions.map((revision) => revision.revisionNumber)).toEqual([1, 2, 3]);
});
it("queries creator profile clips by creator before applying limits", async () => {
it("queries creator profile clips by creator before applying limits without exposing unlisted clips", async () => {
const targetCompanyId = await seedCompany();
const otherCompanyId = await seedCompany();
const [targetProfile] = await db.insert(clipCreatorProfiles).values({
@@ -269,7 +269,27 @@ describeEmbeddedPostgres("clipService", () => {
expect(profile?.clips.map((clip) => clip.slug).sort()).toEqual([
"target-public-" + targetCompanyId.slice(0, 8),
"target-unlisted-" + targetCompanyId.slice(0, 8),
]);
});
it("does not serve blocked or failed revisions through public revision reads", async () => {
const companyId = await seedCompany();
const { clip } = await publishFixture(companyId);
const blocked = await svc.createRevision(clip.id, {
manifestChecksum: "sha256:manifest-blocked",
artifactChecksum: "sha256:artifact-blocked",
manifestPayload: { schema: "paperclip.clip/v1", revision: "blocked" },
securityReviewState: "blocked",
});
const failed = await svc.createRevision(clip.id, {
manifestChecksum: "sha256:manifest-failed",
artifactChecksum: "sha256:artifact-failed",
manifestPayload: { schema: "paperclip.clip/v1", revision: "failed" },
verificationState: "failed",
});
expect(await svc.getPublicRevision(clip.slug, blocked.revision.revisionNumber)).toBeNull();
expect(await svc.getPublicRevision(clip.slug, failed.revision.revisionNumber)).toBeNull();
});
});
+7 -3
View File
@@ -50,6 +50,10 @@ function first<T>(rows: T[]): T | null {
return rows[0] ?? null;
}
function isPubliclyReadableRevision(revision: typeof clipRevisions.$inferSelect) {
return revision.securityReviewState !== "blocked" && revision.verificationState !== "failed";
}
function publicMetrics(row: typeof clips.$inferSelect) {
return {
importCount: row.importCount,
@@ -150,7 +154,8 @@ export function clipService(db: Db) {
async function getPublicCurrentRevision(clip: typeof clips.$inferSelect) {
const revisionId = clip.latestApprovedRevisionId ?? clip.currentRevisionId;
if (!revisionId) return null;
return first(await db.select().from(clipRevisions).where(eq(clipRevisions.id, revisionId)).limit(1));
const revision = first(await db.select().from(clipRevisions).where(eq(clipRevisions.id, revisionId)).limit(1));
return revision && isPubliclyReadableRevision(revision) ? revision : null;
}
async function getPublicClipBySlug(slug: string) {
@@ -230,7 +235,7 @@ export function clipService(db: Db) {
const row = await getPublicClipBySlug(slug);
if (!row) return null;
const revision = await getRevisionByNumber(row.clip.id, revisionNumber);
if (!revision) return null;
if (!revision || !isPubliclyReadableRevision(revision)) return null;
const dependencies = await db.select().from(clipDependencies).where(eq(clipDependencies.revisionId, revision.id));
return serializePublicClip({
clip: row.clip,
@@ -678,7 +683,6 @@ export function clipService(db: Db) {
if (!profile) return null;
const publicClips = await listPublic({
creatorProfileId: profile.id,
includeUnlisted: true,
limit: 100,
});
return {