建立 Go Task Scheduler 协议骨架
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Package taskidentity derives workload identities from tasks assigned by Gitea.
|
||||
package taskidentity
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
runnerv1 "gitea.dev/actionslib/runner/v1"
|
||||
)
|
||||
|
||||
var safeSegment = regexp.MustCompile(`^[A-Za-z0-9._-]+$`)
|
||||
|
||||
// Identity is the trusted identity context extracted from a fetched task.
|
||||
type Identity struct {
|
||||
Repository string
|
||||
Task string
|
||||
SPIFFEID string
|
||||
}
|
||||
|
||||
// FromTask derives the repository/task SPIFFE ID from Gitea's trusted task
|
||||
// context. Workflow input never supplies or overrides the resulting ID.
|
||||
func FromTask(task *runnerv1.Task, trustDomain string) (Identity, error) {
|
||||
if task == nil || task.Context == nil {
|
||||
return Identity{}, errors.New("task context is required")
|
||||
}
|
||||
|
||||
repository := strings.TrimSpace(task.Context.GetFields()["repository"].GetStringValue())
|
||||
taskName := strings.TrimSpace(task.Context.GetFields()["job"].GetStringValue())
|
||||
parts := strings.Split(repository, "/")
|
||||
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
|
||||
return Identity{}, fmt.Errorf("invalid task repository %q", repository)
|
||||
}
|
||||
if taskName == "" {
|
||||
return Identity{}, errors.New("task job is required")
|
||||
}
|
||||
trustDomain = strings.TrimSpace(trustDomain)
|
||||
if trustDomain == "" || strings.ContainsAny(trustDomain, "/ ") {
|
||||
return Identity{}, fmt.Errorf("invalid trust domain %q", trustDomain)
|
||||
}
|
||||
|
||||
path := strings.Join([]string{
|
||||
sanitize(parts[0]),
|
||||
sanitize(parts[1]),
|
||||
sanitize(taskName),
|
||||
}, "/")
|
||||
return Identity{
|
||||
Repository: repository,
|
||||
Task: taskName,
|
||||
SPIFFEID: "spiffe://" + trustDomain + "/ci/" + path,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// sanitize intentionally matches the bootstrap Python implementation so
|
||||
// existing Zot and OpenBao policies keep their current identity names.
|
||||
func sanitize(value string) string {
|
||||
if safeSegment.MatchString(value) {
|
||||
return value
|
||||
}
|
||||
slug := strings.Trim(regexp.MustCompile(`[^A-Za-z0-9._-]+`).ReplaceAllString(value, "-"), "-._")
|
||||
if len(slug) > 48 {
|
||||
slug = strings.TrimRight(slug[:48], "-._")
|
||||
}
|
||||
if slug == "" {
|
||||
slug = "segment"
|
||||
}
|
||||
digest := fmt.Sprintf("%x", sha256.Sum256([]byte(value)))[:12]
|
||||
return slug + "-" + digest
|
||||
}
|
||||
Reference in New Issue
Block a user