From a955949857e305c14f4cddc850d7d4365fb856e2 Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Thu, 3 Apr 2025 13:35:49 +0530 Subject: [PATCH 01/12] fix: added error from error module --- .../implementation/decrypter/decrypter.go | 8 +++++--- .../implementation/encrypter/encrypter.go | 9 +++++---- .../schemavalidator/schemavalidator.go | 5 +++-- pkg/plugin/implementation/signer/signer.go | 7 ++++--- .../signvalidator/signvalidator.go | 20 ++++++++----------- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/pkg/plugin/implementation/decrypter/decrypter.go b/pkg/plugin/implementation/decrypter/decrypter.go index f312f16..1141766 100644 --- a/pkg/plugin/implementation/decrypter/decrypter.go +++ b/pkg/plugin/implementation/decrypter/decrypter.go @@ -9,6 +9,8 @@ import ( "fmt" "github.com/zenazn/pkcs7pad" + + "github.com/beckn/beckn-onix/pkg/model" ) // decrypter implements the Decrypter interface and handles the decryption process. @@ -24,18 +26,18 @@ func New(ctx context.Context) (*decrypter, func() error, error) { func (d *decrypter) Decrypt(ctx context.Context, encryptedData, privateKeyBase64, publicKeyBase64 string) (string, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return "", fmt.Errorf("invalid private key: %w", err) + return "", model.NewBadReqErr(err) } publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return "", fmt.Errorf("invalid public key: %w", err) + return "", model.NewBadReqErr(err) } // Decode the Base64 encoded encrypted data. messageByte, err := base64.StdEncoding.DecodeString(encryptedData) if err != nil { - return "", fmt.Errorf("failed to decode encrypted data: %w", err) + return "", model.NewBadReqErr(err) } aesCipher, err := createAESCipher(privateKeyBytes, publicKeyBytes) diff --git a/pkg/plugin/implementation/encrypter/encrypter.go b/pkg/plugin/implementation/encrypter/encrypter.go index f0a8663..3ba7c3e 100644 --- a/pkg/plugin/implementation/encrypter/encrypter.go +++ b/pkg/plugin/implementation/encrypter/encrypter.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "fmt" + "github.com/beckn/beckn-onix/pkg/model" "github.com/zenazn/pkcs7pad" ) @@ -23,12 +24,12 @@ func New(ctx context.Context) (*encrypter, func() error, error) { func (e *encrypter) Encrypt(ctx context.Context, data string, privateKeyBase64, publicKeyBase64 string) (string, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return "", fmt.Errorf("invalid private key: %w", err) + return "", model.NewBadReqErr(err) } publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return "", fmt.Errorf("invalid public key: %w", err) + return "", model.NewBadReqErr(err) } // Convert the input string to a byte slice. @@ -50,11 +51,11 @@ func createAESCipher(privateKey, publicKey []byte) (cipher.Block, error) { x25519Curve := ecdh.X25519() x25519PrivateKey, err := x25519Curve.NewPrivateKey(privateKey) if err != nil { - return nil, fmt.Errorf("failed to create private key: %w", err) + return nil, model.NewBadReqErr(err) } x25519PublicKey, err := x25519Curve.NewPublicKey(publicKey) if err != nil { - return nil, fmt.Errorf("failed to create public key: %w", err) + return nil, model.NewBadReqErr(err) } sharedSecret, err := x25519PrivateKey.ECDH(x25519PublicKey) if err != nil { diff --git a/pkg/plugin/implementation/schemavalidator/schemavalidator.go b/pkg/plugin/implementation/schemavalidator/schemavalidator.go index 715def7..8b56e03 100644 --- a/pkg/plugin/implementation/schemavalidator/schemavalidator.go +++ b/pkg/plugin/implementation/schemavalidator/schemavalidator.go @@ -3,6 +3,7 @@ package schemavalidator import ( "context" "encoding/json" + "errors" "fmt" "net/url" "os" @@ -77,12 +78,12 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt // Retrieve the schema from the cache. schema, exists := v.schemaCache[schemaFileName] if !exists { - return fmt.Errorf("schema not found for domain: %s", schemaFileName) + return model.NewNotFoundErr(errors.New("schema not found for domain")) } var jsonData any if err := json.Unmarshal(data, &jsonData); err != nil { - return fmt.Errorf("failed to parse JSON data: %v", err) + return model.NewBadReqErr(err) } err = schema.Validate(jsonData) if err != nil { diff --git a/pkg/plugin/implementation/signer/signer.go b/pkg/plugin/implementation/signer/signer.go index 1f5be86..71f8774 100644 --- a/pkg/plugin/implementation/signer/signer.go +++ b/pkg/plugin/implementation/signer/signer.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" + "github.com/beckn/beckn-onix/pkg/model" "golang.org/x/crypto/blake2b" ) @@ -32,7 +33,7 @@ func hash(payload []byte, createdAt, expiresAt int64) (string, error) { _, err := hasher.Write(payload) if err != nil { - return "", fmt.Errorf("failed to hash payload: %w", err) + return "", model.NewBadReqErr(err) } hashSum := hasher.Sum(nil) @@ -45,11 +46,11 @@ func hash(payload []byte, createdAt, expiresAt int64) (string, error) { func generateSignature(signingString []byte, privateKeyBase64 string) ([]byte, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return nil, fmt.Errorf("error decoding private key: %w", err) + return nil, model.NewBadReqErr(err) } if len(privateKeyBytes) != ed25519.SeedSize { - return nil, errors.New("invalid seed length") + return nil, model.NewBadReqErr(errors.New("invalid seed length")) } // Generate the private key from the seed diff --git a/pkg/plugin/implementation/signvalidator/signvalidator.go b/pkg/plugin/implementation/signvalidator/signvalidator.go index c381d40..b107619 100644 --- a/pkg/plugin/implementation/signvalidator/signvalidator.go +++ b/pkg/plugin/implementation/signvalidator/signvalidator.go @@ -4,11 +4,13 @@ import ( "context" "crypto/ed25519" "encoding/base64" + "errors" "fmt" "strconv" "strings" "time" + "github.com/beckn/beckn-onix/pkg/model" "golang.org/x/crypto/blake2b" ) @@ -32,20 +34,17 @@ func New(ctx context.Context, config *Config) (*validator, func() error, error) func (v *validator) Validate(ctx context.Context, body []byte, header string, publicKeyBase64 string) error { createdTimestamp, expiredTimestamp, signature, err := parseAuthHeader(header) if err != nil { - // TODO: Return appropriate error code when Error Code Handling Module is ready - return fmt.Errorf("error parsing header: %w", err) + return model.NewBadReqErr(err) } signatureBytes, err := base64.StdEncoding.DecodeString(signature) if err != nil { - // TODO: Return appropriate error code when Error Code Handling Module is ready return fmt.Errorf("error decoding signature: %w", err) } currentTime := time.Now().Unix() if createdTimestamp > currentTime || currentTime > expiredTimestamp { - // TODO: Return appropriate error code when Error Code Handling Module is ready - return fmt.Errorf("signature is expired or not yet valid") + return model.NewSignValidationErr(errors.New("signature is expired or not yet valid")) } createdTime := time.Unix(createdTimestamp, 0) @@ -55,13 +54,11 @@ func (v *validator) Validate(ctx context.Context, body []byte, header string, pu decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - // TODO: Return appropriate error code when Error Code Handling Module is ready - return fmt.Errorf("error decoding public key: %w", err) + return model.NewBadReqErr(err) } if !ed25519.Verify(ed25519.PublicKey(decodedPublicKey), []byte(signingString), signatureBytes) { - // TODO: Return appropriate error code when Error Code Handling Module is ready - return fmt.Errorf("signature verification failed") + return model.NewSignValidationErr(errors.New("signature verification failed")) } return nil @@ -91,14 +88,13 @@ func parseAuthHeader(header string) (int64, int64, string, error) { expiredTimestamp, err := strconv.ParseInt(signatureMap["expires"], 10, 64) if err != nil { - // TODO: Return appropriate error code when Error Code Handling Module is ready - return 0, 0, "", fmt.Errorf("invalid expires timestamp: %w", err) + return 0, 0, "", model.NewSignValidationErr(err) } signature := signatureMap["signature"] if signature == "" { // TODO: Return appropriate error code when Error Code Handling Module is ready - return 0, 0, "", fmt.Errorf("signature missing in header") + return 0, 0, "", model.NewSignValidationErr(errors.New("signature missing in header")) } return createdTimestamp, expiredTimestamp, signature, nil From dc108ddf68d97c626921516fbdd113ff15cba45a Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Thu, 3 Apr 2025 13:41:58 +0530 Subject: [PATCH 02/12] fix: added error from error module --- .../implementation/schemavalidator/schemavalidator.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/plugin/implementation/schemavalidator/schemavalidator.go b/pkg/plugin/implementation/schemavalidator/schemavalidator.go index 8b56e03..dd3d596 100644 --- a/pkg/plugin/implementation/schemavalidator/schemavalidator.go +++ b/pkg/plugin/implementation/schemavalidator/schemavalidator.go @@ -39,7 +39,7 @@ type Config struct { func New(ctx context.Context, config *Config) (*schemaValidator, func() error, error) { // Check if config is nil if config == nil { - return nil, nil, fmt.Errorf("config cannot be nil") + return nil, nil, model.NewBadReqErr(errors.New("config cannot be nil")) } v := &schemaValidator{ config: config, @@ -105,8 +105,7 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt // Return the array of schema validation errors return &model.SchemaValidationErr{Errors: schemaErrors} } - // Return a generic error for non-validation errors - return fmt.Errorf("validation failed: %v", err) + return model.NewBadReqErr(err) } // Return nil if validation succeeds @@ -191,7 +190,7 @@ func (v *schemaValidator) initialise() error { // Start processing from the root schema directory. if err := processDir(schemaDir); err != nil { - return fmt.Errorf("failed to read schema directory: %v", err) + return model.NewNotFoundErr(err) } return nil From 2a0b2c35d37bc4441ff790a1b1fbd6c181504a9a Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Thu, 3 Apr 2025 18:59:38 +0530 Subject: [PATCH 03/12] fix: error module implementation --- pkg/plugin/implementation/decrypter/decrypter.go | 6 +++--- pkg/plugin/implementation/encrypter/encrypter.go | 8 ++++---- .../schemavalidator/schemavalidator.go | 16 ++++++++-------- pkg/plugin/implementation/signer/signer.go | 4 ++-- .../signvalidator/signvalidator.go | 13 ++++++------- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/pkg/plugin/implementation/decrypter/decrypter.go b/pkg/plugin/implementation/decrypter/decrypter.go index 1141766..f03d438 100644 --- a/pkg/plugin/implementation/decrypter/decrypter.go +++ b/pkg/plugin/implementation/decrypter/decrypter.go @@ -26,18 +26,18 @@ func New(ctx context.Context) (*decrypter, func() error, error) { func (d *decrypter) Decrypt(ctx context.Context, encryptedData, privateKeyBase64, publicKeyBase64 string) (string, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return "", model.NewBadReqErr(err) + return "", model.NewBadReqErr(fmt.Errorf("invalid private key: %w", err)) } publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return "", model.NewBadReqErr(err) + return "", model.NewBadReqErr(fmt.Errorf("invalid public key: %w", err)) } // Decode the Base64 encoded encrypted data. messageByte, err := base64.StdEncoding.DecodeString(encryptedData) if err != nil { - return "", model.NewBadReqErr(err) + return "", model.NewBadReqErr(fmt.Errorf("failed to decode encrypted data: %w", err)) } aesCipher, err := createAESCipher(privateKeyBytes, publicKeyBytes) diff --git a/pkg/plugin/implementation/encrypter/encrypter.go b/pkg/plugin/implementation/encrypter/encrypter.go index 3ba7c3e..301cf0a 100644 --- a/pkg/plugin/implementation/encrypter/encrypter.go +++ b/pkg/plugin/implementation/encrypter/encrypter.go @@ -24,12 +24,12 @@ func New(ctx context.Context) (*encrypter, func() error, error) { func (e *encrypter) Encrypt(ctx context.Context, data string, privateKeyBase64, publicKeyBase64 string) (string, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return "", model.NewBadReqErr(err) + return "", model.NewBadReqErr(fmt.Errorf("invalid private key: %w", err)) } publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return "", model.NewBadReqErr(err) + return "", model.NewBadReqErr(fmt.Errorf("invalid public key: %w", err)) } // Convert the input string to a byte slice. @@ -51,11 +51,11 @@ func createAESCipher(privateKey, publicKey []byte) (cipher.Block, error) { x25519Curve := ecdh.X25519() x25519PrivateKey, err := x25519Curve.NewPrivateKey(privateKey) if err != nil { - return nil, model.NewBadReqErr(err) + return nil, model.NewBadReqErr(fmt.Errorf("failed to create private key: %w", err)) } x25519PublicKey, err := x25519Curve.NewPublicKey(publicKey) if err != nil { - return nil, model.NewBadReqErr(err) + return nil, model.NewBadReqErr(fmt.Errorf("failed to create public key: %w", err)) } sharedSecret, err := x25519PrivateKey.ECDH(x25519PublicKey) if err != nil { diff --git a/pkg/plugin/implementation/schemavalidator/schemavalidator.go b/pkg/plugin/implementation/schemavalidator/schemavalidator.go index dd3d596..9456c07 100644 --- a/pkg/plugin/implementation/schemavalidator/schemavalidator.go +++ b/pkg/plugin/implementation/schemavalidator/schemavalidator.go @@ -11,6 +11,7 @@ import ( "path/filepath" "strings" + "github.com/beckn/beckn-onix/pkg/log" "github.com/beckn/beckn-onix/pkg/model" "github.com/santhosh-tekuri/jsonschema/v6" @@ -39,7 +40,7 @@ type Config struct { func New(ctx context.Context, config *Config) (*schemaValidator, func() error, error) { // Check if config is nil if config == nil { - return nil, nil, model.NewBadReqErr(errors.New("config cannot be nil")) + return nil, nil, fmt.Errorf("config cannot be nil") } v := &schemaValidator{ config: config, @@ -58,7 +59,7 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt var payloadData payload err := json.Unmarshal(data, &payloadData) if err != nil { - return fmt.Errorf("failed to parse JSON payload: %v", err) + return model.NewBadReqErr(fmt.Errorf("failed to parse JSON payload: %v", err)) } // Extract domain, version, and endpoint from the payload and uri. @@ -67,8 +68,7 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt version = fmt.Sprintf("v%s", version) endpoint := path.Base(url.String()) - // ToDo Add debug log here - fmt.Println("Handling request for endpoint:", endpoint) + log.Debugf(ctx, "Handling request for endpoint: %s", endpoint) domain := strings.ToLower(cxtDomain) domain = strings.ReplaceAll(domain, ":", "_") @@ -78,12 +78,12 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt // Retrieve the schema from the cache. schema, exists := v.schemaCache[schemaFileName] if !exists { - return model.NewNotFoundErr(errors.New("schema not found for domain")) + return model.NewBadReqErr(errors.New("schema not found for domain")) } var jsonData any if err := json.Unmarshal(data, &jsonData); err != nil { - return model.NewBadReqErr(err) + return model.NewBadReqErr(fmt.Errorf("failed to parse JSON data: %v", err)) } err = schema.Validate(jsonData) if err != nil { @@ -105,7 +105,7 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt // Return the array of schema validation errors return &model.SchemaValidationErr{Errors: schemaErrors} } - return model.NewBadReqErr(err) + return model.NewBadReqErr(fmt.Errorf("validation failed: %v", err)) } // Return nil if validation succeeds @@ -190,7 +190,7 @@ func (v *schemaValidator) initialise() error { // Start processing from the root schema directory. if err := processDir(schemaDir); err != nil { - return model.NewNotFoundErr(err) + return fmt.Errorf("failed to read schema directory: %v", err) } return nil diff --git a/pkg/plugin/implementation/signer/signer.go b/pkg/plugin/implementation/signer/signer.go index 71f8774..ca659d4 100644 --- a/pkg/plugin/implementation/signer/signer.go +++ b/pkg/plugin/implementation/signer/signer.go @@ -33,7 +33,7 @@ func hash(payload []byte, createdAt, expiresAt int64) (string, error) { _, err := hasher.Write(payload) if err != nil { - return "", model.NewBadReqErr(err) + return "", fmt.Errorf("failed to hash payload: %w", err) } hashSum := hasher.Sum(nil) @@ -46,7 +46,7 @@ func hash(payload []byte, createdAt, expiresAt int64) (string, error) { func generateSignature(signingString []byte, privateKeyBase64 string) ([]byte, error) { privateKeyBytes, err := base64.StdEncoding.DecodeString(privateKeyBase64) if err != nil { - return nil, model.NewBadReqErr(err) + return nil, fmt.Errorf("error decoding private key: %w", err) } if len(privateKeyBytes) != ed25519.SeedSize { diff --git a/pkg/plugin/implementation/signvalidator/signvalidator.go b/pkg/plugin/implementation/signvalidator/signvalidator.go index b107619..07893fd 100644 --- a/pkg/plugin/implementation/signvalidator/signvalidator.go +++ b/pkg/plugin/implementation/signvalidator/signvalidator.go @@ -4,7 +4,6 @@ import ( "context" "crypto/ed25519" "encoding/base64" - "errors" "fmt" "strconv" "strings" @@ -34,7 +33,7 @@ func New(ctx context.Context, config *Config) (*validator, func() error, error) func (v *validator) Validate(ctx context.Context, body []byte, header string, publicKeyBase64 string) error { createdTimestamp, expiredTimestamp, signature, err := parseAuthHeader(header) if err != nil { - return model.NewBadReqErr(err) + return model.NewBadReqErr(fmt.Errorf("error parsing header: %w", err)) } signatureBytes, err := base64.StdEncoding.DecodeString(signature) @@ -44,7 +43,7 @@ func (v *validator) Validate(ctx context.Context, body []byte, header string, pu currentTime := time.Now().Unix() if createdTimestamp > currentTime || currentTime > expiredTimestamp { - return model.NewSignValidationErr(errors.New("signature is expired or not yet valid")) + return model.NewSignValidationErr(fmt.Errorf("signature is expired or not yet valid")) } createdTime := time.Unix(createdTimestamp, 0) @@ -54,11 +53,11 @@ func (v *validator) Validate(ctx context.Context, body []byte, header string, pu decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return model.NewBadReqErr(err) + return model.NewBadReqErr(fmt.Errorf("error decoding public key: %w", err)) } if !ed25519.Verify(ed25519.PublicKey(decodedPublicKey), []byte(signingString), signatureBytes) { - return model.NewSignValidationErr(errors.New("signature verification failed")) + return model.NewSignValidationErr(fmt.Errorf("signature verification failed")) } return nil @@ -88,13 +87,13 @@ func parseAuthHeader(header string) (int64, int64, string, error) { expiredTimestamp, err := strconv.ParseInt(signatureMap["expires"], 10, 64) if err != nil { - return 0, 0, "", model.NewSignValidationErr(err) + return 0, 0, "", model.NewSignValidationErr(fmt.Errorf("invalid expires timestamp: %w", err)) } signature := signatureMap["signature"] if signature == "" { // TODO: Return appropriate error code when Error Code Handling Module is ready - return 0, 0, "", model.NewSignValidationErr(errors.New("signature missing in header")) + return 0, 0, "", model.NewSignValidationErr(fmt.Errorf("signature missing in header")) } return createdTimestamp, expiredTimestamp, signature, nil From edf82b8e8a4f8d92fa8bea8e90f822f3ba14c73e Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Thu, 3 Apr 2025 19:02:42 +0530 Subject: [PATCH 04/12] fix: error module implementation --- pkg/plugin/implementation/signer/signer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/plugin/implementation/signer/signer.go b/pkg/plugin/implementation/signer/signer.go index ca659d4..1f5be86 100644 --- a/pkg/plugin/implementation/signer/signer.go +++ b/pkg/plugin/implementation/signer/signer.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" - "github.com/beckn/beckn-onix/pkg/model" "golang.org/x/crypto/blake2b" ) @@ -50,7 +49,7 @@ func generateSignature(signingString []byte, privateKeyBase64 string) ([]byte, e } if len(privateKeyBytes) != ed25519.SeedSize { - return nil, model.NewBadReqErr(errors.New("invalid seed length")) + return nil, errors.New("invalid seed length") } // Generate the private key from the seed From d1e8716e15d8a6bbd7c238d461067db97a509b5d Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Fri, 4 Apr 2025 15:01:15 +0530 Subject: [PATCH 05/12] ft: module_name wrapper middleware --- config/onix-bap/adapter.yaml | 1 + config/onix-bpp/adapter.yaml | 1 + config/onix/adapter.yaml | 1 + core/module/module.go | 8 ++++++++ core/module/module_test.go | 21 +++++++++++++++++++++ 5 files changed, 32 insertions(+) diff --git a/config/onix-bap/adapter.yaml b/config/onix-bap/adapter.yaml index a95c53f..878b8d9 100644 --- a/config/onix-bap/adapter.yaml +++ b/config/onix-bap/adapter.yaml @@ -7,6 +7,7 @@ log: - transaction_id - message_id - subscriber_id + - module_name http: port: 8080 timeout: diff --git a/config/onix-bpp/adapter.yaml b/config/onix-bpp/adapter.yaml index 8994980..ddee6a5 100644 --- a/config/onix-bpp/adapter.yaml +++ b/config/onix-bpp/adapter.yaml @@ -7,6 +7,7 @@ log: - transaction_id - message_id - subscriber_id + - module_name http: port: 8080 timeout: diff --git a/config/onix/adapter.yaml b/config/onix/adapter.yaml index a626c4e..1aee391 100644 --- a/config/onix/adapter.yaml +++ b/config/onix/adapter.yaml @@ -7,6 +7,7 @@ log: - transaction_id - message_id - subscriber_id + - module_name http: port: 8080 timeout: diff --git a/core/module/module.go b/core/module/module.go index 3b0fcef..2926995 100644 --- a/core/module/module.go +++ b/core/module/module.go @@ -44,6 +44,7 @@ func Register(ctx context.Context, mCfgs []Config, mux *http.ServeMux, mgr handl return fmt.Errorf("failed to add middleware: %w", err) } + h = moduleCtxMiddleware(c.Name, h) log.Debugf(ctx, "Registering handler %s, of type %s @ %s", c.Name, c.Handler.Type, c.Path) mux.Handle(c.Path, h) } @@ -71,3 +72,10 @@ func addMiddleware(ctx context.Context, mgr handler.PluginManager, handler http. log.Debugf(ctx, "Middleware chain setup completed") return handler, nil } + +func moduleCtxMiddleware(moduleName string, next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), "module_name", moduleName) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/core/module/module_test.go b/core/module/module_test.go index 8f9016c..fc191af 100644 --- a/core/module/module_test.go +++ b/core/module/module_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net/http" + "net/http/httptest" "testing" "github.com/beckn/beckn-onix/core/module/handler" @@ -97,6 +98,26 @@ func TestRegisterSuccess(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } + + // Create a request and a response recorder + req := httptest.NewRequest(http.MethodGet, "/test", nil) + rec := httptest.NewRecorder() + + // Create a handler that extracts context + var capturedModuleName any + testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + capturedModuleName = r.Context().Value("module_name") + w.WriteHeader(http.StatusOK) + }) + + wrappedHandler := moduleCtxMiddleware("test-module", testHandler) + wrappedHandler.ServeHTTP(rec, req) + + // Now verify if module name exists in context + if capturedModuleName != "test-module" { + t.Errorf("expected module_name in context to be 'test-module', got %v", capturedModuleName) + } + } // TestRegisterFailure tests scenarios where the handler registration should fail. From 67808f3628e4658c72ede1e419f9cad92fb45e74 Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Fri, 4 Apr 2025 15:08:37 +0530 Subject: [PATCH 06/12] ft: module_name wrapper middleware --- core/module/module.go | 2 +- core/module/module_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/module/module.go b/core/module/module.go index 3b0fcef..0cd7567 100644 --- a/core/module/module.go +++ b/core/module/module.go @@ -51,7 +51,7 @@ func Register(ctx context.Context, mCfgs []Config, mux *http.ServeMux, mgr handl } // addMiddleware applies middleware plugins to the provided handler in reverse order. -// It retrieves middleware instances from the plugin manager and chains them to the handler. +// It retrieves middleware instances from the plugin manager and chains them to the handler.. func addMiddleware(ctx context.Context, mgr handler.PluginManager, handler http.Handler, hCfg *handler.Config) (http.Handler, error) { mws := hCfg.Plugins.Middleware log.Debugf(ctx, "Applying %d middleware(s) to the handler", len(mws)) diff --git a/core/module/module_test.go b/core/module/module_test.go index 8f9016c..8737968 100644 --- a/core/module/module_test.go +++ b/core/module/module_test.go @@ -99,7 +99,7 @@ func TestRegisterSuccess(t *testing.T) { } } -// TestRegisterFailure tests scenarios where the handler registration should fail. +// TestRegisterFailure tests scenarios where the handler registration should fail.. func TestRegisterFailure(t *testing.T) { tests := []struct { name string From 2329efd5628ceaeb81f2171aa8c5cda338a76d17 Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Fri, 4 Apr 2025 15:39:05 +0530 Subject: [PATCH 07/12] fix: module id and linting issues --- config/onix-bap/adapter.yaml | 2 +- config/onix-bpp/adapter.yaml | 2 +- config/onix/adapter.yaml | 2 +- core/module/module.go | 3 ++- core/module/module_test.go | 5 +++-- pkg/model/error_test.go | 2 +- pkg/model/model.go | 4 ++++ 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/config/onix-bap/adapter.yaml b/config/onix-bap/adapter.yaml index 878b8d9..dda19fc 100644 --- a/config/onix-bap/adapter.yaml +++ b/config/onix-bap/adapter.yaml @@ -7,7 +7,7 @@ log: - transaction_id - message_id - subscriber_id - - module_name + - module_id http: port: 8080 timeout: diff --git a/config/onix-bpp/adapter.yaml b/config/onix-bpp/adapter.yaml index ddee6a5..aa3d242 100644 --- a/config/onix-bpp/adapter.yaml +++ b/config/onix-bpp/adapter.yaml @@ -7,7 +7,7 @@ log: - transaction_id - message_id - subscriber_id - - module_name + - module_id http: port: 8080 timeout: diff --git a/config/onix/adapter.yaml b/config/onix/adapter.yaml index 1aee391..e3a785b 100644 --- a/config/onix/adapter.yaml +++ b/config/onix/adapter.yaml @@ -7,7 +7,7 @@ log: - transaction_id - message_id - subscriber_id - - module_name + - module_id http: port: 8080 timeout: diff --git a/core/module/module.go b/core/module/module.go index 2926995..4641fcb 100644 --- a/core/module/module.go +++ b/core/module/module.go @@ -7,6 +7,7 @@ import ( "github.com/beckn/beckn-onix/core/module/handler" "github.com/beckn/beckn-onix/pkg/log" + "github.com/beckn/beckn-onix/pkg/model" ) // Config represents the configuration for a module. @@ -75,7 +76,7 @@ func addMiddleware(ctx context.Context, mgr handler.PluginManager, handler http. func moduleCtxMiddleware(moduleName string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), "module_name", moduleName) + ctx := context.WithValue(r.Context(), model.ContextKeyModuleId, moduleName) next.ServeHTTP(w, r.WithContext(ctx)) }) } diff --git a/core/module/module_test.go b/core/module/module_test.go index fc191af..6091fc1 100644 --- a/core/module/module_test.go +++ b/core/module/module_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/beckn/beckn-onix/core/module/handler" + "github.com/beckn/beckn-onix/pkg/model" "github.com/beckn/beckn-onix/pkg/plugin" "github.com/beckn/beckn-onix/pkg/plugin/definition" ) @@ -106,7 +107,7 @@ func TestRegisterSuccess(t *testing.T) { // Create a handler that extracts context var capturedModuleName any testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - capturedModuleName = r.Context().Value("module_name") + capturedModuleName = r.Context().Value(model.ContextKeyModuleId) w.WriteHeader(http.StatusOK) }) @@ -115,7 +116,7 @@ func TestRegisterSuccess(t *testing.T) { // Now verify if module name exists in context if capturedModuleName != "test-module" { - t.Errorf("expected module_name in context to be 'test-module', got %v", capturedModuleName) + t.Errorf("expected module_id in context to be 'test-module', got %v", capturedModuleName) } } diff --git a/pkg/model/error_test.go b/pkg/model/error_test.go index ee295e6..7b9fd95 100644 --- a/pkg/model/error_test.go +++ b/pkg/model/error_test.go @@ -3,8 +3,8 @@ package model import ( "errors" "fmt" - "testing" "net/http" + "testing" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v2" diff --git a/pkg/model/model.go b/pkg/model/model.go index 621bdeb..536a9ad 100644 --- a/pkg/model/model.go +++ b/pkg/model/model.go @@ -16,6 +16,10 @@ type Subscriber struct { Domain string `json:"domain"` } +type ContextKey string + +const ContextKeyModuleId ContextKey = "module_id" + // Subscription represents subscription details of a network participant. type Subscription struct { Subscriber `json:",inline"` From bb737505d411b57864f577f3b1f3e13c30332d51 Mon Sep 17 00:00:00 2001 From: "mayur.popli" Date: Fri, 4 Apr 2025 16:34:43 +0530 Subject: [PATCH 08/12] fix: resolved comments --- core/module/module.go | 2 +- core/module/module_test.go | 2 +- pkg/plugin/implementation/schemavalidator/schemavalidator.go | 5 +---- pkg/plugin/implementation/signvalidator/signvalidator.go | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/core/module/module.go b/core/module/module.go index 0cd7567..3b0fcef 100644 --- a/core/module/module.go +++ b/core/module/module.go @@ -51,7 +51,7 @@ func Register(ctx context.Context, mCfgs []Config, mux *http.ServeMux, mgr handl } // addMiddleware applies middleware plugins to the provided handler in reverse order. -// It retrieves middleware instances from the plugin manager and chains them to the handler.. +// It retrieves middleware instances from the plugin manager and chains them to the handler. func addMiddleware(ctx context.Context, mgr handler.PluginManager, handler http.Handler, hCfg *handler.Config) (http.Handler, error) { mws := hCfg.Plugins.Middleware log.Debugf(ctx, "Applying %d middleware(s) to the handler", len(mws)) diff --git a/core/module/module_test.go b/core/module/module_test.go index 8737968..8f9016c 100644 --- a/core/module/module_test.go +++ b/core/module/module_test.go @@ -99,7 +99,7 @@ func TestRegisterSuccess(t *testing.T) { } } -// TestRegisterFailure tests scenarios where the handler registration should fail.. +// TestRegisterFailure tests scenarios where the handler registration should fail. func TestRegisterFailure(t *testing.T) { tests := []struct { name string diff --git a/pkg/plugin/implementation/schemavalidator/schemavalidator.go b/pkg/plugin/implementation/schemavalidator/schemavalidator.go index 9456c07..bab2dba 100644 --- a/pkg/plugin/implementation/schemavalidator/schemavalidator.go +++ b/pkg/plugin/implementation/schemavalidator/schemavalidator.go @@ -105,16 +105,13 @@ func (v *schemaValidator) Validate(ctx context.Context, url *url.URL, data []byt // Return the array of schema validation errors return &model.SchemaValidationErr{Errors: schemaErrors} } - return model.NewBadReqErr(fmt.Errorf("validation failed: %v", err)) + return fmt.Errorf("validation failed: %v", err) } // Return nil if validation succeeds return nil } -// ValidatorProvider provides instances of Validator. -type ValidatorProvider struct{} - // Initialise initialises the validator provider by compiling all the JSON schema files // from the specified directory and storing them in a cache indexed by their schema filenames. func (v *schemaValidator) initialise() error { diff --git a/pkg/plugin/implementation/signvalidator/signvalidator.go b/pkg/plugin/implementation/signvalidator/signvalidator.go index 07893fd..612d857 100644 --- a/pkg/plugin/implementation/signvalidator/signvalidator.go +++ b/pkg/plugin/implementation/signvalidator/signvalidator.go @@ -33,7 +33,7 @@ func New(ctx context.Context, config *Config) (*validator, func() error, error) func (v *validator) Validate(ctx context.Context, body []byte, header string, publicKeyBase64 string) error { createdTimestamp, expiredTimestamp, signature, err := parseAuthHeader(header) if err != nil { - return model.NewBadReqErr(fmt.Errorf("error parsing header: %w", err)) + return model.NewSignValidationErr(fmt.Errorf("error parsing header: %w", err)) } signatureBytes, err := base64.StdEncoding.DecodeString(signature) @@ -53,7 +53,7 @@ func (v *validator) Validate(ctx context.Context, body []byte, header string, pu decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKeyBase64) if err != nil { - return model.NewBadReqErr(fmt.Errorf("error decoding public key: %w", err)) + return model.NewSignValidationErr(fmt.Errorf("error decoding public key: %w", err)) } if !ed25519.Verify(ed25519.PublicKey(decodedPublicKey), []byte(signingString), signatureBytes) { From e629e8f522094a87d6a46386eb26fbe4dd3b2f29 Mon Sep 17 00:00:00 2001 From: BushraS-Protean Date: Mon, 7 Apr 2025 11:33:43 +0530 Subject: [PATCH 09/12] Update beckn_ci_test.yml testing From 69116b3e41b2bfa05a7bf8600c1c166e04160427 Mon Sep 17 00:00:00 2001 From: BushraS-Protean Date: Mon, 7 Apr 2025 14:18:51 +0530 Subject: [PATCH 10/12] Update beckn_ci_test.yml new approach --- .github/workflows/beckn_ci_test.yml | 69 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/.github/workflows/beckn_ci_test.yml b/.github/workflows/beckn_ci_test.yml index fb6a4cf..e8d9ae6 100644 --- a/.github/workflows/beckn_ci_test.yml +++ b/.github/workflows/beckn_ci_test.yml @@ -1,64 +1,55 @@ name: CI/CD Test Pipeline - + on: pull_request: branches: - beckn-onix-v1.0-develop - + env: - APP_DIRECTORY: "shared/plugin" # Root directory to start searching from - + APP_DIRECTORY: "shared/plugin" + jobs: lint_and_test: runs-on: ubuntu-latest if: github.event_name == 'pull_request' - timeout-minutes: 10 # Increased timeout due to additional steps + timeout-minutes: 10 + outputs: + coverage_ok: ${{ steps.coverage_check.outputs.coverage_ok }} steps: - # 1. Checkout the code from the test branch (triggered by PR) - name: Checkout code uses: actions/checkout@v4 - - # 2. Set up Go environment + - name: Set up Go 1.24.0 uses: actions/setup-go@v4 with: go-version: '1.24.0' - - # 3. Install golangci-lint + - name: Install golangci-lint - run: | - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest - - # 4. Run golangci-lint on the entire repo, starting from the root directory + run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + - name: Run golangci-lint - run: | - golangci-lint run ./... # This will lint all Go files in the repo and subdirectories - - # 5. Run unit tests with coverage in the entire repository + run: golangci-lint run ./... + - name: Run unit tests with coverage run: | - # Create a directory to store coverage files mkdir -p $GITHUB_WORKSPACE/coverage_files - # Find all *_test.go files test_files=$(find ./ -type f -name '*_test.go') - # Check if there are any test files if [ -z "$test_files" ]; then - echo "No test cases found in the repository. Skipping test execution." + echo "No test cases found. Skipping." exit 0 fi - # Run tests and store coverage for each test directory for test_file in $test_files; do test_dir=$(dirname "$test_file") go_file="${test_file/_test.go/.go}" echo "Running tests in $test_dir for $go_file" go test -v -coverprofile=$GITHUB_WORKSPACE/coverage_files/coverage_$(basename "$go_file" .go).out $test_dir || echo "Tests failed, but continuing." done - - # 6. Check coverage for each generated coverage file + - name: Check coverage for each test file + id: coverage_check run: | + echo "coverage_ok=true" >> $GITHUB_OUTPUT coverage_files=$(find $GITHUB_WORKSPACE/coverage_files -name "coverage_*.out") - # If no coverage files were generated, exit without failure if [ -z "$coverage_files" ]; then echo "No coverage files found. Skipping coverage check." exit 0 @@ -66,9 +57,29 @@ jobs: for coverage_file in $coverage_files; do echo "Checking coverage for $coverage_file" coverage=$(go tool cover -func=$coverage_file | grep total | awk '{print $3}' | sed 's/%//') - echo "Coverage for $coverage_file: $coverage%" + echo "Coverage: $coverage%" if (( $(echo "$coverage < 90" | bc -l) )); then - echo "Coverage for $coverage_file is below 90%. Failing the job." - exit 1 + echo "coverage_ok=false" >> $GITHUB_OUTPUT + break fi done + + require_exception_approval: + needs: lint_and_test + if: needs.lint_and_test.outputs.coverage_ok == 'false' + runs-on: ubuntu-latest + environment: + name: coverage-exception + url: https://your-coverage-dashboard.com # Optional + steps: + - name: Manual approval required + run: echo "Coverage < 90%. Approval required to continue." + + proceed_with_merge: + needs: [lint_and_test, require_exception_approval] + if: | + needs.lint_and_test.outputs.coverage_ok == 'true' || success() + runs-on: ubuntu-latest + steps: + - name: Proceed with merge + run: echo "Coverage requirement met or exception approved. Merge allowed." From 4d86a94b3bfc4581492844e251168befbefea8e3 Mon Sep 17 00:00:00 2001 From: rupinder-syngh Date: Mon, 7 Apr 2025 14:51:39 +0530 Subject: [PATCH 11/12] fix: manager closer change --- pkg/plugin/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/plugin/manager.go b/pkg/plugin/manager.go index 4cb4a37..c3bbfe9 100644 --- a/pkg/plugin/manager.go +++ b/pkg/plugin/manager.go @@ -131,7 +131,7 @@ func (m *Manager) Publisher(ctx context.Context, cfg *Config) (definition.Publis return nil, err } if closer != nil { - m.addCloser(func() { + m.closers = append(m.closers, func() { if err := closer(); err != nil { panic(err) } From d1377583eccbedd3e9bf2bd9e840aebb06f9475b Mon Sep 17 00:00:00 2001 From: rupinder-syngh Date: Mon, 7 Apr 2025 17:37:41 +0530 Subject: [PATCH 12/12] fix: closer function change --- pkg/plugin/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/plugin/manager.go b/pkg/plugin/manager.go index c3bbfe9..12d5909 100644 --- a/pkg/plugin/manager.go +++ b/pkg/plugin/manager.go @@ -159,7 +159,7 @@ func (m *Manager) SchemaValidator(ctx context.Context, cfg *Config) (definition. return nil, err } if closer != nil { - m.addCloser(func() { + m.closers = append(m.closers, func() { if err := closer(); err != nil { panic(err) }