diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 69ef7350..bed8362c 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -24,16 +24,16 @@ jobs: image: worker steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup qemu - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: setup docker buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: login - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -41,15 +41,9 @@ jobs: - name: metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ matrix.image }} - tags: | - type=schedule - type=ref,event=branch - type=ref,event=tag - type=ref,event=pr,prefix=pr- - type=sha,prefix=,format=long - name: create dockerfile.cross run: | @@ -57,7 +51,7 @@ jobs: cat ${{ matrix.dockerfile }}.cross - name: build and push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: platforms: linux/arm64,linux/amd64,linux/s390x,linux/ppc64le file: ${{ matrix.dockerfile }}.cross diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 3ef39196..2c10811a 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup python uses: actions/setup-python@v4 @@ -31,9 +31,9 @@ jobs: python-version: '3.10' - name: setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: '~1.20' + go-version-file: 'go.mod' cache: true - name: install mkdocs and mike diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5874d8df..c1b05cff 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -26,7 +26,7 @@ jobs: needs: [docker] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -36,11 +36,11 @@ jobs: - name: setup go uses: actions/setup-go@v4 with: - go-version: '~1.20' + go-version-file: 'go.mod' cache: true - name: release - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v5 with: distribution: goreleaser version: latest @@ -53,14 +53,14 @@ jobs: needs: [goreleaser] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: main - name: checkout charts - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: undistro/charts.undistro.io + repository: undistro/helm-charts ref: main fetch-depth: 1 token: ${{ secrets.BOT_TOKEN }} # GITHUB_TOKEN is scoped to the current repository, so we need a PAT to checkout a different repository and commit on it. diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f7318f63..8280ff51 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: - go-version: '~1.20' + go-version-file: 'go.mod' cache: true - name: test diff --git a/Makefile b/Makefile index 05b043ac..92dbab36 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ # Image URL to use all building/pushing image targets IMG ?= controller:latest +WORKER_IMG ?= worker:latest + # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.27.1 @@ -33,7 +35,7 @@ all: build .PHONY: help help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) ##@ Development @@ -101,12 +103,16 @@ docker-build: test ## Build docker image with the manager. .PHONY: docker-build-worker docker-build-worker: test ## Build docker image with worker. - docker build -t worker:latest -f cmd/worker/Dockerfile . + docker build -t ${WORKER_IMG} -f cmd/worker/Dockerfile . .PHONY: docker-push docker-push: ## Push docker image with the manager. docker push ${IMG} +.PHONY: docker-push-worker +docker-push-worker: ## Push docker image with worker. + docker push ${WORKER_IMG} + # PLATFORMS defines the target platforms for the manager image be build to provide support to multiple # architectures. (i.e. make docker-buildx IMG=myregistry/myoperator:0.0.1). To use this option you need to: # - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ @@ -130,12 +136,15 @@ ifndef ignore-not-found ignore-not-found = false endif +NAMESPACE ?= zora-system .PHONY: install install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - - @$(KUBECTL) apply -f config/samples/zora_v1alpha1_plugin_popeye_all.yaml - @$(KUBECTL) apply -f config/samples/zora_v1alpha1_plugin_marvin.yaml - @$(KUBECTL) apply -f config/samples/zora_v1alpha1_customcheck_labels.yaml + @$(KUBECTL) create namespace $(NAMESPACE) || true + @$(KUBECTL) apply -f config/samples/zora_v1alpha1_plugin_popeye_all.yaml -n $(NAMESPACE) + @$(KUBECTL) apply -f config/samples/zora_v1alpha1_plugin_marvin.yaml -n $(NAMESPACE) + @$(KUBECTL) apply -f config/samples/zora_v1alpha1_plugin_trivy.yaml -n $(NAMESPACE) + @$(KUBECTL) apply -f config/samples/zora_v1alpha1_customcheck_labels.yaml -n $(NAMESPACE) @$(KUBECTL) apply -f config/rbac/zora_plugins_role.yaml @$(KUBECTL) create -f config/rbac/zora_plugins_role_binding.yaml || true @@ -156,6 +165,18 @@ template: manifests kustomize ## Build kustomize configurations. undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - +##@ Kind + +CLUSTER_NAME ?= kind +.PHONY: kind-create-cluster +kind-create-cluster: kind ## Create a local Kubernetes cluster with Kind + $(KIND) create cluster --name $(CLUSTER_NAME) + +.PHONY: kind-load-images +kind-load-images: kind docker-build docker-build-worker ## Build and load docker images into Kind nodes + $(KIND) load docker-image ${IMG} + $(KIND) load docker-image ${WORKER_IMG} + ##@ Build Dependencies ## Location to install dependencies to @@ -170,10 +191,13 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest ADDLICENSE ?= $(LOCALBIN)/addlicense HELM_DOCS ?= $(LOCALBIN)/helm-docs +KIND ?= $(LOCALBIN)/kind ## Tool Versions KUSTOMIZE_VERSION ?= v5.0.0 CONTROLLER_TOOLS_VERSION ?= v0.11.3 +HELM_DOCS_VERSION ?= v1.11.2 +KIND_VERSION ?= v0.20.0 KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize @@ -202,7 +226,11 @@ $(ADDLICENSE): $(LOCALBIN) test -s $(LOCALBIN)/addlicense || GOBIN=$(LOCALBIN) go install github.com/google/addlicense@latest .PHONY: helm-docs -helm-docs: $(HELM_DOCS) ## Download helm-docs if necessary +helm-docs: $(HELM_DOCS) ## Download helm-docs locally if necessary $(HELM_DOCS): $(LOCALBIN) - test -s $(LOCALBIN)/helm-docs || GOBIN=$(LOCALBIN) go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.8.1 + test -s $(LOCALBIN)/helm-docs || GOBIN=$(LOCALBIN) go install github.com/norwoodj/helm-docs/cmd/helm-docs@$(HELM_DOCS_VERSION) +.PHONY: kind +kind: $(KIND) ## Download kind locally if necessary +$(KIND): $(LOCALBIN) + test -s $(LOCALBIN)/kind || GOBIN=$(LOCALBIN) go install sigs.k8s.io/kind@$(KIND_VERSION) diff --git a/PROJECT b/PROJECT index 83c5c273..97c90883 100644 --- a/PROJECT +++ b/PROJECT @@ -52,4 +52,12 @@ resources: kind: CustomCheck path: github.com/undistro/zora/api/zora/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: undistro.io + group: zora + kind: VulnerabilityReport + path: github.com/undistro/zora/api/zora/v1alpha1 + version: v1alpha1 version: "3" diff --git a/README.md b/README.md index 245b9d6c..c8bda34f 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,19 @@ [![license](https://img.shields.io/github/license/undistro/zora)](https://github.com/undistro/zora/blob/main/LICENSE) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/undistro/zora?display_name=tag&sort=semver&color=blue) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fundistro%2Fzora.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fundistro%2Fzora?ref=badge_shield) +[![slack](https://img.shields.io/badge/Slack-Join-4a154b?logo=slack)](https://join.slack.com/t/undistrocommunity/shared_invite/zt-21slyrao4-dTW_XtOB90QVj05txOX6rA) ## Introduction -Zora is a multi-cluster scan that helps you identify potential issues and vulnerabilities -in your Kubernetes clusters in a centralized way, ensuring that the recommended best practices are in place. +Zora is an open-source solution that helps you achieve compliance with Kubernetes best practices recommended by +industry-leading frameworks. -Zora is the first product created by Undistro's initiative. Visit our [website](https://undistro.io) for more information about the project and sign up for our newsletter to stay up to date with Zora's new features and Undistro's new initiatives. +By scanning your cluster with multiple plugins at scheduled times, Zora identifies potential issues, misconfigurations, +and vulnerabilities. + +_Please [star :star:](https://github.com/undistro/zora/stargazers) the repo if you want us to continue developing and improving Zora!_ :grin: ## Getting Started @@ -27,8 +31,10 @@ Check out our live [documentation](https://zora-docs.undistro.io) for details ab ## Contributing -We are in alpha stage and we'd love it if you contributed to Zora. For information on contributing to this project, please see our [guideline](https://github.com/undistro/zora/blob/main/CONTRIBUTING.md). +Please refer to the [contributing guide](https://github.com/undistro/zora/blob/main/CONTRIBUTING.md) and the +[code of conduct](https://github.com/undistro/zora/blob/main/CODE_OF_CONDUCT.md) +for more information on how to contribute. ## License -Zora is a Undistro product, backed by [Getup.io](https://getup.io) under the [Apache License 2.0](LICENSE). +Zora is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details. diff --git a/api/zora/v1alpha1/clusterissue_types.go b/api/zora/v1alpha1/clusterissue_types.go index 3870ca5c..98c769b5 100644 --- a/api/zora/v1alpha1/clusterissue_types.go +++ b/api/zora/v1alpha1/clusterissue_types.go @@ -69,7 +69,7 @@ type ClusterIssueStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status -//+kubebuilder:resource:shortName="ci" +//+kubebuilder:resource:shortName={issue,issues,misconfig,misconfigs,misconfigurations} //+kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.cluster",priority=0 //+kubebuilder:printcolumn:name="ID",type="string",JSONPath=".spec.id",priority=0 //+kubebuilder:printcolumn:name="Message",type="string",JSONPath=".spec.message",priority=0 diff --git a/api/zora/v1alpha1/clusterscan_types.go b/api/zora/v1alpha1/clusterscan_types.go index fdab5331..ba3ebf0c 100644 --- a/api/zora/v1alpha1/clusterscan_types.go +++ b/api/zora/v1alpha1/clusterscan_types.go @@ -39,16 +39,14 @@ type ClusterScanSpec struct { // The list of Plugin references that are used to scan the referenced Cluster. Defaults to 'popeye' Plugins []PluginReference `json:"plugins,omitempty"` - // SuccessfulScansHistoryLimit specifies the amount of successfully - // completed scan Jobs to be kept in the cluster. This field is analogous - // to from the package. + // The number of successful finished scans and their issues to retain. Value must be non-negative integer. + // Defaults to 3. // +kubebuilder:validation:Minimum=0 // +kubebuilder:default=3 SuccessfulScansHistoryLimit *int32 `json:"successfulScansHistoryLimit,omitempty"` - // FailedScansHistoryLimit specifies the amount of failed scan Jobs to be - // kept in the cluster. This field is analogous to - // from the package. + // The number of failed finished scans to retain. Value must be non-negative integer. + // Defaults to 1. // +kubebuilder:validation:Minimum=0 // +kubebuilder:default=1 FailedScansHistoryLimit *int32 `json:"failedScansHistoryLimit,omitempty"` @@ -61,13 +59,6 @@ type PluginReference struct { // Namespace defines the space within which the Plugin name must be unique. Namespace string `json:"namespace,omitempty"` - // This flag tells the controller to suspend subsequent executions, it does - // not apply to already started executions. Defaults to false. - Suspend *bool `json:"suspend,omitempty"` - - // The schedule in Cron format for this Plugin, see https://en.wikipedia.org/wiki/Cron. - Schedule string `json:"schedule,omitempty"` - // List of environment variables to set in the Plugin container. Env []corev1.EnvVar `json:"env,omitempty"` } @@ -221,19 +212,13 @@ type PluginScanStatus struct { // LastErrorMsg contains a plugin error message from the last failed scan. LastErrorMsg string `json:"lastErrorMsg,omitempty"` - // IssueCount holds the sum of ClusterIssues found in the last successful scan. - IssueCount *int `json:"issueCount,omitempty"` - - // Suspend field value from ClusterScan spec.plugins.*.suspend - Suspend bool `json:"suspend,omitempty"` - - // The Cron schedule of this plugin - Schedule string `json:"schedule,omitempty"` + // TotalIssues holds the sum of ClusterIssues found in the last successful scan. + TotalIssues *int `json:"totalIssues,omitempty"` } //+kubebuilder:object:root=true //+kubebuilder:subresource:status -//+kubebuilder:resource:shortName="cscan" +//+kubebuilder:resource:shortName={scan,scans} //+kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.clusterRef.name",priority=0 //+kubebuilder:printcolumn:name="Schedule",type="string",JSONPath=".spec.schedule",priority=0 //+kubebuilder:printcolumn:name="Suspend",type="boolean",JSONPath=".status.suspend",priority=0 @@ -241,10 +226,9 @@ type PluginScanStatus struct { //+kubebuilder:printcolumn:name="Last Status",type="string",JSONPath=".status.lastStatus",priority=0 //+kubebuilder:printcolumn:name="Last Schedule",type="date",JSONPath=".status.lastScheduleTime",priority=0 //+kubebuilder:printcolumn:name="Last Successful",type="date",JSONPath=".status.lastSuccessfulTime",priority=0 -//+kubebuilder:printcolumn:name="Issues",type="integer",JSONPath=".status.totalIssues",priority=0 //+kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",priority=0 -//+kubebuilder:printcolumn:name="SaaS",type="string",JSONPath=".status.conditions[?(@.type==\"SaaS\")].reason",priority=0 //+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",priority=0 +//+kubebuilder:printcolumn:name="SaaS",type="string",JSONPath=".status.conditions[?(@.type==\"SaaS\")].reason",priority=1 //+kubebuilder:printcolumn:name="Next Schedule",type="string",JSONPath=".status.nextScheduleTime",priority=1 // ClusterScan is the Schema for the clusterscans API diff --git a/api/zora/v1alpha1/clusterscan_types_test.go b/api/zora/v1alpha1/clusterscan_types_test.go index f6c1a51d..fc498a0d 100644 --- a/api/zora/v1alpha1/clusterscan_types_test.go +++ b/api/zora/v1alpha1/clusterscan_types_test.go @@ -440,7 +440,7 @@ func TestSyncStatus(t *testing.T) { css.Plugins = tt.plugins css.SyncStatus() if !reflect.DeepEqual(css, tt.want) { - t.Errorf("SyncStatus() = %s", cmp.Diff(css, tt.want)) + t.Errorf("SyncStatus() mismatch (-want +got):\n%s", cmp.Diff(tt.want, css)) } }) } diff --git a/api/zora/v1alpha1/customcheck_types.go b/api/zora/v1alpha1/customcheck_types.go index c1c2d4ad..2b5b7441 100644 --- a/api/zora/v1alpha1/customcheck_types.go +++ b/api/zora/v1alpha1/customcheck_types.go @@ -58,7 +58,7 @@ type CustomCheckStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status -//+kubebuilder:resource:shortName="checks" +//+kubebuilder:resource:shortName={check,checks} //+kubebuilder:printcolumn:name="Message",type="string",JSONPath=".spec.message",priority=0 //+kubebuilder:printcolumn:name="Severity",type="string",JSONPath=".spec.severity",priority=0 //+kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",priority=0 diff --git a/api/zora/v1alpha1/plugin_types.go b/api/zora/v1alpha1/plugin_types.go index dd38e890..b78791ef 100644 --- a/api/zora/v1alpha1/plugin_types.go +++ b/api/zora/v1alpha1/plugin_types.go @@ -21,6 +21,12 @@ import ( // PluginSpec defines the desired state of Plugin type PluginSpec struct { + + // Indicates what this plugin reports + // +kubebuilder:validation:Enum=misconfiguration;vulnerability + // +kubebuilder:default=misconfiguration + Type string `json:"type"` + // Docker image name. // More info: https://kubernetes.io/docs/concepts/containers/images Image string `json:"image"` @@ -45,7 +51,7 @@ type PluginSpec struct { // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell Args []string `json:"args,omitempty"` - // List of sources to populate environment variables in the container. + // List of sources to populate environment variables in plugin and worker containers. // The keys defined within a source must be a C_IDENTIFIER. All invalid keys // will be reported as an event when the container is starting. When a key exists in multiple // sources, the value associated with the last source will take precedence. @@ -53,7 +59,7 @@ type PluginSpec struct { // Cannot be updated. EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"` - // List of environment variables to set in the container. + // List of environment variables to set in plugin and worker containers. // Cannot be updated. Env []corev1.EnvVar `json:"env,omitempty"` @@ -92,6 +98,7 @@ type PluginStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status //+kubebuilder:printcolumn:name="Image",type="string",JSONPath=".spec.image" +//+kubebuilder:printcolumn:name="Type",type="string",JSONPath=".spec.type" //+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // Plugin is the Schema for the plugins API diff --git a/api/zora/v1alpha1/vulnerabilityreport_types.go b/api/zora/v1alpha1/vulnerabilityreport_types.go new file mode 100644 index 00000000..177cf144 --- /dev/null +++ b/api/zora/v1alpha1/vulnerabilityreport_types.go @@ -0,0 +1,98 @@ +// Copyright 2023 Undistro Authors +// +// 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. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VulnerabilityReportSpec defines the desired state of VulnerabilityReport +type VulnerabilityReportSpec struct { + Cluster string `json:"cluster"` + Image string `json:"image"` + Repository string `json:"repository,omitempty"` + Tag string `json:"tag,omitempty"` + Digest string `json:"digest,omitempty"` + + TotalResources int `json:"totalResources"` + Resources map[string][]string `json:"resources"` + Vulnerabilities []Vulnerability `json:"vulnerabilities"` + + Summary VulnerabilitySummary `json:"summary"` +} + +type Vulnerability struct { + ID string `json:"id"` + Severity string `json:"severity"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Package string `json:"package"` + Version string `json:"version"` + FixVersion string `json:"fixVersion,omitempty"` + URL string `json:"url,omitempty"` + Status string `json:"status,omitempty"` + Type string `json:"type,omitempty"` + Score string `json:"score,omitempty"` +} + +type VulnerabilitySummary struct { + Total int `json:"total"` + + Critical int `json:"critical"` + High int `json:"high"` + Medium int `json:"medium"` + Low int `json:"low"` + Unknown int `json:"unknown"` +} + +// VulnerabilityReportStatus defines the observed state of VulnerabilityReport +type VulnerabilityReportStatus struct{} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:resource:shortName={vuln,vulns,vulnerabilities} +//+kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".spec.cluster",priority=0 +//+kubebuilder:printcolumn:name="Image",type="string",JSONPath=".spec.image",priority=0 +//+kubebuilder:printcolumn:name="Total",type="string",JSONPath=".spec.summary.total",priority=0 +//+kubebuilder:printcolumn:name="Critical",type="string",JSONPath=".spec.summary.critical",priority=0 +//+kubebuilder:printcolumn:name="High",type="string",JSONPath=".spec.summary.high",priority=0 +//+kubebuilder:printcolumn:name="Medium",type="string",JSONPath=".spec.summary.medium",priority=1 +//+kubebuilder:printcolumn:name="Low",type="string",JSONPath=".spec.summary.low",priority=1 +//+kubebuilder:printcolumn:name="Unknown",type="string",JSONPath=".spec.summary.unknown",priority=1 +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",priority=0 + +// VulnerabilityReport is the Schema for the vulnerabilityreports API +// +genclient +// +genclient:noStatus +type VulnerabilityReport struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VulnerabilityReportSpec `json:"spec,omitempty"` + Status VulnerabilityReportStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VulnerabilityReportList contains a list of VulnerabilityReport +type VulnerabilityReportList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VulnerabilityReport `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VulnerabilityReport{}, &VulnerabilityReportList{}) +} diff --git a/api/zora/v1alpha1/zz_generated.deepcopy.go b/api/zora/v1alpha1/zz_generated.deepcopy.go index 00c3f71c..f8ac7a43 100644 --- a/api/zora/v1alpha1/zz_generated.deepcopy.go +++ b/api/zora/v1alpha1/zz_generated.deepcopy.go @@ -568,11 +568,6 @@ func (in *PluginList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PluginReference) DeepCopyInto(out *PluginReference) { *out = *in - if in.Suspend != nil { - in, out := &in.Suspend, &out.Suspend - *out = new(bool) - **out = **in - } if in.Env != nil { in, out := &in.Env, &out.Env *out = make([]v1.EnvVar, len(*in)) @@ -611,8 +606,8 @@ func (in *PluginScanStatus) DeepCopyInto(out *PluginScanStatus) { in, out := &in.NextScheduleTime, &out.NextScheduleTime *out = (*in).DeepCopy() } - if in.IssueCount != nil { - in, out := &in.IssueCount, &out.IssueCount + if in.TotalIssues != nil { + in, out := &in.TotalIssues, &out.TotalIssues *out = new(int) **out = **in } @@ -729,3 +724,143 @@ func (in *Validation) DeepCopy() *Validation { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Vulnerability) DeepCopyInto(out *Vulnerability) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Vulnerability. +func (in *Vulnerability) DeepCopy() *Vulnerability { + if in == nil { + return nil + } + out := new(Vulnerability) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VulnerabilityReport) DeepCopyInto(out *VulnerabilityReport) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VulnerabilityReport. +func (in *VulnerabilityReport) DeepCopy() *VulnerabilityReport { + if in == nil { + return nil + } + out := new(VulnerabilityReport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VulnerabilityReport) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VulnerabilityReportList) DeepCopyInto(out *VulnerabilityReportList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VulnerabilityReport, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VulnerabilityReportList. +func (in *VulnerabilityReportList) DeepCopy() *VulnerabilityReportList { + if in == nil { + return nil + } + out := new(VulnerabilityReportList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VulnerabilityReportList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VulnerabilityReportSpec) DeepCopyInto(out *VulnerabilityReportSpec) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + if in.Vulnerabilities != nil { + in, out := &in.Vulnerabilities, &out.Vulnerabilities + *out = make([]Vulnerability, len(*in)) + copy(*out, *in) + } + out.Summary = in.Summary +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VulnerabilityReportSpec. +func (in *VulnerabilityReportSpec) DeepCopy() *VulnerabilityReportSpec { + if in == nil { + return nil + } + out := new(VulnerabilityReportSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VulnerabilityReportStatus) DeepCopyInto(out *VulnerabilityReportStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VulnerabilityReportStatus. +func (in *VulnerabilityReportStatus) DeepCopy() *VulnerabilityReportStatus { + if in == nil { + return nil + } + out := new(VulnerabilityReportStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VulnerabilitySummary) DeepCopyInto(out *VulnerabilitySummary) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VulnerabilitySummary. +func (in *VulnerabilitySummary) DeepCopy() *VulnerabilitySummary { + if in == nil { + return nil + } + out := new(VulnerabilitySummary) + in.DeepCopyInto(out) + return out +} diff --git a/charts/zora/Chart.yaml b/charts/zora/Chart.yaml index 93420537..40b01d1c 100644 --- a/charts/zora/Chart.yaml +++ b/charts/zora/Chart.yaml @@ -14,10 +14,10 @@ apiVersion: v2 name: zora -description: Zora scans multiple Kubernetes clusters and reports potential issues. -icon: https://zora-docs.undistro.io/assets/logo.png +description: A multi-plugin solution that reports misconfigurations and vulnerabilities by scanning your cluster at scheduled times. +icon: https://zora-docs.undistro.io/v0.7/assets/logo.svg type: application -version: 0.7.0-rc2 -appVersion: "v0.7.0-rc2" +version: 0.7.0 +appVersion: "v0.7.0" sources: - https://github.com/undistro/zora diff --git a/charts/zora/README.md b/charts/zora/README.md index fa752f5b..6ec942cd 100644 --- a/charts/zora/README.md +++ b/charts/zora/README.md @@ -1,28 +1,27 @@ # Zora Helm Chart -![Version: 0.7.0-rc2](https://img.shields.io/badge/Version-0.7.0--rc2-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.7.0-rc2](https://img.shields.io/badge/AppVersion-v0.7.0--rc2-informational?style=flat-square&color=3CA9DD) +![Version: 0.7.0](https://img.shields.io/badge/Version-0.7.0-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.7.0](https://img.shields.io/badge/AppVersion-v0.7.0-informational?style=flat-square&color=3CA9DD) -Zora scans multiple Kubernetes clusters and reports potential issues. +A multi-plugin solution that reports misconfigurations and vulnerabilities by scanning your cluster at scheduled times. ## Installing the Chart -To install the chart with the release name `zora`: +To install the chart with the release name `zora` in `zora-system` namespace: ```console helm repo add undistro https://charts.undistro.io --force-update +helm repo update undistro helm upgrade --install zora undistro/zora \ -n zora-system \ - --version 0.7.0-rc2 \ - --create-namespace --wait + --version 0.7.0 \ + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" ``` -> The Helm chart repository has been updated from `https://registry.undistro.io/chartrepo/library` to `https://charts.undistro.io`. -> -> The `--force-update` flag is needed to update the repository URL. - -These commands deploy Zora on the Kubernetes cluster in the default configuration. +These commands deploy Zora on the Kubernetes cluster with the default configuration. -The [Parameters](#parameters) section lists the parameters that can be configured during installation. +The [Parameters](#parameters) section lists the available parameters that can be configured during installation. > **Tips:** > @@ -32,7 +31,7 @@ The [Parameters](#parameters) section lists the parameters that can be configure > > - List all versions available of `undistro/zora` chart using `helm search repo undistro/zora --versions` > -> - List all releases using `helm list` +> - List all releases in a specific namespace using `helm list -n zora-system` > > - Get the notes provided by `zora` release using `helm get notes zora -n zora-system` @@ -41,7 +40,7 @@ The [Parameters](#parameters) section lists the parameters that can be configure To uninstall/delete the `zora` release: ```console -$ helm delete zora +helm uninstall zora -n zora-system ``` The command removes all the Kubernetes components associated with the chart and deletes the release. @@ -55,12 +54,13 @@ The following table lists the configurable parameters of the Zora chart and thei | nameOverride | string | `""` | String to partially override fullname template with a string (will prepend the release name) | | fullnameOverride | string | `""` | String to fully override fullname template with a string | | clusterName | string | `""` | Cluster name. Should be set by `kubectl config current-context`. | -| scanSchedule | string | Cron expression for every hour at the current minute + 5 minutes | Cluster scan schedule in Cron format | | saas.workspaceID | string | `""` | Your SaaS workspace ID | | saas.server | string | `"https://zora-dashboard.undistro.io"` | SaaS server URL | -| saas.hooks.image.repository | string | `"curlimages/curl"` | SaaS hooks image repository | -| saas.hooks.image.tag | string | `"7.88.1"` | SaaS hooks image tag | -| saas.hooks.installURL | string | `"{{.Values.saas.server}}/zora/api/v1alpha1/workspaces/{{.Values.saas.workspaceID}}/helmreleases"` | SaaS install hook URL template | +| saas.installURL | string | `"{{.Values.saas.server}}/zora/api/v1alpha1/workspaces/{{.Values.saas.workspaceID}}/helmreleases"` | SaaS URL template to notify installation | +| hooks.install.image.repository | string | `"curlimages/curl"` | Install hook image repository | +| hooks.install.image.tag | string | `"8.2.1"` | Install hook image tag | +| hooks.delete.image.repository | string | `"rancher/kubectl"` | Delete hook image repository | +| hooks.delete.image.tag | string | `"v1.28.2"` | Delete hook image tag | | imageCredentials.create | bool | `false` | Specifies whether the secret should be created by providing credentials | | imageCredentials.registry | string | `"ghcr.io"` | Docker registry host | | imageCredentials.username | string | `""` | Docker registry username | @@ -93,14 +93,24 @@ The following table lists the configurable parameters of the Zora chart and thei | operator.log.level | string | `"info"` | Log level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', or any integer value > 0 which corresponds to custom debug levels of increasing verbosity | | operator.log.stacktraceLevel | string | `"error"` | Log level at and above which stacktraces are captured (one of 'info', 'error' or 'panic') | | operator.log.timeEncoding | string | `"rfc3339"` | Log time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano') | +| scan.misconfiguration.enabled | bool | `true` | Specifies whether misconfiguration scan is enabled | +| scan.misconfiguration.schedule | string | Cron expression for every hour at the current minute + 5 minutes | Cluster scan schedule in Cron format for misconfiguration scan | +| scan.misconfiguration.successfulScansHistoryLimit | int | `1` | The number of successful finished scans and their issues to retain. | +| scan.misconfiguration.plugins | list | `["marvin","popeye"]` | Misconfiguration scanners plugins | +| scan.vulnerability.enabled | bool | `true` | Specifies whether vulnerability scan is enabled | +| scan.vulnerability.schedule | string | Cron expression for every day at the current hour and minute + 5 minutes | Cluster scan schedule in Cron format for vulnerability scan | +| scan.vulnerability.successfulScansHistoryLimit | int | `1` | The number of successful finished scans and their issues to retain. | +| scan.vulnerability.plugins | list | `["trivy"]` | Vulnerability scanners plugins | | scan.worker.image.repository | string | `"ghcr.io/undistro/zora/worker"` | worker image repository | | scan.worker.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion | -| scan.defaultPlugins | list | `["popeye","marvin"]` | Names of the default plugins | -| scan.plugins.marvin.enabled | bool | `true` | Specifies whether the marvin plugin should be created | | scan.plugins.marvin.resources | object | `{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `marvin` container | | scan.plugins.marvin.image.repository | string | `"ghcr.io/undistro/marvin"` | marvin plugin image repository | | scan.plugins.marvin.image.tag | string | `"v0.2.0"` | marvin plugin image tag | -| scan.plugins.popeye.enabled | bool | `true` | Specifies whether the popeye plugin should be created | +| scan.plugins.trivy.ignoreUnfixed | bool | `false` | Specifies whether only fixed vulnerabilities should be reported | +| scan.plugins.trivy.ignoreDescriptions | bool | `false` | Specifies whether vulnerability descriptions should be ignored | +| scan.plugins.trivy.resources | object | `{}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `trivy` container | +| scan.plugins.trivy.image.repository | string | `"ghcr.io/aquasecurity/trivy"` | trivy plugin image repository | +| scan.plugins.trivy.image.tag | string | `"0.45.1"` | trivy plugin image tag | | scan.plugins.popeye.skipInternalResources | bool | `false` | Specifies whether the following resources should be skipped by `popeye` scans. 1. resources from `kube-system`, `kube-public` and `kube-node-lease` namespaces; 2. kubernetes system reserved RBAC (prefixed with `system:`); 3. `kube-root-ca.crt` configmaps; 4. `default` namespace; 5. `default` serviceaccounts; 6. Helm secrets (prefixed with `sh.helm.release`); 7. Zora components. See `popeye` configuration file that is used for this case: https://github.com/undistro/zora/blob/main/charts/zora/templates/plugins/popeye-config.yaml | | scan.plugins.popeye.resources | object | `{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `popeye` container | | scan.plugins.popeye.image.repository | string | `"ghcr.io/undistro/popeye"` | popeye plugin image repository | @@ -112,14 +122,14 @@ The following table lists the configurable parameters of the Zora chart and thei Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, ```console -$ helm install zora \ - --set server.service.port=8080 undistro/zora +helm install zora \ + --set operator.resources.limits.memory=256Mi undistro/zora ``` Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, ```console -$ helm install zora -f values.yaml undistro/zora +helm install zora -f values.yaml undistro/zora ``` > **Tip**: You can use the default [values.yaml](values.yaml) diff --git a/charts/zora/README.md.gotmpl b/charts/zora/README.md.gotmpl index 722ed0cd..f660d51e 100644 --- a/charts/zora/README.md.gotmpl +++ b/charts/zora/README.md.gotmpl @@ -1,9 +1,9 @@ {{- $release := "zora" -}} {{- $namespace := "zora-system" -}} {{- $repoURL := "https://charts.undistro.io" -}} -{{- $oldRepoURL := "https://registry.undistro.io/chartrepo/library" -}} {{- $repoName := "undistro" -}} {{- $title := .Name | title -}} + # {{ $title }} Helm Chart {{ template "chart.deprecationWarning" . }} @@ -14,23 +14,22 @@ ## Installing the Chart -To install the chart with the release name `{{ $release }}`: +To install the chart with the release name `{{ $release }}` in `{{ $namespace }}` namespace: ```console -helm repo add {{ $repoName }} {{ $repoURL }} {{ if $oldRepoURL }}--force-update{{ end }} +helm repo add {{ $repoName }} {{ $repoURL }} --force-update +helm repo update {{ $repoName }} helm upgrade --install {{ $release }} {{ $repoName }}/{{ template "chart.name" . }} \ -n {{ $namespace }} \ --version {{ template "chart.version" . }} \ - --create-namespace --wait + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" ``` -{{ if $oldRepoURL }} -> The Helm chart repository has been updated from `{{ $oldRepoURL }}` to `{{ $repoURL }}`. -> -> The `--force-update` flag is needed to update the repository URL. -{{ end }} -These commands deploy {{ $title }} on the Kubernetes cluster in the default configuration. -The [Parameters](#parameters) section lists the parameters that can be configured during installation. +These commands deploy {{ $title }} on the Kubernetes cluster with the default configuration. + +The [Parameters](#parameters) section lists the available parameters that can be configured during installation. > **Tips:** > @@ -40,7 +39,7 @@ The [Parameters](#parameters) section lists the parameters that can be configure > > - List all versions available of `{{ $repoName }}/{{ $release }}` chart using `helm search repo {{ $repoName }}/{{ $release }} --versions` > -> - List all releases using `helm list` +> - List all releases in a specific namespace using `helm list -n {{ $namespace }}` > > - Get the notes provided by `{{ $release }}` release using `helm get notes {{ $release }} -n {{ $namespace }}` @@ -49,7 +48,7 @@ The [Parameters](#parameters) section lists the parameters that can be configure To uninstall/delete the `{{ $release }}` release: ```console -$ helm delete {{ $release }} +helm uninstall {{ $release }} -n {{ $namespace }} ``` The command removes all the Kubernetes components associated with the chart and deletes the release. @@ -63,14 +62,14 @@ The following table lists the configurable parameters of the {{ $title }} chart Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, ```console -$ helm install {{ $release }} \ - --set server.service.port=8080 {{ $repoName }}/{{ template "chart.name" . }} +helm install {{ $release }} \ + --set operator.resources.limits.memory=256Mi {{ $repoName }}/{{ template "chart.name" . }} ``` Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, ```console -$ helm install {{ $release }} -f values.yaml {{ $repoName }}/{{ template "chart.name" . }} +helm install {{ $release }} -f values.yaml {{ $repoName }}/{{ template "chart.name" . }} ``` > **Tip**: You can use the default [values.yaml](values.yaml) diff --git a/charts/zora/crds/zora.undistro.io_clusterissues.yaml b/charts/zora/crds/zora.undistro.io_clusterissues.yaml index 95145cdc..c6bf2bfe 100644 --- a/charts/zora/crds/zora.undistro.io_clusterissues.yaml +++ b/charts/zora/crds/zora.undistro.io_clusterissues.yaml @@ -27,7 +27,11 @@ spec: listKind: ClusterIssueList plural: clusterissues shortNames: - - ci + - issue + - issues + - misconfig + - misconfigs + - misconfigurations singular: clusterissue scope: Namespaced versions: diff --git a/charts/zora/crds/zora.undistro.io_clusterscans.yaml b/charts/zora/crds/zora.undistro.io_clusterscans.yaml index eaadaa0f..1412fa45 100644 --- a/charts/zora/crds/zora.undistro.io_clusterscans.yaml +++ b/charts/zora/crds/zora.undistro.io_clusterscans.yaml @@ -27,7 +27,8 @@ spec: listKind: ClusterScanList plural: clusterscans shortNames: - - cscan + - scan + - scans singular: clusterscan scope: Namespaced versions: @@ -53,18 +54,16 @@ spec: - jsonPath: .status.lastSuccessfulTime name: Last Successful type: date - - jsonPath: .status.totalIssues - name: Issues - type: integer - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string - - jsonPath: .status.conditions[?(@.type=="SaaS")].reason - name: SaaS - type: string - jsonPath: .metadata.creationTimestamp name: Age type: date + - jsonPath: .status.conditions[?(@.type=="SaaS")].reason + name: SaaS + priority: 1 + type: string - jsonPath: .status.nextScheduleTime name: Next Schedule priority: 1 @@ -100,9 +99,8 @@ spec: x-kubernetes-map-type: atomic failedScansHistoryLimit: default: 1 - description: FailedScansHistoryLimit specifies the amount of failed - scan Jobs to be kept in the cluster. This field is analogous to - from the package. + description: The number of failed finished scans to retain. Value + must be non-negative integer. Defaults to 1. format: int32 minimum: 0 type: integer @@ -238,15 +236,6 @@ spec: description: Namespace defines the space within which the Plugin name must be unique. type: string - schedule: - description: The schedule in Cron format for this Plugin, see - https://en.wikipedia.org/wiki/Cron. - type: string - suspend: - description: This flag tells the controller to suspend subsequent - executions, it does not apply to already started executions. Defaults - to false. - type: boolean required: - name type: object @@ -256,9 +245,8 @@ spec: type: string successfulScansHistoryLimit: default: 3 - description: SuccessfulScansHistoryLimit specifies the amount of successfully - completed scan Jobs to be kept in the cluster. This field is analogous - to from the package. + description: The number of successful finished scans and their issues + to retain. Value must be non-negative integer. Defaults to 3. format: int32 minimum: 0 type: integer @@ -378,10 +366,6 @@ spec: plugins: additionalProperties: properties: - issueCount: - description: IssueCount holds the sum of ClusterIssues found - in the last successful scan. - type: integer lastErrorMsg: description: LastErrorMsg contains a plugin error message from the last failed scan. @@ -419,12 +403,10 @@ spec: description: Time when the next job will schedule. format: date-time type: string - schedule: - description: The Cron schedule of this plugin - type: string - suspend: - description: Suspend field value from ClusterScan spec.plugins.*.suspend - type: boolean + totalIssues: + description: TotalIssues holds the sum of ClusterIssues found + in the last successful scan. + type: integer type: object description: Information of the last scans of plugins type: object diff --git a/charts/zora/crds/zora.undistro.io_customchecks.yaml b/charts/zora/crds/zora.undistro.io_customchecks.yaml index 1a94916f..1909dbc1 100644 --- a/charts/zora/crds/zora.undistro.io_customchecks.yaml +++ b/charts/zora/crds/zora.undistro.io_customchecks.yaml @@ -27,6 +27,7 @@ spec: listKind: CustomCheckList plural: customchecks shortNames: + - check - checks singular: customcheck scope: Namespaced diff --git a/charts/zora/crds/zora.undistro.io_plugins.yaml b/charts/zora/crds/zora.undistro.io_plugins.yaml index 07747e50..d19f1ed3 100644 --- a/charts/zora/crds/zora.undistro.io_plugins.yaml +++ b/charts/zora/crds/zora.undistro.io_plugins.yaml @@ -33,6 +33,9 @@ spec: - jsonPath: .spec.image name: Image type: string + - jsonPath: .spec.type + name: Type + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date @@ -83,8 +86,8 @@ spec: type: string type: array env: - description: List of environment variables to set in the container. - Cannot be updated. + description: List of environment variables to set in plugin and worker + containers. Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -194,11 +197,12 @@ spec: type: array envFrom: description: List of sources to populate environment variables in - the container. The keys defined within a source must be a C_IDENTIFIER. - All invalid keys will be reported as an event when the container - is starting. When a key exists in multiple sources, the value associated - with the last source will take precedence. Values defined by an - Env with a duplicate key will take precedence. Cannot be updated. + plugin and worker containers. The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will be reported as an event + when the container is starting. When a key exists in multiple sources, + the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. items: description: EnvFromSource represents the source of a set of ConfigMaps properties: @@ -454,8 +458,16 @@ spec: type: string type: object type: object + type: + default: misconfiguration + description: Indicates what this plugin reports + enum: + - misconfiguration + - vulnerability + type: string required: - image + - type type: object status: description: PluginStatus defines the observed state of Plugin diff --git a/charts/zora/crds/zora.undistro.io_vulnerabilityreports.yaml b/charts/zora/crds/zora.undistro.io_vulnerabilityreports.yaml new file mode 100644 index 00000000..a9c978f6 --- /dev/null +++ b/charts/zora/crds/zora.undistro.io_vulnerabilityreports.yaml @@ -0,0 +1,176 @@ +# Copyright 2023 Undistro Authors +# +# 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. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: vulnerabilityreports.zora.undistro.io +spec: + group: zora.undistro.io + names: + kind: VulnerabilityReport + listKind: VulnerabilityReportList + plural: vulnerabilityreports + shortNames: + - vuln + - vulns + - vulnerabilities + singular: vulnerabilityreport + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.cluster + name: Cluster + type: string + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .spec.summary.total + name: Total + type: string + - jsonPath: .spec.summary.critical + name: Critical + type: string + - jsonPath: .spec.summary.high + name: High + type: string + - jsonPath: .spec.summary.medium + name: Medium + priority: 1 + type: string + - jsonPath: .spec.summary.low + name: Low + priority: 1 + type: string + - jsonPath: .spec.summary.unknown + name: Unknown + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: VulnerabilityReport is the Schema for the vulnerabilityreports + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VulnerabilityReportSpec defines the desired state of VulnerabilityReport + properties: + cluster: + type: string + digest: + type: string + image: + type: string + repository: + type: string + resources: + additionalProperties: + items: + type: string + type: array + type: object + summary: + properties: + critical: + type: integer + high: + type: integer + low: + type: integer + medium: + type: integer + total: + type: integer + unknown: + type: integer + required: + - critical + - high + - low + - medium + - total + - unknown + type: object + tag: + type: string + totalResources: + type: integer + vulnerabilities: + items: + properties: + description: + type: string + fixVersion: + type: string + id: + type: string + package: + type: string + score: + type: string + severity: + type: string + status: + type: string + title: + type: string + type: + type: string + url: + type: string + version: + type: string + required: + - id + - package + - severity + - title + - version + type: object + type: array + required: + - cluster + - image + - resources + - summary + - totalResources + - vulnerabilities + type: object + status: + description: VulnerabilityReportStatus defines the observed state of VulnerabilityReport + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/zora/templates/NOTES.txt b/charts/zora/templates/NOTES.txt index 8e8fcbec..284e5281 100644 --- a/charts/zora/templates/NOTES.txt +++ b/charts/zora/templates/NOTES.txt @@ -2,15 +2,16 @@ Thank you for installing {{ .Chart.Name | title }} version {{ .Chart.Version }}. {{ if .Values.clusterName -}} Cluster `{{ .Values.clusterName }}` is scheduled to be scanned. Check it by running: - kubectl get cluster,clusterscan -o wide -n {{ .Release.Namespace }} - -Once a cluster is successfully scanned, you can check issues by running: - kubectl get clusterissues -n {{ .Release.Namespace }} - -{{ end -}} + kubectl get cluster,scan -o wide -n {{ .Release.Namespace }} +{{ if or .Values.scan.misconfiguration.enabled .Values.scan.vulnerability.enabled }} +Once the cluster is successfully scanned, you can check issues by running: + kubectl get misconfigurations -n {{ .Release.Namespace }} + kubectl get vulnerabilities -n {{ .Release.Namespace }} +{{- end }} +{{- end }} Visit our documentation for in-depth information: https://zora-docs.undistro.io {{ if .Values.saas.workspaceID -}} -You can see your clusters and issues in SaaS: {{ .Values.saas.server }} +Visit Zora Dashboard to explore your clusters and issues: {{ .Values.saas.server }} {{- end }} diff --git a/charts/zora/templates/_helpers.tpl b/charts/zora/templates/_helpers.tpl index af7792e9..1900e6f1 100644 --- a/charts/zora/templates/_helpers.tpl +++ b/charts/zora/templates/_helpers.tpl @@ -77,16 +77,39 @@ Create the name of the service account to use in Operator {{- end }} {{- end }} -{{- define "imagePullSecret" }} +{{- define "zora.imagePullSecret" }} {{- with .Values.imageCredentials }} {{- printf "{\"auths\":{\"%s\":{\"auth\":\"%s\"}}}" .registry (printf "%s:%s" .username .password | b64enc) | b64enc }} {{- end }} {{- end }} -{{- define "clusterName" }} -{{- regexReplaceAll "\\W+" (required "clusterName is required" .Values.clusterName) "-" }} +{{- define "zora.clusterName" }} +{{- regexReplaceAll "\\W+" (required "`clusterName` is required." .Values.clusterName) "-" }} {{- end }} -{{- define "scanSchedule"}} -{{- default (printf "%d * * * *" (add 5 (now | date "04"))) .Values.scanSchedule }} +{{- define "zora.hourlySchedule" }} +{{- $minute := add 5 (now | date "04") }} +{{- if ge $minute 60 }} +{{- $minute = sub $minute 60 }} +{{- end }} +{{- printf "%d * * * *" $minute }} +{{- end }} + +{{- define "zora.dailySchedule" }} +{{- $hour := (dateInZone "15" (now) "UTC" | int) }} +{{- $minute := add 5 (now | date "04") }} +{{- if ge $minute 60 }} +{{- $minute = sub $minute 60 }} +{{- $hour = add1 $hour }} +{{- end }} +{{- printf "%d %d * * *" $minute $hour }} +{{- end }} + +{{- define "zora.misconfigSchedule" }} +{{- default (include "zora.hourlySchedule" .) .Values.scan.misconfiguration.schedule }} +{{- end }} + + +{{- define "zora.vulnSchedule" }} +{{- default (include "zora.dailySchedule" .) .Values.scan.vulnerability.schedule }} {{- end }} diff --git a/charts/zora/templates/cluster/cluster.yaml b/charts/zora/templates/cluster/cluster.yaml deleted file mode 100644 index 6a24cb8d..00000000 --- a/charts/zora/templates/cluster/cluster.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2023 Undistro Authors -# -# 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. -{{ if .Values.clusterName }} -apiVersion: zora.undistro.io/v1alpha1 -kind: Cluster -metadata: - labels: - {{- include "zora.labels" . | nindent 4 }} - name: {{ include "clusterName" . }} -spec: {} ---- -apiVersion: zora.undistro.io/v1alpha1 -kind: ClusterScan -metadata: - labels: - {{- include "zora.labels" . | nindent 4 }} - name: {{ include "clusterName" . }} -spec: - clusterRef: - name: {{ include "clusterName" . }} - schedule: {{ include "scanSchedule" . | quote }} -{{- end }} diff --git a/charts/zora/templates/clusterscan/clusterscan.yaml b/charts/zora/templates/clusterscan/clusterscan.yaml new file mode 100644 index 00000000..ec45a4cc --- /dev/null +++ b/charts/zora/templates/clusterscan/clusterscan.yaml @@ -0,0 +1,66 @@ +# Copyright 2023 Undistro Authors +# +# 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. +{{- if not (.Capabilities.APIVersions.Has "batch/v1") }} + {{- fail "Required API group `batch/v1` not available." }} +{{- end }} +apiVersion: zora.undistro.io/v1alpha1 +kind: Cluster +metadata: + labels: + zora.undistro.io/default: "true" + {{- include "zora.labels" . | nindent 4 }} + name: {{ include "zora.clusterName" . }} +spec: {} +{{- if .Values.scan.misconfiguration.enabled }} +--- +apiVersion: zora.undistro.io/v1alpha1 +kind: ClusterScan +metadata: + labels: + zora.undistro.io/default: "true" + {{- include "zora.labels" . | nindent 4 }} + name: {{ include "zora.clusterName" . }}-misconfig +spec: + clusterRef: + name: {{ include "zora.clusterName" . }} + schedule: {{ include "zora.misconfigSchedule" . | quote }} + successfulScansHistoryLimit: {{ .Values.scan.misconfiguration.successfulScansHistoryLimit }} + {{- if .Values.scan.misconfiguration.plugins }} + plugins: + {{- range .Values.scan.misconfiguration.plugins }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end }} +{{- if .Values.scan.vulnerability.enabled }} +--- +apiVersion: zora.undistro.io/v1alpha1 +kind: ClusterScan +metadata: + labels: + zora.undistro.io/default: "true" + {{- include "zora.labels" . | nindent 4 }} + name: {{ include "zora.clusterName" . }}-vuln +spec: + clusterRef: + name: {{ include "zora.clusterName" . }} + schedule: {{ include "zora.vulnSchedule" . | quote }} + successfulScansHistoryLimit: {{ .Values.scan.vulnerability.successfulScansHistoryLimit }} + {{- if .Values.scan.vulnerability.plugins }} + plugins: + {{- range .Values.scan.vulnerability.plugins }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/zora/templates/hooks/delete.yaml b/charts/zora/templates/hooks/delete.yaml new file mode 100644 index 00000000..4423000c --- /dev/null +++ b/charts/zora/templates/hooks/delete.yaml @@ -0,0 +1,70 @@ +# Copyright 2023 Undistro Authors +# +# 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. +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: zora-cluster-delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: zora-cluster-delete +rules: + - verbs: [ "get", "list", "delete" ] + apiGroups: [ "zora.undistro.io" ] + resources: [ "clusters" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: zora-cluster-delete +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: zora-cluster-delete +subjects: + - kind: ServiceAccount + name: zora-cluster-delete + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "zora.clusterName" . }}-delete-hook + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded + labels: + {{- include "zora.labels" . | nindent 4 }} +spec: + serviceAccountName: zora-cluster-delete + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + containers: + - name: kubectl + image: {{ .Values.hooks.delete.image.repository }}:{{ .Values.hooks.delete.image.tag }} + imagePullPolicy: IfNotPresent + args: + - delete + - clusters.zora.undistro.io + - {{ include "zora.clusterName" . }} + - --namespace={{ .Release.Namespace }} + - --ignore-not-found=true + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + restartPolicy: Never diff --git a/charts/zora/templates/saas/install.yaml b/charts/zora/templates/hooks/install.yaml similarity index 87% rename from charts/zora/templates/saas/install.yaml rename to charts/zora/templates/hooks/install.yaml index a9bd69c3..6c17751e 100644 --- a/charts/zora/templates/saas/install.yaml +++ b/charts/zora/templates/hooks/install.yaml @@ -16,7 +16,7 @@ apiVersion: v1 kind: Pod metadata: - name: "{{ include "zora.fullname" . }}-saas-install-hook" + name: "{{ include "zora.fullname" . }}-install-hook" labels: {{- include "zora.labels" . | nindent 4 }} annotations: @@ -30,12 +30,12 @@ spec: runAsGroup: 1000 containers: - name: curl - image: {{ .Values.saas.hooks.image.repository }}:{{ .Values.saas.hooks.image.tag }} + image: {{ .Values.hooks.install.image.repository }}:{{ .Values.hooks.install.image.tag }} command: - sh - -xc - | - curl -kfsS -X POST '{{ tpl .Values.saas.hooks.installURL . }}' \ + curl -kfsS -X POST '{{ tpl .Values.saas.installURL . }}' \ -H 'content-type: application/json' \ -d '{{ toJson (dict "kubeVersion" .Capabilities.KubeVersion.GitVersion diff --git a/charts/zora/templates/operator/deployment.yaml b/charts/zora/templates/operator/deployment.yaml index 00771ca7..21a3ca84 100644 --- a/charts/zora/templates/operator/deployment.yaml +++ b/charts/zora/templates/operator/deployment.yaml @@ -70,7 +70,7 @@ spec: - --zap-stacktrace-level={{ .Values.operator.log.stacktraceLevel }} - --zap-time-encoding={{ .Values.operator.log.timeEncoding }} - --default-plugins-namespace={{ .Release.Namespace }} - - --default-plugins-names={{ join "," .Values.scan.defaultPlugins }} + - --default-plugins-names={{ join "," .Values.scan.misconfiguration.plugins }} - --worker-image={{ printf "%s:%s" .Values.scan.worker.image.repository (.Values.scan.worker.image.tag | default .Chart.AppVersion) }} - --cronjob-clusterrolebinding-name=zora-plugins-rolebinding - --cronjob-serviceaccount-name=zora-plugins diff --git a/charts/zora/templates/plugins/marvin.yaml b/charts/zora/templates/plugins/marvin.yaml index 157204ea..fab9e67c 100644 --- a/charts/zora/templates/plugins/marvin.yaml +++ b/charts/zora/templates/plugins/marvin.yaml @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{ if .Values.scan.plugins.marvin.enabled -}} apiVersion: zora.undistro.io/v1alpha1 kind: Plugin metadata: @@ -20,12 +19,17 @@ metadata: labels: {{- include "zora.labels" . | nindent 4 }} spec: + type: misconfiguration image: "{{ .Values.scan.plugins.marvin.image.repository }}:{{ .Values.scan.plugins.marvin.image.tag }}" {{- if .Values.scan.plugins.marvin.resources }} resources: {{- toYaml .Values.scan.plugins.marvin.resources | nindent 4 }} {{- end }} mountCustomChecksVolume: true + securityContext: + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false command: - /bin/sh - -c @@ -45,4 +49,3 @@ spec: end=$(date +%s) echo "Scan has finished in $(($end-$start)) seconds with exit code $exitcode" exit $exitcode -{{- end }} diff --git a/charts/zora/templates/plugins/popeye.yaml b/charts/zora/templates/plugins/popeye.yaml index 61e77fda..b0fdc987 100644 --- a/charts/zora/templates/plugins/popeye.yaml +++ b/charts/zora/templates/plugins/popeye.yaml @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -{{ if .Values.scan.plugins.popeye.enabled -}} apiVersion: zora.undistro.io/v1alpha1 kind: Plugin metadata: @@ -20,6 +19,7 @@ metadata: labels: {{- include "zora.labels" . | nindent 4 }} spec: + type: misconfiguration image: "{{ .Values.scan.plugins.popeye.image.repository }}:{{ .Values.scan.plugins.popeye.image.tag }}" {{- if .Values.scan.plugins.popeye.resources }} resources: @@ -31,6 +31,9 @@ spec: name: popeye-config optional: true {{- end }} + securityContext: + runAsNonRoot: true + allowPrivilegeEscalation: false command: - /bin/sh - -c @@ -63,4 +66,3 @@ spec: end=$(date +%s) echo "Scan has finished in $(($end-$start)) seconds with exit code $exitcode" exit $exitcode -{{- end }} diff --git a/charts/zora/templates/plugins/rbac.yaml b/charts/zora/templates/plugins/rbac.yaml index 375a9666..b6d940e6 100644 --- a/charts/zora/templates/plugins/rbac.yaml +++ b/charts/zora/templates/plugins/rbac.yaml @@ -20,10 +20,12 @@ rules: - apiGroups: [ "zora.undistro.io" ] resources: - clusterissues + - vulnerabilityreports verbs: [ "create", "delete", "get", "list", "patch", "update", "watch" ] - apiGroups: [ "zora.undistro.io" ] resources: - clusterissues/status + - vulnerabilityreports/status verbs: [ "get" ] - apiGroups: [ "" ] resources: @@ -35,6 +37,8 @@ rules: - persistentvolumes - persistentvolumeclaims - pods + - replicationcontrollers + - resourcequotas - secrets - serviceaccounts - services @@ -78,7 +82,6 @@ rules: - cronjobs verbs: [ "get", "list" ] --- -{{ $crb := (lookup "rbac.authorization.k8s.io/v1" "ClusterRoleBinding" "" "zora-plugins-rolebinding") }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -91,6 +94,7 @@ subjects: - kind: ServiceAccount name: {{ include "zora.operatorServiceAccountName" . }} namespace: {{ .Release.Namespace }} + {{- $crb := (lookup "rbac.authorization.k8s.io/v1" "ClusterRoleBinding" "" "zora-plugins-rolebinding") }} {{- range $s := $crb.subjects }} - kind: {{ $s.kind }} name: {{ $s.name }} diff --git a/charts/zora/templates/plugins/trivy.yaml b/charts/zora/templates/plugins/trivy.yaml new file mode 100644 index 00000000..22c344c9 --- /dev/null +++ b/charts/zora/templates/plugins/trivy.yaml @@ -0,0 +1,58 @@ +# Copyright 2023 Undistro Authors +# +# 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. + +apiVersion: zora.undistro.io/v1alpha1 +kind: Plugin +metadata: + name: trivy + labels: + {{- include "zora.labels" . | nindent 4 }} +spec: + type: vulnerability + image: "{{ .Values.scan.plugins.trivy.image.repository }}:{{ .Values.scan.plugins.trivy.image.tag }}" + {{- if .Values.scan.plugins.trivy.resources }} + resources: + {{- toYaml .Values.scan.plugins.trivy.resources | nindent 4 }} + {{- end }} + mountCustomChecksVolume: false + securityContext: + allowPrivilegeEscalation: false + env: + - name: TRIVY_IGNORE_VULN_DESCRIPTIONS + value: {{ .Values.scan.plugins.trivy.ignoreDescriptions | quote }} + command: + - /bin/sh + - -c + - | + time trivy k8s \ + --debug \ + --no-progress \ + --all-namespaces \ + --scanners=vuln \ + --report=summary \ + -f=json \ + {{- if .Values.scan.plugins.trivy.ignoreUnfixed }} + --ignore-unfixed \ + {{- end }} + -o $(DONE_DIR)/results.json \ + cluster + + exitcode=$(echo $?) + if [ $exitcode -ne 0 ]; then + echo "ERROR" > $(DONE_DIR)/error + else + echo $(DONE_DIR)/results.json > $(DONE_DIR)/done + fi + ls -lh $(DONE_DIR)/ + exit $exitcode diff --git a/charts/zora/templates/secrets/docker-registry-cred.yaml b/charts/zora/templates/secrets/docker-registry-cred.yaml index bce38282..e8abcd7b 100644 --- a/charts/zora/templates/secrets/docker-registry-cred.yaml +++ b/charts/zora/templates/secrets/docker-registry-cred.yaml @@ -19,5 +19,5 @@ metadata: name: {{ include "zora.fullname" . }}-registry-cred type: kubernetes.io/dockerconfigjson data: - .dockerconfigjson: {{ template "imagePullSecret" . }} + .dockerconfigjson: {{ template "zora.imagePullSecret" . }} {{- end }} diff --git a/charts/zora/values.yaml b/charts/zora/values.yaml index c806ce45..44aeafae 100644 --- a/charts/zora/values.yaml +++ b/charts/zora/values.yaml @@ -20,23 +20,27 @@ fullnameOverride: "" # -- Cluster name. Should be set by `kubectl config current-context`. clusterName: "" -# -- Cluster scan schedule in Cron format -# @default -- Cron expression for every hour at the current minute + 5 minutes -scanSchedule: "" - saas: # -- Your SaaS workspace ID workspaceID: "" # -- SaaS server URL server: "https://zora-dashboard.undistro.io" - hooks: + # -- SaaS URL template to notify installation + installURL: "{{.Values.saas.server}}/zora/api/v1alpha1/workspaces/{{.Values.saas.workspaceID}}/helmreleases" + +hooks: + install: image: - # -- SaaS hooks image repository + # -- Install hook image repository repository: curlimages/curl - # -- SaaS hooks image tag - tag: '7.88.1' - # -- SaaS install hook URL template - installURL: "{{.Values.saas.server}}/zora/api/v1alpha1/workspaces/{{.Values.saas.workspaceID}}/helmreleases" + # -- Install hook image tag + tag: '8.2.1' + delete: + image: + # -- Delete hook image repository + repository: rancher/kubectl + # -- Delete hook image tag + tag: 'v1.28.2' # Credentials for private registries. imageCredentials: @@ -141,20 +145,37 @@ operator: timeEncoding: rfc3339 scan: + misconfiguration: + # -- Specifies whether misconfiguration scan is enabled + enabled: true + # -- Cluster scan schedule in Cron format for misconfiguration scan + # @default -- Cron expression for every hour at the current minute + 5 minutes + schedule: "" + # -- The number of successful finished scans and their issues to retain. + successfulScansHistoryLimit: 1 + # -- Misconfiguration scanners plugins + plugins: + - marvin + - popeye + vulnerability: + # -- Specifies whether vulnerability scan is enabled + enabled: true + # -- Cluster scan schedule in Cron format for vulnerability scan + # @default -- Cron expression for every day at the current hour and minute + 5 minutes + schedule: "" + # -- The number of successful finished scans and their issues to retain. + successfulScansHistoryLimit: 1 + # -- Vulnerability scanners plugins + plugins: + - trivy worker: image: # -- worker image repository repository: ghcr.io/undistro/zora/worker # -- Overrides the image tag whose default is the chart appVersion tag: "" - # -- Names of the default plugins - defaultPlugins: - - popeye - - marvin plugins: marvin: - # -- Specifies whether the marvin plugin should be created - enabled: true # -- [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `marvin` container resources: requests: @@ -169,9 +190,19 @@ scan: # -- marvin plugin image tag tag: v0.2.0 + trivy: + # -- Specifies whether only fixed vulnerabilities should be reported + ignoreUnfixed: false + # -- Specifies whether vulnerability descriptions should be ignored + ignoreDescriptions: false + # -- [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `trivy` container + resources: {} + image: + # -- trivy plugin image repository + repository: ghcr.io/aquasecurity/trivy + # -- trivy plugin image tag + tag: 0.45.1 popeye: - # -- Specifies whether the popeye plugin should be created - enabled: true # -- Specifies whether the following resources should be skipped by `popeye` scans. # 1. resources from `kube-system`, `kube-public` and `kube-node-lease` namespaces; # 2. kubernetes system reserved RBAC (prefixed with `system:`); diff --git a/cmd/main.go b/cmd/main.go index e11d8a48..a6fd66ad 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -79,7 +79,7 @@ func main() { flag.StringVar(&cronJobServiceAccount, "cronjob-serviceaccount-name", "zora-plugins", "Name of ServiceAccount to be configured, appended to ClusterRoleBinding and used by CronJobs") flag.StringVar(&saasWorkspaceID, "saas-workspace-id", "", "Your workspace ID in Zora SaaS") flag.StringVar(&saasServer, "saas-server", "http://localhost:3003", "Address for Zora's saas server") - flag.StringVar(&version, "version", "0.6.2", "Zora version") + flag.StringVar(&version, "version", "0.7.0", "Zora version") flag.StringVar(&checksConfigMapNamespace, "checks-configmap-namespace", "zora-system", "Namespace of custom checks ConfigMap") flag.StringVar(&checksConfigMapName, "checks-configmap-name", "zora-custom-checks", "Name of custom checks ConfigMap") flag.StringVar(&kubexnsImage, "kubexns-image", "ghcr.io/undistro/kubexns:latest", "kubexns image") diff --git a/config/crd/bases/zora.undistro.io_clusterissues.yaml b/config/crd/bases/zora.undistro.io_clusterissues.yaml index dcdd44ec..8da8b890 100644 --- a/config/crd/bases/zora.undistro.io_clusterissues.yaml +++ b/config/crd/bases/zora.undistro.io_clusterissues.yaml @@ -13,7 +13,11 @@ spec: listKind: ClusterIssueList plural: clusterissues shortNames: - - ci + - issue + - issues + - misconfig + - misconfigs + - misconfigurations singular: clusterissue scope: Namespaced versions: diff --git a/config/crd/bases/zora.undistro.io_clusterscans.yaml b/config/crd/bases/zora.undistro.io_clusterscans.yaml index 8b936dcc..b89bd05a 100644 --- a/config/crd/bases/zora.undistro.io_clusterscans.yaml +++ b/config/crd/bases/zora.undistro.io_clusterscans.yaml @@ -13,7 +13,8 @@ spec: listKind: ClusterScanList plural: clusterscans shortNames: - - cscan + - scan + - scans singular: clusterscan scope: Namespaced versions: @@ -39,18 +40,16 @@ spec: - jsonPath: .status.lastSuccessfulTime name: Last Successful type: date - - jsonPath: .status.totalIssues - name: Issues - type: integer - jsonPath: .status.conditions[?(@.type=="Ready")].status name: Ready type: string - - jsonPath: .status.conditions[?(@.type=="SaaS")].reason - name: SaaS - type: string - jsonPath: .metadata.creationTimestamp name: Age type: date + - jsonPath: .status.conditions[?(@.type=="SaaS")].reason + name: SaaS + priority: 1 + type: string - jsonPath: .status.nextScheduleTime name: Next Schedule priority: 1 @@ -86,9 +85,8 @@ spec: x-kubernetes-map-type: atomic failedScansHistoryLimit: default: 1 - description: FailedScansHistoryLimit specifies the amount of failed - scan Jobs to be kept in the cluster. This field is analogous to - from the package. + description: The number of failed finished scans to retain. Value + must be non-negative integer. Defaults to 1. format: int32 minimum: 0 type: integer @@ -224,15 +222,6 @@ spec: description: Namespace defines the space within which the Plugin name must be unique. type: string - schedule: - description: The schedule in Cron format for this Plugin, see - https://en.wikipedia.org/wiki/Cron. - type: string - suspend: - description: This flag tells the controller to suspend subsequent - executions, it does not apply to already started executions. Defaults - to false. - type: boolean required: - name type: object @@ -242,9 +231,8 @@ spec: type: string successfulScansHistoryLimit: default: 3 - description: SuccessfulScansHistoryLimit specifies the amount of successfully - completed scan Jobs to be kept in the cluster. This field is analogous - to from the package. + description: The number of successful finished scans and their issues + to retain. Value must be non-negative integer. Defaults to 3. format: int32 minimum: 0 type: integer @@ -364,10 +352,6 @@ spec: plugins: additionalProperties: properties: - issueCount: - description: IssueCount holds the sum of ClusterIssues found - in the last successful scan. - type: integer lastErrorMsg: description: LastErrorMsg contains a plugin error message from the last failed scan. @@ -405,12 +389,10 @@ spec: description: Time when the next job will schedule. format: date-time type: string - schedule: - description: The Cron schedule of this plugin - type: string - suspend: - description: Suspend field value from ClusterScan spec.plugins.*.suspend - type: boolean + totalIssues: + description: TotalIssues holds the sum of ClusterIssues found + in the last successful scan. + type: integer type: object description: Information of the last scans of plugins type: object diff --git a/config/crd/bases/zora.undistro.io_customchecks.yaml b/config/crd/bases/zora.undistro.io_customchecks.yaml index d8f2bdfd..939e936c 100644 --- a/config/crd/bases/zora.undistro.io_customchecks.yaml +++ b/config/crd/bases/zora.undistro.io_customchecks.yaml @@ -13,6 +13,7 @@ spec: listKind: CustomCheckList plural: customchecks shortNames: + - check - checks singular: customcheck scope: Namespaced diff --git a/config/crd/bases/zora.undistro.io_plugins.yaml b/config/crd/bases/zora.undistro.io_plugins.yaml index 66c425f5..9b1d5903 100644 --- a/config/crd/bases/zora.undistro.io_plugins.yaml +++ b/config/crd/bases/zora.undistro.io_plugins.yaml @@ -19,6 +19,9 @@ spec: - jsonPath: .spec.image name: Image type: string + - jsonPath: .spec.type + name: Type + type: string - jsonPath: .metadata.creationTimestamp name: Age type: date @@ -69,8 +72,8 @@ spec: type: string type: array env: - description: List of environment variables to set in the container. - Cannot be updated. + description: List of environment variables to set in plugin and worker + containers. Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -180,11 +183,12 @@ spec: type: array envFrom: description: List of sources to populate environment variables in - the container. The keys defined within a source must be a C_IDENTIFIER. - All invalid keys will be reported as an event when the container - is starting. When a key exists in multiple sources, the value associated - with the last source will take precedence. Values defined by an - Env with a duplicate key will take precedence. Cannot be updated. + plugin and worker containers. The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will be reported as an event + when the container is starting. When a key exists in multiple sources, + the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. items: description: EnvFromSource represents the source of a set of ConfigMaps properties: @@ -440,8 +444,16 @@ spec: type: string type: object type: object + type: + default: misconfiguration + description: Indicates what this plugin reports + enum: + - misconfiguration + - vulnerability + type: string required: - image + - type type: object status: description: PluginStatus defines the observed state of Plugin diff --git a/config/crd/bases/zora.undistro.io_vulnerabilityreports.yaml b/config/crd/bases/zora.undistro.io_vulnerabilityreports.yaml new file mode 100644 index 00000000..cf30e827 --- /dev/null +++ b/config/crd/bases/zora.undistro.io_vulnerabilityreports.yaml @@ -0,0 +1,162 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: vulnerabilityreports.zora.undistro.io +spec: + group: zora.undistro.io + names: + kind: VulnerabilityReport + listKind: VulnerabilityReportList + plural: vulnerabilityreports + shortNames: + - vuln + - vulns + - vulnerabilities + singular: vulnerabilityreport + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.cluster + name: Cluster + type: string + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .spec.summary.total + name: Total + type: string + - jsonPath: .spec.summary.critical + name: Critical + type: string + - jsonPath: .spec.summary.high + name: High + type: string + - jsonPath: .spec.summary.medium + name: Medium + priority: 1 + type: string + - jsonPath: .spec.summary.low + name: Low + priority: 1 + type: string + - jsonPath: .spec.summary.unknown + name: Unknown + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: VulnerabilityReport is the Schema for the vulnerabilityreports + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VulnerabilityReportSpec defines the desired state of VulnerabilityReport + properties: + cluster: + type: string + digest: + type: string + image: + type: string + repository: + type: string + resources: + additionalProperties: + items: + type: string + type: array + type: object + summary: + properties: + critical: + type: integer + high: + type: integer + low: + type: integer + medium: + type: integer + total: + type: integer + unknown: + type: integer + required: + - critical + - high + - low + - medium + - total + - unknown + type: object + tag: + type: string + totalResources: + type: integer + vulnerabilities: + items: + properties: + description: + type: string + fixVersion: + type: string + id: + type: string + package: + type: string + score: + type: string + severity: + type: string + status: + type: string + title: + type: string + type: + type: string + url: + type: string + version: + type: string + required: + - id + - package + - severity + - title + - version + type: object + type: array + required: + - cluster + - image + - resources + - summary + - totalResources + - vulnerabilities + type: object + status: + description: VulnerabilityReportStatus defines the observed state of VulnerabilityReport + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 852cc2fe..b475eaa7 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -7,6 +7,7 @@ resources: - bases/zora.undistro.io_clusterissues.yaml - bases/zora.undistro.io_clusterscans.yaml - bases/zora.undistro.io_customchecks.yaml +- bases/zora.undistro.io_vulnerabilityreports.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -17,6 +18,7 @@ patchesStrategicMerge: #- path: patches/webhook_in_clusterissues.yaml #- path: patches/webhook_in_clusterscans.yaml #- path: patches/webhook_in_customchecks.yaml +#- path: patches/webhook_in_vulnerabilityreports.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -26,6 +28,7 @@ patchesStrategicMerge: #- path: patches/cainjection_in_clusterissues.yaml #- path: patches/cainjection_in_clusterscans.yaml #- path: patches/cainjection_in_customchecks.yaml +#- path: patches/cainjection_in_vulnerabilityreports.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_zora_vulnerabilityreports.yaml b/config/crd/patches/cainjection_in_zora_vulnerabilityreports.yaml new file mode 100644 index 00000000..529e23ea --- /dev/null +++ b/config/crd/patches/cainjection_in_zora_vulnerabilityreports.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: vulnerabilityreports.zora.undistro.io diff --git a/config/crd/patches/webhook_in_zora_vulnerabilityreports.yaml b/config/crd/patches/webhook_in_zora_vulnerabilityreports.yaml new file mode 100644 index 00000000..10e579d7 --- /dev/null +++ b/config/crd/patches/webhook_in_zora_vulnerabilityreports.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vulnerabilityreports.zora.undistro.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index f269a8f9..1c3ca96f 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -202,3 +202,21 @@ rules: - get - list - watch +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports/status + verbs: + - get diff --git a/config/rbac/zora_plugins_role.yaml b/config/rbac/zora_plugins_role.yaml index 819e159f..a19d1582 100644 --- a/config/rbac/zora_plugins_role.yaml +++ b/config/rbac/zora_plugins_role.yaml @@ -27,10 +27,12 @@ rules: - apiGroups: [ "zora.undistro.io" ] resources: - clusterissues + - vulnerabilityreports verbs: [ "create", "delete", "get", "list", "patch", "update", "watch" ] - apiGroups: [ "zora.undistro.io" ] resources: - clusterissues/status + - vulnerabilityreports/status verbs: [ "get" ] - apiGroups: [ "" ] resources: @@ -42,6 +44,8 @@ rules: - persistentvolumes - persistentvolumeclaims - pods + - replicationcontrollers + - resourcequotas - secrets - serviceaccounts - services diff --git a/config/rbac/zora_vulnerabilityreport_editor_role.yaml b/config/rbac/zora_vulnerabilityreport_editor_role.yaml new file mode 100644 index 00000000..fb3c5861 --- /dev/null +++ b/config/rbac/zora_vulnerabilityreport_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit vulnerabilityreports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: vulnerabilityreport-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zora + app.kubernetes.io/part-of: zora + app.kubernetes.io/managed-by: kustomize + name: vulnerabilityreport-editor-role +rules: +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports/status + verbs: + - get diff --git a/config/rbac/zora_vulnerabilityreport_viewer_role.yaml b/config/rbac/zora_vulnerabilityreport_viewer_role.yaml new file mode 100644 index 00000000..dda9e408 --- /dev/null +++ b/config/rbac/zora_vulnerabilityreport_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view vulnerabilityreports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: vulnerabilityreport-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zora + app.kubernetes.io/part-of: zora + app.kubernetes.io/managed-by: kustomize + name: vulnerabilityreport-viewer-role +rules: +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports + verbs: + - get + - list + - watch +- apiGroups: + - zora.undistro.io + resources: + - vulnerabilityreports/status + verbs: + - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 83f174b2..dcb14227 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -5,4 +5,5 @@ resources: - zora_v1alpha1_clusterissue.yaml - zora_v1alpha1_clusterscan.yaml - zora_v1alpha1_customcheck.yaml +- zora_v1alpha1_vulnerabilityreport.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/zora_v1alpha1_clusterscan.yaml b/config/samples/zora_v1alpha1_clusterscan_misconfig.yaml similarity index 70% rename from config/samples/zora_v1alpha1_clusterscan.yaml rename to config/samples/zora_v1alpha1_clusterscan_misconfig.yaml index a013728b..1f07258c 100644 --- a/config/samples/zora_v1alpha1_clusterscan.yaml +++ b/config/samples/zora_v1alpha1_clusterscan_misconfig.yaml @@ -3,12 +3,15 @@ kind: ClusterScan metadata: labels: app.kubernetes.io/name: clusterscan - app.kubernetes.io/instance: mycluster + app.kubernetes.io/instance: mycluster-misconfig app.kubernetes.io/part-of: zora app.kubernetes.io/managed-by: kustomize app.kubernetes.io/created-by: zora - name: mycluster + name: mycluster-misconfig spec: clusterRef: name: mycluster schedule: "*/2 * * * *" + plugins: + - name: marvin + - name: popeye diff --git a/config/samples/zora_v1alpha1_clusterscan_vuln.yaml b/config/samples/zora_v1alpha1_clusterscan_vuln.yaml new file mode 100644 index 00000000..615e2f4e --- /dev/null +++ b/config/samples/zora_v1alpha1_clusterscan_vuln.yaml @@ -0,0 +1,16 @@ +apiVersion: zora.undistro.io/v1alpha1 +kind: ClusterScan +metadata: + labels: + app.kubernetes.io/name: clusterscan + app.kubernetes.io/instance: mycluster-vuln + app.kubernetes.io/part-of: zora + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zora + name: mycluster-vuln +spec: + clusterRef: + name: mycluster + schedule: "*/10 * * * *" + plugins: + - name: trivy diff --git a/config/samples/zora_v1alpha1_plugin_marvin.yaml b/config/samples/zora_v1alpha1_plugin_marvin.yaml index 6f5256e7..495dd427 100644 --- a/config/samples/zora_v1alpha1_plugin_marvin.yaml +++ b/config/samples/zora_v1alpha1_plugin_marvin.yaml @@ -9,12 +9,17 @@ metadata: app.kubernetes.io/created-by: zora name: marvin spec: + type: misconfiguration image: ghcr.io/undistro/marvin:v0.2.0 resources: limits: cpu: 500m memory: 100Mi mountCustomChecksVolume: true + securityContext: + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false command: - /bin/sh - -c diff --git a/config/samples/zora_v1alpha1_plugin_popeye.yaml b/config/samples/zora_v1alpha1_plugin_popeye.yaml index 53f9d757..83b79d06 100644 --- a/config/samples/zora_v1alpha1_plugin_popeye.yaml +++ b/config/samples/zora_v1alpha1_plugin_popeye.yaml @@ -9,6 +9,7 @@ metadata: app.kubernetes.io/created-by: zora name: popeye spec: + type: misconfiguration image: ghcr.io/undistro/popeye:pr252 resources: limits: @@ -69,6 +70,9 @@ spec: codes: [1109] policy/v1/poddisruptionbudgets: - name: 'rx:^kube-(system|public|node-lease)' + securityContext: + runAsNonRoot: true + allowPrivilegeEscalation: false command: - /bin/sh - -c diff --git a/config/samples/zora_v1alpha1_plugin_popeye_all.yaml b/config/samples/zora_v1alpha1_plugin_popeye_all.yaml index b6533867..b1aab56c 100644 --- a/config/samples/zora_v1alpha1_plugin_popeye_all.yaml +++ b/config/samples/zora_v1alpha1_plugin_popeye_all.yaml @@ -9,11 +9,15 @@ metadata: app.kubernetes.io/created-by: zora name: popeye spec: + type: misconfiguration image: ghcr.io/undistro/popeye:pr252 resources: limits: cpu: 500m memory: 100Mi + securityContext: + runAsNonRoot: true + allowPrivilegeEscalation: false command: - /bin/sh - -c diff --git a/config/samples/zora_v1alpha1_plugin_trivy.yaml b/config/samples/zora_v1alpha1_plugin_trivy.yaml new file mode 100644 index 00000000..019f9991 --- /dev/null +++ b/config/samples/zora_v1alpha1_plugin_trivy.yaml @@ -0,0 +1,40 @@ +apiVersion: zora.undistro.io/v1alpha1 +kind: Plugin +metadata: + labels: + app.kubernetes.io/name: plugin + app.kubernetes.io/instance: trivy + app.kubernetes.io/part-of: zora + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zora + name: trivy +spec: + type: vulnerability + image: ghcr.io/aquasecurity/trivy:0.45.1 + securityContext: + allowPrivilegeEscalation: false + env: + - name: TRIVY_IGNORE_VULN_DESCRIPTIONS + value: "false" + command: + - /bin/sh + - -c + - | + time trivy k8s \ + --debug \ + --no-progress \ + --all-namespaces \ + --scanners=vuln \ + --report=summary \ + -f=json \ + -o $(DONE_DIR)/results.json \ + cluster + + exitcode=$(echo $?) + if [ $exitcode -ne 0 ]; then + echo "ERROR" > $(DONE_DIR)/error + else + echo $(DONE_DIR)/results.json > $(DONE_DIR)/done + fi + ls -lh $(DONE_DIR)/ + exit $exitcode diff --git a/config/samples/zora_v1alpha1_vulnerabilityreport.yaml b/config/samples/zora_v1alpha1_vulnerabilityreport.yaml new file mode 100644 index 00000000..ef79bb2f --- /dev/null +++ b/config/samples/zora_v1alpha1_vulnerabilityreport.yaml @@ -0,0 +1,12 @@ +apiVersion: zora.undistro.io/v1alpha1 +kind: VulnerabilityReport +metadata: + labels: + app.kubernetes.io/name: vulnerabilityreport + app.kubernetes.io/instance: vulnerabilityreport-sample + app.kubernetes.io/part-of: zora + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zora + name: vulnerabilityreport-sample +spec: + # TODO(user): Add fields here diff --git a/docs/assets/arch-dark.png b/docs/assets/arch-dark.png deleted file mode 100644 index 26d8a380..00000000 Binary files a/docs/assets/arch-dark.png and /dev/null differ diff --git a/docs/assets/arch-v2.excalidraw b/docs/assets/arch-v2.excalidraw new file mode 100644 index 00000000..8bf7d73f --- /dev/null +++ b/docs/assets/arch-v2.excalidraw @@ -0,0 +1,4427 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 458, + "versionNonce": 1524642970, + "isDeleted": false, + "id": "kazCVxHNA0eekdhv7Rpw5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 371.9819284532, + "y": 176.82361842326873, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 1332.1286124999742, + "height": 594.7797000283124, + "seed": 1124732645, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false + }, + { + "type": "line", + "version": 1091, + "versionNonce": 1776187910, + "isDeleted": false, + "id": "WC49nuUGu5gEyo8jj-6jT", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 421.14781330273377, + "y": 116.23121780836101, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 143.56691674203188, + "height": 140.52280016029513, + "seed": 1091782292, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -59.25953584671103, + 28.345800890703305 + ], + [ + -71.47799684603292, + 88.95756662507951 + ], + [ + -30.54615249830468, + 140.52280016029513 + ], + [ + 38.182690622880806, + 140.22124908698973 + ], + [ + 72.08891989599896, + 85.03740267210979 + ], + [ + 58.64861279674493, + 25.330290157649763 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 3513, + "versionNonce": 81957210, + "isDeleted": false, + "id": "7OxLrq7OflFZjsOUL7N73", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0.010125045471368388, + "x": 409.95328424535046, + "y": 151.09406366191, + "strokeColor": "#000000", + "backgroundColor": "#ffff", + "width": 107.86796992458478, + "height": 107.43635763197273, + "seed": 1435849748, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 7.6908526319038675, + -2.474404097559366 + ], + [ + 8.40300957861041, + -6.428263196392702 + ], + [ + 7.390374985604823, + -17.677471431347072 + ], + [ + 12.499753845932284, + -18.09913190599692 + ], + [ + 12.269716577363862, + -6.277544968451047 + ], + [ + 14.178773217919089, + -2.6209308432739724 + ], + [ + 22.489559487210585, + -0.9064656499817254 + ], + [ + 34.069448560923384, + 3.5068317569999716 + ], + [ + 42.279627148555804, + 9.192843561430736 + ], + [ + 45.42593141456448, + 8.496970941242745 + ], + [ + 52.91003978696406, + 2.636990981764985 + ], + [ + 55.274422282722114, + 4.788702373135735 + ], + [ + 47.82754828033455, + 10.786025612913757 + ], + [ + 46.598814069940644, + 13.981545934566471 + ], + [ + 51.68130557657019, + 23.577263118211324 + ], + [ + 54.79037547256697, + 34.583037979605514 + ], + [ + 55.13479339517742, + 45.39653224857933 + ], + [ + 57.49917589093545, + 47.420056578336514 + ], + [ + 67.11495194651849, + 48.48217794599191 + ], + [ + 66.58436217384843, + 52.355258450459175 + ], + [ + 56.968586118265335, + 50.54232715049574 + ], + [ + 53.97121933230439, + 51.2565122080571 + ], + [ + 49.41931759834493, + 60.229606521007426 + ], + [ + 42.921920031261706, + 68.03986106074889 + ], + [ + 33.725030638312944, + 75.39230466615614 + ], + [ + 34.87929610868303, + 78.51457523831542 + ], + [ + 40.892646865611056, + 87.13973324117175 + ], + [ + 36.88064349682472, + 89.3372257259758 + ], + [ + 32.53353079793099, + 79.81475829182457 + ], + [ + 28.819402389240086, + 77.15029865399951 + ], + [ + 18.170372565825822, + 80.04366375899161 + ], + [ + 3.658276853672906, + 79.75982097970444 + ], + [ + -5.482760984257906, + 75.90505291261046 + ], + [ + -8.191561402626395, + 77.94688967974103 + ], + [ + -13.05064668918433, + 86.99323374218469 + ], + [ + -16.38312280525279, + 84.71333528920047 + ], + [ + -10.658338415917326, + 76.30792653482455 + ], + [ + -10.183600198265111, + 73.09409377579847 + ], + [ + -17.332599240557215, + 67.60951878247471 + ], + [ + -23.895156955161323, + 58.56317472003095 + ], + [ + -26.75289485357761, + 52.32778979439912 + ], + [ + -30.532183409789287, + 51.94322860955838 + ], + [ + -40.175885242881286, + 54.58021959132341 + ], + [ + -40.7530179780663, + 50.42329630756885 + ], + [ + -31.072081774962445, + 49.196363003553245 + ], + [ + -28.353972764090933, + 46.82490236370207 + ], + [ + -28.31053266574367, + 34.00212677181701 + ], + [ + -25.793075537714287, + 24.182590909164343 + ], + [ + -21.14912216678089, + 15.89519564008344 + ], + [ + -23.327332812479284, + 12.690519099744028 + ], + [ + -32.645233907966805, + 7.737004790247976 + ], + [ + -30.280851412208712, + 3.827299411033904 + ], + [ + -21.949661122037543, + 10.4838703962532 + ], + [ + -17.583931238137815, + 10.877587799780605 + ], + [ + -10.137057235750202, + 4.889420778689255 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1026, + "versionNonce": 491604294, + "isDeleted": false, + "id": "FFLrZfYi8zOzU7ETjRhNG", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 397.6007489507609, + "y": 166.47797541329646, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 21.92924326408606, + "height": 21.92924326408606, + "seed": 2038018452, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 6.528069526592079, + -5.912148115214414 + ], + [ + 13.246277000560614, + -10.014454970669291 + ], + [ + 21.10531215878801, + -10.617735390589138 + ], + [ + 21.92924326408606, + 0.30164020995991053 + ], + [ + 20.471519000866465, + 11.311507873496923 + ], + [ + 9.887173263576368, + 6.213788325174302 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1147, + "versionNonce": 536565274, + "isDeleted": false, + "id": "vM89IVwTjdO50lyKuuj-h", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0.9881310661508964, + "x": 420.8653515071436, + "y": 163.87187587542724, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 22.226225967992807, + "height": 22.671325098920025, + "seed": 737566484, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 6.41586012317913, + -5.810525635521938 + ], + [ + 13.01858995868387, + -9.842318933639184 + ], + [ + 19.926310552356192, + -10.973110939916017 + ], + [ + 22.226225967992807, + -0.4301252550283833 + ], + [ + 21.297589252628583, + 11.698214159004008 + ], + [ + 9.717225040931522, + 6.106981025089355 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1152, + "versionNonce": 1889546374, + "isDeleted": false, + "id": "6sosp0gYMCGYjXZMFG-Fe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 1.880863085334429, + "x": 437.90764450723157, + "y": 180.60781468653656, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 21.849344542700443, + "height": 22.92336094285941, + "seed": 360799380, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684340, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 6.504284647104447, + -5.890607332007288 + ], + [ + 13.04286375553029, + -9.928257057015854 + ], + [ + 21.028415412483355, + -10.579049902380422 + ], + [ + 21.849344542700443, + 0.3005411904085266 + ], + [ + 19.714579453449403, + 12.344311040478992 + ], + [ + 9.739689975644286, + 6.911172341810431 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1330, + "versionNonce": 220037850, + "isDeleted": false, + "id": "B_M6crrOlBJOn6at150PT", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 2.8469082809423476, + "x": 434.45375147509367, + "y": 203.87972561154538, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 20.92790526169209, + "height": 23.789029285039785, + "seed": 1607510548, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 4.065703544024639, + -4.5876603722251765 + ], + [ + 11.294621372121576, + -9.777849939579546 + ], + [ + 18.907118199824346, + -10.88239105809493 + ], + [ + 20.92790526169209, + 0.5316417517459124 + ], + [ + 19.8844191907757, + 12.906638226944855 + ], + [ + 9.503099529123865, + 7.690657354906653 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1462, + "versionNonce": 2140417990, + "isDeleted": false, + "id": "ppJ6DGMc7hKUZMgfWZmD8", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 3.774871714878671, + "x": 413.944582721838, + "y": 215.87573610497742, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 21.42390620823063, + "height": 24.609699516393512, + "seed": 232408980, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 5.4155174429780475, + -5.315288660297181 + ], + [ + 12.15233234241631, + -10.30823640044254 + ], + [ + 19.473026125895345, + -12.244542904615962 + ], + [ + 20.809969820427792, + -0.0020563890074248425 + ], + [ + 21.42390620823063, + 12.36515661177755 + ], + [ + 10.580006235161937, + 6.636301385740124 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1524, + "versionNonce": 383522714, + "isDeleted": false, + "id": "eVrQ31MTzSOieSjQ1cVA0", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 4.759646000521123, + "x": 391.40556984324974, + "y": 206.6727326873464, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 21.21112299075828, + "height": 20.85617865624166, + "seed": 1406416148, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 4.218256912233363, + -5.945597918542437 + ], + [ + 10.873396537077628, + -10.96737166777307 + ], + [ + 16.751050905461714, + -11.355375413246023 + ], + [ + 20.780561864888625, + -1.606136928152377 + ], + [ + 21.21112299075828, + 9.500803242995636 + ], + [ + 9.739689975644286, + 6.911172341810429 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "line", + "version": 1652, + "versionNonce": 1715881734, + "isDeleted": false, + "id": "oE07zZdjza0NEbf6pDyZs", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 5.645190933495279, + "x": 385.24459440343105, + "y": 184.91304702688365, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 23.82408110535899, + "height": 23.02922342267238, + "seed": 1865708180, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 4.218256912233363, + -5.945597918542437 + ], + [ + 10.873396537077628, + -10.96737166777307 + ], + [ + 17.527312548565636, + -12.402352962916003 + ], + [ + 21.299564880149298, + -2.0325929975994415 + ], + [ + 23.82408110535899, + 10.626870459756379 + ], + [ + 11.659961873806143, + 6.509584241535516 + ], + [ + 0, + 0 + ] + ] + }, + { + "type": "ellipse", + "version": 471, + "versionNonce": 1030362202, + "isDeleted": false, + "id": "7R0V-j7Jm9gK-alNPUfwl", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 419.30012998029986, + "y": 184.5239590991327, + "strokeColor": "#000000", + "backgroundColor": "#326ce5", + "width": 9.594168849928392, + "height": 9.594168849928392, + "seed": 2125529108, + "groupIds": [ + "zT_n59q7q6YFANGLPLAb_" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 143, + "versionNonce": 892565062, + "isDeleted": false, + "id": "9hLk5RkFNiQVU94fxtVFY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 503.1652067654401, + "y": 190.87828477776, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 71.19992065429688, + "height": 25, + "seed": 1409548332, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Cluster", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Cluster", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "ellipse", + "version": 2547, + "versionNonce": 43677978, + "isDeleted": false, + "id": "ZDR4zMJcAkQSSKkw4YR59", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -102.6605813611456, + "y": 212.4111039231663, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 55.62921974281601, + "height": 51.201385977351684, + "seed": 611926060, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "line", + "version": 2609, + "versionNonce": 1698217350, + "isDeleted": false, + "id": "VAI3O0OmLeMApqEKibmCc", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -78.01073266464635, + "y": 263.32871315152846, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 2.7296292860039104, + "height": 62.07302017561529, + "seed": 574118572, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -2.7296292860039104, + 62.07302017561529 + ] + ] + }, + { + "type": "line", + "version": 2562, + "versionNonce": 903890394, + "isDeleted": false, + "id": "fErmH-XmXSsLImNYRdTQZ", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -80.49689227865355, + "y": 326.9914792926451, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 24.57187279022971, + "height": 37.855374086622675, + "seed": 2117084460, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 24.57187279022971, + 37.855374086622675 + ] + ] + }, + { + "type": "line", + "version": 2581, + "versionNonce": 1267932358, + "isDeleted": false, + "id": "WZS-Bj-e-zF3F7Ys6BF1b", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -81.75230308717704, + "y": 325.69698097286465, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 23.26521467347229, + "height": 34.011101841242805, + "seed": 1305124780, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -23.26521467347229, + 34.011101841242805 + ] + ] + }, + { + "type": "line", + "version": 2600, + "versionNonce": 1078885018, + "isDeleted": false, + "id": "F7GW4EUEp0V0piO-aDoyW", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -111.94494041726256, + "y": 298.6012182546694, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 32.48711994829731, + "height": 20.807832195149214, + "seed": 1764870700, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 32.48711994829731, + -20.807832195149214 + ] + ] + }, + { + "type": "line", + "version": 2676, + "versionNonce": 232756230, + "isDeleted": false, + "id": "fXqZj05KLlz9nF4c_ETJU", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -77.62482761069788, + "y": 278.39740199951365, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 20.636027957067586, + "height": 25.894951885267858, + "seed": 323986604, + "groupIds": [ + "YfaL6NDl6oQVg5OheTsdq" + ], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 20.636027957067586, + 25.894951885267858 + ] + ] + }, + { + "type": "rectangle", + "version": 212, + "versionNonce": 1889015642, + "isDeleted": false, + "id": "7GRoexcltgMtWcZq1-92N", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 439.59257049204575, + "y": 271.84959115174854, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "width": 176, + "height": 61, + "seed": 1102974484, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "PDJCOMzwHNVgBBJVSUcmE" + }, + { + "id": "9wALvXFlNfJ34lUqp90g7", + "type": "arrow" + }, + { + "id": "wCTRLH1Vtdi420wTZ-zU0", + "type": "arrow" + }, + { + "id": "7ydVW8sgDLOF-pKI6jnDj", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 163, + "versionNonce": 370877254, + "isDeleted": false, + "id": "PDJCOMzwHNVgBBJVSUcmE", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 473.12262267710435, + "y": 289.84959115174854, + "strokeColor": "#1971c2", + "backgroundColor": "#e9ecef", + "width": 108.93989562988281, + "height": 25, + "seed": 1299508140, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "API Server", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "7GRoexcltgMtWcZq1-92N", + "originalText": "API Server", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "arrow", + "version": 792, + "versionNonce": 1192238106, + "isDeleted": false, + "id": "9wALvXFlNfJ34lUqp90g7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -40.13986490820349, + "y": 295.75792242427565, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 470.73243540024913, + "height": 2.7321746081896663, + "seed": 854008852, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "7GRoexcltgMtWcZq1-92N", + "focus": 0.10630172009833401, + "gap": 9.000000000000114 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 470.73243540024913, + 2.7321746081896663 + ] + ] + }, + { + "type": "text", + "version": 200, + "versionNonce": 111331974, + "isDeleted": false, + "id": "ZuqdXFupYa7wK-7Ba-Ap6", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 14.592570492045638, + "y": 259.5638768660343, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 345.61962890625, + "height": 25, + "seed": 86022828, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "helm install zora -n zora-system ...", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "helm install zora -n zora-system ...", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "text", + "version": 326, + "versionNonce": 1101629658, + "isDeleted": false, + "id": "HVbwRCFjmZl8Ud0CmlsiC", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 15.831409777759973, + "y": 302.27816258032, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 282.7396240234375, + "height": 150, + "seed": 105229076, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "kubectl get clusters\n scans\n plugins\n checks\n misconfigurations\n vulnerabilities", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "kubectl get clusters\n scans\n plugins\n checks\n misconfigurations\n vulnerabilities", + "lineHeight": 1.25, + "baseline": 143 + }, + { + "type": "rectangle", + "version": 1381, + "versionNonce": 775129542, + "isDeleted": false, + "id": "RX2X_TTtFQvp_IxwylxJ3", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1169.0318120224524, + "y": 213.49940454882233, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 470.93364469854447, + "height": 514.8216114574409, + "seed": 624634028, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 952, + "versionNonce": 670522778, + "isDeleted": false, + "id": "HCXpfecdpdkry7CGAnlp8", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1281.9488161523457, + "y": 212.49408966638242, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 234.8397216796875, + "height": 25, + "seed": 134265388, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "namespace: zora-system", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "namespace: zora-system", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1068, + "versionNonce": 2078957830, + "isDeleted": false, + "id": "CsM83220VENTZGqU2vYuv", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1308.6511246571138, + "y": 301.4242761816312, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 176, + "height": 61, + "seed": 1542848532, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "JpdUm0DCNQGSrFqRuKOtr" + }, + { + "id": "BvaxM5C85vSoC4EuS2v0E", + "type": "arrow" + }, + { + "id": "X6eugQMUC4Xsd488UbJAB", + "type": "arrow" + }, + { + "id": "TqwFIplYbG81tnNqZoX51", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1026, + "versionNonce": 1462540890, + "isDeleted": false, + "id": "JpdUm0DCNQGSrFqRuKOtr", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1327.911210716684, + "y": 319.42427618163134, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e9ecef", + "width": 137.47982788085938, + "height": 25, + "seed": 1189404052, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "zora-operator", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "CsM83220VENTZGqU2vYuv", + "originalText": "zora-operator", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 870, + "versionNonce": 1933856838, + "isDeleted": false, + "id": "MIJxzPib2nTHQkpgboa1s", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 771.69784140728, + "y": 269.7332077083871, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 1178122392, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "vCB04TvAZubyLAmCyHjSk" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 846, + "versionNonce": 236732186, + "isDeleted": false, + "id": "vCB04TvAZubyLAmCyHjSk", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 847.2981254750116, + "y": 283.8245704984671, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 71.19992065429688, + "height": 25, + "seed": 1215018728, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Cluster", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "MIJxzPib2nTHQkpgboa1s", + "originalText": "Cluster", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 903, + "versionNonce": 538859398, + "isDeleted": false, + "id": "SYmZqQwz3b_zq-NU_O9oe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 772.3239363332001, + "y": 336.4462857207069, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 221.19179048111994, + "height": 53.18272558015997, + "seed": 1225673448, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "RjynVz7t3Wsox0RUp6E5T" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 886, + "versionNonce": 960056282, + "isDeleted": false, + "id": "RjynVz7t3Wsox0RUp6E5T", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 824.8798916933889, + "y": 350.5376485107869, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 116.07987976074219, + "height": 25, + "seed": 1104457192, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ClusterScan", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "SYmZqQwz3b_zq-NU_O9oe", + "originalText": "ClusterScan", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1016, + "versionNonce": 179664582, + "isDeleted": false, + "id": "vvMstb9N1b1YXS1rCntSc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 772.6693235704623, + "y": 592.1132858095235, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 278375470, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "6dNJch3BcVE67CZtYiZM9" + }, + { + "id": "IOvLeWPNmTwIrokPyf5_e", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1011, + "versionNonce": 1050067098, + "isDeleted": false, + "id": "6dNJch3BcVE67CZtYiZM9", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 820.8096390712994, + "y": 606.2046485996035, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 126.11985778808594, + "height": 25, + "seed": 1835923054, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ClusterIssue", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "vvMstb9N1b1YXS1rCntSc", + "originalText": "ClusterIssue", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1096, + "versionNonce": 732343814, + "isDeleted": false, + "id": "IUYylfqN66RbDGXW5gVrS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 772.6693235704621, + "y": 661.0090894020035, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 1171214283, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "WlDfr9CIj9CmTVqRTej58" + }, + { + "id": "j3-zz_rFMzL04_4iTScE7", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1093, + "versionNonce": 1239915866, + "isDeleted": false, + "id": "WlDfr9CIj9CmTVqRTej58", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 794.1796723354594, + "y": 675.1004521920835, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 179.37979125976562, + "height": 25, + "seed": 780738155, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IUYylfqN66RbDGXW5gVrS", + "originalText": "VulnerabilityReport", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1073, + "versionNonce": 1609497926, + "isDeleted": false, + "id": "tTLkmwqpW_XyB5ubDcn6I", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 772.5326346418401, + "y": 404.1333910045472, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 1692333323, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "Y8veTLD6aVu5O6mHNNN1N" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1078, + "versionNonce": 410968602, + "isDeleted": false, + "id": "Y8veTLD6aVu5O6mHNNN1N", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 856.942908638771, + "y": 418.2247537946272, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 53.57994079589844, + "height": 25, + "seed": 787618731, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Plugin", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tTLkmwqpW_XyB5ubDcn6I", + "originalText": "Plugin", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1204, + "versionNonce": 1558930566, + "isDeleted": false, + "id": "hnlPX5ijnyaDEE7YPquG-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 773.7413329504801, + "y": 469.40309967110716, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 630963787, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "N6xq3ZHO9ZCFiu6mpdUUj" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1221, + "versionNonce": 1162841818, + "isDeleted": false, + "id": "N6xq3ZHO9ZCFiu6mpdUUj", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 823.1316408219227, + "y": 483.49446246118714, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 123.619873046875, + "height": 25, + "seed": 1740881131, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "CustomCheck", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "hnlPX5ijnyaDEE7YPquG-", + "originalText": "CustomCheck", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1385, + "versionNonce": 609805254, + "isDeleted": false, + "id": "zwJ2-by1Og0Oeh77kGbyY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1225.2570642471328, + "y": 522.2428930676854, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 370.09649155629756, + "height": 155.92208181456004, + "seed": 2042156261, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "X6eugQMUC4Xsd488UbJAB", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 1361, + "versionNonce": 351052698, + "isDeleted": false, + "id": "2aqDsJfYq-OwTwT7ZU7z9", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1271.1383233580782, + "y": 604.8782382533269, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 75.72632860313931, + "height": 50.77747102174595, + "seed": 995894219, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "r9QGabxp_F8ojb71iUt9w" + }, + { + "id": "UXvX1uwIHDQH3b_3Lv33C", + "type": "arrow" + }, + { + "id": "IOvLeWPNmTwIrokPyf5_e", + "type": "arrow" + }, + { + "id": "j3-zz_rFMzL04_4iTScE7", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1274, + "versionNonce": 2018802438, + "isDeleted": false, + "id": "r9QGabxp_F8ojb71iUt9w", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1278.4315184824018, + "y": 617.7669737641999, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 61.13993835449219, + "height": 25, + "seed": 630151397, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "worker", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "2aqDsJfYq-OwTwT7ZU7z9", + "originalText": "worker", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1461, + "versionNonce": 1099505754, + "isDeleted": false, + "id": "-MWu-M8VGQPddk8iTdRPQ", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1479.4928166425568, + "y": 604.4962069015095, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 75.72632860313934, + "height": 51.54022037147293, + "seed": 1267990437, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "b0HkC5wdR2qPUo78A3z7Q" + }, + { + "id": "iwUznO1UQPEBpjiwkOpjC", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1379, + "versionNonce": 1331374662, + "isDeleted": false, + "id": "b0HkC5wdR2qPUo78A3z7Q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1492.246010851353, + "y": 617.766317087246, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 50.219940185546875, + "height": 25, + "seed": 1520354053, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "plugin", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "-MWu-M8VGQPddk8iTdRPQ", + "originalText": "plugin", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "text", + "version": 1273, + "versionNonce": 1190659354, + "isDeleted": false, + "id": "YnjtQ4n57RSKcHFNkkJgo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1300.7389336662975, + "y": 525.8122488347475, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 221.259765625, + "height": 25, + "seed": 286417515, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "CronJob -> Job -> Pod", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "CronJob -> Job -> Pod", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "line", + "version": 1429, + "versionNonce": 1212805510, + "isDeleted": false, + "id": "KWC-D0cwD9BwZ-fp9ItMQ", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1409.6623044130404, + "y": 625.3667530499727, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10.831394523892964, + "height": 0, + "seed": 310353419, + "groupIds": [ + "38jMtXpGE3nLodBErLPp9", + "pTHR782PSTJNR9W63LkhR" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 10.831394523892964, + 0 + ] + ] + }, + { + "type": "line", + "version": 1607, + "versionNonce": 783045082, + "isDeleted": false, + "id": "X-lD8zJrXpWZJMLvjjtpk", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1409.6623044130404, + "y": 629.6884418965515, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10.831394523892964, + "height": 0, + "seed": 345351339, + "groupIds": [ + "38jMtXpGE3nLodBErLPp9", + "pTHR782PSTJNR9W63LkhR" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 10.831394523892964, + 0 + ] + ] + }, + { + "type": "line", + "version": 1724, + "versionNonce": 509464774, + "isDeleted": false, + "id": "wRKi8oQhVLY2Ggjn4dIHE", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1409.6623044130404, + "y": 634.1489038030328, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10.831394523892964, + "height": 0, + "seed": 2138167115, + "groupIds": [ + "38jMtXpGE3nLodBErLPp9", + "pTHR782PSTJNR9W63LkhR" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 10.831394523892964, + 0 + ] + ] + }, + { + "type": "rectangle", + "version": 1286, + "versionNonce": 1538852506, + "isDeleted": false, + "id": "0Y972U9MtKDmncsqYltHL", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1402.9455890984343, + "y": 618.2060042730444, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 23.304850518986665, + "height": 23.304850518986665, + "seed": 829339115, + "groupIds": [ + "pTHR782PSTJNR9W63LkhR" + ], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "UXvX1uwIHDQH3b_3Lv33C", + "type": "arrow" + }, + { + "id": "iwUznO1UQPEBpjiwkOpjC", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 3469, + "versionNonce": 489932806, + "isDeleted": false, + "id": "UXvX1uwIHDQH3b_3Lv33C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1349.4252329617332, + "y": 632.4575424454415, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 47.26897702435622, + "height": 0.32380570753389293, + "seed": 656276677, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": { + "elementId": "2aqDsJfYq-OwTwT7ZU7z9", + "focus": 0.07481472870797658, + "gap": 2.56058100051564 + }, + "endBinding": { + "elementId": "0Y972U9MtKDmncsqYltHL", + "focus": -0.25958919226117866, + "gap": 6.251379112344921 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 47.26897702435622, + 0.32380570753389293 + ] + ] + }, + { + "type": "arrow", + "version": 3299, + "versionNonce": 1456546650, + "isDeleted": false, + "id": "iwUznO1UQPEBpjiwkOpjC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1476.8408206455747, + "y": 633.0824149716301, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 46.32831351267964, + "height": 1.082047154180941, + "seed": 728020875, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": { + "elementId": "-MWu-M8VGQPddk8iTdRPQ", + "focus": -0.14170424628548298, + "gap": 2.651995996982123 + }, + "endBinding": { + "elementId": "0Y972U9MtKDmncsqYltHL", + "focus": 0.14845288707453994, + "gap": 4.262067515473973 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -46.32831351267964, + -1.082047154180941 + ] + ] + }, + { + "type": "text", + "version": 524, + "versionNonce": 348706630, + "isDeleted": false, + "id": "P2CMC4idF2koE4yKzkpcc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 780.5594700179712, + "y": 223.92996611007612, + "strokeColor": "#868e96", + "backgroundColor": "#b2f2bb", + "width": 210.4597625732422, + "height": 25, + "seed": 955588005, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "CRDs for scan config", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "CRDs for scan config", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 278, + "versionNonce": 440903706, + "isDeleted": false, + "id": "HSiNq4YP0JRZOGJWBeIl3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 737.8084172152761, + "y": 214.1472410197922, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 300.03196985378725, + "height": 332.3774238528945, + "seed": 1348805829, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "wCTRLH1Vtdi420wTZ-zU0", + "type": "arrow" + }, + { + "id": "BvaxM5C85vSoC4EuS2v0E", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 404, + "versionNonce": 1299840646, + "isDeleted": false, + "id": "jIW2hiYI1duE8_1DzssbI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 737.3660974566402, + "y": 546.6400253554145, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 300.03196985378725, + "height": 184.03447965009263, + "seed": 862285957, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "7ydVW8sgDLOF-pKI6jnDj", + "type": "arrow" + } + ], + "updated": 1698127684341, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 527, + "versionNonce": 1578079450, + "isDeleted": false, + "id": "j5n7KwQlqTICJibQN5P1r", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 797.036644008736, + "y": 554.1011535617877, + "strokeColor": "#868e96", + "backgroundColor": "#b2f2bb", + "width": 171.47979736328125, + "height": 25, + "seed": 1612417541, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "CRDs for results", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "CRDs for results", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "arrow", + "version": 216, + "versionNonce": 2080652742, + "isDeleted": false, + "id": "wCTRLH1Vtdi420wTZ-zU0", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 620.9726207879912, + "y": 308.78911678150723, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 107.60243666835822, + "height": 2.0372008361998155, + "seed": 1276583525, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": { + "elementId": "7GRoexcltgMtWcZq1-92N", + "focus": 0.15849260089446404, + "gap": 5.380050295945466 + }, + "endBinding": { + "elementId": "HSiNq4YP0JRZOGJWBeIl3", + "focus": 0.393391989804772, + "gap": 9.23335975892661 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 107.60243666835822, + 2.0372008361998155 + ] + ] + }, + { + "type": "arrow", + "version": 306, + "versionNonce": 1673259418, + "isDeleted": false, + "id": "7ydVW8sgDLOF-pKI6jnDj", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 620.2486280409007, + "y": 327.5960177084178, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 112.31761805617714, + "height": 234.08399627455503, + "seed": 53790981, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684341, + "link": null, + "locked": false, + "startBinding": { + "elementId": "7GRoexcltgMtWcZq1-92N", + "focus": -0.7847500404412927, + "gap": 4.65605754885496 + }, + "endBinding": { + "elementId": "jIW2hiYI1duE8_1DzssbI", + "focus": -0.607108876144791, + "gap": 4.799851359562297 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 112.31761805617714, + 234.08399627455503 + ] + ] + }, + { + "type": "arrow", + "version": 368, + "versionNonce": 897881350, + "isDeleted": false, + "id": "BvaxM5C85vSoC4EuS2v0E", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1049.1432993687563, + "y": 326.8564049064976, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 250.46368017480086, + "height": 3.5292999533923535, + "seed": 396289259, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "EGht6NbSjVmaqpznyG2Bp" + } + ], + "updated": 1698127684342, + "link": null, + "locked": false, + "startBinding": { + "elementId": "HSiNq4YP0JRZOGJWBeIl3", + "focus": -0.33126466321122894, + "gap": 11.302912299692991 + }, + "endBinding": { + "elementId": "CsM83220VENTZGqU2vYuv", + "focus": 0.0053911754340372495, + "gap": 9.044145113556624 + }, + "lastCommittedPoint": null, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 250.46368017480086, + 3.5292999533923535 + ] + ] + }, + { + "type": "text", + "version": 94, + "versionNonce": 1115661914, + "isDeleted": false, + "id": "EGht6NbSjVmaqpznyG2Bp", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1114.5851843169967, + "y": 316.12659037699734, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 85.57991027832031, + "height": 25, + "seed": 1777646507, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Reconcile", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BvaxM5C85vSoC4EuS2v0E", + "originalText": "Reconcile", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "arrow", + "version": 401, + "versionNonce": 1668809798, + "isDeleted": false, + "id": "X6eugQMUC4Xsd488UbJAB", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1390.321408168858, + "y": 367.1160877767219, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 0.6179727511689634, + "height": 142.31309928502787, + "seed": 1509748587, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "startBinding": { + "elementId": "CsM83220VENTZGqU2vYuv", + "focus": 0.07195290166682204, + "gap": 4.691811595090655 + }, + "endBinding": { + "elementId": "zwJ2-by1Og0Oeh77kGbyY", + "focus": -0.10233606605824513, + "gap": 12.813706005935614 + }, + "lastCommittedPoint": null, + "startArrowhead": "arrow", + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0.6179727511689634, + 142.31309928502787 + ] + ] + }, + { + "type": "arrow", + "version": 588, + "versionNonce": 858639130, + "isDeleted": false, + "id": "IOvLeWPNmTwIrokPyf5_e", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1267.6727191175942, + "y": 628.0061911140192, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 268.2743431139379, + "height": 0.6715341696017276, + "seed": 1061290955, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "startBinding": { + "elementId": "2aqDsJfYq-OwTwT7ZU7z9", + "gap": 3.4656042404840264, + "focus": 0.09277774795321045 + }, + "endBinding": { + "elementId": "vvMstb9N1b1YXS1rCntSc", + "gap": 4.328563643433824, + "focus": 0.3819267903556274 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -268.2743431139379, + 0.6715341696017276 + ] + ] + }, + { + "type": "arrow", + "version": 600, + "versionNonce": 935037830, + "isDeleted": false, + "id": "j3-zz_rFMzL04_4iTScE7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1267.5754425880025, + "y": 638.3352462473899, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 270.7833247492374, + "height": 51.59401614491742, + "seed": 605660389, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "startBinding": { + "elementId": "2aqDsJfYq-OwTwT7ZU7z9", + "gap": 3.562880770075708, + "focus": -0.005232116761253777 + }, + "endBinding": { + "elementId": "IUYylfqN66RbDGXW5gVrS", + "gap": 1.7223054785428644, + "focus": 0.49906076626004503 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -270.7833247492374, + 51.59401614491742 + ] + ] + }, + { + "type": "rectangle", + "version": 96, + "versionNonce": 1547261914, + "isDeleted": false, + "id": "BNoY3qR6T1d4LLsa13Ts5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1234.7738539410923, + "y": 571.2309496174865, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 350.24623552574485, + "height": 98.40251379056645, + "seed": 442392139, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 255, + "versionNonce": 546056902, + "isDeleted": false, + "id": "OaigSeqTncIC4hLoLIJaN", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1245.5505980373619, + "y": 570.0459113272652, + "strokeColor": "#868e96", + "backgroundColor": "transparent", + "width": 79.37617492675781, + "height": 20, + "seed": 172853131, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "containers", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "containers", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "rectangle", + "version": 375, + "versionNonce": 498420890, + "isDeleted": false, + "id": "Z6IpX4AhKfGtggGgg41XS", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1822.8860357186543, + "y": 257.0542693371509, + "strokeColor": "#ffffff", + "backgroundColor": "#326ce5", + "width": 430.1512250569724, + "height": 136.8662988817639, + "seed": 1213257669, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "vyMM3rTfmbvvzUGTAK-dY" + }, + { + "id": "TqwFIplYbG81tnNqZoX51", + "type": "arrow" + } + ], + "updated": 1698127684342, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 320, + "versionNonce": 1015472646, + "isDeleted": false, + "id": "vyMM3rTfmbvvzUGTAK-dY", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1891.0815823291719, + "y": 302.98741877803286, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "width": 293.7601318359375, + "height": 45, + "seed": 1753517899, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "fontSize": 36, + "fontFamily": 1, + "text": "Zora Dashboard", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Z6IpX4AhKfGtggGgg41XS", + "originalText": "Zora Dashboard", + "lineHeight": 1.25, + "baseline": 32 + }, + { + "type": "arrow", + "version": 195, + "versionNonce": 1565829466, + "isDeleted": false, + "id": "TqwFIplYbG81tnNqZoX51", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1492.5472387782454, + "y": 329.31285479112626, + "strokeColor": "#326ce5", + "backgroundColor": "#1e1e1e", + "width": 328.83477167797196, + "height": 0.3107959708430599, + "seed": 1336648299, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698127684342, + "link": null, + "locked": false, + "startBinding": { + "elementId": "CsM83220VENTZGqU2vYuv", + "gap": 7.896114121131632, + "focus": -0.08241422059417507 + }, + "endBinding": { + "elementId": "Z6IpX4AhKfGtggGgg41XS", + "gap": 1.5040252624370396, + "focus": -0.0482242653686709 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 328.83477167797196, + -0.3107959708430599 + ] + ] + }, + { + "type": "rectangle", + "version": 1474, + "versionNonce": 38722970, + "isDeleted": false, + "id": "dbzNphIdeYrf5LsaQCeTg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1068.2878828373198, + "y": 978.9341608486686, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 533.868225915037, + "height": 155.92208181456004, + "seed": 900511322, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1698127994849, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 1683, + "versionNonce": 482948250, + "isDeleted": false, + "id": "PfF_uMDlZYCJFGeSqP2sD", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1496.881106823672, + "y": 1008.8732381964824, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 75.72632860313931, + "height": 109.15666970482981, + "seed": 1580784410, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "TUbPaaqhOGM6EXJXvDoGy" + }, + { + "id": "IhrHF9rSIEILR3NbCWLzN", + "type": "arrow" + }, + { + "id": "fQQhaY3Q-XQSFQvoTz2K2", + "type": "arrow" + }, + { + "id": "0dbdrmZLO9NS5kMreJdof", + "type": "arrow" + }, + { + "id": "Q-d9PiUYaq2ZL6T18Jehu", + "type": "arrow" + } + ], + "updated": 1698128089487, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1588, + "versionNonce": 767772614, + "isDeleted": false, + "id": "TUbPaaqhOGM6EXJXvDoGy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1504.1743019479957, + "y": 1050.9515730488972, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 61.13993835449219, + "height": 25, + "seed": 325216218, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127946620, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "worker", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "PfF_uMDlZYCJFGeSqP2sD", + "originalText": "worker", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1693, + "versionNonce": 969037126, + "isDeleted": false, + "id": "ys_UmhVv4qvsxbr3PUQdJ", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1088.5856001055895, + "y": 1001.7750158457259, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 75.72632860313934, + "height": 110.95267920823964, + "seed": 758930586, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "E8jZUjojgEKZM3Hf9ROuV" + }, + { + "id": "0aIsc_k56rfG2kgziF-0B", + "type": "arrow" + }, + { + "id": "MpdjmoEjgAz65hAWRo4XY", + "type": "arrow" + } + ], + "updated": 1698127868441, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1606, + "versionNonce": 1527138694, + "isDeleted": false, + "id": "E8jZUjojgEKZM3Hf9ROuV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1101.3387943143857, + "y": 1044.7513554498457, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 50.219940185546875, + "height": 25, + "seed": 158972250, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127868443, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "plugin", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ys_UmhVv4qvsxbr3PUQdJ", + "originalText": "plugin", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "line", + "version": 1507, + "versionNonce": 1566387334, + "isDeleted": false, + "id": "BsEcYuVUysd4wVbbwCOCo", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1319.4951171600342, + "y": 1018.1892883628684, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 1678420698, + "groupIds": [ + "69VAJfGT_k7oL6SRIYKL5", + "J-k7jSCZFBFtZ_u8NlC9f" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127799383, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "line", + "version": 1685, + "versionNonce": 1129425862, + "isDeleted": false, + "id": "sG9m3NTXooPLr1sI08aof", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1319.4951171600342, + "y": 1024.8102902446358, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 1709457306, + "groupIds": [ + "69VAJfGT_k7oL6SRIYKL5", + "J-k7jSCZFBFtZ_u8NlC9f" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127799383, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "line", + "version": 1802, + "versionNonce": 1291076358, + "isDeleted": false, + "id": "GUbDfR6JUK2aIuNJs-Ao-", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1319.4951171600342, + "y": 1031.6438980597252, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 1227701338, + "groupIds": [ + "69VAJfGT_k7oL6SRIYKL5", + "J-k7jSCZFBFtZ_u8NlC9f" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127799383, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "rectangle", + "version": 1372, + "versionNonce": 1098315718, + "isDeleted": false, + "id": "Xc9h1I_5745MxNpWRoYPG", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1309.204837985376, + "y": 1007.2187319877978, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 35.703972363181336, + "height": 35.703972363181336, + "seed": 2075697434, + "groupIds": [ + "J-k7jSCZFBFtZ_u8NlC9f" + ], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "0aIsc_k56rfG2kgziF-0B", + "type": "arrow" + }, + { + "id": "fQQhaY3Q-XQSFQvoTz2K2", + "type": "arrow" + } + ], + "updated": 1698128061361, + "link": null, + "locked": false + }, + { + "type": "line", + "version": 1600, + "versionNonce": 354513990, + "isDeleted": false, + "id": "Uf-5I4Dvkm9W_7VVIiHfV", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1320.35039552825, + "y": 1087.1024143327274, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 1009008966, + "groupIds": [ + "GqL8ZaA04bBqaeWFcdEDG", + "PcwH76cEAwZcsawu1kmM_", + "EHF7zpN_Y8ATMZYRBDzer" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127804253, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "line", + "version": 1778, + "versionNonce": 1387723654, + "isDeleted": false, + "id": "qZPVsMRFU0lgYuRSyXqYB", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1320.35039552825, + "y": 1093.7234162144948, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 165161094, + "groupIds": [ + "GqL8ZaA04bBqaeWFcdEDG", + "PcwH76cEAwZcsawu1kmM_", + "EHF7zpN_Y8ATMZYRBDzer" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127804253, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "line", + "version": 1895, + "versionNonce": 714709702, + "isDeleted": false, + "id": "XOd8mckVStfvuD5ati8iq", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1320.35039552825, + "y": 1100.557024029584, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 16.594133930218554, + "height": 0, + "seed": 520955846, + "groupIds": [ + "GqL8ZaA04bBqaeWFcdEDG", + "PcwH76cEAwZcsawu1kmM_", + "EHF7zpN_Y8ATMZYRBDzer" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127804253, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 16.594133930218554, + 0 + ] + ] + }, + { + "type": "rectangle", + "version": 1463, + "versionNonce": 394003142, + "isDeleted": false, + "id": "ifm1uPtGq3XtEgY8M0GGx", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1310.0601163535916, + "y": 1076.1318579576566, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 35.703972363181336, + "height": 35.703972363181336, + "seed": 467681030, + "groupIds": [ + "PcwH76cEAwZcsawu1kmM_", + "EHF7zpN_Y8ATMZYRBDzer" + ], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "MpdjmoEjgAz65hAWRo4XY", + "type": "arrow" + }, + { + "id": "IhrHF9rSIEILR3NbCWLzN", + "type": "arrow" + } + ], + "updated": 1698127922920, + "link": null, + "locked": false + }, + { + "type": "line", + "version": 921, + "versionNonce": 1746542918, + "isDeleted": false, + "id": "hyOwy5YddhKlw-ylIpfIk", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1317.8342310573098, + "y": 1092.8906666119815, + "strokeColor": "#2f9e44", + "backgroundColor": "transparent", + "width": 23.25054519459211, + "height": 17.26217871141416, + "seed": 1102693082, + "groupIds": [ + "EHF7zpN_Y8ATMZYRBDzer" + ], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127804253, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 8.398001982131458, + 9.27831659773316 + ], + [ + 23.25054519459211, + -7.983862113680998 + ] + ] + }, + { + "type": "arrow", + "version": 265, + "versionNonce": 1932934086, + "isDeleted": false, + "id": "0aIsc_k56rfG2kgziF-0B", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1170.4685789342452, + "y": 1024.44918118079, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 132.87810098832756, + "height": 0.9183466018876061, + "seed": 518973702, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "OQtHUdw5L5kaiCa4s32jg" + } + ], + "updated": 1698127868442, + "link": null, + "locked": false, + "startBinding": { + "elementId": "ys_UmhVv4qvsxbr3PUQdJ", + "focus": -0.593961837241127, + "gap": 6.156650225516387 + }, + "endBinding": { + "elementId": "Xc9h1I_5745MxNpWRoYPG", + "focus": -0.02562813461088687, + "gap": 5.858158062803227 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 132.87810098832756, + 0.9183466018876061 + ] + ] + }, + { + "type": "text", + "version": 8, + "versionNonce": 322793862, + "isDeleted": false, + "id": "OQtHUdw5L5kaiCa4s32jg", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1224.9995636325107, + "y": 1014.9066984202691, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 60.816131591796875, + "height": 20, + "seed": 1093713690, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127862674, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "creates", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "0aIsc_k56rfG2kgziF-0B", + "originalText": "creates", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "arrow", + "version": 208, + "versionNonce": 541520006, + "isDeleted": false, + "id": "MpdjmoEjgAz65hAWRo4XY", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1173.0517293184523, + "y": 1097.1931223607514, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 132.16190998938873, + "height": 1.2814925139089155, + "seed": 1862993862, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "bKW3fmIOFCHyPLWyCtEKP" + } + ], + "updated": 1698127873463, + "link": null, + "locked": false, + "startBinding": { + "elementId": "ys_UmhVv4qvsxbr3PUQdJ", + "focus": 0.7233333892613873, + "gap": 8.739800609723488 + }, + "endBinding": { + "elementId": "ifm1uPtGq3XtEgY8M0GGx", + "focus": -0.09473978228018179, + "gap": 4.846477045750703 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 132.16190998938873, + -1.2814925139089155 + ] + ] + }, + { + "type": "text", + "version": 8, + "versionNonce": 1791756614, + "isDeleted": false, + "id": "bKW3fmIOFCHyPLWyCtEKP", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1208.7246185172482, + "y": 1086.552376103797, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 60.816131591796875, + "height": 20, + "seed": 964447066, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127873173, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "creates", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "MpdjmoEjgAz65hAWRo4XY", + "originalText": "creates", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "text", + "version": 102, + "versionNonce": 1374152090, + "isDeleted": false, + "id": "skI9bCNNJoaG87GGK80Dv", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1304.1803791541583, + "y": 989.1079385404329, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 55.3441162109375, + "height": 20, + "seed": 943674458, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127885835, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "results", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "results", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "text", + "version": 200, + "versionNonce": 1311773638, + "isDeleted": false, + "id": "dby8ZrBX6pwseXtuGL3Xz", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1311.639166273908, + "y": 1113.4317585192098, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 34.19206237792969, + "height": 20, + "seed": 1267386138, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127899558, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "done", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "done", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "arrow", + "version": 138, + "versionNonce": 1020414086, + "isDeleted": false, + "id": "IhrHF9rSIEILR3NbCWLzN", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1493.8190728981658, + "y": 1096.5801874986928, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 143.65861690511906, + "height": 0.5475834832941473, + "seed": 358812314, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "type": "text", + "id": "k3kaPSqymhUkXz4QIP08z" + } + ], + "updated": 1698127946619, + "link": null, + "locked": false, + "startBinding": { + "elementId": "PfF_uMDlZYCJFGeSqP2sD", + "focus": -0.6082406829032406, + "gap": 3.0620339255062845 + }, + "endBinding": { + "elementId": "ifm1uPtGq3XtEgY8M0GGx", + "focus": 0.1095955505582401, + "gap": 4.396367276273736 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + -143.65861690511906, + -0.5475834832941473 + ] + ] + }, + { + "type": "text", + "version": 20, + "versionNonce": 1494808646, + "isDeleted": false, + "id": "k3kaPSqymhUkXz4QIP08z", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1370.4056808884775, + "y": 1086.3086794850337, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 73.16816711425781, + "height": 20, + "seed": 405267290, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698127942914, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "waits for", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IhrHF9rSIEILR3NbCWLzN", + "originalText": "waits for", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "type": "rectangle", + "version": 1091, + "versionNonce": 1784484806, + "isDeleted": false, + "id": "20NAMr02zoSH9YYLNnlVt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1669.313065607093, + "y": 976.4655878250726, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 809971206, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "Zkv9BVbKRuOQhkQNskv24" + }, + { + "id": "0dbdrmZLO9NS5kMreJdof", + "type": "arrow" + } + ], + "updated": 1698128076816, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1085, + "versionNonce": 540534810, + "isDeleted": false, + "id": "Zkv9BVbKRuOQhkQNskv24", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1717.45338110793, + "y": 990.5569506151526, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 126.11985778808594, + "height": 25, + "seed": 2088729926, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698128046028, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ClusterIssue", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "20NAMr02zoSH9YYLNnlVt", + "originalText": "ClusterIssue", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 1178, + "versionNonce": 1923221146, + "isDeleted": false, + "id": "txLCc8j4Adm7F_T5jPH-_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1666.7299152228863, + "y": 1047.5609775070952, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 222.40048878976006, + "height": 53.18272558015997, + "seed": 208492570, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "sFI0exkcHE6GDyL3CYO6v" + }, + { + "id": "Q-d9PiUYaq2ZL6T18Jehu", + "type": "arrow" + } + ], + "updated": 1698128105157, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 1174, + "versionNonce": 295212250, + "isDeleted": false, + "id": "sFI0exkcHE6GDyL3CYO6v", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1688.2402639878835, + "y": 1061.6523402971752, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 179.37979125976562, + "height": 25, + "seed": 1610564826, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698128105158, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "VulnerabilityReport", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "txLCc8j4Adm7F_T5jPH-_", + "originalText": "VulnerabilityReport", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "arrow", + "version": 105, + "versionNonce": 1112276998, + "isDeleted": false, + "id": "fQQhaY3Q-XQSFQvoTz2K2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1350.1604559930443, + "y": 1025.2720439193347, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 145.17305159244756, + "height": 0.41811213353821586, + "seed": 2092798810, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698128133962, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Xc9h1I_5745MxNpWRoYPG", + "focus": 0.007528463356409857, + "gap": 5.251645644486985 + }, + "endBinding": { + "elementId": "PfF_uMDlZYCJFGeSqP2sD", + "focus": 0.6884203863975367, + "gap": 1.5475992381802826 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 145.17305159244756, + 0.41811213353821586 + ] + ] + }, + { + "type": "arrow", + "version": 44, + "versionNonce": 2021400966, + "isDeleted": false, + "id": "0dbdrmZLO9NS5kMreJdof", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1576.961059726441, + "y": 1025.2720439193347, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 87.82711306304645, + "height": 27.381394072596777, + "seed": 563269466, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698128082666, + "link": null, + "locked": false, + "startBinding": { + "elementId": "PfF_uMDlZYCJFGeSqP2sD", + "focus": -0.37687246768311294, + "gap": 4.353624299629473 + }, + "endBinding": { + "elementId": "20NAMr02zoSH9YYLNnlVt", + "focus": 0.6732865399766382, + "gap": 4.5248928176056324 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 87.82711306304645, + -27.381394072596777 + ] + ] + }, + { + "type": "arrow", + "version": 53, + "versionNonce": 1257285658, + "isDeleted": false, + "id": "Q-d9PiUYaq2ZL6T18Jehu", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1575.927799572758, + "y": 1027.2449982676217, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 85.24396267883913, + "height": 42.97508825450518, + "seed": 714733574, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698128105158, + "link": null, + "locked": false, + "startBinding": { + "elementId": "PfF_uMDlZYCJFGeSqP2sD", + "focus": -0.7720120096474897, + "gap": 3.3203641459465416 + }, + "endBinding": { + "elementId": "txLCc8j4Adm7F_T5jPH-_", + "focus": -0.6646000181191877, + "gap": 5.55815297128936 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 85.24396267883913, + 42.97508825450518 + ] + ] + }, + { + "type": "text", + "version": 58, + "versionNonce": 931111110, + "isDeleted": false, + "id": "9D8Qfr9Z051j1wAVUJnPc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1766.3930697774742, + "y": 1026.4536701134732, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 15.744033813476562, + "height": 20, + "seed": 1378587910, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698128114108, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "or", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "or", + "lineHeight": 1.25, + "baseline": 14 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/docs/assets/arch.excalidraw b/docs/assets/arch.excalidraw deleted file mode 100644 index 05cfd4b8..00000000 --- a/docs/assets/arch.excalidraw +++ /dev/null @@ -1,8544 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 1040, - "versionNonce": 943349198, - "isDeleted": false, - "id": "6T4gFc_wkndMmGBPgHlyt", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 141.76043284913897, - "y": 839.1709223847542, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 898.9637783697626, - "height": 589.5238095238094, - "seed": 1438247446, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "ryKEJNcrZHgErOLi1i01B", - "type": "arrow" - }, - { - "id": "zA0bKm17Yhzy0YApbzKzU", - "type": "arrow" - }, - { - "id": "txiJPesNC-s3bpTySkzdn", - "type": "arrow" - } - ], - "updated": 1672678669096, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 651, - "versionNonce": 1165864466, - "isDeleted": false, - "id": "hc_oPWTAdbkoRobdAwyLp", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1224.284467859403, - "y": 842.0306891097886, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 227.1428571428571, - "height": 118.57142857142844, - "seed": 874036042, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "OFUuNxW3hIQmQLp30HxKz" - }, - { - "id": "ryKEJNcrZHgErOLi1i01B", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 849, - "versionNonce": 487158798, - "isDeleted": false, - "id": "SGvjpM_f78YrFAFAWW5VM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 791.5250742221616, - "y": 965.6264909211623, - "strokeColor": "#000000", - "backgroundColor": "#fd7e14", - "width": 159, - "height": 80, - "seed": 218158678, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "hasibQJ0PGcZ9l6vF9sVv", - "type": "text" - }, - { - "id": "w4GzJ4mNUuFmPe-bRQibL", - "type": "arrow" - }, - { - "id": "Vh7VCMaMFFWUe_gRNKkPR", - "type": "arrow" - }, - { - "id": "WP0Fzn9WjDT2fqCmcNNUb", - "type": "arrow" - }, - { - "id": "j8Fs_n05ESoCYmivqBQts", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 763, - "versionNonce": 696392658, - "isDeleted": false, - "id": "hasibQJ0PGcZ9l6vF9sVv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 811.0250742221616, - "y": 988.1264909211623, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 120, - "height": 35, - "seed": 1625219594, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "operator", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "SGvjpM_f78YrFAFAWW5VM", - "originalText": "operator" - }, - { - "type": "rectangle", - "version": 775, - "versionNonce": 1008452174, - "isDeleted": false, - "id": "AdpKoJr15rbckvpQEh0xC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dotted", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 739.1143934184697, - "y": 903.3197037227569, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 280.31817931957227, - "height": 182.59250148411982, - "seed": 1487132310, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 482, - "versionNonce": 1983041938, - "isDeleted": false, - "id": "JFgCCIwCpzbEEitvXYH9O", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 743.4824867879503, - "y": 906.3239785357218, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 120, - "height": 25, - "seed": 606006154, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "zora-system", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "zora-system" - }, - { - "type": "text", - "version": 382, - "versionNonce": 1481263246, - "isDeleted": false, - "id": "OFUuNxW3hIQmQLp30HxKz", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1316.284467859403, - "y": 883.8164033955028, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 43, - "height": 35, - "seed": 357990666, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "prd", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "hc_oPWTAdbkoRobdAwyLp", - "originalText": "prd" - }, - { - "type": "text", - "version": 458, - "versionNonce": 1590087506, - "isDeleted": false, - "id": "celW1lxpERJp32VnuxG80", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 217.80923895133787, - "y": 850.38381632681, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 278, - "height": 35, - "seed": 515853910, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": "", - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Management Cluster", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Management Cluster" - }, - { - "type": "rectangle", - "version": 689, - "versionNonce": 1900938958, - "isDeleted": false, - "id": "3u8AmVglytwfA-f6-udiJ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1230.7130392879742, - "y": 991.3164033955023, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 227.1428571428571, - "height": 118.57142857142844, - "seed": 743878346, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "3ZmOhMc4ehO3hX-voxGuQ", - "type": "text" - }, - { - "id": "zA0bKm17Yhzy0YApbzKzU", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 429, - "versionNonce": 395646226, - "isDeleted": false, - "id": "3ZmOhMc4ehO3hX-voxGuQ", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1324.2130392879742, - "y": 1033.1021176812164, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 40, - "height": 35, - "seed": 1825045206, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "hml", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "3u8AmVglytwfA-f6-udiJ", - "originalText": "hml" - }, - { - "type": "rectangle", - "version": 743, - "versionNonce": 666893582, - "isDeleted": false, - "id": "OnknN9TXsfWttAHqi2e-H", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1236.42732500226, - "y": 1148.4592605383593, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 227.1428571428571, - "height": 118.57142857142844, - "seed": 1967932426, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "t84msC2gDWIc0onpksaCO", - "type": "text" - }, - { - "id": "txiJPesNC-s3bpTySkzdn", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 482, - "versionNonce": 840213202, - "isDeleted": false, - "id": "t84msC2gDWIc0onpksaCO", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1326.42732500226, - "y": 1190.2449748240736, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 47, - "height": 35, - "seed": 126966166, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "dev", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "OnknN9TXsfWttAHqi2e-H", - "originalText": "dev" - }, - { - "type": "rectangle", - "version": 672, - "versionNonce": 1806864782, - "isDeleted": false, - "id": "AyLr50kly-cYfSvyRRrhm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 539.3756164247947, - "y": 1221.560648315197, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 211, - "height": 62, - "seed": 1944238294, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "MLDJOp-p0XcbjdudkljML", - "type": "text" - }, - { - "id": "Vh7VCMaMFFWUe_gRNKkPR", - "type": "arrow" - }, - { - "id": "LrxZ_jjxg4cWrN2GTzEca", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 607, - "versionNonce": 1269012050, - "isDeleted": false, - "id": "MLDJOp-p0XcbjdudkljML", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 562.8756164247947, - "y": 1235.060648315197, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 164, - "height": 35, - "seed": 996304778, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "ClusterScan", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "AyLr50kly-cYfSvyRRrhm", - "originalText": "ClusterScan" - }, - { - "type": "rectangle", - "version": 876, - "versionNonce": 1657089998, - "isDeleted": false, - "id": "B9WNMPD4KYxfeQgIaRLcF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 535.3368528962321, - "y": 1099.5797738193621, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 211, - "height": 62, - "seed": 1084430346, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "If4c0D8ICvOhYsX8u_N81", - "type": "text" - }, - { - "id": "w4GzJ4mNUuFmPe-bRQibL", - "type": "arrow" - }, - { - "id": "9vP2ksBlzTvl0BICWsiBn", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 811, - "versionNonce": 2067856402, - "isDeleted": false, - "id": "If4c0D8ICvOhYsX8u_N81", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 590.3368528962321, - "y": 1113.0797738193621, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 101, - "height": 35, - "seed": 1623311766, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Cluster", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "B9WNMPD4KYxfeQgIaRLcF", - "originalText": "Cluster" - }, - { - "type": "rectangle", - "version": 739, - "versionNonce": 308938254, - "isDeleted": false, - "id": "tTRI8_KiWRy_91oCCVmjl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 543.5572370962152, - "y": 1306.2472604622828, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 211, - "height": 62, - "seed": 2036659402, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "id": "Gz_IoTp_3aAL714ShlgH6", - "type": "text" - }, - { - "id": "WP0Fzn9WjDT2fqCmcNNUb", - "type": "arrow" - }, - { - "id": "bLckxPIhS7MNSKwsCjY_1", - "type": "arrow" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 688, - "versionNonce": 632007122, - "isDeleted": false, - "id": "Gz_IoTp_3aAL714ShlgH6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 560.0572370962152, - "y": 1319.7472604622828, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 178, - "height": 35, - "seed": 1932072150, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "ClusterIssue", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "tTRI8_KiWRy_91oCCVmjl", - "originalText": "ClusterIssue" - }, - { - "type": "rectangle", - "version": 967, - "versionNonce": 463082574, - "isDeleted": false, - "id": "tTcKAXhbWONU6E_XpLpYo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -209.12006812955912, - "y": 1537.4137422871652, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 25.71428571428578, - "height": 24.285714285714448, - "seed": 2108396682, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 955, - "versionNonce": 301637522, - "isDeleted": false, - "id": "a0w6Rf5ROavXsfDwnm9Fk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -166.26292527241623, - "y": 1538.4851708585938, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 43, - "height": 25, - "seed": 1031872534, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "CRD", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "CRD" - }, - { - "type": "rectangle", - "version": 1028, - "versionNonce": 405691022, - "isDeleted": false, - "id": "vtaIa8_HqcPC8HlbfM1P1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -61.33508473841613, - "y": 1535.7309134700915, - "strokeColor": "#000000", - "backgroundColor": "#fd7e14", - "width": 25.71428571428578, - "height": 24.285714285714448, - "seed": 1599751318, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1033, - "versionNonce": 207936850, - "isDeleted": false, - "id": "5tsqFB76m1hFgnORVQpua", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -18.47794188127324, - "y": 1536.8023420415204, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 158, - "height": 25, - "seed": 231372746, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Zora Component", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Zora Component" - }, - { - "type": "rectangle", - "version": 1145, - "versionNonce": 2128599246, - "isDeleted": false, - "id": "Z67wtEqz7Z5KIdXUzXTtI", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 200.99217107992723, - "y": 1536.6712247117753, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 25.71428571428578, - "height": 24.285714285714448, - "seed": 739274122, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1150, - "versionNonce": 1111581458, - "isDeleted": false, - "id": "_q_ZQDbQO7rQmTexY0Baz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 243.84931393707012, - "y": 1537.7426532832042, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 152, - "height": 25, - "seed": 765364246, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Target Cluster", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Target Cluster" - }, - { - "type": "rectangle", - "version": 544, - "versionNonce": 122130190, - "isDeleted": false, - "id": "bUgq3Ni4c1IwdDnff5G0E", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 536.2654243248037, - "y": 1165.3684502026495, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 210, - "height": 36, - "seed": 1893166090, - "groupIds": [], - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "LXiOH98roS7pq5QUK347m" - } - ], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 456, - "versionNonce": 503787730, - "isDeleted": false, - "id": "LXiOH98roS7pq5QUK347m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 552.7654243248037, - "y": 1170.8684502026495, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 177, - "height": 25, - "seed": 70188182, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Secret: kubeconfig", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "bUgq3Ni4c1IwdDnff5G0E", - "originalText": "Secret: kubeconfig" - }, - { - "type": "arrow", - "version": 585, - "versionNonce": 232684878, - "isDeleted": false, - "id": "4Ige_dLNnT352G_qJ0P-N", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -154.53685899651316, - "y": 1006.1538422178296, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 376.3227896015145, - "height": 4.8494451990105745, - "seed": 1377088406, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "JDOAmO8H4O8DjRc7fx06c", - "focus": 1.061195945349848, - "gap": 15.894518305338583 - }, - "endBinding": { - "elementId": "d1ZH264XLM8uPU-y68hLx", - "focus": -0.062472370200961615, - "gap": 6.266979026112125 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 376.3227896015145, - 4.8494451990105745 - ] - ] - }, - { - "type": "text", - "version": 276, - "versionNonce": 592266898, - "isDeleted": false, - "id": "NTeoybBdCuyh1babJ45ni", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -112.73641677499734, - "y": 1015.2067889633729, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 201, - "height": 25, - "seed": 1780785110, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "kubectl get clusters", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "kubectl get clusters" - }, - { - "type": "line", - "version": 295, - "versionNonce": 2013111182, - "isDeleted": false, - "id": "HDiP7VH6RUEA0WHwpltYD", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 562.1532201335165, - "y": 1378.290835618807, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 198.57532338848205, - "height": 0, - "seed": 1176252618, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 198.57532338848205, - 0 - ] - ] - }, - { - "type": "line", - "version": 295, - "versionNonce": 1254794322, - "isDeleted": false, - "id": "9hGCOBt5qhIlzxicb4sDk", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 572.1532201335165, - "y": 1388.290835618807, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 198.57532338848205, - "height": 0, - "seed": 1795696790, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 198.57532338848205, - 0 - ] - ] - }, - { - "type": "line", - "version": 295, - "versionNonce": 400425422, - "isDeleted": false, - "id": "rvxprlG0tBisVqMOkA7fk", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 582.1532201335165, - "y": 1398.290835618807, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 198.57532338848205, - "height": 0, - "seed": 140682710, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 198.57532338848205, - 0 - ] - ] - }, - { - "type": "line", - "version": 295, - "versionNonce": 1582713362, - "isDeleted": false, - "id": "GqSdWCtzRRT9cUSJWfzjP", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 592.1532201335165, - "y": 1408.290835618807, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 198.57532338848205, - "height": 0, - "seed": 551799434, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 198.57532338848205, - 0 - ] - ] - }, - { - "type": "arrow", - "version": 832, - "versionNonce": 278435854, - "isDeleted": false, - "id": "ryKEJNcrZHgErOLi1i01B", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1055.8713186952905, - "y": 1085.4935968561845, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 161.85248961115985, - "height": 179.30355917432348, - "seed": 861263882, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "6T4gFc_wkndMmGBPgHlyt", - "gap": 16.507212431104506, - "focus": 0.5897334962279493 - }, - "endBinding": { - "elementId": "hc_oPWTAdbkoRobdAwyLp", - "gap": 6.56065955295287, - "focus": 0.6926496903863334 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 161.85248961115985, - -179.30355917432348 - ] - ] - }, - { - "type": "arrow", - "version": 819, - "versionNonce": 1424439250, - "isDeleted": false, - "id": "zA0bKm17Yhzy0YApbzKzU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1057.2314236500065, - "y": 1104.880613053831, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 168.65301438473762, - "height": 50.63943206470253, - "seed": 373929878, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "6T4gFc_wkndMmGBPgHlyt", - "gap": 17.867317385820286, - "focus": 0.2585973256570773 - }, - "endBinding": { - "elementId": "3u8AmVglytwfA-f6-udiJ", - "gap": 4.828601253230204, - "focus": 0.3417144779228769 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 168.65301438473762, - -50.63943206470253 - ] - ] - }, - { - "type": "arrow", - "version": 813, - "versionNonce": 975595086, - "isDeleted": false, - "id": "txiJPesNC-s3bpTySkzdn", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1057.2314236500065, - "y": 1127.6909438950968, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 178.17374906774694, - "height": 82.7413648748659, - "seed": 2029613590, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "6T4gFc_wkndMmGBPgHlyt", - "gap": 17.867317385820286, - "focus": -0.44309892624491715 - }, - "endBinding": { - "elementId": "OnknN9TXsfWttAHqi2e-H", - "gap": 1.0221522845066602, - "focus": -0.4990147978094829 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 178.17374906774694, - 82.7413648748659 - ] - ] - }, - { - "type": "text", - "version": 422, - "versionNonce": 90205326, - "isDeleted": false, - "id": "rRy7I6fqWAOII_x6IYdCZ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1067.5112137405754, - "y": 1093.7698446756806, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 112, - "height": 35, - "seed": 973805270, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "get, list", - "baseline": 25, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "get, list" - }, - { - "type": "arrow", - "version": 207, - "versionNonce": 1351936850, - "isDeleted": false, - "id": "w4GzJ4mNUuFmPe-bRQibL", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 870.8970448539645, - "y": 1047.7853316229086, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 119.68923601497545, - "height": 87.04671710180037, - "seed": 1915942218, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "SGvjpM_f78YrFAFAWW5VM", - "focus": -0.30265149886702686, - "gap": 2.158840701746385 - }, - "endBinding": { - "elementId": "B9WNMPD4KYxfeQgIaRLcF", - "focus": 0.6710412940766041, - "gap": 4.87095594275695 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -44.88346350561574, - 55.76430314334084 - ], - [ - -119.68923601497545, - 87.04671710180037 - ] - ] - }, - { - "type": "arrow", - "version": 213, - "versionNonce": 1610590926, - "isDeleted": false, - "id": "Vh7VCMaMFFWUe_gRNKkPR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 876.337464672827, - "y": 1047.7853316229086, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 118.3291310602599, - "height": 206.73595311677605, - "seed": 251005142, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "SGvjpM_f78YrFAFAWW5VM", - "focus": -0.20784373512796686, - "gap": 2.158840701746385 - }, - "endBinding": { - "elementId": "AyLr50kly-cYfSvyRRrhm", - "focus": 0.8725306594732745, - "gap": 7.632717187772414 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -36.04278129996442, - 108.80839637725035 - ], - [ - -118.3291310602599, - 206.73595311677605 - ] - ] - }, - { - "type": "arrow", - "version": 201, - "versionNonce": 1631564050, - "isDeleted": false, - "id": "WP0Fzn9WjDT2fqCmcNNUb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 872.2571498086801, - "y": 1053.225751441771, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 115.60892115082856, - "height": 288.342250399714, - "seed": 2052680458, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "startBinding": { - "elementId": "SGvjpM_f78YrFAFAWW5VM", - "focus": -0.10155489704962357, - "gap": 7.599260520608823 - }, - "endBinding": { - "elementId": "tTRI8_KiWRy_91oCCVmjl", - "focus": 0.8804210320288132, - "gap": 2.090991561636315 - }, - "lastCommittedPoint": null, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -22.44173175280787, - 142.8110202451412 - ], - [ - -115.60892115082856, - 288.342250399714 - ] - ] - }, - { - "type": "text", - "version": 983, - "versionNonce": 361566866, - "isDeleted": false, - "id": "TMAnpzy29dPiJE-1F02IB", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 843.9300072221439, - "y": 1209.525294752228, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 121, - "height": 35, - "seed": 618056458, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672679729847, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Reconcile", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Reconcile" - }, - { - "type": "rectangle", - "version": 1178, - "versionNonce": 604749522, - "isDeleted": false, - "id": "b5mPras5k5txviox3KXU3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dotted", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 778.9343054259426, - "y": 1537.542384553225, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 25.71428571428578, - "height": 24.285714285714448, - "seed": 1737594122, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1202, - "versionNonce": 1118949198, - "isDeleted": false, - "id": "OYIGeR6MCpktIzBE93srV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 823.2397397056202, - "y": 1538.545346650798, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 106, - "height": 25, - "seed": 383884118, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Namespace", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Namespace" - }, - { - "type": "text", - "version": 335, - "versionNonce": 1435505810, - "isDeleted": false, - "id": "-YSnA_KwmTVXVUatOXxSU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 6.7608336545790735, - "y": 1040.4567635784065, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 124, - "height": 25, - "seed": 1340801370, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "clusterscans", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "clusterscans" - }, - { - "type": "text", - "version": 356, - "versionNonce": 446084494, - "isDeleted": false, - "id": "ib-XUIcTybokhb1_lCckw", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 6.474856254238489, - "y": 1067.3953353173458, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 129, - "height": 25, - "seed": 283561414, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "clusterissues", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "clusterissues" - }, - { - "type": "line", - "version": 783, - "versionNonce": 126071378, - "isDeleted": false, - "id": "VgBpnerzAdb-ptgv_FUMW", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1257.6448223901616, - "y": 876.3554548912084, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 50.872552063656286, - "height": 49.48249785579689, - "seed": 1481626010, - "groupIds": [ - "1l-_Woj5om1oZ9Ig19_1s", - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -1.3115650468715785, - 0.3474133526632701 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -20.25017438531637, - 9.750482868436373 - ], - [ - -20.905359242352013, - 11.101291002704453 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.28567608829117, - 31.45923493670271 - ], - [ - -24.774715491646944, - 32.70785237527916 - ], - [ - -24.583478771558603, - 32.97558260554791 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -11.129776379862978, - 49.15839168796223 - ], - [ - -9.663827224675448, - 49.48249785579689 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 11.48695215532948, - 49.14584411313763 - ], - [ - 12.669433418267904, - 48.218743081312766 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 25.58687597536511, - 31.610234421819158 - ], - [ - 25.571534984536722, - 30.111814465259762 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 20.53902127516687, - 9.731359063443975 - ], - [ - 19.36271653161873, - 8.800076266583918 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - -0.015935237649678337, - -1.734723475976807e-18 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 1300, - "versionNonce": 1770312654, - "isDeleted": false, - "id": "ASA0she7A7e5BbHEQLrwC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1257.644247686098, - "y": 882.6557111915791, - "strokeColor": "#326ce5", - "backgroundColor": "#fff", - "width": 37.25081945503691, - "height": 36.55110370177384, - "seed": 1921199366, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -0.763354876401404, - 0.3762980606460073 - ], - [ - -1.0438348166027671, - 1.1792934555021581 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -0.8972199915357885, - 2.4876714548438046 - ], - [ - -0.7920398239836638, - 4.41597503323698 - ], - [ - -1.1394538415651116, - 4.965780247284959 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -3.080505610077996, - 5.71160408255246 - ], - [ - -5.022330963327559, - 6.304163911568683 - ], - [ - -6.845677786656399, - 7.172373715574011 - ], - [ - -8.521116424189604, - 8.300246583282124 - ], - [ - -10.019211140800904, - 9.671797123219552 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -11.031172442478647, - 9.337132815570726 - ], - [ - -12.460667366834947, - 8.046284337550144 - ], - [ - -13.157087405949898, - 7.305243353296811 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -14.130800337736295, - 6.838306694372137 - ], - [ - -14.977023009354593, - 7.214405659535816 - ], - [ - -15.170252014102399, - 8.051463859716112 - ], - [ - -14.715666114239259, - 8.780952746556453 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -13.61605492623689, - 9.470997930705119 - ], - [ - -12.02560270302248, - 10.58654663607644 - ], - [ - -11.81364960405969, - 11.19850383639671 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -12.663383043343293, - 13.729227789525805 - ], - [ - -13.432188728502993, - 16.102728623949886 - ], - [ - -13.759059435897406, - 18.57633193122058 - ], - [ - -13.630398159934447, - 21.088628153638926 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.532397962858736, - 21.675087453906833 - ], - [ - -16.435202881293154, - 21.98903519270465 - ], - [ - -17.45513256170216, - 22.068715940391602 - ], - [ - -17.737206025668506, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -18.292259913366756, - 22.356659681460652 - ], - [ - -18.611600708034853, - 22.788374677769085 - ], - [ - -18.464824022900185, - 23.845978998721524 - ], - [ - -18.38581731220873, - 23.936462576090303 - ], - [ - -17.878088876601407, - 24.222546066240575 - ], - [ - -17.29576802670259, - 24.199411475157763 - ], - [ - -17.275050697945154, - 24.199411475157763 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.035199539842104, - 23.82012698227699 - ], - [ - -14.183390421512353, - 23.27828938705385 - ], - [ - -13.574620268722027, - 23.493431053359405 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -12.112107410370559, - 25.72442511682881 - ], - [ - -10.738340983309326, - 27.80263239527926 - ], - [ - -9.013774395654409, - 29.59995698312531 - ], - [ - -6.976954660520658, - 31.06799892059641 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.075759213200076, - 32.07358308758858 - ], - [ - -8.036724714773126, - 33.81383870321276 - ], - [ - -8.607247257578543, - 34.66324690254815 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.886827468577374, - 35.50075192770404 - ], - [ - -8.742004502851252, - 36.01784089060601 - ], - [ - -8.366098553918508, - 36.401313987679686 - ], - [ - -7.816965857053191, - 36.55110370177384 - ], - [ - -7.706840218512803, - 36.54533753185084 - ], - [ - -7.16885990828297, - 36.325715457286734 - ], - [ - -6.825558504252345, - 35.85688359174788 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.3873067929099525, - 34.61384386630208 - ], - [ - -6.0157900634652846, - 33.573000041372545 - ], - [ - -5.566583541156827, - 32.70785266024412 - ], - [ - -5.110802308493361, - 32.48474413502013 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -2.455971958489142, - 32.732516183046116 - ], - [ - 0.023292651618423227, - 32.964211650828084 - ], - [ - 2.5036606458494117, - 32.74461997252078 - ], - [ - 4.922749786285883, - 32.07358308758858 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.6765404804718065, - 32.80665873273633 - ], - [ - 6.4032420305597, - 34.59153301377963 - ], - [ - 6.712408438156163, - 35.56524670547247 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 7.179027456196865, - 36.296811656655166 - ], - [ - 7.6706777917473286, - 36.512770982269764 - ], - [ - 8.669632535122132, - 36.13573885202099 - ], - [ - 8.736328001885967, - 36.04493307432972 - ], - [ - 8.906884438654954, - 35.48996429615062 - ], - [ - 8.76182742175113, - 34.927791605099856 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.052658432610022, - 33.794713378407465 - ], - [ - 7.096474262238299, - 32.11023793371498 - ], - [ - 7.20484299713317, - 31.47278283334236 - ], - [ - 7.027948940812576, - 31.044092264589768 - ], - [ - 9.059415895116322, - 29.567113827606978 - ], - [ - 10.777582550893055, - 27.76219321517602 - ], - [ - 12.144052356499268, - 25.677885407977218 - ], - [ - 13.120431799917194, - 23.36275146594211 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 14.167452144237089, - 23.222512255747866 - ], - [ - 16.019262022473253, - 23.76434985097099 - ], - [ - 16.972257625502206, - 24.130886153731986 - ], - [ - 17.246361950830853, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.83568761811903, - 24.21569171032261 - ], - [ - 18.31108811476151, - 23.965986460361425 - ], - [ - 18.607515451115297, - 23.518231359317237 - ], - [ - 18.639218747002054, - 22.94991862438427 - ], - [ - 18.60733003394858, - 22.833665100464394 - ], - [ - 18.27464604243303, - 22.35535264241645 - ], - [ - 17.740392313292105, - 22.12290030783905 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 16.411294705473757, - 21.969909867899357 - ], - [ - 14.508492066758599, - 21.655965168727235 - ], - [ - 14.049523786565212, - 21.196996888533807 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.73226285577153, - 18.559851080760573 - ], - [ - 13.39248133828329, - 16.091194764291018 - ], - [ - 12.613884258888199, - 13.724023950354376 - ], - [ - 11.410456935359512, - 11.518825670254394 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.984165005881982, - 10.569015594942522 - ], - [ - 13.561867519163837, - 9.459842504443921 - ], - [ - 14.441556469565695, - 8.945097092944515 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 15.178349576925338, - 7.815810799293218 - ], - [ - 15.028368366413035, - 7.300193015222433 - ], - [ - 14.615274117046312, - 6.908611716636007 - ], - [ - 14.462274558229574, - 6.841493741902078 - ], - [ - 13.870641815047035, - 6.809621746789864 - ], - [ - 13.353102987543796, - 7.09807006572251 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 12.42082243355301, - 8.02716205237053 - ], - [ - 11.029576638994495, - 9.338727099242107 - ], - [ - 10.385744403936314, - 9.408846704339243 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 8.09513720154745, - 8.044790361526335 - ], - [ - 5.959414125899516, - 6.767389187532886 - ], - [ - 3.6300608149134885, - 5.8903903058615485 - ], - [ - 1.1617631742746461, - 5.440684525034469 - ], - [ - 1.1378565182680294, - 4.967373771049928 - ], - [ - 0.7904425006866282, - 4.438285885759382 - ], - [ - 0.9115594257012792, - 2.5147628786611107 - ], - [ - 1.0581757705810848, - 1.5059893844197219 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 0.7782931168266872, - 0.3842664393772693 - ], - [ - 0.014340953978292355, - 0.007968378731262807 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 947, - "versionNonce": 2092800018, - "isDeleted": false, - "id": "CjfsQRg7IiuwcHLFoD7wH", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1256.319856204265, - "y": 891.0176690034762, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.393680887969856, - "height": 6.369775751776067, - "seed": 1280740954, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.3187275501863063, - 5.566582021344026 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.8717205716706387, - 6.369775751776067 - ], - [ - -1.8279047420423864, - 6.283719389216403 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -3.9621064850353154, - 1.2473590335431695 - ], - [ - -1.1298911791624642, - 0.18167386770913002 - ], - [ - -0.003187047529933336, - 5.298279176502163e-15 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 942, - "versionNonce": 1771383310, - "isDeleted": false, - "id": "o8J2RIYeiav-EXUeGXMrC", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1259.0498930536478, - "y": 890.8884522478527, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.358620325514874, - "height": 6.395273651828406, - "seed": 887331910, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 3.430904540081383, - 1.0107652089709898 - ], - [ - 6.358620325514874, - 3.0661616164740497 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 0.8510040028196162, - 6.395273651828407 - ], - [ - 0.4637496113947366, - 6.054235249119703 - ], - [ - 0.3155405026563627, - 5.560206406471309 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 946, - "versionNonce": 87344594, - "isDeleted": false, - "id": "WS8BGxrD-eNRmbf4XsMuk", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1248.3491435656704, - "y": 896.0789641898034, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.022363254007489, - "height": 6.916394678200529, - "seed": 837268250, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 4.175334706972646, - 3.725927569369057 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.4717514046365565, - 4.664582218419733 - ], - [ - 3.807204120540214, - 5.357815969911158 - ], - [ - 3.807204120540221, - 5.37374968774801 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.3506318359784104, - 3.327306497697913 - ], - [ - 0.0015927638585428532, - -0.0015942836713908797 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 947, - "versionNonce": 700495950, - "isDeleted": false, - "id": "vXHCk36KnoeR1lez64nk5", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1266.9941271719752, - "y": 896.0811987479344, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.030331632738752, - "height": 6.895675069723837, - "seed": 133440390, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 1.361366274082361, - 3.3175584181285167 - ], - [ - 1.5968278380871164, - 6.895675069723839 - ], - [ - -3.7689565105553102, - 5.3498460713670735 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -4.433503794651637, - 4.6358957510246155 - ], - [ - -4.1370855771748944, - 3.7211477579805683 - ], - [ - 0.0063740950598725025, - 0.01274819011975109 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 943, - "versionNonce": 1509964690, - "isDeleted": false, - "id": "g1KJDV_4hlhNItcWj896D", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1256.7884623520772, - "y": 900.0470967234313, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 3.8135782156000984, - "height": 3.7211492777934096, - "seed": 997605338, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1.7083821006991204, - 1.1102230246251565e-16 - ], - [ - 2.752213877676234, - 1.3259090404755651 - ], - [ - 2.372929384795452, - 2.983292301444334 - ], - [ - 0.8382542928870336, - 3.721149277793409 - ], - [ - -0.6996078465513131, - 2.983292301444333 - ], - [ - -1.0613643379238646, - 1.3259090404755602 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 948, - "versionNonce": 1910537870, - "isDeleted": false, - "id": "lrsvMWitanoc5mKTi1kFs", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1262.2610196321293, - "y": 904.5698439281725, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.5578252343579155, - "height": 6.498862575334826, - "seed": 233947846, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.2151416663055704, - 1.5404344466674047e-15 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.0017861333277525, - 2.5857548563296193 - ], - [ - 4.000034934323403, - 4.084299437542195 - ], - [ - 2.7628221713142747, - 5.398478562502228 - ], - [ - 1.3179391419314586, - 6.498862575334826 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.7502616887665088, - 0.4662481837071927 - ], - [ - -0.006374095059873417, - 0.02390665600663141 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 946, - "versionNonce": 2035743058, - "isDeleted": false, - "id": "iGWfY6YCnlfwdJb3b-dg9", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1253.0603215563694, - "y": 904.7021053830537, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.517984860514442, - "height": 6.4526450668057915, - "seed": 1427453082, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669097, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.7713217353198448, - 0.4270947652683569 - ], - [ - 0.8462226716183014, - 1.3035951483274668 - ], - [ - 0.8462226716183012, - 1.3243132369913262 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -3.9283210455548736, - 4.061389778759983 - ], - [ - -5.67176218889614, - 0.9434329406263107 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.009562662402646045, - 0.014340953978288919 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 949, - "versionNonce": 648903886, - "isDeleted": false, - "id": "Pa8rLGBe5T7XlhC3mjQeX", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1257.664671597739, - "y": 906.826968443797, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 7.067792354281676, - "height": 5.943276753141823, - "seed": 427391494, - "groupIds": [ - "m-cn8YeLwkkMord2yBwqP" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.49744082247897325, - 0.12416566957594494 - ], - [ - 0.8557853340209567, - 0.49084179511845694 - ], - [ - 0.8765034226848066, - 0.4908417951184617 - ], - [ - 3.576128736397814, - 5.3625957812996585 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - -0.518131554511648, - 5.943276753141823 - ], - [ - -3.4916636178838614, - 5.372158443702313 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - 0.014343993603975418, - 0.030277711440816472 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 738, - "versionNonce": 42991378, - "isDeleted": false, - "id": "FUP0pvnToBWDXyOZQG7DA", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1260.5804158399005, - "y": 1025.7930150672646, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 50.872552063656286, - "height": 49.48249785579689, - "seed": 1387742490, - "groupIds": [ - "i9G5TvaPFnxyS3oxFD8rc", - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -1.3115650468715785, - 0.3474133526632701 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -20.25017438531637, - 9.750482868436373 - ], - [ - -20.905359242352013, - 11.101291002704453 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.28567608829117, - 31.45923493670271 - ], - [ - -24.774715491646944, - 32.70785237527916 - ], - [ - -24.583478771558603, - 32.97558260554791 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -11.129776379862978, - 49.15839168796223 - ], - [ - -9.663827224675448, - 49.48249785579689 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 11.48695215532948, - 49.14584411313763 - ], - [ - 12.669433418267904, - 48.218743081312766 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 25.58687597536511, - 31.610234421819158 - ], - [ - 25.571534984536722, - 30.111814465259762 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 20.53902127516687, - 9.731359063443975 - ], - [ - 19.36271653161873, - 8.800076266583918 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - -0.015935237649678337, - -1.734723475976807e-18 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 1255, - "versionNonce": 767603470, - "isDeleted": false, - "id": "qXK62414dbhfPvzP6eIS1", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1260.5798411358373, - "y": 1032.0932713676352, - "strokeColor": "#326ce5", - "backgroundColor": "#fff", - "width": 37.25081945503691, - "height": 36.55110370177384, - "seed": 1260302726, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -0.763354876401404, - 0.3762980606460073 - ], - [ - -1.0438348166027671, - 1.1792934555021581 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -0.8972199915357885, - 2.4876714548438046 - ], - [ - -0.7920398239836638, - 4.41597503323698 - ], - [ - -1.1394538415651116, - 4.965780247284959 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -3.080505610077996, - 5.71160408255246 - ], - [ - -5.022330963327559, - 6.304163911568683 - ], - [ - -6.845677786656399, - 7.172373715574011 - ], - [ - -8.521116424189604, - 8.300246583282124 - ], - [ - -10.019211140800904, - 9.671797123219552 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -11.031172442478647, - 9.337132815570726 - ], - [ - -12.460667366834947, - 8.046284337550144 - ], - [ - -13.157087405949898, - 7.305243353296811 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -14.130800337736295, - 6.838306694372137 - ], - [ - -14.977023009354593, - 7.214405659535816 - ], - [ - -15.170252014102399, - 8.051463859716112 - ], - [ - -14.715666114239259, - 8.780952746556453 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -13.61605492623689, - 9.470997930705119 - ], - [ - -12.02560270302248, - 10.58654663607644 - ], - [ - -11.81364960405969, - 11.19850383639671 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -12.663383043343293, - 13.729227789525805 - ], - [ - -13.432188728502993, - 16.102728623949886 - ], - [ - -13.759059435897406, - 18.57633193122058 - ], - [ - -13.630398159934447, - 21.088628153638926 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.532397962858736, - 21.675087453906833 - ], - [ - -16.435202881293154, - 21.98903519270465 - ], - [ - -17.45513256170216, - 22.068715940391602 - ], - [ - -17.737206025668506, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -18.292259913366756, - 22.356659681460652 - ], - [ - -18.611600708034853, - 22.788374677769085 - ], - [ - -18.464824022900185, - 23.845978998721524 - ], - [ - -18.38581731220873, - 23.936462576090303 - ], - [ - -17.878088876601407, - 24.222546066240575 - ], - [ - -17.29576802670259, - 24.199411475157763 - ], - [ - -17.275050697945154, - 24.199411475157763 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.035199539842104, - 23.82012698227699 - ], - [ - -14.183390421512353, - 23.27828938705385 - ], - [ - -13.574620268722027, - 23.493431053359405 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -12.112107410370559, - 25.72442511682881 - ], - [ - -10.738340983309326, - 27.80263239527926 - ], - [ - -9.013774395654409, - 29.59995698312531 - ], - [ - -6.976954660520658, - 31.06799892059641 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.075759213200076, - 32.07358308758858 - ], - [ - -8.036724714773126, - 33.81383870321276 - ], - [ - -8.607247257578543, - 34.66324690254815 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.886827468577374, - 35.50075192770404 - ], - [ - -8.742004502851252, - 36.01784089060601 - ], - [ - -8.366098553918508, - 36.401313987679686 - ], - [ - -7.816965857053191, - 36.55110370177384 - ], - [ - -7.706840218512803, - 36.54533753185084 - ], - [ - -7.16885990828297, - 36.325715457286734 - ], - [ - -6.825558504252345, - 35.85688359174788 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.3873067929099525, - 34.61384386630208 - ], - [ - -6.0157900634652846, - 33.573000041372545 - ], - [ - -5.566583541156827, - 32.70785266024412 - ], - [ - -5.110802308493361, - 32.48474413502013 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -2.455971958489142, - 32.732516183046116 - ], - [ - 0.023292651618423227, - 32.964211650828084 - ], - [ - 2.5036606458494117, - 32.74461997252078 - ], - [ - 4.922749786285883, - 32.07358308758858 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.6765404804718065, - 32.80665873273633 - ], - [ - 6.4032420305597, - 34.59153301377963 - ], - [ - 6.712408438156163, - 35.56524670547247 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 7.179027456196865, - 36.296811656655166 - ], - [ - 7.6706777917473286, - 36.512770982269764 - ], - [ - 8.669632535122132, - 36.13573885202099 - ], - [ - 8.736328001885967, - 36.04493307432972 - ], - [ - 8.906884438654954, - 35.48996429615062 - ], - [ - 8.76182742175113, - 34.927791605099856 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.052658432610022, - 33.794713378407465 - ], - [ - 7.096474262238299, - 32.11023793371498 - ], - [ - 7.20484299713317, - 31.47278283334236 - ], - [ - 7.027948940812576, - 31.044092264589768 - ], - [ - 9.059415895116322, - 29.567113827606978 - ], - [ - 10.777582550893055, - 27.76219321517602 - ], - [ - 12.144052356499268, - 25.677885407977218 - ], - [ - 13.120431799917194, - 23.36275146594211 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 14.167452144237089, - 23.222512255747866 - ], - [ - 16.019262022473253, - 23.76434985097099 - ], - [ - 16.972257625502206, - 24.130886153731986 - ], - [ - 17.246361950830853, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.83568761811903, - 24.21569171032261 - ], - [ - 18.31108811476151, - 23.965986460361425 - ], - [ - 18.607515451115297, - 23.518231359317237 - ], - [ - 18.639218747002054, - 22.94991862438427 - ], - [ - 18.60733003394858, - 22.833665100464394 - ], - [ - 18.27464604243303, - 22.35535264241645 - ], - [ - 17.740392313292105, - 22.12290030783905 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 16.411294705473757, - 21.969909867899357 - ], - [ - 14.508492066758599, - 21.655965168727235 - ], - [ - 14.049523786565212, - 21.196996888533807 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.73226285577153, - 18.559851080760573 - ], - [ - 13.39248133828329, - 16.091194764291018 - ], - [ - 12.613884258888199, - 13.724023950354376 - ], - [ - 11.410456935359512, - 11.518825670254394 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.984165005881982, - 10.569015594942522 - ], - [ - 13.561867519163837, - 9.459842504443921 - ], - [ - 14.441556469565695, - 8.945097092944515 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 15.178349576925338, - 7.815810799293218 - ], - [ - 15.028368366413035, - 7.300193015222433 - ], - [ - 14.615274117046312, - 6.908611716636007 - ], - [ - 14.462274558229574, - 6.841493741902078 - ], - [ - 13.870641815047035, - 6.809621746789864 - ], - [ - 13.353102987543796, - 7.09807006572251 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 12.42082243355301, - 8.02716205237053 - ], - [ - 11.029576638994495, - 9.338727099242107 - ], - [ - 10.385744403936314, - 9.408846704339243 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 8.09513720154745, - 8.044790361526335 - ], - [ - 5.959414125899516, - 6.767389187532886 - ], - [ - 3.6300608149134885, - 5.8903903058615485 - ], - [ - 1.1617631742746461, - 5.440684525034469 - ], - [ - 1.1378565182680294, - 4.967373771049928 - ], - [ - 0.7904425006866282, - 4.438285885759382 - ], - [ - 0.9115594257012792, - 2.5147628786611107 - ], - [ - 1.0581757705810848, - 1.5059893844197219 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 0.7782931168266872, - 0.3842664393772693 - ], - [ - 0.014340953978292355, - 0.007968378731262807 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 902, - "versionNonce": 304237778, - "isDeleted": false, - "id": "6YvvbE4T6hrh21VD7l-Rn", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1259.2554496540042, - "y": 1040.4552291795326, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.393680887969856, - "height": 6.369775751776067, - "seed": 8622554, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.3187275501863063, - 5.566582021344026 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.8717205716706387, - 6.369775751776067 - ], - [ - -1.8279047420423864, - 6.283719389216403 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -3.9621064850353154, - 1.2473590335431695 - ], - [ - -1.1298911791624642, - 0.18167386770913002 - ], - [ - -0.003187047529933336, - 5.298279176502163e-15 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 897, - "versionNonce": 1368596814, - "isDeleted": false, - "id": "Tes9xwUihWCbbu-XJ8Ulm", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1261.9854865033867, - "y": 1040.326012423909, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.358620325514874, - "height": 6.395273651828406, - "seed": 1754960070, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 3.430904540081383, - 1.0107652089709898 - ], - [ - 6.358620325514874, - 3.0661616164740497 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 0.8510040028196162, - 6.395273651828407 - ], - [ - 0.4637496113947366, - 6.054235249119703 - ], - [ - 0.3155405026563627, - 5.560206406471309 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 901, - "versionNonce": 497345170, - "isDeleted": false, - "id": "fRfzpnRYcPXpX0A9sZZPx", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1251.2847370154095, - "y": 1045.5165243658598, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.022363254007489, - "height": 6.916394678200529, - "seed": 1890076314, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 4.175334706972646, - 3.725927569369057 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.4717514046365565, - 4.664582218419733 - ], - [ - 3.807204120540214, - 5.357815969911158 - ], - [ - 3.807204120540221, - 5.37374968774801 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.3506318359784104, - 3.327306497697913 - ], - [ - 0.0015927638585428532, - -0.0015942836713908797 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 902, - "versionNonce": 629000078, - "isDeleted": false, - "id": "kUVzneLIUoJG_WB5B34j7", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1269.9297206217143, - "y": 1045.5187589239908, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.030331632738752, - "height": 6.895675069723837, - "seed": 30967814, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 1.361366274082361, - 3.3175584181285167 - ], - [ - 1.5968278380871164, - 6.895675069723839 - ], - [ - -3.7689565105553102, - 5.3498460713670735 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -4.433503794651637, - 4.6358957510246155 - ], - [ - -4.1370855771748944, - 3.7211477579805683 - ], - [ - 0.0063740950598725025, - 0.01274819011975109 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 898, - "versionNonce": 1338949714, - "isDeleted": false, - "id": "-s3enYFHNJzD0CZCPt9QP", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1259.7240558018166, - "y": 1049.4846568994876, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 3.8135782156000984, - "height": 3.7211492777934096, - "seed": 198730586, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1.7083821006991204, - 1.1102230246251565e-16 - ], - [ - 2.752213877676234, - 1.3259090404755651 - ], - [ - 2.372929384795452, - 2.983292301444334 - ], - [ - 0.8382542928870336, - 3.721149277793409 - ], - [ - -0.6996078465513131, - 2.983292301444333 - ], - [ - -1.0613643379238646, - 1.3259090404755602 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 903, - "versionNonce": 1773774286, - "isDeleted": false, - "id": "AhFMdfGhyBg82w29JoFW2", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1265.1966130818682, - "y": 1054.007404104229, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.5578252343579155, - "height": 6.498862575334826, - "seed": 114661190, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.2151416663055704, - 1.5404344466674047e-15 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.0017861333277525, - 2.5857548563296193 - ], - [ - 4.000034934323403, - 4.084299437542195 - ], - [ - 2.7628221713142747, - 5.398478562502228 - ], - [ - 1.3179391419314586, - 6.498862575334826 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.7502616887665088, - 0.4662481837071927 - ], - [ - -0.006374095059873417, - 0.02390665600663141 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 901, - "versionNonce": 1685513746, - "isDeleted": false, - "id": "wcYV6ClnOvEu7SNWVysrJ", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1255.9959150061086, - "y": 1054.1396655591097, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.517984860514442, - "height": 6.4526450668057915, - "seed": 744941594, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.7713217353198448, - 0.4270947652683569 - ], - [ - 0.8462226716183014, - 1.3035951483274668 - ], - [ - 0.8462226716183012, - 1.3243132369913262 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -3.9283210455548736, - 4.061389778759983 - ], - [ - -5.67176218889614, - 0.9434329406263107 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.009562662402646045, - 0.014340953978288919 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 903, - "versionNonce": 1868545038, - "isDeleted": false, - "id": "L0DvMe4U4d6NXqEMUR1c0", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1260.6002650474784, - "y": 1056.264528619853, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 7.067792354281676, - "height": 5.943276753141823, - "seed": 1609481862, - "groupIds": [ - "K8Yn0EZpqUwzPF0V_SLmF" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.49744082247897325, - 0.12416566957594494 - ], - [ - 0.8557853340209567, - 0.49084179511845694 - ], - [ - 0.8765034226848066, - 0.4908417951184617 - ], - [ - 3.576128736397814, - 5.3625957812996585 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - -0.518131554511648, - 5.943276753141823 - ], - [ - -3.4916636178838614, - 5.372158443702313 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - 0.014343993603975418, - 0.030277711440816472 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 777, - "versionNonce": 76829650, - "isDeleted": false, - "id": "1qPAM5HSXRm-lnnoC4fdB", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1267.0219821898977, - "y": 1183.501659552681, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 50.872552063656286, - "height": 49.48249785579689, - "seed": 1511559194, - "groupIds": [ - "eoa0Dj63xreNQQck-XfjJ", - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -1.3115650468715785, - 0.3474133526632701 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -20.25017438531637, - 9.750482868436373 - ], - [ - -20.905359242352013, - 11.101291002704453 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.28567608829117, - 31.45923493670271 - ], - [ - -24.774715491646944, - 32.70785237527916 - ], - [ - -24.583478771558603, - 32.97558260554791 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -11.129776379862978, - 49.15839168796223 - ], - [ - -9.663827224675448, - 49.48249785579689 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 11.48695215532948, - 49.14584411313763 - ], - [ - 12.669433418267904, - 48.218743081312766 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 25.58687597536511, - 31.610234421819158 - ], - [ - 25.571534984536722, - 30.111814465259762 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 20.53902127516687, - 9.731359063443975 - ], - [ - 19.36271653161873, - 8.800076266583918 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - -0.015935237649678337, - -1.734723475976807e-18 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 1294, - "versionNonce": 2087258702, - "isDeleted": false, - "id": "slCkGhr9_6zXg1ZD1FvIk", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1267.0214074858345, - "y": 1189.8019158530517, - "strokeColor": "#326ce5", - "backgroundColor": "#fff", - "width": 37.25081945503691, - "height": 36.55110370177384, - "seed": 1569429126, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -0.763354876401404, - 0.3762980606460073 - ], - [ - -1.0438348166027671, - 1.1792934555021581 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -0.8972199915357885, - 2.4876714548438046 - ], - [ - -0.7920398239836638, - 4.41597503323698 - ], - [ - -1.1394538415651116, - 4.965780247284959 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -3.080505610077996, - 5.71160408255246 - ], - [ - -5.022330963327559, - 6.304163911568683 - ], - [ - -6.845677786656399, - 7.172373715574011 - ], - [ - -8.521116424189604, - 8.300246583282124 - ], - [ - -10.019211140800904, - 9.671797123219552 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -11.031172442478647, - 9.337132815570726 - ], - [ - -12.460667366834947, - 8.046284337550144 - ], - [ - -13.157087405949898, - 7.305243353296811 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -14.130800337736295, - 6.838306694372137 - ], - [ - -14.977023009354593, - 7.214405659535816 - ], - [ - -15.170252014102399, - 8.051463859716112 - ], - [ - -14.715666114239259, - 8.780952746556453 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -13.61605492623689, - 9.470997930705119 - ], - [ - -12.02560270302248, - 10.58654663607644 - ], - [ - -11.81364960405969, - 11.19850383639671 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -12.663383043343293, - 13.729227789525805 - ], - [ - -13.432188728502993, - 16.102728623949886 - ], - [ - -13.759059435897406, - 18.57633193122058 - ], - [ - -13.630398159934447, - 21.088628153638926 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.532397962858736, - 21.675087453906833 - ], - [ - -16.435202881293154, - 21.98903519270465 - ], - [ - -17.45513256170216, - 22.068715940391602 - ], - [ - -17.737206025668506, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -18.292259913366756, - 22.356659681460652 - ], - [ - -18.611600708034853, - 22.788374677769085 - ], - [ - -18.464824022900185, - 23.845978998721524 - ], - [ - -18.38581731220873, - 23.936462576090303 - ], - [ - -17.878088876601407, - 24.222546066240575 - ], - [ - -17.29576802670259, - 24.199411475157763 - ], - [ - -17.275050697945154, - 24.199411475157763 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.035199539842104, - 23.82012698227699 - ], - [ - -14.183390421512353, - 23.27828938705385 - ], - [ - -13.574620268722027, - 23.493431053359405 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -12.112107410370559, - 25.72442511682881 - ], - [ - -10.738340983309326, - 27.80263239527926 - ], - [ - -9.013774395654409, - 29.59995698312531 - ], - [ - -6.976954660520658, - 31.06799892059641 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.075759213200076, - 32.07358308758858 - ], - [ - -8.036724714773126, - 33.81383870321276 - ], - [ - -8.607247257578543, - 34.66324690254815 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.886827468577374, - 35.50075192770404 - ], - [ - -8.742004502851252, - 36.01784089060601 - ], - [ - -8.366098553918508, - 36.401313987679686 - ], - [ - -7.816965857053191, - 36.55110370177384 - ], - [ - -7.706840218512803, - 36.54533753185084 - ], - [ - -7.16885990828297, - 36.325715457286734 - ], - [ - -6.825558504252345, - 35.85688359174788 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.3873067929099525, - 34.61384386630208 - ], - [ - -6.0157900634652846, - 33.573000041372545 - ], - [ - -5.566583541156827, - 32.70785266024412 - ], - [ - -5.110802308493361, - 32.48474413502013 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -2.455971958489142, - 32.732516183046116 - ], - [ - 0.023292651618423227, - 32.964211650828084 - ], - [ - 2.5036606458494117, - 32.74461997252078 - ], - [ - 4.922749786285883, - 32.07358308758858 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.6765404804718065, - 32.80665873273633 - ], - [ - 6.4032420305597, - 34.59153301377963 - ], - [ - 6.712408438156163, - 35.56524670547247 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 7.179027456196865, - 36.296811656655166 - ], - [ - 7.6706777917473286, - 36.512770982269764 - ], - [ - 8.669632535122132, - 36.13573885202099 - ], - [ - 8.736328001885967, - 36.04493307432972 - ], - [ - 8.906884438654954, - 35.48996429615062 - ], - [ - 8.76182742175113, - 34.927791605099856 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.052658432610022, - 33.794713378407465 - ], - [ - 7.096474262238299, - 32.11023793371498 - ], - [ - 7.20484299713317, - 31.47278283334236 - ], - [ - 7.027948940812576, - 31.044092264589768 - ], - [ - 9.059415895116322, - 29.567113827606978 - ], - [ - 10.777582550893055, - 27.76219321517602 - ], - [ - 12.144052356499268, - 25.677885407977218 - ], - [ - 13.120431799917194, - 23.36275146594211 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 14.167452144237089, - 23.222512255747866 - ], - [ - 16.019262022473253, - 23.76434985097099 - ], - [ - 16.972257625502206, - 24.130886153731986 - ], - [ - 17.246361950830853, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.83568761811903, - 24.21569171032261 - ], - [ - 18.31108811476151, - 23.965986460361425 - ], - [ - 18.607515451115297, - 23.518231359317237 - ], - [ - 18.639218747002054, - 22.94991862438427 - ], - [ - 18.60733003394858, - 22.833665100464394 - ], - [ - 18.27464604243303, - 22.35535264241645 - ], - [ - 17.740392313292105, - 22.12290030783905 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 16.411294705473757, - 21.969909867899357 - ], - [ - 14.508492066758599, - 21.655965168727235 - ], - [ - 14.049523786565212, - 21.196996888533807 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.73226285577153, - 18.559851080760573 - ], - [ - 13.39248133828329, - 16.091194764291018 - ], - [ - 12.613884258888199, - 13.724023950354376 - ], - [ - 11.410456935359512, - 11.518825670254394 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.984165005881982, - 10.569015594942522 - ], - [ - 13.561867519163837, - 9.459842504443921 - ], - [ - 14.441556469565695, - 8.945097092944515 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 15.178349576925338, - 7.815810799293218 - ], - [ - 15.028368366413035, - 7.300193015222433 - ], - [ - 14.615274117046312, - 6.908611716636007 - ], - [ - 14.462274558229574, - 6.841493741902078 - ], - [ - 13.870641815047035, - 6.809621746789864 - ], - [ - 13.353102987543796, - 7.09807006572251 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 12.42082243355301, - 8.02716205237053 - ], - [ - 11.029576638994495, - 9.338727099242107 - ], - [ - 10.385744403936314, - 9.408846704339243 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 8.09513720154745, - 8.044790361526335 - ], - [ - 5.959414125899516, - 6.767389187532886 - ], - [ - 3.6300608149134885, - 5.8903903058615485 - ], - [ - 1.1617631742746461, - 5.440684525034469 - ], - [ - 1.1378565182680294, - 4.967373771049928 - ], - [ - 0.7904425006866282, - 4.438285885759382 - ], - [ - 0.9115594257012792, - 2.5147628786611107 - ], - [ - 1.0581757705810848, - 1.5059893844197219 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 0.7782931168266872, - 0.3842664393772693 - ], - [ - 0.014340953978292355, - 0.007968378731262807 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 941, - "versionNonce": 574491026, - "isDeleted": false, - "id": "T5LwFTzm924qMArgCedQ7", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1265.6970160040014, - "y": 1198.163873664949, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.393680887969856, - "height": 6.369775751776067, - "seed": 1132690650, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.3187275501863063, - 5.566582021344026 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.8717205716706387, - 6.369775751776067 - ], - [ - -1.8279047420423864, - 6.283719389216403 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -3.9621064850353154, - 1.2473590335431695 - ], - [ - -1.1298911791624642, - 0.18167386770913002 - ], - [ - -0.003187047529933336, - 5.298279176502163e-15 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 936, - "versionNonce": 799969422, - "isDeleted": false, - "id": "Tp3IRyYoZHec9AabXoQOD", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1268.4270528533839, - "y": 1198.0346569093256, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.358620325514874, - "height": 6.395273651828406, - "seed": 1176688070, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 3.430904540081383, - 1.0107652089709898 - ], - [ - 6.358620325514874, - 3.0661616164740497 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 0.8510040028196162, - 6.395273651828407 - ], - [ - 0.4637496113947366, - 6.054235249119703 - ], - [ - 0.3155405026563627, - 5.560206406471309 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 940, - "versionNonce": 1420494674, - "isDeleted": false, - "id": "5-NOPeNzEjxPugqkwaBXg", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1257.7263033654067, - "y": 1203.2251688512763, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.022363254007489, - "height": 6.916394678200529, - "seed": 1114821018, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 4.175334706972646, - 3.725927569369057 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.4717514046365565, - 4.664582218419733 - ], - [ - 3.807204120540214, - 5.357815969911158 - ], - [ - 3.807204120540221, - 5.37374968774801 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.3506318359784104, - 3.327306497697913 - ], - [ - 0.0015927638585428532, - -0.0015942836713908797 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 941, - "versionNonce": 1693011662, - "isDeleted": false, - "id": "NlSPecmRjaneYUtR7PGRM", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1276.3712869717115, - "y": 1203.2274034094073, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.030331632738752, - "height": 6.895675069723837, - "seed": 1880108294, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 1.361366274082361, - 3.3175584181285167 - ], - [ - 1.5968278380871164, - 6.895675069723839 - ], - [ - -3.7689565105553102, - 5.3498460713670735 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -4.433503794651637, - 4.6358957510246155 - ], - [ - -4.1370855771748944, - 3.7211477579805683 - ], - [ - 0.0063740950598725025, - 0.01274819011975109 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 937, - "versionNonce": 875711762, - "isDeleted": false, - "id": "dWTShJHoSFaKZdFZoZrjM", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1266.1656221518137, - "y": 1207.193301384904, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 3.8135782156000984, - "height": 3.7211492777934096, - "seed": 2048495194, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1.7083821006991204, - 1.1102230246251565e-16 - ], - [ - 2.752213877676234, - 1.3259090404755651 - ], - [ - 2.372929384795452, - 2.983292301444334 - ], - [ - 0.8382542928870336, - 3.721149277793409 - ], - [ - -0.6996078465513131, - 2.983292301444333 - ], - [ - -1.0613643379238646, - 1.3259090404755602 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 942, - "versionNonce": 414336270, - "isDeleted": false, - "id": "YHOtScchUdIm1b19pdqhy", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1271.6381794318654, - "y": 1211.7160485896454, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.5578252343579155, - "height": 6.498862575334826, - "seed": 2026937414, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.2151416663055704, - 1.5404344466674047e-15 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.0017861333277525, - 2.5857548563296193 - ], - [ - 4.000034934323403, - 4.084299437542195 - ], - [ - 2.7628221713142747, - 5.398478562502228 - ], - [ - 1.3179391419314586, - 6.498862575334826 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.7502616887665088, - 0.4662481837071927 - ], - [ - -0.006374095059873417, - 0.02390665600663141 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 940, - "versionNonce": 910875346, - "isDeleted": false, - "id": "w5TDoyoIKIkZs6PdF4ube", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1262.4374813561058, - "y": 1211.8483100445262, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.517984860514442, - "height": 6.4526450668057915, - "seed": 793424666, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.7713217353198448, - 0.4270947652683569 - ], - [ - 0.8462226716183014, - 1.3035951483274668 - ], - [ - 0.8462226716183012, - 1.3243132369913262 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -3.9283210455548736, - 4.061389778759983 - ], - [ - -5.67176218889614, - 0.9434329406263107 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.009562662402646045, - 0.014340953978288919 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 942, - "versionNonce": 1283617614, - "isDeleted": false, - "id": "flcRj4BJAXxxltqd6rq5z", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1267.0418313974756, - "y": 1213.9731731052696, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 7.067792354281676, - "height": 5.943276753141823, - "seed": 1178674054, - "groupIds": [ - "Yso3NVm0eqvuslK9_3KE9" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.49744082247897325, - 0.12416566957594494 - ], - [ - 0.8557853340209567, - 0.49084179511845694 - ], - [ - 0.8765034226848066, - 0.4908417951184617 - ], - [ - 3.576128736397814, - 5.3625957812996585 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - -0.518131554511648, - 5.943276753141823 - ], - [ - -3.4916636178838614, - 5.372158443702313 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - 0.014343993603975418, - 0.030277711440816472 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 760, - "versionNonce": 814814546, - "isDeleted": false, - "id": "zb6e5AXEESmlDHIibDci5", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 176.36046653207143, - "y": 845.5072864104927, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 50.872552063656286, - "height": 49.48249785579689, - "seed": 147767046, - "groupIds": [ - "Ne8vsN-jRFhS3VlVAeu6C", - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -1.3115650468715785, - 0.3474133526632701 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -19.072674308967926, - 8.819200071576429 - ], - [ - -20.25017438531637, - 9.750482868436373 - ], - [ - -20.905359242352013, - 11.101291002704453 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.25280727405768, - 30.114999992976752 - ], - [ - -25.28567608829117, - 31.45923493670271 - ], - [ - -24.774715491646944, - 32.70785237527916 - ], - [ - -24.583478771558603, - 32.97558260554791 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -12.3124567382838, - 48.23308707491693 - ], - [ - -11.129776379862978, - 49.15839168796223 - ], - [ - -9.663827224675448, - 49.48249785579689 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 10.017618376942519, - 49.48249785579678 - ], - [ - 11.48695215532948, - 49.14584411313763 - ], - [ - 12.669433418267904, - 48.218743081312766 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 24.934079884164117, - 32.95805308422675 - ], - [ - 25.58687597536511, - 31.610234421819158 - ], - [ - 25.571534984536722, - 30.111814465259762 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 21.195404124675274, - 11.082167197712025 - ], - [ - 20.53902127516687, - 9.731359063443975 - ], - [ - 19.36271653161873, - 8.800076266583918 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - 1.6302941168707412, - 0.34900697141651627 - ], - [ - -0.015935237649678337, - -1.734723475976807e-18 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 1276, - "versionNonce": 749936846, - "isDeleted": false, - "id": "bNSHrxgQTjUYC_kkTadEz", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 176.3598918280078, - "y": 851.8075427108633, - "strokeColor": "#326ce5", - "backgroundColor": "#fff", - "width": 37.25081945503691, - "height": 36.55110370177384, - "seed": 1069882458, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - -0.763354876401404, - 0.3762980606460073 - ], - [ - -1.0438348166027671, - 1.1792934555021581 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -1.0438348166027671, - 1.4788972006959973 - ], - [ - -0.8972199915357885, - 2.4876714548438046 - ], - [ - -0.7920398239836638, - 4.41597503323698 - ], - [ - -1.1394538415651116, - 4.965780247284959 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -1.163357457946049, - 5.4151866249821365 - ], - [ - -3.080505610077996, - 5.71160408255246 - ], - [ - -5.022330963327559, - 6.304163911568683 - ], - [ - -6.845677786656399, - 7.172373715574011 - ], - [ - -8.521116424189604, - 8.300246583282124 - ], - [ - -10.019211140800904, - 9.671797123219552 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -10.401684201024475, - 9.400878325607978 - ], - [ - -11.031172442478647, - 9.337132815570726 - ], - [ - -12.460667366834947, - 8.046284337550144 - ], - [ - -13.157087405949898, - 7.305243353296811 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -13.39294564110648, - 7.11719387071497 - ], - [ - -14.130800337736295, - 6.838306694372137 - ], - [ - -14.977023009354593, - 7.214405659535816 - ], - [ - -15.170252014102399, - 8.051463859716112 - ], - [ - -14.715666114239259, - 8.780952746556453 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -14.495743876638786, - 8.956252519205707 - ], - [ - -13.61605492623689, - 9.470997930705119 - ], - [ - -12.02560270302248, - 10.58654663607644 - ], - [ - -11.81364960405969, - 11.19850383639671 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -11.466235586478275, - 11.517231386582994 - ], - [ - -12.663383043343293, - 13.729227789525805 - ], - [ - -13.432188728502993, - 16.102728623949886 - ], - [ - -13.759059435897406, - 18.57633193122058 - ], - [ - -13.630398159934447, - 21.088628153638926 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.076616730195267, - 21.21611917371342 - ], - [ - -14.532397962858736, - 21.675087453906833 - ], - [ - -16.435202881293154, - 21.98903519270465 - ], - [ - -17.45513256170216, - 22.068715940391602 - ], - [ - -17.737206025668506, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -17.76907878068713, - 22.13246297024173 - ], - [ - -18.292259913366756, - 22.356659681460652 - ], - [ - -18.611600708034853, - 22.788374677769085 - ], - [ - -18.464824022900185, - 23.845978998721524 - ], - [ - -18.38581731220873, - 23.936462576090303 - ], - [ - -17.878088876601407, - 24.222546066240575 - ], - [ - -17.29576802670259, - 24.199411475157763 - ], - [ - -17.275050697945154, - 24.199411475157763 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.988195902777484, - 24.16754099985839 - ], - [ - -16.035199539842104, - 23.82012698227699 - ], - [ - -14.183390421512353, - 23.27828938705385 - ], - [ - -13.574620268722027, - 23.493431053359405 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -13.096528943442577, - 23.41374726604678 - ], - [ - -12.112107410370559, - 25.72442511682881 - ], - [ - -10.738340983309326, - 27.80263239527926 - ], - [ - -9.013774395654409, - 29.59995698312531 - ], - [ - -6.976954660520658, - 31.06799892059641 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.171378238162371, - 31.474375597200893 - ], - [ - -7.075759213200076, - 32.07358308758858 - ], - [ - -8.036724714773126, - 33.81383870321276 - ], - [ - -8.607247257578543, - 34.66324690254815 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.742706656384314, - 34.95010245762225 - ], - [ - -8.886827468577374, - 35.50075192770404 - ], - [ - -8.742004502851252, - 36.01784089060601 - ], - [ - -8.366098553918508, - 36.401313987679686 - ], - [ - -7.816965857053191, - 36.55110370177384 - ], - [ - -7.706840218512803, - 36.54533753185084 - ], - [ - -7.16885990828297, - 36.325715457286734 - ], - [ - -6.825558504252345, - 35.85688359174788 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.693286152976508, - 35.58596479413628 - ], - [ - -6.3873067929099525, - 34.61384386630208 - ], - [ - -6.0157900634652846, - 33.573000041372545 - ], - [ - -5.566583541156827, - 32.70785266024412 - ], - [ - -5.110802308493361, - 32.48474413502013 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -4.87175702580686, - 32.04967947120764 - ], - [ - -2.455971958489142, - 32.732516183046116 - ], - [ - 0.023292651618423227, - 32.964211650828084 - ], - [ - 2.5036606458494117, - 32.74461997252078 - ], - [ - 4.922749786285883, - 32.07358308758858 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.13470592487437, - 32.47996280381876 - ], - [ - 5.6765404804718065, - 32.80665873273633 - ], - [ - 6.4032420305597, - 34.59153301377963 - ], - [ - 6.712408438156163, - 35.56524670547247 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 6.84468078943203, - 35.83616550308401 - ], - [ - 7.179027456196865, - 36.296811656655166 - ], - [ - 7.6706777917473286, - 36.512770982269764 - ], - [ - 8.669632535122132, - 36.13573885202099 - ], - [ - 8.736328001885967, - 36.04493307432972 - ], - [ - 8.906884438654954, - 35.48996429615062 - ], - [ - 8.76182742175113, - 34.927791605099856 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.62318097541541, - 34.640936050025765 - ], - [ - 8.052658432610022, - 33.794713378407465 - ], - [ - 7.096474262238299, - 32.11023793371498 - ], - [ - 7.20484299713317, - 31.47278283334236 - ], - [ - 7.027948940812576, - 31.044092264589768 - ], - [ - 9.059415895116322, - 29.567113827606978 - ], - [ - 10.777582550893055, - 27.76219321517602 - ], - [ - 12.144052356499268, - 25.677885407977218 - ], - [ - 13.120431799917194, - 23.36275146594211 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 13.573022945425066, - 23.44243525325472 - ], - [ - 14.167452144237089, - 23.222512255747866 - ], - [ - 16.019262022473253, - 23.76434985097099 - ], - [ - 16.972257625502206, - 24.130886153731986 - ], - [ - 17.246361950830853, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.267080039494733, - 24.189851852380777 - ], - [ - 17.83568761811903, - 24.21569171032261 - ], - [ - 18.31108811476151, - 23.965986460361425 - ], - [ - 18.607515451115297, - 23.518231359317237 - ], - [ - 18.639218747002054, - 22.94991862438427 - ], - [ - 18.60733003394858, - 22.833665100464394 - ], - [ - 18.27464604243303, - 22.35535264241645 - ], - [ - 17.740392313292105, - 22.12290030783905 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 17.431225905695587, - 22.049593655211982 - ], - [ - 16.411294705473757, - 21.969909867899357 - ], - [ - 14.508492066758599, - 21.655965168727235 - ], - [ - 14.049523786565212, - 21.196996888533807 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.619240453954077, - 21.0695058684593 - ], - [ - 13.73226285577153, - 18.559851080760573 - ], - [ - 13.39248133828329, - 16.091194764291018 - ], - [ - 12.613884258888199, - 13.724023950354376 - ], - [ - 11.410456935359512, - 11.518825670254394 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.78655590052317, - 11.171411652672974 - ], - [ - 11.984165005881982, - 10.569015594942522 - ], - [ - 13.561867519163837, - 9.459842504443921 - ], - [ - 14.441556469565695, - 8.945097092944515 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 14.674227657192388, - 8.757047610362658 - ], - [ - 15.178349576925338, - 7.815810799293218 - ], - [ - 15.028368366413035, - 7.300193015222433 - ], - [ - 14.615274117046312, - 6.908611716636007 - ], - [ - 14.462274558229574, - 6.841493741902078 - ], - [ - 13.870641815047035, - 6.809621746789864 - ], - [ - 13.353102987543796, - 7.09807006572251 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 13.117243232574392, - 7.286119548304351 - ], - [ - 12.42082243355301, - 8.02716205237053 - ], - [ - 11.029576638994495, - 9.338727099242107 - ], - [ - 10.385744403936314, - 9.408846704339243 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 9.982556294674584, - 9.695702259413336 - ], - [ - 8.09513720154745, - 8.044790361526335 - ], - [ - 5.959414125899516, - 6.767389187532886 - ], - [ - 3.6300608149134885, - 5.8903903058615485 - ], - [ - 1.1617631742746461, - 5.440684525034469 - ], - [ - 1.1378565182680294, - 4.967373771049928 - ], - [ - 0.7904425006866282, - 4.438285885759382 - ], - [ - 0.9115594257012792, - 2.5147628786611107 - ], - [ - 1.0581757705810848, - 1.5059893844197219 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 1.0581757705810848, - 1.1872618342334218 - ], - [ - 0.7782931168266872, - 0.3842664393772693 - ], - [ - 0.014340953978292355, - 0.007968378731262807 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 924, - "versionNonce": 69638930, - "isDeleted": false, - "id": "pbQcaAtPyC8qKCMlep_FJ", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 175.03550034617467, - "y": 860.1695005227605, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.393680887969856, - "height": 6.369775751776067, - "seed": 1609363014, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.3187275501863063, - 5.566582021344026 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.34263268638008126, - 5.566582021344046 - ], - [ - -0.8717205716706387, - 6.369775751776067 - ], - [ - -1.8279047420423864, - 6.283719389216403 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -6.393680887969856, - 3.0486320951529935 - ], - [ - -3.9621064850353154, - 1.2473590335431695 - ], - [ - -1.1298911791624642, - 0.18167386770913002 - ], - [ - -0.003187047529933336, - 5.298279176502163e-15 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 919, - "versionNonce": 728880910, - "isDeleted": false, - "id": "zkqoYr31LGuvkVb0W2M3z", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 177.7655371955576, - "y": 860.040283767137, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.358620325514874, - "height": 6.395273651828406, - "seed": 341082394, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 3.430904540081383, - 1.0107652089709898 - ], - [ - 6.358620325514874, - 3.0661616164740497 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 1.8358731207736394, - 6.28053234168647 - ], - [ - 0.8510040028196162, - 6.395273651828407 - ], - [ - 0.4637496113947366, - 6.054235249119703 - ], - [ - 0.3155405026563627, - 5.560206406471309 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 923, - "versionNonce": 1585801426, - "isDeleted": false, - "id": "eDHetuvRP4Tvs9g6Kwwgk", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 167.06478770757997, - "y": 865.2307957090877, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.022363254007489, - "height": 6.916394678200529, - "seed": 1778595206, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 4.175334706972646, - 3.725927569369057 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.1753347069726665, - 3.749832705562849 - ], - [ - 4.4717514046365565, - 4.664582218419733 - ], - [ - 3.807204120540214, - 5.357815969911158 - ], - [ - 3.807204120540221, - 5.37374968774801 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.5506118493709349, - 6.91480039452914 - ], - [ - -1.3506318359784104, - 3.327306497697913 - ], - [ - 0.0015927638585428532, - -0.0015942836713908797 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 924, - "versionNonce": 1166001486, - "isDeleted": false, - "id": "toXRGd3zYCb9JbBy-ycI2", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 185.70977131388474, - "y": 865.2330302672187, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.030331632738752, - "height": 6.895675069723837, - "seed": 320425434, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 1.361366274082361, - 3.3175584181285167 - ], - [ - 1.5968278380871164, - 6.895675069723839 - ], - [ - -3.7689565105553102, - 5.3498460713670735 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -3.7689565105553045, - 5.329127982703223 - ], - [ - -4.433503794651637, - 4.6358957510246155 - ], - [ - -4.1370855771748944, - 3.7211477579805683 - ], - [ - 0.0063740950598725025, - 0.01274819011975109 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 920, - "versionNonce": 658800274, - "isDeleted": false, - "id": "9WGeI1tG9PHq1j_14mO-m", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 175.50410649398702, - "y": 869.1989282427157, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 3.8135782156000984, - "height": 3.7211492777934096, - "seed": 1078891718, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1.7083821006991204, - 1.1102230246251565e-16 - ], - [ - 2.752213877676234, - 1.3259090404755651 - ], - [ - 2.372929384795452, - 2.983292301444334 - ], - [ - 0.8382542928870336, - 3.721149277793409 - ], - [ - -0.6996078465513131, - 2.983292301444333 - ], - [ - -1.0613643379238646, - 1.3259090404755602 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 925, - "versionNonce": 1010166670, - "isDeleted": false, - "id": "sAzD-reqjjtyyhZrDq2_8", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 180.97666377403914, - "y": 873.7216754474568, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.5578252343579155, - "height": 6.498862575334826, - "seed": 556171930, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.2151416663055704, - 1.5404344466674047e-15 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.74028751032189, - 0.9322805539908008 - ], - [ - 5.0017861333277525, - 2.5857548563296193 - ], - [ - 4.000034934323403, - 4.084299437542195 - ], - [ - 2.7628221713142747, - 5.398478562502228 - ], - [ - 1.3179391419314586, - 6.498862575334826 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.8175377240360249, - 1.3290976078183425 - ], - [ - -0.7502616887665088, - 0.4662481837071927 - ], - [ - -0.006374095059873417, - 0.02390665600663141 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 923, - "versionNonce": 991616082, - "isDeleted": false, - "id": "sDz8mP-OX1ScSOKgzn64R", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 171.77596569827904, - "y": 873.8539369023379, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 6.517984860514442, - "height": 6.4526450668057915, - "seed": 1282149382, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.7713217353198448, - 0.4270947652683569 - ], - [ - 0.8462226716183014, - 1.3035951483274668 - ], - [ - 0.8462226716183012, - 1.3243132369913262 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -1.2765060042294372, - 6.4526450668057915 - ], - [ - -3.9283210455548736, - 4.061389778759983 - ], - [ - -5.67176218889614, - 0.9434329406263107 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.19442357764171736, - 0.014340953978290216 - ], - [ - -0.009562662402646045, - 0.014340953978288919 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 925, - "versionNonce": 1036863950, - "isDeleted": false, - "id": "BNCQRKEC2AEUOxAwG4XVA", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 176.38031573964884, - "y": 875.9787999630812, - "strokeColor": "#326ce5", - "backgroundColor": "#326ce5", - "width": 7.067792354281676, - "height": 5.943276753141823, - "seed": 154083162, - "groupIds": [ - "RO7zFcMfneOc1iq86iy-j" - ], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 0 - ], - [ - 0.49744082247897325, - 0.12416566957594494 - ], - [ - 0.8557853340209567, - 0.49084179511845694 - ], - [ - 0.8765034226848066, - 0.4908417951184617 - ], - [ - 3.576128736397814, - 5.3625957812996585 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - 2.4972348771528834, - 5.681324851298784 - ], - [ - -0.518131554511648, - 5.943276753141823 - ], - [ - -3.4916636178838614, - 5.372158443702313 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - -0.7824756417681913, - 0.5004014178954267 - ], - [ - 0.014343993603975418, - 0.030277711440816472 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "rectangle", - "version": 87, - "versionNonce": 1205830162, - "isDeleted": false, - "id": "d1ZH264XLM8uPU-y68hLx", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 228.0529096311135, - "y": 977.0753796131136, - "strokeColor": "#326ce5", - "backgroundColor": "transparent", - "width": 151.3525950971616, - "height": 65.73900595129237, - "seed": 904871046, - "groupIds": [], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "q3ywddVdmccnXIZ0yCbb8" - }, - { - "id": "9vP2ksBlzTvl0BICWsiBn", - "type": "arrow" - }, - { - "id": "LrxZ_jjxg4cWrN2GTzEca", - "type": "arrow" - }, - { - "id": "bLckxPIhS7MNSKwsCjY_1", - "type": "arrow" - }, - { - "id": "4Ige_dLNnT352G_qJ0P-N", - "type": "arrow" - } - ], - "updated": 1672678669098, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 48, - "versionNonce": 1230954510, - "isDeleted": false, - "id": "q3ywddVdmccnXIZ0yCbb8", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 248.7292071796943, - "y": 997.4448825887598, - "strokeColor": "#326ce5", - "backgroundColor": "#ffff", - "width": 110, - "height": 25, - "seed": 119890758, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "API Server", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "d1ZH264XLM8uPU-y68hLx", - "originalText": "API Server" - }, - { - "type": "arrow", - "version": 113, - "versionNonce": 680095698, - "isDeleted": false, - "id": "9vP2ksBlzTvl0BICWsiBn", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 333.5410819715595, - "y": 1055.04489829953, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 197.21701785387734, - "height": 79.49833277830749, - "seed": 1381974150, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "startBinding": { - "elementId": "d1ZH264XLM8uPU-y68hLx", - "focus": 0.3287096774193482, - "gap": 12.23051273512391 - }, - "endBinding": { - "elementId": "B9WNMPD4KYxfeQgIaRLcF", - "focus": -0.5139569098348294, - "gap": 4.578753070795301 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 90.20003142154076, - 56.56612139994968 - ], - [ - 197.21701785387734, - 79.49833277830749 - ] - ] - }, - { - "type": "arrow", - "version": 76, - "versionNonce": 316911182, - "isDeleted": false, - "id": "LrxZ_jjxg4cWrN2GTzEca", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 315.1953128688732, - "y": 1050.4584560238586, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 218.62041514034468, - "height": 201.80346012954897, - "seed": 623379546, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "startBinding": { - "elementId": "d1ZH264XLM8uPU-y68hLx", - "focus": 0.19330032655641005, - "gap": 7.644070459452621 - }, - "endBinding": { - "elementId": "AyLr50kly-cYfSvyRRrhm", - "focus": -0.7327561133470003, - "gap": 5.559888415576779 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 84.08477505397866, - 110.07461461611751 - ], - [ - 218.62041514034468, - 201.80346012954897 - ] - ] - }, - { - "type": "arrow", - "version": 142, - "versionNonce": 1093641618, - "isDeleted": false, - "id": "bLckxPIhS7MNSKwsCjY_1", - "fillStyle": "cross-hatch", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 295.32072967429644, - "y": 1047.4008278400775, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 240.0238124268119, - "height": 287.4170492754183, - "seed": 650756422, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "startBinding": { - "elementId": "d1ZH264XLM8uPU-y68hLx", - "focus": 0.29460580912862977, - "gap": 4.586442275671459 - }, - "endBinding": { - "elementId": "tTRI8_KiWRy_91oCCVmjl", - "focus": -0.7531435197419164, - "gap": 8.212694995106858 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 85.61358914586924, - 171.2271782917387 - ], - [ - 240.0238124268119, - 287.4170492754183 - ] - ] - }, - { - "type": "ellipse", - "version": 2378, - "versionNonce": 1731507342, - "isDeleted": false, - "id": "JDOAmO8H4O8DjRc7fx06c", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -214.9892607636217, - "y": 952.9523525267775, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 55.62921974281601, - "height": 51.201385977351684, - "seed": 1570936282, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": null, - "boundElements": [ - { - "id": "4Ige_dLNnT352G_qJ0P-N", - "type": "arrow" - } - ], - "updated": 1672678669098, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 2441, - "versionNonce": 1527325522, - "isDeleted": false, - "id": "DNqkggRB0J8lcYzp2FhZC", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -190.33941206712245, - "y": 1003.8699617551396, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 2.7296292860039104, - "height": 62.07302017561529, - "seed": 870173894, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -2.7296292860039104, - 62.07302017561529 - ] - ] - }, - { - "type": "line", - "version": 2394, - "versionNonce": 269152974, - "isDeleted": false, - "id": "qEXn1ashQJUuVaFfwC4fZ", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -192.82557168112965, - "y": 1067.532727896256, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 24.57187279022971, - "height": 37.855374086622675, - "seed": 1531366042, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 24.57187279022971, - 37.855374086622675 - ] - ] - }, - { - "type": "line", - "version": 2413, - "versionNonce": 7137554, - "isDeleted": false, - "id": "j_ryyTz-FCShtoiVMGq4K", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -194.08098248965314, - "y": 1066.2382295764755, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 23.26521467347229, - "height": 34.011101841242805, - "seed": 2035565574, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -23.26521467347229, - 34.011101841242805 - ] - ] - }, - { - "type": "line", - "version": 2432, - "versionNonce": 939485454, - "isDeleted": false, - "id": "d0uXCE7bjta56uVI9SWTc", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -224.27361981973866, - "y": 1039.14246685828, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 32.48711994829731, - "height": 20.807832195149214, - "seed": 671508314, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 32.48711994829731, - -20.807832195149214 - ] - ] - }, - { - "type": "line", - "version": 2508, - "versionNonce": 1490155218, - "isDeleted": false, - "id": "zZ5lvtyY8QfAYho8p1yAg", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -189.95350701317386, - "y": 1018.9386506031242, - "strokeColor": "#000000", - "backgroundColor": "#ced4da", - "width": 20.636027957067586, - "height": 25.894951885267858, - "seed": 259642182, - "groupIds": [ - "Vkl4BClFmxSwM1wOej3ap" - ], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 20.636027957067586, - 25.894951885267858 - ] - ] - }, - { - "type": "rectangle", - "version": 1107, - "versionNonce": 1317738318, - "isDeleted": false, - "id": "9BHm5wK4J9HuuMoTt88OZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 458.17481447266675, - "y": 1536.9219710029247, - "strokeColor": "#326ce5", - "backgroundColor": "transparent", - "width": 25.71428571428578, - "height": 24.285714285714448, - "seed": 1549514650, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1122, - "versionNonce": 80694418, - "isDeleted": false, - "id": "-zWeO5YWk50qMDRt8AmO6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 501.03195732980964, - "y": 1537.9933995743531, - "strokeColor": "#000000", - "backgroundColor": "#82c91e", - "width": 216, - "height": 25, - "seed": 1913693958, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kubernetes Component", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kubernetes Component" - }, - { - "type": "text", - "version": 70, - "versionNonce": 1812397454, - "isDeleted": false, - "id": "JzUHQCHz-ajxxSAksf05_", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": -204.9429218589097, - "y": 1477.0198829283, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 70, - "height": 25, - "seed": 1590854746, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1672678669098, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Legend:", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Legend:" - }, - { - "type": "rectangle", - "version": 907, - "versionNonce": 1636519246, - "isDeleted": false, - "id": "9sj6Yqq9ecupXl-T8eTX0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1229.2385222188325, - "y": 1304.810639836048, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 233, - "height": 108, - "seed": 1249867918, - "groupIds": [], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "xU6PTm8qdmDh0V_cP1a_u" - }, - { - "id": "j8Fs_n05ESoCYmivqBQts", - "type": "arrow" - } - ], - "updated": 1672679718121, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 661, - "versionNonce": 1234531986, - "isDeleted": false, - "id": "xU6PTm8qdmDh0V_cP1a_u", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1309.7385222188325, - "y": 1341.310639836048, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 72, - "height": 35, - "seed": 968662866, - "groupIds": [], - "roundness": null, - "boundElements": null, - "updated": 1672679718121, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "SaaS", - "baseline": 25, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "9sj6Yqq9ecupXl-T8eTX0", - "originalText": "SaaS" - }, - { - "id": "j8Fs_n05ESoCYmivqBQts", - "type": "arrow", - "x": 963.4172488279073, - "y": 1023.6621916957376, - "width": 258.79251941994835, - "height": 327.6573617027475, - "angle": 0, - "strokeColor": "#862e9c", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 1271076494, - "version": 347, - "versionNonce": 609846670, - "isDeleted": false, - "boundElements": null, - "updated": 1672679726874, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 60.000714949641406, - 301.42074019001393 - ], - [ - 258.79251941994835, - 327.6573617027475 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "SGvjpM_f78YrFAFAWW5VM", - "focus": -1.0153163759335013, - "gap": 12.892174605745709 - }, - "endBinding": { - "elementId": "9sj6Yqq9ecupXl-T8eTX0", - "focus": -0.12702265517541084, - "gap": 7.0287539709768225 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "LyVLTMd2gl7lHMgKVetcw", - "type": "text", - "x": 1042.6600722038045, - "y": 1278.6398736573872, - "width": 172, - "height": 50, - "angle": 0, - "strokeColor": "#862e9c", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "groupIds": [], - "roundness": null, - "seed": 773927502, - "version": 109, - "versionNonce": 574612366, - "isDeleted": false, - "boundElements": null, - "updated": 1672679655222, - "link": null, - "locked": false, - "text": "If\nparam is provided", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 43, - "containerId": null, - "originalText": "If\nparam is provided" - }, - { - "type": "text", - "version": 200, - "versionNonce": 972820302, - "isDeleted": false, - "id": "0z6p1_rC7XVHIsB1plnJp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1067.9186140325617, - "y": 1277.7866034983156, - "strokeColor": "#862e9c", - "backgroundColor": "#e64980", - "width": 189, - "height": 24, - "seed": 1441796178, - "groupIds": [], - "roundness": null, - "boundElements": null, - "updated": 1672679663517, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "saas.workspaceID", - "baseline": 19, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "saas.workspaceID" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/docs/assets/arch.png b/docs/assets/arch.png deleted file mode 100644 index 9553313d..00000000 Binary files a/docs/assets/arch.png and /dev/null differ diff --git a/docs/assets/dashboard-arch-dark.png b/docs/assets/dashboard-arch-dark.png new file mode 100644 index 00000000..1701156a Binary files /dev/null and b/docs/assets/dashboard-arch-dark.png differ diff --git a/docs/assets/dashboard-arch-light.png b/docs/assets/dashboard-arch-light.png new file mode 100644 index 00000000..4afc64a5 Binary files /dev/null and b/docs/assets/dashboard-arch-light.png differ diff --git a/docs/assets/logo.png b/docs/assets/logo.png deleted file mode 100644 index e81e02d5..00000000 Binary files a/docs/assets/logo.png and /dev/null differ diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg new file mode 100644 index 00000000..b7e3dcbe --- /dev/null +++ b/docs/assets/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/assets/oss-arch-dark.png b/docs/assets/oss-arch-dark.png new file mode 100644 index 00000000..b071acca Binary files /dev/null and b/docs/assets/oss-arch-dark.png differ diff --git a/docs/assets/oss-arch-light.png b/docs/assets/oss-arch-light.png new file mode 100644 index 00000000..a7a0be32 Binary files /dev/null and b/docs/assets/oss-arch-light.png differ diff --git a/docs/assets/plugin-arch-dark.png b/docs/assets/plugin-arch-dark.png new file mode 100644 index 00000000..cd6f18c8 Binary files /dev/null and b/docs/assets/plugin-arch-dark.png differ diff --git a/docs/assets/plugin-arch-light.png b/docs/assets/plugin-arch-light.png new file mode 100644 index 00000000..f39eb69a Binary files /dev/null and b/docs/assets/plugin-arch-light.png differ diff --git a/docs/assets/zora-dashboard-screenshot.png b/docs/assets/zora-dashboard-screenshot.png new file mode 100644 index 00000000..1e8dbca8 Binary files /dev/null and b/docs/assets/zora-dashboard-screenshot.png differ diff --git a/docs/cluster-scan.md b/docs/cluster-scan.md deleted file mode 100644 index 0513c5fd..00000000 --- a/docs/cluster-scan.md +++ /dev/null @@ -1,165 +0,0 @@ -# Configure a cluster scan - -Since your clusters are connected the next and last step is configure a scan for them -by creating a `ClusterScan` in the same namespace as `Cluster` resource. - -The `ClusterScan` will be responsible for reporting issues and vulnerabilities of your clusters. - -Failure to perform this step implies that the scan will not be performed, and therefore the health of your cluster will be unknown. - - -## Create a `ClusterScan` - -The `ClusterScan` scans the `Cluster` referenced in `clusterRef.name` field periodically on a given schedule, -written in [Cron](https://en.wikipedia.org/wiki/Cron) format. - -Here is a sample configuration that scan `mycluster` once an hour. -You can modify putting your desired periodicity. - -```yaml -cat << EOF | kubectl apply -f - -apiVersion: zora.undistro.io/v1alpha1 -kind: ClusterScan -metadata: - name: mycluster - namespace: zora-system -spec: - clusterRef: - name: mycluster - schedule: "0 * * * *" # at minute 0 past every hour -EOF -``` - -### Cron schedule syntax - -Cron expression has five fields separated by a space, and each field represents a time unit. - - -``` -┌───────────── minute (0 - 59) -│ ┌───────────── hour (0 - 23) -│ │ ┌───────────── day of the month (1 - 31) -│ │ │ ┌───────────── month (1 - 12) -│ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; -│ │ │ │ │ 7 is also Sunday on some systems) -│ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat -│ │ │ │ │ -* * * * * -``` - -| Operator | Descriptor | Example | -|----------|----------------------|----------------------------------------------------------------------------------------------------| -| * | Any value | `15 * * * *` runs at every minute 15 of every hour of every day. | -| , | Value list separator | `2,10 4,5 * * *` runs at minute 2 and 10 of the 4th and 5th hour of every day. | -| - | Range of values | `30 4-6 * * *` runs at minute 30 of the 4th, 5th, and 6th hour. | -| / | Step values | `20/15 * * * *` runs every 15 minutes starting from minute 20 through 59 (minutes 20, 35, and 50). | - - -Now Zora is ready to help you to identify potential issues and vulnerabilities in your kubernetes clusters. - -You can check the scans status and the reported issues by the following steps: - -## List cluster scans - -Listing the `ClusterScans`, the information of the last scans are available: - -```shell -kubectl get clusterscan -o wide -``` -``` -NAME CLUSTER SCHEDULE SUSPEND PLUGINS LAST STATUS LAST SCHEDULE LAST SUCCESSFUL ISSUES READY SAAS AGE NEXT SCHEDULE -mycluster mycluster 0 * * * * false marvin,popeye Complete 13s 1s 34 True OK 39s 2023-04-18T14:00:00Z -``` - -The `LAST STATUS` column represents the status (`Active`, `Complete` or `Failed`) of the last **scan** -that was scheduled at the time represented by `LAST SCHEDULE` column. - -## Scanner plugins - -Zora uses CLI tools as plugins to scan the clusters. - -Currently, there are two available plugins: -[Marvin](https://github.com/undistro/marvin) and [Popeye](https://github.com/derailed/popeye). -Both plugins are used by default in `ClusterScans`. - -!!! info - To list the available plugins, run the following command: - ``` - kubectl get plugins -n zora-system - ``` - -Marvin is the official [Undistro](https://undistro.io) plugin that scans a k8s cluster -by performing [CEL (Common Expression Language)](https://github.com/google/cel-spec) expressions. -Similarly, Popeye is a widely used open-source tool for k8s cluster scanning. - -## List cluster issues - -Once the cluster is successfully scanned, -the reported issues are available in `ClusterIssue` resources: - -```shell -kubectl get clusterissues -l cluster=mycluster -``` -``` -NAME CLUSTER ID MESSAGE SEVERITY CATEGORY AGE -mycluster-m-102-18e887d99ccb mycluster M-102 Privileged container High Security 100s -mycluster-m-103-18e887d99ccb mycluster M-103 Insecure capabilities High Security 100s -mycluster-m-104-18e887d99ccb mycluster M-104 HostPath volume High Security 100s -mycluster-m-105-18e887d99ccb mycluster M-105 Not allowed hostPort High Security 100s -mycluster-m-111-18e887d99ccb mycluster M-111 Not allowed volume type Low Security 100s -mycluster-m-112-18e887d99ccb mycluster M-112 Allowed privilege escalation Medium Security 100s -mycluster-m-113-18e887d99ccb mycluster M-113 Container could be running as root user Medium Security 100s -mycluster-m-115-18e887d99ccb mycluster M-115 Not allowed seccomp profile Low Security 100s -mycluster-m-201-18e887d99ccb mycluster M-201 Application credentials stored in configuration files High Security 100s -mycluster-m-300-18e887d99ccb mycluster M-300 Root filesystem write allowed Low Security 100s -mycluster-pop-102-c6d6b0eefab4 mycluster POP-102 No probes defined Medium Container 103s -mycluster-pop-106-c6d6b0eefab4 mycluster POP-106 No resources requests/limits defined Medium Container 103s -mycluster-pop-605-c6d6b0eefab4 mycluster POP-605 If ALL HPAs are triggered, cluster memory capacity will match or exceed threshold Medium HorizontalPodAutoscaler 103s -mycluster-pop-710-c6d6b0eefab4 mycluster POP-710 Node Memory threshold reached Medium Node 103s -``` - -It's possible filter issues by cluster, issue ID, severity and category -using [label selector](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/): - -```shell -# issues from mycluster -kubectl get clusterissues -l cluster=mycluster - -# clusters with issue POP-106 -kubectl get clusterissues -l id=POP-106 - -# issues from mycluster with high severity -kubectl get clusterissues -l cluster=mycluster,severity=High - -# only issues reported by the last scan from mycluster -kubectl get clusterissues -l cluster=mycluster,scanID=fa4e63cc-5236-40f3-aa7f-599e1c83208b - -# issues reported from marvin plugin -kubectl get clusterissues -l plugin=marvin - -# issues reported from a custom check -kubectl get clusterissues -l custom=true -``` - -!!! tip "Why is it an issue?" - - The field `url` in `ClusterIssue` spec represents a link for a documentation about this issue. - It is displayed in the UI and you can see by `kubectl` with the `-o=yaml` flag or the command below. - - ```shell - kubectl get clusterissues -o=custom-columns="NAME:.metadata.name,MESSAGE:.spec.message,URL:.spec.url" - ``` - ``` - NAME MESSAGE URL - mycluster-pop-102-27557035 No probes defined https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ - mycluster-pop-105-27557035 Liveness probe uses a port#, prefer a named port - mycluster-pop-106-27557035 No resources requests/limits defined https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - mycluster-pop-1100-27557035 No pods match service selector https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service - mycluster-pop-306-27557035 Container could be running as root user. Check SecurityContext/Image https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted - mycluster-pop-500-27557035 Zero scale detected https://kubernetes.io/docs/concepts/workloads/ - ``` - - These docs should help you understand why it's an issue and how to fix it. - - All URLs are available [here](https://github.com/undistro/zora/blob/main/pkg/worker/report/popeye/parse_types.go#L109) - and you can contribute to Zora adding new links. See our [contribution guidelines](https://github.com/undistro/zora/blob/main/CONTRIBUTING.md). diff --git a/docs/custom-checks.md b/docs/configuration/custom-checks.md similarity index 88% rename from docs/custom-checks.md rename to docs/configuration/custom-checks.md index def9ed65..97646ed6 100644 --- a/docs/custom-checks.md +++ b/docs/configuration/custom-checks.md @@ -4,14 +4,14 @@ Zora offers a declarative way to create your own checks using the `CustomCheck` Custom checks use the [Common Expression Language (CEL)](https://github.com/google/cel-spec) to declare the validation rules and are performed by the [Marvin](https://github.com/undistro/marvin) plugin, -so it should be enabled in your cluster scans. +which should be enabled in your cluster scans. !!! info Marvin is already a default plugin and enabled by default in cluster scans since Zora 0.5.0. -## `CustomCheck` +## `CustomCheck` API -The example below represents a custom check that requires the labels `mycompany.com/squad` and `mycompany.com/component` +The example below demonstrates a custom check that requires the labels `mycompany.com/squad` and `mycompany.com/component` to be present on `Pods`, `Deployments` and `Services`. !!! example @@ -50,10 +50,13 @@ to be present on `Pods`, `Deployments` and `Services`. message: "Resource without required labels" ``` -The `spec.match.resources` defines which resources will be checked by the expressions -defined in `spec.validations.expression` as [Common Expression Language (CEL)](https://github.com/google/cel-spec). +The `spec.match.resources` defines which resources are checked by the expressions +defined in `spec.validations.expression` using [Common Expression Language (CEL)](https://github.com/google/cel-spec). -If an expression evaluates to `false`, the check fails and a `ClusterIssue` is reported. +If an expression evaluates to `false`, the check fails, and a `ClusterIssue` is reported. + +!!! tip "CEL Playground" + To quickly test CEL expressions directly from your browser, check out [CEL Playground](https://playcel.undistro.io/). ### Variables @@ -64,7 +67,7 @@ The variables available in CEL expressions: | `object` | The object being scanned. | | `params` | The parameter defined in `spec.params` field. | -If matches a `PodSpec`, the following useful variables are available: +If the object matches a `PodSpec`, the following useful variables are available: | Variable | Description | |-----------------|---------------------------------------------------------------------------------| @@ -83,17 +86,17 @@ The following resources matches a `PodSpec`: - `batch/v1/jobs` - `batch/v1/cronjobs` -### Apply a `CustomCheck` +### Applying custom checks -Since you have a `CustomCheck` on a file, you can apply it with the command below. +Since you have a `CustomCheck` on a file, you can apply it with the following command. ```shell kubectl apply -f check.yaml -n zora-system ``` -### List custom checks +### Listing custom checks -Once created, list the custom checks to see if it's ready. +Once created, list the custom checks to see if they are ready. ```shell kubectl get customchecks -n zora-system @@ -105,7 +108,7 @@ mycheck Required labels Low True The `READY` column indicates when the check has successfully compiled and is ready to be used in the next Marvin scan. -`ClusterIssues` reported by a custom check have are labeled `custom=true` and can be filtered by the following command: +`ClusterIssues` reported by a custom check are labeled `custom=true` and can be filtered by the following command: ```shell kubectl get clusterissues -l custom=true @@ -120,9 +123,7 @@ mycluster-mycheck-4edd75cb85a4 mycluster mycheck Required labels Low All Marvin checks are similar to the `CustomCheck` API. You can see them in the [`internal/builtins`](https://github.com/undistro/marvin/tree/main/internal/builtins) folder for examples. -If you want to quickly test CEL expressions from your browser, check out the [CEL Playground](https://playcel.undistro.io/). - -Some examples of Marvin built-in checks expressions: +Here are some examples of Marvin built-in checks expressions: - [HostPath volumes must be forbidden](https://github.com/undistro/marvin/blob/main/internal/builtins/pss/baseline/M-104_host_path_volumes.yml) ``` diff --git a/docs/configuration/resources.md b/docs/configuration/resources.md new file mode 100644 index 00000000..a47eb2de --- /dev/null +++ b/docs/configuration/resources.md @@ -0,0 +1,21 @@ +# Compute resources + +[Zora Helm Chart](../helm-chart.md) allows you to define resource requests and limits (memory and CPU) +for `zora-operator` and plugins. +You can do this by setting specific parameters using `--set` argument as the example below. + +``` +--set operator.resources.limits.memory=256Mi +``` + +Alternatively, a YAML file can be specified using `-f myvalues.yaml` flag. + +!!! tip + Refer to the default [values.yaml](../values.yaml) file for more details + +In a similar way, you can customize the resources for plugins. +The following example sets `1Gi` as memory limit for `marvin` plugin. + +``` +--set scan.plugins.marvin.resources.limits.memory=1Gi +``` diff --git a/docs/configuration/retain-issues.md b/docs/configuration/retain-issues.md new file mode 100644 index 00000000..e41f7719 --- /dev/null +++ b/docs/configuration/retain-issues.md @@ -0,0 +1,45 @@ +# Retain issues + +By default, both scans automatically scheduled by Zora upon installation +are configured to retain issues/results only from the last scan. + +To retain results from the last two scans, for example, +you should set the `successfulScansHistoryLimit` field of `ClusterScan` to `2`. + +This can be done by either directly editing the `ClusterScan` object +or by providing a parameter in the Helm installation/upgrade command, + +```shell +# omitted "helm upgrade --install" command and parameters + +--set scan.misconfiguration.successfulScansHistoryLimit=2 +``` + +In this case, it may appear that there are duplicate issues when more than one scan completes successfully. +However, these issues are actually related to different scans. +The identifier of each scan can be found in the `scanID` label of each issue. + +```shell +kubectl get issues -n zora-system --show-labels +``` +``` +NAME CLUSTER ID MESSAGE SEVERITY CATEGORY AGE LABELS +kind-kind-m-102-4wxvv kind-kind M-102 Privileged container High Security 43s scanID=556cc35a-830e-45af-a31c-7130918de262,category=Security,cluster=kind-kind,custom=false,id=M-102,plugin=marvin,severity=High +kind-kind-m-102-nf5xq kind-kind M-102 Privileged container High Security 102s scanID=8464411a-4b9c-456b-a11c-dd3a5ab905f5,category=Security,cluster=kind-kind,custom=false,id=M-102,plugin=marvin,severity=High +``` + +To list issues from a specific scan, you can use a label selector like this: + +```shell +kubectl get issues -n zora-system -l scanID=556cc35a-830e-45af-a31c-7130918de262 +``` + +This also applies to vulnerability scans and `VulnerabilityReport` results. + +!!! warning + Note that results are stored as CRDs in your Kubernetes cluster. + Be cautious not to set a high value that could potentially affect + the performance and storage capacity of your Kubernetes cluster + +!!! note + That applies only to Zora OSS. Zora Dashboard always shows results from the last scan. diff --git a/docs/configuration/scan-schedule.md b/docs/configuration/scan-schedule.md new file mode 100644 index 00000000..00fce699 --- /dev/null +++ b/docs/configuration/scan-schedule.md @@ -0,0 +1,61 @@ +# Scan schedule + +After successfully installing Zora, vulnerability and misconfiguration scans are +automatically scheduled for your cluster, with each scan using different plugins. + +Scan schedules are defined using Cron expressions. +You can view the schedule for your cluster by listing `ClusterScan` resources: + +```shell +kubectl get clusterscans -o wide -n zora-system +``` + +By default, the misconfiguration scan is scheduled to run every hour at the current minute plus 5, +while the vulnerability scan is scheduled to run every day at the current hour and the current minute plus 5. + +For example, if the installation occurred at 10:00 UTC, the scans will have the following schedules: + +| Scan | Cron | Description | +|:------------------|:-------------|:-----------------------| +| Misconfigurations | `5 * * * *` | Every hour at minute 5 | +| Vulnerabilities | `5 10 * * *` | Every day at 10:05 | + +However, you can customize the schedule for each scan +by directly editing the `ClusterScan` resource +or by providing parameters in the `helm upgrade --install` command, as shown in the example below: + +```shell +# omitted "helm upgrade --install" command and parameters + +--set scan.misconfiguration.schedule="0 * * * *" \ +--set scan.vulnerability.schedule="0 0 * * *" +``` + +The recommended approach is to provide parameters through Helm. + +!!! warning + If you directly edit the `ClusterScan` resource, be cautious when running the next update via Helm, as the value may be overwritten. + +## Cron schedule syntax + +Cron expression has five fields separated by a space, and each field represents a time unit. + +``` +┌───────────── minute (0 - 59) +│ ┌───────────── hour (0 - 23) +│ │ ┌───────────── day of the month (1 - 31) +│ │ │ ┌───────────── month (1 - 12) +│ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; +│ │ │ │ │ 7 is also Sunday on some systems) +│ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat +│ │ │ │ │ +* * * * * +``` + +| Operator | Descriptor | Example | +|----------|----------------------|----------------------------------------------------------------------------------------------------| +| * | Any value | `15 * * * *` runs at every minute 15 of every hour of every day. | +| , | Value list separator | `2,10 4,5 * * *` runs at minute 2 and 10 of the 4th and 5th hour of every day. | +| - | Range of values | `30 4-6 * * *` runs at minute 30 of the 4th, 5th, and 6th hour. | +| / | Step values | `20/15 * * * *` runs every 15 minutes starting from minute 20 through 59 (minutes 20, 35, and 50). | + diff --git a/docs/configuration/suspend-scan.md b/docs/configuration/suspend-scan.md new file mode 100644 index 00000000..90dd20d5 --- /dev/null +++ b/docs/configuration/suspend-scan.md @@ -0,0 +1,21 @@ +# Suspending scans + +The cluster scans, which are automatically scheduled upon installation, +can be suspended by setting `spec.suspend` to `true` in a `ClusterScan` object. +This action will suspend subsequent scans, it does not apply to already started scans. + +The command below suspends the `mycluster-vuln` scan. + +```shell +kubectl patch scan mycluster-vuln --type='merge' -p '{"spec":{"suspend":true}}' -n zora-system +``` + +!!! note + This way, the scan results remain available, + unlike if the `ClusterScan` had been deleted, in which case the results would also be removed. + +Setting `spec.suspend` back to `false`, the scans are resume: + +```shell +kubectl patch scan mycluster-vuln --type='merge' -p '{"spec":{"suspend":false}}' -n zora-system +``` diff --git a/docs/connect-cluster.md b/docs/connect-cluster.md deleted file mode 100644 index e624079a..00000000 --- a/docs/connect-cluster.md +++ /dev/null @@ -1,131 +0,0 @@ -# Connect the target cluster to Zora - -After [preparing](../target-cluster) your [target clusters](../glossary#target-cluster), you need to connect them directly to Zora by -following the instructions below. - -## Prerequisites - -1. A kubeconfig file with an authentication `token` of the target cluster. - Follow [these instructions](../target-cluster) to generate it. -2. The [api-server](https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver) - of the [target cluster](../glossary#target-cluster) - must be reachable by the [management cluster](../glossary#management-cluster). - -Without the prerequisites Zora will not be able to connect to the target cluster -and will set a failure status. - -!!! warning "Metrics Server" - If the target cluster hasn't Metrics Server deployed, - information about the usage of memory and CPU won't be collected - and issues about potential resources over/under allocations won't be reported. - - For more information about Metrics Server, visit the - [official documentation](https://github.com/kubernetes-sigs/metrics-server/#readme). - -## 1. Access the [management cluster](../glossary#management-cluster) - -First, make sure you are in the context of the **management cluster**. -You can do this by the following commands: - -- Display list of contexts: `kubectl config get-contexts` - -- Display the current-context: `kubectl config current-context` - -- Set the default context to **my-management-cluster**: `kubectl config use-context my-management-cluster` - -## 2. Create a `Cluster` resource - -First, create a `Secret` with the content of the kubeconfig file: - -```shell -kubectl create secret generic mycluster-kubeconfig \ - -n zora-system \ - --from-file=value=zora-view-kubeconfig.yml -``` - -Now, you are able to create a `Cluster` resource referencing the kubeconfig Secret in the same namespace: - -```yaml -cat << EOF | kubectl apply -f - -apiVersion: zora.undistro.io/v1alpha1 -kind: Cluster -metadata: - name: mycluster - namespace: zora-system - labels: - zora.undistro.io/environment: prod -spec: - kubeconfigRef: - name: mycluster-kubeconfig -EOF -``` - -If you've made it this far, congratulations, your clusters are connected. -Now you can list them and see the discovered data through `kubectl`: - -## List clusters - -```shell -kubectl get clusters -o wide -``` -``` -NAME VERSION MEM AVAILABLE MEM USAGE (%) CPU AVAILABLE CPU USAGE (%) NODES READY AGE PROVIDER REGION -mycluster v1.21.5-eks-bc4871b 10033Mi 3226Mi (32%) 5790m 647m (11%) 3 True 40d aws us-east-1 -``` - -!!! tip - - Get clusters from all namespaces using `--all-namespaces` flag - - Get clusters with additional information using `-o=wide` flag - - Get the documentation for `clusters` manifests using `kubectl explain clusters` - - Get cluster from `prod` environment using `kubectl get clusters -l zora.undistro.io/environment=prod` - -The cluster list output has the following columns: - -- `NAME`: Cluster name -- `VERSION`: Kubernetes version -- `MEM AVAILABLE`: Quantity of memory available (requires Metrics Server) -- `MEM USAGE (%)`: Usage of memory in quantity and percentage (requires Metrics Server) -- `CPU AVAILABLE`: Quantity of CPU available (requires Metrics Server) -- `CPU USAGE (%)`: Usage of CPU in quantity and percentage (requires Metrics Server) -- `NODES`: Total of nodes -- `READY`: Indicates whether the cluster is connected -- `AGE`: Age of the kube-system namespace in cluster -- `PROVIDER`: Cluster provider (with `-o=wide` flag) -- `REGION`: Cluster region (`multi-region` if nodes have different `topology.kubernetes.io/region` label) - (with `-o=wide` flag) - -!!! info "Provider" - The value in `PROVIDER` column is obtained by matching the Node's labels - (e.g., a Node with label key prefix `eks.amazonaws.com/` means that the provider of this cluster is `aws`). - - For now, Zora recognizes only the providers in this [list](https://github.com/undistro/zora/blob/main/pkg/discovery/cluster_labels.go#L21). - But you can connect clusters of any provider. - If the provider isn't in this list, the column will not be filled and Zora will continue to work normally. - - Fell free to contribute to the project and add new labels prefixes for providers. - See our [contribution guidelines](https://github.com/undistro/zora/blob/main/CONTRIBUTING.md). - -!!! info - - The quantity of available and in use resources, is a sum of all Nodes. - - Only one provider is displayed in `PROVIDER` column. Different information can be displayed for multi-cloud clusters. - - Show detailed description of a cluster, including **events**, running `kubectl describe cluster mycluster`. - -## Delete a Cluster - -To delete a Cluster, use the following command: - -```shell -kubectl delete cluster mycluster -n zora-system -``` - -This command deletes the `mycluster` Cluster and its scans and issues. - -!!! warning "Deleting a Cluster from dashboard (SaaS)" - If you installed Zora providing a workspace ID (Zora + SaaS) and - want to delete your [management cluster](../glossary#management-cluster), - please first delete all [target clusters](../glossary#target-cluster). - - If you delete the management cluster first, - you will no longer be able to access or delete your target clusters, - which will remain on your dashboard - until you contact the Undistro team by email: [undistro@getup.io](mailto:undistro@getup.io), so that we can proceed with the deletion. diff --git a/docs/dashboard.md b/docs/dashboard.md new file mode 100644 index 00000000..aeb75c7b --- /dev/null +++ b/docs/dashboard.md @@ -0,0 +1,66 @@ +--- +title: Zora Dashboard +--- +# Zora Dashboard + +Zora Dashboard is a SaaS platform designed to seamlessly centralize the security posture management of all your +Kubernetes clusters, providing a full experience powered by Zora OSS. + +It features a powerful UI that allows you to navigate, filter and explore details of issues and affected resources +across all your clusters. You can also invite users to your workspace. + +![Zora Dashboard Screenshot](assets/zora-dashboard-screenshot.png) + + + +Currently, it's free for up to 3 clusters. +Please [contact us](https://undistro.io/contact) if you need unlock more clusters in Zora Dashboard. + +## Getting started + +To integrate your cluster with Zora Dashboard, you need to provide the workspace ID +as an additional parameter in Zora OSS installation command. + +1. Sign in at [Zora Dashboard](https://zora-dashboard.undistro.io); +2. Click on "Connect cluster" button and copy the workspace ID; +3. Then provide it in `saas.workspaceID` parameter in [Zora OSS installation command](getting-started/installation.md): + +=== "HTTP chart repository" + + ```shell hl_lines="9" + helm repo add undistro https://charts.undistro.io --force-update + helm repo update undistro + helm upgrade --install zora undistro/zora \ + -n zora-system \ + --version 0.7.0 \ + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" \ + --set saas.workspaceID= + ``` + +=== "OCI registry" + + ```shell hl_lines="7" + helm upgrade --install zora oci://ghcr.io/undistro/helm-charts/zora \ + -n zora-system \ + --version 0.7.0 \ + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" \ + --set saas.workspaceID= + ``` + + +## Architecture + +Zora OSS acts as the engine of Zora Dashboard, meaning that once scans are completed, +**only the results are sent to Zora Dashboard**, where they are accessible by you +and those you have invited to your workspace. + +![Zora Architecture Diagram](assets/dashboard-arch-light.png#only-light) +![Zora Architecture Diagram](assets/dashboard-arch-dark.png#only-dark) + +Note that these results do not contain sensitive information or specific data about your cluster configuration. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000..3b28abd9 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,65 @@ +--- +title: FAQ +--- + +# Frequently Asked Questions + +Do you have any question about Zora? +We do our best to answer all of your questions on this page. +If you can't find your question below, +ask it on our [discussion board](https://github.com/undistro/zora/discussions/categories/q-a)! + +## Is Zora open source? + +There are two Zora tools: Zora OSS and Zora Dashboard. + +[Zora OSS is open-source](https://github.com/undistro/zora), available under Apache 2.0 license, +and can be used either as standalone tool or integrated with Zora Dashboard. + +On the other hand, Zora Dashboard is a SaaS platform that provides a full experience, +centralizing the security posture management of all your clusters. +It's free for up to 3 clusters. Visit the [Zora Dashboard page](dashboard.md) for more information. + +## Can I use Zora OSS standalone without Zora Dashboard? + +Yes, you can use Zora OSS as a standalone tool and access scan results (misconfigurations and vulnerabilities) +via `kubectl` one cluster at a time. + +## Can I install Zora in a different namespace? + +Yes, Zora can be installed in any namespace. +Simply provide the namespace name using the `-n` flag in [Helm installation command](getting-started/installation.md). + +The `Cluster`, `ClusterScan`, `Plugin`, `ClusterIssue`, and `VulnerabilityReport` objects +will be created in the specified namespace. + +If you already have Zora installed and want to change the namespace, you will need to reinstall it. + +## Can I integrate my own plugins with Zora, and how? + +Currently, integrating a new plugin into Zora requires modifying the source code of Worker, a Zora component. +The parsing of plugin results into `ClusterIssue` or `VulnerabilityReport` is directly handled by Worker, +which is written in Go. A fully declarative approach is not yet supported. + +Refer to [plugins page](plugins/index.md) to know more about how plugins work. + +Feel free to [open an issue](https://github.com/undistro/zora/issues/new/choose) or +[start a discussion](https://github.com/undistro/zora/discussions/categories/q-a) with any suggestions +regarding this process. + +## Which data is sent to Zora Dashboard (SaaS)? + +When integrated with Zora Dashboard, **only scan results are sent to the SaaS** platform. + +**No sensitive information is collected or exposed**. + +Scans are performed in your cluster and the results are securely sent via HTTPS to Zora Dashboard, +where only you and the users you've invited to your workspace will have access. + +## Can I host Zora Dashboard on-premise? + +Currently, Zora Dashboard is available as a SaaS platform. +While we do not offer an on-premise version of Zora Dashboard at this time, we're continuously working to enhance and +expand our offerings. If you have specific requirements or are interested in on-premise solutions, +please [contact us](https://undistro.io/contact), and we'll be happy to discuss potential options and +explore how we can meet your needs. diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md new file mode 100644 index 00000000..7e241b83 --- /dev/null +++ b/docs/getting-started/installation.md @@ -0,0 +1,122 @@ +# Installation + +Zora OSS is installed inside your Kubernetes clusters using [Helm](https://helm.sh/), +where the `zora-operator` deployment is created and scans are automatically scheduled for your cluster. + +## Prerequisites + +- Kubernetes cluster 1.21+ +- Kubectl +- Helm 3.8+ + +## Install with Helm + +First, [ensure that your current context of `kubectl` refer to the Kubernetes cluster you wish to install Zora into](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/). + +??? tip "Manage kubectl contexts" + The following commands can help you to manage kubectl contexts: + + - List all contexts: `kubectl config get-contexts` + + - Display the current-context: `kubectl config current-context` + + - Use the context for the Kind cluster: `kubectl config use-context kind-kind` + +Then, run the following command to install Zora [Helm chart](https://helm.sh/docs/topics/charts/): + +=== "HTTP chart repository" + + ```shell + helm repo add undistro https://charts.undistro.io --force-update + helm repo update undistro + helm upgrade --install zora undistro/zora \ + -n zora-system \ + --version 0.7.0 \ + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" + ``` + +=== "OCI registry" + + ```shell + helm upgrade --install zora oci://ghcr.io/undistro/helm-charts/zora \ + -n zora-system \ + --version 0.7.0 \ + --create-namespace \ + --wait \ + --set clusterName="$(kubectl config current-context)" + ``` + +This command will install Zora in `zora-system` namespace, creating the namespace if it doesn't already exist. + +!!! info "Zora OSS + Zora Dashboard" + To integrate your Zora OSS installation with Zora Dashboard, you need to provide `saas.workspaceID` parameter in installation command. + For more information, please refer to [this page](../dashboard.md#getting-started). + +With the following commands, you can verify if Zora has been successfully installed and retrieve installation notes: + +```shell +helm list -n zora-system +helm get notes zora -n zora-system +``` + +!!! info "Zora Helm Chart" + To see the full list of available parameters in Zora Helm chart, please visit [this page](../helm-chart.md) + +If everything is set up correctly, your cluster should have scheduled scans. Check it by running: + +```shell +kubectl get cluster,scan -o wide -n zora-system +``` + +!!! tip "Customize scan schedule" + To customize the scan schedule, please refer to the [Scan Schedule page](../configuration/scan-schedule.md). + +Once the cluster is successfully scanned, you can check issues by running: + +```shell +kubectl get misconfigurations -n zora-system +kubectl get vulnerabilities -n zora-system +``` + +## Migrating to 0.7 + +### What's new in 0.7 + +In versions up to [0.6](/v0.6/), Zora was installed in a single cluster (referred to as the management cluster) +and connected to other clusters (referred to as target clusters) via kubeconfig, requiring only read permissions. + +Starting from version [0.7](/v0.7/), Zora should be installed in each cluster you want to scan. +This significant change, in addition to streamlining the quick start, +enables the use of plugins for more in-depth scans of your cluster, +thereby providing more insights to help you keep your cluster secure and adhere to best practices. + +### Migration guide + +The recommended way to migrate to version 0.7 is to [uninstall](#uninstall) Zora 0.6 from your management cluster, +including its CRDs, and then install it again on the clusters you wish to scan. + +The ServiceAccounts in the target clusters, which previously contained the tokens used in the kubeconfig files, +will no longer be needed and can be deleted. + +## Uninstall + +You can uninstall Zora and its components by uninstalling the Helm chart installed above. + +```shell +helm uninstall zora -n zora-system +``` + +By design, [Helm doesn't upgrade or delete CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations). +You can permanently delete Zora CRDs and any remaining associated resources from your cluster, using the following command. + +```shell +kubectl get crd -o=name | grep --color=never 'zora.undistro.io' | xargs kubectl delete +``` + +You can also delete the `zora-system` namespace using the command below. + +```shell +kubectl delete namespace zora-system +``` diff --git a/docs/glossary.md b/docs/glossary.md deleted file mode 100644 index bc794e1f..00000000 --- a/docs/glossary.md +++ /dev/null @@ -1,13 +0,0 @@ -# Glossary - -## Management Cluster - -The only Kubernetes cluster where Zora is installed. - -## Target Cluster - -The Kubernetes cluster that you connect to Zora to be scanned. - -## CEL - -[Common Expression Language](https://github.com/google/cel-spec) diff --git a/docs/index.md b/docs/index.md index 0dfee177..ef7ed81b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,44 +1,82 @@ -# Introduction +# Welcome to the Zora documentation + +This documentation will help you install, explore, and configure Zora! ## What is Zora? -Zora is a multi-cluster scan that helps you to identify potential issues and vulnerabilities -in your Kubernetes clusters in a centralized way, ensuring that the recommended best practices are in place. +Zora is an open-source solution that helps you achieve compliance with Kubernetes best practices recommended by +industry-leading frameworks. + +By scanning your cluster with multiple plugins at scheduled times, +Zora identifies potential issues, misconfigurations, and vulnerabilities. + +## Zora OSS vs Zora Dashboard -Throughout this documentation, we will use the following notation: +[Zora OSS is open-source](https://github.com/undistro/zora), available under Apache 2.0 license, +and can be used either as standalone tool or integrated with [Zora Dashboard](dashboard.md), +a SaaS platform which centralize all your clusters providing a full experience. +Please refer to [Zora Dashboard page](dashboard.md) for more details. -- **[Management Cluster](glossary#management-cluster)** to refer to the only Kubernetes cluster where Zora is installed; -- **[Target Cluster](target-cluster)** to refer to all clusters you will connect to Zora to be scanned. +## Key features -Follow these steps to get started with Zora: +#### :octicons-plug-16: Multi-plugin architecture + +Zora seamlessly integrates open-source tools like +[Popeye](plugins/popeye.md), +[Marvin](plugins/marvin.md), +and [Trivy](plugins/trivy.md) as scanners. +These tools' capabilities are combined to provide you with a unified view of your cluster's security posture, +addressing potential issues, misconfigurations, and vulnerabilities. -1. [Install Zora](install) in a [Management Cluster](glossary#management-cluster) +#### :fontawesome-solid-list-check: Kubernetes compliance -2. [Prepare the target cluster](target-cluster) by creating a service account and generating a kubeconfig +Zora and its plugins provide actionable insights, guiding you to align your cluster with industry-recognized frameworks +such as +[NSA-CISA](https://media.defense.gov/2022/Aug/29/2003066362/-1/-1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF), +[MITRE ATT&CK](https://microsoft.github.io/Threat-Matrix-for-Kubernetes), +[CIS Benchmark](https://downloads.cisecurity.org), +and [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards). -3. [Connect the target cluster to Zora](connect-cluster) +#### :octicons-sliders-16: Custom checks -4. [Configure a scan for the target cluster](cluster-scan) +Enabled by the [Marvin](https://github.com/undistro/marvin) plugin, Zora offers a declarative way to create your own +checks by using [CEL](https://github.com/google/cel-spec) expressions to define validation rules. -5. After a successful scan [checkout the potential reported issues](cluster-scan#list-cluster-issues) +#### :simple-kubernetes: Kubernetes-native -All the information about these steps are detailed throughout this documentation. +All scan configurations and plugin reports, including misconfigurations and vulnerabilities, +are securely stored as [CRDs (Custom Resource Definitions)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +within your Kubernetes cluster, making it easily accessible through the Kubernetes API and `kubectl` command. ## Architecture -![Zora Architecture Diagram](assets/arch.png#only-light) -![Zora Architecture Diagram](assets/arch-dark.png#only-dark) +Zora works as a [Kubernetes Operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), +where both scan and plugin configurations, as well as the results (misconfigurations and vulnerabilities), +are managed in CRDs (Custom Resource Definitions). + +![Zora architecture diagram](assets/oss-arch-light.png#only-light){ loading=lazy } +![Zora architecture diagram](assets/oss-arch-dark.png#only-dark){ loading=lazy } + +!!! note "Zora Dashboard" + When a Zora OSS installation is integrated with Zora Dashboard, + scan results are automatically sent to Zora Dashboard SaaS by `zora-operator`. + + Check out [Zora Dashboard architecture](dashboard.md#architecture) for more details. ## Zora origins -In the early days of the cloud native era, [Borg](https://intl.startrek.com/database_article/borg) dominated the container-oriented cluster management scene. -The origin of the name Borg refers to the cybernetic life form existing in the Star Trek series, +In the early days of the cloud native era, [Borg](https://intl.startrek.com/database_article/borg) +dominated the container-oriented cluster management scene. +The origin of the name Borg refers to the cybernetic life form existing in the Star Trek series, that worked as a collective of individuals with a single mind and the same purpose, as well as a "[cluster](https://pt.wikipedia.org/wiki/Cluster)". -As good nerds as we are and wishing to honor our Kubernetes' [predecessor](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/) (Borg) we named our project [Zora](https://intl.startrek.com/node/15372). +As good nerds as we are and wishing to honor our Kubernetes' +[predecessor](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/) (Borg) we named our project +[Zora](https://intl.startrek.com/node/15372). In Star Trek, Zora is the Artificial Intelligence that controls the ship U.S.S Discovery. -After being merged with a collective of other intelligences, Zora became sentient and became a member of the team, bringing insights and making the ship more efficient. +After being merged with a collective of other intelligences, Zora became sentient and became a member of the team, +bringing insights and making the ship more efficient. -Like Star Trek's Zora, our goal is to help manage your K8s environment by periodically scanning all of your clusters, -looking for potential issues or vulnerabilities with deployed features and configurations, and helping you ensure compliance with the best practices. +Like Star Trek's Zora, our goal is to help manage your Kubernetes environment by combining multiple plugin capabilities to +scan your clusters looking for misconfigurations and vulnerabilities. diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index 1f7473d0..00000000 --- a/docs/install.md +++ /dev/null @@ -1,97 +0,0 @@ -# Install - -Zora requires an existing Kubernetes cluster accessible via `kubectl`. -After the installation process this cluster will be your [management cluster](../glossary#management-cluster) -with the Zora components installed. -So it is recommended to keep it separated from any application workload. - -## Setup Requirements - -Zora's management cluster requires these programs in order to be installed and configured: - -- Kubernetes >= 1.21.0 -- [Helm](https://helm.sh/) >= 3.4.0 -- [Kubectl](https://kubernetes.io/docs/reference/kubectl/) -- Awk -- Cat -- POSIX shell - -## Install with Helm - -!!! warning "Migrating to version 0.6" - If you already have Zora installed and want to migrate to zora 0.6, - you need to follow some additional steps. - - Before running the `helm upgrade` command, it is necessary to apply the modified CRDs. - ```shell - kubectl apply -f https://raw.githubusercontent.com/undistro/zora/v0.6.2/charts/zora/crds/zora.undistro.io_clusterissues.yaml - kubectl apply -f https://raw.githubusercontent.com/undistro/zora/v0.6.2/charts/zora/crds/zora.undistro.io_customchecks.yaml - kubectl apply -f https://raw.githubusercontent.com/undistro/zora/v0.6.2/charts/zora/crds/zora.undistro.io_plugins.yaml - ``` - These commands ensure that the modified Custom Resource Definitions (CRDs) are applied correctly. - - By default, Helm does not upgrade CRDs automatically, which is why this manual step is necessary. - -1. To install Zora using [Helm](https://helm.sh/docs/) follow these commands: - -=== "Zora + SaaS" - - In this option you have access to the powerful dashboard to see your clusters and issues. - - !!! warning - The SaaS (`https://zora-dashboard.undistro.io/`) must be reachable by Zora. - - 1.1 Sign in at [https://zora-dashboard.undistro.io/](https://zora-dashboard.undistro.io/) and select a workspace - - 1.2 Get your workspace ID by clicking on :material-cloud-download: and provide it by the `saas.workspaceID` flag: - - ```shell - helm repo add undistro https://charts.undistro.io --force-update - helm repo update undistro - helm upgrade --install zora undistro/zora \ - --set saas.workspaceID='' - -n zora-system \ - --version 0.6.2 \ - --create-namespace --wait - ``` - -=== "Zora (kubectl)" - - In this option you can see your clusters and issues by `kubectl`. - - ```shell - helm repo add undistro https://charts.undistro.io --force-update - helm repo update undistro - helm upgrade --install zora undistro/zora \ - -n zora-system \ - --version 0.6.2 \ - --create-namespace --wait - ``` - -!!! info - The Helm chart repository has been updated from `https://registry.undistro.io/chartrepo/library` to `https://charts.undistro.io`. - - The `--force-update` flag is needed to update the repository URL. - -These commands deploy Zora to the Kubernetes cluster. -[This section](helm-chart.md) lists the parameters -that can be configured during installation. - -## Access to the dashboard - -If you installed Zora providing a workspace ID (Zora + SaaS), -you have access to the powerful dashboard at [https://zora-dashboard.undistro.io/](https://zora-dashboard.undistro.io/) - -The output of `helm install` and `helm upgrade` commands -contains the dashboard URL and you can get it anytime by running: - -```shell -helm get notes zora -n zora-system -``` - -## Uninstall - -```shell -helm delete zora -n zora-system -kubectl delete namespace zora-system -``` diff --git a/docs/plugins/index.md b/docs/plugins/index.md new file mode 100644 index 00000000..ae5e128d --- /dev/null +++ b/docs/plugins/index.md @@ -0,0 +1,91 @@ +# Zora Plugins + +## Overview + +Zora utilizes open-source CLI tools like +[Marvin](marvin.md), +[Popeye](popeye.md), +and [Trivy](trivy.md) +as plugins to perform scans on Kubernetes clusters. + +The current available plugins of a Zora installation can be listed by running the following command: + +```shell +kubectl get plugins -n zora-system +``` +``` +NAME IMAGE TYPE AGE +marvin ghcr.io/undistro/marvin:v0.2.0 misconfiguration 14m +popeye ghcr.io/undistro/popeye:pr252 misconfiguration 14m +trivy ghcr.io/aquasecurity/trivy:0.45.1 vulnerability 14m +``` + +Each item listed above is an instance of `Plugin` CRD and represents the execution configuration of a plugin. +More details can be seen by getting the YAML output of a plugin: + +```shell +kubectl get plugin marvin -o yaml -n zora-system +``` + +## Plugin types + +Currently, Zora has two plugin types: `vulnerability` and `misconfiguration`, +which determine the focus of plugin scans. + +- `vulnerability` plugins scan cluster images for vulnerabilities, + and their results are stored as instances of `VulnerabilityReport` CRD. + +- `misconfiguration` plugins scan cluster resources for potential configuration issues, + and their results are available as instances of the `ClusterIssue` CRD. + +Both result types can be listed using `kubectl`, and some aliases are supported for your convenience, +as shown in the following commands: + +```shell + +kubectl get vulnerabilityreports +kubectl get vuln +kubectl get vulns +kubectl get vulnerabilities +``` +```shell +kubectl get clusterissues +kubectl get issue +kubectl get issues +kubectl get misconfig +kubectl get misconfigs +kubectl get misconfigurations +``` + +!!! note + The results are only available after a successful scan, in the same namespace as the `ClusterScan` (default is `zora-system`). + +!!! note + Currently, vulnerability reports are only available in Zora OSS. + We are working to include this in Zora Dashboard, and it will be available soon. + +## How plugins work + +Starting from a `Plugin` and a `ClusterScan`, Zora manages and schedules scans by applying `CronJobs`, which +creates `Jobs` and `Pods`. + +The `Pods` where the scans run, include a "sidecar" container called **worker** alongside the plugin container. + +After the plugin completes its scan, it needs to signal to Zora (worker) by writing out the path of the results file +into a "done file". + +Worker container waits for the "done file" to be present, +then transforms the results and creates `ClusterIssues` and `VulnerabilityReports` (depending on the plugin type). + +!!! note + This is the aspect that currently prevents the full declarative integration of new plugins. + The code responsible for transforming the output of each plugin into CRDs is written in Go within the worker. + + Any contributions or suggestions in this regard are greatly appreciated. + +![Zora plugin diagram](../assets/plugin-arch-light.png#only-light) +![Zora plugin diagram](../assets/plugin-arch-dark.png#only-dark) + +!!! note + This architecture for supporting plugins is inspired by [Sonobuoy](https://sonobuoy.io/), + a project used for CNCF conformance certification. diff --git a/docs/plugins/marvin.md b/docs/plugins/marvin.md new file mode 100644 index 00000000..d5b3026a --- /dev/null +++ b/docs/plugins/marvin.md @@ -0,0 +1,16 @@ +--- +title: Marvin Plugin +--- + +# Marvin Plugin + +Marvin is an open-source CLI tool that scans a Kubernetes cluster by performing CEL expressions +to report potential issues and misconfigurations. + +Marvin enables Zora's custom checks using CEL. For further information, please visit [this page](../configuration/custom-checks.md). + +:octicons-codescan-24: **Type**: `misconfiguration` + +:simple-docker: **Image**: `ghcr.io/undistro/marvin:v0.2.0` + +:simple-github: **GitHub repository**: [https://github.com/undistro/marvin](https://github.com/undistro/marvin) diff --git a/docs/plugins/popeye.md b/docs/plugins/popeye.md new file mode 100644 index 00000000..12401a33 --- /dev/null +++ b/docs/plugins/popeye.md @@ -0,0 +1,17 @@ +--- +title: Popeye Plugin +--- + +# Popeye Plugin + +Popeye is a utility that scans live Kubernetes cluster and reports potential issues with deployed resources and configurations. + +:octicons-codescan-24: **Type**: `misconfiguration` + +:simple-docker: **Image**: `ghcr.io/undistro/popeye:pr252` + +:simple-github: **GitHub repository**: [https://github.com/derailed/popeye](https://github.com/derailed/popeye) + +!!! info + Currently, Zora does not use the official Popeye image (`derailed/popeye`) due to its lack of multi-architecture support. + diff --git a/docs/plugins/trivy.md b/docs/plugins/trivy.md new file mode 100644 index 00000000..6118854a --- /dev/null +++ b/docs/plugins/trivy.md @@ -0,0 +1,37 @@ +--- +title: Trivy Plugin +--- + +# Trivy Plugin + +Trivy is a versatile security scanner that can find **vulnerabilities**, misconfigurations, secrets, SBOM +in different targets like containers, code repositories and **Kubernetes cluster**. + +**Zora uses Trivy as a plugin exclusively to scan vulnerabilities in a Kubernetes cluster.** + +:octicons-codescan-24: **Type**: `vulnerability` + +:simple-docker: **Image**: `ghcr.io/aquasecurity/trivy:0.45.1` + +:simple-github: **GitHub repository**: [https://github.com/aquasecurity/trivy](https://github.com/aquasecurity/trivy) + +## Large vulnerability reports + +Vulnerability reports can be large. +If you encounter issues with etcd request payload limit, you can ignore unfixed vulnerabilities from reports +by providing the following flag to `helm upgrade --install` command: + +``` +--set 'scan.plugins.trivy.ignoreUnfixed=true' +``` + +To identify this issue, check the logs of worker container in trivy pod. +The `ClusterScan` will have a `Failed` status. You will see a log entry similar to the following example: + +``` +2023-09-26T14:18:02Z ERROR worker failed to run worker {"error": "failed to create VulnerabilityReport \"kind-kind-usdockerpkgdevgooglesamplescontainersgkegbfrontendsha256dc8de8e0d569d2f828b187528c9317bd6b605c273ac5a282aebe471f630420fc-rzntw\": etcdserver: request is too large"} +``` + +!!! note + Currently, Trivy results (`VulnerabilityReport`) are only available in Zora OSS. + We are working to include this in Zora Dashboard, and it will be available soon. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 814b05a3..ba15141f 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -2,8 +2,10 @@ --md-primary-fg-color: #3CA9DD; --md-primary-fg-color--light: #2086B6; --md-primary-fg-color--dark: #3CA9DD; + --md-accent-fg-color: #3CA9DD; } .md-typeset a:is(:focus,:hover), .md-nav__link:is(:focus,:hover) { color: #176082 } + diff --git a/docs/target-cluster.md b/docs/target-cluster.md deleted file mode 100644 index e01565f8..00000000 --- a/docs/target-cluster.md +++ /dev/null @@ -1,265 +0,0 @@ -# Prepare the target cluster - -Follow this guide to create a service account and generate a kubeconfig file from a [target cluster](../glossary#target-cluster). -These are the only steps required to be performed in the target cluster. - -For manual configuration, go to [Manual Configuration](#manual-configuration), otherwise proceed to [Setup Script](#setup-script). - -!!! note - If your target cluster is under a server proxy for external communication, like those present on platforms like [Rancher](https://www.rancher.com/), - we recommend generating a kubeconfig file through your own platform. - - Normally these platforms handle their own tokens instead of a service account token. - - Zora requires read-only access, as described [here](#2-create-the-rbac-resources). - - -## Setup Script - -A [script](https://zora-docs.undistro.io/v0.5/targetcluster.sh) is available to prepare a cluster, which can be executed by any POSIX compliant shell. - -```shel -curl -q https://zora-docs.undistro.io/v0.5/targetcluster.sh | sh -``` - -By default, the script uses the current context. -But it's possible to set the target cluster context by exporting the `CONTEXT`: - -```shel -curl -q https://zora-docs.undistro.io/v0.5/targetcluster.sh | CONTEXT= sh -``` - -Or switching the current context via `kubectl` before running the script: - -```shel -kubectl config use-context -curl -q https://zora-docs.undistro.io/v0.5/targetcluster.sh | sh -``` - -The generated kubeconfig will be named as your Kuberntes context suffixed with `-kubeconfig.yaml`, by default. - -Before finishing, the script will show a command to [connect the target cluster](../connect-cluster) through the generated kubeconfig, and save a sample `Cluster` manifest. - -A complete list of customizable environment variables can be seen on the table below. - -| Environment Variable | Description | -|:--------------------------|:---------------------------------------------------------------------------------------------------------------| -| `SVC_ACCOUNT_NS` | Service Account namespace, defaults to `zora-system` | -| `SVC_ACCOUNT_NAME` | Service Account name, defaults to `zora-view` | -| `CLUSTER_ROLE_NAME` | Cluster Role name, defaults to `zora-view` | -| `SVC_ACCOUNT_SECRET_NS` | Service Account Secret namespace, defaults to the value of `SVC_ACCOUNT_NS` | -| `SVC_ACCOUNT_SECRET_NAME` | Service Account Secret name, defaults to the of value of `SVC_ACCOUNT_NAME` with the "-token" suffix | -| `KCONFIG_SECRET_NAME` | Name of the displayed kubeconfig Secret, defaults to the value of `CLUSTER_NAME` with the "-kubeconfig" suffix | -| `TOKEN_NAME` | Uses the value of `SVC_ACCOUNT_SECRET_NAME` or the one generated by K8s, according to the cluster version | -| `CONTEXT` | K8s context, using the current one as default | -| `CLUSTER_NAME` | Cluster name from the `CONTEXT` variable | -| `CLUSTER_NS` | Cluster namespace used on the manifest sample, defaults to the value of `SVC_ACCOUNT_NS` | -| `CLUSTER_CA` | Cluster Certificate Authority, extracted according to `CONTEXT` | -| `CLUSTER_SERVER` | Cluster server address, extracted according to `CONTEXT` | -| `KCONFIG_NAME` | Name of the generated kubeconfig, defaulting to the value of `CONTEXT` plus the string "_kubeconfig.yaml" | -| `SAMPLE_MANIFEST_NAME` | Name of the `Cluster` manifest sample, defaults to `cluster_sample.yaml` plus the K8s context as prefix | - -The next instructions explain how to manually configure your target clusters. - - -## Manual Configuration - -The target cluster can be configured through the steps described in the next sections. - -### 1. Access the [target cluster](../glossary#target-cluster) - -First, make sure you are in the context of the **target cluster**. -You can do this by the following commands: - -- Display list of contexts: `kubectl config get-contexts` - -- Display the current-context: `kubectl config current-context` - -- Set the default context to **my-target-cluster**: `kubectl config use-context my-target-cluster` - -### 2. Create the RBAC resources - -Create the service account in a separate namespace and configure `view` permissions. -The token generated by this service account will be used in the kubeconfig file. - -!!! warning "Important" - You should create a separate service account in the target cluster to connect it to Zora. - This is required because the kubeconfig files generated by most cloud providers, - call CLI commands, such as `aws` or `gcloud`, those can’t be called by Zora. - -```yaml -kubectl create namespace zora-system -kubectl -n zora-system create serviceaccount zora-view -cat << EOF | kubectl apply -f - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: zora-view -rules: - - apiGroups: [ "" ] - resources: - - configmaps - - endpoints - - limitranges - - namespaces - - nodes - - persistentvolumes - - persistentvolumeclaims - - pods - - replicationcontrollers - - secrets - - serviceaccounts - - services - verbs: [ "get", "list" ] - - apiGroups: [ "apps" ] - resources: - - daemonsets - - deployments - - statefulsets - - replicasets - verbs: [ "get", "list" ] - - apiGroups: [ "autoscaling" ] - resources: - - horizontalpodautoscalers - verbs: [ "get", "list" ] - - apiGroups: [ "networking.k8s.io" ] - resources: - - ingresses - - networkpolicies - verbs: [ "get", "list" ] - - apiGroups: [ "policy" ] - resources: - - poddisruptionbudgets - - podsecuritypolicies - verbs: [ "get", "list" ] - - apiGroups: [ "rbac.authorization.k8s.io" ] - resources: - - clusterroles - - clusterrolebindings - - roles - - rolebindings - verbs: [ "get", "list" ] - - apiGroups: [ "metrics.k8s.io" ] - resources: - - pods - - nodes - verbs: [ "get", "list" ] - - apiGroups: [ batch ] - resources: - - jobs - - cronjobs - verbs: [ "get", "list" ] - - apiGroups: [ admissionregistration.k8s.io ] - resources: - - validatingwebhookconfigurations - - mutatingwebhookconfigurations - verbs: [ "get", "list" ] -EOF -kubectl create clusterrolebinding zora-view --clusterrole=zora-view --serviceaccount=zora-system:zora-view -``` - -!!! info - Zora requires just view permissions of your target clusters. - -### 3. Set up the environment variables - -Set up the following environment variables based on the Kubernetes version of the target cluster. - -You can verify the version of your cluster by running: -```shell -kubectl version -``` - -The _Server Version_ is the version of Kubernetes your target cluster is running. - -=== "Kubernetes prior to 1.24.0" - - ```shell - export TOKEN_NAME=$(kubectl -n zora-system get serviceaccount zora-view -o=jsonpath='{.secrets[0].name}') - export TOKEN_VALUE=$(kubectl -n zora-system get secret ${TOKEN_NAME} -o=jsonpath='{.data.token}' | base64 --decode) - export CURRENT_CONTEXT=$(kubectl config current-context) - export CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}') - export CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}') - export CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}') - ``` - -=== "Kubernetes 1.24.0 or later" - - ```shell - export TOKEN_NAME="zora-view-token" - cat << EOF | kubectl apply -f - - apiVersion: v1 - kind: Secret - metadata: - name: "$TOKEN_NAME" - namespace: "zora-system" - annotations: - kubernetes.io/service-account.name: "zora-view" - type: kubernetes.io/service-account-token - EOF - export TOKEN_VALUE=$(kubectl -n zora-system get secret ${TOKEN_NAME} -o=jsonpath='{.data.token}' | base64 --decode) - export CURRENT_CONTEXT=$(kubectl config current-context) - export CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}') - export CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}') - export CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}') - ``` - -### 4. Generate a kubeconfig file - -Generate a file with kubeconfig data, based on the environment variables defined before: - -```yaml -cat << EOF > zora-view-kubeconfig.yml -apiVersion: v1 -kind: Config -current-context: ${CURRENT_CONTEXT} -contexts: -- name: ${CURRENT_CONTEXT} - context: - cluster: ${CURRENT_CONTEXT} - user: zora-view -clusters: -- name: ${CURRENT_CONTEXT} - cluster: - certificate-authority-data: ${CLUSTER_CA} - server: ${CLUSTER_SERVER} -users: -- name: zora-view - user: - token: ${TOKEN_VALUE} -EOF -``` - -??? info "Example of a generated kubeconfig file" - - ```yaml - apiVersion: v1 - kind: Config - current-context: mycluster-prod - contexts: - - name: mycluster-prod - context: - cluster: mycluster-prod - user: zora-view - clusters: - - name: mycluster-prod - cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJU...OMITTED - server: https://OMITTED.us-east-1.eks.amazonaws.com - users: - - name: zora-view - user: - token: eyJhbGciOiJSUzI1NiIs...OMITTED - ``` - - -### Verify the generated kubeconfig - -These steps create a file in your current working directory called `zora-view-kubeconfig.yml`. -The contents of this file are used in [the next guide](../connect-cluster) to connect this target cluster into Zora. - -Before using this kubeconfig, you can verify that it is functional by running: - -```shell -kubectl --kubeconfig zora-view-kubeconfig.yml get all --all-namespaces -``` diff --git a/go.mod b/go.mod index ccd75180..d5329e78 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/undistro/zora go 1.20 require ( + github.com/aquasecurity/trivy v0.44.1 github.com/caarlos0/env/v9 v9.0.0 github.com/go-logr/logr v1.2.4 github.com/google/go-cmp v0.5.9 @@ -11,25 +12,34 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/undistro/marvin v0.1.6 go.uber.org/zap v1.24.0 - k8s.io/api v0.27.2 + k8s.io/api v0.27.4 k8s.io/apiextensions-apiserver v0.27.2 - k8s.io/apimachinery v0.27.2 - k8s.io/client-go v0.27.2 + k8s.io/apimachinery v0.27.4 + k8s.io/client-go v0.27.3 k8s.io/metrics v0.27.2 - k8s.io/utils v0.0.0-20230209194617-a36077c30491 + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 sigs.k8s.io/controller-runtime v0.15.0 sigs.k8s.io/yaml v1.3.0 ) require ( + github.com/CycloneDX/cyclonedx-go v0.7.2-0.20230625092137-07e2f29defc3 // indirect + github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect + github.com/aquasecurity/go-dep-parser v0.0.0-20230803125501-bd9cf68d8636 // indirect + github.com/aquasecurity/table v1.8.0 // indirect + github.com/aquasecurity/tml v0.6.1 // indirect + github.com/aquasecurity/trivy-db v0.0.0-20230726112157-167ba4f2faeb // indirect + github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230708090141-f44c2292c9a9 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.14.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect @@ -38,46 +48,76 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/cel-go v0.13.0 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/go-containerregistry v0.15.2 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/imdario/mergo v0.3.15 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/package-url/packageurl-go v0.1.1 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/samber/lo v1.38.1 // indirect + github.com/spdx/tools-golang v0.5.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.5.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/tools v0.10.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiserver v0.27.2 // indirect - k8s.io/component-base v0.27.2 // indirect - k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/cli-runtime v0.27.3 // indirect + k8s.io/component-base v0.27.3 // indirect + k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.13.2 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 7ad55c40..3c5ebeed 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,113 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/storage v1.29.0 h1:6weCgzRvMg7lzuUurI4697AqIRPU1SvzHhynwpW31jI= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/CycloneDX/cyclonedx-go v0.7.2-0.20230625092137-07e2f29defc3 h1:NqeV+ZMqpcosu0Xg2VW14Ru9ayBs/toe2oihS7sN6Xo= +github.com/CycloneDX/cyclonedx-go v0.7.2-0.20230625092137-07e2f29defc3/go.mod h1:fGXSp1lCDfMQ8KR1EjxT4ewc5HHhGczRF2pWhLSWohs= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM= +github.com/aquasecurity/defsec v0.91.1 h1:dBIPm6Tva9I+ZTQv+6t9wob3ZlMSu8NFqMJr4mgJC5A= +github.com/aquasecurity/go-dep-parser v0.0.0-20230803125501-bd9cf68d8636 h1:8f/1XPe9xcd8BkXU0LfQXNKmlCUB957674usf+Y/af0= +github.com/aquasecurity/go-dep-parser v0.0.0-20230803125501-bd9cf68d8636/go.mod h1:Cl6aYro+Ddzh1MB451j/C6rvwKdn/Ifa7z98sFirJ9I= +github.com/aquasecurity/table v1.8.0 h1:9ntpSwrUfjrM6/YviArlx/ZBGd6ix8W+MtojQcM7tv0= +github.com/aquasecurity/table v1.8.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw= +github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= +github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= +github.com/aquasecurity/trivy v0.44.1 h1:KcYhS/sNheabe6U3NTVYb+NSMg34OzWzWv5VyPbCl0c= +github.com/aquasecurity/trivy v0.44.1/go.mod h1:jVUjY3SwpovchdasfIoY/3P3w9u6UyhcFo1lyXQvHe8= +github.com/aquasecurity/trivy-db v0.0.0-20230726112157-167ba4f2faeb h1:uz2+9G7E0/mjf5Q0MB/BwbpdObU34CKGUdnypTYWTfs= +github.com/aquasecurity/trivy-db v0.0.0-20230726112157-167ba4f2faeb/go.mod h1:st35g9O0ecDGBqnRHNFFz8imlDD3GWTCwo1WyJixI2c= +github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230708090141-f44c2292c9a9 h1:PA91rctNeAZY0hb2tPK68lAEpau3ItSto4FnqFXPF4g= +github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230708090141-f44c2292c9a9/go.mod h1:R7LNrrjSc4PEs0suUd+pXSqSUMMU/eY5byWHfKSZyjQ= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/aws/aws-sdk-go v1.44.273 h1:CX8O0gK+cGrgUyv7bgJ6QQP9mQg7u5mweHdNzULH47c= +github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= +github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= +github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/docker v23.0.7-0.20230714215826-f00e7af96042+incompatible h1:j7cPAKd+yLS4f16Jqri/wXRK+7TtFQCt89WPqECWnIM= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= +github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE= +github.com/go-gorp/gorp/v3 v3.0.5 h1:PUjzYdYu3HBOh8LE+UUmRG2P0IRDak9XMeGNvaeq4Ow= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -43,6 +118,8 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/goccy/go-yaml v1.8.1 h1:JuZRFlqLM5cWF6A+waL8AKVuCcqvKOuhJtUQI+L3ez0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -62,6 +139,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU= github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= @@ -73,23 +152,53 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= +github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 h1:aC6MEAs3PE3lWD7lqrJfDxHd6hcced9R4JTZu85cJwU= +github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -98,21 +207,62 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/liamg/iamgo v0.0.9 h1:tADGm3xVotyRJmuKKaH4+zsBn7LOcvgdpuF3WsSKW3c= +github.com/liamg/jfather v0.0.7 h1:Xf78zS263yfT+xr2VSo6+kyAy4ROlCacRqJG7s5jt4k= +github.com/liamg/memoryfs v1.4.3 h1:+ChjcuPRYpjJSulD13PXDNR3JeJ5HUYKjLHyWVK0bqU= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 h1:X6W6raTo07X0q4pvSI/68Pj/Ic4iIU2CfQU65OH0Zhc= +github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70/go.mod h1:QKBZqdn6teT0LK3QhAf3K6xakItd1LonOShOEC44idQ= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/moby/buildkit v0.11.6 h1:VYNdoKk5TVxN7k4RvZgdeM4GOyRvIi4Z8MXOY7xvyUs= +github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/open-policy-agent/opa v0.45.0 h1:P5nuhVRtR+e58fk3CMMbiqr6ZFyWQPNOC3otsorGsFs= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/owenrumney/squealer v1.1.1 h1:e+fg29IxdNARSc4s7CbYnqVSepm9eOqErLNNNR5XbAs= +github.com/package-url/packageurl-go v0.1.1 h1:KTRE0bK3sKbFKAk3yy63DpeskU7Cvs/x/Da5l+RtzyU= +github.com/package-url/packageurl-go v0.1.1/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -127,15 +277,34 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE= +github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= +github.com/spdx/tools-golang v0.5.0 h1:/fqihV2Jna7fmow65dHpgKNsilgLK7ICpd2tkCnPEyY= +github.com/spdx/tools-golang v0.5.0/go.mod h1:kkGlrSXXfHwuSzHQZJRV3aKu9ZXCq/MSf2+xyiJH1lM= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -144,24 +313,50 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= +github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/undistro/marvin v0.1.6 h1:4fRGNgdXL9+/+b5hsygB0e76TgPBy/5W6okNf+nPVJs= github.com/undistro/marvin v0.1.6/go.mod h1:lKwqT15MtbE39CtiWhvanIHy33jPTtC3k+w6vgVdYSk= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= +github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -169,7 +364,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -180,11 +375,11 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -192,25 +387,28 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -222,14 +420,17 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/api v0.121.0 h1:8Oopoo8Vavxx6gt+sgs8s8/X60WBAtKQq6JqnkF+xow= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -238,11 +439,12 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -253,50 +455,60 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.12.1 h1:lzU7etZX24A6BTMXYQF3bFq0ECfD8s+fKlNBBL8AbEc= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= -k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= +k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= +k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= -k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= -k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= +k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E= k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y= -k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= -k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= -k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= -k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= -k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/cli-runtime v0.27.3 h1:h592I+2eJfXj/4jVYM+tu9Rv8FEc/dyCoD80UJlMW2Y= +k8s.io/cli-runtime v0.27.3/go.mod h1:LzXud3vFFuDFXn2LIrWnscPgUiEj7gQQcYZE2UPn9Kw= +k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8= +k8s.io/client-go v0.27.3/go.mod h1:2MBEKuTo6V1lbKy3z1euEGnhPfGZLKTS9tiJ2xodM48= +k8s.io/component-base v0.27.3 h1:g078YmdcdTfrCE4fFobt7qmVXwS8J/3cI1XxRi/2+6k= +k8s.io/component-base v0.27.3/go.mod h1:JNiKYcGImpQ44iwSYs6dysxzR9SxIIgQalk4HaCNVUY= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/kubectl v0.27.3 h1:HyC4o+8rCYheGDWrkcOQHGwDmyLKR5bxXFgpvF82BOw= k8s.io/metrics v0.27.2 h1:TD6z3dhhN9bgg5YkbTh72bPiC1BsxipBLPBWyC3VQAU= k8s.io/metrics v0.27.2/go.mod h1:v3OT7U0DBvoAzWVzGZWQhdV4qsRJWchzs/LeVN8bhW4= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go v1.2.2 h1:0E9tOHUfrNH7TCDk5KU0jVBEzCqbfdyuVfGmJ7ZeRPE= sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.13.2 h1:kejWfLeJhUsTGioDoFNJET5LQe/ajzXhJGYoU+pJsiA= +sigs.k8s.io/kustomize/api v0.13.2/go.mod h1:DUp325VVMFVcQSq+ZxyDisA8wtldwHxLZbr1g94UHsw= +sigs.k8s.io/kustomize/kyaml v0.14.1 h1:c8iibius7l24G2wVAGZn/Va2wNys03GXLjYVIcFVxKA= +sigs.k8s.io/kustomize/kyaml v0.14.1/go.mod h1:AN1/IpawKilWD7V+YvQwRGUvuUOOWpjsHu6uHwonSF4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/internal/controller/zora/clusterscan_controller.go b/internal/controller/zora/clusterscan_controller.go index 161d98b5..64f9318c 100644 --- a/internal/controller/zora/clusterscan_controller.go +++ b/internal/controller/zora/clusterscan_controller.go @@ -73,6 +73,8 @@ type ClusterScanReconciler struct { //+kubebuilder:rbac:groups=zora.undistro.io,resources=plugins,verbs=get;list;watch //+kubebuilder:rbac:groups=zora.undistro.io,resources=clusterissues,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=zora.undistro.io,resources=clusterissues/status,verbs=get +//+kubebuilder:rbac:groups=zora.undistro.io,resources=vulnerabilityreports,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zora.undistro.io,resources=vulnerabilityreports/status,verbs=get //+kubebuilder:rbac:groups=batch,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=batch,resources=cronjobs/status,verbs=get //+kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch @@ -225,8 +227,6 @@ func (r *ClusterScanReconciler) reconcile(ctx context.Context, clusterscan *v1al } pluginStatus := clusterscan.Status.GetPluginStatus(plugin.Name) - pluginStatus.Suspend = *cronJob.Spec.Suspend - pluginStatus.Schedule = cronJob.Spec.Schedule if sched, err := cron.ParseStandard(cronJob.Spec.Schedule); err != nil { log.Error(err, "failed to parse CronJob Schedule") @@ -282,12 +282,13 @@ func (r *ClusterScanReconciler) reconcile(ctx context.Context, clusterscan *v1al return notReadyErr } -// countIssues update the fields IssueCount (for each plugin) and TotalIssues from ClusterScan status based on the given issues +// countIssues update the fields TotalIssues (for each plugin) and TotalIssues from ClusterScan status based on the given issues func (r *ClusterScanReconciler) countIssues(issues []v1alpha1.ClusterIssue, clusterscan *v1alpha1.ClusterScan) { totalIssuesByPlugin := map[string]int{} var totalIssues *int for _, i := range issues { - totalIssuesByPlugin[i.Labels[v1alpha1.LabelPlugin]]++ + pluginName := i.Labels[v1alpha1.LabelPlugin] + totalIssuesByPlugin[pluginName]++ if totalIssues == nil { totalIssues = new(int) } @@ -295,9 +296,9 @@ func (r *ClusterScanReconciler) countIssues(issues []v1alpha1.ClusterIssue, clus } for p, ps := range clusterscan.Status.Plugins { if t, ok := totalIssuesByPlugin[p]; ok { - ps.IssueCount = &t + ps.TotalIssues = &t } else { - ps.IssueCount = nil + ps.TotalIssues = nil } } clusterscan.Status.TotalIssues = totalIssues @@ -394,7 +395,7 @@ func (r *ClusterScanReconciler) getLastJob(ctx context.Context, cronJob *batchv1 log := ctrllog.FromContext(ctx, "CronJob", cronJob.Name) jobList := &batchv1.JobList{} - if err := r.List(ctx, jobList, client.MatchingFields{jobOwnerKey: cronJob.Name}); err != nil { + if err := r.List(ctx, jobList, client.InNamespace(cronJob.Namespace), client.MatchingFields{jobOwnerKey: cronJob.Name}); err != nil { log.Error(err, "failed to list Jobs") return nil, err } diff --git a/internal/saas/clusters.go b/internal/saas/clusters.go index 5c742c21..804d0c41 100644 --- a/internal/saas/clusters.go +++ b/internal/saas/clusters.go @@ -18,6 +18,7 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" "github.com/undistro/zora/api/zora/v1alpha1" "github.com/undistro/zora/pkg/formats" @@ -153,14 +154,14 @@ func NewScanStatus(scans []v1alpha1.ClusterScan) (map[string]*PluginStatus, *int }, } } - pluginStatus[p].Scan.Suspend = s.Suspend - pluginStatus[p].Schedule = s.Schedule + pluginStatus[p].Scan.Suspend = pointer.BoolDeref(cs.Spec.Suspend, false) + pluginStatus[p].Schedule = cs.Spec.Schedule - if s.IssueCount != nil { + if s.TotalIssues != nil { if pluginStatus[p].IssueCount == nil { pluginStatus[p].IssueCount = new(int) } - *pluginStatus[p].IssueCount += *s.IssueCount + *pluginStatus[p].IssueCount += *s.TotalIssues } switch s.LastFinishedStatus { diff --git a/internal/saas/clusters_test.go b/internal/saas/clusters_test.go index ccaaf6be..7b2411ac 100644 --- a/internal/saas/clusters_test.go +++ b/internal/saas/clusters_test.go @@ -94,7 +94,7 @@ func TestNewCluster(t *testing.T) { t.Errorf("failed to load Cluster payload testdata: %v", err) } if got := NewCluster(cluster); !reflect.DeepEqual(got, payload) { - t.Errorf("NewCluster() = %s", cmp.Diff(got, payload)) + t.Errorf("NewCluster() mismatch (-want +got):\n%s", cmp.Diff(payload, got)) } }) } diff --git a/internal/saas/issues_test.go b/internal/saas/issues_test.go index 4eca63de..33354075 100644 --- a/internal/saas/issues_test.go +++ b/internal/saas/issues_test.go @@ -127,7 +127,7 @@ func TestNewResourcedIssue(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got := NewResourcedIssue(tt.clusterIssue) if !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewIssues() = %s", cmp.Diff(got, tt.want)) + t.Errorf("NewIssues() mismatch (-want +got):\n%s", cmp.Diff(tt.want, got)) } }) } diff --git a/mkdocs.yml b/mkdocs.yml index 7236bf76..81a3cbe4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -site_name: "Zora" +site_name: "Zora OSS" site_url: https://zora-docs.undistro.io repo_url: https://github.com/undistro/zora repo_name: undistro/zora @@ -22,7 +22,7 @@ extra_css: theme: name: material language: en - logo: assets/logo.png + logo: assets/logo.svg favicon: assets/favicon.ico custom_dir: docs/overrides palette: @@ -77,12 +77,27 @@ copyright: Copyright © 2022 - 2023 Undistro Authors nav: - Documentation: - - Introduction: index.md - - Install: install.md - - Prepare the target cluster: target-cluster.md - - Connect the target cluster to Zora: connect-cluster.md - - Configure a cluster scan: cluster-scan.md - - Create your own check: custom-checks.md - - Glossary: glossary.md + - "🚀 Getting Started": + - Overview: index.md + - Installation: getting-started/installation.md + - "🛠️ Configuration": + - Scan schedule: configuration/scan-schedule.md + - Custom checks with CEL: configuration/custom-checks.md + - Compute resources: configuration/resources.md + - Suspending scans: configuration/suspend-scan.md + - Retain issues: configuration/retain-issues.md + - Ignore unfixed vulnerabilities: plugins/trivy/#large-vulnerability-reports + - "🔌 Plugins": + - Overview: plugins/index.md + - Misconfiguration: + - Marvin: plugins/marvin.md + - Popeye: plugins/popeye.md + - Vulnerability: + - Trivy: plugins/trivy.md + - "🔄 Migrating to 0.7": getting-started/installation/#migrating-to-07 +# - "🔐 Data privacy": data-privacy.md + - "📊 Zora Dashboard": dashboard.md +# - "🗃️ Troubleshooting": troubleshooting.md + - "❓ FAQ": faq.md - Helm Chart: - Zora Helm Chart: helm-chart.md diff --git a/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_vulnerabilityreport.go b/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_vulnerabilityreport.go new file mode 100644 index 00000000..4a03bb77 --- /dev/null +++ b/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_vulnerabilityreport.go @@ -0,0 +1,114 @@ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/undistro/zora/api/zora/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeVulnerabilityReports implements VulnerabilityReportInterface +type FakeVulnerabilityReports struct { + Fake *FakeZoraV1alpha1 + ns string +} + +var vulnerabilityreportsResource = schema.GroupVersionResource{Group: "zora", Version: "v1alpha1", Resource: "vulnerabilityreports"} + +var vulnerabilityreportsKind = schema.GroupVersionKind{Group: "zora", Version: "v1alpha1", Kind: "VulnerabilityReport"} + +// Get takes name of the vulnerabilityReport, and returns the corresponding vulnerabilityReport object, and an error if there is any. +func (c *FakeVulnerabilityReports) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VulnerabilityReport, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(vulnerabilityreportsResource, c.ns, name), &v1alpha1.VulnerabilityReport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VulnerabilityReport), err +} + +// List takes label and field selectors, and returns the list of VulnerabilityReports that match those selectors. +func (c *FakeVulnerabilityReports) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VulnerabilityReportList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(vulnerabilityreportsResource, vulnerabilityreportsKind, c.ns, opts), &v1alpha1.VulnerabilityReportList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.VulnerabilityReportList{ListMeta: obj.(*v1alpha1.VulnerabilityReportList).ListMeta} + for _, item := range obj.(*v1alpha1.VulnerabilityReportList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested vulnerabilityReports. +func (c *FakeVulnerabilityReports) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(vulnerabilityreportsResource, c.ns, opts)) + +} + +// Create takes the representation of a vulnerabilityReport and creates it. Returns the server's representation of the vulnerabilityReport, and an error, if there is any. +func (c *FakeVulnerabilityReports) Create(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.CreateOptions) (result *v1alpha1.VulnerabilityReport, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(vulnerabilityreportsResource, c.ns, vulnerabilityReport), &v1alpha1.VulnerabilityReport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VulnerabilityReport), err +} + +// Update takes the representation of a vulnerabilityReport and updates it. Returns the server's representation of the vulnerabilityReport, and an error, if there is any. +func (c *FakeVulnerabilityReports) Update(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.UpdateOptions) (result *v1alpha1.VulnerabilityReport, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(vulnerabilityreportsResource, c.ns, vulnerabilityReport), &v1alpha1.VulnerabilityReport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VulnerabilityReport), err +} + +// Delete takes name of the vulnerabilityReport and deletes it. Returns an error if one occurs. +func (c *FakeVulnerabilityReports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(vulnerabilityreportsResource, c.ns, name, opts), &v1alpha1.VulnerabilityReport{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVulnerabilityReports) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(vulnerabilityreportsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.VulnerabilityReportList{}) + return err +} + +// Patch applies the patch and returns the patched vulnerabilityReport. +func (c *FakeVulnerabilityReports) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VulnerabilityReport, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(vulnerabilityreportsResource, c.ns, name, pt, data, subresources...), &v1alpha1.VulnerabilityReport{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.VulnerabilityReport), err +} diff --git a/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_zora_client.go b/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_zora_client.go index 2e6a155b..39b79999 100644 --- a/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_zora_client.go +++ b/pkg/clientset/versioned/typed/zora/v1alpha1/fake/fake_zora_client.go @@ -24,6 +24,10 @@ func (c *FakeZoraV1alpha1) ClusterScans(namespace string) v1alpha1.ClusterScanIn return &FakeClusterScans{c, namespace} } +func (c *FakeZoraV1alpha1) VulnerabilityReports(namespace string) v1alpha1.VulnerabilityReportInterface { + return &FakeVulnerabilityReports{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeZoraV1alpha1) RESTClient() rest.Interface { diff --git a/pkg/clientset/versioned/typed/zora/v1alpha1/generated_expansion.go b/pkg/clientset/versioned/typed/zora/v1alpha1/generated_expansion.go index 2f044c8e..07ffdf10 100644 --- a/pkg/clientset/versioned/typed/zora/v1alpha1/generated_expansion.go +++ b/pkg/clientset/versioned/typed/zora/v1alpha1/generated_expansion.go @@ -7,3 +7,5 @@ type ClusterExpansion interface{} type ClusterIssueExpansion interface{} type ClusterScanExpansion interface{} + +type VulnerabilityReportExpansion interface{} diff --git a/pkg/clientset/versioned/typed/zora/v1alpha1/vulnerabilityreport.go b/pkg/clientset/versioned/typed/zora/v1alpha1/vulnerabilityreport.go new file mode 100644 index 00000000..7d8cb588 --- /dev/null +++ b/pkg/clientset/versioned/typed/zora/v1alpha1/vulnerabilityreport.go @@ -0,0 +1,162 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/undistro/zora/api/zora/v1alpha1" + scheme "github.com/undistro/zora/pkg/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// VulnerabilityReportsGetter has a method to return a VulnerabilityReportInterface. +// A group's client should implement this interface. +type VulnerabilityReportsGetter interface { + VulnerabilityReports(namespace string) VulnerabilityReportInterface +} + +// VulnerabilityReportInterface has methods to work with VulnerabilityReport resources. +type VulnerabilityReportInterface interface { + Create(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.CreateOptions) (*v1alpha1.VulnerabilityReport, error) + Update(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.UpdateOptions) (*v1alpha1.VulnerabilityReport, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.VulnerabilityReport, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.VulnerabilityReportList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VulnerabilityReport, err error) + VulnerabilityReportExpansion +} + +// vulnerabilityReports implements VulnerabilityReportInterface +type vulnerabilityReports struct { + client rest.Interface + ns string +} + +// newVulnerabilityReports returns a VulnerabilityReports +func newVulnerabilityReports(c *ZoraV1alpha1Client, namespace string) *vulnerabilityReports { + return &vulnerabilityReports{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the vulnerabilityReport, and returns the corresponding vulnerabilityReport object, and an error if there is any. +func (c *vulnerabilityReports) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.VulnerabilityReport, err error) { + result = &v1alpha1.VulnerabilityReport{} + err = c.client.Get(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of VulnerabilityReports that match those selectors. +func (c *vulnerabilityReports) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.VulnerabilityReportList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.VulnerabilityReportList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested vulnerabilityReports. +func (c *vulnerabilityReports) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a vulnerabilityReport and creates it. Returns the server's representation of the vulnerabilityReport, and an error, if there is any. +func (c *vulnerabilityReports) Create(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.CreateOptions) (result *v1alpha1.VulnerabilityReport, err error) { + result = &v1alpha1.VulnerabilityReport{} + err = c.client.Post(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(vulnerabilityReport). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a vulnerabilityReport and updates it. Returns the server's representation of the vulnerabilityReport, and an error, if there is any. +func (c *vulnerabilityReports) Update(ctx context.Context, vulnerabilityReport *v1alpha1.VulnerabilityReport, opts v1.UpdateOptions) (result *v1alpha1.VulnerabilityReport, err error) { + result = &v1alpha1.VulnerabilityReport{} + err = c.client.Put(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + Name(vulnerabilityReport.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(vulnerabilityReport). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the vulnerabilityReport and deletes it. Returns an error if one occurs. +func (c *vulnerabilityReports) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *vulnerabilityReports) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("vulnerabilityreports"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched vulnerabilityReport. +func (c *vulnerabilityReports) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.VulnerabilityReport, err error) { + result = &v1alpha1.VulnerabilityReport{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("vulnerabilityreports"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/clientset/versioned/typed/zora/v1alpha1/zora_client.go b/pkg/clientset/versioned/typed/zora/v1alpha1/zora_client.go index 97d74566..a966f3c0 100644 --- a/pkg/clientset/versioned/typed/zora/v1alpha1/zora_client.go +++ b/pkg/clientset/versioned/typed/zora/v1alpha1/zora_client.go @@ -15,6 +15,7 @@ type ZoraV1alpha1Interface interface { ClustersGetter ClusterIssuesGetter ClusterScansGetter + VulnerabilityReportsGetter } // ZoraV1alpha1Client is used to interact with features provided by the zora group. @@ -34,6 +35,10 @@ func (c *ZoraV1alpha1Client) ClusterScans(namespace string) ClusterScanInterface return newClusterScans(c, namespace) } +func (c *ZoraV1alpha1Client) VulnerabilityReports(namespace string) VulnerabilityReportInterface { + return newVulnerabilityReports(c, namespace) +} + // NewForConfig creates a new ZoraV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/pkg/plugins/cronjob.go b/pkg/plugins/cronjob.go index 03160f35..26059b9e 100644 --- a/pkg/plugins/cronjob.go +++ b/pkg/plugins/cronjob.go @@ -100,18 +100,14 @@ func (r *CronJobMutator) Mutate() error { } r.Existing.ObjectMeta.Labels[LabelClusterScan] = r.ClusterScan.Name r.Existing.ObjectMeta.Labels[LabelPlugin] = r.Plugin.Name - schedule := r.PluginRef.Schedule - if schedule == "" { - schedule = r.ClusterScan.Spec.Schedule - } - r.Existing.Spec.Schedule = schedule + r.Existing.Spec.Schedule = r.ClusterScan.Spec.Schedule r.Existing.Spec.ConcurrencyPolicy = batchv1.ForbidConcurrent r.Existing.Spec.SuccessfulJobsHistoryLimit = r.ClusterScan.Spec.SuccessfulScansHistoryLimit r.Existing.Spec.FailedJobsHistoryLimit = r.ClusterScan.Spec.FailedScansHistoryLimit r.Existing.Spec.Suspend = &r.Suspend if !r.Suspend { - r.Existing.Spec.Suspend = firstNonNilBoolPointer(r.PluginRef.Suspend, r.ClusterScan.Spec.Suspend) + r.Existing.Spec.Suspend = r.ClusterScan.Spec.Suspend } r.Existing.Spec.JobTemplate.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyNever r.Existing.Spec.JobTemplate.Spec.BackoffLimit = pointer.Int32(0) @@ -139,9 +135,6 @@ func (r *CronJobMutator) Mutate() error { }, }) } - r.Existing.Spec.JobTemplate.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{ - RunAsNonRoot: pointer.Bool(true), - } if pointer.BoolDeref(r.Plugin.Spec.MountCustomChecksVolume, false) { initContainer := r.initContainer() @@ -196,9 +189,14 @@ func (r *CronJobMutator) workerContainer() corev1.Container { Name: workerContainerName, Image: r.WorkerImage, Env: r.workerEnv(), + EnvFrom: r.Plugin.Spec.EnvFrom, Resources: r.Plugin.Spec.Resources, VolumeMounts: commonVolumeMounts, ImagePullPolicy: corev1.PullIfNotPresent, + SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: pointer.Bool(true), + AllowPrivilegeEscalation: pointer.Bool(false), + }, } } @@ -238,6 +236,10 @@ func (r *CronJobMutator) initContainer() corev1.Container { VolumeMounts: []corev1.VolumeMount{customChecksVolume}, ImagePullPolicy: corev1.PullIfNotPresent, Resources: r.Plugin.Spec.Resources, + SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: pointer.Bool(true), + AllowPrivilegeEscalation: pointer.Bool(false), + }, } } @@ -269,7 +271,8 @@ func (r *CronJobMutator) pluginEnv() []corev1.EnvVar { // workerEnv returns a list of environment variables to set in the Worker container func (r *CronJobMutator) workerEnv() []corev1.EnvVar { - return append(commonEnv, + p := append(commonEnv, r.Plugin.Spec.Env...) + p = append(p, corev1.EnvVar{ Name: "CLUSTER_NAME", Value: r.ClusterScan.Spec.ClusterRef.Name, @@ -284,6 +287,10 @@ func (r *CronJobMutator) workerEnv() []corev1.EnvVar { Name: "PLUGIN_NAME", Value: r.Plugin.Name, }, + corev1.EnvVar{ + Name: "PLUGIN_TYPE", + Value: r.Plugin.Spec.Type, + }, corev1.EnvVar{ Name: "JOB_NAME", ValueFrom: &corev1.EnvVarSource{ @@ -303,13 +310,5 @@ func (r *CronJobMutator) workerEnv() []corev1.EnvVar { }, }, ) -} - -func firstNonNilBoolPointer(pointers ...*bool) *bool { - for _, b := range pointers { - if b != nil { - return b - } - } - return pointer.Bool(false) + return p } diff --git a/pkg/worker/config.go b/pkg/worker/config.go index 0c5e8cda..636c46dd 100644 --- a/pkg/worker/config.go +++ b/pkg/worker/config.go @@ -26,6 +26,7 @@ type config struct { DoneFile string `env:"DONE_FILE" envDefault:"/tmp/zora/results/done"` ErrorFile string `env:"ERROR_FILE" envDefault:"/tmp/zora/results/error"` PluginName string `env:"PLUGIN_NAME,required"` + PluginType string `env:"PLUGIN_TYPE,required"` ClusterName string `env:"CLUSTER_NAME,required"` Namespace string `env:"NAMESPACE,required"` JobName string `env:"JOB_NAME,required"` diff --git a/pkg/worker/config_test.go b/pkg/worker/config_test.go index 5f9d2e20..e1b689fa 100644 --- a/pkg/worker/config_test.go +++ b/pkg/worker/config_test.go @@ -36,6 +36,7 @@ func TestConfigFromEnv(t *testing.T) { name: "required only", env: map[string]string{ "PLUGIN_NAME": "plugin", + "PLUGIN_TYPE": "misconfiguration", "CLUSTER_NAME": "cluster", "NAMESPACE": "ns", "JOB_NAME": "cluster-plugin-28140229", @@ -46,6 +47,7 @@ func TestConfigFromEnv(t *testing.T) { DoneFile: "/tmp/zora/results/done", ErrorFile: "/tmp/zora/results/error", PluginName: "plugin", + PluginType: "misconfiguration", ClusterName: "cluster", Namespace: "ns", JobName: "cluster-plugin-28140229", @@ -59,6 +61,7 @@ func TestConfigFromEnv(t *testing.T) { name: "one required env missing", env: map[string]string{ //"PLUGIN_NAME": "plugin", + "PLUGIN_TYPE": "misconfiguration", "CLUSTER_NAME": "cluster", "NAMESPACE": "ns", "JOB_NAME": "cluster-plugin-28140229", @@ -71,6 +74,7 @@ func TestConfigFromEnv(t *testing.T) { name: "all", env: map[string]string{ "PLUGIN_NAME": "plugin", + "PLUGIN_TYPE": "vulnerability", "CLUSTER_NAME": "cluster", "NAMESPACE": "ns", "JOB_NAME": "cluster-plugin-28140229", @@ -84,6 +88,7 @@ func TestConfigFromEnv(t *testing.T) { DoneFile: "/done", ErrorFile: "/error", PluginName: "plugin", + PluginType: "vulnerability", ClusterName: "cluster", Namespace: "ns", JobName: "cluster-plugin-28140229", diff --git a/pkg/worker/parse.go b/pkg/worker/misconfig.go similarity index 66% rename from pkg/worker/parse.go rename to pkg/worker/misconfig.go index f5864703..e1f36dd4 100644 --- a/pkg/worker/parse.go +++ b/pkg/worker/misconfig.go @@ -22,17 +22,17 @@ import ( "strconv" "strings" - batchv1 "k8s.io/api/batch/v1" + "github.com/go-logr/logr" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" "github.com/undistro/zora/api/zora/v1alpha1" + zora "github.com/undistro/zora/pkg/clientset/versioned" "github.com/undistro/zora/pkg/worker/report/marvin" "github.com/undistro/zora/pkg/worker/report/popeye" ) -// pluginParsers maps parse function by plugin name -var pluginParsers = map[string]func(ctx context.Context, reader io.Reader) ([]v1alpha1.ClusterIssueSpec, error){ +// misconfigPlugins maps parse function by misconfig plugin name +var misconfigPlugins = map[string]func(ctx context.Context, reader io.Reader) ([]v1alpha1.ClusterIssueSpec, error){ "popeye": popeye.Parse, "marvin": marvin.Parse, } @@ -42,9 +42,27 @@ var clusterIssueTypeMeta = metav1.TypeMeta{ APIVersion: v1alpha1.SchemeGroupVersion.String(), } -// parseResults converts the given results into ClusterIssues -func parseResults(ctx context.Context, cfg *config, results io.Reader) ([]v1alpha1.ClusterIssue, error) { - parseFunc, ok := pluginParsers[cfg.PluginName] +var createOpts = metav1.CreateOptions{} + +func handleMisconfiguration(ctx context.Context, cfg *config, results io.Reader, client *zora.Clientset) error { + log := logr.FromContextOrDiscard(ctx) + issues, err := parseMisconfigResults(ctx, cfg, results) + if err != nil { + return err + } + for _, issue := range issues { + issue, err := client.ZoraV1alpha1().ClusterIssues(cfg.Namespace).Create(ctx, &issue, createOpts) + if err != nil { + return fmt.Errorf("failed to create ClusterIssue %q: %v", issue.Name, err) + } + log.Info(fmt.Sprintf("ClusterIssue %q successfully created", issue.Name), "resourceVersion", issue.ResourceVersion) + } + return nil +} + +// parseMisconfigResults converts the given results into ClusterIssues +func parseMisconfigResults(ctx context.Context, cfg *config, results io.Reader) ([]v1alpha1.ClusterIssue, error) { + parseFunc, ok := misconfigPlugins[cfg.PluginName] if !ok { return nil, errors.New(fmt.Sprintf("invalid plugin %q", cfg.PluginName)) } @@ -52,12 +70,7 @@ func parseResults(ctx context.Context, cfg *config, results io.Reader) ([]v1alph if err != nil { return nil, fmt.Errorf("failed to parse %q results: %v", cfg.PluginName, err) } - owner := metav1.OwnerReference{ - APIVersion: batchv1.SchemeGroupVersion.String(), - Kind: "Job", - Name: cfg.JobName, - UID: types.UID(cfg.JobUID), - } + owner := ownerReference(cfg) issues := make([]v1alpha1.ClusterIssue, len(specs)) for i := 0; i < len(specs); i++ { issues[i] = newClusterIssue(cfg, specs[i], owner) @@ -77,10 +90,10 @@ func newClusterIssue(cfg *config, spec v1alpha1.ClusterIssueSpec, owner metav1.O Labels: map[string]string{ v1alpha1.LabelScanID: cfg.JobUID, v1alpha1.LabelCluster: cfg.ClusterName, + v1alpha1.LabelPlugin: cfg.PluginName, v1alpha1.LabelSeverity: string(spec.Severity), v1alpha1.LabelIssueID: spec.ID, v1alpha1.LabelCategory: strings.ReplaceAll(spec.Category, " ", ""), - v1alpha1.LabelPlugin: cfg.PluginName, v1alpha1.LabelCustom: strconv.FormatBool(spec.Custom), }, }, diff --git a/pkg/worker/parse_test.go b/pkg/worker/misconfig_test.go similarity index 95% rename from pkg/worker/parse_test.go rename to pkg/worker/misconfig_test.go index c22e376c..2c1c36eb 100644 --- a/pkg/worker/parse_test.go +++ b/pkg/worker/misconfig_test.go @@ -29,7 +29,7 @@ import ( "github.com/undistro/zora/api/zora/v1alpha1" ) -func TestParseResults(t *testing.T) { +func TestParseMisconfigResults(t *testing.T) { type args struct { cfg *config filename string @@ -42,12 +42,12 @@ func TestParseResults(t *testing.T) { }{ { name: "invalid plugin", - args: args{cfg: &config{PluginName: "foo"}}, + args: args{cfg: &config{PluginName: "trivy"}}, // trivy is not a misconfiguration plugin want: nil, wantErr: true, }, { - name: "reader of a directory", + name: "directory reader", args: args{ cfg: &config{PluginName: "marvin"}, filename: t.TempDir(), @@ -331,20 +331,20 @@ func TestParseResults(t *testing.T) { if tt.args.filename != "" { f, err := os.Open(tt.args.filename) if err != nil { - t.Errorf("parseResults() setup error = %v", err) + t.Errorf("parseMisconfigResults() setup error = %v", err) return } r = f } - got, err := parseResults(context.TODO(), tt.args.cfg, r) + got, err := parseMisconfigResults(context.TODO(), tt.args.cfg, r) if (err != nil) != tt.wantErr { - t.Errorf("parseResults() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("parseMisconfigResults() error = %v, wantErr %v", err, tt.wantErr) return } sortClusterIssues(got) sortClusterIssues(tt.want) if !reflect.DeepEqual(got, tt.want) { - t.Errorf("parseResults() got unexpect result, diff = %v", cmp.Diff(got, tt.want)) + t.Errorf("parseMisconfigResults() mismatch (-want +got):\n%s", cmp.Diff(tt.want, got)) } }) } diff --git a/pkg/worker/report/marvin/parse_test.go b/pkg/worker/report/marvin/parse_test.go index 5281fbd3..18546366 100644 --- a/pkg/worker/report/marvin/parse_test.go +++ b/pkg/worker/report/marvin/parse_test.go @@ -129,7 +129,7 @@ func TestParse(t *testing.T) { return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Parse() = %s", cmp.Diff(got, tt.want)) + t.Errorf("Parse() mismatch (-want +got):\n%s", cmp.Diff(tt.want, got)) } }) } diff --git a/pkg/worker/report/trivy/parse.go b/pkg/worker/report/trivy/parse.go new file mode 100644 index 00000000..26776cba --- /dev/null +++ b/pkg/worker/report/trivy/parse.go @@ -0,0 +1,171 @@ +// Copyright 2023 Undistro Authors +// +// 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. + +package trivy + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "strconv" + "strings" + + trivyreport "github.com/aquasecurity/trivy/pkg/k8s/report" + trivytypes "github.com/aquasecurity/trivy/pkg/types" + "github.com/go-logr/logr" + + "github.com/undistro/zora/api/zora/v1alpha1" +) + +func Parse(ctx context.Context, results io.Reader) ([]v1alpha1.VulnerabilityReportSpec, error) { + log := logr.FromContextOrDiscard(ctx) + report := &trivyreport.ConsolidatedReport{} + if err := json.NewDecoder(results).Decode(report); err != nil { + return nil, err + } + ignoreDescriptions, _ := strconv.ParseBool(os.Getenv("TRIVY_IGNORE_VULN_DESCRIPTIONS")) + vulnsByImage := make(map[string]*v1alpha1.VulnerabilityReportSpec) + + // map to control which image + class was parsed + parsed := make(map[string]bool) + + for _, f := range report.Findings { + if f.Kind == "" { + continue + } + if len(f.Error) > 0 { + log.Info(fmt.Sprintf("trivy error for %q \"%s/%s\": %s", f.Kind, f.Namespace, f.Name, f.Error)) + continue + } + img := getImage(f) + if img == "" { + log.Info(`skipping finding without "os-pkgs" result`) + continue + } + for _, result := range f.Results { + if len(result.Vulnerabilities) == 0 { + continue + } + if _, ok := vulnsByImage[img]; !ok { + vulnsByImage[img] = &v1alpha1.VulnerabilityReportSpec{Image: img} + } + spec := vulnsByImage[img] + addResource(spec, f.Kind, f.Namespace, f.Name) + + k := fmt.Sprintf("%s;%s", img, result.Class) + if _, ok := parsed[k]; ok { + continue + } + parsed[k] = true + + for _, vuln := range result.Vulnerabilities { + spec.Vulnerabilities = append(spec.Vulnerabilities, newVulnerability(vuln, ignoreDescriptions, result.Type)) + } + } + } + specs := make([]v1alpha1.VulnerabilityReportSpec, 0, len(vulnsByImage)) + for _, spec := range vulnsByImage { + summarize(spec) + specs = append(specs, *spec) + } + return specs, nil +} + +func newVulnerability(vuln trivytypes.DetectedVulnerability, ignoreDescriptions bool, resultType string) v1alpha1.Vulnerability { + description := "" + if !ignoreDescriptions { + description = vuln.Description + } + + return v1alpha1.Vulnerability{ + ID: vuln.VulnerabilityID, + Severity: vuln.Severity, + Title: vuln.Title, + Description: description, + Package: vuln.PkgName, + Version: vuln.InstalledVersion, + FixVersion: vuln.FixedVersion, + URL: vuln.PrimaryURL, + Status: vuln.Status.String(), + Score: getScore(vuln), + Type: resultType, + } +} + +func getScore(vuln trivytypes.DetectedVulnerability) string { + var vendor *float64 + for id, cvss := range vuln.CVSS { + if cvss.V3Score == 0.0 { + continue + } + if string(id) == "nvd" { + return fmt.Sprintf("%v", cvss.V3Score) + } + vendor = &cvss.V3Score + } + if vendor == nil { + return "" + } + return fmt.Sprintf("%v", *vendor) +} + +func getImage(finding trivyreport.Resource) string { + for _, r := range finding.Results { + if r.Class == "os-pkgs" { + return strings.SplitN(r.Target, " (", 2)[0] + } + } + return "" +} + +func addResource(spec *v1alpha1.VulnerabilityReportSpec, kind, namespace, name string) { + if spec.Resources == nil { + spec.Resources = map[string][]string{} + } + id := name + if namespace != "" { + id = fmt.Sprintf("%s/%s", namespace, name) + } + if res, ok := spec.Resources[kind]; ok { + for _, re := range res { + if re == id { + return + } + } + } + spec.Resources[kind] = append(spec.Resources[kind], id) + spec.TotalResources++ +} + +func summarize(spec *v1alpha1.VulnerabilityReportSpec) { + s := &v1alpha1.VulnerabilitySummary{} + for _, v := range spec.Vulnerabilities { + s.Total++ + switch v.Severity { + case "CRITICAL": + s.Critical++ + case "HIGH": + s.High++ + case "MEDIUM": + s.Medium++ + case "LOW": + s.Low++ + default: + s.Unknown++ + } + } + spec.Summary = *s +} diff --git a/pkg/worker/report/trivy/parse_test.go b/pkg/worker/report/trivy/parse_test.go new file mode 100644 index 00000000..606e3464 --- /dev/null +++ b/pkg/worker/report/trivy/parse_test.go @@ -0,0 +1,246 @@ +// Copyright 2023 Undistro Authors +// +// 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. + +package trivy + +import ( + "context" + "os" + "reflect" + "sort" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/undistro/zora/api/zora/v1alpha1" +) + +func TestParse(t *testing.T) { + tests := []struct { + name string + testfile string + want []v1alpha1.VulnerabilityReportSpec + wantErr bool + }{ + { + name: "ok", + testfile: "testdata/report.json", + wantErr: false, + want: []v1alpha1.VulnerabilityReportSpec{ + { + Image: "registry.k8s.io/kube-apiserver:v1.25.3", + Resources: map[string][]string{"Pod": {"kube-system/kube-apiserver-kind-control-plane"}}, + TotalResources: 1, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2022-41723", + Severity: "HIGH", + Title: "avoid quadratic complexity in HPACK decoding", + Description: "A maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder, sufficient to cause a denial of service from a small number of small requests.", + Package: "golang.org/x/net", + Version: "v0.0.0-20220722155237-a158d28d115b", + FixVersion: "0.7.0", + URL: "https://avd.aquasec.com/nvd/cve-2022-41723", + Status: "fixed", + Type: "gobinary", + Score: "7.5", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 1, High: 1}, + }, + { + Image: "quay.io/kiwigrid/k8s-sidecar:1.22.0", + Resources: map[string][]string{"Deployment": {"apps/app1", "apps/app2"}}, + TotalResources: 2, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2022-4450", + Severity: "HIGH", + Title: "double free after calling PEM_read_bio_ex", + Description: "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + Package: "libssl1.1", + Version: "1.1.1s-r0", + FixVersion: "1.1.1t-r0", + URL: "https://avd.aquasec.com/nvd/cve-2022-4450", + Status: "fixed", + Type: "alpine", + Score: "7.5", + }, + { + ID: "CVE-2022-4450", + Severity: "HIGH", + Title: "double free after calling PEM_read_bio_ex", + Description: "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + Package: "libcrypto1.1", + Version: "1.1.1s-r0", + FixVersion: "1.1.1t-r0", + URL: "https://avd.aquasec.com/nvd/cve-2022-4450", + Status: "fixed", + Type: "alpine", + Score: "7.5", + }, + { + ID: "CVE-2023-37920", + Severity: "CRITICAL", + Title: "Removal of e-Tugra root certificate", + Description: "Certifi is a curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. Certifi prior to version 2023.07.22 recognizes \"e-Tugra\" root certificates. e-Tugra's root certificates were subject to an investigation prompted by reporting of security issues in their systems. Certifi 2023.07.22 removes root certificates from \"e-Tugra\" from the root store.", + Package: "certifi", + Version: "2022.12.7", + FixVersion: "2023.7.22", + URL: "https://avd.aquasec.com/nvd/cve-2023-37920", + Status: "fixed", + Type: "python-pkg", + Score: "9.8", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 3, Critical: 1, High: 2}, + }, + { + Image: "docker.io/istio/examples-bookinfo-ratings-v1:1.17.0", + Resources: map[string][]string{"Deployment": {"apps/app1"}}, + TotalResources: 1, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "DLA-3051-1", + Severity: "UNKNOWN", + Title: "tzdata - new timezone database", + Description: "", + Package: "tzdata", + Version: "2019c-0+deb9u1", + FixVersion: "2021a-0+deb9u4", + URL: "", + Status: "fixed", + Type: "debian", + }, + { + ID: "CVE-2016-2779", + Severity: "HIGH", + Title: "util-linux: runuser tty hijack via TIOCSTI ioctl", + Description: "runuser in util-linux allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + Package: "bsdutils", + Version: "1:2.29.2-1+deb9u1", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2016-2779", + Status: "affected", + Type: "debian", + Score: "7.8", + }, + { + ID: "GHSA-jmqm-f2gx-4fjv", + Severity: "MEDIUM", + Title: "Sensitive information exposure through logs in npm-registry-fetch", + Description: "Affected versions of `npm-registry-fetch` are vulnerable to an information exposure vulnerability through log files. The cli supports URLs like `\u003cprotocol\u003e://[\u003cuser\u003e[:\u003cpassword\u003e]@]\u003chostname\u003e[:\u003cport\u003e][:][/]\u003cpath\u003e`. The password value is not redacted and is printed to stdout and also to any generated log files.", + Package: "npm-registry-fetch", + Version: "4.0.4", + FixVersion: "8.1.1, 4.0.5", + URL: "https://github.com/advisories/GHSA-jmqm-f2gx-4fjv", + Status: "fixed", + Type: "node-pkg", + Score: "5.3", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 3, High: 1, Medium: 1, Unknown: 1}, + }, + { + Image: "docker.io/istio/examples-bookinfo-details-v1:1.17.0", + Resources: map[string][]string{"Deployment": {"apps/app2"}}, + TotalResources: 1, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2016-2781", + Severity: "LOW", + Title: "coreutils: Non-privileged session can escape to the parent session in chroot", + Description: "chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + Package: "coreutils", + Version: "8.30-3", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2016-2781", + Status: "will_not_fix", + Type: "debian", + Score: "6.5", + }, + { + ID: "CVE-2023-28755", + Severity: "HIGH", + Title: "ReDoS vulnerability in URI", + Description: "A ReDoS issue was discovered in the URI component through 0.12.0 in Ruby through 3.2.1. The URI parser mishandles invalid URLs that have specific characters. It causes an increase in execution time for parsing strings to URI objects. The fixed versions are 0.12.1, 0.11.1, 0.10.2 and 0.10.0.1.", + Package: "uri", + Version: "0.10.0", + FixVersion: "~\u003e 0.10.0.1, ~\u003e 0.10.2, ~\u003e 0.11.1, \u003e= 0.12.1", + URL: "https://avd.aquasec.com/nvd/cve-2023-28755", + Status: "fixed", + Type: "gemspec", + Score: "5.3", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 2, High: 1, Low: 1}, + }, + { + Image: "nginx@sha256:af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305", + TotalResources: 1, + Resources: map[string][]string{"Deployment": {"default/nginx"}}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2023-3446", + Severity: "MEDIUM", + Title: "Excessive time spent checking DH keys and parameters", + Description: "Issue summary: Checking excessively long DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_check(), DH_check_ex()\nor EVP_PKEY_param_check() to check a DH key or DH parameters may experience long\ndelays. Where the key or parameters that are being checked have been obtained\nfrom an untrusted source this may lead to a Denial of Service.\n\nThe function DH_check() performs various checks on DH parameters. One of those\nchecks confirms that the modulus ('p' parameter) is not too large. Trying to use\na very large modulus is slow and OpenSSL will not normally use a modulus which\nis over 10,000 bits in length.\n\nHowever the DH_check() function checks numerous aspects of the key or parameters\nthat have been supplied. Some of those checks use the supplied modulus value\neven if it has already been found to be too large.\n\nAn application that calls DH_check() and supplies a key or parameters obtained\nfrom an untrusted source could be vulernable to a Denial of Service attack.\n\nThe function DH_check() is itself called by a number of other OpenSSL functions.\nAn application calling any of those other functions may similarly be affected.\nThe other functions affected by this are DH_check_ex() and\nEVP_PKEY_param_check().\n\nAlso vulnerable are the OpenSSL dhparam and pkeyparam command line applications\nwhen using the '-check' option.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", + Package: "openssl", + Version: "1.1.1n-0+deb11u4", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2023-3446", + Status: "fix_deferred", + Type: "debian", + Score: "5.3", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 1, Medium: 1}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.testfile) + if err != nil { + t.Errorf("Parse() setup error = %v", err) + } + got, err := Parse(context.TODO(), f) + if (err != nil) != tt.wantErr { + t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) + return + } + sortVulns(got) + sortVulns(tt.want) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Parse() mismatch (-want +got):\n%s", cmp.Diff(tt.want, got)) + } + }) + } +} + +func sortVulns(specs []v1alpha1.VulnerabilityReportSpec) { + sort.Slice(specs, func(i, j int) bool { + return strings.Compare(specs[i].Image, specs[j].Image) == -1 + }) + for _, s := range specs { + for _, v := range s.Resources { + sort.Strings(v) + } + sort.Slice(s.Vulnerabilities, func(i, j int) bool { + return strings.Compare(s.Vulnerabilities[i].ID, s.Vulnerabilities[j].ID) == -1 + }) + } +} diff --git a/pkg/worker/report/trivy/testdata/report.json b/pkg/worker/report/trivy/testdata/report.json new file mode 100644 index 00000000..074dbc6b --- /dev/null +++ b/pkg/worker/report/trivy/testdata/report.json @@ -0,0 +1,982 @@ +{ + "ClusterName": "kind-kind", + "Findings": [ + { + "Kind": "", + "Name": "" + }, + { + "Namespace": "foo", + "Kind": "Deployment", + "Name": "bar", + "Error": "scan error: unable to initialize a scanner: unable to initialize a docker scanner: 4 errors occurred:\n\t* unable to inspect the image (ghcr.io/myorg/bar:5b815c4e78fd89811a9f2c5f7653120379c80d8b): Error response from daemon: No such image: ghcr.io/myorg/bar:5b815c4e78fd89811a9f2c5f7653120379c80d8b\n\t* failed to initialize a containerd client: failed to dial \"/run/containerd/containerd.sock\": connection error: desc = \"transport: error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied\"\n\t* unable to initialize Podman client: no podman socket found: stat /run/user/1000/podman/podman.sock: no such file or directory\n\t* GET https://ghcr.io/token?scope=repository%3Amyorg%2Fbar%3Apull\u0026service=ghcr.io: UNAUTHORIZED: authentication required\n\n" + }, + { + "Namespace": "kube-system", + "Kind": "Deployment", + "Name": "coredns", + "Results": [ + { + "Target": "coredns", + "Class": "lang-pkgs", + "Type": "gobinary", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2022-1996", + "PkgName": "github.com/emicklei/go-restful", + "InstalledVersion": "v2.9.5+incompatible", + "FixedVersion": "2.16.0", + "Status": "fixed", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-1996", + "Title": "Authorization Bypass Through User-Controlled Key", + "Description": "Authorization Bypass Through User-Controlled Key in GitHub repository emicklei/go-restful prior to v3.8.0.", + "Severity": "CRITICAL" + } + ] + } + ] + }, + { + "Kind": "", + "Name": "" + }, + { + "Kind": "", + "Name": "" + }, + { + "Namespace": "kube-system", + "Kind": "Pod", + "Name": "kube-apiserver-kind-control-plane", + "Results": [ + { + "Target": "registry.k8s.io/kube-apiserver:v1.25.3 (debian 11.5)", + "Class": "os-pkgs", + "Type": "debian" + }, + { + "Target": "usr/local/bin/kube-apiserver", + "Class": "lang-pkgs", + "Type": "gobinary", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2022-41723", + "PkgName": "golang.org/x/net", + "InstalledVersion": "v0.0.0-20220722155237-a158d28d115b", + "FixedVersion": "0.7.0", + "Status": "fixed", + "Layer": { + "Digest": "sha256:b913ed5667fbc0c07d41f42c8dbecc16ae6850a370e8a9d1047ac8bfb68c82e7", + "DiffID": "sha256:1eb50537ffcc3bc68ac7394d729f2a60b36d943af6ee1a6eabc8641a84811726" + }, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-41723", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Go", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Ago" + }, + "Title": "avoid quadratic complexity in HPACK decoding", + "Description": "A maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder, sufficient to cause a denial of service from a small number of small requests.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-400" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/security/cve/CVE-2022-41723", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41723", + "https://github.com/advisories/GHSA-vvpx-j8f3-3w6h", + "https://go.dev/cl/468135", + "https://go.dev/cl/468295", + "https://go.dev/issue/57855", + "https://groups.google.com/g/golang-announce/c/V0aBFqaFs_E", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4MA5XS5DAOJ5PKKNG5TUXKPQOFHT5VBC/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RGW7GE2Z32ZT47UFAQFDRQE33B7Q7LMT/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RLBQ3A7ROLEQXQLXFDLNJ7MYPKG5GULE/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XX3IMUTZKRQ73PBZM4E2JP4BKYH4C6XE/", + "https://nvd.nist.gov/vuln/detail/CVE-2022-41723", + "https://pkg.go.dev/vuln/GO-2023-1571", + "https://vuln.go.dev/ID/GO-2023-1571.json", + "https://www.cve.org/CVERecord?id=CVE-2022-41723" + ], + "PublishedDate": "2023-02-28T18:15:00Z", + "LastModifiedDate": "2023-05-16T10:50:00Z" + } + ] + } + ] + }, + { + "Kind": "", + "Name": "" + }, + { + "Kind": "", + "Name": "" + }, + { + "Namespace": "apps", + "Kind": "Deployment", + "Name": "app1", + "Results": [ + { + "Target": "docker.io/istio/examples-bookinfo-ratings-v1:1.17.0 (debian 9.12)", + "Class": "os-pkgs", + "Type": "debian", + "Vulnerabilities": [ + { + "VulnerabilityID": "DLA-3051-1", + "VendorIDs": [ + "DLA-3051-1" + ], + "PkgID": "tzdata@2019c-0+deb9u1", + "PkgName": "tzdata", + "InstalledVersion": "2019c-0+deb9u1", + "FixedVersion": "2021a-0+deb9u4", + "Status": "fixed", + "Layer": { + "Digest": "sha256:7d2977b12acb33f192e3f20b7e15a467cc8f3f5124a15d975a6d4afe5fa3d258", + "DiffID": "sha256:333e2cb4c707229901f45d7f5e4e3caf5a983229da7fefb0605975ff3a1eaf6f" + }, + "DataSource": { + "ID": "debian", + "Name": "Debian Security Tracker", + "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "Title": "tzdata - new timezone database", + "Severity": "UNKNOWN" + }, + { + "VulnerabilityID": "CVE-2016-2779", + "PkgID": "bsdutils@1:2.29.2-1+deb9u1", + "PkgName": "bsdutils", + "InstalledVersion": "1:2.29.2-1+deb9u1", + "Status": "affected", + "Layer": { + "Digest": "sha256:7d2977b12acb33f192e3f20b7e15a467cc8f3f5124a15d975a6d4afe5fa3d258", + "DiffID": "sha256:333e2cb4c707229901f45d7f5e4e3caf5a983229da7fefb0605975ff3a1eaf6f" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2016-2779", + "DataSource": { + "ID": "debian", + "Name": "Debian Security Tracker", + "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "Title": "util-linux: runuser tty hijack via TIOCSTI ioctl", + "Description": "runuser in util-linux allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-264" + ], + "CVSS": { + "nvd": { + "V2Vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C", + "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "V2Score": 7.2, + "V3Score": 7.8 + }, + "redhat": { + "V2Vector": "AV:L/AC:H/Au:N/C:C/I:C/A:C", + "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", + "V2Score": 6.2, + "V3Score": 8.6 + } + }, + "References": [ + "http://www.openwall.com/lists/oss-security/2016/02/27/1", + "http://www.openwall.com/lists/oss-security/2016/02/27/2", + "https://access.redhat.com/security/cve/CVE-2016-2779", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815922", + "https://nvd.nist.gov/vuln/detail/CVE-2016-2779", + "https://www.cve.org/CVERecord?id=CVE-2016-2779" + ], + "PublishedDate": "2017-02-07T15:59:00Z", + "LastModifiedDate": "2019-01-04T14:14:00Z" + } + ] + }, + { + "Target": "Node.js", + "Class": "lang-pkgs", + "Type": "node-pkg", + "Vulnerabilities": [ + { + "VulnerabilityID": "GHSA-jmqm-f2gx-4fjv", + "PkgID": "npm-registry-fetch@4.0.4", + "PkgName": "npm-registry-fetch", + "PkgPath": "usr/local/lib/node_modules/npm/node_modules/npm-registry-fetch/package.json", + "InstalledVersion": "4.0.4", + "FixedVersion": "8.1.1, 4.0.5", + "Status": "fixed", + "Layer": { + "Digest": "sha256:a0b03ba934df0a8901b50182c763d4ecd985ef4087f06ea223b796831b82622d", + "DiffID": "sha256:98b7d0c5ef14f59e0a17429a6430028b12c5ea3c6312c4bbc1d99c4a6cd62538" + }, + "SeveritySource": "ghsa", + "PrimaryURL": "https://github.com/advisories/GHSA-jmqm-f2gx-4fjv", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Npm", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm" + }, + "Title": "Sensitive information exposure through logs in npm-registry-fetch", + "Description": "Affected versions of `npm-registry-fetch` are vulnerable to an information exposure vulnerability through log files. The cli supports URLs like `\u003cprotocol\u003e://[\u003cuser\u003e[:\u003cpassword\u003e]@]\u003chostname\u003e[:\u003cport\u003e][:][/]\u003cpath\u003e`. The password value is not redacted and is printed to stdout and also to any generated log files.", + "Severity": "MEDIUM", + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "V3Score": 5.3 + } + }, + "References": [ + "https://github.com/advisories/GHSA-jmqm-f2gx-4fjv", + "https://github.com/npm/npm-registry-fetch/commit/18bf9b97fb1deecdba01ffb05580370846255c88", + "https://github.com/npm/npm-registry-fetch/pull/29", + "https://github.com/npm/npm-registry-fetch/security/advisories/GHSA-jmqm-f2gx-4fjv", + "https://snyk.io/vuln/SNYK-JS-NPMREGISTRYFETCH-575432" + ] + } + ] + } + ] + }, + { + "Namespace": "apps", + "Kind": "Deployment", + "Name": "app1", + "Results": [ + { + "Target": "quay.io/kiwigrid/k8s-sidecar:1.22.0 (alpine 3.16.3)", + "Class": "os-pkgs", + "Type": "alpine", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2022-4450", + "PkgID": "libssl1.1@1.1.1s-r0", + "PkgName": "libssl1.1", + "InstalledVersion": "1.1.1s-r0", + "FixedVersion": "1.1.1t-r0", + "Status": "fixed", + "Layer": { + "Digest": "sha256:ca7dd9ec2225f2385955c43b2379305acd51543c28cf1d4e94522b3d94cce3ce", + "DiffID": "sha256:e5e13b0c77cbb769548077189c3da2f0a764ceca06af49d8d558e759f5c232bd" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-4450", + "DataSource": { + "ID": "alpine", + "Name": "Alpine Secdb", + "URL": "https://secdb.alpinelinux.org/" + }, + "Title": "double free after calling PEM_read_bio_ex", + "Description": "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-415" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:2165", + "https://access.redhat.com/security/cve/CVE-2022-4450", + "https://bugzilla.redhat.com/1960321", + "https://bugzilla.redhat.com/2164440", + "https://bugzilla.redhat.com/2164487", + "https://bugzilla.redhat.com/2164492", + "https://bugzilla.redhat.com/2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144000", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144003", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144008", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144010", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144012", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144015", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144017", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144019", + "https://bugzilla.redhat.com/show_bug.cgi?id=2145170", + "https://bugzilla.redhat.com/show_bug.cgi?id=2158412", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164440", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164487", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164488", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164492", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164497", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164499", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164500", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4203", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4304", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4450", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0215", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0216", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0217", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0286", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0401", + "https://errata.almalinux.org/9/ALSA-2023-2165.html", + "https://errata.rockylinux.org/RLSA-2023:0946", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=63bcf189be73a9cc1264059bed6f57974be74a83", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=bbcf509bd046b34cca19c766bbddc31683d0858b", + "https://github.com/advisories/GHSA-v5w6-wcm8-jm4q", + "https://linux.oracle.com/cve/CVE-2022-4450.html", + "https://linux.oracle.com/errata/ELSA-2023-2932.html", + "https://nvd.nist.gov/vuln/detail/CVE-2022-4450", + "https://rustsec.org/advisories/RUSTSEC-2023-0010.html", + "https://ubuntu.com/security/notices/USN-5844-1", + "https://www.cve.org/CVERecord?id=CVE-2022-4450", + "https://www.openssl.org/news/secadv/20230207.txt" + ], + "PublishedDate": "2023-02-08T20:15:00Z", + "LastModifiedDate": "2023-07-19T00:57:00Z" + }, + { + "VulnerabilityID": "CVE-2022-4450", + "PkgID": "libcrypto1.1@1.1.1s-r0", + "PkgName": "libcrypto1.1", + "InstalledVersion": "1.1.1s-r0", + "FixedVersion": "1.1.1t-r0", + "Status": "fixed", + "Layer": { + "Digest": "sha256:ca7dd9ec2225f2385955c43b2379305acd51543c28cf1d4e94522b3d94cce3ce", + "DiffID": "sha256:e5e13b0c77cbb769548077189c3da2f0a764ceca06af49d8d558e759f5c232bd" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-4450", + "DataSource": { + "ID": "alpine", + "Name": "Alpine Secdb", + "URL": "https://secdb.alpinelinux.org/" + }, + "Title": "double free after calling PEM_read_bio_ex", + "Description": "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-415" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:2165", + "https://access.redhat.com/security/cve/CVE-2022-4450", + "https://bugzilla.redhat.com/1960321", + "https://bugzilla.redhat.com/2164440", + "https://bugzilla.redhat.com/2164487", + "https://bugzilla.redhat.com/2164492", + "https://bugzilla.redhat.com/2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144000", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144003", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144008", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144010", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144012", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144015", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144017", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144019", + "https://bugzilla.redhat.com/show_bug.cgi?id=2145170", + "https://bugzilla.redhat.com/show_bug.cgi?id=2158412", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164440", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164487", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164488", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164492", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164497", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164499", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164500", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4203", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4304", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4450", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0215", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0216", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0217", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0286", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0401", + "https://errata.almalinux.org/9/ALSA-2023-2165.html", + "https://errata.rockylinux.org/RLSA-2023:0946", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=63bcf189be73a9cc1264059bed6f57974be74a83", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=bbcf509bd046b34cca19c766bbddc31683d0858b", + "https://github.com/advisories/GHSA-v5w6-wcm8-jm4q", + "https://linux.oracle.com/cve/CVE-2022-4450.html", + "https://linux.oracle.com/errata/ELSA-2023-2932.html", + "https://nvd.nist.gov/vuln/detail/CVE-2022-4450", + "https://rustsec.org/advisories/RUSTSEC-2023-0010.html", + "https://ubuntu.com/security/notices/USN-5844-1", + "https://www.cve.org/CVERecord?id=CVE-2022-4450", + "https://www.openssl.org/news/secadv/20230207.txt" + ], + "PublishedDate": "2023-02-08T20:15:00Z", + "LastModifiedDate": "2023-07-19T00:57:00Z" + } + ] + }, + { + "Target": "Python", + "Class": "lang-pkgs", + "Type": "python-pkg", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2023-37920", + "PkgName": "certifi", + "PkgPath": "app/.venv/lib/python3.11/site-packages/certifi-2022.12.7.dist-info/METADATA", + "InstalledVersion": "2022.12.7", + "FixedVersion": "2023.7.22", + "Status": "fixed", + "Layer": { + "Digest": "sha256:4546a550c1814d1af6f74b7960c4e0ebcf5c5c85080a3b2fe35e9ca3397a4259", + "DiffID": "sha256:ce34393fe7243a48e39beea73159b7b4ee007a57463f3bf5d4deff2b05220841" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-37920", + "DataSource": { + "ID": "osv", + "Name": "Python Packaging Advisory Database", + "URL": "https://github.com/pypa/advisory-db" + }, + "Title": "Removal of e-Tugra root certificate", + "Description": "Certifi is a curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. Certifi prior to version 2023.07.22 recognizes \"e-Tugra\" root certificates. e-Tugra's root certificates were subject to an investigation prompted by reporting of security issues in their systems. Certifi 2023.07.22 removes root certificates from \"e-Tugra\" from the root store.", + "Severity": "CRITICAL", + "CweIDs": [ + "CWE-345" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "V3Score": 9.8 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/security/cve/CVE-2023-37920", + "https://github.com/advisories/GHSA-xqr8-7jwr-rhp7", + "https://github.com/certifi/python-certifi/commit/8fb96ed81f71e7097ed11bc4d9b19afd7ea5c909", + "https://github.com/certifi/python-certifi/security/advisories/GHSA-xqr8-7jwr-rhp7", + "https://github.com/pypa/advisory-database/tree/main/vulns/certifi/PYSEC-2023-135.yaml", + "https://groups.google.com/a/mozilla.org/g/dev-security-policy/c/C-HrP1SEq1A", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5EX6NG7WUFNUKGFHLM35KHHU3GAKXRTG/", + "https://nvd.nist.gov/vuln/detail/CVE-2023-37920", + "https://www.cve.org/CVERecord?id=CVE-2023-37920" + ], + "PublishedDate": "2023-07-25T21:15:00Z", + "LastModifiedDate": "2023-08-12T06:16:00Z" + } + ] + } + ] + }, + { + "Kind": "", + "Name": "" + }, + { + "Kind": "", + "Name": "" + }, + { + "Namespace": "apps", + "Kind": "Deployment", + "Name": "app2", + "Results": [ + { + "Target": "quay.io/kiwigrid/k8s-sidecar:1.22.0 (alpine 3.16.3)", + "Class": "os-pkgs", + "Type": "alpine", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2022-4450", + "PkgID": "libssl1.1@1.1.1s-r0", + "PkgName": "libssl1.1", + "InstalledVersion": "1.1.1s-r0", + "FixedVersion": "1.1.1t-r0", + "Status": "fixed", + "Layer": { + "Digest": "sha256:ca7dd9ec2225f2385955c43b2379305acd51543c28cf1d4e94522b3d94cce3ce", + "DiffID": "sha256:e5e13b0c77cbb769548077189c3da2f0a764ceca06af49d8d558e759f5c232bd" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-4450", + "DataSource": { + "ID": "alpine", + "Name": "Alpine Secdb", + "URL": "https://secdb.alpinelinux.org/" + }, + "Title": "double free after calling PEM_read_bio_ex", + "Description": "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-415" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:2165", + "https://access.redhat.com/security/cve/CVE-2022-4450", + "https://bugzilla.redhat.com/1960321", + "https://bugzilla.redhat.com/2164440", + "https://bugzilla.redhat.com/2164487", + "https://bugzilla.redhat.com/2164492", + "https://bugzilla.redhat.com/2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144000", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144003", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144008", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144010", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144012", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144015", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144017", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144019", + "https://bugzilla.redhat.com/show_bug.cgi?id=2145170", + "https://bugzilla.redhat.com/show_bug.cgi?id=2158412", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164440", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164487", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164488", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164492", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164497", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164499", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164500", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4203", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4304", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4450", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0215", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0216", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0217", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0286", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0401", + "https://errata.almalinux.org/9/ALSA-2023-2165.html", + "https://errata.rockylinux.org/RLSA-2023:0946", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=63bcf189be73a9cc1264059bed6f57974be74a83", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=bbcf509bd046b34cca19c766bbddc31683d0858b", + "https://github.com/advisories/GHSA-v5w6-wcm8-jm4q", + "https://linux.oracle.com/cve/CVE-2022-4450.html", + "https://linux.oracle.com/errata/ELSA-2023-2932.html", + "https://nvd.nist.gov/vuln/detail/CVE-2022-4450", + "https://rustsec.org/advisories/RUSTSEC-2023-0010.html", + "https://ubuntu.com/security/notices/USN-5844-1", + "https://www.cve.org/CVERecord?id=CVE-2022-4450", + "https://www.openssl.org/news/secadv/20230207.txt" + ], + "PublishedDate": "2023-02-08T20:15:00Z", + "LastModifiedDate": "2023-07-19T00:57:00Z" + }, + { + "VulnerabilityID": "CVE-2022-4450", + "PkgID": "libcrypto1.1@1.1.1s-r0", + "PkgName": "libcrypto1.1", + "InstalledVersion": "1.1.1s-r0", + "FixedVersion": "1.1.1t-r0", + "Status": "fixed", + "Layer": { + "Digest": "sha256:ca7dd9ec2225f2385955c43b2379305acd51543c28cf1d4e94522b3d94cce3ce", + "DiffID": "sha256:e5e13b0c77cbb769548077189c3da2f0a764ceca06af49d8d558e759f5c232bd" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-4450", + "DataSource": { + "ID": "alpine", + "Name": "Alpine Secdb", + "URL": "https://secdb.alpinelinux.org/" + }, + "Title": "double free after calling PEM_read_bio_ex", + "Description": "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-415" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:2165", + "https://access.redhat.com/security/cve/CVE-2022-4450", + "https://bugzilla.redhat.com/1960321", + "https://bugzilla.redhat.com/2164440", + "https://bugzilla.redhat.com/2164487", + "https://bugzilla.redhat.com/2164492", + "https://bugzilla.redhat.com/2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144000", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144003", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144008", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144010", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144012", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144015", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144017", + "https://bugzilla.redhat.com/show_bug.cgi?id=2144019", + "https://bugzilla.redhat.com/show_bug.cgi?id=2145170", + "https://bugzilla.redhat.com/show_bug.cgi?id=2158412", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164440", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164487", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164488", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164492", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164494", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164497", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164499", + "https://bugzilla.redhat.com/show_bug.cgi?id=2164500", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4203", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4304", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-4450", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0215", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0216", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0217", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0286", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0401", + "https://errata.almalinux.org/9/ALSA-2023-2165.html", + "https://errata.rockylinux.org/RLSA-2023:0946", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=63bcf189be73a9cc1264059bed6f57974be74a83", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=bbcf509bd046b34cca19c766bbddc31683d0858b", + "https://github.com/advisories/GHSA-v5w6-wcm8-jm4q", + "https://linux.oracle.com/cve/CVE-2022-4450.html", + "https://linux.oracle.com/errata/ELSA-2023-2932.html", + "https://nvd.nist.gov/vuln/detail/CVE-2022-4450", + "https://rustsec.org/advisories/RUSTSEC-2023-0010.html", + "https://ubuntu.com/security/notices/USN-5844-1", + "https://www.cve.org/CVERecord?id=CVE-2022-4450", + "https://www.openssl.org/news/secadv/20230207.txt" + ], + "PublishedDate": "2023-02-08T20:15:00Z", + "LastModifiedDate": "2023-07-19T00:57:00Z" + } + ] + }, + { + "Target": "Python", + "Class": "lang-pkgs", + "Type": "python-pkg", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2023-37920", + "PkgName": "certifi", + "PkgPath": "app/.venv/lib/python3.11/site-packages/certifi-2022.12.7.dist-info/METADATA", + "InstalledVersion": "2022.12.7", + "FixedVersion": "2023.7.22", + "Status": "fixed", + "Layer": { + "Digest": "sha256:4546a550c1814d1af6f74b7960c4e0ebcf5c5c85080a3b2fe35e9ca3397a4259", + "DiffID": "sha256:ce34393fe7243a48e39beea73159b7b4ee007a57463f3bf5d4deff2b05220841" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-37920", + "DataSource": { + "ID": "osv", + "Name": "Python Packaging Advisory Database", + "URL": "https://github.com/pypa/advisory-db" + }, + "Title": "Removal of e-Tugra root certificate", + "Description": "Certifi is a curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. Certifi prior to version 2023.07.22 recognizes \"e-Tugra\" root certificates. e-Tugra's root certificates were subject to an investigation prompted by reporting of security issues in their systems. Certifi 2023.07.22 removes root certificates from \"e-Tugra\" from the root store.", + "Severity": "CRITICAL", + "CweIDs": [ + "CWE-345" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "V3Score": 9.8 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "V3Score": 7.5 + } + }, + "References": [ + "https://access.redhat.com/security/cve/CVE-2023-37920", + "https://github.com/advisories/GHSA-xqr8-7jwr-rhp7", + "https://github.com/certifi/python-certifi/commit/8fb96ed81f71e7097ed11bc4d9b19afd7ea5c909", + "https://github.com/certifi/python-certifi/security/advisories/GHSA-xqr8-7jwr-rhp7", + "https://github.com/pypa/advisory-database/tree/main/vulns/certifi/PYSEC-2023-135.yaml", + "https://groups.google.com/a/mozilla.org/g/dev-security-policy/c/C-HrP1SEq1A", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5EX6NG7WUFNUKGFHLM35KHHU3GAKXRTG/", + "https://nvd.nist.gov/vuln/detail/CVE-2023-37920", + "https://www.cve.org/CVERecord?id=CVE-2023-37920" + ], + "PublishedDate": "2023-07-25T21:15:00Z", + "LastModifiedDate": "2023-08-12T06:16:00Z" + } + ] + } + ] + }, + { + "Namespace": "apps", + "Kind": "Deployment", + "Name": "app2", + "Results": [ + { + "Target": "docker.io/istio/examples-bookinfo-details-v1:1.17.0 (debian 10.5)", + "Class": "os-pkgs", + "Type": "debian", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2016-2781", + "PkgID": "coreutils@8.30-3", + "PkgName": "coreutils", + "InstalledVersion": "8.30-3", + "Status": "will_not_fix", + "Layer": { + "Digest": "sha256:d121f8d1c4128ebc1e95e5bfad90a0189b84eadbbb2fbaad20cbb26d20b2c8a2", + "DiffID": "sha256:07cab433985205f29909739f511777a810f4a9aff486355b71308bb654cdc868" + }, + "SeveritySource": "debian", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2016-2781", + "DataSource": { + "ID": "debian", + "Name": "Debian Security Tracker", + "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "Title": "coreutils: Non-privileged session can escape to the parent session in chroot", + "Description": "chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + "Severity": "LOW", + "CweIDs": [ + "CWE-20" + ], + "CVSS": { + "nvd": { + "V2Vector": "AV:L/AC:L/Au:N/C:N/I:P/A:N", + "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", + "V2Score": 2.1, + "V3Score": 6.5 + }, + "redhat": { + "V2Vector": "AV:L/AC:H/Au:N/C:C/I:C/A:C", + "V3Vector": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H", + "V2Score": 6.2, + "V3Score": 8.6 + } + }, + "References": [ + "http://seclists.org/oss-sec/2016/q1/452", + "http://www.openwall.com/lists/oss-security/2016/02/28/2", + "http://www.openwall.com/lists/oss-security/2016/02/28/3", + "https://access.redhat.com/security/cve/CVE-2016-2781", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2781", + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E", + "https://lore.kernel.org/patchwork/patch/793178/", + "https://nvd.nist.gov/vuln/detail/CVE-2016-2781", + "https://www.cve.org/CVERecord?id=CVE-2016-2781" + ], + "PublishedDate": "2017-02-07T15:59:00Z", + "LastModifiedDate": "2021-02-25T17:15:00Z" + } + ] + }, + { + "Target": "Ruby", + "Class": "lang-pkgs", + "Type": "gemspec", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2023-28755", + "PkgName": "uri", + "PkgPath": "usr/local/lib/ruby/gems/2.7.0/specifications/default/uri-0.10.0.gemspec", + "InstalledVersion": "0.10.0", + "FixedVersion": "~\u003e 0.10.0.1, ~\u003e 0.10.2, ~\u003e 0.11.1, \u003e= 0.12.1", + "Status": "fixed", + "Layer": { + "Digest": "sha256:026a6f0bbb704596202b0d24ad1fc1d0d7349cc72e4c89b6438a7aec82b1523c", + "DiffID": "sha256:3ef556e0d9e2bd857ebdd209ef980f7b78c351f3180ad4359ff98bf1909a6046" + }, + "SeveritySource": "ruby-advisory-db", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-28755", + "DataSource": { + "ID": "ruby-advisory-db", + "Name": "Ruby Advisory Database", + "URL": "https://github.com/rubysec/ruby-advisory-db" + }, + "Title": "ReDoS vulnerability in URI", + "Description": "A ReDoS issue was discovered in the URI component through 0.12.0 in Ruby through 3.2.1. The URI parser mishandles invalid URLs that have specific characters. It causes an increase in execution time for parsing strings to URI objects. The fixed versions are 0.12.1, 0.11.1, 0.10.2 and 0.10.0.1.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-1333" + ], + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 5.3 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 5.3 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:3821", + "https://access.redhat.com/security/cve/CVE-2023-28755", + "https://bugzilla.redhat.com/2149706", + "https://bugzilla.redhat.com/2184059", + "https://bugzilla.redhat.com/2184061", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28755", + "https://errata.almalinux.org/8/ALSA-2023-3821.html", + "https://github.com/advisories/GHSA-hv5j-3h9f-99c2", + "https://github.com/ruby/ruby/commit/8ce4ab146498879b65e22f1be951b25eebb79300", + "https://github.com/ruby/uri/releases/", + "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/uri/CVE-2023-28755.yml", + "https://linux.oracle.com/cve/CVE-2023-28755.html", + "https://linux.oracle.com/errata/ELSA-2023-3821.html", + "https://lists.debian.org/debian-lts-announce/2023/04/msg00033.html", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/FFZANOQA4RYX7XCB42OO3P24DQKWHEKA/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/G76GZG3RAGYF4P75YY7J7TGYAU7Z5E2T/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WMIOPLBAAM3FEQNAXA2L7BDKOGSVUT5Z/", + "https://nvd.nist.gov/vuln/detail/CVE-2023-28755", + "https://security.netapp.com/advisory/ntap-20230526-0003/", + "https://ubuntu.com/security/notices/USN-6055-1", + "https://ubuntu.com/security/notices/USN-6055-2", + "https://ubuntu.com/security/notices/USN-6087-1", + "https://ubuntu.com/security/notices/USN-6181-1", + "https://ubuntu.com/security/notices/USN-6219-1", + "https://www.cve.org/CVERecord?id=CVE-2023-28755", + "https://www.ruby-lang.org/en/downloads/releases/", + "https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/", + "https://www.ruby-lang.org/en/news/2023/03/28/redos-in-uri-cve-2023-28755/" + ], + "PublishedDate": "2023-03-31T04:15:00Z", + "LastModifiedDate": "2023-05-30T17:17:00Z" + } + ] + } + ] + }, + { + "Kind": "", + "Name": "" + }, + { + "Namespace": "default", + "Kind": "Deployment", + "Name": "nginx", + "Results": [ + { + "Target": "nginx@sha256:af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305 (debian 11.7)", + "Class": "os-pkgs", + "Type": "debian", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2023-3446", + "PkgID": "openssl@1.1.1n-0+deb11u4", + "PkgName": "openssl", + "InstalledVersion": "1.1.1n-0+deb11u4", + "Status": "fix_deferred", + "Layer": { + "DiffID": "sha256:4b8862fe7056d8a3c2c0910eb38ebb8fc08785eaa1f9f53b2043bf7ca8adbafb" + }, + "SeveritySource": "nvd", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-3446", + "DataSource": { + "ID": "debian", + "Name": "Debian Security Tracker", + "URL": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "Title": "Excessive time spent checking DH keys and parameters", + "Description": "Issue summary: Checking excessively long DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_check(), DH_check_ex()\nor EVP_PKEY_param_check() to check a DH key or DH parameters may experience long\ndelays. Where the key or parameters that are being checked have been obtained\nfrom an untrusted source this may lead to a Denial of Service.\n\nThe function DH_check() performs various checks on DH parameters. One of those\nchecks confirms that the modulus ('p' parameter) is not too large. Trying to use\na very large modulus is slow and OpenSSL will not normally use a modulus which\nis over 10,000 bits in length.\n\nHowever the DH_check() function checks numerous aspects of the key or parameters\nthat have been supplied. Some of those checks use the supplied modulus value\neven if it has already been found to be too large.\n\nAn application that calls DH_check() and supplies a key or parameters obtained\nfrom an untrusted source could be vulernable to a Denial of Service attack.\n\nThe function DH_check() is itself called by a number of other OpenSSL functions.\nAn application calling any of those other functions may similarly be affected.\nThe other functions affected by this are DH_check_ex() and\nEVP_PKEY_param_check().\n\nAlso vulnerable are the OpenSSL dhparam and pkeyparam command line applications\nwhen using the '-check' option.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", + "Severity": "MEDIUM", + "CweIDs": [ + "CWE-1333" + ], + "CVSS": { + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 5.3 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 5.3 + } + }, + "References": [ + "http://www.openwall.com/lists/oss-security/2023/07/19/4", + "http://www.openwall.com/lists/oss-security/2023/07/19/5", + "http://www.openwall.com/lists/oss-security/2023/07/19/6", + "http://www.openwall.com/lists/oss-security/2023/07/31/1", + "https://access.redhat.com/security/cve/CVE-2023-3446", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-3446", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=1fa20cf2f506113c761777127a38bce5068740eb", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=8780a896543a654e757db1b9396383f9d8095528", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=9a0a4d3c1e7138915563c0df4fe6a3f9377b839c", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=fc9867c1e03c22ebf56943be205202e576aabf23", + "https://lists.debian.org/debian-lts-announce/2023/08/msg00019.html", + "https://nvd.nist.gov/vuln/detail/CVE-2023-3446", + "https://security.netapp.com/advisory/ntap-20230803-0011/", + "https://www.cve.org/CVERecord?id=CVE-2023-3446", + "https://www.openssl.org/news/secadv/20230719.txt" + ], + "PublishedDate": "2023-07-19T12:15:00Z", + "LastModifiedDate": "2023-08-16T08:15:00Z" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/pkg/worker/vuln.go b/pkg/worker/vuln.go new file mode 100644 index 00000000..6d11fe64 --- /dev/null +++ b/pkg/worker/vuln.go @@ -0,0 +1,97 @@ +// Copyright 2023 Undistro Authors +// +// 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. + +package worker + +import ( + "context" + "errors" + "fmt" + "io" + "regexp" + "strings" + + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/undistro/zora/api/zora/v1alpha1" + zora "github.com/undistro/zora/pkg/clientset/versioned" + "github.com/undistro/zora/pkg/worker/report/trivy" +) + +var vulnPlugins = map[string]func(ctx context.Context, reader io.Reader) ([]v1alpha1.VulnerabilityReportSpec, error){ + "trivy": trivy.Parse, +} + +var vulnReportTypeMeta = metav1.TypeMeta{ + Kind: "VulnerabilityReport", + APIVersion: v1alpha1.SchemeGroupVersion.String(), +} + +var nonAlphanumericRegex = regexp.MustCompile(`\W+`) + +func handleVulnerability(ctx context.Context, cfg *config, results io.Reader, client *zora.Clientset) error { + log := logr.FromContextOrDiscard(ctx) + vulns, err := parseVulnResults(ctx, cfg, results) + if err != nil { + return err + } + for _, vuln := range vulns { + v, err := client.ZoraV1alpha1().VulnerabilityReports(cfg.Namespace).Create(ctx, &vuln, createOpts) + if err != nil { + return fmt.Errorf("failed to create VulnerabilityReport %q: %v", vuln.Name, err) + } + log.Info(fmt.Sprintf("VulnerabilityReport %q successfully created", v.Name), "resourceVersion", v.ResourceVersion) + } + return nil +} + +func parseVulnResults(ctx context.Context, cfg *config, results io.Reader) ([]v1alpha1.VulnerabilityReport, error) { + parseFunc, ok := vulnPlugins[cfg.PluginName] + if !ok { + return nil, errors.New(fmt.Sprintf("invalid plugin %q", cfg.PluginName)) + } + specs, err := parseFunc(ctx, results) + if err != nil { + return nil, fmt.Errorf("failed to parse %q results: %v", cfg.PluginName, err) + } + owner := ownerReference(cfg) + vulns := make([]v1alpha1.VulnerabilityReport, 0, len(specs)) + for _, spec := range specs { + vulns = append(vulns, newVulnReport(cfg, spec, owner)) + } + return vulns, nil +} + +func newVulnReport(cfg *config, spec v1alpha1.VulnerabilityReportSpec, owner metav1.OwnerReference) v1alpha1.VulnerabilityReport { + spec.Cluster = cfg.ClusterName + return v1alpha1.VulnerabilityReport{ + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s-%s", cfg.ClusterName, strings.ToLower(cleanString(spec.Image)), cfg.suffix), + Namespace: cfg.Namespace, + OwnerReferences: []metav1.OwnerReference{owner}, + Labels: map[string]string{ + v1alpha1.LabelScanID: cfg.JobUID, + v1alpha1.LabelCluster: cfg.ClusterName, + v1alpha1.LabelPlugin: cfg.PluginName, + }, + }, + Spec: spec, + } +} + +func cleanString(s string) string { + return nonAlphanumericRegex.ReplaceAllString(s, "") +} diff --git a/pkg/worker/vuln_test.go b/pkg/worker/vuln_test.go new file mode 100644 index 00000000..cdf28ecf --- /dev/null +++ b/pkg/worker/vuln_test.go @@ -0,0 +1,350 @@ +// Copyright 2023 Undistro Authors +// +// 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. + +package worker + +import ( + "context" + "io" + "os" + "reflect" + "sort" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + batchv1 "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/undistro/zora/api/zora/v1alpha1" +) + +var labels = map[string]string{ + v1alpha1.LabelScanID: "50c8957e-c9e1-493a-9fa4-d0786deea017", + v1alpha1.LabelCluster: "cluster", + v1alpha1.LabelPlugin: "trivy", +} + +var owners = []metav1.OwnerReference{ + { + APIVersion: batchv1.SchemeGroupVersion.String(), + Kind: "Job", + Name: "cluster-trivy-28140229", + UID: types.UID("50c8957e-c9e1-493a-9fa4-d0786deea017"), + }, +} + +func TestParseVulnResults(t *testing.T) { + type args struct { + cfg *config + filename string + } + tests := []struct { + name string + args args + want []v1alpha1.VulnerabilityReport + wantErr bool + }{ + { + name: "invalid plugin", + args: args{cfg: &config{PluginName: "marvin"}}, // marvin is not a vulnerability plugin + want: nil, + wantErr: true, + }, + { + name: "directory reader", + args: args{ + cfg: &config{PluginName: "trivy"}, + filename: t.TempDir(), + }, + want: nil, + wantErr: true, + }, + { + name: "ok", + args: args{ + cfg: &config{ + PluginName: "trivy", + ClusterName: "cluster", + Namespace: "ns", + JobName: "cluster-trivy-28140229", + JobUID: "50c8957e-c9e1-493a-9fa4-d0786deea017", + PodName: "cluster-trivy-28140229-h9kcn", + suffix: "h9kcn", + }, + filename: "report/trivy/testdata/report.json", + }, + want: []v1alpha1.VulnerabilityReport{ + { + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-registryk8siokubeapiserverv1253-h9kcn", + Namespace: "ns", + OwnerReferences: owners, + Labels: labels, + }, + Spec: v1alpha1.VulnerabilityReportSpec{ + Cluster: "cluster", + Image: "registry.k8s.io/kube-apiserver:v1.25.3", + Resources: map[string][]string{"Pod": {"kube-system/kube-apiserver-kind-control-plane"}}, + TotalResources: 1, + Summary: v1alpha1.VulnerabilitySummary{Total: 1, High: 1}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2022-41723", + Severity: "HIGH", + Title: "avoid quadratic complexity in HPACK decoding", + Description: "A maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder, sufficient to cause a denial of service from a small number of small requests.", + Package: "golang.org/x/net", + Version: "v0.0.0-20220722155237-a158d28d115b", + FixVersion: "0.7.0", + URL: "https://avd.aquasec.com/nvd/cve-2022-41723", + Status: "fixed", + Type: "gobinary", + Score: "7.5", + }, + }, + }, + }, + { + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-quayiokiwigridk8ssidecar1220-h9kcn", + Namespace: "ns", + OwnerReferences: owners, + Labels: labels, + }, + Spec: v1alpha1.VulnerabilityReportSpec{ + Cluster: "cluster", + Image: "quay.io/kiwigrid/k8s-sidecar:1.22.0", + Resources: map[string][]string{"Deployment": {"apps/app1", "apps/app2"}}, + TotalResources: 2, + Summary: v1alpha1.VulnerabilitySummary{Total: 3, Critical: 1, High: 2}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2022-4450", + Severity: "HIGH", + Title: "double free after calling PEM_read_bio_ex", + Description: "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + Package: "libssl1.1", + Version: "1.1.1s-r0", + FixVersion: "1.1.1t-r0", + URL: "https://avd.aquasec.com/nvd/cve-2022-4450", + Status: "fixed", + Type: "alpine", + Score: "7.5", + }, + { + ID: "CVE-2022-4450", + Severity: "HIGH", + Title: "double free after calling PEM_read_bio_ex", + Description: "The function PEM_read_bio_ex() reads a PEM file from a BIO and parses and decodes the \"name\" (e.g. \"CERTIFICATE\"), any header data and the payload data. If the function succeeds then the \"name_out\", \"header\" and \"data\" arguments are populated with pointers to buffers containing the relevant decoded data. The caller is responsible for freeing those buffers. It is possible to construct a PEM file that results in 0 bytes of payload data. In this case PEM_read_bio_ex() will return a failure code but will populate the header argument with a pointer to a buffer that has already been freed. If the caller also frees this buffer then a double free will occur. This will most likely lead to a crash. This could be exploited by an attacker who has the ability to supply malicious PEM files for parsing to achieve a denial of service attack. The functions PEM_read_bio() and PEM_read() are simple wrappers around PEM_read_bio_ex() and therefore these functions are also directly affected. These functions are also called indirectly by a number of other OpenSSL functions including PEM_X509_INFO_read_bio_ex() and SSL_CTX_use_serverinfo_file() which are also vulnerable. Some OpenSSL internal uses of these functions are not vulnerable because the caller does not free the header argument if PEM_read_bio_ex() returns a failure code. These locations include the PEM_read_bio_TYPE() functions as well as the decoders introduced in OpenSSL 3.0. The OpenSSL asn1parse command line application is also impacted by this issue.", + Package: "libcrypto1.1", + Version: "1.1.1s-r0", + FixVersion: "1.1.1t-r0", + URL: "https://avd.aquasec.com/nvd/cve-2022-4450", + Status: "fixed", + Type: "alpine", + Score: "7.5", + }, + { + ID: "CVE-2023-37920", + Severity: "CRITICAL", + Title: "Removal of e-Tugra root certificate", + Description: "Certifi is a curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts. Certifi prior to version 2023.07.22 recognizes \"e-Tugra\" root certificates. e-Tugra's root certificates were subject to an investigation prompted by reporting of security issues in their systems. Certifi 2023.07.22 removes root certificates from \"e-Tugra\" from the root store.", + Package: "certifi", + Version: "2022.12.7", + FixVersion: "2023.7.22", + URL: "https://avd.aquasec.com/nvd/cve-2023-37920", + Status: "fixed", + Type: "python-pkg", + Score: "9.8", + }, + }, + }, + }, + { + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-dockerioistioexamplesbookinforatingsv11170-h9kcn", + Namespace: "ns", + OwnerReferences: owners, + Labels: labels, + }, + Spec: v1alpha1.VulnerabilityReportSpec{ + Cluster: "cluster", + Image: "docker.io/istio/examples-bookinfo-ratings-v1:1.17.0", + Resources: map[string][]string{"Deployment": {"apps/app1"}}, + TotalResources: 1, + Summary: v1alpha1.VulnerabilitySummary{Total: 3, High: 1, Medium: 1, Unknown: 1}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "DLA-3051-1", + Severity: "UNKNOWN", + Title: "tzdata - new timezone database", + Description: "", + Package: "tzdata", + Version: "2019c-0+deb9u1", + FixVersion: "2021a-0+deb9u4", + URL: "", + Status: "fixed", + Type: "debian", + }, + { + ID: "CVE-2016-2779", + Severity: "HIGH", + Title: "util-linux: runuser tty hijack via TIOCSTI ioctl", + Description: "runuser in util-linux allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + Package: "bsdutils", + Version: "1:2.29.2-1+deb9u1", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2016-2779", + Status: "affected", + Type: "debian", + Score: "7.8", + }, + { + ID: "GHSA-jmqm-f2gx-4fjv", + Severity: "MEDIUM", + Title: "Sensitive information exposure through logs in npm-registry-fetch", + Description: "Affected versions of `npm-registry-fetch` are vulnerable to an information exposure vulnerability through log files. The cli supports URLs like `\u003cprotocol\u003e://[\u003cuser\u003e[:\u003cpassword\u003e]@]\u003chostname\u003e[:\u003cport\u003e][:][/]\u003cpath\u003e`. The password value is not redacted and is printed to stdout and also to any generated log files.", + Package: "npm-registry-fetch", + Version: "4.0.4", + FixVersion: "8.1.1, 4.0.5", + URL: "https://github.com/advisories/GHSA-jmqm-f2gx-4fjv", + Status: "fixed", + Type: "node-pkg", + Score: "5.3", + }, + }, + }, + }, + { + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-dockerioistioexamplesbookinfodetailsv11170-h9kcn", + Namespace: "ns", + OwnerReferences: owners, + Labels: labels, + }, + Spec: v1alpha1.VulnerabilityReportSpec{ + Cluster: "cluster", + Image: "docker.io/istio/examples-bookinfo-details-v1:1.17.0", + Resources: map[string][]string{"Deployment": {"apps/app2"}}, + TotalResources: 1, + Summary: v1alpha1.VulnerabilitySummary{Total: 2, High: 1, Low: 1}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2016-2781", + Severity: "LOW", + Title: "coreutils: Non-privileged session can escape to the parent session in chroot", + Description: "chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + Package: "coreutils", + Version: "8.30-3", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2016-2781", + Status: "will_not_fix", + Type: "debian", + Score: "6.5", + }, + { + ID: "CVE-2023-28755", + Severity: "HIGH", + Title: "ReDoS vulnerability in URI", + Description: "A ReDoS issue was discovered in the URI component through 0.12.0 in Ruby through 3.2.1. The URI parser mishandles invalid URLs that have specific characters. It causes an increase in execution time for parsing strings to URI objects. The fixed versions are 0.12.1, 0.11.1, 0.10.2 and 0.10.0.1.", + Package: "uri", + Version: "0.10.0", + FixVersion: "~\u003e 0.10.0.1, ~\u003e 0.10.2, ~\u003e 0.11.1, \u003e= 0.12.1", + URL: "https://avd.aquasec.com/nvd/cve-2023-28755", + Status: "fixed", + Type: "gemspec", + Score: "5.3", + }, + }, + }, + }, + { + TypeMeta: vulnReportTypeMeta, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-nginxsha256af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305-h9kcn", + Namespace: "ns", + OwnerReferences: owners, + Labels: labels, + }, + Spec: v1alpha1.VulnerabilityReportSpec{ + Cluster: "cluster", + Image: "nginx@sha256:af296b188c7b7df99ba960ca614439c99cb7cf252ed7bbc23e90cfda59092305", + TotalResources: 1, + Resources: map[string][]string{"Deployment": {"default/nginx"}}, + Vulnerabilities: []v1alpha1.Vulnerability{ + { + ID: "CVE-2023-3446", + Severity: "MEDIUM", + Title: "Excessive time spent checking DH keys and parameters", + Description: "Issue summary: Checking excessively long DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_check(), DH_check_ex()\nor EVP_PKEY_param_check() to check a DH key or DH parameters may experience long\ndelays. Where the key or parameters that are being checked have been obtained\nfrom an untrusted source this may lead to a Denial of Service.\n\nThe function DH_check() performs various checks on DH parameters. One of those\nchecks confirms that the modulus ('p' parameter) is not too large. Trying to use\na very large modulus is slow and OpenSSL will not normally use a modulus which\nis over 10,000 bits in length.\n\nHowever the DH_check() function checks numerous aspects of the key or parameters\nthat have been supplied. Some of those checks use the supplied modulus value\neven if it has already been found to be too large.\n\nAn application that calls DH_check() and supplies a key or parameters obtained\nfrom an untrusted source could be vulernable to a Denial of Service attack.\n\nThe function DH_check() is itself called by a number of other OpenSSL functions.\nAn application calling any of those other functions may similarly be affected.\nThe other functions affected by this are DH_check_ex() and\nEVP_PKEY_param_check().\n\nAlso vulnerable are the OpenSSL dhparam and pkeyparam command line applications\nwhen using the '-check' option.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", + Package: "openssl", + Version: "1.1.1n-0+deb11u4", + FixVersion: "", + URL: "https://avd.aquasec.com/nvd/cve-2023-3446", + Status: "fix_deferred", + Type: "debian", + Score: "5.3", + }, + }, + Summary: v1alpha1.VulnerabilitySummary{Total: 1, Medium: 1}, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var r io.Reader + if tt.args.filename != "" { + f, err := os.Open(tt.args.filename) + if err != nil { + t.Errorf("parseVulnResults() setup error = %v", err) + return + } + r = f + } + got, err := parseVulnResults(context.TODO(), tt.args.cfg, r) + if (err != nil) != tt.wantErr { + t.Errorf("parseVulnResults() error = %v, wantErr %v", err, tt.wantErr) + return + } + sortVulns(got) + sortVulns(tt.want) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseVulnResults() mismatch (-want +got):\n%s", cmp.Diff(tt.want, got)) + } + }) + } +} + +func sortVulns(vulns []v1alpha1.VulnerabilityReport) { + sort.Slice(vulns, func(i, j int) bool { + return strings.Compare(vulns[i].Spec.Image, vulns[j].Spec.Image) == -1 + }) + for _, v := range vulns { + for _, r := range v.Spec.Resources { + sort.Strings(r) + } + sort.Slice(v.Spec.Vulnerabilities, func(i, j int) bool { + return strings.Compare(v.Spec.Vulnerabilities[i].ID, v.Spec.Vulnerabilities[j].ID) == -1 + }) + } +} diff --git a/pkg/worker/worker.go b/pkg/worker/worker.go index 21bbe2e8..1667e69a 100644 --- a/pkg/worker/worker.go +++ b/pkg/worker/worker.go @@ -24,14 +24,15 @@ import ( "time" "github.com/go-logr/logr" + batchv1 "k8s.io/api/batch/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" zora "github.com/undistro/zora/pkg/clientset/versioned" ) func Run(ctx context.Context) error { - log := logr.FromContextOrDiscard(ctx) cfg, err := configFromEnv() if err != nil { return fmt.Errorf("failed to get config from env: %v", err) @@ -44,16 +45,11 @@ func Run(ctx context.Context) error { if err != nil { return fmt.Errorf("failed to gather results: %v", err) } - issues, err := parseResults(ctx, cfg, results) - if err != nil { - return err - } - for _, issue := range issues { - issue, err := client.ZoraV1alpha1().ClusterIssues(cfg.Namespace).Create(ctx, &issue, metav1.CreateOptions{}) - if err != nil { - return fmt.Errorf("failed to create ClusterIssue %q: %v", issue.Name, err) - } - log.Info(fmt.Sprintf("cluster issue %q successfully created", issue.Name), "resource version", issue.ResourceVersion) + switch cfg.PluginType { + case "misconfiguration": + return handleMisconfiguration(ctx, cfg, results, client) + case "vulnerability": + return handleVulnerability(ctx, cfg, results, client) } return nil } @@ -134,3 +130,12 @@ func ignoreNotExist(err error) error { } return err } + +func ownerReference(cfg *config) metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: batchv1.SchemeGroupVersion.String(), + Kind: "Job", + Name: cfg.JobName, + UID: types.UID(cfg.JobUID), + } +}