feat: artifacts client
All checks were successful
default / ensure tests work (push) Successful in 29s
All checks were successful
default / ensure tests work (push) Successful in 29s
This commit is contained in:
parent
24ad00274d
commit
402ecfd760
1 changed files with 1162 additions and 6 deletions
84
artifact/jwt.go
Normal file
84
artifact/jwt.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package artifact
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JobInfo returns the backend workflow run and job identifiers encoded in the
|
||||
// ACTIONS_RUNTIME_TOKEN environment variable. The token is only available from
|
||||
// the context of an action.
|
||||
func JobInfo() (run, job string, err error) {
|
||||
return jobInfo(os.Getenv)
|
||||
}
|
||||
|
||||
func jobInfo(env func(string) string) (string, string, error) {
|
||||
var empty string
|
||||
rt := env("ACTIONS_RUNTIME_TOKEN")
|
||||
if rt == "" {
|
||||
return empty, empty, fmt.Errorf("env ACTIONS_RUNTIME_TOKEN is only available from the context of an action")
|
||||
}
|
||||
jt, err := newJwtDecode(rt)
|
||||
if err != nil {
|
||||
return empty, empty, err
|
||||
}
|
||||
scp, ok := jt.Payload["scp"].(string)
|
||||
if !ok {
|
||||
return empty, empty, fmt.Errorf("no scp in ACTIONS_RUNTIME_TOKEN")
|
||||
}
|
||||
for _, scopes := range strings.Split(scp, " ") {
|
||||
parts := strings.Split(scopes, ":")
|
||||
if parts[0] != "Actions.Results" {
|
||||
continue
|
||||
}
|
||||
if len(parts) != 3 {
|
||||
return empty, empty, fmt.Errorf("invalid scp in ACTIONS_RUNTIME_TOKEN")
|
||||
}
|
||||
return parts[1], parts[2], nil
|
||||
}
|
||||
|
||||
return empty, empty, fmt.Errorf("no backend ids found")
|
||||
}
|
||||
|
||||
type jwt struct {
|
||||
Header map[string]any
|
||||
Payload map[string]any
|
||||
Signature string
|
||||
}
|
||||
|
||||
func newJwtDecode(token string) (*jwt, error) {
|
||||
parts := strings.Split(token, ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, fmt.Errorf("invalid JWT: expected 3 segments")
|
||||
}
|
||||
|
||||
decode := func(seg string) ([]byte, error) {
|
||||
if l := len(seg) % 4; l != 0 {
|
||||
seg += strings.Repeat("=", 4-l)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(seg)
|
||||
}
|
||||
|
||||
headerBytes, err := decode(parts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid JWT header: %v", err)
|
||||
}
|
||||
var header map[string]any
|
||||
if err := json.Unmarshal(headerBytes, &header); err != nil {
|
||||
return nil, fmt.Errorf("invalid JWT header json: %v", err)
|
||||
}
|
||||
|
||||
payloadBytes, err := decode(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid JWT payload: %v", err)
|
||||
}
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(payloadBytes, &payload); err != nil {
|
||||
return nil, fmt.Errorf("invalid JWT payload json: %v", err)
|
||||
}
|
||||
|
||||
return &jwt{Header: header, Payload: payload, Signature: parts[2]}, nil
|
||||
}
|
||||
Loading…
Reference in a new issue