Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitee6f795

Browse files
Skarlsomichelvocks
authored andcommitted
Automatically update pipelines github webhook (#48)
* POC: Implement handling of push event.* Some additional comments.* Working hook creation.* Added go-github dependency.* Working hook creation through a UI provided github token.* introduced vault and push build. only thing remaining is triggerring the build.* to be continued.* First unit test for signature checking.* Fixed test.* Merged master and fixed hook test.* Clearing the certificate service as well.* Unit testing createGithubWebhook* A bunch of more tests.* Even moer coverage.* A little bit more coverage.* Fixed the password generation issue. Now it is in the right place. Also fixed the url it was sending.* Fixed tests and correct creation of secret so github accepts it.* Addressed comments.* dep ensure again
1 parent312ae68 commitee6f795

File tree

143 files changed

+38084
-56
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+38084
-56
lines changed

‎Gopkg.lock‎

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Gopkg.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@
6565
branch ="master"
6666
name ="golang.org/x/net"
6767

68+
[[constraint]]
69+
name ="github.com/google/go-github"
70+
version ="15.0.0"
71+
6872
[[constraint]]
6973
name ="google.golang.org/grpc"
7074
version ="1.13.0"

‎cmd/gaia/main.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func init() {
3737
// command line arguments
3838
flag.StringVar(&gaia.Cfg.ListenPort,"port","8080","Listen port for gaia")
3939
flag.StringVar(&gaia.Cfg.HomePath,"homepath","","Path to the gaia home folder")
40+
flag.StringVar(&gaia.Cfg.Hostname,"hostname","https://localhost","The host's name under which gaia is deployed at e.g.: https://gaia-pipeline.com")
4041
flag.StringVar(&gaia.Cfg.VaultPath,"vaultpath","","Path to the gaia vault folder")
4142
flag.StringVar(&gaia.Cfg.Worker,"worker","2","Number of worker gaia will use to execute pipelines in parallel")
4243
flag.StringVar(&gaia.Cfg.JwtPrivateKeyPath,"jwtPrivateKeyPath","","A RSA private key used to sign JWT tokens")

‎frontend/client/views/pipeline/create.vue‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
</span>
3333
<span>Add credentials</span>
3434
</a>
35+
<aclass="button is-primary"v-on:click="showGitHubWebHookModal">
36+
<spanclass="icon">
37+
<iclass="fa fa-wrench"></i>
38+
</span>
39+
<span>Add GitHub WebHook</span>
40+
</a>
3541
</p>
3642
<hrclass="dotted-line">
3743
<labelclass="label">Type the name of your pipeline here.</label>
@@ -179,6 +185,35 @@
179185
</div>
180186
</modal>
181187

188+
<!-- GitHub WebHook modal-->
189+
<modal:visible="gitWebHookModal"class="modal-z-index"@close="close">
190+
<divclass="box credentials-modal">
191+
<divclass="block credentials-modal-content">
192+
<collapseaccordionis-fullwidth>
193+
<collapse-itemtitle="GitHub Token"selected>
194+
<divclass="credentials-modal-content">
195+
<labelclass="label"style="text-align:left;">Add GitHub token with repo permissions:</label>
196+
<pclass="control has-icons-left"style="padding-bottom:5px;">
197+
<inputclass="input is-medium input-bar"v-focustype="text"v-model="createPipeline.githubtoken"placeholder="Token">
198+
<spanclass="icon is-small is-left">
199+
<iclass="fas fa-code-branch"></i>
200+
</span>
201+
</p>
202+
</div>
203+
</collapse-item>
204+
</collapse>
205+
<divclass="modal-footer">
206+
<divstyle="float:left;">
207+
<buttonclass="button is-primary"v-on:click="close">Add Token</button>
208+
</div>
209+
<divstyle="float:right;">
210+
<buttonclass="button is-danger"v-on:click="cancel">Cancel</button>
211+
</div>
212+
</div>
213+
</div>
214+
</div>
215+
</modal>
216+
182217
<!-- status output modal-->
183218
<modal:visible="statusOutputModal"class="modal-z-index"@close="closeStatusModal">
184219
<divclass="box statusModal">
@@ -214,6 +249,7 @@ export default {
214249
gitErrorMsg:'',
215250
gitSuccess:false,
216251
gitCredentialsModal:false,
252+
gitWebHookModal:false,
217253
gitBranches: [],
218254
giturl:'',
219255
pipelinename:'',
@@ -224,6 +260,7 @@ export default {
224260
output:'',
225261
status:0,
226262
created:newDate(),
263+
githubtoken:'',
227264
pipeline: {
228265
name:'',
229266
type:'golang',
@@ -425,6 +462,7 @@ export default {
425462
close () {
426463
this.checkGitRepo()
427464
this.gitCredentialsModal=false
465+
this.gitWebHookModal=false
428466
this.$emit('close')
429467
},
430468
@@ -443,6 +481,10 @@ export default {
443481
this.gitCredentialsModal=true
444482
},
445483
484+
showGitHubWebHookModal () {
485+
this.gitWebHookModal=true
486+
},
487+
446488
showStatusOutputModal (msg) {
447489
if (!msg) {
448490
msg='No output found.'

‎gaia.go‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ const (
7676
// LogsFileName represents the file name of the logs output
7777
LogsFileName="output.log"
7878

79+
// APIVersion represents the current API version
80+
APIVersion="v1"
81+
7982
// TmpFolder is the temp folder for temporary files
8083
TmpFolder="tmp"
8184

@@ -141,12 +144,13 @@ type Argument struct {
141144
// CreatePipeline represents a pipeline which is not yet
142145
// compiled.
143146
typeCreatePipelinestruct {
144-
IDstring`json:"id,omitempty"`
145-
PipelinePipeline`json:"pipeline,omitempty"`
146-
Statusint`json:"status,omitempty"`
147-
StatusTypeCreatePipelineType`json:"statustype,omitempty"`
148-
Outputstring`json:"output,omitempty"`
149-
Created time.Time`json:"created,omitempty"`
147+
IDstring`json:"id,omitempty"`
148+
PipelinePipeline`json:"pipeline,omitempty"`
149+
Statusint`json:"status,omitempty"`
150+
StatusTypeCreatePipelineType`json:"statustype,omitempty"`
151+
Outputstring`json:"output,omitempty"`
152+
Created time.Time`json:"created,omitempty"`
153+
GitHubTokenstring`json:"githubtoken,omitempty"`
150154
}
151155

152156
// PrivateKey represents a pem encoded private key
@@ -179,6 +183,7 @@ type Config struct {
179183
PValint
180184
ListenPortstring
181185
HomePathstring
186+
Hostnamestring
182187
VaultPathstring
183188
DataPathstring
184189
PipelinePathstring
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "ref": "refs/tags/simple-tag", "before": "a10867b14bb761a232cd80139fbd4c0d33264240", "after": "0000000000000000000000000000000000000000", "created": false, "deleted": true, "forced": false, "base_ref": null, "compare": "https://github.com/Codertocat/Hello-World/compare/a10867b14bb7...000000000000", "commits": [ ], "head_commit": null, "repository": { "id": 135493233, "node_id": "MDEwOlJlcG9zaXRvcnkxMzU0OTMyMzM=", "name": "Hello-World", "full_name": "Codertocat/Hello-World", "owner": { "name": "Codertocat", "email": "21031067+Codertocat@users.noreply.github.com", "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }, "private": false, "html_url": "https://github.com/Codertocat/Hello-World", "description": null, "fork": false, "url": "https://github.com/Codertocat/Hello-World", "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", "created_at": 1527711484, "updated_at": "2018-05-30T20:18:35Z", "pushed_at": 1527711528, "git_url": "git://github.com/Codertocat/Hello-World.git", "ssh_url": "git@github.com:Codertocat/Hello-World.git", "clone_url": "https://github.com/Codertocat/Hello-World.git", "svn_url": "https://github.com/Codertocat/Hello-World", "homepage": null, "size": 0, "stargazers_count": 0, "watchers_count": 0, "language": null, "has_issues": true, "has_projects": true, "has_downloads": true, "has_wiki": true, "has_pages": true, "forks_count": 0, "mirror_url": null, "archived": false, "open_issues_count": 2, "license": null, "forks": 0, "open_issues": 2, "watchers": 0, "default_branch": "master", "stargazers": 0, "master_branch": "master" }, "pusher": { "name": "Codertocat", "email": "21031067+Codertocat@users.noreply.github.com" }, "sender": { "login": "Codertocat", "id": 21031067, "node_id": "MDQ6VXNlcjIxMDMxMDY3", "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", "gravatar_id": "", "url": "https://api.github.com/users/Codertocat", "html_url": "https://github.com/Codertocat", "followers_url": "https://api.github.com/users/Codertocat/followers", "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", "organizations_url": "https://api.github.com/users/Codertocat/orgs", "repos_url": "https://api.github.com/users/Codertocat/repos", "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", "received_events_url": "https://api.github.com/users/Codertocat/received_events", "type": "User", "site_admin": false }}

‎handlers/handler.go‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ import (
1616
"github.com/labstack/echo/middleware"
1717
)
1818

19-
const (
20-
// apiVersion represents the current API version
21-
apiVersion="v1"
22-
)
23-
2419
var (
2520
// errNotAuthorized is thrown when user wants to access resource which is protected
2621
errNotAuthorized=errors.New("no or invalid jwt token provided. You are not authorized")
@@ -50,7 +45,7 @@ var (
5045
// InitHandlers initializes(registers) all handlers
5146
funcInitHandlers(e*echo.Echo)error {
5247
// Define prefix
53-
p:="/api/"+apiVersion+"/"
48+
p:="/api/"+gaia.APIVersion+"/"
5449

5550
// --- Register handlers at echo instance ---
5651

@@ -72,6 +67,7 @@ func InitHandlers(e *echo.Echo) error {
7267
e.DELETE(p+"pipeline/:pipelineid",PipelineDelete)
7368
e.POST(p+"pipeline/:pipelineid/start",PipelineStart)
7469
e.GET(p+"pipeline/latest",PipelineGetAllWithLatestRun)
70+
e.POST(p+"pipeline/githook",GitWebHook)
7571

7672
// PipelineRun
7773
e.GET(p+"pipelinerun/:pipelineid/:runid",PipelineRunGet)
@@ -120,8 +116,13 @@ func InitHandlers(e *echo.Echo) error {
120116
// TODO: Role based access
121117
funcauthBarrier(next echo.HandlerFunc) echo.HandlerFunc {
122118
returnfunc(c echo.Context)error {
123-
// Login and static resources are open
124-
ifstrings.Contains(c.Path(),"/login")||c.Path()=="/"||strings.Contains(c.Path(),"/assets/")||c.Path()=="/favicon.ico" {
119+
// Login, WebHook callback and static resources are open
120+
// The webhook callback has it's own authentication method
121+
ifstrings.Contains(c.Path(),"/login")||
122+
c.Path()=="/"||
123+
strings.Contains(c.Path(),"/assets/")||
124+
c.Path()=="/favicon.ico"||
125+
strings.Contains(c.Path(),"pipeline/githook") {
125126
returnnext(c)
126127
}
127128

‎handlers/hook.go‎

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package handlers
2+
3+
import (
4+
"crypto/hmac"
5+
"crypto/sha1"
6+
"encoding/hex"
7+
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"io/ioutil"
11+
"net/http"
12+
"strings"
13+
14+
"github.com/gaia-pipeline/gaia"
15+
16+
"github.com/gaia-pipeline/gaia/pipeline"
17+
"github.com/gaia-pipeline/gaia/services"
18+
19+
"github.com/labstack/echo"
20+
)
21+
22+
// Hook represent a github based webhook context.
23+
typeHookstruct {
24+
Signaturestring
25+
Eventstring
26+
IDstring
27+
Payload []byte
28+
}
29+
30+
// Repository contains information about the repository. All we care about
31+
// here are the possible urls for identification.
32+
typeRepositorystruct {
33+
GitURLstring`json:"git_url"`
34+
SSHURLstring`json:"ssh_url"`
35+
HTMLURLstring`json:"html_url"`
36+
}
37+
38+
// Payload contains information about the event like, user, commit id and so on.
39+
// All we care about for the sake of identification is the repository.
40+
typePayloadstruct {
41+
RepoRepository`json:"repository"`
42+
}
43+
44+
funcsignBody(secret,body []byte) []byte {
45+
computed:=hmac.New(sha1.New,secret)
46+
computed.Write(body)
47+
return []byte(computed.Sum(nil))
48+
}
49+
50+
funcverifySignature(secret []byte,signaturestring,body []byte)bool {
51+
signaturePrefix:="sha1="
52+
signatureLength:=45
53+
54+
iflen(signature)!=signatureLength||!strings.HasPrefix(signature,signaturePrefix) {
55+
returnfalse
56+
}
57+
58+
actual:=make([]byte,20)
59+
hex.Decode(actual, []byte(signature[5:]))
60+
expected:=signBody(secret,body)
61+
returnhmac.Equal(expected,actual)
62+
}
63+
64+
funcparse(secret []byte,req*http.Request) (Hook,error) {
65+
h:=Hook{}
66+
67+
ifh.Signature=req.Header.Get("x-hub-signature");len(h.Signature)==0 {
68+
returnHook{},errors.New("no signature")
69+
}
70+
71+
ifh.Event=req.Header.Get("x-github-event");len(h.Event)==0 {
72+
returnHook{},errors.New("no event")
73+
}
74+
75+
ifh.Event!="push" {
76+
returnHook{},errors.New("invalid event")
77+
}
78+
79+
ifh.ID=req.Header.Get("x-github-delivery");len(h.ID)==0 {
80+
returnHook{},errors.New("no event id")
81+
}
82+
83+
body,err:=ioutil.ReadAll(req.Body)
84+
85+
iferr!=nil {
86+
returnHook{},err
87+
}
88+
89+
if!verifySignature(secret,h.Signature,body) {
90+
returnHook{},errors.New("Invalid signature")
91+
}
92+
93+
h.Payload=body
94+
returnh,err
95+
}
96+
97+
// GitWebHook handles callbacks from GitHub's webhook system.
98+
funcGitWebHook(c echo.Context)error {
99+
vault,err:=services.VaultService(nil)
100+
iferr!=nil {
101+
returnc.String(http.StatusInternalServerError,"unable to initialize vault: "+err.Error())
102+
}
103+
104+
err=vault.LoadSecrets()
105+
iferr!=nil {
106+
returnc.String(http.StatusInternalServerError,"unable to open vault: "+err.Error())
107+
}
108+
109+
secret,err:=vault.Get("GITHUB_WEBHOOK_SECRET")
110+
iferr!=nil {
111+
returnc.String(http.StatusBadRequest,err.Error())
112+
}
113+
114+
h,err:=parse(secret,c.Request())
115+
c.Request().Header.Set("Content-type","application/json")
116+
117+
iferr!=nil {
118+
returnc.String(http.StatusBadRequest,err.Error())
119+
}
120+
121+
p:=new(Payload)
122+
iferr:=json.Unmarshal(h.Payload,p);err!=nil {
123+
returnc.String(http.StatusBadRequest,"error in unmarshalling json payload")
124+
}
125+
126+
varfoundPipe*gaia.Pipeline
127+
forpipe:=rangepipeline.GlobalActivePipelines.Iter() {
128+
ifpipe.Repo.URL==p.Repo.GitURL||pipe.Repo.URL==p.Repo.HTMLURL||pipe.Repo.URL==p.Repo.SSHURL {
129+
foundPipe=&pipe
130+
}
131+
}
132+
err=pipeline.UpdateRepository(foundPipe)
133+
iferr!=nil {
134+
message:=fmt.Sprintln("failed to build pipeline: ",err.Error())
135+
returnc.String(http.StatusInternalServerError,message)
136+
}
137+
returnc.String(http.StatusOK,"successfully processed event")
138+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp