From 699f36753b3592badfc0c14b4506f567f2b38e71 Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Thu, 22 Oct 2026 13:08:51 +0200 Subject: [PATCH 1/2] chore: fix holderPid generation --- agent/common/identityhub/identityhub.go | 16 ++++++++++++++++ agent/common/identityhub/identityhub_test.go | 17 +++++++++++++++++ agent/common/identityhub/types.go | 1 - agent/common/identityhub/types_test.go | 10 +++++++--- .../onboarding/activity/activity.go | 9 +++++---- .../onboarding/activity/activity_test.go | 2 +- 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/agent/common/identityhub/identityhub.go b/agent/common/identityhub/identityhub.go index 95652a2..2b6adb3 100644 --- a/agent/common/identityhub/identityhub.go +++ b/agent/common/identityhub/identityhub.go @@ -21,6 +21,8 @@ import ( "fmt" "io" "net/http" + "net/url" + "path" "github.com/eclipse-cfm/cfm/agent/common" "github.com/eclipse-cfm/cfm/common/token" @@ -152,6 +154,20 @@ func (a HttpIdentityAPIClient) RequestCredentials(ctx context.Context, participa return location, nil } +// HolderPIDFromLocation extracts the holderPid that IdentityHub assigned to a credential request from the Location +// header returned on its creation, which ends with ".../credentials/request/{holderPid}". +func HolderPIDFromLocation(location string) (string, error) { + u, err := url.Parse(location) + if err != nil { + return "", fmt.Errorf("invalid credential request location '%s': %w", location, err) + } + holderPID := path.Base(u.Path) + if holderPID == "" || holderPID == "." || holderPID == "/" || holderPID == "request" { + return "", fmt.Errorf("credential request location '%s' does not contain a holderPid", location) + } + return holderPID, nil +} + func (a HttpIdentityAPIClient) GetCredentialRequestState(ctx context.Context, participantContextID string, credentialRequestID string) (string, error) { accessToken, err := a.TokenProvider.GetToken(ctx, ScopeCredentialsRead, participantContextID) if err != nil { diff --git a/agent/common/identityhub/identityhub_test.go b/agent/common/identityhub/identityhub_test.go index c55ab9c..19e3ca6 100644 --- a/agent/common/identityhub/identityhub_test.go +++ b/agent/common/identityhub/identityhub_test.go @@ -180,3 +180,20 @@ func TestHttpIdentityAPIClient_DeleteParticipantContext_NotFound(t *testing.T) { err := client.DeleteParticipantContext(t.Context(), "test") require.ErrorContains(t, err, "participant context test not found") } + +func TestHolderPIDFromLocation(t *testing.T) { + holderPID, err := HolderPIDFromLocation("v1/participants/participant-1/credentials/request/holder-123") + require.NoError(t, err) + require.Equal(t, "holder-123", holderPID) + + holderPID, err = HolderPIDFromLocation("http://identityhub/api/identity/v1/participants/participant-1/credentials/request/holder-123") + require.NoError(t, err) + require.Equal(t, "holder-123", holderPID) +} + +func TestHolderPIDFromLocation_Invalid(t *testing.T) { + for _, location := range []string{"", "/", "v1/participants/participant-1/credentials/request", "http://[::1"} { + _, err := HolderPIDFromLocation(location) + require.Error(t, err, location) + } +} diff --git a/agent/common/identityhub/types.go b/agent/common/identityhub/types.go index f629a69..4b61026 100644 --- a/agent/common/identityhub/types.go +++ b/agent/common/identityhub/types.go @@ -123,6 +123,5 @@ type CredentialType struct { type CredentialRequest struct { IssuerDID string `json:"issuerDid" validate:"required"` - HolderPID string `json:"holderPid" validate:"required"` Credentials []CredentialType `json:"credentials" validate:"required"` } diff --git a/agent/common/identityhub/types_test.go b/agent/common/identityhub/types_test.go index ada9c74..448612c 100644 --- a/agent/common/identityhub/types_test.go +++ b/agent/common/identityhub/types_test.go @@ -53,7 +53,6 @@ func TestParticipantManifest_Serialization(t *testing.T) { func TestCredentialRequest_Serialization(t *testing.T) { cr := CredentialRequest{ IssuerDID: "did:example:issuer", - HolderPID: "holder-123", Credentials: []CredentialType{ { Format: "ldp", @@ -73,12 +72,17 @@ func TestCredentialRequest_Serialization(t *testing.T) { } func TestCredentialRequest_Deserialization(t *testing.T) { - jsonString := `{"issuerDid": "did:example:issuer", "holderPid": "holder-123", "credentials": [{"format": "ldp", "type": "VerifiableCredential", "id": "cred-1"}]}` + jsonString := `{"issuerDid": "did:example:issuer", "credentials": [{"format": "ldp", "type": "VerifiableCredential", "id": "cred-1"}]}` request := CredentialRequest{} err := json.Unmarshal([]byte(jsonString), &request) require.NoError(t, err) require.Equal(t, "did:example:issuer", request.IssuerDID) - require.Equal(t, "holder-123", request.HolderPID) require.Len(t, request.Credentials, 1) } + +func TestCredentialRequest_Serialization_OmitsHolderPid(t *testing.T) { + data, err := json.Marshal(CredentialRequest{IssuerDID: "did:example:issuer"}) + require.NoError(t, err) + require.NotContains(t, string(data), "holderPid") +} diff --git a/agent/orchestration/onboarding/activity/activity.go b/agent/orchestration/onboarding/activity/activity.go index ef0b777..e7a6a3d 100644 --- a/agent/orchestration/onboarding/activity/activity.go +++ b/agent/orchestration/onboarding/activity/activity.go @@ -21,7 +21,6 @@ import ( "github.com/eclipse-cfm/cfm/common/model" "github.com/eclipse-cfm/cfm/common/system" "github.com/eclipse-cfm/cfm/pmanager/api" - "github.com/google/uuid" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -167,17 +166,19 @@ func (p OnboardingActivityProcessor) processNewRequest(ctx api.ActivityContext, return api.ActivityResult{Result: api.ActivityResultFatalError, Error: fmt.Errorf("multiple issuers not supported yet")} } - holderPid := uuid.New().String() cr := identityhub.CredentialRequest{ IssuerDID: issuer, - HolderPID: holderPid, Credentials: credentials, } - // make credential request + // make credential request, IdentityHub assigns the holderPid and returns it at the end of the location location, err := p.IdentityApiClient.RequestCredentials(ctx.Context(), credentialRequest.ParticipantContextID, cr) if err != nil { return api.ActivityResult{Result: api.ActivityResultFatalError, Error: fmt.Errorf("error requesting credentials: %w", err)} } + holderPid, err := identityhub.HolderPIDFromLocation(location) + if err != nil { + return api.ActivityResult{Result: api.ActivityResultFatalError, Error: fmt.Errorf("error requesting credentials: %w", err)} + } p.Monitor.Infof("Credentials request for participant '%s' and credentials '%s' submitted successfully, credential is at %s", credentialRequest.ParticipantContextID, credentialsTypes, location) ctx.SetValue("participantContextId", credentialRequest.ParticipantContextID) ctx.SetValue("holderPid", holderPid) diff --git a/agent/orchestration/onboarding/activity/activity_test.go b/agent/orchestration/onboarding/activity/activity_test.go index 0c43ea7..f022af0 100644 --- a/agent/orchestration/onboarding/activity/activity_test.go +++ b/agent/orchestration/onboarding/activity/activity_test.go @@ -64,7 +64,7 @@ func TestOnboardingActivityProcessor_ProcessDeploy_WhenNewRequest(t *testing.T) assert.Equal(t, ih.expectedURL, activityContext.Values()["credentialRequest"]) assert.Equal(t, "test-participant", activityContext.Values()["participantContextId"]) - assert.Contains(t, activityContext.Values(), "holderPid") + assert.Equal(t, "123", activityContext.Values()["holderPid"]) } func TestOnboardingActivityProcessor_ProcessDeploy_WhenNewRequestError(t *testing.T) { From 4ef8b795920f3f0542e5e35b34aadfa7db773038 Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Thu, 22 Oct 2026 13:17:38 +0200 Subject: [PATCH 2/2] chore: pin mockery --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e13511d..82fb3db 100644 --- a/Makefile +++ b/Makefile @@ -180,7 +180,7 @@ clean: #============================================================================== install-mockery: - go install github.com/vektra/mockery/v2@latest + go install github.com/vektra/mockery/v2@v2.53.7 install-gotestsum: go install gotest.tools/gotestsum@latest