Skip to content

Commit ae2de73

Browse files
committed
Remove GH access token from API output
1 parent 0b05b7e commit ae2de73

File tree

6 files changed

+129
-45
lines changed

6 files changed

+129
-45
lines changed

api/api.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ func NewAPIWithVersion(ctx context.Context, globalConfig *conf.GlobalConfigurati
7171
r.Get("/health", api.HealthCheck)
7272

7373
r.Route("/", func(r *router) {
74-
7574
if globalConfig.MultiInstanceMode {
7675
r.Use(api.loadJWSSignatureHeader)
7776
r.Use(api.loadInstanceConfig)

api/github.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ import (
66
"net/http/httputil"
77
"net/url"
88
"regexp"
9-
"strings"
10-
11-
"github.com/netlify/git-gateway/conf"
129
)
1310

1411
// GitHubGateway acts as a proxy to GitHub
@@ -65,19 +62,8 @@ func (gh *GitHubGateway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
6562
return
6663
}
6764

68-
var endpoint string
69-
if config.GitHub.Endpoint != "" {
70-
endpoint = config.GitHub.Endpoint
71-
} else {
72-
endpoint = conf.DefaultGitHubEndpoint
73-
}
74-
var apiURL string
75-
if strings.HasSuffix(endpoint, "/") {
76-
apiURL = endpoint + "repos/" + config.GitHub.Repo
77-
} else {
78-
apiURL = endpoint + "/repos/" + config.GitHub.Repo
79-
}
80-
65+
endpoint := config.GitHub.Endpoint
66+
apiURL := singleJoiningSlash(endpoint, "/repos/"+config.GitHub.Repo)
8167
target, err := url.Parse(apiURL)
8268
if err != nil {
8369
handleError(internalServerError("Unable to process GitHub endpoint"), w, r)

api/helpers.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"net/http"
88
"strings"
99

10+
"github.com/netlify/git-gateway/conf"
11+
"github.com/netlify/git-gateway/models"
1012
"github.com/pborman/uuid"
1113
"github.com/pkg/errors"
1214
)
@@ -18,7 +20,30 @@ func addRequestID(w http.ResponseWriter, r *http.Request) (context.Context, erro
1820
return ctx, nil
1921
}
2022

23+
func sanitizeOutput(obj interface{}) interface{} {
24+
switch v := obj.(type) {
25+
case InstanceResponse:
26+
v.Instance.BaseConfig.GitHub.AccessToken = ""
27+
case *InstanceResponse:
28+
v.Instance.BaseConfig.GitHub.AccessToken = ""
29+
case models.Instance:
30+
v.BaseConfig.GitHub.AccessToken = ""
31+
case *models.Instance:
32+
v.BaseConfig.GitHub.AccessToken = ""
33+
case *conf.Configuration:
34+
v.GitHub.AccessToken = ""
35+
case conf.Configuration:
36+
v.GitHub.AccessToken = ""
37+
// must return here because v != obj due to value copying
38+
return v
39+
default:
40+
}
41+
return obj
42+
}
43+
2144
func sendJSON(w http.ResponseWriter, status int, obj interface{}) error {
45+
obj = sanitizeOutput(obj)
46+
2247
w.Header().Set("Content-Type", "application/json")
2348
b, err := json.Marshal(obj)
2449
if err != nil {

api/helpers_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package api
2+
3+
import (
4+
"testing"
5+
6+
"github.com/netlify/git-gateway/conf"
7+
"github.com/netlify/git-gateway/models"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestSanitizeOutput(t *testing.T) {
13+
t.Run("InstanceResponse", func(t *testing.T) {
14+
v := InstanceResponse{
15+
Instance: models.Instance{
16+
BaseConfig: &conf.Configuration{
17+
GitHub: conf.GitHubConfig{
18+
AccessToken: "remove",
19+
},
20+
},
21+
},
22+
}
23+
24+
ov := sanitizeOutput(v)
25+
require.IsType(t, v, ov)
26+
assert.Equal(t, "", ov.(InstanceResponse).Instance.BaseConfig.GitHub.AccessToken)
27+
})
28+
29+
t.Run("InstanceResponsePtr", func(t *testing.T) {
30+
v := &InstanceResponse{
31+
Instance: models.Instance{
32+
BaseConfig: &conf.Configuration{
33+
GitHub: conf.GitHubConfig{
34+
AccessToken: "remove",
35+
},
36+
},
37+
},
38+
}
39+
40+
ov := sanitizeOutput(v)
41+
require.IsType(t, v, ov)
42+
assert.Equal(t, "", ov.(*InstanceResponse).Instance.BaseConfig.GitHub.AccessToken)
43+
})
44+
45+
t.Run("Instance", func(t *testing.T) {
46+
v := models.Instance{
47+
BaseConfig: &conf.Configuration{
48+
GitHub: conf.GitHubConfig{
49+
AccessToken: "remove",
50+
},
51+
},
52+
}
53+
54+
ov := sanitizeOutput(v)
55+
require.IsType(t, v, ov)
56+
assert.Equal(t, "", ov.(models.Instance).BaseConfig.GitHub.AccessToken)
57+
})
58+
59+
t.Run("InstancePtr", func(t *testing.T) {
60+
v := &models.Instance{
61+
BaseConfig: &conf.Configuration{
62+
GitHub: conf.GitHubConfig{
63+
AccessToken: "remove",
64+
},
65+
},
66+
}
67+
68+
ov := sanitizeOutput(v)
69+
require.IsType(t, v, ov)
70+
assert.Equal(t, "", ov.(*models.Instance).BaseConfig.GitHub.AccessToken)
71+
})
72+
73+
t.Run("Configuration", func(t *testing.T) {
74+
v := conf.Configuration{
75+
GitHub: conf.GitHubConfig{
76+
AccessToken: "remove",
77+
},
78+
}
79+
80+
ov := sanitizeOutput(v)
81+
require.IsType(t, v, ov)
82+
assert.Equal(t, "", ov.(conf.Configuration).GitHub.AccessToken)
83+
})
84+
85+
t.Run("ConfigurationPtr", func(t *testing.T) {
86+
v := &conf.Configuration{
87+
GitHub: conf.GitHubConfig{
88+
AccessToken: "remove",
89+
},
90+
}
91+
92+
ov := sanitizeOutput(v)
93+
require.IsType(t, v, ov)
94+
assert.Equal(t, "", ov.(*conf.Configuration).GitHub.AccessToken)
95+
})
96+
}

api/instance.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ func (a *API) GetAppManifest(w http.ResponseWriter, r *http.Request) error {
3030
// TODO update to real manifest
3131
return sendJSON(w, http.StatusOK, map[string]string{
3232
"version": a.version,
33-
"name": "GoTrue",
34-
"description": "GoTrue is a user registration and authentication API",
33+
"name": "GitGateway",
34+
"description": "GitGateway is an access control proxy to git repos",
3535
})
3636
}
3737

conf/configuration.go

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package conf
22

33
import (
4-
"encoding/json"
54
"os"
6-
"strings"
75

86
"github.com/joho/godotenv"
97
"github.com/kelseyhightower/envconfig"
@@ -13,7 +11,7 @@ import (
1311
const DefaultGitHubEndpoint = "https://api.github.com"
1412

1513
type GitHubConfig struct {
16-
AccessToken string `envconfig:"ACCESS_TOKEN" json:"access_token"`
14+
AccessToken string `envconfig:"ACCESS_TOKEN" json:"access_token,omitempty"`
1715
Endpoint string `envconfig:"ENDPOINT" json:"endpoint"`
1816
Repo string `envconfig:"REPO" json:"repo"` // Should be "owner/repo" format
1917
}
@@ -52,29 +50,6 @@ type Configuration struct {
5250
Roles []string `envconfig:"ROLES" json:"roles"`
5351
}
5452

55-
func maskAccessToken(token string) string {
56-
return strings.Repeat("*", len(token))
57-
}
58-
59-
func githubEndpoint(endpoint string) string {
60-
if endpoint == "" {
61-
return DefaultGitHubEndpoint
62-
}
63-
return endpoint
64-
}
65-
66-
func (gh *GitHubConfig) MarshalJSON() ([]byte, error) {
67-
return json.Marshal(&struct {
68-
AccessToken string `json:"access_token"`
69-
Endpoint string `json:"endpoint"`
70-
Repo string `json:"repo"`
71-
}{
72-
AccessToken: maskAccessToken(gh.AccessToken),
73-
Endpoint: githubEndpoint(gh.Endpoint),
74-
Repo: gh.Repo,
75-
})
76-
}
77-
7853
func loadEnvironment(filename string) error {
7954
var err error
8055
if filename != "" {
@@ -121,4 +96,7 @@ func LoadConfig(filename string) (*Configuration, error) {
12196

12297
// ApplyDefaults sets defaults for a Configuration
12398
func (config *Configuration) ApplyDefaults() {
99+
if config.GitHub.Endpoint == "" {
100+
config.GitHub.Endpoint = DefaultGitHubEndpoint
101+
}
124102
}

0 commit comments

Comments
 (0)