generated from coulomb/repo-seed
API-completeness polish
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -324,6 +325,220 @@ class CandidateEvidenceMerge(BaseModel):
|
||||
}
|
||||
|
||||
|
||||
class RepositoryResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
url: str
|
||||
description: str | None
|
||||
branch: str
|
||||
status: str
|
||||
|
||||
|
||||
class RepositorySnapshotResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
commit_hash: str
|
||||
branch: str
|
||||
source_path: str
|
||||
file_count: int
|
||||
|
||||
|
||||
class AnalysisRunResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
snapshot_id: int | None
|
||||
status: str
|
||||
started_at: str
|
||||
completed_at: str | None
|
||||
error_message: str | None
|
||||
scanner_version: str
|
||||
|
||||
|
||||
class ReviewDecisionResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
analysis_run_id: int | None
|
||||
action: str
|
||||
notes: str
|
||||
created_at: str
|
||||
|
||||
|
||||
class ObservedFactResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
analysis_run_id: int
|
||||
snapshot_id: int | None
|
||||
kind: str
|
||||
path: str
|
||||
name: str
|
||||
value: str
|
||||
metadata: dict[str, Any]
|
||||
|
||||
|
||||
class ContentChunkResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
analysis_run_id: int
|
||||
snapshot_id: int | None
|
||||
path: str
|
||||
kind: str
|
||||
start_line: int
|
||||
end_line: int
|
||||
text: str
|
||||
|
||||
|
||||
class ScanSummaryResponse(BaseModel):
|
||||
analysis_run: AnalysisRunResponse
|
||||
snapshot: RepositorySnapshotResponse | None
|
||||
facts: list[ObservedFactResponse]
|
||||
|
||||
|
||||
class SourceReferenceResponse(BaseModel):
|
||||
fact_id: int | None
|
||||
path: str
|
||||
kind: str
|
||||
name: str
|
||||
line: int | None = None
|
||||
|
||||
|
||||
class CandidateEvidenceResponse(BaseModel):
|
||||
id: int
|
||||
type: str
|
||||
reference: str
|
||||
strength: str
|
||||
status: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
|
||||
|
||||
class CandidateFeatureResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
type: str
|
||||
location: str
|
||||
confidence: float
|
||||
status: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
confidence_label: str
|
||||
|
||||
|
||||
class CandidateCapabilityResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str
|
||||
inputs: list[str]
|
||||
outputs: list[str]
|
||||
confidence: float
|
||||
status: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
confidence_label: str
|
||||
features: list[CandidateFeatureResponse]
|
||||
evidence: list[CandidateEvidenceResponse]
|
||||
|
||||
|
||||
class CandidateAbilityResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str
|
||||
confidence: float
|
||||
status: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
confidence_label: str
|
||||
capabilities: list[CandidateCapabilityResponse]
|
||||
|
||||
|
||||
class CandidateGraphResponse(BaseModel):
|
||||
repository: RepositoryResponse
|
||||
analysis_run: AnalysisRunResponse
|
||||
abilities: list[CandidateAbilityResponse]
|
||||
|
||||
|
||||
class EvidenceResponse(BaseModel):
|
||||
id: int
|
||||
type: str
|
||||
reference: str
|
||||
strength: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
|
||||
|
||||
class FeatureResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
type: str
|
||||
location: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
source_refs: list[SourceReferenceResponse]
|
||||
|
||||
|
||||
class CapabilityResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str
|
||||
inputs: list[str]
|
||||
outputs: list[str]
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
features: list[FeatureResponse]
|
||||
evidence: list[EvidenceResponse]
|
||||
|
||||
|
||||
class AbilityResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
capabilities: list[CapabilityResponse]
|
||||
|
||||
|
||||
class RepositoryAbilityMapResponse(BaseModel):
|
||||
repository: RepositoryResponse
|
||||
abilities: list[AbilityResponse]
|
||||
|
||||
|
||||
class IdResponse(BaseModel):
|
||||
id: int
|
||||
|
||||
|
||||
class SearchResultResponse(BaseModel):
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
match_type: str
|
||||
match_name: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
match_description: str
|
||||
matched_field: str
|
||||
ability_id: int | None = None
|
||||
ability_name: str | None = None
|
||||
capability_id: int | None = None
|
||||
capability_name: str | None = None
|
||||
evidence_level: str | None = None
|
||||
source_reference: str | None = None
|
||||
|
||||
|
||||
class AbilitySummaryResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
name: str
|
||||
description: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
|
||||
|
||||
class CapabilitySummaryResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
ability_id: int
|
||||
ability_name: str
|
||||
name: str
|
||||
description: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
|
||||
|
||||
API_DESCRIPTION = (
|
||||
"Register repositories, analyze their observable implementation facts, "
|
||||
"curate reviewable ability graphs, and search approved repository abilities."
|
||||
@@ -356,7 +571,12 @@ def health() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.post("/repos", status_code=201, tags=["repositories"])
|
||||
@app.post(
|
||||
"/repos",
|
||||
status_code=201,
|
||||
tags=["repositories"],
|
||||
response_model=RepositoryResponse,
|
||||
)
|
||||
def create_repository(
|
||||
payload: RepositoryCreate,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -368,14 +588,18 @@ def create_repository(
|
||||
return asdict(repository)
|
||||
|
||||
|
||||
@app.get("/repos", tags=["repositories"])
|
||||
@app.get("/repos", tags=["repositories"], response_model=list[RepositoryResponse])
|
||||
def list_repositories(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [asdict(repository) for repository in service.list_repositories()]
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}", tags=["repositories"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}",
|
||||
tags=["repositories"],
|
||||
response_model=RepositoryResponse,
|
||||
)
|
||||
def get_repository(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -386,7 +610,11 @@ def get_repository(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}", tags=["repositories"])
|
||||
@app.patch(
|
||||
"/repos/{repository_id}",
|
||||
tags=["repositories"],
|
||||
response_model=RepositoryResponse,
|
||||
)
|
||||
def update_repository(
|
||||
repository_id: int,
|
||||
payload: RepositoryUpdate,
|
||||
@@ -414,7 +642,12 @@ def delete_repository(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/analysis-runs", status_code=201, tags=["analysis"])
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs",
|
||||
status_code=201,
|
||||
tags=["analysis"],
|
||||
response_model=ScanSummaryResponse,
|
||||
)
|
||||
def create_analysis_run(
|
||||
repository_id: int,
|
||||
payload: AnalysisRunCreate,
|
||||
@@ -430,7 +663,11 @@ def create_analysis_run(
|
||||
return asdict(summary)
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs", tags=["analysis"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs",
|
||||
tags=["analysis"],
|
||||
response_model=list[AnalysisRunResponse],
|
||||
)
|
||||
def list_analysis_runs(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -441,7 +678,11 @@ def list_analysis_runs(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}", tags=["analysis"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}",
|
||||
tags=["analysis"],
|
||||
response_model=AnalysisRunResponse,
|
||||
)
|
||||
def get_analysis_run(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -453,7 +694,11 @@ def get_analysis_run(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/review-decisions", tags=["review"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/review-decisions",
|
||||
tags=["review"],
|
||||
response_model=list[ReviewDecisionResponse],
|
||||
)
|
||||
def list_repository_review_decisions(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -470,6 +715,7 @@ def list_repository_review_decisions(
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions",
|
||||
tags=["review"],
|
||||
response_model=list[ReviewDecisionResponse],
|
||||
)
|
||||
def list_analysis_run_review_decisions(
|
||||
repository_id: int,
|
||||
@@ -488,7 +734,11 @@ def list_analysis_run_review_decisions(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/observed-facts", tags=["analysis"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/observed-facts",
|
||||
tags=["analysis"],
|
||||
response_model=list[ObservedFactResponse],
|
||||
)
|
||||
def list_observed_facts(
|
||||
repository_id: int,
|
||||
analysis_run_id: int | None = None,
|
||||
@@ -503,7 +753,11 @@ def list_observed_facts(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/content-chunks", tags=["analysis"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/content-chunks",
|
||||
tags=["analysis"],
|
||||
response_model=list[ContentChunkResponse],
|
||||
)
|
||||
def list_content_chunks(
|
||||
repository_id: int,
|
||||
analysis_run_id: int | None = None,
|
||||
@@ -521,6 +775,7 @@ def list_content_chunks(
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/content-chunks",
|
||||
tags=["analysis"],
|
||||
response_model=list[ContentChunkResponse],
|
||||
)
|
||||
def list_analysis_run_content_chunks(
|
||||
repository_id: int,
|
||||
@@ -539,6 +794,7 @@ def list_analysis_run_content_chunks(
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def get_candidate_graph(
|
||||
repository_id: int,
|
||||
@@ -554,6 +810,7 @@ def get_candidate_graph(
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph/approve",
|
||||
tags=["review"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def approve_candidate_graph(
|
||||
repository_id: int,
|
||||
@@ -577,6 +834,7 @@ def approve_candidate_graph(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{candidate_ability_id}/reject",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def reject_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -602,6 +860,7 @@ def reject_candidate_ability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}/reject",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def reject_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -627,6 +886,7 @@ def reject_candidate_capability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{candidate_feature_id}/reject",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def reject_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -652,6 +912,7 @@ def reject_candidate_feature(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{candidate_evidence_id}/reject",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def reject_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -677,6 +938,7 @@ def reject_candidate_evidence(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{candidate_ability_id}",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def edit_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -702,6 +964,7 @@ def edit_candidate_ability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def edit_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -727,6 +990,7 @@ def edit_candidate_capability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}/relink",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def relink_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -752,6 +1016,7 @@ def relink_candidate_capability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{candidate_feature_id}/relink",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def relink_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -777,6 +1042,7 @@ def relink_candidate_feature(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{candidate_evidence_id}/relink",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def relink_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -802,6 +1068,7 @@ def relink_candidate_evidence(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{source_ability_id}/merge",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def merge_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -827,6 +1094,7 @@ def merge_candidate_ability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{source_capability_id}/merge",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def merge_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -852,6 +1120,7 @@ def merge_candidate_capability(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{source_feature_id}/merge",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def merge_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -877,6 +1146,7 @@ def merge_candidate_feature(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{source_evidence_id}/merge",
|
||||
tags=["review"],
|
||||
response_model=CandidateGraphResponse,
|
||||
)
|
||||
def merge_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -898,7 +1168,12 @@ def merge_candidate_evidence(
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/abilities", status_code=201, tags=["registry"])
|
||||
@app.post(
|
||||
"/repos/{repository_id}/abilities",
|
||||
status_code=201,
|
||||
tags=["registry"],
|
||||
response_model=IdResponse,
|
||||
)
|
||||
def create_ability(
|
||||
repository_id: int,
|
||||
payload: AbilityCreate,
|
||||
@@ -911,7 +1186,11 @@ def create_ability(
|
||||
return {"id": ability_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/abilities/{ability_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def update_ability(
|
||||
repository_id: int,
|
||||
ability_id: int,
|
||||
@@ -930,7 +1209,11 @@ def update_ability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
||||
@app.delete(
|
||||
"/repos/{repository_id}/abilities/{ability_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def delete_ability(
|
||||
repository_id: int,
|
||||
ability_id: int,
|
||||
@@ -942,7 +1225,12 @@ def delete_ability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/capabilities", status_code=201, tags=["registry"])
|
||||
@app.post(
|
||||
"/repos/{repository_id}/capabilities",
|
||||
status_code=201,
|
||||
tags=["registry"],
|
||||
response_model=IdResponse,
|
||||
)
|
||||
def create_capability(
|
||||
repository_id: int,
|
||||
payload: CapabilityCreate,
|
||||
@@ -955,7 +1243,11 @@ def create_capability(
|
||||
return {"id": capability_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/capabilities/{capability_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def update_capability(
|
||||
repository_id: int,
|
||||
capability_id: int,
|
||||
@@ -974,7 +1266,11 @@ def update_capability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
||||
@app.delete(
|
||||
"/repos/{repository_id}/capabilities/{capability_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def delete_capability(
|
||||
repository_id: int,
|
||||
capability_id: int,
|
||||
@@ -986,7 +1282,12 @@ def delete_capability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/features", status_code=201, tags=["registry"])
|
||||
@app.post(
|
||||
"/repos/{repository_id}/features",
|
||||
status_code=201,
|
||||
tags=["registry"],
|
||||
response_model=IdResponse,
|
||||
)
|
||||
def create_feature(
|
||||
repository_id: int,
|
||||
payload: FeatureCreate,
|
||||
@@ -999,7 +1300,11 @@ def create_feature(
|
||||
return {"id": feature_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/features/{feature_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def update_feature(
|
||||
repository_id: int,
|
||||
feature_id: int,
|
||||
@@ -1018,7 +1323,11 @@ def update_feature(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
||||
@app.delete(
|
||||
"/repos/{repository_id}/features/{feature_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def delete_feature(
|
||||
repository_id: int,
|
||||
feature_id: int,
|
||||
@@ -1030,7 +1339,12 @@ def delete_feature(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/evidence", status_code=201, tags=["registry"])
|
||||
@app.post(
|
||||
"/repos/{repository_id}/evidence",
|
||||
status_code=201,
|
||||
tags=["registry"],
|
||||
response_model=IdResponse,
|
||||
)
|
||||
def create_evidence(
|
||||
repository_id: int,
|
||||
payload: EvidenceCreate,
|
||||
@@ -1043,7 +1357,11 @@ def create_evidence(
|
||||
return {"id": evidence_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/evidence/{evidence_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def update_evidence(
|
||||
repository_id: int,
|
||||
evidence_id: int,
|
||||
@@ -1062,7 +1380,11 @@ def update_evidence(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
||||
@app.delete(
|
||||
"/repos/{repository_id}/evidence/{evidence_id}",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def delete_evidence(
|
||||
repository_id: int,
|
||||
evidence_id: int,
|
||||
@@ -1074,7 +1396,11 @@ def delete_evidence(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/ability-map", tags=["registry"])
|
||||
@app.get(
|
||||
"/repos/{repository_id}/ability-map",
|
||||
tags=["registry"],
|
||||
response_model=RepositoryAbilityMapResponse,
|
||||
)
|
||||
def get_ability_map(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -1085,7 +1411,7 @@ def get_ability_map(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/search", tags=["search"])
|
||||
@app.get("/search", tags=["search"], response_model=list[SearchResultResponse])
|
||||
def search(
|
||||
q: str = Query(
|
||||
...,
|
||||
@@ -1127,14 +1453,18 @@ def search(
|
||||
]
|
||||
|
||||
|
||||
@app.get("/abilities", tags=["search"])
|
||||
@app.get("/abilities", tags=["search"], response_model=list[AbilitySummaryResponse])
|
||||
def list_abilities(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [asdict(ability) for ability in service.list_abilities()]
|
||||
|
||||
|
||||
@app.get("/capabilities", tags=["search"])
|
||||
@app.get(
|
||||
"/capabilities",
|
||||
tags=["search"],
|
||||
response_model=list[CapabilitySummaryResponse],
|
||||
)
|
||||
def list_capabilities(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
|
||||
@@ -20,10 +20,18 @@ def test_openapi_groups_agent_facing_endpoints():
|
||||
}
|
||||
search_operation = schema["paths"]["/search"]["get"]
|
||||
assert search_operation["tags"] == ["search"]
|
||||
search_response = search_operation["responses"]["200"]["content"][
|
||||
"application/json"
|
||||
]["schema"]
|
||||
assert search_response["items"]["$ref"].endswith("/SearchResultResponse")
|
||||
assert {
|
||||
parameter["name"]: parameter["description"]
|
||||
for parameter in search_operation["parameters"]
|
||||
}["q"].startswith("Natural-language")
|
||||
ability_map_response = schema["paths"]["/repos/{repository_id}/ability-map"][
|
||||
"get"
|
||||
]["responses"]["200"]["content"]["application/json"]["schema"]
|
||||
assert ability_map_response["$ref"].endswith("/RepositoryAbilityMapResponse")
|
||||
|
||||
|
||||
def test_api_manual_registry_loop(tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user