remote-helper: allow fetching from canonical refs

There is no mechanism for fetching the canonical `refs/heads/master`
from a project's repository into a local working copy.

Allow setting up a remote in the working copy, e.g.

    [remote "canon"]
	url = rad://z3gqcJUoA1n9HaHKufZs5FCSGazv5
	fetch = +refs/heads/master:refs/remotes/canon/master

Such that it can fetch the `master` branch, but disallows push to the
canonical reference namespace.

This is achieved by allowing the namespace in `radicle::git::Url` to
be `None` when the radicle-remote-helper is called. It disallows the
namespace to be None during a `git-receive-pack` -- also keeping the
check for the namespace being equal to the local operator's key.

When the namespace is `None` then `GIT_NAMESPACE` is set to the empty
string.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2023-04-19 15:36:22 +01:00 committed by Alexis Sellier
parent a16be24517
commit f11991737f
No known key found for this signature in database
1 changed files with 16 additions and 5 deletions

View File

@ -25,6 +25,9 @@ pub enum Error {
/// Public key doesn't match the remote namespace we're pushing to.
#[error("public key `{0}` does not match remote namespace")]
KeyMismatch(PublicKey),
/// No public key is given
#[error("no public key given as a remote namespace, perhaps you are attempting to push to restricted refs")]
NoKey,
/// Invalid command received.
#[error("invalid command `{0}`")]
InvalidCommand(String),
@ -52,8 +55,6 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box<dyn std::error::Error +
}
}
}?;
// Default to profile key.
let namespace = url.namespace.unwrap_or(profile.public_key);
let proj = profile.storage.repository_mut(url.repo)?;
if proj.is_empty()? {
@ -82,10 +83,17 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box<dyn std::error::Error +
// 1. Our key is not in ssh-agent, which means we won't be able to sign the refs.
// 2. Our key is not the one loaded in the profile, which means that the signed refs
// won't match the remote we're pushing to.
// 3. The URL namespace is not set, which is used for fetching canonical refs.
let signer = if *service == GIT_RECEIVE_PACK {
if profile.public_key != namespace {
return Err(Error::KeyMismatch(profile.public_key).into());
match url.namespace {
Some(namespace) => {
if profile.public_key != namespace {
return Err(Error::KeyMismatch(profile.public_key).into());
}
}
None => return Err(Error::NoKey.into()),
}
let signer = profile.signer()?;
Some(signer)
@ -101,7 +109,10 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box<dyn std::error::Error +
let mut child = process::Command::new(service)
.arg(proj.path())
.env("GIT_DIR", proj.path())
.env("GIT_NAMESPACE", namespace.to_string())
.env(
"GIT_NAMESPACE",
url.namespace.map(|ns| ns.to_string()).unwrap_or_default(),
)
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit())
.stdin(process::Stdio::inherit())