Git-Native

 view release on metacpan or  search on metacpan

lib/Git/Native/Credential.pm  view on Meta::CPAN

  my $pass = $args{password} // Carp::croak "userpass: 'password' required";
  check_rc Git::Libgit2::FFI::git_credential_userpass_plaintext_new(
    \my $cred, $user, $pass,
  );
  return $class->new( _handle => $cred );
}

sub ssh_key {
  my ( $class, %args ) = @_;
  my $user        = $args{username}    // Carp::croak "ssh_key: 'username' required";
  my $private_key = $args{private_key} // Carp::croak "ssh_key: 'private_key' required";
  my $public_key  = $args{public_key};   # may be undef → libgit2 derives
  my $passphrase  = $args{passphrase} // '';
  check_rc Git::Libgit2::FFI::git_credential_ssh_key_new(
    \my $cred, $user, $public_key, $private_key, $passphrase,
  );
  return $class->new( _handle => $cred );
}

sub ssh_agent {
  my ( $class, %args ) = @_;
  my $user = $args{username} // Carp::croak "ssh_agent: 'username' required";
  check_rc Git::Libgit2::FFI::git_credential_ssh_key_from_agent(
    \my $cred, $user,
  );

lib/Git/Native/Credential.pm  view on Meta::CPAN

    password => $ENV{GITHUB_TOKEN},
  );

  # ssh-agent (matches CLI default for git+ssh remotes)
  my $cred = Git::Native::Credential->ssh_agent(username => 'git');

  # explicit key file
  my $cred = Git::Native::Credential->ssh_key(
    username    => 'git',
    public_key  => "$ENV{HOME}/.ssh/id_ed25519.pub",
    private_key => "$ENV{HOME}/.ssh/id_ed25519",
    passphrase  => '',
  );

=head1 DESCRIPTION

Returned from the C<credentials> callback you pass to
L<Git::Native::Remote>'s C<fetch>/C<push>. libgit2 takes ownership of
the credential once the callback returns successfully — the Perl wrapper
is disowned automatically so it won't double-free.

lib/Git/Native/Credential.pm  view on Meta::CPAN


Username and password (C<git_credential_userpass_plaintext_new>). Both
arguments are required. This is also the constructor for HTTPS token auth:
the token goes in C<password>, and which username the host expects varies
(C<git> and C<oauth2> are the usual answers).

=head2 ssh_key

  Git::Native::Credential->ssh_key(
    username    => 'git',
    private_key => "$ENV{HOME}/.ssh/id_ed25519",
    public_key  => "$ENV{HOME}/.ssh/id_ed25519.pub",   # optional
    passphrase  => 'hunter2',                          # optional
  );

An on-disk key pair (C<git_credential_ssh_key_new>). C<username> and
C<private_key> are required; C<public_key> may be left out, in which case
libgit2 derives it from the private key, and C<passphrase> defaults to the
empty string. The key files are not touched at construction time — libgit2
reads them when the transport uses the credential, so a wrong path surfaces
as an auth failure during C<fetch> / C<push>, not here.

=head2 ssh_agent

  Git::Native::Credential->ssh_agent( username => 'git' );

Take a key from the running ssh-agent

t/35-credential.t  view on Meta::CPAN

}

# ssh_key — skip unless test key files present
SKIP: {
  my $priv = $ENV{TEST_GIT_NATIVE_SSH_KEY};
  skip 'TEST_GIT_NATIVE_SSH_KEY not set — skipping ssh_key test', 1
    unless $priv && -f $priv;

  my $cred = Git::Native::Credential->ssh_key(
    username    => 'git',
    private_key => $priv,
  );
  isa_ok( $cred, ['Git::Native::Credential'], 'ssh_key credential' );
}

done_testing;

t/40-remote-ssh.t  view on Meta::CPAN

my $remote = $repo->remote_create( 'origin', $url );

my $cb_calls = 0;
my $cred_cb = sub {
  my (%args) = @_;
  $cb_calls++;
  my $user = $args{username_from_url} // 'git';
  if ($key_path) {
    return Git::Native::Credential->ssh_key(
      username    => $user,
      private_key => $key_path,
      public_key  => -r "${key_path}.pub" ? "${key_path}.pub" : undef,
      passphrase  => $ENV{TEST_GIT_NATIVE_SSH_PASSPHRASE} // '',
    );
  }
  return Git::Native::Credential->ssh_agent( username => $user );
};

eval {
  $remote->fetch(
    refspecs    => ['+refs/heads/*:refs/remotes/origin/*'],

t/55-credential-args.t  view on Meta::CPAN

#
# No network and no agent contact: git_credential_ssh_key_new and
# git_credential_ssh_key_from_agent only allocate the credential struct. The
# key file is not read until the transport uses it, so a synthetic path is
# enough to reach the allocation.

# ---- required arguments croak before any FFI call ----
# These run on every libgit2 build, including one without SSH support,
# because Carp::croak fires ahead of the FFI.
{
  my $err = dies { Git::Native::Credential->ssh_key( private_key => '/tmp/k' ) };
  like $err, qr/ssh_key: 'username' required/, 'ssh_key without username croaks';
}
{
  my $err = dies { Git::Native::Credential->ssh_key( username => 'git' ) };
  like $err, qr/ssh_key: 'private_key' required/,
    'ssh_key without private_key croaks';
}
{
  my $err = dies { Git::Native::Credential->ssh_agent() };
  like $err, qr/ssh_agent: 'username' required/, 'ssh_agent without username croaks';
}
{
  # A croak, not a libgit2 error - the argument check must happen in Perl
  # before a NULL is handed to C.
  my $err = dies { Git::Native::Credential->ssh_key( username => 'git' ) };
  ok !ref($err),
    'the missing-argument failure is a plain croak string, not a libgit2 error object';
}

# ---- construction ----
# libgit2 can be built without SSH support; there the allocation itself fails.
# Skip loudly rather than shipping a test that fails on such a build.
my $ssh_probe = dies {
  Git::Native::Credential->ssh_key(
    username => 'git', private_key => '/nonexistent/id_ed25519',
  );
};

SKIP: {
  if ($ssh_probe) {
    diag "libgit2 rejected an ssh_key credential: $ssh_probe";
    diag 'this build appears to lack SSH support - skipping the SSH constructors';
    skip 'libgit2 built without SSH support', 4;
  }

  # public_key omitted: the wrapper passes undef and lets libgit2 derive it.
  my $derived = Git::Native::Credential->ssh_key(
    username => 'git', private_key => '/nonexistent/id_ed25519',
  );
  isa_ok $derived, ['Git::Native::Credential'],
    'ssh_key without public_key builds (libgit2 derives it)';

  # Explicit public key and passphrase take the other side of both defaults.
  my $explicit = Git::Native::Credential->ssh_key(
    username    => 'git',
    private_key => '/nonexistent/id_ed25519',
    public_key  => '/nonexistent/id_ed25519.pub',
    passphrase  => 'hunter2',
  );
  isa_ok $explicit, ['Git::Native::Credential'],
    'ssh_key with public_key and passphrase builds';

  my $agent = Git::Native::Credential->ssh_agent( username => 'git' );
  isa_ok $agent, ['Git::Native::Credential'], 'ssh_agent builds';

  # Ownership: a credential that never reaches libgit2 still owns its handle,



( run in 3.165 seconds using v1.01-cache-2.11-cpan-8dfa8b56332 )