Repository: edgexfoundry/edgex-go
Pull request #4211 (2022-10-24 19:07:57)

build(deps): Bump github.com/stretchr/testify from 1.8.0 to 1.8.1
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.0 to 1.8.1.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/stretchr/testify/commit/b747d7c5f853d017ddbc5e623d026d7fc2770a58"><code>b747d7c</code></a> Bump github.com/stretchr/objx from 0.4.0 to 0.5.0 (<a href="https://github-redirect.dependabot.com/stretchr/testify/issues/1283">#1283</a>)</li>
<li>See full diff in <a href="https://github.com/stretchr/testify/compare/v1.8.0...v1.8.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/stretchr/testify&package-manager=go_modules&previous-version=1.8.0&new-version=1.8.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/Attribution.txt b/Attribution.txt
index c326f0d5..b5055998 100644
--- a/Attribution.txt
+++ b/Attribution.txt
@@ -8,9 +8,6 @@ https://github.com/pkg/errors/blob/master/LICENSE
 gorilla/mux (BSD-3) https://github.com/gorilla/mux
 https://github.com/gorilla/mux/blob/master/LICENSE
 
-pebbe/zmq4 (BSD-2) https://github.com/pebbe/zmq4
-https://github.com/pebbe/zmq4/blob/master/LICENSE.txt
-
 go-kit/kit (MIT) github.com/go-kit/kit
 https://github.com/go-kit/kit/blob/master/LICENSE
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91bc8777..f3892f10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,87 @@
 - [go-mod-secrets](https://github.com/edgexfoundry/go-mod-secrets/blob/main/CHANGELOG.md)
 - [go-mod-configuration](https://github.com/edgexfoundry/go-mod-configuration/blob/main/CHANGELOG.md) (indirect dependency)
 
+## [v2.3.0] Levski - 2022-11-09 (Only compatible with the 2.x release)
+
+### Features ✨
+
+- Secure MQTT Bus Credentials ([#4142](https://github.com/edgexfoundry/edgex-go/issues/4142)) ([#21503d9d](https://github.com/edgexfoundry/edgex-go/commits/21503d9d))
+- Add secure mqtt support for eKuiper ([#4155](https://github.com/edgexfoundry/edgex-go/issues/4155)) ([#b7de7b77](https://github.com/edgexfoundry/edgex-go/commits/b7de7b77))
+- Enable common security secret service metrics ([#4184](https://github.com/edgexfoundry/edgex-go/issues/4184)) ([#8629e80a](https://github.com/edgexfoundry/edgex-go/commits/8629e80a))
+- Add go-winio to attribution (new SPIFFE dependency) ([#4029](https://github.com/edgexfoundry/edgex-go/issues/4029)) ([#ba7dda9b](https://github.com/edgexfoundry/edgex-go/commits/ba7dda9b))
+- use different consul service policy rule for service role ([#4104](https://github.com/edgexfoundry/edgex-go/issues/4104)) ([#85bfaaf4](https://github.com/edgexfoundry/edgex-go/commits/85bfaaf4))
+- Implement Device System Events ([#4101](https://github.com/edgexfoundry/edgex-go/issues/4101)) ([#643a1ec0](https://github.com/edgexfoundry/edgex-go/commits/643a1ec0))
+- Add management acl token and save token info to file ([#4126](https://github.com/edgexfoundry/edgex-go/issues/4126)) ([#96e03a37](https://github.com/edgexfoundry/edgex-go/commits/96e03a37))
+- Add option to build Core/Support services with NATS Capability ([#4137](https://github.com/edgexfoundry/edgex-go/issues/4137)) ([#604c3c95](https://github.com/edgexfoundry/edgex-go/commits/604c3c95))
+- Add NATS Subject for autoprovisioning streams ([#4165](https://github.com/edgexfoundry/edgex-go/issues/4165)) ([#cf21bfd5](https://github.com/edgexfoundry/edgex-go/commits/cf21bfd5))
+- Add security Consul metrics ([#4203](https://github.com/edgexfoundry/edgex-go/issues/4203)) ([#1656a83b](https://github.com/edgexfoundry/edgex-go/commits/1656a83b))
+- **command:** 3rd party command query via messaging ([#4135](https://github.com/edgexfoundry/edgex-go/issues/4135)) ([#a0e04e55](https://github.com/edgexfoundry/edgex-go/commits/a0e04e55))
+- **command:** Command request from external MQTT to internal MessageBus ([#4153](https://github.com/edgexfoundry/edgex-go/issues/4153)) ([#1c2713d9](https://github.com/edgexfoundry/edgex-go/commits/1c2713d9))
+- **command:** Update core-command to support message bus access ([#4129](https://github.com/edgexfoundry/edgex-go/issues/4129)) ([#fd31c876](https://github.com/edgexfoundry/edgex-go/commits/fd31c876))
+- **command:** Publish device service response to external MQTT ([#4166](https://github.com/edgexfoundry/edgex-go/issues/4166)) ([#1845739d](https://github.com/edgexfoundry/edgex-go/commits/1845739d))
+- **command:** Subscribe command request via internal messaging ([#6f71b1dc](https://github.com/edgexfoundry/edgex-go/commits/6f71b1dc))
+- **command:** Command query via internal messaging ([#4182](https://github.com/edgexfoundry/edgex-go/issues/4182)) ([#07636ef9](https://github.com/edgexfoundry/edgex-go/commits/07636ef9))
+- **metadata:** Add UoM validation to POST deviceresource API ([#4140](https://github.com/edgexfoundry/edgex-go/issues/4140)) ([#f87a0e7a](https://github.com/edgexfoundry/edgex-go/commits/f87a0e7a))
+- **metadata:** Implement GET Units of Measure API ([#4127](https://github.com/edgexfoundry/edgex-go/issues/4127)) ([#de42c75f](https://github.com/edgexfoundry/edgex-go/commits/de42c75f))
+- **metadata:** Implement Unit of Measure (UoM) ADR ([#4119](https://github.com/edgexfoundry/edgex-go/issues/4119)) ([#03487ec6](https://github.com/edgexfoundry/edgex-go/commits/03487ec6))
+- **snap:** Remove device-virtual ([#4041](https://github.com/edgexfoundry/edgex-go/issues/4041)) ([#fed831e0](https://github.com/edgexfoundry/edgex-go/commits/fed831e0))
+- **snap:** Add secretstore token for device camera services ([#4034](https://github.com/edgexfoundry/edgex-go/issues/4034)) ([#6f84e707](https://github.com/edgexfoundry/edgex-go/commits/6f84e707))
+
+### Bug Fixes 🐛
+
+- Delayed start services for support- services fail ([#4159](https://github.com/edgexfoundry/edgex-go/issues/4159)) ([#726ff502](https://github.com/edgexfoundry/edgex-go/commits/726ff502))
+- Fixed security-bootstrapper Docker volume init semantics ([#4085](https://github.com/edgexfoundry/edgex-go/issues/4085)) ([#ad21f989](https://github.com/edgexfoundry/edgex-go/commits/ad21f989))
+- Fix security-secretstore-setup volume init semantics ([#4092](https://github.com/edgexfoundry/edgex-go/issues/4092)) ([#66f7195a](https://github.com/edgexfoundry/edgex-go/commits/66f7195a))
+- Fixed Missing error check ([#4100](https://github.com/edgexfoundry/edgex-go/issues/4100)) ([#062af8d3](https://github.com/edgexfoundry/edgex-go/commits/062af8d3))
+- Always run "kong migrations up" ([#4172](https://github.com/edgexfoundry/edgex-go/issues/4172)) ([#f2edda91](https://github.com/edgexfoundry/edgex-go/commits/f2edda91))
+- Security services' bootstrap handler return true/false properly ([#4107](https://github.com/edgexfoundry/edgex-go/issues/4107)) ([#48044024](https://github.com/edgexfoundry/edgex-go/commits/48044024))
+- Add consul policy list check ([#4164](https://github.com/edgexfoundry/edgex-go/issues/4164)) ([#a3948579](https://github.com/edgexfoundry/edgex-go/commits/a3948579))
+- Add missing edgex/security config stem resolution in security-consul-bootstrapper ([#4110](https://github.com/edgexfoundry/edgex-go/issues/4110)) ([#a9913775](https://github.com/edgexfoundry/edgex-go/commits/a9913775))
+- Addressed permission error in redis v7 [#4027](https://github.com/edgexfoundry/edgex-go/issues/4027) ([#4118](https://github.com/edgexfoundry/edgex-go/issues/4118)) ([#153a8924](https://github.com/edgexfoundry/edgex-go/commits/153a8924))
+- Change redis username from redis5 to default ([#4031](https://github.com/edgexfoundry/edgex-go/issues/4031)) ([#4c165043](https://github.com/edgexfoundry/edgex-go/commits/4c165043))
+- **data:** Fix deleting numerous events HTTP request timeout by goroutines ([#4063](https://github.com/edgexfoundry/edgex-go/issues/4063)) ([#e2bcede5](https://github.com/edgexfoundry/edgex-go/commits/e2bcede5))
+- **scheduler:** Check interval when adding intervalAction ([#895df5c4](https://github.com/edgexfoundry/edgex-go/commits/895df5c4))
+- **scheduler:** Remove unused field in scheduler config ([#81b3411d](https://github.com/edgexfoundry/edgex-go/commits/81b3411d))
+- **snap:** Bind redis server to loopback interface ([#4154](https://github.com/edgexfoundry/edgex-go/issues/4154)) ([#0ef95e30](https://github.com/edgexfoundry/edgex-go/commits/0ef95e30))
+
+### Code Refactoring ♻
+
+- Move all the db related check to the infrastructure layer ([#b0f671d9](https://github.com/edgexfoundry/edgex-go/commits/b0f671d9))
+- Move consul access and role interface ([#4193](https://github.com/edgexfoundry/edgex-go/issues/4193)) ([#5b680ce2](https://github.com/edgexfoundry/edgex-go/commits/5b680ce2))
+- **command:** refactor messaging handler ([#4204](https://github.com/edgexfoundry/edgex-go/issues/4204)) ([#23251983](https://github.com/edgexfoundry/edgex-go/commits/23251983))
+- **data:** Use deepCopy of messageBusInfo to avoid external adds ([#4038](https://github.com/edgexfoundry/edgex-go/issues/4038)) ([#9735311b](https://github.com/edgexfoundry/edgex-go/commits/9735311b))
+- **snap:** Option handling and helper-go build ([#822255de](https://github.com/edgexfoundry/edgex-go/commits/822255de))
+- **snap:** Merge install and configure packages ([#d8cdf693](https://github.com/edgexfoundry/edgex-go/commits/d8cdf693))
+- **snap:** Environment variable usage and const definitions ([#4207](https://github.com/edgexfoundry/edgex-go/issues/4207)) ([#87ac77fe](https://github.com/edgexfoundry/edgex-go/commits/87ac77fe))
+- **snap:** Use snapctl and log packages ([#4187](https://github.com/edgexfoundry/edgex-go/issues/4187)) ([#d47f91d7](https://github.com/edgexfoundry/edgex-go/commits/d47f91d7))
+
+### Documentation 📖
+
+- Publish swager to 2.3.0 ([#4023](https://github.com/edgexfoundry/edgex-go/issues/4023)) ([#f46214d8](https://github.com/edgexfoundry/edgex-go/commits/f46214d8))
+
+### Build 👷
+
+- Dockerfile fix ([#4217](https://github.com/edgexfoundry/edgex-go/issues/4217)) ([#8ec17376](https://github.com/edgexfoundry/edgex-go/commits/8ec17376))
+- Upgrade CodeQL modules, enable additional checkers ([#4080](https://github.com/edgexfoundry/edgex-go/issues/4080)) ([#c49e1d00](https://github.com/edgexfoundry/edgex-go/commits/c49e1d00))
+- Upgrade to go 1.18 and latest golangci-lint ([#4068](https://github.com/edgexfoundry/edgex-go/issues/4068)) ([#fb67e349](https://github.com/edgexfoundry/edgex-go/commits/fb67e349))
+- Add convenient alias for each service's build and docker target ([#4123](https://github.com/edgexfoundry/edgex-go/issues/4123)) ([#23918450](https://github.com/edgexfoundry/edgex-go/commits/23918450))
+- Optimize test-attribution-txt.sh to use go.mod, not vendor ([#4059](https://github.com/edgexfoundry/edgex-go/issues/4059)) ([#25cc1d46](https://github.com/edgexfoundry/edgex-go/commits/25cc1d46))
+- Switch from docker to alpine base image for sys-mgmt-agent ([#6a305a0d](https://github.com/edgexfoundry/edgex-go/commits/6a305a0d))
+- **snap:** Kong migrations up before Kong startup ([#4223](https://github.com/edgexfoundry/edgex-go/issues/4223)) ([#c8dc4aaa](https://github.com/edgexfoundry/edgex-go/commits/c8dc4aaa))
+- **snap:** Exclude redundant eKuiper dependencies ([#4035](https://github.com/edgexfoundry/edgex-go/issues/4035)) ([#a09756d4](https://github.com/edgexfoundry/edgex-go/commits/a09756d4))
+- **snap:** Exclude redundant eKuiper dependencies ([#8ccbfcee](https://github.com/edgexfoundry/edgex-go/commits/8ccbfcee))
+- **snap:** Upgrade kong, redis, consul, vault ([#4210](https://github.com/edgexfoundry/edgex-go/issues/4210)) ([#bec6ac51](https://github.com/edgexfoundry/edgex-go/commits/bec6ac51))
+
+### Other changes
+
+- Update instructions to get latest linter ([#4067](https://github.com/edgexfoundry/edgex-go/issues/4067)) ([#33a3e4f3](https://github.com/edgexfoundry/edgex-go/commits/33a3e4f3))
+
+### Continuous Integration 🔄
+
+- Add blubracket ignore file ([#4167](https://github.com/edgexfoundry/edgex-go/issues/4167)) ([#a8eb28e7](https://github.com/edgexfoundry/edgex-go/commits/a8eb28e7))
+- Add local cache to optimize local docker builds ([#eebbc51e](https://github.com/edgexfoundry/edgex-go/commits/eebbc51e))
+- Update spire Dockerfile's to allow conditional compilation ([#184e7bf7](https://github.com/edgexfoundry/edgex-go/commits/184e7bf7))
+
 ## [v2.2.0] Kamakura - 2022-5-11 (Only compatible with the 2.x release)
 
 ### Features ✨
diff --git a/Makefile b/Makefile
index 7d4d1a1a..c567fb3e 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,6 @@
 # SPDX-License-Identifier: Apache-2.0
 #
 
-
 .PHONY: build clean unittest hadolint lint test docker run
 
 # change the following boolean flag to include or exclude the delayed start libs for builds for most of core services except support services
@@ -13,14 +12,7 @@ INCLUDE_DELAYED_START_BUILD_CORE:="false"
 # change the following boolean flag to include or exclude the delayed start libs for builds for support services exculsively
 INCLUDE_DELAYED_START_BUILD_SUPPORT:="true"
 
-GO=CGO_ENABLED=0 GO111MODULE=on go
-
-# see https://shibumi.dev/posts/hardening-executables
-CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2"
-CGO_CFLAGS="-O2 -pipe -fno-plt"
-CGO_CXXFLAGS="-O2 -pipe -fno-plt"
-CGO_LDFLAGS="-Wl,-O1,–sort-common,–as-needed,-z,relro,-z,now"
-GOCGO=CGO_ENABLED=1 GO111MODULE=on go
+GO=go
 
 DOCKERS= \
 	docker_core_data \
@@ -60,7 +52,6 @@ VERSION=$(shell cat ./VERSION 2>/dev/null || echo 0.0.0)
 DOCKER_TAG=$(VERSION)-dev
 
 GOFLAGS=-ldflags "-X github.com/edgexfoundry/edgex-go.Version=$(VERSION)" -trimpath -mod=readonly
-CGOFLAGS=-ldflags "-linkmode=external -X github.com/edgexfoundry/edgex-go.Version=$(VERSION)" -trimpath -mod=readonly -buildmode=pie
 GOTESTFLAGS?=-race
 
 GIT_SHA=$(shell git rev-parse HEAD)
@@ -80,7 +71,6 @@ ifeq ($(INCLUDE_DELAYED_START_BUILD_SUPPORT),"false")
 endif
 
 NO_MESSAGEBUS_GO_BUILD_TAG:=no_messagebus
-NO_ZMQ_GO_BUILD_TAG:=no_zmq
 
 # Base docker image to speed up local builds
 BASE_DOCKERFILE=https://raw.githubusercontent.com/edgexfoundry/ci-build-images/golang-${GO_VERSION}/Dockerfile
@@ -93,31 +83,31 @@ build-nats:
 	make -e ADD_BUILD_TAGS=include_nats_messaging build
 
 tidy:
-	go mod tidy
+	$(GO) mod tidy
 
 core: metadata data command
 
 metadata: cmd/core-metadata/core-metadata
 cmd/core-metadata/core-metadata:
-	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NO_ZMQ_GO_BUILD_TAG) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/core-metadata
+	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/core-metadata
 
 data: cmd/core-data/core-data
 cmd/core-data/core-data:
-	$(GOCGO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(CGOFLAGS) -o $@ ./cmd/core-data
+	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/core-data
 
 command: cmd/core-command/core-command
 cmd/core-command/core-command:
-	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NO_ZMQ_GO_BUILD_TAG) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/core-command
+	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/core-command
 
 support: notifications scheduler
 
 notifications: cmd/support-notifications/support-notifications
 cmd/support-notifications/support-notifications:
-	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NO_ZMQ_GO_BUILD_TAG) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_SUPPORT)" $(GOFLAGS) -o $@ ./cmd/support-notifications
+	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_SUPPORT)" $(GOFLAGS) -o $@ ./cmd/support-notifications
 
 scheduler: cmd/support-scheduler/support-scheduler
 cmd/support-scheduler/support-scheduler:
-	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NO_ZMQ_GO_BUILD_TAG) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_SUPPORT)" $(GOFLAGS) -o $@ ./cmd/support-scheduler
+	$(GO) build -tags "$(ADD_BUILD_TAGS) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_SUPPORT)" $(GOFLAGS) -o $@ ./cmd/support-scheduler
 
 cmd/sys-mgmt-executor/sys-mgmt-executor:
 	$(GO) build -tags "$(NO_MESSAGEBUS_GO_BUILD_TAG) $(NON_DELAYED_START_GO_BUILD_TAG_FOR_CORE)" $(GOFLAGS) -o $@ ./cmd/sys-mgmt-executor
@@ -153,7 +143,7 @@ clean:
 	rm -f $(MICROSERVICES)
 
 unittest:
-	GO111MODULE=on go test $(GOTESTFLAGS) -coverprofile=coverage.out ./...
+	$(GO) test $(GOTESTFLAGS) -coverprofile=coverage.out ./...
 
 hadolint:
 	if which hadolint > /dev/null ; then hadolint --config .hadolint.yml `find * -type f -name 'Dockerfile*' -print` ; elif test "${ARCH}" = "x86_64" && which docker > /dev/null ; then docker run --rm -v `pwd`:/host:ro,z --entrypoint /bin/hadolint hadolint/hadolint:latest --config /host/.hadolint.yml `find * -type f -name 'Dockerfile*' | xargs -i echo '/host/{}'` ; fi
@@ -164,7 +154,7 @@ lint:
 
 
 test: unittest hadolint lint
-	GO111MODULE=on go vet ./...
+	$(GO) vet ./...
 	gofmt -l $$(find . -type f -name '*.go'| grep -v "/vendor/")
 	[ "`gofmt -l $$(find . -type f -name '*.go'| grep -v "/vendor/")`" = "" ]
 	./bin/test-attribution-txt.sh
diff --git a/README.md b/README.md
index e41cd0a9..b871bc44 100644
--- a/README.md
+++ b/README.md
@@ -67,20 +67,6 @@ For more details on the snap, including how to build and install it, please refe
 - The current targeted version of the Go language runtime for release artifacts is v1.18.x
 - The minimum supported version of the Go language runtime is v1.18.x
 
-##### ZeroMQ
-
-Several EdgeX Foundry services depend on ZeroMQ for communications by default.
-
-The easiest way to get and install ZeroMQ on Linux is to use this [setup script](https://gist.github.com/katopz/8b766a5cb0ca96c816658e9407e83d00).
-
-For macOS, use brew:
-
-```sh
-brew install zeromq
-```
-
-For directions installing ZeroMQ on Windows, please see [the Windows documentation.](ZMQWindows.md)
-
 #### Installation and Execution
 
 EdgeX is organized as Go Modules; there is no requirement to set the GOPATH or
diff --git a/ZMQWindows.md b/ZMQWindows.md
deleted file mode 100644
index 18febca2..00000000
--- a/ZMQWindows.md
+++ /dev/null
@@ -1,43 +0,0 @@
-## Setting up ZMQ to build on Windows
-
-> Last updated Nov 2019 to be reworked for module directory structure.
-
-0. Ensure that you've followed the steps leading up to this on the [README.md](README.md), this includes any dependenices. Clone this repository into the `%GOPATH%\src\github.com\edgexfoundry\` directory, using `git clone https://github.com/edgexfoundry/edgex-go.git %GOPATH%\src\github.com\edgexfoundry\edgex-go`.
-
-1. Download & install the TDM-GCC from this URL: http://tdm-gcc.tdragon.net/download
-
-2. Run `go get -v -x github.com/pebbe/zmq4`, **expect it to fail** due to a missing `zmq.h` file. This will create the directory structure needed in order to accomplish the steps below. This step can be skipped, but if skipped the directories in the following steps will have to be manually created.
-
-3. Download the release version of ZMQ from AppVeyor builds from zmq: https://ci.appveyor.com/project/zeromq/libzmq. Verify it is a successful build and ensure  the platform architecture and VERSION is correct for your system.  Ensure the commit that is built matches the version you clone from source in step 3. Example: `Environment: platform=x64, configuration=Release, WITH_LIBSODIUM=ON, ENABLE_CURVE=ON, NO_PR=TRUE`. You can download the zip from the artifacts tab.
-
-    3.a. Extract the contents of the downloaded zip file anywhere you prefer.
-
-    3.b. Copy the `libsodium.dll` and `libzmq-v120-mt-4_x_x.dll` files from step 3 into `%GOPATH%\pkg\mod\github.com\pebbe\zmq4@v1.0.0\lib`; create the lib directory as needed. Rename `libzmq-v120-mt-4_x_x.dll` to `libzmq.dll`, so that gcc can link and find `-lzmq`. If this is not done, errors like this may occur: `C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe:cannot find -lzmq`
-
-> Note: As of Nov 2019, ZMQ 4.3.3 does not work and results in an error: https://github.com/pebbe/zmq4/issues/152/. 4.3.2 is recommended and tested on Win 10:
-https://ci.appveyor.com/project/zeromq/libzmq/builds/25882500/job/s2yhbnjrdouq5qnm/artifacts
-and
-https://github.com/zeromq/libzmq/tree/a84ffa12b2eb3569ced199660bac5ad128bff1f0. 
-
-4. In any directory you prefer, clone the source of ZMQ `git clone https://github.com/zeromq/libzmq.git` and ensure it matches the version/commit you downloaded from AppVeyor (i.e `git reset --hard a84ffa12`).
-
-5. Copy over the `include` directory from the source downloaded in step 3 to  `%GOPATH%\pkg\mod\github.com\pebbe\zmq4@v1.0.0\`.
-
-6. Set the following environment variables (run this in PowerShell):
-
-```
-$Env:CGO_CFLAGS="-I$Env:GOPATH\pkg\mod\github.com\pebbe\zmq4@v1.0.0\include"
-$Env:CGO_LDFLAGS="-L$Env:GOPATH\pkg\mod\github.com\pebbe\zmq4@v1.0.0\lib"
-```
-
-After setting those, running `go get -v -x github.com/pebbe/zmq4` should succeed. If it fails, it most likely due to the `.h` files or `dll`s existing in a directory that doesnt match your `CGO_` environment variables. It may also fail due to the same error as before (see step 3.b) - try downloading the artifact from a different build on the [AppVeyor builds site](https://ci.appveyor.com/project/zeromq/libzmq).
-
-> It is recommended to set these environment variables in your System or IDE so that you do not need to set them in every terminal session. This especially required if you wish to debug services that depend on ZMQ. 
-
-7. Next, navigate to `$Env:GOPATH\src\github.com\edgexfoundry\edgex-go\cmd\core-data`. *If you didn't acquire dependencies previously, run `go get -v` to acquire all dependencies*. Run `go build -v`. If it complains about not finding zmq.h from auth.go, double check the CGO_ environment variables by running `go env`.
-
-8. There should now be a `core-data.exe` file in your directory. The last step is to ensure that a copy of the DLL's `libsodium.dll` and `libzmq-v120-mt-4_x_x.dll` (yes, this one, not with the rename we did earlier) is in the same directory as your `.exe`. You will need to copy these .dlls in manually. 
-
-9. Run `.\core-data.exe`.
-
-> If you get a segfault, try setting `$Env:GOCACHE="off"` and rerun the build command from step 5
\ No newline at end of file
diff --git a/cmd/core-command/Dockerfile b/cmd/core-command/Dockerfile
index 996787a5..eeb95a67 100644
--- a/cmd/core-command/Dockerfile
+++ b/cmd/core-command/Dockerfile
@@ -23,11 +23,6 @@ ARG ADD_BUILD_TAGS=""
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/core-command/res/configuration.toml b/cmd/core-command/res/configuration.toml
index 061d6ee0..6281c040 100644
--- a/cmd/core-command/res/configuration.toml
+++ b/cmd/core-command/res/configuration.toml
@@ -23,6 +23,7 @@ LogLevel = "INFO"
   Interval = "30s"
   PublishTopicPrefix  = "edgex/telemetry" # /<service-name>/<metric-name> will be added to this Publish Topic prefix
     [Writable.Telemetry.Metrics] # All service's metric names must be present in this list.
+    # Common Security Service Metrics
     SecuritySecretsRequested = false
     SecuritySecretsStored = false
     SecurityConsulTokensRequested = false
diff --git a/cmd/core-data/Dockerfile b/cmd/core-data/Dockerfile
index 64764db3..b8a5d3f0 100644
--- a/cmd/core-data/Dockerfile
+++ b/cmd/core-data/Dockerfile
@@ -24,12 +24,7 @@ ARG ADD_BUILD_TAGS=""
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
-RUN apk add --update --no-cache zeromq-dev libsodium-dev pkgconfig build-base git
+RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
 RUN [ ! -d "vendor" ] && go mod download all || echo "skipping..."
@@ -47,11 +42,7 @@ ENV APP_PORT=59880
 #expose core data port
 EXPOSE $APP_PORT
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
-RUN apk add --update --no-cache zeromq dumb-init
+RUN apk add --update --no-cache dumb-init
 COPY --from=builder /edgex-go/Attribution.txt /
 COPY --from=builder /edgex-go/cmd/core-data/core-data /
 COPY --from=builder /edgex-go/cmd/core-data/res/configuration.toml /res/configuration.toml
diff --git a/cmd/core-data/res/configuration.toml b/cmd/core-data/res/configuration.toml
index f75561f0..cc786ace 100644
--- a/cmd/core-data/res/configuration.toml
+++ b/cmd/core-data/res/configuration.toml
@@ -13,8 +13,10 @@ LogLevel = "INFO"
   Interval = "30s"
   PublishTopicPrefix  = "edgex/telemetry" # /<service-name>/<metric-name> will be added to this Publish Topic prefix
     [Writable.Telemetry.Metrics] # All service's metric names must be present in this list.
+    # Core Data Service Metrics
     EventsPersisted = false
     ReadingsPersisted = false
+    # Common Security Service Metrics
     SecuritySecretsRequested = false
     SecuritySecretsStored = false
     SecurityConsulTokensRequested = false
diff --git a/cmd/core-metadata/Dockerfile b/cmd/core-metadata/Dockerfile
index 06d23ca2..9cdb71e6 100644
--- a/cmd/core-metadata/Dockerfile
+++ b/cmd/core-metadata/Dockerfile
@@ -23,11 +23,6 @@ ARG ADD_BUILD_TAGS=""
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/core-metadata/res/configuration.toml b/cmd/core-metadata/res/configuration.toml
index 2fca8e1f..08817b6d 100644
--- a/cmd/core-metadata/res/configuration.toml
+++ b/cmd/core-metadata/res/configuration.toml
@@ -20,6 +20,7 @@ LogLevel = "INFO"
   Interval = "30s"
   PublishTopicPrefix  = "edgex/telemetry" # /<service-name>/<metric-name> will be added to this Publish Topic prefix
     [Writable.Telemetry.Metrics] # All service's metric names must be present in this list.
+    # Common Security Service Metrics
     SecuritySecretsRequested = false
     SecuritySecretsStored = false
     SecurityConsulTokensRequested = false
diff --git a/cmd/security-bootstrapper/Dockerfile b/cmd/security-bootstrapper/Dockerfile
index d3fbe0c3..9087b01c 100644
--- a/cmd/security-bootstrapper/Dockerfile
+++ b/cmd/security-bootstrapper/Dockerfile
@@ -22,8 +22,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh b/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh
index c05107cb..719e568c 100755
--- a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh
+++ b/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh
@@ -37,17 +37,6 @@ vault_ready()
 
 # env settings are populated from env files of docker-compose
 
-echo "Script for waiting security bootstrapping on Consul"
-
-echo "$(date) Consul waits on Vault to be initialized"
-# check the http status code from Vault using SECRETSTORE_HOST and SECRETSTORE_PORT as input to the function call
-vault_inited=$(vault_ready "${SECRETSTORE_HOST}" "${SECRETSTORE_PORT}")
-until [ "$vault_inited" -eq 1 ]; do
-    echo "$(date) waiting for Vault ${SECRETSTORE_HOST}:${SECRETSTORE_PORT} to be initialized";
-    sleep 1;
-    vault_inited=$(vault_ready "${SECRETSTORE_HOST}" "${SECRETSTORE_PORT}")
-done
-
 # only in json format according to Consul's documentation
 DEFAULT_CONSUL_LOCAL_CONFIG='
 {
diff --git a/cmd/security-proxy-setup/Dockerfile b/cmd/security-proxy-setup/Dockerfile
index 2bafb3be..ca838f2f 100644
--- a/cmd/security-proxy-setup/Dockerfile
+++ b/cmd/security-proxy-setup/Dockerfile
@@ -21,8 +21,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/security-secretstore-setup/Dockerfile b/cmd/security-secretstore-setup/Dockerfile
index 24c8e803..bb95b33b 100644
--- a/cmd/security-secretstore-setup/Dockerfile
+++ b/cmd/security-secretstore-setup/Dockerfile
@@ -21,8 +21,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/security-spiffe-token-provider/Dockerfile b/cmd/security-spiffe-token-provider/Dockerfile
index c5e38f13..8f7d764b 100644
--- a/cmd/security-spiffe-token-provider/Dockerfile
+++ b/cmd/security-spiffe-token-provider/Dockerfile
@@ -35,7 +35,6 @@ FROM alpine:3.15
 LABEL license='SPDX-License-Identifier: Apache-2.0' \
       copyright='Copyright (c) 2022 Intel Corporation'
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
 RUN apk update && apk --no-cache --update add dumb-init curl gcompat
 
 COPY --from=builder /edgex-go/Attribution.txt /
diff --git a/cmd/security-spire-agent/Dockerfile b/cmd/security-spire-agent/Dockerfile
index f0cbc072..f7439bb2 100644
--- a/cmd/security-spire-agent/Dockerfile
+++ b/cmd/security-spire-agent/Dockerfile
@@ -21,8 +21,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git build-base curl
 
 COPY go.mod vendor* ./
@@ -51,7 +49,6 @@ FROM alpine:3.15
 LABEL license='SPDX-License-Identifier: Apache-2.0' \
       copyright='Copyright (c) 2022 Intel Corporation'
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
 RUN apk update && apk --no-cache --update add dumb-init openssl gcompat
 
 COPY --from=builder /usr/local/bin/spire-agent /usr/local/bin
diff --git a/cmd/security-spire-config/Dockerfile b/cmd/security-spire-config/Dockerfile
index d1284cf4..e220e879 100644
--- a/cmd/security-spire-config/Dockerfile
+++ b/cmd/security-spire-config/Dockerfile
@@ -21,8 +21,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git build-base curl
 
 COPY go.mod vendor* ./
@@ -51,7 +49,6 @@ FROM alpine:3.15
 LABEL license='SPDX-License-Identifier: Apache-2.0' \
       copyright='Copyright (c) 2022 Intel Corporation'
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
 RUN apk update && apk --no-cache --update add dumb-init gcompat
 
 COPY --from=builder /usr/local/bin/spire-server /usr/local/bin
diff --git a/cmd/security-spire-server/Dockerfile b/cmd/security-spire-server/Dockerfile
index 13f1931a..b0a737a3 100644
--- a/cmd/security-spire-server/Dockerfile
+++ b/cmd/security-spire-server/Dockerfile
@@ -21,8 +21,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git build-base curl
 
 COPY go.mod vendor* ./
@@ -51,7 +49,6 @@ FROM alpine:3.15
 LABEL license='SPDX-License-Identifier: Apache-2.0' \
       copyright='Copyright (c) 2022 Intel Corporation'
 
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
 RUN apk update && apk --no-cache --update add dumb-init openssl gcompat
 
 COPY --from=builder /usr/local/bin/spire-server /usr/local/bin
diff --git a/cmd/support-notifications/Dockerfile b/cmd/support-notifications/Dockerfile
index bac004ac..2d83c163 100644
--- a/cmd/support-notifications/Dockerfile
+++ b/cmd/support-notifications/Dockerfile
@@ -22,11 +22,6 @@ ARG ADD_BUILD_TAGS=""
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make bash git ca-certificates
 
 COPY go.mod vendor* ./
diff --git a/cmd/support-notifications/res/configuration.toml b/cmd/support-notifications/res/configuration.toml
index 785bcd97..6beedc60 100644
--- a/cmd/support-notifications/res/configuration.toml
+++ b/cmd/support-notifications/res/configuration.toml
@@ -22,6 +22,7 @@ ResendInterval = "5s"
   Interval = "30s"
   PublishTopicPrefix  = "edgex/telemetry" # /<service-name>/<metric-name> will be added to this Publish Topic prefix
     [Writable.Telemetry.Metrics] # All service's metric names must be present in this list.
+    # Common Security Service Metrics
     SecuritySecretsRequested = false
     SecuritySecretsStored = false
     SecurityConsulTokensRequested = false
diff --git a/cmd/support-scheduler/Dockerfile b/cmd/support-scheduler/Dockerfile
index 75971312..c59dfabd 100644
--- a/cmd/support-scheduler/Dockerfile
+++ b/cmd/support-scheduler/Dockerfile
@@ -23,11 +23,6 @@ ARG ADD_BUILD_TAGS=""
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make git
 
 COPY go.mod vendor* ./
diff --git a/cmd/support-scheduler/res/configuration.toml b/cmd/support-scheduler/res/configuration.toml
index dc0c05f8..ab07969c 100644
--- a/cmd/support-scheduler/res/configuration.toml
+++ b/cmd/support-scheduler/res/configuration.toml
@@ -17,6 +17,7 @@ LogLevel = "INFO"
   Interval = "30s"
   PublishTopicPrefix  = "edgex/telemetry" # /<service-name>/<metric-name> will be added to this Publish Topic prefix
     [Writable.Telemetry.Metrics] # All service's metric names must be present in this list.
+    # Common Security Service Metrics
     SecuritySecretsRequested = false
     SecuritySecretsStored = false
     SecurityConsulTokensRequested = false
diff --git a/cmd/sys-mgmt-agent/Dockerfile b/cmd/sys-mgmt-agent/Dockerfile
index c0ee64a1..37ad0e77 100644
--- a/cmd/sys-mgmt-agent/Dockerfile
+++ b/cmd/sys-mgmt-agent/Dockerfile
@@ -10,10 +10,6 @@ FROM ${BUILDER_BASE} AS builder
 
 WORKDIR /edgex-go
 
-# The main mirrors are giving us timeout issues on builds periodically.
-# So we can try these.
-RUN sed -e 's/dl-cdn[.]alpinelinux.org/dl-4.alpinelinux.org/g' -i~ /etc/apk/repositories
-
 RUN apk add --update --no-cache make bash git
 
 COPY go.mod vendor* ./
diff --git a/go.mod b/go.mod
index 3cb71b23..a9fcb77e 100644
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,13 @@ module github.com/edgexfoundry/edgex-go
 require (
 	bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690
 	github.com/eclipse/paho.mqtt.golang v1.4.1
-	github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0-dev.23
-	github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0-dev.18
-	github.com/edgexfoundry/go-mod-messaging/v2 v2.3.0-dev.24
-	github.com/edgexfoundry/go-mod-registry/v2 v2.3.0-dev.10
-	github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0-dev.9
+	github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0
+	github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0
+	github.com/edgexfoundry/go-mod-messaging/v2 v2.3.1-dev.1
+	github.com/edgexfoundry/go-mod-registry/v2 v2.3.0
+	github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0
 	github.com/fxamacker/cbor/v2 v2.4.0
-	github.com/golang-jwt/jwt/v4 v4.4.2
+	github.com/golang-jwt/jwt/v4 v4.4.3
 	github.com/gomodule/redigo v1.8.9
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/mux v1.8.0
@@ -17,7 +17,7 @@ require (
 	github.com/pelletier/go-toml v1.9.5
 	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
 	github.com/spiffe/go-spiffe/v2 v2.1.1
-	github.com/stretchr/testify v1.8.0
+	github.com/stretchr/testify v1.8.1
 	golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2
 	gopkg.in/eapache/queue.v1 v1.1.0
 	gopkg.in/yaml.v3 v3.0.1
@@ -28,7 +28,7 @@ require (
 	github.com/armon/go-metrics v0.3.10 // indirect
 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0-dev.14 // indirect
+	github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0 // indirect
 	github.com/fatih/color v1.9.0 // indirect
 	github.com/go-kit/log v0.2.1 // indirect
 	github.com/go-logfmt/logfmt v0.5.1 // indirect
@@ -38,7 +38,7 @@ require (
 	github.com/go-redis/redis/v7 v7.3.0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
-	github.com/hashicorp/consul/api v1.15.2 // indirect
+	github.com/hashicorp/consul/api v1.15.3 // indirect
 	github.com/hashicorp/errwrap v1.0.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
 	github.com/hashicorp/go-hclog v0.14.1 // indirect
@@ -58,9 +58,8 @@ require (
 	github.com/nats-io/nats.go v1.18.0 // indirect
 	github.com/nats-io/nkeys v0.3.0 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
-	github.com/pebbe/zmq4 v1.2.7 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/stretchr/objx v0.4.0 // indirect
+	github.com/stretchr/objx v0.5.0 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/zeebo/errs v1.2.2 // indirect
 	golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
diff --git a/go.sum b/go.sum
index b56274f9..7ba09c2e 100644
--- a/go.sum
+++ b/go.sum
@@ -43,18 +43,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
 github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
-github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0-dev.23 h1:Yc3veKQ1Duk0MlqGPmVQXiKfKvbjknOPQjckHn6MeyY=
-github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0-dev.23/go.mod h1:D27mjjRoYzpSGpR+SploF5wauAR69knnzGo2A+Za/+g=
-github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0-dev.14 h1:hjAFgpx/e0iLjESYmKQ3oc4hALJ2BD6qpd9Qk8SIV1U=
-github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0-dev.14/go.mod h1:4do/6nXmtMcWoMu4eqKjlr3Ot+l0rF68qOJpZwnN9R8=
-github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0-dev.18 h1:Smkhoqq9+XsMcs0B3JokAmIT7hXJy9eQWk6SYk9z4yE=
-github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0-dev.18/go.mod h1:4/e61acxVkhQWCTjQ4XcHVJDnrMDloFsZZB1B6STCRw=
-github.com/edgexfoundry/go-mod-messaging/v2 v2.3.0-dev.24 h1:h2hsipXIC72xySkgS/uwq3HOyFQ3iiJCRgXGodeXTUU=
-github.com/edgexfoundry/go-mod-messaging/v2 v2.3.0-dev.24/go.mod h1:S78Q/vqwRiu11oJFqB3NoyV1kQ7pGfuzVb41FDWjNsA=
-github.com/edgexfoundry/go-mod-registry/v2 v2.3.0-dev.10 h1:qKwzfX2Eb2spjzc35omFl+Bx+KIwu4KNFq5D4c2V/iU=
-github.com/edgexfoundry/go-mod-registry/v2 v2.3.0-dev.10/go.mod h1:bpDKvtS7gpvqK2v5D1CKxaolZHFQi4mCXscsPLXdKgo=
-github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0-dev.9 h1:K6wGLHXASBcCEJrIec4vvTNkuooduOS+9TtjhrBm3Jc=
-github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0-dev.9/go.mod h1:h/FohFNY8xHalioLg1bhjAuEj0z+danSDtixirvaXmQ=
+github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0 h1:NCOc5bOz6oX+KuOcv0Rt6BTSDShbg4VmCapXO19IoCM=
+github.com/edgexfoundry/go-mod-bootstrap/v2 v2.3.0/go.mod h1:jWZjsy0BaO6+S+Tq111mcrkGKpg6bhTyqngyYcl+70E=
+github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0 h1:VeK7VBiNc/RIR7HXC0ya3fWCmcFQzrSLITPYn87cQsA=
+github.com/edgexfoundry/go-mod-configuration/v2 v2.3.0/go.mod h1:1tKJhcPEWftFy+I4n7+sNIBOo7H5ys/QaPvyXl0tMtc=
+github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0 h1:8Svk1HTehXEgwxgyA4muVhSkP3D9n1q+oSHI3B1Ac90=
+github.com/edgexfoundry/go-mod-core-contracts/v2 v2.3.0/go.mod h1:4/e61acxVkhQWCTjQ4XcHVJDnrMDloFsZZB1B6STCRw=
+github.com/edgexfoundry/go-mod-messaging/v2 v2.3.1-dev.1 h1:SXMpiOnXGkP/FxxCkFWYXz3GhphDpoEGXSfzvtifn18=
+github.com/edgexfoundry/go-mod-messaging/v2 v2.3.1-dev.1/go.mod h1:nDjncg1n9kGivIsSr32/vCQh4fqGxn5BF7GUG2tuuwo=
+github.com/edgexfoundry/go-mod-registry/v2 v2.3.0 h1:QEZvYSDkQKAo6WVFrjBkQjjfpbn045Lsv4gNdgATgeM=
+github.com/edgexfoundry/go-mod-registry/v2 v2.3.0/go.mod h1:Gyx8a+7jfzy53ljq9kgiz553xhgYYKNNWhnaTn76i+g=
+github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0 h1:MRehbe0ZdIP2jx3Nv18LktENlWdXSmw0E6x6VKvFOfo=
+github.com/edgexfoundry/go-mod-secrets/v2 v2.3.0/go.mod h1:y9l/5p0EEA2IBf2ctvJ0PtjTN/XPab5BWnfIi3Sy6C4=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -89,8 +89,8 @@ github.com/go-redis/redis/v7 v7.3.0 h1:3oHqd0W7f/VLKBxeYTEpqdMUsmMectngjM9OtoRoI
 github.com/go-redis/redis/v7 v7.3.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
-github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
+github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -131,8 +131,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
 github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hashicorp/consul/api v1.15.2 h1:3Q/pDqvJ7udgt/60QOOW/p/PeKioQN+ncYzzCdN2av0=
-github.com/hashicorp/consul/api v1.15.2/go.mod h1:v6nvB10borjOuIwNRZYPZiHKrTM/AyrGtd0WVVodKM8=
+github.com/hashicorp/consul/api v1.15.3 h1:WYONYL2rxTXtlekAqblR2SCdJsizMDIj/uXb5wNy9zU=
+github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY=
 github.com/hashicorp/consul/sdk v0.11.0 h1:HRzj8YSCln2yGgCumN5CL8lYlD3gBurnervJRJAZyC4=
 github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw=
 github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -248,8 +248,6 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pebbe/zmq4 v1.2.7 h1:6EaX83hdFSRUEhgzSW1E/SPoTS3JeYZgYkBvwdcrA9A=
-github.com/pebbe/zmq4 v1.2.7/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48=
 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -291,8 +289,9 @@ github.com/spiffe/go-spiffe/v2 v2.1.1 h1:RT9kM8MZLZIsPTH+HKQEP5yaAk3yd/VBzlINaRj
 github.com/spiffe/go-spiffe/v2 v2.1.1/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -300,8 +299,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
 github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
diff --git a/internal/core/command/controller/messaging/external.go b/internal/core/command/controller/messaging/external.go
index 34133e25..7509d640 100644
--- a/internal/core/command/controller/messaging/external.go
+++ b/internal/core/command/controller/messaging/external.go
@@ -128,7 +128,13 @@ func commandRequestHandler(router MessagingRouter, dic *di.Container) mqtt.Messa
 
 		deviceRequestTopic, err := validateRequestTopic(messageBusInfo.Internal.Topics[DeviceRequestTopicPrefix], deviceName, commandName, method, dic)
 		if err != nil {
-			lc.Errorf("invalid request topic: %s", err.Error())
+			responseEnvelope := types.NewMessageEnvelopeWithError(requestEnvelope.RequestID, err.Error())
+			publishMessage(client, externalResponseTopic, qos, retain, responseEnvelope, lc)
+			return
+		}
+
+		err = validateGetCommandQueryParameters(requestEnvelope.QueryParams)
+		if err != nil {
 			responseEnvelope := types.NewMessageEnvelopeWithError(requestEnvelope.RequestID, err.Error())
 			publishMessage(client, externalResponseTopic, qos, retain, responseEnvelope, lc)
 			return
diff --git a/internal/core/command/controller/messaging/internal.go b/internal/core/command/controller/messaging/internal.go
index 178fd621..32524395 100644
--- a/internal/core/command/controller/messaging/internal.go
+++ b/internal/core/command/controller/messaging/internal.go
@@ -145,6 +145,18 @@ func SubscribeCommandRequests(ctx context.Context, router MessagingRouter, dic *
 					continue
 				}
 
+				err = validateGetCommandQueryParameters(requestEnvelope.QueryParams)
+				if err != nil {
+					lc.Errorf(err.Error())
+					responseEnvelope := types.NewMessageEnvelopeWithError(requestEnvelope.RequestID, err.Error())
+					err = messageBus.Publish(responseEnvelope, internalResponseTopic)
+					if err != nil {
+						lc.Errorf("Could not publish to topic '%s': %s", internalResponseTopic, err.Error())
+					}
+
+					continue
+				}
+
 				// expected internal command request topic scheme: #/<device-service>/<device>/<command-name>/<method>
 				err = messageBus.Publish(requestEnvelope, deviceRequestTopic)
 				if err != nil {
diff --git a/internal/core/command/controller/messaging/utils.go b/internal/core/command/controller/messaging/utils.go
index 3841305f..c35e2c50 100644
--- a/internal/core/command/controller/messaging/utils.go
+++ b/internal/core/command/controller/messaging/utils.go
@@ -51,6 +51,22 @@ func validateRequestTopic(prefix string, deviceName string, commandName string,
 
 }
 
+// validateGetCommandQueryParameters validates the value is valid for device service's reserved query parameters
+func validateGetCommandQueryParameters(queryParams map[string]string) error {
+	if dsReturnEvent, ok := queryParams[common.ReturnEvent]; ok {
+		if dsReturnEvent != common.ValueYes && dsReturnEvent != common.ValueNo {
+			return fmt.Errorf("invalid query parameter, %s has to be '%s' or '%s'", common.ReturnEvent, common.ValueYes, common.ValueNo)
+		}
+	}
+	if dsPushEvent, ok := queryParams[common.PushEvent]; ok {
+		if dsPushEvent != common.ValueYes && dsPushEvent != common.ValueNo {
+			return fmt.Errorf("invalid query parameter, %s has to be '%s' or '%s'", common.PushEvent, common.ValueYes, common.ValueNo)
+		}
+	}
+
+	return nil
+}
+
 // getCommandQueryResponseEnvelope returns the MessageEnvelope containing the DeviceCoreCommand payload bytes
 func getCommandQueryResponseEnvelope(requestEnvelope types.MessageEnvelope, deviceName string, dic *di.Container) (types.MessageEnvelope, error) {
 	var commandsResponse any
diff --git a/internal/core/data/mocks/container.go b/internal/core/data/mocks/container.go
index 690cda1e..9172ffd1 100644
--- a/internal/core/data/mocks/container.go
+++ b/internal/core/data/mocks/container.go
@@ -8,9 +8,8 @@ package mocks
 import (
 	"github.com/edgexfoundry/edgex-go/internal/core/data/config"
 	dataContainer "github.com/edgexfoundry/edgex-go/internal/core/data/container"
-
-	"github.com/edgexfoundry/go-mod-messaging/v2/messaging"
-	msgTypes "github.com/edgexfoundry/go-mod-messaging/v2/pkg/types"
+	"github.com/edgexfoundry/go-mod-messaging/v2/messaging/mocks"
+	"github.com/stretchr/testify/mock"
 
 	"github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container"
 	bootstrapConfig "github.com/edgexfoundry/go-mod-bootstrap/v2/config"
@@ -20,14 +19,8 @@ import (
 
 // NewMockDIC function returns a mock bootstrap di Container
 func NewMockDIC() *di.Container {
-	msgClient, _ := messaging.NewMessageClient(msgTypes.MessageBusConfig{
-		PublishHost: msgTypes.HostInfo{
-			Host:     "*",
-			Protocol: "tcp",
-			Port:     5563,
-		},
-		Type: "zero",
-	})
+	msgClient := &mocks.MessageClient{}
+	msgClient.On("Publish", mock.Anything, mock.Anything).Return(nil)
 
 	return di.NewContainer(di.ServiceConstructorMap{
 		dataContainer.ConfigurationName: func(get di.Get) interface{} {
diff --git a/openapi/v2/core-command.yaml b/openapi/v2/core-command.yaml
index 0ff4deeb..2d2de526 100644
--- a/openapi/v2/core-command.yaml
+++ b/openapi/v2/core-command.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - Core Command API
   description: This is the definition of the API for the Core Command service in the EdgeX Foundry IOT microservice platform. Core Command is responsible for storing command definitions and also for executing those commands as reads and writes against target devices.
-  version: 2.3.0
+  version: 2.4.0
   
 servers:
   - url: http://localhost:59882/api/v2
@@ -903,7 +903,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "2.0.0-dev.13"
+                version: 2.4.0
         '500':
           description: "Interval Server Error"
           headers:
diff --git a/openapi/v2/core-data.yaml b/openapi/v2/core-data.yaml
index b0cd49bb..eb21f03b 100644
--- a/openapi/v2/core-data.yaml
+++ b/openapi/v2/core-data.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - Core Data API
   description: This is the definition of the API for the Core Data service in the EdgeX Foundry IOT microservice platform. Core Data is responsible for storing event and reading data ingested from edge devices in the environment.
-  version: 2.3.0
+  version: 2.4.0
   
 servers:
   - url: http://localhost:59880/api/v2
@@ -1981,7 +1981,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "master"                
+                version: 2.4.0
         '500':
           description: "Interval Server Error"
           headers:
diff --git a/openapi/v2/core-metadata.yaml b/openapi/v2/core-metadata.yaml
index 5fe7053d..26c1677d 100644
--- a/openapi/v2/core-metadata.yaml
+++ b/openapi/v2/core-metadata.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - Core Metadata API
   description: "This is the definition of the API for the Core Metadata service in the EdgeX Foundry IOT microservice platform. Core Metadata is responsible for all information related to provisioned devices and their associated services."
-  version: 2.3.0
+  version: 2.4.0
 servers:
   - url: 'http://localhost:59881/api/v2'
     description: URL for local development and testing
@@ -4018,7 +4018,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "2.0.0-dev.13"
+                version: 2.4.0
         '500':
           description: "Internal Server Error"
           headers:
diff --git a/openapi/v2/support-notifications.yaml b/openapi/v2/support-notifications.yaml
index e8b31a47..f647627f 100644
--- a/openapi/v2/support-notifications.yaml
+++ b/openapi/v2/support-notifications.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - Support Notifications API
   description: This is the definition of the API for the Support Notifications service in the EdgeX Foundry IOT microservice platform. Support Notifications provides functionality for sending notifications via email/REST from the EdgeX Foundry platform.
-  version: 2.3.0
+  version: 2.4.0
 
 servers:
   - url: http://localhost:59860/api/v2
@@ -2403,7 +2403,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "2.0.0-dev.13"
+                version: 2.4.0
         '500':
           description: "Interval Server Error"
           headers:
diff --git a/openapi/v2/support-scheduler.yaml b/openapi/v2/support-scheduler.yaml
index 47e8e9dd..c896f36f 100644
--- a/openapi/v2/support-scheduler.yaml
+++ b/openapi/v2/support-scheduler.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - Support Scheduler API
   description: This is the definition of the API for the Support Scheduler service in the EdgeX Foundry IOT microservice platform. Support Scheduler provides functionality for scheduling different actions in the EdgeX Foundry platform.
-  version: 2.3.0
+  version: 2.4.0
   
 servers:
   - url: http://localhost:59861/api/v2
@@ -1053,7 +1053,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "2.0.0-dev.13"
+                version: 2.4.0
         '500':
           description: "Interval Server Error"
           headers:
diff --git a/openapi/v2/system-agent.yaml b/openapi/v2/system-agent.yaml
index f1289392..4f0c957b 100644
--- a/openapi/v2/system-agent.yaml
+++ b/openapi/v2/system-agent.yaml
@@ -2,7 +2,7 @@ openapi: 3.0.0
 info:
   title: Edgex Foundry - System Management Agent API
   description: "This is the definition of the API for the System Management Agent service in the EdgeX Foundry IOT microservice platform. System Management Agent is responsible for management of EdgeX microservices and supported infrastructure."
-  version: 2.3.0
+  version: 2.4.0
 
 servers:
   - url: "http://localhost:58890/api/v2"
@@ -521,7 +521,7 @@ paths:
                 $ref: '#/components/schemas/VersionResponse'
               example:
                 apiVersion: "v2"
-                version: "2.0.0-dev.1"
+                version: 2.4.0
         '500':
           description: "Interval Server Error"
           headers:
diff --git a/snap/local/helper-go/configure.go b/snap/local/helper-go/configure.go
index b626391c..1f8b102d 100644
--- a/snap/local/helper-go/configure.go
+++ b/snap/local/helper-go/configure.go
@@ -25,81 +25,66 @@ import (
 	"path/filepath"
 	"strings"
 
-	hooks "github.com/canonical/edgex-snap-hooks/v2"
+	"github.com/canonical/edgex-snap-hooks/v2/env"
 	"github.com/canonical/edgex-snap-hooks/v2/log"
 	"github.com/canonical/edgex-snap-hooks/v2/snapctl"
 )
 
-const ( // iota is reset to 0
-	kuiperService = iota
-	secProxyService
-	secStoreService
-	otherService
-)
-
 const (
 	ON    = "on"
 	OFF   = "off"
 	UNSET = ""
 )
 
-// getKuiperServices returns the list of services used for
-// EdgeX rules-engine processing.
-func getKuiperServices() []string {
-	return []string{hooks.ServiceAppCfg, hooks.ServiceKuiper}
-}
-
-// getProxyServices returns the list of services which implement
-// the API Gateway. Note this list *excludes* Consul and the
-// Secret Store services.
-func getProxyServices() []string {
-	return []string{"postgres", "kong-daemon", "security-proxy-setup"}
-}
-
-// getSecretStoreServices returns the list of services which implement
-// the Secret Store and related dependencies (i.e. the services that
-// secure redis and consul which are tightly bound to the secret store
-// being enabled).
-func getSecretStoreServices() []string {
-	return []string{"security-secretstore-setup", "vault",
-		"security-consul-bootstrapper", "security-bootstrapper-redis"}
-}
-
-// getEdgeXRefServices returns the list of EdgeX reference services in the snap
-// (excludes all non-EdgeX runtime dependencies, and security-*-setup jobs).
-func getEdgeXRefServices() []string {
-	return []string{"core-data", "core-metadata", "core-command",
-		"support-notifications",
-		"support-scheduler", "sys-mgmt-agent"}
-}
-
-// getRequiredServices returns the minimum list of required
-// snap services for a working EdgeX instance.
-func getRequiredServices() []string {
-	return []string{"consul", "redis", "core-metadata"}
-}
-
-// getCoreDefaultServices returns the list of core services
-// that are started by default (in addition to the required
-// services)
-func getCoreDefaultServices() []string {
-	return []string{"core-command", "core-data"}
-}
+var (
+	rulesEngineServices = []string{
+		appServiceConfigurable,
+		eKuiper,
+	}
+	proxyServices = []string{
+		kong,
+		postgres,
+		securityProxySetup,
+	}
+	secretStoreServices = []string{
+		vault,
+		securitySecretStoreSetup,
+		securityBootstrapperConsul,
+		securityBootstrapperRedis,
+	}
+	referenceServices = []string{
+		coreData,
+		coreMetadata,
+		coreCommand,
+		supportNotifications,
+		supportScheduler,
+		systemManagementAgent,
+	}
+	requiredServices = []string{
+		consul,
+		redis,
+		coreMetadata,
+	}
+	coreDefaultServices = []string{
+		coreCommand,
+		coreData,
+	}
+	optionalServices = []string{
+		supportNotifications,
+		supportScheduler,
+		eKuiper,
+		appServiceConfigurable,
+		systemManagementAgent,
+	}
+)
 
-// getOptServices returns the list of optional EdgeX services
-// (i.e. disabled by default).
-//
-// Note:
-// - sys-mgmt-agent isn't included because as of Ireland
-//   it's considered deprecated.
-// - kuiper isn't included because it's not yet possible
-//   to provide kuiper configuration via content interface
-func getOptServices() []string {
-	return []string{"support-notifications", "support-scheduler"}
+// snapService returns the snap service name for the given app as <snap>.<app>
+func snapService(app string) string {
+	return env.SnapName + "." + app
 }
 
 func isDisableAllowed(s string) error {
-	for _, v := range getRequiredServices() {
+	for _, v := range requiredServices {
 		if s == v {
 			return fmt.Errorf("can't disable required service: %s", s)
 		}
@@ -115,7 +100,7 @@ func handleSingleService(name, state string) error {
 	switch state {
 	case OFF:
 		log.Debugf("%s state: off", name)
-		if err := snapctl.Stop(hooks.SnapName + "." + name).Disable().Run(); err != nil {
+		if err := snapctl.Stop(snapService(name)).Disable().Run(); err != nil {
 			return err
 		}
 		if err := snapctl.Set(name, OFF).Run(); err != nil {
@@ -123,7 +108,7 @@ func handleSingleService(name, state string) error {
 		}
 	case ON:
 		log.Debugf("%s state: on", name)
-		if err := snapctl.Start(hooks.SnapName + "." + name).Enable().Run(); err != nil {
+		if err := snapctl.Start(snapService(name)).Enable().Run(); err != nil {
 			return err
 		}
 		if err := snapctl.Set(name, ON).Run(); err != nil {
@@ -145,34 +130,13 @@ func handleServices(serviceList []string, state string) error {
 	return nil
 }
 
-func serviceType(name string) int {
-	switch name {
-	case hooks.ServiceKuiper:
-		return kuiperService
-	case hooks.ServiceProxy:
-		return secProxyService
-	case hooks.ServiceSecStore:
-		return secStoreService
-	default:
-		return otherService
-	}
-}
-
-func buildStartCmd(startServices []string, newServices []string) []string {
-	for _, s := range newServices {
-		s = hooks.SnapName + "." + s
-		startServices = append(startServices, s)
-	}
-	return startServices
-}
-
 // This function creates the redis config dir under $SNAP_DATA,
 // and creates an empty redis.conf file. This allows the command
 // line for the service to always specify the config file, and
 // allows for redis when the config option security-secret-store
 // is "on" or "off".
 func clearRedisConf() error {
-	path := filepath.Join(hooks.SnapData, "/redis/conf/redis.conf")
+	path := filepath.Join(env.SnapData, "/redis/conf/redis.conf")
 	if err := ioutil.WriteFile(path, nil, 0644); err != nil {
 		return err
 	}
@@ -180,7 +144,7 @@ func clearRedisConf() error {
 }
 
 func consulAclFileExists() bool {
-	path := filepath.Join(hooks.SnapData, "/consul/config/consul_acl.json")
+	path := filepath.Join(env.SnapData, "/consul/config/consul_acl.json")
 	_, err := os.Stat(path)
 	return err == nil
 }
@@ -188,7 +152,7 @@ func consulAclFileExists() bool {
 // This function deletes the Consul ACL configuration file. This
 // allows Consul to operate in insecure mode.
 func rmConsulAclFile() error {
-	path := filepath.Join(hooks.SnapData, "/consul/config/consul_acl.json")
+	path := filepath.Join(env.SnapData, "/consul/config/consul_acl.json")
 	if err := os.Remove(path); err != nil {
 		return err
 	}
@@ -206,14 +170,14 @@ func disableSecretStoreAndRestart() error {
 	}
 
 	// stop & disable proxy services
-	for _, s := range getProxyServices() {
+	for _, s := range proxyServices {
 		if err := handleSingleService(s, OFF); err != nil {
 			return err
 		}
 	}
 
 	// stop & disable secret store services
-	for _, s := range getSecretStoreServices() {
+	for _, s := range secretStoreServices {
 		if err := handleSingleService(s, OFF); err != nil {
 			return err
 		}
@@ -223,8 +187,8 @@ func disableSecretStoreAndRestart() error {
 	// TODO: can't use handleServices because that would result in the
 	// snap config option for each service to be needlessly set to "off"
 	// then back to "on"; re-factor handleServices/handleSingleService
-	for _, s := range getEdgeXRefServices() {
-		if err := snapctl.Stop(hooks.SnapName + "." + s).Run(); err != nil {
+	for _, s := range referenceServices {
+		if err := snapctl.Stop(snapService(s)).Run(); err != nil {
 			return err
 		}
 	}
@@ -232,19 +196,19 @@ func disableSecretStoreAndRestart() error {
 	// stop Kuiper-related services
 	// TODO - kuiper will be stopped, but not restarted because
 	// additional re-configuration may be needed.
-	for _, s := range getKuiperServices() {
-		if err := snapctl.Stop(hooks.SnapName + "." + s).Run(); err != nil {
+	for _, s := range rulesEngineServices {
+		if err := snapctl.Stop(snapService(s)).Run(); err != nil {
 			return err
 		}
 	}
 
 	// stop redis
-	if err := snapctl.Stop(hooks.SnapName + "." + "redis").Run(); err != nil {
+	if err := snapctl.Stop(snapService(redis)).Run(); err != nil {
 		return err
 	}
 
 	// stop consul
-	if err := snapctl.Stop(hooks.SnapName + "." + "consul").Run(); err != nil {
+	if err := snapctl.Stop(snapService(consul)).Run(); err != nil {
 		return err
 	}
 
@@ -259,15 +223,15 @@ func disableSecretStoreAndRestart() error {
 	}
 
 	// - start required services
-	for _, s := range getRequiredServices() {
-		if err := snapctl.Start(hooks.SnapName + "." + s).Run(); err != nil {
+	for _, s := range requiredServices {
+		if err := snapctl.Start(snapService(s)).Run(); err != nil {
 			return err
 		}
 	}
 
 	// Now check config status of the optional EdgeX
 	// services and restart where necessary
-	for _, s := range getEdgeXRefServices() {
+	for _, s := range referenceServices {
 		status, err := snapctl.Get(s).Run()
 		if err != nil {
 			return err
@@ -279,7 +243,7 @@ func disableSecretStoreAndRestart() error {
 		// part of the enabledServices (i.e. services
 		// always started), then also start it
 		if status == ON || (status == "" && strings.HasPrefix(s, "core-")) {
-			if err := snapctl.Start(hooks.SnapName + "." + s).Run(); err != nil {
+			if err := snapctl.Start(snapService(s)).Run(); err != nil {
 				return err
 			}
 		}
@@ -308,8 +272,30 @@ func disableSecretStoreAndRestart() error {
 func handleAllServices(deferStartup bool) error {
 	secretStoreActive := true
 
+	var services = []string{
+		// core services
+		consul,
+		redis,
+		coreData,
+		coreMetadata,
+		coreCommand,
+		// support services
+		supportNotifications,
+		supportScheduler,
+		eKuiper,
+		// app-services
+		appServiceConfigurable,
+		// security services
+		securitySecretStore,
+		securityProxy,
+		// management
+		systemManagementAgent,
+		// others
+		securityBootstrapper, // oneshot service
+	}
+
 	// grab and log the current service configuration
-	for _, s := range hooks.Services {
+	for _, s := range services {
 		var serviceList []string
 
 		status, err := snapctl.Get(s).Run()
@@ -317,7 +303,7 @@ func handleAllServices(deferStartup bool) error {
 			return err
 		}
 
-		log.Debugf("service: %s status: %s", s, status)
+		log.Debugf("Handling service: %s, status: '%s'", s, status)
 
 		err = applyConfigOptions(s)
 		if err != nil {
@@ -333,19 +319,17 @@ func handleAllServices(deferStartup bool) error {
 		// purposes, however it isn't individually controlable
 		// using on|off, so once configuration has been handled
 		// skip to the next service.
-		if s == hooks.ServiceSecBootstrapper {
+		if s == securityBootstrapper {
 			continue
 		}
 
-		sType := serviceType(s)
-
-		switch sType {
-		case kuiperService:
-			log.Debug("kuiper")
+		// sType := serviceType(s)
 
+		switch s {
+		case eKuiper:
 			switch status {
 			case ON, OFF:
-				serviceList = getKuiperServices()
+				serviceList = rulesEngineServices
 			case UNSET:
 				// this is the default status of all services if no
 				// configuration has been specified; no-op
@@ -354,9 +338,7 @@ func handleAllServices(deferStartup bool) error {
 				return fmt.Errorf("invalid value for kuiper: %s", status)
 			}
 
-		case secProxyService:
-			log.Debug("proxy")
-
+		case securityProxy:
 			switch status {
 			case ON:
 				// NOTE: the original bash based implementation would
@@ -370,7 +352,7 @@ func handleAllServices(deferStartup bool) error {
 
 				fallthrough
 			case OFF:
-				serviceList = getProxyServices()
+				serviceList = proxyServices
 			case UNSET:
 				// this is the default status of all services if no
 				// configuration has been specified; no-op
@@ -379,9 +361,7 @@ func handleAllServices(deferStartup bool) error {
 				return fmt.Errorf("invalid value for security-proxy: %s", status)
 			}
 
-		case secStoreService:
-			log.Debug("secretstore")
-
+		case securitySecretStore:
 			switch status {
 			case ON:
 				return fmt.Errorf("security-secret-store=on not allowed")
@@ -405,10 +385,7 @@ func handleAllServices(deferStartup bool) error {
 				return fmt.Errorf("invalid value for security-secret-store: %s", status)
 			}
 
-		default:
-			log.Debugf("other service: %s", s)
-			// default case for all other services
-
+		default: // default case for all other services
 			switch status {
 			case ON:
 				serviceList = []string{s}
@@ -437,7 +414,7 @@ func handleAllServices(deferStartup bool) error {
 
 func checkCoreConfig(services []string) ([]string, error) {
 	// walk thru the list of default services
-	for _, s := range getCoreDefaultServices() {
+	for _, s := range coreDefaultServices {
 		status, err := snapctl.Get(s).Run()
 		if err != nil {
 			return nil, err
@@ -458,7 +435,7 @@ func checkCoreConfig(services []string) ([]string, error) {
 
 func checkOptConfig(services []string) ([]string, error) {
 	// walk thru the list of default services
-	for _, s := range getOptServices() {
+	for _, s := range optionalServices {
 		status, err := snapctl.Get(s).Run()
 		if err != nil {
 			return nil, err
@@ -490,7 +467,7 @@ func checkSecurityConfig(services []string) ([]string, error) {
 		return services, nil
 	case UNSET:
 		// default behavior
-		services = append(services, getSecretStoreServices()...)
+		services = append(services, secretStoreServices...)
 	default:
 		err = fmt.Errorf("invalid setting for security-secret-store: %s", status)
 		return nil, err
@@ -507,7 +484,7 @@ func checkSecurityConfig(services []string) ([]string, error) {
 		break
 	case UNSET:
 		// default behavior
-		services = append(services, getProxyServices()...)
+		services = append(services, proxyServices...)
 	default:
 		err = fmt.Errorf("invalid setting for security-proxy: %s", status)
 		return nil, err
@@ -517,23 +494,19 @@ func checkSecurityConfig(services []string) ([]string, error) {
 
 func configure() {
 	log.SetComponentName("configure")
-
-	// process the EdgeX >=2.2 app options
-	if err := processAppOptions(); err != nil {
-		log.Fatalf("error processing app options: %v", err)
-	}
-
-	var err error
-	var startServices []string
-
-	log.Info("Started")
+	log.Debug("Start")
 
 	installMode, err := snapctl.Get("install-mode").Run()
 	if err != nil {
 		log.Fatalf("error reading 'install-mode': %v", err)
 	}
-	log.Info("install-mode=%s", installMode)
 	deferStartup := (installMode == "defer-startup")
+	log.Infof("Defer startup: %t", deferStartup)
+
+	// process the EdgeX >=2.2 app options
+	if err := processAppOptions(deferStartup); err != nil {
+		log.Fatalf("error processing app options: %v", err)
+	}
 
 	// handle per service configuration and enable/disable services
 	if err = handleAllServices(deferStartup); err != nil {
@@ -548,11 +521,12 @@ func configure() {
 	// an underlying snapd limitation (namely that services are started
 	// before the config hook runs), leaving the duplication means less
 	// re-factoring if/when snapd adds a new hook.
+	var startServices []string
 	if deferStartup {
-		log.Info("install-mode=defer-startup; starting disabled services")
+		log.Info("Defer startup: starting disabled services")
 
 		// add required services
-		startServices = append(startServices, getRequiredServices()...)
+		startServices = append(startServices, requiredServices...)
 
 		// check security configuration
 		startServices, err = checkSecurityConfig(startServices)
@@ -577,7 +551,7 @@ func configure() {
 		}
 
 		for i, s := range startServices {
-			startServices[i] = hooks.SnapName + "." + s
+			startServices[i] = snapService(s)
 		}
 		// NOTE: the services will be scheduled to start by snapd after the configure hook exits
 		if err = snapctl.Start(startServices...).Enable().Run(); err != nil {
@@ -588,4 +562,6 @@ func configure() {
 			log.Fatalf("error un-setting 'install'; %v", err)
 		}
 	}
+
+	log.Debug("End")
 }
diff --git a/snap/local/helper-go/const.go b/snap/local/helper-go/const.go
new file mode 100644
index 00000000..c8a1f51c
--- /dev/null
+++ b/snap/local/helper-go/const.go
@@ -0,0 +1,35 @@
+package main
+
+// snapped apps
+const (
+	// core services
+	coreData       = "core-data"
+	coreMetadata   = "core-metadata"
+	coreCommand    = "core-command"
+	consul         = "consul"
+	redis          = "redis"
+	registry       = consul
+	configProvider = consul
+	// support services
+	supportNotifications = "support-notifications"
+	supportScheduler     = "support-scheduler"
+	eKuiper              = "kuiper"
+	rulesEngine          = eKuiper
+	// security services
+	securitySecretStore        = "security-secret-store"
+	securitySecretStoreSetup   = "security-secretstore-setup"
+	securityProxy              = "security-proxy"
+	securityProxySetup         = "security-proxy-setup"
+	securityBootstrapper       = "security-bootstrapper"
+	securityBootstrapperRedis  = "security-bootstrapper-redis"
+	securityBootstrapperConsul = "security-consul-bootstrapper"
+	securityFileTokenProvider  = "security-file-token-provider"
+	secretsConfig              = "secrets-config"
+	kong                       = "kong-daemon"
+	postgres                   = "postgres"
+	vault                      = "vault"
+	// app services
+	appServiceConfigurable = "app-service-configurable"
+	// management services
+	systemManagementAgent = "sys-mgmt-agent"
+)
diff --git a/snap/local/helper-go/install.go b/snap/local/helper-go/install.go
index dad1a348..7c6c336d 100644
--- a/snap/local/helper-go/install.go
+++ b/snap/local/helper-go/install.go
@@ -26,6 +26,7 @@ import (
 	"strings"
 
 	hooks "github.com/canonical/edgex-snap-hooks/v2"
+	"github.com/canonical/edgex-snap-hooks/v2/env"
 	"github.com/canonical/edgex-snap-hooks/v2/log"
 	"github.com/canonical/edgex-snap-hooks/v2/snapctl"
 )
@@ -86,29 +87,41 @@ var secretStoreKnownSecrets = []string{
 	"redisdb[edgex-ekuiper]",
 }
 
-// services w/configuration that needs to be copied
-// to $SNAP_DATA
-func getServicesWithConfig() []string {
-	return []string{"security-bootstrapper", "security-bootstrap-redis",
-		"security-file-token-provider", "security-proxy-setup",
-		"security-secretstore-setup", "core-command", "core-data",
-		"core-metadata", "support-notifications", "support-scheduler",
-		"sys-mgmt-agent", "app-service-configurable"}
-}
+var (
+	snapConf     = env.Snap + "/config"
+	snapDataConf = env.SnapData + "/config"
+)
 
 // installConfFiles copies service configuration.toml files from $SNAP to $SNAP_DATA
 func installConfFiles() error {
 	var err error
 
-	for _, v := range getServicesWithConfig() {
-		destDir := hooks.SnapDataConf + "/"
-		srcDir := hooks.SnapConf + "/"
+	// services w/configuration that needs to be copied
+	// to $SNAP_DATA
+	var servicesWithConfig = []string{
+		securityBootstrapper,
+		securityBootstrapperRedis,
+		securityFileTokenProvider,
+		securityProxySetup,
+		securitySecretStoreSetup,
+		coreCommand,
+		coreData,
+		coreMetadata,
+		supportNotifications,
+		supportScheduler,
+		systemManagementAgent,
+		appServiceConfigurable,
+	}
+
+	for _, v := range servicesWithConfig {
+		destDir := snapDataConf + "/"
+		srcDir := snapConf + "/"
 
 		// handle exceptions (i.e. config in non-std dirs)
-		if v == "security-bootstrap-redis" {
+		if v == securityBootstrapperRedis {
 			destDir = destDir + "security-bootstrapper/res-bootstrap-redis"
 			srcDir = srcDir + "security-bootstrapper/res-bootstrap-redis"
-		} else if v == "app-service-configurable" {
+		} else if v == appServiceConfigurable {
 			destDir = destDir + v + "/res/rules-engine"
 			srcDir = srcDir + "/res/rules-engine"
 		} else {
@@ -120,7 +133,15 @@ func installConfFiles() error {
 			return err
 		}
 
-		if v == "core-metadata" {
+		srcPath := srcDir + "/configuration.toml"
+		destPath := destDir + "/configuration.toml"
+		err = hooks.CopyFile(srcPath, destPath)
+		if err != nil {
+			return err
+		}
+
+		// copy additional files
+		if v == coreMetadata {
 			uomSrcPath := srcDir + "/uom.toml"
 			uomDestPath := destDir + "/uom.toml"
 			err = hooks.CopyFile(uomSrcPath, uomDestPath)
@@ -128,14 +149,6 @@ func installConfFiles() error {
 				return err
 			}
 		}
-
-		srcPath := srcDir + "/configuration.toml"
-		destPath := destDir + "/configuration.toml"
-
-		err = hooks.CopyFile(srcPath, destPath)
-		if err != nil {
-			return err
-		}
 	}
 
 	return nil
@@ -144,11 +157,11 @@ func installConfFiles() error {
 // installKuiper execs a shell script to install Kuiper's file into $SNAP_DATA
 func installKuiper() error {
 	// install files using edgex-ekuiper install hook
-	filePath := hooks.Snap + "/snap.edgex-ekuiper/hooks/install"
+	filePath := env.Snap + "/snap.edgex-ekuiper/hooks/install"
 
 	cmdSetupKuiper := exec.Cmd{
 		Path:   filePath,
-		Env:    append(os.Environ(), "KUIPER_BASE_KEY="+hooks.SnapData+"/kuiper"),
+		Env:    append(os.Environ(), "KUIPER_BASE_KEY="+env.SnapData+"/kuiper"),
 		Stdout: os.Stdout,
 		Stderr: os.Stderr,
 	}
@@ -179,30 +192,30 @@ func installSecretStore() error {
 		return err
 	}
 
-	if err = os.MkdirAll(hooks.SnapData+"/secrets", 0700); err != nil {
+	if err = os.MkdirAll(env.SnapData+"/secrets", 0700); err != nil {
 		return err
 	}
 
 	path := "/security-file-token-provider/res/token-config.json"
-	if err = hooks.CopyFile(hooks.SnapConf+path, hooks.SnapDataConf+path); err != nil {
+	if err = hooks.CopyFile(snapConf+path, snapDataConf+path); err != nil {
 		return err
 	}
 
 	// install the template config yaml file for securing Kong's admin
 	// APIs in security-secretstore-setup service
 	path = "/security-secretstore-setup/res/kong-admin-config.template.yml"
-	err = hooks.CopyFile(hooks.SnapConf+path, hooks.SnapDataConf+path)
+	err = hooks.CopyFile(snapConf+path, snapDataConf+path)
 	if err != nil {
 		return err
 	}
 
-	if err = os.MkdirAll(hooks.SnapDataConf+"/security-secret-store", 0755); err != nil {
+	if err = os.MkdirAll(snapDataConf+"/security-secret-store", 0755); err != nil {
 		return err
 	}
 
 	path = "/security-secret-store/vault-config.hcl"
-	destPath := hooks.SnapDataConf + path
-	if err = hooks.CopyFile(hooks.SnapConf+path, destPath); err != nil {
+	destPath := snapDataConf + path
+	if err = hooks.CopyFile(snapConf+path, destPath); err != nil {
 		return err
 	}
 
@@ -225,11 +238,11 @@ func installConsul() error {
 		return err
 	}
 
-	if err = os.MkdirAll(hooks.SnapData+"/consul/config", 0755); err != nil {
+	if err = os.MkdirAll(env.SnapData+"/consul/config", 0755); err != nil {
 		return err
 	}
 
-	if err = os.MkdirAll(hooks.SnapData+"/consul/data", 0755); err != nil {
+	if err = os.MkdirAll(env.SnapData+"/consul/data", 0755); err != nil {
 		return err
 	}
 
@@ -264,24 +277,24 @@ func setupPostgres() error {
 func installProxy() error {
 	var err error
 
-	if err = os.MkdirAll(hooks.SnapCommon+"/logs", 0755); err != nil {
+	if err = os.MkdirAll(env.SnapCommon+"/logs", 0755); err != nil {
 		return err
 	}
 
-	if err = os.MkdirAll(hooks.SnapDataConf+"/security-proxy-setup", 0755); err != nil {
+	if err = os.MkdirAll(snapDataConf+"/security-proxy-setup", 0755); err != nil {
 		return err
 	}
 
 	// ensure prefix uses the 'current' symlink in it's path, otherwise refreshes to a
 	// new snap revision will break
-	snapDataCurr := strings.Replace(hooks.SnapData, hooks.SnapRev, "current", 1)
+	snapDataCurr := strings.Replace(env.SnapData, env.SnapRev, "current", 1)
 	rStrings := map[string]string{
 		"#prefix = /usr/local/kong/":  "prefix = " + snapDataCurr + "/kong",
 		"#nginx_user = nobody nobody": "nginx_user = root root",
 	}
 
 	path := "/security-proxy-setup/kong.conf"
-	if err = hooks.CopyFileReplace(hooks.SnapConf+path, hooks.SnapDataConf+path, rStrings); err != nil {
+	if err = hooks.CopyFileReplace(snapConf+path, snapDataConf+path, rStrings); err != nil {
 		return err
 	}
 
@@ -298,8 +311,8 @@ func installProxy() error {
 // allows for redis when the config option security-secret-store
 // is "on" or "off".
 func installRedis() error {
-	fileName := filepath.Join(hooks.SnapData, "/redis/conf/redis.conf")
-	if _, err := os.Stat(filepath.Join(hooks.SnapData, "redis")); err != nil {
+	fileName := filepath.Join(env.SnapData, "/redis/conf/redis.conf")
+	if _, err := os.Stat(filepath.Join(env.SnapData, "redis")); err != nil {
 		// dir doesn't exist
 		if err := os.MkdirAll(filepath.Dir(fileName), 0755); err != nil {
 			return err
@@ -352,7 +365,7 @@ func install() {
 		}
 	}
 
-	log.Infof("Disabling all services: %v", services)
+	log.Infof("Disabling all services to defer startup to after configuration: %v", services)
 	if err = snapctl.Stop(services...).Disable().Run(); err != nil {
 		log.Fatalf("Error disabling services: %v", err)
 	}
diff --git a/snap/local/helper-go/main.go b/snap/local/helper-go/main.go
index d2319ccf..ff499405 100644
--- a/snap/local/helper-go/main.go
+++ b/snap/local/helper-go/main.go
@@ -21,6 +21,9 @@ import (
 )
 
 func main() {
+	// uncomment to enable snap debugging during development
+	// snapctl.Set("debug", "true").Run()
+
 	subCommand := os.Args[1]
 	switch subCommand {
 	case "install": // snap install hook
diff --git a/snap/local/helper-go/options.go b/snap/local/helper-go/options.go
index 702e1d76..8d3c12fa 100644
--- a/snap/local/helper-go/options.go
+++ b/snap/local/helper-go/options.go
@@ -20,6 +20,7 @@ import (
 	"flag"
 	"fmt"
 	"os"
+	"strings"
 
 	hooks "github.com/canonical/edgex-snap-hooks/v2"
 	"github.com/canonical/edgex-snap-hooks/v2/log"
@@ -27,6 +28,8 @@ import (
 	"github.com/canonical/edgex-snap-hooks/v2/snapctl"
 )
 
+// Deprecated
+// Legacy options starting with "env." are superseded by app options
 func applyConfigOptions(service string) error {
 	envJSON, err := snapctl.Get(hooks.EnvConfig + "." + service).Run()
 	if err != nil {
@@ -34,7 +37,7 @@ func applyConfigOptions(service string) error {
 	}
 
 	if envJSON != "" {
-		log.Debugf("service: %s envJSON: %s", service, envJSON)
+		log.Debugf("Applying env options to service: %s: %s", service, strings.ReplaceAll(envJSON, "\n", ""))
 		if err := hooks.HandleEdgeXConfig(service, envJSON, nil); err != nil {
 			return err
 		}
@@ -63,19 +66,19 @@ func options() {
 	}
 }
 
-func processAppOptions() error {
+func processAppOptions(deferStartup bool) error {
 	log.Info("Processing config options")
 	err := opt.ProcessConfig(
-		"core-data",
-		"core-metadata",
-		"core-command",
-		"support-notifications",
-		"support-scheduler",
-		"app-service-configurable",
-		"security-secretstore-setup",
-		"security-bootstrapper", // local executable
-		"security-proxy-setup",
-		"sys-mgmt-agent",
+		coreData,
+		coreMetadata,
+		coreCommand,
+		supportNotifications,
+		supportScheduler,
+		appServiceConfigurable,
+		securitySecretStoreSetup,
+		securityBootstrapper, // local executable
+		securityProxySetup,
+		systemManagementAgent,
 	)
 	if err != nil {
 		return fmt.Errorf("could not process config options: %v", err)
@@ -88,13 +91,9 @@ func processAppOptions() error {
 	// The following options should not be processed within the configure hook during
 	//	the initial installation (install-mode=defer-startup). They should be processed
 	//	only on follow-up calls to the configure hook (i.e. when snap set/unset is called)
-	installMode, err := snapctl.Get("install-mode").Run() // this set in the install hook
-	if err != nil {
-		return fmt.Errorf("failed to read 'install-mode': %s", err)
-	}
-	if installMode != "defer-startup" {
+	if !deferStartup {
 		err = opt.ProcessAppCustomOptions(
-			"secrets-config", // also processed in security-proxy-post-setup.sh
+			secretsConfig, // also processed in security-proxy-post-setup.sh
 		)
 		if err != nil {
 			return fmt.Errorf("could not process custom options: %v", err)
diff --git a/snap/local/runtime-helpers/bin/kong-daemon.sh b/snap/local/runtime-helpers/bin/kong-daemon.sh
index 09afc1fc..f5e5532e 100755
--- a/snap/local/runtime-helpers/bin/kong-daemon.sh
+++ b/snap/local/runtime-helpers/bin/kong-daemon.sh
@@ -2,8 +2,8 @@
 
 KONG=/usr/local/bin/kong
 
-# run kong migrations up to bootstrap the cassandra database
-# note that sometimes cassandra can be in a "starting up" state, etc.
+# bootstrap the database
+# note that sometimes the database can be in a "starting up" state, etc.
 # and in this case we should just loop and keep trying
 # we don't implement a timeout here because systemd will kill us if we 
 # don't succeed in 15 minutes (or whatever the configured stop-timeout is)
@@ -11,6 +11,9 @@ until "$KONG" migrations bootstrap --conf "$KONG_CONF"; do
     sleep 5
 done
 
+# perform migration for upgrades
+"$KONG" migrations up --conf "$KONG_CONF"
+
 # set up Kong's admin API plugins via kong.yml:
 "$KONG" config db_import "$KONGADMIN_CONFIGFILEPATH" || true
 
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 8b8607b7..14fef58e 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -575,17 +575,17 @@ parts:
       - curl
       - unzip
     override-build: |
-      VERSION=1.10.4
+      VERSION=1.13.0
 
       # use dpkg architecture to figure out our target arch
       case "$(dpkg --print-architecture)" in
         amd64)
           FILE_NAME=consul_${VERSION}_linux_amd64.zip
-          FILE_HASH=2be6414cdce1540c022acda76da55ef6bbd51c537dc2e3d4020652e72daec62d
+          FILE_HASH=db771e40126a88e1cfe2968724adbf2d1cdcc41c503fa326f3a93148ea642d38
           ;;
         arm64)
           FILE_NAME=consul_${VERSION}_linux_arm64.zip
-          FILE_HASH=d4be8f68f0275701bcde71d130a997f5a32b47f91d5fb8a7eae7db666325a33b
+          FILE_HASH=768119d9464685bd39329c537ee140ba19f45f5a2f68ea8fe49403f3141d39ec
           ;;
       esac
 
@@ -603,7 +603,7 @@ parts:
 
   redis:
     source: https://github.com/redis/redis.git
-    source-tag: "6.2.6"
+    source-tag: "6.2.7"
     source-depth: 1
     plugin: make
     make-parameters:
@@ -681,11 +681,8 @@ parts:
         "$SNAPCRAFT_PART_INSTALL/config/security-file-token-provider/res/token-config.json"
 
     build-packages:
-      - libzmq3-dev
       - zip
       - pkg-config
-    stage-packages:
-      - libzmq5
 
   kong:
     plugin: nil
@@ -696,23 +693,23 @@ parts:
       - perl
       - zlib1g-dev
     override-build: |
-      VERSION=2.6.0
+      VERSION=2.8.2
 
       # use dpkg architecture to figure out our target arch
       case "$(dpkg --print-architecture)" in
         amd64)
           FILE_NAME=kong_${VERSION}_amd64.deb
-          FILE_HASH=80913c3c41249a77f7ca1c358d06ae3716a43c79f980f3dd77cd445ac3a62e25
+          FILE_HASH=d600227d07cb862b2dd2de3925eca5841b2292ef838af21ddf5f412c9ab0f3ee
           ;;
         arm64)
           FILE_NAME=kong_${VERSION}_arm64.deb
-          FILE_HASH=6f7c5b9592ce858db890d4e5451a66935bf68b7c44a9ffee4b8f627280a9016c
+          FILE_HASH=c23b22bf34df1f3a8428c998875e868025557d5f9599fd9bed10b12c9fb8ed57
           ;;
       esac
 
       # download the archive and verify the checksum
       curl --silent --show-error --location --output $FILE_NAME \
-        https://download.konghq.com/gateway-2.x-ubuntu-xenial/pool/all/k/kong/$FILE_NAME
+        https://download.konghq.com/gateway-2.x-ubuntu-focal/pool/all/k/kong/$FILE_NAME
       echo "$FILE_HASH $FILE_NAME" > sha256
       sha256sum -c sha256 | grep OK
       
@@ -748,17 +745,17 @@ parts:
       - curl
       - unzip
     override-build: |
-      VERSION=1.8.5
+      VERSION=1.11.3
 
       # use dpkg architecture to figure out the target arch
       case "$(dpkg --print-architecture)" in
         amd64)
           FILE_NAME=vault_${VERSION}_linux_amd64.zip
-          FILE_HASH=97d7ac9145ffdf256ab91045a4857a640ecaa7c56bbd66b61fb70990620f3d33
+          FILE_HASH=b433413ce524f26abe6292f7fc95f267e809daeacdf7ba92b68dead322f92deb
           ;;
         arm64)
           FILE_NAME=vault_${VERSION}_linux_arm64.zip
-          FILE_HASH=a1a57c51505cce0857c32a159ed193dd330e43bee1f3340d2143993c64cf0645
+          FILE_HASH=5ccf49bd3601e29d6d1a8c321ece1eacf0f7cc12ea604ac392edd4f7a54d69c4
           ;;
       esac
 
@@ -791,8 +788,11 @@ parts:
       - -usr/lib/*
       - -usr/share/doc/libnorm1/*
       - -usr/share/doc/libpgm-5.2-0/*
-      - -usr/share/doc/libsodium23/*
-      - -usr/share/doc/libzmq5/*
+      # Exclude snap extras
+      - -bin/helper-go
+      - -bin/source-env-file.sh
+      - -bin/service-wrapper.sh
+
   # Deprecated
   kuiper:
     plugin: nil
@@ -801,15 +801,13 @@ parts:
     organize: 
       bin/setup-redis-credentials.sh: bin/kuiper-setup-redis-credentials.sh
     stage:
-      # Exclude redundant files
+      # Exclude redundant dependencies
       - -usr/bin/curl
       - -usr/lib/*/libcurl*
       - -usr/lib/*/liblber*
       - -usr/lib/*/libldap*
       - -usr/lib/*/libnorm*
       - -usr/lib/*/libpgm*
-      - -usr/lib/*/libsodium*
-      - -usr/lib/*/libzmq*
       - -usr/lib/*/libasn1*
       - -usr/lib/*/libgssapi*
       - -usr/lib/*/libhcrypto*
@@ -824,8 +822,6 @@ parts:
       - -usr/share/doc/libldap*
       - -usr/share/doc/libnorm*
       - -usr/share/doc/libpgm*
-      - -usr/share/doc/libsodium*
-      - -usr/share/doc/libzmq*
       - -usr/share/doc/libheimbase1-heimdal
       - -usr/share/doc/libroken18-heimdal
 


Test patch:
diff --git a/internal/core/command/controller/messaging/external_test.go b/internal/core/command/controller/messaging/external_test.go
index 7039d117..baef9904 100644
--- a/internal/core/command/controller/messaging/external_test.go
+++ b/internal/core/command/controller/messaging/external_test.go
@@ -331,6 +331,9 @@ func Test_commandRequestHandler(t *testing.T) {
 	validPayload := testCommandRequestPayload()
 	invalidRequestPayload := testCommandRequestPayload()
 	invalidRequestPayload.ApiVersion = "v1"
+	invalidQueryParamsPayload := testCommandQueryPayload()
+	invalidQueryParamsPayload.QueryParams[common.PushEvent] = "invalid"
+	invalidQueryParamsPayload.QueryParams[common.ReturnEvent] = "invalid"
 
 	tests := []struct {
 		name                 string
@@ -345,6 +348,7 @@ func Test_commandRequestHandler(t *testing.T) {
 		{"invalid - unrecognized command method", "unittest/request/testDevice/testCommand/invalid", validPayload, true, false},
 		{"invalid - device not found", "unittest/request/unknown-device/testCommand/get", validPayload, true, true},
 		{"invalid - device service not found", "unittest/request/unknownService-device/testCommand/get", validPayload, true, true},
+		{"invalid - invalid device service reserved query parameters", testExternalCommandRequestTopicExample, invalidQueryParamsPayload, true, true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {