1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-08-11 17:50:58 +00:00

integrate the new cache proxy with the server viceice set up

This commit is contained in:
Kwonunn 2024-12-07 17:48:07 +01:00 committed by Kwonunn
parent a6a1df7556
commit 95e754c06b
3 changed files with 58 additions and 52 deletions

View file

@ -20,6 +20,7 @@ import (
"github.com/timshannon/bolthold" "github.com/timshannon/bolthold"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
"github.com/nektos/act/pkg/cacheproxy"
"github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/common"
) )
@ -83,12 +84,12 @@ func StartHandler(dir, outboundIP string, port uint16, secret string, logger log
} }
router := httprouter.New() router := httprouter.New()
router.GET(cachePrefixPath+urlBase+"/cache", h.middleware(h.find)) router.GET(urlBase+"/cache", h.middleware(h.find))
router.POST(cachePrefixPath+urlBase+"/caches", h.middleware(h.reserve)) router.POST(urlBase+"/caches", h.middleware(h.reserve))
router.PATCH(cachePrefixPath+urlBase+"/caches/:id", h.middleware(h.upload)) router.PATCH(urlBase+"/caches/:id", h.middleware(h.upload))
router.POST(cachePrefixPath+urlBase+"/caches/:id", h.middleware(h.commit)) router.POST(urlBase+"/caches/:id", h.middleware(h.commit))
router.GET(cachePrefixPath+urlBase+"/artifacts/:id", h.middleware(h.get)) router.GET(urlBase+"/artifacts/:id", h.middleware(h.get))
router.POST(cachePrefixPath+urlBase+"/clean", h.middleware(h.clean)) router.POST(urlBase+"/clean", h.middleware(h.clean))
h.router = router h.router = router
@ -159,7 +160,8 @@ func (h *Handler) openDB() (*bolthold.Store, error) {
// GET /_apis/artifactcache/cache // GET /_apis/artifactcache/cache
func (h *Handler) find(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) find(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
repo, err := h.validateMac(params) rundata := runDataFromHeaders(r)
repo, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -206,7 +208,8 @@ func (h *Handler) find(w http.ResponseWriter, r *http.Request, params httprouter
// POST /_apis/artifactcache/caches // POST /_apis/artifactcache/caches
func (h *Handler) reserve(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) reserve(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
repo, err := h.validateMac(params) rundata := runDataFromHeaders(r)
repo, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -243,7 +246,8 @@ func (h *Handler) reserve(w http.ResponseWriter, r *http.Request, params httprou
// PATCH /_apis/artifactcache/caches/:id // PATCH /_apis/artifactcache/caches/:id
func (h *Handler) upload(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) upload(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
repo, err := h.validateMac(params) rundata := runDataFromHeaders(r)
repo, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -296,7 +300,8 @@ func (h *Handler) upload(w http.ResponseWriter, r *http.Request, params httprout
// POST /_apis/artifactcache/caches/:id // POST /_apis/artifactcache/caches/:id
func (h *Handler) commit(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) commit(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
repo, err := h.validateMac(params) rundata := runDataFromHeaders(r)
repo, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -363,7 +368,8 @@ func (h *Handler) commit(w http.ResponseWriter, r *http.Request, params httprout
// GET /_apis/artifactcache/artifacts/:id // GET /_apis/artifactcache/artifacts/:id
func (h *Handler) get(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) get(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
repo, err := h.validateMac(params) rundata := runDataFromHeaders(r)
repo, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -403,7 +409,8 @@ func (h *Handler) get(w http.ResponseWriter, r *http.Request, params httprouter.
// POST /_apis/artifactcache/clean // POST /_apis/artifactcache/clean
func (h *Handler) clean(w http.ResponseWriter, r *http.Request, params httprouter.Params) { func (h *Handler) clean(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
_, err := h.validateMac(params) rundata := runDataFromHeaders(r)
_, err := h.validateMac(rundata)
if err != nil { if err != nil {
h.responseJSON(w, r, 500, err) h.responseJSON(w, r, 500, err)
return return
@ -621,3 +628,12 @@ func parseContentRange(s string) (uint64, uint64, error) {
} }
return start, stop, nil return start, stop, nil
} }
func runDataFromHeaders(r *http.Request) cacheproxy.RunData {
return cacheproxy.RunData{
RepositoryFullName: r.Header.Get("Forgejo-Cache-Repo"),
RunNumber: r.Header.Get("Forgejo-Cache-RunNumber"),
Timestamp: r.Header.Get("Forgejo-Cache-Timestamp"),
RepositoryMAC: r.Header.Get("Forgejo-Cache-MAC"),
}
}

View file

@ -6,36 +6,29 @@ package artifactcache
import ( import (
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"encoding/hex"
"errors" "errors"
"hash"
"strconv" "strconv"
"time" "time"
"github.com/julienschmidt/httprouter" "github.com/nektos/act/pkg/cacheproxy"
) )
var ( var (
ErrValidation = errors.New("validation error") ErrValidation = errors.New("validation error")
cachePrefixPath = "/:org/:repo/:run/:ts/:mac"
) )
func (h *Handler) validateMac(params httprouter.Params) (string, error) { func (h *Handler) validateMac(rundata cacheproxy.RunData) (string, error) {
ts := params.ByName("ts")
repo := params.ByName("org") + "/" + params.ByName("repo")
run := params.ByName("run")
messageMAC := params.ByName("mac")
// TODO: allow configurable max age // TODO: allow configurable max age
if !validateAge(ts) { if !validateAge(rundata.Timestamp) {
return "", ErrValidation return "", ErrValidation
} }
expectedMAC := computeMac(h.secret, repo, run, ts).Sum(nil) expectedMAC := computeMac(h.secret, rundata.RepositoryFullName, rundata.RunNumber, rundata.Timestamp)
if hmac.Equal([]byte(messageMAC), expectedMAC) { if expectedMAC == rundata.RepositoryMAC {
return repo, nil return rundata.RepositoryFullName, nil
} }
return repo, ErrValidation return rundata.RepositoryFullName, ErrValidation
} }
func validateAge(ts string) bool { func validateAge(ts string) bool {
@ -49,15 +42,10 @@ func validateAge(ts string) bool {
return true return true
} }
func computeMac(key, repo, run, ts string) hash.Hash { func computeMac(secret, repo, run, ts string) string {
mac := hmac.New(sha256.New, []byte(key)) mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(repo)) mac.Write([]byte(repo))
mac.Write([]byte(run)) mac.Write([]byte(run))
mac.Write([]byte(ts)) mac.Write([]byte(ts))
return mac return hex.EncodeToString(mac.Sum(nil))
}
func ComputeMac(key, repo, run, ts string) string {
mac := computeMac(key, repo, run, ts)
return string(mac.Sum(nil))
} }

View file

@ -45,19 +45,19 @@ type Handler struct {
} }
type RunData struct { type RunData struct {
repositoryFullName string RepositoryFullName string
runNumber string RunNumber string
timestamp string Timestamp string
repositoryMAC string RepositoryMAC string
} }
func (h *Handler) CreateRunData(fullName string, runNumber string, timestamp string) RunData { func (h *Handler) CreateRunData(fullName string, runNumber string, timestamp string) RunData {
mac := computeMac(h.cacheSecret, fullName, runNumber, timestamp) mac := computeMac(h.cacheSecret, fullName, runNumber, timestamp)
return RunData{ return RunData{
repositoryFullName: fullName, RepositoryFullName: fullName,
runNumber: runNumber, RunNumber: runNumber,
timestamp: timestamp, Timestamp: timestamp,
repositoryMAC: mac, RepositoryMAC: mac,
} }
} }
@ -126,16 +126,14 @@ func proxyRequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter,
} }
func (h *Handler) newReverseProxy(targetHost string) (*httputil.ReverseProxy, error) { func (h *Handler) newReverseProxy(targetHost string) (*httputil.ReverseProxy, error) {
url, err := url.Parse(targetHost) targetURL, err := url.Parse(targetHost)
if err != nil { if err != nil {
return nil, err return nil, err
} }
proxy := &httputil.ReverseProxy{ proxy := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) { Rewrite: func(r *httputil.ProxyRequest) {
r.SetURL(url) re := regexp.MustCompile(`/(\w+)(/_apis/artifactcache/.+)`)
r.Out.Host = r.In.Host // if desired
re := regexp.MustCompile(`/(\w+)/_apis/artifactcache`)
matches := re.FindStringSubmatch(r.In.URL.Path) matches := re.FindStringSubmatch(r.In.URL.Path)
id := matches[1] id := matches[1]
data, ok := h.runs.Load(id) data, ok := h.runs.Load(id)
@ -146,11 +144,15 @@ func (h *Handler) newReverseProxy(targetHost string) (*httputil.ReverseProxy, er
// ! it really shouldn't happen anyway so it's fine for now // ! it really shouldn't happen anyway so it's fine for now
return return
} }
uri := matches[2]
r.Out.Header.Add("Forgejo-Cache-Repo", runData.repositoryFullName) r.SetURL(targetURL)
r.Out.Header.Add("Forgejo-Cache-RunNumber", runData.runNumber) r.Out.URL.Path = uri
r.Out.Header.Add("Forgejo-Cache-Timestamp", runData.timestamp)
r.Out.Header.Add("Forgejo-Cache-MAC", runData.repositoryMAC) r.Out.Header.Add("Forgejo-Cache-Repo", runData.RepositoryFullName)
r.Out.Header.Add("Forgejo-Cache-RunNumber", runData.RunNumber)
r.Out.Header.Add("Forgejo-Cache-Timestamp", runData.Timestamp)
r.Out.Header.Add("Forgejo-Cache-MAC", runData.RepositoryMAC)
}, },
} }
return proxy, nil return proxy, nil