Skip to content

Commit 0652be7

Browse files
refactor(evaluation): rename concepts (#11)
* refactor(evaluation): rename concepts * refactor(evaluation): fix ci
1 parent baf0ade commit 0652be7

File tree

6 files changed

+122
-72
lines changed

6 files changed

+122
-72
lines changed

.github/workflows/ci-rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040

4141
security:
4242
needs: [lint, tests]
43-
runs-on: warp-ubuntu-2404-x64-4x
43+
runs-on: warp-ubuntu-2404-x64-8x
4444

4545
steps:
4646
- name: Project checkout

crates/pollux/src/core.rs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 Dotanuki Labs
22
// SPDX-License-Identifier: MIT
33

4-
use crate::infra::{ReproducibleBuildsEvaluator, TrustedPublishingEvaluator};
4+
use crate::infra::{CrateBuildReproducibilityEvaluator, CrateProvenanceEvaluator};
55
use std::fmt::Display;
66

77
#[derive(Debug, PartialEq)]
@@ -14,6 +14,14 @@ impl CrateInfo {
1414
pub fn new(name: String, version: String) -> Self {
1515
Self { name, version }
1616
}
17+
18+
#[cfg(test)]
19+
pub fn with(name: &str, version: &str) -> Self {
20+
Self {
21+
name: name.to_string(),
22+
version: version.to_string(),
23+
}
24+
}
1725
}
1826

1927
impl Display for CrateInfo {
@@ -24,52 +32,60 @@ impl Display for CrateInfo {
2432

2533
#[allow(dead_code)]
2634
#[derive(Debug, PartialEq)]
27-
pub enum VerificationKind {
28-
ReproducedBuild,
29-
UsesTrustedPublishing,
35+
pub enum VeracityFactor {
36+
ReproducibleBuilds,
37+
ProvenanceAttested,
3038
}
3139

3240
#[allow(dead_code)]
3341
#[derive(Debug, PartialEq)]
34-
pub enum TruthfulnessVerification {
42+
pub enum CrateVeracityLevel {
3543
NotAvailable,
36-
Partial(VerificationKind),
37-
Total,
44+
SingleFactor(VeracityFactor),
45+
TwoFactors,
3846
}
3947

4048
#[allow(dead_code)]
41-
pub trait TruthfulnessEvaluation {
49+
pub trait VeracityEvaluation {
4250
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool>;
4351
}
4452

45-
pub struct TruthfulnessEvaluator {
46-
trusted_publishing_evaluator: TrustedPublishingEvaluator,
47-
reproducible_builds_evaluator: ReproducibleBuildsEvaluator,
53+
pub struct CrateVeracityEvaluator {
54+
provenance: CrateProvenanceEvaluator,
55+
reproducibility: CrateBuildReproducibilityEvaluator,
4856
}
4957

50-
#[allow(dead_code)]
51-
impl TruthfulnessEvaluator {
52-
pub fn new(
53-
trusted_publishing_evaluator: TrustedPublishingEvaluator,
54-
reproducible_builds_evaluator: ReproducibleBuildsEvaluator,
55-
) -> Self {
56-
Self {
57-
trusted_publishing_evaluator,
58-
reproducible_builds_evaluator,
59-
}
60-
}
61-
62-
pub async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<TruthfulnessVerification> {
63-
let uses_trusted_publishing = self.trusted_publishing_evaluator.evaluate(crate_info).await?;
64-
let has_reproduced_build = self.reproducible_builds_evaluator.evaluate(crate_info).await?;
58+
impl CrateVeracityEvaluator {
59+
pub async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<CrateVeracityLevel> {
60+
let uses_trusted_publishing = self.provenance.evaluate(crate_info).await?;
61+
let has_reproduced_build = self.reproducibility.evaluate(crate_info).await?;
6562

6663
let verification = match (uses_trusted_publishing, has_reproduced_build) {
67-
(true, true) => TruthfulnessVerification::Total,
68-
(false, true) => TruthfulnessVerification::Partial(VerificationKind::ReproducedBuild),
69-
(true, false) => TruthfulnessVerification::Partial(VerificationKind::UsesTrustedPublishing),
70-
(false, false) => TruthfulnessVerification::NotAvailable,
64+
(true, true) => CrateVeracityLevel::TwoFactors,
65+
(false, true) => CrateVeracityLevel::SingleFactor(VeracityFactor::ReproducibleBuilds),
66+
(true, false) => CrateVeracityLevel::SingleFactor(VeracityFactor::ProvenanceAttested),
67+
(false, false) => CrateVeracityLevel::NotAvailable,
7168
};
7269

7370
Ok(verification)
7471
}
72+
73+
fn new(provenance: CrateProvenanceEvaluator, reproducibility: CrateBuildReproducibilityEvaluator) -> Self {
74+
Self {
75+
provenance,
76+
reproducibility,
77+
}
78+
}
79+
}
80+
81+
pub mod factory {
82+
use crate::core::CrateVeracityEvaluator;
83+
use crate::infra::{CrateBuildReproducibilityEvaluator, CrateProvenanceEvaluator};
84+
85+
pub fn create_veracity_evaluator(
86+
provenance_factory: fn() -> CrateProvenanceEvaluator,
87+
reproducibility_factory: fn() -> CrateBuildReproducibilityEvaluator,
88+
) -> CrateVeracityEvaluator {
89+
CrateVeracityEvaluator::new(provenance_factory(), reproducibility_factory())
90+
}
7591
}

crates/pollux/src/infra.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,52 @@
44
pub mod cratesio;
55
mod ossrebuild;
66

7-
use crate::core::{CrateInfo, TruthfulnessEvaluation};
7+
use crate::core::{CrateInfo, VeracityEvaluation};
88
use crate::infra::cratesio::CratesIOEvaluator;
99
use crate::infra::ossrebuild::OssRebuildEvaluator;
1010
use reqwest::Client;
1111

1212
pub type HTTPClient = Client;
1313

1414
#[allow(dead_code)]
15-
pub enum TrustedPublishingEvaluator {
16-
FromCratesIO(CratesIOEvaluator),
15+
pub enum CrateProvenanceEvaluator {
16+
CratesOfficialRegistry(CratesIOEvaluator),
1717
#[cfg(test)]
18-
Fake(FakeTruthfulnessEvaluator),
18+
FakeRegistry(FakeTruthfulnessEvaluator),
1919
}
2020

21-
impl TruthfulnessEvaluation for TrustedPublishingEvaluator {
21+
impl VeracityEvaluation for CrateProvenanceEvaluator {
2222
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool> {
2323
match self {
24-
TrustedPublishingEvaluator::FromCratesIO(evaluator) => evaluator.evaluate(crate_info).await,
24+
CrateProvenanceEvaluator::CratesOfficialRegistry(evaluator) => evaluator.evaluate(crate_info).await,
2525
#[cfg(test)]
26-
TrustedPublishingEvaluator::Fake(evaluator) => evaluator.evaluate(crate_info).await,
26+
CrateProvenanceEvaluator::FakeRegistry(evaluator) => evaluator.evaluate(crate_info).await,
2727
}
2828
}
2929
}
3030

3131
#[allow(dead_code)]
32-
pub enum ReproducibleBuildsEvaluator {
33-
FromOssRebuild(OssRebuildEvaluator),
32+
pub enum CrateBuildReproducibilityEvaluator {
33+
GoogleOssRebuild(OssRebuildEvaluator),
3434
#[cfg(test)]
35-
Fake(Vec<CrateInfo>),
35+
FakeRebuilder(Vec<CrateInfo>),
3636
}
3737

3838
#[allow(unused_variables)]
39-
impl TruthfulnessEvaluation for ReproducibleBuildsEvaluator {
39+
impl VeracityEvaluation for CrateBuildReproducibilityEvaluator {
4040
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool> {
4141
match self {
42-
ReproducibleBuildsEvaluator::FromOssRebuild(delegate) => delegate.evaluate(crate_info).await,
42+
CrateBuildReproducibilityEvaluator::GoogleOssRebuild(delegate) => delegate.evaluate(crate_info).await,
4343
#[cfg(test)]
44-
ReproducibleBuildsEvaluator::Fake(crates) => Ok(crates.contains(crate_info)),
44+
CrateBuildReproducibilityEvaluator::FakeRebuilder(crates) => Ok(crates.contains(crate_info)),
4545
}
4646
}
4747
}
4848

4949
pub mod factories {
5050
use crate::infra::cratesio::CratesIOEvaluator;
5151
use crate::infra::ossrebuild::OssRebuildEvaluator;
52-
use crate::infra::{HTTPClient, ReproducibleBuildsEvaluator, TrustedPublishingEvaluator};
52+
use crate::infra::{CrateBuildReproducibilityEvaluator, CrateProvenanceEvaluator, HTTPClient};
5353
use reqwest::header;
5454
use std::sync::{Arc, LazyLock};
5555

@@ -66,22 +66,22 @@ pub mod factories {
6666
static CRATES_IO_API: &str = "https://crates.io";
6767
static OSS_REBUILD_CRATES_IO_URL: &str = "https://storage.googleapis.com/google-rebuild-attestations/cratesio";
6868

69-
pub fn trusted_publishing_evaluator() -> TrustedPublishingEvaluator {
69+
pub fn provenance_evaluator() -> CrateProvenanceEvaluator {
7070
let delegate = CratesIOEvaluator::new(CRATES_IO_API.to_string(), HTTP_CLIENT.clone());
71-
TrustedPublishingEvaluator::FromCratesIO(delegate)
71+
CrateProvenanceEvaluator::CratesOfficialRegistry(delegate)
7272
}
7373

74-
pub fn reproducible_builds_evaluator() -> ReproducibleBuildsEvaluator {
74+
pub fn reproducibility_evaluator() -> CrateBuildReproducibilityEvaluator {
7575
let delegate = OssRebuildEvaluator::new(OSS_REBUILD_CRATES_IO_URL.to_string(), HTTP_CLIENT.clone());
76-
ReproducibleBuildsEvaluator::FromOssRebuild(delegate)
76+
CrateBuildReproducibilityEvaluator::GoogleOssRebuild(delegate)
7777
}
7878
}
7979

8080
#[cfg(test)]
8181
pub struct FakeTruthfulnessEvaluator(Vec<CrateInfo>);
8282

8383
#[cfg(test)]
84-
impl TruthfulnessEvaluation for FakeTruthfulnessEvaluator {
84+
impl VeracityEvaluation for FakeTruthfulnessEvaluator {
8585
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool> {
8686
Ok(self.0.contains(crate_info))
8787
}

crates/pollux/src/infra/cratesio.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 Dotanuki Labs
22
// SPDX-License-Identifier: MIT
33

4-
use crate::core::{CrateInfo, TruthfulnessEvaluation};
4+
use crate::core::{CrateInfo, VeracityEvaluation};
55
use crate::infra::HTTPClient;
66
use serde::Deserialize;
77
use std::fmt::Display;
@@ -44,7 +44,7 @@ impl CratesIOEvaluator {
4444
}
4545
}
4646

47-
impl TruthfulnessEvaluation for CratesIOEvaluator {
47+
impl VeracityEvaluation for CratesIOEvaluator {
4848
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool> {
4949
let endpoint = format!(
5050
"{}/api/v1/crates/{}/{}",
@@ -72,10 +72,10 @@ impl TruthfulnessEvaluation for CratesIOEvaluator {
7272

7373
#[cfg(test)]
7474
mod tests {
75-
use crate::core::{CrateInfo, TruthfulnessEvaluation};
75+
use crate::core::{CrateInfo, VeracityEvaluation};
7676
use crate::infra::cratesio::CratesIOEvaluator;
7777
use crate::infra::factories;
78-
use assertor::BooleanAssertion;
78+
use assertor::{BooleanAssertion, ResultAssertion};
7979
use httpmock::{MockServer, Then, When};
8080

8181
fn responds_with_existing_provenance(crate_name: &str, crate_version: &str) -> impl FnOnce(When, Then) {
@@ -135,15 +135,28 @@ mod tests {
135135
}
136136
}
137137

138+
fn responds_without_server_error(crate_name: &str, crate_version: &str) -> impl FnOnce(When, Then) {
139+
move |when, then| {
140+
when.method("GET")
141+
.path(format!("/api/v1/crates/{}/{}", crate_name, crate_version));
142+
143+
then.status(503)
144+
.header("content-type", "application/text; charset=UTF-8")
145+
.body("internal error");
146+
}
147+
}
148+
138149
#[tokio::test]
139-
async fn should_evaluate_provenance_when_available() {
150+
async fn should_evaluate_crate_provenance_when_available() {
151+
let crate_name = "bon";
152+
let crate_version = "3.7.2";
153+
let crate_info = CrateInfo::with(crate_name, crate_version);
154+
140155
let mock_server = MockServer::start();
141156
let evaluator = CratesIOEvaluator::new(mock_server.base_url(), factories::HTTP_CLIENT.clone());
142157

143-
let response_with_provenance = responds_with_existing_provenance("bon", "3.7.2");
144-
145-
let mocked = mock_server.mock(response_with_provenance);
146-
let crate_info = CrateInfo::new("bon".to_string(), "3.7.2".to_string());
158+
let with_provenance = responds_with_existing_provenance(crate_name, crate_version);
159+
let mocked = mock_server.mock(with_provenance);
147160

148161
let evaluation = evaluator.evaluate(&crate_info).await.unwrap();
149162

@@ -152,19 +165,39 @@ mod tests {
152165
}
153166

154167
#[tokio::test]
155-
async fn should_evaluate_provenance_when_not_available() {
168+
async fn should_evaluate_crate_provenance_when_not_available() {
169+
let crate_name = "canopus";
170+
let crate_version = "0.1.1";
171+
let crate_info = CrateInfo::with(crate_name, crate_version);
172+
156173
let mock_server = MockServer::start();
157174
let evaluator = CratesIOEvaluator::new(mock_server.base_url(), factories::HTTP_CLIENT.clone());
158175

159-
let response_without_provenance = responds_without_provenance("canopus", "0.1.1");
160-
161-
let mocked = mock_server.mock(response_without_provenance);
176+
let without_provenance = responds_without_provenance(crate_name, crate_version);
162177

163-
let crate_info = CrateInfo::new("canopus".to_string(), "0.1.1".to_string());
178+
let mocked = mock_server.mock(without_provenance);
164179

165180
let evaluation = evaluator.evaluate(&crate_info).await.unwrap();
166181

167182
mocked.assert();
168183
assertor::assert_that!(evaluation).is_false()
169184
}
185+
186+
#[tokio::test]
187+
async fn should_evaluate_provenance_when_server_not_available() {
188+
let crate_name = "canopus";
189+
let crate_version = "0.0.1";
190+
let crate_info = CrateInfo::with(crate_name, crate_version);
191+
192+
let mock_server = MockServer::start();
193+
let evaluator = CratesIOEvaluator::new(mock_server.base_url(), factories::HTTP_CLIENT.clone());
194+
195+
let not_found = responds_without_server_error(crate_name, crate_version);
196+
let mocked = mock_server.mock(not_found);
197+
198+
let evaluation = evaluator.evaluate(&crate_info).await;
199+
200+
mocked.assert();
201+
assertor::assert_that!(evaluation).is_err()
202+
}
170203
}

crates/pollux/src/infra/ossrebuild.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 Dotanuki Labs
22
// SPDX-License-Identifier: MIT
33

4-
use crate::core::{CrateInfo, TruthfulnessEvaluation};
4+
use crate::core::{CrateInfo, VeracityEvaluation};
55
use crate::infra::HTTPClient;
66
use anyhow::bail;
77
use reqwest::StatusCode;
@@ -18,7 +18,7 @@ impl OssRebuildEvaluator {
1818
}
1919
}
2020

21-
impl TruthfulnessEvaluation for OssRebuildEvaluator {
21+
impl VeracityEvaluation for OssRebuildEvaluator {
2222
async fn evaluate(&self, crate_info: &CrateInfo) -> anyhow::Result<bool> {
2323
let endpoint = format!(
2424
"{}/{}/{}/{}-{}.crate/rebuild.intoto.jsonl",
@@ -46,7 +46,7 @@ impl TruthfulnessEvaluation for OssRebuildEvaluator {
4646

4747
#[cfg(test)]
4848
mod tests {
49-
use crate::core::{CrateInfo, TruthfulnessEvaluation};
49+
use crate::core::{CrateInfo, VeracityEvaluation};
5050
use crate::infra::factories;
5151
use crate::infra::ossrebuild::OssRebuildEvaluator;
5252
use assertor::{BooleanAssertion, ResultAssertion};

crates/pollux/src/main.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
mod core;
55
mod infra;
66

7-
use crate::core::{CrateInfo, TruthfulnessEvaluator};
7+
use crate::core::CrateInfo;
88
use clap::Parser;
99
use console::style;
1010
use tikv_jemallocator::Jemalloc;
@@ -34,14 +34,15 @@ async fn main() {
3434

3535
let arguments = ProgramArguments::parse();
3636

37-
let trusted_publishing_evaluator = infra::factories::trusted_publishing_evaluator();
38-
let reproducible_builds_evaluator = infra::factories::reproducible_builds_evaluator();
39-
let evaluator = TruthfulnessEvaluator::new(trusted_publishing_evaluator, reproducible_builds_evaluator);
37+
let veracity_evaluator = core::factory::create_veracity_evaluator(
38+
infra::factories::provenance_evaluator,
39+
infra::factories::reproducibility_evaluator,
40+
);
4041

4142
let parts = arguments.name.split("@").collect::<Vec<_>>();
4243
let crates_info = CrateInfo::new(parts[0].to_string(), parts[1].to_string());
4344

44-
let evaluation = evaluator.evaluate(&crates_info).await.unwrap();
45+
let evaluation = veracity_evaluator.evaluate(&crates_info).await.unwrap();
4546

4647
println!("For {} : truthfulness = {:?} ", crates_info, style(evaluation).cyan());
4748
}

0 commit comments

Comments
 (0)