Initial scaffold: API service, K8s operator, and CRDs
Forgebot is a K8s operator + API service for dispatching AI agent jobs from git forge commands. Includes: - CRDs: AgentPool, AgentTask, ProviderQueue, RepositoryBinding - API server with webhook handler, task queue, and comment proxy - Operator controllers for task scheduling and job management - Gitea provider with webhook parsing and signature verification - PostgreSQL database with auto-migration - Woodpecker CI pipelines and multi-stage Dockerfiles
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
api *gitea.Client
|
||||
url string
|
||||
}
|
||||
|
||||
func NewClient(url, token string) *Client {
|
||||
client, _ := gitea.NewClient(url, gitea.SetToken(token))
|
||||
return &Client{
|
||||
api: client,
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
sdk "code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
func (c *Client) PostComment(owner, repo string, issueOrPR int, body string) error {
|
||||
_, _, err := c.api.CreateIssueComment(owner, repo, int64(issueOrPR), sdk.CreateIssueCommentOption{
|
||||
Body: body,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) AddReaction(owner, repo string, commentID int64, reaction string) error {
|
||||
_, _, err := c.api.PostIssueCommentReaction(owner, repo, commentID, reaction)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.unkin.net/unkin/forgebot/internal/provider"
|
||||
)
|
||||
|
||||
type webhookPayload struct {
|
||||
Action string `json:"action"`
|
||||
Comment *commentPayload `json:"comment,omitempty"`
|
||||
Issue *issuePayload `json:"issue,omitempty"`
|
||||
Repository *repoPayload `json:"repository"`
|
||||
PullRequest *prPayload `json:"pull_request,omitempty"`
|
||||
}
|
||||
|
||||
type commentPayload struct {
|
||||
ID int64 `json:"id"`
|
||||
Body string `json:"body"`
|
||||
User struct {
|
||||
Login string `json:"login"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
type issuePayload struct {
|
||||
Number int `json:"number"`
|
||||
PullRequest *struct{} `json:"pull_request,omitempty"`
|
||||
}
|
||||
|
||||
type prPayload struct {
|
||||
Number int `json:"number"`
|
||||
Head struct {
|
||||
Ref string `json:"ref"`
|
||||
} `json:"head"`
|
||||
}
|
||||
|
||||
type repoPayload struct {
|
||||
FullName string `json:"full_name"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
}
|
||||
|
||||
func (c *Client) ParseWebhook(body []byte, secret string) (*provider.WebhookEvent, error) {
|
||||
var payload webhookPayload
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal webhook: %w", err)
|
||||
}
|
||||
|
||||
if payload.Action != "created" || payload.Comment == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
event := &provider.WebhookEvent{
|
||||
Action: payload.Action,
|
||||
Repository: payload.Repository.FullName,
|
||||
CommentID: payload.Comment.ID,
|
||||
Body: payload.Comment.Body,
|
||||
Author: payload.Comment.User.Login,
|
||||
}
|
||||
|
||||
if payload.Issue != nil {
|
||||
if payload.Issue.PullRequest != nil {
|
||||
event.Type = "pull_request_comment"
|
||||
event.PRNum = payload.Issue.Number
|
||||
if payload.PullRequest != nil {
|
||||
event.Ref = payload.PullRequest.Head.Ref
|
||||
}
|
||||
} else {
|
||||
event.Type = "issue_comment"
|
||||
event.IssueNum = payload.Issue.Number
|
||||
}
|
||||
event.Ref = payload.Repository.DefaultBranch
|
||||
}
|
||||
|
||||
return event, nil
|
||||
}
|
||||
|
||||
func VerifySignature(body []byte, secret, signature string) bool {
|
||||
if secret == "" {
|
||||
return true
|
||||
}
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
mac.Write(body)
|
||||
expected := hex.EncodeToString(mac.Sum(nil))
|
||||
return hmac.Equal([]byte(expected), []byte(signature))
|
||||
}
|
||||
Reference in New Issue
Block a user