From 98a91099dfb4009f1fe00d3bb9e7892ab875e794 Mon Sep 17 00:00:00 2001 From: chenchanglew Date: Tue, 19 Aug 2025 15:34:16 +0200 Subject: [PATCH] tests: add integration test for skvs on secret manager Signed-off-by: chenchanglew --- integration/go_chaincode/Makefile | 2 +- integration/go_chaincode/skvs/Makefile | 21 ++++ integration/go_chaincode/skvs/client.go | 46 ++++++++ integration/go_chaincode/skvs/skvs_test.go | 122 +++++++++++++++++++++ integration/go_chaincode/skvs/topology.go | 71 ++++++++++++ 5 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 integration/go_chaincode/skvs/Makefile create mode 100644 integration/go_chaincode/skvs/client.go create mode 100644 integration/go_chaincode/skvs/skvs_test.go create mode 100644 integration/go_chaincode/skvs/topology.go diff --git a/integration/go_chaincode/Makefile b/integration/go_chaincode/Makefile index 3644fcdf9..8e1077969 100644 --- a/integration/go_chaincode/Makefile +++ b/integration/go_chaincode/Makefile @@ -3,7 +3,7 @@ TOP = ../.. include $(TOP)/build.mk -GO_TEST_DIRS=auction kv_test +GO_TEST_DIRS=auction kv_test skvs deps: ercc images diff --git a/integration/go_chaincode/skvs/Makefile b/integration/go_chaincode/skvs/Makefile new file mode 100644 index 000000000..a44b17e1c --- /dev/null +++ b/integration/go_chaincode/skvs/Makefile @@ -0,0 +1,21 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../../.. +include $(TOP)/build.mk + +CHAINCODE_PATH=$(FPC_PATH)/samples/chaincode/secret-keeper-go + +all: build test clean + +test: + FABRIC_LOGGING_SPEC=fpc=debug:grpc=error:comm.grpc=error:gossip=warning:info go test -v -failfast . + +build: + make -C $(CHAINCODE_PATH) ECC_MAIN_FILES=$(CHAINCODE_PATH)/cmd/skvs/main.go with_go env docker + cp $(CHAINCODE_PATH)/mrenclave . + +clean: + rm -rf cmd + rm mrenclave diff --git a/integration/go_chaincode/skvs/client.go b/integration/go_chaincode/skvs/client.go new file mode 100644 index 000000000..45d315389 --- /dev/null +++ b/integration/go_chaincode/skvs/client.go @@ -0,0 +1,46 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package kv + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/pkg/errors" +) + +type Client struct { + CID string + Function string + Args []string +} + +type ClientView struct { + *Client +} + +func (c *ClientView) Call(context view.Context) (interface{}, error) { + fmt.Printf("Call FPC (CID='%s') with f='%s' and Args='%v'\n", c.CID, c.Function, c.Args) + _, err := fpc.GetDefaultChannel(context).Chaincode(c.CID).Invoke(c.Function, fpc.StringsToArgs(c.Args)...).Call() + if err != nil { + return nil, errors.Wrapf(err, "error invoking %s", c.Function) + } + + return nil, nil +} + +type ClientViewFactory struct{} + +func (c *ClientViewFactory) NewView(in []byte) (view.View, error) { + f := &ClientView{Client: &Client{}} + if err := json.Unmarshal(in, f.Client); err != nil { + return nil, err + } + return f, nil +} diff --git a/integration/go_chaincode/skvs/skvs_test.go b/integration/go_chaincode/skvs/skvs_test.go new file mode 100644 index 000000000..3cd0d4ee9 --- /dev/null +++ b/integration/go_chaincode/skvs/skvs_test.go @@ -0,0 +1,122 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kv + +import ( + "testing" + + "github.com/hyperledger-labs/fabric-smart-client/integration" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/common" + "github.com/stretchr/testify/assert" +) + +func TestFlow(t *testing.T) { + + // setup fabric network + ii, err := integration.Generate(23000, false, Topology()...) + assert.NoError(t, err) + ii.Start() + defer ii.Stop() + + // 1. Initialize Secret Keeper: + // ./fpcclient invoke InitSecretKeeper + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "InitSecretKeeper", + Args: []string{}, + })) + assert.NoError(t, err) + + // 2. Reveal the secret as Alice: + // ./fpcclient query RevealSecret Alice + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "RevealSecret", + Args: []string{"Alice"}, + })) + assert.NoError(t, err) + + // 3. Change the secret as Bob: + // ./fpcclient invoke LockSecret Bob NewSecret + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "LockSecret", + Args: []string{"Bob", "NewSecret"}, + })) + assert.NoError(t, err) + + // 4. Attempt to reveal the secret as Alice (now updated): + // ./fpcclient query revealSecret Alice + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "RevealSecret", + Args: []string{"Alice"}, + })) + assert.NoError(t, err) + + // 5. Remove Bob's access as Alice: + // ./fpcclient invoke removeUser Alice Bob + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "RemoveUser", + Args: []string{"Alice", "Bob"}, + })) + assert.NoError(t, err) + + // 6. Attempt to reveal the secret as Bob (should fail): + // ./fpcclient query revealSecret Bob // (will failed) + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "RevealSecret", + Args: []string{"Bob"}, + })) + assert.Error(t, err) + + // 7. Re-add Bob to the authorization list as Alice: + // ./fpcclient invoke addUser Alice Bob + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "AddUser", + Args: []string{"Alice", "Bob"}, + })) + assert.NoError(t, err) + + // 8. Bob can now reveal the secret successfully: + // ./fpcclient query revealSecret Bob // (will success) + _, err = ii.Client("alice").CallView("invoke", common.JSONMarshall(&Client{ + CID: ChaincodeName, + Function: "RevealSecret", + Args: []string{"Bob"}, + })) + assert.NoError(t, err) + + /* + TODO: + instead of using Alice/Bob as a parameter during invoke/query + we use the signer identity + NEED to change secret-keeper.go implementation. + + Before: + cd $FPC_PATH/samples/application/simple-cli-go + make + source $FPC_PATH/samples/chaincode/secret-keeper-go/details.env + $FPC_PATH/samples/deployment/fabric-smart-client/the-simple-testing-network/env.sh Org1 + source Org1.env + After: + cd $FPC_PATH/samples/application/simple-cli-go + make + source $FPC_PATH/samples/chaincode/secret-keeper-go/details.env + $FPC_PATH/samples/deployment/fabric-smart-client/the-simple-testing-network/env.sh Org1 + source Org1.env + + (Another Terminal) + $FPC_PATH/samples/deployment/fabric-smart-client/the-simple-testing-network/env.sh Org2 + source Org2.env + + make ECC_MAIN_FILES=cmd/skvs/main.go with_go env docker + */ +} diff --git a/integration/go_chaincode/skvs/topology.go b/integration/go_chaincode/skvs/topology.go new file mode 100644 index 000000000..3b731b986 --- /dev/null +++ b/integration/go_chaincode/skvs/topology.go @@ -0,0 +1,71 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kv + +import ( + "fmt" + "os" + "strings" + + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/api" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric/topology" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fsc" + fabric2 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/sdk" + "github.com/hyperledger/fabric-private-chaincode/integration/go_chaincode/utils" + "github.com/pkg/errors" +) + +const ( + ChaincodeName = "secret-keeper-go" + ChaincodeImageName = "fpc/secret-keeper-go" + ChaincodeImageTag = "latest" +) + +func Topology() []api.Topology { + // make ECC_MAIN_FILES=cmd/skvs/main.go with_go env docker + chaincodeImageName := fmt.Sprintf("%s:%s", ChaincodeImageName, ChaincodeImageTag) + var fpcOptions []func(chaincode *topology.ChannelChaincode) + + if strings.ToUpper(os.Getenv("SGX_MODE")) == "HW" { + chaincodeImageName = fmt.Sprintf("%s-hw:%s", ChaincodeImageName, ChaincodeImageTag) + fpcOptions = append(fpcOptions, topology.WithSGXMode("HW")) + + mrenclave, err := utils.ReadMrenclaveFromFile("mrenclave") + if err != nil { + panic(errors.Wrapf(err, "cannot get mrenclave")) + } + fpcOptions = append(fpcOptions, topology.WithMREnclave(mrenclave)) + + sgxDevicePath, err := utils.DetectSgxDevicePath() + if err != nil { + panic(errors.Wrapf(err, "SGX HW mode set but now sgx device found")) + } + fpcOptions = append(fpcOptions, topology.WithSGXDevicesPaths(sgxDevicePath)) + } + + fabricTopology := fabric.NewDefaultTopology() + fabricTopology.AddOrganizationsByName("Org1") + fabricTopology.AddFPC(ChaincodeName, chaincodeImageName, fpcOptions...) + fabricTopology.SetLogging("fpc=debug:grpc=error:comm.grpc=error:gossip=warning:info", "") + fscTopology := fsc.NewTopology() + + // client Alice + clientNodeAlice := fscTopology.AddNodeByName("alice") + clientNodeAlice.AddOptions(fabric.WithOrganization("Org1")) + clientNodeAlice.RegisterViewFactory("invoke", &ClientViewFactory{}) + + // client Bob + // clientNodeBob := fscTopology.AddNodeByName("bob") + // clientNodeBob.AddOptions(fabric.WithOrganization("Org2")) + // clientNodeBob.RegisterViewFactory("invoke", &ClientViewFactory{}) + + // Add Fabric SDK to FSC Nodes + fscTopology.AddSDK(&fabric2.SDK{}) + + return []api.Topology{fabricTopology, fscTopology} +}