forked from mirrors/kingfisher
When scanning a self-hosted Gitea/Forgejo instance, the API may be
reachable at a different hostname than the git clone endpoint (e.g.,
internal API vs. public clone URL behind a reverse proxy). The
--clone-url-base flag rewrites the scheme, host, and port of clone
URLs returned by the API, preserving the path.
Example:
kingfisher scan gitea \
--api-url https://forge.internal.example.com/api/v1/ \
--clone-url-base https://forge.internal.example.com/ \
--user eblume
This avoids routing clone traffic through an external proxy when the
API and git endpoints share the same internal host but the instance's
ROOT_URL points to the public endpoint.
Includes unit tests for the URL rewriting function and an integration
test using wiremock to verify the full enumeration path.
84 lines
2.6 KiB
Rust
84 lines
2.6 KiB
Rust
// tests/int_gitea_clone_url_base.rs
|
|
//
|
|
// Integration test: verify that --clone-url-base rewrites clone URLs
|
|
// returned by the Gitea API during repository enumeration.
|
|
//
|
|
// Uses wiremock to mock the Gitea API and assert_cmd to exercise the full
|
|
// CLI path: argument parsing → API enumeration → URL rewriting → output.
|
|
|
|
use assert_cmd::Command;
|
|
use predicates::str::contains;
|
|
use wiremock::{
|
|
matchers::{method, path, query_param},
|
|
Mock, MockServer, ResponseTemplate,
|
|
};
|
|
|
|
/// Run `kingfisher scan gitea --list-only` against a mock Gitea API with and
|
|
/// without --clone-url-base, verifying that clone URLs are rewritten.
|
|
#[tokio::test]
|
|
async fn clone_url_base_rewrites_listed_urls() {
|
|
let mock_server = MockServer::start().await;
|
|
|
|
let public_host = "https://forge.public.example.com";
|
|
let repo_json = serde_json::json!([{
|
|
"full_name": "eblume/kingfisher",
|
|
"clone_url": format!("{public_host}/eblume/kingfisher.git"),
|
|
"fork": false
|
|
}]);
|
|
|
|
// Page 1: return one repo.
|
|
Mock::given(method("GET"))
|
|
.and(path("/api/v1/users/eblume/repos"))
|
|
.and(query_param("page", "1"))
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&repo_json))
|
|
.mount(&mock_server)
|
|
.await;
|
|
|
|
// Page 2: return empty array to terminate pagination.
|
|
Mock::given(method("GET"))
|
|
.and(path("/api/v1/users/eblume/repos"))
|
|
.and(query_param("page", "2"))
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!([])))
|
|
.mount(&mock_server)
|
|
.await;
|
|
|
|
let api_url = format!("{}/api/v1/", mock_server.uri());
|
|
|
|
// WITH --clone-url-base: URLs should be rewritten.
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
"gitea",
|
|
"--api-url",
|
|
&api_url,
|
|
"--clone-url-base",
|
|
"https://forge.internal.example.com/",
|
|
"--user",
|
|
"eblume",
|
|
"--list-only",
|
|
"--no-update-check",
|
|
"--quiet",
|
|
])
|
|
.assert()
|
|
.success()
|
|
.stdout(contains("https://forge.internal.example.com/eblume/kingfisher.git"));
|
|
|
|
// WITHOUT --clone-url-base: URLs should be unchanged.
|
|
Command::new(assert_cmd::cargo::cargo_bin!("kingfisher"))
|
|
.args([
|
|
"scan",
|
|
"gitea",
|
|
"--api-url",
|
|
&api_url,
|
|
"--user",
|
|
"eblume",
|
|
"--list-only",
|
|
"--no-update-check",
|
|
"--quiet",
|
|
])
|
|
.assert()
|
|
.success()
|
|
.stdout(contains(&format!(
|
|
"{public_host}/eblume/kingfisher.git"
|
|
)));
|
|
}
|