Skip to content

Commit 919ce21

Browse files
mkedjourjadiaconu
authored andcommitted
feat(node): propagated request ID to Identity Node
Signed-off-by: Mohamed Tahar KEDJOUR <mkedjour@cisco.com>
1 parent 1e7cf3b commit 919ce21

3 files changed

Lines changed: 144 additions & 5 deletions

File tree

backend/internal/core/identity/identity_service.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ type Service interface {
6868
) error
6969
}
7070

71-
// The verificationService struct implements the VerificationService interface
71+
// service struct implements the VerificationService interface
7272
type service struct {
7373
issuerClient issuersdk.ClientService
7474
idClient idsdk.ClientService
@@ -78,7 +78,7 @@ type service struct {
7878
uniqueIssuerPerTenant bool
7979
}
8080

81-
// NewVerificationService creates a new instance of the VerificationService
81+
// NewService creates a new instance of the VerificationService
8282
func NewService(
8383
identityHost, identityPort string,
8484
keyStore KeyStore,
@@ -90,6 +90,7 @@ func NewService(
9090
"",
9191
nil,
9292
)
93+
transport.Transport = newTransportWithRequestID()
9394

9495
return &service{
9596
issuerClient: issuersdk.New(transport, strfmt.Default),
@@ -145,6 +146,7 @@ func (s *service) RegisterIssuer(
145146
Issuer: issuer,
146147
Proof: proof,
147148
},
149+
Context: ctx,
148150
})
149151

150152
if err != nil &&
@@ -178,6 +180,7 @@ func (s *service) GenerateID(
178180
},
179181
Proof: proof,
180182
},
183+
Context: ctx,
181184
})
182185
if err != nil {
183186
return "", fmt.Errorf("error generating ID with identity service: %w", err)
@@ -239,6 +242,7 @@ func (s *service) PublishVerifiableCredential(
239242
ProofValue: proof.ProofValue,
240243
},
241244
},
245+
Context: ctx,
242246
})
243247
if err != nil {
244248
return err
@@ -332,6 +336,7 @@ func (s *service) VerifyVerifiableCredential(
332336
Value: *vc,
333337
},
334338
},
339+
Context: ctx,
335340
})
336341
if err != nil {
337342
return nil, fmt.Errorf("error verifying verifiable credential: %w", err)
@@ -349,8 +354,8 @@ func (s *service) VerifyVerifiableCredential(
349354
MediaType: result.MediaType,
350355
Controller: result.Controller,
351356
ControlledIdentifierDocument: result.ControlledIdentifierDocument,
352-
Warnings: convertutil.ConvertSlice(result.Warnings, convertErroInfo),
353-
Errors: convertutil.ConvertSlice(result.Errors, convertErroInfo),
357+
Warnings: convertutil.ConvertSlice(result.Warnings, convertErrorInfo),
358+
Errors: convertutil.ConvertSlice(result.Errors, convertErrorInfo),
354359
}, nil
355360
}
356361

@@ -403,6 +408,7 @@ func (s *service) RevokeVerifiableCredential(
403408
ProofValue: proof.ProofValue,
404409
},
405410
},
411+
Context: ctx,
406412
})
407413
if err != nil {
408414
errInfo, err := tryGetErrorInfo(err)
@@ -441,7 +447,7 @@ func tryGetErrorInfo(err error) (*identitymodels.V1alpha1ErrorInfo, error) {
441447
return nil, err
442448
}
443449

444-
func convertErroInfo(err *identitymodels.V1alpha1ErrorInfo) *badgetypes.ErrorInfo {
450+
func convertErrorInfo(err *identitymodels.V1alpha1ErrorInfo) *badgetypes.ErrorInfo {
445451
if err == nil {
446452
return nil
447453
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2025 AGNTCY Contributors (https://github.com/agntcy)
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package identity
5+
6+
import (
7+
"net/http"
8+
9+
identitycontext "github.com/agntcy/identity-service/internal/pkg/context"
10+
)
11+
12+
// transportWithRequestID is an HTTP transport that propagates the request ID to the Identity Node
13+
type transportWithRequestID struct {
14+
Transport http.RoundTripper
15+
}
16+
17+
func (t *transportWithRequestID) RoundTrip(req *http.Request) (*http.Response, error) {
18+
reqID, ok := identitycontext.GetRequestID(req.Context())
19+
if !ok || reqID == "" {
20+
return t.Transport.RoundTrip(req)
21+
}
22+
23+
if req.Header == nil {
24+
req.Header = make(http.Header)
25+
}
26+
27+
req.Header.Add("X-Request-Id", reqID)
28+
29+
return t.Transport.RoundTrip(req)
30+
}
31+
32+
func newTransportWithRequestID() *transportWithRequestID {
33+
return &transportWithRequestID{
34+
Transport: http.DefaultTransport,
35+
}
36+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2025 AGNTCY Contributors (https://github.com/agntcy)
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//nolint:testpackage // this file is testing a private struct
5+
package identity
6+
7+
import (
8+
"context"
9+
"net/http"
10+
"net/http/httptest"
11+
"testing"
12+
13+
identitycontext "github.com/agntcy/identity-service/internal/pkg/context"
14+
"github.com/google/uuid"
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func createTestServerWithReqHeadersPropagation(t *testing.T) *httptest.Server {
19+
t.Helper()
20+
21+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22+
for k, v := range r.Header {
23+
w.Header().Add(k, v[0])
24+
}
25+
26+
_, _ = w.Write([]byte(uuid.NewString()))
27+
}))
28+
}
29+
30+
func TestTransportWithRequestID_should_inject_request_id_in_http_request(t *testing.T) {
31+
t.Parallel()
32+
33+
ts := createTestServerWithReqHeadersPropagation(t)
34+
defer ts.Close()
35+
36+
requestID := uuid.NewString()
37+
ctx := identitycontext.InsertRequestID(t.Context(), requestID)
38+
39+
transport := newTransportWithRequestID()
40+
client := http.Client{
41+
Transport: transport,
42+
}
43+
44+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, http.NoBody)
45+
assert.NoError(t, err)
46+
47+
resp, err := client.Do(req)
48+
49+
defer func() {
50+
_ = resp.Body.Close()
51+
}()
52+
53+
assert.NoError(t, err)
54+
assert.Equal(t, requestID, resp.Header.Get("X-Request-Id"))
55+
}
56+
57+
func TestTransportWithRequestID_should_not_inject_request_id_in_http_request(t *testing.T) {
58+
t.Parallel()
59+
60+
testCases := map[string]*struct {
61+
ctx context.Context //nolint:containedctx // essential part of the test case
62+
}{
63+
"empty request ID in context": {
64+
ctx: identitycontext.InsertRequestID(t.Context(), ""),
65+
},
66+
"context without request ID": {
67+
ctx: t.Context(),
68+
},
69+
}
70+
71+
for tn, tc := range testCases {
72+
t.Run(tn, func(t *testing.T) {
73+
t.Parallel()
74+
75+
ts := createTestServerWithReqHeadersPropagation(t)
76+
defer ts.Close()
77+
78+
transport := newTransportWithRequestID()
79+
client := http.Client{Transport: transport}
80+
81+
req, err := http.NewRequestWithContext(tc.ctx, http.MethodGet, ts.URL, http.NoBody)
82+
assert.NoError(t, err)
83+
84+
resp, err := client.Do(req)
85+
86+
defer func() {
87+
_ = resp.Body.Close()
88+
}()
89+
90+
assert.NoError(t, err)
91+
92+
v, exists := resp.Header[http.CanonicalHeaderKey("X-Request-Id")]
93+
assert.False(t, exists)
94+
assert.Empty(t, v)
95+
})
96+
}
97+
}

0 commit comments

Comments
 (0)