Skip to content

Commit 7f5d46f

Browse files
authored
Merge pull request #545 from Beckn-One/540-dedi-wrapper
Issue 540 - fix: remove hardcoded value and add test cases
2 parents ffdd94e + 5bd485d commit 7f5d46f

File tree

5 files changed

+236
-272
lines changed

5 files changed

+236
-272
lines changed
Lines changed: 94 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,142 @@
11
# DeDi Registry Plugin
22

3-
A **registry type plugin** for Beckn-ONIX that integrates with DeDi (Decentralized Digital Infrastructure) registry services.
3+
A **registry type plugin** for Beckn-ONIX that integrates with DeDi (Decentralized Digital Infrastructure) registry services via the new DeDi Wrapper API.
44

55
## Overview
66

7-
The DeDi Registry plugin is a **registry implementation** that enables Beckn-ONIX to lookup participant records from remote DeDi registries via REST API calls.
7+
The DeDi Registry plugin implements the `RegistryLookup` interface to retrieve public keys and participant information from DeDi registry services. It's used by the KeyManager for **signature validation of incoming requests** from other network participants.
88

9-
## Configuration
10-
11-
```yaml
12-
plugins:
13-
registry:
14-
id: dediregistry
15-
config:
16-
baseURL: "https://dedi-api.example.com"
17-
apiKey: "your-bearer-token"
18-
namespaceID: "76EU8BF1gzRGGatgw7wZZb7nEVx77XSwkKDv4UDLdxh8ztty4zmbYU"
19-
registryName: "dedi_registry"
20-
timeout: "30" # seconds
21-
```
229

23-
### Configuration Parameters
2410

25-
| Parameter | Required | Description | Default |
26-
|-----------|----------|-------------|---------|
27-
| `baseURL` | Yes | DeDi registry API base URL | - |
28-
| `apiKey` | Yes | Bearer token for API authentication | - |
29-
| `namespaceID` | Yes | DeDi namespace identifier | - |
30-
| `registryName` | Yes | Registry name to query | - |
31-
| `timeout` | No | Request timeout in seconds | 30 |
3211

33-
## Usage
3412

35-
### In Module Configuration
13+
## Configuration
3614

3715
```yaml
38-
modules:
39-
- name: bapTxnReceiver
40-
handler:
41-
plugins:
42-
registry:
43-
id: dediregistry
44-
config:
45-
baseURL: "https://dedi-registry.example.com"
46-
apiKey: "your-api-key"
47-
namespaceID: "beckn-network"
48-
registryName: "participants"
16+
registry:
17+
id: dediregistry
18+
config:
19+
url: "https://dedi-wrapper.example.com/dedi"
20+
registryName: "subscribers.beckn.one"
21+
timeout: 30
4922
```
5023
51-
### In Code
52-
53-
```go
54-
// Load DeDi registry plugin (same as any registry plugin)
55-
dediRegistry, err := manager.Registry(ctx, &plugin.Config{
56-
ID: "dediregistry", // Plugin ID specifies DeDi implementation
57-
Config: map[string]string{
58-
"baseURL": "https://dedi-registry.example.com",
59-
"apiKey": "your-api-key",
60-
"namespaceID": "beckn-network",
61-
"registryName": "participants",
62-
},
63-
})
64-
65-
// Lookup participant with dynamic subscriber ID (from request context)
66-
subscription := &model.Subscription{
67-
Subscriber: model.Subscriber{
68-
SubscriberID: "bap-network", // Extracted from Authorization header or request body
69-
},
70-
}
71-
results, err := dediRegistry.Lookup(ctx, subscription)
72-
if err != nil {
73-
return err
74-
}
24+
### Configuration Parameters
7525
76-
// Extract public key from result (standard Beckn format)
77-
if len(results) > 0 {
78-
publicKey := results[0].SigningPublicKey
79-
subscriberID := results[0].SubscriberID
80-
}
81-
```
26+
| Parameter | Required | Description | Default |
27+
|-----------|----------|-------------|---------|
28+
| `url` | Yes | DeDi wrapper API base URL (include /dedi path) | - |
29+
| `registryName` | Yes | Registry name for lookup path | - |
30+
| `timeout` | No | Request timeout in seconds | Client default |
8231

8332
## API Integration
8433

85-
### DeDi API URL Pattern
34+
### DeDi Wrapper API Format
8635
```
87-
{baseURL}/dedi/lookup/{namespaceID}/{registryName}/{subscriberID}
36+
GET {url}/lookup/{subscriber_id}/{registryName}/{key_id}
8837
```
8938
90-
**Example**: `https://dedi-api.com/dedi/lookup/76EU8BF1gzRGGatgw7wZZb7nEVx77XSwkKDv4UDLdxh8ztty4zmbYU/dedi_registry/bap-network`
39+
**Example**: `https://dedi-wrapper.com/dedi/lookup/bpp.example.com/subscribers.beckn.one/key-1`
9140
9241
### Authentication
93-
```
94-
Authorization: Bearer {apiKey}
95-
```
42+
**No authentication required** - DeDi wrapper API is public.
9643
97-
### Expected DeDi Response Format
44+
### Expected Response Format
9845
9946
```json
10047
{
101-
"message": "Resource retrieved successfully",
48+
"message": "Record retrieved from registry cache",
10249
"data": {
103-
"namespace": "dediregistry",
104-
"namespace_id": "76EU8BF1gzRGGatgw7wZZb7nEVx77XSwkKDv4UDLdxh8ztty4zmbYU",
105-
"registry_name": "dedi_registry",
106-
"record_name": "bap-network",
50+
"record_id": "76EU8vY9TkuJ9T62Sc3FyQLf5Kt9YAVgbZhryX6mFi56ipefkP9d9a",
10751
"details": {
108-
"key_id": "b692d295-5425-40f5-af77-d62646841dca",
109-
"signing_public_key": "YK3Xqc83Bpobc1UT0ObAe6mBJMiAOkceIsNtmph9WTc=",
110-
"encr_public_key": "YK3Xqc83Bpobc1UT0ObAe6mBJMiAOkceIsNtmph9WTc=",
111-
"status": "SUBSCRIBED",
112-
"created": "2024-01-15T10:00:00Z",
113-
"updated": "2024-01-15T10:00:00Z",
114-
"valid_from": "2024-01-01T00:00:00Z",
115-
"valid_until": "2025-12-31T23:59:59Z"
52+
"url": "http://dev.np2.com/beckn/bap",
53+
"type": "BAP",
54+
"domain": "energy",
55+
"subscriber_id": "dev.np2.com",
56+
"signing_public_key": "384qqkIIpxo71WaJPsWqQNWUDGAFnfnJPxuDmtuBiLo=",
57+
"encr_public_key": "test-encr-key"
11658
},
117-
"state": "live",
118-
"created_at": "2025-10-09T06:09:48.295Z"
59+
"created_at": "2025-10-27T11:45:27.963Z",
60+
"updated_at": "2025-10-27T11:46:23.563Z"
11961
}
12062
}
12163
```
12264

123-
### Field Mapping to Beckn Subscription
65+
## Usage Context
66+
67+
### Signature Validation Flow
68+
```
69+
1. External ONIX → Request with Authorization header
70+
2. ONIX Receiver → parseHeader() extracts subscriberID/keyID
71+
3. validateSign step → KeyManager.LookupNPKeys()
72+
4. KeyManager → DeDiRegistry.Lookup() with extracted values
73+
5. DeDi Registry → GET {url}/lookup/{subscriberID}/{registryName}/{keyID}
74+
6. DeDi Wrapper → Returns participant public keys
75+
7. SignValidator → Validates signature using retrieved public key
76+
```
77+
78+
### Module Configuration Example
12479

125-
| DeDi Field | Beckn Field | Description |
126-
|------------|-------------|-------------|
127-
| `data.record_name` | `subscriber_id` | Participant identifier |
128-
| `data.details.key_id` | `key_id` | Unique key identifier |
80+
```yaml
81+
modules:
82+
- name: bppTxnReceiver
83+
handler:
84+
plugins:
85+
registry:
86+
id: dediregistry
87+
config:
88+
url: "https://dedi-wrapper.example.com/dedi"
89+
registryName: "subscribers.beckn.one"
90+
timeout: 30
91+
steps:
92+
- validateSign # Required for registry lookup
93+
- addRoute
94+
```
95+
96+
## Field Mapping
97+
98+
| DeDi Wrapper Field | Beckn Field | Description |
99+
|-------------------|-------------|-------------|
100+
| `data.details.subscriber_id` | `subscriber_id` | Participant identifier |
101+
| `{key_id from URL}` | `key_id` | Unique key identifier |
129102
| `data.details.signing_public_key` | `signing_public_key` | Public key for signature verification |
130103
| `data.details.encr_public_key` | `encr_public_key` | Public key for encryption |
131-
| `data.details.status` | `status` | Subscription status |
132-
| `data.details.created` | `created` | Creation timestamp |
133-
| `data.details.updated` | `updated` | Last update timestamp |
134-
| `data.details.valid_from` | `valid_from` | Key validity start |
135-
| `data.details.valid_until` | `valid_until` | Key validity end |
104+
| `data.is_revoked` | `status` | Not mapped (Status field will be empty) |
105+
| `data.created_at` | `created` | Creation timestamp |
106+
| `data.updated_at` | `updated` | Last update timestamp |
136107

137-
### Lookup Flow
108+
## Features
138109

139-
1. **Request Processing**: Plugin extracts `subscriber_id` from incoming request
140-
2. **API Call**: Makes GET request to DeDi API with static config + dynamic subscriber ID
141-
3. **Response Parsing**: Extracts data from `data.details` object
142-
4. **Format Conversion**: Maps DeDi fields to Beckn Subscription format
143-
5. **Return**: Returns array of Subscription objects
110+
- **No Authentication Required**: DeDi wrapper API doesn't require API keys
111+
- **GET Request Format**: Simple URL-based parameter passing
112+
- **Comprehensive Error Handling**: Validates required fields and HTTP responses
113+
- **Simplified Response**: Focuses on public key retrieval for signature validation
114+
- **Retry Support**: Built-in retry mechanism for network resilience
144115

145116
## Testing
146117

147-
Run plugin tests:
118+
Run the test suite:
148119

149120
```bash
150121
go test ./pkg/plugin/implementation/dediregistry -v
151122
```
152123

153-
Test coverage includes:
124+
The tests cover:
125+
- URL construction validation
126+
- Response parsing for new API format
127+
- Error handling scenarios
154128
- Configuration validation
155-
- Successful API responses
156-
- HTTP error handling
157-
- Network failures
158-
- Invalid JSON responses
159-
- Missing required fields
129+
- Plugin provider functionality
130+
131+
## Migration Notes
132+
133+
This plugin replaces direct DeDi API integration with the new DeDi Wrapper API format:
134+
135+
- **Removed**: API key authentication, namespaceID parameters
136+
- **Added**: Configurable registryName parameter
137+
- **Changed**: POST requests → GET requests
138+
- **Updated**: Response structure parsing (`data.details` object)
139+
- **Added**: New URL path parameter format
160140

161141
## Dependencies
162142

@@ -165,19 +145,8 @@ Test coverage includes:
165145

166146
## Error Handling
167147

168-
- **Configuration Errors**: Missing required config parameters
148+
- **Configuration Errors**: Missing url or registryName
169149
- **Network Errors**: Connection failures, timeouts
170-
- **HTTP Errors**: Non-200 status codes from DeDi API
150+
- **HTTP Errors**: Non-200 status codes from DeDi wrapper
171151
- **Data Errors**: Missing required fields in response
172-
- **Validation Errors**: Empty subscriber ID in request
173-
174-
175-
### Integration Notes
176-
177-
- **Plugin Type**: Registry implementation
178-
- **Interface**: Implements `RegistryLookup` interface with `Lookup(ctx, *model.Subscription) ([]model.Subscription, error)`
179-
- **Manager Access**: Available via `manager.Registry()` method (same as standard registry)
180-
- **Dynamic Lookup**: Uses `req.SubscriberID` from request context, not static configuration
181-
- **Data Conversion**: Automatically converts DeDi API format to Beckn Subscription format
182-
- **Build Integration**: Included in `build-plugins.sh`, compiles to `dediregistry.so`
183-
- **Usage Pattern**: Configure with `id: dediregistry` in registry plugin configuration
152+
- **Validation Errors**: Empty subscriber ID or key ID in request

pkg/plugin/implementation/dediregistry/cmd/plugin.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ func (d dediRegistryProvider) New(ctx context.Context, config map[string]string)
2121

2222
// Create dediregistry.Config directly from map - validation is handled by dediregistry.New
2323
dediConfig := &dediregistry.Config{
24-
BaseURL: config["baseURL"],
24+
URL: config["url"],
25+
RegistryName: config["registryName"],
2526
}
2627

2728
// Parse timeout if provided

pkg/plugin/implementation/dediregistry/cmd/plugin_test.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ func TestDediRegistryProvider_New(t *testing.T) {
1010
provider := dediRegistryProvider{}
1111

1212
config := map[string]string{
13-
"baseURL": "https://test.com",
14-
"apiKey": "test-key",
15-
"namespaceID": "test-namespace",
16-
"registryName": "test-registry",
17-
"recordName": "test-record",
13+
"url": "https://test.com/dedi",
14+
"registryName": "subscribers.beckn.one",
1815
"timeout": "30",
1916
}
2017

@@ -47,12 +44,12 @@ func TestDediRegistryProvider_New_InvalidConfig(t *testing.T) {
4744
config map[string]string
4845
}{
4946
{
50-
name: "missing baseURL",
51-
config: map[string]string{"apiKey": "test-key"},
47+
name: "missing url",
48+
config: map[string]string{"registryName": "subscribers.beckn.one", "timeout": "30"},
5249
},
5350
{
54-
name: "missing apiKey",
55-
config: map[string]string{"baseURL": "https://test.com"},
51+
name: "missing registryName",
52+
config: map[string]string{"url": "https://test.com/dedi", "timeout": "30"},
5653
},
5754
{
5855
name: "empty config",
@@ -75,11 +72,8 @@ func TestDediRegistryProvider_New_InvalidTimeout(t *testing.T) {
7572
provider := dediRegistryProvider{}
7673

7774
config := map[string]string{
78-
"baseURL": "https://test.com",
79-
"apiKey": "test-key",
80-
"namespaceID": "test-namespace",
81-
"registryName": "test-registry",
82-
"recordName": "test-record",
75+
"url": "https://test.com/dedi",
76+
"registryName": "subscribers.beckn.one",
8377
"timeout": "invalid",
8478
}
8579

@@ -95,3 +89,20 @@ func TestDediRegistryProvider_New_InvalidTimeout(t *testing.T) {
9589
closer()
9690
}
9791
}
92+
93+
func TestDediRegistryProvider_New_NilContext(t *testing.T) {
94+
provider := dediRegistryProvider{}
95+
96+
config := map[string]string{
97+
"url": "https://test.com/dedi",
98+
"registryName": "subscribers.beckn.one",
99+
}
100+
101+
_, _, err := provider.New(nil, config)
102+
if err == nil {
103+
t.Error("New() with nil context should return error")
104+
}
105+
if err.Error() != "context cannot be nil" {
106+
t.Errorf("Expected specific error message, got %v", err)
107+
}
108+
}

0 commit comments

Comments
 (0)