hive-forge: stop embedding the forge token in clone URLs
This commit is contained in:
parent
aad5d3638f
commit
676f7715fd
6 changed files with 154 additions and 27 deletions
|
|
@ -31,10 +31,12 @@ pub struct Client {
|
|||
/// header the typed client sends.
|
||||
web: HttpClient,
|
||||
base: String,
|
||||
/// Per-agent forge token. Kept so verbs that shell out to `git`
|
||||
/// (e.g. `clone`) can assemble an authenticated push URL without
|
||||
/// re-reading the token file.
|
||||
token: String,
|
||||
/// The `-f/--forge` label this client resolved against, `None` for
|
||||
/// the default internal forge. `clone` bakes this back into the
|
||||
/// `credential.helper` command it configures, so a later `git push`/
|
||||
/// `git fetch` in that checkout re-resolves the *same* forge account
|
||||
/// rather than silently falling back to the internal one.
|
||||
forge_label: Option<String>,
|
||||
/// Default repo used when a verb doesn't carry an explicit
|
||||
/// `[repo]` override.
|
||||
pub default_repo: String,
|
||||
|
|
@ -98,7 +100,7 @@ impl Client {
|
|||
api,
|
||||
web,
|
||||
base,
|
||||
token,
|
||||
forge_label,
|
||||
default_repo,
|
||||
json_mode,
|
||||
})
|
||||
|
|
@ -111,21 +113,26 @@ impl Client {
|
|||
&self.api
|
||||
}
|
||||
|
||||
/// Assemble an authenticated git URL for `repo` (e.g.
|
||||
/// `internal/knowledge`) by injecting the agent's forge user +
|
||||
/// token into the base URL's authority: `http://<user>:<token>@host/<repo>.git`.
|
||||
/// The user comes from `HIVE_LABEL` (the agent's forge login),
|
||||
/// falling back to `oauth2` which Forgejo also accepts as the
|
||||
/// token-bearer username. Used by `clone` to clone/push.
|
||||
/// The *credential-free* git URL for `repo` — no user/token in the
|
||||
/// authority, so nothing durable lands in `.git/config` when this is
|
||||
/// the URL `git clone` is given. Pairs with the `credential-helper`
|
||||
/// verb, which `clone` configures as the repo's `credential.helper`
|
||||
/// so git asks for (and gets) the token fresh from its file on every
|
||||
/// fetch/push instead of it being embedded here. Replaces the old
|
||||
/// `authed_git_url` (`http://<user>:<token>@host/<repo>.git`), which
|
||||
/// left a durable token in every checkout's `.git/config` — a real
|
||||
/// leak reported by atlas.
|
||||
#[must_use]
|
||||
pub fn authed_git_url(&self, repo: &str) -> String {
|
||||
let user = std::env::var("HIVE_LABEL").unwrap_or_else(|_| "oauth2".to_owned());
|
||||
// Split scheme from authority so credentials land in the right spot.
|
||||
let (scheme, host) = self
|
||||
.base
|
||||
.split_once("://")
|
||||
.unwrap_or(("http", self.base.as_str()));
|
||||
format!("{scheme}://{user}:{}@{host}/{repo}.git", self.token)
|
||||
pub fn plain_git_url(&self, repo: &str) -> String {
|
||||
format!("{}/{repo}.git", self.base)
|
||||
}
|
||||
|
||||
/// The `-f/--forge` label this client resolved against (`None` for
|
||||
/// the internal forge). See the `forge_label` field doc for why
|
||||
/// `clone` needs this.
|
||||
#[must_use]
|
||||
pub fn forge_label(&self) -> Option<&str> {
|
||||
self.forge_label.as_deref()
|
||||
}
|
||||
|
||||
/// True when the operator passed the global `--json` flag.
|
||||
|
|
@ -331,7 +338,7 @@ pub fn index(n: u64) -> Result<i64> {
|
|||
/// `/` or `..`) is rejected up front with the same charset spelled out,
|
||||
/// rather than silently building a nonsense/traversing path and
|
||||
/// surfacing a confusing file error later.
|
||||
fn resolve_credentials(forge_label: Option<&str>) -> Result<(String, String)> {
|
||||
pub(crate) fn resolve_credentials(forge_label: Option<&str>) -> Result<(String, String)> {
|
||||
let Some(label) = forge_label else {
|
||||
let base = std::env::var("HIVE_FORGE_URL").unwrap_or_else(|_| DEFAULT_URL.to_owned());
|
||||
let token = read_token().context("read forge-token")?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue