feat(task): replace built-in task adaptors with a sandboxed JS plugin system (#7076)

This commit is contained in:
Calcium-Ion
2026-08-29 18:51:57 +08:00
committed by GitHub
parent 7037ac15bd
commit eb48396d5f
336 changed files with 52333 additions and 6369 deletions
+139
View File
@@ -0,0 +1,139 @@
package jsplugin
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"net/url"
"sort"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
"github.com/grafana/sobek"
)
type volcSignRequest struct {
Method string `json:"method"`
URL string `json:"url"`
Headers map[string]string `json:"headers"`
Body string `json:"body"`
AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"`
Region string `json:"region"`
Service string `json:"service"`
Timestamp int64 `json:"timestamp"`
}
func injectGlobals(runtime *sobek.Runtime, identity func() string, now func() time.Time, logOutput func(string)) error {
utils := map[string]any{
"unixNow": func() int64 { return now().Unix() },
"jwtSignHS256": func(claims map[string]any, secret string) (string, error) {
return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims)).SignedString([]byte(secret))
},
"hmacSHA256": func(message, secret string) string {
mac := hmac.New(sha256.New, []byte(secret))
_, _ = mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil))
},
"base64": func(value string) string { return base64.StdEncoding.EncodeToString([]byte(value)) },
"base64URL": func(value string) string {
return base64.RawURLEncoding.EncodeToString([]byte(value))
},
"base64URLDecode": func(value string) (string, error) {
decoded, err := base64.RawURLEncoding.DecodeString(value)
return string(decoded), err
},
"uuid": func() string { return uuid.NewString() },
"volcSignV4": func(request volcSignRequest) (map[string]string, error) {
return signVolcV4(request, now)
},
}
if err := runtime.Set("utils", utils); err != nil {
return err
}
console := runtime.NewObject()
if err := console.Set("log", func(call sobek.FunctionCall) sobek.Value {
parts := make([]string, len(call.Arguments))
for i, argument := range call.Arguments {
parts[i] = argument.String()
}
if logOutput != nil {
logOutput(identity() + " " + strings.Join(parts, " "))
}
return sobek.Undefined()
}); err != nil {
return err
}
return runtime.Set("console", console)
}
func signVolcV4(request volcSignRequest, now func() time.Time) (map[string]string, error) {
parsedURL, err := url.Parse(request.URL)
if err != nil || parsedURL.Host == "" {
return nil, fmt.Errorf("invalid Volcengine signing URL")
}
region := request.Region
if region == "" {
region = "cn-north-1"
}
service := request.Service
if service == "" {
service = "cv"
}
timestamp := now().UTC()
if request.Timestamp != 0 {
timestamp = time.Unix(request.Timestamp, 0).UTC()
}
xDate := timestamp.Format("20060102T150405Z")
shortDate := timestamp.Format("20060102")
bodyHash := sha256.Sum256([]byte(request.Body))
requestPath := parsedURL.EscapedPath()
if requestPath == "" {
requestPath = "/"
}
headers := make(map[string]string, len(request.Headers)+3)
for name, value := range request.Headers {
headers[strings.ToLower(name)] = strings.TrimSpace(value)
}
headers["host"] = parsedURL.Host
headers["x-date"] = xDate
headers["x-content-sha256"] = hex.EncodeToString(bodyHash[:])
keys := make([]string, 0, len(headers))
for name := range headers {
keys = append(keys, name)
}
sort.Strings(keys)
var canonicalHeaders strings.Builder
for _, name := range keys {
canonicalHeaders.WriteString(name)
canonicalHeaders.WriteByte(':')
canonicalHeaders.WriteString(headers[name])
canonicalHeaders.WriteByte('\n')
}
signedHeaders := strings.Join(keys, ";")
canonicalRequest := strings.Join([]string{
strings.ToUpper(request.Method), requestPath, parsedURL.Query().Encode(),
canonicalHeaders.String(), signedHeaders, hex.EncodeToString(bodyHash[:]),
}, "\n")
canonicalHash := sha256.Sum256([]byte(canonicalRequest))
scope := fmt.Sprintf("%s/%s/%s/request", shortDate, region, service)
stringToSign := fmt.Sprintf("HMAC-SHA256\n%s\n%s\n%s", xDate, scope, hex.EncodeToString(canonicalHash[:]))
sign := func(key []byte, value string) []byte {
mac := hmac.New(sha256.New, key)
_, _ = mac.Write([]byte(value))
return mac.Sum(nil)
}
signingKey := sign(sign(sign([]byte(request.SecretKey), shortDate), region), service)
signingKey = sign(signingKey, "request")
signature := hex.EncodeToString(sign(signingKey, stringToSign))
return map[string]string{
"Authorization": fmt.Sprintf("HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s", request.AccessKey, scope, signedHeaders, signature),
"X-Date": xDate,
"X-Content-Sha256": hex.EncodeToString(bodyHash[:]),
}, nil
}