From 79b4a31f1a00016427fad837e28eff7a1e1b3f91 Mon Sep 17 00:00:00 2001 From: Sara Date: Fri, 12 Jun 2026 17:43:40 -0400 Subject: [PATCH] Document snippets and bump to 0.2.0 for release Adds the snippet surface to user- and contributor-facing docs ahead of the 0.2.0 release that ships snippet support: - README: new Snippets CLI section (list snippets/snippet-paths/ snippet-locations, get snippet/snippet-match), MCP tools table updated (snippet on `list`, the `snippet_match` tool, no get/update), and the Snippet locator form - CLAUDE.md: ERD (Revision->Snippet->SnippetMatch), architecture tree, the four snippet endpoints, the Snippet model entry with its API quirks, and Future Work (reject/unreject + cross-revision compare) - Bump version 0.1.0 -> 0.2.0 (Cargo.toml + Cargo.lock) Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 31 ++++++++++++++++++++++++++++++- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 39 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f1942b1..a1e8496 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,7 +38,9 @@ erDiagram Project ||--o{ Revision : "has many" Project ||--o{ Issue : "has many" Revision ||--o{ Dependency : "contains" + Revision ||--o{ Snippet : "matched in" Dependency ||--o{ Issue : "flagged by" + Snippet ||--o{ SnippetMatch : "matched at" Project { String id "locator: custom+org/project" @@ -73,6 +75,22 @@ erDiagram String cve "CVE identifier (vulns only)" DateTime created_at } + + Snippet { + String id PK "numeric string, e.g. 1295019" + String locator "matched OSS package: pod+Alamofire$5.11.0" + String purl "pkg:cocoapods/Alamofire@5.11.0" + SnippetKind kind "whole-file or partial match" + f64 highest_match_percentage "0.0-1.0" + u32 match_count "first-party files matched" + } + + SnippetMatch { + String path "first-party file path" + f64 match_percentage "0-100 in matchDetails, 0-1 elsewhere" + Vec_Line detected_code "first-party lines + numbers" + Vec_Line reference_code "open-source lines + numbers" + } ``` ## Architecture @@ -82,7 +100,11 @@ Project (top-level container) ├── latest_revision: LatestRevision │ └── locator → can fetch full Revision ├── revisions() → Vec -│ └── revision.dependencies() → Vec +│ ├── revision.dependencies() → Vec +│ └── get_snippets(revision) → Vec (snippet-scan OSS matches) +│ ├── get_snippet_details(snippet) → matched first-party files +│ ├── get_snippet_match(snippet, path) → side-by-side detected vs reference code +│ └── get_snippet_locations(revision) → flat (snippet, file) report (+ line ranges) └── get_project_issues() → Vec └── Issues across all revisions/dependencies ``` @@ -97,6 +119,10 @@ Project (top-level container) | Dependencies | `GET /v2/revisions/{locator}/dependencies` | For a revision | | Issues | `GET /v2/issues` | Paginated, filterable by category/project | | Issue | `GET /v2/issues/{id}` | Single issue with full details | +| Snippets | `GET /revisions/{locator}/snippets` | Paginated; `pageSize` capped at 50 (`list_all` overrides) | +| Snippet paths | `GET /revisions/{locator}/snippets/paths` | File/dir tree, drill in via `path` | +| Snippet details | `GET /revisions/{locator}/snippets/{id}` | Single snippet + its per-file matches | +| Snippet match | `GET /revisions/{locator}/snippets/{id}/matches/{path}` | Side-by-side detected vs reference code | ## Traits @@ -112,6 +138,7 @@ Project (top-level container) - **Revision** - Snapshot at point in time, implements Get/List - **Dependency** - Package dependency, implements List only (via revision) - **Issue** - Vulnerability/licensing/quality issue, implements Get/List +- **Snippet** - Third-party (OSS) code matched into first-party files, implements List only (via revision). Read-only; reached through the `get_snippet_*` convenience functions. Quirks: `id` is a string, `matchDetails.matchPercentage` is 0-100 (other percentages are 0-1), and whole-file matches highlight a trailing blank EOF line that is excluded from the reported range. - **LicenseInfo** - Can be simple string ("MIT") or full object ## Issue Categories @@ -127,6 +154,8 @@ Issues come in three categories with different fields: ## Future Work - **IssueScan** - Issue scans tied to revisions (not yet implemented) +- **Snippet reject/unreject** - Mutating a snippet's rejection status (out of scope for v1) +- **Cross-revision snippet compare** - Diffing snippet matches across revisions (out of scope for v1) ## Nudge diff --git a/Cargo.lock b/Cargo.lock index df57ffc..043da18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -526,7 +526,7 @@ dependencies = [ [[package]] name = "fossapi" -version = "0.1.0" +version = "0.2.0" dependencies = [ "async-trait", "axum", diff --git a/Cargo.toml b/Cargo.toml index 097eaeb..35c793e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fossapi" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Rust client library for the FOSSA REST API" license = "MIT" diff --git a/README.md b/README.md index 8454619..ddc6134 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,36 @@ fossapi list issues --category licensing fossapi get issue 12345 ``` +### Snippets + +Snippet scanning finds third-party (open-source) code copied into your +first-party files. Each **snippet** is a matched OSS package; its **matches** +are the first-party files where that code was found. The snippet surface is +read-only and scoped to a single revision. + +```bash +# List snippets (matched OSS packages) in a revision +fossapi list snippets "custom+1/my-project\$abc123" + +# Restrict to a file/directory subtree (defaults to the repo root) +fossapi list snippets "custom+1/my-project\$abc123" --path /src + +# Show the file/directory tree where snippets were detected +fossapi list snippet-paths "custom+1/my-project\$abc123" + +# Flat report: every match location (first-party file -> matched package) +fossapi list snippet-locations "custom+1/my-project\$abc123" + +# ...and resolve the first-party line range for each match (extra API calls) +fossapi list snippet-locations "custom+1/my-project\$abc123" --with-lines + +# Get a snippet's details, including its matched first-party files +fossapi get snippet "custom+1/my-project\$abc123" + +# Side-by-side match details (detected vs reference code) at a matched path +fossapi get snippet-match "custom+1/my-project\$abc123" src/foo.rs +``` + ### Output Formats ```bash @@ -121,8 +151,14 @@ Add to your MCP config: | Tool | Description | |------|-------------| | `get` | Fetch a single project, revision, or issue by ID | -| `list` | List projects, revisions, dependencies, or issues | +| `list` | List projects, revisions, dependencies, issues, or snippet match locations | | `update` | Update project metadata (title, description, url, public) | +| `snippet_match` | Drill into one snippet match: the matched first-party and reference code | + +> **Snippets over MCP:** use `list` with `entity: snippet` and `parent: locator>` (optional `path` and `with_lines`) to map third-party matches to +> first-party files, then `snippet_match` to drill into a single match. Snippets +> don't support `get` or `update`. ## Locators @@ -131,3 +167,4 @@ FOSSA uses locators to identify entities: - **Project**: `custom+{org_id}/{project_name}` - **Revision**: `custom+{org_id}/{project_name}${revision_ref}` - **Dependency**: `{fetcher}+{package}${version}` (e.g., `npm+lodash$4.17.21`) +- **Snippet**: identified by its parent revision locator plus a snippet ID (a string)