mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
feat(git): push webhook receiver + repo connect on service create
New public POST /api/git/webhooks/🆔 verifies provider signatures (GitHub/Gitea HMAC-SHA256, GitLab token), filters branch pushes, matches connected repo to services by clone_url/full_name + branch, inserts deployment rows and enqueues runDeploymentAndSync (trigger=webhook). Service-create dialog now connects the selected provider repo and registers a push webhook (409-tolerant via connected-repo lookup). api-client: connectGitRepository, listConnectedGitRepositories, createGitWebhook typed from generated schemas. GitWebhook spec schema corrected (events array + branch field). Authored By: TDvorak <[email protected]>
This commit is contained in:
1 parent
93e3074477
commit
25703592c6
8 files changed
+550
-11
No files matched your search
@@ -0,0 +1,84 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func signBody(t *testing.T, secret string, body []byte) string {
|
||||
t.Helper()
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
mac.Write(body)
|
||||
return hex.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
func TestVerifyGitWebhookSignature(t *testing.T) {
|
||||
body := []byte(`{"ref":"refs/heads/main"}`)
|
||||
secret := "test-secret"
|
||||
valid := signBody(t, secret, body)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
provider string
|
||||
headers map[string]string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "github sha256 prefix",
|
||||
provider: "github",
|
||||
headers: map[string]string{"X-Hub-Signature-256": "sha256=" + valid},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "gitea signature",
|
||||
provider: "gitea",
|
||||
headers: map[string]string{"X-Gitea-Signature": valid},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "gitlab token",
|
||||
provider: "gitlab",
|
||||
headers: map[string]string{"X-Gitlab-Token": secret},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "gitlab rejects wrong token",
|
||||
provider: "gitlab",
|
||||
headers: map[string]string{"X-Gitlab-Token": "wrong"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "github rejects wrong signature",
|
||||
provider: "github",
|
||||
headers: map[string]string{"X-Hub-Signature-256": "sha256=" + signBody(t, "other", body)},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "missing signature",
|
||||
provider: "github",
|
||||
headers: map[string]string{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "malformed hex",
|
||||
provider: "github",
|
||||
headers: map[string]string{"X-Hub-Signature-256": "sha256=zzz"},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest("POST", "/api/git/webhooks/x", nil)
|
||||
for k, v := range tc.headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
if got := verifyGitWebhookSignature(tc.provider, secret, req, body); got != tc.want {
|
||||
t.Fatalf("verifyGitWebhookSignature = %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user