Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ workspace = true

[features]
default = ["cli"]
cli = ["dep:gix", "dep:gix-traverse", "dep:ureq", "dep:clap", "dep:clap_complete", "dep:colored", "dep:hmac"]
cli = ["dep:gix", "dep:gix-traverse", "dep:ureq", "dep:clap", "dep:clap_complete", "dep:colored", "dep:hmac", "dep:mimalloc"]

[dependencies]
serde = { version = "1", features = ["derive"] }
Expand All @@ -57,6 +57,10 @@ ureq = { version = "3", features = ["json"], optional = true }
sha2 = "0.11.0"
hex = "0.4.3"
hmac = { version = "0.13", optional = true }
# mimalloc: faster allocator for the CLI hot paths (TagIndex::build,
# revwalk, regex captures). Typical 5-15% wall-time win on alloc-heavy
# workloads — see #507. CLI-only (no value for the wasm build).
mimalloc = { version = "0.1", default-features = false, optional = true }
# tempfile is used at runtime by the TS config loader to drop the
# generated wrapper script in a directory we own (security: writing into
# the user's config directory is a symlink TOCTOU). Tests also use it.
Expand Down
13 changes: 12 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,18 @@ exceptions = []
multiple-versions = "warn"
wildcards = "deny"
allow-wildcard-paths = true
deny = []
deny = [
# We migrated off libgit2 in #487. Reintroducing git2 / libgit2-sys
# silently re-adds ~3 MB to the release binary plus libgit2's CVE
# surface. Keep them banned.
{ crate = "git2", reason = "Use gix (gitoxide) — see #487." },
{ crate = "libgit2-sys", reason = "Pulled in only via git2 which is banned." },
# OpenSSL was vendored via the libgit2 chain. The gix migration
# removed it; if someone reintroduces it the binary jumps from
# ~5 MB to ~9 MB and we inherit OpenSSL's CVE cadence. Use rustls.
{ crate = "openssl-sys", reason = "Use rustls (via gix / ureq) instead." },
{ crate = "openssl-src", reason = "Vendoring OpenSSL bloats the binary." },
]
skip = []
skip-tree = []

Expand Down
31 changes: 23 additions & 8 deletions src/forge/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct GitHubForge {
pub token: String,
pub slug: String,
pub api_base: String,
pub agent: ureq::Agent,
}

impl Forge for GitHubForge {
Expand All @@ -31,7 +32,8 @@ impl Forge for GitHubForge {
payload["target_commitish"] = serde_json::Value::String(sha.to_string());
}

ureq::post(&url)
self.agent
.post(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
Expand All @@ -46,7 +48,9 @@ impl Forge for GitHubForge {
fn find_draft_release(&self, tag: &str) -> Result<Option<u64>> {
let url = format!("{}/repos/{}/releases", self.api_base, self.slug);

let response: serde_json::Value = ureq::get(&url)
let response: serde_json::Value = self
.agent
.get(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
Expand Down Expand Up @@ -83,7 +87,8 @@ impl Forge for GitHubForge {
"draft": false,
});

ureq::patch(&url)
self.agent
.patch(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
Expand Down Expand Up @@ -111,7 +116,9 @@ impl Forge for GitHubForge {
"base": base,
});

let response: serde_json::Value = ureq::post(&url)
let response: serde_json::Value = self
.agent
.post(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("X-GitHub-Api-Version", "2022-11-28")
Expand Down Expand Up @@ -148,7 +155,9 @@ impl Forge for GitHubForge {
});

let graphql_url = format!("{}/graphql", self.api_base);
let response: serde_json::Value = ureq::post(&graphql_url)
let response: serde_json::Value = self
.agent
.post(&graphql_url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("User-Agent", "ferrflow")
.send_json(query)
Expand Down Expand Up @@ -183,7 +192,9 @@ impl Forge for GitHubForge {
"{}/repos/{}/issues/{}/comments?per_page=100",
self.api_base, self.slug, pr_id
);
let comments: Vec<serde_json::Value> = ureq::get(&url)
let comments: Vec<serde_json::Value> = self
.agent
.get(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("User-Agent", "ferrflow")
Expand All @@ -209,7 +220,8 @@ impl Forge for GitHubForge {
"{}/repos/{}/issues/{}/comments",
self.api_base, self.slug, pr_id
);
ureq::post(&url)
self.agent
.post(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("User-Agent", "ferrflow")
Expand All @@ -223,7 +235,8 @@ impl Forge for GitHubForge {
"{}/repos/{}/issues/comments/{}",
self.api_base, self.slug, comment_id
);
ureq::patch(&url)
self.agent
.patch(&url)
.header("Authorization", &format!("Bearer {}", self.token))
.header("Accept", "application/vnd.github+json")
.header("User-Agent", "ferrflow")
Expand All @@ -242,6 +255,7 @@ mod tests {
token: "test-token".to_string(),
slug: "owner/repo".to_string(),
api_base: "https://api.github.com".to_string(),
agent: ureq::Agent::new_with_defaults(),
}
}

Expand Down Expand Up @@ -423,6 +437,7 @@ mod tests {
token: "tok".to_string(),
slug: "owner/repo".to_string(),
api_base: "https://github.corp.com/api/v3".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.api_base, "https://github.corp.com/api/v3");
}
Expand Down
32 changes: 25 additions & 7 deletions src/forge/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct GitLabForge {
pub token: String,
pub slug: String,
pub api_base: String,
pub agent: ureq::Agent,
}

impl GitLabForge {
Expand Down Expand Up @@ -44,7 +45,8 @@ impl Forge for GitLabForge {
payload["upcoming_release"] = serde_json::json!(true);
}

ureq::post(&url)
self.agent
.post(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(payload)
Expand Down Expand Up @@ -79,7 +81,9 @@ impl Forge for GitLabForge {
"description": body,
});

let response: serde_json::Value = ureq::post(&url)
let response: serde_json::Value = self
.agent
.post(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(payload)
Expand Down Expand Up @@ -113,7 +117,9 @@ impl Forge for GitLabForge {
"squash": true,
});

let result = ureq::put(&url)
let result = self
.agent
.put(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(payload);
Expand All @@ -127,7 +133,8 @@ impl Forge for GitLabForge {
"should_remove_source_branch": true,
});

ureq::put(&url)
self.agent
.put(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(payload)
Expand All @@ -152,7 +159,9 @@ impl Forge for GitLabForge {
self.encoded_project_id(),
mr_id
);
let notes: Vec<serde_json::Value> = ureq::get(&url)
let notes: Vec<serde_json::Value> = self
.agent
.get(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.call()
Expand All @@ -179,7 +188,8 @@ impl Forge for GitLabForge {
self.encoded_project_id(),
mr_id
);
ureq::post(&url)
self.agent
.post(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(serde_json::json!({ "body": body }))
Expand All @@ -195,7 +205,8 @@ impl Forge for GitLabForge {
mr_id,
comment_id
);
ureq::put(&url)
self.agent
.put(&url)
.header("PRIVATE-TOKEN", &self.token)
.header("User-Agent", "ferrflow")
.send_json(serde_json::json!({ "body": body }))
Expand All @@ -214,6 +225,7 @@ mod tests {
token: String::new(),
slug: "owner/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.encoded_project_id(), "owner%2Frepo");
}
Expand All @@ -224,6 +236,7 @@ mod tests {
token: String::new(),
slug: "group/subgroup/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.encoded_project_id(), "group%2Fsubgroup%2Frepo");
}
Expand All @@ -234,6 +247,7 @@ mod tests {
token: String::new(),
slug: "owner/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.mr_noun(), "MR");
}
Expand All @@ -244,6 +258,7 @@ mod tests {
token: String::new(),
slug: "owner/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.release_noun(), "GitLab Release");
}
Expand All @@ -254,6 +269,7 @@ mod tests {
token: String::new(),
slug: "owner/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.find_draft_release("v1.0.0").unwrap(), None);
}
Expand All @@ -264,6 +280,7 @@ mod tests {
token: String::new(),
slug: "owner/repo".to_string(),
api_base: "https://gitlab.com/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert!(forge.publish_release(123).is_ok());
}
Expand Down Expand Up @@ -303,6 +320,7 @@ mod tests {
token: String::new(),
slug: "team/project".to_string(),
api_base: "https://gitlab.internal/api/v4".to_string(),
agent: ureq::Agent::new_with_defaults(),
};
assert_eq!(forge.api_base, "https://gitlab.internal/api/v4");
}
Expand Down
Loading
Loading