Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
pull_request:

env:
GO_VERSION: 1.22.6
GO_VERSION: 1.23.2

jobs:
setup:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ROOT_PACKAGE := github.com/n-r-w/protodep
ROOT_PACKAGE := github.com/torqio/protodep
VERSION_PACKAGE := $(ROOT_PACKAGE)/version
LDFLAG_GIT_COMMIT := "$(VERSION_PACKAGE).gitCommit"
LDFLAG_GIT_COMMIT_FULL := "$(VERSION_PACKAGE).gitCommitFull"
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
protodep - dependency tool for Protocol Buffers IDL file (.proto) vendoring tool
=======

## Evolution of <https://github.com/stormcat24/protodep>, which unfortunately has not been updated by the author for a long time
## Evolution of <https://github.com/n-r-w/protodep>, which is the evolution of <https://github.com/stormcat24/protodep>

## What's new in this fork (compared to the original project)
## What's new in this fork (compared to n-r-w fork)
- [x] Added support for git credential helpers

### Stuff added in n-r-w's fork
- [x] Added support for .netrc file
- [x] Added support for local proto files import
- [x] Added support for gitlab subgroups
Expand All @@ -22,7 +24,7 @@ If you manage proto files in a git repository, what will you do? Most remote ser
### go install

```bash
go install -v github.com/n-r-w/protodep@latest
go install -v github.com/torqio/protodep@latest
```

## Usage
Expand Down
35 changes: 22 additions & 13 deletions cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"

"github.com/n-r-w/protodep/internal/logger"
"github.com/n-r-w/protodep/internal/resolver"
"github.com/torqio/protodep/internal/logger"
"github.com/torqio/protodep/internal/resolver"
)

var upCmd = &cobra.Command{
Expand Down Expand Up @@ -47,6 +47,12 @@ var upCmd = &cobra.Command{
}
logger.Info("use netrc = %t", useNetrc)

useGitCredentials, err := cmd.Flags().GetBool("use-git-credentials")
if err != nil {
return err
}
logger.Info("use git credentials = %t", useGitCredentials)

basicAuthUsername, err := cmd.Flags().GetString("basic-auth-username")
if err != nil {
return err
Expand Down Expand Up @@ -74,15 +80,16 @@ var upCmd = &cobra.Command{
}

conf := resolver.Config{
UseHttps: useHTTPS,
UseNetrc: useNetrc,
HomeDir: homeDir,
TargetDir: pwd,
OutputDir: pwd,
BasicAuthUsername: basicAuthUsername,
BasicAuthPassword: basicAuthPassword,
IdentityFile: identityFile,
IdentityPassword: password,
UseHttps: useHTTPS,
UseGitCredentialsHelper: useGitCredentials,
UseNetrc: useNetrc,
HomeDir: homeDir,
TargetDir: pwd,
OutputDir: pwd,
BasicAuthUsername: basicAuthUsername,
BasicAuthPassword: basicAuthPassword,
IdentityFile: identityFile,
IdentityPassword: password,
}

httpsProvider, err := conf.GetHttpsAuthProvider()
Expand All @@ -108,8 +115,10 @@ func initDepCmd() {
upCmd.PersistentFlags().StringP("identity-file", "i", "", "set the identity file for SSH")
upCmd.PersistentFlags().StringP("password", "p", "", "set the password for SSH")
upCmd.PersistentFlags().BoolP("cleanup", "c", false, "cleanup cache before exec.")
upCmd.PersistentFlags().BoolP("use-https", "u", false, "use HTTPS to get dependencies.")
upCmd.PersistentFlags().BoolP("use-netrc", "n", true, "use netrc file for authentication")
upCmd.PersistentFlags().BoolP("use-https", "u", true, "use HTTPS to get dependencies.")
upCmd.PersistentFlags().BoolP("use-netrc", "n", false, "use netrc file for authentication")
upCmd.PersistentFlags().BoolP("use-git-credentials", "m", true, "use git credentials for authentication")

upCmd.PersistentFlags().StringP("basic-auth-username", "", "", "set the username with Basic Auth via HTTPS")
upCmd.PersistentFlags().StringP("basic-auth-password", "", "", "set the password or personal access token(when enabled 2FA) with Basic Auth via HTTPS")
}
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/spf13/cobra"

"github.com/n-r-w/protodep/version"
"github.com/torqio/protodep/version"
)

const art = `
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/n-r-w/protodep
module github.com/torqio/protodep

go 1.23

Expand Down
12 changes: 6 additions & 6 deletions internal/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import (

func TestGetRepositoryURLWithSSH(t *testing.T) {
target := &AuthProviderWithSSH{}
actual := target.GetRepositoryURL("github.com/n-r-w/protodep")
actual := target.GetRepositoryURL("github.com/torqio/protodep")

require.Equal(t, "ssh://github.com/n-r-w/protodep.git", actual)
require.Equal(t, "ssh://github.com/torqio/protodep.git", actual)
}

func TestGetRepositoryURLWithSSHAgent(t *testing.T) {
target := &AuthProviderWithSSHAgent{}
actual := target.GetRepositoryURL("github.com/n-r-w/protodep")
actual := target.GetRepositoryURL("github.com/torqio/protodep")

require.Equal(t, "ssh://github.com/n-r-w/protodep.git", actual)
require.Equal(t, "ssh://github.com/torqio/protodep.git", actual)
}

func TestGetRepositoryURLHTTPS(t *testing.T) {
target := &AuthProviderHTTPS{}
actual := target.GetRepositoryURL("github.com/n-r-w/protodep")
actual := target.GetRepositoryURL("github.com/torqio/protodep")

require.Equal(t, "https://github.com/n-r-w/protodep.git", actual)
require.Equal(t, "https://github.com/torqio/protodep.git", actual)
}
6 changes: 3 additions & 3 deletions internal/repository/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"

"github.com/n-r-w/protodep/internal/auth"
"github.com/n-r-w/protodep/internal/config"
"github.com/n-r-w/protodep/internal/logger"
"github.com/torqio/protodep/internal/auth"
"github.com/torqio/protodep/internal/config"
"github.com/torqio/protodep/internal/logger"
)

const masterBranch = "master"
Expand Down
7 changes: 5 additions & 2 deletions internal/resolver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"fmt"
"path/filepath"

"github.com/n-r-w/protodep/internal/auth"
"github.com/n-r-w/protodep/internal/logger"
"github.com/torqio/protodep/internal/auth"
"github.com/torqio/protodep/internal/logger"
)

type Config struct {
// UseHttps will force https on each proto dependencies fetch.
UseHttps bool

// UseGitCredentialsHelper will use git credentials helper for authentication.
UseGitCredentialsHelper bool

// UseNetrc will use netrc file for authentication.
UseNetrc bool

Expand Down
196 changes: 196 additions & 0 deletions internal/resolver/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package resolver

import (
"bytes"
"fmt"
"github.com/go-git/go-git/v5/config"
format "github.com/go-git/go-git/v5/plumbing/format/config"
"net/url"
"os/exec"
"strings"
)

const credentialSection = "credential"

type CredentialConfigEntry struct {
Helper []string
Username string
UseHttpPath bool
}

type Credentials map[string]*CredentialConfigEntry

type GitCredential struct {
Protocol string
Host string
Username string
Password string
URL string
}

func (c GitCredential) String() string {
var b strings.Builder

if c.Protocol != "" {
fmt.Fprintf(&b, "protocol=%s\n", c.Protocol)
}

// If full URL is provided, use that
if c.URL != "" {
fmt.Fprintf(&b, "url=%s\n", c.URL)
}

// Otherwise fall back to protocol/host
if c.Host != "" {
fmt.Fprintf(&b, "host=%s\n", c.Host)
}

if c.Username != "" {
fmt.Fprintf(&b, "username=%s\n", c.Username)
}
if c.Password != "" {
fmt.Fprintf(&b, "password=%s\n", c.Password)
}
return b.String()
}

func newCredential(opts format.Options) *CredentialConfigEntry {
return &CredentialConfigEntry{
Helper: opts.GetAll("helper"),
Username: opts.Get("username"),
UseHttpPath: opts.Get("usehttppath") == "true",
}
}

func buildCredentialCommand(helperName, action string) (*exec.Cmd, error) {
if strings.HasPrefix(helperName, "!") {
// For helpers starting with !, execute the command directly
cmdStr := strings.TrimPrefix(helperName, "!")
cmdParts := strings.Fields(cmdStr)
if len(cmdParts) == 0 {
return nil, fmt.Errorf("invalid credential helper command: %s", helperName)
}

// Append the action to the command parts
cmdParts = append(cmdParts, action)
return exec.Command(cmdParts[0], cmdParts[1:]...), nil
}

// Regular git credential helper
return exec.Command("git", "credential-"+helperName, action), nil
}

func invokeCredentialHelper(helperName, action string, cred GitCredential) (GitCredential, error) {
cmd, err := buildCredentialCommand(helperName, action)
if err != nil {
return GitCredential{}, err
}

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Stdin = strings.NewReader(cred.String())

if err := cmd.Run(); err != nil {
return GitCredential{}, fmt.Errorf("credential helper failed: %v, stderr: %s", err, stderr.String())
}

// Parse output
output := stdout.String()
result := GitCredential{}

for _, line := range strings.Split(output, "\n") {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
switch parts[0] {
case "protocol":
result.Protocol = parts[1]
case "host":
result.Host = parts[1]
case "username":
result.Username = parts[1]
case "password":
result.Password = parts[1]
}
}

return result, nil
}

var ErrNoCredentialHelperFound = fmt.Errorf("no credential helper found")

func (c *CredentialConfigEntry) Evaluate(repoURL string) (*GitCredential, error) {
parsedUrl, err := url.Parse(repoURL)
if err != nil {
return nil, err
}

testedUrl := repoURL
if !c.UseHttpPath {
testedUrl = parsedUrl.Scheme + "://" + parsedUrl.Host
}

cred := GitCredential{
Protocol: parsedUrl.Scheme,
Host: parsedUrl.Host,
URL: testedUrl,
Username: c.Username,
}

for _, helperName := range c.Helper {
cred, err = invokeCredentialHelper(helperName, "get", cred)
if err != nil {
return nil, err
}

return &cred, nil
}

return nil, ErrNoCredentialHelperFound
}

func ParseGitCredentials() (Credentials, error) {
c, err := config.LoadConfig(config.GlobalScope)
if err != nil {
return nil, err
}

sect := c.Raw.Section(credentialSection)

result := make(map[string]*CredentialConfigEntry)
result["default"] = newCredential(sect.Options)

for _, sub := range sect.Subsections {
result[sub.Name] = newCredential(sub.Options)
}

return result, nil
}

func (c Credentials) Has(section string) bool {
_, ok := c[section]
return ok
}

func (c Credentials) Get(host string) *CredentialConfigEntry {

parsedURL, err := url.Parse(host)
if err != nil {
return c["default"]
}

if parsedURL.Scheme == "" {
parsedURL.Scheme = "https"
}

checkTargets := []string{parsedURL.Scheme + "://" + parsedURL.Host, "default"}
for _, target := range checkTargets {
if c.Has(target) {
return c[target]
}
}

return nil
}
Loading