Merge pull request 'Check for repo write permissions -- needed to create labels' (#5) from label-again into main
Reviewed-on: https://git.ts.mattnite.net/mattnite/forgejo-tickets/pulls/5
This commit is contained in:
commit
0df41e08a0
|
|
@ -429,6 +429,42 @@ func (c *Client) CreateLabel(owner, repo, labelName, color string) (*Label, erro
|
|||
return &label, nil
|
||||
}
|
||||
|
||||
// CheckRepoPermission verifies the bot user has write (push) access to the repo.
|
||||
func (c *Client) CheckRepoPermission(owner, repo string) error {
|
||||
reqURL := fmt.Sprintf("%s/api/v1/repos/%s/%s", c.baseURL, owner, repo)
|
||||
httpReq, err := http.NewRequest("GET", reqURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpReq.Header.Set("Authorization", "token "+c.apiToken)
|
||||
|
||||
resp, err := c.httpClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("forgejo API request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("forgejo API returned %d: %s", resp.StatusCode, string(respBody))
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Permissions struct {
|
||||
Admin bool `json:"admin"`
|
||||
Push bool `json:"push"`
|
||||
Pull bool `json:"pull"`
|
||||
} `json:"permissions"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return err
|
||||
}
|
||||
if !result.Permissions.Push {
|
||||
return fmt.Errorf("bot user does not have write access to %s/%s — add it as a collaborator with Write permission", owner, repo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrCreateLabel looks up a label by name, creating it if it doesn't exist.
|
||||
func (c *Client) GetOrCreateLabel(owner, repo, labelName, color string) (*Label, error) {
|
||||
label, err := c.GetLabel(owner, repo, labelName)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,19 @@ func (h *RepoHandler) Create(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Verify the bot user has write access to the Forgejo repo
|
||||
if err := h.deps.ForgejoClient.CheckRepoPermission(forgejoOwner, forgejoRepo); err != nil {
|
||||
log.Error().Err(err).Msg("repo permission check failed")
|
||||
h.deps.Renderer.Render(c.Writer, c.Request, "admin/repos/new", map[string]interface{}{
|
||||
"Error": "Forgejo repo check failed: " + err.Error(),
|
||||
"Name": name,
|
||||
"Slug": slug,
|
||||
"ForgejoOwner": forgejoOwner,
|
||||
"ForgejoRepo": forgejoRepo,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
webhookSecret, err := forgejo.GenerateWebhookSecret()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("generate webhook secret error")
|
||||
|
|
@ -105,10 +118,17 @@ func (h *RepoHandler) EditForm(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Check bot write access to the Forgejo repo
|
||||
var repoPermErr string
|
||||
if err := h.deps.ForgejoClient.CheckRepoPermission(repo.ForgejoOwner, repo.ForgejoRepo); err != nil {
|
||||
repoPermErr = err.Error()
|
||||
}
|
||||
|
||||
h.deps.Renderer.Render(c.Writer, c.Request, "admin/repos/edit", map[string]interface{}{
|
||||
"Repo": repo,
|
||||
"BaseURL": h.deps.Config.BaseURL,
|
||||
"ForgejoURL": h.deps.Config.ForgejoURL,
|
||||
"Repo": repo,
|
||||
"BaseURL": h.deps.Config.BaseURL,
|
||||
"ForgejoURL": h.deps.Config.ForgejoURL,
|
||||
"RepoPermErr": repoPermErr,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,27 @@
|
|||
|
||||
<h1 class="text-2xl font-bold text-gray-900 mb-6">Edit Repo</h1>
|
||||
|
||||
{{if .RepoPermErr}}
|
||||
<div class="mb-6 rounded-md bg-red-50 p-4 ring-1 ring-red-200">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="h-5 w-5 text-red-600" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
||||
</svg>
|
||||
<p class="text-sm font-semibold text-red-800">Bot write access missing</p>
|
||||
</div>
|
||||
<p class="mt-1 text-sm text-red-700">{{.RepoPermErr}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="mb-6 rounded-md bg-green-50 p-4 ring-1 ring-green-200">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="h-5 w-5 text-green-600" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<p class="text-sm font-semibold text-green-800">Bot write access verified</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .Repo.WebhookVerified}}
|
||||
<div class="mb-6 rounded-md bg-green-50 p-4 ring-1 ring-green-200">
|
||||
<div class="flex items-center gap-2">
|
||||
|
|
|
|||
Loading…
Reference in New Issue