Skip to content

Commit be5f0a0

Browse files
committed
database: Add trustpub_data columns to the trustpub_tokens and versions tables
1 parent c306296 commit be5f0a0

File tree

15 files changed

+94
-2
lines changed

15 files changed

+94
-2
lines changed

crates/crates_io_database/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ utoipa = { version = "=5.4.0", features = ["chrono"] }
3131
claims = "=0.8.0"
3232
crates_io_test_db = { path = "../crates_io_test_db" }
3333
googletest = "=0.14.2"
34-
insta = "=1.43.1"
34+
insta = { version = "=1.43.1", features = ["json"] }
3535
tokio = { version = "=1.46.0", features = ["macros", "rt"] }

crates/crates_io_database/src/models/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use self::krate::{Crate, CrateName, NewCrate, RecentCrateDownloads};
1414
pub use self::owner::{CrateOwner, Owner, OwnerKind};
1515
pub use self::team::{NewTeam, Team};
1616
pub use self::token::ApiToken;
17+
pub use self::trustpub::TrustpubData;
1718
pub use self::user::{NewUser, User};
1819
pub use self::version::{NewVersion, TopVersions, Version};
1920

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use diesel::deserialize::{self, FromSql};
2+
use diesel::pg::{Pg, PgValue};
3+
use diesel::serialize::{self, Output, ToSql};
4+
use diesel::sql_types::Jsonb;
5+
use diesel::{AsExpression, FromSqlRow};
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Data structure containing trusted publisher information extracted from JWT claims
9+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromSqlRow, AsExpression)]
10+
#[diesel(sql_type = Jsonb)]
11+
#[serde(tag = "provider")]
12+
pub enum TrustpubData {
13+
#[serde(rename = "github")]
14+
GitHub {
15+
/// Repository (e.g. "octo-org/octo-repo")
16+
repository: String,
17+
/// Workflow run ID
18+
run_id: String,
19+
/// SHA of the commit
20+
sha: String,
21+
},
22+
}
23+
24+
impl ToSql<Jsonb, Pg> for TrustpubData {
25+
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
26+
let json = serde_json::to_value(self)?;
27+
<serde_json::Value as ToSql<Jsonb, Pg>>::to_sql(&json, &mut out.reborrow())
28+
}
29+
}
30+
31+
impl FromSql<Jsonb, Pg> for TrustpubData {
32+
fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
33+
let json = <serde_json::Value as FromSql<Jsonb, Pg>>::from_sql(bytes)?;
34+
Ok(serde_json::from_value(json)?)
35+
}
36+
}
37+
38+
#[cfg(test)]
39+
mod tests {
40+
use super::*;
41+
use insta::assert_json_snapshot;
42+
43+
#[test]
44+
fn test_serialization() {
45+
let data = TrustpubData::GitHub {
46+
repository: "octo-org/octo-repo".to_string(),
47+
run_id: "example-run-id".to_string(),
48+
sha: "example-sha".to_string(),
49+
};
50+
51+
assert_json_snapshot!(data, @r#"
52+
{
53+
"provider": "github",
54+
"repository": "octo-org/octo-repo",
55+
"run_id": "example-run-id",
56+
"sha": "example-sha"
57+
}
58+
"#);
59+
}
60+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
mod data;
12
mod github_config;
23
mod token;
34
mod used_jti;
45

6+
pub use self::data::TrustpubData;
57
pub use self::github_config::{GitHubConfig, NewGitHubConfig};
68
pub use self::token::NewToken;
79
pub use self::used_jti::NewUsedJti;

crates/crates_io_database/src/models/trustpub/token.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::models::TrustpubData;
12
use crate::schema::trustpub_tokens;
23
use chrono::{DateTime, Utc};
34
use diesel::prelude::*;
@@ -9,6 +10,7 @@ pub struct NewToken<'a> {
910
pub expires_at: DateTime<Utc>,
1011
pub hashed_token: &'a [u8],
1112
pub crate_ids: &'a [i32],
13+
pub trustpub_data: Option<&'a TrustpubData>,
1214
}
1315

1416
impl NewToken<'_> {

crates/crates_io_database/src/models/version.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use diesel::prelude::*;
77
use diesel_async::{AsyncPgConnection, RunQueryDsl};
88
use serde::Deserialize;
99

10-
use crate::models::{Crate, User};
10+
use crate::models::{Crate, TrustpubData, User};
1111
use crate::schema::{readme_renderings, users, versions};
1212

1313
// Queryable has a custom implementation below
@@ -36,6 +36,7 @@ pub struct Version {
3636
pub homepage: Option<String>,
3737
pub documentation: Option<String>,
3838
pub repository: Option<String>,
39+
pub trustpub_data: Option<TrustpubData>,
3940
}
4041

4142
impl Version {
@@ -103,6 +104,7 @@ pub struct NewVersion<'a> {
103104
repository: Option<&'a str>,
104105
categories: Option<&'a [&'a str]>,
105106
keywords: Option<&'a [&'a str]>,
107+
trustpub_data: Option<&'a TrustpubData>,
106108
}
107109

108110
impl NewVersion<'_> {

crates/crates_io_database/src/schema.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,8 @@ diesel::table! {
800800
hashed_token -> Bytea,
801801
/// Unique identifiers of the crates that can be published using this token
802802
crate_ids -> Array<Nullable<Int4>>,
803+
/// JSONB data containing JWT claims from the trusted publisher (e.g., GitHub Actions context like repository, run_id, sha)
804+
trustpub_data -> Nullable<Jsonb>,
803805
}
804806
}
805807

@@ -1077,6 +1079,8 @@ diesel::table! {
10771079
keywords -> Array<Nullable<Text>>,
10781080
/// JSONB representation of the version number for sorting purposes.
10791081
semver_ord -> Nullable<Jsonb>,
1082+
/// JSONB data containing JWT claims from the trusted publisher (e.g., GitHub Actions context like repository, run_id, sha)
1083+
trustpub_data -> Nullable<Jsonb>,
10801084
}
10811085
}
10821086

crates/crates_io_database_dump/src/dump-db.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ created_at = "private"
206206
expires_at = "private"
207207
hashed_token = "private"
208208
crate_ids = "private"
209+
trustpub_data = "private"
209210

210211
[trustpub_used_jtis.columns]
211212
id = "private"
@@ -280,6 +281,8 @@ documentation = "public"
280281
repository = "public"
281282
categories = "public"
282283
keywords = "public"
284+
# The following column is private for now, until we can guarantee a stable data schema.
285+
trustpub_data = "private"
283286

284287
[versions_published_by.columns]
285288
version_id = "private"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- Remove trustpub_data column from versions table
2+
ALTER TABLE versions DROP COLUMN trustpub_data;
3+
4+
-- Remove trustpub_data column from trustpub_tokens table
5+
ALTER TABLE trustpub_tokens DROP COLUMN trustpub_data;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Add trustpub_data column to trustpub_tokens table
2+
ALTER TABLE trustpub_tokens ADD COLUMN trustpub_data JSONB;
3+
COMMENT ON COLUMN trustpub_tokens.trustpub_data IS 'JSONB data containing JWT claims from the trusted publisher (e.g., GitHub Actions context like repository, run_id, sha)';
4+
5+
-- Add trustpub_data column to versions table
6+
ALTER TABLE versions ADD COLUMN trustpub_data JSONB;
7+
COMMENT ON COLUMN versions.trustpub_data IS 'JSONB data containing JWT claims from the trusted publisher (e.g., GitHub Actions context like repository, run_id, sha)';

0 commit comments

Comments
 (0)