.forgejo: add build/test workflows #478

Merged
fyrchik merged 3 commits from fyrchik/frostfs-node:add-workflows into master 2023-06-28 15:01:51 +00:00
4 changed files with 147 additions and 41 deletions

View file

@ -0,0 +1,38 @@
name: Build
on: [pull_request]
jobs:
build:
name: Build Components
runs-on: ubuntu-latest
strategy:
matrix:
go_versions: [ '1.19', '1.20' ]
steps:
- uses: actions/checkout@v3
with:
# Allows to fetch all history for all branches and tags.
# Need this for proper versioning.
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go_versions }}'
- name: Build CLI
run: make bin/frostfs-cli
- name: Build NODE
run: make bin/frostfs-node
- name: Build IR
run: make bin/frostfs-ir
- name: Build ADM
run: make bin/frostfs-adm
- name: Build LENS
run: make bin/frostfs-lens

View file

@ -0,0 +1,54 @@
name: Tests and linters
on: [pull_request]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
cache: true
- name: golangci-lint
uses: https://github.com/golangci/golangci-lint-action@v3
with:
version: latest
tests:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
go_versions: [ '1.19', '1.20' ]
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go_versions }}'
cache: true
- name: Run tests
run: make test
tests-race:
name: Tests with -race
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
cache: true
- name: Run tests
run: go test ./... -count=1 -race

View file

@ -4,7 +4,7 @@
# options for analysis running # options for analysis running
run: run:
# timeout for analysis, e.g. 30s, 5m, default is 1m # timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 10m timeout: 20m
# include test files or not, default is true # include test files or not, default is true
tests: false tests: false

View file

@ -51,20 +51,10 @@ func (s *Service) verifyClient(req message, cid cidSDK.ID, rawBearer []byte, op
if err != nil { if err != nil {
return err return err
} }
if op == acl.OpObjectGet {
// verify if the request for a client operation isAuthorized, err := s.isAuthorized(req, op)
// was signed by a key from authorized list. if isAuthorized || err != nil {
// Operation must be one of READ. return err
sign := req.GetSignature()
if sign == nil {
return errors.New("missing signature")
}
var key = sign.GetKey()
for i := range s.authorizedKeys {
if bytes.Equal(s.authorizedKeys[i], key) {
return nil
}
}
} }
cnr, err := s.cnrSource.Get(cid) cnr, err := s.cnrSource.Get(cid)
@ -74,18 +64,9 @@ func (s *Service) verifyClient(req message, cid cidSDK.ID, rawBearer []byte, op
eaclOp := eACLOp(op) eaclOp := eACLOp(op)
var bt *bearer.Token bt, err := parseBearer(rawBearer, cid, eaclOp)
if len(rawBearer) > 0 { if err != nil {
bt = new(bearer.Token) return err
if err = bt.Unmarshal(rawBearer); err != nil {
return eACLErr(eaclOp, fmt.Errorf("invalid bearer token: %w", err))
}
if !bt.AssertContainer(cid) {
return eACLErr(eaclOp, errBearerWrongContainer)
}
if !bt.VerifySignature() {
return eACLErr(eaclOp, errBearerSignature)
}
} }
role, err := roleFromReq(cnr, req, bt) role, err := roleFromReq(cnr, req, bt)
@ -117,32 +98,65 @@ func (s *Service) verifyClient(req message, cid cidSDK.ID, rawBearer []byte, op
var tb eacl.Table var tb eacl.Table
signer := req.GetSignature().GetKey() signer := req.GetSignature().GetKey()
if tableFromBearer { if tableFromBearer && !bt.Impersonate() {
if bt.Impersonate() {
tbCore, err := s.eaclSource.GetEACL(cid)
if err != nil {
return handleGetEACLError(err)
}
tb = *tbCore.Value
signer = bt.SigningKeyBytes()
} else {
if !bearer.ResolveIssuer(*bt).Equals(cnr.Value.Owner()) { if !bearer.ResolveIssuer(*bt).Equals(cnr.Value.Owner()) {
return eACLErr(eaclOp, errBearerWrongOwner) return eACLErr(eaclOp, errBearerWrongOwner)
} }
tb = bt.EACLTable() tb = bt.EACLTable()
}
} else { } else {
tbCore, err := s.eaclSource.GetEACL(cid) tbCore, err := s.eaclSource.GetEACL(cid)
if err != nil { if err != nil {
return handleGetEACLError(err) return handleGetEACLError(err)
} }
tb = *tbCore.Value tb = *tbCore.Value
if bt.Impersonate() {
signer = bt.SigningKeyBytes()
}
} }
return checkEACL(tb, signer, eACLRole(role), eaclOp) return checkEACL(tb, signer, eACLRole(role), eaclOp)
} }
// Returns true iff the operation is read-only and request was signed
// with one of the authorized keys.
func (s *Service) isAuthorized(req message, op acl.Op) (bool, error) {
if op != acl.OpObjectGet {
return false, nil
}
sign := req.GetSignature()
if sign == nil {
return false, errors.New("missing signature")
}
key := sign.GetKey()
for i := range s.authorizedKeys {
if bytes.Equal(s.authorizedKeys[i], key) {
return true, nil
}
}
return false, nil
}
func parseBearer(rawBearer []byte, cid cidSDK.ID, eaclOp eacl.Operation) (*bearer.Token, error) {
if len(rawBearer) == 0 {
return nil, nil
}
bt := new(bearer.Token)
if err := bt.Unmarshal(rawBearer); err != nil {
return nil, eACLErr(eaclOp, fmt.Errorf("invalid bearer token: %w", err))
}
if !bt.AssertContainer(cid) {
return nil, eACLErr(eaclOp, errBearerWrongContainer)
}
if !bt.VerifySignature() {
return nil, eACLErr(eaclOp, errBearerSignature)
}
return bt, nil
}
func handleGetEACLError(err error) error { func handleGetEACLError(err error) error {
if client.IsErrEACLNotFound(err) { if client.IsErrEACLNotFound(err) {
return nil return nil