From 5b89fbc07bd304757febb719e5d62615ef282848 Mon Sep 17 00:00:00 2001 From: Laurent Wouters Date: Thu, 12 Sep 2024 14:36:20 +0200 Subject: [PATCH] fix: fixing self auth on doc gen with sparse protocol (#24) --- README.docker.md | 9 ++- README.md | 6 +- docker-compose.yml | 2 +- src/model/config.rs | 170 +++++++++++++++++++++++++++++-------------- src/services/docs.rs | 7 ++ 5 files changed, 133 insertions(+), 61 deletions(-) diff --git a/README.docker.md b/README.docker.md index d6dbcd9..ecd6bef 100644 --- a/README.docker.md +++ b/README.docker.md @@ -38,7 +38,7 @@ services: REGISTRY_WEB_PUBLIC_URI: http://localhost # REGISTRY_WEB_BODY_LIMIT: 10485760 REGISTRY_DATA_DIR: /data - # REGISTRY_INDEX_PROTOCOL_GIT: "true" + # REGISTRY_INDEX_PROTOCOL_GIT: "false" # REGISTRY_INDEX_PROTOCOL_SPARSE: "true" # REGISTRY_GIT_REMOTE: # REGISTRY_GIT_REMOTE_SSH_KEY_FILENAME: @@ -173,6 +173,13 @@ This is controlled by the following configuration : ### Index +The index can be served using both the legacy `git` and the new `sparse` protocols, see [Registry Protocols](https://doc.rust-lang.org/cargo/reference/registries.html#registry-protocols). +The legacy `git` protocol is disabled by default, and the new `sparse` protocol enabled: +* `REGISTRY_INDEX_PROTOCOL_GIT`, defaults to `false` to de-activate the legacy `git` "smart" protocol. Use `true` to activate. +* `REGISTRY_INDEX_PROTOCOL_SPARSE`, defaults to `true` to activate the `sparse` protocol. Any other value deactivates it. + +Fetching the index always requires authentication, regardless of the used protocol. + The index for the registry is managed as a git repository. When `cratery` commits to this repository as an author: * `REGISTRY_GIT_USER_NAME` is the username to use, diff --git a/README.md b/README.md index da02317..d26bd89 100644 --- a/README.md +++ b/README.md @@ -131,9 +131,9 @@ This is controlled by the following configuration : ### Index -The index can be served using both the `git` and `sparse` protocols. -Both are activated by default, but can be activated / deactivated as required: -* `REGISTRY_INDEX_PROTOCOL_GIT`, defaults to `true` to activate the `git` "smart" protocol. Any other value deactivates it. +The index can be served using both the legacy `git` and the new `sparse` protocols, see [Registry Protocols](https://doc.rust-lang.org/cargo/reference/registries.html#registry-protocols). +The legacy `git` protocol is disabled by default, and the new `sparse` protocol enabled: +* `REGISTRY_INDEX_PROTOCOL_GIT`, defaults to `false` to de-activate the legacy `git` "smart" protocol. Use `true` to activate. * `REGISTRY_INDEX_PROTOCOL_SPARSE`, defaults to `true` to activate the `sparse` protocol. Any other value deactivates it. Fetching the index always requires authentication, regardless of the used protocol. diff --git a/docker-compose.yml b/docker-compose.yml index 3e12eb2..6e9556d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,7 +19,7 @@ services: # REGISTRY_WEB_BODY_LIMIT: 10485760 REGISTRY_HOME_DIR: /home/cratery REGISTRY_DATA_DIR: /data - # REGISTRY_INDEX_PROTOCOL_GIT: "true" + # REGISTRY_INDEX_PROTOCOL_GIT: "false" # REGISTRY_INDEX_PROTOCOL_SPARSE: "true" # REGISTRY_GIT_REMOTE: # REGISTRY_GIT_REMOTE_SSH_KEY_FILENAME: diff --git a/src/model/config.rs b/src/model/config.rs index 8c39128..352f3af 100644 --- a/src/model/config.rs +++ b/src/model/config.rs @@ -173,7 +173,7 @@ impl IndexConfig { Ok(IndexConfig { home_dir: home_dir.to_string(), location: format!("{data_dir}/index"), - allow_protocol_git: get_var("REGISTRY_INDEX_PROTOCOL_GIT").map(|v| v == "true").unwrap_or(true), + allow_protocol_git: get_var("REGISTRY_INDEX_PROTOCOL_GIT").map(|v| v == "true").unwrap_or(false), allow_protocol_sparse: get_var("REGISTRY_INDEX_PROTOCOL_SPARSE").map(|v| v == "true").unwrap_or(true), remote_origin: get_var("REGISTRY_GIT_REMOTE").ok(), remote_ssh_key_file_name: get_var("REGISTRY_GIT_REMOTE_SSH_KEY_FILENAME").ok(), @@ -550,69 +550,127 @@ impl Configuration { /// /// Return an error when writing fail pub async fn write_auth_config(&self) -> Result<(), ApiError> { - { - let file = File::create(self.get_home_path_for(&[".gitconfig"])).await?; - let mut writer = BufWriter::new(file); - writer.write_all("[credential]\n helper = store\n".as_bytes()).await?; - writer.flush().await?; + if self.index.allow_protocol_git { + self.write_auth_config_git_config().await?; + self.write_auth_config_git_credentials().await?; } - { - let file = File::create(self.get_home_path_for(&[".git-credentials"])).await?; - let mut writer = BufWriter::new(file); - let index = self.web_public_uri.find('/').unwrap() + 2; + self.write_auth_config_cargo_config().await?; + self.write_auth_config_cargo_credentials().await?; + Ok(()) + } + + /// Write the configuration for authenticating to registries + async fn write_auth_config_git_config(&self) -> Result<(), ApiError> { + let file = File::create(self.get_home_path_for(&[".gitconfig"])).await?; + let mut writer = BufWriter::new(file); + writer.write_all("[credential]\n helper = store\n".as_bytes()).await?; + writer.flush().await?; + Ok(()) + } + + /// Write the configuration for authenticating to registries + async fn write_auth_config_git_credentials(&self) -> Result<(), ApiError> { + let file = File::create(self.get_home_path_for(&[".git-credentials"])).await?; + let mut writer = BufWriter::new(file); + let index = self.web_public_uri.find('/').unwrap() + 2; + writer + .write_all( + format!( + "{}{}:{}@{}\n", + &self.web_public_uri[..index], + self.self_service_login, + self.self_service_token, + &self.web_public_uri[index..] + ) + .as_bytes(), + ) + .await?; + for registry in &self.external_registries { + let index = registry.index.find('/').unwrap() + 2; writer .write_all( format!( - "{}{}:{}@{}\n", - &self.web_public_uri[..index], - self.self_service_login, - self.self_service_token, - &self.web_public_uri[index..] + "{}{}:{}@{}", + ®istry.index[..index], + registry.login, + registry.token, + ®istry.index[index..] ) .as_bytes(), ) .await?; - for registry in &self.external_registries { - let index = registry.index.find('/').unwrap() + 2; + } + writer.flush().await?; + Ok(()) + } + + /// Write the configuration for authenticating to registries + async fn write_auth_config_cargo_config(&self) -> Result<(), ApiError> { + let file = File::create(self.get_home_path_for(&[".cargo", "config.toml"])).await?; + let mut writer = BufWriter::new(file); + writer.write_all("[registry]\n".as_bytes()).await?; + writer + .write_all("global-credential-providers = [\"cargo:token\"]\n".as_bytes()) + .await?; + writer.write_all("\n".as_bytes()).await?; + writer.write_all("[registries]\n".as_bytes()).await?; + if self.index.allow_protocol_git { + writer + .write_all(format!("{} = {{ index = \"{}\" }}\n", self.self_local_name, self.web_public_uri).as_bytes()) + .await?; + if self.index.allow_protocol_sparse { + // both git and sparse writer .write_all( format!( - "{}{}:{}@{}", - ®istry.index[..index], - registry.login, - registry.token, - ®istry.index[index..] + "{}sparse = {{ index = \"sparse+{}/\" }}\n", + self.self_local_name, self.web_public_uri ) .as_bytes(), ) .await?; } - writer.flush().await?; - } - { - let file = File::create(self.get_home_path_for(&[".cargo", "config.toml"])).await?; - let mut writer = BufWriter::new(file); - writer.write_all("[registry]\n".as_bytes()).await?; + } else if self.index.allow_protocol_sparse { + // sparse only writer - .write_all("global-credential-providers = [\"cargo:token\"]\n".as_bytes()) + .write_all( + format!( + "{} = {{ index = \"sparse+{}/\" }}\n", + self.self_local_name, self.web_public_uri + ) + .as_bytes(), + ) .await?; - writer.write_all("\n".as_bytes()).await?; - writer.write_all("[registries]\n".as_bytes()).await?; + } + for registry in &self.external_registries { writer - .write_all(format!("{} = {{ index = \"{}\" }}\n", self.self_local_name, self.web_public_uri).as_bytes()) + .write_all(format!("{} = {{ index = \"{}\" }}\n", registry.name, registry.index).as_bytes()) .await?; - for registry in &self.external_registries { - writer - .write_all(format!("{} = {{ index = \"{}\" }}\n", registry.name, registry.index).as_bytes()) - .await?; - } - writer.flush().await?; } - { - let file = File::create(self.get_home_path_for(&[".cargo", "credentials.toml"])).await?; - let mut writer = BufWriter::new(file); + writer.flush().await?; + Ok(()) + } + + /// Write the configuration for authenticating to registries + async fn write_auth_config_cargo_credentials(&self) -> Result<(), ApiError> { + let file = File::create(self.get_home_path_for(&[".cargo", "credentials.toml"])).await?; + let mut writer = BufWriter::new(file); + writer + .write_all(format!("[registries.{}]\n", self.self_local_name).as_bytes()) + .await?; + writer + .write_all( + format!( + "token = \"Basic {}\"\n", + STANDARD.encode(format!("{}:{}", self.self_service_login, self.self_service_token)) + ) + .as_bytes(), + ) + .await?; + if self.index.allow_protocol_git && self.index.allow_protocol_sparse { + // add credential for specialized sparse registry writer - .write_all(format!("[registries.{}]\n", self.self_local_name).as_bytes()) + .write_all(format!("[registries.{}sparse]\n", self.self_local_name).as_bytes()) .await?; writer .write_all( @@ -623,22 +681,22 @@ impl Configuration { .as_bytes(), ) .await?; - for registry in &self.external_registries { - writer - .write_all(format!("[registries.{}]\n", registry.name).as_bytes()) - .await?; - writer - .write_all( - format!( - "token = \"Basic {}\"\n", - STANDARD.encode(format!("{}:{}", registry.login, registry.token)) - ) - .as_bytes(), + } + for registry in &self.external_registries { + writer + .write_all(format!("[registries.{}]\n", registry.name).as_bytes()) + .await?; + writer + .write_all( + format!( + "token = \"Basic {}\"\n", + STANDARD.encode(format!("{}:{}", registry.login, registry.token)) ) - .await?; - } - writer.flush().await?; + .as_bytes(), + ) + .await?; } + writer.flush().await?; Ok(()) } } diff --git a/src/services/docs.rs b/src/services/docs.rs index 9037e89..6710e2c 100644 --- a/src/services/docs.rs +++ b/src/services/docs.rs @@ -303,6 +303,13 @@ impl DocsGeneratorImpl { "doc.extern-map.registries.{}=\"{}/docs\"", self.configuration.self_local_name, self.configuration.web_public_uri )); + if self.configuration.index.allow_protocol_git && self.configuration.index.allow_protocol_sparse { + // both git and sparse => add specialized sparse + command.arg(format!( + "doc.extern-map.registries.{}sparse=\"{}/docs\"", + self.configuration.self_local_name, self.configuration.web_public_uri + )); + } for external in &self.configuration.external_registries { command.arg("--config").arg(format!( "doc.extern-map.registries.{}=\"{}\"",