Step 12 - completed

This commit is contained in:
2026-03-03 14:53:34 +01:00
parent 5d485b3665
commit d0b303e745
13 changed files with 950 additions and 487 deletions

View File

@@ -1,4 +1,4 @@
"""Plugin review workflow.
"""Plugin review workflow backed by PostgreSQL.
Manages the approval queue for newly submitted plugins and enforces a
security checklist before any plugin is made visible in the marketplace.
@@ -11,10 +11,12 @@ Module-level singleton::
from __future__ import annotations
import re
import time
from typing import Any, Literal
from sqlalchemy.ext.asyncio import AsyncSession
from app.marketplace.plugin_registry import registry
from app.models import PluginReview as PluginReviewModel
from app.schemas import PluginManifest
# ── Security policy ───────────────────────────────────────────────────
@@ -72,20 +74,16 @@ def validate_manifest(manifest: PluginManifest) -> None:
class ReviewQueue:
"""Approval queue for pending plugin submissions.
Delegates status changes to the shared ``PluginRegistry`` singleton so
there is a single source of truth for plugin state.
Delegates status changes to the shared ``PluginRegistry`` singleton.
Review records are persisted in the ``plugin_reviews`` table.
"""
def __init__(self) -> None:
# Completed reviews — Step 12 stores in plugin_reviews table
self._reviews: list[dict[str, Any]] = []
async def get_pending(self) -> list[dict[str, Any]]:
async def get_pending(self, db: AsyncSession) -> list[dict[str, Any]]:
"""Return all plugins currently awaiting review.
Each item is ``{plugin_id, manifest, submitted_at}``.
"""
entries = registry._get_pending_entries()
entries = await registry.get_pending_entries(db)
return [
{
"plugin_id": e["manifest"].id,
@@ -97,6 +95,7 @@ class ReviewQueue:
async def submit_review(
self,
db: AsyncSession,
plugin_id: str,
reviewer_id: str,
decision: Literal["approved", "rejected"],
@@ -108,19 +107,18 @@ class ReviewQueue:
``KeyError`` if *plugin_id* is not found in the registry.
"""
if decision == "approved":
await registry.approve_plugin(plugin_id)
await registry.approve_plugin(db, plugin_id)
else:
await registry.reject_plugin(plugin_id, reason=notes)
await registry.reject_plugin(db, plugin_id, reason=notes)
self._reviews.append(
{
"plugin_id": plugin_id,
"reviewer_id": reviewer_id,
"decision": decision,
"notes": notes,
"reviewed_at": int(time.time()),
}
review = PluginReviewModel(
plugin_id=plugin_id,
reviewer_id=reviewer_id,
decision=decision,
notes=notes,
)
db.add(review)
await db.commit()
# Module-level singleton