mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-05 01:18:33 +00:00
Co-authored-by: Rui Chen <rui@chenrui.dev>
This commit is contained in:
@@ -90,6 +90,7 @@ const (
|
||||
GHAppKeyFlag = "gh-app-key"
|
||||
GHAppKeyFileFlag = "gh-app-key-file"
|
||||
GHAppSlugFlag = "gh-app-slug"
|
||||
GHInstallationIDFlag = "gh-installation-id"
|
||||
GHOrganizationFlag = "gh-org"
|
||||
GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec
|
||||
GHAllowMergeableBypassApply = "gh-allow-mergeable-bypass-apply" // nolint: gosec
|
||||
@@ -618,6 +619,13 @@ var int64Flags = map[string]int64Flag{
|
||||
description: "GitHub App Id. If defined, initializes the GitHub client with app-based credentials",
|
||||
defaultValue: 0,
|
||||
},
|
||||
GHInstallationIDFlag: {
|
||||
description: "GitHub Installation Id. If defined, initializes the GitHub client with app-based credentials " +
|
||||
"using this specific GitHub Application Installation ID, otherwise it attempts to auto-detect it. " +
|
||||
"Note that this value must be set if you want to have one App and multiple installations of that same " +
|
||||
"application.",
|
||||
defaultValue: 0,
|
||||
},
|
||||
}
|
||||
|
||||
// ValidLogLevels are the valid log levels that can be set
|
||||
|
||||
@@ -91,6 +91,7 @@ var testFlags = map[string]interface{}{
|
||||
GHAppKeyFlag: "",
|
||||
GHAppKeyFileFlag: "",
|
||||
GHAppSlugFlag: "atlantis",
|
||||
GHInstallationIDFlag: int64(0),
|
||||
GHOrganizationFlag: "",
|
||||
GHWebhookSecretFlag: "secret",
|
||||
GiteaBaseURLFlag: "http://localhost",
|
||||
@@ -746,6 +747,21 @@ func TestExecute_GithubApp(t *testing.T) {
|
||||
Equals(t, int64(1), passedConfig.GithubAppID)
|
||||
}
|
||||
|
||||
func TestExecute_GithubAppWithInstallationID(t *testing.T) {
|
||||
t.Log("Should pass the installation ID to the config.")
|
||||
c := setup(map[string]interface{}{
|
||||
GHAppKeyFlag: testdata.GithubPrivateKey,
|
||||
GHAppIDFlag: "1",
|
||||
GHInstallationIDFlag: "2",
|
||||
RepoAllowlistFlag: "*",
|
||||
}, t)
|
||||
err := c.Execute()
|
||||
Ok(t, err)
|
||||
|
||||
Equals(t, int64(1), passedConfig.GithubAppID)
|
||||
Equals(t, int64(2), passedConfig.GithubInstallationID)
|
||||
}
|
||||
|
||||
func TestExecute_GiteaUser(t *testing.T) {
|
||||
t.Log("Should remove the @ from the gitea username if it's passed.")
|
||||
c := setup(map[string]interface{}{
|
||||
|
||||
@@ -7,7 +7,4 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
)
|
||||
require github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
|
||||
26
go.mod
26
go.mod
@@ -47,19 +47,15 @@ require (
|
||||
github.com/xanzy/go-gitlab v0.102.0
|
||||
go.etcd.io/bbolt v1.3.10
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/term v0.19.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/term v0.20.0
|
||||
golang.org/x/text v0.15.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/agext/levenshtein v1.2.3
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.20.1
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
)
|
||||
@@ -82,6 +78,8 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
@@ -92,15 +90,17 @@ require (
|
||||
github.com/gookit/gsr v0.1.0 // indirect
|
||||
github.com/gookit/slog v0.5.5 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
@@ -131,15 +131,15 @@ require (
|
||||
github.com/yuin/gopher-lua v1.1.1 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/oauth2 v0.15.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
golang.org/x/tools v0.21.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
||||
19
go.sum
19
go.sum
@@ -230,9 +230,8 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter/v2 v2.2.1 h1:2JXqPZs1Jej67RtdTi0YZaEB2hEFB3fkBA4cPYKQwFQ=
|
||||
@@ -486,6 +485,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -522,6 +523,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -560,6 +563,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -583,6 +588,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -632,6 +639,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
@@ -640,6 +649,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -652,6 +663,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -701,6 +714,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
|
||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -687,6 +687,21 @@ and set `--autoplan-modules` to `false`.
|
||||
Hostname of your GitHub Enterprise installation. If using [GitHub.com](https://github.com),
|
||||
don't set. Defaults to `github.com`.
|
||||
|
||||
### `--gh-installation-id`
|
||||
|
||||
```bash
|
||||
atlantis server --gh-installation-id="123"
|
||||
# or
|
||||
ATLANTIS_GH_INSTALLATION_ID="123"
|
||||
```
|
||||
|
||||
The installation ID of a specific instance of a GitHub application. Normally this value is
|
||||
derived by querying GitHub for the list of installations of the ID supplied via `--gh-app-id` and selecting
|
||||
the first one found and where multiple installations results in an error. Use this flag if you have multiple
|
||||
instances of Atlantis but you want to use a single already-installed GitHub app for all of them. You would normally do this if
|
||||
you are running a proxy as your single GitHub application that will proxy to an appropriate Atlantis instance
|
||||
based on the organization or user that triggered the webhook.
|
||||
|
||||
### `--gh-org`
|
||||
|
||||
```bash
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock/v4"
|
||||
models "github.com/runatlantis/atlantis/server/events/models"
|
||||
logging "github.com/runatlantis/atlantis/server/logging"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockWorkingDir struct {
|
||||
|
||||
@@ -71,7 +71,7 @@ type GithubAppCredentials struct {
|
||||
Key []byte
|
||||
Hostname string
|
||||
apiURL *url.URL
|
||||
installationID int64
|
||||
InstallationID int64
|
||||
tr *ghinstallation.Transport
|
||||
AppSlug string
|
||||
}
|
||||
@@ -122,8 +122,8 @@ func (c *GithubAppCredentials) GetToken() (string, error) {
|
||||
}
|
||||
|
||||
func (c *GithubAppCredentials) getInstallationID() (int64, error) {
|
||||
if c.installationID != 0 {
|
||||
return c.installationID, nil
|
||||
if c.InstallationID != 0 {
|
||||
return c.InstallationID, nil
|
||||
}
|
||||
|
||||
tr := http.DefaultTransport
|
||||
@@ -148,8 +148,8 @@ func (c *GithubAppCredentials) getInstallationID() (int64, error) {
|
||||
return 0, fmt.Errorf("wrong number of installations, expected 1, found %d", len(installations))
|
||||
}
|
||||
|
||||
c.installationID = installations[0].GetID()
|
||||
return c.installationID, nil
|
||||
c.InstallationID = installations[0].GetID()
|
||||
return c.InstallationID, nil
|
||||
}
|
||||
|
||||
func (c *GithubAppCredentials) transport() (*ghinstallation.Transport, error) {
|
||||
|
||||
@@ -69,3 +69,40 @@ func TestGithubClient_AppAuthentication(t *testing.T) {
|
||||
t.Errorf("app token was not cached: %q != %q", token, newToken)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubClient_MultipleAppAuthentication(t *testing.T) {
|
||||
logger := logging.NewNoopLogger(t)
|
||||
defer disableSSLVerification()()
|
||||
testServer, err := testdata.GithubMultipleAppTestServer(t)
|
||||
Ok(t, err)
|
||||
|
||||
anonCreds := &vcs.GithubAnonymousCredentials{}
|
||||
anonClient, err := vcs.NewGithubClient(testServer, anonCreds, vcs.GithubConfig{}, logging.NewNoopLogger(t))
|
||||
Ok(t, err)
|
||||
tempSecrets, err := anonClient.ExchangeCode(logger, "good-code")
|
||||
Ok(t, err)
|
||||
|
||||
appCreds := &vcs.GithubAppCredentials{
|
||||
AppID: tempSecrets.ID,
|
||||
InstallationID: 1,
|
||||
Key: []byte(testdata.GithubPrivateKey),
|
||||
Hostname: testServer,
|
||||
}
|
||||
_, err = vcs.NewGithubClient(testServer, appCreds, vcs.GithubConfig{}, logging.NewNoopLogger(t))
|
||||
Ok(t, err)
|
||||
|
||||
token, err := appCreds.GetToken()
|
||||
Ok(t, err)
|
||||
|
||||
newToken, err := appCreds.GetToken()
|
||||
Ok(t, err)
|
||||
|
||||
user, err := appCreds.GetUser()
|
||||
Ok(t, err)
|
||||
|
||||
Assert(t, user == "", "user should be empty")
|
||||
|
||||
if token != newToken {
|
||||
t.Errorf("app token was not cached: %q != %q", token, newToken)
|
||||
}
|
||||
}
|
||||
|
||||
128
server/events/vcs/testdata/fixtures.go
vendored
128
server/events/vcs/testdata/fixtures.go
vendored
@@ -496,6 +496,79 @@ var githubAppInstallationJSON = `[
|
||||
}
|
||||
]`
|
||||
|
||||
var githubAppMultipleInstallationJSON = `[
|
||||
{
|
||||
"id": 1,
|
||||
"account": {
|
||||
"login": "github",
|
||||
"id": 1,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
|
||||
"url": "https://api.github.com/orgs/github",
|
||||
"repos_url": "https://api.github.com/orgs/github/repos",
|
||||
"events_url": "https://api.github.com/orgs/github/events",
|
||||
"hooks_url": "https://api.github.com/orgs/github/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/github/issues",
|
||||
"members_url": "https://api.github.com/orgs/github/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
|
||||
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
||||
"description": "A great organization"
|
||||
},
|
||||
"access_tokens_url": "https://api.github.com/installations/1/access_tokens",
|
||||
"repositories_url": "https://api.github.com/installation/repositories",
|
||||
"html_url": "https://github.com/organizations/github/settings/installations/1",
|
||||
"app_id": 1,
|
||||
"target_id": 1,
|
||||
"target_type": "Organization",
|
||||
"permissions": {
|
||||
"metadata": "read",
|
||||
"contents": "read",
|
||||
"issues": "write",
|
||||
"single_file": "write"
|
||||
},
|
||||
"events": [
|
||||
"push",
|
||||
"pull_request"
|
||||
],
|
||||
"single_file_name": "config.yml",
|
||||
"repository_selection": "selected"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"account": {
|
||||
"login": "github",
|
||||
"id": 1,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
|
||||
"url": "https://api.github.com/orgs/github",
|
||||
"repos_url": "https://api.github.com/orgs/github/repos",
|
||||
"events_url": "https://api.github.com/orgs/github/events",
|
||||
"hooks_url": "https://api.github.com/orgs/github/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/github/issues",
|
||||
"members_url": "https://api.github.com/orgs/github/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/github/public_members{/member}",
|
||||
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
||||
"description": "A great organization"
|
||||
},
|
||||
"access_tokens_url": "https://api.github.com/installations/1/access_tokens",
|
||||
"repositories_url": "https://api.github.com/installation/repositories",
|
||||
"html_url": "https://github.com/organizations/github/settings/installations/1",
|
||||
"app_id": 1,
|
||||
"target_id": 1,
|
||||
"target_type": "Organization",
|
||||
"permissions": {
|
||||
"metadata": "read",
|
||||
"contents": "read",
|
||||
"issues": "write",
|
||||
"single_file": "write"
|
||||
},
|
||||
"events": [
|
||||
"push",
|
||||
"pull_request"
|
||||
],
|
||||
"single_file_name": "config.yml",
|
||||
"repository_selection": "selected"
|
||||
}
|
||||
]`
|
||||
|
||||
// nolint: gosec
|
||||
var githubAppTokenJSON = `{
|
||||
"token": "some-token",
|
||||
@@ -741,3 +814,58 @@ func GithubAppTestServer(t *testing.T) (string, error) {
|
||||
|
||||
return testServerURL.Host, err
|
||||
}
|
||||
|
||||
func GithubMultipleAppTestServer(t *testing.T) (string, error) {
|
||||
counter := 0
|
||||
testServer := httptest.NewTLSServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.RequestURI {
|
||||
case "/api/v3/app-manifests/good-code/conversions":
|
||||
encodedKey := strings.Join(strings.Split(GithubPrivateKey, "\n"), "\\n")
|
||||
appInfo := fmt.Sprintf(githubConversionJSON, encodedKey)
|
||||
w.Write([]byte(appInfo)) // nolint: errcheck
|
||||
// https://developer.github.com/v3/apps/#list-installations
|
||||
case "/api/v3/app/installations":
|
||||
token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1)
|
||||
if err := validateGithubToken(token); err != nil {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("Invalid token")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(githubAppMultipleInstallationJSON)) // nolint: errcheck
|
||||
return
|
||||
case "/api/v3/apps/some-app":
|
||||
token := strings.Replace(r.Header.Get("Authorization"), "token ", "", 1)
|
||||
|
||||
// token is taken from githubAppTokenJSON
|
||||
if token != "some-token" {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("Invalid installation token")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
w.Write([]byte(githubAppJSON)) // nolint: errcheck
|
||||
return
|
||||
case "/api/v3/app/installations/1/access_tokens":
|
||||
token := strings.Replace(r.Header.Get("Authorization"), "Bearer ", "", 1)
|
||||
if err := validateGithubToken(token); err != nil {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte("Invalid token")) // nolint: errcheck
|
||||
return
|
||||
}
|
||||
|
||||
appToken := fmt.Sprintf(githubAppTokenJSON, counter)
|
||||
counter++
|
||||
w.Write([]byte(appToken)) // nolint: errcheck
|
||||
return
|
||||
default:
|
||||
t.Errorf("got unexpected request at %q", r.RequestURI)
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
}))
|
||||
|
||||
testServerURL, err := url.Parse(testServer.URL)
|
||||
|
||||
return testServerURL.Host, err
|
||||
}
|
||||
|
||||
@@ -239,18 +239,20 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
githubCredentials = &vcs.GithubAppCredentials{
|
||||
AppID: userConfig.GithubAppID,
|
||||
Key: privateKey,
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
AppID: userConfig.GithubAppID,
|
||||
InstallationID: userConfig.GithubInstallationID,
|
||||
Key: privateKey,
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
}
|
||||
githubAppEnabled = true
|
||||
} else if userConfig.GithubAppID != 0 && userConfig.GithubAppKey != "" {
|
||||
githubCredentials = &vcs.GithubAppCredentials{
|
||||
AppID: userConfig.GithubAppID,
|
||||
Key: []byte(userConfig.GithubAppKey),
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
AppID: userConfig.GithubAppID,
|
||||
InstallationID: userConfig.GithubInstallationID,
|
||||
Key: []byte(userConfig.GithubAppKey),
|
||||
Hostname: userConfig.GithubHostname,
|
||||
AppSlug: userConfig.GithubAppSlug,
|
||||
}
|
||||
githubAppEnabled = true
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ type UserConfig struct {
|
||||
GithubAppKey string `mapstructure:"gh-app-key"`
|
||||
GithubAppKeyFile string `mapstructure:"gh-app-key-file"`
|
||||
GithubAppSlug string `mapstructure:"gh-app-slug"`
|
||||
GithubInstallationID int64 `mapstructure:"gh-installation-id"`
|
||||
GithubTeamAllowlist string `mapstructure:"gh-team-allowlist"`
|
||||
GiteaBaseURL string `mapstructure:"gitea-base-url"`
|
||||
GiteaToken string `mapstructure:"gitea-token"`
|
||||
|
||||
Reference in New Issue
Block a user