Repository: clouditor/clouditor
Pull request #410 (2021-12-10 15:45:44)

Add hooks
Add hooks for incoming (#384)
- evidences in evidence_store -> StoreEvidence() / StoreEvidences()
- assessment_results in orchestrator -> StoreAssessmentResult() / StoreAssessmentResults()


codecov[bot]: # [Codecov](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) Report
> Merging [#410](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (97a6bd2) into [main](https://codecov.io/gh/clouditor/clouditor/commit/5d80de5dfdcd0d777ed126941ee77e9b1ed6436a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) (5d80de5) will **decrease** coverage by `0.00%`.
> The diff coverage is `67.74%`.

[![Impacted file tree graph](https://codecov.io/gh/clouditor/clouditor/pull/410/graphs/tree.svg?width=650&height=150&src=pr&token=syrXsw5LTX&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)

```diff
@@            Coverage Diff             @@
##             main     #410      +/-   ##
==========================================
- Coverage   67.85%   67.85%   -0.01%     
==========================================
  Files          38       38              
  Lines        3388     3419      +31     
==========================================
+ Hits         2299     2320      +21     
- Misses        971      981      +10     
  Partials      118      118              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `67.85% <67.74%> (-0.01%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor) | Coverage Δ | |
|---|---|---|
| [cmd/engine/engine.go](https://codecov.io/gh/clouditor/clouditor/pull/410/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-Y21kL2VuZ2luZS9lbmdpbmUuZ28=) | `21.42% <0.00%> (-1.30%)` | :arrow_down: |
| [service/auth/auth.go](https://codecov.io/gh/clouditor/clouditor/pull/410/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9hdXRoL2F1dGguZ28=) | `81.41% <ø> (ø)` | |
| [service/orchestrator/orchestrator.go](https://codecov.io/gh/clouditor/clouditor/pull/410/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor#diff-c2VydmljZS9vcmNoZXN0cmF0b3Ivb3JjaGVzdHJhdG9yLmdv) | `78.18% <91.30%> (+3.46%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor). Last update [5d80de5...97a6bd2](https://codecov.io/gh/clouditor/clouditor/pull/410?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=clouditor).


Patch:
diff --git a/api/assessment/assessment.go b/api/assessment/assessment.go
new file mode 100644
index 00000000..179f278b
--- /dev/null
+++ b/api/assessment/assessment.go
@@ -0,0 +1,67 @@
+// Copyright 2021 Fraunhofer AISEC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//           $$\                           $$\ $$\   $$\
+//           $$ |                          $$ |\__|  $$ |
+//  $$$$$$$\ $$ | $$$$$$\  $$\   $$\  $$$$$$$ |$$\ $$$$$$\    $$$$$$\   $$$$$$\
+// $$  _____|$$ |$$  __$$\ $$ |  $$ |$$  __$$ |$$ |\_$$  _|  $$  __$$\ $$  __$$\
+// $$ /      $$ |$$ /  $$ |$$ |  $$ |$$ /  $$ |$$ |  $$ |    $$ /  $$ |$$ | \__|
+// $$ |      $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$\ $$ |  $$ |$$ |
+// \$$$$$$\  $$ |\$$$$$   |\$$$$$   |\$$$$$$  |$$ |  \$$$   |\$$$$$   |$$ |
+//  \_______|\__| \______/  \______/  \_______|\__|   \____/  \______/ \__|
+//
+// This file is part of Clouditor Community Edition.
+
+package assessment
+
+import "errors"
+
+var (
+	ErrTimestampMissing             = errors.New("timestamp in assessment result is missing")
+	ErrMetricIdMissing              = errors.New("metric id in assessment result is missing")
+	ErrMetricDataMissing            = errors.New("metric data in assessment result is missing")
+	ErrEvidenceIdMissing            = errors.New("evidence id in assessment result is missing")
+	ErrNonComplianceCommentsMissing = errors.New("non-compliance comments in assessment result is missing")
+	ErrMetricDataOperatorMissing    = errors.New("operator in metric data is missing")
+	ErrMetricDataTargetValueMissing = errors.New("target value in metric data is missing")
+)
+
+// Validate validates the assessment result according to several required fields
+func (result *AssessmentResult) Validate() (resourceId string, err error) {
+	if result.Timestamp == nil {
+		return "", ErrTimestampMissing
+	}
+
+	if result.MetricId == "" {
+		return "", ErrMetricIdMissing
+	}
+
+	if result.MetricConfiguration == nil {
+		return "", ErrMetricDataMissing
+	}
+
+	if result.MetricConfiguration.Operator == "" {
+		return "", ErrMetricDataOperatorMissing
+	}
+
+	if result.MetricConfiguration.TargetValue == nil {
+		return "", ErrMetricDataTargetValueMissing
+	}
+
+	if result.EvidenceId == "" {
+		return "", ErrEvidenceIdMissing
+	}
+
+	return
+}
diff --git a/api/assessment/assessment.pb.gw.go b/api/assessment/assessment.pb.gw.go
index f8deabfa..bc9a0d58 100644
--- a/api/assessment/assessment.pb.gw.go
+++ b/api/assessment/assessment.pb.gw.go
@@ -95,7 +95,7 @@ func RegisterAssessmentHandlerServer(ctx context.Context, mux *runtime.ServeMux,
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Assessment/ListAssessmentResults", runtime.WithHTTPPathPattern("/v1/assessment/results"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Assessment/ListAssessmentResults")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -118,7 +118,7 @@ func RegisterAssessmentHandlerServer(ctx context.Context, mux *runtime.ServeMux,
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Assessment/AssessEvidence", runtime.WithHTTPPathPattern("/v1/assessment/evidences"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Assessment/AssessEvidence")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -180,7 +180,7 @@ func RegisterAssessmentHandlerClient(ctx context.Context, mux *runtime.ServeMux,
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Assessment/ListAssessmentResults", runtime.WithHTTPPathPattern("/v1/assessment/results"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Assessment/ListAssessmentResults")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -200,7 +200,7 @@ func RegisterAssessmentHandlerClient(ctx context.Context, mux *runtime.ServeMux,
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Assessment/AssessEvidence", runtime.WithHTTPPathPattern("/v1/assessment/evidences"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Assessment/AssessEvidence")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
diff --git a/api/auth/auth.pb.gw.go b/api/auth/auth.pb.gw.go
index 44c6463e..19e18fdb 100644
--- a/api/auth/auth.pb.gw.go
+++ b/api/auth/auth.pb.gw.go
@@ -77,7 +77,7 @@ func RegisterAuthenticationHandlerServer(ctx context.Context, mux *runtime.Serve
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Authentication/Login", runtime.WithHTTPPathPattern("/v1/auth/login"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Authentication/Login")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -139,7 +139,7 @@ func RegisterAuthenticationHandlerClient(ctx context.Context, mux *runtime.Serve
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Authentication/Login", runtime.WithHTTPPathPattern("/v1/auth/login"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Authentication/Login")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
diff --git a/api/discovery/discovery.pb.gw.go b/api/discovery/discovery.pb.gw.go
index f769205d..11f24a90 100644
--- a/api/discovery/discovery.pb.gw.go
+++ b/api/discovery/discovery.pb.gw.go
@@ -111,7 +111,7 @@ func RegisterDiscoveryHandlerServer(ctx context.Context, mux *runtime.ServeMux,
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Discovery/Start", runtime.WithHTTPPathPattern("/v1/discovery/start"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Discovery/Start")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -134,7 +134,7 @@ func RegisterDiscoveryHandlerServer(ctx context.Context, mux *runtime.ServeMux,
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Discovery/Query", runtime.WithHTTPPathPattern("/v1/discovery/query"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Discovery/Query")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -196,7 +196,7 @@ func RegisterDiscoveryHandlerClient(ctx context.Context, mux *runtime.ServeMux,
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Discovery/Start", runtime.WithHTTPPathPattern("/v1/discovery/start"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Discovery/Start")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -216,7 +216,7 @@ func RegisterDiscoveryHandlerClient(ctx context.Context, mux *runtime.ServeMux,
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Discovery/Query", runtime.WithHTTPPathPattern("/v1/discovery/query"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Discovery/Query")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
diff --git a/api/evidence/evidence.go b/api/evidence/evidence.go
index 5091433f..0d4d29c7 100644
--- a/api/evidence/evidence.go
+++ b/api/evidence/evidence.go
@@ -1,3 +1,28 @@
+// Copyright 2021 Fraunhofer AISEC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//           $$\                           $$\ $$\   $$\
+//           $$ |                          $$ |\__|  $$ |
+//  $$$$$$$\ $$ | $$$$$$\  $$\   $$\  $$$$$$$ |$$\ $$$$$$\    $$$$$$\   $$$$$$\
+// $$  _____|$$ |$$  __$$\ $$ |  $$ |$$  __$$ |$$ |\_$$  _|  $$  __$$\ $$  __$$\
+// $$ /      $$ |$$ /  $$ |$$ |  $$ |$$ /  $$ |$$ |  $$ |    $$ /  $$ |$$ | \__|
+// $$ |      $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$ |  $$ |$$\ $$ |  $$ |$$ |
+// \$$$$$$\  $$ |\$$$$$   |\$$$$$   |\$$$$$$  |$$ |  \$$$   |\$$$$$   |$$ |
+//  \_______|\__| \______/  \______/  \_______|\__|   \____/  \______/ \__|
+//
+// This file is part of Clouditor Community Edition.
+
 package evidence
 
 import "errors"
diff --git a/api/evidence/evidence_store.pb.gw.go b/api/evidence/evidence_store.pb.gw.go
index baaf4839..98a0b52b 100644
--- a/api/evidence/evidence_store.pb.gw.go
+++ b/api/evidence/evidence_store.pb.gw.go
@@ -95,7 +95,7 @@ func RegisterEvidenceStoreHandlerServer(ctx context.Context, mux *runtime.ServeM
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.EvidenceStore/StoreEvidence", runtime.WithHTTPPathPattern("/v1/evidence_store/evidence"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.EvidenceStore/StoreEvidence")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -118,7 +118,7 @@ func RegisterEvidenceStoreHandlerServer(ctx context.Context, mux *runtime.ServeM
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.EvidenceStore/ListEvidences", runtime.WithHTTPPathPattern("/v1/evidence_store/evidences"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.EvidenceStore/ListEvidences")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -180,7 +180,7 @@ func RegisterEvidenceStoreHandlerClient(ctx context.Context, mux *runtime.ServeM
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.EvidenceStore/StoreEvidence", runtime.WithHTTPPathPattern("/v1/evidence_store/evidence"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.EvidenceStore/StoreEvidence")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -200,7 +200,7 @@ func RegisterEvidenceStoreHandlerClient(ctx context.Context, mux *runtime.ServeM
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.EvidenceStore/ListEvidences", runtime.WithHTTPPathPattern("/v1/evidence_store/evidences"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.EvidenceStore/ListEvidences")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
diff --git a/api/orchestrator/orchestrator.pb.gw.go b/api/orchestrator/orchestrator.pb.gw.go
index afc9d8f4..49470cf3 100644
--- a/api/orchestrator/orchestrator.pb.gw.go
+++ b/api/orchestrator/orchestrator.pb.gw.go
@@ -789,7 +789,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -812,7 +812,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -835,7 +835,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools", runtime.WithHTTPPathPattern("/v1/orchestrator/{metric_id}/assessment_tools"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -858,7 +858,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -881,7 +881,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -904,7 +904,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/DeregisterAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/DeregisterAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -927,7 +927,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/StoreAssessmentResult", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_results"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/StoreAssessmentResult")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -950,7 +950,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetrics", runtime.WithHTTPPathPattern("/v1/orchestrator/metrics"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetrics")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -973,7 +973,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetric", runtime.WithHTTPPathPattern("/v1/orchestrator/metrics/{metric_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetric")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -996,7 +996,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1019,7 +1019,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1042,7 +1042,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1065,7 +1065,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListCloudServices", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListCloudServices")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1088,7 +1088,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RemoveCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/RemoveCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1111,7 +1111,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetricConfiguration", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}/metric_configurations/{metric_id}"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetricConfiguration")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1134,7 +1134,7 @@ func RegisterOrchestratorHandlerServer(ctx context.Context, mux *runtime.ServeMu
 		var stream runtime.ServerTransportStream
 		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetricConfigurations", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}/metric_configurations"))
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetricConfigurations")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1196,7 +1196,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1216,7 +1216,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1236,7 +1236,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools", runtime.WithHTTPPathPattern("/v1/orchestrator/{metric_id}/assessment_tools"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListAssessmentTools")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1256,7 +1256,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1276,7 +1276,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1296,7 +1296,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/DeregisterAssessmentTool", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_tools/{tool_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/DeregisterAssessmentTool")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1316,7 +1316,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/StoreAssessmentResult", runtime.WithHTTPPathPattern("/v1/orchestrator/assessment_results"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/StoreAssessmentResult")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1336,7 +1336,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetrics", runtime.WithHTTPPathPattern("/v1/orchestrator/metrics"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetrics")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1356,7 +1356,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetric", runtime.WithHTTPPathPattern("/v1/orchestrator/metrics/{metric_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetric")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1376,7 +1376,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RegisterCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1396,7 +1396,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/UpdateCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1416,7 +1416,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1436,7 +1436,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListCloudServices", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListCloudServices")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1456,7 +1456,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RemoveCloudService", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/RemoveCloudService")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1476,7 +1476,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetricConfiguration", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}/metric_configurations/{metric_id}"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/GetMetricConfiguration")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
@@ -1496,7 +1496,7 @@ func RegisterOrchestratorHandlerClient(ctx context.Context, mux *runtime.ServeMu
 		ctx, cancel := context.WithCancel(req.Context())
 		defer cancel()
 		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
-		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetricConfigurations", runtime.WithHTTPPathPattern("/v1/orchestrator/cloud_services/{service_id}/metric_configurations"))
+		rctx, err := runtime.AnnotateContext(ctx, mux, req, "/clouditor.Orchestrator/ListMetricConfigurations")
 		if err != nil {
 			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
 			return
diff --git a/cmd/engine/engine.go b/cmd/engine/engine.go
index 757eb6dd..79d80c76 100644
--- a/cmd/engine/engine.go
+++ b/cmd/engine/engine.go
@@ -94,8 +94,8 @@ var server *grpc.Server
 var authService *service_auth.Service
 var discoveryService *service_discovery.Service
 var orchestratorService *service_orchestrator.Service
-var assessmentService assessment.AssessmentServer
-var evidenceStoreService evidence.EvidenceStoreServer
+var assessmentService *service_assessment.Service
+var evidenceStoreService *service_evidenceStore.Service
 
 var log *logrus.Entry
 
@@ -178,6 +178,26 @@ func doCmd(_ *cobra.Command, _ []string) (err error) {
 	assessmentService = service_assessment.NewService()
 	evidenceStoreService = service_evidenceStore.NewService()
 
+	// It is possible to register hook functions for the orchestrator, evidenceStore and assessment service.
+	// The hook functions in orchestrator are implemented in StoreAssessmentResult(s)
+	// The hook functions in evidenceStore are implemented in StoreEvidence(s)
+	// The hook functions in assessment are implemented in AssessEvidence(s)
+
+	// orchestratorService.RegisterAssessmentResultHook(func(result *assessment.AssessmentResult, err error) {})
+	// evidenceStoreService.RegisterEvidenceHook(func(result *evidence.Evidence, err error) {})
+	assessmentService.RegisterAssessmentResultHook(func(result *assessment.AssessmentResult, err error) {
+
+		if err != nil {
+			return
+		}
+		_, err = orchestratorService.StoreAssessmentResult(context.Background(), &orchestrator.StoreAssessmentResultRequest{
+			Result: result})
+
+		if err != nil {
+			log.Errorf("error storing assessment result in orchestrator: %v", err)
+		}
+	})
+
 	authService.CreateDefaultUser(viper.GetString(APIDefaultUserFlag), viper.GetString(APIDefaultPasswordFlag))
 
 	if viper.GetBool(CreateDefaultTarget) {
diff --git a/openapi/assessment/openapi.yaml b/openapi/assessment/openapi.yaml
index 153bd0c4..56d1c2d4 100644
--- a/openapi/assessment/openapi.yaml
+++ b/openapi/assessment/openapi.yaml
@@ -1,5 +1,5 @@
 # Generated with protoc-gen-openapi
-# https://github.com/google/gnostic/tree/master/apps/protoc-gen-openapi
+# https://github.com/googleapis/gnostic/tree/master/apps/protoc-gen-openapi
 
 openapi: 3.0.3
 info:
diff --git a/openapi/discovery/openapi.yaml b/openapi/discovery/openapi.yaml
index 6114fc87..5cb3c0ae 100644
--- a/openapi/discovery/openapi.yaml
+++ b/openapi/discovery/openapi.yaml
@@ -1,5 +1,5 @@
 # Generated with protoc-gen-openapi
-# https://github.com/google/gnostic/tree/master/apps/protoc-gen-openapi
+# https://github.com/googleapis/gnostic/tree/master/apps/protoc-gen-openapi
 
 openapi: 3.0.3
 info:
diff --git a/openapi/evidence/openapi.yaml b/openapi/evidence/openapi.yaml
index dfdfaa72..ec0d9145 100644
--- a/openapi/evidence/openapi.yaml
+++ b/openapi/evidence/openapi.yaml
@@ -1,5 +1,5 @@
 # Generated with protoc-gen-openapi
-# https://github.com/google/gnostic/tree/master/apps/protoc-gen-openapi
+# https://github.com/googleapis/gnostic/tree/master/apps/protoc-gen-openapi
 
 openapi: 3.0.3
 info:
diff --git a/openapi/orchestrator/openapi.yaml b/openapi/orchestrator/openapi.yaml
index 32bbbf4a..df6c718f 100644
--- a/openapi/orchestrator/openapi.yaml
+++ b/openapi/orchestrator/openapi.yaml
@@ -1,5 +1,5 @@
 # Generated with protoc-gen-openapi
-# https://github.com/google/gnostic/tree/master/apps/protoc-gen-openapi
+# https://github.com/googleapis/gnostic/tree/master/apps/protoc-gen-openapi
 
 openapi: 3.0.3
 info:
diff --git a/service/assessment/assessment.go b/service/assessment/assessment.go
index b0318d3c..8721d6ab 100644
--- a/service/assessment/assessment.go
+++ b/service/assessment/assessment.go
@@ -54,13 +54,13 @@ NewService constructor should be used. It implements the AssessmentServer interf
 type Service struct {
 	// ResultHook is a hook function that can be used if one wants to be
 	// informed about each assessment result
-	ResultHook func(result *assessment.AssessmentResult, err error)
+	ResultHook []func(result *assessment.AssessmentResult, err error)
 
 	results map[string]*assessment.AssessmentResult
 	assessment.UnimplementedAssessmentServer
 }
 
-func NewService() assessment.AssessmentServer {
+func NewService() *Service {
 	return &Service{
 		results: make(map[string]*assessment.AssessmentResult),
 	}
@@ -107,7 +107,6 @@ func (s Service) AssessEvidences(stream assessment.Assessment_AssessEvidencesSer
 		if err != nil {
 			return status.Errorf(codes.Internal, "Error while handling evidence: %v", err)
 		}
-
 	}
 }
 
@@ -115,7 +114,17 @@ func (s Service) AssessEvidences(stream assessment.Assessment_AssessEvidencesSer
 func (s Service) handleEvidence(evidence *evidence.Evidence) error {
 	resourceId, err := evidence.Validate()
 	if err != nil {
-		return fmt.Errorf("invalid evidence: %w", err)
+		log.Errorf("Invalid evidence: %v", err)
+		newError := fmt.Errorf("invalid evidence: %w", err)
+
+		// Inform our hook, if we have any
+		if s.ResultHook != nil {
+			for _, hook := range s.ResultHook {
+				go hook(nil, newError)
+			}
+		}
+
+		return newError
 	}
 
 	log.Infof("Running evidence %s (%s) collected by %s at %v", evidence.Id, resourceId, evidence.ToolId, evidence.Timestamp)
@@ -124,13 +133,15 @@ func (s Service) handleEvidence(evidence *evidence.Evidence) error {
 	evaluations, err := policies.RunEvidence(evidence)
 	if err != nil {
 		log.Errorf("Could not evaluate evidence: %v", err)
+		newError := fmt.Errorf("could not evaluate evidence: %w", err)
 
 		// Inform our hook, if we have any
 		if s.ResultHook != nil {
-			go s.ResultHook(nil, err)
+			for _, hook := range s.ResultHook {
+				go hook(nil, newError)
+			}
 		}
-
-		return err
+		return newError
 	}
 
 	for i, data := range evaluations {
@@ -162,7 +173,9 @@ func (s Service) handleEvidence(evidence *evidence.Evidence) error {
 
 		// Inform our hook, if we have any
 		if s.ResultHook != nil {
-			go s.ResultHook(result, nil)
+			for _, hook := range s.ResultHook {
+				go hook(result, nil)
+			}
 		}
 	}
 
@@ -180,3 +193,7 @@ func (s Service) ListAssessmentResults(_ context.Context, _ *assessment.ListAsse
 
 	return
 }
+
+func (s *Service) RegisterAssessmentResultHook(assessmentResultsHook func(result *assessment.AssessmentResult, err error)) {
+	s.ResultHook = append(s.ResultHook, assessmentResultsHook)
+}
diff --git a/service/auth/auth.go b/service/auth/auth.go
index 5959f35e..1f6ca8ab 100644
--- a/service/auth/auth.go
+++ b/service/auth/auth.go
@@ -192,7 +192,6 @@ func StartDedicatedAuthServer(address string) (sock net.Listener, server *grpc.S
 		return nil, nil, fmt.Errorf("could not listen: %w", err)
 	}
 
-
 	authService = &Service{}
 	authService.CreateDefaultUser("clouditor", "clouditor")
 
diff --git a/service/evidence/evidence_store.go b/service/evidence/evidence_store.go
index d2b34274..2f0eba50 100644
--- a/service/evidence/evidence_store.go
+++ b/service/evidence/evidence_store.go
@@ -2,6 +2,7 @@ package evidences
 
 import (
 	"context"
+	"fmt"
 	"io"
 
 	"clouditor.io/clouditor/api/evidence"
@@ -17,6 +18,10 @@ var log *logrus.Entry
 type Service struct {
 	// Currently only in-memory
 	evidences map[string]*evidence.Evidence
+
+	// Hook
+	EvidenceHook []func(result *evidence.Evidence, err error)
+
 	evidence.UnimplementedEvidenceStoreServer
 }
 
@@ -40,11 +45,29 @@ func (s *Service) StoreEvidence(_ context.Context, req *evidence.StoreEvidenceRe
 
 	_, err = e.Validate()
 	if err != nil {
-		return nil, status.Errorf(codes.InvalidArgument, "invalid req: %v", err)
+		log.Errorf("Invalid evidence: %v", err)
+		newError := fmt.Errorf("invalid evidence: %w", err)
+
+		// Inform our hook, if we have any
+		if s.EvidenceHook != nil {
+			for _, hook := range s.EvidenceHook {
+				go hook(nil, newError)
+			}
+		}
+
+		return resp, status.Errorf(codes.InvalidArgument, "invalid req: %v", err)
 	}
 
 	s.evidences[e.Id] = e
 	resp.Status = true
+
+	// Inform our hook, if we have any
+	if s.EvidenceHook != nil {
+		for _, hook := range s.EvidenceHook {
+			go hook(e, nil)
+		}
+	}
+
 	return resp, err
 }
 
@@ -62,6 +85,13 @@ func (s *Service) StoreEvidences(stream evidence.EvidenceStore_StoreEvidencesSer
 			return stream.SendAndClose(&emptypb.Empty{})
 		}
 		s.evidences[e.Id] = e
+
+		// Inform our hook, if we have any
+		if s.EvidenceHook != nil {
+			for _, hook := range s.EvidenceHook {
+				go hook(e, nil)
+			}
+		}
 	}
 }
 
@@ -74,3 +104,7 @@ func (s *Service) ListEvidences(_ context.Context, _ *evidence.ListEvidencesRequ
 
 	return &evidence.ListEvidencesResponse{Evidences: listOfEvidences}, nil
 }
+
+func (s *Service) RegisterEvidenceHook(evidenceHook func(result *evidence.Evidence, err error)) {
+	s.EvidenceHook = append(s.EvidenceHook, evidenceHook)
+}
diff --git a/service/orchestrator/orchestrator.go b/service/orchestrator/orchestrator.go
index adb3514e..f5009ad8 100644
--- a/service/orchestrator/orchestrator.go
+++ b/service/orchestrator/orchestrator.go
@@ -30,6 +30,8 @@ import (
 	"embed"
 	"encoding/json"
 	"fmt"
+	"google.golang.org/protobuf/types/known/emptypb"
+	"io"
 	"io/ioutil"
 
 	"clouditor.io/clouditor/api/assessment"
@@ -58,6 +60,12 @@ type Service struct {
 	// metricConfigurations holds a double-map of metric configurations associated first by service ID and then metric ID
 	metricConfigurations map[string]map[string]*assessment.MetricConfiguration
 
+	// Currently only in-memory
+	Results map[string]*assessment.AssessmentResult
+
+	// Hook
+	AssessmentResultsHook []func(result *assessment.AssessmentResult, err error)
+
 	db *gorm.DB
 }
 
@@ -67,6 +75,7 @@ func init() {
 
 func NewService() *Service {
 	s := Service{
+		Results:              make(map[string]*assessment.AssessmentResult),
 		metricConfigurations: make(map[string]map[string]*assessment.MetricConfiguration),
 	}
 
@@ -185,6 +194,70 @@ func (s *Service) ListMetricConfigurations(ctx context.Context, req *orchestrato
 	return
 }
 
+// StoreAssessmentResult is a method implementation of the orchestrator interface: It receives an assessment result and stores it
+func (s *Service) StoreAssessmentResult(_ context.Context, req *orchestrator.StoreAssessmentResultRequest) (response *orchestrator.StoreAssessmentResultResponse, err error) {
+
+	response = &orchestrator.StoreAssessmentResultResponse{}
+
+	err = s.handleResult(req.Result)
+
+	if err != nil {
+		return response, status.Errorf(codes.InvalidArgument, "invalid assessment result: %v", err)
+	}
+
+	return
+}
+
+func (s *Service) StoreAssessmentResults(stream orchestrator.Orchestrator_StoreAssessmentResultsServer) (err error) {
+	var result *assessment.AssessmentResult
+
+	for {
+		result, err = stream.Recv()
+		if err == io.EOF {
+			log.Infof("Stopped receiving streamed assessment results")
+			return stream.SendAndClose(&emptypb.Empty{})
+		}
+
+		err = s.handleResult(result)
+		if err != nil {
+			return fmt.Errorf("error handle assessment result: %w", err)
+		}
+	}
+
+}
+
+func (s Service) handleResult(result *assessment.AssessmentResult) error {
+	_, err := result.Validate()
+	if err != nil {
+		log.Errorf("Invalid assessment result: %v", err)
+		newError := fmt.Errorf("invalid assessment result: %w", err)
+
+		// Inform our hook, if we have any
+		if s.AssessmentResultsHook != nil {
+			for _, hook := range s.AssessmentResultsHook {
+				go hook(nil, newError)
+			}
+		}
+
+		return newError
+	}
+
+	s.Results[result.Id] = result
+
+	// Inform our hook, if we have any
+	if s.AssessmentResultsHook != nil {
+		for _, hook := range s.AssessmentResultsHook {
+			go hook(result, nil)
+		}
+	}
+
+	return nil
+}
+
+func (s *Service) RegisterAssessmentResultHook(hook func(result *assessment.AssessmentResult, err error)) {
+	s.AssessmentResultsHook = append(s.AssessmentResultsHook, hook)
+}
+
 //// Tools
 //
 //// TODO Implement DeregisterAssessmentTool


Test patch:
diff --git a/service/assessment/assessment_test.go b/service/assessment/assessment_test.go
index 26ac643a..b0d00c00 100644
--- a/service/assessment/assessment_test.go
+++ b/service/assessment/assessment_test.go
@@ -26,20 +26,23 @@
 package assessment
 
 import (
+	"clouditor.io/clouditor/api/assessment"
+	"clouditor.io/clouditor/api/evidence"
+	"clouditor.io/clouditor/api/orchestrator"
+	orchestrator_service "clouditor.io/clouditor/service/orchestrator"
+	"clouditor.io/clouditor/voc"
 	"context"
+	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/protobuf/types/known/emptypb"
+	"google.golang.org/protobuf/types/known/structpb"
+	"google.golang.org/protobuf/types/known/timestamppb"
 	"io"
 	"os"
 	"reflect"
+	"runtime"
 	"testing"
-
-	"clouditor.io/clouditor/api/assessment"
-	"clouditor.io/clouditor/api/evidence"
-	"clouditor.io/clouditor/voc"
-	"github.com/stretchr/testify/assert"
-	"google.golang.org/protobuf/types/known/structpb"
-	"google.golang.org/protobuf/types/known/timestamppb"
+	"time"
 )
 
 func TestMain(m *testing.M) {
@@ -148,7 +151,7 @@ func TestAssessEvidence(t *testing.T) {
 
 func TestService_AssessEvidences(t *testing.T) {
 	type fields struct {
-		ResultHook                    func(result *assessment.AssessmentResult, err error)
+		ResultHook                    []func(result *assessment.AssessmentResult, err error)
 		results                       map[string]*assessment.AssessmentResult
 		UnimplementedAssessmentServer assessment.UnimplementedAssessmentServer
 	}
@@ -201,6 +204,112 @@ func TestService_AssessEvidences(t *testing.T) {
 	}
 }
 
+func TestAssessmentResultHook(t *testing.T) {
+	var (
+		hookCallCounter = 0
+		// Service needs to outlive the lifetime of the hook function
+		service = *orchestrator_service.NewService()
+	)
+
+	firstHookFunction := func(assessmentResult *assessment.AssessmentResult, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the firstHookFunction")
+	}
+
+	secondHookFunction := func(assessmentResult *assessment.AssessmentResult, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the secondHookFunction")
+	}
+
+	// TODO(garuppel): Delete that test after adding an additional test for assessment.Validate()
+	storeAssessmentResultToOrchestrator := func(result *assessment.AssessmentResult, err error) {
+
+		hookCallCounter++
+
+		if err != nil {
+			log.Println("error as input %w: ", err)
+			log.Infof("stop hook for storing assessment result")
+			return
+		}
+
+		_, err = service.StoreAssessmentResult(context.Background(), &orchestrator.StoreAssessmentResultRequest{
+			Result: result})
+
+		if err != nil {
+			log.Errorf("error storing assessment result in orchestrator: %v", err)
+		} else {
+			log.Infof("assessment result stored in orchestrator")
+		}
+	}
+
+	// Check GRPC call
+	type args struct {
+		in0                 context.Context
+		evidence            *assessment.AssessEvidenceRequest
+		resultHookFunctions []func(assessmentResult *assessment.AssessmentResult, err error)
+	}
+	tests := []struct {
+		name     string
+		args     args
+		wantResp *assessment.AssessEvidenceResponse
+		wantErr  bool
+	}{
+		{
+			name: "Store evidence to the map",
+			args: args{
+				in0: context.TODO(),
+				evidence: &assessment.AssessEvidenceRequest{
+					Evidence: &evidence.Evidence{
+						Id:        "MockEvidenceID",
+						ToolId:    "mock",
+						Timestamp: timestamppb.Now(),
+						Resource: toStruct(voc.VirtualMachine{
+							Compute: &voc.Compute{
+								CloudResource: &voc.CloudResource{
+									ID:   "my-resource-id",
+									Type: []string{"VirtualMachine"}},
+							},
+						}, t),
+					}},
+				resultHookFunctions: []func(assessmentResult *assessment.AssessmentResult, err error){storeAssessmentResultToOrchestrator, firstHookFunction, secondHookFunction},
+			},
+			wantErr:  false,
+			wantResp: &assessment.AssessEvidenceResponse{Status: true},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			hookCallCounter = 0
+			s := NewService()
+
+			for i, hookFunction := range tt.args.resultHookFunctions {
+				s.RegisterAssessmentResultHook(hookFunction)
+
+				// Check if hook is registered
+				funcName1 := runtime.FuncForPC(reflect.ValueOf(s.ResultHook[i]).Pointer()).Name()
+				funcName2 := runtime.FuncForPC(reflect.ValueOf(hookFunction).Pointer()).Name()
+				assert.Equal(t, funcName1, funcName2)
+			}
+
+			gotResp, err := s.AssessEvidence(tt.args.in0, tt.args.evidence)
+
+			// That isn´t nice, but we have somehow to wait for the hook functions
+			time.Sleep(3 * time.Second)
+
+			if (err != nil) != tt.wantErr {
+				t.Errorf("StoreAssessmentResult() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(gotResp, tt.wantResp) {
+				t.Errorf("StoreAssessmentResult() gotResp = %v, want %v", gotResp, tt.wantResp)
+			}
+			assert.NotEmpty(t, s.results)
+			assert.Equal(t, 18, hookCallCounter) //
+		})
+	}
+}
+
 func TestListAssessmentResults(t *testing.T) {
 	s := NewService()
 	_, err := s.AssessEvidence(context.TODO(), &assessment.AssessEvidenceRequest{
diff --git a/service/evidence/evidence_store_test.go b/service/evidence/evidence_store_test.go
index efed20dc..fca600eb 100644
--- a/service/evidence/evidence_store_test.go
+++ b/service/evidence/evidence_store_test.go
@@ -4,7 +4,9 @@ import (
 	"context"
 	"io"
 	"reflect"
+	"runtime"
 	"testing"
+	"time"
 
 	"google.golang.org/protobuf/types/known/emptypb"
 	"google.golang.org/protobuf/types/known/structpb"
@@ -71,6 +73,30 @@ func TestStoreEvidence(t *testing.T) {
 			wantErr:  false,
 			wantResp: &evidence.StoreEvidenceResponse{Status: true},
 		},
+		{
+			name: "Store an evidence without toolId to the map",
+			args: args{
+				in0: context.TODO(),
+				req: &evidence.StoreEvidenceRequest{Evidence: &evidence.Evidence{
+					Id:        "MockEvidenceId-1",
+					ServiceId: "MockServiceId-1",
+					Timestamp: timestamppb.Now(),
+					Raw:       "",
+					Resource: toStruct(voc.VirtualMachine{
+						Compute: &voc.Compute{
+							CloudResource: &voc.CloudResource{
+								ID: "mock-id-1",
+							},
+						},
+					}, t),
+				},
+				},
+			},
+			wantErr: true,
+			wantResp: &evidence.StoreEvidenceResponse{
+				Status: false,
+			},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -80,10 +106,16 @@ func TestStoreEvidence(t *testing.T) {
 				t.Errorf("StoreEvidence() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
+
 			if !reflect.DeepEqual(gotResp, tt.wantResp) {
 				t.Errorf("StoreEvidence() gotResp = %v, want %v", gotResp, tt.wantResp)
 			}
-			assert.NotNil(t, s.evidences["MockEvidenceId"])
+
+			if gotResp.Status {
+				assert.NotNil(t, s.evidences["MockEvidenceId"])
+			} else {
+				assert.Empty(t, s.evidences)
+			}
 		})
 	}
 }
@@ -138,6 +170,112 @@ func TestListEvidences(t *testing.T) {
 	assert.Equal(t, 2, len(resp.Evidences))
 }
 
+func TestEvidenceHook(t *testing.T) {
+	var ready1 = make(chan bool)
+	var ready2 = make(chan bool)
+	hookCallCounter := 0
+
+	firstHookFunction := func(evidence *evidence.Evidence, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the firstHookFunction")
+
+		ready1 <- true
+	}
+
+	secondHookFunction := func(evidence *evidence.Evidence, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the secondHookFunction")
+
+		ready2 <- true
+	}
+
+	service := NewService()
+	service.RegisterEvidenceHook(firstHookFunction)
+	service.RegisterEvidenceHook(secondHookFunction)
+
+	// Check if first hook is registered
+	funcName1 := runtime.FuncForPC(reflect.ValueOf(service.EvidenceHook[0]).Pointer()).Name()
+	funcName2 := runtime.FuncForPC(reflect.ValueOf(firstHookFunction).Pointer()).Name()
+	assert.Equal(t, funcName1, funcName2)
+
+	// Check if second hook is registered
+	funcName1 = runtime.FuncForPC(reflect.ValueOf(service.EvidenceHook[1]).Pointer()).Name()
+	funcName2 = runtime.FuncForPC(reflect.ValueOf(secondHookFunction).Pointer()).Name()
+	assert.Equal(t, funcName1, funcName2)
+
+	// Check GRPC call
+	type args struct {
+		in0      context.Context
+		evidence *evidence.StoreEvidenceRequest
+	}
+	tests := []struct {
+		name     string
+		args     args
+		wantResp *evidence.StoreEvidenceResponse
+		wantErr  bool
+	}{
+		{
+			name: "Store an evidence to the map",
+			args: args{
+				in0: context.TODO(),
+				evidence: &evidence.StoreEvidenceRequest{Evidence: &evidence.Evidence{
+					Id:        "MockEvidenceId-1",
+					ServiceId: "MockServiceId-1",
+					Timestamp: timestamppb.Now(),
+					Raw:       "",
+					ToolId:    "mockToolId-1",
+					Resource: toStruct(voc.VirtualMachine{
+						Compute: &voc.Compute{
+							CloudResource: &voc.CloudResource{
+								ID: "mock-id-1",
+							},
+						},
+					}, t),
+				},
+				},
+			},
+			wantErr: false,
+			wantResp: &evidence.StoreEvidenceResponse{
+				Status: true,
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			hookCallCounter = 0
+			s := service
+			gotResp, err := s.StoreEvidence(tt.args.in0, tt.args.evidence)
+
+			//make the test wait
+			select {
+			case <-ready1:
+				break
+			case <-time.After(10 * time.Second):
+				log.Println("Timeout while waiting for first StoreEvidence to be ready")
+			}
+
+			select {
+			case <-ready2:
+				break
+			case <-time.After(10 * time.Second):
+				log.Println("Timeout while waiting for second StoreEvidence to be ready")
+			}
+
+			if (err != nil) != tt.wantErr {
+				t.Errorf("StoreEvidence() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(gotResp, tt.wantResp) {
+				t.Errorf("StoreEvidence() gotResp = %v, want %v", gotResp, tt.wantResp)
+			}
+			assert.NotEmpty(t, s.evidences)
+			assert.Equal(t, 2, hookCallCounter)
+		})
+	}
+
+}
+
 type mockStreamer struct {
 	counter int
 }
diff --git a/service/orchestrator/orchestrator_test.go b/service/orchestrator/orchestrator_test.go
index 45b50f0b..a2f6074d 100644
--- a/service/orchestrator/orchestrator_test.go
+++ b/service/orchestrator/orchestrator_test.go
@@ -27,9 +27,19 @@ package orchestrator_test
 
 import (
 	"context"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/protobuf/types/known/emptypb"
+	"google.golang.org/protobuf/types/known/structpb"
+	"google.golang.org/protobuf/types/known/timestamppb"
+	"io"
 	"io/fs"
+	"k8s.io/apimachinery/pkg/util/json"
+	"log"
 	"os"
+	"reflect"
+	"runtime"
 	"testing"
+	"time"
 
 	"clouditor.io/clouditor/api/assessment"
 	"clouditor.io/clouditor/persistence"
@@ -62,6 +72,109 @@ func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
 
+func TestAssessmentResultHook(t *testing.T) {
+	var ready1 = make(chan bool)
+	var ready2 = make(chan bool)
+	hookCallCounter := 0
+
+	firstHookFunction := func(assessmentResult *assessment.AssessmentResult, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the firstHookFunction")
+
+		ready1 <- true
+	}
+
+	secondHookFunction := func(assessmentResult *assessment.AssessmentResult, err error) {
+		hookCallCounter++
+		log.Println("Hello from inside the secondHookFunction")
+
+		ready2 <- true
+	}
+
+	service := service_orchestrator.NewService()
+	service.RegisterAssessmentResultHook(firstHookFunction)
+	service.RegisterAssessmentResultHook(secondHookFunction)
+
+	// Check if first hook is registered
+	funcName1 := runtime.FuncForPC(reflect.ValueOf(service.AssessmentResultsHook[0]).Pointer()).Name()
+	funcName2 := runtime.FuncForPC(reflect.ValueOf(firstHookFunction).Pointer()).Name()
+	assert.Equal(t, funcName1, funcName2)
+
+	// Check if second hook is registered
+	funcName1 = runtime.FuncForPC(reflect.ValueOf(service.AssessmentResultsHook[1]).Pointer()).Name()
+	funcName2 = runtime.FuncForPC(reflect.ValueOf(secondHookFunction).Pointer()).Name()
+	assert.Equal(t, funcName1, funcName2)
+
+	// Check GRPC call
+	type args struct {
+		in0        context.Context
+		assessment *orchestrator.StoreAssessmentResultRequest
+	}
+	tests := []struct {
+		name     string
+		args     args
+		wantResp *orchestrator.StoreAssessmentResultResponse
+		wantErr  bool
+	}{
+		{
+			name: "Store first assessment result to the map",
+			args: args{
+				in0: context.TODO(),
+				assessment: &orchestrator.StoreAssessmentResultRequest{
+					Result: &assessment.AssessmentResult{
+						Id:         "assessmentResultID",
+						MetricId:   "assessmentResultMetricID",
+						EvidenceId: "evidenceID",
+						Timestamp:  timestamppb.Now(),
+						MetricConfiguration: &assessment.MetricConfiguration{
+							TargetValue: toStruct(1.0),
+							Operator:    "operator",
+							IsDefault:   true,
+						},
+						NonComplianceComments: "non_compliance_comment",
+						Compliant:             true,
+						ResourceId:            "resourceID",
+					},
+				},
+			},
+			wantErr:  false,
+			wantResp: &orchestrator.StoreAssessmentResultResponse{},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			hookCallCounter = 0
+			s := service
+			gotResp, err := s.StoreAssessmentResult(tt.args.in0, tt.args.assessment)
+			//make the test wait
+			select {
+			case <-ready1:
+				break
+			case <-time.After(10 * time.Second):
+				log.Println("Timeout while waiting for first StoreAssessmentResult to be ready")
+			}
+
+			select {
+			case <-ready2:
+				break
+			case <-time.After(10 * time.Second):
+				log.Println("Timeout while waiting for second StoreAssessmentResult to be ready")
+			}
+
+			if (err != nil) != tt.wantErr {
+				t.Errorf("StoreAssessmentResult() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(gotResp, tt.wantResp) {
+				t.Errorf("StoreAssessmentResult() gotResp = %v, want %v", gotResp, tt.wantResp)
+			}
+			assert.NotEmpty(t, s.Results)
+			assert.Equal(t, 2, hookCallCounter)
+		})
+	}
+}
+
 func TestListMetrics(t *testing.T) {
 	var (
 		response *orchestrator.ListMetricsResponse
@@ -104,6 +217,115 @@ func TestGetMetric(t *testing.T) {
 	assert.Equal(t, request.MetricId, metric.Id)
 }
 
+func TestStoreAssessmentResult(t *testing.T) {
+	type args struct {
+		in0        context.Context
+		assessment *orchestrator.StoreAssessmentResultRequest
+	}
+	tests := []struct {
+		name     string
+		args     args
+		wantResp *orchestrator.StoreAssessmentResultResponse
+		wantErr  bool
+	}{
+		{
+			name: "Store assessment to the map",
+			args: args{
+				in0: context.TODO(),
+				assessment: &orchestrator.StoreAssessmentResultRequest{
+					Result: &assessment.AssessmentResult{
+						Id:         "assessmentResultID",
+						MetricId:   "assessmentResultMetricID",
+						EvidenceId: "evidenceID",
+						Timestamp:  timestamppb.Now(),
+						MetricConfiguration: &assessment.MetricConfiguration{
+							TargetValue: toStruct(1.0),
+							Operator:    "operator",
+							IsDefault:   true,
+						},
+						NonComplianceComments: "non_compliance_comment",
+						Compliant:             true,
+						ResourceId:            "resourceID",
+					},
+				},
+			},
+			wantErr:  false,
+			wantResp: &orchestrator.StoreAssessmentResultResponse{},
+		},
+		{
+			name: "Store assessment without metricId to the map",
+			args: args{
+				in0: context.TODO(),
+				assessment: &orchestrator.StoreAssessmentResultRequest{
+					Result: &assessment.AssessmentResult{
+						Id:         "assessmentResultID",
+						EvidenceId: "evidenceID",
+						Timestamp:  timestamppb.Now(),
+						MetricConfiguration: &assessment.MetricConfiguration{
+							TargetValue: toStruct(1.0),
+							Operator:    "operator",
+							IsDefault:   true,
+						},
+						NonComplianceComments: "non_compliance_comment",
+						Compliant:             true,
+						ResourceId:            "resourceID",
+					},
+				},
+			},
+			wantErr:  true,
+			wantResp: &orchestrator.StoreAssessmentResultResponse{},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := service_orchestrator.NewService()
+			gotResp, err := s.StoreAssessmentResult(tt.args.in0, tt.args.assessment)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("StoreAssessmentResult() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(gotResp, tt.wantResp) {
+				t.Errorf("StoreAssessmentResult() gotResp = %v, want %v", gotResp, tt.wantResp)
+			}
+
+			if err == nil {
+				assert.NotNil(t, s.Results["assessmentResultID"])
+			} else {
+				assert.Empty(t, s.Results)
+			}
+		})
+	}
+}
+
+func TestStoreAssessmentResults(t *testing.T) {
+	type args struct {
+		stream orchestrator.Orchestrator_StoreAssessmentResultsServer
+	}
+
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name:    "Store 2 assessment results to the map",
+			args:    args{stream: &mockStreamer{counter: 0}},
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := service_orchestrator.NewService()
+			if err := s.StoreAssessmentResults(tt.args.stream); (err != nil) != tt.wantErr {
+				t.Errorf("StoreAssessmentResults() error = %v, wantErr %v", err, tt.wantErr)
+				assert.Equal(t, 2, len(s.Results))
+			}
+		})
+	}
+}
+
 func TestLoad(t *testing.T) {
 	var err = service_orchestrator.LoadMetrics("notfound.json")
 
@@ -113,3 +335,92 @@ func TestLoad(t *testing.T) {
 
 	assert.Nil(t, err)
 }
+
+type mockStreamer struct {
+	counter int
+}
+
+func (mockStreamer) SendAndClose(_ *emptypb.Empty) error {
+	return nil
+}
+
+func (m *mockStreamer) Recv() (*assessment.AssessmentResult, error) {
+	if m.counter == 0 {
+		m.counter++
+		return &assessment.AssessmentResult{
+			Id:         "assessmentResultID",
+			MetricId:   "assessmentResultMetricID",
+			EvidenceId: "evidenceID",
+			Timestamp:  timestamppb.Now(),
+			MetricConfiguration: &assessment.MetricConfiguration{
+				TargetValue: toStruct(1.0),
+				Operator:    "operator",
+				IsDefault:   true,
+			},
+			NonComplianceComments: "non_compliance_comment",
+			Compliant:             true,
+			ResourceId:            "resourceID",
+		}, nil
+	} else if m.counter == 1 {
+		m.counter++
+		return &assessment.AssessmentResult{
+			Id:         "assessmentResultID2",
+			MetricId:   "assessmentResultMetricID2",
+			EvidenceId: "evidenceID2",
+			Timestamp:  timestamppb.Now(),
+			MetricConfiguration: &assessment.MetricConfiguration{
+				TargetValue: toStruct(1.0),
+				Operator:    "operator2",
+				IsDefault:   false,
+			},
+			NonComplianceComments: "non_compliance_comment",
+			Compliant:             true,
+			ResourceId:            "resourceID",
+		}, nil
+	} else {
+		return nil, io.EOF
+	}
+}
+
+func (mockStreamer) SetHeader(_ metadata.MD) error {
+	panic("implement me")
+}
+
+func (mockStreamer) SendHeader(_ metadata.MD) error {
+	panic("implement me")
+}
+
+func (mockStreamer) SetTrailer(_ metadata.MD) {
+	panic("implement me")
+}
+
+func (mockStreamer) Context() context.Context {
+	panic("implement me")
+}
+
+func (mockStreamer) SendMsg(_ interface{}) error {
+	panic("implement me")
+}
+
+func (mockStreamer) RecvMsg(_ interface{}) error {
+	panic("implement me")
+}
+
+func toStruct(f float32) (s *structpb.Value) {
+	var (
+		b   []byte
+		err error
+	)
+
+	s = new(structpb.Value)
+
+	b, err = json.Marshal(f)
+	if err != nil {
+		return nil
+	}
+	if err = json.Unmarshal(b, &s); err != nil {
+		return nil
+	}
+
+	return
+}