b058fb4012
Also resolves a warning for current releases ``` | ##[group]GitHub Actions runtime token ACs | ##[warning]Cannot parse GitHub Actions Runtime Token ACs: "undefined" is not valid JSON | ##[endgroup] ====> | ##[group]GitHub Actions runtime token ACs | ##[endgroup] ``` \* this is an error in v3 References in the docker org: -831ca179d3/src/main.ts (L24)
-7d8b4dc669/src/github.ts (L61)
No known official action of GitHub makes use of this claim. Current releases throw an error when configure to use actions cache ``` | ERROR: failed to solve: failed to configure gha cache exporter: invalid token without access controls | ##[error]buildx failed with: ERROR: failed to solve: failed to configure gha cache exporter: invalid token without access controls ``` (cherry picked from commit 368743baf3d904f86b553a88718583906f571c87)
103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
// Copyright 2024 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/modules/json"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
type actionsClaims struct {
|
|
jwt.RegisteredClaims
|
|
Scp string `json:"scp"`
|
|
TaskID int64
|
|
RunID int64
|
|
JobID int64
|
|
Ac string `json:"ac"`
|
|
}
|
|
|
|
type actionsCacheScope struct {
|
|
Scope string
|
|
Permission actionsCachePermission
|
|
}
|
|
|
|
type actionsCachePermission int
|
|
|
|
const (
|
|
actionsCachePermissionRead = 1 << iota
|
|
actionsCachePermissionWrite
|
|
)
|
|
|
|
func CreateAuthorizationToken(taskID, runID, jobID int64) (string, error) {
|
|
now := time.Now()
|
|
|
|
ac, err := json.Marshal(&[]actionsCacheScope{
|
|
{
|
|
Scope: "",
|
|
Permission: actionsCachePermissionWrite,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
claims := actionsClaims{
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)),
|
|
NotBefore: jwt.NewNumericDate(now),
|
|
},
|
|
Scp: fmt.Sprintf("Actions.Results:%d:%d", runID, jobID),
|
|
Ac: string(ac),
|
|
TaskID: taskID,
|
|
RunID: runID,
|
|
JobID: jobID,
|
|
}
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
|
|
tokenString, err := token.SignedString(setting.GetGeneralTokenSigningSecret())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return tokenString, nil
|
|
}
|
|
|
|
func ParseAuthorizationToken(req *http.Request) (int64, error) {
|
|
h := req.Header.Get("Authorization")
|
|
if h == "" {
|
|
return 0, nil
|
|
}
|
|
|
|
parts := strings.SplitN(h, " ", 2)
|
|
if len(parts) != 2 {
|
|
log.Error("split token failed: %s", h)
|
|
return 0, fmt.Errorf("split token failed")
|
|
}
|
|
|
|
token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
|
|
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
|
}
|
|
return setting.GetGeneralTokenSigningSecret(), nil
|
|
})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
c, ok := token.Claims.(*actionsClaims)
|
|
if !token.Valid || !ok {
|
|
return 0, fmt.Errorf("invalid token claim")
|
|
}
|
|
|
|
return c.TaskID, nil
|
|
}
|