From d18b21fc3f0636a3a510cfe969184b6c3bf45038 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 5 Mar 2024 18:06:19 +0530 Subject: [PATCH] feat: use provenance in JSR score (#163) Closes https://github.com/jsr-io/jsr/issues/84 --------- Co-authored-by: Luca Casonato --- ...110c9cb56ff45bc6a9f1bc068e06536d291bd68.json | 17 +++++++++++++++++ ...5d6f99a87bf8fa0776b2ae6271bb7cfce246f91.json | 17 ----------------- api/src/analysis.rs | 1 + api/src/api/package.rs | 10 ++++++++++ api/src/api/types.rs | 8 +++++++- api/src/db/database.rs | 2 +- api/src/db/models.rs | 1 + frontend/docs/scoring.md | 7 ++++++- frontend/routes/package/score.tsx | 11 +++++++++++ frontend/utils/api_types.ts | 1 + 10 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 api/.sqlx/query-0f0d573741aa1a7b32d8a2b4a110c9cb56ff45bc6a9f1bc068e06536d291bd68.json delete mode 100644 api/.sqlx/query-3beb0c1d37cb338fafe35c6b55d6f99a87bf8fa0776b2ae6271bb7cfce246f91.json diff --git a/api/.sqlx/query-0f0d573741aa1a7b32d8a2b4a110c9cb56ff45bc6a9f1bc068e06536d291bd68.json b/api/.sqlx/query-0f0d573741aa1a7b32d8a2b4a110c9cb56ff45bc6a9f1bc068e06536d291bd68.json new file mode 100644 index 00000000..ff0450b6 --- /dev/null +++ b/api/.sqlx/query-0f0d573741aa1a7b32d8a2b4a110c9cb56ff45bc6a9f1bc068e06536d291bd68.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE package_versions\n SET rekor_log_id = $1, meta = jsonb_set_lax(meta, '{hasProvenance}', 'true'::jsonb, true)\n WHERE scope = $2 AND name = $3 AND version = $4 AND rekor_log_id IS NULL AND created_at > now() - '2 minute'::interval", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "0f0d573741aa1a7b32d8a2b4a110c9cb56ff45bc6a9f1bc068e06536d291bd68" +} diff --git a/api/.sqlx/query-3beb0c1d37cb338fafe35c6b55d6f99a87bf8fa0776b2ae6271bb7cfce246f91.json b/api/.sqlx/query-3beb0c1d37cb338fafe35c6b55d6f99a87bf8fa0776b2ae6271bb7cfce246f91.json deleted file mode 100644 index 44bfc2a1..00000000 --- a/api/.sqlx/query-3beb0c1d37cb338fafe35c6b55d6f99a87bf8fa0776b2ae6271bb7cfce246f91.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE package_versions\n SET rekor_log_id = $1\n WHERE scope = $2 AND name = $3 AND version = $4 AND rekor_log_id IS NULL AND created_at > now() - '2 minute'::interval", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Text", - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3beb0c1d37cb338fafe35c6b55d6f99a87bf8fa0776b2ae6271bb7cfce246f91" -} diff --git a/api/src/analysis.rs b/api/src/analysis.rs index 1800c224..fb273655 100644 --- a/api/src/analysis.rs +++ b/api/src/analysis.rs @@ -302,6 +302,7 @@ fn generate_score( doc_nodes_by_url, ), all_fast_check, + has_provenance: false, // Provenance score is updated after version publish } } diff --git a/api/src/api/package.rs b/api/src/api/package.rs index a888a88f..e1860d45 100644 --- a/api/src/api/package.rs +++ b/api/src/api/package.rs @@ -1365,6 +1365,7 @@ mod test { use crate::api::ApiList; use crate::api::ApiMetrics; use crate::api::ApiPackage; + use crate::api::ApiPackageScore; use crate::api::ApiPackageVersion; use crate::api::ApiPackageVersionDocs; use crate::api::ApiPackageVersionSource; @@ -1876,6 +1877,15 @@ ggHohNAjhbzDaY2iBW/m3NC5dehGUP4T2GBo/cwGhg== .unwrap(); resp.expect_ok_no_content().await; + let mut resp = t + .http() + .get("/api/scopes/scope/packages/foo/score") + .call() + .await + .unwrap(); + let score: ApiPackageScore = resp.expect_ok().await; + assert!(score.has_provenance); + // Invalid subject. update_bundle_subject( &mut bundle, diff --git a/api/src/api/types.rs b/api/src/api/types.rs index 2d061ec1..93289625 100644 --- a/api/src/api/types.rs +++ b/api/src/api/types.rs @@ -331,6 +331,7 @@ pub struct ApiPackageScore { pub all_entrypoints_docs: bool, pub percentage_documented_symbols: f32, pub all_fast_check: bool, + pub has_provenance: bool, // package wide pub has_description: bool, @@ -344,7 +345,7 @@ impl ApiPackageScore { pub const MAX_SCORE: u32 = 17; pub fn score_percentage(&self) -> u32 { - (self.total * 100) / Self::MAX_SCORE + u32::min((self.total * 100) / Self::MAX_SCORE, 100) } } @@ -364,6 +365,10 @@ impl From<(&PackageVersionMeta, &Package)> for ApiPackageScore { score += 1; } + if meta.has_provenance { + score += 1; + } + // You only need to document 80% of your symbols to get all the points. score += ((meta.percentage_documented_symbols / 0.8).min(1.0) * 5.0).floor() as u32; @@ -409,6 +414,7 @@ impl From<(&PackageVersionMeta, &Package)> for ApiPackageScore { all_entrypoints_docs: meta.all_entrypoints_docs, percentage_documented_symbols: meta.percentage_documented_symbols, all_fast_check: meta.all_fast_check, + has_provenance: meta.has_provenance, has_description: !package.description.is_empty(), at_least_one_runtime_compatible: compatible_runtimes_count >= 1, multiple_runtimes_compatible: compatible_runtimes_count >= 2, diff --git a/api/src/db/database.rs b/api/src/db/database.rs index 6a801f27..67480f54 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -335,7 +335,7 @@ impl Database { ) -> Result<()> { sqlx::query!( r#"UPDATE package_versions - SET rekor_log_id = $1 + SET rekor_log_id = $1, meta = jsonb_set_lax(meta, '{hasProvenance}', 'true'::jsonb, true) WHERE scope = $2 AND name = $3 AND version = $4 AND rekor_log_id IS NULL AND created_at > now() - '2 minute'::interval"#, rekor_log_id, package_scope as _, diff --git a/api/src/db/models.rs b/api/src/db/models.rs index 292dceda..adb4bdfd 100644 --- a/api/src/db/models.rs +++ b/api/src/db/models.rs @@ -243,6 +243,7 @@ pub struct PackageVersionMeta { pub all_entrypoints_docs: bool, pub percentage_documented_symbols: f32, pub all_fast_check: bool, + pub has_provenance: bool, } impl sqlx::Decode<'_, sqlx::Postgres> for PackageVersionMeta { diff --git a/frontend/docs/scoring.md b/frontend/docs/scoring.md index c69dc096..b96ce9c5 100644 --- a/frontend/docs/scoring.md +++ b/frontend/docs/scoring.md @@ -14,7 +14,8 @@ factors from 4 high level categories: documentation for public functions and types. [Learn more about writing documentation](/docs/writing-docs). - **Best practices**: Packages should not use - [slow types](/docs/about-slow-types). + [slow types](/docs/about-slow-types), and should be published with + [package provenance](/docs/trust). - **Discoverability**: The package should have a description to help users find packages via search. - **Compatibility**: The package should have at least one runtime marked as @@ -25,3 +26,7 @@ factors from 4 high level categories: Each of these categories has different specific factors that contribute to the score. Each of these factors is weighted differently. You can find the exact factors and weights in the "Score" tab of the package page. + +Currently you do not need to complete all factors to get a 100% score. The exact +wheights and factors are subject to change as we learn more about what makes a +good package. diff --git a/frontend/routes/package/score.tsx b/frontend/routes/package/score.tsx index 16436c96..af8a880c 100644 --- a/frontend/routes/package/score.tsx +++ b/frontend/routes/package/score.tsx @@ -164,6 +164,17 @@ export default function Score( This package is compatible with more than one runtime, and is marked as such in the package settings. + + This package is published from a verifiable CI/CD workflow, and has + a{" "} + + public transparency log entry + . + diff --git a/frontend/utils/api_types.ts b/frontend/utils/api_types.ts index dd3d550e..cdbe5973 100644 --- a/frontend/utils/api_types.ts +++ b/frontend/utils/api_types.ts @@ -95,6 +95,7 @@ export interface PackageScore { allEntrypointsDocs: boolean; percentageDocumentedSymbols: number; allFastCheck: boolean; + hasProvenance: boolean; // package specific hasDescription: boolean;