Skip to content

Commit 6f9f084

Browse files
committed
Support loading git token from disk
Signed-off-by: Henry Muru Paenga <[email protected]>
1 parent 2c15413 commit 6f9f084

11 files changed

+142
-54
lines changed

cmd/server.go

+16-8
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const (
9191
GHHostnameFlag = "gh-hostname"
9292
GHTeamAllowlistFlag = "gh-team-allowlist"
9393
GHTokenFlag = "gh-token"
94+
GHTokenFileFlag = "gh-token-file" // nolint: gosec
9495
GHUserFlag = "gh-user"
9596
GHAppIDFlag = "gh-app-id"
9697
GHAppKeyFlag = "gh-app-key"
@@ -317,6 +318,9 @@ var stringFlags = map[string]stringFlag{
317318
GHTokenFlag: {
318319
description: "GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN environment variable.",
319320
},
321+
GHTokenFileFlag: {
322+
description: "A path to a file containing the GitHub token of API user. Can also be specified via the ATLANTIS_GH_TOKEN_FILE environment variable.",
323+
},
320324
GHAppKeyFlag: {
321325
description: "The GitHub App's private key",
322326
defaultValue: "",
@@ -965,26 +969,29 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
965969
}
966970

967971
// The following combinations are valid.
968-
// 1. github user and token set
972+
// 1. github user and (token or token file)
969973
// 2. github app ID and (key file set or key set)
970974
// 3. gitea user and token set
971975
// 4. gitlab user and token set
972976
// 5. bitbucket user and token set
973977
// 6. azuredevops user and token set
974978
// 7. any combination of the above
975-
vcsErr := fmt.Errorf("--%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s must be set", GHUserFlag, GHTokenFlag, GHAppIDFlag, GHAppKeyFileFlag, GHAppIDFlag, GHAppKeyFlag, GiteaUserFlag, GiteaTokenFlag, GitlabUserFlag, GitlabTokenFlag, BitbucketUserFlag, BitbucketTokenFlag, ADUserFlag, ADTokenFlag)
976-
if ((userConfig.GithubUser == "") != (userConfig.GithubToken == "")) ||
977-
((userConfig.GiteaUser == "") != (userConfig.GiteaToken == "")) ||
979+
vcsErr := fmt.Errorf("--%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s or --%s/--%s must be set", GHUserFlag, GHTokenFlag, GHUserFlag, GHTokenFileFlag, GHAppIDFlag, GHAppKeyFileFlag, GHAppIDFlag, GHAppKeyFlag, GiteaUserFlag, GiteaTokenFlag, GitlabUserFlag, GitlabTokenFlag, BitbucketUserFlag, BitbucketTokenFlag, ADUserFlag, ADTokenFlag)
980+
if ((userConfig.GiteaUser == "") != (userConfig.GiteaToken == "")) ||
978981
((userConfig.GitlabUser == "") != (userConfig.GitlabToken == "")) ||
979982
((userConfig.BitbucketUser == "") != (userConfig.BitbucketToken == "")) ||
980983
((userConfig.AzureDevopsUser == "") != (userConfig.AzureDevopsToken == "")) {
981984
return vcsErr
982985
}
983-
if (userConfig.GithubAppID != 0) && ((userConfig.GithubAppKey == "") && (userConfig.GithubAppKeyFile == "")) {
984-
return vcsErr
986+
if userConfig.GithubUser != "" {
987+
if (userConfig.GithubToken == "") == (userConfig.GithubTokenFile == "") {
988+
return vcsErr
989+
}
985990
}
986-
if (userConfig.GithubAppID == 0) && ((userConfig.GithubAppKey != "") || (userConfig.GithubAppKeyFile != "")) {
987-
return vcsErr
991+
if userConfig.GithubAppID != 0 {
992+
if (userConfig.GithubAppKey == "") == (userConfig.GithubAppKeyFile == "") {
993+
return vcsErr
994+
}
988995
}
989996
// At this point, we know that there can't be a single user/token without
990997
// its partner, but we haven't checked if any user/token is set at all.
@@ -1026,6 +1033,7 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
10261033
// Warn if any tokens have newlines.
10271034
for name, token := range map[string]string{
10281035
GHTokenFlag: userConfig.GithubToken,
1036+
GHTokenFileFlag: userConfig.GithubTokenFile,
10291037
GHWebhookSecretFlag: userConfig.GithubWebhookSecret,
10301038
GitlabTokenFlag: userConfig.GitlabToken,
10311039
GitlabWebhookSecretFlag: userConfig.GitlabWebhookSecret,

cmd/server_test.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ var testFlags = map[string]interface{}{
8686
GHHostnameFlag: "ghhostname",
8787
GHTeamAllowlistFlag: "",
8888
GHTokenFlag: "token",
89+
GHTokenFileFlag: "",
8990
GHUserFlag: "user",
9091
GHAppIDFlag: int64(0),
9192
GHAppKeyFlag: "",
@@ -433,7 +434,7 @@ func TestExecute_ValidateSSLConfig(t *testing.T) {
433434
}
434435

435436
func TestExecute_ValidateVCSConfig(t *testing.T) {
436-
expErr := "--gh-user/--gh-token or --gh-app-id/--gh-app-key-file or --gh-app-id/--gh-app-key or --gitea-user/--gitea-token or --gitlab-user/--gitlab-token or --bitbucket-user/--bitbucket-token or --azuredevops-user/--azuredevops-token must be set"
437+
expErr := "--gh-user/--gh-token or --gh-user/--gh-token-file or --gh-app-id/--gh-app-key-file or --gh-app-id/--gh-app-key or --gitea-user/--gitea-token or --gitlab-user/--gitlab-token or --bitbucket-user/--bitbucket-token or --azuredevops-user/--azuredevops-token must be set"
437438
cases := []struct {
438439
description string
439440
flags map[string]interface{}
@@ -583,6 +584,23 @@ func TestExecute_ValidateVCSConfig(t *testing.T) {
583584
},
584585
false,
585586
},
587+
{
588+
"github user and github token file and should be successful",
589+
map[string]interface{}{
590+
GHUserFlag: "user",
591+
GHTokenFileFlag: "/path/to/token",
592+
},
593+
false,
594+
},
595+
{
596+
"github user, github token, and github token file and should fail",
597+
map[string]interface{}{
598+
GHUserFlag: "user",
599+
GHTokenFlag: "token",
600+
GHTokenFileFlag: "/path/to/token",
601+
},
602+
true,
603+
},
586604
{
587605
"gitea user and gitea token set and should be successful",
588606
map[string]interface{}{

runatlantis.io/docs/server-configuration.md

+10
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,16 @@ based on the organization or user that triggered the webhook.
743743

744744
GitHub token of API user.
745745

746+
### `--gh-token-file`
747+
748+
```bash
749+
atlantis server --gh-token-file="/path/to/token"
750+
# or
751+
ATLANTIS_GH_TOKEN_FILE="/path/to/token"
752+
```
753+
754+
GitHub token of API user. The token is loaded from disk regularly to allow for rotation of the token without the need to restart the Atlantis server.
755+
746756
### `--gh-user`
747757

748758
```bash

server/events/vcs/git_cred_writer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func WriteGitCreds(gitUser string, gitToken string, gitHostname string, home str
4747
if err := fileLineReplace(config, gitUser, gitHostname, credsFile); err != nil {
4848
return errors.Wrap(err, "replacing git credentials line for github app")
4949
}
50-
logger.Info("updated git app credentials in %s", credsFile)
50+
logger.Info("updated git credentials in %s", credsFile)
5151
} else {
5252
if err := fileAppend(config, credsFile); err != nil {
5353
return err

server/events/vcs/github_client_internal_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import (
2222

2323
// If the hostname is github.com, should use normal BaseURL.
2424
func TestNewGithubClient_GithubCom(t *testing.T) {
25-
client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass"}, GithubConfig{}, 0, logging.NewNoopLogger(t))
25+
client, err := NewGithubClient("github.com", &GithubUserCredentials{"user", "pass", ""}, GithubConfig{}, 0, logging.NewNoopLogger(t))
2626
Ok(t, err)
2727
Equals(t, "https://api.github.com/", client.client.BaseURL.String())
2828
}
2929

3030
// If the hostname is a non-github hostname should use the right BaseURL.
3131
func TestNewGithubClient_NonGithub(t *testing.T) {
32-
client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass"}, GithubConfig{}, 0, logging.NewNoopLogger(t))
32+
client, err := NewGithubClient("example.com", &GithubUserCredentials{"user", "pass", ""}, GithubConfig{}, 0, logging.NewNoopLogger(t))
3333
Ok(t, err)
3434
Equals(t, "https://example.com/api/v3/", client.client.BaseURL.String())
3535
// If possible in the future, test the GraphQL client's URL as well. But at the

server/events/vcs/github_client_test.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func TestGithubClient_GetModifiedFiles(t *testing.T) {
6363

6464
testServerURL, err := url.Parse(testServer.URL)
6565
Ok(t, err)
66-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logger)
66+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger)
6767
Ok(t, err)
6868
defer disableSSLVerification()()
6969

@@ -121,7 +121,7 @@ func TestGithubClient_GetModifiedFilesMovedFile(t *testing.T) {
121121

122122
testServerURL, err := url.Parse(testServer.URL)
123123
Ok(t, err)
124-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
124+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
125125
Ok(t, err)
126126
defer disableSSLVerification()()
127127

@@ -218,7 +218,7 @@ func TestGithubClient_PaginatesComments(t *testing.T) {
218218
testServerURL, err := url.Parse(testServer.URL)
219219
Ok(t, err)
220220

221-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
221+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
222222
Ok(t, err)
223223
defer disableSSLVerification()()
224224

@@ -334,7 +334,7 @@ func TestGithubClient_HideOldComments(t *testing.T) {
334334
testServerURL, err := url.Parse(testServer.URL)
335335
Ok(t, err)
336336

337-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{atlantisUser, "pass"}, vcs.GithubConfig{}, 0,
337+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{atlantisUser, "pass", ""}, vcs.GithubConfig{}, 0,
338338
logging.NewNoopLogger(t))
339339
Ok(t, err)
340340
defer disableSSLVerification()()
@@ -407,7 +407,7 @@ func TestGithubClient_UpdateStatus(t *testing.T) {
407407

408408
testServerURL, err := url.Parse(testServer.URL)
409409
Ok(t, err)
410-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
410+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
411411
Ok(t, err)
412412
defer disableSSLVerification()()
413413

@@ -496,7 +496,7 @@ func TestGithubClient_PullIsApproved(t *testing.T) {
496496

497497
testServerURL, err := url.Parse(testServer.URL)
498498
Ok(t, err)
499-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
499+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
500500
Ok(t, err)
501501
defer disableSSLVerification()()
502502

@@ -591,7 +591,7 @@ func TestGithubClient_PullIsMergeable(t *testing.T) {
591591
}))
592592
testServerURL, err := url.Parse(testServer.URL)
593593
Ok(t, err)
594-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
594+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
595595
Ok(t, err)
596596
defer disableSSLVerification()()
597597

@@ -874,7 +874,7 @@ func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApply(t *testing.T)
874874
}))
875875
testServerURL, err := url.Parse(testServer.URL)
876876
Ok(t, err)
877-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{AllowMergeableBypassApply: true}, 0, logging.NewNoopLogger(t))
877+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{AllowMergeableBypassApply: true}, 0, logging.NewNoopLogger(t))
878878
Ok(t, err)
879879
defer disableSSLVerification()()
880880

@@ -959,7 +959,7 @@ func TestGithubClient_MergePullHandlesError(t *testing.T) {
959959

960960
testServerURL, err := url.Parse(testServer.URL)
961961
Ok(t, err)
962-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
962+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
963963
Ok(t, err)
964964
defer disableSSLVerification()()
965965

@@ -1139,7 +1139,7 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) {
11391139

11401140
testServerURL, err := url.Parse(testServer.URL)
11411141
Ok(t, err)
1142-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1142+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
11431143
Ok(t, err)
11441144
defer disableSSLVerification()()
11451145

@@ -1173,7 +1173,7 @@ func TestGithubClient_MergePullCorrectMethod(t *testing.T) {
11731173
}
11741174

11751175
func TestGithubClient_MarkdownPullLink(t *testing.T) {
1176-
client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1176+
client, err := vcs.NewGithubClient("hostname", &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
11771177
Ok(t, err)
11781178
pull := models.PullRequest{Num: 1}
11791179
s, _ := client.MarkdownPullLink(pull)
@@ -1229,7 +1229,7 @@ func TestGithubClient_SplitComments(t *testing.T) {
12291229

12301230
testServerURL, err := url.Parse(testServer.URL)
12311231
Ok(t, err)
1232-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1232+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
12331233
Ok(t, err)
12341234
defer disableSSLVerification()()
12351235
pull := models.PullRequest{Num: 1}
@@ -1288,7 +1288,7 @@ func TestGithubClient_Retry404(t *testing.T) {
12881288

12891289
testServerURL, err := url.Parse(testServer.URL)
12901290
Ok(t, err)
1291-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1291+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
12921292
Ok(t, err)
12931293
defer disableSSLVerification()()
12941294
repo := models.Repo{
@@ -1334,7 +1334,7 @@ func TestGithubClient_Retry404Files(t *testing.T) {
13341334

13351335
testServerURL, err := url.Parse(testServer.URL)
13361336
Ok(t, err)
1337-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1337+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
13381338
Ok(t, err)
13391339
defer disableSSLVerification()()
13401340
repo := models.Repo{
@@ -1387,7 +1387,7 @@ func TestGithubClient_GetTeamNamesForUser(t *testing.T) {
13871387
}))
13881388
testServerURL, err := url.Parse(testServer.URL)
13891389
Ok(t, err)
1390-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logger)
1390+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger)
13911391
Ok(t, err)
13921392
defer disableSSLVerification()()
13931393

@@ -1585,7 +1585,7 @@ func TestGithubClient_DiscardReviews(t *testing.T) {
15851585
}))
15861586
testServerURL, err := url.Parse(testServer.URL)
15871587
Ok(t, err)
1588-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
1588+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logging.NewNoopLogger(t))
15891589
Ok(t, err)
15901590
defer disableSSLVerification()()
15911591
if err := client.DiscardReviews(tt.args.repo, tt.args.pull); (err != nil) != tt.wantErr {
@@ -1654,7 +1654,7 @@ func TestGithubClient_GetPullLabels(t *testing.T) {
16541654
}))
16551655
testServerURL, err := url.Parse(testServer.URL)
16561656
Ok(t, err)
1657-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logger)
1657+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger)
16581658
Ok(t, err)
16591659
defer disableSSLVerification()()
16601660

@@ -1691,7 +1691,7 @@ func TestGithubClient_GetPullLabels_EmptyResponse(t *testing.T) {
16911691
}))
16921692
testServerURL, err := url.Parse(testServer.URL)
16931693
Ok(t, err)
1694-
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{}, 0, logger)
1694+
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass", ""}, vcs.GithubConfig{}, 0, logger)
16951695
Ok(t, err)
16961696
defer disableSSLVerification()()
16971697

server/events/vcs/github_credentials.go

+44-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/http"
77
"net/url"
8+
"os"
89
"strings"
910

1011
"github.com/bradleyfalzon/ghinstallation/v2"
@@ -42,17 +43,45 @@ func (c *GithubAnonymousCredentials) GetToken() (string, error) {
4243

4344
// GithubUserCredentials implements GithubCredentials for the personal auth token flow.
4445
type GithubUserCredentials struct {
45-
User string
46-
Token string
46+
User string
47+
Token string
48+
TokenFile string
49+
}
50+
51+
type GitHubUserTransport struct {
52+
Credentials *GithubUserCredentials
53+
Transport *github.BasicAuthTransport
54+
}
55+
56+
func (t *GitHubUserTransport) RoundTrip(req *http.Request) (*http.Response, error) {
57+
// update token
58+
token, err := t.Credentials.GetToken()
59+
if err != nil {
60+
return nil, err
61+
}
62+
t.Transport.Password = token
63+
64+
// defer to the underlying transport
65+
return t.Transport.RoundTrip(req)
4766
}
4867

4968
// Client returns a client for basic auth user credentials.
5069
func (c *GithubUserCredentials) Client() (*http.Client, error) {
51-
tr := &github.BasicAuthTransport{
52-
Username: strings.TrimSpace(c.User),
53-
Password: strings.TrimSpace(c.Token),
70+
password, err := c.GetToken()
71+
if err != nil {
72+
return nil, err
73+
}
74+
75+
client := &http.Client{
76+
Transport: &GitHubUserTransport{
77+
Credentials: c,
78+
Transport: &github.BasicAuthTransport{
79+
Username: strings.TrimSpace(c.User),
80+
Password: strings.TrimSpace(password),
81+
},
82+
},
5483
}
55-
return tr.Client(), nil
84+
return client, nil
5685
}
5786

5887
// GetUser returns the username for these credentials.
@@ -62,6 +91,15 @@ func (c *GithubUserCredentials) GetUser() (string, error) {
6291

6392
// GetToken returns the user token.
6493
func (c *GithubUserCredentials) GetToken() (string, error) {
94+
if c.TokenFile != "" {
95+
content, err := os.ReadFile(c.TokenFile)
96+
if err != nil {
97+
return "", fmt.Errorf("failed reading github token file: %w", err)
98+
}
99+
100+
return string(content), nil
101+
}
102+
65103
return c.Token, nil
66104
}
67105

0 commit comments

Comments
 (0)