From b5f7a61e3669216a6eb40a97adf8d0d893f9c9a3 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Tue, 11 Jun 2024 14:37:53 +0800 Subject: [PATCH 01/74] =?UTF-8?q?Adjust=20the=20query=20by=20UUID=20sql=20?= =?UTF-8?q?so=20that=20it=20can=20use=20the=20idx=5Ftask=5Fextra=5Fat?= =?UTF-8?q?=E2=80=A6=20(#20545)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the query by UUID sql so that it can use the idx_task_extra_attrs_report_uuids fixes #20505 Signed-off-by: stonezdj --- src/pkg/task/dao/task.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/task/dao/task.go b/src/pkg/task/dao/task.go index 1777385618..b42781c17a 100644 --- a/src/pkg/task/dao/task.go +++ b/src/pkg/task/dao/task.go @@ -114,8 +114,8 @@ func (t *taskDAO) ListScanTasksByReportUUID(ctx context.Context, uuid string) ([ } var tasks []*Task - param := fmt.Sprintf(`{"report_uuids":["%s"]}`, uuid) - sql := `SELECT * FROM task WHERE extra_attrs::jsonb @> cast( ? as jsonb )` + param := fmt.Sprintf(`"%s"`, uuid) + sql := `SELECT * FROM task WHERE extra_attrs::jsonb -> 'report_uuids' @> ?` _, err = ormer.Raw(sql, param).QueryRows(&tasks) if err != nil { return nil, err From 1c9cb2e2536bec0e47c1d8e1ec576b499dd5b337 Mon Sep 17 00:00:00 2001 From: Shengwen YU Date: Wed, 12 Jun 2024 13:54:14 +0800 Subject: [PATCH 02/74] fix: update image tag for nightly-trivy-scan (#20574) Signed-off-by: Shengwen Yu --- .github/workflows/nightly-trivy-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly-trivy-scan.yml b/.github/workflows/nightly-trivy-scan.yml index 73e1037591..83355424fc 100644 --- a/.github/workflows/nightly-trivy-scan.yml +++ b/.github/workflows/nightly-trivy-scan.yml @@ -12,7 +12,7 @@ jobs: matrix: # maintain the versions of harbor that need to be actively # security scanned - versions: [dev, v2.10.0-dev] + versions: [dev, v2.11.0-dev] # list of images that need to be scanned images: [harbor-core, harbor-db, harbor-exporter, harbor-jobservice, harbor-log, harbor-portal, harbor-registryctl, prepare] permissions: From 6a38ed3d7769e3598c6cf829aae4e0e152f93a83 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Wed, 12 Jun 2024 18:16:55 +0800 Subject: [PATCH 03/74] style: delete duplicate error check in artifacttrash dao (#20557) Signed-off-by: chlins --- src/pkg/artifactrash/dao/dao.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pkg/artifactrash/dao/dao.go b/src/pkg/artifactrash/dao/dao.go index 918254cacc..f10beba4f4 100644 --- a/src/pkg/artifactrash/dao/dao.go +++ b/src/pkg/artifactrash/dao/dao.go @@ -102,10 +102,8 @@ func (d *dao) Flush(ctx context.Context, cutOff time.Time) (err error) { if err != nil { return err } + sql := fmt.Sprintf(`DELETE FROM artifact_trash where creation_time <= TO_TIMESTAMP('%f')`, float64(cutOff.UnixNano())/float64((time.Second))) - if err != nil { - return err - } _, err = ormer.Raw(sql).Exec() if err != nil { return err From e960711579974e8e027ad11c1fda2154f40a9862 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Fri, 14 Jun 2024 17:10:52 +0800 Subject: [PATCH 04/74] Use internal registry url to push artifact accessory (#20575) fixes #20565 Signed-off-by: stonezdj --- .github/workflows/CI.yml | 12 ++++++------ src/pkg/scan/sbom/sbom.go | 23 ++++------------------- src/pkg/scan/sbom/sbom_test.go | 1 - 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5ed78ff1be..da8aa2932e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -5,7 +5,7 @@ env: POSTGRESQL_USR: postgres POSTGRESQL_PWD: root123 POSTGRESQL_DATABASE: registry - DOCKER_COMPOSE_VERSION: 1.23.0 + DOCKER_COMPOSE_VERSION: 2.27.1 HARBOR_ADMIN: admin HARBOR_ADMIN_PASSWD: Harbor12345 CORE_SECRET: tempString @@ -66,7 +66,7 @@ jobs: env #sudo apt install -y xvfb #xvfb-run ls - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin IP=`hostname -I | awk '{print $1}'` @@ -131,7 +131,7 @@ jobs: df -h #sudo apt install -y xvfb #xvfb-run ls - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin - name: install @@ -186,7 +186,7 @@ jobs: df -h #sudo apt install -y xvfb #xvfb-run ls - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin - name: install @@ -240,7 +240,7 @@ jobs: df -h #sudo apt install -y xvfb #xvfb-run ls - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin - name: install @@ -292,7 +292,7 @@ jobs: df -h #sudo apt install -y xvfb #xvfb-run ls - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose sudo mv docker-compose /usr/local/bin IP=`hostname -I | awk '{print $1}'` diff --git a/src/pkg/scan/sbom/sbom.go b/src/pkg/scan/sbom/sbom.go index 8aaf5da337..b58057f9e3 100644 --- a/src/pkg/scan/sbom/sbom.go +++ b/src/pkg/scan/sbom/sbom.go @@ -22,13 +22,11 @@ import ( "strings" "time" - "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/controller/artifact" scanCtl "github.com/goharbor/harbor/src/controller/scan" "github.com/goharbor/harbor/src/jobservice/job" "github.com/goharbor/harbor/src/jobservice/logger" - "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/orm" @@ -54,7 +52,6 @@ const ( func init() { scan.RegisterScanHanlder(v1.ScanTypeSbom, &scanHandler{ GenAccessoryFunc: scan.GenAccessoryArt, - RegistryServer: registry, SBOMMgrFunc: func() Manager { return Mgr }, TaskMgrFunc: func() task.Manager { return task.Mgr }, ArtifactControllerFunc: func() artifact.Controller { return artifact.Ctl }, @@ -67,7 +64,6 @@ func init() { // scanHandler defines the Handler to generate sbom type scanHandler struct { GenAccessoryFunc func(scanRep v1.ScanRequest, sbomContent []byte, labels map[string]string, mediaType string, robot *model.Robot) (string, error) - RegistryServer func(ctx context.Context) (string, bool) SBOMMgrFunc func() Manager TaskMgrFunc func() task.Manager ArtifactControllerFunc func() artifact.Controller @@ -96,8 +92,10 @@ func (h *scanHandler) PostScan(ctx job.Context, sr *v1.ScanRequest, _ *scanModel Registry: sr.Registry, Artifact: sr.Artifact, } - // the registry server url is core by default, need to replace it with real registry server url - scanReq.Registry.URL, scanReq.Registry.Insecure = h.RegistryServer(ctx.SystemContext()) + scanReq.Registry.Insecure = strings.HasPrefix(scanReq.Registry.URL, "http://") + // the registry URL should not contain http:// or https:// prefix + scanReq.Registry.URL = strings.TrimPrefix(scanReq.Registry.URL, "http://") + scanReq.Registry.URL = strings.TrimPrefix(scanReq.Registry.URL, "https://") if len(scanReq.Registry.URL) == 0 { return "", fmt.Errorf("empty registry server") } @@ -170,19 +168,6 @@ func (h *scanHandler) Update(ctx context.Context, uuid string, report string) er return nil } -// extract server name from config, and remove the protocol prefix -func registry(ctx context.Context) (string, bool) { - cfgMgr, ok := config.FromContext(ctx) - if ok { - extURL := cfgMgr.Get(context.Background(), common.ExtEndpoint).GetString() - insecure := strings.HasPrefix(extURL, "http://") - server := strings.TrimPrefix(extURL, "https://") - server = strings.TrimPrefix(server, "http://") - return server, insecure - } - return "", false -} - // retrieveSBOMContent retrieves the "sbom" field from the raw report func retrieveSBOMContent(rawReport string) ([]byte, *v1.Scanner, error) { rpt := sbom.RawSBOMReport{} diff --git a/src/pkg/scan/sbom/sbom_test.go b/src/pkg/scan/sbom/sbom_test.go index 04a3c2ece5..753ff97d93 100644 --- a/src/pkg/scan/sbom/sbom_test.go +++ b/src/pkg/scan/sbom/sbom_test.go @@ -147,7 +147,6 @@ func (suite *SBOMTestSuite) SetupSuite() { suite.handler = &scanHandler{ GenAccessoryFunc: mockGenAccessory, - RegistryServer: mockGetRegistry, SBOMMgrFunc: func() Manager { return suite.sbomManager }, TaskMgrFunc: func() task.Manager { return suite.taskMgr }, ArtifactControllerFunc: func() artifact.Controller { return suite.artifactCtl }, From 793dc54aec2bff006882742e19e186e1966d1d51 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Mon, 17 Jun 2024 15:02:58 +0800 Subject: [PATCH 05/74] Remove the delete local manifest when remote doesn't exist (#20597) Previous impl it calls c.local.DeleteManifest(remoteRepo, art.Tag), because the remoteRepo is incorrect repository and it always delete nothing, to keep consistency with the previous version and code clarity, remove this go routine Signed-off-by: stonezdj --- src/controller/proxy/controller.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/controller/proxy/controller.go b/src/controller/proxy/controller.go index f177f85e04..38d55397c3 100644 --- a/src/controller/proxy/controller.go +++ b/src/controller/proxy/controller.go @@ -172,9 +172,6 @@ func (c *controller) UseLocalManifest(ctx context.Context, art lib.ArtifactInfo, return false, nil, err } if !exist || desc == nil { - go func() { - c.local.DeleteManifest(remoteRepo, art.Tag) - }() return false, nil, errors.NotFoundError(fmt.Errorf("repo %v, tag %v not found", art.Repository, art.Tag)) } @@ -220,11 +217,6 @@ func (c *controller) ProxyManifest(ctx context.Context, art lib.ArtifactInfo, re ref := getReference(art) man, dig, err := remote.Manifest(remoteRepo, ref) if err != nil { - if errors.IsNotFoundErr(err) { - go func() { - c.local.DeleteManifest(remoteRepo, art.Tag) - }() - } return man, err } ct, _, err := man.Payload() From df4ab856c7597e6fe28b466ba8419257de8a1af7 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Mon, 17 Jun 2024 18:29:43 +0800 Subject: [PATCH 06/74] fix: update the execution sweep sql to resolve the exec deletion conflict (#20603) fix: update the execution sweep sql to resolve the exec deleteion conflict Resolve the execution deleteion conflict when there are tasks still referenced by the execution, remained execs can wait for next sweep cycle. Signed-off-by: chlins Co-authored-by: Wang Yan --- src/pkg/task/sweep_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/task/sweep_manager.go b/src/pkg/task/sweep_manager.go index 95c96b8041..e82131fbc6 100644 --- a/src/pkg/task/sweep_manager.go +++ b/src/pkg/task/sweep_manager.go @@ -176,7 +176,7 @@ func (sm *sweepManager) Clean(ctx context.Context, execIDs []int64) error { return errors.Wrap(err, "failed to delete tasks") } // delete executions - sql = fmt.Sprintf("DELETE FROM execution WHERE id IN (%s)", orm.ParamPlaceholderForIn(len(params))) + sql = fmt.Sprintf("DELETE FROM execution WHERE id IN (%s) AND id NOT IN (SELECT DISTINCT execution_id FROM task)", orm.ParamPlaceholderForIn(len(params))) _, err = ormer.Raw(sql, params...).Exec() if err != nil { return errors.Wrap(err, "failed to delete executions") From ac671617fb3ddab0dfde5a5481f85b4c3e62f032 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Mon, 17 Jun 2024 19:06:15 +0800 Subject: [PATCH 07/74] fix: reduce the execution sweep job frequency from hourly to daily (#20601) Signed-off-by: chlins --- src/controller/task/sweep.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/task/sweep.go b/src/controller/task/sweep.go index 1c03914da7..b4bf023d80 100644 --- a/src/controller/task/sweep.go +++ b/src/controller/task/sweep.go @@ -41,8 +41,8 @@ const ( systemVendorID = -1 cronTypeCustom = "Custom" - // run for every hour - cronSpec = "0 0 * * * *" + // run for every day + cronSpec = "0 0 0 * * *" ) func init() { From 02b3561ffff7e92153793eb3e590b5f9d61ecd6a Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Mon, 17 Jun 2024 19:47:05 +0800 Subject: [PATCH 08/74] Add menu item for ko_KR local (#20602) fixes #20600 Signed-off-by: stonezdj Co-authored-by: Shengwen YU --- src/portal/src/app/shared/entities/shared.const.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/portal/src/app/shared/entities/shared.const.ts b/src/portal/src/app/shared/entities/shared.const.ts index 573cda40bb..8cbb344e0e 100644 --- a/src/portal/src/app/shared/entities/shared.const.ts +++ b/src/portal/src/app/shared/entities/shared.const.ts @@ -14,6 +14,7 @@ import locale_en from '@angular/common/locales/en'; import locale_zh_CN from '@angular/common/locales/zh-Hans'; +import locale_kr from '@angular/common/locales/ko'; import locale_zh_TW from '@angular/common/locales/zh-Hans-HK'; import locale_es from '@angular/common/locales/es'; import locale_fr from '@angular/common/locales/fr'; @@ -237,6 +238,7 @@ export const LANGUAGES = { 'en-us': ['English', locale_en], 'zh-cn': ['中文简体', locale_zh_CN], 'zh-tw': ['中文繁體', locale_zh_TW], + 'ko-kr': ['한국어', locale_kr], 'es-es': ['Español', locale_es], 'fr-fr': ['Français', locale_fr], 'pt-br': ['Português do Brasil', locale_pt], From c75d08fcc4d36f7e15cdf0191a42171ea8e9e9a0 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Thu, 20 Jun 2024 13:30:02 +0800 Subject: [PATCH 09/74] fix: hide the scan related button when installation without scanner (#20616) Signed-off-by: chlins --- .../artifact-list-tab/artifact-list-tab.component.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index 6ee406793c..cc9ac24f3a 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -15,6 +15,7 @@
From bb2c62c4c553042d3e613c2a6927336f8d6c5fd0 Mon Sep 17 00:00:00 2001 From: Shengwen YU Date: Thu, 20 Jun 2024 14:43:19 +0800 Subject: [PATCH 10/74] fix: update the cron of execution sweep in test (#20636) fix: update the cron of execution sweep in test per the change of this PR: https://github.com/goharbor/harbor/pull/20601 Signed-off-by: Shengwen Yu --- tests/resources/Harbor-Pages/Job_Service_Dashboard.robot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/Harbor-Pages/Job_Service_Dashboard.robot b/tests/resources/Harbor-Pages/Job_Service_Dashboard.robot index 19446cca38..f13ff2018c 100644 --- a/tests/resources/Harbor-Pages/Job_Service_Dashboard.robot +++ b/tests/resources/Harbor-Pages/Job_Service_Dashboard.robot @@ -141,7 +141,7 @@ Check Schedule List # Check log rotation schedule Retry Wait Until Page Contains Element //clr-dg-row[.//clr-dg-cell[text()='PURGE_AUDIT_LOG'] and .//clr-dg-cell[text()='${schedule_cron}']] # Check execution sweep schedule - Retry Wait Until Page Contains Element //clr-dg-row[.//clr-dg-cell[text()='EXECUTION_SWEEP'] and .//clr-dg-cell[text()='0 0 * * * *']] + Retry Wait Until Page Contains Element //clr-dg-row[.//clr-dg-cell[text()='EXECUTION_SWEEP'] and .//clr-dg-cell[text()='0 0 0 * * *']] # Check system artifact cleanup schedule Retry Wait Until Page Contains Element //clr-dg-row[.//clr-dg-cell[text()='SYSTEM_ARTIFACT_CLEANUP'] and .//clr-dg-cell[text()='0 0 0 * * *']] From 76851493e9e9139a9c366c5d2da383c377421fff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 17:37:11 +0800 Subject: [PATCH 11/74] chore(deps): bump golang.org/x/net from 0.25.0 to 0.26.0 in /src (#20567) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.26.0. - [Commits](https://github.com/golang/net/compare/v0.25.0...v0.26.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 12 ++++++------ src/go.sum | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/go.mod b/src/go.mod index 4f3a878cae..1646f2604d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -63,11 +63,11 @@ require ( go.opentelemetry.io/otel/sdk v1.26.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/ratelimit v0.3.1 - golang.org/x/crypto v0.23.0 - golang.org/x/net v0.25.0 + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 golang.org/x/oauth2 v0.19.0 - golang.org/x/sync v0.6.0 - golang.org/x/text v0.15.0 + golang.org/x/sync v0.7.0 + golang.org/x/text v0.16.0 golang.org/x/time v0.5.0 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 @@ -170,8 +170,8 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect google.golang.org/api v0.162.0 // indirect google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect diff --git a/src/go.sum b/src/go.sum index f7aeb58c61..9cdc80d0e4 100644 --- a/src/go.sum +++ b/src/go.sum @@ -699,8 +699,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -726,8 +726,8 @@ 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -754,8 +754,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -771,8 +771,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -813,16 +813,16 @@ golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= 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= @@ -833,8 +833,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= @@ -867,8 +867,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From e175c898f39cf4f4c32b6bffa90ad0bf6da2edb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 18:25:40 +0800 Subject: [PATCH 12/74] chore(deps): bump helm.sh/helm/v3 from 3.14.4 to 3.15.2 in /src (#20609) Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.14.4 to 3.15.2. - [Release notes](https://github.com/helm/helm/releases) - [Commits](https://github.com/helm/helm/compare/v3.14.4...v3.15.2) --- updated-dependencies: - dependency-name: helm.sh/helm/v3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 10 +++++----- src/go.sum | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/go.mod b/src/go.mod index 1646f2604d..ccb2079613 100644 --- a/src/go.mod +++ b/src/go.mod @@ -16,7 +16,7 @@ require ( github.com/cloudevents/sdk-go/v2 v2.15.2 github.com/coreos/go-oidc/v3 v3.10.0 github.com/dghubble/sling v1.1.0 - github.com/docker/distribution v2.8.2+incompatible + github.com/docker/distribution v2.8.3+incompatible github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 github.com/go-asn1-ber/asn1-ber v1.5.7 github.com/go-ldap/ldap/v3 v3.4.6 @@ -71,10 +71,10 @@ require ( golang.org/x/time v0.5.0 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 - helm.sh/helm/v3 v3.14.4 + helm.sh/helm/v3 v3.15.2 k8s.io/api v0.30.0 k8s.io/apimachinery v0.30.0 - k8s.io/client-go v0.29.0 + k8s.io/client-go v0.30.0 sigs.k8s.io/yaml v1.4.0 ) @@ -101,8 +101,8 @@ require ( github.com/denverdino/aliyungo v0.0.0-20191227032621-df38c6fa730c // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dnaeon/go-vcr v1.2.0 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/docker v24.0.9+incompatible // indirect + github.com/docker/cli v25.0.1+incompatible // indirect + github.com/docker/docker v25.0.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect diff --git a/src/go.sum b/src/go.sum index 9cdc80d0e4..d7525187de 100644 --- a/src/go.sum +++ b/src/go.sum @@ -134,16 +134,18 @@ github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= github.com/distribution/distribution v2.8.2+incompatible h1:k9+4DKdOG+quPFZXT/mUsiQrGu9vYCp+dXpuPkuqhk8= github.com/distribution/distribution v2.8.2+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= -github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU= +github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= +github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -955,8 +957,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -helm.sh/helm/v3 v3.14.4 h1:6FSpEfqyDalHq3kUr4gOMThhgY55kXUEjdQoyODYnrM= -helm.sh/helm/v3 v3.14.4/go.mod h1:Tje7LL4gprZpuBNTbG34d1Xn5NmRT3OWfBRwpOSer9I= +helm.sh/helm/v3 v3.15.2 h1:/3XINUFinJOBjQplGnjw92eLGpgXXp1L8chWPkCkDuw= +helm.sh/helm/v3 v3.15.2/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -965,8 +967,8 @@ k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE= k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA= k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ= +k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= From ab13c6571b53b87710cca82d887e5c85c2957573 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Sun, 23 Jun 2024 09:10:29 +0800 Subject: [PATCH 13/74] Add translation for zh_CN (#20617) add sbom translation for zh_CN Signed-off-by: stonezdj --- src/portal/src/i18n/lang/zh-cn-lang.json | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json index d3eafdaf33..4977d13351 100644 --- a/src/portal/src/i18n/lang/zh-cn-lang.json +++ b/src/portal/src/i18n/lang/zh-cn-lang.json @@ -286,9 +286,9 @@ "SCAN": "漏洞扫描", "AUTOSCAN_TOGGLE": "自动扫描镜像", "AUTOSCAN_POLICY": "当镜像上传后,自动进行扫描", - "SBOM": "SBOM generation", - "AUTOSBOM_TOGGLE": "Automatically generate SBOM on push", - "AUTOSBOM_POLICY": "Automatically generate SBOM when the images are pushed to the project registry." + "SBOM": "生成软件物料清单", + "AUTOSBOM_TOGGLE": "在推送镜像时自动生成软件物料清单", + "AUTOSBOM_POLICY": "在推送镜像时自动生成该镜像的软件物料清单(SBOM)。" }, "MEMBER": { "NEW_USER": "添加用户成员", @@ -405,7 +405,7 @@ "REPOSITORY": "仓库", "ARTIFACT": "Artifact", "SCAN": "扫描", - "SBOM": "SBOM", + "SBOM": "软件物料清单", "TAG": "Tag", "ACCESSORY": "附件", "ARTIFACT_ADDITION": "Artifact 额外信息", @@ -777,7 +777,7 @@ "ARTIFACTS": "Artifacts", "SIZE": "大小", "VULNERABILITY": "漏洞", - "SBOM": "SBOM", + "SBOM": "软件物料清单", "BUILD_HISTORY": "构建历史", "SIGNED": "已签名", "AUTHOR": "作者", @@ -1038,31 +1038,31 @@ "TOOLTIPS_TITLE_ZERO": "No recognizable SBOM detected" }, "GRID": { - "PLACEHOLDER": "No scan results found.", - "COLUMN_PACKAGE": "Package", - "COLUMN_PACKAGES": "Packages", - "COLUMN_VERSION": "Current version", - "COLUMN_LICENSE": "License", - "COLUMN_DESCRIPTION": "Description", + "PLACEHOLDER": "没有扫描结果.", + "COLUMN_PACKAGE": "软件包", + "COLUMN_PACKAGES": "软件包", + "COLUMN_VERSION": "当前版本", + "COLUMN_LICENSE": "许可证", + "COLUMN_DESCRIPTION": "描述", "FOOT_ITEMS": "Items", "FOOT_OF": "of" }, "STATE": { - "OTHER_STATUS": "No SBOM", + "OTHER_STATUS": "无软件物料清单", "QUEUED": "Queued", "ERROR": "View Log", "SCANNING": "Generating", "STOPPED": "Generation stopped" }, - "NO_SBOM": "No SBOM", + "NO_SBOM": "无软件物料清单", "PACKAGES": "SBOM", "COMPLETED": "Completed", "REPORTED_BY": "Reported by {{scanner}}", - "GENERATE": "Generate SBOM", - "DOWNLOAD": "Download SBOM", - "Details": "SBOM details", - "STOP": "Stop Generate SBOM", - "TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully" + "GENERATE": "生成软件物料清单", + "DOWNLOAD": "下载软件物料清单", + "Details": "软件物料清单详情", + "STOP": "停止生成软件物料清单", + "TRIGGER_STOP_SUCCESS": "成功触发停止执行" }, "VULNERABILITY": { "STATE": { @@ -1108,12 +1108,12 @@ "PLACEHOLDER": "过滤漏洞", "PACKAGE": "组件", "PACKAGES": "组件", - "SCAN_NOW": "Scan vulnerability", + "SCAN_NOW": "漏洞扫描", "SCAN_BY": "使用 {{scanner}} 进行扫描", "REPORTED_BY": "结果由 {{scanner}} 提供", "NO_SCANNER": "无扫描器", "TRIGGER_STOP_SUCCESS": "停止扫描成功", - "STOP_NOW": "Stop Scan Vulnerability" + "STOP_NOW": "停止漏洞扫描" }, "PUSH_IMAGE": { "TITLE": "推送命令", @@ -1469,10 +1469,10 @@ "NAME_REQUIRED": "名称为必填项", "NAME_REX": "名称由小写字符、数字和._-组成且至少2个字符并以字符或者数字开头。", "DESCRIPTION": "描述", - "SBOM": "SBOM", - "VULNERABILITY": "Vulnerability", - "SUPPORTED": "Supported", - "NOT_SUPPORTED": "Not Supported", + "SBOM": "软件物料清单", + "VULNERABILITY": "漏洞扫描", + "SUPPORTED": "支持", + "NOT_SUPPORTED": "不支持", "ENDPOINT": "地址", "ENDPOINT_EXISTS": "地址已存在", "ENDPOINT_REQUIRED": "地址为必填项", From 04b0cc0b0846e65629087859b6c0432909b4418d Mon Sep 17 00:00:00 2001 From: Shengwen YU Date: Mon, 24 Jun 2024 17:09:10 +0800 Subject: [PATCH 14/74] fix: change coporate harbor to registry.goharbor.io (#20651) fix: change coporate harbor to registry.goharbor.io and configurable Signed-off-by: Shengwen Yu --- tests/robot-cases/Group3-Upgrade/data.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/robot-cases/Group3-Upgrade/data.json b/tests/robot-cases/Group3-Upgrade/data.json index 8c2865e1d7..32c6222720 100644 --- a/tests/robot-cases/Group3-Upgrade/data.json +++ b/tests/robot-cases/Group3-Upgrade/data.json @@ -28,7 +28,7 @@ ], "endpoint":[ { - "url":"https://harbor-repo.vmware.com", + "url":"https://registry.goharbor.io", "name":"endpoint_for_proxy_cache", "user":"", "pass":"", From 35d1032ff712593ca062f4e0a65a9ea02aada6e4 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Tue, 25 Jun 2024 14:24:38 +0800 Subject: [PATCH 15/74] fix: disable the scan related button when installation without scanner or scanner deactived (#20652) Signed-off-by: chlins --- .../artifact-list-page/artifact-list-page.service.ts | 6 ++++++ .../artifact-list-tab/artifact-list-tab.component.html | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts index daf0c0ae5c..e91765cee8 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list-page.service.ts @@ -127,6 +127,12 @@ export class ArtifactListPageService { ClrLoadingState.ERROR ); } + } else { + this.updateStates( + false, + ClrLoadingState.ERROR, + ClrLoadingState.ERROR + ); } }, error => { diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index cc9ac24f3a..ad601cf6d6 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -15,7 +15,6 @@
From 2332953c88120507e8708a08f08597549bf1c6ec Mon Sep 17 00:00:00 2001 From: Florian Blampey Date: Wed, 26 Jun 2024 15:08:22 +0200 Subject: [PATCH 16/74] Add SBOM translation for fr_FR (#20625) Add translation for fr_FR Signed-off-by: Florian Blampey Co-authored-by: Shengwen YU --- src/portal/src/i18n/lang/fr-fr-lang.json | 54 ++++++++++++------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/portal/src/i18n/lang/fr-fr-lang.json b/src/portal/src/i18n/lang/fr-fr-lang.json index 0e931772d2..fdd45c0dd6 100644 --- a/src/portal/src/i18n/lang/fr-fr-lang.json +++ b/src/portal/src/i18n/lang/fr-fr-lang.json @@ -1031,38 +1031,38 @@ }, "SBOM": { "CHART": { - "SCANNING_TIME": "Scan completed time:", - "SCANNING_PERCENT": "Scan progress:", - "SCANNING_PERCENT_EXPLAIN": "The scan completion progress is calculated as # of successfully scanned images / total number of images referenced within the image index.", - "TOOLTIPS_TITLE": "{{totalSbom}} of {{totalPackages}} {{package}} have known {{sbom}}.", - "TOOLTIPS_TITLE_SINGULAR": "{{totalSbom}} of {{totalPackages}} {{package}} has known {{sbom}}.", - "TOOLTIPS_TITLE_ZERO": "No recognizable SBOM detected" + "SCANNING_TIME": "Temps d'analyse complète:", + "SCANNING_PERCENT": "Analyse en cours:", + "SCANNING_PERCENT_EXPLAIN": "Le pourcentage d'avancement de l'analyse est calculé comme suit : nombre d'images analysées avec succès / nombre total d'images référencées dans l'index d'images.", + "TOOLTIPS_TITLE": "{{totalSbom}} sur {{totalPackages}} {{package}} ont un {{sbom}} connu.", + "TOOLTIPS_TITLE_SINGULAR": "{{totalSbom}} sur {{totalPackages}} {{package}} a un {{sbom}} connu.", + "TOOLTIPS_TITLE_ZERO": "Aucun SBOM identifiable détecté" }, "GRID": { - "PLACEHOLDER": "No scan results found.", + "PLACEHOLDER": "Aucun résultat d'analyse trouvé.", "COLUMN_PACKAGE": "Package", "COLUMN_PACKAGES": "Packages", - "COLUMN_VERSION": "Current version", + "COLUMN_VERSION": "Version actuelle", "COLUMN_LICENSE": "License", "COLUMN_DESCRIPTION": "Description", - "FOOT_ITEMS": "Items", + "FOOT_ITEMS": "Elements", "FOOT_OF": "of" }, "STATE": { - "OTHER_STATUS": "No SBOM", - "QUEUED": "Queued", - "ERROR": "View Log", - "SCANNING": "Generating", - "STOPPED": "Generation stopped" + "OTHER_STATUS": "Pas de SBOM", + "QUEUED": "En attente", + "ERROR": "Voir le log", + "SCANNING": "En cours de génération", + "STOPPED": "Génération arrêtée" }, - "NO_SBOM": "No SBOM", + "NO_SBOM": "Pas de SBOM", "PACKAGES": "SBOM", - "COMPLETED": "Completed", - "REPORTED_BY": "Reported by {{scanner}}", - "GENERATE": "Generate SBOM", - "DOWNLOAD": "Download SBOM", - "Details": "SBOM details", - "STOP": "Stop Generate SBOM", + "COMPLETED": "Terminé", + "REPORTED_BY": "Généré par {{scanner}}", + "GENERATE": "Générer le SBOM", + "DOWNLOAD": "Télécharger le SBOM", + "Details": "Détails du SBOM", + "STOP": "Arrêter la génération du SBOM", "TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully" }, "VULNERABILITY": { @@ -1079,7 +1079,7 @@ "COLUMN_SEVERITY": "Séverité", "COLUMN_PACKAGE": "Paquet", "COLUMN_PACKAGES": "Paquets", - "COLUMN_VERSION": "Version Actuelle", + "COLUMN_VERSION": "Version actuelle", "COLUMN_FIXED": "Réparé dans la version", "COLUMN_DESCRIPTION": "Description", "FOOT_ITEMS": "Entrées", @@ -1089,8 +1089,8 @@ }, "CHART": { "SCANNING_TIME": "Temps d'analyse complète :", - "SCANNING_PERCENT": "Pourcentage de complétion d'analyse :", - "SCANNING_PERCENT_EXPLAIN": "Le pourcentage de complétion d'analyse est calculé en tant que nombre d'images analysées avec succès / nombre total d'images référencées dans l'index d'images.", + "SCANNING_PERCENT": "Analyse en cours :", + "SCANNING_PERCENT_EXPLAIN": "Le pourcentage d'avancement de l'analyse est calculé comme suit : nombre d'images analysées avec succès / nombre total d'images référencées dans l'index d'images.", "TOOLTIPS_TITLE": "{{totalVulnerability}} sur {{totalPackages}} {{package}} ont des {{vulnerability}} connues.", "TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} sur {{totalPackages}} {{package}} a des {{vulnerability}} connues.", "TOOLTIPS_TITLE_ZERO": "Pas de vulnérabilité identifiable trouvée" @@ -1109,12 +1109,12 @@ "PLACEHOLDER": "Filtrer les vulnérabilités", "PACKAGE": "paquet", "PACKAGES": "paquets", - "SCAN_NOW": "Scan vulnerability", - "SCAN_BY": "Scan par {{scanner}}", + "SCAN_NOW": "Lancer le scan de vulnérabilités", + "SCAN_BY": "Scanné par {{scanner}}", "REPORTED_BY": "Rapporté par {{scanner}}", "NO_SCANNER": "Aucun scanneur", "TRIGGER_STOP_SUCCESS": "Déclenchement avec succès de l'arrêt d'analyse", - "STOP_NOW": "Stop Scan Vulnerability" + "STOP_NOW": "Arrêter le scan de vulnérabilités" }, "PUSH_IMAGE": { "TITLE": "Commande de push", From 562c01ea816467be4bd59e9284a08cc108d07b85 Mon Sep 17 00:00:00 2001 From: MinerYang Date: Thu, 27 Jun 2024 14:38:18 +0800 Subject: [PATCH 17/74] bump up beego to v2.2.1 (#20555) bump up beego v2.2.1 Signed-off-by: yminer --- src/go.mod | 15 ++++++++------- src/go.sum | 31 +++++++++++++++++-------------- src/lib/orm/query.go | 31 ++++++++++++++++++++++++++++--- src/pkg/artifact/dao/dao.go | 6 +++--- src/pkg/task/dao/execution.go | 6 +++--- src/pkg/task/dao/task.go | 6 +++--- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/go.mod b/src/go.mod index ccb2079613..d5c31c4292 100644 --- a/src/go.mod +++ b/src/go.mod @@ -8,7 +8,7 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/aws/aws-sdk-go v1.53.14 - github.com/beego/beego/v2 v2.0.6 + github.com/beego/beego/v2 v2.2.1 github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0 github.com/bmatcuk/doublestar v1.3.4 github.com/casbin/casbin v1.9.1 @@ -21,12 +21,12 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.7 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/errors v0.22.0 - github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/loads v0.21.2 github.com/go-openapi/runtime v0.26.2 - github.com/go-openapi/spec v0.20.11 // indirect + github.com/go-openapi/spec v0.20.11 github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 - github.com/go-openapi/validate v0.22.3 // indirect + github.com/go-openapi/validate v0.22.3 github.com/go-redis/redis/v8 v8.11.4 github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 github.com/gocraft/work v0.5.1 @@ -160,6 +160,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/volcengine/volc-sdk-golang v1.0.23 // indirect @@ -167,9 +168,9 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.19.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + go.uber.org/zap v1.19.1 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect google.golang.org/api v0.162.0 // indirect diff --git a/src/go.sum b/src/go.sum index d7525187de..40895035fa 100644 --- a/src/go.sum +++ b/src/go.sum @@ -14,6 +14,8 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go v37.2.0+incompatible h1:LTdcd2GK+cv+e7yhWCN8S7yf3eblBypKFZsPfKjCQ7E= github.com/Azure/azure-sdk-for-go v37.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -79,8 +81,8 @@ github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevB github.com/aws/aws-sdk-go v1.53.14 h1:SzhkC2Pzag0iRW8WBb80RzKdGXDydJR9LAMs2GyKJ2M= github.com/aws/aws-sdk-go v1.53.14/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/beego/beego/v2 v2.0.6 h1:21Aqz3+RzUE1yP9a5xdU6LK54n9Z7NLEJtR4PE7NrPQ= -github.com/beego/beego/v2 v2.0.6/go.mod h1:CH2/JIaB4ceGYVQlYqTAFft4pVk/ol1ZkakUrUvAyns= +github.com/beego/beego/v2 v2.2.1 h1:5RatpEOKnw6sm76hj6lQvEFi4Tco+E21VQomnVB7NsA= +github.com/beego/beego/v2 v2.2.1/go.mod h1:X4hHhM2AXn0hN2tbyz5X/PD7v5JUdE4IihZApiljpNA= github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0 h1:fQaDnUQvBXHHQdGBu9hz8nPznB4BeiPQokvmQVjmNEw= github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0/go.mod h1:KLeFCpAMq2+50NkXC8iiJxLLiiTfTqrGtKEVm+2fk7s= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -221,8 +223,8 @@ github.com/go-openapi/validate v0.22.3 h1:KxG9mu5HBRYbecRb37KRCihvGGtND2aXziBAv0 github.com/go-openapi/validate v0.22.3/go.mod h1:kVxh31KbfsxU8ZyoHaDbLBWU5CnMdqBUEtadQ2G4d5M= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 h1:hp1oqdzmv37vPLYFGjuM/RmUgUMfD9vQfMszc54l55Y= @@ -452,8 +454,8 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -667,15 +669,17 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -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.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= @@ -683,8 +687,8 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -716,7 +720,6 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -858,7 +861,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -867,6 +869,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= diff --git a/src/lib/orm/query.go b/src/lib/orm/query.go index 0e193886a9..b30bf47a19 100644 --- a/src/lib/orm/query.go +++ b/src/lib/orm/query.go @@ -64,7 +64,14 @@ import ( // }, // } // } -func QuerySetter(ctx context.Context, model interface{}, query *q.Query) (orm.QuerySeter, error) { + +type Config struct { + DisableSort bool +} + +type Option func(*Config) + +func QuerySetter(ctx context.Context, model interface{}, query *q.Query, options ...Option) (orm.QuerySeter, error) { t := reflect.TypeOf(model) if t.Kind() != reflect.Ptr { return nil, fmt.Errorf(" cannot use non-ptr model struct `%s`", getFullName(t.Elem())) @@ -82,8 +89,12 @@ func QuerySetter(ctx context.Context, model interface{}, query *q.Query) (orm.Qu // set filters qs = setFilters(ctx, qs, query, metadata) + opts := newConfig(options...) // sorting - qs = setSorts(qs, query, metadata) + // Do not set sort when sort disabled. e.g. for Count() + if !opts.DisableSort { + qs = setSorts(qs, query, metadata) + } // pagination if query.PageSize > 0 { @@ -96,6 +107,20 @@ func QuerySetter(ctx context.Context, model interface{}, query *q.Query) (orm.Qu return qs, nil } +func WithSortDisabled(disableSort bool) Option { + return func(cfg *Config) { + cfg.DisableSort = disableSort + } +} + +func newConfig(opts ...Option) *Config { + config := &Config{} + for _, opt := range opts { + opt(config) + } + return config +} + // PaginationOnRawSQL append page information to the raw sql // It should be called after the order by // e.g. @@ -121,7 +146,7 @@ func QuerySetterForCount(ctx context.Context, model interface{}, query *q.Query, query.Sorts = nil query.PageSize = 0 query.PageNumber = 0 - return QuerySetter(ctx, model, query) + return QuerySetter(ctx, model, query, WithSortDisabled(true)) } // set filters according to the query diff --git a/src/pkg/artifact/dao/dao.go b/src/pkg/artifact/dao/dao.go index 880667e7fa..0e2e79a41c 100644 --- a/src/pkg/artifact/dao/dao.go +++ b/src/pkg/artifact/dao/dao.go @@ -93,7 +93,7 @@ func (d *dao) Count(ctx context.Context, query *q.Query) (int64, error) { Keywords: query.Keywords, } } - qs, err := querySetter(ctx, query) + qs, err := querySetter(ctx, query, orm.WithSortDisabled(true)) if err != nil { return 0, err } @@ -282,8 +282,8 @@ func (d *dao) DeleteReferences(ctx context.Context, parentID int64) error { return err } -func querySetter(ctx context.Context, query *q.Query) (beegoorm.QuerySeter, error) { - qs, err := orm.QuerySetter(ctx, &Artifact{}, query) +func querySetter(ctx context.Context, query *q.Query, options ...orm.Option) (beegoorm.QuerySeter, error) { + qs, err := orm.QuerySetter(ctx, &Artifact{}, query, options...) if err != nil { return nil, err } diff --git a/src/pkg/task/dao/execution.go b/src/pkg/task/dao/execution.go index 8cd66e75aa..6775a7f3ac 100644 --- a/src/pkg/task/dao/execution.go +++ b/src/pkg/task/dao/execution.go @@ -107,7 +107,7 @@ func (e *executionDAO) Count(ctx context.Context, query *q.Query) (int64, error) Keywords: query.Keywords, } } - qs, err := e.querySetter(ctx, query) + qs, err := e.querySetter(ctx, query, orm.WithSortDisabled(true)) if err != nil { return 0, err } @@ -349,8 +349,8 @@ type jsonbStru struct { value interface{} } -func (e *executionDAO) querySetter(ctx context.Context, query *q.Query) (orm.QuerySeter, error) { - qs, err := orm.QuerySetter(ctx, &Execution{}, query) +func (e *executionDAO) querySetter(ctx context.Context, query *q.Query, options ...orm.Option) (orm.QuerySeter, error) { + qs, err := orm.QuerySetter(ctx, &Execution{}, query, options...) if err != nil { return nil, err } diff --git a/src/pkg/task/dao/task.go b/src/pkg/task/dao/task.go index b42781c17a..6bdcec1994 100644 --- a/src/pkg/task/dao/task.go +++ b/src/pkg/task/dao/task.go @@ -74,7 +74,7 @@ func (t *taskDAO) Count(ctx context.Context, query *q.Query) (int64, error) { Keywords: query.Keywords, } } - qs, err := t.querySetter(ctx, query) + qs, err := t.querySetter(ctx, query, orm.WithSortDisabled(true)) if err != nil { return 0, err } @@ -250,8 +250,8 @@ func (t *taskDAO) GetMaxEndTime(ctx context.Context, executionID int64) (time.Ti return endTime, nil } -func (t *taskDAO) querySetter(ctx context.Context, query *q.Query) (orm.QuerySeter, error) { - qs, err := orm.QuerySetter(ctx, &Task{}, query) +func (t *taskDAO) querySetter(ctx context.Context, query *q.Query, options ...orm.Option) (orm.QuerySeter, error) { + qs, err := orm.QuerySetter(ctx, &Task{}, query, options...) if err != nil { return nil, err } From 7ffc3780e7cc5358ca831b5d17f18e3a3d33a0c2 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Mon, 1 Jul 2024 09:25:41 +0800 Subject: [PATCH 18/74] fix: correct the API data for the dependencies of the helm chart (#20676) Fix the handle logic of the chart operator, correct the data for the dependencies of the helm chart. Signed-off-by: chlins --- src/pkg/chart/operator.go | 24 +- src/pkg/chart/operator_test.go | 126 +- .../chart/testdata/harbor-schema1/.helmignore | 6 + .../chart/testdata/harbor-schema1/Chart.yaml | 24 + src/pkg/chart/testdata/harbor-schema1/LICENSE | 201 ++++ .../chart/testdata/harbor-schema1/README.md | 422 +++++++ .../testdata/harbor-schema1/requirements.yaml | 10 + .../harbor-schema1/templates/NOTES.txt | 3 + .../harbor-schema1/templates/_helpers.tpl | 581 +++++++++ .../templates/core/core-cm.yaml | 90 ++ .../templates/core/core-dpl.yaml | 257 ++++ .../templates/core/core-pre-upgrade-job.yaml | 77 ++ .../templates/core/core-secret.yaml | 36 + .../templates/core/core-svc.yaml | 25 + .../templates/core/core-tls.yaml | 15 + .../templates/database/database-secret.yaml | 11 + .../templates/database/database-ss.yaml | 162 +++ .../templates/database/database-svc.yaml | 14 + .../templates/exporter/exporter-cm-env.yaml | 35 + .../templates/exporter/exporter-dpl.yaml | 146 +++ .../templates/exporter/exporter-secret.yaml | 16 + .../templates/exporter/exporter-svc.yaml | 15 + .../templates/ingress/ingress.yaml | 142 +++ .../templates/ingress/secret.yaml | 15 + .../templates/internal/auto-tls.yaml | 81 ++ .../jobservice/jobservice-cm-env.yaml | 34 + .../templates/jobservice/jobservice-cm.yaml | 57 + .../templates/jobservice/jobservice-dpl.yaml | 182 +++ .../templates/jobservice/jobservice-pvc.yaml | 31 + .../jobservice/jobservice-secrets.yaml | 16 + .../templates/jobservice/jobservice-svc.yaml | 18 + .../templates/jobservice/jobservice-tls.yaml | 15 + .../templates/metrics/metrics-svcmon.yaml | 28 + .../templates/nginx/configmap-http.yaml | 150 +++ .../templates/nginx/configmap-https.yaml | 187 +++ .../templates/nginx/deployment.yaml | 132 ++ .../templates/nginx/secret.yaml | 23 + .../templates/nginx/service.yaml | 94 ++ .../templates/portal/configmap.yaml | 67 ++ .../templates/portal/deployment.yaml | 123 ++ .../templates/portal/service.yaml | 20 + .../harbor-schema1/templates/portal/tls.yaml | 15 + .../templates/redis/service.yaml | 14 + .../templates/redis/statefulset.yaml | 125 ++ .../templates/registry/registry-cm.yaml | 246 ++++ .../templates/registry/registry-dpl.yaml | 431 +++++++ .../templates/registry/registry-pvc.yaml | 33 + .../templates/registry/registry-secret.yaml | 55 + .../templates/registry/registry-svc.yaml | 20 + .../templates/registry/registry-tls.yaml | 15 + .../templates/registry/registryctl-cm.yaml | 8 + .../registry/registryctl-secret.yaml | 9 + .../templates/trivy/trivy-secret.yaml | 12 + .../templates/trivy/trivy-sts.yaml | 230 ++++ .../templates/trivy/trivy-svc.yaml | 16 + .../templates/trivy/trivy-tls.yaml | 15 + .../chart/testdata/harbor-schema1/values.yaml | 1058 +++++++++++++++++ .../chart/testdata/harbor-schema2/.helmignore | 6 + .../chart/testdata/harbor-schema2/Chart.yaml | 34 + src/pkg/chart/testdata/harbor-schema2/LICENSE | 201 ++++ .../chart/testdata/harbor-schema2/README.md | 422 +++++++ .../harbor-schema2/templates/NOTES.txt | 3 + .../harbor-schema2/templates/_helpers.tpl | 581 +++++++++ .../templates/core/core-cm.yaml | 90 ++ .../templates/core/core-dpl.yaml | 257 ++++ .../templates/core/core-pre-upgrade-job.yaml | 77 ++ .../templates/core/core-secret.yaml | 36 + .../templates/core/core-svc.yaml | 25 + .../templates/core/core-tls.yaml | 15 + .../templates/database/database-secret.yaml | 11 + .../templates/database/database-ss.yaml | 162 +++ .../templates/database/database-svc.yaml | 14 + .../templates/exporter/exporter-cm-env.yaml | 35 + .../templates/exporter/exporter-dpl.yaml | 146 +++ .../templates/exporter/exporter-secret.yaml | 16 + .../templates/exporter/exporter-svc.yaml | 15 + .../templates/ingress/ingress.yaml | 142 +++ .../templates/ingress/secret.yaml | 15 + .../templates/internal/auto-tls.yaml | 81 ++ .../jobservice/jobservice-cm-env.yaml | 34 + .../templates/jobservice/jobservice-cm.yaml | 57 + .../templates/jobservice/jobservice-dpl.yaml | 182 +++ .../templates/jobservice/jobservice-pvc.yaml | 31 + .../jobservice/jobservice-secrets.yaml | 16 + .../templates/jobservice/jobservice-svc.yaml | 18 + .../templates/jobservice/jobservice-tls.yaml | 15 + .../templates/metrics/metrics-svcmon.yaml | 28 + .../templates/nginx/configmap-http.yaml | 150 +++ .../templates/nginx/configmap-https.yaml | 187 +++ .../templates/nginx/deployment.yaml | 132 ++ .../templates/nginx/secret.yaml | 23 + .../templates/nginx/service.yaml | 94 ++ .../templates/portal/configmap.yaml | 67 ++ .../templates/portal/deployment.yaml | 123 ++ .../templates/portal/service.yaml | 20 + .../harbor-schema2/templates/portal/tls.yaml | 15 + .../templates/redis/service.yaml | 14 + .../templates/redis/statefulset.yaml | 125 ++ .../templates/registry/registry-cm.yaml | 246 ++++ .../templates/registry/registry-dpl.yaml | 431 +++++++ .../templates/registry/registry-pvc.yaml | 33 + .../templates/registry/registry-secret.yaml | 55 + .../templates/registry/registry-svc.yaml | 20 + .../templates/registry/registry-tls.yaml | 15 + .../templates/registry/registryctl-cm.yaml | 8 + .../registry/registryctl-secret.yaml | 9 + .../templates/trivy/trivy-secret.yaml | 12 + .../templates/trivy/trivy-sts.yaml | 230 ++++ .../templates/trivy/trivy-svc.yaml | 16 + .../templates/trivy/trivy-tls.yaml | 15 + .../chart/testdata/harbor-schema2/values.yaml | 1058 +++++++++++++++++ 111 files changed, 11858 insertions(+), 18 deletions(-) create mode 100644 src/pkg/chart/testdata/harbor-schema1/.helmignore create mode 100644 src/pkg/chart/testdata/harbor-schema1/Chart.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/LICENSE create mode 100644 src/pkg/chart/testdata/harbor-schema1/README.md create mode 100644 src/pkg/chart/testdata/harbor-schema1/requirements.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/NOTES.txt create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/_helpers.tpl create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-pre-upgrade-job.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/core/core-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/database/database-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/database/database-ss.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/database/database-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-cm-env.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/ingress/ingress.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/ingress/secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/internal/auto-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm-env.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-pvc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-secrets.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/metrics/metrics-svcmon.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-http.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-https.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/nginx/deployment.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/nginx/secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/nginx/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/portal/configmap.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/portal/deployment.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/portal/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/portal/tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/redis/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/redis/statefulset.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-pvc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-sts.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema1/values.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/.helmignore create mode 100644 src/pkg/chart/testdata/harbor-schema2/Chart.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/LICENSE create mode 100644 src/pkg/chart/testdata/harbor-schema2/README.md create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/NOTES.txt create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/_helpers.tpl create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-pre-upgrade-job.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/core/core-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/database/database-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/database/database-ss.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/database/database-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-cm-env.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/ingress/ingress.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/ingress/secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/internal/auto-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm-env.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-pvc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-secrets.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/metrics/metrics-svcmon.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-http.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-https.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/nginx/deployment.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/nginx/secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/nginx/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/portal/configmap.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/portal/deployment.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/portal/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/portal/tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/redis/service.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/redis/statefulset.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-dpl.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-pvc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-cm.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-secret.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-sts.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-svc.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-tls.yaml create mode 100644 src/pkg/chart/testdata/harbor-schema2/values.yaml diff --git a/src/pkg/chart/operator.go b/src/pkg/chart/operator.go index 66951fe7e4..d3ce0fc6a3 100644 --- a/src/pkg/chart/operator.go +++ b/src/pkg/chart/operator.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "gopkg.in/yaml.v2" helm_chart "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" ) @@ -30,8 +31,9 @@ var ( ) const ( - readmeFileName = "README.MD" - valuesFileName = "VALUES.YAML" + readmeFileName = "README.MD" + valuesFileName = "VALUES.YAML" + dependenciesFileName = "REQUIREMENTS.YAML" ) // Operator ... @@ -64,7 +66,7 @@ func (cho *operator) GetDetails(content []byte) (*VersionDetails, error) { depts := make([]*helm_chart.Dependency, 0) // for APIVersionV2, the dependency is in the Chart.yaml - if chartData.Metadata.APIVersion == helm_chart.APIVersionV1 { + if chartData.Metadata.APIVersion == helm_chart.APIVersionV2 { depts = chartData.Metadata.Dependencies } @@ -77,10 +79,26 @@ func (cho *operator) GetDetails(content []byte) (*VersionDetails, error) { // Append other files like 'README.md' 'values.yaml' for _, v := range chartData.Raw { + // for APIVersionV1, the dependency is in the requirements.yaml + if strings.ToUpper(v.Name) == dependenciesFileName && chartData.Metadata.APIVersion == helm_chart.APIVersionV1 { + depMap := make(map[string][]*helm_chart.Dependency) + if err := yaml.Unmarshal(v.Data, &depMap); err != nil { + return nil, err + } + + deps, ok := depMap["dependencies"] + if !ok { + return nil, errors.New("invalid requirements.yaml, no dependencies found") + } + depts = deps + continue + } + if strings.ToUpper(v.Name) == readmeFileName { files[readmeFileName] = string(v.Data) continue } + if strings.ToUpper(v.Name) == valuesFileName { files[valuesFileName] = string(v.Data) continue diff --git a/src/pkg/chart/operator_test.go b/src/pkg/chart/operator_test.go index 909e96a483..c93725e3c2 100644 --- a/src/pkg/chart/operator_test.go +++ b/src/pkg/chart/operator_test.go @@ -1,29 +1,125 @@ package chart import ( + "archive/tar" + "compress/gzip" + "io" + "io/fs" + "os" + "path/filepath" + "strings" "testing" + + "github.com/stretchr/testify/assert" ) -// HelmChartContent is mock data of chart tgz... -var HelmChartContent = []byte{0x1f, 0x8b, 0x8, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x29, 0x0, 0x2b, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, 0x35, 0x62, 0x33, 0x56, 0x30, 0x64, 0x53, 0x35, 0x69, 0x5a, 0x53, 0x39, 0x36, 0x4f, 0x56, 0x56, 0x36, 0x4d, 0x57, 0x6c, 0x6a, 0x61, 0x6e, 0x64, 0x79, 0x54, 0x51, 0x6f, 0x3d, 0x48, 0x65, 0x6c, 0x6d, 0x0, 0xec, 0xfd, 0x7b, 0x77, 0xe2, 0x38, 0xb3, 0x28, 0xe, 0xef, 0xbf, 0xf9, 0x14, 0x7a, 0xd3, 0xe7, 0x9c, 0x99, 0xee, 0x34, 0x60, 0xee, 0x97, 0x77, 0xcf, 0xde, 0xf, 0xb7, 0x0, 0xe1, 0x1a, 0x2e, 0x49, 0xc8, 0x9c, 0x59, 0x89, 0xb0, 0x5, 0x28, 0xd8, 0x96, 0x63, 0xd9, 0x10, 0x32, 0x3d, 0xe7, 0xb3, 0xff, 0x96, 0x24, 0xdb, 0x18, 0x30, 0x21, 0xf7, 0x9e, 0x79, 0x76, 0xb4, 0xd6, 0x4c, 0x7, 0x5b, 0x55, 0x2a, 0xc9, 0x55, 0xa5, 0x52, 0xa9, 0x54, 0x9a, 0x41, 0x73, 0x4c, 0xcc, 0x68, 0x69, 0x6, 0x4d, 0x2b, 0xb2, 0x82, 0x9a, 0xfa, 0x1f, 0x6f, 0x5f, 0x24, 0x49, 0x92, 0x32, 0xa9, 0x14, 0xff, 0x57, 0x92, 0xa4, 0xed, 0x7f, 0xa5, 0x4c, 0x2c, 0xe3, 0xfd, 0xcd, 0x9f, 0xc7, 0xe2, 0x89, 0x44, 0xe6, 0x3f, 0xc0, 0x3b, 0x90, 0xb2, 0x5b, 0x6c, 0x6a, 0x41, 0xf3, 0x3f, 0x24, 0xe9, 0xb5, 0x78, 0xb6, 0x3b, 0xf7, 0xf, 0x29, 0xd0, 0x30, 0xce, 0x91, 0x49, 0x31, 0xd1, 0xf3, 0x20, 0x16, 0x49, 0x45, 0xa4, 0x90, 0x82, 0xa8, 0x6c, 0x62, 0xc3, 0xe2, 0x8f, 0xa, 0x3a, 0xa8, 0xe8, 0x16, 0x32, 0xd, 0x13, 0x53, 0x14, 0x96, 0x55, 0x48, 0x29, 0x28, 0x13, 0x79, 0x8e, 0x4c, 0xd0, 0x43, 0x53, 0x4c, 0x2d, 0x73, 0x5, 0xc6, 0x2b, 0x70, 0xde, 0x5a, 0x42, 0x13, 0x85, 0x90, 0x3e, 0xc5, 0x3a, 0xca, 0x83, 0x29, 0xb1, 0xc, 0x35, 0x34, 0x23, 0x1a, 0xca, 0x83, 0x99, 0x65, 0x19, 0x34, 0x1f, 0x8d, 0x4e, 0xb1, 0x35, 0xb3, 0xc7, 0x11, 0x99, 0x68, 0xd1, 0x85, 0xc6, 0x6a, 0x47, 0x5, 0xeb, 0x85, 0xb0, 0xcc, 0x1a, 0x3a, 0x54, 0x2d, 0x3a, 0x56, 0xc9, 0x38, 0xaa, 0x41, 0x6a, 0x21, 0x33, 0xaa, 0x10, 0x99, 0x46, 0xb1, 0x36, 0x75, 0xde, 0x5d, 0xab, 0x64, 0x4a, 0x22, 0x86, 0x3e, 0xd, 0xcd, 0xd1, 0x6a, 0x49, 0x4c, 0x85, 0xe6, 0x43, 0x61, 0x20, 0xc0, 0x43, 0x61, 0xa0, 0x70, 0x7a, 0x43, 0x61, 0x60, 0x3a, 0x14, 0x87, 0xc2, 0xc0, 0x69, 0x5b, 0x83, 0x58, 0xb7, 0x20, 0xd6, 0x91, 0xc9, 0x41, 0x90, 0x6, 0xb1, 0x9a, 0x7, 0x33, 0x7b, 0xf6, 0x2f, 0x1, 0xcd, 0xe8, 0x8, 0x1, 0xa0, 0x43, 0xd6, 0x93, 0x53, 0x44, 0x29, 0x2, 0x35, 0x7b, 0x5d, 0xd1, 0xa6, 0xc8, 0x64, 0xef, 0x22, 0x16, 0x9c, 0x23, 0xfd, 0x5f, 0x53, 0xf6, 0x74, 0x3, 0xc4, 0x80, 0xb6, 0x2a, 0x3f, 0x40, 0x33, 0x24, 0x7e, 0x3a, 0xad, 0x52, 0x62, 0x9b, 0x32, 0xe2, 0x2d, 0x1e, 0xec, 0xb6, 0x65, 0x22, 0xe4, 0x76, 0x5b, 0x26, 0xba, 0x65, 0xe2, 0x71, 0x74, 0x86, 0x54, 0xcd, 0x1d, 0xbd, 0x85, 0xfb, 0xf1, 0xa4, 0x48, 0x3c, 0x22, 0x85, 0x9e, 0xfd, 0xfd, 0x9d, 0x66, 0x16, 0x50, 0xb5, 0x11, 0x7d, 0x27, 0x5, 0xf0, 0xb8, 0xfc, 0xc7, 0xd3, 0x99, 0xf4, 0x8e, 0xfc, 0xa7, 0x63, 0xf1, 0x4f, 0xf9, 0xff, 0x88, 0xf2, 0x5, 0x94, 0x88, 0x3e, 0xc1, 0x53, 0xdb, 0x44, 0xc0, 0x60, 0xbc, 0x44, 0x2d, 0xa4, 0x83, 0x73, 0xa2, 0xda, 0x1a, 0xa2, 0xec, 0x9, 0x80, 0x86, 0xa1, 0x62, 0x19, 0x32, 0x7d, 0x10, 0xfa, 0xf2, 0x5, 0x14, 0xd6, 0x3f, 0x29, 0xb0, 0x66, 0xd0, 0x2, 0x26, 0xba, 0xb3, 0xb1, 0x89, 0x0, 0xb5, 0x88, 0x9, 0xa7, 0x8, 0xcc, 0xe0, 0x2, 0x1, 0x8, 0x6e, 0x16, 0x2, 0xc9, 0xd, 0x50, 0xd0, 0x4, 0xeb, 0x98, 0x41, 0x80, 0xe5, 0xc, 0xcb, 0x33, 0xb0, 0xc4, 0xaa, 0xa, 0xc6, 0x88, 0xc9, 0x8f, 0xc2, 0x70, 0x2e, 0x67, 0x48, 0x7, 0x37, 0x5e, 0xf3, 0x32, 0x8a, 0x20, 0x1d, 0x8e, 0x55, 0xa4, 0xdc, 0x0, 0x4c, 0x1, 0x45, 0x16, 0xb0, 0x8, 0xb0, 0x4c, 0x1b, 0x45, 0x58, 0x6d, 0x74, 0xf, 0x35, 0x43, 0x45, 0xa1, 0x2f, 0x40, 0x5b, 0xd1, 0x3b, 0x35, 0x1f, 0xfa, 0x2, 0x0, 0x70, 0x1a, 0x13, 0x3f, 0x0, 0x50, 0xa0, 0x5, 0xf3, 0xac, 0x72, 0xd7, 0x45, 0x6a, 0x39, 0x9d, 0x2, 0x7d, 0x87, 0xcc, 0x12, 0x53, 0x66, 0xac, 0x4a, 0x7d, 0x22, 0x28, 0x44, 0xca, 0x77, 0xb7, 0xf, 0xfc, 0x5d, 0x9b, 0xcb, 0xec, 0x7f, 0xfa, 0x1f, 0xfd, 0x97, 0x53, 0xdf, 0x21, 0xe9, 0x28, 0x7c, 0x14, 0x4, 0x72, 0x74, 0xf4, 0xdd, 0xe9, 0xa8, 0x82, 0x29, 0xeb, 0x7, 0x5, 0xca, 0x4a, 0x87, 0x1a, 0x96, 0x81, 0x61, 0x92, 0x5, 0x66, 0x2, 0x8b, 0xf5, 0xa9, 0x83, 0xcb, 0xd6, 0x9d, 0xd6, 0xc1, 0xaf, 0xd6, 0xc, 0x31, 0x52, 0xa0, 0xad, 0x5a, 0x5f, 0x1, 0x31, 0xdd, 0x66, 0x74, 0x5b, 0x55, 0xbf, 0x3, 0x9d, 0xec, 0x34, 0x5, 0xa8, 0x81, 0x64, 0x80, 0x79, 0x2f, 0x0, 0xab, 0xfd, 0x1d, 0xc8, 0x33, 0x42, 0x28, 0xd6, 0xa7, 0xc0, 0x87, 0x6b, 0xdd, 0x2a, 0x32, 0x23, 0x0, 0xfc, 0x3a, 0x35, 0xe2, 0x80, 0xe8, 0xa0, 0x70, 0xd1, 0x67, 0xd4, 0x43, 0x5d, 0x81, 0xa6, 0x2, 0xc4, 0xd7, 0x5, 0xa0, 0xda, 0xa8, 0x7c, 0x67, 0xaf, 0xc0, 0xff, 0x1, 0x1d, 0x3, 0xe9, 0x7d, 0xb, 0xca, 0xf3, 0xaf, 0xa1, 0x2f, 0x5f, 0x9c, 0x81, 0xf5, 0x93, 0x90, 0x67, 0x3, 0xe0, 0x3c, 0x87, 0xb2, 0x8c, 0x28, 0x6d, 0x11, 0x5, 0xe5, 0x41, 0xf, 0x41, 0xe5, 0xc2, 0xc4, 0x16, 0xea, 0xe8, 0x32, 0x72, 0xe1, 0xf0, 0x3, 0xca, 0x83, 0x58, 0x15, 0x87, 0x58, 0x33, 0x6b, 0x9e, 0x33, 0x91, 0xd0, 0x86, 0x9c, 0x8b, 0x10, 0xb5, 0x28, 0x80, 0xba, 0x2, 0x54, 0xac, 0x61, 0x2b, 0x90, 0xfd, 0x4c, 0x34, 0x11, 0x93, 0x45, 0x3e, 0x1a, 0x9d, 0xdb, 0x63, 0x64, 0xea, 0xc8, 0x42, 0x34, 0x82, 0x89, 0x98, 0x14, 0x98, 0x46, 0xe, 0x4f, 0x6d, 0xac, 0xa0, 0xa8, 0x4c, 0x34, 0xc3, 0xb6, 0x50, 0xd8, 0x6d, 0x81, 0x46, 0x45, 0x2f, 0x7c, 0x4c, 0xe3, 0xbd, 0x72, 0xd9, 0xc6, 0x25, 0xc2, 0xfd, 0xd, 0x80, 0x86, 0x34, 0x62, 0xae, 0xf2, 0x20, 0x9e, 0x4a, 0xb7, 0xb0, 0xf7, 0x54, 0x36, 0xec, 0x3c, 0x88, 0x49, 0x92, 0x16, 0xa, 0xf9, 0xb8, 0x36, 0x1f, 0x2, 0xc0, 0x61, 0xdc, 0x3c, 0x67, 0xd7, 0x50, 0xe8, 0xb, 0x18, 0xcc, 0x10, 0xb0, 0xe0, 0x14, 0x4c, 0x88, 0x9, 0x6a, 0x5c, 0xd9, 0x3a, 0x13, 0x12, 0xc0, 0x1a, 0x9c, 0x22, 0x1a, 0x9, 0x9, 0x15, 0x5c, 0x67, 0xbf, 0x6, 0x70, 0x9a, 0x7, 0xff, 0xc7, 0x99, 0xd5, 0xf8, 0xfb, 0x6b, 0x6, 0xbb, 0xe0, 0x33, 0x73, 0x58, 0x66, 0x46, 0x5a, 0xd8, 0x80, 0x96, 0x3c, 0x73, 0x31, 0x9f, 0x9c, 0x95, 0xdb, 0x7e, 0xd4, 0x14, 0x99, 0xb, 0x2c, 0xa3, 0x48, 0x8, 0xdd, 0x5b, 0x6c, 0x6e, 0x52, 0xcb, 0x84, 0xcd, 0x71, 0xee, 0xd4, 0x13, 0xd1, 0x56, 0x11, 0x85, 0x3f, 0x9, 0x31, 0x39, 0x12, 0x55, 0xba, 0xc4, 0xb4, 0x98, 0x9c, 0x31, 0x8e, 0xe1, 0x7f, 0xef, 0xe2, 0xfb, 0xe, 0x54, 0xc4, 0xa4, 0x1a, 0x69, 0x86, 0xb5, 0x2, 0x78, 0xc2, 0xeb, 0x3a, 0xef, 0x38, 0x28, 0x61, 0xe2, 0x3c, 0x26, 0xb6, 0xae, 0x0, 0x8b, 0x84, 0xbe, 0x0, 0x83, 0xe1, 0xc9, 0x4a, 0xd1, 0x64, 0x32, 0x11, 0xf2, 0xb7, 0x93, 0x7, 0x89, 0x78, 0x46, 0x92, 0x42, 0x7e, 0x29, 0x62, 0x23, 0xf5, 0x1d, 0xac, 0x88, 0xd, 0x14, 0xa2, 0xff, 0x62, 0x1, 0x1d, 0x21, 0x86, 0x45, 0xbc, 0x56, 0x69, 0xc9, 0xb4, 0xa2, 0x96, 0x4a, 0x1b, 0x68, 0x15, 0x95, 0x61, 0xc9, 0xb4, 0xbe, 0x83, 0xb1, 0x6d, 0x1, 0xcd, 0xa6, 0x16, 0x80, 0x8a, 0x12, 0xfa, 0xe2, 0x92, 0xca, 0x87, 0x2, 0x52, 0x80, 0x75, 0x8a, 0x64, 0xdb, 0x64, 0x1f, 0x9e, 0x4f, 0xf7, 0x18, 0x51, 0xde, 0xa3, 0x15, 0xb1, 0xbd, 0xa1, 0x97, 0x55, 0x8c, 0x74, 0x2b, 0x12, 0x72, 0xeb, 0xba, 0xb6, 0x4c, 0x1e, 0x4c, 0xa0, 0x4a, 0x51, 0x68, 0x8a, 0x74, 0x64, 0x42, 0xb, 0x95, 0x90, 0x69, 0xe1, 0x9, 0x63, 0x3f, 0x44, 0x9d, 0x4f, 0x2a, 0xc6, 0x7d, 0xd0, 0xec, 0x3, 0x79, 0xfd, 0xd2, 0x37, 0x64, 0x11, 0xfe, 0x5e, 0x26, 0x9a, 0x46, 0x74, 0x6e, 0x5, 0x0, 0x32, 0x71, 0xba, 0x21, 0x88, 0xd6, 0xd8, 0xf7, 0xe3, 0x3, 0xb8, 0xf9, 0x8d, 0x0, 0x1c, 0x93, 0x5, 0x8a, 0x84, 0x44, 0xdd, 0x7c, 0x48, 0xf4, 0x39, 0x1f, 0xe2, 0x9d, 0xce, 0xbb, 0x1f, 0x9c, 0x22, 0xd9, 0x44, 0x16, 0x98, 0xa3, 0x15, 0xd7, 0x9e, 0xbc, 0x61, 0xa4, 0xcb, 0xe6, 0x8a, 0x1b, 0x6c, 0x11, 0xd0, 0x62, 0x4d, 0x8c, 0x99, 0xfe, 0x65, 0x5d, 0xd7, 0xa7, 0xac, 0xf5, 0x58, 0x1a, 0x30, 0xd6, 0xa1, 0x91, 0x90, 0x80, 0x66, 0x68, 0x81, 0x4e, 0xac, 0x30, 0xc, 0x3b, 0x43, 0x35, 0x47, 0x2b, 0xa7, 0x1, 0x8a, 0x0, 0xd4, 0x75, 0x62, 0x39, 0xa, 0x1e, 0xaa, 0x2a, 0x59, 0x72, 0x62, 0x5d, 0xe3, 0x89, 0x7d, 0x99, 0x25, 0x31, 0xe7, 0x60, 0x8c, 0x66, 0x98, 0x7d, 0xee, 0x19, 0x2, 0xcc, 0xec, 0xbb, 0xf, 0x7d, 0x1, 0x58, 0x9f, 0x9a, 0x88, 0x52, 0xc0, 0xd, 0x15, 0xa2, 0xaa, 0xc8, 0x64, 0x43, 0xcc, 0x9f, 0xed, 0xca, 0x6, 0xf0, 0x37, 0xc4, 0x5e, 0x3, 0x17, 0x3e, 0xb2, 0x29, 0xd8, 0x94, 0xaa, 0x61, 0x13, 0x29, 0xd8, 0x44, 0xb2, 0x95, 0x7, 0x47, 0xc, 0xf8, 0xe8, 0x91, 0xea, 0x86, 0x49, 0xee, 0x57, 0xe1, 0x31, 0x51, 0x56, 0x61, 0xa1, 0x74, 0x8e, 0x24, 0x51, 0x9d, 0x53, 0x19, 0x79, 0x6, 0x50, 0x8, 0x2a, 0x1a, 0xe3, 0x10, 0x73, 0x81, 0x4c, 0x46, 0x20, 0x17, 0x48, 0x41, 0xa9, 0x89, 0xc, 0x42, 0xb1, 0xc5, 0x55, 0xc3, 0x86, 0xc1, 0x16, 0xf6, 0xc1, 0xf0, 0x9a, 0x16, 0x13, 0xe9, 0x6f, 0xdb, 0x22, 0xcd, 0x5f, 0x19, 0xb6, 0xaa, 0x76, 0x89, 0x8a, 0xe5, 0x55, 0x1e, 0xd4, 0x27, 0x6d, 0x62, 0x75, 0x4d, 0x44, 0x91, 0x6e, 0xb1, 0xa1, 0x62, 0xa6, 0x64, 0x8d, 0x50, 0xd6, 0x61, 0xaa, 0x59, 0x46, 0x44, 0x5b, 0x9, 0xb9, 0x65, 0x26, 0xe2, 0x91, 0x5b, 0x41, 0x48, 0xd4, 0x51, 0x3c, 0xe5, 0x3d, 0x19, 0x52, 0x64, 0x32, 0x10, 0x3e, 0x43, 0x5e, 0x73, 0x5a, 0xfe, 0x15, 0x8, 0xda, 0xa7, 0x6a, 0x1e, 0x1c, 0x71, 0x6e, 0xf7, 0x9e, 0x9d, 0x98, 0x44, 0xcb, 0x83, 0x23, 0xe, 0x5, 0xfe, 0x73, 0x2f, 0x8e, 0xff, 0xf2, 0x0, 0xea, 0xa, 0xd2, 0x2d, 0x6c, 0xad, 0xd8, 0x94, 0xe7, 0x3d, 0x73, 0x44, 0x2a, 0xf, 0x8e, 0x4e, 0x36, 0xb0, 0x77, 0x97, 0xca, 0x16, 0xd7, 0x19, 0x90, 0x52, 0x66, 0xae, 0x33, 0x56, 0x60, 0xad, 0x74, 0x9d, 0xdf, 0x79, 0x47, 0x94, 0x62, 0xf1, 0x44, 0x32, 0xc5, 0x5e, 0xda, 0xd6, 0x8c, 0x35, 0x24, 0x66, 0x1, 0x31, 0xc7, 0x1c, 0x29, 0xe3, 0x6b, 0xf6, 0x9c, 0xa1, 0xa7, 0x48, 0x9d, 0x38, 0x12, 0xc, 0xc5, 0xb2, 0xe5, 0x88, 0xe8, 0xec, 0x85, 0xaa, 0x40, 0x43, 0x7c, 0x2f, 0xdb, 0x64, 0xdd, 0x65, 0xbf, 0x99, 0xb5, 0xcd, 0xff, 0xe5, 0x9f, 0x48, 0x70, 0x6, 0x45, 0xd0, 0x94, 0x67, 0xe5, 0xb6, 0xd3, 0xf, 0xf7, 0xc1, 0x9a, 0x1e, 0xe7, 0xf1, 0x18, 0x52, 0xe4, 0xab, 0x35, 0xc1, 0xaa, 0xc5, 0x87, 0xfb, 0x57, 0x32, 0xbe, 0x45, 0xb2, 0xc5, 0x27, 0xc5, 0xdf, 0xd8, 0x84, 0x40, 0xf4, 0xaf, 0xa2, 0x8a, 0x8d, 0x19, 0xb4, 0x8d, 0x15, 0x7, 0xaf, 0x4c, 0xc, 0x46, 0x7c, 0x5c, 0xfc, 0xb4, 0xb0, 0x86, 0x88, 0xcd, 0x3e, 0x61, 0x4a, 0x3c, 0x58, 0x20, 0x13, 0x4f, 0x56, 0x4c, 0xeb, 0xe4, 0xc1, 0xd1, 0xc0, 0x61, 0xf4, 0xb5, 0x15, 0xc3, 0xcd, 0x1a, 0x26, 0x80, 0x70, 0x6d, 0xab, 0x59, 0x8e, 0xe9, 0x13, 0xf2, 0xd9, 0x40, 0x7c, 0x8a, 0xe2, 0x53, 0xac, 0xf8, 0x1b, 0x80, 0x2f, 0x1, 0x13, 0x37, 0x38, 0x30, 0x71, 0x83, 0xad, 0x89, 0x9b, 0x61, 0xf1, 0xcd, 0x98, 0xec, 0xa7, 0x6f, 0xc2, 0xe4, 0x3f, 0xb7, 0xe7, 0x4b, 0xe7, 0xe1, 0x7a, 0xba, 0x4, 0x40, 0x27, 0xa, 0xea, 0x23, 0x15, 0xc9, 0x16, 0x31, 0xf3, 0xe0, 0xcf, 0xbf, 0x42, 0x0, 0x58, 0x44, 0x45, 0xa6, 0xa3, 0x7, 0xc0, 0xef, 0x7f, 0xb0, 0x2f, 0x3e, 0xe1, 0x16, 0xe3, 0x8a, 0x57, 0x60, 0xd3, 0xfe, 0x2d, 0x19, 0x3b, 0xd3, 0x4d, 0xe8, 0x4b, 0x68, 0xfd, 0xe3, 0xc9, 0x52, 0xe9, 0x83, 0x7f, 0xb9, 0x50, 0xa, 0xed, 0xb9, 0xc5, 0xc4, 0xe2, 0x61, 0x8, 0x0, 0xd, 0xde, 0x5f, 0x10, 0x73, 0xce, 0x96, 0x92, 0x20, 0xc5, 0x66, 0xb8, 0x2d, 0xeb, 0x62, 0xdb, 0xb6, 0x8, 0xb2, 0x2c, 0x5e, 0x3f, 0x50, 0xc3, 0x7a, 0xe8, 0x4b, 0xc8, 0xc6, 0x4f, 0x1e, 0x18, 0x1b, 0xbf, 0xdb, 0x80, 0x18, 0x26, 0x5e, 0x40, 0xb, 0x35, 0xd0, 0xaa, 0x8b, 0xb4, 0x3c, 0xf8, 0xc1, 0xb1, 0x85, 0x59, 0x29, 0x56, 0xaa, 0xf5, 0x36, 0xe8, 0xf5, 0xb, 0xa0, 0xdb, 0xab, 0x9f, 0x17, 0x6, 0x15, 0xd0, 0xa8, 0x8c, 0xf8, 0x1b, 0x5e, 0xa7, 0x55, 0xaf, 0x9f, 0x36, 0xa, 0xf5, 0x62, 0xa1, 0xd0, 0x28, 0x15, 0xa6, 0x95, 0x42, 0xf2, 0x62, 0x34, 0xbe, 0x57, 0xcc, 0x93, 0x6a, 0x35, 0xdd, 0xd3, 0x27, 0xab, 0x51, 0x43, 0xad, 0x8d, 0x5a, 0xcd, 0x84, 0x5a, 0xb9, 0xb3, 0xa, 0x39, 0x79, 0x74, 0x71, 0xd1, 0x59, 0xe9, 0x95, 0x5c, 0x11, 0xc1, 0x8a, 0x19, 0x95, 0x5b, 0x7a, 0x4b, 0xc8, 0x6a, 0xd1, 0x8c, 0x29, 0x4a, 0x2e, 0x16, 0x6d, 0x6b, 0xe9, 0x1e, 0x1e, 0xcd, 0xce, 0x16, 0x83, 0xf2, 0x30, 0xde, 0x90, 0xd3, 0x6d, 0x74, 0x7b, 0x77, 0xab, 0xa8, 0xf8, 0x22, 0x55, 0xcc, 0xdd, 0xf, 0xc9, 0x79, 0x3, 0xae, 0x4c, 0x9c, 0xed, 0xc, 0xb3, 0x31, 0x98, 0x3d, 0xc7, 0x97, 0xa8, 0x3d, 0x6d, 0x2c, 0x4b, 0xdd, 0x1e, 0x47, 0x52, 0xc0, 0x83, 0x81, 0xa, 0x63, 0xf, 0xe4, 0x32, 0x55, 0xd6, 0x17, 0xe4, 0xde, 0xe8, 0xe4, 0xaa, 0x9, 0xf5, 0x7e, 0xd5, 0x5e, 0xc, 0x1a, 0x97, 0xb2, 0x24, 0x2f, 0xb3, 0xed, 0xdb, 0xb3, 0x72, 0xe1, 0xd2, 0x80, 0xe5, 0xf1, 0xc3, 0xe9, 0xa8, 0x39, 0xa7, 0xb3, 0x12, 0xb2, 0x57, 0xe5, 0xdc, 0x58, 0x26, 0xd9, 0x5e, 0x2e, 0xcd, 0x91, 0x44, 0x1f, 0x4c, 0xa3, 0x58, 0xb9, 0xcc, 0x5a, 0x85, 0x72, 0x3b, 0x71, 0x9c, 0x58, 0x15, 0x12, 0x93, 0x96, 0x7c, 0xf5, 0x70, 0x7e, 0x49, 0x8b, 0x5a, 0xb2, 0x38, 0x30, 0x6a, 0xa7, 0xbd, 0x79, 0xf4, 0xae, 0x68, 0xd4, 0x46, 0x95, 0x6e, 0xbf, 0xf6, 0x70, 0xbf, 0xaa, 0x25, 0x70, 0xb5, 0xd5, 0x6e, 0xcc, 0x13, 0x8b, 0xd6, 0xb0, 0x78, 0xf5, 0xc0, 0x91, 0x20, 0xa9, 0x32, 0x9a, 0x37, 0xb2, 0xed, 0x52, 0x21, 0x5e, 0xb2, 0x2b, 0x8d, 0x96, 0x5e, 0x4a, 0x40, 0xf9, 0x3e, 0x57, 0x57, 0x7a, 0xcb, 0xf9, 0x7d, 0x4c, 0x82, 0xe3, 0xea, 0xa2, 0x76, 0x56, 0x6a, 0xf6, 0x4a, 0xe7, 0xa3, 0x8c, 0x59, 0x25, 0x70, 0x7e, 0x3c, 0x96, 0xc8, 0x55, 0x2e, 0xd7, 0x3b, 0xad, 0xf7, 0xce, 0x72, 0xf5, 0x3b, 0x8e, 0x64, 0x74, 0x49, 0xf5, 0xec, 0x84, 0xb6, 0x8a, 0x67, 0xea, 0x2a, 0x7d, 0x7f, 0xbf, 0xe8, 0xa3, 0x51, 0xea, 0xd2, 0xee, 0x77, 0x33, 0x97, 0xe3, 0xf4, 0x69, 0xa3, 0x6c, 0x25, 0x56, 0xd9, 0xbe, 0x81, 0x93, 0xd3, 0x5e, 0xac, 0x15, 0x4d, 0xc1, 0xca, 0xc3, 0xcc, 0xee, 0xac, 0xec, 0xb8, 0x14, 0x33, 0x5b, 0x3a, 0xcc, 0xf4, 0x68, 0x94, 0x23, 0xa9, 0x76, 0x27, 0xb0, 0x71, 0x5b, 0x54, 0xc7, 0x97, 0xd2, 0x2d, 0x6e, 0x96, 0x61, 0x66, 0x91, 0x7c, 0xb8, 0xa5, 0xc5, 0x2e, 0xed, 0xc2, 0x49, 0x54, 0x4e, 0xda, 0x84, 0x3c, 0x24, 0xea, 0xa5, 0x26, 0x55, 0xec, 0x39, 0x24, 0xda, 0x71, 0x25, 0x95, 0xc8, 0xf6, 0xa4, 0xa, 0xee, 0xcc, 0x2f, 0xad, 0xe8, 0x72, 0xb5, 0x8c, 0x73, 0x24, 0xf1, 0x91, 0x6, 0x2f, 0xda, 0x25, 0x3a, 0x52, 0x2b, 0xc6, 0x1c, 0x65, 0xe4, 0xf3, 0x52, 0x22, 0x81, 0xa2, 0x92, 0xd2, 0x2d, 0xde, 0x25, 0xeb, 0x35, 0x7a, 0x3e, 0x51, 0xe1, 0xb2, 0x7f, 0x92, 0xeb, 0x5c, 0xf4, 0xe3, 0x9, 0x3c, 0x3f, 0x2f, 0xd0, 0xa8, 0x7e, 0x9c, 0x49, 0x37, 0x6e, 0x6d, 0x5b, 0xae, 0x94, 0xb5, 0xf1, 0x80, 0x23, 0x81, 0x8d, 0xe1, 0xa8, 0x70, 0x7a, 0xbb, 0x28, 0x68, 0x57, 0xcd, 0x58, 0xf2, 0xf6, 0xb8, 0xd2, 0x90, 0xa3, 0x25, 0x62, 0xa8, 0xb3, 0x12, 0x4a, 0x1b, 0x8d, 0x19, 0x5c, 0xdc, 0x6a, 0xed, 0x7a, 0x67, 0x52, 0xea, 0x2b, 0xaa, 0x89, 0xea, 0xdd, 0xe2, 0xac, 0x73, 0x3e, 0x9e, 0xc4, 0x26, 0xd9, 0x58, 0x66, 0xd9, 0x20, 0xfd, 0xfa, 0x15, 0x47, 0x72, 0x77, 0xbe, 0x2a, 0x15, 0x62, 0x85, 0x51, 0x7b, 0x5e, 0xcf, 0xf5, 0x46, 0x7d, 0x49, 0x82, 0xf7, 0xd6, 0x69, 0xb5, 0x58, 0x6d, 0xa9, 0x8d, 0xb1, 0x72, 0x76, 0x57, 0x6a, 0x1b, 0xcd, 0x66, 0x2a, 0x2b, 0xa7, 0x7, 0x24, 0xe, 0x97, 0x9a, 0x3c, 0xaf, 0x5f, 0x95, 0x2a, 0x72, 0x61, 0xd0, 0xe8, 0x18, 0xc7, 0xc7, 0x6d, 0x52, 0xd5, 0x38, 0x92, 0xfa, 0x58, 0x1a, 0xcf, 0x94, 0x3e, 0xa4, 0x4a, 0xb5, 0x98, 0x3a, 0x2f, 0x59, 0xcb, 0xab, 0x73, 0xd5, 0x6e, 0x67, 0xc7, 0x4d, 0x35, 0x96, 0x78, 0x28, 0x36, 0xc8, 0xfd, 0xa0, 0x7a, 0xdb, 0x56, 0x2b, 0xd0, 0x1a, 0x56, 0xcb, 0x3d, 0xbd, 0x5c, 0xd0, 0x9b, 0xca, 0xd5, 0xf8, 0xf2, 0x72, 0x32, 0xb9, 0xa5, 0xa5, 0xc2, 0xb2, 0x52, 0x10, 0xcc, 0x76, 0xc6, 0xd8, 0xbd, 0x58, 0x19, 0xe2, 0x69, 0x27, 0x1b, 0x4d, 0xe, 0x4f, 0x29, 0x4a, 0xdf, 0x37, 0xcc, 0x44, 0xa1, 0x5b, 0x5b, 0x64, 0x2a, 0xb9, 0x64, 0xfb, 0xb6, 0x61, 0xdd, 0xb6, 0xee, 0xba, 0x83, 0x6c, 0x6f, 0x56, 0x2e, 0x35, 0x67, 0x77, 0x85, 0x5a, 0x54, 0xed, 0xd9, 0x25, 0x75, 0x70, 0x3e, 0xce, 0xce, 0xa5, 0x11, 0x47, 0xd2, 0xab, 0x37, 0x71, 0x9a, 0xd4, 0xa6, 0x53, 0xda, 0xa8, 0x96, 0x17, 0xf3, 0x7e, 0x6c, 0x71, 0x5a, 0xa9, 0xf4, 0x4b, 0xc3, 0x54, 0x73, 0x32, 0x2a, 0xde, 0x96, 0xb, 0x97, 0x51, 0x33, 0xda, 0x92, 0xea, 0x99, 0xa9, 0x91, 0x1e, 0xc, 0x63, 0x5, 0x7b, 0x5e, 0xb8, 0x6c, 0xb4, 0x94, 0xca, 0x60, 0x31, 0x9f, 0x90, 0xd6, 0x78, 0x2a, 0x3e, 0x71, 0xee, 0x36, 0x73, 0x11, 0xad, 0xc6, 0x52, 0xf1, 0xd9, 0x49, 0xb2, 0xf1, 0x60, 0x2d, 0x6e, 0x97, 0x9a, 0x5c, 0x5b, 0xd, 0x95, 0xc, 0x84, 0xab, 0xe3, 0x7e, 0x79, 0x26, 0xe9, 0x31, 0xb, 0x76, 0xb5, 0xe8, 0xc9, 0x3, 0xbc, 0x9c, 0x4c, 0x3b, 0xed, 0xa5, 0x76, 0x76, 0xa2, 0x91, 0xa4, 0x64, 0x9f, 0xc5, 0xfb, 0x93, 0xe5, 0xec, 0x52, 0x8c, 0x49, 0xc2, 0x2a, 0xa7, 0x71, 0xeb, 0xe2, 0xb6, 0xd0, 0x6f, 0x9e, 0x27, 0x51, 0x6f, 0x82, 0x52, 0xcb, 0x6c, 0xf6, 0xc2, 0x38, 0x3d, 0x4b, 0x98, 0xa9, 0x7a, 0x75, 0xd4, 0x6a, 0xdb, 0x8d, 0x93, 0x93, 0x58, 0x4f, 0x3e, 0xcf, 0xb4, 0xda, 0xcd, 0xc4, 0x7d, 0xab, 0x56, 0x2c, 0x2c, 0xd5, 0xd8, 0xdc, 0x56, 0xb4, 0xde, 0xc5, 0x28, 0xb9, 0x14, 0xca, 0x27, 0x7d, 0x9c, 0x4d, 0x54, 0x65, 0x49, 0x3b, 0x8e, 0x17, 0xce, 0xc6, 0xa3, 0x8c, 0x34, 0x98, 0x9f, 0xd9, 0xbd, 0x31, 0x1a, 0x9e, 0xcc, 0xeb, 0x45, 0x7a, 0xa1, 0xe7, 0x72, 0xab, 0xca, 0xdd, 0x65, 0xe9, 0x38, 0x33, 0x8b, 0xdb, 0xf4, 0xf8, 0xb4, 0xa9, 0xa5, 0x32, 0xb8, 0xda, 0x8e, 0x15, 0x57, 0x67, 0x8b, 0x73, 0xbd, 0xb2, 0x6c, 0x72, 0x24, 0x57, 0x34, 0xd3, 0x55, 0xa5, 0xda, 0x14, 0x25, 0x55, 0xd4, 0xbf, 0x47, 0x57, 0x17, 0xb3, 0xc5, 0x31, 0xac, 0xc4, 0x7a, 0xd1, 0x5b, 0x2d, 0x7a, 0xae, 0x54, 0x93, 0xca, 0x54, 0xad, 0xeb, 0xf6, 0xac, 0x52, 0x96, 0xec, 0x69, 0xf6, 0xa2, 0x70, 0x3a, 0x4d, 0x65, 0xeb, 0xf3, 0xf2, 0x68, 0xd2, 0x6a, 0x74, 0x3a, 0x85, 0x66, 0xed, 0x9e, 0x23, 0x39, 0x96, 0x4a, 0xed, 0x5a, 0x45, 0x8a, 0x5f, 0xde, 0xdd, 0xd, 0xeb, 0x27, 0xcb, 0x31, 0xb9, 0x3a, 0xed, 0x8f, 0x6, 0xb7, 0xad, 0xd1, 0xe2, 0xa4, 0x19, 0xc3, 0xb1, 0x64, 0x33, 0x21, 0x9d, 0x5c, 0xe8, 0x77, 0xb5, 0xa8, 0x34, 0x2f, 0xd3, 0xe4, 0x72, 0x76, 0x59, 0x1b, 0xeb, 0xd5, 0x8b, 0xd9, 0xb9, 0x4d, 0x2d, 0xda, 0xea, 0x37, 0x72, 0xc2, 0x62, 0x5d, 0xd5, 0xab, 0xc8, 0xb0, 0xab, 0xb3, 0x96, 0xbe, 0xb0, 0x86, 0x27, 0xb1, 0x25, 0x8c, 0xf6, 0xcd, 0xa2, 0x12, 0x8b, 0xdf, 0x4d, 0xca, 0xb7, 0xe9, 0xec, 0x59, 0xad, 0x7c, 0x49, 0x1b, 0x8d, 0x31, 0x4d, 0xa3, 0x41, 0x7b, 0x54, 0x9b, 0xe8, 0x89, 0xb3, 0x66, 0xce, 0xc6, 0xd4, 0x9c, 0xb4, 0xea, 0x30, 0x55, 0x2b, 0x58, 0xc2, 0x8e, 0xbd, 0x8c, 0x8f, 0x3a, 0xb4, 0x70, 0x7e, 0x3f, 0x3d, 0x5e, 0x2d, 0xee, 0xe7, 0x17, 0xe5, 0xb4, 0x1e, 0x2b, 0xf, 0x8f, 0x61, 0xf4, 0xd8, 0x28, 0xd8, 0x69, 0x5c, 0x98, 0xe2, 0xe5, 0xea, 0xbe, 0x7f, 0x85, 0x57, 0x7a, 0x7a, 0x71, 0x3a, 0xac, 0xc4, 0x1f, 0x3a, 0x69, 0xe3, 0xb4, 0x3d, 0x9e, 0xc7, 0xe6, 0xa7, 0x17, 0xe9, 0xdb, 0x61, 0x42, 0x30, 0x5b, 0x3a, 0x47, 0x4d, 0x6b, 0xdc, 0x49, 0xde, 0x9e, 0xe9, 0xc9, 0x4a, 0x2b, 0x9b, 0xca, 0x5d, 0x8e, 0xfa, 0x77, 0xca, 0xdd, 0xf2, 0x72, 0x7a, 0xda, 0x3c, 0xbe, 0x3c, 0xad, 0x8c, 0xda, 0xe3, 0xa2, 0x5c, 0x83, 0xaa, 0x86, 0xeb, 0x9d, 0x45, 0x6f, 0x9a, 0x2b, 0x95, 0x16, 0xe5, 0x7e, 0xa3, 0x9f, 0x69, 0xa5, 0xcc, 0x53, 0xa9, 0x15, 0xe3, 0x48, 0x9a, 0x19, 0x52, 0x7a, 0x50, 0xd3, 0x95, 0x8b, 0xe3, 0x87, 0xe1, 0x38, 0x79, 0x5a, 0x9b, 0xf7, 0x3b, 0x99, 0xf3, 0x94, 0x7d, 0x5f, 0xbf, 0xb2, 0xe3, 0xb4, 0xa2, 0xd8, 0xcb, 0xd4, 0x94, 0x4c, 0xce, 0x12, 0x9d, 0x41, 0xae, 0x19, 0xbd, 0x2b, 0xcf, 0xca, 0x75, 0xc6, 0xe1, 0x67, 0x95, 0x42, 0x76, 0x10, 0xcd, 0x92, 0xf9, 0x89, 0x50, 0x5, 0x67, 0x99, 0x7e, 0xe7, 0x36, 0x41, 0xed, 0x74, 0xa3, 0x71, 0x99, 0xae, 0x45, 0xe1, 0x38, 0x11, 0xeb, 0x2f, 0x6a, 0x95, 0xd2, 0x24, 0x4a, 0xd0, 0xa9, 0x55, 0xcb, 0x5e, 0x4d, 0x9a, 0xc5, 0x51, 0x33, 0x95, 0x1a, 0x91, 0x89, 0x64, 0x5c, 0x2d, 0xef, 0xb2, 0xf8, 0xf2, 0x2c, 0x9e, 0x56, 0xb2, 0x72, 0x2d, 0x73, 0xd2, 0x6d, 0x14, 0x9, 0x47, 0x32, 0x7b, 0x90, 0x7a, 0x57, 0x39, 0x1c, 0xef, 0x27, 0xc6, 0xa3, 0xf9, 0x43, 0xe5, 0xbc, 0xd4, 0x5d, 0xe4, 0xea, 0xfd, 0x93, 0x69, 0xac, 0x5d, 0x28, 0xdd, 0x37, 0x13, 0xca, 0x50, 0xea, 0xb6, 0x8a, 0xba, 0x36, 0xd6, 0xa6, 0xf1, 0x45, 0x77, 0xd6, 0x7a, 0xa8, 0xd8, 0x67, 0xf5, 0xf8, 0x69, 0x67, 0x68, 0xa7, 0xeb, 0xcd, 0xce, 0x65, 0xa5, 0xcd, 0x91, 0x68, 0x75, 0x6d, 0x31, 0xb9, 0xbd, 0xba, 0x34, 0x68, 0x74, 0x9c, 0xed, 0xdc, 0x9e, 0x4d, 0x1f, 0xb0, 0x5c, 0x93, 0xe8, 0xbc, 0x58, 0x94, 0xc7, 0x43, 0xf5, 0x72, 0x90, 0x80, 0xc9, 0xc9, 0x49, 0x2a, 0x3e, 0xb7, 0x4a, 0xd9, 0x13, 0x7c, 0x39, 0x2d, 0x56, 0x73, 0xa7, 0xa3, 0x69, 0xaa, 0x44, 0x2f, 0xb5, 0x49, 0xb7, 0x77, 0x2f, 0x8b, 0x99, 0xb4, 0x3e, 0x80, 0xc9, 0x65, 0xf2, 0xaa, 0x59, 0xb1, 0x2b, 0x25, 0xcd, 0x3a, 0xc5, 0xa8, 0x2f, 0xb5, 0x94, 0xc6, 0x65, 0xb7, 0xb9, 0x1c, 0x9e, 0x2f, 0x12, 0x28, 0x5e, 0x54, 0xdb, 0xfd, 0xb4, 0x1c, 0x3b, 0x7d, 0xb8, 0x5c, 0x19, 0xe9, 0xca, 0xea, 0x32, 0x8a, 0xec, 0xd3, 0xac, 0x5c, 0x42, 0x9, 0x3d, 0x5a, 0xad, 0x8d, 0x7, 0x42, 0x8a, 0xe3, 0xb7, 0xb1, 0x4e, 0xe7, 0xf8, 0x7e, 0x70, 0x36, 0x39, 0x3b, 0x3d, 0x9f, 0xa4, 0xfb, 0xb9, 0x49, 0x5c, 0xeb, 0x3f, 0xdc, 0x2a, 0x35, 0x94, 0x6b, 0x5c, 0x2d, 0x2f, 0x1a, 0xd3, 0xd5, 0xfd, 0x59, 0x4e, 0xb9, 0xca, 0x9d, 0x59, 0x33, 0x12, 0x7f, 0x88, 0x4e, 0x87, 0xed, 0x5c, 0x74, 0x38, 0x6f, 0xa6, 0xe2, 0x13, 0x45, 0xbd, 0xbd, 0x55, 0x85, 0xec, 0x1c, 0x1f, 0x8f, 0xa3, 0xf, 0xb9, 0xae, 0x21, 0xab, 0xb9, 0x86, 0xe4, 0x8c, 0x7c, 0x66, 0x95, 0x3c, 0x59, 0x64, 0x95, 0xee, 0x49, 0xb3, 0xa9, 0x9b, 0x52, 0x2f, 0xda, 0xcf, 0x20, 0x52, 0x68, 0x40, 0xa9, 0x9f, 0x4b, 0xdd, 0x9f, 0xa3, 0x5c, 0xa6, 0x72, 0x5a, 0x3b, 0x1f, 0xce, 0x2e, 0x56, 0x9d, 0xba, 0x24, 0x38, 0xb6, 0x91, 0x3b, 0x57, 0xae, 0x6a, 0x46, 0x7a, 0x8c, 0xb2, 0x17, 0xd2, 0x48, 0xc9, 0xcd, 0xa2, 0xd, 0x9a, 0xbd, 0xc2, 0xc9, 0x4a, 0xb7, 0x87, 0x7, 0x3, 0x78, 0xc2, 0xa6, 0x33, 0x5c, 0x28, 0x2f, 0x95, 0xc6, 0x9, 0xba, 0xb2, 0x92, 0xb9, 0xdb, 0xea, 0x3, 0x6a, 0x1d, 0x57, 0xd5, 0xcc, 0x59, 0xbc, 0xa9, 0xe6, 0xb2, 0x17, 0x62, 0x4c, 0x52, 0xd3, 0x8e, 0x72, 0x3a, 0xaf, 0xf5, 0xcf, 0xb, 0xdd, 0xb8, 0xdd, 0xc8, 0xdc, 0xf5, 0x6f, 0xaf, 0xb2, 0x6a, 0xb7, 0x64, 0x27, 0xf1, 0x70, 0xd4, 0xa3, 0x10, 0x1d, 0x77, 0x29, 0xd4, 0x32, 0x23, 0x25, 0x7d, 0x19, 0xcb, 0xf4, 0xba, 0x52, 0x2b, 0x97, 0x4e, 0x77, 0xd5, 0xe1, 0xc9, 0x6d, 0x4c, 0xd7, 0xcd, 0xd3, 0xdb, 0x33, 0x8e, 0xa4, 0xd2, 0x4e, 0x3e, 0xa0, 0x59, 0x54, 0x93, 0x62, 0x77, 0xb9, 0xc5, 0x1d, 0x1a, 0x17, 0x73, 0xa5, 0xd8, 0x45, 0xf4, 0xa, 0x9f, 0xa6, 0x4d, 0xc3, 0x4a, 0x9f, 0x9f, 0xd7, 0xa, 0x72, 0xe7, 0xec, 0x2c, 0x9d, 0x3b, 0x89, 0xaa, 0xd, 0x65, 0x80, 0x27, 0xc9, 0xcb, 0xd2, 0x62, 0xdc, 0xaa, 0xcf, 0xea, 0x97, 0x83, 0x51, 0x1b, 0x4f, 0xe6, 0x1c, 0x49, 0x8c, 0xd4, 0x17, 0xf1, 0xbb, 0x41, 0x59, 0x9f, 0x3c, 0x3c, 0x2c, 0x8e, 0xc7, 0x53, 0x53, 0x5d, 0x18, 0xc5, 0xd3, 0xae, 0xd1, 0x1d, 0xf5, 0xa4, 0x8e, 0x9c, 0xb9, 0x20, 0x15, 0x63, 0xa5, 0xc4, 0x46, 0xb9, 0xfa, 0x3, 0x46, 0x7a, 0xf3, 0xa, 0x67, 0x7b, 0xba, 0x7d, 0x7b, 0x1e, 0x8d, 0x9e, 0x5c, 0x56, 0xb4, 0xd3, 0x64, 0xaa, 0xc2, 0x91, 0x9c, 0xe4, 0xaa, 0x95, 0x58, 0xad, 0xa3, 0x91, 0x4a, 0x4f, 0xa9, 0x5c, 0x14, 0x62, 0xe3, 0xd6, 0x68, 0xd6, 0xe9, 0xa4, 0x3a, 0x93, 0xde, 0x28, 0x56, 0xeb, 0xb7, 0xec, 0x93, 0x56, 0x21, 0x79, 0x9c, 0x22, 0xb7, 0xfd, 0xa5, 0x18, 0x74, 0x6d, 0x69, 0x8f, 0x31, 0x89, 0xc6, 0xec, 0x16, 0xd2, 0x96, 0x89, 0x9a, 0xe8, 0xce, 0xbc, 0xdb, 0xab, 0x56, 0xa9, 0x42, 0xd4, 0x72, 0x2f, 0x9a, 0xb4, 0x74, 0x7c, 0x51, 0xb5, 0x26, 0xab, 0xf8, 0xf0, 0xa1, 0x54, 0x1e, 0x1d, 0x9b, 0x99, 0x73, 0x38, 0xc9, 0xa2, 0x8e, 0x51, 0x5f, 0x65, 0x87, 0x67, 0x1a, 0xb4, 0x2a, 0x45, 0xba, 0x9a, 0x77, 0x8e, 0xb3, 0x3d, 0xb3, 0x21, 0x2f, 0x26, 0xb9, 0x91, 0x29, 0xb, 0x1, 0xbc, 0x18, 0xf6, 0xcf, 0x4f, 0xd1, 0xe2, 0x6e, 0x7c, 0x9c, 0xce, 0xd4, 0xba, 0x77, 0x39, 0x23, 0x3d, 0x19, 0x3c, 0xa4, 0xed, 0x7e, 0xf7, 0x72, 0x79, 0x75, 0xdc, 0x68, 0x5f, 0x35, 0xab, 0x97, 0xe7, 0x27, 0xe7, 0xb7, 0xf, 0x93, 0xfb, 0x8b, 0x56, 0x4c, 0x59, 0x98, 0xdd, 0xc, 0x2a, 0x66, 0x6, 0x97, 0x8d, 0xda, 0x4c, 0xab, 0x66, 0xac, 0xdc, 0x82, 0x23, 0xc9, 0xa4, 0x47, 0xcb, 0x44, 0xbf, 0x38, 0xe8, 0x8c, 0xeb, 0xb9, 0x66, 0xa9, 0x9d, 0xb8, 0x5d, 0x9d, 0x6b, 0x98, 0x96, 0xe5, 0xce, 0x71, 0x25, 0x9e, 0xa8, 0x1c, 0x9f, 0x9f, 0x8f, 0xbb, 0x1d, 0xa3, 0x14, 0x4f, 0x4b, 0x8d, 0xf8, 0x38, 0x1b, 0x23, 0xf2, 0xe5, 0xb0, 0x4b, 0xcf, 0x8e, 0xa5, 0x66, 0xfd, 0xc1, 0xb2, 0xa3, 0xc3, 0xba, 0x98, 0x1, 0x8d, 0xe4, 0x6c, 0xb5, 0xba, 0xb7, 0xa7, 0xe9, 0xe3, 0xc4, 0xc5, 0x83, 0x3e, 0xb0, 0xac, 0xcb, 0xf6, 0xa8, 0x21, 0xcf, 0x8e, 0x73, 0xf5, 0x45, 0x69, 0x6a, 0xa6, 0x9a, 0x2b, 0xa9, 0x6d, 0xf, 0x17, 0xcb, 0xe3, 0x7b, 0xa3, 0x75, 0x52, 0xb8, 0xba, 0x9d, 0x2e, 0x2f, 0x8b, 0x76, 0xa2, 0xd8, 0x30, 0xda, 0xc9, 0xca, 0x3c, 0x3b, 0x2a, 0x8, 0x1, 0x54, 0x66, 0x77, 0xfa, 0xfc, 0x7c, 0x81, 0x4a, 0x83, 0xa9, 0x5d, 0x31, 0xcf, 0x4e, 0x32, 0xd9, 0xba, 0x5a, 0x2d, 0x8e, 0xeb, 0xf3, 0xa1, 0x79, 0x9c, 0x1d, 0x14, 0xc6, 0xd, 0x7a, 0x91, 0x9c, 0x4d, 0xa7, 0x95, 0x8b, 0xfb, 0xf3, 0xe4, 0x79, 0x2c, 0xb3, 0x2a, 0xe8, 0xa7, 0xb4, 0xf2, 0x90, 0x4e, 0x8d, 0x7, 0x96, 0xaa, 0xdc, 0xd, 0x6e, 0xc5, 0x84, 0x5e, 0x5b, 0x3d, 0x50, 0xce, 0xee, 0xc5, 0xea, 0x6c, 0x91, 0x9e, 0x46, 0xe3, 0x4a, 0xae, 0x37, 0x9d, 0xc4, 0xe4, 0x71, 0xb1, 0x69, 0xe8, 0xf4, 0x78, 0x81, 0xd4, 0xf4, 0xc5, 0xf8, 0x3e, 0x71, 0x9f, 0x96, 0x63, 0x7d, 0xc3, 0x32, 0xb4, 0xe9, 0x48, 0x9a, 0xb7, 0xd4, 0x5e, 0xe6, 0x14, 0x21, 0x59, 0x6d, 0xa5, 0x4, 0x92, 0xcb, 0x68, 0xa5, 0xf8, 0xf0, 0xa0, 0x27, 0x8d, 0xd3, 0xaa, 0x11, 0xcf, 0x5c, 0xc2, 0x33, 0x9c, 0x50, 0x27, 0xe7, 0xc5, 0xfb, 0x55, 0x25, 0x19, 0xab, 0x8d, 0x6, 0x35, 0x7c, 0x75, 0x7e, 0x72, 0x76, 0x92, 0x68, 0x46, 0xb3, 0x3d, 0x1a, 0xcb, 0x5e, 0x56, 0x1b, 0xc5, 0xbb, 0xe2, 0xbd, 0x7a, 0x5b, 0x4f, 0x1a, 0x97, 0xe6, 0xc5, 0xd2, 0x51, 0xd4, 0xbd, 0xd6, 0x64, 0xb5, 0x4a, 0xa8, 0x85, 0xbb, 0xc5, 0xe9, 0x62, 0xd6, 0x92, 0xb2, 0xf1, 0x42, 0x6c, 0x86, 0xcf, 0x93, 0x27, 0xad, 0xfb, 0xa4, 0x34, 0xc1, 0xc9, 0xfb, 0xd8, 0x69, 0xa7, 0x2d, 0x49, 0xfd, 0x3a, 0xa9, 0xdb, 0xb4, 0xaf, 0x3e, 0xdc, 0x76, 0xea, 0xc9, 0x7, 0xa5, 0x59, 0xb1, 0x8c, 0xb2, 0x72, 0xd1, 0x7b, 0x80, 0x1c, 0xc9, 0xf4, 0x38, 0x35, 0x9b, 0x5b, 0xa5, 0x45, 0xb3, 0x32, 0x46, 0x9d, 0xf2, 0xe4, 0xf2, 0xfc, 0x54, 0x1b, 0xd, 0x49, 0xfb, 0xf2, 0xec, 0x42, 0x55, 0xb4, 0xcc, 0x24, 0x4b, 0x68, 0x59, 0xcb, 0xa2, 0x55, 0xb3, 0x55, 0x5f, 0xa6, 0x8e, 0x5b, 0xa5, 0x6a, 0x67, 0x4a, 0xcd, 0xab, 0xee, 0x68, 0xaa, 0xd3, 0x72, 0xe2, 0xee, 0xbe, 0x20, 0xe6, 0xe2, 0x45, 0x7f, 0xba, 0x38, 0xe9, 0xcf, 0x52, 0xe4, 0xa, 0x96, 0x71, 0x21, 0x79, 0x12, 0xb7, 0x6a, 0x28, 0x31, 0x39, 0x2b, 0x3e, 0xcc, 0xea, 0xc3, 0x55, 0xed, 0x2c, 0x6b, 0x25, 0xef, 0xd5, 0x87, 0x64, 0x32, 0x73, 0x55, 0x94, 0xc9, 0xc3, 0x22, 0xd3, 0x8c, 0x59, 0x8d, 0x8b, 0xab, 0x8b, 0x69, 0x45, 0x9a, 0xa4, 0xb4, 0xea, 0xc3, 0xd4, 0x16, 0x86, 0x5f, 0xf1, 0xae, 0x3d, 0x9e, 0x25, 0x57, 0xb1, 0xc9, 0xc5, 0x6d, 0xb6, 0xab, 0x1a, 0xd1, 0x95, 0x45, 0x6, 0xfd, 0xe2, 0x54, 0x29, 0xd6, 0xaf, 0x14, 0x7b, 0x7e, 0x5b, 0x20, 0xf5, 0x62, 0xa1, 0xd2, 0x3c, 0xed, 0xf6, 0xcf, 0x4f, 0x74, 0x75, 0x12, 0x9d, 0x2e, 0xd2, 0x9d, 0x8b, 0x5e, 0xa9, 0xb6, 0x6a, 0xdc, 0xdf, 0xd9, 0xd5, 0x5b, 0xc1, 0x6c, 0x93, 0x8a, 0x1e, 0xad, 0x64, 0xc7, 0xcb, 0xd4, 0x45, 0xff, 0xae, 0x25, 0xdf, 0x46, 0x33, 0x4b, 0xdc, 0x3f, 0x25, 0xf, 0xa6, 0x34, 0xca, 0x92, 0xd5, 0xc5, 0xad, 0x75, 0x71, 0xd9, 0x19, 0xab, 0xb8, 0xd9, 0x3b, 0xbb, 0x94, 0x2b, 0xb3, 0x52, 0x76, 0x99, 0x50, 0x9b, 0xad, 0xdb, 0xf6, 0x9d, 0x7e, 0xf2, 0x70, 0xd6, 0x29, 0xd4, 0x33, 0x94, 0x23, 0xe9, 0xc0, 0x74, 0xf1, 0xac, 0x8b, 0xa7, 0x77, 0xab, 0xcb, 0xab, 0xee, 0x65, 0x35, 0x55, 0x6d, 0x1c, 0x9f, 0x4b, 0x3, 0x75, 0x38, 0x5a, 0x5c, 0x9d, 0xe9, 0x39, 0x3a, 0x29, 0xdd, 0x25, 0x47, 0xa5, 0xfb, 0x61, 0xb1, 0x6d, 0x9d, 0x25, 0xab, 0xb5, 0x71, 0xa3, 0xa1, 0x26, 0x4e, 0xaa, 0x67, 0xcd, 0x84, 0x79, 0x8a, 0xed, 0x13, 0x33, 0x5d, 0x15, 0x94, 0x9c, 0xcb, 0xc8, 0xb2, 0xcb, 0x27, 0xed, 0x12, 0xae, 0x57, 0x47, 0xe3, 0xe1, 0xc9, 0xf1, 0x14, 0x9f, 0xc6, 0xe5, 0x4a, 0x3b, 0x1, 0xa3, 0x67, 0xc7, 0x99, 0x49, 0x2f, 0x7d, 0x9e, 0xbc, 0x2f, 0x65, 0xce, 0xcb, 0x4a, 0xf3, 0xb8, 0x78, 0xd7, 0x92, 0x72, 0xcb, 0xab, 0x74, 0x2f, 0x97, 0xad, 0x26, 0xb3, 0x97, 0xf, 0xa5, 0x46, 0xc3, 0x10, 0x66, 0xf9, 0xbc, 0x6d, 0x54, 0x26, 0xda, 0xe2, 0x14, 0xdb, 0xf3, 0x9c, 0x75, 0x72, 0x72, 0xb6, 0x2c, 0x77, 0x2f, 0xe4, 0xb3, 0xb4, 0xbd, 0xaa, 0xdd, 0x21, 0xda, 0x88, 0x5e, 0xe0, 0x25, 0x22, 0x29, 0x7d, 0x96, 0x5a, 0xc5, 0xaf, 0xba, 0xd8, 0x58, 0xca, 0x63, 0xc9, 0x2e, 0x92, 0x51, 0xe7, 0xac, 0x96, 0x96, 0xda, 0x77, 0x15, 0x61, 0x9f, 0xa4, 0x5b, 0x97, 0xbd, 0xf3, 0xb6, 0x62, 0x35, 0xec, 0xdb, 0x5b, 0x35, 0x76, 0x79, 0x35, 0xaf, 0x4a, 0xa9, 0x44, 0x7b, 0x21, 0x3f, 0x44, 0x47, 0x93, 0x93, 0xb4, 0x7a, 0x72, 0x5b, 0x46, 0xf3, 0xe5, 0x74, 0xa2, 0xe4, 0xb4, 0x64, 0x6e, 0x1c, 0xa5, 0x52, 0xa5, 0x3a, 0x30, 0xd5, 0xcc, 0x43, 0xee, 0x21, 0x3b, 0xfa, 0x6d, 0xbd, 0xa8, 0xaa, 0xb4, 0xcb, 0xc1, 0x4b, 0xaa, 0xed, 0x95, 0xe8, 0xd6, 0x42, 0x34, 0x60, 0x1d, 0xfa, 0xca, 0x65, 0xa8, 0x2, 0x2d, 0x38, 0x86, 0x14, 0x9, 0xa7, 0x0, 0x9e, 0x78, 0x8e, 0x4e, 0xe0, 0xbe, 0x1, 0x98, 0x72, 0xf7, 0xe5, 0x77, 0xee, 0xe4, 0x3d, 0xb2, 0x56, 0x6, 0x3a, 0xe2, 0x1b, 0x2a, 0x6e, 0x4d, 0xee, 0xf7, 0xe0, 0x5b, 0x1, 0x13, 0xac, 0xaa, 0xdc, 0xc9, 0x28, 0x13, 0x5d, 0x47, 0x32, 0xdf, 0x45, 0xc2, 0xfa, 0x84, 0x98, 0x9a, 0xe3, 0xa2, 0xc4, 0xba, 0xf, 0x8c, 0x2d, 0x49, 0xf9, 0x56, 0x1, 0x0, 0xc, 0x69, 0x1e, 0x60, 0x5d, 0xbc, 0x61, 0xeb, 0x61, 0xe7, 0x4f, 0xc7, 0xd7, 0xb8, 0x5e, 0x1d, 0x3f, 0xb6, 0x3e, 0x56, 0xc6, 0x4e, 0x95, 0x47, 0x56, 0xc8, 0x8f, 0xae, 0x91, 0x59, 0x3f, 0xb8, 0xb7, 0xdc, 0x36, 0x90, 0x69, 0x53, 0x64, 0x2, 0xd7, 0xed, 0x5, 0xc8, 0xc4, 0x1b, 0x10, 0xa1, 0x43, 0xd7, 0xfe, 0x26, 0x79, 0x6, 0xf5, 0x29, 0xc2, 0x96, 0xe3, 0x16, 0xf2, 0x3b, 0x76, 0xdc, 0xcd, 0x2d, 0x67, 0x2b, 0xe2, 0x11, 0xd7, 0xce, 0x61, 0xe7, 0xce, 0xa6, 0x7b, 0x67, 0xc7, 0xc1, 0xb3, 0xe3, 0xe2, 0xd9, 0xe3, 0xe4, 0x9, 0x70, 0xf3, 0x4, 0x32, 0x4e, 0x10, 0xeb, 0x6c, 0x31, 0xf, 0xf0, 0x98, 0x45, 0xb4, 0x37, 0x13, 0x3e, 0xd0, 0x58, 0x2e, 0x1e, 0x89, 0xa5, 0xb3, 0x11, 0x29, 0x12, 0x13, 0xbd, 0x33, 0x84, 0xeb, 0x33, 0x95, 0x4c, 0x38, 0xbe, 0x34, 0x77, 0x2f, 0x3e, 0xf, 0x8e, 0xd8, 0x9f, 0x47, 0xdb, 0x23, 0xea, 0xfe, 0x79, 0xe4, 0x78, 0xc7, 0x4c, 0x54, 0x76, 0xd9, 0x14, 0x1c, 0xb9, 0xce, 0x6d, 0xe7, 0xa5, 0xa, 0xb1, 0xe9, 0x7b, 0xcb, 0x7f, 0x3b, 0x3e, 0x64, 0x62, 0x41, 0x73, 0xd5, 0xe7, 0xbe, 0x43, 0x5f, 0xd, 0xf1, 0xf8, 0xda, 0xef, 0x53, 0x74, 0x6a, 0xe2, 0xa9, 0x1e, 0x58, 0x93, 0x3f, 0x3f, 0xa, 0x85, 0x42, 0x6e, 0xd3, 0x87, 0x3d, 0x36, 0x6e, 0xcd, 0xb0, 0x31, 0x23, 0x16, 0x67, 0x71, 0x87, 0x2b, 0x17, 0xf1, 0x48, 0x3a, 0x12, 0xf, 0x7, 0xec, 0x12, 0x1d, 0xe0, 0xcd, 0x99, 0x65, 0x19, 0xfd, 0x47, 0x7d, 0x38, 0x2a, 0x99, 0x36, 0xd1, 0x2, 0xa9, 0x79, 0x2e, 0x73, 0xa1, 0x2f, 0x7c, 0x63, 0x3, 0xe9, 0x16, 0x20, 0xb6, 0x5, 0x88, 0x2e, 0x36, 0x37, 0x66, 0x8, 0x8c, 0x11, 0xdf, 0x27, 0x20, 0xec, 0x33, 0x88, 0x9d, 0x16, 0x59, 0x25, 0xb6, 0xf2, 0xb, 0x5, 0xc2, 0x35, 0xea, 0xf2, 0x68, 0x84, 0x29, 0x18, 0xf1, 0xc8, 0xd9, 0x87, 0x75, 0xb4, 0xd0, 0x54, 0x5e, 0x6f, 0xba, 0xcd, 0xd1, 0x6a, 0x82, 0x55, 0xbe, 0x91, 0xea, 0x3e, 0x1a, 0xdb, 0xf2, 0x9c, 0x51, 0xb9, 0x7e, 0x22, 0xcf, 0x6c, 0x7d, 0xee, 0xf8, 0xea, 0x53, 0xf1, 0x64, 0x3c, 0x9b, 0x95, 0x9c, 0x77, 0x34, 0xe1, 0x61, 0x62, 0x43, 0xc6, 0xfd, 0xc1, 0x1e, 0x98, 0x90, 0x88, 0x39, 0x5a, 0xf9, 0x1f, 0x8a, 0xee, 0x6e, 0x3d, 0xdc, 0x6d, 0xd2, 0xd9, 0x67, 0xf1, 0xf6, 0x20, 0xf8, 0x63, 0xf8, 0x60, 0x9b, 0x28, 0xef, 0x43, 0x4f, 0x6c, 0xdd, 0x72, 0x18, 0xf1, 0x68, 0xeb, 0xf1, 0x56, 0xb, 0x32, 0x71, 0x82, 0x4f, 0x1c, 0x8f, 0xb2, 0x49, 0x88, 0x55, 0x62, 0x6c, 0xbd, 0xe3, 0x2a, 0x2b, 0x55, 0x7a, 0x83, 0xfa, 0x49, 0xbd, 0x54, 0x18, 0x54, 0x36, 0xdc, 0x64, 0x15, 0xe9, 0xa1, 0x54, 0x2a, 0x98, 0xf6, 0xb4, 0xb0, 0xac, 0x17, 0xb, 0xd3, 0xfa, 0x69, 0xa1, 0x3e, 0xa5, 0x89, 0xfe, 0xf1, 0x8c, 0xde, 0xce, 0xb4, 0x56, 0x41, 0xaa, 0x96, 0xfa, 0x77, 0xd5, 0x7e, 0x7d, 0x9c, 0x28, 0x9f, 0x55, 0x8a, 0xa5, 0xe5, 0xb0, 0xd0, 0x2a, 0x14, 0x96, 0xb5, 0x99, 0xdc, 0x6e, 0xd, 0x64, 0xb1, 0xac, 0x6d, 0xd, 0xa, 0xa9, 0xd6, 0x40, 0x5e, 0xb5, 0x1f, 0xce, 0x52, 0x17, 0xec, 0xc5, 0xad, 0x7c, 0xdf, 0x1a, 0x14, 0x12, 0xde, 0xb3, 0xdb, 0x42, 0xa1, 0x55, 0xaf, 0x97, 0xea, 0xb7, 0x85, 0x76, 0x71, 0x3a, 0xbf, 0x9b, 0xcd, 0x71, 0x35, 0xb7, 0x94, 0x8a, 0x85, 0xb3, 0xca, 0x49, 0xa1, 0xd0, 0x29, 0x89, 0xc5, 0xe4, 0x34, 0xcb, 0x2b, 0x95, 0xa6, 0x9f, 0xe, 0xbb, 0x4f, 0x87, 0xdd, 0xff, 0x1c, 0x87, 0x1d, 0x6c, 0x9f, 0xb5, 0x2a, 0xc9, 0x65, 0xed, 0x6c, 0x54, 0x3e, 0xef, 0x49, 0x9d, 0x62, 0x71, 0x54, 0x39, 0x29, 0xb5, 0x46, 0xa3, 0x56, 0xa7, 0x29, 0x55, 0xa2, 0xc3, 0xd5, 0x6d, 0x6a, 0x49, 0x51, 0x79, 0x52, 0x57, 0x33, 0x24, 0x59, 0x69, 0xd2, 0x56, 0x31, 0x5b, 0x2d, 0xc4, 0x86, 0x4a, 0x7d, 0x79, 0x36, 0x6a, 0x15, 0xa1, 0x40, 0xf2, 0x28, 0x40, 0x61, 0xc9, 0x1, 0x2a, 0xcb, 0xb3, 0x93, 0x56, 0xa1, 0x55, 0x2c, 0x4c, 0xb2, 0xcb, 0xf2, 0xd9, 0xe8, 0xb4, 0x41, 0xae, 0xea, 0xb3, 0x85, 0xdc, 0x2e, 0x9c, 0x39, 0x16, 0x64, 0xf1, 0xac, 0x50, 0x9e, 0x4e, 0xeb, 0xc5, 0x42, 0xb1, 0x9a, 0x9d, 0x74, 0x17, 0xa6, 0xd9, 0x3b, 0x46, 0xa6, 0xb1, 0x3c, 0x3b, 0xb1, 0x8b, 0xd1, 0x54, 0xfa, 0x36, 0x8e, 0xd3, 0xb4, 0x73, 0x7c, 0x47, 0x3a, 0xa7, 0x5d, 0xa3, 0xd0, 0x1a, 0x2d, 0xe7, 0xf, 0xf5, 0x92, 0x39, 0x90, 0x10, 0x32, 0x2f, 0xa, 0x70, 0xb1, 0x24, 0x2b, 0x61, 0x10, 0x4b, 0xc3, 0x42, 0xa3, 0x9d, 0x91, 0x87, 0xa8, 0x72, 0x7a, 0x79, 0x5b, 0xef, 0x65, 0x68, 0xa6, 0x44, 0xa6, 0xd5, 0x13, 0x7c, 0x7b, 0xa1, 0xc0, 0xb, 0x78, 0x46, 0x2f, 0x87, 0x65, 0xe9, 0xe1, 0xf4, 0x2e, 0x5, 0x89, 0xd5, 0x1c, 0x5d, 0x35, 0xb1, 0x56, 0x91, 0x63, 0x1d, 0xc9, 0x2e, 0x68, 0xa7, 0x15, 0x3a, 0x19, 0x9, 0x55, 0xb0, 0xc8, 0x68, 0x55, 0x29, 0x83, 0x86, 0xe9, 0x29, 0x8a, 0xc7, 0x69, 0x9f, 0xa4, 0x66, 0xf7, 0xb3, 0x73, 0x43, 0xad, 0x5a, 0xa9, 0xf8, 0x4c, 0xbf, 0xd4, 0x7, 0x52, 0x59, 0x99, 0xf6, 0x7b, 0x57, 0xc6, 0x5d, 0x5c, 0x5b, 0x4c, 0x95, 0x9c, 0x2a, 0x13, 0xa3, 0x80, 0x95, 0xd6, 0x71, 0xa3, 0xa6, 0x42, 0x48, 0x2f, 0xc5, 0x2a, 0xbd, 0x8e, 0xe4, 0x5a, 0xa3, 0x95, 0xcb, 0x35, 0x2e, 0x73, 0xe5, 0x2c, 0xd5, 0x4c, 0xa9, 0x20, 0x9f, 0xa5, 0x5b, 0xd1, 0xd1, 0x74, 0x3c, 0x89, 0xdf, 0xdd, 0x76, 0x72, 0xa3, 0x9e, 0x66, 0x14, 0xeb, 0xb7, 0xab, 0xb3, 0x8b, 0xa, 0x9c, 0xa3, 0xe4, 0x2a, 0x9a, 0x6c, 0x5e, 0x68, 0xc7, 0x89, 0xe3, 0x85, 0x94, 0x45, 0xf2, 0x34, 0x59, 0x74, 0x16, 0x4e, 0xb8, 0x55, 0x92, 0x7a, 0xcb, 0xd8, 0x99, 0xdc, 0xbd, 0x9b, 0x2e, 0x61, 0x15, 0x5e, 0xd8, 0x99, 0x58, 0xcf, 0x1a, 0xcd, 0x56, 0x83, 0x69, 0xa6, 0xaf, 0x17, 0xe6, 0xfa, 0x38, 0xa5, 0x17, 0xe5, 0x5a, 0x7d, 0xdc, 0x1c, 0x4b, 0x33, 0xa5, 0x39, 0x3d, 0x1b, 0xc0, 0xc4, 0x95, 0x62, 0x5d, 0x4e, 0xef, 0xe4, 0x59, 0x5d, 0xd8, 0x35, 0x55, 0xfb, 0x44, 0xad, 0x14, 0xb5, 0xda, 0xc9, 0x55, 0x37, 0x3d, 0x6e, 0x9e, 0x76, 0x7a, 0xbd, 0xe1, 0x99, 0x4, 0x4d, 0x9c, 0x5a, 0x1a, 0x97, 0x75, 0x3a, 0x9a, 0x98, 0xc5, 0xe4, 0x20, 0xdb, 0x5d, 0x8d, 0x7, 0xf, 0xb, 0x98, 0xe8, 0x94, 0x5a, 0x6a, 0x85, 0xb6, 0x6e, 0xed, 0x15, 0x3d, 0x31, 0x73, 0x68, 0x39, 0x7b, 0x10, 0x9a, 0x2d, 0x37, 0xac, 0x36, 0x71, 0xff, 0xac, 0x5d, 0x5e, 0x35, 0xa, 0x31, 0xe9, 0x34, 0x7b, 0xb1, 0x54, 0x1f, 0xc6, 0xa8, 0x2c, 0x15, 0xa, 0x17, 0xb9, 0x64, 0x72, 0x76, 0x91, 0x2c, 0x8f, 0xa7, 0xe9, 0xfe, 0xc5, 0x22, 0x39, 0x2d, 0x90, 0x54, 0x6c, 0x70, 0x9c, 0x2e, 0xd8, 0xf3, 0x9e, 0x62, 0x1b, 0xa9, 0x55, 0x5a, 0x9d, 0x9c, 0xa5, 0xc4, 0x3a, 0x70, 0x96, 0x6c, 0x8e, 0x49, 0xda, 0x78, 0x80, 0x85, 0x44, 0x3a, 0x57, 0xa7, 0xa7, 0x45, 0xdd, 0x5a, 0x34, 0x16, 0x18, 0xa6, 0x67, 0xc3, 0x49, 0xb4, 0x3f, 0x9d, 0xe9, 0xe3, 0x6a, 0xc6, 0x28, 0xd5, 0x2e, 0xa3, 0x85, 0xa, 0x56, 0xe5, 0xe9, 0x60, 0x1c, 0x4b, 0xd4, 0x74, 0xe5, 0x24, 0x5a, 0x3d, 0xce, 0xc0, 0xab, 0x69, 0x43, 0xa8, 0x47, 0xd, 0xe7, 0xee, 0x16, 0xed, 0x5e, 0xbf, 0x4c, 0x2b, 0xd1, 0xa2, 0x39, 0xbd, 0x82, 0x4b, 0xb2, 0x30, 0xb2, 0xb1, 0xe3, 0xdb, 0x34, 0x6c, 0x26, 0x57, 0xe9, 0xa1, 0x75, 0x39, 0xa2, 0x46, 0xcd, 0x3c, 0xee, 0xdb, 0x17, 0xb4, 0x31, 0xa2, 0xb0, 0x96, 0x31, 0xd4, 0x54, 0x8d, 0x1a, 0xed, 0xd2, 0xea, 0x34, 0xb5, 0x38, 0x17, 0xea, 0x51, 0x31, 0x4e, 0xb, 0x4b, 0x42, 0x4f, 0x8a, 0x77, 0xfd, 0x8a, 0x5e, 0x4f, 0x24, 0x12, 0xcb, 0x82, 0xad, 0x1b, 0xad, 0x91, 0x86, 0xa3, 0xb7, 0x8d, 0x5a, 0x2d, 0x7a, 0x9b, 0xbc, 0xb8, 0xbb, 0x6d, 0xea, 0xa5, 0xba, 0x6e, 0x48, 0xd1, 0x25, 0xb1, 0x1f, 0x46, 0x76, 0x32, 0xae, 0x66, 0xbb, 0xda, 0x43, 0x2a, 0x17, 0x2b, 0xf6, 0xc5, 0xc2, 0xe9, 0x14, 0x4e, 0x53, 0x92, 0x34, 0xae, 0x14, 0xef, 0xef, 0xea, 0xf1, 0x5e, 0xb3, 0xd2, 0x9c, 0xb6, 0xac, 0xe8, 0x78, 0xa8, 0xdc, 0x1a, 0xc9, 0x76, 0xbc, 0x95, 0xd1, 0xcc, 0x7b, 0xc5, 0x6c, 0x1f, 0xc7, 0x53, 0x99, 0x5c, 0x6d, 0xf0, 0x30, 0x4e, 0xd7, 0x16, 0xd8, 0xce, 0x6d, 0xae, 0x75, 0x2, 0xe6, 0xc4, 0x97, 0xed, 0x94, 0xfa, 0xcd, 0xe9, 0xd7, 0xee, 0x93, 0xa6, 0xde, 0x6c, 0x9f, 0xf4, 0xcb, 0x17, 0x50, 0xe1, 0xf1, 0x12, 0x4e, 0xf4, 0x85, 0x82, 0x29, 0x90, 0xa1, 0x3c, 0xc3, 0xfa, 0x94, 0x2d, 0x79, 0xfc, 0x21, 0x19, 0xac, 0x36, 0xaf, 0xe0, 0x60, 0x87, 0x8a, 0x62, 0x72, 0xa3, 0x56, 0xc1, 0x34, 0xcc, 0xd, 0xe8, 0x74, 0x22, 0x93, 0x13, 0x4b, 0x2a, 0xa0, 0x8c, 0xf3, 0x20, 0xfe, 0xb2, 0x75, 0x1d, 0xb7, 0x83, 0x83, 0x2, 0x39, 0xf6, 0xd8, 0xad, 0xab, 0xe5, 0x3c, 0x9e, 0x4a, 0xc4, 0x24, 0x29, 0xca, 0x21, 0x83, 0xec, 0x56, 0x29, 0x12, 0x7b, 0xb6, 0xdd, 0xfa, 0x9a, 0xf5, 0xec, 0x17, 0x60, 0x4c, 0x7b, 0xaf, 0x58, 0xd, 0x6f, 0x30, 0x8e, 0x31, 0x2d, 0xbf, 0x21, 0xeb, 0xfc, 0xec, 0x2d, 0xf6, 0x3e, 0xb2, 0x2c, 0xac, 0x4f, 0x45, 0xb0, 0x94, 0xe0, 0x37, 0x5, 0x19, 0x48, 0x57, 0x90, 0x2e, 0xaf, 0x78, 0xe0, 0x25, 0x45, 0x28, 0x28, 0x60, 0x79, 0x1d, 0x49, 0x13, 0xe5, 0xdf, 0x90, 0x6e, 0x4, 0x2d, 0x53, 0x8b, 0xf1, 0x4a, 0x94, 0x23, 0x64, 0x48, 0x18, 0xf6, 0x89, 0x6d, 0x5a, 0x33, 0x64, 0x3a, 0x31, 0xa, 0xb6, 0xc9, 0x63, 0x24, 0x23, 0x21, 0x87, 0x87, 0xbf, 0x80, 0xa1, 0xa1, 0x40, 0xb, 0xf1, 0x40, 0x30, 0xa4, 0xb8, 0xdc, 0x2e, 0x6b, 0x22, 0xdc, 0x54, 0x44, 0x4b, 0x52, 0x41, 0xe2, 0xb5, 0x6d, 0xaa, 0x0, 0x4f, 0xd8, 0xb2, 0xc3, 0x8d, 0xd6, 0xd8, 0x9, 0x19, 0x5, 0xfe, 0xb7, 0x6e, 0x84, 0x17, 0x5b, 0xe5, 0xd9, 0x8c, 0x40, 0xf1, 0xf9, 0x3c, 0x8e, 0x76, 0xdf, 0xa, 0xea, 0x9d, 0xef, 0xec, 0xf, 0xf1, 0xfb, 0x2, 0x6, 0x9d, 0x72, 0x27, 0xf, 0x6, 0x33, 0x64, 0x72, 0x3f, 0x6, 0xd7, 0x30, 0x1a, 0xc0, 0x94, 0xda, 0x28, 0xf, 0x4a, 0x50, 0xff, 0xc5, 0x2, 0xc4, 0x40, 0x82, 0x68, 0x68, 0xb0, 0x11, 0xc, 0x13, 0x5d, 0x5d, 0x1, 0xb1, 0xa6, 0xe9, 0x22, 0x53, 0xc3, 0x94, 0x62, 0xa2, 0x3, 0x5, 0xe9, 0x18, 0x29, 0x1e, 0x46, 0xe7, 0x3, 0x0, 0xcc, 0x69, 0xe7, 0x84, 0x8, 0xfc, 0x16, 0xd2, 0xc, 0x1e, 0x73, 0x5, 0x4d, 0x62, 0xeb, 0x4a, 0x4, 0x80, 0xb, 0xac, 0xaa, 0xc0, 0x44, 0xe1, 0x5, 0xa6, 0xac, 0xf6, 0xc, 0x53, 0x60, 0x98, 0x64, 0xac, 0x22, 0x2d, 0x12, 0x72, 0xd7, 0x2a, 0x1b, 0x1d, 0xa, 0x89, 0x75, 0x67, 0x90, 0xf0, 0xae, 0xe3, 0x9b, 0xe, 0x3b, 0x45, 0x4, 0x96, 0xb0, 0x0, 0xf1, 0xcb, 0xb3, 0x2b, 0xd1, 0x52, 0x24, 0xb5, 0x5f, 0xa2, 0x1f, 0x8f, 0x25, 0xe0, 0x2b, 0xe2, 0xe7, 0x91, 0xc1, 0x41, 0xde, 0x96, 0xc, 0x36, 0x3e, 0xb, 0xb7, 0xe9, 0x76, 0x67, 0x50, 0xe8, 0x8d, 0xae, 0xfb, 0xf5, 0x6a, 0xbb, 0xd2, 0xbb, 0x2e, 0x57, 0x4e, 0xa, 0xc3, 0xe6, 0xa0, 0xd0, 0xac, 0x17, 0xfa, 0x79, 0x37, 0xb6, 0x16, 0xaa, 0x18, 0x52, 0xc7, 0x5, 0xb2, 0x2f, 0x30, 0xb0, 0xcd, 0xc9, 0x5, 0xc2, 0x17, 0x10, 0x11, 0x1f, 0xf, 0xda, 0x16, 0x1, 0x6e, 0x98, 0x21, 0x63, 0x15, 0x8d, 0xb3, 0xb1, 0x4e, 0xd, 0x24, 0xe3, 0x9, 0x46, 0xa, 0x60, 0xfc, 0x25, 0xbe, 0xa6, 0x13, 0x1, 0xc8, 0xbb, 0xe7, 0x4, 0x7, 0x3a, 0x7f, 0xf3, 0x0, 0xc1, 0x97, 0x8, 0xbc, 0x17, 0xff, 0xed, 0x1e, 0x33, 0x40, 0x9a, 0xa1, 0x42, 0x26, 0xc2, 0xed, 0xce, 0xa0, 0xd2, 0x8f, 0x58, 0xf7, 0xd6, 0xdb, 0xc5, 0x98, 0x1f, 0x38, 0xff, 0x13, 0x8f, 0xa7, 0x13, 0x5b, 0xf1, 0xff, 0x49, 0xe9, 0xf3, 0xfc, 0xcf, 0xc7, 0x94, 0x50, 0x57, 0x45, 0x90, 0x22, 0xb0, 0x84, 0x58, 0x4, 0xfe, 0x52, 0xb4, 0x40, 0x26, 0x54, 0x81, 0x86, 0x75, 0xdb, 0x72, 0x42, 0x67, 0xdd, 0xb8, 0x65, 0x64, 0xa8, 0x64, 0xc5, 0xdd, 0x3f, 0x16, 0x1, 0x32, 0xd1, 0xc, 0x15, 0x59, 0x28, 0x12, 0x1a, 0xcc, 0x90, 0xe, 0x26, 0xc4, 0xb, 0x15, 0xa5, 0x16, 0x32, 0xe8, 0xa6, 0x4b, 0xc8, 0x89, 0x8d, 0xd, 0x85, 0x62, 0x11, 0x50, 0x50, 0x44, 0xd4, 0xa8, 0x83, 0xb5, 0x54, 0xd8, 0x10, 0x18, 0x8b, 0xb8, 0x7, 0x8c, 0xc6, 0x2b, 0x80, 0xee, 0x91, 0x6c, 0x5b, 0x6e, 0x38, 0xbb, 0x68, 0x82, 0xfd, 0x92, 0x89, 0xa6, 0x41, 0x5d, 0xc9, 0x87, 0x98, 0xe2, 0xb0, 0x15, 0x2, 0xb4, 0xb9, 0x82, 0x4d, 0x10, 0x36, 0x40, 0x14, 0x59, 0x72, 0x54, 0x44, 0xf9, 0x46, 0x19, 0x5a, 0x1a, 0x51, 0xa2, 0x7f, 0xfe, 0x9, 0x22, 0xe7, 0xe2, 0x80, 0xcb, 0x56, 0xc8, 0xed, 0x5f, 0x4c, 0x54, 0xd8, 0xfc, 0x25, 0x5b, 0x2a, 0x98, 0x22, 0xcb, 0xd, 0xaf, 0xfd, 0xbf, 0x8e, 0xa9, 0xa9, 0x43, 0xd, 0x51, 0x3, 0xca, 0x8, 0x30, 0x1c, 0x3d, 0xc4, 0xc7, 0x2a, 0xd2, 0xf6, 0x9e, 0xfe, 0xf5, 0x17, 0x7b, 0xe1, 0xa, 0xf, 0x38, 0x72, 0xa2, 0xac, 0x27, 0xb6, 0xaa, 0x32, 0xd0, 0x23, 0x10, 0x1, 0x7f, 0xfd, 0x15, 0x76, 0xc3, 0x62, 0x1d, 0xac, 0x4, 0xdc, 0x52, 0xa2, 0x1b, 0xd0, 0x9a, 0xfd, 0x76, 0xf4, 0x67, 0x84, 0x59, 0x9f, 0x11, 0x19, 0xfe, 0xdf, 0x88, 0x6c, 0x5a, 0x7f, 0x1d, 0x81, 0x1f, 0x3c, 0xc8, 0x30, 0x9d, 0x4, 0xe1, 0xb0, 0x82, 0x64, 0xa2, 0x20, 0xf0, 0xc3, 0x81, 0xe3, 0xfd, 0xb4, 0x10, 0x7a, 0x76, 0x17, 0xa3, 0x32, 0x64, 0xc8, 0x43, 0xa1, 0x78, 0x4, 0x54, 0x91, 0xe5, 0x8e, 0xbb, 0x8, 0xf3, 0xf4, 0x9c, 0xd1, 0x4f, 0x1c, 0xed, 0x80, 0xc1, 0x7a, 0xab, 0x61, 0xf2, 0x45, 0xce, 0x6, 0xe, 0x52, 0xad, 0xd0, 0x2b, 0x76, 0x7a, 0xd7, 0x85, 0x72, 0xab, 0xde, 0xbe, 0xee, 0x16, 0xfa, 0xfd, 0x8b, 0x4e, 0xaf, 0x1c, 0x34, 0x64, 0xff, 0x7f, 0x80, 0xe4, 0x19, 0x9, 0x85, 0x12, 0x82, 0xd7, 0xca, 0xed, 0x3e, 0x37, 0xaa, 0x54, 0x9b, 0x6f, 0x1e, 0x20, 0xdd, 0x32, 0x57, 0x7e, 0xb6, 0xe6, 0x81, 0xe3, 0x8f, 0xd, 0x20, 0xe3, 0xc9, 0x46, 0x96, 0x82, 0xba, 0xf3, 0x1d, 0x4b, 0x5e, 0x78, 0x33, 0xa8, 0x77, 0x1, 0xd1, 0x79, 0xb, 0xc2, 0x27, 0xc, 0x88, 0xc9, 0xec, 0x15, 0x36, 0xd5, 0x8b, 0xef, 0xc4, 0xcc, 0x6f, 0x1a, 0x9, 0xfd, 0xf9, 0x67, 0x98, 0xe9, 0x77, 0xb7, 0x9, 0x31, 0x81, 0xb9, 0xa7, 0x5c, 0x4, 0x1b, 0x3e, 0x4e, 0xab, 0x33, 0x87, 0xb8, 0xb4, 0xee, 0x8c, 0xa5, 0xc0, 0xc8, 0x5e, 0x8b, 0xd1, 0x7c, 0x23, 0x9a, 0x91, 0xce, 0xa9, 0xb, 0x25, 0x23, 0xa0, 0xc0, 0xad, 0x58, 0x77, 0xd0, 0x86, 0x75, 0xb0, 0xc0, 0xd0, 0x33, 0x7, 0x1f, 0x15, 0xb1, 0x50, 0x2a, 0x2, 0x9a, 0x64, 0x8a, 0x75, 0x17, 0x78, 0x89, 0xad, 0x99, 0x2b, 0xe5, 0xa5, 0x66, 0x9d, 0x33, 0x96, 0x13, 0x99, 0xaf, 0xf2, 0x7a, 0x8f, 0xa2, 0xfb, 0xd9, 0x2a, 0xf3, 0xdf, 0xaa, 0xec, 0xcc, 0xff, 0xd7, 0x33, 0xa4, 0x32, 0x83, 0x37, 0x62, 0x19, 0x6f, 0x75, 0x14, 0xf0, 0xf1, 0xf9, 0x3f, 0x16, 0x4b, 0x48, 0x3b, 0xf3, 0x7f, 0x26, 0x9e, 0xf8, 0x9c, 0xff, 0x3f, 0xa2, 0xfc, 0xf9, 0x67, 0xf4, 0x1b, 0x58, 0x60, 0x2d, 0xcf, 0xd7, 0x4c, 0x4c, 0x7, 0x58, 0x2b, 0x3, 0xfd, 0xa6, 0xb1, 0x61, 0x91, 0x67, 0x28, 0xf, 0xbe, 0x45, 0xff, 0xfa, 0x2b, 0xc4, 0x6a, 0x85, 0x2a, 0xf7, 0x6, 0x74, 0xf, 0x7c, 0xb8, 0xe7, 0x5a, 0xd8, 0xba, 0x8c, 0x1f, 0x1d, 0xf, 0x5d, 0x20, 0xb6, 0xa0, 0xd0, 0xf9, 0x1c, 0xe, 0x2d, 0x90, 0x4e, 0x88, 0x33, 0x27, 0x60, 0x8c, 0x64, 0xc8, 0x2c, 0x0, 0x4a, 0x34, 0x4, 0x1a, 0xde, 0x52, 0x51, 0xa0, 0x98, 0x60, 0xa4, 0x2a, 0x14, 0x40, 0x13, 0x89, 0x23, 0x5f, 0xe2, 0xe0, 0xf, 0x5f, 0xcf, 0xfc, 0x3a, 0x5e, 0x71, 0xf4, 0x4c, 0x4f, 0xe9, 0x50, 0x63, 0xf3, 0x10, 0xb3, 0x8d, 0xbf, 0x46, 0x42, 0xe, 0x45, 0x61, 0x67, 0x25, 0xb8, 0x56, 0x81, 0x7c, 0x2a, 0x9, 0xaf, 0x5f, 0xf2, 0xb3, 0x6f, 0xce, 0xdb, 0xa3, 0xb5, 0xee, 0x85, 0x1a, 0xea, 0x2c, 0x90, 0x69, 0x62, 0x3e, 0xb9, 0x72, 0xa2, 0x19, 0xb9, 0xec, 0x4f, 0xac, 0xf5, 0xed, 0xc9, 0x4, 0xdf, 0xb3, 0xc5, 0xbb, 0x87, 0x89, 0xe9, 0x40, 0xf6, 0xb7, 0x18, 0x85, 0x92, 0x89, 0x78, 0x17, 0xbd, 0x6, 0xd8, 0x2c, 0xb6, 0x2, 0x77, 0x36, 0x54, 0x85, 0xdd, 0xe, 0xd, 0x83, 0x77, 0xee, 0xef, 0x30, 0x24, 0xeb, 0x19, 0xd6, 0xed, 0xcc, 0xff, 0xe2, 0x8d, 0xe4, 0x7f, 0x7b, 0xe2, 0xf8, 0xb8, 0x60, 0x86, 0x89, 0x75, 0x6b, 0x2, 0x8e, 0xfe, 0x37, 0xd, 0xff, 0x6f, 0x7a, 0xb4, 0x39, 0xc7, 0x3b, 0x38, 0x9f, 0x3d, 0x94, 0xa0, 0x86, 0x54, 0xcd, 0x3d, 0x3d, 0xaa, 0x0, 0x15, 0x8e, 0x91, 0x4a, 0xc1, 0xbe, 0xae, 0x88, 0xd7, 0x2, 0xd5, 0xc, 0x99, 0xd8, 0x62, 0x4b, 0xc4, 0xd, 0x7b, 0xa3, 0xef, 0x9c, 0x47, 0xfb, 0xeb, 0xaf, 0x90, 0x29, 0x1e, 0xe5, 0x77, 0xec, 0x11, 0xf6, 0x92, 0x33, 0xac, 0x78, 0x25, 0xd2, 0x1e, 0x38, 0x2f, 0xc2, 0xeb, 0x27, 0xce, 0x91, 0x78, 0xf0, 0x83, 0xad, 0x3e, 0x55, 0x66, 0xc2, 0x1c, 0x1d, 0x1f, 0x81, 0xa3, 0xeb, 0x23, 0x6, 0xf, 0xd, 0x23, 0xf, 0x8e, 0x2, 0x27, 0x61, 0xcf, 0x98, 0x39, 0xa, 0xe8, 0x2e, 0x3f, 0xf8, 0xd5, 0x7c, 0xbc, 0x97, 0xbe, 0x3a, 0xa2, 0xab, 0x8f, 0xf6, 0xe4, 0x45, 0x94, 0xec, 0xb4, 0xe9, 0xce, 0xb0, 0xc3, 0x5e, 0x73, 0xfd, 0xa5, 0x7c, 0xc6, 0xca, 0xc6, 0x39, 0xc1, 0x5d, 0x86, 0xc8, 0x73, 0x86, 0x8, 0x9e, 0xad, 0x7f, 0xb5, 0x48, 0x5f, 0x1c, 0x43, 0xb, 0x42, 0xf6, 0x75, 0xcd, 0x17, 0x2a, 0x5d, 0xf3, 0xda, 0x1e, 0x5c, 0xdb, 0x3c, 0xb4, 0x2b, 0x9a, 0x43, 0x8a, 0xc0, 0xb7, 0xc8, 0xfa, 0xa0, 0x12, 0x80, 0xe2, 0x50, 0x63, 0x49, 0x1c, 0xc6, 0xe3, 0xa3, 0xe6, 0x3a, 0x93, 0xd6, 0x2b, 0x8e, 0xef, 0x21, 0x4a, 0x0, 0xb6, 0x80, 0xc, 0x75, 0xe7, 0x6c, 0xde, 0xe6, 0xd9, 0x47, 0xe7, 0x60, 0xa1, 0xae, 0xb8, 0x36, 0x98, 0xff, 0xf9, 0x7e, 0xd1, 0x63, 0x2d, 0x88, 0x86, 0xdb, 0x9b, 0x2, 0xa8, 0x62, 0x6a, 0x31, 0x1, 0xa4, 0x86, 0x8a, 0xad, 0x26, 0xfb, 0x71, 0x14, 0xd9, 0x3b, 0x80, 0x3b, 0x50, 0x86, 0xc9, 0x7d, 0x72, 0xe0, 0x57, 0x13, 0x51, 0x4b, 0x3c, 0xfe, 0xa, 0x8e, 0xbe, 0xf9, 0xf0, 0xcb, 0x3a, 0xab, 0x77, 0x4b, 0xb0, 0xce, 0x11, 0xb, 0xc8, 0xdd, 0xcf, 0x76, 0xc4, 0x6b, 0x6, 0xb, 0xe6, 0xc0, 0x77, 0x38, 0x51, 0x74, 0x9f, 0x4c, 0xfc, 0xbd, 0x47, 0x66, 0x64, 0x2f, 0x7, 0xfb, 0xd, 0xd1, 0xed, 0x56, 0x1d, 0xbf, 0xcd, 0x23, 0xc, 0x13, 0x40, 0xcf, 0x9e, 0x16, 0x1c, 0x69, 0xdf, 0x1c, 0x5c, 0x9f, 0x9a, 0xda, 0x70, 0x55, 0x1d, 0x81, 0x5f, 0xb1, 0x2e, 0xab, 0xb6, 0x12, 0xb8, 0xf8, 0xf8, 0xfa, 0xa4, 0x66, 0xdd, 0x50, 0x9d, 0x8, 0x33, 0x8f, 0x45, 0x93, 0x0, 0x38, 0xa2, 0x82, 0xee, 0xbc, 0xe, 0x79, 0xd5, 0xd8, 0x3c, 0xa, 0x8e, 0xdc, 0xa0, 0x23, 0x17, 0x40, 0x80, 0x1c, 0x5a, 0xa, 0xf9, 0xc2, 0x82, 0x36, 0xc4, 0xc3, 0x85, 0xdf, 0x69, 0xcc, 0x1d, 0x46, 0x4e, 0x9c, 0x8f, 0xb6, 0x3d, 0xc2, 0xb2, 0xbf, 0x73, 0x6, 0x31, 0x5f, 0xdb, 0x39, 0x3f, 0x8f, 0x89, 0x0, 0x1d, 0x3f, 0x41, 0x4f, 0xef, 0x8a, 0xe1, 0xea, 0x9b, 0x17, 0x76, 0xc5, 0x8d, 0x8, 0x7a, 0xcb, 0xee, 0x18, 0x84, 0x5a, 0x6c, 0x41, 0xf5, 0xc2, 0x2e, 0xb9, 0x24, 0xbd, 0xea, 0xb, 0xb9, 0x81, 0x4c, 0xaf, 0xeb, 0xd6, 0x4e, 0x65, 0xb7, 0x9a, 0xd7, 0x0, 0x5b, 0x58, 0xa7, 0x93, 0x48, 0x97, 0xc1, 0xf, 0x70, 0x67, 0x13, 0xb, 0xbd, 0xf0, 0x33, 0x3e, 0x5, 0xdd, 0x73, 0x7, 0xc1, 0x84, 0xcb, 0xee, 0x87, 0x8d, 0xc3, 0xeb, 0xba, 0xfd, 0x8a, 0x5e, 0xfa, 0xa3, 0xd4, 0xde, 0x92, 0x8b, 0xbd, 0x70, 0xb7, 0x97, 0x75, 0xcd, 0x4f, 0xd6, 0xab, 0xba, 0xe7, 0x8f, 0xb3, 0xfb, 0x1b, 0x49, 0xe9, 0x6, 0x5d, 0xaf, 0xe9, 0x60, 0x50, 0xb4, 0xe0, 0x5b, 0xf6, 0x53, 0xe0, 0x77, 0xa7, 0xb8, 0x17, 0xf5, 0x35, 0x88, 0xc4, 0x37, 0xe8, 0xf2, 0x46, 0xd8, 0xe3, 0x3b, 0x74, 0x59, 0x84, 0x4f, 0xbe, 0xaa, 0xcb, 0x1b, 0x24, 0xbe, 0x9a, 0x8d, 0x5, 0x2d, 0x2e, 0xe3, 0x9, 0x8f, 0xd8, 0xce, 0x2c, 0x1f, 0x30, 0x35, 0xb1, 0xe9, 0x3e, 0xff, 0x68, 0xdd, 0xd, 0x55, 0xc7, 0xaa, 0xff, 0xeb, 0xd1, 0xea, 0xc2, 0x3a, 0x39, 0x8c, 0x56, 0x4c, 0xf4, 0xac, 0xde, 0xe3, 0xa4, 0x6e, 0x9, 0x29, 0x3, 0xf8, 0x6f, 0x4a, 0x55, 0x8d, 0x28, 0xe8, 0x37, 0x27, 0xbd, 0xcd, 0xcb, 0x4, 0xe2, 0xdf, 0x76, 0xc4, 0x82, 0xa5, 0xfe, 0x4d, 0x6, 0xce, 0xc7, 0xf6, 0xff, 0xbe, 0x3, 0xb7, 0xa5, 0x3b, 0xe, 0xe, 0xdc, 0xcf, 0x76, 0xa1, 0xfd, 0xa3, 0xcb, 0x8e, 0xff, 0xd7, 0xb7, 0xb, 0xe3, 0xff, 0x3b, 0x2c, 0x6b, 0x2f, 0xce, 0xe, 0x77, 0x60, 0xff, 0x37, 0x15, 0x4b, 0x6c, 0xf9, 0x7f, 0xe3, 0x52, 0x2a, 0x9e, 0xfc, 0xf4, 0xff, 0x7e, 0x44, 0x81, 0x6, 0xf6, 0xf2, 0x3f, 0x2e, 0x62, 0xa1, 0x39, 0xd6, 0x95, 0xbc, 0x93, 0x9e, 0xab, 0x5, 0x8d, 0x90, 0x86, 0x2c, 0xe8, 0xc6, 0xc7, 0x39, 0x41, 0xed, 0xcf, 0xdb, 0xc9, 0xe3, 0x69, 0x58, 0xb8, 0x3f, 0x2b, 0x1f, 0xfa, 0xf3, 0x4f, 0xb0, 0xbd, 0xa, 0x77, 0xbd, 0x7a, 0x11, 0xf0, 0x3, 0x60, 0x5d, 0x41, 0xba, 0x5, 0x92, 0xce, 0x76, 0x18, 0xdf, 0x60, 0x26, 0x3a, 0xd2, 0xad, 0x3c, 0xf0, 0x27, 0xd5, 0x71, 0xc9, 0xe9, 0x76, 0xfa, 0x83, 0x6a, 0xaf, 0xd2, 0x3f, 0x6b, 0x5e, 0xd7, 0x3a, 0xfd, 0xc1, 0x1e, 0xca, 0x2, 0x94, 0xd5, 0xd1, 0x26, 0x70, 0xb7, 0xd3, 0x3b, 0x8, 0xbc, 0xd6, 0x60, 0x5b, 0xc0, 0xc3, 0x7e, 0xa5, 0xd7, 0x2e, 0xb4, 0x2a, 0x87, 0x10, 0x6c, 0x6a, 0xe1, 0x2d, 0x24, 0xe5, 0xc2, 0xa0, 0x50, 0x2c, 0xf4, 0xf, 0x22, 0xd9, 0x5c, 0xe, 0xb8, 0x88, 0x2a, 0xad, 0x42, 0xdd, 0x3f, 0x4, 0xae, 0xe1, 0xe3, 0x1b, 0xb3, 0x88, 0x97, 0x4e, 0x68, 0x3, 0x66, 0xdd, 0xf3, 0xbd, 0x30, 0xdc, 0xe7, 0xe7, 0x87, 0x19, 0xf6, 0x7b, 0x7, 0x40, 0x86, 0x14, 0x99, 0x1b, 0x20, 0xfd, 0x7e, 0xf3, 0x0, 0x48, 0x9f, 0xaa, 0x1b, 0x10, 0x27, 0xbd, 0x4e, 0xeb, 0x0, 0xc8, 0x89, 0x49, 0xb4, 0xd, 0x98, 0x7a, 0xb9, 0xd2, 0x1e, 0xd4, 0x7, 0xa3, 0x3, 0x70, 0x6e, 0xca, 0xa2, 0x4d, 0xd8, 0x76, 0xbf, 0x52, 0x1a, 0xf6, 0x2a, 0x87, 0x60, 0x9d, 0xd4, 0x46, 0x2e, 0xec, 0xe5, 0xe0, 0xba, 0xd2, 0x2e, 0x77, 0x3b, 0xf5, 0x36, 0x1b, 0xc6, 0xa7, 0x6c, 0x85, 0x32, 0xb0, 0x61, 0xfd, 0x7a, 0xd8, 0x6b, 0x3a, 0x0, 0x7b, 0x66, 0xef, 0x2d, 0x79, 0xb2, 0x31, 0x3, 0x3c, 0xed, 0x14, 0xfb, 0x95, 0xde, 0x79, 0xbd, 0x54, 0x79, 0x36, 0x82, 0x75, 0xfa, 0x1b, 0x86, 0xa8, 0x57, 0xa9, 0xd6, 0xfb, 0x83, 0xde, 0xe8, 0xd9, 0x68, 0xbc, 0xb3, 0x4a, 0x29, 0x49, 0xe2, 0x49, 0xb5, 0x6, 0x9d, 0x46, 0xa5, 0x7d, 0xfd, 0x52, 0xaa, 0x6c, 0x1c, 0x75, 0xa8, 0x8a, 0x5a, 0x64, 0x8e, 0x78, 0xca, 0xa6, 0x8b, 0xfa, 0xa0, 0x76, 0x2d, 0xe2, 0xae, 0x36, 0xbf, 0xc6, 0xce, 0x96, 0x39, 0xab, 0xed, 0x4, 0x68, 0x1d, 0x6c, 0x38, 0xc0, 0x65, 0xc8, 0xcd, 0x96, 0x64, 0x32, 0x99, 0x60, 0x78, 0x9a, 0x9d, 0xea, 0x75, 0xb3, 0x72, 0x5e, 0x61, 0x68, 0xb0, 0x3e, 0x21, 0xec, 0x59, 0xbd, 0x55, 0xa8, 0x56, 0xae, 0xfb, 0x83, 0x4e, 0xaf, 0x72, 0xdd, 0x2d, 0xc, 0x6a, 0x79, 0x70, 0x14, 0x3d, 0xe2, 0x51, 0x5e, 0x98, 0xae, 0xe3, 0xf2, 0x88, 0x9, 0xcd, 0x15, 0x98, 0x41, 0x79, 0x1e, 0x9, 0x1, 0x50, 0x18, 0xe, 0x6a, 0xd7, 0xad, 0x4e, 0xf9, 0x11, 0x4e, 0xda, 0x4d, 0x66, 0xe5, 0xf4, 0xa5, 0x5f, 0x69, 0x9e, 0x5c, 0x3b, 0x9f, 0xa6, 0x30, 0xa8, 0x77, 0xda, 0xfb, 0x71, 0x6c, 0x27, 0xbc, 0x72, 0x30, 0x34, 0xcb, 0x85, 0xae, 0x33, 0x16, 0x7b, 0x0, 0x55, 0x5, 0x1a, 0x11, 0xdb, 0x54, 0xfd, 0x0, 0xfd, 0x4a, 0xa1, 0x57, 0xaa, 0x5d, 0x97, 0x1f, 0x69, 0x8f, 0x83, 0xb9, 0x49, 0xb2, 0xfc, 0xb0, 0x4c, 0x6b, 0x1d, 0x86, 0x14, 0x69, 0xb3, 0xfc, 0x70, 0x27, 0xf5, 0xe6, 0xa0, 0xf2, 0x88, 0x22, 0xe1, 0x60, 0x22, 0xbd, 0xd6, 0x46, 0xdf, 0xea, 0xe5, 0x43, 0x7d, 0xc3, 0xca, 0x46, 0xdf, 0x4a, 0x9d, 0xee, 0x23, 0xdf, 0x42, 0xf4, 0x4b, 0x26, 0x6, 0xf2, 0x3, 0xd, 0xea, 0xad, 0x4a, 0x67, 0xf8, 0x88, 0x66, 0xe4, 0x60, 0x4e, 0xee, 0x2e, 0x3f, 0xe0, 0x79, 0xa5, 0x57, 0x3f, 0x19, 0x5d, 0x97, 0x2a, 0x8f, 0xa9, 0x55, 0xe, 0xbc, 0xce, 0xf3, 0xe5, 0xc0, 0xbb, 0x53, 0xc0, 0xf5, 0x60, 0xc4, 0x9, 0x76, 0xad, 0xfb, 0x3b, 0x7e, 0x12, 0xb6, 0xdb, 0xeb, 0x9c, 0x56, 0x4a, 0x83, 0xeb, 0x52, 0xaf, 0xc2, 0x39, 0xe3, 0xba, 0x57, 0xe9, 0xf, 0x7a, 0xf5, 0x92, 0xc3, 0x25, 0x68, 0x81, 0xcc, 0x15, 0xd1, 0xb9, 0x6c, 0x3b, 0x34, 0xf4, 0x2a, 0xad, 0xce, 0xa0, 0xe2, 0x92, 0x42, 0x26, 0x13, 0xf6, 0xae, 0x55, 0xb8, 0xbc, 0x3e, 0xed, 0x14, 0xaf, 0x2f, 0x3a, 0xbd, 0x46, 0xa5, 0xd7, 0xcf, 0x83, 0xa3, 0xc4, 0x5a, 0x88, 0x2b, 0x97, 0xdd, 0xba, 0xc7, 0x77, 0x9, 0x2e, 0xdd, 0xa5, 0x93, 0xea, 0xe6, 0x63, 0x9e, 0xa5, 0xac, 0xda, 0x29, 0x57, 0x8a, 0xc3, 0x6a, 0x1e, 0x1c, 0xe9, 0xc8, 0x52, 0x74, 0xfa, 0x9b, 0x3c, 0xe5, 0xf2, 0x52, 0x28, 0xb7, 0xea, 0xbd, 0x42, 0xd3, 0x61, 0xc0, 0x76, 0x41, 0x68, 0x9a, 0x7e, 0x65, 0xe0, 0xcf, 0x33, 0xc7, 0xc5, 0xbb, 0xd4, 0x2c, 0xd4, 0xb7, 0x3e, 0x3e, 0x5f, 0x65, 0x6e, 0x9, 0x37, 0xaf, 0x76, 0x5d, 0x2e, 0xbe, 0x60, 0x7a, 0xf7, 0x40, 0x9f, 0x3f, 0xb9, 0x7b, 0xa0, 0x2f, 0x9f, 0xda, 0x5d, 0x14, 0x7, 0xe7, 0xf3, 0xdd, 0xa5, 0xf5, 0x1a, 0xfc, 0xb9, 0xca, 0x54, 0x4, 0xe7, 0xa7, 0xa5, 0x34, 0xff, 0x74, 0xc3, 0x42, 0xc1, 0x3f, 0x37, 0xb9, 0x8f, 0x4a, 0xcd, 0x3a, 0x9b, 0x25, 0xcb, 0x3b, 0x8f, 0xfa, 0x95, 0x52, 0xaf, 0xe2, 0xaf, 0xb9, 0xc9, 0xcb, 0x6e, 0x2a, 0x3a, 0x6f, 0xe6, 0x60, 0x6a, 0x91, 0xa9, 0xc7, 0x6e, 0xaf, 0x73, 0x5e, 0x2f, 0x57, 0x7a, 0xd7, 0xce, 0x48, 0x4d, 0xb0, 0x8a, 0xe8, 0x8a, 0x5a, 0x48, 0x3b, 0xfa, 0x5c, 0x97, 0xfd, 0x13, 0xca, 0x93, 0xd7, 0x7f, 0x22, 0xd8, 0xef, 0x45, 0x29, 0xc2, 0xf, 0xac, 0xff, 0x62, 0xa9, 0x58, 0x7a, 0x6b, 0xfd, 0x17, 0x4b, 0x65, 0xd2, 0x9f, 0xeb, 0xbf, 0x8f, 0x28, 0x81, 0xeb, 0x3f, 0x71, 0x26, 0xfc, 0xef, 0xb8, 0xf8, 0x13, 0x49, 0x1d, 0x3a, 0x6, 0xbc, 0xb3, 0x91, 0xb7, 0x12, 0xf4, 0x65, 0xb5, 0xf5, 0x4d, 0x29, 0xde, 0xd3, 0xdd, 0x8d, 0x27, 0xde, 0x86, 0xb3, 0x6, 0xba, 0x28, 0x6f, 0x40, 0xed, 0xae, 0x80, 0x96, 0x1, 0x3b, 0x57, 0x1c, 0x41, 0x60, 0x3c, 0xea, 0x5e, 0x64, 0x1b, 0x19, 0x4e, 0xf7, 0x60, 0xf4, 0xaf, 0x4a, 0xfd, 0xf8, 0x1e, 0x99, 0xbb, 0x36, 0xdc, 0x75, 0x9b, 0x8b, 0x4, 0x57, 0xa7, 0xfb, 0x8, 0x5a, 0xaf, 0x3, 0x9c, 0xe1, 0xd9, 0x43, 0xc8, 0xb0, 0x1e, 0x4, 0x6d, 0xe3, 0xc7, 0xa0, 0x76, 0xbd, 0xfb, 0x7, 0xcc, 0x5e, 0x9e, 0x8e, 0x55, 0x24, 0x71, 0x5, 0x7f, 0xfd, 0x5, 0xb6, 0xec, 0xd1, 0xc7, 0x3e, 0x8c, 0xcf, 0x1e, 0xdd, 0xf3, 0x79, 0x80, 0x3f, 0x7a, 0x95, 0xb1, 0xde, 0x64, 0xaf, 0xa9, 0xb1, 0x61, 0x2e, 0xbc, 0x68, 0xd4, 0xff, 0xfc, 0xd3, 0x6d, 0xe9, 0x67, 0x4b, 0xf3, 0xf3, 0xcb, 0xd3, 0xf5, 0xff, 0xcb, 0x6f, 0x87, 0x38, 0xe4, 0xff, 0x8b, 0xa7, 0x92, 0x3b, 0xfe, 0xbf, 0xd4, 0xa7, 0xfe, 0xff, 0x90, 0xe2, 0xd7, 0xff, 0xd0, 0x30, 0x68, 0x74, 0x11, 0x1b, 0x23, 0xb, 0xc6, 0xdd, 0x99, 0xc0, 0x82, 0x16, 0x9a, 0xd8, 0x6a, 0xff, 0xef, 0x39, 0x1d, 0x50, 0x3, 0xc9, 0x8c, 0x1c, 0x13, 0xf1, 0x4b, 0x2, 0x68, 0x1e, 0xc4, 0x9c, 0x13, 0x6d, 0xce, 0x3a, 0xff, 0x45, 0x34, 0x52, 0xf7, 0x28, 0x95, 0x38, 0x33, 0xbd, 0xe, 0xc9, 0xb, 0x24, 0x7b, 0x23, 0x64, 0xcf, 0x47, 0x7b, 0xda, 0xa5, 0x7d, 0x2f, 0xf5, 0xc0, 0x23, 0xcc, 0x69, 0xc9, 0x37, 0xc0, 0xac, 0x3c, 0x6f, 0xac, 0xb2, 0xeb, 0xf6, 0x1e, 0x69, 0xf1, 0xd1, 0x57, 0xee, 0x70, 0x2, 0x7f, 0x72, 0x12, 0x2f, 0xed, 0x50, 0xd8, 0xf9, 0xea, 0xdb, 0x50, 0xeb, 0x13, 0x7b, 0x7b, 0x17, 0xbd, 0xfc, 0x75, 0x64, 0x7d, 0x92, 0xcf, 0xd9, 0x32, 0xda, 0x5f, 0xd5, 0x82, 0x53, 0x67, 0x35, 0xe4, 0xc3, 0xdf, 0xf5, 0x1d, 0xdb, 0x7b, 0xbc, 0xa5, 0xf5, 0x1, 0xbf, 0xd, 0x2c, 0xbe, 0xa3, 0xb5, 0x8c, 0x2b, 0xc8, 0x8, 0x6a, 0x6a, 0x20, 0x16, 0xaf, 0xe2, 0x7a, 0x78, 0x63, 0x92, 0x7f, 0x7c, 0x91, 0xbe, 0xe0, 0xd9, 0xd2, 0xbd, 0x7, 0x61, 0xe7, 0x30, 0x6b, 0xb, 0x1a, 0x3d, 0x34, 0x59, 0x3f, 0x67, 0xe5, 0xc5, 0xc2, 0xe2, 0xa2, 0x16, 0xb3, 0xee, 0x5b, 0xe3, 0xf5, 0x1d, 0x74, 0xf4, 0x7f, 0x5e, 0xb6, 0x64, 0xde, 0x68, 0x86, 0xdf, 0xd, 0x94, 0x7, 0x47, 0x59, 0x29, 0x2b, 0x1d, 0x5, 0x0, 0x9c, 0xf6, 0x3b, 0xed, 0xeb, 0xd2, 0x49, 0xd5, 0xe7, 0x2b, 0xb, 0x82, 0xe7, 0x47, 0x4b, 0xfc, 0xb3, 0x8b, 0x18, 0x30, 0xe7, 0x9f, 0xc8, 0x2d, 0xf5, 0xce, 0x70, 0xfa, 0x91, 0x37, 0x2a, 0xa3, 0xa7, 0x63, 0x9c, 0xa3, 0x95, 0x57, 0x8f, 0xad, 0xea, 0xe9, 0xd6, 0xf7, 0x11, 0xc, 0x2d, 0xb2, 0xe6, 0xb3, 0xde, 0x78, 0x6f, 0xc5, 0xb1, 0xee, 0x16, 0xb1, 0xf5, 0x4d, 0x98, 0x1d, 0x86, 0xf, 0xb, 0x6a, 0x7d, 0xd4, 0x68, 0xc, 0xa8, 0xb, 0xad, 0xd9, 0xde, 0x1e, 0x3e, 0x8a, 0xcf, 0x4f, 0xf2, 0xe3, 0xc8, 0x36, 0x6b, 0x52, 0x7b, 0x2c, 0xea, 0xad, 0x1f, 0x6f, 0x65, 0x9, 0x73, 0xec, 0x31, 0x9d, 0x58, 0x1e, 0x8b, 0x7, 0xdc, 0xb0, 0xb3, 0x66, 0xea, 0x27, 0xf4, 0x96, 0x5f, 0xff, 0x51, 0xc6, 0xeb, 0x74, 0x5e, 0xeb, 0x88, 0x89, 0x47, 0xd1, 0xf8, 0x49, 0x77, 0x72, 0x86, 0xfb, 0xbb, 0xc2, 0x9f, 0xbc, 0x58, 0x5b, 0xbb, 0x5, 0x5b, 0x48, 0xa3, 0x9b, 0xc, 0xcd, 0xf3, 0x2d, 0x79, 0xeb, 0x80, 0xd, 0x16, 0x32, 0x36, 0x6, 0x8f, 0xf5, 0x82, 0x1f, 0x4a, 0xa, 0x52, 0x6, 0xfe, 0xd3, 0xb5, 0xeb, 0x7e, 0x6e, 0x9c, 0xb9, 0xf5, 0xab, 0x93, 0x0, 0x8d, 0xbc, 0x35, 0x48, 0x8f, 0xb6, 0xe6, 0x1e, 0xd3, 0x5d, 0xb7, 0xe4, 0x1d, 0xdc, 0x7d, 0xc3, 0x56, 0x7c, 0xc7, 0x83, 0xd7, 0xd, 0xf9, 0xcf, 0xc, 0x3f, 0xa7, 0xad, 0xad, 0x78, 0xf1, 0xbd, 0x5c, 0x26, 0x18, 0xb4, 0xa4, 0x42, 0xac, 0xd, 0x5c, 0x7b, 0x93, 0x7d, 0xb0, 0xf0, 0xce, 0xcc, 0xf7, 0x28, 0x27, 0xfa, 0x67, 0xa9, 0x75, 0x6a, 0x5, 0x9a, 0x7, 0xbf, 0xef, 0x99, 0x13, 0x1c, 0xc1, 0x88, 0x38, 0x9a, 0x66, 0xd, 0xe3, 0x5b, 0x30, 0xfc, 0xb1, 0x29, 0x35, 0x4f, 0x40, 0xe3, 0xcf, 0xf6, 0xb0, 0x1e, 0x43, 0x7, 0xfe, 0x57, 0x74, 0xc7, 0xf, 0x3e, 0x3c, 0x13, 0xcf, 0xd7, 0x35, 0xa2, 0xa0, 0x6b, 0xa5, 0xfc, 0x32, 0xa7, 0x52, 0xf4, 0x68, 0xe5, 0xa7, 0x8d, 0xc5, 0x56, 0x27, 0x8e, 0xf6, 0x49, 0xf5, 0xce, 0x83, 0xad, 0x3c, 0x81, 0x0, 0x6c, 0x27, 0xa, 0xdc, 0x20, 0x6c, 0xef, 0x4a, 0x6e, 0x9b, 0x1c, 0xfc, 0x80, 0x36, 0x57, 0xa2, 0x9f, 0x81, 0x1e, 0xef, 0x5b, 0x9e, 0xbe, 0xfe, 0x5b, 0xc8, 0x2f, 0x5d, 0x0, 0x1e, 0x58, 0xff, 0x49, 0x89, 0xd4, 0x4e, 0xfc, 0x47, 0x26, 0xf6, 0x79, 0xfe, 0xff, 0x43, 0xca, 0x1e, 0xff, 0x9f, 0xb8, 0x2a, 0xe5, 0xd, 0x56, 0x7c, 0xae, 0xb2, 0xf6, 0x99, 0x63, 0x61, 0x27, 0x79, 0xa7, 0x67, 0x7f, 0x59, 0xd0, 0x9c, 0x22, 0x6b, 0xc3, 0x2c, 0xa3, 0xfe, 0x99, 0xf5, 0xa9, 0x2b, 0xae, 0x3, 0xab, 0xc5, 0x9f, 0x3d, 0xd4, 0x7f, 0xcb, 0xb2, 0x23, 0xff, 0xdc, 0x3d, 0xe6, 0x24, 0x6c, 0x7a, 0x45, 0xcc, 0x97, 0xbf, 0x1c, 0xf2, 0xff, 0xa7, 0xb7, 0xfd, 0x3f, 0xb1, 0xb4, 0xf4, 0xe9, 0xff, 0xf9, 0x98, 0x72, 0xc0, 0x37, 0xfa, 0xec, 0xf0, 0xb0, 0xa7, 0xee, 0x54, 0xbe, 0x89, 0x2b, 0x48, 0x60, 0x72, 0x9, 0x70, 0x6c, 0x8, 0xc6, 0xb1, 0x6e, 0xa, 0x55, 0x2f, 0x63, 0x19, 0x70, 0xf2, 0xbc, 0xb9, 0x69, 0xa9, 0x1d, 0xc5, 0xc3, 0x77, 0x13, 0x8c, 0x29, 0xbd, 0x53, 0xbd, 0x67, 0xc4, 0xf0, 0x5d, 0x48, 0xe7, 0x18, 0x31, 0xdc, 0xd2, 0x79, 0xd2, 0x6e, 0xee, 0x7a, 0x17, 0xd7, 0x2d, 0x5f, 0x40, 0xdb, 0xd6, 0xc6, 0xc8, 0x4, 0x64, 0x2, 0x90, 0x8a, 0x34, 0xa4, 0x5b, 0x14, 0xcc, 0x91, 0x61, 0x79, 0x47, 0x11, 0xa1, 0x3c, 0x43, 0x1b, 0x0, 0xe2, 0x63, 0x0, 0x5b, 0x57, 0xf1, 0x1c, 0xa9, 0xfc, 0xc6, 0x3d, 0x91, 0xf, 0x1a, 0xfc, 0x8a, 0x22, 0xd3, 0x8, 0xf0, 0xd2, 0x6d, 0xd0, 0xaf, 0xfc, 0x9c, 0x30, 0xc7, 0xc0, 0xf3, 0x64, 0x11, 0x53, 0x41, 0x26, 0xbf, 0x3b, 0x11, 0x2e, 0x10, 0x30, 0x4c, 0xb4, 0x60, 0x43, 0xa7, 0x23, 0xa4, 0xa8, 0x88, 0x52, 0xc0, 0xd3, 0x47, 0x59, 0x26, 0x36, 0xa8, 0x38, 0x53, 0x8c, 0xbc, 0x31, 0x89, 0xf8, 0x8, 0xe0, 0xe8, 0x9c, 0x9c, 0x64, 0xe9, 0x44, 0x36, 0x19, 0x72, 0x6d, 0x6d, 0x3, 0xfb, 0xb3, 0x4e, 0x17, 0xba, 0x75, 0xe7, 0x30, 0x20, 0xd7, 0xe7, 0x1b, 0xb, 0xef, 0x3c, 0x48, 0x4b, 0xe9, 0xf5, 0xf2, 0x7a, 0x86, 0xa0, 0x6a, 0xcd, 0xbc, 0x17, 0xb1, 0x90, 0xf, 0x4d, 0x19, 0x41, 0x45, 0xc5, 0x3a, 0x2, 0x63, 0x34, 0x21, 0x26, 0x2, 0x50, 0xe7, 0x98, 0x1d, 0x63, 0x52, 0x5c, 0x15, 0x6b, 0x22, 0x6a, 0x10, 0x5d, 0x11, 0xcb, 0x19, 0x8, 0x52, 0x52, 0x62, 0xfd, 0x9, 0xdd, 0x2b, 0xd4, 0x12, 0x92, 0x44, 0x9d, 0xa7, 0x36, 0x4f, 0x1f, 0x66, 0xae, 0x89, 0xe5, 0xe7, 0xa, 0x16, 0x50, 0xcd, 0x83, 0x58, 0x7c, 0x16, 0xf2, 0x16, 0x70, 0x16, 0x9e, 0x60, 0x7f, 0x35, 0x68, 0xb1, 0xaf, 0x6b, 0xd1, 0x3c, 0x48, 0xf8, 0x8c, 0x5a, 0x5e, 0x6f, 0xb5, 0x46, 0x11, 0x9f, 0xad, 0xfb, 0x65, 0x59, 0x86, 0x9f, 0x51, 0x90, 0xae, 0x18, 0x4, 0x33, 0xce, 0x7c, 0x59, 0x14, 0x94, 0x20, 0xc9, 0xb9, 0x5c, 0x37, 0xea, 0xa4, 0x9d, 0x7e, 0xdf, 0xdd, 0x85, 0x47, 0xf5, 0xbf, 0x62, 0xa8, 0x6f, 0x31, 0x1, 0x1c, 0xd0, 0xff, 0xf1, 0x0, 0xfd, 0x1f, 0xff, 0xcc, 0xff, 0xf4, 0x31, 0xe5, 0x19, 0xfa, 0x1f, 0xdd, 0x5b, 0x48, 0xa7, 0x9c, 0x35, 0xc5, 0x26, 0x81, 0x3b, 0x1f, 0x94, 0xbd, 0xbc, 0x50, 0x7f, 0x8f, 0x9, 0x61, 0xdf, 0xae, 0xc0, 0xfb, 0x79, 0xf5, 0xdd, 0x1e, 0x7c, 0x84, 0x3f, 0xdf, 0x6d, 0xeb, 0xa9, 0xee, 0xfa, 0x75, 0x7d, 0xb0, 0x76, 0xd4, 0xef, 0x84, 0x5e, 0x1d, 0xf0, 0xd0, 0xfb, 0x2b, 0x9, 0xdf, 0xfc, 0x7e, 0xd7, 0xfc, 0x1e, 0xb0, 0xd, 0x9f, 0xfc, 0x5a, 0xe7, 0x9a, 0x53, 0x9a, 0x7, 0xbf, 0x1f, 0x85, 0xbd, 0x6b, 0x7b, 0x2d, 0x95, 0x1e, 0x7d, 0x7, 0x47, 0x8e, 0xc7, 0x87, 0xfd, 0xc9, 0x5d, 0xa1, 0x8e, 0x5e, 0x5a, 0xcf, 0xf1, 0x47, 0x7f, 0x3c, 0xcd, 0xaf, 0x2f, 0x68, 0x38, 0xe8, 0xd1, 0x3f, 0xe4, 0x2f, 0xde, 0x98, 0xd0, 0x1e, 0xf7, 0x17, 0x3b, 0xc6, 0xf3, 0x21, 0x4f, 0xf1, 0x4e, 0x8f, 0x82, 0xdc, 0xbb, 0xbb, 0xaf, 0xb7, 0xdc, 0xbc, 0x8f, 0x36, 0xea, 0xed, 0x49, 0xf8, 0x67, 0xa9, 0xa7, 0xaf, 0xe4, 0x7c, 0x17, 0x1f, 0x38, 0xdf, 0x7a, 0xdb, 0xc7, 0xea, 0x79, 0x59, 0x83, 0xbb, 0x1, 0x3c, 0x4f, 0xeb, 0xf6, 0xfb, 0x1d, 0xef, 0xa4, 0xf8, 0x4c, 0xef, 0xef, 0x6b, 0x15, 0xed, 0xbc, 0x9f, 0x97, 0x55, 0xe0, 0x7f, 0x43, 0xff, 0xea, 0x4f, 0x9c, 0xff, 0x5f, 0xe1, 0xf3, 0xf1, 0x97, 0x43, 0xfe, 0x9f, 0x74, 0x3a, 0xbd, 0x33, 0xff, 0xa7, 0x3e, 0xcf, 0xff, 0x7c, 0x48, 0x39, 0x30, 0xff, 0x7f, 0x11, 0x7a, 0x85, 0x5f, 0xc3, 0x2, 0x30, 0xd5, 0x7f, 0xb1, 0x36, 0x92, 0xf6, 0x82, 0x15, 0xb2, 0x22, 0x40, 0x64, 0x27, 0x92, 0x79, 0x62, 0x24, 0xa, 0x20, 0xf0, 0x6e, 0xea, 0x5, 0x3c, 0xc7, 0xa9, 0x5, 0xb0, 0xc5, 0xd3, 0xd7, 0x62, 0x5d, 0x5c, 0x83, 0xaf, 0x93, 0x65, 0x24, 0xb4, 0x37, 0x9d, 0xf0, 0xc6, 0xfd, 0x3b, 0x51, 0x9e, 0x56, 0x97, 0x46, 0x13, 0xf1, 0x94, 0x14, 0xbc, 0x18, 0x7d, 0x9d, 0xaf, 0xca, 0xd3, 0x70, 0x2f, 0xb0, 0x3d, 0x1e, 0x71, 0x6d, 0x39, 0x93, 0xc5, 0x9b, 0x79, 0xb1, 0xc4, 0x1c, 0xfe, 0x1e, 0x9a, 0x60, 0x47, 0xfe, 0xdd, 0x15, 0xa1, 0xf7, 0x87, 0x13, 0xf9, 0xf9, 0xa, 0x45, 0x70, 0x48, 0xfe, 0x93, 0x49, 0x69, 0xdb, 0xff, 0x2b, 0xa5, 0xa5, 0x4f, 0xf9, 0xff, 0x88, 0xf2, 0xcc, 0x33, 0xf9, 0x6f, 0x1f, 0x2e, 0xea, 0x36, 0xf7, 0x42, 0x21, 0xc, 0xc, 0x8, 0x75, 0xe3, 0x28, 0x5f, 0x1c, 0xcf, 0xf7, 0x3f, 0x67, 0xcf, 0xe9, 0x29, 0xf2, 0xff, 0xf2, 0xc8, 0x3f, 0x51, 0xe, 0xc8, 0x7f, 0x32, 0x9e, 0x8a, 0x6d, 0xcd, 0xff, 0x99, 0xf8, 0xe7, 0xf9, 0xdf, 0x8f, 0x29, 0xaf, 0x90, 0xff, 0x77, 0x9, 0x17, 0x7c, 0xa5, 0x3a, 0xd8, 0x9a, 0x37, 0xbd, 0x3c, 0x5a, 0x6f, 0x14, 0x28, 0xe8, 0xa7, 0xee, 0x3d, 0xfd, 0x9, 0xbe, 0xfc, 0x5f, 0x1f, 0xe1, 0x52, 0xd8, 0xb8, 0x85, 0xf0, 0x69, 0x5e, 0x85, 0xd, 0x10, 0x10, 0xe8, 0x58, 0xd8, 0xcd, 0xa8, 0x74, 0xc0, 0xc9, 0xb0, 0xf, 0xe0, 0x19, 0xe, 0x87, 0x7d, 0x28, 0x82, 0x9d, 0xf, 0x8f, 0xfa, 0xd, 0x76, 0x51, 0x3d, 0x3f, 0x2a, 0xf0, 0x91, 0xe0, 0xbd, 0x97, 0xa, 0x85, 0xdf, 0x9, 0xb0, 0xcf, 0x1, 0xe1, 0xa9, 0x6e, 0xf6, 0xc7, 0x1e, 0xf, 0xc4, 0x2, 0x9a, 0x51, 0x15, 0x8f, 0xa3, 0xeb, 0x93, 0x86, 0x51, 0x5f, 0xed, 0xe7, 0x6, 0x8f, 0xed, 0x71, 0x4a, 0x1c, 0x6d, 0x50, 0x72, 0xf4, 0x94, 0x40, 0xb2, 0xf0, 0xbe, 0x85, 0xf5, 0xee, 0xf7, 0x78, 0x7f, 0x67, 0xc1, 0x6e, 0x9b, 0xef, 0xe7, 0x38, 0xd8, 0x6d, 0xeb, 0x1f, 0x11, 0xa4, 0x15, 0xfc, 0x89, 0x5f, 0xa8, 0x97, 0x9e, 0x14, 0xda, 0xb5, 0x3b, 0x50, 0x6e, 0x14, 0x11, 0x4f, 0x13, 0xff, 0x9c, 0xf0, 0xae, 0x3, 0xa8, 0x9e, 0x15, 0xe2, 0xf5, 0xc, 0x5c, 0xef, 0x13, 0xe6, 0xf5, 0xbc, 0xce, 0x7c, 0x48, 0xa8, 0xd7, 0x21, 0x92, 0x1e, 0xd, 0xf7, 0xfa, 0xc, 0xfe, 0xfa, 0x80, 0xf2, 0x14, 0xfb, 0xff, 0xb5, 0x5e, 0xc0, 0x43, 0xeb, 0xff, 0x94, 0x24, 0x6d, 0xdb, 0xff, 0x89, 0xf4, 0x67, 0xfe, 0xf7, 0xf, 0x29, 0x6f, 0xb3, 0xfe, 0x7f, 0x8d, 0xb, 0xee, 0x95, 0x16, 0xff, 0x23, 0x5e, 0xb8, 0x54, 0x32, 0x11, 0x7f, 0x4b, 0x2f, 0x9c, 0x67, 0xf3, 0xfa, 0xf4, 0xd2, 0xcf, 0xfe, 0x7e, 0xaf, 0x2d, 0x3b, 0xf2, 0xef, 0x5c, 0x56, 0xe3, 0xfe, 0xfb, 0x1, 0xfe, 0xff, 0x44, 0x2c, 0xb1, 0x2d, 0xff, 0xe9, 0x64, 0xec, 0xd3, 0xff, 0xf7, 0x21, 0x65, 0xd3, 0xff, 0xef, 0x7e, 0x74, 0xd7, 0x22, 0x7c, 0x72, 0x8, 0x80, 0x73, 0xcd, 0xcc, 0xb, 0x55, 0x80, 0xd3, 0x6c, 0xd8, 0xc6, 0x4e, 0xda, 0xee, 0x17, 0xaf, 0xfe, 0xa1, 0xce, 0x10, 0xec, 0x5a, 0xc7, 0x5b, 0xfd, 0xf3, 0x55, 0xb, 0x54, 0x27, 0x62, 0x54, 0xfc, 0xab, 0x1f, 0x77, 0x7b, 0xda, 0x49, 0xbb, 0xe3, 0xd8, 0xff, 0x96, 0xea, 0xd8, 0xc6, 0xfc, 0xca, 0x1c, 0x57, 0xfb, 0x1c, 0x1d, 0x4a, 0x1, 0xe5, 0x56, 0x3a, 0x78, 0x8b, 0x8f, 0xa8, 0xfc, 0xdc, 0x3, 0x32, 0x4e, 0x2f, 0xfd, 0xa1, 0x43, 0x0, 0x98, 0xb6, 0x8a, 0x7c, 0xc4, 0xe6, 0x9f, 0x42, 0xa5, 0x3f, 0xbe, 0xc9, 0x80, 0xd6, 0xcc, 0xb7, 0xbe, 0x13, 0xbb, 0xba, 0x51, 0xcf, 0xfe, 0x1b, 0x43, 0x79, 0x8e, 0x74, 0x65, 0xf3, 0x5c, 0x8f, 0xcf, 0xbb, 0xf2, 0xa4, 0x40, 0xa8, 0x5d, 0xe0, 0xee, 0x3a, 0x52, 0xd8, 0x4f, 0xf7, 0x13, 0x7, 0xee, 0x9d, 0xe9, 0xdf, 0x93, 0x55, 0x6a, 0x5f, 0x2f, 0x92, 0xc9, 0x64, 0x22, 0x14, 0xa, 0x87, 0xc3, 0x1f, 0x29, 0x52, 0x5e, 0xaa, 0xe7, 0x9f, 0x26, 0x51, 0x7c, 0xa9, 0x38, 0xc5, 0xfa, 0xbd, 0x57, 0x77, 0x7d, 0x61, 0x68, 0x4, 0x93, 0xa8, 0x89, 0x96, 0x26, 0xb6, 0x50, 0x58, 0x44, 0x81, 0xe7, 0x41, 0xd4, 0x25, 0xd9, 0x30, 0xc9, 0xfd, 0x2a, 0xba, 0x10, 0xf7, 0x8f, 0xbf, 0x14, 0xf6, 0x83, 0xe4, 0xf9, 0x6f, 0x2c, 0xa2, 0xce, 0x0, 0x7e, 0x84, 0x90, 0x86, 0xd6, 0xdd, 0xf9, 0xd9, 0xf3, 0xda, 0x67, 0x79, 0x5a, 0xd9, 0x6b, 0xff, 0xbd, 0x7a, 0xd7, 0x77, 0x5d, 0xe, 0xd8, 0x7f, 0xb1, 0x58, 0x7c, 0xc7, 0xfe, 0x8b, 0xc7, 0x3f, 0xed, 0xbf, 0xf, 0x29, 0x4f, 0xd3, 0x8c, 0x9b, 0x56, 0xa2, 0x7b, 0x6d, 0x6d, 0x69, 0x7d, 0x89, 0xe, 0x75, 0x6a, 0xfd, 0x2f, 0x19, 0x82, 0xfc, 0x6f, 0x60, 0x8a, 0xf4, 0x52, 0xc1, 0x55, 0x21, 0x61, 0x19, 0x1e, 0x81, 0x44, 0x3a, 0x25, 0x79, 0x75, 0x90, 0x69, 0x39, 0xb5, 0x78, 0xb2, 0x67, 0x85, 0x27, 0xc2, 0xdb, 0xb9, 0xa1, 0x65, 0xfb, 0x6, 0x9d, 0xc8, 0x57, 0xa0, 0x63, 0x95, 0xff, 0xc7, 0xb1, 0xb1, 0xb6, 0xde, 0x65, 0x4b, 0xda, 0x53, 0xce, 0xaf, 0xd8, 0x91, 0xde, 0x9c, 0xa7, 0x2c, 0x95, 0x7a, 0x9b, 0xd3, 0x96, 0x4a, 0x23, 0xb2, 0x7b, 0x1, 0x95, 0x33, 0xa2, 0xe2, 0x5a, 0x5f, 0xf0, 0xc3, 0xbb, 0x95, 0x8b, 0x8f, 0x51, 0x84, 0x8f, 0x4b, 0x70, 0x86, 0x1e, 0x86, 0x65, 0xbe, 0x95, 0xf1, 0x48, 0x5c, 0x8, 0xbc, 0x83, 0x65, 0x7f, 0xa, 0x24, 0x71, 0x31, 0xe8, 0x66, 0xc4, 0x26, 0xdc, 0x26, 0x4, 0xee, 0x27, 0x63, 0x3d, 0x79, 0x7d, 0xea, 0xfd, 0x7f, 0x68, 0xd9, 0xd1, 0xff, 0xeb, 0x14, 0x51, 0xbe, 0x3f, 0x5f, 0x77, 0x12, 0xec, 0xa0, 0xfe, 0xdf, 0x3d, 0xff, 0x19, 0x4b, 0xc5, 0x3f, 0xf5, 0xff, 0x47, 0x94, 0x77, 0xc9, 0xff, 0xbd, 0x99, 0x6e, 0xf8, 0x5, 0x3a, 0x74, 0xfb, 0x48, 0x17, 0x3f, 0xd1, 0x75, 0xcc, 0x2d, 0x4f, 0xc3, 0x24, 0x16, 0x91, 0x89, 0xea, 0x9c, 0xb1, 0x11, 0x56, 0xb0, 0xb1, 0x99, 0xd2, 0x63, 0x49, 0xcc, 0x39, 0x32, 0xaf, 0xd, 0x42, 0x54, 0xd7, 0xd6, 0x15, 0x8f, 0xe8, 0xbe, 0x6c, 0x68, 0x1a, 0xbc, 0xbf, 0x10, 0x35, 0xd6, 0xb, 0x38, 0xd7, 0x5a, 0x6, 0x47, 0x26, 0x52, 0x30, 0x3d, 0xf2, 0xb6, 0x43, 0x14, 0x4c, 0x37, 0x70, 0xbb, 0xcf, 0x6c, 0x53, 0x75, 0x6c, 0xf6, 0xad, 0x8b, 0xfa, 0xc2, 0xfc, 0x7d, 0x58, 0x83, 0xd4, 0x42, 0xa6, 0x7f, 0xc7, 0x9b, 0x3f, 0x8f, 0x88, 0xe7, 0xe2, 0xbe, 0x2b, 0xff, 0xe1, 0x31, 0xef, 0x9c, 0x57, 0xde, 0x1d, 0xb0, 0xeb, 0x5b, 0x32, 0xbe, 0x76, 0x68, 0xbe, 0xf6, 0x5e, 0xb, 0x8, 0x95, 0x4c, 0xa7, 0xeb, 0xd3, 0x4c, 0xc2, 0xf8, 0x3f, 0x12, 0xdb, 0xbc, 0x64, 0xca, 0x65, 0xd9, 0xdb, 0x9c, 0x43, 0xb, 0xc4, 0x28, 0xad, 0xb7, 0x4f, 0x3a, 0xee, 0x33, 0x68, 0xca, 0x33, 0xbc, 0x40, 0xd7, 0x6, 0x32, 0x31, 0x51, 0xf2, 0x20, 0x96, 0x4, 0x5f, 0x14, 0xb8, 0x12, 0x47, 0xaa, 0xf8, 0x21, 0xda, 0x6b, 0x71, 0xd8, 0xeb, 0x59, 0x67, 0x9b, 0x36, 0x8e, 0x2, 0xff, 0x6c, 0x56, 0xff, 0x2c, 0x1, 0xe5, 0x89, 0xfa, 0xff, 0x55, 0x27, 0xc1, 0xe, 0xf9, 0x7f, 0xe3, 0xb1, 0x9d, 0xf8, 0xcf, 0x44, 0xfc, 0xf3, 0xfc, 0xef, 0x87, 0x94, 0xd7, 0x1f, 0xf0, 0xfa, 0x90, 0x9, 0x61, 0x6b, 0x27, 0x66, 0x8d, 0xef, 0x27, 0x1c, 0xf6, 0xf2, 0x35, 0xfe, 0x31, 0xe1, 0x59, 0x1b, 0xd, 0x3e, 0x35, 0x40, 0x6b, 0xb, 0x8, 0x4, 0x86, 0x68, 0xf9, 0x66, 0xc0, 0x3, 0xb1, 0x59, 0x3b, 0x35, 0x9f, 0x11, 0x94, 0xb5, 0x3, 0xfb, 0x82, 0x68, 0x2c, 0x1f, 0x8e, 0x97, 0x24, 0x67, 0x7b, 0x75, 0x6, 0xb5, 0x4d, 0xe, 0xf6, 0xda, 0x9, 0x4a, 0xa0, 0xe6, 0x5d, 0x26, 0xb0, 0xd1, 0x94, 0x93, 0xb3, 0x4c, 0x41, 0x63, 0x7b, 0x1a, 0x0, 0xe4, 0x64, 0x55, 0xf, 0x2, 0x59, 0xa7, 0x59, 0xf7, 0xde, 0xbe, 0x61, 0x72, 0x33, 0xbf, 0x91, 0x7f, 0xe8, 0xc4, 0x9a, 0x6f, 0x6e, 0x58, 0x5b, 0x66, 0x7e, 0x7f, 0xe0, 0xf6, 0xa9, 0x35, 0xdf, 0x5b, 0x5f, 0x7b, 0x61, 0x95, 0x4c, 0xe9, 0x63, 0x61, 0x69, 0x8e, 0xbd, 0xf2, 0x78, 0x6c, 0xd9, 0x7e, 0xc2, 0x5f, 0x79, 0xea, 0x6d, 0xf7, 0x53, 0xef, 0xa5, 0x7d, 0x27, 0x8e, 0x6d, 0x27, 0xaa, 0xcb, 0xc7, 0xb7, 0xef, 0x1f, 0xae, 0xe6, 0x6b, 0xec, 0xfd, 0xe2, 0xd4, 0x7c, 0x8d, 0xbc, 0x61, 0x80, 0xda, 0xcf, 0x9e, 0x7, 0xff, 0xa7, 0x96, 0x27, 0xda, 0x7f, 0xaf, 0xc8, 0xfe, 0xfe, 0x84, 0xf8, 0x9f, 0x78, 0x66, 0x3b, 0xff, 0x7b, 0x3c, 0xfe, 0x79, 0xfe, 0xff, 0x43, 0xca, 0xdb, 0x7b, 0x4f, 0x5f, 0x6d, 0xeb, 0xbd, 0x61, 0x8e, 0xf7, 0x9f, 0x96, 0xd, 0xfd, 0x67, 0x7f, 0xd6, 0x27, 0x97, 0xa7, 0xca, 0xff, 0x6b, 0x62, 0x0, 0xf, 0xc9, 0x7f, 0x32, 0xb1, 0x2d, 0xff, 0x52, 0xe2, 0xd3, 0xff, 0xf7, 0x31, 0xe5, 0x1d, 0x2, 0xfa, 0x5e, 0xad, 0x0, 0x7e, 0x76, 0xce, 0x38, 0xdf, 0xd2, 0xe9, 0x67, 0x7f, 0x9e, 0x77, 0x2f, 0x3b, 0xf2, 0x2f, 0x82, 0x5a, 0x9c, 0x7f, 0xde, 0x26, 0x3, 0xdc, 0x21, 0xff, 0x4f, 0x2a, 0xbe, 0x73, 0xfe, 0x3f, 0x15, 0xff, 0x94, 0xff, 0xf, 0x29, 0x9b, 0x3b, 0xbb, 0x3b, 0x97, 0xec, 0xbd, 0x4b, 0x2, 0x38, 0xd1, 0xca, 0x9b, 0x38, 0x82, 0x1c, 0x54, 0x2e, 0x9, 0xfb, 0x76, 0xa0, 0x5d, 0x6e, 0xf6, 0x6d, 0x44, 0x3b, 0x95, 0x83, 0xb7, 0xa2, 0xd7, 0x57, 0x8e, 0xbb, 0xa0, 0xee, 0x8d, 0xe3, 0x3b, 0xbb, 0xd4, 0xbe, 0xbe, 0x7d, 0xd, 0xde, 0xa0, 0x6, 0x60, 0x3, 0x47, 0xd8, 0xdd, 0x75, 0xfd, 0x11, 0xda, 0xbd, 0xde, 0x50, 0x54, 0x71, 0x76, 0x61, 0x83, 0xb6, 0x61, 0xc1, 0xce, 0x78, 0x6c, 0x20, 0x3f, 0x88, 0xf9, 0xf1, 0x9d, 0xe6, 0xc7, 0x30, 0xf3, 0xdd, 0xe6, 0xc7, 0x31, 0xef, 0xdb, 0x7d, 0xde, 0xc1, 0xbc, 0x91, 0xd4, 0x39, 0xe2, 0x1e, 0x41, 0xe3, 0x39, 0xe0, 0xdd, 0xd4, 0x7d, 0x7f, 0x3a, 0x8a, 0xfe, 0xc8, 0xd9, 0x3e, 0xc8, 0x7b, 0x4f, 0x80, 0xd8, 0x81, 0xb8, 0x86, 0x8a, 0xc2, 0x1e, 0x1f, 0x79, 0xb7, 0x38, 0xb2, 0xf2, 0xd7, 0x77, 0x17, 0xce, 0x32, 0x6d, 0x6a, 0xb9, 0x9b, 0x25, 0x9b, 0xe0, 0xcc, 0xc2, 0x3c, 0xe2, 0xfb, 0x3a, 0x1a, 0xb1, 0xd0, 0xd1, 0x77, 0x1f, 0x62, 0x42, 0x2d, 0xfe, 0x35, 0x9f, 0x36, 0xd5, 0x6d, 0x32, 0x87, 0xf, 0xf, 0xbf, 0x53, 0x2e, 0xf, 0x8e, 0x32, 0xd9, 0x5c, 0xce, 0xff, 0xdc, 0x52, 0xe9, 0xb5, 0xc, 0xaf, 0x27, 0x58, 0xe5, 0x4d, 0x44, 0xa2, 0x41, 0xac, 0xe1, 0x7, 0x98, 0xa3, 0xd5, 0x35, 0x54, 0xa7, 0xc4, 0xc4, 0xd6, 0x4c, 0x63, 0x20, 0x48, 0x56, 0x28, 0xdc, 0xed, 0xad, 0x4a, 0xa6, 0x53, 0xac, 0x4f, 0x37, 0xfb, 0xc9, 0x37, 0x7a, 0x18, 0x10, 0xf7, 0x3a, 0xed, 0x2, 0x39, 0x47, 0x76, 0x36, 0x81, 0x9c, 0x6d, 0xaf, 0x23, 0xdf, 0x2d, 0x84, 0x7e, 0x82, 0x94, 0xf1, 0xb5, 0x6d, 0xaa, 0xfb, 0xc6, 0x67, 0xcf, 0x4d, 0xef, 0xfe, 0xa4, 0x88, 0xeb, 0xe6, 0xf9, 0xd5, 0x3f, 0xfe, 0xb6, 0x7d, 0x9f, 0x46, 0x5c, 0x8, 0xfa, 0xdd, 0xff, 0xca, 0xc9, 0xcc, 0xb8, 0x5, 0xc1, 0x5f, 0x99, 0x8, 0xaa, 0x7c, 0x74, 0x7c, 0x97, 0xb0, 0xee, 0xd0, 0xe6, 0x46, 0xd0, 0xd, 0x7b, 0x4d, 0xe7, 0x36, 0xf2, 0xcd, 0xdb, 0x47, 0xbf, 0x6f, 0x63, 0x5d, 0xf3, 0xce, 0xa6, 0x1e, 0xd9, 0xad, 0xc9, 0xb3, 0x94, 0x98, 0xbe, 0x8a, 0x1c, 0x63, 0xd8, 0x79, 0xbc, 0x53, 0xdd, 0x24, 0xc4, 0x62, 0xc2, 0x31, 0xb6, 0x75, 0x45, 0x30, 0x42, 0x94, 0x3d, 0xe2, 0xdf, 0xde, 0x57, 0xd7, 0xf5, 0xa8, 0x88, 0x7f, 0xb9, 0xdc, 0x38, 0x6c, 0xf2, 0x52, 0xb9, 0x99, 0x9a, 0x86, 0xbc, 0x96, 0x9b, 0x40, 0xe6, 0x44, 0xa6, 0xb5, 0x8f, 0x3d, 0xb7, 0x79, 0x93, 0xd5, 0x67, 0xfc, 0xb9, 0xaf, 0xfa, 0x1c, 0xad, 0xfe, 0x31, 0x8c, 0xea, 0xa8, 0x77, 0xce, 0xa8, 0x7e, 0x24, 0x42, 0x97, 0x5d, 0x43, 0x15, 0x43, 0x2a, 0x8, 0xe4, 0xf, 0xc4, 0xef, 0xad, 0xef, 0xf3, 0x4f, 0xbc, 0x7, 0xea, 0x80, 0xfd, 0xe7, 0xa4, 0x69, 0x7f, 0xd7, 0xfc, 0xf, 0x89, 0x78, 0x7c, 0x27, 0xff, 0x43, 0x32, 0x1e, 0xfb, 0xb4, 0xff, 0x3e, 0xa2, 0x3c, 0xc7, 0xfe, 0x7b, 0xb7, 0x4, 0x90, 0x1b, 0xcc, 0xf6, 0x86, 0x76, 0x61, 0xf8, 0xc0, 0x35, 0x51, 0xef, 0xb7, 0x47, 0xb8, 0xdd, 0xa3, 0x8f, 0xd8, 0x26, 0xdc, 0x6e, 0xf3, 0xa9, 0x3b, 0x85, 0xbb, 0x70, 0x20, 0x70, 0xb3, 0xd0, 0x35, 0xf7, 0x9e, 0x74, 0xa5, 0x53, 0x50, 0xe5, 0x67, 0x6c, 0x19, 0x6, 0x81, 0xbf, 0x60, 0xd7, 0x70, 0x13, 0xcd, 0x53, 0x36, 0xe, 0x77, 0x37, 0xc8, 0x5a, 0xf5, 0xaa, 0xb8, 0x0, 0xb9, 0xbf, 0x7d, 0x11, 0x91, 0xb3, 0x3f, 0xa7, 0xe1, 0xa9, 0xb3, 0xdf, 0x11, 0x75, 0xee, 0x4d, 0x58, 0xe7, 0x54, 0xd8, 0xc1, 0x56, 0x2e, 0x5e, 0xf, 0x7b, 0xcd, 0x5d, 0x24, 0xcf, 0x34, 0xa6, 0x9e, 0xb8, 0xb9, 0xe7, 0xae, 0x7b, 0xe, 0x6d, 0xec, 0x79, 0x2b, 0xb2, 0x4d, 0x70, 0x66, 0x94, 0x84, 0xe5, 0x75, 0x94, 0xef, 0x1e, 0xc, 0xae, 0xed, 0x12, 0xb4, 0x13, 0xb8, 0xf5, 0x6e, 0xcf, 0x5e, 0x5e, 0x30, 0x9d, 0xaf, 0xdc, 0xc7, 0x5b, 0x1f, 0x25, 0x7b, 0x52, 0x9f, 0x5e, 0x7f, 0x31, 0x91, 0xff, 0xac, 0x4d, 0xc0, 0xc6, 0x99, 0xc3, 0x8c, 0xef, 0xbf, 0xd, 0xe8, 0x34, 0xf4, 0x7e, 0x5b, 0x80, 0x4e, 0x3, 0xff, 0x98, 0x24, 0x97, 0x9f, 0x65, 0x6f, 0x39, 0x64, 0xff, 0x9, 0x4b, 0xfe, 0x5d, 0xed, 0xbf, 0x78, 0x72, 0x3b, 0xfe, 0x2b, 0x96, 0x49, 0x4a, 0x9f, 0xf6, 0xdf, 0x87, 0x94, 0xbf, 0x95, 0xfd, 0xc7, 0x99, 0xed, 0x4d, 0xed, 0x3f, 0x81, 0xf1, 0xe7, 0xd9, 0x7f, 0x6e, 0x8f, 0x3e, 0xd2, 0xfe, 0x73, 0xdb, 0x7c, 0xae, 0xfd, 0xb7, 0x86, 0x3, 0x8f, 0xda, 0x7f, 0x42, 0x25, 0x3c, 0xd1, 0xfe, 0xf3, 0x57, 0x7e, 0x81, 0xfd, 0xe7, 0x7, 0x7f, 0x85, 0xfd, 0x27, 0xd0, 0x7c, 0x80, 0xfd, 0xc7, 0x1b, 0x7a, 0x2f, 0xfb, 0xcf, 0xe7, 0xa3, 0xd8, 0xc1, 0xdb, 0xee, 0xc, 0xa, 0xbd, 0xd1, 0x75, 0xbf, 0x5e, 0x6d, 0x57, 0x7a, 0xd7, 0xe5, 0xca, 0x49, 0x61, 0xd8, 0x1c, 0x14, 0x9a, 0xf5, 0x42, 0x3f, 0xb0, 0xad, 0xe0, 0x1, 0x42, 0xfa, 0x22, 0xb2, 0x1f, 0xd1, 0x3b, 0x9b, 0x9d, 0x3f, 0xc3, 0x34, 0xfc, 0x34, 0x3b, 0xe, 0xcd, 0xff, 0x6f, 0x91, 0x1, 0xfc, 0xc0, 0xfc, 0x1f, 0x8b, 0x49, 0xdb, 0xfe, 0x9f, 0x74, 0xe6, 0x73, 0xfe, 0xff, 0x98, 0xf2, 0xa2, 0xfd, 0xbf, 0xfd, 0xf1, 0x1, 0xcf, 0x4b, 0x93, 0xf0, 0x16, 0xb1, 0x1, 0x6e, 0x64, 0x0, 0xcf, 0xae, 0xf0, 0x86, 0x41, 0x0, 0x9b, 0x5e, 0x91, 0x9d, 0xb4, 0xd, 0x2f, 0x1c, 0x8b, 0xb7, 0x37, 0x7c, 0xf6, 0xe, 0x48, 0x26, 0x9b, 0xcb, 0xbd, 0xc7, 0x80, 0x8, 0x5a, 0x3f, 0xf, 0x7c, 0xfe, 0x7b, 0x94, 0x1d, 0xfd, 0xef, 0x3a, 0x31, 0xbc, 0x3f, 0x5e, 0x1f, 0x3, 0x72, 0x70, 0xfd, 0x97, 0xce, 0xec, 0xac, 0xff, 0x62, 0xa9, 0x4f, 0xfd, 0xff, 0x11, 0xe5, 0x5d, 0xce, 0x7f, 0xbe, 0x32, 0xe9, 0xcc, 0x23, 0xa7, 0x3f, 0x17, 0x2e, 0xad, 0x52, 0x24, 0xc6, 0x1f, 0xa8, 0x64, 0xea, 0xad, 0xa2, 0xc4, 0xb1, 0xc6, 0x8d, 0xe3, 0x95, 0x82, 0x8e, 0x88, 0x4a, 0xa6, 0x4d, 0xf6, 0x76, 0x6d, 0xc2, 0x4e, 0x30, 0x52, 0x15, 0x9f, 0xe9, 0xea, 0xec, 0xf5, 0xe6, 0x81, 0xb, 0x23, 0x16, 0x50, 0x4e, 0x4e, 0x4b, 0xa7, 0xda, 0x56, 0xf6, 0x50, 0xf, 0x3d, 0x19, 0xdf, 0x22, 0xd9, 0xea, 0x8b, 0xca, 0x8e, 0x3b, 0x6b, 0x6b, 0x25, 0xb2, 0xa7, 0x6e, 0xd0, 0x32, 0x72, 0x37, 0xef, 0xe7, 0x4, 0xab, 0x88, 0xae, 0xa8, 0x85, 0x7c, 0x67, 0x5a, 0x4c, 0x42, 0x2c, 0x5, 0x9b, 0x5c, 0xb7, 0xaf, 0x7c, 0xf9, 0x7c, 0x37, 0xe8, 0xf, 0xc8, 0xe6, 0xc9, 0x6f, 0xf7, 0x5b, 0xa3, 0x51, 0xe1, 0xa, 0x99, 0x58, 0x9f, 0x90, 0x3c, 0xc0, 0xba, 0x86, 0x34, 0xe2, 0x41, 0x6a, 0x10, 0xeb, 0x16, 0xd2, 0xa1, 0x2e, 0xfb, 0xaa, 0xdb, 0x86, 0x4a, 0xa0, 0x62, 0xd8, 0xe6, 0x14, 0xeb, 0xd3, 0xcd, 0xab, 0xef, 0xb8, 0xc9, 0x90, 0x7, 0x13, 0xa8, 0x7a, 0x59, 0xa1, 0x15, 0xa4, 0x22, 0xcb, 0x7, 0xed, 0x55, 0xb2, 0x4c, 0x1b, 0x85, 0x1e, 0x1b, 0x51, 0x7e, 0x30, 0xd6, 0x25, 0x9a, 0xff, 0x8, 0x5a, 0xde, 0x6d, 0x55, 0xdf, 0x1d, 0xcc, 0xad, 0xde, 0xfb, 0x93, 0xe5, 0x40, 0x45, 0x31, 0xf3, 0x20, 0x9f, 0x92, 0x24, 0x37, 0xa4, 0xf0, 0xb, 0xa0, 0xc8, 0x2, 0xb, 0xc, 0xd9, 0x3a, 0x10, 0x9b, 0x44, 0xd7, 0x18, 0xae, 0x5, 0x34, 0x31, 0xa3, 0xda, 0x57, 0x89, 0xfb, 0x89, 0x81, 0xa1, 0x42, 0x19, 0xcd, 0x88, 0xaa, 0x78, 0x8b, 0x66, 0xbe, 0x79, 0xed, 0xbb, 0x4e, 0x90, 0xb7, 0xa0, 0x12, 0x19, 0xaa, 0x3c, 0x9d, 0x4f, 0x4a, 0x92, 0x4, 0xcf, 0x42, 0xdb, 0x9a, 0xe5, 0x3d, 0x77, 0xe9, 0x1c, 0xe9, 0xbe, 0x9b, 0xa, 0x79, 0xc4, 0x40, 0x1e, 0x4, 0x84, 0x11, 0xf8, 0x56, 0xbc, 0x50, 0xd5, 0x5e, 0x19, 0xeb, 0xb0, 0xc1, 0x46, 0xeb, 0x50, 0x4, 0x67, 0x5d, 0xb6, 0x9e, 0x3, 0xb6, 0x3d, 0xfb, 0x9e, 0x98, 0x38, 0x4, 0x7a, 0xdc, 0xc6, 0x6b, 0x6c, 0xdc, 0x5f, 0xe8, 0x76, 0xca, 0xbd, 0x14, 0x31, 0x60, 0x9d, 0x28, 0x90, 0xf8, 0xb8, 0x48, 0xc1, 0x34, 0x80, 0x8d, 0x38, 0xe3, 0x99, 0x6a, 0x1e, 0xbc, 0xfe, 0x52, 0x45, 0x1f, 0x46, 0xff, 0xcd, 0x91, 0x92, 0xb6, 0xf1, 0x66, 0x66, 0x22, 0xca, 0xbe, 0x6c, 0x1e, 0xa4, 0x7c, 0x8f, 0xc7, 0x50, 0x9e, 0x93, 0xc9, 0x24, 0xf, 0x62, 0xf4, 0xdf, 0x67, 0xb9, 0xf8, 0x84, 0xf9, 0xff, 0x67, 0xdc, 0xff, 0x12, 0xcf, 0x7c, 0xe6, 0xff, 0xf9, 0x90, 0xf2, 0xf6, 0xe7, 0x3f, 0x5e, 0x39, 0xf9, 0x7, 0x9e, 0xfe, 0x60, 0x82, 0xdf, 0x77, 0xf4, 0x6e, 0xd0, 0xfc, 0xbe, 0x7e, 0xbf, 0xe7, 0x8, 0x87, 0xab, 0xc8, 0x82, 0xc1, 0xd9, 0xdb, 0x52, 0x70, 0x8e, 0x9b, 0x9f, 0xfd, 0x7d, 0xde, 0xbb, 0x3c, 0x45, 0xfe, 0xdf, 0xf9, 0xfe, 0x97, 0x54, 0x3c, 0xb5, 0x1d, 0xff, 0x9d, 0x49, 0x26, 0x3f, 0xe3, 0xbf, 0x3f, 0xa4, 0xbc, 0xfb, 0x85, 0x2e, 0xaf, 0x4e, 0x40, 0xb9, 0xe1, 0x84, 0xf0, 0xec, 0x8d, 0x37, 0xba, 0xd0, 0xc5, 0x4f, 0xdd, 0x7b, 0xee, 0x7, 0xf9, 0xac, 0xf2, 0x8f, 0xd8, 0xa, 0xda, 0x5c, 0xc4, 0x3c, 0x69, 0x17, 0x68, 0x6b, 0xdd, 0x10, 0xb4, 0x1, 0xe4, 0xe9, 0xcb, 0x3, 0x7b, 0x3f, 0x5b, 0xf5, 0x9e, 0xb1, 0xed, 0xb3, 0x5, 0xf9, 0x82, 0x1d, 0x1f, 0xdf, 0x92, 0xe0, 0xc0, 0x66, 0x8f, 0x7b, 0xf3, 0x2c, 0xf7, 0xf0, 0x79, 0xd7, 0xcc, 0x7a, 0xea, 0x6f, 0xbd, 0xf8, 0xf4, 0x5d, 0x34, 0xbb, 0xe7, 0xc4, 0x7f, 0xaf, 0x52, 0xad, 0xf7, 0x7, 0xbd, 0xd1, 0x75, 0x6d, 0x30, 0xe8, 0x3a, 0x67, 0x5, 0x7d, 0xd5, 0x9c, 0x8d, 0x97, 0xed, 0xab, 0x61, 0x0, 0xf0, 0x1d, 0x6b, 0xc, 0xb8, 0x1f, 0xe6, 0xa5, 0x52, 0xb6, 0x59, 0x78, 0xd8, 0xfe, 0x7a, 0x7e, 0xf4, 0xde, 0x1f, 0x4a, 0x21, 0xe0, 0x5b, 0x18, 0x5, 0xbf, 0x8d, 0xed, 0xd9, 0xc, 0x72, 0x96, 0x74, 0x50, 0x57, 0xc0, 0xaf, 0xfe, 0xbc, 0x82, 0xc1, 0x2b, 0xe0, 0xaf, 0x4f, 0xbb, 0x5f, 0x66, 0x97, 0x4f, 0x9f, 0x72, 0xb7, 0x8d, 0xc7, 0xd3, 0x3b, 0xab, 0xe0, 0x0, 0x7c, 0x4f, 0xc, 0x76, 0x7a, 0x7c, 0x7d, 0xb4, 0x3f, 0xf2, 0x29, 0xa0, 0xc5, 0x83, 0xfb, 0x63, 0x1, 0xcc, 0x18, 0xd4, 0xd2, 0xce, 0xdb, 0x3d, 0x5b, 0x69, 0x87, 0xbb, 0xfa, 0xd6, 0x31, 0x50, 0x87, 0x3b, 0xfd, 0xca, 0x8d, 0xbc, 0x3, 0x21, 0x57, 0x1e, 0xcf, 0xbd, 0x7f, 0xd0, 0x95, 0xd7, 0xd4, 0xfb, 0x85, 0x5d, 0x79, 0x4d, 0xbc, 0xc7, 0xc5, 0x40, 0x6f, 0x27, 0xaf, 0xcf, 0xbd, 0x41, 0x28, 0x48, 0xa2, 0xdf, 0xf3, 0xfe, 0x20, 0xaf, 0x63, 0x2f, 0xbe, 0x36, 0x28, 0x18, 0xc3, 0xb3, 0x6e, 0xb, 0x3a, 0x8c, 0xe2, 0x7d, 0x2e, 0x9, 0x7a, 0x12, 0xe9, 0x1f, 0x72, 0x37, 0xd0, 0x1e, 0x4a, 0x1e, 0xbd, 0x12, 0xe8, 0x67, 0x5b, 0xcb, 0xff, 0x7e, 0xe5, 0x29, 0xeb, 0xbf, 0xf7, 0xbe, 0xff, 0x27, 0x29, 0xa5, 0xb6, 0xd7, 0x7f, 0xa9, 0xcc, 0x67, 0xfe, 0x8f, 0xf, 0x29, 0xef, 0x70, 0xfe, 0xff, 0x95, 0x2b, 0xbe, 0xc7, 0x2e, 0xf4, 0x11, 0x36, 0xe9, 0x9b, 0x6d, 0x69, 0xbb, 0x94, 0xfe, 0xec, 0x8f, 0xf0, 0x13, 0xcb, 0x8e, 0xfc, 0xdb, 0x38, 0x6a, 0xe3, 0xb7, 0x39, 0xf7, 0xef, 0x96, 0xc3, 0xf2, 0xbf, 0x1d, 0xff, 0x93, 0xcc, 0xc4, 0x3e, 0xe3, 0x7f, 0x3e, 0xa4, 0xbc, 0xcb, 0xfe, 0xaf, 0x8d, 0x5f, 0xb9, 0xf3, 0xb, 0xd, 0x23, 0xc2, 0x56, 0x6, 0xde, 0xbe, 0x2f, 0x34, 0xc, 0x86, 0x1f, 0xfc, 0x6, 0x6a, 0xeb, 0x3d, 0x23, 0xd3, 0xd6, 0x35, 0x66, 0xaf, 0xfd, 0x6, 0xc, 0x93, 0x28, 0xfc, 0x91, 0x30, 0x44, 0xa7, 0xf, 0xd8, 0x0, 0xbf, 0x89, 0x5d, 0x46, 0xfe, 0xf8, 0x77, 0x56, 0xe1, 0xf, 0x6f, 0xf, 0x90, 0x67, 0xda, 0xfd, 0x4d, 0xe4, 0xd, 0xf9, 0xd9, 0x1f, 0xe0, 0x27, 0x97, 0x3d, 0xf2, 0xff, 0xaa, 0x7c, 0xaf, 0xdb, 0xe5, 0x90, 0xff, 0x37, 0x95, 0x8c, 0x6f, 0xc9, 0x7f, 0x2a, 0x26, 0x7d, 0xde, 0xff, 0xfd, 0x21, 0xe5, 0x63, 0xf2, 0xbf, 0xbe, 0x58, 0x21, 0x6c, 0x4d, 0xd8, 0x36, 0xde, 0xe3, 0xf8, 0x7d, 0xb1, 0x53, 0x75, 0x9f, 0xb9, 0xb0, 0xcf, 0xb3, 0xea, 0xdc, 0x7f, 0xf3, 0x34, 0x9f, 0xaa, 0xef, 0xb2, 0x9c, 0x5d, 0x6f, 0xaa, 0x8d, 0xf, 0xf9, 0x51, 0xbd, 0x1a, 0xcf, 0xf0, 0xa0, 0x7a, 0x30, 0xc1, 0xbe, 0xd3, 0x3d, 0xe, 0x4c, 0x2f, 0xc3, 0xd9, 0xc7, 0x7a, 0x2d, 0x5, 0x5b, 0x6c, 0x16, 0xee, 0xaf, 0xa4, 0x9b, 0xbe, 0xca, 0x35, 0xa1, 0x3b, 0x9, 0xdd, 0xfe, 0x26, 0x4, 0xaf, 0x53, 0x46, 0xf5, 0xf7, 0x91, 0xfe, 0xbc, 0xc, 0xaf, 0xaf, 0x4c, 0x27, 0x5b, 0xea, 0xb4, 0x4f, 0xea, 0xd5, 0xed, 0x3, 0xb, 0x1e, 0x18, 0xf7, 0x2e, 0xda, 0x38, 0xea, 0xce, 0xb3, 0x1, 0x18, 0x2a, 0xed, 0x42, 0xb1, 0x59, 0xb9, 0xae, 0x15, 0x7a, 0xc5, 0x4e, 0xef, 0xba, 0x5f, 0x2a, 0xb4, 0xaf, 0x3b, 0xed, 0xeb, 0xee, 0xb0, 0x1f, 0x88, 0xf0, 0x28, 0x76, 0x14, 0x80, 0xa3, 0x50, 0x6e, 0xd5, 0xdb, 0xec, 0x7b, 0x55, 0x7a, 0x5b, 0xa7, 0x1e, 0xd6, 0x80, 0x2f, 0x4c, 0x26, 0xef, 0xa2, 0x79, 0xc3, 0x4c, 0xb8, 0xcc, 0xec, 0x3d, 0xe4, 0x91, 0xd, 0x1e, 0x33, 0xcf, 0x13, 0xbb, 0xf3, 0xce, 0x87, 0xdb, 0x49, 0xa1, 0x19, 0x9e, 0xa3, 0xd5, 0xe3, 0xd, 0x6c, 0x56, 0xf0, 0x70, 0xfb, 0x1f, 0x7, 0xa0, 0x35, 0x4c, 0xbc, 0x80, 0x16, 0x3a, 0x8c, 0xde, 0xa9, 0x78, 0x3d, 0x47, 0xab, 0x88, 0x81, 0xb4, 0xa0, 0xa6, 0xf6, 0x55, 0xd9, 0xe7, 0x2a, 0xdc, 0xbe, 0x32, 0xe8, 0xeb, 0xde, 0xb, 0x25, 0x3, 0x1c, 0xf0, 0x32, 0xc, 0x2b, 0x64, 0xa9, 0xab, 0x4, 0x2a, 0x8f, 0x13, 0x2e, 0xc3, 0xa8, 0xc8, 0x8f, 0x13, 0xe8, 0x3, 0xdf, 0x7c, 0xf3, 0x88, 0xc3, 0xdf, 0xa0, 0xf2, 0xe3, 0xed, 0xf0, 0x8, 0xa9, 0xc7, 0x3d, 0xe9, 0xbb, 0xac, 0xf2, 0x4a, 0x3f, 0xf6, 0x5a, 0xb1, 0x1c, 0xe0, 0x98, 0xd7, 0x7b, 0xe8, 0x37, 0x75, 0x18, 0xb6, 0x90, 0x46, 0x37, 0x55, 0x62, 0xd8, 0xaf, 0x83, 0x1b, 0x1b, 0xec, 0x4, 0xbc, 0x9b, 0x25, 0xd6, 0x34, 0x3d, 0x91, 0x17, 0x3f, 0x8e, 0xf0, 0xfd, 0xc, 0xbe, 0x26, 0x3f, 0xb8, 0xce, 0x1b, 0xf2, 0xf7, 0x63, 0xdc, 0xfd, 0xfa, 0xa1, 0xf0, 0xdd, 0x50, 0x75, 0x78, 0x3c, 0x76, 0x84, 0x66, 0x3d, 0xc, 0x1b, 0xaf, 0x76, 0x64, 0x26, 0x48, 0x62, 0xe, 0x67, 0xbc, 0xb6, 0xf1, 0x7, 0xec, 0xb6, 0xd8, 0xf8, 0x1d, 0xf7, 0x59, 0x6c, 0xfc, 0x3f, 0x27, 0xb3, 0xf5, 0x9e, 0xf5, 0xdf, 0xab, 0xf2, 0x3d, 0x6f, 0x97, 0x43, 0xfe, 0x9f, 0x74, 0x6c, 0x3b, 0xfe, 0x27, 0x95, 0xc9, 0x7c, 0xc6, 0xff, 0x7c, 0x48, 0x79, 0xfb, 0xf8, 0xbf, 0x17, 0xaf, 0xf5, 0xde, 0x30, 0xef, 0x33, 0xdd, 0x8d, 0x15, 0x7c, 0x34, 0x5d, 0x73, 0x8, 0x6c, 0xcf, 0x8, 0xdb, 0xb0, 0xce, 0xeb, 0x6, 0x5a, 0x75, 0x91, 0xb6, 0x7, 0xc5, 0xf6, 0x22, 0xe0, 0xf9, 0xc9, 0xa6, 0x3f, 0xfe, 0xfb, 0xef, 0x93, 0xff, 0xb7, 0x38, 0xf7, 0xe9, 0x96, 0x83, 0xfe, 0xdf, 0xd8, 0xf6, 0xf9, 0x9f, 0x54, 0x2c, 0xf6, 0xe9, 0xff, 0xf9, 0x90, 0xf2, 0xe, 0xfb, 0x3f, 0x2f, 0x56, 0x0, 0x3f, 0x3b, 0xef, 0xb3, 0x8d, 0xff, 0xe6, 0x93, 0xf5, 0x3b, 0x14, 0x47, 0xfe, 0x23, 0x33, 0xa4, 0x6a, 0x78, 0xaa, 0x13, 0x13, 0xbd, 0x7d, 0x1b, 0x87, 0xe4, 0x3f, 0x15, 0xdb, 0xde, 0xff, 0x8d, 0xa7, 0x92, 0x9f, 0xf1, 0xff, 0x1f, 0x52, 0xbe, 0x80, 0x2e, 0xb4, 0x2c, 0x64, 0xea, 0x14, 0x58, 0x4, 0x8, 0xe, 0x0, 0xcb, 0x19, 0xd2, 0xc1, 0xd8, 0xc6, 0xaa, 0x82, 0xf5, 0x29, 0x30, 0xa0, 0x3c, 0x87, 0x53, 0x44, 0x23, 0xa1, 0x2f, 0x60, 0x30, 0xc3, 0x14, 0x50, 0x9b, 0xef, 0xa0, 0x50, 0x40, 0x67, 0x48, 0x55, 0xc1, 0x54, 0x25, 0x63, 0x11, 0x2e, 0x8b, 0xf5, 0xe9, 0x77, 0x60, 0x22, 0x15, 0x5a, 0x78, 0x81, 0xf8, 0x12, 0xc3, 0xf7, 0x1c, 0xea, 0x4a, 0xe8, 0xb, 0xd0, 0xd1, 0x94, 0x5b, 0xd0, 0xe0, 0x57, 0xc3, 0x44, 0x13, 0x7c, 0x8f, 0x14, 0x61, 0x7b, 0xff, 0xff, 0xbe, 0x46, 0x40, 0x47, 0x57, 0x57, 0x80, 0xe8, 0x1c, 0x92, 0x91, 0x4, 0xc, 0x64, 0x2, 0x15, 0xeb, 0x28, 0x12, 0x8a, 0x94, 0xfb, 0xd7, 0x7d, 0x8b, 0x98, 0x28, 0xf4, 0x5, 0x88, 0x3b, 0x81, 0xc1, 0x79, 0xa9, 0xf, 0x14, 0x6c, 0xd2, 0x50, 0x64, 0x8a, 0xad, 0x28, 0xff, 0xbf, 0x20, 0x3f, 0x14, 0x19, 0x3f, 0x98, 0x51, 0xfe, 0x7f, 0xf7, 0xc1, 0x6c, 0x1a, 0x65, 0xff, 0x73, 0x7f, 0xd2, 0x85, 0x1e, 0x5d, 0x23, 0x1a, 0x43, 0x79, 0x6e, 0x1b, 0xe2, 0x90, 0x5d, 0xe8, 0x5b, 0x84, 0x2e, 0x8d, 0xd0, 0xb7, 0xc8, 0x18, 0xce, 0x43, 0xdf, 0x22, 0x96, 0x66, 0x84, 0xbe, 0xfd, 0xbf, 0xd0, 0x17, 0x70, 0xe, 0x4d, 0x4c, 0x6c, 0xa, 0xea, 0xe5, 0xa, 0xd, 0x45, 0xc, 0x93, 0xdc, 0x22, 0xd9, 0xa, 0x45, 0xb0, 0x82, 0x60, 0x54, 0xd4, 0x33, 0xc9, 0xed, 0x3f, 0x51, 0x7b, 0x38, 0xf2, 0x5f, 0xea, 0xb4, 0x7, 0xbd, 0x7a, 0x71, 0x38, 0xa8, 0xb7, 0xab, 0x11, 0x4d, 0x79, 0xdb, 0x36, 0xe, 0xc8, 0x7f, 0x4c, 0xca, 0x6c, 0xcf, 0xff, 0xf1, 0x74, 0x32, 0xf1, 0x29, 0xff, 0x1f, 0x51, 0x98, 0x14, 0xe8, 0x96, 0x89, 0xc7, 0xb6, 0xc5, 0x64, 0xdd, 0x22, 0xa0, 0x86, 0x54, 0xd, 0x94, 0x66, 0xd0, 0xb4, 0xc0, 0x84, 0x98, 0xee, 0x7e, 0x6b, 0xa8, 0xcb, 0x6f, 0x34, 0x5, 0x13, 0xa2, 0xaa, 0x64, 0x9, 0x7e, 0x17, 0x8f, 0xb9, 0xb7, 0xd5, 0x3, 0x9e, 0xda, 0x58, 0x41, 0x7f, 0xfc, 0xea, 0x9e, 0x4b, 0x9c, 0x62, 0x6b, 0x66, 0x8f, 0x23, 0x32, 0xd1, 0xa2, 0xb, 0x6d, 0x9, 0x4d, 0x14, 0x75, 0x98, 0x6d, 0xac, 0x92, 0x71, 0x54, 0x5c, 0x7a, 0xba, 0xcd, 0x78, 0x5f, 0x19, 0x5, 0x2a, 0x82, 0xa6, 0xe, 0x66, 0x64, 0xc9, 0x7e, 0x68, 0x70, 0x8e, 0x80, 0x4c, 0x14, 0xe4, 0x6b, 0x8b, 0xe8, 0x91, 0x50, 0xc8, 0x47, 0x39, 0x32, 0x69, 0x28, 0x34, 0x98, 0x41, 0x7d, 0x4e, 0xc1, 0x2, 0x99, 0x2b, 0xa0, 0xd9, 0xf2, 0x8c, 0x1, 0x43, 0x55, 0x5d, 0x83, 0x21, 0x93, 0x82, 0xe5, 0x8c, 0x0, 0x6a, 0x8f, 0x35, 0x6c, 0x59, 0x48, 0x1, 0x86, 0xad, 0xaa, 0x5e, 0xbc, 0xda, 0xde, 0xbe, 0x47, 0x42, 0xa1, 0x30, 0xf8, 0xbd, 0xb, 0x6d, 0x15, 0x94, 0x1e, 0xa0, 0x39, 0x27, 0x4b, 0x3a, 0xc7, 0xe0, 0x5f, 0x6, 0xb4, 0x55, 0xf9, 0x1, 0x9a, 0x81, 0x1d, 0x76, 0x5f, 0x7e, 0x65, 0xa0, 0x4d, 0x5b, 0x86, 0xa0, 0xae, 0xeb, 0x44, 0x46, 0xba, 0x85, 0x41, 0xb, 0x9b, 0x26, 0x6, 0xff, 0x52, 0x6d, 0x19, 0x62, 0x2d, 0x10, 0x5a, 0xbc, 0xe2, 0xb0, 0x7d, 0xb, 0x2d, 0x90, 0xe, 0xa, 0xa6, 0x4e, 0x2c, 0xb, 0xfc, 0xab, 0x60, 0xca, 0x16, 0x96, 0xfb, 0x3a, 0x59, 0x6a, 0x50, 0xf, 0x84, 0xdd, 0xa8, 0xc1, 0x51, 0x14, 0x54, 0x74, 0xf, 0x5a, 0xe0, 0x5f, 0x8a, 0x9, 0x91, 0x49, 0x82, 0xa1, 0x9c, 0x77, 0xa2, 0x49, 0xa8, 0x4f, 0x4f, 0x6d, 0x1d, 0x8c, 0xec, 0xe0, 0xba, 0x23, 0x5b, 0x77, 0xaa, 0x7c, 0xfd, 0x27, 0x6a, 0xbc, 0xcf, 0xe2, 0x2f, 0x8e, 0x48, 0xf6, 0x2a, 0x85, 0x72, 0xab, 0xf2, 0xe6, 0x9a, 0x5f, 0x94, 0xc7, 0xf5, 0x7f, 0x22, 0x96, 0x49, 0x24, 0xb7, 0xf4, 0x7f, 0x2c, 0x9d, 0xf9, 0x5c, 0xff, 0x7d, 0x48, 0xf9, 0xb2, 0x4f, 0xdf, 0x7f, 0xf9, 0x2, 0xea, 0xba, 0x65, 0x12, 0xc5, 0x96, 0x99, 0xc2, 0x65, 0xfa, 0x15, 0x53, 0xf0, 0x3b, 0xab, 0x1d, 0xa8, 0x15, 0xe6, 0xf6, 0x18, 0x99, 0x3a, 0xb2, 0x10, 0x8d, 0xb2, 0xb5, 0xc4, 0x57, 0x20, 0x73, 0x94, 0x58, 0xa7, 0x16, 0x54, 0x55, 0xea, 0xce, 0x18, 0x2, 0x36, 0x1f, 0x75, 0xa6, 0x84, 0x88, 0x83, 0x1, 0x13, 0x77, 0x72, 0xf8, 0xa, 0xb0, 0xe, 0x20, 0x68, 0x78, 0xe8, 0x80, 0xac, 0xda, 0xfc, 0x7e, 0x6c, 0x50, 0xb2, 0x4d, 0x13, 0xe9, 0x96, 0xba, 0x2, 0x16, 0xa3, 0x45, 0x34, 0xe0, 0x19, 0xa3, 0xce, 0x8c, 0xb4, 0x88, 0x45, 0x92, 0x11, 0x89, 0x59, 0xa1, 0xfc, 0x6, 0x6e, 0x70, 0x81, 0x54, 0x99, 0x68, 0x88, 0x69, 0xf7, 0xdf, 0xd7, 0x53, 0xc1, 0x1f, 0xbf, 0x6, 0x4d, 0x3c, 0xfb, 0xd4, 0xff, 0x97, 0x2f, 0xa0, 0x6b, 0x22, 0x36, 0x51, 0x60, 0x8a, 0x2d, 0x44, 0xd9, 0x84, 0xb0, 0x4b, 0x20, 0x88, 0x45, 0xb2, 0xc7, 0xc2, 0x9a, 0x2d, 0x22, 0xb, 0x82, 0x42, 0xb7, 0x4e, 0xdd, 0x94, 0x7, 0x9b, 0x0, 0x75, 0xe1, 0xbe, 0x17, 0x13, 0x18, 0x51, 0x55, 0x64, 0x2, 0xec, 0xaf, 0xca, 0xc6, 0x52, 0xb6, 0x54, 0x50, 0x6a, 0xd6, 0x39, 0xd2, 0x50, 0xd8, 0x21, 0xad, 0x59, 0x7, 0xf1, 0x48, 0x36, 0x22, 0x1d, 0x73, 0x9a, 0x1a, 0x3a, 0x59, 0xea, 0xa0, 0x4e, 0xa9, 0x2d, 0x48, 0x1a, 0xac, 0x47, 0x45, 0x21, 0x88, 0xea, 0xbf, 0x58, 0xfc, 0xda, 0x73, 0x41, 0x92, 0xaf, 0x79, 0xbe, 0x99, 0x81, 0xad, 0x15, 0xb0, 0xd, 0x85, 0xad, 0xe3, 0x9d, 0xb1, 0x62, 0x4d, 0x45, 0x72, 0xc7, 0x7c, 0xfb, 0x23, 0x16, 0xc9, 0x45, 0x92, 0xc7, 0x11, 0xd0, 0x43, 0x13, 0x64, 0xf2, 0xb1, 0xe3, 0x49, 0x8, 0x40, 0x32, 0x99, 0x4b, 0x3f, 0x61, 0x86, 0xe7, 0x95, 0x69, 0x94, 0xd5, 0xfe, 0x2a, 0xc6, 0xaf, 0x8f, 0x2c, 0xdb, 0x8, 0xfc, 0xae, 0xa1, 0xd0, 0x88, 0xd8, 0x40, 0x86, 0x3a, 0xb0, 0x29, 0x2, 0x50, 0x5f, 0x1, 0x8b, 0x10, 0x95, 0x4f, 0xc7, 0xd4, 0x5, 0xca, 0xae, 0xb9, 0x20, 0x54, 0xd7, 0xc5, 0xe7, 0xe7, 0xd6, 0xc6, 0x77, 0xb0, 0x44, 0x1c, 0xee, 0x77, 0xd, 0xeb, 0x98, 0x8d, 0xdb, 0x21, 0xe6, 0x74, 0xeb, 0x7d, 0x5, 0x52, 0x24, 0x9e, 0x8a, 0x48, 0x7b, 0xda, 0x1, 0x90, 0x2, 0x6b, 0x86, 0x80, 0x82, 0x16, 0x51, 0xb, 0x51, 0xb, 0x20, 0x7d, 0x11, 0x9, 0xdd, 0xdc, 0xdc, 0x8c, 0x21, 0x9d, 0x85, 0xbe, 0x80, 0xbe, 0xc5, 0x86, 0xd9, 0x45, 0x16, 0x72, 0xff, 0x0, 0x94, 0x3f, 0xf, 0x87, 0x17, 0x5a, 0x58, 0x31, 0xf1, 0x2, 0x99, 0xbf, 0xe9, 0x44, 0x67, 0xab, 0x96, 0xa, 0xff, 0xba, 0x1, 0x9f, 0x7e, 0xd, 0xb, 0x15, 0x85, 0xe8, 0x2e, 0x1f, 0x0, 0x67, 0x8f, 0x87, 0xb5, 0x29, 0x84, 0x91, 0xb, 0x12, 0x37, 0xd2, 0x66, 0x48, 0x70, 0x69, 0x28, 0x74, 0x82, 0x4d, 0xea, 0x9, 0x99, 0x90, 0x4e, 0xc6, 0x25, 0x4f, 0x91, 0xd0, 0x2f, 0xe, 0xd4, 0xd7, 0xef, 0xc, 0xa1, 0xe, 0xb0, 0x8e, 0x2d, 0xc, 0x55, 0xfc, 0x80, 0x38, 0xb3, 0xad, 0x3b, 0xcb, 0x2a, 0xf3, 0xb7, 0x9c, 0x94, 0xb2, 0xb3, 0x9b, 0xe5, 0xca, 0x1b, 0x7f, 0x2b, 0x98, 0x8e, 0x59, 0x69, 0x6b, 0xb0, 0x29, 0xb6, 0x80, 0xac, 0xb2, 0xe5, 0xdc, 0x21, 0x76, 0x9, 0xc9, 0x8a, 0x6b, 0xa5, 0x71, 0xca, 0xdc, 0xc7, 0x1b, 0xcd, 0xb9, 0x19, 0x2d, 0x80, 0x82, 0xc, 0x24, 0x7c, 0x38, 0xbc, 0x55, 0xca, 0xd, 0x38, 0x6c, 0x22, 0x5, 0x8c, 0x57, 0x2e, 0x51, 0xfc, 0xcd, 0x56, 0xf, 0x5c, 0x38, 0xd9, 0xe5, 0x7b, 0x67, 0x64, 0x19, 0x6f, 0xca, 0xb6, 0x89, 0x80, 0xbb, 0xbb, 0x7, 0x5a, 0x44, 0x41, 0xa1, 0x50, 0x71, 0xe5, 0xdd, 0x64, 0xe3, 0x53, 0x37, 0x4b, 0xcc, 0x56, 0xbc, 0x48, 0x47, 0x26, 0x93, 0x1c, 0xc8, 0x4f, 0x79, 0x81, 0x52, 0x81, 0xb, 0x4d, 0xbf, 0xdf, 0x4, 0xbe, 0x53, 0x55, 0x5c, 0x87, 0xac, 0x88, 0xbd, 0x56, 0x24, 0x2e, 0xa3, 0x43, 0x95, 0x12, 0xce, 0xb5, 0xfc, 0x2d, 0x13, 0xe2, 0x52, 0x41, 0xdc, 0xed, 0xa1, 0xf8, 0x11, 0xe4, 0x43, 0x21, 0x62, 0x20, 0x5d, 0x84, 0x4a, 0x88, 0xbd, 0x98, 0xef, 0x3c, 0x47, 0x9, 0x63, 0x0, 0xfe, 0x10, 0x90, 0x9, 0xf8, 0xc5, 0x1d, 0x99, 0x32, 0xd1, 0x20, 0xd6, 0x7f, 0x61, 0xc, 0xed, 0x6b, 0x15, 0x9c, 0x9c, 0x95, 0xdb, 0x62, 0xf5, 0xcd, 0xd3, 0x9b, 0x78, 0x60, 0xe2, 0x26, 0xa0, 0x5f, 0xbe, 0xf3, 0xbf, 0x1a, 0x68, 0xc5, 0xfe, 0xe2, 0xf7, 0xe, 0xfd, 0x12, 0x1, 0x83, 0x19, 0x33, 0xb7, 0xf9, 0xea, 0x98, 0x87, 0x5d, 0x92, 0x9, 0x6f, 0xd3, 0xdf, 0x39, 0xcd, 0xa6, 0x96, 0x58, 0xdd, 0xef, 0xb4, 0x16, 0x9, 0x85, 0x1c, 0x6e, 0xe5, 0x50, 0xbb, 0x8c, 0xc2, 0x15, 0x12, 0xf4, 0xf4, 0xe, 0x6f, 0xe2, 0x46, 0x5b, 0x85, 0x9d, 0x7, 0x37, 0xf9, 0x6d, 0xde, 0x13, 0xc8, 0x22, 0x20, 0x1c, 0xe6, 0x1, 0x2f, 0x20, 0x1c, 0xe6, 0x30, 0x6b, 0x10, 0x10, 0xe, 0xb3, 0xde, 0x6d, 0xe, 0xc5, 0x6f, 0xae, 0xf, 0x70, 0x15, 0x51, 0xf8, 0x3, 0xfe, 0xc5, 0xbf, 0x7d, 0x6b, 0xb1, 0x25, 0x5, 0xb5, 0x4d, 0xf4, 0xed, 0x1b, 0xb8, 0xd9, 0xae, 0x73, 0xc3, 0xcf, 0xb4, 0xa8, 0xb, 0xc4, 0x35, 0x10, 0xa3, 0x9f, 0x69, 0x85, 0x0, 0x8d, 0x5d, 0xef, 0x2, 0xa2, 0xf3, 0xa, 0x1a, 0x94, 0x67, 0x58, 0x47, 0x6c, 0x75, 0x81, 0x4c, 0xfe, 0x51, 0x81, 0x69, 0xeb, 0x40, 0x21, 0xf2, 0x1c, 0x99, 0x80, 0x98, 0xce, 0x51, 0x24, 0x77, 0x20, 0x86, 0x75, 0x1f, 0x27, 0x28, 0x4a, 0x10, 0x9, 0x8c, 0x9b, 0xea, 0x5d, 0xa0, 0x41, 0xc3, 0x60, 0x2, 0x8f, 0x45, 0x3b, 0xe5, 0x76, 0xdf, 0xb9, 0x39, 0xe9, 0x3b, 0xc3, 0x8a, 0x75, 0x11, 0xb2, 0x30, 0x23, 0xd4, 0xa2, 0xfc, 0x9, 0x63, 0x29, 0x56, 0x91, 0x7d, 0x4, 0xf, 0xed, 0x7f, 0xd6, 0xbb, 0xff, 0x15, 0xb9, 0xc7, 0x46, 0x4, 0x93, 0x9b, 0x48, 0x28, 0x74, 0x22, 0x16, 0x70, 0xac, 0xda, 0x4d, 0xbb, 0x33, 0xa8, 0xf4, 0x6f, 0xd8, 0x7c, 0xc0, 0x5d, 0x32, 0x4e, 0x33, 0xec, 0xc3, 0x33, 0x2, 0x88, 0x6d, 0x19, 0xb6, 0xc5, 0x46, 0x61, 0x8a, 0x2c, 0x97, 0x78, 0x1e, 0x84, 0x3, 0xc, 0x48, 0xe9, 0x92, 0x98, 0xa, 0x27, 0xf4, 0xdb, 0x37, 0xd6, 0xb, 0xe7, 0xbd, 0x2b, 0xf, 0x58, 0xb7, 0x88, 0x3b, 0x2, 0xfc, 0x26, 0xa6, 0x4d, 0xd6, 0xa6, 0xdf, 0xbe, 0x31, 0x2e, 0x99, 0xf0, 0xc1, 0x82, 0x26, 0xd3, 0xe1, 0xac, 0xa3, 0x50, 0x5f, 0xcb, 0xb9, 0xb3, 0x5b, 0x2, 0x54, 0x3c, 0x47, 0xe0, 0x77, 0x6, 0x1b, 0xd6, 0xa0, 0xe, 0xa7, 0x28, 0x78, 0xc5, 0x75, 0x8b, 0x2c, 0x6a, 0x41, 0x79, 0x1e, 0xf5, 0xd7, 0xfc, 0xca, 0x65, 0xd0, 0x11, 0x57, 0x57, 0x75, 0xe, 0x9a, 0xfd, 0xd, 0x52, 0xbe, 0x87, 0x18, 0x11, 0x5c, 0xb0, 0x97, 0x50, 0xe7, 0x1d, 0x76, 0xf2, 0xd0, 0xec, 0x30, 0xbd, 0x8b, 0x89, 0xe8, 0x4c, 0xd9, 0x70, 0xe6, 0x1c, 0xaf, 0x98, 0x48, 0x7a, 0xc8, 0x85, 0x7c, 0xdd, 0xb8, 0x1a, 0xa2, 0xe4, 0x6b, 0xe7, 0x86, 0x61, 0xbe, 0xe6, 0x89, 0x6d, 0xae, 0xb9, 0x88, 0x89, 0xe1, 0x76, 0xf4, 0xfc, 0x2f, 0x0, 0xea, 0x3a, 0xb1, 0x9c, 0x3d, 0x67, 0x4e, 0xd, 0x9b, 0x4e, 0x64, 0xa8, 0xeb, 0x48, 0x9, 0x8d, 0x57, 0xe0, 0xda, 0xdf, 0xb1, 0x6b, 0x3e, 0xf2, 0xc, 0x1c, 0x1a, 0x86, 0x49, 0xc, 0x13, 0x33, 0xf2, 0x9c, 0x8d, 0x25, 0x47, 0x47, 0x59, 0x40, 0x36, 0x11, 0x64, 0x3, 0xcf, 0xea, 0xa, 0x9d, 0xc7, 0x95, 0x24, 0x3, 0x73, 0xf7, 0xa2, 0xf8, 0x47, 0x70, 0x6, 0x5f, 0xd6, 0xd0, 0x2f, 0x74, 0x73, 0x68, 0x80, 0x42, 0x80, 0x4e, 0xb8, 0x39, 0xc4, 0x10, 0xb2, 0x25, 0xb5, 0x22, 0xda, 0x15, 0x8e, 0x0, 0xf1, 0xd1, 0x5c, 0xba, 0x81, 0x45, 0x42, 0x5c, 0x19, 0xb8, 0x61, 0x11, 0x21, 0x26, 0x71, 0x4c, 0x6f, 0x85, 0x9c, 0x27, 0x3c, 0xb8, 0x7b, 0xdd, 0x4f, 0xe1, 0xe4, 0x5f, 0x4f, 0x4c, 0xcc, 0xe, 0xb4, 0x54, 0x1a, 0x66, 0xa4, 0xe4, 0xf9, 0x15, 0x5e, 0xe8, 0x88, 0xb, 0x6d, 0x68, 0xe0, 0x63, 0x4c, 0x85, 0x87, 0xa3, 0x7a, 0xf2, 0xe4, 0x48, 0x61, 0x80, 0x41, 0xe6, 0x30, 0xb4, 0xab, 0xc6, 0x45, 0x8c, 0x8e, 0x2d, 0x3e, 0x60, 0x84, 0xa3, 0xfc, 0x7d, 0xe3, 0xd9, 0x1f, 0xbf, 0x7e, 0xd9, 0xf8, 0xfd, 0xd5, 0x13, 0xd, 0x15, 0x73, 0xf, 0xc1, 0xc, 0x1, 0x3, 0x9a, 0x50, 0x43, 0xdc, 0x99, 0x60, 0xcd, 0xa0, 0xc5, 0xa5, 0x78, 0x8c, 0x3c, 0xdc, 0x48, 0x61, 0xad, 0xfa, 0x34, 0x36, 0x93, 0xcb, 0x5, 0x86, 0xe0, 0x17, 0xae, 0xa1, 0x7e, 0x11, 0xf0, 0x14, 0x28, 0xb6, 0x29, 0x24, 0x9b, 0xab, 0x36, 0x87, 0xa2, 0xd0, 0x7f, 0x81, 0x6f, 0xdf, 0x6, 0xd8, 0xf8, 0xf6, 0x2d, 0xf, 0x9a, 0x98, 0x5a, 0xdc, 0x7f, 0xe1, 0x68, 0x38, 0xea, 0x7c, 0xa5, 0x1b, 0xce, 0x75, 0x8c, 0x9e, 0x9b, 0x50, 0x88, 0x4f, 0x5f, 0x75, 0x27, 0x3a, 0x65, 0x7b, 0x2, 0xab, 0x4f, 0x3c, 0xce, 0x74, 0x46, 0xca, 0xab, 0x0, 0x29, 0x70, 0x63, 0x5a, 0xdc, 0xe3, 0x3a, 0x18, 0x51, 0x2e, 0x2c, 0x42, 0x66, 0x85, 0x4c, 0x28, 0x84, 0xd9, 0x90, 0x3a, 0x42, 0x8a, 0xd0, 0x2, 0xce, 0xac, 0xd7, 0x3b, 0x30, 0xe7, 0xf9, 0x94, 0xbe, 0xf3, 0xd9, 0xc5, 0xf4, 0xce, 0xf5, 0xe6, 0xdf, 0x76, 0x72, 0xf8, 0xbe, 0x1d, 0xe5, 0xf3, 0x1b, 0x3f, 0x3f, 0xf0, 0x39, 0x65, 0x84, 0xb8, 0xaa, 0xe2, 0xcd, 0x1e, 0x5, 0x70, 0xcd, 0x51, 0x1e, 0xfc, 0x7e, 0xb4, 0x4d, 0xcf, 0xd1, 0x1f, 0x37, 0x9e, 0xf4, 0x89, 0x3e, 0x29, 0x10, 0x31, 0x73, 0x42, 0xc8, 0x9, 0x77, 0xb6, 0x73, 0x92, 0x4d, 0x24, 0x2c, 0x66, 0xa7, 0xd6, 0x5a, 0x2d, 0x7d, 0xf9, 0x2, 0x86, 0x3a, 0xe, 0x34, 0x7a, 0x7, 0x4, 0xd8, 0xee, 0xab, 0xa8, 0xc8, 0x31, 0x27, 0xe6, 0x33, 0x1f, 0x97, 0x38, 0x4a, 0x42, 0x43, 0xba, 0x95, 0xf, 0x6d, 0x1b, 0x82, 0x1c, 0x62, 0x5d, 0x79, 0x57, 0xc3, 0x98, 0x48, 0x23, 0xec, 0x73, 0xba, 0x5c, 0xea, 0xd7, 0x2d, 0xee, 0x7e, 0x21, 0x5, 0x90, 0x52, 0x22, 0x63, 0xae, 0x55, 0x39, 0xd3, 0xf2, 0xd9, 0x82, 0xf3, 0xb0, 0xd0, 0x52, 0x2a, 0x7, 0x60, 0x4f, 0xdd, 0xd5, 0x28, 0xef, 0x56, 0xc9, 0xaf, 0x62, 0x44, 0xbb, 0x6b, 0x65, 0x6a, 0xb1, 0x79, 0x87, 0xfa, 0xf4, 0x8d, 0xa7, 0x90, 0xd8, 0x7c, 0xe4, 0x53, 0x3e, 0x8e, 0x49, 0xe6, 0x37, 0x78, 0xbd, 0x39, 0xc1, 0x55, 0x78, 0x8e, 0x1a, 0xa, 0x85, 0x7e, 0x80, 0xae, 0xb, 0x9, 0x76, 0xca, 0xf, 0x50, 0x46, 0x54, 0x36, 0x31, 0xbf, 0x5e, 0x6f, 0xf7, 0xf5, 0xba, 0x92, 0x40, 0xba, 0xf3, 0x26, 0xf4, 0x3, 0x84, 0x83, 0x8b, 0x0, 0xdc, 0xf3, 0xd2, 0x5f, 0x6f, 0x3f, 0x6, 0x86, 0xfd, 0xdb, 0x37, 0xd1, 0xcb, 0x6f, 0xdf, 0xf8, 0x4f, 0x87, 0x4b, 0xeb, 0x1a, 0x9c, 0xa2, 0x1, 0x9c, 0xde, 0x38, 0xf4, 0xb1, 0x71, 0xb4, 0xe0, 0xd4, 0xb7, 0x72, 0x77, 0x99, 0x8a, 0x7, 0xc4, 0x53, 0xf0, 0x3, 0xdc, 0x8, 0xe7, 0xc0, 0x8d, 0x40, 0xb3, 0xa9, 0xf, 0x6e, 0xbc, 0x8e, 0x3a, 0xc0, 0x7c, 0x16, 0x65, 0x42, 0x49, 0x74, 0xe0, 0x19, 0x1c, 0xdb, 0x40, 0xd1, 0xaf, 0x6c, 0x8d, 0xcc, 0xd8, 0x6, 0xb1, 0x39, 0x96, 0x6b, 0xe8, 0x3d, 0xc2, 0xcf, 0x25, 0xc, 0xd2, 0x9d, 0x76, 0xb9, 0x18, 0x6a, 0xae, 0x7e, 0x11, 0x6b, 0xd, 0x5e, 0xf7, 0xc9, 0x4a, 0x25, 0x2, 0x7e, 0x4, 0x69, 0x4, 0xde, 0xc9, 0x6d, 0xa5, 0xe6, 0x8e, 0x96, 0x98, 0x1c, 0x38, 0x6a, 0xd3, 0x46, 0xdf, 0xc1, 0xae, 0xba, 0xe7, 0xaf, 0xf9, 0x1a, 0x21, 0x2a, 0x16, 0x8, 0x51, 0xbe, 0x3a, 0xf8, 0xe, 0xc6, 0xb6, 0x25, 0xac, 0x7f, 0x9f, 0xd9, 0xe7, 0x76, 0x6e, 0xdf, 0xac, 0xc2, 0xad, 0x2, 0xe7, 0x73, 0xc8, 0x2a, 0x46, 0xba, 0xc5, 0x89, 0xe6, 0xc6, 0x90, 0x43, 0x69, 0xb0, 0xc9, 0x4, 0x7e, 0x80, 0xbe, 0xa0, 0x93, 0xd7, 0x5, 0x78, 0xb2, 0x6d, 0xbf, 0x79, 0xb6, 0x92, 0x30, 0x8d, 0xb8, 0x85, 0x13, 0x64, 0x47, 0xfe, 0x0, 0x37, 0xac, 0xab, 0x4e, 0x6b, 0xa2, 0x67, 0x37, 0x3b, 0x5c, 0xbe, 0x8d, 0xdc, 0x12, 0xb, 0xb5, 0x35, 0x53, 0xfd, 0x42, 0xc5, 0x7a, 0xd6, 0xcb, 0x6b, 0x18, 0x1, 0x75, 0x8b, 0x82, 0x52, 0xdb, 0xbf, 0x22, 0xda, 0xfe, 0xc6, 0xac, 0xb3, 0xd0, 0xb6, 0x48, 0xd8, 0xed, 0xa4, 0xe2, 0x51, 0xd1, 0x40, 0xab, 0x60, 0x2a, 0xe6, 0x68, 0xf5, 0x84, 0xd6, 0xf7, 0x20, 0xe6, 0x9f, 0x6a, 0x1b, 0x2f, 0xf8, 0xc1, 0x66, 0x6d, 0x7e, 0xd5, 0x2b, 0xc3, 0x48, 0x91, 0x3a, 0x71, 0x57, 0x9d, 0x6e, 0xb7, 0xf7, 0xa0, 0xb, 0xc8, 0xf5, 0x70, 0x3, 0x7e, 0xb8, 0x9e, 0xa, 0xef, 0xad, 0x5, 0x14, 0x68, 0x41, 0xf7, 0xb4, 0xff, 0xf6, 0x7, 0xf6, 0x82, 0xb6, 0x6e, 0x1c, 0x69, 0x75, 0xcc, 0x55, 0xd6, 0x51, 0x9b, 0x22, 0x85, 0x13, 0x85, 0x74, 0xd9, 0x5c, 0x71, 0x4d, 0x14, 0x1, 0x2d, 0x36, 0xa0, 0x63, 0xb6, 0xca, 0x66, 0x9c, 0xa4, 0x4f, 0x99, 0xce, 0x8b, 0xa5, 0xb9, 0xae, 0xa3, 0x9c, 0x7d, 0x74, 0x62, 0x85, 0x61, 0xd8, 0xe1, 0xb8, 0x39, 0x47, 0xcc, 0xd5, 0x45, 0x61, 0x7d, 0x52, 0xc0, 0xd5, 0x19, 0xbe, 0xc3, 0x3, 0x3b, 0xc7, 0x6e, 0x18, 0x3d, 0xbd, 0xf5, 0x21, 0x9c, 0x89, 0xbb, 0xcc, 0x11, 0xd5, 0x85, 0xfa, 0xe0, 0xda, 0xc3, 0xef, 0xb4, 0xf0, 0x1f, 0x47, 0xb8, 0xd9, 0xd7, 0x86, 0xc5, 0xd4, 0xd3, 0xf, 0x30, 0x70, 0xd4, 0x52, 0x30, 0x56, 0xbf, 0x4e, 0xda, 0x45, 0xb1, 0x3e, 0xc7, 0xc3, 0x30, 0x75, 0x6d, 0x55, 0x5, 0xce, 0xb1, 0x9e, 0xbd, 0x18, 0xeb, 0x93, 0x36, 0xb1, 0xba, 0x26, 0xa2, 0x48, 0xb7, 0x2, 0xf0, 0x22, 0xd, 0x62, 0xb5, 0x46, 0xa8, 0xc5, 0x3f, 0x21, 0xfb, 0xe1, 0x98, 0x8, 0xc, 0x96, 0x6a, 0x96, 0x11, 0xd1, 0x56, 0x42, 0x87, 0xb0, 0x85, 0xd5, 0x3e, 0x4, 0x5d, 0x62, 0xfa, 0x10, 0xf0, 0x13, 0x95, 0x3f, 0xc0, 0x4d, 0x3c, 0xb5, 0xaf, 0xfe, 0x90, 0xf2, 0x71, 0x72, 0xea, 0xdb, 0x94, 0x89, 0x87, 0xc6, 0xc9, 0xa5, 0x50, 0x33, 0x54, 0x74, 0xcd, 0x21, 0xfe, 0xf5, 0x94, 0xa6, 0xfb, 0x54, 0xdd, 0xc0, 0x44, 0x99, 0x15, 0xfa, 0xdf, 0xdb, 0xec, 0xb6, 0x3, 0x76, 0x62, 0x72, 0x94, 0x80, 0x32, 0x55, 0x2d, 0x80, 0x27, 0x26, 0xd1, 0x78, 0x9e, 0x56, 0xa6, 0x53, 0x5d, 0x18, 0xf0, 0x9f, 0x7b, 0x29, 0xfa, 0xaf, 0x7d, 0xb8, 0xeb, 0xa, 0xd2, 0x2d, 0x6c, 0xf1, 0x6f, 0xf4, 0x3, 0x1c, 0x1d, 0xed, 0x56, 0x13, 0xec, 0xe9, 0x7e, 0x30, 0x36, 0xda, 0x73, 0x1e, 0xbe, 0xb8, 0x87, 0x89, 0x3, 0x6, 0x7c, 0xc9, 0x65, 0xce, 0x5b, 0x7a, 0x73, 0x69, 0xe1, 0xbd, 0xd8, 0x46, 0xe2, 0x56, 0x9, 0xc0, 0xc4, 0xff, 0xee, 0xae, 0xdf, 0x6f, 0xa2, 0x13, 0xdd, 0x67, 0xdf, 0x86, 0xe1, 0x14, 0x1a, 0x27, 0x16, 0x4f, 0x24, 0x83, 0x3e, 0x2a, 0xb4, 0xad, 0x19, 0xeb, 0xb3, 0x48, 0xac, 0xca, 0x56, 0x1c, 0x37, 0x42, 0x79, 0xf8, 0x9e, 0x2, 0x7e, 0x3c, 0xd7, 0x37, 0x21, 0xff, 0xa, 0x6e, 0x94, 0xf1, 0x35, 0xab, 0x74, 0xc3, 0x1f, 0xf3, 0xe4, 0xb8, 0xc0, 0xbd, 0xe7, 0xe4, 0x3b, 0xb8, 0x51, 0x15, 0x68, 0xf8, 0xde, 0x37, 0xcb, 0x85, 0xee, 0x77, 0x80, 0x2c, 0x39, 0x12, 0x89, 0x7c, 0x5, 0xbf, 0x97, 0x89, 0x4c, 0x9f, 0xb9, 0xbf, 0xac, 0x10, 0x99, 0x46, 0x59, 0x8f, 0xae, 0xb9, 0xbf, 0x38, 0xa2, 0x29, 0x5f, 0xd8, 0xaf, 0x30, 0x94, 0x65, 0x62, 0xeb, 0xd6, 0x57, 0xd6, 0x51, 0x8f, 0xa4, 0x9d, 0x4e, 0x32, 0x15, 0xe9, 0xcc, 0x9c, 0xbc, 0x43, 0xac, 0x8b, 0x5, 0x66, 0xaa, 0x51, 0x3e, 0x4a, 0x7c, 0x6a, 0x16, 0x33, 0x1d, 0x32, 0x9d, 0x95, 0xb5, 0x46, 0x11, 0x9b, 0xb4, 0xbf, 0x3, 0x62, 0xcd, 0x90, 0xb9, 0xc4, 0x14, 0x1, 0xa2, 0xab, 0x2b, 0x31, 0xb6, 0x2, 0x11, 0x31, 0xa9, 0x67, 0xc9, 0xb, 0x34, 0x3f, 0xc0, 0xd, 0xd1, 0x3, 0xda, 0x67, 0xc3, 0x11, 0xb1, 0x4d, 0xce, 0xee, 0x6c, 0x2c, 0x5c, 0x41, 0x1d, 0xf6, 0x9a, 0x7c, 0x7c, 0xfc, 0xe3, 0xb5, 0x35, 0xf4, 0x3f, 0xc4, 0x4b, 0x36, 0x50, 0xfc, 0xdf, 0x7d, 0x8a, 0x8a, 0x37, 0x41, 0x11, 0x34, 0xe5, 0x59, 0xb9, 0xed, 0xb5, 0xd3, 0xe7, 0xf, 0x40, 0xb9, 0xcd, 0xf0, 0xec, 0x83, 0x62, 0xdf, 0xcc, 0x7, 0x53, 0x64, 0x4b, 0xad, 0xc7, 0x21, 0x26, 0x58, 0xb5, 0x84, 0x1a, 0xe0, 0x10, 0x27, 0xfc, 0x27, 0x3, 0xf8, 0x55, 0x24, 0x19, 0xe2, 0x9, 0x68, 0x7e, 0x63, 0xf3, 0x9, 0xd1, 0xbf, 0xee, 0x1d, 0xf, 0xac, 0x78, 0x18, 0x86, 0xf5, 0x32, 0x3, 0x17, 0x8f, 0x82, 0xbb, 0x26, 0x13, 0x3, 0xad, 0xfb, 0xc5, 0x7e, 0x71, 0x45, 0xb5, 0xaf, 0xbe, 0x93, 0x16, 0xd8, 0x83, 0x18, 0x88, 0xdf, 0xc, 0x26, 0x48, 0xc, 0x38, 0xcc, 0x2, 0x99, 0x78, 0xb2, 0x62, 0x13, 0xab, 0x7, 0x76, 0xce, 0x1f, 0x81, 0xda, 0x60, 0xd0, 0xed, 0x3, 0x9f, 0x49, 0xc3, 0xf0, 0xc, 0xd6, 0x66, 0x88, 0x1f, 0x95, 0x97, 0x4b, 0x87, 0x21, 0xf9, 0xdd, 0xfb, 0xb5, 0x66, 0xf8, 0x4d, 0x3f, 0x9, 0xe7, 0x6c, 0x99, 0xe8, 0x32, 0x32, 0x2c, 0x1a, 0xdd, 0xf0, 0x5b, 0x44, 0x85, 0x29, 0x14, 0x66, 0x6b, 0x15, 0xdb, 0x62, 0xc6, 0x98, 0x83, 0x2b, 0xec, 0x9d, 0x8e, 0x8b, 0x7e, 0x75, 0xe2, 0x23, 0x88, 0xb7, 0x6c, 0xf7, 0xde, 0x71, 0x4b, 0xc1, 0xd6, 0x15, 0x34, 0xc1, 0xba, 0x6b, 0x1, 0xf8, 0x9, 0x75, 0xe, 0x45, 0x31, 0x32, 0xf9, 0xbc, 0x6d, 0x11, 0xc7, 0xd3, 0x4, 0xba, 0xe7, 0x25, 0xca, 0x4c, 0x34, 0x9f, 0xbd, 0xe0, 0xdb, 0xd9, 0x2, 0xbf, 0x52, 0x84, 0xf8, 0x82, 0xdd, 0x14, 0x9b, 0x8a, 0x74, 0xcb, 0x57, 0xf2, 0x95, 0x6b, 0x67, 0xb4, 0xe1, 0x3e, 0xd9, 0x69, 0xdd, 0x7f, 0x8c, 0x84, 0x91, 0xd0, 0x66, 0x3a, 0x46, 0x84, 0x94, 0xf2, 0x6e, 0x18, 0x44, 0x61, 0x2b, 0x33, 0x3c, 0x15, 0xf9, 0xbb, 0x7f, 0x80, 0x9b, 0x3f, 0xff, 0xa, 0x18, 0x6d, 0xdf, 0x61, 0xe, 0x3e, 0x45, 0xfb, 0xe, 0x7c, 0x4, 0x63, 0xf9, 0xfd, 0x8f, 0x20, 0x2d, 0xe8, 0x1c, 0x39, 0x71, 0x9, 0x89, 0x76, 0x19, 0x9c, 0x78, 0x88, 0xc5, 0x9a, 0xc3, 0x6d, 0xfd, 0xdb, 0xb7, 0x53, 0x2f, 0x4, 0xdc, 0xb5, 0x4a, 0x7c, 0x41, 0xe1, 0x4f, 0x30, 0x4a, 0xd6, 0xb5, 0xf7, 0xd9, 0x24, 0xeb, 0x1a, 0x37, 0x7b, 0x1a, 0xd8, 0xb2, 0x48, 0x2, 0x51, 0xfa, 0xd, 0x92, 0x1d, 0x4, 0x8f, 0xdb, 0x23, 0x41, 0xf8, 0x2, 0xcc, 0x11, 0x1f, 0x56, 0x67, 0x5e, 0xf4, 0x1, 0x3e, 0x3e, 0x2f, 0xee, 0xc4, 0xd1, 0x6f, 0x41, 0x7b, 0xc1, 0xf5, 0x9b, 0x8, 0xbc, 0xba, 0x5b, 0x38, 0xfe, 0xd6, 0x42, 0xe7, 0xa3, 0xf3, 0x15, 0x5c, 0xef, 0xc3, 0xf2, 0x72, 0xa6, 0xf7, 0x21, 0x79, 0x16, 0xcf, 0xf, 0xeb, 0x2e, 0xaf, 0x7, 0x9c, 0x77, 0xf, 0xe0, 0x71, 0x1b, 0xef, 0xe3, 0x6d, 0x1b, 0xdf, 0x6c, 0x21, 0xda, 0xe2, 0xe5, 0xd, 0x50, 0x3f, 0xf, 0x7, 0x9c, 0x89, 0xf, 0xe2, 0x5d, 0x3f, 0x7c, 0x0, 0xcf, 0xda, 0xd8, 0xe5, 0x55, 0x1b, 0x1f, 0xe0, 0x51, 0xef, 0xac, 0x89, 0x53, 0xfb, 0x29, 0x3c, 0xb9, 0x7d, 0xc6, 0xc4, 0x1, 0x75, 0x9e, 0x39, 0xd, 0x6, 0x2a, 0x47, 0x1b, 0xff, 0xbd, 0xb9, 0x78, 0xeb, 0x40, 0xe0, 0x33, 0xb9, 0x77, 0xf3, 0x30, 0xde, 0x33, 0xb9, 0xd6, 0x77, 0x4c, 0xf0, 0x49, 0xdc, 0xda, 0x5a, 0xf5, 0xcf, 0x9a, 0x2e, 0xc3, 0x6a, 0x2b, 0x7a, 0xa7, 0x3e, 0x85, 0x67, 0x79, 0xc5, 0x7d, 0x6c, 0xcb, 0x5f, 0xde, 0xec, 0x62, 0xdc, 0x62, 0xde, 0x6d, 0x1c, 0x7e, 0xfe, 0xf5, 0x83, 0x3d, 0xce, 0xc2, 0x5b, 0x58, 0x2, 0xb8, 0x58, 0xe0, 0x9a, 0x39, 0xab, 0x3f, 0xde, 0x5f, 0xd0, 0xf7, 0x56, 0x7f, 0xff, 0x6f, 0xa3, 0x96, 0xe1, 0x2c, 0xf1, 0x44, 0xad, 0xae, 0xb3, 0xc4, 0x4b, 0x24, 0xa4, 0xf4, 0x46, 0x35, 0xdb, 0x59, 0xd9, 0x89, 0x6a, 0x43, 0xdf, 0xca, 0xce, 0x24, 0x64, 0xb3, 0x5d, 0xb6, 0xda, 0xf0, 0x61, 0x74, 0xd7, 0x1e, 0xac, 0xaa, 0xe7, 0x9f, 0xf2, 0x55, 0x77, 0x17, 0x6, 0x6b, 0x90, 0xb2, 0xf3, 0x64, 0x2f, 0xc8, 0xdf, 0x5a, 0x12, 0x4, 0x89, 0x1f, 0x6f, 0x3e, 0x89, 0x76, 0x5f, 0x21, 0x84, 0x2, 0xc1, 0xcb, 0xe5, 0x50, 0xc0, 0x3f, 0x4b, 0x14, 0x5d, 0x87, 0xa5, 0x2b, 0x8d, 0x7b, 0x93, 0x4f, 0x7, 0x8, 0xa4, 0x5b, 0x77, 0x47, 0x26, 0xbd, 0x9c, 0x86, 0xc6, 0x8c, 0x58, 0xde, 0x8a, 0x6b, 0x37, 0x5f, 0xb5, 0x5f, 0x32, 0x3, 0x90, 0xc5, 0x23, 0xe9, 0x48, 0x3c, 0xbc, 0x21, 0xa3, 0x7b, 0x33, 0x57, 0x7, 0x89, 0xe9, 0x2e, 0xca, 0x0, 0x49, 0xdd, 0xbe, 0x9d, 0x80, 0x21, 0xf2, 0x0, 0xf9, 0x36, 0xbb, 0xe3, 0xb0, 0xb, 0xfc, 0xe4, 0x1, 0x57, 0x23, 0x6c, 0x20, 0x78, 0xca, 0x94, 0xb4, 0x9b, 0x4b, 0xfb, 0xef, 0x28, 0x54, 0xdb, 0x79, 0x44, 0x3f, 0x50, 0xae, 0x2, 0xd3, 0xb, 0x3f, 0x53, 0xb4, 0x82, 0x92, 0xfa, 0x3e, 0x53, 0xba, 0x76, 0x52, 0xf, 0x3f, 0x49, 0xc0, 0x4a, 0x2a, 0xc4, 0x9e, 0x7b, 0x54, 0x66, 0x3f, 0xfc, 0xae, 0x5d, 0x27, 0x5c, 0x8d, 0x57, 0xfa, 0xef, 0x2d, 0xdf, 0xb9, 0xa8, 0xfc, 0x4, 0x39, 0xe4, 0x15, 0x77, 0x84, 0x90, 0x3f, 0xdd, 0x94, 0x40, 0x3f, 0xc6, 0x2d, 0xf1, 0xdb, 0xc6, 0x11, 0x8f, 0x48, 0x91, 0x98, 0x2b, 0x7b, 0x6b, 0xd8, 0xbf, 0x29, 0x8b, 0xae, 0x9, 0x7c, 0x5, 0x8b, 0x8, 0x4, 0x2f, 0xe7, 0xf, 0x1, 0xff, 0xc, 0xe6, 0xb8, 0x59, 0x5f, 0x60, 0xcc, 0x6a, 0x77, 0x16, 0xc8, 0x34, 0xb1, 0x82, 0xdc, 0x86, 0xdc, 0x77, 0xce, 0xae, 0xe3, 0xef, 0x3e, 0xb9, 0x38, 0x14, 0x78, 0x28, 0x42, 0xf6, 0x84, 0x87, 0x6e, 0x12, 0xcf, 0x25, 0xb2, 0x30, 0x99, 0x46, 0x9, 0x88, 0xb2, 0x28, 0x9e, 0x8a, 0xc5, 0x91, 0x82, 0x62, 0xb1, 0x64, 0x3c, 0x99, 0x4e, 0x49, 0x52, 0x52, 0xca, 0x25, 0xe5, 0x84, 0x9c, 0x48, 0x24, 0xa2, 0x94, 0x6f, 0x8a, 0xfa, 0x6e, 0x55, 0x8e, 0x3e, 0x2e, 0x9c, 0x9c, 0xbd, 0xdb, 0xfc, 0xba, 0x4a, 0x97, 0xbf, 0x37, 0x2f, 0x36, 0xf5, 0x31, 0xb8, 0xa8, 0xb6, 0xcd, 0xe1, 0xee, 0xb5, 0xc8, 0x4f, 0xde, 0x2f, 0x10, 0x0, 0x60, 0xcf, 0x8e, 0xc1, 0xc6, 0x5d, 0xa2, 0x9b, 0x9c, 0x1f, 0xd4, 0xd2, 0x96, 0x4, 0xec, 0xc3, 0x2d, 0x45, 0x52, 0x9b, 0x92, 0xf0, 0xf8, 0x5, 0xdd, 0x8f, 0x50, 0xcd, 0x1, 0xf6, 0x52, 0xcd, 0xdf, 0x6, 0x53, 0xbd, 0x75, 0xbb, 0x77, 0x10, 0xd5, 0xdb, 0xb8, 0xf7, 0x51, 0xad, 0x8c, 0x9f, 0x41, 0xb1, 0x6b, 0x18, 0xee, 0xd0, 0xac, 0x41, 0x13, 0x43, 0x65, 0x1c, 0x48, 0xad, 0xd7, 0x42, 0x30, 0xa5, 0x1, 0x38, 0x83, 0x88, 0xf4, 0x39, 0xd7, 0xf9, 0x26, 0x96, 0xe7, 0x40, 0x27, 0x13, 0xc7, 0x99, 0x1b, 0x84, 0xf3, 0x7, 0xe8, 0x1b, 0x48, 0xc6, 0x93, 0xd5, 0x3a, 0xe4, 0xd3, 0x3, 0xf4, 0xd3, 0xf8, 0xa, 0x2d, 0xe1, 0x60, 0x78, 0xb9, 0x9a, 0x70, 0x10, 0x3c, 0x6b, 0x12, 0x71, 0xf6, 0xa3, 0x5d, 0x31, 0xdb, 0x4a, 0x87, 0xe3, 0x93, 0x33, 0x37, 0x10, 0x48, 0xf8, 0x79, 0xc5, 0xf6, 0x9d, 0x2b, 0x70, 0x21, 0x77, 0x6c, 0x10, 0x94, 0x67, 0xeb, 0x18, 0x7, 0x67, 0x3b, 0x9d, 0x47, 0x76, 0x88, 0x8, 0x9e, 0x39, 0x5a, 0xfd, 0xc6, 0xe5, 0xfc, 0xf7, 0xef, 0xde, 0x9f, 0x7f, 0xdc, 0x0, 0x68, 0x4e, 0x6d, 0xde, 0x1b, 0x8b, 0x38, 0xe1, 0x51, 0x4e, 0x70, 0xc8, 0x4d, 0x4, 0x9c, 0x10, 0x13, 0xa0, 0x7b, 0xbe, 0x9f, 0xb3, 0x1d, 0x7, 0xe2, 0x8f, 0x1c, 0x7a, 0x4e, 0xc4, 0x90, 0x2f, 0x3a, 0x46, 0x44, 0x8e, 0x14, 0x54, 0x5e, 0xcd, 0xc2, 0xb, 0xa4, 0xae, 0xbe, 0x3, 0x8, 0x46, 0x85, 0x56, 0x53, 0x84, 0xb8, 0xf0, 0x10, 0x31, 0xca, 0xbb, 0x87, 0x9d, 0x58, 0x10, 0xa1, 0xa8, 0xbc, 0x40, 0x29, 0x5f, 0x48, 0x87, 0x13, 0x4a, 0x66, 0x98, 0x64, 0x81, 0x15, 0xa4, 0x80, 0xe5, 0xc, 0xab, 0x8, 0x6c, 0xc5, 0xc0, 0x88, 0xd0, 0x66, 0x7f, 0xbf, 0xbe, 0x3f, 0xa7, 0x5f, 0x13, 0x10, 0x35, 0xa0, 0x35, 0x8b, 0x5a, 0xc4, 0xaf, 0x44, 0x45, 0x3f, 0x7c, 0xd1, 0x67, 0xfe, 0x90, 0x7c, 0x7f, 0x44, 0xc9, 0xa6, 0xae, 0xf7, 0xab, 0x61, 0x71, 0x4a, 0x62, 0x6d, 0x60, 0x85, 0x42, 0xce, 0x9e, 0xf, 0xb5, 0x88, 0xe9, 0x74, 0x9d, 0xef, 0xe, 0x43, 0x5d, 0xd9, 0x8c, 0xc4, 0xe3, 0xe6, 0x96, 0x9b, 0x57, 0xc8, 0xcd, 0xb8, 0x15, 0xf1, 0x48, 0x90, 0x67, 0x50, 0x9f, 0x22, 0xdf, 0xd0, 0x9, 0x3, 0xcc, 0x22, 0x3b, 0xdb, 0xcf, 0xb2, 0x8, 0x29, 0xe2, 0xc7, 0x8, 0xd6, 0xa4, 0x58, 0xe7, 0xeb, 0xfb, 0x8, 0xf8, 0xd8, 0x20, 0xa8, 0x88, 0x50, 0xbb, 0xa3, 0xc2, 0x4e, 0xbb, 0xcc, 0x2c, 0x9c, 0xf0, 0x98, 0x7a, 0x37, 0x76, 0x92, 0x9f, 0x85, 0x86, 0x80, 0x9, 0x1, 0xa6, 0x8e, 0xe8, 0x8, 0xe3, 0x12, 0x72, 0xf1, 0xe0, 0xa1, 0xd5, 0x0, 0xdd, 0xf3, 0x80, 0x1d, 0x48, 0x81, 0x4a, 0xf4, 0xa9, 0x38, 0x3c, 0x0, 0x2d, 0x17, 0xca, 0xb4, 0x75, 0x9d, 0xef, 0x5f, 0xeb, 0xe2, 0x31, 0x93, 0xf2, 0x8, 0xb8, 0xd8, 0xc0, 0x2c, 0x42, 0x8e, 0x14, 0x67, 0x4b, 0x92, 0x57, 0x11, 0x7b, 0x72, 0xfa, 0xa, 0x98, 0x8, 0x52, 0xa2, 0x7f, 0x5f, 0x8f, 0xa1, 0x13, 0x5a, 0xe5, 0x11, 0x8f, 0xa9, 0x13, 0x6e, 0xc4, 0xf7, 0xf1, 0x10, 0x9b, 0x4a, 0x8e, 0xbe, 0x3d, 0xe9, 0x70, 0x9e, 0xb3, 0x65, 0xe6, 0xc4, 0xd0, 0x33, 0x29, 0xa2, 0x11, 0x95, 0xc8, 0xf3, 0xb7, 0x3c, 0x63, 0x74, 0xe8, 0xfc, 0x7f, 0x22, 0x95, 0xd8, 0xce, 0xff, 0x2c, 0x49, 0x9f, 0xe7, 0x7f, 0x3f, 0xa4, 0x78, 0xa7, 0x22, 0x30, 0xa2, 0xf9, 0xd0, 0xfa, 0xb6, 0x16, 0x5, 0x53, 0x91, 0x64, 0xd5, 0x99, 0x7d, 0xf3, 0x60, 0xd7, 0x90, 0xe, 0xb, 0x6b, 0xce, 0xbd, 0x3d, 0x22, 0x32, 0x25, 0x64, 0xaa, 0x22, 0x68, 0x60, 0xca, 0xcc, 0xbe, 0x90, 0xef, 0xb6, 0xde, 0x44, 0x24, 0x1e, 0x49, 0x85, 0x14, 0x3c, 0x45, 0xd4, 0xca, 0x3, 0x3a, 0x83, 0xf1, 0x54, 0x3a, 0x8f, 0xa4, 0x49, 0x2c, 0x1b, 0x4f, 0x66, 0xa4, 0x44, 0x16, 0x41, 0x38, 0xce, 0x2a, 0x59, 0x94, 0xcd, 0xa2, 0xf1, 0x38, 0x9, 0xc7, 0x93, 0x24, 0x82, 0xa9, 0x5c, 0x26, 0x93, 0x85, 0xd9, 0x74, 0x2a, 0x99, 0x8a, 0x67, 0x73, 0xa9, 0x4c, 0x2e, 0x95, 0x49, 0x25, 0x92, 0x50, 0x99, 0xa4, 0x13, 0x89, 0x4c, 0x2e, 0x96, 0x1a, 0x87, 0xbc, 0x20, 0x95, 0x3c, 0x88, 0x4b, 0xb1, 0x6c, 0x58, 0x4a, 0x85, 0x63, 0xe9, 0x41, 0x2c, 0x96, 0x4f, 0x24, 0xf3, 0x52, 0x2e, 0x22, 0x65, 0xa4, 0x4c, 0x2e, 0x97, 0xcd, 0xa6, 0x8f, 0xa5, 0x6c, 0x5e, 0xfa, 0x1f, 0x9f, 0xe9, 0x39, 0xb8, 0x4, 0xc9, 0xff, 0xdb, 0x65, 0x7e, 0x17, 0xe5, 0x90, 0xfc, 0xc7, 0x52, 0xdb, 0xe7, 0x3f, 0x93, 0xd2, 0x67, 0xfe, 0x9f, 0x8f, 0x29, 0x8f, 0xcb, 0xff, 0x96, 0x0, 0xbf, 0x52, 0x21, 0xfc, 0xec, 0xbe, 0x7e, 0x96, 0xcf, 0xf2, 0x59, 0x3e, 0xcb, 0x67, 0x59, 0x97, 0xff, 0x2f, 0x0, 0x0, 0xff, 0xff, 0xb9, 0xe, 0xe4, 0x88, 0x0, 0x6c, 0x1, 0x0} +func addFileToTar(tarWriter *tar.Writer, filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + info, err := file.Stat() + if err != nil { + return err + } + + header, err := tar.FileInfoHeader(info, info.Name()) + if err != nil { + return err + } + + header.Name = strings.TrimPrefix(filename, "testdata/") + + if err = tarWriter.WriteHeader(header); err != nil { + return err + } + + _, err = io.Copy(tarWriter, file) + return err +} + +// loadChart archive and compress the chart folder. +func loadChart(path string) ([]byte, error) { + compressedFileName := path + ".tar.gz" + chartTar, err := os.Create(compressedFileName) + if err != nil { + return nil, err + } + + defer func() { + os.Remove(compressedFileName) + }() + + gzipWritter := gzip.NewWriter(chartTar) + tarWriter := tar.NewWriter(gzipWritter) + + if err = filepath.WalkDir(path, func(fpath string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if path == fpath { + return nil + } + + if !d.IsDir() { + if err = addFileToTar(tarWriter, fpath); err != nil { + return err + } + } + + return nil + }); err != nil { + return nil, err + } + // flush and close writer + tarWriter.Close() + gzipWritter.Close() + chartTar.Close() + + return os.ReadFile(compressedFileName) +} func TestGetChartDetails(t *testing.T) { chartOpr := NewOperator() - _, err := chartOpr.GetDetails(HelmChartContent) - if err != nil { - t.Fatal(err) + + { + // test schema v1 chart + chartV1, err := loadChart("testdata/harbor-schema1") + if err != nil { + t.Fatalf("load chart error: %s", err) + } + + details, err := chartOpr.GetDetails(chartV1) + if err != nil { + t.Fatalf("get chart details error: %s", err) + } + + assert.Equal(t, 2, len(details.Dependencies)) + assert.Equal(t, "postgresql", details.Dependencies[0].Name) + assert.Equal(t, "redis", details.Dependencies[1].Name) + // the length of files should be greater than 0 + assert.Greater(t, len(details.Files), 0) } - // ToDo add a v3 supported test data - // if len(chartDetails.Dependencies) == 0 { - // t.Fatal("At least 1 dependency exitsing, but we got 0 now") - // } + { + // test schema v2 chart + chartV2, err := loadChart("testdata/harbor-schema2") + if err != nil { + t.Fatalf("load chart error: %s", err) + } - // if len(chartDetails.Values) == 0 { - // t.Fatal("At least 1 value existing, but we got 0 now") - // } + details, err := chartOpr.GetDetails(chartV2) + if err != nil { + t.Fatalf("get chart details error: %s", err) + } - // if chartDetails.Values["adminserver.adminPassword"] != "Harbor12345" { - // t.Fatalf("The value of 'adminserver.adminPassword' should be 'Harbor12345' but we got '%s' now", chartDetails.Values["adminserver.adminPassword"]) - // } + assert.Equal(t, 2, len(details.Dependencies)) + assert.Equal(t, "postgresql", details.Dependencies[0].Name) + assert.Equal(t, "redis", details.Dependencies[1].Name) + // the length of files should be greater than 0 + assert.Greater(t, len(details.Files), 0) + } } diff --git a/src/pkg/chart/testdata/harbor-schema1/.helmignore b/src/pkg/chart/testdata/harbor-schema1/.helmignore new file mode 100644 index 0000000000..b4424fd59b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/.helmignore @@ -0,0 +1,6 @@ +.github/* +docs/* +.git/* +.gitignore +CONTRIBUTING.md +test/* \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/Chart.yaml b/src/pkg/chart/testdata/harbor-schema1/Chart.yaml new file mode 100644 index 0000000000..541455381c --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +appVersion: 2.11.0 +description: An open source trusted cloud native registry that stores, signs, and + scans content +home: https://goharbor.io +icon: https://raw.githubusercontent.com/goharbor/website/main/static/img/logos/harbor-icon-color.png +keywords: +- docker +- registry +- harbor +maintainers: +- email: yan-yw.wang@broadcom.com + name: Yan Wang +- email: wenkai.yin@broadcom.com + name: Wenkai Yin +- email: miner.yang@broadcom.com + name: Miner Yang +- email: shengwen.yu@broadcom.com + name: Shengwen Yu +name: harbor +sources: +- https://github.com/goharbor/harbor +- https://github.com/goharbor/harbor-helm +version: 1.15.0 diff --git a/src/pkg/chart/testdata/harbor-schema1/LICENSE b/src/pkg/chart/testdata/harbor-schema1/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/src/pkg/chart/testdata/harbor-schema1/README.md b/src/pkg/chart/testdata/harbor-schema1/README.md new file mode 100644 index 0000000000..a78cfa6700 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/README.md @@ -0,0 +1,422 @@ +# Helm Chart for Harbor + +**Notes:** The master branch is in heavy development, please use the other stable versions instead. A highly available solution for Harbor based on chart can be found [here](docs/High%20Availability.md). And refer to the [guide](docs/Upgrade.md) to upgrade the existing deployment. + +This repository, including the issues, focuses on deploying Harbor chart via helm. For functionality issues or Harbor questions, please open issues on [goharbor/harbor](https://github.com/goharbor/harbor) + +## Introduction + +This [Helm](https://github.com/kubernetes/helm) chart installs [Harbor](https://github.com/goharbor/harbor) in a Kubernetes cluster. Welcome to [contribute](CONTRIBUTING.md) to Helm Chart for Harbor. + +## Prerequisites + +- Kubernetes cluster 1.20+ +- Helm v3.2.0+ + +## Installation + +### Add Helm repository + +```bash +helm repo add harbor https://helm.goharbor.io +``` + +### Configure the chart + +The following items can be set via `--set` flag during installation or configured by editing the `values.yaml` directly (need to download the chart first). + +#### Configure how to expose Harbor service + +- **Ingress**: The ingress controller must be installed in the Kubernetes cluster. + **Notes:** if TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to issue [#5291](https://github.com/goharbor/harbor/issues/5291) for details. +- **ClusterIP**: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from within the cluster. +- **NodePort**: Exposes the service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the NodePort service, from outside the cluster, by requesting `NodeIP:NodePort`. +- **LoadBalancer**: Exposes the service externally using a cloud provider’s load balancer. + +#### Configure the external URL + +The external URL for Harbor core service is used to: + +1. populate the docker/helm commands showed on portal +2. populate the token service URL returned to docker client + +Format: `protocol://domain[:port]`. Usually: + +- if service exposed via `Ingress`, the `domain` should be the value of `expose.ingress.hosts.core` +- if service exposed via `ClusterIP`, the `domain` should be the value of `expose.clusterIP.name` +- if service exposed via `NodePort`, the `domain` should be the IP address of one Kubernetes node +- if service exposed via `LoadBalancer`, set the `domain` as your own domain name and add a CNAME record to map the domain name to the one you got from the cloud provider + +If Harbor is deployed behind the proxy, set it as the URL of proxy. + +#### Configure how to persist data + +- **Disable**: The data does not survive the termination of a pod. +- **Persistent Volume Claim(default)**: A default `StorageClass` is needed in the Kubernetes cluster to dynamically provision the volumes. Specify another StorageClass in the `storageClass` or set `existingClaim` if you already have existing persistent volumes to use. +- **External Storage(only for images and charts)**: For images and charts, the external storages are supported: `azure`, `gcs`, `s3` `swift` and `oss`. + +#### Configure the other items listed in [configuration](#configuration) section + +### Install the chart + +Install the Harbor helm chart with a release name `my-release`: +```bash +helm install my-release harbor/harbor +``` + +## Uninstallation + +To uninstall/delete the `my-release` deployment: +```bash +helm uninstall my-release +``` + +## Configuration + +The following table lists the configurable parameters of the Harbor chart and the default values. + +| Parameter | Description | Default | +|-----------------------------------------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| **Expose** | | | +| `expose.type` | How to expose the service: `ingress`, `clusterIP`, `nodePort` or `loadBalancer`, other values will be ignored and the creation of service will be skipped. | `ingress` | +| `expose.tls.enabled` | Enable TLS or not. Delete the `ssl-redirect` annotations in `expose.ingress.annotations` when TLS is disabled and `expose.type` is `ingress`. Note: if the `expose.type` is `ingress` and TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to https://github.com/goharbor/harbor/issues/5291 for details. | `true` | +| `expose.tls.certSource` | The source of the TLS certificate. Set as `auto`, `secret` or `none` and fill the information in the corresponding section: 1) auto: generate the TLS certificate automatically 2) secret: read the TLS certificate from the specified secret. The TLS certificate can be generated manually or by cert manager 3) none: configure no TLS certificate for the ingress. If the default TLS certificate is configured in the ingress controller, choose this option | `auto` | +| `expose.tls.auto.commonName` | The common name used to generate the certificate, it's necessary when the type isn't `ingress` | | +| `expose.tls.secret.secretName` | The name of secret which contains keys named: `tls.crt` - the certificate; `tls.key` - the private key | | +| `expose.ingress.hosts.core` | The host of Harbor core service in ingress rule | `core.harbor.domain` | +| `expose.ingress.controller` | The ingress controller type. Currently supports `default`, `gce`, `alb`, `f5-bigip` and `ncp` | `default` | +| `expose.ingress.kubeVersionOverride` | Allows the ability to override the kubernetes version used while templating the ingress | | +| `expose.ingress.annotations` | The annotations used commonly for ingresses | | +| `expose.ingress.labels` | The labels specific to ingress | {} | +| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` | +| `expose.clusterIP.annotations` | The annotations attached to the ClusterIP service | {} | +| `expose.clusterIP.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.clusterIP.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.clusterIP.annotations` | The annotations used commonly for clusterIP | | +| `expose.clusterIP.labels` | The labels specific to clusterIP | {} | +| `expose.nodePort.name` | The name of NodePort service | `harbor` | +| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving HTTP | `30002` | +| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving HTTPS | `30003` | +| `expose.nodePort.annotations` | The annotations used commonly for nodePort | | +| `expose.nodePort.labels` | The labels specific to nodePort | {} | +| `expose.loadBalancer.name` | The name of service | `harbor` | +| `expose.loadBalancer.IP` | The IP of the loadBalancer. It only works when loadBalancer supports assigning IP | `""` | +| `expose.loadBalancer.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.loadBalancer.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `30002` | +| `expose.loadBalancer.annotations` | The annotations attached to the loadBalancer service | {} | +| `expose.loadBalancer.labels` | The labels specific to loadBalancer | {} | +| `expose.loadBalancer.sourceRanges` | List of IP address ranges to assign to loadBalancerSourceRanges | [] | +| **Internal TLS** | | | +| `internalTLS.enabled` | Enable TLS for the components (core, jobservice, portal, registry, trivy) | `false` | +| `internalTLS.strong_ssl_ciphers` | Enable strong ssl ciphers for nginx and portal | `false` +| `internalTLS.certSource` | Method to provide TLS for the components, options are `auto`, `manual`, `secret`. | `auto` | +| `internalTLS.trustCa` | The content of trust CA, only available when `certSource` is `manual`. **Note**: all the internal certificates of the components must be issued by this CA | | +| `internalTLS.core.secretName` | The secret name for core component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.core.crt` | Content of core's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.core.key` | Content of core's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.secretName` | The secret name for jobservice component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.jobservice.crt` | Content of jobservice's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.key` | Content of jobservice's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.registry.secretName` | The secret name for registry component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.registry.crt` | Content of registry's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.registry.key` | Content of registry's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.portal.secretName` | The secret name for portal component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.portal.crt` | Content of portal's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.portal.key` | Content of portal's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.secretName` | The secret name for trivy component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.trivy.crt` | Content of trivy's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.key` | Content of trivy's TLS key file, only available when `certSource` is `manual` | | +| **IPFamily** | | | +| `ipFamily.ipv4.enabled` | if cluster is ipv4 enabled, all ipv4 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| `ipFamily.ipv6.enabled` | if cluster is ipv6 enabled, all ipv6 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| **Persistence** | | | +| `persistence.enabled` | Enable the data persistence or not | `true` | +| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted. Does not affect PVCs created for internal database and redis components. | `keep` | +| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.registry.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.database.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.redis.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.trivy.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.trivy.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.trivy.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.trivy.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.trivy.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.trivy.annotations` | The annotations of the volume | | +| `persistence.imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more details | `false` | +| `persistence.imageChartStorage.caBundleSecretName` | Specify the `caBundleSecretName` if the storage service uses a self-signed certificate. The secret must contain keys named `ca.crt` which will be injected into the trust store of registry's and containers. | | +| `persistence.imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more details | `filesystem` | +| `persistence.imageChartStorage.gcs.existingSecret` | An existing secret containing the gcs service account json key. The key must be gcs-key.json. | `""` | +| `persistence.imageChartStorage.gcs.useWorkloadIdentity` | A boolean to allow the use of workloadidentity in a GKE cluster. To use it, create a kubernetes service account and set the name in the key `serviceAccountName` of each component, then allow automounting the service account. | `false` | +| **General** | | | +| `externalURL` | The external URL for Harbor core service | `https://core.harbor.domain` | +| `caBundleSecretName` | The custom CA bundle secret name, the secret must contain key named "ca.crt" which will be injected into the trust store for core, jobservice, registry, trivy components. | | +| `uaaSecretName` | If using external UAA auth which has a self signed cert, you can provide a pre-created secret containing it under the key `ca.crt`. | | +| `imagePullPolicy` | The image pull policy | | +| `imagePullSecrets` | The imagePullSecrets names for all deployments | | +| `updateStrategy.type` | The update strategy for deployments with persistent volumes(jobservice, registry): `RollingUpdate` or `Recreate`. Set it as `Recreate` when `RWM` for volumes isn't supported | `RollingUpdate` | +| `logLevel` | The log level: `debug`, `info`, `warning`, `error` or `fatal` | `info` | +| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` | +| `existingSecretAdminPassword` | The name of secret where admin password can be found. | | +| `existingSecretAdminPasswordKey` | The name of the key in the secret where to find harbor admin password Harbor | `HARBOR_ADMIN_PASSWORD` | +| `caSecretName` | The name of the secret which contains key named `ca.crt`. Setting this enables the download link on portal to download the CA certificate when the certificate isn't generated automatically | | +| `secretKey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` | +| `existingSecretSecretKey` | An existing secret containing the encoding secretKey | `""` | +| `proxy.httpProxy` | The URL of the HTTP proxy server | | +| `proxy.httpsProxy` | The URL of the HTTPS proxy server | | +| `proxy.noProxy` | The URLs that the proxy settings not apply to | 127.0.0.1,localhost,.local,.internal | +| `proxy.components` | The component list that the proxy settings apply to | core, jobservice, trivy | +| `enableMigrateHelmHook` | Run the migration job via helm hook, if it is true, the database migration will be separated from harbor-core, run with a preupgrade job migration-job | `false` | +| **Nginx** (if service exposed via `ingress`, Nginx will not be used) | | | +| `nginx.image.repository` | Image repository | `goharbor/nginx-photon` | +| `nginx.image.tag` | Image tag | `dev` | +| `nginx.replicas` | The replica count | `1` | +| `nginx.revisionHistoryLimit` | The revision history limit | `10` | +| `nginx.resources` | The [resources] to allocate for container | undefined | +| `nginx.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `nginx.nodeSelector` | Node labels for pod assignment | `{}` | +| `nginx.tolerations` | Tolerations for pod assignment | `[]` | +| `nginx.affinity` | Node/Pod affinities | `{}` | +| `nginx.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `nginx.podAnnotations` | Annotations to add to the nginx pod | `{}` | +| `nginx.priorityClassName` | The priority class to run the pod as | | +| **Portal** | | | +| `portal.image.repository` | Repository for portal image | `goharbor/harbor-portal` | +| `portal.image.tag` | Tag for portal image | `dev` | +| `portal.replicas` | The replica count | `1` | +| `portal.revisionHistoryLimit` | The revision history limit | `10` | +| `portal.resources` | The [resources] to allocate for container | undefined | +| `portal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `portal.nodeSelector` | Node labels for pod assignment | `{}` | +| `portal.tolerations` | Tolerations for pod assignment | `[]` | +| `portal.affinity` | Node/Pod affinities | `{}` | +| `portal.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `portal.podAnnotations` | Annotations to add to the portal pod | `{}` | +| `portal.serviceAnnotations` | Annotations to add to the portal service | `{}` | +| `portal.priorityClassName` | The priority class to run the pod as | | +| `portal.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Core** | | | +| `core.image.repository` | Repository for Harbor core image | `goharbor/harbor-core` | +| `core.image.tag` | Tag for Harbor core image | `dev` | +| `core.replicas` | The replica count | `1` | +| `core.revisionHistoryLimit` | The revision history limit | `10` | +| `core.startupProbe.initialDelaySeconds` | The initial delay in seconds for the startup probe | `10` | +| `core.resources` | The [resources] to allocate for container | undefined | +| `core.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `core.nodeSelector` | Node labels for pod assignment | `{}` | +| `core.tolerations` | Tolerations for pod assignment | `[]` | +| `core.affinity` | Node/Pod affinities | `{}` | +| `core.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `core.podAnnotations` | Annotations to add to the core pod | `{}` | +| `core.serviceAnnotations` | Annotations to add to the core service | `{}` | +| `core.configureUserSettings` | A JSON string to set in the environment variable `CONFIG_OVERWRITE_JSON` to configure user settings. See the [official docs](https://goharbor.io/docs/latest/install-config/configure-user-settings-cli/#configure-users-settings-using-an-environment-variable). | | +| `core.quotaUpdateProvider` | The provider for updating project quota(usage), there are 2 options, redis or db. By default it is implemented by db but you can configure it to redis which can improve the performance of high concurrent pushing to the same project, and reduce the database connections spike and occupies. Using redis will bring up some delay for quota usage updation for display, so only suggest switch provider to redis if you were ran into the db connections spike around the scenario of high concurrent pushing to same project, no improvment for other scenes. | `db` | +| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `core.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named: `tls.crt` - the certificate and `tls.key` - the private key. The default key pair will be used if it isn't set | | +| `core.tokenKey` | PEM-formatted RSA private key used to sign service tokens. Only used if `core.secretName` is unset. If set, `core.tokenCert` MUST also be set. | | +| `core.tokenCert` | PEM-formatted certificate signed by `core.tokenKey` used to validate service tokens. Only used if `core.secretName` is unset. If set, `core.tokenKey` MUST also be set. | | +| `core.xsrfKey` | The XSRF key. Will be generated automatically if it isn't specified | | +| `core.priorityClassName` | The priority class to run the pod as | | +| `core.artifactPullAsyncFlushDuration` | The time duration for async update artifact pull_time and repository pull_count | | +| `core.gdpr.deleteUser` | Enable GDPR compliant user delete | `false` | +| `core.gdpr.auditLogsCompliant` | Enable GDPR compliant for audit logs by changing username to its CRC32 value if that user was deleted from the system | `false` | +| `core.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Jobservice** | | | +| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` | +| `jobservice.image.tag` | Tag for jobservice image | `dev` | +| `jobservice.replicas` | The replica count | `1` | +| `jobservice.revisionHistoryLimit` | The revision history limit | `10` | +| `jobservice.maxJobWorkers` | The max job workers | `10` | +| `jobservice.jobLoggers` | The loggers for jobs: `file`, `database` or `stdout` | `[file]` | +| `jobservice.loggerSweeperDuration` | The jobLogger sweeper duration in days (ignored if `jobLoggers` is set to `stdout`) | `14` | +| `jobservice.notification.webhook_job_max_retry` | The maximum retry of webhook sending notifications | `3` | +| `jobservice.notification.webhook_job_http_client_timeout` | The http client timeout value of webhook sending notifications | `3` | +| `jobservice.reaper.max_update_hours` | the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 | `24` | +| `jobservice.reaper.max_dangling_hours` | the max time for execution in running state without new task created | `168` | +| `jobservice.resources` | The [resources] to allocate for container | undefined | +| `jobservice.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` | +| `jobservice.tolerations` | Tolerations for pod assignment | `[]` | +| `jobservice.affinity` | Node/Pod affinities | `{}` | +| `jobservice.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` | +| `jobservice.priorityClassName` | The priority class to run the pod as | | +| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `jobservice.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Registry** | | | +| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` | +| `registry.registry.image.tag` | Tag for registry image | `dev` | +| `registry.registry.resources` | The [resources] to allocate for container | undefined | +| `registry.controller.image.repository` | Repository for registry controller image | `goharbor/harbor-registryctl` | +| `registry.controller.image.tag` | Tag for registry controller image | `dev` | +| `registry.controller.resources` | The [resources] to allocate for container | undefined | +| `registry.replicas` | The replica count | `1` | +| `registry.revisionHistoryLimit` | The revision history limit | `10` | +| `registry.nodeSelector` | Node labels for pod assignment | `{}` | +| `registry.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `registry.tolerations` | Tolerations for pod assignment | `[]` | +| `registry.affinity` | Node/Pod affinities | `{}` | +| `registry.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `registry.middleware` | Middleware is used to add support for a CDN between backend storage and `docker pull` recipient. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#middleware). | | +| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` | +| `registry.priorityClassName` | The priority class to run the pod as | | +| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#http). If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `registry.credentials.username` | The username that harbor core uses internally to access the registry instance. Together with the `registry.credentials.password`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). | `harbor_registry_user` | +| `registry.credentials.password` | The password that harbor core uses internally to access the registry instance. Together with the `registry.credentials.username`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). It is suggested you update this value before installation. | `harbor_registry_password` | +| `registry.credentials.existingSecret` | An existing secret containing the password for accessing the registry instance, which is hosted by htpasswd auth mode. More details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). The key must be `REGISTRY_PASSWD` | `""` | +| `registry.credentials.htpasswdString` | Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. | undefined | +| `registry.relativeurls` | If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. Needed if harbor is behind a reverse proxy | `false` | +| `registry.upload_purging.enabled` | If true, enable purge _upload directories | `true` | +| `registry.upload_purging.age` | Remove files in _upload directories which exist for a period of time, default is one week. | `168h` | +| `registry.upload_purging.interval` | The interval of the purge operations | `24h` | +| `registry.upload_purging.dryrun` | If true, enable dryrun for purging _upload, default false | `false` | +| `registry.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **[Trivy][trivy]** | | | +| `trivy.enabled` | The flag to enable Trivy scanner | `true` | +| `trivy.image.repository` | Repository for Trivy adapter image | `goharbor/trivy-adapter-photon` | +| `trivy.image.tag` | Tag for Trivy adapter image | `dev` | +| `trivy.resources` | The [resources] to allocate for Trivy adapter container | | +| `trivy.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `trivy.replicas` | The number of Pod replicas | `1` | +| `trivy.debugMode` | The flag to enable Trivy debug mode | `false` | +| `trivy.vulnType` | Comma-separated list of vulnerability types. Possible values `os` and `library`. | `os,library` | +| `trivy.severity` | Comma-separated list of severities to be checked | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | +| `trivy.ignoreUnfixed` | The flag to display only fixed vulnerabilities | `false` | +| `trivy.insecure` | The flag to skip verifying registry certificate | `false` | +| `trivy.skipUpdate` | The flag to disable [Trivy DB][trivy-db] downloads from GitHub | `false` | +| `trivy.skipJavaDBUpdate` | If the flag is enabled you have to manually download the `trivy-java.db` file [Trivy Java DB][trivy-java-db] and mount it in the `/home/scanner/.cache/trivy/java-db/trivy-java.db` path | `false` | +| `trivy.offlineScan` | The flag prevents Trivy from sending API requests to identify dependencies. | `false` | +| `trivy.securityCheck` | Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. | `vuln` | +| `trivy.timeout` | The duration to wait for scan completion | `5m0s` | +| `trivy.gitHubToken` | The GitHub access token to download [Trivy DB][trivy-db] (see [GitHub rate limiting][trivy-rate-limiting]) | | +| `trivy.priorityClassName` | The priority class to run the pod as | | +| `trivy.topologySpreadConstraints` | The priority class to run the pod as | | +| `trivy.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Database** | | | +| `database.type` | If external database is used, set it to `external` | `internal` | +| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` | +| `database.internal.image.tag` | Tag for database image | `dev` | +| `database.internal.password` | The password for database | `changeit` | +| `database.internal.shmSizeLimit` | The limit for the size of shared memory for internal PostgreSQL, conventionally it's around 50% of the memory limit of the container | `512Mi` | +| `database.internal.resources` | The [resources] to allocate for container | undefined | +| `database.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `database.internal.initContainer.migrator.resources` | The [resources] to allocate for the database migrator initContainer | undefined | +| `database.internal.initContainer.permissions.resources` | The [resources] to allocate for the database permissions initContainer | undefined | +| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `database.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `database.internal.affinity` | Node/Pod affinities | `{}` | +| `database.internal.priorityClassName` | The priority class to run the pod as | | +| `database.internal.livenessProbe.timeoutSeconds` | The timeout used in liveness probe; 1 to 5 seconds | 1 | +| `database.internal.readinessProbe.timeoutSeconds` | The timeout used in readiness probe; 1 to 5 seconds | 1 | +| `database.internal.extrInitContainers` | Extra init containers to be run before the database's container starts. | `[]` | +| `database.external.host` | The hostname of external database | `192.168.0.1` | +| `database.external.port` | The port of external database | `5432` | +| `database.external.username` | The username of external database | `user` | +| `database.external.password` | The password of external database | `password` | +| `database.external.coreDatabase` | The database used by core service | `registry` | +| `database.external.existingSecret` | An existing password containing the database password. the key must be `password`. | `""` | +| `database.external.sslmode` | Connection method of external database (require, verify-full, verify-ca, disable) | `disable` | +| `database.maxIdleConns` | The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. | `50` | +| `database.maxOpenConns` | The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections. | `100` | +| `database.podAnnotations` | Annotations to add to the database pod | `{}` | +| **Redis** | | | +| `redis.type` | If external redis is used, set it to `external` | `internal` | +| `redis.internal.image.repository` | Repository for redis image | `goharbor/redis-photon` | +| `redis.internal.image.tag` | Tag for redis image | `dev` | +| `redis.internal.resources` | The [resources] to allocate for container | undefined | +| `redis.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `redis.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `redis.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `redis.internal.affinity` | Node/Pod affinities | `{}` | +| `redis.internal.priorityClassName` | The priority class to run the pod as | | +| `redis.internal.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.internal.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.internal.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.internal.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.internal.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.internal.initContainers` | Init containers to be run before the redis's container starts. | `[]` | +| `redis.external.addr` | The addr of external Redis: :. When using sentinel, it should be :,:,: | `192.168.0.2:6379` | +| `redis.external.sentinelMasterSet` | The name of the set of Redis instances to monitor | | +| `redis.external.coreDatabaseIndex` | The database index for core | `0` | +| `redis.external.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.external.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.external.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.external.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.external.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.external.username` | The username of external Redis | | +| `redis.external.password` | The password of external Redis | | +| `redis.external.existingSecret` | Use an existing secret to connect to redis. The key must be `REDIS_PASSWORD`. | `""` | +| `redis.podAnnotations` | Annotations to add to the redis pod | `{}` | +| **Exporter** | | | +| `exporter.replicas` | The replica count | `1` | +| `exporter.revisionHistoryLimit` | The revision history limit | `10` | +| `exporter.podAnnotations` | Annotations to add to the exporter pod | `{}` | +| `exporter.image.repository` | Repository for redis image | `goharbor/harbor-exporter` | +| `exporter.image.tag` | Tag for exporter image | `dev` | +| `exporter.nodeSelector` | Node labels for pod assignment | `{}` | +| `exporter.tolerations` | Tolerations for pod assignment | `[]` | +| `exporter.affinity` | Node/Pod affinities | `{}` | +| `exporter.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `exporter.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `exporter.cacheDuration` | the cache duration for information that exporter collected from Harbor | `30` | +| `exporter.cacheCleanInterval` | cache clean interval for information that exporter collected from Harbor | `14400` | +| `exporter.priorityClassName` | The priority class to run the pod as | | +| **Metrics** | | | +| `metrics.enabled` | if enable harbor metrics | `false` | +| `metrics.core.path` | the url path for core metrics | `/metrics` | +| `metrics.core.port` | the port for core metrics | `8001` | +| `metrics.registry.path` | the url path for registry metrics | `/metrics` | +| `metrics.registry.port` | the port for registry metrics | `8001` | +| `metrics.exporter.path` | the url path for exporter metrics | `/metrics` | +| `metrics.exporter.port` | the port for exporter metrics | `8001` | +| `metrics.serviceMonitor.enabled` | create prometheus serviceMonitor. Requires prometheus CRD's | `false` | +| `metrics.serviceMonitor.additionalLabels` | additional labels to upsert to the manifest | `""` | +| `metrics.serviceMonitor.interval` | scrape period for harbor metrics | `""` | +| `metrics.serviceMonitor.metricRelabelings` | metrics relabel to add/mod/del before ingestion | `[]` | +| `metrics.serviceMonitor.relabelings` | relabels to add/mod/del to sample before scrape | `[]` | +| **Trace** | | | +| `trace.enabled` | Enable tracing or not | `false` | +| `trace.provider` | The tracing provider: `jaeger` or `otel`. `jaeger` should be 1.26+ | `jaeger` | +| `trace.sample_rate` | Set `sample_rate` to 1 if you want sampling 100% of trace data; set 0.5 if you want sampling 50% of trace data, and so forth | `1` | +| `trace.namespace` | Namespace used to differentiate different harbor services | | +| `trace.attributes` | `attributes` is a key value dict contains user defined attributes used to initialize trace provider | | +| `trace.jaeger.endpoint` | The endpoint of jaeger | `http://hostname:14268/api/traces` | +| `trace.jaeger.username` | The username of jaeger | | +| `trace.jaeger.password` | The password of jaeger | | +| `trace.jaeger.agent_host` | The agent host of jaeger | | +| `trace.jaeger.agent_port` | The agent port of jaeger | `6831` | +| `trace.otel.endpoint` | The endpoint of otel | `hostname:4318` | +| `trace.otel.url_path` | The URL path of otel | `/v1/traces` | +| `trace.otel.compression` | Whether enable compression or not for otel | `false` | +| `trace.otel.insecure` | Whether establish insecure connection or not for otel | `true` | +| `trace.otel.timeout` | The timeout in seconds of otel | `10` | +| **Cache** | | | +| `cache.enabled` | Enable cache layer or not | `false` | +| `cache.expireHours` | The expire hours of cache layer | `24` | + +[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +[trivy]: https://github.com/aquasecurity/trivy +[trivy-db]: https://github.com/aquasecurity/trivy-db +[trivy-java-db]: https://github.com/aquasecurity/trivy-java-db +[trivy-rate-limiting]: https://github.com/aquasecurity/trivy#github-rate-limiting diff --git a/src/pkg/chart/testdata/harbor-schema1/requirements.yaml b/src/pkg/chart/testdata/harbor-schema1/requirements.yaml new file mode 100644 index 0000000000..600e68ab8b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/requirements.yaml @@ -0,0 +1,10 @@ +# NOTICE: Harbor chart is not dependent on other charts. This is just a mock for UT coverage. +dependencies: + - name: postgresql + version: 1.0.0 + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: postgresql.enabled + - name: redis + version: 2.0.0 + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: redis.enabled \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/NOTES.txt b/src/pkg/chart/testdata/harbor-schema1/templates/NOTES.txt new file mode 100644 index 0000000000..0980c08a35 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/NOTES.txt @@ -0,0 +1,3 @@ +Please wait for several minutes for Harbor deployment to complete. +Then you should be able to visit the Harbor portal at {{ .Values.externalURL }} +For more details, please visit https://github.com/goharbor/harbor diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/_helpers.tpl b/src/pkg/chart/testdata/harbor-schema1/templates/_helpers.tpl new file mode 100644 index 0000000000..f6249b3993 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/_helpers.tpl @@ -0,0 +1,581 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "harbor.name" -}} +{{- default "harbor" .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "harbor.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default "harbor" .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Helm required labels: legacy */}} +{{- define "harbor.legacy.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helm required labels */}} +{{- define "harbor.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/name: {{ include "harbor.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: {{ include "harbor.name" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- end -}} + +{{/* matchLabels */}} +{{- define "harbor.matchLabels" -}} +release: {{ .Release.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helper for printing values from existing secrets*/}} +{{- define "harbor.secretKeyHelper" -}} + {{- if and (not (empty .data)) (hasKey .data .key) }} + {{- index .data .key | b64dec -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCert" -}} + {{- if and .Values.expose.tls.enabled (eq .Values.expose.tls.certSource "auto") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForIngress" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (eq .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForNginx" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (ne .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.host" -}} + {{- if eq .Values.database.type "internal" -}} + {{- template "harbor.database" . }} + {{- else -}} + {{- .Values.database.external.host -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.port" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "5432" -}} + {{- else -}} + {{- .Values.database.external.port -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.username" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "postgres" -}} + {{- else -}} + {{- .Values.database.external.username -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.rawPassword" -}} + {{- if eq .Values.database.type "internal" -}} + {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.database" .) -}} + {{- if and (not (empty $existingSecret)) (hasKey $existingSecret.data "POSTGRES_PASSWORD") -}} + {{- .Values.database.internal.password | default (index $existingSecret.data "POSTGRES_PASSWORD" | b64dec) -}} + {{- else -}} + {{- .Values.database.internal.password -}} + {{- end -}} + {{- else -}} + {{- .Values.database.external.password -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.escapedRawPassword" -}} + {{- include "harbor.database.rawPassword" . | urlquery | replace "+" "%20" -}} +{{- end -}} + +{{- define "harbor.database.encryptedPassword" -}} + {{- include "harbor.database.rawPassword" . | b64enc | quote -}} +{{- end -}} + +{{- define "harbor.database.coreDatabase" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "registry" -}} + {{- else -}} + {{- .Values.database.external.coreDatabase -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.sslmode" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "disable" -}} + {{- else -}} + {{- .Values.database.external.sslmode -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.scheme" -}} + {{- with .Values.redis }} + {{- ternary "redis+sentinel" "redis" (and (eq .type "external" ) (not (not .external.sentinelMasterSet))) }} + {{- end }} +{{- end -}} + +/*host:port*/ +{{- define "harbor.redis.addr" -}} + {{- with .Values.redis }} + {{- ternary (printf "%s:6379" (include "harbor.redis" $ )) .external.addr (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.masterSet" -}} + {{- with .Values.redis }} + {{- ternary .external.sentinelMasterSet "" (eq "redis+sentinel" (include "harbor.redis.scheme" $)) }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.password" -}} + {{- with .Values.redis }} + {{- ternary "" .external.password (eq .type "internal") }} + {{- end }} +{{- end -}} + + +{{- define "harbor.redis.pwdfromsecret" -}} + {{- (lookup "v1" "Secret" .Release.Namespace (.Values.redis.external.existingSecret)).data.REDIS_PASSWORD | b64dec }} +{{- end -}} + +{{- define "harbor.redis.cred" -}} + {{- with .Values.redis }} + {{- if (and (eq .type "external" ) (.external.existingSecret)) }} + {{- printf ":%s@" (include "harbor.redis.pwdfromsecret" $) }} + {{- else }} + {{- ternary (printf "%s:%s@" (.external.username | urlquery) (.external.password | urlquery)) "" (and (eq .type "external" ) (not (not .external.password))) }} + {{- end }} + {{- end }} +{{- end -}} + +/*scheme://[:password@]host:port[/master_set]*/ +{{- define "harbor.redis.url" -}} + {{- with .Values.redis }} + {{- $path := ternary "" (printf "/%s" (include "harbor.redis.masterSet" $)) (not (include "harbor.redis.masterSet" $)) }} + {{- printf "%s://%s%s%s" (include "harbor.redis.scheme" $) (include "harbor.redis.cred" $) (include "harbor.redis.addr" $) $path -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCore" -}} + {{- with .Values.redis }} + {{- $index := ternary "0" .external.coreDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index*/ +{{- define "harbor.redis.urlForJobservice" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.jobserviceDatabaseIndex .external.jobserviceDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForRegistry" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForTrivy" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.trivyAdapterIndex .external.trivyAdapterIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForHarbor" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.harborDatabaseIndex .external.harborDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCache" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.cacheLayerDatabaseIndex .external.cacheLayerDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.dbForRegistry" -}} + {{- with .Values.redis }} + {{- ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.portal" -}} + {{- printf "%s-portal" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.core" -}} + {{- printf "%s-core" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.redis" -}} + {{- printf "%s-redis" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.jobservice" -}} + {{- printf "%s-jobservice" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registry" -}} + {{- printf "%s-registry" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registryCtl" -}} + {{- printf "%s-registryctl" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.database" -}} + {{- printf "%s-database" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.trivy" -}} + {{- printf "%s-trivy" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.nginx" -}} + {{- printf "%s-nginx" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.exporter" -}} + {{- printf "%s-exporter" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.ingress" -}} + {{- printf "%s-ingress" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.noProxy" -}} + {{- printf "%s,%s,%s,%s,%s,%s,%s,%s" (include "harbor.core" .) (include "harbor.jobservice" .) (include "harbor.database" .) (include "harbor.registry" .) (include "harbor.portal" .) (include "harbor.trivy" .) (include "harbor.exporter" .) .Values.proxy.noProxy -}} +{{- end -}} + +{{- define "harbor.caBundleVolume" -}} +- name: ca-bundle-certs + secret: + secretName: {{ .Values.caBundleSecretName }} +{{- end -}} + +{{- define "harbor.caBundleVolumeMount" -}} +- name: ca-bundle-certs + mountPath: /harbor_cust_cert/custom-ca.crt + subPath: ca.crt +{{- end -}} + +{{/* scheme for all components because it only support http mode */}} +{{- define "harbor.component.scheme" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "https" -}} + {{- else -}} + {{- printf "http" -}} + {{- end -}} +{{- end -}} + +{{/* core component container port */}} +{{- define "harbor.core.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* core component service port */}} +{{- define "harbor.core.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component container port */}} +{{- define "harbor.jobservice.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component service port */}} +{{- define "harbor.jobservice.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* portal component container port */}} +{{- define "harbor.portal.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* portal component service port */}} +{{- define "harbor.portal.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* registry component container port */}} +{{- define "harbor.registry.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registry component service port */}} +{{- define "harbor.registry.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component container port */}} +{{- define "harbor.registryctl.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component service port */}} +{{- define "harbor.registryctl.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component container port */}} +{{- define "harbor.trivy.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component service port */}} +{{- define "harbor.trivy.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* CORE_URL */}} +{{/* port is included in this url as a workaround for issue https://github.com/aquasecurity/harbor-scanner-trivy/issues/108 */}} +{{- define "harbor.coreURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.core" .) (include "harbor.core.servicePort" .) -}} +{{- end -}} + +{{/* JOBSERVICE_URL */}} +{{- define "harbor.jobserviceURL" -}} + {{- printf "%s://%s-jobservice" (include "harbor.component.scheme" .) (include "harbor.fullname" .) -}} +{{- end -}} + +{{/* PORTAL_URL */}} +{{- define "harbor.portalURL" -}} + {{- printf "%s://%s" (include "harbor.component.scheme" .) (include "harbor.portal" .) -}} +{{- end -}} + +{{/* REGISTRY_URL */}} +{{- define "harbor.registryURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registry.servicePort" .) -}} +{{- end -}} + +{{/* REGISTRY_CONTROLLER_URL */}} +{{- define "harbor.registryControllerURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registryctl.servicePort" .) -}} +{{- end -}} + +{{/* TOKEN_SERVICE_URL */}} +{{- define "harbor.tokenServiceURL" -}} + {{- printf "%s/service/token" (include "harbor.coreURL" .) -}} +{{- end -}} + +{{/* TRIVY_ADAPTER_URL */}} +{{- define "harbor.trivyAdapterURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.trivy" .) (include "harbor.trivy.servicePort" .) -}} +{{- end -}} + +{{- define "harbor.internalTLS.core.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.core.secretName -}} + {{- else -}} + {{- printf "%s-core-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.jobservice.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.jobservice.secretName -}} + {{- else -}} + {{- printf "%s-jobservice-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.portal.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.portal.secretName -}} + {{- else -}} + {{- printf "%s-portal-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.registry.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.registry.secretName -}} + {{- else -}} + {{- printf "%s-registry-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.trivy.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.trivy.secretName -}} + {{- else -}} + {{- printf "%s-trivy-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsCoreSecretForIngress" -}} + {{- if eq .Values.expose.tls.certSource "none" -}} + {{- printf "" -}} + {{- else if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.ingress" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsSecretForNginx" -}} + {{- if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.nginx" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.metricsPortName" -}} + {{- if .Values.internalTLS.enabled }} + {{- printf "https-metrics" -}} + {{- else -}} + {{- printf "http-metrics" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.traceEnvs" -}} + TRACE_ENABLED: "{{ .Values.trace.enabled }}" + TRACE_SAMPLE_RATE: "{{ .Values.trace.sample_rate }}" + TRACE_NAMESPACE: "{{ .Values.trace.namespace }}" + {{- if .Values.trace.attributes }} + TRACE_ATTRIBUTES: {{ .Values.trace.attributes | toJson | squote }} + {{- end }} + {{- if eq .Values.trace.provider "jaeger" }} + TRACE_JAEGER_ENDPOINT: "{{ .Values.trace.jaeger.endpoint }}" + TRACE_JAEGER_USERNAME: "{{ .Values.trace.jaeger.username }}" + TRACE_JAEGER_AGENT_HOSTNAME: "{{ .Values.trace.jaeger.agent_host }}" + TRACE_JAEGER_AGENT_PORT: "{{ .Values.trace.jaeger.agent_port }}" + {{- else }} + TRACE_OTEL_ENDPOINT: "{{ .Values.trace.otel.endpoint }}" + TRACE_OTEL_URL_PATH: "{{ .Values.trace.otel.url_path }}" + TRACE_OTEL_COMPRESSION: "{{ .Values.trace.otel.compression }}" + TRACE_OTEL_INSECURE: "{{ .Values.trace.otel.insecure }}" + TRACE_OTEL_TIMEOUT: "{{ .Values.trace.otel.timeout }}" + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForCore" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-core" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForJobservice" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-jobservice" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForRegistryCtl" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-registryctl" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceJaegerPassword" -}} + {{- if and .Values.trace.enabled (eq .Values.trace.provider "jaeger") }} + TRACE_JAEGER_PASSWORD: "{{ .Values.trace.jaeger.password | default "" | b64enc }}" + {{- end }} +{{- end -}} + +{{/* Allow KubeVersion to be overridden. */}} +{{- define "harbor.ingress.kubeVersion" -}} + {{- default .Capabilities.KubeVersion.Version .Values.expose.ingress.kubeVersionOverride -}} +{{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-cm.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-cm.yaml new file mode 100644 index 0000000000..93cab01b4c --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-cm.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + app.conf: |+ + appname = Harbor + runmode = prod + enablegzip = true + + [prod] + httpport = {{ ternary "8443" "8080" .Values.internalTLS.enabled }} + PORT: "{{ ternary "8443" "8080" .Values.internalTLS.enabled }}" + DATABASE_TYPE: "postgresql" + POSTGRESQL_HOST: "{{ template "harbor.database.host" . }}" + POSTGRESQL_PORT: "{{ template "harbor.database.port" . }}" + POSTGRESQL_USERNAME: "{{ template "harbor.database.username" . }}" + POSTGRESQL_DATABASE: "{{ template "harbor.database.coreDatabase" . }}" + POSTGRESQL_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + POSTGRESQL_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + POSTGRESQL_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" + EXT_ENDPOINT: "{{ .Values.externalURL }}" + CORE_URL: "{{ template "harbor.coreURL" . }}" + JOBSERVICE_URL: "{{ template "harbor.jobserviceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + CORE_LOCAL_URL: "{{ ternary "https://127.0.0.1:8443" "http://127.0.0.1:8080" .Values.internalTLS.enabled }}" + WITH_TRIVY: {{ .Values.trivy.enabled | quote }} + TRIVY_ADAPTER_URL: "{{ template "harbor.trivyAdapterURL" . }}" + REGISTRY_STORAGE_PROVIDER_NAME: "{{ .Values.persistence.imageChartStorage.type }}" + LOG_LEVEL: "{{ .Values.logLevel }}" + CONFIG_PATH: "/etc/core/app.conf" + CHART_CACHE_DRIVER: "redis" + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + _REDIS_URL_REG: "{{ template "harbor.redis.urlForRegistry" . }}" + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.harborDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.harborDatabaseIndex) }} + _REDIS_URL_HARBOR: "{{ template "harbor.redis.urlForHarbor" . }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} + PORTAL_URL: "{{ template "harbor.portalURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + {{- if .Values.uaaSecretName }} + UAA_CA_ROOT: "/etc/core/auth-ca/auth-ca.crt" + {{- end }} + {{- if has "core" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE: "docker-hub,harbor,azure-acr,aws-ecr,google-gcr,quay,docker-registry,github-ghcr,jfrog-artifactory" + {{- if .Values.metrics.enabled}} + METRIC_ENABLE: "true" + METRIC_PATH: "{{ .Values.metrics.core.path }}" + METRIC_PORT: "{{ .Values.metrics.core.port }}" + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: core + {{- end }} + + {{- if hasKey .Values.core "gcTimeWindowHours" }} + #make the GC time window configurable for testing + GC_TIME_WINDOW_HOURS: "{{ .Values.core.gcTimeWindowHours }}" + {{- end }} + {{- template "harbor.traceEnvsForCore" . }} + + {{- if .Values.core.artifactPullAsyncFlushDuration }} + ARTIFACT_PULL_ASYNC_FLUSH_DURATION: {{ .Values.core.artifactPullAsyncFlushDuration | quote }} + {{- end }} + + {{- if .Values.core.gdpr}} + {{- if .Values.core.gdpr.deleteUser}} + GDPR_DELETE_USER: "true" + {{- end }} + {{- if .Values.core.gdpr.auditLogsCompliant}} + GDPR_AUDIT_LOGS: "true" + {{- end }} + {{- end }} + + {{- if .Values.cache.enabled }} + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + + {{- if .Values.core.quotaUpdateProvider }} + QUOTA_UPDATE_PROVIDER: "{{ .Values.core.quotaUpdateProvider }}" + {{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-dpl.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-dpl.yaml new file mode 100644 index 0000000000..2ee8fd59c2 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-dpl.yaml @@ -0,0 +1,257 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: core + app.kubernetes.io/component: core +spec: + replicas: {{ .Values.core.replicas }} + revisionHistoryLimit: {{ .Values.core.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: core + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: core + app.kubernetes.io/component: core +{{- if .Values.core.podLabels }} +{{ toYaml .Values.core.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/core/core-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.core.podAnnotations }} +{{ toYaml .Values.core.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.core.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.core.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: core +{{- end }} +{{- end }} + {{- with .Values.core.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: core + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.core.startupProbe.enabled }} + startupProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 360 + initialDelaySeconds: {{ .Values.core.startupProbe.initialDelaySeconds }} + periodSeconds: 10 + {{- end }} + livenessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/core/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/core/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/core/ca.crt + {{- end }} + {{- if .Values.database.external.existingSecret }} + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} + {{- if .Values.core.existingXsrfSecret }} + - name: CSRF_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.core.existingXsrfSecret }} + key: {{ .Values.core.existingXsrfSecretKey }} + {{- end }} +{{- with .Values.core.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ template "harbor.core.containerPort" . }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + - name: secret-key + mountPath: /etc/core/key + subPath: key + - name: token-service-private-key + mountPath: /etc/core/private_key.pem + subPath: tls.key + {{- if .Values.expose.tls.enabled }} + - name: ca-download + mountPath: /etc/core/ca + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + mountPath: /etc/core/auth-ca/auth-ca.crt + subPath: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + {{- end }} + - name: psc + mountPath: /etc/core/token + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} +{{- if .Values.core.resources }} + resources: +{{ toYaml .Values.core.resources | indent 10 }} +{{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + - name: secret-key + secret: + {{- if .Values.existingSecretSecretKey }} + secretName: {{ .Values.existingSecretSecretKey }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + items: + - key: secretKey + path: key + - name: token-service-private-key + secret: + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: ca-download + secret: + {{- if .Values.caSecretName }} + secretName: {{ .Values.caSecretName }} + {{- else if eq (include "harbor.autoGenCertForIngress" .) "true" }} + secretName: "{{ template "harbor.ingress" . }}" + {{- else if eq (include "harbor.autoGenCertForNginx" .) "true" }} + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + secret: + secretName: {{ .Values.uaaSecretName }} + items: + - key: ca.crt + path: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + - name: psc + emptyDir: {} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.core.priorityClassName }} + priorityClassName: {{ .Values.core.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-pre-upgrade-job.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-pre-upgrade-job.yaml new file mode 100644 index 0000000000..ce0b13134d --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-pre-upgrade-job.yaml @@ -0,0 +1,77 @@ +{{- if .Values.enableMigrateHelmHook }} +apiVersion: batch/v1 +kind: Job +metadata: + name: migration-job + labels: +{{ include "harbor.labels" . | indent 4 }} + component: migrator + annotations: + # This is what defines this resource as a hook. Without this line, the + # job is considered part of the release. + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + template: + metadata: + labels: +{{ include "harbor.matchLabels" . | indent 8 }} + component: migrator + spec: + restartPolicy: Never + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: 120 + containers: + - name: core-job + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: ["/harbor/harbor_core", "-mode=migrate"] + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + {{- if .Values.database.external.existingSecret }} + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-secret.yaml new file mode 100644 index 0000000000..62a41fce80 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-secret.yaml @@ -0,0 +1,36 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.core" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.existingSecretSecretKey }} + secretKey: {{ .Values.secretKey | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingSecret }} + secret: {{ .Values.core.secret | default (include "harbor.secretKeyHelper" (dict "key" "secret" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.core.secretName }} + {{- $ca := genCA "harbor-token-ca" 365 }} + tls.key: {{ .Values.core.tokenKey | default $ca.Key | b64enc | quote }} + tls.crt: {{ .Values.core.tokenCert | default $ca.Cert | b64enc | quote }} + {{- end }} + {{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} + {{- end }} + {{- if not .Values.database.external.existingSecret }} + POSTGRESQL_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingXsrfSecret }} + CSRF_KEY: {{ .Values.core.xsrfKey | default (include "harbor.secretKeyHelper" (dict "key" "CSRF_KEY" "data" $existingSecret.data)) | default (randAlphaNum 32) | b64enc | quote }} + {{- end }} +{{- if .Values.core.configureUserSettings }} + CONFIG_OVERWRITE_JSON: {{ .Values.core.configureUserSettings | b64enc | quote }} +{{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-svc.yaml new file mode 100644 index 0000000000..0d2cfb2915 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-svc.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.core.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} + ports: + - name: {{ ternary "https-web" "http-web" .Values.internalTLS.enabled }} + port: {{ template "harbor.core.servicePort" . }} + targetPort: {{ template "harbor.core.containerPort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.core.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: core diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/core/core-tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-tls.yaml new file mode 100644 index 0000000000..c52148f0d9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/core/core-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.core.crt\" is required!" .Values.internalTLS.core.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.core.key\" is required!" .Values.internalTLS.core.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/database/database-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-secret.yaml new file mode 100644 index 0000000000..864aff4a18 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-secret.yaml @@ -0,0 +1,11 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + POSTGRES_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/database/database-ss.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-ss.yaml new file mode 100644 index 0000000000..71c5eb1e08 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-ss.yaml @@ -0,0 +1,162 @@ +{{- if eq .Values.database.type "internal" -}} +{{- $database := .Values.persistence.persistentVolumeClaim.database -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: database + app.kubernetes.io/component: database +spec: + replicas: 1 + serviceName: "{{ template "harbor.database" . }}" + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: database + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: database + app.kubernetes.io/component: database +{{- if .Values.database.podLabels }} +{{ toYaml .Values.database.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/database/database-secret.yaml") . | sha256sum }} +{{- if .Values.database.podAnnotations }} +{{ toYaml .Values.database.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.database.internal.serviceAccountName }} + serviceAccountName: {{ .Values.database.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.database.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + initContainers: + # with "fsGroup" set, each time a volume is mounted, Kubernetes must recursively chown() and chmod() all the files and directories inside the volume + # this causes the postgresql reports the "data directory /var/lib/postgresql/data/pgdata has group or world access" issue when using some CSIs e.g. Ceph + # use this init container to correct the permission + # as "fsGroup" applied before the init container running, the container has enough permission to execute the command + - name: "data-permissions-ensurer" + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + command: ["/bin/sh"] + args: ["-c", "chmod -R 700 /var/lib/postgresql/data/pgdata || true"] +{{- if .Values.database.internal.initContainer.permissions.resources }} + resources: +{{ toYaml .Values.database.internal.initContainer.permissions.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + {{- with .Values.database.internal.extrInitContainers }} + {{- toYaml . | nindent 6 }} + {{- end }} + containers: + - name: database + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 300 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.livenessProbe.timeoutSeconds }} + readinessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 1 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.readinessProbe.timeoutSeconds }} +{{- if .Values.database.internal.resources }} + resources: +{{ toYaml .Values.database.internal.resources | indent 10 }} +{{- end }} + envFrom: + - secretRef: + name: "{{ template "harbor.database" . }}" + env: + # put the data into a sub directory to avoid the permission issue in k8s with restricted psp enabled + # more detail refer to https://github.com/goharbor/harbor-helm/issues/756 + - name: PGDATA + value: "/var/lib/postgresql/data/pgdata" +{{- with .Values.database.internal.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + - name: shm-volume + mountPath: /dev/shm + volumes: + - name: shm-volume + emptyDir: + medium: Memory + sizeLimit: {{ .Values.database.internal.shmSizeLimit }} + {{- if not .Values.persistence.enabled }} + - name: "database-data" + emptyDir: {} + {{- else if $database.existingClaim }} + - name: "database-data" + persistentVolumeClaim: + claimName: {{ $database.existingClaim }} + {{- end -}} + {{- with .Values.database.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.database.internal.priorityClassName }} + priorityClassName: {{ .Values.database.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $database.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: "database-data" + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $database.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $database.accessMode | quote }}] + {{- if $database.storageClass }} + {{- if (eq "-" $database.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $database.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $database.size | quote }} + {{- end -}} + {{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/database/database-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-svc.yaml new file mode 100644 index 0000000000..6475048cd9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/database/database-svc.yaml @@ -0,0 +1,14 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - port: 5432 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: database +{{- end -}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-cm-env.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-cm-env.yaml new file mode 100644 index 0000000000..0bf4e7d905 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-cm-env.yaml @@ -0,0 +1,35 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.exporter" . }}-env" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + LOG_LEVEL: "{{ .Values.logLevel }}" + HARBOR_EXPORTER_PORT: "{{ .Values.metrics.exporter.port }}" + HARBOR_EXPORTER_METRICS_PATH: "{{ .Values.metrics.exporter.path }}" + HARBOR_EXPORTER_METRICS_ENABLED: "{{ .Values.metrics.enabled }}" + HARBOR_EXPORTER_CACHE_TIME: "{{ .Values.exporter.cacheDuration }}" + HARBOR_EXPORTER_CACHE_CLEAN_INTERVAL: "{{ .Values.exporter.cacheCleanInterval }}" + HARBOR_METRIC_NAMESPACE: harbor + HARBOR_METRIC_SUBSYSTEM: exporter + HARBOR_REDIS_URL: "{{ template "harbor.redis.urlForJobservice" . }}" + HARBOR_REDIS_NAMESPACE: harbor_job_service_namespace + HARBOR_REDIS_TIMEOUT: "3600" + HARBOR_SERVICE_SCHEME: "{{ template "harbor.component.scheme" . }}" + HARBOR_SERVICE_HOST: "{{ template "harbor.core" . }}" + HARBOR_SERVICE_PORT: "{{ template "harbor.core.servicePort" . }}" + HARBOR_DATABASE_HOST: "{{ template "harbor.database.host" . }}" + HARBOR_DATABASE_PORT: "{{ template "harbor.database.port" . }}" + HARBOR_DATABASE_USERNAME: "{{ template "harbor.database.username" . }}" + HARBOR_DATABASE_DBNAME: "{{ template "harbor.database.coreDatabase" . }}" + HARBOR_DATABASE_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + HARBOR_DATABASE_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + HARBOR_DATABASE_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" +{{- end}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-dpl.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-dpl.yaml new file mode 100644 index 0000000000..01e9258ea9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-dpl.yaml @@ -0,0 +1,146 @@ +{{- if .Values.metrics.enabled}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.exporter" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: exporter + app.kubernetes.io/component: exporter +spec: + replicas: {{ .Values.exporter.replicas }} + revisionHistoryLimit: {{ .Values.exporter.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: exporter + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: exporter + app.kubernetes.io/component: exporter +{{- if .Values.exporter.podLabels }} +{{ toYaml .Values.exporter.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/exporter/exporter-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/exporter/exporter-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.exporter.podAnnotations }} +{{ toYaml .Values.exporter.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.exporter.serviceAccountName }} + serviceAccountName: {{ .Values.exporter.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.exporter.automountServiceAccountToken | default false }} +{{- with .Values.exporter.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: exporter +{{- end }} +{{- end }} + containers: + - name: exporter + image: {{ .Values.exporter.image.repository }}:{{ .Values.exporter.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 30 + periodSeconds: 10 + args: ["-log-level", "{{ .Values.logLevel }}"] + envFrom: + - configMapRef: + name: "{{ template "harbor.exporter" . }}-env" + - secretRef: + name: "{{ template "harbor.exporter" . }}" + env: + {{- if .Values.database.external.existingSecret }} + - name: HARBOR_DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} +{{- if .Values.exporter.resources }} + resources: +{{ toYaml .Values.exporter.resources | indent 10 }} +{{- end }} +{{- with .Values.exporter.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ .Values.metrics.exporter.port }} + volumeMounts: + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + # There are some metric data are collectd from harbor core. + # When internal TLS is enabled, the Exporter need the CA file to collect these data. + {{- end }} + volumes: + - name: config + secret: + secretName: "{{ template "harbor.exporter" . }}" + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.exporter.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.exporter.priorityClassName }} + priorityClassName: {{ .Values.exporter.priorityClassName }} + {{- end }} +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-secret.yaml new file mode 100644 index 0000000000..434a1bf689 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-secret.yaml @@ -0,0 +1,16 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.exporter" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: +{{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} +{{- end }} +{{- if not .Values.database.external.existingSecret }} + HARBOR_DATABASE_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-svc.yaml new file mode 100644 index 0000000000..4a6f3fdec6 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/exporter/exporter-svc.yaml @@ -0,0 +1,15 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.exporter" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.exporter.port }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: exporter +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/ingress/ingress.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/ingress/ingress.yaml new file mode 100644 index 0000000000..73472c6056 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/ingress/ingress.yaml @@ -0,0 +1,142 @@ +{{- if eq .Values.expose.type "ingress" }} +{{- $ingress := .Values.expose.ingress -}} +{{- $tls := .Values.expose.tls -}} +{{- if eq .Values.expose.ingress.controller "gce" }} + {{- $_ := set . "portal_path" "/*" -}} + {{- $_ := set . "api_path" "/api/*" -}} + {{- $_ := set . "service_path" "/service/*" -}} + {{- $_ := set . "v2_path" "/v2/*" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/*" -}} + {{- $_ := set . "controller_path" "/c/*" -}} +{{- else if eq .Values.expose.ingress.controller "ncp" }} + {{- $_ := set . "portal_path" "/.*" -}} + {{- $_ := set . "api_path" "/api/.*" -}} + {{- $_ := set . "service_path" "/service/.*" -}} + {{- $_ := set . "v2_path" "/v2/.*" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/.*" -}} + {{- $_ := set . "controller_path" "/c/.*" -}} +{{- else }} + {{- $_ := set . "portal_path" "/" -}} + {{- $_ := set . "api_path" "/api/" -}} + {{- $_ := set . "service_path" "/service/" -}} + {{- $_ := set . "v2_path" "/v2/" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/" -}} + {{- $_ := set . "controller_path" "/c/" -}} +{{- end }} + +--- +{{- if semverCompare "<1.14-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: extensions/v1beta1 +{{- else if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: networking.k8s.io/v1 +{{- end }} +kind: Ingress +metadata: + name: "{{ template "harbor.ingress" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if $ingress.labels }} +{{ toYaml $ingress.labels | indent 4 }} +{{- end }} + annotations: +{{ toYaml $ingress.annotations | indent 4 }} +{{- if .Values.internalTLS.enabled }} + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" +{{- end }} +{{- if eq .Values.expose.ingress.controller "ncp" }} + ncp/use-regex: "true" + {{- if $tls.enabled }} + ncp/http-redirect: "true" + {{- end }} +{{- end }} +spec: + {{- if $ingress.className }} + ingressClassName: {{ $ingress.className }} + {{- end }} + {{- if $tls.enabled }} + tls: + - secretName: {{ template "harbor.tlsCoreSecretForIngress" . }} + {{- if $ingress.hosts.core }} + hosts: + - {{ $ingress.hosts.core }} + {{- end }} + {{- end }} + rules: + - http: + paths: +{{- if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} + - path: {{ .api_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .chartrepo_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + backend: + serviceName: {{ template "harbor.portal" . }} + servicePort: {{ template "harbor.portal.servicePort" . }} +{{- else }} + - path: {{ .api_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .chartrepo_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.portal" . }} + port: + number: {{ template "harbor.portal.servicePort" . }} +{{- end }} + {{- if $ingress.hosts.core }} + host: {{ $ingress.hosts.core }} + {{- end }} + +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/ingress/secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/ingress/secret.yaml new file mode 100644 index 0000000000..41507b3dd9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/ingress/secret.yaml @@ -0,0 +1,15 @@ +{{- if eq (include "harbor.autoGenCertForIngress" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cert := genSignedCert .Values.expose.ingress.hosts.core nil (list .Values.expose.ingress.hosts.core) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.ingress" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/internal/auto-tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/internal/auto-tls.yaml new file mode 100644 index 0000000000..da5f5e2c7b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/internal/auto-tls.yaml @@ -0,0 +1,81 @@ +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} +{{- $ca := genCA "harbor-internal-ca" 365 }} +{{- $coreCN := (include "harbor.core" .) }} +{{- $coreCrt := genSignedCert $coreCN (list "127.0.0.1") (list "localhost" $coreCN) 365 $ca }} +{{- $jsCN := (include "harbor.jobservice" .) }} +{{- $jsCrt := genSignedCert $jsCN nil (list $jsCN) 365 $ca }} +{{- $regCN := (include "harbor.registry" .) }} +{{- $regCrt := genSignedCert $regCN nil (list $regCN) 365 $ca }} +{{- $portalCN := (include "harbor.portal" .) }} +{{- $portalCrt := genSignedCert $portalCN nil (list $portalCN) 365 $ca }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $coreCrt.Cert | b64enc | quote }} + tls.key: {{ $coreCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $jsCrt.Cert | b64enc | quote }} + tls.key: {{ $jsCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $regCrt.Cert | b64enc | quote }} + tls.key: {{ $regCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $portalCrt.Cert | b64enc | quote }} + tls.key: {{ $portalCrt.Key | b64enc | quote }} + +{{- if and .Values.trivy.enabled}} +--- +{{- $trivyCN := (include "harbor.trivy" .) }} +{{- $trivyCrt := genSignedCert $trivyCN nil (list $trivyCN) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $trivyCrt.Cert | b64enc | quote }} + tls.key: {{ $trivyCrt.Key | b64enc | quote }} +{{- end }} + +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm-env.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm-env.yaml new file mode 100644 index 0000000000..8411c7a47c --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm-env.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}-env" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + CORE_URL: "{{ template "harbor.coreURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + + JOBSERVICE_WEBHOOK_JOB_MAX_RETRY: "{{ .Values.jobservice.notification.webhook_job_max_retry }}" + JOBSERVICE_WEBHOOK_JOB_HTTP_CLIENT_TIMEOUT: "{{ .Values.jobservice.notification.webhook_job_http_client_timeout }}" + + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.metrics.enabled}} + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: jobservice + {{- end }} + {{- template "harbor.traceEnvsForJobservice" . }} + {{- if .Values.cache.enabled }} + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm.yaml new file mode 100644 index 0000000000..8211c62209 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-cm.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + #Server listening port + protocol: "{{ template "harbor.component.scheme" . }}" + port: {{ template "harbor.jobservice.containerPort". }} + {{- if .Values.internalTLS.enabled }} + https_config: + cert: "/etc/harbor/ssl/jobservice/tls.crt" + key: "/etc/harbor/ssl/jobservice/tls.key" + {{- end }} + worker_pool: + workers: {{ .Values.jobservice.maxJobWorkers }} + backend: "redis" + redis_pool: + redis_url: "{{ template "harbor.redis.urlForJobservice" . }}" + namespace: "harbor_job_service_namespace" + idle_timeout_second: 3600 + job_loggers: + {{- if has "file" .Values.jobservice.jobLoggers }} + - name: "FILE" + level: {{ .Values.logLevel | upper }} + settings: # Customized settings of logger + base_dir: "/var/log/jobs" + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + settings: # Customized settings of sweeper + work_dir: "/var/log/jobs" + {{- end }} + {{- if has "database" .Values.jobservice.jobLoggers }} + - name: "DB" + level: {{ .Values.logLevel | upper }} + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + {{- end }} + {{- if has "stdout" .Values.jobservice.jobLoggers }} + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + {{- end }} + metric: + enabled: {{ .Values.metrics.enabled }} + path: {{ .Values.metrics.jobservice.path }} + port: {{ .Values.metrics.jobservice.port }} + #Loggers for the job service + loggers: + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: {{ .Values.jobservice.reaper.max_update_hours }} + # the max time for execution in running state without new task created + max_dangling_hours: {{ .Values.jobservice.reaper.max_dangling_hours }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-dpl.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-dpl.yaml new file mode 100644 index 0000000000..1bb6690824 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-dpl.yaml @@ -0,0 +1,182 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + replicas: {{ .Values.jobservice.replicas }} + revisionHistoryLimit: {{ .Values.jobservice.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: jobservice + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: jobservice + app.kubernetes.io/component: jobservice +{{- if .Values.jobservice.podLabels }} +{{ toYaml .Values.jobservice.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm.yaml") . | sha256sum }} + checksum/configmap-env: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/jobservice/jobservice-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.jobservice.podAnnotations }} +{{ toYaml .Values.jobservice.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.jobservice.serviceAccountName }} + serviceAccountName: {{ .Values.jobservice.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.jobservice.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.jobservice.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: jobservice +{{- end }} +{{- end }} + {{- with .Values.jobservice.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: jobservice + image: {{ .Values.jobservice.image.repository }}:{{ .Values.jobservice.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 20 + periodSeconds: 10 +{{- if .Values.jobservice.resources }} + resources: +{{ toYaml .Values.jobservice.resources | indent 10 }} +{{- end }} + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + {{- if .Values.jobservice.existingSecret }} + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/jobservice/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/jobservice/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/jobservice/ca.crt + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} +{{- with .Values.jobservice.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.jobservice" . }}-env" + - secretRef: + name: "{{ template "harbor.jobservice" . }}" + ports: + - containerPort: {{ template "harbor.jobservice.containerPort" . }} + volumeMounts: + - name: jobservice-config + mountPath: /etc/jobservice/config.yml + subPath: config.yml + - name: job-logs + mountPath: /var/log/jobs + subPath: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.subPath }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + mountPath: /etc/harbor/ssl/jobservice + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: jobservice-config + configMap: + name: "{{ template "harbor.jobservice" . }}" + - name: job-logs + {{- if and .Values.persistence.enabled (has "file" .Values.jobservice.jobLoggers) }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim | default (include "harbor.jobservice" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.jobservice.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.jobservice.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.jobservice.priorityClassName }} + priorityClassName: {{ .Values.jobservice.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-pvc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-pvc.yaml new file mode 100644 index 0000000000..3f7d00b671 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-pvc.yaml @@ -0,0 +1,31 @@ +{{- $jobLog := .Values.persistence.persistentVolumeClaim.jobservice.jobLog -}} +{{- if and .Values.persistence.enabled (not $jobLog.existingClaim) (has "file" .Values.jobservice.jobLoggers) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.jobservice" . }} + annotations: + {{- range $key, $value := $jobLog.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + accessModes: + - {{ $jobLog.accessMode }} + resources: + requests: + storage: {{ $jobLog.size }} + {{- if $jobLog.storageClass }} + {{- if eq "-" $jobLog.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $jobLog.storageClass }} + {{- end }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-secrets.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-secrets.yaml new file mode 100644 index 0000000000..eeb00bde00 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-secrets.yaml @@ -0,0 +1,16 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.jobservice" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.jobservice.existingSecret }} + JOBSERVICE_SECRET: {{ .Values.jobservice.secret | default (include "harbor.secretKeyHelper" (dict "key" "JOBSERVICE_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-svc.yaml new file mode 100644 index 0000000000..d2b7a47fd4 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-svc.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-jobservice" "http-jobservice" .Values.internalTLS.enabled }} + port: {{ template "harbor.jobservice.servicePort" . }} + targetPort: {{ template "harbor.jobservice.containerPort" . }} +{{- if .Values.metrics.enabled }} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.jobservice.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: jobservice diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-tls.yaml new file mode 100644 index 0000000000..234cb39995 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/jobservice/jobservice-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.jobservice.crt\" is required!" .Values.internalTLS.jobservice.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.jobservice.key\" is required!" .Values.internalTLS.jobservice.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/metrics/metrics-svcmon.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/metrics/metrics-svcmon.yaml new file mode 100644 index 0000000000..1122ef01ef --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/metrics/metrics-svcmon.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "harbor.fullname" . }} + labels: {{ include "harbor.labels" . | nindent 4 }} +{{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} +{{- end }} +spec: + jobLabel: app.kubernetes.io/name + endpoints: + - port: {{ template "harbor.metricsPortName" . }} + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + honorLabels: true +{{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.metrics.serviceMonitor.metricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.metrics.serviceMonitor.relabelings | indent 4 }} +{{- end }} + selector: + matchLabels: {{ include "harbor.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-http.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-http.yaml new file mode 100644 index 0000000000..c4b8354d06 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-http.yaml @@ -0,0 +1,150 @@ +{{- if and (ne .Values.expose.type "ingress") (not .Values.expose.tls.enabled) }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server {{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled}} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end }} + server_tokens off; + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # Add extra headers + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass {{ $scheme }}://core/chartrepo/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + proxy_send_timeout 900; + proxy_read_timeout 900; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + } +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-https.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-https.yaml new file mode 100644 index 0000000000..56c943a619 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/configmap-https.yaml @@ -0,0 +1,187 @@ +{{- if and (ne .Values.expose.type "ingress") .Values.expose.tls.enabled }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server "{{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}"; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8443 ssl; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8443 ssl; + {{- end }} + # server_name harbordomain.com; + server_tokens off; + # SSL + ssl_certificate /etc/nginx/cert/tls.crt; + ssl_certificate_key /etc/nginx/cert/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + # Add extra headers + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; HttpOnly; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass {{ $scheme }}://core/chartrepo/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end}} + #server_name harbordomain.com; + return 301 https://$host$request_uri; + } + } +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/nginx/deployment.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/deployment.yaml new file mode 100644 index 0000000000..3abc941989 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/deployment.yaml @@ -0,0 +1,132 @@ +{{- if ne .Values.expose.type "ingress" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: nginx + app.kubernetes.io/component: nginx +spec: + replicas: {{ .Values.nginx.replicas }} + revisionHistoryLimit: {{ .Values.nginx.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: nginx + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: nginx + app.kubernetes.io/component: nginx +{{- if .Values.nginx.podLabels }} +{{ toYaml .Values.nginx.podLabels | indent 8 }} +{{- end }} + annotations: + {{- if not .Values.expose.tls.enabled }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-http.yaml") . | sha256sum }} + {{- else }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-https.yaml") . | sha256sum }} + {{- end }} + {{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} + checksum/secret: {{ include (print $.Template.BasePath "/nginx/secret.yaml") . | sha256sum }} + {{- end }} +{{- if .Values.nginx.podAnnotations }} +{{ toYaml .Values.nginx.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- if .Values.nginx.serviceAccountName }} + serviceAccountName: {{ .Values.nginx.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.nginx.automountServiceAccountToken | default false }} +{{- with .Values.nginx.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: nginx +{{- end }} +{{- end }} + containers: + - name: nginx + image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + {{- $_ := set . "scheme" "HTTP" -}} + {{- $_ := set . "port" "8080" -}} + {{- if .Values.expose.tls.enabled }} + {{- $_ := set . "scheme" "HTTPS" -}} + {{- $_ := set . "port" "8443" -}} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.nginx.resources }} + resources: +{{ toYaml .Values.nginx.resources | indent 10 }} +{{- end }} +{{- with .Values.nginx.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: 8080 + {{- if .Values.expose.tls.enabled }} + - containerPort: 8443 + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.expose.tls.enabled }} + - name: certificate + mountPath: /etc/nginx/cert + {{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.nginx" . }} + {{- if .Values.expose.tls.enabled }} + - name: certificate + secret: + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- with .Values.nginx.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.nginx.priorityClassName }} + priorityClassName: {{ .Values.nginx.priorityClassName }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/nginx/secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/secret.yaml new file mode 100644 index 0000000000..c819c556d9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/secret.yaml @@ -0,0 +1,23 @@ +{{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cn := (required "The \"expose.tls.auto.commonName\" is required!" .Values.expose.tls.auto.commonName) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if regexMatch `^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` $cn }} + {{- $cert := genSignedCert $cn (list $cn) nil 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- else }} + {{- $cert := genSignedCert $cn nil (list $cn) 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/nginx/service.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/service.yaml new file mode 100644 index 0000000000..691584ce02 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/nginx/service.yaml @@ -0,0 +1,94 @@ +{{- if or (eq .Values.expose.type "clusterIP") (eq .Values.expose.type "nodePort") (eq .Values.expose.type "loadBalancer") }} +apiVersion: v1 +kind: Service +metadata: +{{- if eq .Values.expose.type "clusterIP" }} +{{- $clusterIP := .Values.expose.clusterIP }} + name: {{ $clusterIP.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.clusterIP.labels }} +{{ toYaml $clusterIP.labels | indent 4 }} +{{- end }} +{{- with $clusterIP.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: ClusterIP + {{- if .Values.expose.clusterIP.staticClusterIP }} + clusterIP: {{ .Values.expose.clusterIP.staticClusterIP }} + {{- end }} + ports: + - name: http + port: {{ $clusterIP.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $clusterIP.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- else if eq .Values.expose.type "nodePort" }} +{{- $nodePort := .Values.expose.nodePort }} + name: {{ $nodePort.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.nodePort.labels }} +{{ toYaml $nodePort.labels | indent 4 }} +{{- end }} +{{- with $nodePort.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: NodePort + ports: + - name: http + port: {{ $nodePort.ports.http.port }} + targetPort: 8080 + {{- if $nodePort.ports.http.nodePort }} + nodePort: {{ $nodePort.ports.http.nodePort }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $nodePort.ports.https.port }} + targetPort: 8443 + {{- if $nodePort.ports.https.nodePort }} + nodePort: {{ $nodePort.ports.https.nodePort }} + {{- end }} + {{- end }} +{{- else if eq .Values.expose.type "loadBalancer" }} +{{- $loadBalancer := .Values.expose.loadBalancer }} + name: {{ $loadBalancer.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.loadBalancer.labels }} +{{ toYaml $loadBalancer.labels | indent 4 }} +{{- end }} +{{- with $loadBalancer.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: LoadBalancer + {{- with $loadBalancer.sourceRanges }} + loadBalancerSourceRanges: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $loadBalancer.IP }} + loadBalancerIP: {{ $loadBalancer.IP }} + {{- end }} + ports: + - name: http + port: {{ $loadBalancer.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $loadBalancer.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: nginx +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/portal/configmap.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/portal/configmap.yaml new file mode 100644 index 0000000000..7b2118e721 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/portal/configmap.yaml @@ -0,0 +1,67 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + events { + worker_connections 1024; + } + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + server { + {{- if .Values.internalTLS.enabled }} + {{- if .Values.ipFamily.ipv4.enabled}} + listen {{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + # SSL + ssl_certificate /etc/harbor/ssl/portal/tls.crt; + ssl_certificate_key /etc/harbor/ssl/portal/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + {{- else }} + {{- if .Values.ipFamily.ipv4.enabled }} + listen {{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- end }} + server_name localhost; + root /usr/share/nginx/html; + index index.html index.htm; + include /etc/nginx/mime.types; + gzip on; + gzip_min_length 1000; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + location /devcenter-api-2.0 { + try_files $uri $uri/ /swagger-ui-index.html; + } + location / { + try_files $uri $uri/ /index.html; + } + location = /index.html { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + } + } diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/portal/deployment.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/portal/deployment.yaml new file mode 100644 index 0000000000..4dea944382 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/portal/deployment.yaml @@ -0,0 +1,123 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: portal + app.kubernetes.io/component: portal +spec: + replicas: {{ .Values.portal.replicas }} + revisionHistoryLimit: {{ .Values.portal.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: portal + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: portal + app.kubernetes.io/component: portal +{{- if .Values.portal.podLabels }} +{{ toYaml .Values.portal.podLabels | indent 8 }} +{{- end }} + annotations: +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/portal/tls.yaml") . | sha256sum }} +{{- end }} + checksum/configmap: {{ include (print $.Template.BasePath "/portal/configmap.yaml") . | sha256sum }} +{{- if .Values.portal.podAnnotations }} +{{ toYaml .Values.portal.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- if .Values.portal.serviceAccountName }} + serviceAccountName: {{ .Values.portal.serviceAccountName }} +{{- end }} + automountServiceAccountToken: {{ .Values.portal.automountServiceAccountToken | default false }} +{{- with .Values.portal.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: portal +{{- end }} +{{- end }} + {{- with .Values.portal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: portal + image: {{ .Values.portal.image.repository }}:{{ .Values.portal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.portal.resources }} + resources: +{{ toYaml .Values.portal.resources | indent 10 }} +{{- end }} +{{- with .Values.portal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 + ports: + - containerPort: {{ template "harbor.portal.containerPort" . }} + volumeMounts: + - name: portal-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + mountPath: /etc/harbor/ssl/portal + {{- end }} + volumes: + - name: portal-config + configMap: + name: "{{ template "harbor.portal" . }}" + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.portal.secretName" . }} + {{- end }} + {{- with .Values.portal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.portal.priorityClassName }} + priorityClassName: {{ .Values.portal.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/portal/service.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/portal/service.yaml new file mode 100644 index 0000000000..d00026da46 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/portal/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.portal.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} + ports: + - port: {{ template "harbor.portal.servicePort" . }} + targetPort: {{ template "harbor.portal.containerPort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: portal diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/portal/tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/portal/tls.yaml new file mode 100644 index 0000000000..de63f4e813 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/portal/tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.portal.crt\" is required!" .Values.internalTLS.portal.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.portal.key\" is required!" .Values.internalTLS.portal.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/redis/service.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/redis/service.yaml new file mode 100644 index 0000000000..79c95c3e05 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/redis/service.yaml @@ -0,0 +1,14 @@ +{{- if eq .Values.redis.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.redis" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - port: 6379 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: redis +{{- end -}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/redis/statefulset.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/redis/statefulset.yaml new file mode 100644 index 0000000000..1d37fb184b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/redis/statefulset.yaml @@ -0,0 +1,125 @@ +{{- if eq .Values.redis.type "internal" -}} +{{- $redis := .Values.persistence.persistentVolumeClaim.redis -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.redis" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: redis + app.kubernetes.io/component: redis +spec: + replicas: 1 + serviceName: {{ template "harbor.redis" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: redis + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: redis + app.kubernetes.io/component: redis +{{- if .Values.redis.podLabels }} +{{ toYaml .Values.redis.podLabels | indent 8 }} +{{- end }} +{{- if .Values.redis.podAnnotations }} + annotations: +{{ toYaml .Values.redis.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.redis.internal.serviceAccountName }} + serviceAccountName: {{ .Values.redis.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.redis.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + {{- with .Values.redis.internal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: redis + image: {{ .Values.redis.internal.image.repository }}:{{ .Values.redis.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.redis.internal.resources }} + resources: +{{ toYaml .Values.redis.internal.resources | indent 10 }} +{{- end }} +{{- with .Values.redis.internal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /var/lib/redis + subPath: {{ $redis.subPath }} + {{- if not .Values.persistence.enabled }} + volumes: + - name: data + emptyDir: {} + {{- else if $redis.existingClaim }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ $redis.existingClaim }} + {{- end -}} + {{- with .Values.redis.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.redis.internal.priorityClassName }} + priorityClassName: {{ .Values.redis.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $redis.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $redis.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $redis.accessMode | quote }}] + {{- if $redis.storageClass }} + {{- if (eq "-" $redis.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $redis.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $redis.size | quote }} + {{- end -}} + {{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-cm.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-cm.yaml new file mode 100644 index 0000000000..4f7056c384 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-cm.yaml @@ -0,0 +1,246 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + version: 0.1 + log: + {{- if eq .Values.logLevel "warning" }} + level: warn + {{- else if eq .Values.logLevel "fatal" }} + level: error + {{- else }} + level: {{ .Values.logLevel }} + {{- end }} + fields: + service: registry + storage: + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if eq $type "filesystem" }} + filesystem: + rootdirectory: {{ $storage.filesystem.rootdirectory }} + {{- if $storage.filesystem.maxthreads }} + maxthreads: {{ $storage.filesystem.maxthreads }} + {{- end }} + {{- else if eq $type "azure" }} + azure: + accountname: {{ $storage.azure.accountname }} + container: {{ $storage.azure.container }} + {{- if $storage.azure.realm }} + realm: {{ $storage.azure.realm }} + {{- end }} + {{- else if eq $type "gcs" }} + gcs: + bucket: {{ $storage.gcs.bucket }} + {{- if not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity }} + keyfile: /etc/registry/gcs-key.json + {{- end }} + {{- if $storage.gcs.rootdirectory }} + rootdirectory: {{ $storage.gcs.rootdirectory }} + {{- end }} + {{- if $storage.gcs.chunksize }} + chunksize: {{ $storage.gcs.chunksize }} + {{- end }} + {{- else if eq $type "s3" }} + s3: + region: {{ $storage.s3.region }} + bucket: {{ $storage.s3.bucket }} + {{- if $storage.s3.regionendpoint }} + regionendpoint: {{ $storage.s3.regionendpoint }} + {{- end }} + {{- if $storage.s3.encrypt }} + encrypt: {{ $storage.s3.encrypt }} + {{- end }} + {{- if $storage.s3.keyid }} + keyid: {{ $storage.s3.keyid }} + {{- end }} + {{- if $storage.s3.secure }} + secure: {{ $storage.s3.secure }} + {{- end }} + {{- if and $storage.s3.secure $storage.s3.skipverify }} + skipverify: {{ $storage.s3.skipverify }} + {{- end }} + {{- if $storage.s3.v4auth }} + v4auth: {{ $storage.s3.v4auth }} + {{- end }} + {{- if $storage.s3.chunksize }} + chunksize: {{ $storage.s3.chunksize }} + {{- end }} + {{- if $storage.s3.rootdirectory }} + rootdirectory: {{ $storage.s3.rootdirectory }} + {{- end }} + {{- if $storage.s3.storageclass }} + storageclass: {{ $storage.s3.storageclass }} + {{- end }} + {{- if $storage.s3.multipartcopychunksize }} + multipartcopychunksize: {{ $storage.s3.multipartcopychunksize }} + {{- end }} + {{- if $storage.s3.multipartcopymaxconcurrency }} + multipartcopymaxconcurrency: {{ $storage.s3.multipartcopymaxconcurrency }} + {{- end }} + {{- if $storage.s3.multipartcopythresholdsize }} + multipartcopythresholdsize: {{ $storage.s3.multipartcopythresholdsize }} + {{- end }} + {{- else if eq $type "swift" }} + swift: + authurl: {{ $storage.swift.authurl }} + username: {{ $storage.swift.username }} + container: {{ $storage.swift.container }} + {{- if $storage.swift.region }} + region: {{ $storage.swift.region }} + {{- end }} + {{- if $storage.swift.tenant }} + tenant: {{ $storage.swift.tenant }} + {{- end }} + {{- if $storage.swift.tenantid }} + tenantid: {{ $storage.swift.tenantid }} + {{- end }} + {{- if $storage.swift.domain }} + domain: {{ $storage.swift.domain }} + {{- end }} + {{- if $storage.swift.domainid }} + domainid: {{ $storage.swift.domainid }} + {{- end }} + {{- if $storage.swift.trustid }} + trustid: {{ $storage.swift.trustid }} + {{- end }} + {{- if $storage.swift.insecureskipverify }} + insecureskipverify: {{ $storage.swift.insecureskipverify }} + {{- end }} + {{- if $storage.swift.chunksize }} + chunksize: {{ $storage.swift.chunksize }} + {{- end }} + {{- if $storage.swift.prefix }} + prefix: {{ $storage.swift.prefix }} + {{- end }} + {{- if $storage.swift.authversion }} + authversion: {{ $storage.swift.authversion }} + {{- end }} + {{- if $storage.swift.endpointtype }} + endpointtype: {{ $storage.swift.endpointtype }} + {{- end }} + {{- if $storage.swift.tempurlcontainerkey }} + tempurlcontainerkey: {{ $storage.swift.tempurlcontainerkey }} + {{- end }} + {{- if $storage.swift.tempurlmethods }} + tempurlmethods: {{ $storage.swift.tempurlmethods }} + {{- end }} + {{- else if eq $type "oss" }} + oss: + accesskeyid: {{ $storage.oss.accesskeyid }} + region: {{ $storage.oss.region }} + bucket: {{ $storage.oss.bucket }} + {{- if $storage.oss.endpoint }} + endpoint: {{ $storage.oss.bucket }}.{{ $storage.oss.endpoint }} + {{- end }} + {{- if $storage.oss.internal }} + internal: {{ $storage.oss.internal }} + {{- end }} + {{- if $storage.oss.encrypt }} + encrypt: {{ $storage.oss.encrypt }} + {{- end }} + {{- if $storage.oss.secure }} + secure: {{ $storage.oss.secure }} + {{- end }} + {{- if $storage.oss.chunksize }} + chunksize: {{ $storage.oss.chunksize }} + {{- end }} + {{- if $storage.oss.rootdirectory }} + rootdirectory: {{ $storage.oss.rootdirectory }} + {{- end }} + {{- end }} + cache: + layerinfo: redis + maintenance: + uploadpurging: + {{- if .Values.registry.upload_purging.enabled }} + enabled: true + age: {{ .Values.registry.upload_purging.age }} + interval: {{ .Values.registry.upload_purging.interval }} + dryrun: {{ .Values.registry.upload_purging.dryrun }} + {{- else }} + enabled: false + {{- end }} + delete: + enabled: true + redirect: + disable: {{ $storage.disableredirect }} + redis: + addr: {{ template "harbor.redis.addr" . }} + {{- if eq "redis+sentinel" (include "harbor.redis.scheme" .) }} + sentinelMasterSet: {{ template "harbor.redis.masterSet" . }} + {{- end }} + db: {{ template "harbor.redis.dbForRegistry" . }} + {{- if not (eq (include "harbor.redis.password" .) "") }} + password: {{ template "harbor.redis.password" . }} + {{- end }} + readtimeout: 10s + writetimeout: 10s + dialtimeout: 10s + pool: + maxidle: 100 + maxactive: 500 + idletimeout: 60s + http: + addr: :{{ template "harbor.registry.containerPort" . }} + relativeurls: {{ .Values.registry.relativeurls }} + {{- if .Values.internalTLS.enabled }} + tls: + certificate: /etc/harbor/ssl/registry/tls.crt + key: /etc/harbor/ssl/registry/tls.key + minimumtls: tls1.2 + {{- end }} + # set via environment variable + # secret: placeholder + debug: + {{- if .Values.metrics.enabled}} + addr: :{{ .Values.metrics.registry.port }} + prometheus: + enabled: true + path: {{ .Values.metrics.registry.path }} + {{- else }} + addr: localhost:5001 + {{- end }} + auth: + htpasswd: + realm: harbor-registry-basic-realm + path: /etc/registry/passwd + validation: + disabled: true + compatibility: + schema1: + enabled: true + + {{- if .Values.registry.middleware.enabled }} + {{- $middleware := .Values.registry.middleware }} + {{- $middlewareType := $middleware.type }} + {{- if eq $middlewareType "cloudFront" }} + middleware: + storage: + - name: cloudfront + options: + baseurl: {{ $middleware.cloudFront.baseurl }} + privatekey: /etc/registry/pk.pem + keypairid: {{ $middleware.cloudFront.keypairid }} + duration: {{ $middleware.cloudFront.duration }} + ipfilteredby: {{ $middleware.cloudFront.ipfilteredby }} + {{- end }} + {{- end }} + ctl-config.yml: |+ + --- + {{- if .Values.internalTLS.enabled }} + protocol: "https" + port: 8443 + https_config: + cert: "/etc/harbor/ssl/registry/tls.crt" + key: "/etc/harbor/ssl/registry/tls.key" + {{- else }} + protocol: "http" + port: 8080 + {{- end }} + log_level: {{ .Values.logLevel }} + registry_config: "/etc/registry/config.yml" diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-dpl.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-dpl.yaml new file mode 100644 index 0000000000..0965cf2e2a --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-dpl.yaml @@ -0,0 +1,431 @@ +{{- $storage := .Values.persistence.imageChartStorage }} +{{- $type := $storage.type }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + replicas: {{ .Values.registry.replicas }} + revisionHistoryLimit: {{ .Values.registry.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: registry + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: registry + app.kubernetes.io/component: registry +{{- if .Values.registry.podLabels }} +{{ toYaml .Values.registry.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/registry/registry-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/registry/registry-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/registry/registry-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.registry.podAnnotations }} +{{ toYaml .Values.registry.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + fsGroupChangePolicy: OnRootMismatch +{{- if .Values.registry.serviceAccountName }} + serviceAccountName: {{ .Values.registry.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.registry.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.registry.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: registry +{{- end }} +{{- end }} + {{- with .Values.registry.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: registry + image: {{ .Values.registry.registry.image.repository }}:{{ .Values.registry.registry.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.registry.resources }} + resources: +{{ toYaml .Values.registry.registry.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + args: ["serve", "/etc/registry/config.yml"] + envFrom: + - secretRef: + name: "{{ template "harbor.registry" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.registry.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registry.containerPort" . }} + - containerPort: {{ ternary .Values.metrics.registry.port 5001 .Values.metrics.enabled }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-htpasswd + mountPath: /etc/registry/passwd + subPath: passwd + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + mountPath: /etc/registry/pk.pem + subPath: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + - name: registryctl + image: {{ .Values.registry.controller.image.repository }}:{{ .Values.registry.controller.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.controller.resources }} + resources: +{{ toYaml .Values.registry.controller.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.registryCtl" . }}" + - secretRef: + name: "{{ template "harbor.registry" . }}" + - secretRef: + name: "{{ template "harbor.registryCtl" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.controller.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registryctl.containerPort" . }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + - name: registry-config + mountPath: /etc/registryctl/config.yml + subPath: ctl-config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: registry-htpasswd + secret: + {{- if not .Values.registry.credentials.existingSecret }} + secretName: {{ template "harbor.registry" . }}-htpasswd + {{ else }} + secretName: {{ .Values.registry.credentials.existingSecret }} + {{- end }} + items: + - key: REGISTRY_HTPASSWD + path: passwd + - name: registry-config + configMap: + name: "{{ template "harbor.registry" . }}" + - name: registry-data + {{- if and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "filesystem") }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.registry.existingClaim | default (include "harbor.registry" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.registry.secretName" . }} + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + secret: + {{- if and (eq $type "gcs") $storage.gcs.existingSecret }} + secretName: {{ $storage.gcs.existingSecret }} + {{- else }} + secretName: {{ template "harbor.registry" . }} + {{- end }} + items: + - key: GCS_KEY_DATA + path: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + secret: + secretName: {{ .Values.persistence.imageChartStorage.caBundleSecretName }} + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + secret: + secretName: {{ .Values.registry.middleware.cloudFront.privateKeySecret }} + items: + - key: CLOUDFRONT_KEY_DATA + path: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.registry.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.registry.priorityClassName }} + priorityClassName: {{ .Values.registry.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-pvc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-pvc.yaml new file mode 100644 index 0000000000..5d6d4d3ddf --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-pvc.yaml @@ -0,0 +1,33 @@ +{{- if .Values.persistence.enabled }} +{{- $registry := .Values.persistence.persistentVolumeClaim.registry -}} +{{- if and (not $registry.existingClaim) (eq .Values.persistence.imageChartStorage.type "filesystem") }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.registry" . }} + annotations: + {{- range $key, $value := $registry.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + accessModes: + - {{ $registry.accessMode }} + resources: + requests: + storage: {{ $registry.size }} + {{- if $registry.storageClass }} + {{- if eq "-" $registry.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $registry.storageClass }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-secret.yaml new file mode 100644 index 0000000000..e853a9cbec --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-secret.yaml @@ -0,0 +1,55 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.registry" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.registry.existingSecret }} + REGISTRY_HTTP_SECRET: {{ .Values.registry.secret | default (include "harbor.secretKeyHelper" (dict "key" "REGISTRY_HTTP_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.redis.external.existingSecret }} + REGISTRY_REDIS_PASSWORD: {{ include "harbor.redis.password" . | b64enc | quote }} + {{- end }} + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if and (eq $type "azure") (not $storage.azure.existingSecret) }} + REGISTRY_STORAGE_AZURE_ACCOUNTKEY: {{ $storage.azure.accountkey | b64enc | quote }} + {{- else if and (and (eq $type "gcs") (not $storage.gcs.existingSecret)) (not $storage.gcs.useWorkloadIdentity) }} + GCS_KEY_DATA: {{ $storage.gcs.encodedkey | quote }} + {{- else if eq $type "s3" }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.accesskey) }} + REGISTRY_STORAGE_S3_ACCESSKEY: {{ $storage.s3.accesskey | b64enc | quote }} + {{- end }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.secretkey) }} + REGISTRY_STORAGE_S3_SECRETKEY: {{ $storage.s3.secretkey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "swift") (not ($storage.swift.existingSecret)) }} + REGISTRY_STORAGE_SWIFT_PASSWORD: {{ $storage.swift.password | b64enc | quote }} + {{- if $storage.swift.secretkey }} + REGISTRY_STORAGE_SWIFT_SECRETKEY: {{ $storage.swift.secretkey | b64enc | quote }} + {{- end }} + {{- if $storage.swift.accesskey }} + REGISTRY_STORAGE_SWIFT_ACCESSKEY: {{ $storage.swift.accesskey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "oss") ((not ($storage.oss.existingSecret))) }} + REGISTRY_STORAGE_OSS_ACCESSKEYSECRET: {{ $storage.oss.accesskeysecret | b64enc | quote }} + {{- end }} +{{- if not .Values.registry.credentials.existingSecret }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}-htpasswd" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if .Values.registry.credentials.htpasswdString }} + REGISTRY_HTPASSWD: {{ .Values.registry.credentials.htpasswdString | b64enc | quote }} + {{- else }} + REGISTRY_HTPASSWD: {{ htpasswd .Values.registry.credentials.username .Values.registry.credentials.password | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-svc.yaml new file mode 100644 index 0000000000..749690ea03 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-svc.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-registry" "http-registry" .Values.internalTLS.enabled }} + port: {{ template "harbor.registry.servicePort" . }} + + - name: {{ ternary "https-controller" "http-controller" .Values.internalTLS.enabled }} + port: {{ template "harbor.registryctl.servicePort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.registry.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: registry \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-tls.yaml new file mode 100644 index 0000000000..9d1862c417 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registry-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.registry.crt\" is required!" .Values.internalTLS.registry.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.registry.key\" is required!" .Values.internalTLS.registry.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-cm.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-cm.yaml new file mode 100644 index 0000000000..87aa5ffe24 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-cm.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registryCtl" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- template "harbor.traceEnvsForRegistryCtl" . }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-secret.yaml new file mode 100644 index 0000000000..70097703e9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/registry/registryctl-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registryCtl" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- template "harbor.traceJaegerPassword" . }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-secret.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-secret.yaml new file mode 100644 index 0000000000..84652c7498 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.trivy.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.trivy" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + redisURL: {{ include "harbor.redis.urlForTrivy" . | b64enc }} + gitHubToken: {{ .Values.trivy.gitHubToken | default "" | b64enc | quote }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-sts.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-sts.yaml new file mode 100644 index 0000000000..c876ba3878 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-sts.yaml @@ -0,0 +1,230 @@ +{{- if .Values.trivy.enabled }} +{{- $trivy := .Values.persistence.persistentVolumeClaim.trivy }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.trivy" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: trivy + app.kubernetes.io/component: trivy +spec: + replicas: {{ .Values.trivy.replicas }} + serviceName: {{ template "harbor.trivy" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: trivy + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: trivy + app.kubernetes.io/component: trivy +{{- if .Values.trivy.podLabels }} +{{ toYaml .Values.trivy.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/trivy/trivy-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/trivy/trivy-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.trivy.podAnnotations }} +{{ toYaml .Values.trivy.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} +{{- end }} +{{- if .Values.trivy.serviceAccountName }} + serviceAccountName: {{ .Values.trivy.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + automountServiceAccountToken: {{ .Values.trivy.automountServiceAccountToken | default false }} +{{- with .Values.trivy.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: trivy +{{- end }} +{{- end }} + {{- with .Values.trivy.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: trivy + image: {{ .Values.trivy.image.repository }}:{{ .Values.trivy.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 12 }} + {{- end }} + env: + {{- if has "trivy" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + - name: "SCANNER_LOG_LEVEL" + value: {{ .Values.logLevel | quote }} + - name: "SCANNER_TRIVY_CACHE_DIR" + value: "/home/scanner/.cache/trivy" + - name: "SCANNER_TRIVY_REPORTS_DIR" + value: "/home/scanner/.cache/reports" + - name: "SCANNER_TRIVY_DEBUG_MODE" + value: {{ .Values.trivy.debugMode | quote }} + - name: "SCANNER_TRIVY_VULN_TYPE" + value: {{ .Values.trivy.vulnType | quote }} + - name: "SCANNER_TRIVY_TIMEOUT" + value: {{ .Values.trivy.timeout | quote }} + - name: "SCANNER_TRIVY_GITHUB_TOKEN" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: gitHubToken + - name: "SCANNER_TRIVY_SEVERITY" + value: {{ .Values.trivy.severity | quote }} + - name: "SCANNER_TRIVY_IGNORE_UNFIXED" + value: {{ .Values.trivy.ignoreUnfixed | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_UPDATE" + value: {{ .Values.trivy.skipUpdate | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_JAVA_DB_UPDATE" + value: {{ .Values.trivy.skipJavaDBUpdate | default false | quote }} + - name: "SCANNER_TRIVY_OFFLINE_SCAN" + value: {{ .Values.trivy.offlineScan | default false | quote }} + - name: "SCANNER_TRIVY_SECURITY_CHECKS" + value: {{ .Values.trivy.securityCheck | quote }} + - name: "SCANNER_TRIVY_INSECURE" + value: {{ .Values.trivy.insecure | default false | quote }} + - name: SCANNER_API_SERVER_ADDR + value: ":{{ template "harbor.trivy.containerPort" . }}" + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: SCANNER_API_SERVER_TLS_KEY + value: /etc/harbor/ssl/trivy/tls.key + - name: SCANNER_API_SERVER_TLS_CERTIFICATE + value: /etc/harbor/ssl/trivy/tls.crt + {{- end }} + - name: "SCANNER_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_STORE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_JOB_QUEUE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL +{{- with .Values.trivy.extraEnvVars }} +{{- toYaml . | nindent 12 }} +{{- end }} + ports: + - name: api-server + containerPort: {{ template "harbor.trivy.containerPort" . }} + volumeMounts: + - name: data + mountPath: /home/scanner/.cache + subPath: {{ .Values.persistence.persistentVolumeClaim.trivy.subPath }} + readOnly: false + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + mountPath: /etc/harbor/ssl/trivy + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 10 }} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/healthy + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 10 + readinessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/ready + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 3 + resources: +{{ toYaml .Values.trivy.resources | indent 12 }} + {{- if or (or .Values.internalTLS.enabled .Values.caBundleSecretName) (or (not .Values.persistence.enabled) $trivy.existingClaim) }} + volumes: + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.trivy.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- if not .Values.persistence.enabled }} + - name: "data" + emptyDir: {} + {{- else if $trivy.existingClaim }} + - name: "data" + persistentVolumeClaim: + claimName: {{ $trivy.existingClaim }} + {{- end }} + {{- end }} + {{- with .Values.trivy.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.trivy.priorityClassName }} + priorityClassName: {{ .Values.trivy.priorityClassName }} + {{- end }} +{{- if and .Values.persistence.enabled (not $trivy.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $trivy.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $trivy.accessMode | quote }}] + {{- if $trivy.storageClass }} + {{- if (eq "-" $trivy.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $trivy.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $trivy.size | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-svc.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-svc.yaml new file mode 100644 index 0000000000..24daf094e8 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-svc.yaml @@ -0,0 +1,16 @@ +{{ if .Values.trivy.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.trivy" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-trivy" "http-trivy" .Values.internalTLS.enabled }} + protocol: TCP + port: {{ template "harbor.trivy.servicePort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: trivy +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-tls.yaml b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-tls.yaml new file mode 100644 index 0000000000..a9c8330c37 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/templates/trivy/trivy-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.trivy.enabled .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.trivy.crt\" is required!" .Values.internalTLS.trivy.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.trivy.key\" is required!" .Values.internalTLS.trivy.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema1/values.yaml b/src/pkg/chart/testdata/harbor-schema1/values.yaml new file mode 100644 index 0000000000..529ec928b7 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema1/values.yaml @@ -0,0 +1,1058 @@ +expose: + # Set how to expose the service. Set the type as "ingress", "clusterIP", "nodePort" or "loadBalancer" + # and fill the information in the corresponding section + type: ingress + tls: + # Enable TLS or not. + # Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress" + # Note: if the "expose.type" is "ingress" and TLS is disabled, + # the port must be included in the command when pulling/pushing images. + # Refer to https://github.com/goharbor/harbor/issues/5291 for details. + enabled: true + # The source of the tls certificate. Set as "auto", "secret" + # or "none" and fill the information in the corresponding section + # 1) auto: generate the tls certificate automatically + # 2) secret: read the tls certificate from the specified secret. + # The tls certificate can be generated manually or by cert manager + # 3) none: configure no tls certificate for the ingress. If the default + # tls certificate is configured in the ingress controller, choose this option + certSource: auto + auto: + # The common name used to generate the certificate, it's necessary + # when the type isn't "ingress" + commonName: "" + secret: + # The name of secret which contains keys named: + # "tls.crt" - the certificate + # "tls.key" - the private key + secretName: "" + ingress: + hosts: + core: core.harbor.domain + # set to the type of ingress controller if it has specific requirements. + # leave as `default` for most ingress controllers. + # set to `gce` if using the GCE ingress controller + # set to `ncp` if using the NCP (NSX-T Container Plugin) ingress controller + # set to `alb` if using the ALB ingress controller + # set to `f5-bigip` if using the F5 BIG-IP ingress controller + controller: default + ## Allow .Capabilities.KubeVersion.Version to be overridden while creating ingress + kubeVersionOverride: "" + className: "" + annotations: + # note different ingress controllers may require a different ssl-redirect annotation + # for Envoy, use ingress.kubernetes.io/force-ssl-redirect: "true" and remove the nginx lines below + ingress.kubernetes.io/ssl-redirect: "true" + ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + # ingress-specific labels + labels: {} + clusterIP: + # The name of ClusterIP service + name: harbor + # The ip address of the ClusterIP service (leave empty for acquiring dynamic ip) + staticClusterIP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the ClusterIP service + annotations: {} + # ClusterIP-specific labels + labels: {} + nodePort: + # The name of NodePort service + name: harbor + ports: + http: + # The service port Harbor listens on when serving HTTP + port: 80 + # The node port Harbor listens on when serving HTTP + nodePort: 30002 + https: + # The service port Harbor listens on when serving HTTPS + port: 443 + # The node port Harbor listens on when serving HTTPS + nodePort: 30003 + # Annotations on the nodePort service + annotations: {} + # nodePort-specific labels + labels: {} + loadBalancer: + # The name of LoadBalancer service + name: harbor + # Set the IP if the LoadBalancer supports assigning IP + IP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the loadBalancer service + annotations: {} + # loadBalancer-specific labels + labels: {} + sourceRanges: [] + +# The external URL for Harbor core service. It is used to +# 1) populate the docker/helm commands showed on portal +# 2) populate the token service URL returned to docker client +# +# Format: protocol://domain[:port]. Usually: +# 1) if "expose.type" is "ingress", the "domain" should be +# the value of "expose.ingress.hosts.core" +# 2) if "expose.type" is "clusterIP", the "domain" should be +# the value of "expose.clusterIP.name" +# 3) if "expose.type" is "nodePort", the "domain" should be +# the IP address of k8s node +# +# If Harbor is deployed behind the proxy, set it as the URL of proxy +externalURL: https://core.harbor.domain + +# The persistence is enabled by default and a default StorageClass +# is needed in the k8s cluster to provision volumes dynamically. +# Specify another StorageClass in the "storageClass" or set "existingClaim" +# if you already have existing persistent volumes to use +# +# For storing images and charts, you can also use "azure", "gcs", "s3", +# "swift" or "oss". Set it in the "imageChartStorage" section +persistence: + enabled: true + # Setting it to "keep" to avoid removing PVCs during a helm delete + # operation. Leaving it empty will delete PVCs after the chart deleted + # (this does not apply for PVCs that are created for internal database + # and redis components, i.e. they are never deleted automatically) + resourcePolicy: "keep" + persistentVolumeClaim: + registry: + # Use the existing PVC which must be created manually before bound, + # and specify the "subPath" if the PVC is shared with other components + existingClaim: "" + # Specify the "storageClass" used to provision the volume. Or the default + # StorageClass will be used (the default). + # Set it to "-" to disable dynamic provisioning + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + jobservice: + jobLog: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external database is used, the following settings for database will + # be ignored + database: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external Redis is used, the following settings for Redis will + # be ignored + redis: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + trivy: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + # Define which storage backend is used for registry to store + # images and charts. Refer to + # https://github.com/distribution/distribution/blob/main/docs/content/about/configuration.md#storage + # for the detail. + imageChartStorage: + # Specify whether to disable `redirect` for images and chart storage, for + # backends which not supported it (such as using minio for `s3` storage type), please disable + # it. To disable redirects, simply set `disableredirect` to `true` instead. + # Refer to + # https://github.com/distribution/distribution/blob/main/docs/configuration.md#redirect + # for the detail. + disableredirect: false + # Specify the "caBundleSecretName" if the storage service uses a self-signed certificate. + # The secret must contain keys named "ca.crt" which will be injected into the trust store + # of registry's containers. + # caBundleSecretName: + + # Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift", + # "oss" and fill the information needed in the corresponding section. The type + # must be "filesystem" if you want to use persistent volumes for registry + type: filesystem + filesystem: + rootdirectory: /storage + #maxthreads: 100 + azure: + accountname: accountname + accountkey: base64encodedaccountkey + container: containername + #realm: core.windows.net + # To use existing secret, the key must be AZURE_STORAGE_ACCESS_KEY + existingSecret: "" + gcs: + bucket: bucketname + # The base64 encoded json file which contains the key + encodedkey: base64-encoded-json-key-file + #rootdirectory: /gcs/object/name/prefix + #chunksize: "5242880" + # To use existing secret, the key must be GCS_KEY_DATA + existingSecret: "" + useWorkloadIdentity: false + s3: + # Set an existing secret for S3 accesskey and secretkey + # keys in the secret should be REGISTRY_STORAGE_S3_ACCESSKEY and REGISTRY_STORAGE_S3_SECRETKEY for registry + #existingSecret: "" + region: us-west-1 + bucket: bucketname + #accesskey: awsaccesskey + #secretkey: awssecretkey + #regionendpoint: http://myobjects.local + #encrypt: false + #keyid: mykeyid + #secure: true + #skipverify: false + #v4auth: true + #chunksize: "5242880" + #rootdirectory: /s3/object/name/prefix + #storageclass: STANDARD + #multipartcopychunksize: "33554432" + #multipartcopymaxconcurrency: 100 + #multipartcopythresholdsize: "33554432" + swift: + authurl: https://storage.myprovider.com/v3/auth + username: username + password: password + container: containername + # keys in existing secret must be REGISTRY_STORAGE_SWIFT_PASSWORD, REGISTRY_STORAGE_SWIFT_SECRETKEY, REGISTRY_STORAGE_SWIFT_ACCESSKEY + existingSecret: "" + #region: fr + #tenant: tenantname + #tenantid: tenantid + #domain: domainname + #domainid: domainid + #trustid: trustid + #insecureskipverify: false + #chunksize: 5M + #prefix: + #secretkey: secretkey + #accesskey: accesskey + #authversion: 3 + #endpointtype: public + #tempurlcontainerkey: false + #tempurlmethods: + oss: + accesskeyid: accesskeyid + accesskeysecret: accesskeysecret + region: regionname + bucket: bucketname + # key in existingSecret must be REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + existingSecret: "" + #endpoint: endpoint + #internal: false + #encrypt: false + #secure: true + #chunksize: 10M + #rootdirectory: rootdirectory + +# The initial password of Harbor admin. Change it from portal after launching Harbor +# or give an existing secret for it +# key in secret is given via (default to HARBOR_ADMIN_PASSWORD) +# existingSecretAdminPassword: +existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD +harborAdminPassword: "Harbor12345" + +# The internal TLS used for harbor components secure communicating. In order to enable https +# in each component tls cert files need to provided in advance. +internalTLS: + # If internal TLS enabled + enabled: false + # enable strong ssl ciphers (default: false) + strong_ssl_ciphers: false + # There are three ways to provide tls + # 1) "auto" will generate cert automatically + # 2) "manual" need provide cert file manually in following value + # 3) "secret" internal certificates from secret + certSource: "auto" + # The content of trust ca, only available when `certSource` is "manual" + trustCa: "" + # core related cert configuration + core: + # secret name for core's tls certs + secretName: "" + # Content of core's TLS cert file, only available when `certSource` is "manual" + crt: "" + # Content of core's TLS key file, only available when `certSource` is "manual" + key: "" + # jobservice related cert configuration + jobservice: + # secret name for jobservice's tls certs + secretName: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + key: "" + # registry related cert configuration + registry: + # secret name for registry's tls certs + secretName: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + key: "" + # portal related cert configuration + portal: + # secret name for portal's tls certs + secretName: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + key: "" + # trivy related cert configuration + trivy: + # secret name for trivy's tls certs + secretName: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + key: "" + +ipFamily: + # ipv6Enabled set to true if ipv6 is enabled in cluster, currently it affected the nginx related component + ipv6: + enabled: true + # ipv4Enabled set to true if ipv4 is enabled in cluster, currently it affected the nginx related component + ipv4: + enabled: true + +imagePullPolicy: IfNotPresent + +# Use this set to assign a list of default pullSecrets +imagePullSecrets: +# - name: docker-registry-secret +# - name: internal-registry-secret + +# The update strategy for deployments with persistent volumes(jobservice, registry): "RollingUpdate" or "Recreate" +# Set it as "Recreate" when "RWM" for volumes isn't supported +updateStrategy: + type: RollingUpdate + +# debug, info, warning, error or fatal +logLevel: info + +# The name of the secret which contains key named "ca.crt". Setting this enables the +# download link on portal to download the CA certificate when the certificate isn't +# generated automatically +caSecretName: "" + +# The secret key used for encryption. Must be a string of 16 chars. +secretKey: "not-a-secure-key" +# If using existingSecretSecretKey, the key must be secretKey +existingSecretSecretKey: "" + +# The proxy settings for updating trivy vulnerabilities from the Internet and replicating +# artifacts from/to the registries that cannot be reached directly +proxy: + httpProxy: + httpsProxy: + noProxy: 127.0.0.1,localhost,.local,.internal + components: + - core + - jobservice + - trivy + +# Run the migration job via helm hook +enableMigrateHelmHook: false + +# The custom ca bundle secret, the secret must contain key named "ca.crt" +# which will be injected into the trust store for core, jobservice, registry, trivy components +# caBundleSecretName: "" + +## UAA Authentication Options +# If you're using UAA for authentication behind a self-signed +# certificate you will need to provide the CA Cert. +# Set uaaSecretName below to provide a pre-created secret that +# contains a base64 encoded CA Certificate named `ca.crt`. +# uaaSecretName: + +metrics: + enabled: false + core: + path: /metrics + port: 8001 + registry: + path: /metrics + port: 8001 + jobservice: + path: /metrics + port: 8001 + exporter: + path: /metrics + port: 8001 + ## Create prometheus serviceMonitor to scrape harbor metrics. + ## This requires the monitoring.coreos.com/v1 CRD. Please see + ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md + ## + serviceMonitor: + enabled: false + additionalLabels: {} + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: "" + # Metric relabel configs to apply to samples before ingestion. + metricRelabelings: + [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + # Relabel configs to apply to samples before ingestion. + relabelings: + [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + +trace: + enabled: false + # trace provider: jaeger or otel + # jaeger should be 1.26+ + provider: jaeger + # set sample_rate to 1 if you wanna sampling 100% of trace data; set 0.5 if you wanna sampling 50% of trace data, and so forth + sample_rate: 1 + # namespace used to differentiate different harbor services + # namespace: + # attributes is a key value dict contains user defined attributes used to initialize trace provider + # attributes: + # application: harbor + jaeger: + # jaeger supports two modes: + # collector mode(uncomment endpoint and uncomment username, password if needed) + # agent mode(uncomment agent_host and agent_port) + endpoint: http://hostname:14268/api/traces + # username: + # password: + # agent_host: hostname + # export trace data by jaeger.thrift in compact mode + # agent_port: 6831 + otel: + endpoint: hostname:4318 + url_path: /v1/traces + compression: false + insecure: true + # timeout is in seconds + timeout: 10 + +# cache layer configurations +# if this feature enabled, harbor will cache the resource +# `project/project_metadata/repository/artifact/manifest` in the redis +# which help to improve the performance of high concurrent pulling manifest. +cache: + # default is not enabled. + enabled: false + # default keep cache for one day. + expireHours: 24 + +## set Container Security Context to comply with PSP restricted policy if necessary +## each of the conatiner will apply the same security context +## containerSecurityContext:{} is initially an empty yaml that you could edit it on demand, we just filled with a common template for convenience +containerSecurityContext: + privileged: false + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + +# If service exposed via "ingress", the Nginx will not be used +nginx: + image: + repository: goharbor/nginx-photon + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + +portal: + image: + repository: goharbor/harbor-portal + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + +core: + image: + repository: goharbor/harbor-core + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + ## Startup probe values + startupProbe: + enabled: true + initialDelaySeconds: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + ## User settings configuration json string + configureUserSettings: + # The provider for updating project quota(usage), there are 2 options, redis or db. + # By default it is implemented by db but you can configure it to redis which + # can improve the performance of high concurrent pushing to the same project, + # and reduce the database connections spike and occupies. + # Using redis will bring up some delay for quota usage updation for display, so only + # suggest switch provider to redis if you were ran into the db connections spike around + # the scenario of high concurrent pushing to same project, no improvment for other scenes. + quotaUpdateProvider: db # Or redis + # Secret is used when core server communicates with other components. + # If a secret key is not specified, Helm will generate one. Alternatively set existingSecret to use an existing secret + # Must be a string of 16 chars. + secret: "" + # Fill in the name of a kubernetes secret if you want to use your own + # If using existingSecret, the key must be secret + existingSecret: "" + # Fill the name of a kubernetes secret if you want to use your own + # TLS certificate and private key for token encryption/decryption. + # The secret must contain keys named: + # "tls.key" - the private key + # "tls.crt" - the certificate + secretName: "" + # If not specifying a preexisting secret, a secret can be created from tokenKey and tokenCert and used instead. + # If none of secretName, tokenKey, and tokenCert are specified, an ephemeral key and certificate will be autogenerated. + # tokenKey and tokenCert must BOTH be set or BOTH unset. + # The tokenKey value is formatted as a multiline string containing a PEM-encoded RSA key, indented one more than tokenKey on the following line. + tokenKey: | + # If tokenKey is set, the value of tokenCert must be set as a PEM-encoded certificate signed by tokenKey, and supplied as a multiline string, indented one more than tokenCert on the following line. + tokenCert: | + # The XSRF key. Will be generated automatically if it isn't specified + xsrfKey: "" + # If using existingSecret, the key is defined by core.existingXsrfSecretKey + existingXsrfSecret: "" + # If using existingSecret, the key + existingXsrfSecretKey: CSRF_KEY + # The time duration for async update artifact pull_time and repository + # pull_count, the unit is second. Will be 10 seconds if it isn't set. + # eg. artifactPullAsyncFlushDuration: 10 + artifactPullAsyncFlushDuration: + gdpr: + deleteUser: false + auditLogsCompliant: false + +jobservice: + image: + repository: goharbor/harbor-jobservice + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + maxJobWorkers: 10 + # The logger for jobs: "file", "database" or "stdout" + jobLoggers: + - file + # - database + # - stdout + # The jobLogger sweeper duration (ignored if `jobLogger` is `stdout`) + loggerSweeperDuration: 14 #days + notification: + webhook_job_max_retry: 3 + webhook_job_http_client_timeout: 3 # in seconds + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: 24 + # the max time for execution in running state without new task created + max_dangling_hours: 168 + # Secret is used when job service communicates with other components. + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the job service secret + existingSecretKey: JOBSERVICE_SECRET + +registry: + registry: + image: + repository: goharbor/registry-photon + tag: v2.11.0 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + controller: + image: + repository: goharbor/harbor-registryctl + tag: v2.11.0 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # Secret is used to secure the upload state from client + # and registry storage backend. + # See: https://github.com/distribution/distribution/blob/main/docs/configuration.md#http + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the registry service secret + existingSecretKey: REGISTRY_HTTP_SECRET + # If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. + relativeurls: false + credentials: + username: "harbor_registry_user" + password: "harbor_registry_password" + # If using existingSecret, the key must be REGISTRY_PASSWD and REGISTRY_HTPASSWD + existingSecret: "" + # Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. + # htpasswdString: $apr1$XLefHzeG$Xl4.s00sMSCCcMyJljSZb0 # example string + htpasswdString: "" + middleware: + enabled: false + type: cloudFront + cloudFront: + baseurl: example.cloudfront.net + keypairid: KEYPAIRID + duration: 3000s + ipfilteredby: none + # The secret key that should be present is CLOUDFRONT_KEY_DATA, which should be the encoded private key + # that allows access to CloudFront + privateKeySecret: "my-secret" + # enable purge _upload directories + upload_purging: + enabled: true + # remove files in _upload directories which exist for a period of time, default is one week. + age: 168h + # the interval of the purge operations + interval: 24h + dryrun: false + +trivy: + # enabled the flag to enable Trivy scanner + enabled: true + image: + # repository the repository for Trivy adapter image + repository: goharbor/trivy-adapter-photon + # tag the tag for Trivy adapter image + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # replicas the number of Pod replicas + replicas: 1 + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 1 + memory: 1Gi + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # debugMode the flag to enable Trivy debug mode with more verbose scanning log + debugMode: false + # vulnType a comma-separated list of vulnerability types. Possible values are `os` and `library`. + vulnType: "os,library" + # severity a comma-separated list of severities to be checked + severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" + # ignoreUnfixed the flag to display only fixed vulnerabilities + ignoreUnfixed: false + # insecure the flag to skip verifying registry certificate + insecure: false + # gitHubToken the GitHub access token to download Trivy DB + # + # Trivy DB contains vulnerability information from NVD, Red Hat, and many other upstream vulnerability databases. + # It is downloaded by Trivy from the GitHub release page https://github.com/aquasecurity/trivy-db/releases and cached + # in the local file system (`/home/scanner/.cache/trivy/db/trivy.db`). In addition, the database contains the update + # timestamp so Trivy can detect whether it should download a newer version from the Internet or use the cached one. + # Currently, the database is updated every 12 hours and published as a new release to GitHub. + # + # Anonymous downloads from GitHub are subject to the limit of 60 requests per hour. Normally such rate limit is enough + # for production operations. If, for any reason, it's not enough, you could increase the rate limit to 5000 + # requests per hour by specifying the GitHub access token. For more details on GitHub rate limiting please consult + # https://developer.github.com/v3/#rate-limiting + # + # You can create a GitHub token by following the instructions in + # https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line + gitHubToken: "" + # skipUpdate the flag to disable Trivy DB downloads from GitHub + # + # You might want to set the value of this flag to `true` in test or CI/CD environments to avoid GitHub rate limiting issues. + # If the value is set to `true` you have to manually download the `trivy.db` file and mount it in the + # `/home/scanner/.cache/trivy/db/trivy.db` path. + skipUpdate: false + # skipJavaDBUpdate If the flag is enabled you have to manually download the `trivy-java.db` file and mount it in the + # `/home/scanner/.cache/trivy/java-db/trivy-java.db` path + # + skipJavaDBUpdate: false + # The offlineScan option prevents Trivy from sending API requests to identify dependencies. + # + # Scanning JAR files and pom.xml may require Internet access for better detection, but this option tries to avoid it. + # For example, the offline mode will not try to resolve transitive dependencies in pom.xml when the dependency doesn't + # exist in the local repositories. It means a number of detected vulnerabilities might be fewer in offline mode. + # It would work if all the dependencies are in local. + # This option doesn’t affect DB download. You need to specify skipUpdate as well as offlineScan in an air-gapped environment. + offlineScan: false + # Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. Defaults to `vuln`. + securityCheck: "vuln" + # The duration to wait for scan completion + timeout: 5m0s + +database: + # if external database is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/harbor-db + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + # The timeout used in livenessProbe; 1 to 5 seconds + livenessProbe: + timeoutSeconds: 1 + # The timeout used in readinessProbe; 1 to 5 seconds + readinessProbe: + timeoutSeconds: 1 + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + extrInitContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # The initial superuser password for internal database + password: "changeit" + # The size limit for Shared memory, pgSQL use it for shared_buffer + # More details see: + # https://github.com/goharbor/harbor/issues/15034 + shmSizeLimit: 512Mi + initContainer: + migrator: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + permissions: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + external: + host: "192.168.0.1" + port: "5432" + username: "user" + password: "password" + coreDatabase: "registry" + # if using existing secret, the key must be "password" + existingSecret: "" + # "disable" - No SSL + # "require" - Always SSL (skip verification) + # "verify-ca" - Always SSL (verify that the certificate presented by the + # server was signed by a trusted CA) + # "verify-full" - Always SSL (verify that the certification presented by the + # server was signed by a trusted CA and the server host name matches the one + # in the certificate) + sslmode: "disable" + # The maximum number of connections in the idle connection pool per pod (core+exporter). + # If it <=0, no idle connections are retained. + maxIdleConns: 100 + # The maximum number of open connections to the database per pod (core+exporter). + # If it <= 0, then there is no limit on the number of open connections. + # Note: the default number of connections is 1024 for harbor's postgres. + maxOpenConns: 900 + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +redis: + # if external Redis is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/redis-photon + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # # jobserviceDatabaseIndex defaults to "1" + # # registryDatabaseIndex defaults to "2" + # # trivyAdapterIndex defaults to "5" + # # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + external: + # support redis, redis+sentinel + # addr for redis: : + # addr for redis+sentinel: :,:,: + addr: "192.168.0.2:6379" + # The name of the set of Redis instances to monitor, it must be set to support redis+sentinel + sentinelMasterSet: "" + # The "coreDatabaseIndex" must be "0" as the library Harbor + # used doesn't support configuring it + # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + coreDatabaseIndex: "0" + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + # username field can be an empty string, and it will be authenticated against the default user + username: "" + password: "" + # If using existingSecret, the key must be REDIS_PASSWORD + existingSecret: "" + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +exporter: + image: + repository: goharbor/harbor-exporter + tag: v2.11.0 + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + ## The priority class to run the pod as + priorityClassName: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + cacheDuration: 23 + cacheCleanInterval: 14400 diff --git a/src/pkg/chart/testdata/harbor-schema2/.helmignore b/src/pkg/chart/testdata/harbor-schema2/.helmignore new file mode 100644 index 0000000000..b4424fd59b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/.helmignore @@ -0,0 +1,6 @@ +.github/* +docs/* +.git/* +.gitignore +CONTRIBUTING.md +test/* \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/Chart.yaml b/src/pkg/chart/testdata/harbor-schema2/Chart.yaml new file mode 100644 index 0000000000..939c7c5344 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/Chart.yaml @@ -0,0 +1,34 @@ +apiVersion: v2 +appVersion: 2.11.0 +description: An open source trusted cloud native registry that stores, signs, and + scans content +home: https://goharbor.io +icon: https://raw.githubusercontent.com/goharbor/website/main/static/img/logos/harbor-icon-color.png +keywords: +- docker +- registry +- harbor +maintainers: +- email: yan-yw.wang@broadcom.com + name: Yan Wang +- email: wenkai.yin@broadcom.com + name: Wenkai Yin +- email: miner.yang@broadcom.com + name: Miner Yang +- email: shengwen.yu@broadcom.com + name: Shengwen Yu +name: harbor +sources: +- https://github.com/goharbor/harbor +- https://github.com/goharbor/harbor-helm +version: 1.15.0 +# NOTICE: Harbor chart is not dependent on other charts. This is just a mock for UT coverage. +dependencies: + - name: postgresql + version: 1.0.0 + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: postgresql.enabled + - name: redis + version: 2.0.0 + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: redis.enabled diff --git a/src/pkg/chart/testdata/harbor-schema2/LICENSE b/src/pkg/chart/testdata/harbor-schema2/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/src/pkg/chart/testdata/harbor-schema2/README.md b/src/pkg/chart/testdata/harbor-schema2/README.md new file mode 100644 index 0000000000..a78cfa6700 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/README.md @@ -0,0 +1,422 @@ +# Helm Chart for Harbor + +**Notes:** The master branch is in heavy development, please use the other stable versions instead. A highly available solution for Harbor based on chart can be found [here](docs/High%20Availability.md). And refer to the [guide](docs/Upgrade.md) to upgrade the existing deployment. + +This repository, including the issues, focuses on deploying Harbor chart via helm. For functionality issues or Harbor questions, please open issues on [goharbor/harbor](https://github.com/goharbor/harbor) + +## Introduction + +This [Helm](https://github.com/kubernetes/helm) chart installs [Harbor](https://github.com/goharbor/harbor) in a Kubernetes cluster. Welcome to [contribute](CONTRIBUTING.md) to Helm Chart for Harbor. + +## Prerequisites + +- Kubernetes cluster 1.20+ +- Helm v3.2.0+ + +## Installation + +### Add Helm repository + +```bash +helm repo add harbor https://helm.goharbor.io +``` + +### Configure the chart + +The following items can be set via `--set` flag during installation or configured by editing the `values.yaml` directly (need to download the chart first). + +#### Configure how to expose Harbor service + +- **Ingress**: The ingress controller must be installed in the Kubernetes cluster. + **Notes:** if TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to issue [#5291](https://github.com/goharbor/harbor/issues/5291) for details. +- **ClusterIP**: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from within the cluster. +- **NodePort**: Exposes the service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the NodePort service, from outside the cluster, by requesting `NodeIP:NodePort`. +- **LoadBalancer**: Exposes the service externally using a cloud provider’s load balancer. + +#### Configure the external URL + +The external URL for Harbor core service is used to: + +1. populate the docker/helm commands showed on portal +2. populate the token service URL returned to docker client + +Format: `protocol://domain[:port]`. Usually: + +- if service exposed via `Ingress`, the `domain` should be the value of `expose.ingress.hosts.core` +- if service exposed via `ClusterIP`, the `domain` should be the value of `expose.clusterIP.name` +- if service exposed via `NodePort`, the `domain` should be the IP address of one Kubernetes node +- if service exposed via `LoadBalancer`, set the `domain` as your own domain name and add a CNAME record to map the domain name to the one you got from the cloud provider + +If Harbor is deployed behind the proxy, set it as the URL of proxy. + +#### Configure how to persist data + +- **Disable**: The data does not survive the termination of a pod. +- **Persistent Volume Claim(default)**: A default `StorageClass` is needed in the Kubernetes cluster to dynamically provision the volumes. Specify another StorageClass in the `storageClass` or set `existingClaim` if you already have existing persistent volumes to use. +- **External Storage(only for images and charts)**: For images and charts, the external storages are supported: `azure`, `gcs`, `s3` `swift` and `oss`. + +#### Configure the other items listed in [configuration](#configuration) section + +### Install the chart + +Install the Harbor helm chart with a release name `my-release`: +```bash +helm install my-release harbor/harbor +``` + +## Uninstallation + +To uninstall/delete the `my-release` deployment: +```bash +helm uninstall my-release +``` + +## Configuration + +The following table lists the configurable parameters of the Harbor chart and the default values. + +| Parameter | Description | Default | +|-----------------------------------------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| **Expose** | | | +| `expose.type` | How to expose the service: `ingress`, `clusterIP`, `nodePort` or `loadBalancer`, other values will be ignored and the creation of service will be skipped. | `ingress` | +| `expose.tls.enabled` | Enable TLS or not. Delete the `ssl-redirect` annotations in `expose.ingress.annotations` when TLS is disabled and `expose.type` is `ingress`. Note: if the `expose.type` is `ingress` and TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to https://github.com/goharbor/harbor/issues/5291 for details. | `true` | +| `expose.tls.certSource` | The source of the TLS certificate. Set as `auto`, `secret` or `none` and fill the information in the corresponding section: 1) auto: generate the TLS certificate automatically 2) secret: read the TLS certificate from the specified secret. The TLS certificate can be generated manually or by cert manager 3) none: configure no TLS certificate for the ingress. If the default TLS certificate is configured in the ingress controller, choose this option | `auto` | +| `expose.tls.auto.commonName` | The common name used to generate the certificate, it's necessary when the type isn't `ingress` | | +| `expose.tls.secret.secretName` | The name of secret which contains keys named: `tls.crt` - the certificate; `tls.key` - the private key | | +| `expose.ingress.hosts.core` | The host of Harbor core service in ingress rule | `core.harbor.domain` | +| `expose.ingress.controller` | The ingress controller type. Currently supports `default`, `gce`, `alb`, `f5-bigip` and `ncp` | `default` | +| `expose.ingress.kubeVersionOverride` | Allows the ability to override the kubernetes version used while templating the ingress | | +| `expose.ingress.annotations` | The annotations used commonly for ingresses | | +| `expose.ingress.labels` | The labels specific to ingress | {} | +| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` | +| `expose.clusterIP.annotations` | The annotations attached to the ClusterIP service | {} | +| `expose.clusterIP.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.clusterIP.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.clusterIP.annotations` | The annotations used commonly for clusterIP | | +| `expose.clusterIP.labels` | The labels specific to clusterIP | {} | +| `expose.nodePort.name` | The name of NodePort service | `harbor` | +| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving HTTP | `30002` | +| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving HTTPS | `30003` | +| `expose.nodePort.annotations` | The annotations used commonly for nodePort | | +| `expose.nodePort.labels` | The labels specific to nodePort | {} | +| `expose.loadBalancer.name` | The name of service | `harbor` | +| `expose.loadBalancer.IP` | The IP of the loadBalancer. It only works when loadBalancer supports assigning IP | `""` | +| `expose.loadBalancer.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.loadBalancer.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `30002` | +| `expose.loadBalancer.annotations` | The annotations attached to the loadBalancer service | {} | +| `expose.loadBalancer.labels` | The labels specific to loadBalancer | {} | +| `expose.loadBalancer.sourceRanges` | List of IP address ranges to assign to loadBalancerSourceRanges | [] | +| **Internal TLS** | | | +| `internalTLS.enabled` | Enable TLS for the components (core, jobservice, portal, registry, trivy) | `false` | +| `internalTLS.strong_ssl_ciphers` | Enable strong ssl ciphers for nginx and portal | `false` +| `internalTLS.certSource` | Method to provide TLS for the components, options are `auto`, `manual`, `secret`. | `auto` | +| `internalTLS.trustCa` | The content of trust CA, only available when `certSource` is `manual`. **Note**: all the internal certificates of the components must be issued by this CA | | +| `internalTLS.core.secretName` | The secret name for core component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.core.crt` | Content of core's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.core.key` | Content of core's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.secretName` | The secret name for jobservice component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.jobservice.crt` | Content of jobservice's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.key` | Content of jobservice's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.registry.secretName` | The secret name for registry component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.registry.crt` | Content of registry's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.registry.key` | Content of registry's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.portal.secretName` | The secret name for portal component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.portal.crt` | Content of portal's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.portal.key` | Content of portal's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.secretName` | The secret name for trivy component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.trivy.crt` | Content of trivy's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.key` | Content of trivy's TLS key file, only available when `certSource` is `manual` | | +| **IPFamily** | | | +| `ipFamily.ipv4.enabled` | if cluster is ipv4 enabled, all ipv4 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| `ipFamily.ipv6.enabled` | if cluster is ipv6 enabled, all ipv6 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| **Persistence** | | | +| `persistence.enabled` | Enable the data persistence or not | `true` | +| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted. Does not affect PVCs created for internal database and redis components. | `keep` | +| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.registry.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.database.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.redis.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.trivy.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.trivy.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.trivy.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.trivy.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.trivy.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.trivy.annotations` | The annotations of the volume | | +| `persistence.imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more details | `false` | +| `persistence.imageChartStorage.caBundleSecretName` | Specify the `caBundleSecretName` if the storage service uses a self-signed certificate. The secret must contain keys named `ca.crt` which will be injected into the trust store of registry's and containers. | | +| `persistence.imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more details | `filesystem` | +| `persistence.imageChartStorage.gcs.existingSecret` | An existing secret containing the gcs service account json key. The key must be gcs-key.json. | `""` | +| `persistence.imageChartStorage.gcs.useWorkloadIdentity` | A boolean to allow the use of workloadidentity in a GKE cluster. To use it, create a kubernetes service account and set the name in the key `serviceAccountName` of each component, then allow automounting the service account. | `false` | +| **General** | | | +| `externalURL` | The external URL for Harbor core service | `https://core.harbor.domain` | +| `caBundleSecretName` | The custom CA bundle secret name, the secret must contain key named "ca.crt" which will be injected into the trust store for core, jobservice, registry, trivy components. | | +| `uaaSecretName` | If using external UAA auth which has a self signed cert, you can provide a pre-created secret containing it under the key `ca.crt`. | | +| `imagePullPolicy` | The image pull policy | | +| `imagePullSecrets` | The imagePullSecrets names for all deployments | | +| `updateStrategy.type` | The update strategy for deployments with persistent volumes(jobservice, registry): `RollingUpdate` or `Recreate`. Set it as `Recreate` when `RWM` for volumes isn't supported | `RollingUpdate` | +| `logLevel` | The log level: `debug`, `info`, `warning`, `error` or `fatal` | `info` | +| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` | +| `existingSecretAdminPassword` | The name of secret where admin password can be found. | | +| `existingSecretAdminPasswordKey` | The name of the key in the secret where to find harbor admin password Harbor | `HARBOR_ADMIN_PASSWORD` | +| `caSecretName` | The name of the secret which contains key named `ca.crt`. Setting this enables the download link on portal to download the CA certificate when the certificate isn't generated automatically | | +| `secretKey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` | +| `existingSecretSecretKey` | An existing secret containing the encoding secretKey | `""` | +| `proxy.httpProxy` | The URL of the HTTP proxy server | | +| `proxy.httpsProxy` | The URL of the HTTPS proxy server | | +| `proxy.noProxy` | The URLs that the proxy settings not apply to | 127.0.0.1,localhost,.local,.internal | +| `proxy.components` | The component list that the proxy settings apply to | core, jobservice, trivy | +| `enableMigrateHelmHook` | Run the migration job via helm hook, if it is true, the database migration will be separated from harbor-core, run with a preupgrade job migration-job | `false` | +| **Nginx** (if service exposed via `ingress`, Nginx will not be used) | | | +| `nginx.image.repository` | Image repository | `goharbor/nginx-photon` | +| `nginx.image.tag` | Image tag | `dev` | +| `nginx.replicas` | The replica count | `1` | +| `nginx.revisionHistoryLimit` | The revision history limit | `10` | +| `nginx.resources` | The [resources] to allocate for container | undefined | +| `nginx.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `nginx.nodeSelector` | Node labels for pod assignment | `{}` | +| `nginx.tolerations` | Tolerations for pod assignment | `[]` | +| `nginx.affinity` | Node/Pod affinities | `{}` | +| `nginx.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `nginx.podAnnotations` | Annotations to add to the nginx pod | `{}` | +| `nginx.priorityClassName` | The priority class to run the pod as | | +| **Portal** | | | +| `portal.image.repository` | Repository for portal image | `goharbor/harbor-portal` | +| `portal.image.tag` | Tag for portal image | `dev` | +| `portal.replicas` | The replica count | `1` | +| `portal.revisionHistoryLimit` | The revision history limit | `10` | +| `portal.resources` | The [resources] to allocate for container | undefined | +| `portal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `portal.nodeSelector` | Node labels for pod assignment | `{}` | +| `portal.tolerations` | Tolerations for pod assignment | `[]` | +| `portal.affinity` | Node/Pod affinities | `{}` | +| `portal.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `portal.podAnnotations` | Annotations to add to the portal pod | `{}` | +| `portal.serviceAnnotations` | Annotations to add to the portal service | `{}` | +| `portal.priorityClassName` | The priority class to run the pod as | | +| `portal.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Core** | | | +| `core.image.repository` | Repository for Harbor core image | `goharbor/harbor-core` | +| `core.image.tag` | Tag for Harbor core image | `dev` | +| `core.replicas` | The replica count | `1` | +| `core.revisionHistoryLimit` | The revision history limit | `10` | +| `core.startupProbe.initialDelaySeconds` | The initial delay in seconds for the startup probe | `10` | +| `core.resources` | The [resources] to allocate for container | undefined | +| `core.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `core.nodeSelector` | Node labels for pod assignment | `{}` | +| `core.tolerations` | Tolerations for pod assignment | `[]` | +| `core.affinity` | Node/Pod affinities | `{}` | +| `core.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `core.podAnnotations` | Annotations to add to the core pod | `{}` | +| `core.serviceAnnotations` | Annotations to add to the core service | `{}` | +| `core.configureUserSettings` | A JSON string to set in the environment variable `CONFIG_OVERWRITE_JSON` to configure user settings. See the [official docs](https://goharbor.io/docs/latest/install-config/configure-user-settings-cli/#configure-users-settings-using-an-environment-variable). | | +| `core.quotaUpdateProvider` | The provider for updating project quota(usage), there are 2 options, redis or db. By default it is implemented by db but you can configure it to redis which can improve the performance of high concurrent pushing to the same project, and reduce the database connections spike and occupies. Using redis will bring up some delay for quota usage updation for display, so only suggest switch provider to redis if you were ran into the db connections spike around the scenario of high concurrent pushing to same project, no improvment for other scenes. | `db` | +| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `core.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named: `tls.crt` - the certificate and `tls.key` - the private key. The default key pair will be used if it isn't set | | +| `core.tokenKey` | PEM-formatted RSA private key used to sign service tokens. Only used if `core.secretName` is unset. If set, `core.tokenCert` MUST also be set. | | +| `core.tokenCert` | PEM-formatted certificate signed by `core.tokenKey` used to validate service tokens. Only used if `core.secretName` is unset. If set, `core.tokenKey` MUST also be set. | | +| `core.xsrfKey` | The XSRF key. Will be generated automatically if it isn't specified | | +| `core.priorityClassName` | The priority class to run the pod as | | +| `core.artifactPullAsyncFlushDuration` | The time duration for async update artifact pull_time and repository pull_count | | +| `core.gdpr.deleteUser` | Enable GDPR compliant user delete | `false` | +| `core.gdpr.auditLogsCompliant` | Enable GDPR compliant for audit logs by changing username to its CRC32 value if that user was deleted from the system | `false` | +| `core.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Jobservice** | | | +| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` | +| `jobservice.image.tag` | Tag for jobservice image | `dev` | +| `jobservice.replicas` | The replica count | `1` | +| `jobservice.revisionHistoryLimit` | The revision history limit | `10` | +| `jobservice.maxJobWorkers` | The max job workers | `10` | +| `jobservice.jobLoggers` | The loggers for jobs: `file`, `database` or `stdout` | `[file]` | +| `jobservice.loggerSweeperDuration` | The jobLogger sweeper duration in days (ignored if `jobLoggers` is set to `stdout`) | `14` | +| `jobservice.notification.webhook_job_max_retry` | The maximum retry of webhook sending notifications | `3` | +| `jobservice.notification.webhook_job_http_client_timeout` | The http client timeout value of webhook sending notifications | `3` | +| `jobservice.reaper.max_update_hours` | the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 | `24` | +| `jobservice.reaper.max_dangling_hours` | the max time for execution in running state without new task created | `168` | +| `jobservice.resources` | The [resources] to allocate for container | undefined | +| `jobservice.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` | +| `jobservice.tolerations` | Tolerations for pod assignment | `[]` | +| `jobservice.affinity` | Node/Pod affinities | `{}` | +| `jobservice.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` | +| `jobservice.priorityClassName` | The priority class to run the pod as | | +| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `jobservice.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Registry** | | | +| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` | +| `registry.registry.image.tag` | Tag for registry image | `dev` | +| `registry.registry.resources` | The [resources] to allocate for container | undefined | +| `registry.controller.image.repository` | Repository for registry controller image | `goharbor/harbor-registryctl` | +| `registry.controller.image.tag` | Tag for registry controller image | `dev` | +| `registry.controller.resources` | The [resources] to allocate for container | undefined | +| `registry.replicas` | The replica count | `1` | +| `registry.revisionHistoryLimit` | The revision history limit | `10` | +| `registry.nodeSelector` | Node labels for pod assignment | `{}` | +| `registry.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `registry.tolerations` | Tolerations for pod assignment | `[]` | +| `registry.affinity` | Node/Pod affinities | `{}` | +| `registry.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `registry.middleware` | Middleware is used to add support for a CDN between backend storage and `docker pull` recipient. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#middleware). | | +| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` | +| `registry.priorityClassName` | The priority class to run the pod as | | +| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#http). If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `registry.credentials.username` | The username that harbor core uses internally to access the registry instance. Together with the `registry.credentials.password`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). | `harbor_registry_user` | +| `registry.credentials.password` | The password that harbor core uses internally to access the registry instance. Together with the `registry.credentials.username`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). It is suggested you update this value before installation. | `harbor_registry_password` | +| `registry.credentials.existingSecret` | An existing secret containing the password for accessing the registry instance, which is hosted by htpasswd auth mode. More details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). The key must be `REGISTRY_PASSWD` | `""` | +| `registry.credentials.htpasswdString` | Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. | undefined | +| `registry.relativeurls` | If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. Needed if harbor is behind a reverse proxy | `false` | +| `registry.upload_purging.enabled` | If true, enable purge _upload directories | `true` | +| `registry.upload_purging.age` | Remove files in _upload directories which exist for a period of time, default is one week. | `168h` | +| `registry.upload_purging.interval` | The interval of the purge operations | `24h` | +| `registry.upload_purging.dryrun` | If true, enable dryrun for purging _upload, default false | `false` | +| `registry.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **[Trivy][trivy]** | | | +| `trivy.enabled` | The flag to enable Trivy scanner | `true` | +| `trivy.image.repository` | Repository for Trivy adapter image | `goharbor/trivy-adapter-photon` | +| `trivy.image.tag` | Tag for Trivy adapter image | `dev` | +| `trivy.resources` | The [resources] to allocate for Trivy adapter container | | +| `trivy.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `trivy.replicas` | The number of Pod replicas | `1` | +| `trivy.debugMode` | The flag to enable Trivy debug mode | `false` | +| `trivy.vulnType` | Comma-separated list of vulnerability types. Possible values `os` and `library`. | `os,library` | +| `trivy.severity` | Comma-separated list of severities to be checked | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | +| `trivy.ignoreUnfixed` | The flag to display only fixed vulnerabilities | `false` | +| `trivy.insecure` | The flag to skip verifying registry certificate | `false` | +| `trivy.skipUpdate` | The flag to disable [Trivy DB][trivy-db] downloads from GitHub | `false` | +| `trivy.skipJavaDBUpdate` | If the flag is enabled you have to manually download the `trivy-java.db` file [Trivy Java DB][trivy-java-db] and mount it in the `/home/scanner/.cache/trivy/java-db/trivy-java.db` path | `false` | +| `trivy.offlineScan` | The flag prevents Trivy from sending API requests to identify dependencies. | `false` | +| `trivy.securityCheck` | Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. | `vuln` | +| `trivy.timeout` | The duration to wait for scan completion | `5m0s` | +| `trivy.gitHubToken` | The GitHub access token to download [Trivy DB][trivy-db] (see [GitHub rate limiting][trivy-rate-limiting]) | | +| `trivy.priorityClassName` | The priority class to run the pod as | | +| `trivy.topologySpreadConstraints` | The priority class to run the pod as | | +| `trivy.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Database** | | | +| `database.type` | If external database is used, set it to `external` | `internal` | +| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` | +| `database.internal.image.tag` | Tag for database image | `dev` | +| `database.internal.password` | The password for database | `changeit` | +| `database.internal.shmSizeLimit` | The limit for the size of shared memory for internal PostgreSQL, conventionally it's around 50% of the memory limit of the container | `512Mi` | +| `database.internal.resources` | The [resources] to allocate for container | undefined | +| `database.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `database.internal.initContainer.migrator.resources` | The [resources] to allocate for the database migrator initContainer | undefined | +| `database.internal.initContainer.permissions.resources` | The [resources] to allocate for the database permissions initContainer | undefined | +| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `database.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `database.internal.affinity` | Node/Pod affinities | `{}` | +| `database.internal.priorityClassName` | The priority class to run the pod as | | +| `database.internal.livenessProbe.timeoutSeconds` | The timeout used in liveness probe; 1 to 5 seconds | 1 | +| `database.internal.readinessProbe.timeoutSeconds` | The timeout used in readiness probe; 1 to 5 seconds | 1 | +| `database.internal.extrInitContainers` | Extra init containers to be run before the database's container starts. | `[]` | +| `database.external.host` | The hostname of external database | `192.168.0.1` | +| `database.external.port` | The port of external database | `5432` | +| `database.external.username` | The username of external database | `user` | +| `database.external.password` | The password of external database | `password` | +| `database.external.coreDatabase` | The database used by core service | `registry` | +| `database.external.existingSecret` | An existing password containing the database password. the key must be `password`. | `""` | +| `database.external.sslmode` | Connection method of external database (require, verify-full, verify-ca, disable) | `disable` | +| `database.maxIdleConns` | The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. | `50` | +| `database.maxOpenConns` | The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections. | `100` | +| `database.podAnnotations` | Annotations to add to the database pod | `{}` | +| **Redis** | | | +| `redis.type` | If external redis is used, set it to `external` | `internal` | +| `redis.internal.image.repository` | Repository for redis image | `goharbor/redis-photon` | +| `redis.internal.image.tag` | Tag for redis image | `dev` | +| `redis.internal.resources` | The [resources] to allocate for container | undefined | +| `redis.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `redis.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `redis.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `redis.internal.affinity` | Node/Pod affinities | `{}` | +| `redis.internal.priorityClassName` | The priority class to run the pod as | | +| `redis.internal.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.internal.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.internal.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.internal.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.internal.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.internal.initContainers` | Init containers to be run before the redis's container starts. | `[]` | +| `redis.external.addr` | The addr of external Redis: :. When using sentinel, it should be :,:,: | `192.168.0.2:6379` | +| `redis.external.sentinelMasterSet` | The name of the set of Redis instances to monitor | | +| `redis.external.coreDatabaseIndex` | The database index for core | `0` | +| `redis.external.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.external.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.external.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.external.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.external.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.external.username` | The username of external Redis | | +| `redis.external.password` | The password of external Redis | | +| `redis.external.existingSecret` | Use an existing secret to connect to redis. The key must be `REDIS_PASSWORD`. | `""` | +| `redis.podAnnotations` | Annotations to add to the redis pod | `{}` | +| **Exporter** | | | +| `exporter.replicas` | The replica count | `1` | +| `exporter.revisionHistoryLimit` | The revision history limit | `10` | +| `exporter.podAnnotations` | Annotations to add to the exporter pod | `{}` | +| `exporter.image.repository` | Repository for redis image | `goharbor/harbor-exporter` | +| `exporter.image.tag` | Tag for exporter image | `dev` | +| `exporter.nodeSelector` | Node labels for pod assignment | `{}` | +| `exporter.tolerations` | Tolerations for pod assignment | `[]` | +| `exporter.affinity` | Node/Pod affinities | `{}` | +| `exporter.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `exporter.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `exporter.cacheDuration` | the cache duration for information that exporter collected from Harbor | `30` | +| `exporter.cacheCleanInterval` | cache clean interval for information that exporter collected from Harbor | `14400` | +| `exporter.priorityClassName` | The priority class to run the pod as | | +| **Metrics** | | | +| `metrics.enabled` | if enable harbor metrics | `false` | +| `metrics.core.path` | the url path for core metrics | `/metrics` | +| `metrics.core.port` | the port for core metrics | `8001` | +| `metrics.registry.path` | the url path for registry metrics | `/metrics` | +| `metrics.registry.port` | the port for registry metrics | `8001` | +| `metrics.exporter.path` | the url path for exporter metrics | `/metrics` | +| `metrics.exporter.port` | the port for exporter metrics | `8001` | +| `metrics.serviceMonitor.enabled` | create prometheus serviceMonitor. Requires prometheus CRD's | `false` | +| `metrics.serviceMonitor.additionalLabels` | additional labels to upsert to the manifest | `""` | +| `metrics.serviceMonitor.interval` | scrape period for harbor metrics | `""` | +| `metrics.serviceMonitor.metricRelabelings` | metrics relabel to add/mod/del before ingestion | `[]` | +| `metrics.serviceMonitor.relabelings` | relabels to add/mod/del to sample before scrape | `[]` | +| **Trace** | | | +| `trace.enabled` | Enable tracing or not | `false` | +| `trace.provider` | The tracing provider: `jaeger` or `otel`. `jaeger` should be 1.26+ | `jaeger` | +| `trace.sample_rate` | Set `sample_rate` to 1 if you want sampling 100% of trace data; set 0.5 if you want sampling 50% of trace data, and so forth | `1` | +| `trace.namespace` | Namespace used to differentiate different harbor services | | +| `trace.attributes` | `attributes` is a key value dict contains user defined attributes used to initialize trace provider | | +| `trace.jaeger.endpoint` | The endpoint of jaeger | `http://hostname:14268/api/traces` | +| `trace.jaeger.username` | The username of jaeger | | +| `trace.jaeger.password` | The password of jaeger | | +| `trace.jaeger.agent_host` | The agent host of jaeger | | +| `trace.jaeger.agent_port` | The agent port of jaeger | `6831` | +| `trace.otel.endpoint` | The endpoint of otel | `hostname:4318` | +| `trace.otel.url_path` | The URL path of otel | `/v1/traces` | +| `trace.otel.compression` | Whether enable compression or not for otel | `false` | +| `trace.otel.insecure` | Whether establish insecure connection or not for otel | `true` | +| `trace.otel.timeout` | The timeout in seconds of otel | `10` | +| **Cache** | | | +| `cache.enabled` | Enable cache layer or not | `false` | +| `cache.expireHours` | The expire hours of cache layer | `24` | + +[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +[trivy]: https://github.com/aquasecurity/trivy +[trivy-db]: https://github.com/aquasecurity/trivy-db +[trivy-java-db]: https://github.com/aquasecurity/trivy-java-db +[trivy-rate-limiting]: https://github.com/aquasecurity/trivy#github-rate-limiting diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/NOTES.txt b/src/pkg/chart/testdata/harbor-schema2/templates/NOTES.txt new file mode 100644 index 0000000000..0980c08a35 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/NOTES.txt @@ -0,0 +1,3 @@ +Please wait for several minutes for Harbor deployment to complete. +Then you should be able to visit the Harbor portal at {{ .Values.externalURL }} +For more details, please visit https://github.com/goharbor/harbor diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/_helpers.tpl b/src/pkg/chart/testdata/harbor-schema2/templates/_helpers.tpl new file mode 100644 index 0000000000..f6249b3993 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/_helpers.tpl @@ -0,0 +1,581 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "harbor.name" -}} +{{- default "harbor" .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "harbor.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default "harbor" .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Helm required labels: legacy */}} +{{- define "harbor.legacy.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helm required labels */}} +{{- define "harbor.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/name: {{ include "harbor.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: {{ include "harbor.name" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- end -}} + +{{/* matchLabels */}} +{{- define "harbor.matchLabels" -}} +release: {{ .Release.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helper for printing values from existing secrets*/}} +{{- define "harbor.secretKeyHelper" -}} + {{- if and (not (empty .data)) (hasKey .data .key) }} + {{- index .data .key | b64dec -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCert" -}} + {{- if and .Values.expose.tls.enabled (eq .Values.expose.tls.certSource "auto") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForIngress" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (eq .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForNginx" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (ne .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.host" -}} + {{- if eq .Values.database.type "internal" -}} + {{- template "harbor.database" . }} + {{- else -}} + {{- .Values.database.external.host -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.port" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "5432" -}} + {{- else -}} + {{- .Values.database.external.port -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.username" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "postgres" -}} + {{- else -}} + {{- .Values.database.external.username -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.rawPassword" -}} + {{- if eq .Values.database.type "internal" -}} + {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.database" .) -}} + {{- if and (not (empty $existingSecret)) (hasKey $existingSecret.data "POSTGRES_PASSWORD") -}} + {{- .Values.database.internal.password | default (index $existingSecret.data "POSTGRES_PASSWORD" | b64dec) -}} + {{- else -}} + {{- .Values.database.internal.password -}} + {{- end -}} + {{- else -}} + {{- .Values.database.external.password -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.escapedRawPassword" -}} + {{- include "harbor.database.rawPassword" . | urlquery | replace "+" "%20" -}} +{{- end -}} + +{{- define "harbor.database.encryptedPassword" -}} + {{- include "harbor.database.rawPassword" . | b64enc | quote -}} +{{- end -}} + +{{- define "harbor.database.coreDatabase" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "registry" -}} + {{- else -}} + {{- .Values.database.external.coreDatabase -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.sslmode" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "disable" -}} + {{- else -}} + {{- .Values.database.external.sslmode -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.scheme" -}} + {{- with .Values.redis }} + {{- ternary "redis+sentinel" "redis" (and (eq .type "external" ) (not (not .external.sentinelMasterSet))) }} + {{- end }} +{{- end -}} + +/*host:port*/ +{{- define "harbor.redis.addr" -}} + {{- with .Values.redis }} + {{- ternary (printf "%s:6379" (include "harbor.redis" $ )) .external.addr (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.masterSet" -}} + {{- with .Values.redis }} + {{- ternary .external.sentinelMasterSet "" (eq "redis+sentinel" (include "harbor.redis.scheme" $)) }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.password" -}} + {{- with .Values.redis }} + {{- ternary "" .external.password (eq .type "internal") }} + {{- end }} +{{- end -}} + + +{{- define "harbor.redis.pwdfromsecret" -}} + {{- (lookup "v1" "Secret" .Release.Namespace (.Values.redis.external.existingSecret)).data.REDIS_PASSWORD | b64dec }} +{{- end -}} + +{{- define "harbor.redis.cred" -}} + {{- with .Values.redis }} + {{- if (and (eq .type "external" ) (.external.existingSecret)) }} + {{- printf ":%s@" (include "harbor.redis.pwdfromsecret" $) }} + {{- else }} + {{- ternary (printf "%s:%s@" (.external.username | urlquery) (.external.password | urlquery)) "" (and (eq .type "external" ) (not (not .external.password))) }} + {{- end }} + {{- end }} +{{- end -}} + +/*scheme://[:password@]host:port[/master_set]*/ +{{- define "harbor.redis.url" -}} + {{- with .Values.redis }} + {{- $path := ternary "" (printf "/%s" (include "harbor.redis.masterSet" $)) (not (include "harbor.redis.masterSet" $)) }} + {{- printf "%s://%s%s%s" (include "harbor.redis.scheme" $) (include "harbor.redis.cred" $) (include "harbor.redis.addr" $) $path -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCore" -}} + {{- with .Values.redis }} + {{- $index := ternary "0" .external.coreDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index*/ +{{- define "harbor.redis.urlForJobservice" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.jobserviceDatabaseIndex .external.jobserviceDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForRegistry" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForTrivy" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.trivyAdapterIndex .external.trivyAdapterIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForHarbor" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.harborDatabaseIndex .external.harborDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCache" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.cacheLayerDatabaseIndex .external.cacheLayerDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.dbForRegistry" -}} + {{- with .Values.redis }} + {{- ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.portal" -}} + {{- printf "%s-portal" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.core" -}} + {{- printf "%s-core" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.redis" -}} + {{- printf "%s-redis" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.jobservice" -}} + {{- printf "%s-jobservice" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registry" -}} + {{- printf "%s-registry" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registryCtl" -}} + {{- printf "%s-registryctl" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.database" -}} + {{- printf "%s-database" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.trivy" -}} + {{- printf "%s-trivy" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.nginx" -}} + {{- printf "%s-nginx" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.exporter" -}} + {{- printf "%s-exporter" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.ingress" -}} + {{- printf "%s-ingress" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.noProxy" -}} + {{- printf "%s,%s,%s,%s,%s,%s,%s,%s" (include "harbor.core" .) (include "harbor.jobservice" .) (include "harbor.database" .) (include "harbor.registry" .) (include "harbor.portal" .) (include "harbor.trivy" .) (include "harbor.exporter" .) .Values.proxy.noProxy -}} +{{- end -}} + +{{- define "harbor.caBundleVolume" -}} +- name: ca-bundle-certs + secret: + secretName: {{ .Values.caBundleSecretName }} +{{- end -}} + +{{- define "harbor.caBundleVolumeMount" -}} +- name: ca-bundle-certs + mountPath: /harbor_cust_cert/custom-ca.crt + subPath: ca.crt +{{- end -}} + +{{/* scheme for all components because it only support http mode */}} +{{- define "harbor.component.scheme" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "https" -}} + {{- else -}} + {{- printf "http" -}} + {{- end -}} +{{- end -}} + +{{/* core component container port */}} +{{- define "harbor.core.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* core component service port */}} +{{- define "harbor.core.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component container port */}} +{{- define "harbor.jobservice.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component service port */}} +{{- define "harbor.jobservice.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* portal component container port */}} +{{- define "harbor.portal.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* portal component service port */}} +{{- define "harbor.portal.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* registry component container port */}} +{{- define "harbor.registry.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registry component service port */}} +{{- define "harbor.registry.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component container port */}} +{{- define "harbor.registryctl.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component service port */}} +{{- define "harbor.registryctl.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component container port */}} +{{- define "harbor.trivy.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component service port */}} +{{- define "harbor.trivy.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* CORE_URL */}} +{{/* port is included in this url as a workaround for issue https://github.com/aquasecurity/harbor-scanner-trivy/issues/108 */}} +{{- define "harbor.coreURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.core" .) (include "harbor.core.servicePort" .) -}} +{{- end -}} + +{{/* JOBSERVICE_URL */}} +{{- define "harbor.jobserviceURL" -}} + {{- printf "%s://%s-jobservice" (include "harbor.component.scheme" .) (include "harbor.fullname" .) -}} +{{- end -}} + +{{/* PORTAL_URL */}} +{{- define "harbor.portalURL" -}} + {{- printf "%s://%s" (include "harbor.component.scheme" .) (include "harbor.portal" .) -}} +{{- end -}} + +{{/* REGISTRY_URL */}} +{{- define "harbor.registryURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registry.servicePort" .) -}} +{{- end -}} + +{{/* REGISTRY_CONTROLLER_URL */}} +{{- define "harbor.registryControllerURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registryctl.servicePort" .) -}} +{{- end -}} + +{{/* TOKEN_SERVICE_URL */}} +{{- define "harbor.tokenServiceURL" -}} + {{- printf "%s/service/token" (include "harbor.coreURL" .) -}} +{{- end -}} + +{{/* TRIVY_ADAPTER_URL */}} +{{- define "harbor.trivyAdapterURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.trivy" .) (include "harbor.trivy.servicePort" .) -}} +{{- end -}} + +{{- define "harbor.internalTLS.core.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.core.secretName -}} + {{- else -}} + {{- printf "%s-core-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.jobservice.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.jobservice.secretName -}} + {{- else -}} + {{- printf "%s-jobservice-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.portal.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.portal.secretName -}} + {{- else -}} + {{- printf "%s-portal-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.registry.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.registry.secretName -}} + {{- else -}} + {{- printf "%s-registry-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.trivy.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.trivy.secretName -}} + {{- else -}} + {{- printf "%s-trivy-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsCoreSecretForIngress" -}} + {{- if eq .Values.expose.tls.certSource "none" -}} + {{- printf "" -}} + {{- else if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.ingress" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsSecretForNginx" -}} + {{- if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.nginx" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.metricsPortName" -}} + {{- if .Values.internalTLS.enabled }} + {{- printf "https-metrics" -}} + {{- else -}} + {{- printf "http-metrics" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.traceEnvs" -}} + TRACE_ENABLED: "{{ .Values.trace.enabled }}" + TRACE_SAMPLE_RATE: "{{ .Values.trace.sample_rate }}" + TRACE_NAMESPACE: "{{ .Values.trace.namespace }}" + {{- if .Values.trace.attributes }} + TRACE_ATTRIBUTES: {{ .Values.trace.attributes | toJson | squote }} + {{- end }} + {{- if eq .Values.trace.provider "jaeger" }} + TRACE_JAEGER_ENDPOINT: "{{ .Values.trace.jaeger.endpoint }}" + TRACE_JAEGER_USERNAME: "{{ .Values.trace.jaeger.username }}" + TRACE_JAEGER_AGENT_HOSTNAME: "{{ .Values.trace.jaeger.agent_host }}" + TRACE_JAEGER_AGENT_PORT: "{{ .Values.trace.jaeger.agent_port }}" + {{- else }} + TRACE_OTEL_ENDPOINT: "{{ .Values.trace.otel.endpoint }}" + TRACE_OTEL_URL_PATH: "{{ .Values.trace.otel.url_path }}" + TRACE_OTEL_COMPRESSION: "{{ .Values.trace.otel.compression }}" + TRACE_OTEL_INSECURE: "{{ .Values.trace.otel.insecure }}" + TRACE_OTEL_TIMEOUT: "{{ .Values.trace.otel.timeout }}" + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForCore" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-core" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForJobservice" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-jobservice" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForRegistryCtl" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-registryctl" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceJaegerPassword" -}} + {{- if and .Values.trace.enabled (eq .Values.trace.provider "jaeger") }} + TRACE_JAEGER_PASSWORD: "{{ .Values.trace.jaeger.password | default "" | b64enc }}" + {{- end }} +{{- end -}} + +{{/* Allow KubeVersion to be overridden. */}} +{{- define "harbor.ingress.kubeVersion" -}} + {{- default .Capabilities.KubeVersion.Version .Values.expose.ingress.kubeVersionOverride -}} +{{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-cm.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-cm.yaml new file mode 100644 index 0000000000..93cab01b4c --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-cm.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + app.conf: |+ + appname = Harbor + runmode = prod + enablegzip = true + + [prod] + httpport = {{ ternary "8443" "8080" .Values.internalTLS.enabled }} + PORT: "{{ ternary "8443" "8080" .Values.internalTLS.enabled }}" + DATABASE_TYPE: "postgresql" + POSTGRESQL_HOST: "{{ template "harbor.database.host" . }}" + POSTGRESQL_PORT: "{{ template "harbor.database.port" . }}" + POSTGRESQL_USERNAME: "{{ template "harbor.database.username" . }}" + POSTGRESQL_DATABASE: "{{ template "harbor.database.coreDatabase" . }}" + POSTGRESQL_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + POSTGRESQL_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + POSTGRESQL_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" + EXT_ENDPOINT: "{{ .Values.externalURL }}" + CORE_URL: "{{ template "harbor.coreURL" . }}" + JOBSERVICE_URL: "{{ template "harbor.jobserviceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + CORE_LOCAL_URL: "{{ ternary "https://127.0.0.1:8443" "http://127.0.0.1:8080" .Values.internalTLS.enabled }}" + WITH_TRIVY: {{ .Values.trivy.enabled | quote }} + TRIVY_ADAPTER_URL: "{{ template "harbor.trivyAdapterURL" . }}" + REGISTRY_STORAGE_PROVIDER_NAME: "{{ .Values.persistence.imageChartStorage.type }}" + LOG_LEVEL: "{{ .Values.logLevel }}" + CONFIG_PATH: "/etc/core/app.conf" + CHART_CACHE_DRIVER: "redis" + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + _REDIS_URL_REG: "{{ template "harbor.redis.urlForRegistry" . }}" + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.harborDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.harborDatabaseIndex) }} + _REDIS_URL_HARBOR: "{{ template "harbor.redis.urlForHarbor" . }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} + PORTAL_URL: "{{ template "harbor.portalURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + {{- if .Values.uaaSecretName }} + UAA_CA_ROOT: "/etc/core/auth-ca/auth-ca.crt" + {{- end }} + {{- if has "core" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE: "docker-hub,harbor,azure-acr,aws-ecr,google-gcr,quay,docker-registry,github-ghcr,jfrog-artifactory" + {{- if .Values.metrics.enabled}} + METRIC_ENABLE: "true" + METRIC_PATH: "{{ .Values.metrics.core.path }}" + METRIC_PORT: "{{ .Values.metrics.core.port }}" + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: core + {{- end }} + + {{- if hasKey .Values.core "gcTimeWindowHours" }} + #make the GC time window configurable for testing + GC_TIME_WINDOW_HOURS: "{{ .Values.core.gcTimeWindowHours }}" + {{- end }} + {{- template "harbor.traceEnvsForCore" . }} + + {{- if .Values.core.artifactPullAsyncFlushDuration }} + ARTIFACT_PULL_ASYNC_FLUSH_DURATION: {{ .Values.core.artifactPullAsyncFlushDuration | quote }} + {{- end }} + + {{- if .Values.core.gdpr}} + {{- if .Values.core.gdpr.deleteUser}} + GDPR_DELETE_USER: "true" + {{- end }} + {{- if .Values.core.gdpr.auditLogsCompliant}} + GDPR_AUDIT_LOGS: "true" + {{- end }} + {{- end }} + + {{- if .Values.cache.enabled }} + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + + {{- if .Values.core.quotaUpdateProvider }} + QUOTA_UPDATE_PROVIDER: "{{ .Values.core.quotaUpdateProvider }}" + {{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-dpl.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-dpl.yaml new file mode 100644 index 0000000000..2ee8fd59c2 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-dpl.yaml @@ -0,0 +1,257 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: core + app.kubernetes.io/component: core +spec: + replicas: {{ .Values.core.replicas }} + revisionHistoryLimit: {{ .Values.core.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: core + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: core + app.kubernetes.io/component: core +{{- if .Values.core.podLabels }} +{{ toYaml .Values.core.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/core/core-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.core.podAnnotations }} +{{ toYaml .Values.core.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.core.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.core.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: core +{{- end }} +{{- end }} + {{- with .Values.core.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: core + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.core.startupProbe.enabled }} + startupProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 360 + initialDelaySeconds: {{ .Values.core.startupProbe.initialDelaySeconds }} + periodSeconds: 10 + {{- end }} + livenessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/core/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/core/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/core/ca.crt + {{- end }} + {{- if .Values.database.external.existingSecret }} + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} + {{- if .Values.core.existingXsrfSecret }} + - name: CSRF_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.core.existingXsrfSecret }} + key: {{ .Values.core.existingXsrfSecretKey }} + {{- end }} +{{- with .Values.core.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ template "harbor.core.containerPort" . }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + - name: secret-key + mountPath: /etc/core/key + subPath: key + - name: token-service-private-key + mountPath: /etc/core/private_key.pem + subPath: tls.key + {{- if .Values.expose.tls.enabled }} + - name: ca-download + mountPath: /etc/core/ca + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + mountPath: /etc/core/auth-ca/auth-ca.crt + subPath: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + {{- end }} + - name: psc + mountPath: /etc/core/token + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} +{{- if .Values.core.resources }} + resources: +{{ toYaml .Values.core.resources | indent 10 }} +{{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + - name: secret-key + secret: + {{- if .Values.existingSecretSecretKey }} + secretName: {{ .Values.existingSecretSecretKey }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + items: + - key: secretKey + path: key + - name: token-service-private-key + secret: + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: ca-download + secret: + {{- if .Values.caSecretName }} + secretName: {{ .Values.caSecretName }} + {{- else if eq (include "harbor.autoGenCertForIngress" .) "true" }} + secretName: "{{ template "harbor.ingress" . }}" + {{- else if eq (include "harbor.autoGenCertForNginx" .) "true" }} + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + secret: + secretName: {{ .Values.uaaSecretName }} + items: + - key: ca.crt + path: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + - name: psc + emptyDir: {} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.core.priorityClassName }} + priorityClassName: {{ .Values.core.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-pre-upgrade-job.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-pre-upgrade-job.yaml new file mode 100644 index 0000000000..ce0b13134d --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-pre-upgrade-job.yaml @@ -0,0 +1,77 @@ +{{- if .Values.enableMigrateHelmHook }} +apiVersion: batch/v1 +kind: Job +metadata: + name: migration-job + labels: +{{ include "harbor.labels" . | indent 4 }} + component: migrator + annotations: + # This is what defines this resource as a hook. Without this line, the + # job is considered part of the release. + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + template: + metadata: + labels: +{{ include "harbor.matchLabels" . | indent 8 }} + component: migrator + spec: + restartPolicy: Never + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: 120 + containers: + - name: core-job + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: ["/harbor/harbor_core", "-mode=migrate"] + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + {{- if .Values.database.external.existingSecret }} + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-secret.yaml new file mode 100644 index 0000000000..62a41fce80 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-secret.yaml @@ -0,0 +1,36 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.core" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.existingSecretSecretKey }} + secretKey: {{ .Values.secretKey | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingSecret }} + secret: {{ .Values.core.secret | default (include "harbor.secretKeyHelper" (dict "key" "secret" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.core.secretName }} + {{- $ca := genCA "harbor-token-ca" 365 }} + tls.key: {{ .Values.core.tokenKey | default $ca.Key | b64enc | quote }} + tls.crt: {{ .Values.core.tokenCert | default $ca.Cert | b64enc | quote }} + {{- end }} + {{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} + {{- end }} + {{- if not .Values.database.external.existingSecret }} + POSTGRESQL_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingXsrfSecret }} + CSRF_KEY: {{ .Values.core.xsrfKey | default (include "harbor.secretKeyHelper" (dict "key" "CSRF_KEY" "data" $existingSecret.data)) | default (randAlphaNum 32) | b64enc | quote }} + {{- end }} +{{- if .Values.core.configureUserSettings }} + CONFIG_OVERWRITE_JSON: {{ .Values.core.configureUserSettings | b64enc | quote }} +{{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-svc.yaml new file mode 100644 index 0000000000..0d2cfb2915 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-svc.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.core" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.core.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} + ports: + - name: {{ ternary "https-web" "http-web" .Values.internalTLS.enabled }} + port: {{ template "harbor.core.servicePort" . }} + targetPort: {{ template "harbor.core.containerPort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.core.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: core diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/core/core-tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-tls.yaml new file mode 100644 index 0000000000..c52148f0d9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/core/core-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.core.crt\" is required!" .Values.internalTLS.core.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.core.key\" is required!" .Values.internalTLS.core.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/database/database-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-secret.yaml new file mode 100644 index 0000000000..864aff4a18 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-secret.yaml @@ -0,0 +1,11 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + POSTGRES_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/database/database-ss.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-ss.yaml new file mode 100644 index 0000000000..71c5eb1e08 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-ss.yaml @@ -0,0 +1,162 @@ +{{- if eq .Values.database.type "internal" -}} +{{- $database := .Values.persistence.persistentVolumeClaim.database -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: database + app.kubernetes.io/component: database +spec: + replicas: 1 + serviceName: "{{ template "harbor.database" . }}" + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: database + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: database + app.kubernetes.io/component: database +{{- if .Values.database.podLabels }} +{{ toYaml .Values.database.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/database/database-secret.yaml") . | sha256sum }} +{{- if .Values.database.podAnnotations }} +{{ toYaml .Values.database.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.database.internal.serviceAccountName }} + serviceAccountName: {{ .Values.database.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.database.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + initContainers: + # with "fsGroup" set, each time a volume is mounted, Kubernetes must recursively chown() and chmod() all the files and directories inside the volume + # this causes the postgresql reports the "data directory /var/lib/postgresql/data/pgdata has group or world access" issue when using some CSIs e.g. Ceph + # use this init container to correct the permission + # as "fsGroup" applied before the init container running, the container has enough permission to execute the command + - name: "data-permissions-ensurer" + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + command: ["/bin/sh"] + args: ["-c", "chmod -R 700 /var/lib/postgresql/data/pgdata || true"] +{{- if .Values.database.internal.initContainer.permissions.resources }} + resources: +{{ toYaml .Values.database.internal.initContainer.permissions.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + {{- with .Values.database.internal.extrInitContainers }} + {{- toYaml . | nindent 6 }} + {{- end }} + containers: + - name: database + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 300 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.livenessProbe.timeoutSeconds }} + readinessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 1 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.readinessProbe.timeoutSeconds }} +{{- if .Values.database.internal.resources }} + resources: +{{ toYaml .Values.database.internal.resources | indent 10 }} +{{- end }} + envFrom: + - secretRef: + name: "{{ template "harbor.database" . }}" + env: + # put the data into a sub directory to avoid the permission issue in k8s with restricted psp enabled + # more detail refer to https://github.com/goharbor/harbor-helm/issues/756 + - name: PGDATA + value: "/var/lib/postgresql/data/pgdata" +{{- with .Values.database.internal.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + - name: shm-volume + mountPath: /dev/shm + volumes: + - name: shm-volume + emptyDir: + medium: Memory + sizeLimit: {{ .Values.database.internal.shmSizeLimit }} + {{- if not .Values.persistence.enabled }} + - name: "database-data" + emptyDir: {} + {{- else if $database.existingClaim }} + - name: "database-data" + persistentVolumeClaim: + claimName: {{ $database.existingClaim }} + {{- end -}} + {{- with .Values.database.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.database.internal.priorityClassName }} + priorityClassName: {{ .Values.database.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $database.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: "database-data" + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $database.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $database.accessMode | quote }}] + {{- if $database.storageClass }} + {{- if (eq "-" $database.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $database.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $database.size | quote }} + {{- end -}} + {{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/database/database-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-svc.yaml new file mode 100644 index 0000000000..6475048cd9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/database/database-svc.yaml @@ -0,0 +1,14 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.database" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - port: 5432 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: database +{{- end -}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-cm-env.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-cm-env.yaml new file mode 100644 index 0000000000..0bf4e7d905 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-cm-env.yaml @@ -0,0 +1,35 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.exporter" . }}-env" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + LOG_LEVEL: "{{ .Values.logLevel }}" + HARBOR_EXPORTER_PORT: "{{ .Values.metrics.exporter.port }}" + HARBOR_EXPORTER_METRICS_PATH: "{{ .Values.metrics.exporter.path }}" + HARBOR_EXPORTER_METRICS_ENABLED: "{{ .Values.metrics.enabled }}" + HARBOR_EXPORTER_CACHE_TIME: "{{ .Values.exporter.cacheDuration }}" + HARBOR_EXPORTER_CACHE_CLEAN_INTERVAL: "{{ .Values.exporter.cacheCleanInterval }}" + HARBOR_METRIC_NAMESPACE: harbor + HARBOR_METRIC_SUBSYSTEM: exporter + HARBOR_REDIS_URL: "{{ template "harbor.redis.urlForJobservice" . }}" + HARBOR_REDIS_NAMESPACE: harbor_job_service_namespace + HARBOR_REDIS_TIMEOUT: "3600" + HARBOR_SERVICE_SCHEME: "{{ template "harbor.component.scheme" . }}" + HARBOR_SERVICE_HOST: "{{ template "harbor.core" . }}" + HARBOR_SERVICE_PORT: "{{ template "harbor.core.servicePort" . }}" + HARBOR_DATABASE_HOST: "{{ template "harbor.database.host" . }}" + HARBOR_DATABASE_PORT: "{{ template "harbor.database.port" . }}" + HARBOR_DATABASE_USERNAME: "{{ template "harbor.database.username" . }}" + HARBOR_DATABASE_DBNAME: "{{ template "harbor.database.coreDatabase" . }}" + HARBOR_DATABASE_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + HARBOR_DATABASE_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + HARBOR_DATABASE_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" +{{- end}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-dpl.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-dpl.yaml new file mode 100644 index 0000000000..01e9258ea9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-dpl.yaml @@ -0,0 +1,146 @@ +{{- if .Values.metrics.enabled}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.exporter" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: exporter + app.kubernetes.io/component: exporter +spec: + replicas: {{ .Values.exporter.replicas }} + revisionHistoryLimit: {{ .Values.exporter.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: exporter + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: exporter + app.kubernetes.io/component: exporter +{{- if .Values.exporter.podLabels }} +{{ toYaml .Values.exporter.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/exporter/exporter-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/exporter/exporter-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.exporter.podAnnotations }} +{{ toYaml .Values.exporter.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.exporter.serviceAccountName }} + serviceAccountName: {{ .Values.exporter.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.exporter.automountServiceAccountToken | default false }} +{{- with .Values.exporter.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: exporter +{{- end }} +{{- end }} + containers: + - name: exporter + image: {{ .Values.exporter.image.repository }}:{{ .Values.exporter.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 30 + periodSeconds: 10 + args: ["-log-level", "{{ .Values.logLevel }}"] + envFrom: + - configMapRef: + name: "{{ template "harbor.exporter" . }}-env" + - secretRef: + name: "{{ template "harbor.exporter" . }}" + env: + {{- if .Values.database.external.existingSecret }} + - name: HARBOR_DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} +{{- if .Values.exporter.resources }} + resources: +{{ toYaml .Values.exporter.resources | indent 10 }} +{{- end }} +{{- with .Values.exporter.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ .Values.metrics.exporter.port }} + volumeMounts: + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + # There are some metric data are collectd from harbor core. + # When internal TLS is enabled, the Exporter need the CA file to collect these data. + {{- end }} + volumes: + - name: config + secret: + secretName: "{{ template "harbor.exporter" . }}" + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.exporter.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.exporter.priorityClassName }} + priorityClassName: {{ .Values.exporter.priorityClassName }} + {{- end }} +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-secret.yaml new file mode 100644 index 0000000000..434a1bf689 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-secret.yaml @@ -0,0 +1,16 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.exporter" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: +{{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} +{{- end }} +{{- if not .Values.database.external.existingSecret }} + HARBOR_DATABASE_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-svc.yaml new file mode 100644 index 0000000000..4a6f3fdec6 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/exporter/exporter-svc.yaml @@ -0,0 +1,15 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.exporter" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.exporter.port }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: exporter +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/ingress/ingress.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/ingress/ingress.yaml new file mode 100644 index 0000000000..73472c6056 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/ingress/ingress.yaml @@ -0,0 +1,142 @@ +{{- if eq .Values.expose.type "ingress" }} +{{- $ingress := .Values.expose.ingress -}} +{{- $tls := .Values.expose.tls -}} +{{- if eq .Values.expose.ingress.controller "gce" }} + {{- $_ := set . "portal_path" "/*" -}} + {{- $_ := set . "api_path" "/api/*" -}} + {{- $_ := set . "service_path" "/service/*" -}} + {{- $_ := set . "v2_path" "/v2/*" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/*" -}} + {{- $_ := set . "controller_path" "/c/*" -}} +{{- else if eq .Values.expose.ingress.controller "ncp" }} + {{- $_ := set . "portal_path" "/.*" -}} + {{- $_ := set . "api_path" "/api/.*" -}} + {{- $_ := set . "service_path" "/service/.*" -}} + {{- $_ := set . "v2_path" "/v2/.*" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/.*" -}} + {{- $_ := set . "controller_path" "/c/.*" -}} +{{- else }} + {{- $_ := set . "portal_path" "/" -}} + {{- $_ := set . "api_path" "/api/" -}} + {{- $_ := set . "service_path" "/service/" -}} + {{- $_ := set . "v2_path" "/v2/" -}} + {{- $_ := set . "chartrepo_path" "/chartrepo/" -}} + {{- $_ := set . "controller_path" "/c/" -}} +{{- end }} + +--- +{{- if semverCompare "<1.14-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: extensions/v1beta1 +{{- else if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: networking.k8s.io/v1 +{{- end }} +kind: Ingress +metadata: + name: "{{ template "harbor.ingress" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if $ingress.labels }} +{{ toYaml $ingress.labels | indent 4 }} +{{- end }} + annotations: +{{ toYaml $ingress.annotations | indent 4 }} +{{- if .Values.internalTLS.enabled }} + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" +{{- end }} +{{- if eq .Values.expose.ingress.controller "ncp" }} + ncp/use-regex: "true" + {{- if $tls.enabled }} + ncp/http-redirect: "true" + {{- end }} +{{- end }} +spec: + {{- if $ingress.className }} + ingressClassName: {{ $ingress.className }} + {{- end }} + {{- if $tls.enabled }} + tls: + - secretName: {{ template "harbor.tlsCoreSecretForIngress" . }} + {{- if $ingress.hosts.core }} + hosts: + - {{ $ingress.hosts.core }} + {{- end }} + {{- end }} + rules: + - http: + paths: +{{- if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} + - path: {{ .api_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .chartrepo_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + backend: + serviceName: {{ template "harbor.portal" . }} + servicePort: {{ template "harbor.portal.servicePort" . }} +{{- else }} + - path: {{ .api_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .chartrepo_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + pathType: Prefix + backend: + service: + name: {{ template "harbor.portal" . }} + port: + number: {{ template "harbor.portal.servicePort" . }} +{{- end }} + {{- if $ingress.hosts.core }} + host: {{ $ingress.hosts.core }} + {{- end }} + +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/ingress/secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/ingress/secret.yaml new file mode 100644 index 0000000000..41507b3dd9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/ingress/secret.yaml @@ -0,0 +1,15 @@ +{{- if eq (include "harbor.autoGenCertForIngress" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cert := genSignedCert .Values.expose.ingress.hosts.core nil (list .Values.expose.ingress.hosts.core) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.ingress" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/internal/auto-tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/internal/auto-tls.yaml new file mode 100644 index 0000000000..da5f5e2c7b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/internal/auto-tls.yaml @@ -0,0 +1,81 @@ +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} +{{- $ca := genCA "harbor-internal-ca" 365 }} +{{- $coreCN := (include "harbor.core" .) }} +{{- $coreCrt := genSignedCert $coreCN (list "127.0.0.1") (list "localhost" $coreCN) 365 $ca }} +{{- $jsCN := (include "harbor.jobservice" .) }} +{{- $jsCrt := genSignedCert $jsCN nil (list $jsCN) 365 $ca }} +{{- $regCN := (include "harbor.registry" .) }} +{{- $regCrt := genSignedCert $regCN nil (list $regCN) 365 $ca }} +{{- $portalCN := (include "harbor.portal" .) }} +{{- $portalCrt := genSignedCert $portalCN nil (list $portalCN) 365 $ca }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $coreCrt.Cert | b64enc | quote }} + tls.key: {{ $coreCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $jsCrt.Cert | b64enc | quote }} + tls.key: {{ $jsCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $regCrt.Cert | b64enc | quote }} + tls.key: {{ $regCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $portalCrt.Cert | b64enc | quote }} + tls.key: {{ $portalCrt.Key | b64enc | quote }} + +{{- if and .Values.trivy.enabled}} +--- +{{- $trivyCN := (include "harbor.trivy" .) }} +{{- $trivyCrt := genSignedCert $trivyCN nil (list $trivyCN) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $trivyCrt.Cert | b64enc | quote }} + tls.key: {{ $trivyCrt.Key | b64enc | quote }} +{{- end }} + +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm-env.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm-env.yaml new file mode 100644 index 0000000000..8411c7a47c --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm-env.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}-env" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + CORE_URL: "{{ template "harbor.coreURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + + JOBSERVICE_WEBHOOK_JOB_MAX_RETRY: "{{ .Values.jobservice.notification.webhook_job_max_retry }}" + JOBSERVICE_WEBHOOK_JOB_HTTP_CLIENT_TIMEOUT: "{{ .Values.jobservice.notification.webhook_job_http_client_timeout }}" + + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.metrics.enabled}} + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: jobservice + {{- end }} + {{- template "harbor.traceEnvsForJobservice" . }} + {{- if .Values.cache.enabled }} + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm.yaml new file mode 100644 index 0000000000..8211c62209 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-cm.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + #Server listening port + protocol: "{{ template "harbor.component.scheme" . }}" + port: {{ template "harbor.jobservice.containerPort". }} + {{- if .Values.internalTLS.enabled }} + https_config: + cert: "/etc/harbor/ssl/jobservice/tls.crt" + key: "/etc/harbor/ssl/jobservice/tls.key" + {{- end }} + worker_pool: + workers: {{ .Values.jobservice.maxJobWorkers }} + backend: "redis" + redis_pool: + redis_url: "{{ template "harbor.redis.urlForJobservice" . }}" + namespace: "harbor_job_service_namespace" + idle_timeout_second: 3600 + job_loggers: + {{- if has "file" .Values.jobservice.jobLoggers }} + - name: "FILE" + level: {{ .Values.logLevel | upper }} + settings: # Customized settings of logger + base_dir: "/var/log/jobs" + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + settings: # Customized settings of sweeper + work_dir: "/var/log/jobs" + {{- end }} + {{- if has "database" .Values.jobservice.jobLoggers }} + - name: "DB" + level: {{ .Values.logLevel | upper }} + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + {{- end }} + {{- if has "stdout" .Values.jobservice.jobLoggers }} + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + {{- end }} + metric: + enabled: {{ .Values.metrics.enabled }} + path: {{ .Values.metrics.jobservice.path }} + port: {{ .Values.metrics.jobservice.port }} + #Loggers for the job service + loggers: + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: {{ .Values.jobservice.reaper.max_update_hours }} + # the max time for execution in running state without new task created + max_dangling_hours: {{ .Values.jobservice.reaper.max_dangling_hours }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-dpl.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-dpl.yaml new file mode 100644 index 0000000000..1bb6690824 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-dpl.yaml @@ -0,0 +1,182 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + replicas: {{ .Values.jobservice.replicas }} + revisionHistoryLimit: {{ .Values.jobservice.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: jobservice + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: jobservice + app.kubernetes.io/component: jobservice +{{- if .Values.jobservice.podLabels }} +{{ toYaml .Values.jobservice.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm.yaml") . | sha256sum }} + checksum/configmap-env: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/jobservice/jobservice-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.jobservice.podAnnotations }} +{{ toYaml .Values.jobservice.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.jobservice.serviceAccountName }} + serviceAccountName: {{ .Values.jobservice.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.jobservice.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.jobservice.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: jobservice +{{- end }} +{{- end }} + {{- with .Values.jobservice.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: jobservice + image: {{ .Values.jobservice.image.repository }}:{{ .Values.jobservice.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 20 + periodSeconds: 10 +{{- if .Values.jobservice.resources }} + resources: +{{ toYaml .Values.jobservice.resources | indent 10 }} +{{- end }} + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + {{- if .Values.jobservice.existingSecret }} + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/jobservice/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/jobservice/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/jobservice/ca.crt + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} +{{- with .Values.jobservice.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.jobservice" . }}-env" + - secretRef: + name: "{{ template "harbor.jobservice" . }}" + ports: + - containerPort: {{ template "harbor.jobservice.containerPort" . }} + volumeMounts: + - name: jobservice-config + mountPath: /etc/jobservice/config.yml + subPath: config.yml + - name: job-logs + mountPath: /var/log/jobs + subPath: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.subPath }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + mountPath: /etc/harbor/ssl/jobservice + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: jobservice-config + configMap: + name: "{{ template "harbor.jobservice" . }}" + - name: job-logs + {{- if and .Values.persistence.enabled (has "file" .Values.jobservice.jobLoggers) }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim | default (include "harbor.jobservice" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.jobservice.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.jobservice.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.jobservice.priorityClassName }} + priorityClassName: {{ .Values.jobservice.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-pvc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-pvc.yaml new file mode 100644 index 0000000000..3f7d00b671 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-pvc.yaml @@ -0,0 +1,31 @@ +{{- $jobLog := .Values.persistence.persistentVolumeClaim.jobservice.jobLog -}} +{{- if and .Values.persistence.enabled (not $jobLog.existingClaim) (has "file" .Values.jobservice.jobLoggers) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.jobservice" . }} + annotations: + {{- range $key, $value := $jobLog.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + accessModes: + - {{ $jobLog.accessMode }} + resources: + requests: + storage: {{ $jobLog.size }} + {{- if $jobLog.storageClass }} + {{- if eq "-" $jobLog.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $jobLog.storageClass }} + {{- end }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-secrets.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-secrets.yaml new file mode 100644 index 0000000000..eeb00bde00 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-secrets.yaml @@ -0,0 +1,16 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.jobservice" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.jobservice.existingSecret }} + JOBSERVICE_SECRET: {{ .Values.jobservice.secret | default (include "harbor.secretKeyHelper" (dict "key" "JOBSERVICE_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-svc.yaml new file mode 100644 index 0000000000..d2b7a47fd4 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-svc.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.jobservice" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-jobservice" "http-jobservice" .Values.internalTLS.enabled }} + port: {{ template "harbor.jobservice.servicePort" . }} + targetPort: {{ template "harbor.jobservice.containerPort" . }} +{{- if .Values.metrics.enabled }} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.jobservice.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: jobservice diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-tls.yaml new file mode 100644 index 0000000000..234cb39995 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/jobservice/jobservice-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.jobservice.crt\" is required!" .Values.internalTLS.jobservice.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.jobservice.key\" is required!" .Values.internalTLS.jobservice.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/metrics/metrics-svcmon.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/metrics/metrics-svcmon.yaml new file mode 100644 index 0000000000..1122ef01ef --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/metrics/metrics-svcmon.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "harbor.fullname" . }} + labels: {{ include "harbor.labels" . | nindent 4 }} +{{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} +{{- end }} +spec: + jobLabel: app.kubernetes.io/name + endpoints: + - port: {{ template "harbor.metricsPortName" . }} + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + honorLabels: true +{{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.metrics.serviceMonitor.metricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.metrics.serviceMonitor.relabelings | indent 4 }} +{{- end }} + selector: + matchLabels: {{ include "harbor.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-http.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-http.yaml new file mode 100644 index 0000000000..c4b8354d06 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-http.yaml @@ -0,0 +1,150 @@ +{{- if and (ne .Values.expose.type "ingress") (not .Values.expose.tls.enabled) }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server {{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled}} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end }} + server_tokens off; + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # Add extra headers + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass {{ $scheme }}://core/chartrepo/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + proxy_send_timeout 900; + proxy_read_timeout 900; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + } +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-https.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-https.yaml new file mode 100644 index 0000000000..56c943a619 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/configmap-https.yaml @@ -0,0 +1,187 @@ +{{- if and (ne .Values.expose.type "ingress") .Values.expose.tls.enabled }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server "{{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}"; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8443 ssl; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8443 ssl; + {{- end }} + # server_name harbordomain.com; + server_tokens off; + # SSL + ssl_certificate /etc/nginx/cert/tls.crt; + ssl_certificate_key /etc/nginx/cert/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + # Add extra headers + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; HttpOnly; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /chartrepo/ { + proxy_pass {{ $scheme }}://core/chartrepo/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end}} + #server_name harbordomain.com; + return 301 https://$host$request_uri; + } + } +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/nginx/deployment.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/deployment.yaml new file mode 100644 index 0000000000..3abc941989 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/deployment.yaml @@ -0,0 +1,132 @@ +{{- if ne .Values.expose.type "ingress" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: nginx + app.kubernetes.io/component: nginx +spec: + replicas: {{ .Values.nginx.replicas }} + revisionHistoryLimit: {{ .Values.nginx.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: nginx + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: nginx + app.kubernetes.io/component: nginx +{{- if .Values.nginx.podLabels }} +{{ toYaml .Values.nginx.podLabels | indent 8 }} +{{- end }} + annotations: + {{- if not .Values.expose.tls.enabled }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-http.yaml") . | sha256sum }} + {{- else }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-https.yaml") . | sha256sum }} + {{- end }} + {{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} + checksum/secret: {{ include (print $.Template.BasePath "/nginx/secret.yaml") . | sha256sum }} + {{- end }} +{{- if .Values.nginx.podAnnotations }} +{{ toYaml .Values.nginx.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- if .Values.nginx.serviceAccountName }} + serviceAccountName: {{ .Values.nginx.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.nginx.automountServiceAccountToken | default false }} +{{- with .Values.nginx.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: nginx +{{- end }} +{{- end }} + containers: + - name: nginx + image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + {{- $_ := set . "scheme" "HTTP" -}} + {{- $_ := set . "port" "8080" -}} + {{- if .Values.expose.tls.enabled }} + {{- $_ := set . "scheme" "HTTPS" -}} + {{- $_ := set . "port" "8443" -}} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.nginx.resources }} + resources: +{{ toYaml .Values.nginx.resources | indent 10 }} +{{- end }} +{{- with .Values.nginx.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: 8080 + {{- if .Values.expose.tls.enabled }} + - containerPort: 8443 + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.expose.tls.enabled }} + - name: certificate + mountPath: /etc/nginx/cert + {{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.nginx" . }} + {{- if .Values.expose.tls.enabled }} + - name: certificate + secret: + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- with .Values.nginx.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.nginx.priorityClassName }} + priorityClassName: {{ .Values.nginx.priorityClassName }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/nginx/secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/secret.yaml new file mode 100644 index 0000000000..c819c556d9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/secret.yaml @@ -0,0 +1,23 @@ +{{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cn := (required "The \"expose.tls.auto.commonName\" is required!" .Values.expose.tls.auto.commonName) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.nginx" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if regexMatch `^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` $cn }} + {{- $cert := genSignedCert $cn (list $cn) nil 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- else }} + {{- $cert := genSignedCert $cn nil (list $cn) 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/nginx/service.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/service.yaml new file mode 100644 index 0000000000..691584ce02 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/nginx/service.yaml @@ -0,0 +1,94 @@ +{{- if or (eq .Values.expose.type "clusterIP") (eq .Values.expose.type "nodePort") (eq .Values.expose.type "loadBalancer") }} +apiVersion: v1 +kind: Service +metadata: +{{- if eq .Values.expose.type "clusterIP" }} +{{- $clusterIP := .Values.expose.clusterIP }} + name: {{ $clusterIP.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.clusterIP.labels }} +{{ toYaml $clusterIP.labels | indent 4 }} +{{- end }} +{{- with $clusterIP.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: ClusterIP + {{- if .Values.expose.clusterIP.staticClusterIP }} + clusterIP: {{ .Values.expose.clusterIP.staticClusterIP }} + {{- end }} + ports: + - name: http + port: {{ $clusterIP.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $clusterIP.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- else if eq .Values.expose.type "nodePort" }} +{{- $nodePort := .Values.expose.nodePort }} + name: {{ $nodePort.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.nodePort.labels }} +{{ toYaml $nodePort.labels | indent 4 }} +{{- end }} +{{- with $nodePort.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: NodePort + ports: + - name: http + port: {{ $nodePort.ports.http.port }} + targetPort: 8080 + {{- if $nodePort.ports.http.nodePort }} + nodePort: {{ $nodePort.ports.http.nodePort }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $nodePort.ports.https.port }} + targetPort: 8443 + {{- if $nodePort.ports.https.nodePort }} + nodePort: {{ $nodePort.ports.https.nodePort }} + {{- end }} + {{- end }} +{{- else if eq .Values.expose.type "loadBalancer" }} +{{- $loadBalancer := .Values.expose.loadBalancer }} + name: {{ $loadBalancer.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.loadBalancer.labels }} +{{ toYaml $loadBalancer.labels | indent 4 }} +{{- end }} +{{- with $loadBalancer.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: LoadBalancer + {{- with $loadBalancer.sourceRanges }} + loadBalancerSourceRanges: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $loadBalancer.IP }} + loadBalancerIP: {{ $loadBalancer.IP }} + {{- end }} + ports: + - name: http + port: {{ $loadBalancer.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $loadBalancer.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: nginx +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/portal/configmap.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/portal/configmap.yaml new file mode 100644 index 0000000000..7b2118e721 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/portal/configmap.yaml @@ -0,0 +1,67 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + events { + worker_connections 1024; + } + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + server { + {{- if .Values.internalTLS.enabled }} + {{- if .Values.ipFamily.ipv4.enabled}} + listen {{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + # SSL + ssl_certificate /etc/harbor/ssl/portal/tls.crt; + ssl_certificate_key /etc/harbor/ssl/portal/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + {{- else }} + {{- if .Values.ipFamily.ipv4.enabled }} + listen {{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- end }} + server_name localhost; + root /usr/share/nginx/html; + index index.html index.htm; + include /etc/nginx/mime.types; + gzip on; + gzip_min_length 1000; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + location /devcenter-api-2.0 { + try_files $uri $uri/ /swagger-ui-index.html; + } + location / { + try_files $uri $uri/ /index.html; + } + location = /index.html { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + } + } diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/portal/deployment.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/portal/deployment.yaml new file mode 100644 index 0000000000..4dea944382 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/portal/deployment.yaml @@ -0,0 +1,123 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: portal + app.kubernetes.io/component: portal +spec: + replicas: {{ .Values.portal.replicas }} + revisionHistoryLimit: {{ .Values.portal.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: portal + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: portal + app.kubernetes.io/component: portal +{{- if .Values.portal.podLabels }} +{{ toYaml .Values.portal.podLabels | indent 8 }} +{{- end }} + annotations: +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/portal/tls.yaml") . | sha256sum }} +{{- end }} + checksum/configmap: {{ include (print $.Template.BasePath "/portal/configmap.yaml") . | sha256sum }} +{{- if .Values.portal.podAnnotations }} +{{ toYaml .Values.portal.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- if .Values.portal.serviceAccountName }} + serviceAccountName: {{ .Values.portal.serviceAccountName }} +{{- end }} + automountServiceAccountToken: {{ .Values.portal.automountServiceAccountToken | default false }} +{{- with .Values.portal.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: portal +{{- end }} +{{- end }} + {{- with .Values.portal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: portal + image: {{ .Values.portal.image.repository }}:{{ .Values.portal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.portal.resources }} + resources: +{{ toYaml .Values.portal.resources | indent 10 }} +{{- end }} +{{- with .Values.portal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 + ports: + - containerPort: {{ template "harbor.portal.containerPort" . }} + volumeMounts: + - name: portal-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + mountPath: /etc/harbor/ssl/portal + {{- end }} + volumes: + - name: portal-config + configMap: + name: "{{ template "harbor.portal" . }}" + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.portal.secretName" . }} + {{- end }} + {{- with .Values.portal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.portal.priorityClassName }} + priorityClassName: {{ .Values.portal.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/portal/service.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/portal/service.yaml new file mode 100644 index 0000000000..d00026da46 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/portal/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.portal" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.portal.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} + ports: + - port: {{ template "harbor.portal.servicePort" . }} + targetPort: {{ template "harbor.portal.containerPort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: portal diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/portal/tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/portal/tls.yaml new file mode 100644 index 0000000000..de63f4e813 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/portal/tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.portal.crt\" is required!" .Values.internalTLS.portal.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.portal.key\" is required!" .Values.internalTLS.portal.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/redis/service.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/redis/service.yaml new file mode 100644 index 0000000000..79c95c3e05 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/redis/service.yaml @@ -0,0 +1,14 @@ +{{- if eq .Values.redis.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.redis" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - port: 6379 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: redis +{{- end -}} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/redis/statefulset.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/redis/statefulset.yaml new file mode 100644 index 0000000000..1d37fb184b --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/redis/statefulset.yaml @@ -0,0 +1,125 @@ +{{- if eq .Values.redis.type "internal" -}} +{{- $redis := .Values.persistence.persistentVolumeClaim.redis -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.redis" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: redis + app.kubernetes.io/component: redis +spec: + replicas: 1 + serviceName: {{ template "harbor.redis" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: redis + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: redis + app.kubernetes.io/component: redis +{{- if .Values.redis.podLabels }} +{{ toYaml .Values.redis.podLabels | indent 8 }} +{{- end }} +{{- if .Values.redis.podAnnotations }} + annotations: +{{ toYaml .Values.redis.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.redis.internal.serviceAccountName }} + serviceAccountName: {{ .Values.redis.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.redis.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + {{- with .Values.redis.internal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: redis + image: {{ .Values.redis.internal.image.repository }}:{{ .Values.redis.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.redis.internal.resources }} + resources: +{{ toYaml .Values.redis.internal.resources | indent 10 }} +{{- end }} +{{- with .Values.redis.internal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /var/lib/redis + subPath: {{ $redis.subPath }} + {{- if not .Values.persistence.enabled }} + volumes: + - name: data + emptyDir: {} + {{- else if $redis.existingClaim }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ $redis.existingClaim }} + {{- end -}} + {{- with .Values.redis.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.redis.internal.priorityClassName }} + priorityClassName: {{ .Values.redis.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $redis.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $redis.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $redis.accessMode | quote }}] + {{- if $redis.storageClass }} + {{- if (eq "-" $redis.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $redis.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $redis.size | quote }} + {{- end -}} + {{- end -}} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-cm.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-cm.yaml new file mode 100644 index 0000000000..4f7056c384 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-cm.yaml @@ -0,0 +1,246 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + version: 0.1 + log: + {{- if eq .Values.logLevel "warning" }} + level: warn + {{- else if eq .Values.logLevel "fatal" }} + level: error + {{- else }} + level: {{ .Values.logLevel }} + {{- end }} + fields: + service: registry + storage: + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if eq $type "filesystem" }} + filesystem: + rootdirectory: {{ $storage.filesystem.rootdirectory }} + {{- if $storage.filesystem.maxthreads }} + maxthreads: {{ $storage.filesystem.maxthreads }} + {{- end }} + {{- else if eq $type "azure" }} + azure: + accountname: {{ $storage.azure.accountname }} + container: {{ $storage.azure.container }} + {{- if $storage.azure.realm }} + realm: {{ $storage.azure.realm }} + {{- end }} + {{- else if eq $type "gcs" }} + gcs: + bucket: {{ $storage.gcs.bucket }} + {{- if not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity }} + keyfile: /etc/registry/gcs-key.json + {{- end }} + {{- if $storage.gcs.rootdirectory }} + rootdirectory: {{ $storage.gcs.rootdirectory }} + {{- end }} + {{- if $storage.gcs.chunksize }} + chunksize: {{ $storage.gcs.chunksize }} + {{- end }} + {{- else if eq $type "s3" }} + s3: + region: {{ $storage.s3.region }} + bucket: {{ $storage.s3.bucket }} + {{- if $storage.s3.regionendpoint }} + regionendpoint: {{ $storage.s3.regionendpoint }} + {{- end }} + {{- if $storage.s3.encrypt }} + encrypt: {{ $storage.s3.encrypt }} + {{- end }} + {{- if $storage.s3.keyid }} + keyid: {{ $storage.s3.keyid }} + {{- end }} + {{- if $storage.s3.secure }} + secure: {{ $storage.s3.secure }} + {{- end }} + {{- if and $storage.s3.secure $storage.s3.skipverify }} + skipverify: {{ $storage.s3.skipverify }} + {{- end }} + {{- if $storage.s3.v4auth }} + v4auth: {{ $storage.s3.v4auth }} + {{- end }} + {{- if $storage.s3.chunksize }} + chunksize: {{ $storage.s3.chunksize }} + {{- end }} + {{- if $storage.s3.rootdirectory }} + rootdirectory: {{ $storage.s3.rootdirectory }} + {{- end }} + {{- if $storage.s3.storageclass }} + storageclass: {{ $storage.s3.storageclass }} + {{- end }} + {{- if $storage.s3.multipartcopychunksize }} + multipartcopychunksize: {{ $storage.s3.multipartcopychunksize }} + {{- end }} + {{- if $storage.s3.multipartcopymaxconcurrency }} + multipartcopymaxconcurrency: {{ $storage.s3.multipartcopymaxconcurrency }} + {{- end }} + {{- if $storage.s3.multipartcopythresholdsize }} + multipartcopythresholdsize: {{ $storage.s3.multipartcopythresholdsize }} + {{- end }} + {{- else if eq $type "swift" }} + swift: + authurl: {{ $storage.swift.authurl }} + username: {{ $storage.swift.username }} + container: {{ $storage.swift.container }} + {{- if $storage.swift.region }} + region: {{ $storage.swift.region }} + {{- end }} + {{- if $storage.swift.tenant }} + tenant: {{ $storage.swift.tenant }} + {{- end }} + {{- if $storage.swift.tenantid }} + tenantid: {{ $storage.swift.tenantid }} + {{- end }} + {{- if $storage.swift.domain }} + domain: {{ $storage.swift.domain }} + {{- end }} + {{- if $storage.swift.domainid }} + domainid: {{ $storage.swift.domainid }} + {{- end }} + {{- if $storage.swift.trustid }} + trustid: {{ $storage.swift.trustid }} + {{- end }} + {{- if $storage.swift.insecureskipverify }} + insecureskipverify: {{ $storage.swift.insecureskipverify }} + {{- end }} + {{- if $storage.swift.chunksize }} + chunksize: {{ $storage.swift.chunksize }} + {{- end }} + {{- if $storage.swift.prefix }} + prefix: {{ $storage.swift.prefix }} + {{- end }} + {{- if $storage.swift.authversion }} + authversion: {{ $storage.swift.authversion }} + {{- end }} + {{- if $storage.swift.endpointtype }} + endpointtype: {{ $storage.swift.endpointtype }} + {{- end }} + {{- if $storage.swift.tempurlcontainerkey }} + tempurlcontainerkey: {{ $storage.swift.tempurlcontainerkey }} + {{- end }} + {{- if $storage.swift.tempurlmethods }} + tempurlmethods: {{ $storage.swift.tempurlmethods }} + {{- end }} + {{- else if eq $type "oss" }} + oss: + accesskeyid: {{ $storage.oss.accesskeyid }} + region: {{ $storage.oss.region }} + bucket: {{ $storage.oss.bucket }} + {{- if $storage.oss.endpoint }} + endpoint: {{ $storage.oss.bucket }}.{{ $storage.oss.endpoint }} + {{- end }} + {{- if $storage.oss.internal }} + internal: {{ $storage.oss.internal }} + {{- end }} + {{- if $storage.oss.encrypt }} + encrypt: {{ $storage.oss.encrypt }} + {{- end }} + {{- if $storage.oss.secure }} + secure: {{ $storage.oss.secure }} + {{- end }} + {{- if $storage.oss.chunksize }} + chunksize: {{ $storage.oss.chunksize }} + {{- end }} + {{- if $storage.oss.rootdirectory }} + rootdirectory: {{ $storage.oss.rootdirectory }} + {{- end }} + {{- end }} + cache: + layerinfo: redis + maintenance: + uploadpurging: + {{- if .Values.registry.upload_purging.enabled }} + enabled: true + age: {{ .Values.registry.upload_purging.age }} + interval: {{ .Values.registry.upload_purging.interval }} + dryrun: {{ .Values.registry.upload_purging.dryrun }} + {{- else }} + enabled: false + {{- end }} + delete: + enabled: true + redirect: + disable: {{ $storage.disableredirect }} + redis: + addr: {{ template "harbor.redis.addr" . }} + {{- if eq "redis+sentinel" (include "harbor.redis.scheme" .) }} + sentinelMasterSet: {{ template "harbor.redis.masterSet" . }} + {{- end }} + db: {{ template "harbor.redis.dbForRegistry" . }} + {{- if not (eq (include "harbor.redis.password" .) "") }} + password: {{ template "harbor.redis.password" . }} + {{- end }} + readtimeout: 10s + writetimeout: 10s + dialtimeout: 10s + pool: + maxidle: 100 + maxactive: 500 + idletimeout: 60s + http: + addr: :{{ template "harbor.registry.containerPort" . }} + relativeurls: {{ .Values.registry.relativeurls }} + {{- if .Values.internalTLS.enabled }} + tls: + certificate: /etc/harbor/ssl/registry/tls.crt + key: /etc/harbor/ssl/registry/tls.key + minimumtls: tls1.2 + {{- end }} + # set via environment variable + # secret: placeholder + debug: + {{- if .Values.metrics.enabled}} + addr: :{{ .Values.metrics.registry.port }} + prometheus: + enabled: true + path: {{ .Values.metrics.registry.path }} + {{- else }} + addr: localhost:5001 + {{- end }} + auth: + htpasswd: + realm: harbor-registry-basic-realm + path: /etc/registry/passwd + validation: + disabled: true + compatibility: + schema1: + enabled: true + + {{- if .Values.registry.middleware.enabled }} + {{- $middleware := .Values.registry.middleware }} + {{- $middlewareType := $middleware.type }} + {{- if eq $middlewareType "cloudFront" }} + middleware: + storage: + - name: cloudfront + options: + baseurl: {{ $middleware.cloudFront.baseurl }} + privatekey: /etc/registry/pk.pem + keypairid: {{ $middleware.cloudFront.keypairid }} + duration: {{ $middleware.cloudFront.duration }} + ipfilteredby: {{ $middleware.cloudFront.ipfilteredby }} + {{- end }} + {{- end }} + ctl-config.yml: |+ + --- + {{- if .Values.internalTLS.enabled }} + protocol: "https" + port: 8443 + https_config: + cert: "/etc/harbor/ssl/registry/tls.crt" + key: "/etc/harbor/ssl/registry/tls.key" + {{- else }} + protocol: "http" + port: 8080 + {{- end }} + log_level: {{ .Values.logLevel }} + registry_config: "/etc/registry/config.yml" diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-dpl.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-dpl.yaml new file mode 100644 index 0000000000..0965cf2e2a --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-dpl.yaml @@ -0,0 +1,431 @@ +{{- $storage := .Values.persistence.imageChartStorage }} +{{- $type := $storage.type }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + replicas: {{ .Values.registry.replicas }} + revisionHistoryLimit: {{ .Values.registry.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: registry + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: registry + app.kubernetes.io/component: registry +{{- if .Values.registry.podLabels }} +{{ toYaml .Values.registry.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/registry/registry-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/registry/registry-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/registry/registry-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.registry.podAnnotations }} +{{ toYaml .Values.registry.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + fsGroupChangePolicy: OnRootMismatch +{{- if .Values.registry.serviceAccountName }} + serviceAccountName: {{ .Values.registry.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.registry.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.registry.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: registry +{{- end }} +{{- end }} + {{- with .Values.registry.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: registry + image: {{ .Values.registry.registry.image.repository }}:{{ .Values.registry.registry.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.registry.resources }} + resources: +{{ toYaml .Values.registry.registry.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + args: ["serve", "/etc/registry/config.yml"] + envFrom: + - secretRef: + name: "{{ template "harbor.registry" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.registry.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registry.containerPort" . }} + - containerPort: {{ ternary .Values.metrics.registry.port 5001 .Values.metrics.enabled }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-htpasswd + mountPath: /etc/registry/passwd + subPath: passwd + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + mountPath: /etc/registry/pk.pem + subPath: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + - name: registryctl + image: {{ .Values.registry.controller.image.repository }}:{{ .Values.registry.controller.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.controller.resources }} + resources: +{{ toYaml .Values.registry.controller.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.registryCtl" . }}" + - secretRef: + name: "{{ template "harbor.registry" . }}" + - secretRef: + name: "{{ template "harbor.registryCtl" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.controller.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registryctl.containerPort" . }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + - name: registry-config + mountPath: /etc/registryctl/config.yml + subPath: ctl-config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: registry-htpasswd + secret: + {{- if not .Values.registry.credentials.existingSecret }} + secretName: {{ template "harbor.registry" . }}-htpasswd + {{ else }} + secretName: {{ .Values.registry.credentials.existingSecret }} + {{- end }} + items: + - key: REGISTRY_HTPASSWD + path: passwd + - name: registry-config + configMap: + name: "{{ template "harbor.registry" . }}" + - name: registry-data + {{- if and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "filesystem") }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.registry.existingClaim | default (include "harbor.registry" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.registry.secretName" . }} + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + secret: + {{- if and (eq $type "gcs") $storage.gcs.existingSecret }} + secretName: {{ $storage.gcs.existingSecret }} + {{- else }} + secretName: {{ template "harbor.registry" . }} + {{- end }} + items: + - key: GCS_KEY_DATA + path: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + secret: + secretName: {{ .Values.persistence.imageChartStorage.caBundleSecretName }} + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + secret: + secretName: {{ .Values.registry.middleware.cloudFront.privateKeySecret }} + items: + - key: CLOUDFRONT_KEY_DATA + path: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.registry.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.registry.priorityClassName }} + priorityClassName: {{ .Values.registry.priorityClassName }} + {{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-pvc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-pvc.yaml new file mode 100644 index 0000000000..5d6d4d3ddf --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-pvc.yaml @@ -0,0 +1,33 @@ +{{- if .Values.persistence.enabled }} +{{- $registry := .Values.persistence.persistentVolumeClaim.registry -}} +{{- if and (not $registry.existingClaim) (eq .Values.persistence.imageChartStorage.type "filesystem") }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.registry" . }} + annotations: + {{- range $key, $value := $registry.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + accessModes: + - {{ $registry.accessMode }} + resources: + requests: + storage: {{ $registry.size }} + {{- if $registry.storageClass }} + {{- if eq "-" $registry.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $registry.storageClass }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-secret.yaml new file mode 100644 index 0000000000..e853a9cbec --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-secret.yaml @@ -0,0 +1,55 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.registry" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.registry.existingSecret }} + REGISTRY_HTTP_SECRET: {{ .Values.registry.secret | default (include "harbor.secretKeyHelper" (dict "key" "REGISTRY_HTTP_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.redis.external.existingSecret }} + REGISTRY_REDIS_PASSWORD: {{ include "harbor.redis.password" . | b64enc | quote }} + {{- end }} + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if and (eq $type "azure") (not $storage.azure.existingSecret) }} + REGISTRY_STORAGE_AZURE_ACCOUNTKEY: {{ $storage.azure.accountkey | b64enc | quote }} + {{- else if and (and (eq $type "gcs") (not $storage.gcs.existingSecret)) (not $storage.gcs.useWorkloadIdentity) }} + GCS_KEY_DATA: {{ $storage.gcs.encodedkey | quote }} + {{- else if eq $type "s3" }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.accesskey) }} + REGISTRY_STORAGE_S3_ACCESSKEY: {{ $storage.s3.accesskey | b64enc | quote }} + {{- end }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.secretkey) }} + REGISTRY_STORAGE_S3_SECRETKEY: {{ $storage.s3.secretkey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "swift") (not ($storage.swift.existingSecret)) }} + REGISTRY_STORAGE_SWIFT_PASSWORD: {{ $storage.swift.password | b64enc | quote }} + {{- if $storage.swift.secretkey }} + REGISTRY_STORAGE_SWIFT_SECRETKEY: {{ $storage.swift.secretkey | b64enc | quote }} + {{- end }} + {{- if $storage.swift.accesskey }} + REGISTRY_STORAGE_SWIFT_ACCESSKEY: {{ $storage.swift.accesskey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "oss") ((not ($storage.oss.existingSecret))) }} + REGISTRY_STORAGE_OSS_ACCESSKEYSECRET: {{ $storage.oss.accesskeysecret | b64enc | quote }} + {{- end }} +{{- if not .Values.registry.credentials.existingSecret }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}-htpasswd" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if .Values.registry.credentials.htpasswdString }} + REGISTRY_HTPASSWD: {{ .Values.registry.credentials.htpasswdString | b64enc | quote }} + {{- else }} + REGISTRY_HTPASSWD: {{ htpasswd .Values.registry.credentials.username .Values.registry.credentials.password | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-svc.yaml new file mode 100644 index 0000000000..749690ea03 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-svc.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.registry" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-registry" "http-registry" .Values.internalTLS.enabled }} + port: {{ template "harbor.registry.servicePort" . }} + + - name: {{ ternary "https-controller" "http-controller" .Values.internalTLS.enabled }} + port: {{ template "harbor.registryctl.servicePort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.registry.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: registry \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-tls.yaml new file mode 100644 index 0000000000..9d1862c417 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registry-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.registry.crt\" is required!" .Values.internalTLS.registry.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.registry.key\" is required!" .Values.internalTLS.registry.key) | b64enc | quote }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-cm.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-cm.yaml new file mode 100644 index 0000000000..87aa5ffe24 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-cm.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registryCtl" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- template "harbor.traceEnvsForRegistryCtl" . }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-secret.yaml new file mode 100644 index 0000000000..70097703e9 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/registry/registryctl-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registryCtl" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- template "harbor.traceJaegerPassword" . }} \ No newline at end of file diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-secret.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-secret.yaml new file mode 100644 index 0000000000..84652c7498 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.trivy.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.trivy" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + redisURL: {{ include "harbor.redis.urlForTrivy" . | b64enc }} + gitHubToken: {{ .Values.trivy.gitHubToken | default "" | b64enc | quote }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-sts.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-sts.yaml new file mode 100644 index 0000000000..c876ba3878 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-sts.yaml @@ -0,0 +1,230 @@ +{{- if .Values.trivy.enabled }} +{{- $trivy := .Values.persistence.persistentVolumeClaim.trivy }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.trivy" . }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: trivy + app.kubernetes.io/component: trivy +spec: + replicas: {{ .Values.trivy.replicas }} + serviceName: {{ template "harbor.trivy" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: trivy + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: trivy + app.kubernetes.io/component: trivy +{{- if .Values.trivy.podLabels }} +{{ toYaml .Values.trivy.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/trivy/trivy-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/trivy/trivy-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.trivy.podAnnotations }} +{{ toYaml .Values.trivy.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} +{{- end }} +{{- if .Values.trivy.serviceAccountName }} + serviceAccountName: {{ .Values.trivy.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + automountServiceAccountToken: {{ .Values.trivy.automountServiceAccountToken | default false }} +{{- with .Values.trivy.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: trivy +{{- end }} +{{- end }} + {{- with .Values.trivy.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: trivy + image: {{ .Values.trivy.image.repository }}:{{ .Values.trivy.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 12 }} + {{- end }} + env: + {{- if has "trivy" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + - name: "SCANNER_LOG_LEVEL" + value: {{ .Values.logLevel | quote }} + - name: "SCANNER_TRIVY_CACHE_DIR" + value: "/home/scanner/.cache/trivy" + - name: "SCANNER_TRIVY_REPORTS_DIR" + value: "/home/scanner/.cache/reports" + - name: "SCANNER_TRIVY_DEBUG_MODE" + value: {{ .Values.trivy.debugMode | quote }} + - name: "SCANNER_TRIVY_VULN_TYPE" + value: {{ .Values.trivy.vulnType | quote }} + - name: "SCANNER_TRIVY_TIMEOUT" + value: {{ .Values.trivy.timeout | quote }} + - name: "SCANNER_TRIVY_GITHUB_TOKEN" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: gitHubToken + - name: "SCANNER_TRIVY_SEVERITY" + value: {{ .Values.trivy.severity | quote }} + - name: "SCANNER_TRIVY_IGNORE_UNFIXED" + value: {{ .Values.trivy.ignoreUnfixed | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_UPDATE" + value: {{ .Values.trivy.skipUpdate | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_JAVA_DB_UPDATE" + value: {{ .Values.trivy.skipJavaDBUpdate | default false | quote }} + - name: "SCANNER_TRIVY_OFFLINE_SCAN" + value: {{ .Values.trivy.offlineScan | default false | quote }} + - name: "SCANNER_TRIVY_SECURITY_CHECKS" + value: {{ .Values.trivy.securityCheck | quote }} + - name: "SCANNER_TRIVY_INSECURE" + value: {{ .Values.trivy.insecure | default false | quote }} + - name: SCANNER_API_SERVER_ADDR + value: ":{{ template "harbor.trivy.containerPort" . }}" + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: SCANNER_API_SERVER_TLS_KEY + value: /etc/harbor/ssl/trivy/tls.key + - name: SCANNER_API_SERVER_TLS_CERTIFICATE + value: /etc/harbor/ssl/trivy/tls.crt + {{- end }} + - name: "SCANNER_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_STORE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_JOB_QUEUE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL +{{- with .Values.trivy.extraEnvVars }} +{{- toYaml . | nindent 12 }} +{{- end }} + ports: + - name: api-server + containerPort: {{ template "harbor.trivy.containerPort" . }} + volumeMounts: + - name: data + mountPath: /home/scanner/.cache + subPath: {{ .Values.persistence.persistentVolumeClaim.trivy.subPath }} + readOnly: false + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + mountPath: /etc/harbor/ssl/trivy + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 10 }} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/healthy + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 10 + readinessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/ready + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 3 + resources: +{{ toYaml .Values.trivy.resources | indent 12 }} + {{- if or (or .Values.internalTLS.enabled .Values.caBundleSecretName) (or (not .Values.persistence.enabled) $trivy.existingClaim) }} + volumes: + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.trivy.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- if not .Values.persistence.enabled }} + - name: "data" + emptyDir: {} + {{- else if $trivy.existingClaim }} + - name: "data" + persistentVolumeClaim: + claimName: {{ $trivy.existingClaim }} + {{- end }} + {{- end }} + {{- with .Values.trivy.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.trivy.priorityClassName }} + priorityClassName: {{ .Values.trivy.priorityClassName }} + {{- end }} +{{- if and .Values.persistence.enabled (not $trivy.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $trivy.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $trivy.accessMode | quote }}] + {{- if $trivy.storageClass }} + {{- if (eq "-" $trivy.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $trivy.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $trivy.size | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-svc.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-svc.yaml new file mode 100644 index 0000000000..24daf094e8 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-svc.yaml @@ -0,0 +1,16 @@ +{{ if .Values.trivy.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.trivy" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + ports: + - name: {{ ternary "https-trivy" "http-trivy" .Values.internalTLS.enabled }} + protocol: TCP + port: {{ template "harbor.trivy.servicePort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: trivy +{{ end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-tls.yaml b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-tls.yaml new file mode 100644 index 0000000000..a9c8330c37 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/templates/trivy/trivy-tls.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.trivy.enabled .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.trivy.crt\" is required!" .Values.internalTLS.trivy.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.trivy.key\" is required!" .Values.internalTLS.trivy.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/src/pkg/chart/testdata/harbor-schema2/values.yaml b/src/pkg/chart/testdata/harbor-schema2/values.yaml new file mode 100644 index 0000000000..529ec928b7 --- /dev/null +++ b/src/pkg/chart/testdata/harbor-schema2/values.yaml @@ -0,0 +1,1058 @@ +expose: + # Set how to expose the service. Set the type as "ingress", "clusterIP", "nodePort" or "loadBalancer" + # and fill the information in the corresponding section + type: ingress + tls: + # Enable TLS or not. + # Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress" + # Note: if the "expose.type" is "ingress" and TLS is disabled, + # the port must be included in the command when pulling/pushing images. + # Refer to https://github.com/goharbor/harbor/issues/5291 for details. + enabled: true + # The source of the tls certificate. Set as "auto", "secret" + # or "none" and fill the information in the corresponding section + # 1) auto: generate the tls certificate automatically + # 2) secret: read the tls certificate from the specified secret. + # The tls certificate can be generated manually or by cert manager + # 3) none: configure no tls certificate for the ingress. If the default + # tls certificate is configured in the ingress controller, choose this option + certSource: auto + auto: + # The common name used to generate the certificate, it's necessary + # when the type isn't "ingress" + commonName: "" + secret: + # The name of secret which contains keys named: + # "tls.crt" - the certificate + # "tls.key" - the private key + secretName: "" + ingress: + hosts: + core: core.harbor.domain + # set to the type of ingress controller if it has specific requirements. + # leave as `default` for most ingress controllers. + # set to `gce` if using the GCE ingress controller + # set to `ncp` if using the NCP (NSX-T Container Plugin) ingress controller + # set to `alb` if using the ALB ingress controller + # set to `f5-bigip` if using the F5 BIG-IP ingress controller + controller: default + ## Allow .Capabilities.KubeVersion.Version to be overridden while creating ingress + kubeVersionOverride: "" + className: "" + annotations: + # note different ingress controllers may require a different ssl-redirect annotation + # for Envoy, use ingress.kubernetes.io/force-ssl-redirect: "true" and remove the nginx lines below + ingress.kubernetes.io/ssl-redirect: "true" + ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + # ingress-specific labels + labels: {} + clusterIP: + # The name of ClusterIP service + name: harbor + # The ip address of the ClusterIP service (leave empty for acquiring dynamic ip) + staticClusterIP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the ClusterIP service + annotations: {} + # ClusterIP-specific labels + labels: {} + nodePort: + # The name of NodePort service + name: harbor + ports: + http: + # The service port Harbor listens on when serving HTTP + port: 80 + # The node port Harbor listens on when serving HTTP + nodePort: 30002 + https: + # The service port Harbor listens on when serving HTTPS + port: 443 + # The node port Harbor listens on when serving HTTPS + nodePort: 30003 + # Annotations on the nodePort service + annotations: {} + # nodePort-specific labels + labels: {} + loadBalancer: + # The name of LoadBalancer service + name: harbor + # Set the IP if the LoadBalancer supports assigning IP + IP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the loadBalancer service + annotations: {} + # loadBalancer-specific labels + labels: {} + sourceRanges: [] + +# The external URL for Harbor core service. It is used to +# 1) populate the docker/helm commands showed on portal +# 2) populate the token service URL returned to docker client +# +# Format: protocol://domain[:port]. Usually: +# 1) if "expose.type" is "ingress", the "domain" should be +# the value of "expose.ingress.hosts.core" +# 2) if "expose.type" is "clusterIP", the "domain" should be +# the value of "expose.clusterIP.name" +# 3) if "expose.type" is "nodePort", the "domain" should be +# the IP address of k8s node +# +# If Harbor is deployed behind the proxy, set it as the URL of proxy +externalURL: https://core.harbor.domain + +# The persistence is enabled by default and a default StorageClass +# is needed in the k8s cluster to provision volumes dynamically. +# Specify another StorageClass in the "storageClass" or set "existingClaim" +# if you already have existing persistent volumes to use +# +# For storing images and charts, you can also use "azure", "gcs", "s3", +# "swift" or "oss". Set it in the "imageChartStorage" section +persistence: + enabled: true + # Setting it to "keep" to avoid removing PVCs during a helm delete + # operation. Leaving it empty will delete PVCs after the chart deleted + # (this does not apply for PVCs that are created for internal database + # and redis components, i.e. they are never deleted automatically) + resourcePolicy: "keep" + persistentVolumeClaim: + registry: + # Use the existing PVC which must be created manually before bound, + # and specify the "subPath" if the PVC is shared with other components + existingClaim: "" + # Specify the "storageClass" used to provision the volume. Or the default + # StorageClass will be used (the default). + # Set it to "-" to disable dynamic provisioning + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + jobservice: + jobLog: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external database is used, the following settings for database will + # be ignored + database: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external Redis is used, the following settings for Redis will + # be ignored + redis: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + trivy: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + # Define which storage backend is used for registry to store + # images and charts. Refer to + # https://github.com/distribution/distribution/blob/main/docs/content/about/configuration.md#storage + # for the detail. + imageChartStorage: + # Specify whether to disable `redirect` for images and chart storage, for + # backends which not supported it (such as using minio for `s3` storage type), please disable + # it. To disable redirects, simply set `disableredirect` to `true` instead. + # Refer to + # https://github.com/distribution/distribution/blob/main/docs/configuration.md#redirect + # for the detail. + disableredirect: false + # Specify the "caBundleSecretName" if the storage service uses a self-signed certificate. + # The secret must contain keys named "ca.crt" which will be injected into the trust store + # of registry's containers. + # caBundleSecretName: + + # Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift", + # "oss" and fill the information needed in the corresponding section. The type + # must be "filesystem" if you want to use persistent volumes for registry + type: filesystem + filesystem: + rootdirectory: /storage + #maxthreads: 100 + azure: + accountname: accountname + accountkey: base64encodedaccountkey + container: containername + #realm: core.windows.net + # To use existing secret, the key must be AZURE_STORAGE_ACCESS_KEY + existingSecret: "" + gcs: + bucket: bucketname + # The base64 encoded json file which contains the key + encodedkey: base64-encoded-json-key-file + #rootdirectory: /gcs/object/name/prefix + #chunksize: "5242880" + # To use existing secret, the key must be GCS_KEY_DATA + existingSecret: "" + useWorkloadIdentity: false + s3: + # Set an existing secret for S3 accesskey and secretkey + # keys in the secret should be REGISTRY_STORAGE_S3_ACCESSKEY and REGISTRY_STORAGE_S3_SECRETKEY for registry + #existingSecret: "" + region: us-west-1 + bucket: bucketname + #accesskey: awsaccesskey + #secretkey: awssecretkey + #regionendpoint: http://myobjects.local + #encrypt: false + #keyid: mykeyid + #secure: true + #skipverify: false + #v4auth: true + #chunksize: "5242880" + #rootdirectory: /s3/object/name/prefix + #storageclass: STANDARD + #multipartcopychunksize: "33554432" + #multipartcopymaxconcurrency: 100 + #multipartcopythresholdsize: "33554432" + swift: + authurl: https://storage.myprovider.com/v3/auth + username: username + password: password + container: containername + # keys in existing secret must be REGISTRY_STORAGE_SWIFT_PASSWORD, REGISTRY_STORAGE_SWIFT_SECRETKEY, REGISTRY_STORAGE_SWIFT_ACCESSKEY + existingSecret: "" + #region: fr + #tenant: tenantname + #tenantid: tenantid + #domain: domainname + #domainid: domainid + #trustid: trustid + #insecureskipverify: false + #chunksize: 5M + #prefix: + #secretkey: secretkey + #accesskey: accesskey + #authversion: 3 + #endpointtype: public + #tempurlcontainerkey: false + #tempurlmethods: + oss: + accesskeyid: accesskeyid + accesskeysecret: accesskeysecret + region: regionname + bucket: bucketname + # key in existingSecret must be REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + existingSecret: "" + #endpoint: endpoint + #internal: false + #encrypt: false + #secure: true + #chunksize: 10M + #rootdirectory: rootdirectory + +# The initial password of Harbor admin. Change it from portal after launching Harbor +# or give an existing secret for it +# key in secret is given via (default to HARBOR_ADMIN_PASSWORD) +# existingSecretAdminPassword: +existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD +harborAdminPassword: "Harbor12345" + +# The internal TLS used for harbor components secure communicating. In order to enable https +# in each component tls cert files need to provided in advance. +internalTLS: + # If internal TLS enabled + enabled: false + # enable strong ssl ciphers (default: false) + strong_ssl_ciphers: false + # There are three ways to provide tls + # 1) "auto" will generate cert automatically + # 2) "manual" need provide cert file manually in following value + # 3) "secret" internal certificates from secret + certSource: "auto" + # The content of trust ca, only available when `certSource` is "manual" + trustCa: "" + # core related cert configuration + core: + # secret name for core's tls certs + secretName: "" + # Content of core's TLS cert file, only available when `certSource` is "manual" + crt: "" + # Content of core's TLS key file, only available when `certSource` is "manual" + key: "" + # jobservice related cert configuration + jobservice: + # secret name for jobservice's tls certs + secretName: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + key: "" + # registry related cert configuration + registry: + # secret name for registry's tls certs + secretName: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + key: "" + # portal related cert configuration + portal: + # secret name for portal's tls certs + secretName: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + key: "" + # trivy related cert configuration + trivy: + # secret name for trivy's tls certs + secretName: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + key: "" + +ipFamily: + # ipv6Enabled set to true if ipv6 is enabled in cluster, currently it affected the nginx related component + ipv6: + enabled: true + # ipv4Enabled set to true if ipv4 is enabled in cluster, currently it affected the nginx related component + ipv4: + enabled: true + +imagePullPolicy: IfNotPresent + +# Use this set to assign a list of default pullSecrets +imagePullSecrets: +# - name: docker-registry-secret +# - name: internal-registry-secret + +# The update strategy for deployments with persistent volumes(jobservice, registry): "RollingUpdate" or "Recreate" +# Set it as "Recreate" when "RWM" for volumes isn't supported +updateStrategy: + type: RollingUpdate + +# debug, info, warning, error or fatal +logLevel: info + +# The name of the secret which contains key named "ca.crt". Setting this enables the +# download link on portal to download the CA certificate when the certificate isn't +# generated automatically +caSecretName: "" + +# The secret key used for encryption. Must be a string of 16 chars. +secretKey: "not-a-secure-key" +# If using existingSecretSecretKey, the key must be secretKey +existingSecretSecretKey: "" + +# The proxy settings for updating trivy vulnerabilities from the Internet and replicating +# artifacts from/to the registries that cannot be reached directly +proxy: + httpProxy: + httpsProxy: + noProxy: 127.0.0.1,localhost,.local,.internal + components: + - core + - jobservice + - trivy + +# Run the migration job via helm hook +enableMigrateHelmHook: false + +# The custom ca bundle secret, the secret must contain key named "ca.crt" +# which will be injected into the trust store for core, jobservice, registry, trivy components +# caBundleSecretName: "" + +## UAA Authentication Options +# If you're using UAA for authentication behind a self-signed +# certificate you will need to provide the CA Cert. +# Set uaaSecretName below to provide a pre-created secret that +# contains a base64 encoded CA Certificate named `ca.crt`. +# uaaSecretName: + +metrics: + enabled: false + core: + path: /metrics + port: 8001 + registry: + path: /metrics + port: 8001 + jobservice: + path: /metrics + port: 8001 + exporter: + path: /metrics + port: 8001 + ## Create prometheus serviceMonitor to scrape harbor metrics. + ## This requires the monitoring.coreos.com/v1 CRD. Please see + ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md + ## + serviceMonitor: + enabled: false + additionalLabels: {} + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: "" + # Metric relabel configs to apply to samples before ingestion. + metricRelabelings: + [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + # Relabel configs to apply to samples before ingestion. + relabelings: + [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + +trace: + enabled: false + # trace provider: jaeger or otel + # jaeger should be 1.26+ + provider: jaeger + # set sample_rate to 1 if you wanna sampling 100% of trace data; set 0.5 if you wanna sampling 50% of trace data, and so forth + sample_rate: 1 + # namespace used to differentiate different harbor services + # namespace: + # attributes is a key value dict contains user defined attributes used to initialize trace provider + # attributes: + # application: harbor + jaeger: + # jaeger supports two modes: + # collector mode(uncomment endpoint and uncomment username, password if needed) + # agent mode(uncomment agent_host and agent_port) + endpoint: http://hostname:14268/api/traces + # username: + # password: + # agent_host: hostname + # export trace data by jaeger.thrift in compact mode + # agent_port: 6831 + otel: + endpoint: hostname:4318 + url_path: /v1/traces + compression: false + insecure: true + # timeout is in seconds + timeout: 10 + +# cache layer configurations +# if this feature enabled, harbor will cache the resource +# `project/project_metadata/repository/artifact/manifest` in the redis +# which help to improve the performance of high concurrent pulling manifest. +cache: + # default is not enabled. + enabled: false + # default keep cache for one day. + expireHours: 24 + +## set Container Security Context to comply with PSP restricted policy if necessary +## each of the conatiner will apply the same security context +## containerSecurityContext:{} is initially an empty yaml that you could edit it on demand, we just filled with a common template for convenience +containerSecurityContext: + privileged: false + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + +# If service exposed via "ingress", the Nginx will not be used +nginx: + image: + repository: goharbor/nginx-photon + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + +portal: + image: + repository: goharbor/harbor-portal + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + +core: + image: + repository: goharbor/harbor-core + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + ## Startup probe values + startupProbe: + enabled: true + initialDelaySeconds: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + ## User settings configuration json string + configureUserSettings: + # The provider for updating project quota(usage), there are 2 options, redis or db. + # By default it is implemented by db but you can configure it to redis which + # can improve the performance of high concurrent pushing to the same project, + # and reduce the database connections spike and occupies. + # Using redis will bring up some delay for quota usage updation for display, so only + # suggest switch provider to redis if you were ran into the db connections spike around + # the scenario of high concurrent pushing to same project, no improvment for other scenes. + quotaUpdateProvider: db # Or redis + # Secret is used when core server communicates with other components. + # If a secret key is not specified, Helm will generate one. Alternatively set existingSecret to use an existing secret + # Must be a string of 16 chars. + secret: "" + # Fill in the name of a kubernetes secret if you want to use your own + # If using existingSecret, the key must be secret + existingSecret: "" + # Fill the name of a kubernetes secret if you want to use your own + # TLS certificate and private key for token encryption/decryption. + # The secret must contain keys named: + # "tls.key" - the private key + # "tls.crt" - the certificate + secretName: "" + # If not specifying a preexisting secret, a secret can be created from tokenKey and tokenCert and used instead. + # If none of secretName, tokenKey, and tokenCert are specified, an ephemeral key and certificate will be autogenerated. + # tokenKey and tokenCert must BOTH be set or BOTH unset. + # The tokenKey value is formatted as a multiline string containing a PEM-encoded RSA key, indented one more than tokenKey on the following line. + tokenKey: | + # If tokenKey is set, the value of tokenCert must be set as a PEM-encoded certificate signed by tokenKey, and supplied as a multiline string, indented one more than tokenCert on the following line. + tokenCert: | + # The XSRF key. Will be generated automatically if it isn't specified + xsrfKey: "" + # If using existingSecret, the key is defined by core.existingXsrfSecretKey + existingXsrfSecret: "" + # If using existingSecret, the key + existingXsrfSecretKey: CSRF_KEY + # The time duration for async update artifact pull_time and repository + # pull_count, the unit is second. Will be 10 seconds if it isn't set. + # eg. artifactPullAsyncFlushDuration: 10 + artifactPullAsyncFlushDuration: + gdpr: + deleteUser: false + auditLogsCompliant: false + +jobservice: + image: + repository: goharbor/harbor-jobservice + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + maxJobWorkers: 10 + # The logger for jobs: "file", "database" or "stdout" + jobLoggers: + - file + # - database + # - stdout + # The jobLogger sweeper duration (ignored if `jobLogger` is `stdout`) + loggerSweeperDuration: 14 #days + notification: + webhook_job_max_retry: 3 + webhook_job_http_client_timeout: 3 # in seconds + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: 24 + # the max time for execution in running state without new task created + max_dangling_hours: 168 + # Secret is used when job service communicates with other components. + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the job service secret + existingSecretKey: JOBSERVICE_SECRET + +registry: + registry: + image: + repository: goharbor/registry-photon + tag: v2.11.0 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + controller: + image: + repository: goharbor/harbor-registryctl + tag: v2.11.0 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # Secret is used to secure the upload state from client + # and registry storage backend. + # See: https://github.com/distribution/distribution/blob/main/docs/configuration.md#http + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the registry service secret + existingSecretKey: REGISTRY_HTTP_SECRET + # If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. + relativeurls: false + credentials: + username: "harbor_registry_user" + password: "harbor_registry_password" + # If using existingSecret, the key must be REGISTRY_PASSWD and REGISTRY_HTPASSWD + existingSecret: "" + # Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. + # htpasswdString: $apr1$XLefHzeG$Xl4.s00sMSCCcMyJljSZb0 # example string + htpasswdString: "" + middleware: + enabled: false + type: cloudFront + cloudFront: + baseurl: example.cloudfront.net + keypairid: KEYPAIRID + duration: 3000s + ipfilteredby: none + # The secret key that should be present is CLOUDFRONT_KEY_DATA, which should be the encoded private key + # that allows access to CloudFront + privateKeySecret: "my-secret" + # enable purge _upload directories + upload_purging: + enabled: true + # remove files in _upload directories which exist for a period of time, default is one week. + age: 168h + # the interval of the purge operations + interval: 24h + dryrun: false + +trivy: + # enabled the flag to enable Trivy scanner + enabled: true + image: + # repository the repository for Trivy adapter image + repository: goharbor/trivy-adapter-photon + # tag the tag for Trivy adapter image + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # replicas the number of Pod replicas + replicas: 1 + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 1 + memory: 1Gi + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # debugMode the flag to enable Trivy debug mode with more verbose scanning log + debugMode: false + # vulnType a comma-separated list of vulnerability types. Possible values are `os` and `library`. + vulnType: "os,library" + # severity a comma-separated list of severities to be checked + severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" + # ignoreUnfixed the flag to display only fixed vulnerabilities + ignoreUnfixed: false + # insecure the flag to skip verifying registry certificate + insecure: false + # gitHubToken the GitHub access token to download Trivy DB + # + # Trivy DB contains vulnerability information from NVD, Red Hat, and many other upstream vulnerability databases. + # It is downloaded by Trivy from the GitHub release page https://github.com/aquasecurity/trivy-db/releases and cached + # in the local file system (`/home/scanner/.cache/trivy/db/trivy.db`). In addition, the database contains the update + # timestamp so Trivy can detect whether it should download a newer version from the Internet or use the cached one. + # Currently, the database is updated every 12 hours and published as a new release to GitHub. + # + # Anonymous downloads from GitHub are subject to the limit of 60 requests per hour. Normally such rate limit is enough + # for production operations. If, for any reason, it's not enough, you could increase the rate limit to 5000 + # requests per hour by specifying the GitHub access token. For more details on GitHub rate limiting please consult + # https://developer.github.com/v3/#rate-limiting + # + # You can create a GitHub token by following the instructions in + # https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line + gitHubToken: "" + # skipUpdate the flag to disable Trivy DB downloads from GitHub + # + # You might want to set the value of this flag to `true` in test or CI/CD environments to avoid GitHub rate limiting issues. + # If the value is set to `true` you have to manually download the `trivy.db` file and mount it in the + # `/home/scanner/.cache/trivy/db/trivy.db` path. + skipUpdate: false + # skipJavaDBUpdate If the flag is enabled you have to manually download the `trivy-java.db` file and mount it in the + # `/home/scanner/.cache/trivy/java-db/trivy-java.db` path + # + skipJavaDBUpdate: false + # The offlineScan option prevents Trivy from sending API requests to identify dependencies. + # + # Scanning JAR files and pom.xml may require Internet access for better detection, but this option tries to avoid it. + # For example, the offline mode will not try to resolve transitive dependencies in pom.xml when the dependency doesn't + # exist in the local repositories. It means a number of detected vulnerabilities might be fewer in offline mode. + # It would work if all the dependencies are in local. + # This option doesn’t affect DB download. You need to specify skipUpdate as well as offlineScan in an air-gapped environment. + offlineScan: false + # Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. Defaults to `vuln`. + securityCheck: "vuln" + # The duration to wait for scan completion + timeout: 5m0s + +database: + # if external database is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/harbor-db + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + # The timeout used in livenessProbe; 1 to 5 seconds + livenessProbe: + timeoutSeconds: 1 + # The timeout used in readinessProbe; 1 to 5 seconds + readinessProbe: + timeoutSeconds: 1 + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + extrInitContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # The initial superuser password for internal database + password: "changeit" + # The size limit for Shared memory, pgSQL use it for shared_buffer + # More details see: + # https://github.com/goharbor/harbor/issues/15034 + shmSizeLimit: 512Mi + initContainer: + migrator: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + permissions: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + external: + host: "192.168.0.1" + port: "5432" + username: "user" + password: "password" + coreDatabase: "registry" + # if using existing secret, the key must be "password" + existingSecret: "" + # "disable" - No SSL + # "require" - Always SSL (skip verification) + # "verify-ca" - Always SSL (verify that the certificate presented by the + # server was signed by a trusted CA) + # "verify-full" - Always SSL (verify that the certification presented by the + # server was signed by a trusted CA and the server host name matches the one + # in the certificate) + sslmode: "disable" + # The maximum number of connections in the idle connection pool per pod (core+exporter). + # If it <=0, no idle connections are retained. + maxIdleConns: 100 + # The maximum number of open connections to the database per pod (core+exporter). + # If it <= 0, then there is no limit on the number of open connections. + # Note: the default number of connections is 1024 for harbor's postgres. + maxOpenConns: 900 + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +redis: + # if external Redis is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/redis-photon + tag: v2.11.0 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # # jobserviceDatabaseIndex defaults to "1" + # # registryDatabaseIndex defaults to "2" + # # trivyAdapterIndex defaults to "5" + # # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + external: + # support redis, redis+sentinel + # addr for redis: : + # addr for redis+sentinel: :,:,: + addr: "192.168.0.2:6379" + # The name of the set of Redis instances to monitor, it must be set to support redis+sentinel + sentinelMasterSet: "" + # The "coreDatabaseIndex" must be "0" as the library Harbor + # used doesn't support configuring it + # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + coreDatabaseIndex: "0" + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + # username field can be an empty string, and it will be authenticated against the default user + username: "" + password: "" + # If using existingSecret, the key must be REDIS_PASSWORD + existingSecret: "" + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +exporter: + image: + repository: goharbor/harbor-exporter + tag: v2.11.0 + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + ## The priority class to run the pod as + priorityClassName: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + cacheDuration: 23 + cacheCleanInterval: 14400 From 0eb75053261085eb4e7dd826616a9c6bb0d4e57a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:46:45 +0800 Subject: [PATCH 19/74] chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.26.0 to 1.27.0 in /src (#20653) chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.26.0...v1.27.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 31 +++++++++++++++---------------- src/go.sum | 52 ++++++++++++++++++++++++---------------------------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/src/go.mod b/src/go.mod index d5c31c4292..3e571a7689 100644 --- a/src/go.mod +++ b/src/go.mod @@ -21,12 +21,12 @@ require ( github.com/go-asn1-ber/asn1-ber v1.5.7 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/errors v0.22.0 - github.com/go-openapi/loads v0.21.2 + github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/runtime v0.26.2 - github.com/go-openapi/spec v0.20.11 + github.com/go-openapi/spec v0.20.11 // indirect github.com/go-openapi/strfmt v0.23.0 github.com/go-openapi/swag v0.23.0 - github.com/go-openapi/validate v0.22.3 + github.com/go-openapi/validate v0.22.3 // indirect github.com/go-redis/redis/v8 v8.11.4 github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 github.com/gocraft/work v0.5.1 @@ -56,16 +56,16 @@ require ( github.com/vmihailenco/msgpack/v5 v5.4.1 github.com/volcengine/volcengine-go-sdk v1.0.138 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/exporters/jaeger v1.0.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 - go.opentelemetry.io/otel/sdk v1.26.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 + go.opentelemetry.io/otel/sdk v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/ratelimit v0.3.1 golang.org/x/crypto v0.24.0 golang.org/x/net v0.26.0 - golang.org/x/oauth2 v0.19.0 + golang.org/x/oauth2 v0.20.0 golang.org/x/sync v0.7.0 golang.org/x/text v0.16.0 golang.org/x/time v0.5.0 @@ -79,8 +79,7 @@ require ( ) require ( - cloud.google.com/go/compute v1.24.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect github.com/Azure/azure-sdk-for-go v37.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect @@ -118,7 +117,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -165,7 +164,7 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/volcengine/volc-sdk-golang v1.0.23 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect @@ -173,12 +172,12 @@ require ( go.uber.org/zap v1.19.1 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect - google.golang.org/api v0.162.0 // indirect + google.golang.org/api v0.169.0 // indirect google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/src/go.sum b/src/go.sum index 40895035fa..167901c2b5 100644 --- a/src/go.sum +++ b/src/go.sum @@ -5,10 +5,8 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -313,8 +311,8 @@ github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pw github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -552,8 +550,8 @@ 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/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -644,22 +642,22 @@ go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGc go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0 h1:rXpHmgy1pMXlfv3W1T5ctoDA3QeTFjNq/YwCmwrfr8Q= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0/go.mod h1:9uIRD3NZrM7QMQEGeKhr7V4xSDTMku3MPOVs8iZ3VVk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= go.opentelemetry.io/otel/exporters/jaeger v1.0.0 h1:cLhx8llHw02h5JTqGqaRbYn+QVKHmrzD9vEbKnSPk5U= go.opentelemetry.io/otel/exporters/jaeger v1.0.0/go.mod h1:q10N1AolE1JjqKrFJK2tYw0iZpmX+HBaXBtuCzRnBGQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 h1:1u/AyyOqAWzy+SkPxDpahCNZParHV8Vid1RnI2clyDE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0/go.mod h1:z46paqbJ9l7c9fIPCXTqTGwhQZ5XoTIsfeFYWboizjs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM= -go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= -go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= @@ -764,8 +762,8 @@ golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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= @@ -896,12 +894,10 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -910,8 +906,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= 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= @@ -923,8 +919,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= From 707c35c76ef3aededb53273eb5c30bc72d779aed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:25:46 +0800 Subject: [PATCH 20/74] chore(deps): bump k8s.io/api from 0.30.0 to 0.30.2 in /src (#20655) Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.30.0 to 0.30.2. - [Commits](https://github.com/kubernetes/api/compare/v0.30.0...v0.30.2) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 4 ++-- src/go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/go.mod b/src/go.mod index 3e571a7689..aab5cd0c55 100644 --- a/src/go.mod +++ b/src/go.mod @@ -72,8 +72,8 @@ require ( gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 helm.sh/helm/v3 v3.15.2 - k8s.io/api v0.30.0 - k8s.io/apimachinery v0.30.0 + k8s.io/api v0.30.2 + k8s.io/apimachinery v0.30.2 k8s.io/client-go v0.30.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/src/go.sum b/src/go.sum index 167901c2b5..bd132ffa4a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -962,10 +962,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= -k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE= -k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA= -k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= +k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= +k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= +k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ= k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= From 27e06ac6099d5da4421b2e1b1b0a24985c2a1392 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:01:50 +0800 Subject: [PATCH 21/74] chore(deps): bump github.com/google/go-containerregistry from 0.19.0 to 0.19.2 in /src (#20656) chore(deps): bump github.com/google/go-containerregistry in /src Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.19.0 to 0.19.2. - [Release notes](https://github.com/google/go-containerregistry/releases) - [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml) - [Commits](https://github.com/google/go-containerregistry/compare/v0.19.0...v0.19.2) --- updated-dependencies: - dependency-name: github.com/google/go-containerregistry dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 2 +- src/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go.mod b/src/go.mod index aab5cd0c55..9132e67d1e 100644 --- a/src/go.mod +++ b/src/go.mod @@ -33,7 +33,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang-migrate/migrate/v4 v4.17.1 github.com/gomodule/redigo v2.0.0+incompatible - github.com/google/go-containerregistry v0.19.0 + github.com/google/go-containerregistry v0.19.2 github.com/google/uuid v1.6.0 github.com/gorilla/csrf v1.7.2 github.com/gorilla/handlers v1.5.2 diff --git a/src/go.sum b/src/go.sum index bd132ffa4a..8e965a77d7 100644 --- a/src/go.sum +++ b/src/go.sum @@ -281,8 +281,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= -github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= +github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From cc1acc389008d31a8166a89c97ed4829d9482d1f Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah <69568555+mohamedawnallah@users.noreply.github.com> Date: Thu, 4 Jul 2024 06:30:03 +0300 Subject: [PATCH 22/74] JobService: fix for missing log data in jobservice DB logging (#20684) * 20548 MISSING CONDITION FOR RETURNING LOG DATA As per bug 20548, if DB logging is enabled for jobservice and the parameter is also set for maximum log size the log data is not being returned and 'Clean Up->Show GC Logs' shows a blank page Signed-off-by: Mohamed Awnallah Co-authored-by: Nick Hindley * db_getter_test.go: test fix for missing log data in jobservice DB logging Signed-off-by: Mohamed Awnallah --------- Signed-off-by: Mohamed Awnallah Co-authored-by: Nick Hindley Co-authored-by: Shengwen YU --- src/jobservice/logger/getter/db_getter.go | 2 +- src/jobservice/logger/getter/db_getter_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jobservice/logger/getter/db_getter.go b/src/jobservice/logger/getter/db_getter.go index 1d98170abc..ba96b9905b 100644 --- a/src/jobservice/logger/getter/db_getter.go +++ b/src/jobservice/logger/getter/db_getter.go @@ -47,7 +47,7 @@ func (dbg *DBGetter) Retrieve(logID string) ([]byte, error) { sz := int64(len(jobLog.Content)) var buf []byte sizeLimit := logSizeLimit() - if sizeLimit <= 0 { + if sizeLimit <= 0 || sz <= sizeLimit { buf = []byte(jobLog.Content) return buf, nil } diff --git a/src/jobservice/logger/getter/db_getter_test.go b/src/jobservice/logger/getter/db_getter_test.go index ef69630317..0faccca8de 100644 --- a/src/jobservice/logger/getter/db_getter_test.go +++ b/src/jobservice/logger/getter/db_getter_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/goharbor/harbor/src/common/dao" + "github.com/goharbor/harbor/src/jobservice/config" "github.com/goharbor/harbor/src/jobservice/logger/backend" "github.com/goharbor/harbor/src/jobservice/logger/sweeper" "github.com/goharbor/harbor/src/lib/log" @@ -44,9 +45,11 @@ func TestDBGetter(t *testing.T) { err = l.Close() require.NoError(t, err) + _ = config.DefaultConfig.Load("../../config_test.yml", true) dbGetter := NewDBGetter() ll, err := dbGetter.Retrieve(uuid) require.Nil(t, err) + require.NotEqual(t, 0, len(ll)) log.Infof("get logger %s", ll) err = sweeper.PrepareDBSweep() From f86f1cebc3a1af8c5c14c0a94d687fff04ebc6eb Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Thu, 4 Jul 2024 15:42:12 +0800 Subject: [PATCH 23/74] Change the log message when PostScan failed. (#20650) fixes #20573 remove s from additions/sboms in the link Signed-off-by: stonezdj --- src/controller/artifact/model.go | 3 ++- src/pkg/scan/job.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controller/artifact/model.go b/src/controller/artifact/model.go index 0953fd0690..6bf731dd75 100644 --- a/src/controller/artifact/model.go +++ b/src/controller/artifact/model.go @@ -80,6 +80,7 @@ func (artifact *Artifact) SetAdditionLink(addition, version string) { artifact.AdditionLinks[addition] = &AdditionLink{HREF: href, Absolute: false} } +// SetSBOMAdditionLink set the link of SBOM addition func (artifact *Artifact) SetSBOMAdditionLink(sbomDgst string, version string) { if artifact.AdditionLinks == nil { artifact.AdditionLinks = make(map[string]*AdditionLink) @@ -88,7 +89,7 @@ func (artifact *Artifact) SetSBOMAdditionLink(sbomDgst string, version string) { projectName, repo := utils.ParseRepository(artifact.RepositoryName) // encode slash as %252F repo = repository.Encode(repo) - href := fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/%s", version, projectName, repo, sbomDgst, addition) + href := fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/sbom", version, projectName, repo, sbomDgst) artifact.AdditionLinks[addition] = &AdditionLink{HREF: href, Absolute: false} } diff --git a/src/pkg/scan/job.go b/src/pkg/scan/job.go index f0db850e62..e485a143dd 100644 --- a/src/pkg/scan/job.go +++ b/src/pkg/scan/job.go @@ -304,7 +304,7 @@ func (j *Job) Run(ctx job.Context, params job.Parameters) error { reportData, err := handler.PostScan(ctx, req, rp, rawReports[i], startTime, robotAccount) if err != nil { - myLogger.Errorf("Failed to convert vulnerability data to new schema for report %s, error %v", rp.UUID, err) + myLogger.Errorf("handler failed at PostScan, report %s, error %v", rp.UUID, err) return err } From 0da13ebd28d702e35751860327b8dec38a313ad0 Mon Sep 17 00:00:00 2001 From: Wang Yan Date: Thu, 11 Jul 2024 15:08:49 +0800 Subject: [PATCH 24/74] update ldap (#20724) update openldap image and tls settings Signed-off-by: wang yan --- tests/ldapprepare.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ldapprepare.sh b/tests/ldapprepare.sh index 3bc22a1837..cd1418a503 100755 --- a/tests/ldapprepare.sh +++ b/tests/ldapprepare.sh @@ -6,9 +6,11 @@ docker run --env LDAP_ORGANISATION="Harbor." \ --env LDAP_DOMAIN="example.com" \ --env LDAP_ADMIN_PASSWORD="admin" \ --env LDAP_TLS_VERIFY_CLIENT="never" \ +--env LDAP_TLS_PROTOCOL_MIN=3.0 \ +--env LDAP_TLS_CIPHER_SUITE="normal" \ -p 389:389 \ -p 636:636 \ ---detach --name $NAME osixia/openldap:1.1.7 +--detach --name $NAME osixia/openldap:1.5.0 sleep 5 docker cp ldap_test.ldif ldap_server:/ From 753c7651012e1501136183480cf9c0858968e30c Mon Sep 17 00:00:00 2001 From: Shengwen YU Date: Mon, 15 Jul 2024 16:51:12 +0800 Subject: [PATCH 25/74] fix: add quote to dockerhub cred (#20693) Signed-off-by: Shengwen Yu Co-authored-by: Wang Yan --- .github/workflows/publish_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index 7ba4df99c2..a399aa45f3 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -60,7 +60,7 @@ jobs: docker load -i ./harbor/harbor.${{ env.BASE_TAG }}.tar.gz images="$(docker images --format "{{.Repository}}" --filter=reference='goharbor/*:${{ env.BASE_TAG }}' | xargs)" source tools/release/release_utils.sh - publishImages ${{ env.CUR_TAG }} ${{ env.BASE_TAG }} ${{ secrets.DOCKER_HUB_USERNAME }} ${{ secrets.DOCKER_HUB_PASSWORD }} $images + publishImages ${{ env.CUR_TAG }} ${{ env.BASE_TAG }} "${{ secrets.DOCKER_HUB_USERNAME }}" "${{ secrets.DOCKER_HUB_PASSWORD }}" $images publishPackages ${{ env.CUR_TAG }} ${{ env.BASE_TAG }} ${{ github.actor }} ${{ secrets.GITHUB_TOKEN }} $images - name: Generate release notes run: | From 64df11bcf1a3bedaf48aec40c848fcc75456c1f6 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Wed, 17 Jul 2024 17:56:17 +0800 Subject: [PATCH 26/74] feat: bump mockery and switch to generate by config file (#20742) The packages feature in mockery is the new way for managing mocks, and will be the only way to generate mocks in v3. see https://vektra.github.io/mockery/v2.43/migrating_to_packages/. 1. Bump mockery to v2.43.2. 2. Switch the generation from old way to configuration yaml. Signed-off-by: chlins --- CONTRIBUTING.md | 2 +- Makefile | 6 +- src/.mockery.yaml | 524 ++++++++++++++++++ src/controller/replication/flow/mock.go | 3 - .../flow/mock_adapter_factory_test.go | 2 +- .../replication/flow/mock_adapter_test.go | 2 +- src/controller/replication/mock.go | 17 - .../replication/mock_flow_controller_test.go | 2 +- src/jobservice/mgt/mock.go | 17 - src/jobservice/mgt/mock_manager.go | 3 +- src/jobservice/period/mock.go | 17 - src/jobservice/period/mock_scheduler.go | 2 +- src/lib/cache/cache.go | 2 - src/lib/cache/mock_cache_test.go | 2 +- src/pkg/scheduler/mock.go | 17 - src/pkg/scheduler/mock_dao_test.go | 2 +- src/pkg/task/mock.go | 21 - src/pkg/task/mock_execution_dao_test.go | 2 +- src/pkg/task/mock_jobservice_client_test.go | 2 +- src/pkg/task/mock_sweep_manager_test.go | 2 +- src/pkg/task/mock_task_dao_test.go | 2 +- src/pkg/task/mock_task_manager_test.go | 2 +- src/testing/common/common.go | 17 - src/testing/common/security/context.go | 2 +- src/testing/controller/artifact/controller.go | 2 +- src/testing/controller/blob/controller.go | 2 +- src/testing/controller/config/controller.go | 2 +- src/testing/controller/controller.go | 38 -- .../jobservice/scheduler_controller.go | 2 +- src/testing/controller/project/controller.go | 2 +- .../controller/proxy/remote_interface.go | 2 +- src/testing/controller/purge/controller.go | 2 +- src/testing/controller/quota/controller.go | 2 +- .../controller/replication/controller.go | 2 +- .../controller/repository/controller.go | 2 +- .../controller/retention/controller.go | 2 +- src/testing/controller/robot/controller.go | 2 +- src/testing/controller/scan/checker.go | 2 +- src/testing/controller/scan/controller.go | 2 +- .../controller/scandataexport/controller.go | 2 +- src/testing/controller/scanner/controller.go | 2 +- .../controller/securityhub/controller.go | 2 +- .../controller/systemartifact/controller.go | 2 +- src/testing/controller/task/controller.go | 2 +- .../controller/task/execution_controller.go | 2 +- src/testing/controller/user/controller.go | 2 +- src/testing/controller/webhook/controller.go | 2 +- src/testing/lib/cache/cache.go | 2 +- src/testing/lib/cache/iterator.go | 2 +- src/testing/lib/config/manager.go | 2 +- src/testing/lib/lib.go | 20 - src/testing/lib/orm/creator.go | 2 +- src/testing/pkg/accessory/dao/dao.go | 2 +- src/testing/pkg/accessory/manager.go | 2 +- src/testing/pkg/accessory/model/accessory.go | 2 +- src/testing/pkg/allowlist/dao/dao.go | 2 +- src/testing/pkg/allowlist/manager.go | 4 +- src/testing/pkg/artifact/manager.go | 2 +- src/testing/pkg/audit/dao/dao.go | 2 +- src/testing/pkg/audit/manager.go | 2 +- src/testing/pkg/blob/manager.go | 2 +- .../cached/manifest/redis/cached_manager.go | 2 +- src/testing/pkg/immutable/dao/dao.go | 2 +- src/testing/pkg/joblog/dao/dao.go | 2 +- src/testing/pkg/joblog/manager.go | 2 +- .../jobmonitor/job_service_monitor_client.go | 2 +- src/testing/pkg/jobmonitor/pool_manager.go | 2 +- src/testing/pkg/jobmonitor/queue_manager.go | 2 +- src/testing/pkg/jobmonitor/redis_client.go | 2 +- src/testing/pkg/jobmonitor/worker_manager.go | 2 +- src/testing/pkg/label/dao/dao.go | 2 +- src/testing/pkg/label/manager.go | 2 +- src/testing/pkg/ldap/manager.go | 2 +- src/testing/pkg/member/fake_member_manager.go | 2 +- .../pkg/notification/policy/dao/dao.go | 2 +- .../pkg/notification/policy/manager.go | 2 +- src/testing/pkg/oidc/dao/meta_dao.go | 2 +- src/testing/pkg/oidc/meta_manager.go | 2 +- src/testing/pkg/pkg.go | 78 --- src/testing/pkg/project/manager.go | 2 +- src/testing/pkg/project/metadata/manager.go | 2 +- src/testing/pkg/queuestatus/manager.go | 2 +- src/testing/pkg/quota/driver/driver.go | 2 +- src/testing/pkg/quota/manager.go | 2 +- src/testing/pkg/rbac/dao/dao.go | 2 +- src/testing/pkg/rbac/manager.go | 2 +- src/testing/pkg/reg/adapter/adapter.go | 2 +- src/testing/pkg/reg/dao/dao.go | 2 +- src/testing/pkg/reg/manager.go | 4 +- .../pkg/registry/fake_registry_client.go | 2 +- src/testing/pkg/replication/dao/dao.go | 2 +- src/testing/pkg/replication/manager.go | 4 +- src/testing/pkg/repository/dao/dao.go | 2 +- src/testing/pkg/repository/manager.go | 2 +- src/testing/pkg/robot/dao/dao.go | 2 +- src/testing/pkg/robot/manager.go | 2 +- .../scan/export/artifact_digest_calculator.go | 2 +- .../pkg/scan/export/filter_processor.go | 2 +- src/testing/pkg/scan/export/manager.go | 2 +- src/testing/pkg/scan/handler.go | 2 +- src/testing/pkg/scan/report/manager.go | 2 +- src/testing/pkg/scan/rest/v1/client.go | 2 +- src/testing/pkg/scan/rest/v1/client_pool.go | 2 +- .../pkg/scan/rest/v1/request_resolver.go | 2 +- .../pkg/scan/rest/v1/response_handler.go | 2 +- src/testing/pkg/scan/sbom/manager.go | 2 +- src/testing/pkg/scan/scanner/manager.go | 2 +- src/testing/pkg/scheduler/scheduler.go | 2 +- src/testing/pkg/securityhub/manager.go | 2 +- .../pkg/systemartifact/cleanup/selector.go | 2 +- src/testing/pkg/systemartifact/dao/dao.go | 2 +- src/testing/pkg/systemartifact/manager.go | 2 +- src/testing/pkg/task/execution_manager.go | 2 +- src/testing/pkg/task/manager.go | 2 +- src/testing/pkg/user/dao/dao.go | 2 +- src/testing/pkg/user/manager.go | 2 +- .../pkg/usergroup/fake_usergroup_manager.go | 2 +- 117 files changed, 635 insertions(+), 357 deletions(-) create mode 100644 src/.mockery.yaml delete mode 100644 src/controller/replication/mock.go delete mode 100644 src/jobservice/mgt/mock.go delete mode 100644 src/jobservice/period/mock.go delete mode 100644 src/pkg/scheduler/mock.go delete mode 100644 src/pkg/task/mock.go delete mode 100644 src/testing/common/common.go delete mode 100644 src/testing/controller/controller.go delete mode 100644 src/testing/lib/lib.go delete mode 100644 src/testing/pkg/pkg.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f1f5bc2a1..dabf434bbb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -276,7 +276,7 @@ To build the code, please refer to [build](https://goharbor.io/docs/edge/build-c **Note**: from v2.0, Harbor uses [go-swagger](https://github.com/go-swagger/go-swagger) to generate API server from Swagger 2.0 (aka [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md)). To add or change the APIs, first update the `api/v2.0/swagger.yaml` file, then run `make gen_apis` to generate the API server, finally, implement or update the API handlers in `src/server/v2.0/handler` package. -As now Harbor uses `controller/manager/dao` programming model, we suggest to use [testify mock](https://github.com/stretchr/testify/blob/master/mock/doc.go) to test `controller` and `manager`. Harbor integrates [mockery](https://github.com/vektra/mockery) to generate mocks for golang interfaces using the testify mock package. To generate mocks for the interface, first add `//go:generate mockery xxx` comment with mockery command in the subpackages of `src/testing`, then run `make gen_mocks` to generate mocks. +As now Harbor uses `controller/manager/dao` programming model, we suggest to use [testify mock](https://github.com/stretchr/testify/blob/master/mock/doc.go) to test `controller` and `manager`. Harbor integrates [mockery](https://github.com/vektra/mockery) to generate mocks for golang interfaces using the testify mock package. To generate mocks for the interface, first add mock config in the `src/.mockery.yaml`, then run `make gen_mocks` to generate mocks. ### Keep sync with upstream diff --git a/Makefile b/Makefile index ecd4972dde..1c0c02e8ad 100644 --- a/Makefile +++ b/Makefile @@ -312,13 +312,13 @@ gen_apis: lint_apis MOCKERY_IMAGENAME=$(IMAGENAMESPACE)/mockery -MOCKERY_VERSION=v2.42.2 -MOCKERY=$(RUNCONTAINER) ${MOCKERY_IMAGENAME}:${MOCKERY_VERSION} +MOCKERY_VERSION=v2.43.2 +MOCKERY=$(RUNCONTAINER)/src ${MOCKERY_IMAGENAME}:${MOCKERY_VERSION} MOCKERY_IMAGE_BUILD_CMD=${DOCKERBUILD} -f ${TOOLSPATH}/mockery/Dockerfile --build-arg GOLANG=${GOBUILDIMAGE} --build-arg MOCKERY_VERSION=${MOCKERY_VERSION} -t ${MOCKERY_IMAGENAME}:$(MOCKERY_VERSION) . gen_mocks: $(call prepare_docker_image,${MOCKERY_IMAGENAME},${MOCKERY_VERSION},${MOCKERY_IMAGE_BUILD_CMD}) - ${MOCKERY} go generate ./... + ${MOCKERY} mockery mocks_check: gen_mocks @echo checking mocks... diff --git a/src/.mockery.yaml b/src/.mockery.yaml new file mode 100644 index 0000000000..c0d0b35a6c --- /dev/null +++ b/src/.mockery.yaml @@ -0,0 +1,524 @@ +with-expecter: false +outpkg: "{{.PackageName}}" +mockname: "{{.InterfaceName}}" +filename: "{{.InterfaceName | snakecase}}.go" +packages: + # controller related mocks + github.com/goharbor/harbor/src/controller/artifact: + interfaces: + Controller: + config: + dir: testing/controller/artifact + github.com/goharbor/harbor/src/controller/blob: + interfaces: + Controller: + config: + dir: testing/controller/blob + github.com/goharbor/harbor/src/controller/project: + interfaces: + Controller: + config: + dir: testing/controller/project + github.com/goharbor/harbor/src/controller/quota: + interfaces: + Controller: + config: + dir: testing/controller/quota + github.com/goharbor/harbor/src/controller/scan: + interfaces: + Controller: + config: + dir: testing/controller/scan + Checker: + config: + dir: testing/controller/scan + github.com/goharbor/harbor/src/controller/scanner: + interfaces: + Controller: + config: + dir: testing/controller/scanner + github.com/goharbor/harbor/src/controller/replication: + interfaces: + Controller: + config: + dir: testing/controller/replication + github.com/goharbor/harbor/src/controller/replication/flow: + interfaces: + Controller: + config: + dir: controller/replication + outpkg: replication + mockname: flowController + filename: mock_flow_controller_test.go + registryAdapter: + config: + dir: controller/replication/flow + outpkg: flow + mockname: mockAdapter + filename: mock_adapter_test.go + github.com/goharbor/harbor/src/controller/robot: + interfaces: + Controller: + config: + dir: testing/controller/robot + github.com/goharbor/harbor/src/controller/proxy: + interfaces: + RemoteInterface: + config: + dir: testing/controller/proxy + github.com/goharbor/harbor/src/controller/retention: + interfaces: + Controller: + config: + dir: testing/controller/retention + github.com/goharbor/harbor/src/controller/config: + interfaces: + Controller: + config: + dir: testing/controller/config + github.com/goharbor/harbor/src/controller/user: + interfaces: + Controller: + config: + dir: testing/controller/user + github.com/goharbor/harbor/src/controller/repository: + interfaces: + Controller: + config: + dir: testing/controller/repository + github.com/goharbor/harbor/src/controller/purge: + interfaces: + Controller: + config: + dir: testing/controller/purge + github.com/goharbor/harbor/src/controller/jobservice: + interfaces: + SchedulerController: + config: + dir: testing/controller/jobservice + github.com/goharbor/harbor/src/controller/systemartifact: + interfaces: + Controller: + config: + dir: testing/controller/systemartifact + github.com/goharbor/harbor/src/controller/scandataexport: + interfaces: + Controller: + config: + dir: testing/controller/scandataexport + github.com/goharbor/harbor/src/controller/task: + interfaces: + Controller: + config: + dir: testing/controller/task + ExecutionController: + config: + dir: testing/controller/task + github.com/goharbor/harbor/src/controller/webhook: + interfaces: + Controller: + config: + dir: testing/controller/webhook + github.com/goharbor/harbor/src/controller/securityhub: + interfaces: + Controller: + config: + dir: testing/controller/securityhub + + # jobservice related mocks + github.com/goharbor/harbor/src/jobservice/mgt: + interfaces: + Manager: + config: + dir: jobservice/mgt + outpkg: mgt + mockname: MockManager + filename: mock_manager.go + github.com/goharbor/harbor/src/jobservice/period: + interfaces: + Scheduler: + config: + dir: jobservice/period + outpkg: period + mockname: MockScheduler + filename: mock_scheduler.go + inpackage: True + + # common and lib related mocks + github.com/goharbor/harbor/src/lib/cache: + interfaces: + Cache: + configs: + - dir: lib/cache + outpkg: cache + mockname: mockCache + filename: mock_cache_test.go + inpackage: True + - dir: testing/lib/cache + Iterator: + config: + dir: testing/lib/cache + github.com/goharbor/harbor/src/lib/orm: + interfaces: + Creator: + config: + dir: testing/lib/orm + github.com/goharbor/harbor/src/lib/config: + interfaces: + Manager: + config: + dir: testing/lib/config + github.com/goharbor/harbor/src/common/job: + interfaces: + Client: + config: + dir: pkg/task + outpkg: task + mockname: mockJobserviceClient + filename: mock_jobservice_client_test.go + github.com/goharbor/harbor/src/common/security: + interfaces: + Context: + config: + dir: testing/common/security + + # pkg related mocks + github.com/goharbor/harbor/src/pkg/artifact: + interfaces: + Manager: + config: + dir: testing/pkg/artifact + github.com/goharbor/harbor/src/pkg/blob: + interfaces: + Manager: + config: + dir: testing/pkg/blob + github.com/goharbor/harbor/src/pkg/project: + interfaces: + Manager: + config: + dir: testing/pkg/project + github.com/goharbor/harbor/src/pkg/project/metadata: + interfaces: + Manager: + config: + dir: testing/pkg/project/metadata + github.com/goharbor/harbor/src/pkg/quota: + interfaces: + Manager: + config: + dir: testing/pkg/quota + github.com/goharbor/harbor/src/pkg/quota/driver: + interfaces: + Driver: + config: + dir: testing/pkg/quota/driver + github.com/goharbor/harbor/src/pkg/scan: + interfaces: + Handler: + config: + dir: testing/pkg/scan + github.com/goharbor/harbor/src/pkg/scan/report: + interfaces: + Manager: + config: + dir: testing/pkg/scan/report + github.com/goharbor/harbor/src/pkg/scan/rest/v1: + config: + dir: testing/pkg/scan/rest/v1 + all: True + github.com/goharbor/harbor/src/pkg/scan/scanner: + config: + dir: testing/pkg/scan/scanner + all: True + github.com/goharbor/harbor/src/pkg/scheduler: + interfaces: + DAO: + config: + dir: pkg/scheduler + outpkg: scheduler + mockname: mockDAO + filename: mock_dao_test.go + inpackage: True + Scheduler: + config: + dir: testing/pkg/scheduler + github.com/goharbor/harbor/src/pkg/task: + interfaces: + Manager: + configs: + - dir: pkg/task + outpkg: task + mockname: mockTaskManager + filename: mock_task_manager_test.go + inpackage: True + - dir: testing/pkg/task + SweepManager: + config: + dir: pkg/task + outpkg: task + mockname: mockSweepManager + filename: mock_sweep_manager_test.go + inpackage: True + ExecutionManager: + config: + dir: testing/pkg/task + github.com/goharbor/harbor/src/pkg/task/dao: + interfaces: + TaskDAO: + config: + dir: pkg/task + outpkg: task + mockname: mockTaskDAO + filename: mock_task_dao_test.go + ExecutionDAO: + config: + dir: pkg/task + outpkg: task + mockname: mockExecutionDAO + filename: mock_execution_dao_test.go + github.com/goharbor/harbor/src/pkg/user: + interfaces: + Manager: + config: + dir: testing/pkg/user + github.com/goharbor/harbor/src/pkg/user/dao: + interfaces: + DAO: + config: + dir: testing/pkg/user/dao + github.com/goharbor/harbor/src/pkg/oidc: + interfaces: + MetaManager: + config: + dir: testing/pkg/oidc + github.com/goharbor/harbor/src/pkg/oidc/dao: + interfaces: + MetaDAO: + config: + dir: testing/pkg/oidc/dao + github.com/goharbor/harbor/src/pkg/rbac: + interfaces: + Manager: + config: + dir: testing/pkg/rbac + github.com/goharbor/harbor/src/pkg/rbac/dao: + interfaces: + DAO: + config: + dir: testing/pkg/rbac/dao + github.com/goharbor/harbor/src/pkg/robot: + interfaces: + Manager: + config: + dir: testing/pkg/robot + github.com/goharbor/harbor/src/pkg/robot/dao: + interfaces: + DAO: + config: + dir: testing/pkg/robot/dao + github.com/goharbor/harbor/src/pkg/repository: + interfaces: + Manager: + config: + dir: testing/pkg/repository + github.com/goharbor/harbor/src/pkg/repository/dao: + interfaces: + DAO: + config: + dir: testing/pkg/repository/dao + github.com/goharbor/harbor/src/pkg/notification/policy: + interfaces: + Manager: + config: + dir: testing/pkg/notification/policy + github.com/goharbor/harbor/src/pkg/notification/policy/dao: + interfaces: + DAO: + config: + dir: testing/pkg/notification/policy/dao + github.com/goharbor/harbor/src/pkg/immutable/dao: + interfaces: + DAO: + config: + dir: testing/pkg/immutable/dao + github.com/goharbor/harbor/src/pkg/ldap: + interfaces: + Manager: + config: + dir: testing/pkg/ldap + github.com/goharbor/harbor/src/pkg/allowlist: + interfaces: + Manager: + config: + dir: testing/pkg/allowlist + github.com/goharbor/harbor/src/pkg/allowlist/dao: + interfaces: + DAO: + config: + dir: testing/pkg/allowlist/dao + github.com/goharbor/harbor/src/pkg/reg: + interfaces: + Manager: + config: + dir: testing/pkg/reg + github.com/goharbor/harbor/src/pkg/reg/dao: + interfaces: + DAO: + config: + dir: testing/pkg/reg/dao + github.com/goharbor/harbor/src/pkg/reg/adapter: + interfaces: + Factory: + config: + dir: controller/replication/flow + outpkg: flow + mockname: mockFactory + filename: mock_adapter_factory_test.go + Adapter: + config: + dir: testing/pkg/reg/adapter + github.com/goharbor/harbor/src/pkg/replication: + interfaces: + Manager: + config: + dir: testing/pkg/replication + github.com/goharbor/harbor/src/pkg/replication/dao: + interfaces: + DAO: + config: + dir: testing/pkg/replication/dao + github.com/goharbor/harbor/src/pkg/label: + interfaces: + Manager: + config: + dir: testing/pkg/label + github.com/goharbor/harbor/src/pkg/label/dao: + interfaces: + DAO: + config: + dir: testing/pkg/label/dao + github.com/goharbor/harbor/src/pkg/joblog: + interfaces: + Manager: + config: + dir: testing/pkg/joblog + github.com/goharbor/harbor/src/pkg/joblog/dao: + interfaces: + DAO: + config: + dir: testing/pkg/joblog/dao + github.com/goharbor/harbor/src/pkg/accessory: + interfaces: + Manager: + config: + dir: testing/pkg/accessory + github.com/goharbor/harbor/src/pkg/accessory/dao: + interfaces: + DAO: + config: + dir: testing/pkg/accessory/dao + github.com/goharbor/harbor/src/pkg/accessory/model: + interfaces: + Accessory: + config: + dir: testing/pkg/accessory/model + github.com/goharbor/harbor/src/pkg/audit: + interfaces: + Manager: + config: + dir: testing/pkg/audit + github.com/goharbor/harbor/src/pkg/audit/dao: + interfaces: + DAO: + config: + dir: testing/pkg/audit/dao + github.com/goharbor/harbor/src/pkg/systemartifact: + interfaces: + Manager: + config: + dir: testing/pkg/systemartifact + Selector: + config: + dir: testing/pkg/systemartifact/cleanup + outpkg: cleanup + github.com/goharbor/harbor/src/pkg/systemartifact/dao: + interfaces: + DAO: + config: + dir: testing/pkg/systemartifact/dao + github.com/goharbor/harbor/src/pkg/cached/manifest/redis: + interfaces: + CachedManager: + config: + dir: testing/pkg/cached/manifest/redis + github.com/goharbor/harbor/src/pkg/scan/export: + interfaces: + FilterProcessor: + config: + dir: testing/pkg/scan/export + Manager: + config: + dir: testing/pkg/scan/export + ArtifactDigestCalculator: + config: + dir: testing/pkg/scan/export + github.com/goharbor/harbor/src/pkg/scan/sbom: + interfaces: + Manager: + config: + dir: testing/pkg/scan/sbom + github.com/goharbor/harbor/src/pkg/registry: + interfaces: + Client: + config: + dir: testing/pkg/registry + filename: fake_registry_client.go + github.com/goharbor/harbor/src/pkg/member: + interfaces: + Manager: + config: + dir: testing/pkg/member + filename: fake_member_manager.go + github.com/goharbor/harbor/src/pkg/usergroup: + interfaces: + Manager: + config: + dir: testing/pkg/usergroup + filename: fake_usergroup_manager.go + github.com/goharbor/harbor/src/pkg/jobmonitor: + config: + dir: testing/pkg/jobmonitor + interfaces: + PoolManager: + JobServiceMonitorClient: + WorkerManager: + QueueManager: + RedisClient: + github.com/goharbor/harbor/src/pkg/queuestatus: + interfaces: + Manager: + config: + dir: testing/pkg/queuestatus + github.com/goharbor/harbor/src/pkg/securityhub: + interfaces: + Manager: + config: + dir: testing/pkg/securityhub + + + + + + + + + + + + + + + + + diff --git a/src/controller/replication/flow/mock.go b/src/controller/replication/flow/mock.go index 90212aed8b..2d47cf2660 100644 --- a/src/controller/replication/flow/mock.go +++ b/src/controller/replication/flow/mock.go @@ -24,6 +24,3 @@ type registryAdapter interface { adapter.Adapter adapter.ArtifactRegistry } - -//go:generate mockery --dir . --name registryAdapter --output . --outpkg flow --filename mock_adapter_test.go --structname mockAdapter -//go:generate mockery --dir ../../../pkg/reg/adapter --name Factory --output . --outpkg flow --filename mock_adapter_factory_test.go --structname mockFactory diff --git a/src/controller/replication/flow/mock_adapter_factory_test.go b/src/controller/replication/flow/mock_adapter_factory_test.go index e11e8baca7..05d63df3fa 100644 --- a/src/controller/replication/flow/mock_adapter_factory_test.go +++ b/src/controller/replication/flow/mock_adapter_factory_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package flow diff --git a/src/controller/replication/flow/mock_adapter_test.go b/src/controller/replication/flow/mock_adapter_test.go index 331b98e2ff..5f7f07bcb2 100644 --- a/src/controller/replication/flow/mock_adapter_test.go +++ b/src/controller/replication/flow/mock_adapter_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package flow diff --git a/src/controller/replication/mock.go b/src/controller/replication/mock.go deleted file mode 100644 index e434d2586d..0000000000 --- a/src/controller/replication/mock.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Project Harbor 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 replication - -//go:generate mockery --dir ./flow --name Controller --output . --outpkg replication --filename mock_flow_controller_test.go --structname flowController diff --git a/src/controller/replication/mock_flow_controller_test.go b/src/controller/replication/mock_flow_controller_test.go index a3d6ec854b..672aa710ff 100644 --- a/src/controller/replication/mock_flow_controller_test.go +++ b/src/controller/replication/mock_flow_controller_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package replication diff --git a/src/jobservice/mgt/mock.go b/src/jobservice/mgt/mock.go deleted file mode 100644 index a8b3f45517..0000000000 --- a/src/jobservice/mgt/mock.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Project Harbor 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 mgt - -//go:generate mockery --name Manager --output . --outpkg mgt --filename mock_manager.go --structname MockManager --inpackage diff --git a/src/jobservice/mgt/mock_manager.go b/src/jobservice/mgt/mock_manager.go index 8f1ccd3a22..71e516cbf1 100644 --- a/src/jobservice/mgt/mock_manager.go +++ b/src/jobservice/mgt/mock_manager.go @@ -1,9 +1,10 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mgt import ( job "github.com/goharbor/harbor/src/jobservice/job" + mock "github.com/stretchr/testify/mock" query "github.com/goharbor/harbor/src/jobservice/common/query" diff --git a/src/jobservice/period/mock.go b/src/jobservice/period/mock.go deleted file mode 100644 index e2e540d226..0000000000 --- a/src/jobservice/period/mock.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Project Harbor 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 period - -//go:generate mockery --name Scheduler --output . --outpkg period --filename mock_scheduler.go --structname MockScheduler --inpackage diff --git a/src/jobservice/period/mock_scheduler.go b/src/jobservice/period/mock_scheduler.go index abbf494b7d..556fe2a731 100644 --- a/src/jobservice/period/mock_scheduler.go +++ b/src/jobservice/period/mock_scheduler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package period diff --git a/src/lib/cache/cache.go b/src/lib/cache/cache.go index ba49c1aa1a..11d8f299c7 100644 --- a/src/lib/cache/cache.go +++ b/src/lib/cache/cache.go @@ -47,8 +47,6 @@ type Iterator interface { Val() string } -//go:generate mockery --name Cache --output . --outpkg cache --filename mock_cache_test.go --structname mockCache --inpackage - // Cache cache interface type Cache interface { // Contains returns true if key exists diff --git a/src/lib/cache/mock_cache_test.go b/src/lib/cache/mock_cache_test.go index 62af8f2bb4..b990522fa5 100644 --- a/src/lib/cache/mock_cache_test.go +++ b/src/lib/cache/mock_cache_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package cache diff --git a/src/pkg/scheduler/mock.go b/src/pkg/scheduler/mock.go deleted file mode 100644 index 00a574f2b6..0000000000 --- a/src/pkg/scheduler/mock.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Project Harbor 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 scheduler - -//go:generate mockery --name DAO --output . --outpkg scheduler --filename mock_dao_test.go --structname mockDAO --inpackage diff --git a/src/pkg/scheduler/mock_dao_test.go b/src/pkg/scheduler/mock_dao_test.go index 8fc6ea3c58..e875cb40d1 100644 --- a/src/pkg/scheduler/mock_dao_test.go +++ b/src/pkg/scheduler/mock_dao_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scheduler diff --git a/src/pkg/task/mock.go b/src/pkg/task/mock.go deleted file mode 100644 index 856fd7fabc..0000000000 --- a/src/pkg/task/mock.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Project Harbor 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 task - -//go:generate mockery --dir ./dao --name TaskDAO --output . --outpkg task --filename mock_task_dao_test.go --structname mockTaskDAO -//go:generate mockery --dir ./dao --name ExecutionDAO --output . --outpkg task --filename mock_execution_dao_test.go --structname mockExecutionDAO -//go:generate mockery --name Manager --output . --outpkg task --filename mock_task_manager_test.go --structname mockTaskManager --inpackage -//go:generate mockery --dir ../../common/job --name Client --output . --outpkg task --filename mock_jobservice_client_test.go --structname mockJobserviceClient -//go:generate mockery --name SweepManager --output . --outpkg task --filename mock_sweep_manager_test.go --structname mockSweepManager --inpackage diff --git a/src/pkg/task/mock_execution_dao_test.go b/src/pkg/task/mock_execution_dao_test.go index f26a035a62..155b959ea8 100644 --- a/src/pkg/task/mock_execution_dao_test.go +++ b/src/pkg/task/mock_execution_dao_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/pkg/task/mock_jobservice_client_test.go b/src/pkg/task/mock_jobservice_client_test.go index 0d9ecfeca8..06f58aff75 100644 --- a/src/pkg/task/mock_jobservice_client_test.go +++ b/src/pkg/task/mock_jobservice_client_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/pkg/task/mock_sweep_manager_test.go b/src/pkg/task/mock_sweep_manager_test.go index 735c34304c..5bd1a62276 100644 --- a/src/pkg/task/mock_sweep_manager_test.go +++ b/src/pkg/task/mock_sweep_manager_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/pkg/task/mock_task_dao_test.go b/src/pkg/task/mock_task_dao_test.go index 357353bfa2..00a810c63b 100644 --- a/src/pkg/task/mock_task_dao_test.go +++ b/src/pkg/task/mock_task_dao_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/pkg/task/mock_task_manager_test.go b/src/pkg/task/mock_task_manager_test.go index 2c99c1b553..9f9c358511 100644 --- a/src/pkg/task/mock_task_manager_test.go +++ b/src/pkg/task/mock_task_manager_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/testing/common/common.go b/src/testing/common/common.go deleted file mode 100644 index 1374775656..0000000000 --- a/src/testing/common/common.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Project Harbor 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 common - -//go:generate mockery --case snake --dir ../../common/security --name Context --output ./security --outpkg security diff --git a/src/testing/common/security/context.go b/src/testing/common/security/context.go index 9f6c80f6bc..f277d19d7c 100644 --- a/src/testing/common/security/context.go +++ b/src/testing/common/security/context.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package security diff --git a/src/testing/controller/artifact/controller.go b/src/testing/controller/artifact/controller.go index 8fe07f2978..23ed6396f0 100644 --- a/src/testing/controller/artifact/controller.go +++ b/src/testing/controller/artifact/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package artifact diff --git a/src/testing/controller/blob/controller.go b/src/testing/controller/blob/controller.go index 3081f5e255..ba8fcc706b 100644 --- a/src/testing/controller/blob/controller.go +++ b/src/testing/controller/blob/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package blob diff --git a/src/testing/controller/config/controller.go b/src/testing/controller/config/controller.go index c82468518e..0b6205200f 100644 --- a/src/testing/controller/config/controller.go +++ b/src/testing/controller/config/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package config diff --git a/src/testing/controller/controller.go b/src/testing/controller/controller.go deleted file mode 100644 index 2daf186ad2..0000000000 --- a/src/testing/controller/controller.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright Project Harbor 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 controller - -//go:generate mockery --case snake --dir ../../controller/artifact --name Controller --output ./artifact --outpkg artifact -//go:generate mockery --case snake --dir ../../controller/blob --name Controller --output ./blob --outpkg blob -//go:generate mockery --case snake --dir ../../controller/project --name Controller --output ./project --outpkg project -//go:generate mockery --case snake --dir ../../controller/quota --name Controller --output ./quota --outpkg quota -//go:generate mockery --case snake --dir ../../controller/scan --name Controller --output ./scan --outpkg scan -//go:generate mockery --case snake --dir ../../controller/scan --name Checker --output ./scan --outpkg scan -//go:generate mockery --case snake --dir ../../controller/scanner --name Controller --output ./scanner --outpkg scanner -//go:generate mockery --case snake --dir ../../controller/replication --name Controller --output ./replication --outpkg replication -//go:generate mockery --case snake --dir ../../controller/robot --name Controller --output ./robot --outpkg robot -//go:generate mockery --case snake --dir ../../controller/proxy --name RemoteInterface --output ./proxy --outpkg proxy -//go:generate mockery --case snake --dir ../../controller/retention --name Controller --output ./retention --outpkg retention -//go:generate mockery --case snake --dir ../../controller/config --name Controller --output ./config --outpkg config -//go:generate mockery --case snake --dir ../../controller/user --name Controller --output ./user --outpkg user -//go:generate mockery --case snake --dir ../../controller/repository --name Controller --output ./repository --outpkg repository -//go:generate mockery --case snake --dir ../../controller/purge --name Controller --output ./purge --outpkg purge -//go:generate mockery --case snake --dir ../../controller/jobservice --name SchedulerController --output ./jobservice --outpkg jobservice -//go:generate mockery --case snake --dir ../../controller/systemartifact --name Controller --output ./systemartifact --outpkg systemartifact -//go:generate mockery --case snake --dir ../../controller/scandataexport --name Controller --output ./scandataexport --outpkg scandataexport -//go:generate mockery --case snake --dir ../../controller/task --name Controller --output ./task --outpkg task -//go:generate mockery --case snake --dir ../../controller/task --name ExecutionController --output ./task --outpkg task -//go:generate mockery --case snake --dir ../../controller/webhook --name Controller --output ./webhook --outpkg webhook -//go:generate mockery --case snake --dir ../../controller/securityhub --name Controller --output ./securityhub --outpkg securityhub diff --git a/src/testing/controller/jobservice/scheduler_controller.go b/src/testing/controller/jobservice/scheduler_controller.go index 4f5a09328f..1d9eea5c96 100644 --- a/src/testing/controller/jobservice/scheduler_controller.go +++ b/src/testing/controller/jobservice/scheduler_controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobservice diff --git a/src/testing/controller/project/controller.go b/src/testing/controller/project/controller.go index bcb9331b2b..c95d067912 100644 --- a/src/testing/controller/project/controller.go +++ b/src/testing/controller/project/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package project diff --git a/src/testing/controller/proxy/remote_interface.go b/src/testing/controller/proxy/remote_interface.go index 48b52a094a..dbe085f70d 100644 --- a/src/testing/controller/proxy/remote_interface.go +++ b/src/testing/controller/proxy/remote_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package proxy diff --git a/src/testing/controller/purge/controller.go b/src/testing/controller/purge/controller.go index 7c3e27fedb..08416914bc 100644 --- a/src/testing/controller/purge/controller.go +++ b/src/testing/controller/purge/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package purge diff --git a/src/testing/controller/quota/controller.go b/src/testing/controller/quota/controller.go index 7053fb4d74..14dbd1412b 100644 --- a/src/testing/controller/quota/controller.go +++ b/src/testing/controller/quota/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package quota diff --git a/src/testing/controller/replication/controller.go b/src/testing/controller/replication/controller.go index 02a2afbb59..8d4dc5ab28 100644 --- a/src/testing/controller/replication/controller.go +++ b/src/testing/controller/replication/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package replication diff --git a/src/testing/controller/repository/controller.go b/src/testing/controller/repository/controller.go index bdc1097705..445bc5872f 100644 --- a/src/testing/controller/repository/controller.go +++ b/src/testing/controller/repository/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package repository diff --git a/src/testing/controller/retention/controller.go b/src/testing/controller/retention/controller.go index 8eb3c98895..907b901963 100644 --- a/src/testing/controller/retention/controller.go +++ b/src/testing/controller/retention/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package retention diff --git a/src/testing/controller/robot/controller.go b/src/testing/controller/robot/controller.go index 03c6af4838..735f5df09e 100644 --- a/src/testing/controller/robot/controller.go +++ b/src/testing/controller/robot/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package robot diff --git a/src/testing/controller/scan/checker.go b/src/testing/controller/scan/checker.go index 9c2e4b6743..7af46b09bd 100644 --- a/src/testing/controller/scan/checker.go +++ b/src/testing/controller/scan/checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scan diff --git a/src/testing/controller/scan/controller.go b/src/testing/controller/scan/controller.go index bc24b91741..dad2b5dbf7 100644 --- a/src/testing/controller/scan/controller.go +++ b/src/testing/controller/scan/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scan diff --git a/src/testing/controller/scandataexport/controller.go b/src/testing/controller/scandataexport/controller.go index b75de2fc86..4fdf81b269 100644 --- a/src/testing/controller/scandataexport/controller.go +++ b/src/testing/controller/scandataexport/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scandataexport diff --git a/src/testing/controller/scanner/controller.go b/src/testing/controller/scanner/controller.go index 38d66f9b9c..403f4d807b 100644 --- a/src/testing/controller/scanner/controller.go +++ b/src/testing/controller/scanner/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scanner diff --git a/src/testing/controller/securityhub/controller.go b/src/testing/controller/securityhub/controller.go index 5382fb2b1a..7df0998274 100644 --- a/src/testing/controller/securityhub/controller.go +++ b/src/testing/controller/securityhub/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package securityhub diff --git a/src/testing/controller/systemartifact/controller.go b/src/testing/controller/systemartifact/controller.go index 52354277ad..d533c629c1 100644 --- a/src/testing/controller/systemartifact/controller.go +++ b/src/testing/controller/systemartifact/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package systemartifact diff --git a/src/testing/controller/task/controller.go b/src/testing/controller/task/controller.go index 4e542513de..7a6072832d 100644 --- a/src/testing/controller/task/controller.go +++ b/src/testing/controller/task/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/testing/controller/task/execution_controller.go b/src/testing/controller/task/execution_controller.go index 5501b14de7..9488a76f09 100644 --- a/src/testing/controller/task/execution_controller.go +++ b/src/testing/controller/task/execution_controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/testing/controller/user/controller.go b/src/testing/controller/user/controller.go index 5976018d4b..a0325fa2bc 100644 --- a/src/testing/controller/user/controller.go +++ b/src/testing/controller/user/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package user diff --git a/src/testing/controller/webhook/controller.go b/src/testing/controller/webhook/controller.go index c50d448501..e265fb0338 100644 --- a/src/testing/controller/webhook/controller.go +++ b/src/testing/controller/webhook/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package webhook diff --git a/src/testing/lib/cache/cache.go b/src/testing/lib/cache/cache.go index e4e719d9b9..2faca2d6c8 100644 --- a/src/testing/lib/cache/cache.go +++ b/src/testing/lib/cache/cache.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package cache diff --git a/src/testing/lib/cache/iterator.go b/src/testing/lib/cache/iterator.go index 7a80fb382a..65daab8335 100644 --- a/src/testing/lib/cache/iterator.go +++ b/src/testing/lib/cache/iterator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package cache diff --git a/src/testing/lib/config/manager.go b/src/testing/lib/config/manager.go index ff6456b5dd..c692e3a3f3 100644 --- a/src/testing/lib/config/manager.go +++ b/src/testing/lib/config/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package config diff --git a/src/testing/lib/lib.go b/src/testing/lib/lib.go deleted file mode 100644 index 3b6f4a36a0..0000000000 --- a/src/testing/lib/lib.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright Project Harbor 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 lib - -//go:generate mockery --case snake --dir ../../lib/orm --name Creator --output ./orm --outpkg orm -//go:generate mockery --case snake --dir ../../lib/cache --name Cache --output ./cache --outpkg cache -//go:generate mockery --case snake --dir ../../lib/cache --name Iterator --output ./cache --outpkg cache -//go:generate mockery --case snake --dir ../../lib/config --name Manager --output ./config --outpkg config diff --git a/src/testing/lib/orm/creator.go b/src/testing/lib/orm/creator.go index d10e5f918b..c05dbf761f 100644 --- a/src/testing/lib/orm/creator.go +++ b/src/testing/lib/orm/creator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package orm diff --git a/src/testing/pkg/accessory/dao/dao.go b/src/testing/pkg/accessory/dao/dao.go index d4165cf9b3..d7a109b687 100644 --- a/src/testing/pkg/accessory/dao/dao.go +++ b/src/testing/pkg/accessory/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/accessory/manager.go b/src/testing/pkg/accessory/manager.go index 1245311d87..f3688f7845 100644 --- a/src/testing/pkg/accessory/manager.go +++ b/src/testing/pkg/accessory/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package accessory diff --git a/src/testing/pkg/accessory/model/accessory.go b/src/testing/pkg/accessory/model/accessory.go index a33371896e..c0ee08fa96 100644 --- a/src/testing/pkg/accessory/model/accessory.go +++ b/src/testing/pkg/accessory/model/accessory.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package model diff --git a/src/testing/pkg/allowlist/dao/dao.go b/src/testing/pkg/allowlist/dao/dao.go index a8ebfec107..850201b8f8 100644 --- a/src/testing/pkg/allowlist/dao/dao.go +++ b/src/testing/pkg/allowlist/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/allowlist/manager.go b/src/testing/pkg/allowlist/manager.go index ecb1b41153..00cfcae31f 100644 --- a/src/testing/pkg/allowlist/manager.go +++ b/src/testing/pkg/allowlist/manager.go @@ -1,6 +1,6 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. -package robot +package allowlist import ( context "context" diff --git a/src/testing/pkg/artifact/manager.go b/src/testing/pkg/artifact/manager.go index bf19a0b605..208bfa040a 100644 --- a/src/testing/pkg/artifact/manager.go +++ b/src/testing/pkg/artifact/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package artifact diff --git a/src/testing/pkg/audit/dao/dao.go b/src/testing/pkg/audit/dao/dao.go index 74dd03aaa6..b90655034b 100644 --- a/src/testing/pkg/audit/dao/dao.go +++ b/src/testing/pkg/audit/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/audit/manager.go b/src/testing/pkg/audit/manager.go index 887996c0ba..cf3524c02a 100644 --- a/src/testing/pkg/audit/manager.go +++ b/src/testing/pkg/audit/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package audit diff --git a/src/testing/pkg/blob/manager.go b/src/testing/pkg/blob/manager.go index 8308e4aaf6..01bc657423 100644 --- a/src/testing/pkg/blob/manager.go +++ b/src/testing/pkg/blob/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package blob diff --git a/src/testing/pkg/cached/manifest/redis/cached_manager.go b/src/testing/pkg/cached/manifest/redis/cached_manager.go index 033e96aca9..86f17e7493 100644 --- a/src/testing/pkg/cached/manifest/redis/cached_manager.go +++ b/src/testing/pkg/cached/manifest/redis/cached_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package redis diff --git a/src/testing/pkg/immutable/dao/dao.go b/src/testing/pkg/immutable/dao/dao.go index 8ad5aac0fe..07776e6001 100644 --- a/src/testing/pkg/immutable/dao/dao.go +++ b/src/testing/pkg/immutable/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/joblog/dao/dao.go b/src/testing/pkg/joblog/dao/dao.go index 353d2c1685..e010d2309e 100644 --- a/src/testing/pkg/joblog/dao/dao.go +++ b/src/testing/pkg/joblog/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/joblog/manager.go b/src/testing/pkg/joblog/manager.go index d00e413c9e..0e4204da68 100644 --- a/src/testing/pkg/joblog/manager.go +++ b/src/testing/pkg/joblog/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package joblog diff --git a/src/testing/pkg/jobmonitor/job_service_monitor_client.go b/src/testing/pkg/jobmonitor/job_service_monitor_client.go index d528776fc8..567942c61d 100644 --- a/src/testing/pkg/jobmonitor/job_service_monitor_client.go +++ b/src/testing/pkg/jobmonitor/job_service_monitor_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobmonitor diff --git a/src/testing/pkg/jobmonitor/pool_manager.go b/src/testing/pkg/jobmonitor/pool_manager.go index 51dc4fbf9a..b2a8eb3afe 100644 --- a/src/testing/pkg/jobmonitor/pool_manager.go +++ b/src/testing/pkg/jobmonitor/pool_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobmonitor diff --git a/src/testing/pkg/jobmonitor/queue_manager.go b/src/testing/pkg/jobmonitor/queue_manager.go index bce10ef38e..2bf71c5f8f 100644 --- a/src/testing/pkg/jobmonitor/queue_manager.go +++ b/src/testing/pkg/jobmonitor/queue_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobmonitor diff --git a/src/testing/pkg/jobmonitor/redis_client.go b/src/testing/pkg/jobmonitor/redis_client.go index 5a7f91837c..099b41db7a 100644 --- a/src/testing/pkg/jobmonitor/redis_client.go +++ b/src/testing/pkg/jobmonitor/redis_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobmonitor diff --git a/src/testing/pkg/jobmonitor/worker_manager.go b/src/testing/pkg/jobmonitor/worker_manager.go index d6f136f2ae..5fef25392f 100644 --- a/src/testing/pkg/jobmonitor/worker_manager.go +++ b/src/testing/pkg/jobmonitor/worker_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package jobmonitor diff --git a/src/testing/pkg/label/dao/dao.go b/src/testing/pkg/label/dao/dao.go index 63cb4525b9..c552f751be 100644 --- a/src/testing/pkg/label/dao/dao.go +++ b/src/testing/pkg/label/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/label/manager.go b/src/testing/pkg/label/manager.go index 73c7229446..dff40d983b 100644 --- a/src/testing/pkg/label/manager.go +++ b/src/testing/pkg/label/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package label diff --git a/src/testing/pkg/ldap/manager.go b/src/testing/pkg/ldap/manager.go index de682ae5d1..aeb7ff7d5a 100644 --- a/src/testing/pkg/ldap/manager.go +++ b/src/testing/pkg/ldap/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package ldap diff --git a/src/testing/pkg/member/fake_member_manager.go b/src/testing/pkg/member/fake_member_manager.go index 1517a3784c..6fe7aac32d 100644 --- a/src/testing/pkg/member/fake_member_manager.go +++ b/src/testing/pkg/member/fake_member_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package member diff --git a/src/testing/pkg/notification/policy/dao/dao.go b/src/testing/pkg/notification/policy/dao/dao.go index 83181b5a40..6c3061e250 100644 --- a/src/testing/pkg/notification/policy/dao/dao.go +++ b/src/testing/pkg/notification/policy/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/notification/policy/manager.go b/src/testing/pkg/notification/policy/manager.go index b68aaecb5f..4b41766e55 100644 --- a/src/testing/pkg/notification/policy/manager.go +++ b/src/testing/pkg/notification/policy/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package policy diff --git a/src/testing/pkg/oidc/dao/meta_dao.go b/src/testing/pkg/oidc/dao/meta_dao.go index c773133ef2..1a2e1fbbed 100644 --- a/src/testing/pkg/oidc/dao/meta_dao.go +++ b/src/testing/pkg/oidc/dao/meta_dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/oidc/meta_manager.go b/src/testing/pkg/oidc/meta_manager.go index c9a688a2e8..350fdef1c2 100644 --- a/src/testing/pkg/oidc/meta_manager.go +++ b/src/testing/pkg/oidc/meta_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package oidc diff --git a/src/testing/pkg/pkg.go b/src/testing/pkg/pkg.go deleted file mode 100644 index 9ded95ee64..0000000000 --- a/src/testing/pkg/pkg.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright Project Harbor 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 pkg - -//go:generate mockery --case snake --dir ../../pkg/artifact --name Manager --output ./artifact --outpkg artifact -//go:generate mockery --case snake --dir ../../pkg/blob --name Manager --output ./blob --outpkg blob -// go::generate mockery --case snake --dir ../../vendor/github.com/docker/distribution --name Manifest --output ./distribution --outpkg distribution -//go:generate mockery --case snake --dir ../../pkg/project --name Manager --output ./project --outpkg project -//go:generate mockery --case snake --dir ../../pkg/project/metadata --name Manager --output ./project/metadata --outpkg metadata -//go:generate mockery --case snake --dir ../../pkg/quota --name Manager --output ./quota --outpkg quota -//go:generate mockery --case snake --dir ../../pkg/quota/driver --name Driver --output ./quota/driver --outpkg driver -//go:generate mockery --case snake --dir ../../pkg/scan/report --name Manager --output ./scan/report --outpkg report -//go:generate mockery --case snake --dir ../../pkg/scan/rest/v1 --all --output ./scan/rest/v1 --outpkg v1 -//go:generate mockery --case snake --dir ../../pkg/scan/scanner --all --output ./scan/scanner --outpkg scanner -//go:generate mockery --case snake --dir ../../pkg/scheduler --name Scheduler --output ./scheduler --outpkg scheduler -//go:generate mockery --case snake --dir ../../pkg/task --name Manager --output ./task --outpkg task -//go:generate mockery --case snake --dir ../../pkg/task --name ExecutionManager --output ./task --outpkg task -//go:generate mockery --case snake --dir ../../pkg/user --name Manager --output ./user --outpkg user -//go:generate mockery --case snake --dir ../../pkg/user/dao --name DAO --output ./user/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/oidc --name MetaManager --output ./oidc --outpkg oidc -//go:generate mockery --case snake --dir ../../pkg/oidc/dao --name MetaDAO --output ./oidc/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/rbac --name Manager --output ./rbac --outpkg rbac -//go:generate mockery --case snake --dir ../../pkg/rbac/dao --name DAO --output ./rbac/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/robot --name Manager --output ./robot --outpkg robot -//go:generate mockery --case snake --dir ../../pkg/robot/dao --name DAO --output ./robot/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/repository --name Manager --output ./repository --outpkg repository -//go:generate mockery --case snake --dir ../../pkg/repository/dao --name DAO --output ./repository/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/notification/policy/dao --name DAO --output ./notification/policy/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/notification/policy --name Manager --output ./notification/policy --outpkg policy -//go:generate mockery --case snake --dir ../../pkg/immutable/dao --name DAO --output ./immutable/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/ldap --name Manager --output ./ldap --outpkg ldap -//go:generate mockery --case snake --dir ../../pkg/allowlist --name Manager --output ./allowlist --outpkg robot -//go:generate mockery --case snake --dir ../../pkg/allowlist/dao --name DAO --output ./allowlist/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/reg/dao --name DAO --output ./reg/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/reg --name Manager --output ./reg --outpkg manager -//go:generate mockery --case snake --dir ../../pkg/reg/adapter --name Adapter --output ./reg/adapter --outpkg adapter -//go:generate mockery --case snake --dir ../../pkg/replication/dao --name DAO --output ./replication/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/replication --name Manager --output ./replication --outpkg manager -//go:generate mockery --case snake --dir ../../pkg/label --name Manager --output ./label --outpkg label -//go:generate mockery --case snake --dir ../../pkg/label/dao --name DAO --output ./label/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/joblog --name Manager --output ./joblog --outpkg joblog -//go:generate mockery --case snake --dir ../../pkg/joblog/dao --name DAO --output ./joblog/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/accessory/model --name Accessory --output ./accessory/model --outpkg model -//go:generate mockery --case snake --dir ../../pkg/accessory/dao --name DAO --output ./accessory/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/accessory --name Manager --output ./accessory --outpkg accessory -//go:generate mockery --case snake --dir ../../pkg/audit/dao --name DAO --output ./audit/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/audit --name Manager --output ./audit --outpkg audit -//go:generate mockery --case snake --dir ../../pkg/systemartifact --name Manager --output ./systemartifact --outpkg systemartifact -//go:generate mockery --case snake --dir ../../pkg/systemartifact/ --name Selector --output ./systemartifact/cleanup --outpkg cleanup -//go:generate mockery --case snake --dir ../../pkg/systemartifact/dao --name DAO --output ./systemartifact/dao --outpkg dao -//go:generate mockery --case snake --dir ../../pkg/cached/manifest/redis --name CachedManager --output ./cached/manifest/redis --outpkg redis -//go:generate mockery --case snake --dir ../../pkg/scan/export --name FilterProcessor --output ./scan/export --outpkg export -//go:generate mockery --case snake --dir ../../pkg/scan/export --name Manager --output ./scan/export --outpkg export -//go:generate mockery --case snake --dir ../../pkg/scan/export --name ArtifactDigestCalculator --output ./scan/export --outpkg export -//go:generate mockery --case snake --dir ../../pkg/registry --name Client --output ./registry --outpkg registry --filename fake_registry_client.go -//go:generate mockery --case snake --dir ../../pkg/member --name Manager --output ./member --outpkg member --filename fake_member_manager.go -//go:generate mockery --case snake --dir ../../pkg/usergroup --name Manager --output ./usergroup --outpkg usergroup --filename fake_usergroup_manager.go -//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name PoolManager --output ./jobmonitor --outpkg jobmonitor -//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name JobServiceMonitorClient --output ./jobmonitor --outpkg jobmonitor -//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name WorkerManager --output ./jobmonitor --outpkg jobmonitor -//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name QueueManager --output ./jobmonitor --outpkg jobmonitor -//go:generate mockery --case snake --dir ../../pkg/jobmonitor --name RedisClient --output ./jobmonitor --outpkg jobmonitor -//go:generate mockery --case snake --dir ../../pkg/queuestatus --name Manager --output ./queuestatus --outpkg queuestatus -//go:generate mockery --case snake --dir ../../pkg/securityhub --name Manager --output ./securityhub --outpkg securityhub -//go:generate mockery --case snake --dir ../../pkg/scan/sbom --name Manager --output ./scan/sbom --outpkg sbom -//go:generate mockery --case snake --dir ../../pkg/scan --name Handler --output ./scan --outpkg scan diff --git a/src/testing/pkg/project/manager.go b/src/testing/pkg/project/manager.go index 10b1c8e086..b9ec7051b2 100644 --- a/src/testing/pkg/project/manager.go +++ b/src/testing/pkg/project/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package project diff --git a/src/testing/pkg/project/metadata/manager.go b/src/testing/pkg/project/metadata/manager.go index 7135b3be23..774f4d78bb 100644 --- a/src/testing/pkg/project/metadata/manager.go +++ b/src/testing/pkg/project/metadata/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package metadata diff --git a/src/testing/pkg/queuestatus/manager.go b/src/testing/pkg/queuestatus/manager.go index 924bc4ca85..d2942cabe3 100644 --- a/src/testing/pkg/queuestatus/manager.go +++ b/src/testing/pkg/queuestatus/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package queuestatus diff --git a/src/testing/pkg/quota/driver/driver.go b/src/testing/pkg/quota/driver/driver.go index 2ef8b7c37a..9bfb32728e 100644 --- a/src/testing/pkg/quota/driver/driver.go +++ b/src/testing/pkg/quota/driver/driver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package driver diff --git a/src/testing/pkg/quota/manager.go b/src/testing/pkg/quota/manager.go index 4d570f3ed4..71df09fcef 100644 --- a/src/testing/pkg/quota/manager.go +++ b/src/testing/pkg/quota/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package quota diff --git a/src/testing/pkg/rbac/dao/dao.go b/src/testing/pkg/rbac/dao/dao.go index 91a2c351ce..379e5c0bce 100644 --- a/src/testing/pkg/rbac/dao/dao.go +++ b/src/testing/pkg/rbac/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/rbac/manager.go b/src/testing/pkg/rbac/manager.go index 0cc460753d..98ea998064 100644 --- a/src/testing/pkg/rbac/manager.go +++ b/src/testing/pkg/rbac/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package rbac diff --git a/src/testing/pkg/reg/adapter/adapter.go b/src/testing/pkg/reg/adapter/adapter.go index a10a0f2ff1..4b18309df8 100644 --- a/src/testing/pkg/reg/adapter/adapter.go +++ b/src/testing/pkg/reg/adapter/adapter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package adapter diff --git a/src/testing/pkg/reg/dao/dao.go b/src/testing/pkg/reg/dao/dao.go index 23ae0ecc8a..e70de513f8 100644 --- a/src/testing/pkg/reg/dao/dao.go +++ b/src/testing/pkg/reg/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/reg/manager.go b/src/testing/pkg/reg/manager.go index c25e542d11..1ead2cc165 100644 --- a/src/testing/pkg/reg/manager.go +++ b/src/testing/pkg/reg/manager.go @@ -1,6 +1,6 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. -package manager +package reg import ( context "context" diff --git a/src/testing/pkg/registry/fake_registry_client.go b/src/testing/pkg/registry/fake_registry_client.go index 72a6decf23..e0b99787af 100644 --- a/src/testing/pkg/registry/fake_registry_client.go +++ b/src/testing/pkg/registry/fake_registry_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package registry diff --git a/src/testing/pkg/replication/dao/dao.go b/src/testing/pkg/replication/dao/dao.go index 29c9a2be49..bcfe17c178 100644 --- a/src/testing/pkg/replication/dao/dao.go +++ b/src/testing/pkg/replication/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/replication/manager.go b/src/testing/pkg/replication/manager.go index 652331740e..a22c831fbb 100644 --- a/src/testing/pkg/replication/manager.go +++ b/src/testing/pkg/replication/manager.go @@ -1,6 +1,6 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. -package manager +package replication import ( context "context" diff --git a/src/testing/pkg/repository/dao/dao.go b/src/testing/pkg/repository/dao/dao.go index 59094a22c6..865fed0ee2 100644 --- a/src/testing/pkg/repository/dao/dao.go +++ b/src/testing/pkg/repository/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/repository/manager.go b/src/testing/pkg/repository/manager.go index db6df7bde6..8f25fc36f4 100644 --- a/src/testing/pkg/repository/manager.go +++ b/src/testing/pkg/repository/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package repository diff --git a/src/testing/pkg/robot/dao/dao.go b/src/testing/pkg/robot/dao/dao.go index f1160128fe..7b9c86106a 100644 --- a/src/testing/pkg/robot/dao/dao.go +++ b/src/testing/pkg/robot/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/robot/manager.go b/src/testing/pkg/robot/manager.go index 12101d09ed..b49aa8a386 100644 --- a/src/testing/pkg/robot/manager.go +++ b/src/testing/pkg/robot/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package robot diff --git a/src/testing/pkg/scan/export/artifact_digest_calculator.go b/src/testing/pkg/scan/export/artifact_digest_calculator.go index 150c11cfd6..0b007f1ebc 100644 --- a/src/testing/pkg/scan/export/artifact_digest_calculator.go +++ b/src/testing/pkg/scan/export/artifact_digest_calculator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package export diff --git a/src/testing/pkg/scan/export/filter_processor.go b/src/testing/pkg/scan/export/filter_processor.go index 4087eba62b..6f35bb4b11 100644 --- a/src/testing/pkg/scan/export/filter_processor.go +++ b/src/testing/pkg/scan/export/filter_processor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package export diff --git a/src/testing/pkg/scan/export/manager.go b/src/testing/pkg/scan/export/manager.go index 158ed47adb..c39505276a 100644 --- a/src/testing/pkg/scan/export/manager.go +++ b/src/testing/pkg/scan/export/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package export diff --git a/src/testing/pkg/scan/handler.go b/src/testing/pkg/scan/handler.go index 7c3d93867f..8e0a953bdd 100644 --- a/src/testing/pkg/scan/handler.go +++ b/src/testing/pkg/scan/handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scan diff --git a/src/testing/pkg/scan/report/manager.go b/src/testing/pkg/scan/report/manager.go index 046ac253e6..a3f18870a1 100644 --- a/src/testing/pkg/scan/report/manager.go +++ b/src/testing/pkg/scan/report/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package report diff --git a/src/testing/pkg/scan/rest/v1/client.go b/src/testing/pkg/scan/rest/v1/client.go index 1d15012c74..1b718adf82 100644 --- a/src/testing/pkg/scan/rest/v1/client.go +++ b/src/testing/pkg/scan/rest/v1/client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package v1 diff --git a/src/testing/pkg/scan/rest/v1/client_pool.go b/src/testing/pkg/scan/rest/v1/client_pool.go index 6533473a81..9a6eb3f617 100644 --- a/src/testing/pkg/scan/rest/v1/client_pool.go +++ b/src/testing/pkg/scan/rest/v1/client_pool.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package v1 diff --git a/src/testing/pkg/scan/rest/v1/request_resolver.go b/src/testing/pkg/scan/rest/v1/request_resolver.go index f5e67b78e2..75fb726a13 100644 --- a/src/testing/pkg/scan/rest/v1/request_resolver.go +++ b/src/testing/pkg/scan/rest/v1/request_resolver.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package v1 diff --git a/src/testing/pkg/scan/rest/v1/response_handler.go b/src/testing/pkg/scan/rest/v1/response_handler.go index 6909341464..3bd7c77c14 100644 --- a/src/testing/pkg/scan/rest/v1/response_handler.go +++ b/src/testing/pkg/scan/rest/v1/response_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package v1 diff --git a/src/testing/pkg/scan/sbom/manager.go b/src/testing/pkg/scan/sbom/manager.go index 464e821ef9..e3be4bf423 100644 --- a/src/testing/pkg/scan/sbom/manager.go +++ b/src/testing/pkg/scan/sbom/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package sbom diff --git a/src/testing/pkg/scan/scanner/manager.go b/src/testing/pkg/scan/scanner/manager.go index 08890ace3f..561f381107 100644 --- a/src/testing/pkg/scan/scanner/manager.go +++ b/src/testing/pkg/scan/scanner/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scanner diff --git a/src/testing/pkg/scheduler/scheduler.go b/src/testing/pkg/scheduler/scheduler.go index 0550dcdf4d..4f64e3dfac 100644 --- a/src/testing/pkg/scheduler/scheduler.go +++ b/src/testing/pkg/scheduler/scheduler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package scheduler diff --git a/src/testing/pkg/securityhub/manager.go b/src/testing/pkg/securityhub/manager.go index 5050fb40db..27d4f58187 100644 --- a/src/testing/pkg/securityhub/manager.go +++ b/src/testing/pkg/securityhub/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package securityhub diff --git a/src/testing/pkg/systemartifact/cleanup/selector.go b/src/testing/pkg/systemartifact/cleanup/selector.go index 68b3f8f20d..f7ebecd2b2 100644 --- a/src/testing/pkg/systemartifact/cleanup/selector.go +++ b/src/testing/pkg/systemartifact/cleanup/selector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package cleanup diff --git a/src/testing/pkg/systemartifact/dao/dao.go b/src/testing/pkg/systemartifact/dao/dao.go index 1d49abae36..aa6a01a2ab 100644 --- a/src/testing/pkg/systemartifact/dao/dao.go +++ b/src/testing/pkg/systemartifact/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/systemartifact/manager.go b/src/testing/pkg/systemartifact/manager.go index 1af03bee80..c2ccccdb1f 100644 --- a/src/testing/pkg/systemartifact/manager.go +++ b/src/testing/pkg/systemartifact/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package systemartifact diff --git a/src/testing/pkg/task/execution_manager.go b/src/testing/pkg/task/execution_manager.go index 7960eea185..92a6ff4f01 100644 --- a/src/testing/pkg/task/execution_manager.go +++ b/src/testing/pkg/task/execution_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/testing/pkg/task/manager.go b/src/testing/pkg/task/manager.go index 299b865809..acc8158984 100644 --- a/src/testing/pkg/task/manager.go +++ b/src/testing/pkg/task/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package task diff --git a/src/testing/pkg/user/dao/dao.go b/src/testing/pkg/user/dao/dao.go index f46ec54d59..b9ee65ab5e 100644 --- a/src/testing/pkg/user/dao/dao.go +++ b/src/testing/pkg/user/dao/dao.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package dao diff --git a/src/testing/pkg/user/manager.go b/src/testing/pkg/user/manager.go index cee323805f..18a642ad37 100644 --- a/src/testing/pkg/user/manager.go +++ b/src/testing/pkg/user/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package user diff --git a/src/testing/pkg/usergroup/fake_usergroup_manager.go b/src/testing/pkg/usergroup/fake_usergroup_manager.go index 8f1bf2d8fc..b6b9007ea3 100644 --- a/src/testing/pkg/usergroup/fake_usergroup_manager.go +++ b/src/testing/pkg/usergroup/fake_usergroup_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package usergroup From c701174ee91b0b3c41479f177ff4942d072f80ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:27:15 +0800 Subject: [PATCH 27/74] chore(deps): bump golang.org/x/oauth2 from 0.20.0 to 0.21.0 in /src (#20713) Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.20.0 to 0.21.0. - [Commits](https://github.com/golang/oauth2/compare/v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 2 +- src/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go.mod b/src/go.mod index 9132e67d1e..ec9430d7f2 100644 --- a/src/go.mod +++ b/src/go.mod @@ -65,7 +65,7 @@ require ( go.uber.org/ratelimit v0.3.1 golang.org/x/crypto v0.24.0 golang.org/x/net v0.26.0 - golang.org/x/oauth2 v0.20.0 + golang.org/x/oauth2 v0.21.0 golang.org/x/sync v0.7.0 golang.org/x/text v0.16.0 golang.org/x/time v0.5.0 diff --git a/src/go.sum b/src/go.sum index 8e965a77d7..f6aa9c4ae0 100644 --- a/src/go.sum +++ b/src/go.sum @@ -762,8 +762,8 @@ golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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= From a4671ee00842c19f393abcdd827e063e69518a22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 16:05:23 +0800 Subject: [PATCH 28/74] chore(deps): bump go.opentelemetry.io/otel from 1.27.0 to 1.28.0 in /src (#20715) Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.27.0 to 1.28.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.27.0...v1.28.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/otel dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 8 ++++---- src/go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/go.mod b/src/go.mod index ec9430d7f2..5dae969d0b 100644 --- a/src/go.mod +++ b/src/go.mod @@ -57,11 +57,11 @@ require ( github.com/volcengine/volcengine-go-sdk v1.0.138 go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 - go.opentelemetry.io/otel v1.27.0 + go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/exporters/jaeger v1.0.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 go.opentelemetry.io/otel/sdk v1.27.0 - go.opentelemetry.io/otel/trace v1.27.0 + go.opentelemetry.io/otel/trace v1.28.0 go.uber.org/ratelimit v0.3.1 golang.org/x/crypto v0.24.0 golang.org/x/net v0.26.0 @@ -107,7 +107,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/jsonpointer v0.20.0 // indirect @@ -165,7 +165,7 @@ require ( github.com/volcengine/volc-sdk-golang v1.0.23 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect diff --git a/src/go.sum b/src/go.sum index f6aa9c4ae0..ff96c4cc55 100644 --- a/src/go.sum +++ b/src/go.sum @@ -184,8 +184,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= @@ -645,22 +645,22 @@ go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel/exporters/jaeger v1.0.0 h1:cLhx8llHw02h5JTqGqaRbYn+QVKHmrzD9vEbKnSPk5U= go.opentelemetry.io/otel/exporters/jaeger v1.0.0/go.mod h1:q10N1AolE1JjqKrFJK2tYw0iZpmX+HBaXBtuCzRnBGQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM= go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= From 2dd029e7026bbc11b4a71e627e13fd3975508457 Mon Sep 17 00:00:00 2001 From: MinerYang Date: Wed, 24 Jul 2024 16:41:58 +0800 Subject: [PATCH 29/74] make distribution_src configurable (#20769) Signed-off-by: yminer --- Makefile | 4 +++- make/photon/Makefile | 2 +- make/photon/registry/builder | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1c0c02e8ad..0dfd8b6e44 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,8 @@ TRIVYADAPTERVERSION=v0.31.2 # version of registry for pulling the source code REGISTRY_SRC_TAG=v2.8.3 +# source of upstream distribution code +DISTRIBUTION_SRC=https://github.com/distribution/distribution.git # dependency binaries REGISTRYURL=https://storage.googleapis.com/harbor-builds/bin/registry/release-${REGISTRYVERSION}/registry @@ -388,7 +390,7 @@ build: exit 1; \ fi make -f $(MAKEFILEPATH_PHOTON)/Makefile $(BUILDTARGET) -e DEVFLAG=$(DEVFLAG) -e GOBUILDIMAGE=$(GOBUILDIMAGE) \ - -e REGISTRYVERSION=$(REGISTRYVERSION) -e REGISTRY_SRC_TAG=$(REGISTRY_SRC_TAG) \ + -e REGISTRYVERSION=$(REGISTRYVERSION) -e REGISTRY_SRC_TAG=$(REGISTRY_SRC_TAG) -e DISTRIBUTION_SRC=$(DISTRIBUTION_SRC)\ -e TRIVYVERSION=$(TRIVYVERSION) -e TRIVYADAPTERVERSION=$(TRIVYADAPTERVERSION) \ -e VERSIONTAG=$(VERSIONTAG) \ -e BUILDBIN=$(BUILDBIN) \ diff --git a/make/photon/Makefile b/make/photon/Makefile index c6de67da34..0dc0678cc0 100644 --- a/make/photon/Makefile +++ b/make/photon/Makefile @@ -178,7 +178,7 @@ _build_registry: rm -rf $(DOCKERFILEPATH_REG)/binary && mkdir -p $(DOCKERFILEPATH_REG)/binary && \ $(call _get_binary, $(REGISTRYURL), $(DOCKERFILEPATH_REG)/binary/registry); \ else \ - cd $(DOCKERFILEPATH_REG) && $(DOCKERFILEPATH_REG)/builder $(REGISTRY_SRC_TAG) && cd - ; \ + cd $(DOCKERFILEPATH_REG) && $(DOCKERFILEPATH_REG)/builder $(REGISTRY_SRC_TAG) $(DISTRIBUTION_SRC) && cd - ; \ fi @echo "building registry container for photon..." @chmod 655 $(DOCKERFILEPATH_REG)/binary/registry && $(DOCKERBUILD_WITH_PULL_PARA) --build-arg harbor_base_image_version=$(BASEIMAGETAG) --build-arg harbor_base_namespace=$(BASEIMAGENAMESPACE) -f $(DOCKERFILEPATH_REG)/$(DOCKERFILENAME_REG) -t $(DOCKERIMAGENAME_REG):$(VERSIONTAG) . diff --git a/make/photon/registry/builder b/make/photon/registry/builder index e076f8565d..0c254cbf7b 100755 --- a/make/photon/registry/builder +++ b/make/photon/registry/builder @@ -7,7 +7,13 @@ if [ -z $1 ]; then exit 1 fi +if [ -z $2 ]; then + error "Please set the 'distribution_src' variable" + exit 1 +fi + VERSION="$1" +DISTRIBUTION_SRC="$2" set -e @@ -20,7 +26,7 @@ cur=$PWD # the temp folder to store distribution source code... TEMP=`mktemp -d ${TMPDIR-/tmp}/distribution.XXXXXX` -git clone -b $VERSION https://github.com/distribution/distribution.git $TEMP +git clone -b $VERSION $DISTRIBUTION_SRC $TEMP # add patch redis cd $TEMP From d4c99d2dd16496aaf186eb62b310f7a8fa5eeb64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:32:04 +0800 Subject: [PATCH 30/74] chore(deps): bump github.com/spf13/viper from 1.8.1 to 1.19.0 in /src (#20716) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.8.1 to 1.19.0. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.8.1...v1.19.0) --- updated-dependencies: - dependency-name: github.com/spf13/viper dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: Shengwen YU Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 33 +++++---- src/go.sum | 206 +++++++++++------------------------------------------ 2 files changed, 58 insertions(+), 181 deletions(-) diff --git a/src/go.mod b/src/go.mod index 5dae969d0b..652335ca8e 100644 --- a/src/go.mod +++ b/src/go.mod @@ -50,7 +50,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.1 github.com/robfig/cron/v3 v3.0.1 - github.com/spf13/viper v1.8.1 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible github.com/vmihailenco/msgpack/v5 v5.4.1 @@ -96,7 +96,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denverdino/aliyungo v0.0.0-20191227032621-df38c6fa730c // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dnaeon/go-vcr v1.2.0 // indirect @@ -105,7 +105,7 @@ require ( github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -133,9 +133,9 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/magiconair/properties v1.8.5 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -144,21 +144,23 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/robfig/cron v1.0.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/subosito/gotenv v1.2.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -168,18 +170,19 @@ require ( go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.19.1 // indirect + go.uber.org/multierr v1.9.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect - google.golang.org/api v0.169.0 // indirect + google.golang.org/api v0.171.0 // indirect google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect diff --git a/src/go.sum b/src/go.sum index ff96c4cc55..a355858092 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,17 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go v37.2.0+incompatible h1:LTdcd2GK+cv+e7yhWCN8S7yf3eblBypKFZsPfKjCQ7E= @@ -47,7 +36,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/FZambia/sentinel v1.1.0 h1:qrCBfxc8SvJihYNjBWgwUI93ZCvFe/PJIPTHKmlp8a8= github.com/FZambia/sentinel v1.1.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= @@ -68,10 +56,6 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1L github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97 h1:bNE5ID4C3YOkROfvBjXJUG53gyb+8az3TQN02LqnGBk= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190726115642-cd293c93fd97/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -90,8 +74,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM= @@ -105,24 +87,21 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc= github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20191227032621-df38c6fa730c h1:ZjNKFQ2pBtbkmtporMvGVu2M7fs3Ip3sSy0Gyqsq8xc= github.com/denverdino/aliyungo v0.0.0-20191227032621-df38c6fa730c/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dghubble/sling v1.1.0 h1:DLu20Bq2qsB9cI5Hldaxj+TMPEaPpPE8IR2kvD22Atg= @@ -156,24 +135,19 @@ github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -229,7 +203,6 @@ github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8 h1:hp1oqdzmv37vPLYF github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/gocraft/work v0.5.1 h1:3bRjMiOo6N4zcRgZWV3Y7uX7R22SF+A9bPTk4xRXr34= github.com/gocraft/work v0.5.1/go.mod h1:pc3n9Pb5FAESPPGfM0nL+7Q1xtgtRnF8rr/azzhQVlM= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -246,11 +219,9 @@ github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMn github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -266,8 +237,6 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E= github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -288,16 +257,12 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= @@ -310,38 +275,19 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -404,21 +350,18 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 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.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -436,17 +379,15 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -455,16 +396,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -514,17 +447,15 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= @@ -548,7 +479,6 @@ github.com/robfig/cron v1.0.0 h1:slmQxIUH6U9ruw4XoJ7C2pyyx4yYeiHx8S9pNootHsM= github.com/robfig/cron v1.0.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= 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/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= @@ -556,10 +486,12 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik= github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -574,20 +506,18 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 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/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -604,10 +534,11 @@ 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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible h1:q+D/Y9jla3afgsIihtyhwyl0c2W+eRWNM9ohVwPiiPw= github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -633,13 +564,9 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0 h1:rXpHmgy1pMXlfv3W1T5ctoDA3QeTFjNq/YwCmwrfr8Q= go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.51.0/go.mod h1:9uIRD3NZrM7QMQEGeKhr7V4xSDTMku3MPOVs8iZ3VVk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= @@ -670,29 +597,26 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +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/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= @@ -706,23 +630,13 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -734,21 +648,15 @@ golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -767,7 +675,6 @@ golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht 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= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -776,21 +683,15 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -804,7 +705,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -830,7 +730,6 @@ 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.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -845,28 +744,18 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -882,30 +771,18 @@ google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff h1:mk5zS3XLqVUzdF/CQCZ5 google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= 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.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 h1:Cpp2P6TPjujNoC5M2KHY6g7wfyLYfIWRZaSdIKfDasA= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -936,13 +813,12 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/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= @@ -959,7 +835,6 @@ gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= helm.sh/helm/v3 v3.15.2 h1:/3XINUFinJOBjQplGnjw92eLGpgXXp1L8chWPkCkDuw= helm.sh/helm/v3 v3.15.2/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= @@ -974,7 +849,6 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 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/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= From e0b94aa7d7277fede3b42add7332d5dc8d5df3f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:01:47 +0800 Subject: [PATCH 31/74] chore(deps): bump google.golang.org/grpc from 1.64.0 to 1.64.1 in /src (#20721) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.64.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: Shengwen YU Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shengwen YU --- src/go.mod | 2 +- src/go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/go.mod b/src/go.mod index 652335ca8e..cb3fc840e9 100644 --- a/src/go.mod +++ b/src/go.mod @@ -179,7 +179,7 @@ require ( google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect - google.golang.org/grpc v1.64.0 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/src/go.sum b/src/go.sum index a355858092..3f704380ad 100644 --- a/src/go.sum +++ b/src/go.sum @@ -783,8 +783,10 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go. 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.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= 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= From 295e075568aff89599b1fcfdb9adbb6b1a17ec07 Mon Sep 17 00:00:00 2001 From: Shengwen YU Date: Thu, 1 Aug 2024 16:05:39 +0800 Subject: [PATCH 32/74] add Test Case for SBOM feature (#20797) Signed-off-by: Shengwen Yu --- tests/apitests/python/library/artifact.py | 25 +++++ tests/apitests/python/library/scan.py | 15 +++ tests/apitests/python/library/scan_stop.py | 15 +++ .../python/test_project_permission.py | 15 ++- .../test_sbom_generation_of_image_artifact.py | 87 ++++++++++++++++++ ..._stop_sbom_generation_of_image_artifact.py | 91 +++++++++++++++++++ .../Harbor-Pages/Project-Repository.robot | 17 +++- .../Project-Repository_Elements.robot | 5 +- .../Harbor-Pages/Vulnerability.robot | 35 +++++++ tests/resources/TestCaseBody.robot | 43 +++++++++ tests/robot-cases/Group0-BAT/API_DB.robot | 8 ++ tests/robot-cases/Group1-Nightly/Trivy.robot | 12 +++ 12 files changed, 359 insertions(+), 9 deletions(-) create mode 100644 tests/apitests/python/test_sbom_generation_of_image_artifact.py create mode 100644 tests/apitests/python/test_stop_sbom_generation_of_image_artifact.py diff --git a/tests/apitests/python/library/artifact.py b/tests/apitests/python/library/artifact.py index d8b6905b96..eca6a37c82 100644 --- a/tests/apitests/python/library/artifact.py +++ b/tests/apitests/python/library/artifact.py @@ -30,6 +30,8 @@ class Artifact(base.Base, object): if "with_scan_overview" in kwargs: params["with_scan_overview"] = kwargs["with_scan_overview"] params["x_accept_vulnerabilities"] = ",".join(report_mime_types) + if "with_sbom_overview" in kwargs: + params["with_sbom_overview"] = kwargs["with_sbom_overview"] if "with_immutable_status" in kwargs: params["with_immutable_status"] = kwargs["with_immutable_status"] if "with_accessory" in kwargs: @@ -140,6 +142,29 @@ class Artifact(base.Base, object): return raise Exception("Scan image result is {}, not as expected {}.".format(scan_status, expected_scan_status)) + def check_image_sbom_generation_result(self, project_name, repo_name, reference, expected_scan_status = "Success", **kwargs): + timeout_count = 30 + scan_status="" + while True: + time.sleep(5) + timeout_count = timeout_count - 1 + if (timeout_count == 0): + break + artifact = self.get_reference_info(project_name, repo_name, reference, **kwargs) + if expected_scan_status in ["Not Scanned", "No SBOM Overview"]: + if artifact.sbom_overview is None: + if (timeout_count > 24): + continue + print("artifact SBOM is not generated.") + return + else: + raise Exception("Artifact SBOM should not be generated {}.".format(artifact.sbom_overview)) + + scan_status = artifact.sbom_overview.scan_status + if scan_status == expected_scan_status: + return + raise Exception("Generate image SBOM result is {}, not as expected {}.".format(scan_status, expected_scan_status)) + def check_reference_exist(self, project_name, repo_name, reference, ignore_not_found = False, **kwargs): artifact = self.get_reference_info( project_name, repo_name, reference, ignore_not_found=ignore_not_found, **kwargs) return { diff --git a/tests/apitests/python/library/scan.py b/tests/apitests/python/library/scan.py index a9260e2d64..6af92200fa 100644 --- a/tests/apitests/python/library/scan.py +++ b/tests/apitests/python/library/scan.py @@ -21,3 +21,18 @@ class Scan(base.Base, object): base._assert_status_code(expect_status_code, status_code) return data + + def sbom_generation_of_artifact(self, project_name, repo_name, reference, expect_status_code = 202, expect_response_body = None, **kwargs): + try: + req_param = dict(scan_type = {"scan_type":"sbom"}) + data, status_code, _ = self._get_client(**kwargs).scan_artifact_with_http_info(project_name, repo_name, reference, **req_param) + except ApiException as e: + base._assert_status_code(expect_status_code, e.status) + if expect_response_body is not None: + base._assert_status_body(expect_response_body, e.body) + return + + base._assert_status_code(expect_status_code, status_code) + + return data + diff --git a/tests/apitests/python/library/scan_stop.py b/tests/apitests/python/library/scan_stop.py index e002239b27..80507ebbb5 100644 --- a/tests/apitests/python/library/scan_stop.py +++ b/tests/apitests/python/library/scan_stop.py @@ -22,4 +22,19 @@ class StopScan(base.Base, object): base._assert_status_code(expect_status_code, status_code) + return data + + def stop_sbom_generation_of_artifact(self, project_name, repo_name, reference, expect_status_code = 202, expect_response_body = None, **kwargs): + try: + scanType = v2_swagger_client.ScanType() + scanType.scan_type = "sbom" + data, status_code, _ = self._get_client(**kwargs).stop_scan_artifact_with_http_info(project_name, repo_name, reference, scanType) + except ApiException as e: + base._assert_status_code(expect_status_code, e.status) + if expect_response_body is not None: + base._assert_status_body(expect_response_body, e.body) + return + + base._assert_status_code(expect_status_code, status_code) + return data \ No newline at end of file diff --git a/tests/apitests/python/test_project_permission.py b/tests/apitests/python/test_project_permission.py index 491eba2dcb..a7533c7229 100644 --- a/tests/apitests/python/test_project_permission.py +++ b/tests/apitests/python/test_project_permission.py @@ -73,7 +73,7 @@ list_metadata = Permission("{}/projects/{}/metadatas".format(harbor_base_url, pr read_metadata = Permission("{}/projects/{}/metadatas/auto_scan".format(harbor_base_url, project_id), "GET", 200, metadata_payload) metadata_payload_for_update = { "auto_scan": "false" } update_metadata = Permission("{}/projects/{}/metadatas/auto_scan".format(harbor_base_url, project_id), "PUT", 200, metadata_payload_for_update) -delete_metadata = Permission("{}/projects/{}/metadatas/auto_scan".format(harbor_base_url, project_id), "DELETE", 200, metadata_payload) +delete_metadata = Permission("{}/projects/{}/metadatas/auto_scan".format(harbor_base_url, project_id), "DELETE", 200, metadata_payload_for_update) # 4. Resource: repository actions: ['read', 'list', 'update', 'delete', 'pull', 'push'] # note: pull and push are for docker cli, no API needs them @@ -89,12 +89,17 @@ copy_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts?fr delete_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts/{}".format(harbor_base_url, project_name, source_artifact_tag), "DELETE", 200) # 6. Resource scan actions: ['read', 'create', 'stop'] -stop_scan_payload = { +vulnerability_scan_payload = { "scan_type": "vulnerability" } -create_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202) -stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, stop_scan_payload) +create_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, vulnerability_scan_payload) +stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, vulnerability_scan_payload) read_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/83be44fd-1234-5678-b49f-4b6d6e8f5730/log".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "get", 404) +sbom_gen_payload = { + "scan_type": "sbom" +} +create_sbom_generation = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, sbom_gen_payload) +stop_sbom_generation = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, sbom_gen_payload) # 7. Resource tag actions: ['list', 'create', 'delete'] tag_payload = { "name": "test-{}".format(int(random.randint(1000, 9999))) } @@ -240,7 +245,7 @@ resource_permissions = { "metadata": [create_metadata, list_metadata, read_metadata, update_metadata, delete_metadata], "repository": [list_repo, read_repo, update_repo, delete_repo], "artifact": [list_artifact, read_artifact, copy_artifact, delete_artifact], - "scan": [create_scan, stop_scan, read_scan], + "scan": [create_scan, stop_scan, read_scan, create_sbom_generation, stop_sbom_generation], "tag": [create_tag, list_tag, delete_tag], "accessory": [list_accessory], "artifact-addition": [read_artifact_addition_vul, read_artifact_addition_dependencies], diff --git a/tests/apitests/python/test_sbom_generation_of_image_artifact.py b/tests/apitests/python/test_sbom_generation_of_image_artifact.py new file mode 100644 index 0000000000..8025fafe3b --- /dev/null +++ b/tests/apitests/python/test_sbom_generation_of_image_artifact.py @@ -0,0 +1,87 @@ +from __future__ import absolute_import +import unittest +import sys + +from testutils import harbor_server, suppress_urllib3_warning +from testutils import TEARDOWN +from testutils import ADMIN_CLIENT, BASE_IMAGE, BASE_IMAGE_ABS_PATH_NAME +from library.project import Project +from library.user import User +from library.repository import Repository +from library.repository import push_self_build_image_to_project +from library.artifact import Artifact +from library.scan import Scan + +class TestSBOMGeneration(unittest.TestCase): + @suppress_urllib3_warning + def setUp(self): + self.project= Project() + self.user= User() + self.artifact = Artifact() + self.repo = Repository() + self.scan = Scan() + + self.url = ADMIN_CLIENT["endpoint"] + self.user_password = "Aa123456" + self.project_id, self.project_name, self.user_id, self.user_name, self.repo_name1 = [None] * 5 + self.user_id, self.user_name = self.user.create_user(user_password = self.user_password, **ADMIN_CLIENT) + self.USER_CLIENT = dict(with_signature = True, with_immutable_status = True, endpoint = self.url, username = self.user_name, password = self.user_password, with_sbom_overview = True) + + + #2. Create a new private project(PA) by user(UA); + self.project_id, self.project_name = self.project.create_project(metadata = {"public": "false"}, **ADMIN_CLIENT) + + #3. Add user(UA) as a member of project(PA) with project-admin role; + self.project.add_project_members(self.project_id, user_id = self.user_id, **ADMIN_CLIENT) + + @unittest.skipIf(TEARDOWN == False, "Test data won't be erased.") + def do_tearDown(self): + #1. Delete repository(RA) by user(UA); + self.repo.delete_repository(self.project_name, self.repo_name1.split('/')[1], **self.USER_CLIENT) + + #2. Delete project(PA); + self.project.delete_project(self.project_id, **self.USER_CLIENT) + + #3. Delete user(UA); + self.user.delete_user(self.user_id, **ADMIN_CLIENT) + + def testGenerateSBOMOfImageArtifact(self): + """ + Test case: + Generate an SBOM of An Image Artifact + Test step and expected result: + 1. Create a new user(UA); + 2. Create a new private project(PA) by user(UA); + 3. Add user(UA) as a member of project(PA) with project-admin role; + 4. Get private project of user(UA), user(UA) can see only one private project which is project(PA); + 5. Create a new repository(RA) and tag(TA) in project(PA) by user(UA); + 6. Send sbom generation of an image command and get tag(TA) information to check sbom generation result, it should be finished; + Tear down: + 1. Delete repository(RA) by user(UA); + 2. Delete project(PA); + 3. Delete user(UA); + """ + + #4. Get private project of user(UA), user(UA) can see only one private project which is project(PA); + self.project.projects_should_exist(dict(public=False), expected_count = 1, + expected_project_id = self.project_id, **self.USER_CLIENT) + + #Note: Please make sure that this Image has never been pulled before by any other cases, + # so it is a not-scanned image right after repository creation. + image = "docker" + src_tag = "1.13" + #5. Create a new repository(RA) and tag(TA) in project(PA) by user(UA); + self.repo_name1, tag = push_self_build_image_to_project(self.project_name, harbor_server, self.user_name, self.user_password, image, src_tag) + + #6. Send sbom generation of an image command and get tag(TA) information to check sbom generation result, it should be finished; + self.scan.sbom_generation_of_artifact(self.project_name, self.repo_name1.split('/')[1], tag, **self.USER_CLIENT) + self.artifact.check_image_sbom_generation_result(self.project_name, image, tag, **self.USER_CLIENT) + + self.do_tearDown() + + +if __name__ == '__main__': + suite = unittest.TestSuite(unittest.makeSuite(TestSBOMGeneration)) + result = unittest.TextTestRunner(sys.stdout, verbosity=2, failfast=True).run(suite) + if not result.wasSuccessful(): + raise Exception(r"SBOM generation test failed: {}".format(result)) diff --git a/tests/apitests/python/test_stop_sbom_generation_of_image_artifact.py b/tests/apitests/python/test_stop_sbom_generation_of_image_artifact.py new file mode 100644 index 0000000000..232e5e85dd --- /dev/null +++ b/tests/apitests/python/test_stop_sbom_generation_of_image_artifact.py @@ -0,0 +1,91 @@ +from __future__ import absolute_import +import unittest +import sys + +from testutils import harbor_server, suppress_urllib3_warning +from testutils import TEARDOWN +from testutils import ADMIN_CLIENT, BASE_IMAGE, BASE_IMAGE_ABS_PATH_NAME +from library.project import Project +from library.user import User +from library.repository import Repository +from library.repository import push_self_build_image_to_project +from library.artifact import Artifact +from library.scan import Scan +from library.scan_stop import StopScan + +class TestStopSBOMGeneration(unittest.TestCase): + @suppress_urllib3_warning + def setUp(self): + self.project= Project() + self.user= User() + self.artifact = Artifact() + self.repo = Repository() + self.scan = Scan() + self.stop_scan = StopScan() + + self.url = ADMIN_CLIENT["endpoint"] + self.user_password = "Aa123456" + self.project_id, self.project_name, self.user_id, self.user_name, self.repo_name1 = [None] * 5 + self.user_id, self.user_name = self.user.create_user(user_password = self.user_password, **ADMIN_CLIENT) + self.USER_CLIENT = dict(with_signature = True, with_immutable_status = True, endpoint = self.url, username = self.user_name, password = self.user_password, with_sbom_overview = True) + + + #2. Create a new private project(PA) by user(UA); + self.project_id, self.project_name = self.project.create_project(metadata = {"public": "false"}, **ADMIN_CLIENT) + + #3. Add user(UA) as a member of project(PA) with project-admin role; + self.project.add_project_members(self.project_id, user_id = self.user_id, **ADMIN_CLIENT) + + @unittest.skipIf(TEARDOWN == False, "Test data won't be erased.") + def do_tearDown(self): + #1. Delete repository(RA) by user(UA); + self.repo.delete_repository(self.project_name, self.repo_name1.split('/')[1], **self.USER_CLIENT) + + #2. Delete project(PA); + self.project.delete_project(self.project_id, **self.USER_CLIENT) + + #3. Delete user(UA); + self.user.delete_user(self.user_id, **ADMIN_CLIENT) + + def testStopSBOMGenerationOfImageArtifact(self): + """ + Test case: + Stop SBOM Generation Of An Image Artifact + Test step and expected result: + 1. Create a new user(UA); + 2. Create a new private project(PA) by user(UA); + 3. Add user(UA) as a member of project(PA) with project-admin role; + 4. Get private project of user(UA), user(UA) can see only one private project which is project(PA); + 5. Create a new repository(RA) and tag(TA) in project(PA) by user(UA); + 6. Send SBOM generation of an image command; + 7. Send stop SBOM generation of an image command. + Tear down: + 1. Delete repository(RA) by user(UA); + 2. Delete project(PA); + 3. Delete user(UA); + """ + + #4. Get private project of user(UA), user(UA) can see only one private project which is project(PA); + self.project.projects_should_exist(dict(public=False), expected_count = 1, + expected_project_id = self.project_id, **self.USER_CLIENT) + + #Note: Please make sure that this Image has never been pulled before by any other cases, + # so it is a not-scanned image right after repository creation. + image = "docker" + src_tag = "1.13" + #5. Create a new repository(RA) and tag(TA) in project(PA) by user(UA); + self.repo_name1, tag = push_self_build_image_to_project(self.project_name, harbor_server, self.user_name, self.user_password, image, src_tag) + + #6. Send SBOM generation of an image command; + self.scan.sbom_generation_of_artifact(self.project_name, self.repo_name1.split('/')[1], tag, **self.USER_CLIENT) + + #7. Send stop SBOM generation of an image command. + self.stop_scan.stop_sbom_generation_of_artifact(self.project_name, self.repo_name1.split('/')[1], tag, **self.USER_CLIENT) + + self.do_tearDown() + +if __name__ == '__main__': + suite = unittest.TestSuite(unittest.makeSuite(TestStopSBOMGeneration)) + result = unittest.TextTestRunner(sys.stdout, verbosity=2, failfast=True).run(suite) + if not result.wasSuccessful(): + raise Exception(r"Stop SBOM generation test failed: {}".format(result)) diff --git a/tests/resources/Harbor-Pages/Project-Repository.robot b/tests/resources/Harbor-Pages/Project-Repository.robot index 04c0b355b3..1eef8e0685 100644 --- a/tests/resources/Harbor-Pages/Project-Repository.robot +++ b/tests/resources/Harbor-Pages/Project-Repository.robot @@ -41,9 +41,20 @@ Stop Scan Artifact Retry Element Click ${stop_scan_artifact_btn} Check Scan Artifact Job Status Is Stopped - Wait Until Element Is Visible ${stopped_label} - ${job_status}= Get Text ${stopped_label} - Should Be Equal As Strings '${job_status}' 'Scan stopped' + Wait Until Element Is Visible ${scan_stopped_label} + +Generate Artifact SBOM + [Arguments] ${project} ${repo} ${label_xpath}=//clr-dg-row//label[contains(@class,'clr-control-label')][1] + Go Into Repo ${project} ${repo} + Retry Element Click ${label_xpath} + Retry Element Click ${gen_artifact_sbom_btn} + +Stop Gen Artifact SBOM + Retry Element Click ${artifact_action_xpath} + Retry Element Click ${stop_gen_artifact_sbom_btn} + +Check Gen Artifact SBOM Job Status Is Stopped + Wait Until Element Is Visible ${gen_sbom_stopped_label} Refresh Repositories Retry Element Click ${refresh_repositories_xpath} diff --git a/tests/resources/Harbor-Pages/Project-Repository_Elements.robot b/tests/resources/Harbor-Pages/Project-Repository_Elements.robot index 6cb3440586..66c6aa7ffe 100644 --- a/tests/resources/Harbor-Pages/Project-Repository_Elements.robot +++ b/tests/resources/Harbor-Pages/Project-Repository_Elements.robot @@ -24,5 +24,8 @@ ${build_history_data} //clr-dg-row ${push_image_command_btn} //hbr-push-image-button//button ${scan_artifact_btn} //button[@id='scan-btn'] ${stop_scan_artifact_btn} //button[@id='stop-scan'] -${stopped_label} //span[@class='label stopped'] +${scan_stopped_label} //span[normalize-space()='Scan stopped'] +${gen_sbom_stopped_label} //span[normalize-space()='Generation stopped'] +${gen_artifact_sbom_btn} //button[@id='generate-sbom-btn'] +${stop_gen_artifact_sbom_btn} //button[@id='stop-sbom-btn'] ${refresh_repositories_xpath} //hbr-repository-gridview//span[contains(@class,'refresh-btn')] \ No newline at end of file diff --git a/tests/resources/Harbor-Pages/Vulnerability.robot b/tests/resources/Harbor-Pages/Vulnerability.robot index b7fb6d430f..03ed48eefa 100644 --- a/tests/resources/Harbor-Pages/Vulnerability.robot +++ b/tests/resources/Harbor-Pages/Vulnerability.robot @@ -59,6 +59,41 @@ Enable Scan On Push Checkbox Should Be Selected //clr-checkbox-wrapper[@id='scan-image-on-push-wrapper']//input Retry Element Click ${project_config_save_btn} +Generate Repo SBOM + [Arguments] ${tagname} ${status} + Retry Element Click //clr-dg-row[contains(.,'${tagname}')]//label[contains(@class,'clr-control-label')] + Retry Element Click //button[@id='generate-sbom-btn'] + Run Keyword If '${status}' == 'Succeed' Wait Until Element Is Visible //a[@title='SBOM details'] 300 + +Checkout And Review SBOM Details + [Arguments] ${tagname} + Retry Element Click //clr-dg-row[contains(.,'${tagname}')]//a[@title='SBOM details'] + # Download SBOM file + Retry Element Click //button[@id='sbom-btn'] + ${sbom_artifact_short_sha256}= Get Text //span[@class='margin-left-10px'] + ${sbom_filename_raw}= Get Text //clr-dg-cell[contains(text(),'${sbom_artifact_short_sha256}')] + ${sbom_filename}= Replace String ${sbom_filename_raw} : _ count=-1 + ${sbom_filename}= Replace String ${sbom_filename} / _ count=-1 + ${sbom_json_path}= Set Variable ${download_directory}/${sbom_filename}.json + Retry File Should Exist ${sbom_json_path} + # Load the downloaded SBOM json file and verify the first N package records + ${sbom_json_content}= Load Json From File ${sbom_json_path} + ${items}= Get Value From JSON ${sbom_json_content} packages + ${items_length}= Get Length ${items} + ${first_n_records}= Evaluate min(5, ${items_length}) + FOR ${idx} IN RANGE 1 ${first_n_records} + ${item}= Get From List ${items} ${idx} + Wait Until Element Is Visible //clr-dg-cell[normalize-space()='${item.name}'] + Wait Until Element Is Visible //clr-dg-cell[normalize-space()='${item.versionInfo}'] + Wait Until Element Is Visible //clr-dg-cell[normalize-space()='${item.licenseConcluded}'] + END + +Enable Generating SBOM On Push + Checkbox Should Not Be Selected //clr-checkbox-wrapper[@id='generate-sbom-on-push-wrapper']//input + Retry Element Click //clr-checkbox-wrapper[@id='generate-sbom-on-push-wrapper']//label[contains(@class,'clr-control-label')] + Checkbox Should Be Selected //clr-checkbox-wrapper[@id='generate-sbom-on-push-wrapper']//input + Retry Element Click ${project_config_save_btn} + Vulnerability Not Ready Project Hint Sleep 2 ${element}= Set Variable xpath=//span[contains(@class, 'db-status-warning')] diff --git a/tests/resources/TestCaseBody.robot b/tests/resources/TestCaseBody.robot index fc785a1858..9c721d8deb 100644 --- a/tests/resources/TestCaseBody.robot +++ b/tests/resources/TestCaseBody.robot @@ -417,6 +417,49 @@ Stop Scan All Stop Scan All Artifact Retry Action Keyword Check Scan All Artifact Job Status Is Stopped +Body Of Generate SBOM of An Image In The Repo + [Arguments] ${image_argument} ${tag_argument} + Init Chrome Driver + + ${d}= get current date result_format=%m%s + Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} + Create An New Project And Go Into Project project${d} + Push Image ${ip} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} project${d} ${image_argument}:${tag_argument} + Go Into Repo project${d} ${image_argument} + Generate Repo SBOM ${tag_argument} Succeed + Checkout And Review SBOM Details ${tag_argument} + Close Browser + +Body Of Generate Image SBOM On Push + Init Chrome Driver + ${d}= get current date result_format=%m%s + Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} + Create An New Project And Go Into Project project${d} + Goto Project Config + Enable Generating SBOM On Push + Push Image ${ip} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} project${d} memcached + Go Into Repo project${d} memcached + Checkout And Review SBOM Details latest + Close Browser + +Body Of Stop SBOM Manual Generation + Init Chrome Driver + ${d}= get current date result_format=%m%s + ${repo}= Set Variable goharbor/harbor-e2e-engine + ${tag}= Set Variable test-ui + Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} + Create An New Project And Go Into Project project${d} + Push Image With Tag ${ip} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} project${d} ${repo} ${tag} ${tag} + # stop generate sbom of an artifact + Retry Action Keyword Stop SBOM Generation project${d} ${repo} + Close Browser + +Stop SBOM Generation + [Arguments] ${project_name} ${repo} + Generate Artifact SBOM ${project_name} ${repo} + Stop Gen Artifact SBOM + Retry Action Keyword Check Gen Artifact SBOM Job Status Is Stopped + Prepare Image Package Test Files [Arguments] ${files_path} ${rc} ${output}= Run And Return Rc And Output bash tests/robot-cases/Group0-Util/prepare_imgpkg_test_files.sh ${files_path} diff --git a/tests/robot-cases/Group0-BAT/API_DB.robot b/tests/robot-cases/Group0-BAT/API_DB.robot index f1a92b7205..7e5bae3c23 100644 --- a/tests/robot-cases/Group0-BAT/API_DB.robot +++ b/tests/robot-cases/Group0-BAT/API_DB.robot @@ -120,6 +120,14 @@ Test Case - Stop Scan All Images [Tags] stop_scan_all Harbor API Test ./tests/apitests/python/test_system_level_stop_scan_all.py +Test Case - Generate SBOM Of An Image + [Tags] generate_sbom + Harbor API Test ./tests/apitests/python/test_sbom_generation_of_image_artifact.py + +Test Case - Stop Generating SBOM Of An Image + [Tags] stop_generating_sbom + Harbor API Test ./tests/apitests/python/test_stop_sbom_generation_of_image_artifact.py + Test Case - Registry API [Tags] reg_api Harbor API Test ./tests/apitests/python/test_registry_api.py diff --git a/tests/robot-cases/Group1-Nightly/Trivy.robot b/tests/robot-cases/Group1-Nightly/Trivy.robot index bcfff07d24..4d976ace38 100644 --- a/tests/robot-cases/Group1-Nightly/Trivy.robot +++ b/tests/robot-cases/Group1-Nightly/Trivy.robot @@ -164,6 +164,18 @@ Test Case - Stop Scan And Stop Scan All [Tags] stop_scan_job Body Of Stop Scan And Stop Scan All +Test Case - Verify SBOM Manual Generation + [Tags] sbom_manual_gen + Body Of Generate SBOM of An Image In The Repo alpine 3.10 + +Test Case - Generate Image SBOM On Push + [Tags] run-once + Body Of Generate Image SBOM On Push + +Test Case - Stop SBOM Manual Generation + [Tags] stop_sbom_gen + Body Of Stop SBOM Manual Generation + Test Case - External Scanner CRUD [Tags] external_scanner_crud need_scanner_endpoint ${SCANNER_ENDPOINT_VALUE}= Get Variable Value ${SCANNER_ENDPOINT} ${EMPTY} From 5deedf4c7cb9e858dd698aa0f79073ee46886376 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Mon, 5 Aug 2024 19:11:05 +0800 Subject: [PATCH 33/74] refactor: unify the mock file generation (#20765) 1. Mock remote interface for distribution manifest by mockery package feature. 2. Refactor hand-generated mock files to automated management generation. 3. Clean useless mocks. Signed-off-by: chlins --- src/.mockery.yaml | 81 ++++-- src/controller/artifact/controller_test.go | 8 +- .../artifact/processor/chart/chart_test.go | 6 +- src/controller/p2p/preheat/controllor_test.go | 8 +- src/controller/p2p/preheat/enforcer_test.go | 4 +- src/controller/scan/base_controller_test.go | 5 +- src/controller/scan/callback_test.go | 4 +- src/controller/securityhub/controller_test.go | 4 +- src/controller/tag/controller_test.go | 50 ++-- .../job/impl/gc/garbage_collection_test.go | 20 +- src/pkg/scan/vulnerability/vul_test.go | 7 +- src/testing/lib/libcache/cache.go | 136 ---------- src/testing/pkg/artifactrash/manager.go | 129 +++++++-- src/testing/pkg/chart/operator.go | 94 +++++-- src/testing/pkg/distribution/manifest.go | 19 +- src/testing/pkg/immutable/matcher.go | 54 +++- .../pkg/p2p/preheat/instance/manager.go | 90 ++++-- src/testing/pkg/p2p/preheat/policy/manager.go | 108 ++++++-- src/testing/pkg/parser/parser.go | 24 +- src/testing/pkg/processor/processor.go | 40 ++- .../scan/dao/scan/vulnerability_record_dao.go | 256 ------------------ .../native_scan_report_converter.go | 91 +++++++ .../scan/postprocessors/report_converters.go | 23 -- src/testing/pkg/tag/manager.go | 239 ++++++++++++---- src/testing/registryctl/client.go | 80 +++++- 25 files changed, 926 insertions(+), 654 deletions(-) delete mode 100644 src/testing/lib/libcache/cache.go delete mode 100644 src/testing/pkg/scan/dao/scan/vulnerability_record_dao.go create mode 100644 src/testing/pkg/scan/postprocessors/native_scan_report_converter.go delete mode 100644 src/testing/pkg/scan/postprocessors/report_converters.go diff --git a/src/.mockery.yaml b/src/.mockery.yaml index c0d0b35a6c..7c5e856971 100644 --- a/src/.mockery.yaml +++ b/src/.mockery.yaml @@ -9,6 +9,17 @@ packages: Controller: config: dir: testing/controller/artifact + github.com/goharbor/harbor/src/controller/artifact/processor: + interfaces: + Processor: + config: + dir: testing/pkg/processor + github.com/goharbor/harbor/src/controller/artifact/annotation: + interfaces: + Parser: + config: + dir: testing/pkg/parser + outpkg: parser github.com/goharbor/harbor/src/controller/blob: interfaces: Controller: @@ -188,6 +199,11 @@ packages: Manager: config: dir: testing/pkg/artifact + github.com/goharbor/harbor/src/pkg/artifactrash: + interfaces: + Manager: + config: + dir: testing/pkg/artifactrash github.com/goharbor/harbor/src/pkg/blob: interfaces: Manager: @@ -218,6 +234,11 @@ packages: Handler: config: dir: testing/pkg/scan + github.com/goharbor/harbor/src/pkg/scan/postprocessors: + interfaces: + NativeScanReportConverter: + config: + dir: testing/pkg/scan/postprocessors github.com/goharbor/harbor/src/pkg/scan/report: interfaces: Manager: @@ -238,7 +259,7 @@ packages: dir: pkg/scheduler outpkg: scheduler mockname: mockDAO - filename: mock_dao_test.go + filename: mock_dao_test.go inpackage: True Scheduler: config: @@ -342,6 +363,14 @@ packages: DAO: config: dir: testing/pkg/immutable/dao + github.com/goharbor/harbor/src/pkg/immutable/match: + interfaces: + ImmutableTagMatcher: + config: + dir: testing/pkg/immutable + filename: matcher.go + outpkg: immutable + mockname: FakeMatcher github.com/goharbor/harbor/src/pkg/ldap: interfaces: Manager: @@ -505,20 +534,36 @@ packages: Manager: config: dir: testing/pkg/securityhub - - - - - - - - - - - - - - - - - + github.com/goharbor/harbor/src/pkg/tag: + interfaces: + Manager: + config: + dir: testing/pkg/tag + github.com/goharbor/harbor/src/pkg/p2p/preheat/policy: + interfaces: + Manager: + config: + dir: testing/pkg/p2p/preheat/policy + github.com/goharbor/harbor/src/pkg/p2p/preheat/instance: + interfaces: + Manager: + config: + dir: testing/pkg/p2p/preheat/instance + github.com/goharbor/harbor/src/pkg/chart: + interfaces: + Operator: + config: + dir: testing/pkg/chart + # registryctl related mocks + github.com/goharbor/harbor/src/registryctl/client: + interfaces: + Client: + config: + dir: testing/registryctl + outpkg: registryctl + # remote interfaces + github.com/docker/distribution: + interfaces: + Manifest: + config: + dir: testing/pkg/distribution diff --git a/src/controller/artifact/controller_test.go b/src/controller/artifact/controller_test.go index 0e6ed458a2..6521b1f19e 100644 --- a/src/controller/artifact/controller_test.go +++ b/src/controller/artifact/controller_test.go @@ -67,7 +67,7 @@ type controllerTestSuite struct { ctl *controller repoMgr *repotesting.Manager artMgr *arttesting.Manager - artrashMgr *artrashtesting.FakeManager + artrashMgr *artrashtesting.Manager blobMgr *blob.Manager tagCtl *tagtesting.FakeController labelMgr *label.Manager @@ -80,7 +80,7 @@ type controllerTestSuite struct { func (c *controllerTestSuite) SetupTest() { c.repoMgr = &repotesting.Manager{} c.artMgr = &arttesting.Manager{} - c.artrashMgr = &artrashtesting.FakeManager{} + c.artrashMgr = &artrashtesting.Manager{} c.blobMgr = &blob.Manager{} c.tagCtl = &tagtesting.FakeController{} c.labelMgr = &label.Manager{} @@ -476,7 +476,7 @@ func (c *controllerTestSuite) TestDeleteDeeply() { }, }, nil) c.repoMgr.On("Get", mock.Anything, mock.Anything).Return(&repomodel.RepoRecord{}, nil) - c.artrashMgr.On("Create").Return(0, nil) + c.artrashMgr.On("Create", mock.Anything, mock.Anything).Return(int64(0), nil) c.accMgr.On("List", mock.Anything, mock.Anything).Return([]accessorymodel.Accessory{}, nil) err = c.ctl.deleteDeeply(orm.NewContext(nil, &ormtesting.FakeOrmer{}), 1, false, false) c.Require().Nil(err) @@ -534,7 +534,7 @@ func (c *controllerTestSuite) TestDeleteDeeply() { c.blobMgr.On("List", mock.Anything, mock.Anything).Return(nil, nil) c.blobMgr.On("CleanupAssociationsForProject", mock.Anything, mock.Anything, mock.Anything).Return(nil) c.repoMgr.On("Get", mock.Anything, mock.Anything).Return(&repomodel.RepoRecord{}, nil) - c.artrashMgr.On("Create").Return(0, nil) + c.artrashMgr.On("Create", mock.Anything, mock.Anything).Return(int64(0), nil) err = c.ctl.deleteDeeply(orm.NewContext(nil, &ormtesting.FakeOrmer{}), 1, true, true) c.Require().Nil(err) diff --git a/src/controller/artifact/processor/chart/chart_test.go b/src/controller/artifact/processor/chart/chart_test.go index e8e208dd99..637da7bf6f 100644 --- a/src/controller/artifact/processor/chart/chart_test.go +++ b/src/controller/artifact/processor/chart/chart_test.go @@ -64,12 +64,12 @@ type processorTestSuite struct { suite.Suite processor *processor regCli *registry.Client - chartOptr *chart.FakeOpertaor + chartOptr *chart.Operator } func (p *processorTestSuite) SetupTest() { p.regCli = ®istry.Client{} - p.chartOptr = &chart.FakeOpertaor{} + p.chartOptr = &chart.Operator{} p.processor = &processor{ chartOperator: p.chartOptr, } @@ -106,7 +106,7 @@ func (p *processorTestSuite) TestAbstractAddition() { p.Require().Nil(err) p.regCli.On("PullManifest", mock.Anything, mock.Anything).Return(manifest, "", nil) p.regCli.On("PullBlob", mock.Anything, mock.Anything).Return(int64(0), io.NopCloser(strings.NewReader(chartYaml)), nil) - p.chartOptr.On("GetDetails").Return(chartDetails, nil) + p.chartOptr.On("GetDetails", mock.Anything).Return(chartDetails, nil) // values.yaml addition, err := p.processor.AbstractAddition(nil, artifact, AdditionTypeValues) diff --git a/src/controller/p2p/preheat/controllor_test.go b/src/controller/p2p/preheat/controllor_test.go index b06af2672e..c57802dd98 100644 --- a/src/controller/p2p/preheat/controllor_test.go +++ b/src/controller/p2p/preheat/controllor_test.go @@ -31,8 +31,8 @@ type preheatSuite struct { suite.Suite ctx context.Context controller Controller - fakeInstanceMgr *instance.FakeManager - fakePolicyMgr *pmocks.FakeManager + fakeInstanceMgr *instance.Manager + fakePolicyMgr *pmocks.Manager fakeScheduler *smocks.Scheduler mockInstanceServer *httptest.Server fakeExecutionMgr *tmocks.ExecutionManager @@ -40,8 +40,8 @@ type preheatSuite struct { func TestPreheatSuite(t *testing.T) { t.Log("Start TestPreheatSuite") - fakeInstanceMgr := &instance.FakeManager{} - fakePolicyMgr := &pmocks.FakeManager{} + fakeInstanceMgr := &instance.Manager{} + fakePolicyMgr := &pmocks.Manager{} fakeScheduler := &smocks.Scheduler{} fakeExecutionMgr := &tmocks.ExecutionManager{} diff --git a/src/controller/p2p/preheat/enforcer_test.go b/src/controller/p2p/preheat/enforcer_test.go index b789bd3ab5..9d6ed5f243 100644 --- a/src/controller/p2p/preheat/enforcer_test.go +++ b/src/controller/p2p/preheat/enforcer_test.go @@ -70,7 +70,7 @@ func (suite *EnforcerTestSuite) SetupSuite() { suite.server.StartTLS() fakePolicies := mockPolicies() - fakePolicyManager := &policy.FakeManager{} + fakePolicyManager := &policy.Manager{} fakePolicyManager.On("Get", context.TODO(), mock.AnythingOfType("int64")). @@ -130,7 +130,7 @@ func (suite *EnforcerTestSuite) SetupSuite() { }, }, nil) - fakeInstanceMgr := &instance.FakeManager{} + fakeInstanceMgr := &instance.Manager{} fakeInstanceMgr.On("Get", context.TODO(), mock.AnythingOfType("int64"), diff --git a/src/controller/scan/base_controller_test.go b/src/controller/scan/base_controller_test.go index 28811ce68b..ca12196d7d 100644 --- a/src/controller/scan/base_controller_test.go +++ b/src/controller/scan/base_controller_test.go @@ -82,7 +82,7 @@ type ControllerTestSuite struct { reportMgr *reporttesting.Manager ar artifact.Controller c *basicController - reportConverter *postprocessorstesting.ScanReportV1ToV2Converter + reportConverter *postprocessorstesting.NativeScanReportConverter cache *mockcache.Cache } @@ -339,7 +339,7 @@ func (suite *ControllerTestSuite) SetupSuite() { execMgr: suite.execMgr, taskMgr: suite.taskMgr, - reportConverter: &postprocessorstesting.ScanReportV1ToV2Converter{}, + reportConverter: &postprocessorstesting.NativeScanReportConverter{}, cache: func() cache.Cache { return suite.cache }, } mock.OnAnything(suite.scanHandler, "JobVendorType").Return("IMAGE_SCAN") @@ -486,6 +486,7 @@ func (suite *ControllerTestSuite) TestScanControllerGetReport() { {ExtraAttrs: suite.makeExtraAttrs(int64(1), "rp-uuid-001")}, }, nil).Once() mock.OnAnything(suite.accessoryMgr, "List").Return(nil, nil) + mock.OnAnything(suite.c.reportConverter, "FromRelationalSchema").Return("", nil) rep, err := suite.c.GetReport(ctx, suite.artifact, []string{v1.MimeTypeNativeReport}) require.NoError(suite.T(), err) assert.Equal(suite.T(), 1, len(rep)) diff --git a/src/controller/scan/callback_test.go b/src/controller/scan/callback_test.go index e1fe6c4e28..165524e458 100644 --- a/src/controller/scan/callback_test.go +++ b/src/controller/scan/callback_test.go @@ -51,7 +51,7 @@ type CallbackTestSuite struct { scanCtl Controller taskMgr *tasktesting.Manager - reportConverter *postprocessorstesting.ScanReportV1ToV2Converter + reportConverter *postprocessorstesting.NativeScanReportConverter } func (suite *CallbackTestSuite) SetupSuite() { @@ -69,7 +69,7 @@ func (suite *CallbackTestSuite) SetupSuite() { suite.taskMgr = &tasktesting.Manager{} taskMgr = suite.taskMgr - suite.reportConverter = &postprocessorstesting.ScanReportV1ToV2Converter{} + suite.reportConverter = &postprocessorstesting.NativeScanReportConverter{} suite.scanCtl = &basicController{ makeCtx: context.TODO, diff --git a/src/controller/securityhub/controller_test.go b/src/controller/securityhub/controller_test.go index 600c692bf8..68140d2f6b 100644 --- a/src/controller/securityhub/controller_test.go +++ b/src/controller/securityhub/controller_test.go @@ -44,7 +44,7 @@ type ControllerTestSuite struct { c *controller scannerMgr *scannerMock.Manager secHubMgr *securityMock.Manager - tagMgr *tagMock.FakeManager + tagMgr *tagMock.Manager } // TestController is the entry of controller test suite @@ -56,7 +56,7 @@ func TestController(t *testing.T) { func (suite *ControllerTestSuite) SetupTest() { suite.secHubMgr = &securityMock.Manager{} suite.scannerMgr = &scannerMock.Manager{} - suite.tagMgr = &tagMock.FakeManager{} + suite.tagMgr = &tagMock.Manager{} suite.c = &controller{ secHubMgr: suite.secHubMgr, diff --git a/src/controller/tag/controller_test.go b/src/controller/tag/controller_test.go index bd8d1e7ecd..9755bbd607 100644 --- a/src/controller/tag/controller_test.go +++ b/src/controller/tag/controller_test.go @@ -18,7 +18,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" "github.com/goharbor/harbor/src/lib/errors" @@ -27,6 +26,7 @@ import ( _ "github.com/goharbor/harbor/src/pkg/config/inmemory" "github.com/goharbor/harbor/src/pkg/tag/model/tag" ormtesting "github.com/goharbor/harbor/src/testing/lib/orm" + "github.com/goharbor/harbor/src/testing/mock" "github.com/goharbor/harbor/src/testing/pkg/artifact" "github.com/goharbor/harbor/src/testing/pkg/immutable" "github.com/goharbor/harbor/src/testing/pkg/repository" @@ -38,14 +38,14 @@ type controllerTestSuite struct { ctl *controller repoMgr *repository.Manager artMgr *artifact.Manager - tagMgr *tagtesting.FakeManager + tagMgr *tagtesting.Manager immutableMtr *immutable.FakeMatcher } func (c *controllerTestSuite) SetupTest() { c.repoMgr = &repository.Manager{} c.artMgr = &artifact.Manager{} - c.tagMgr = &tagtesting.FakeManager{} + c.tagMgr = &tagtesting.Manager{} c.immutableMtr = &immutable.FakeMatcher{} c.ctl = &controller{ tagMgr: c.tagMgr, @@ -56,7 +56,7 @@ func (c *controllerTestSuite) SetupTest() { func (c *controllerTestSuite) TestEnsureTag() { // the tag already exists under the repository and is attached to the artifact - c.tagMgr.On("List").Return([]*tag.Tag{ + c.tagMgr.On("List", mock.Anything, mock.Anything).Return([]*tag.Tag{ { ID: 1, RepositoryID: 1, @@ -67,7 +67,7 @@ func (c *controllerTestSuite) TestEnsureTag() { c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(false, nil) + mock.OnAnything(c.immutableMtr, "Match").Return(false, nil) _, err := c.ctl.Ensure(orm.NewContext(nil, &ormtesting.FakeOrmer{}), 1, 1, "latest") c.Require().Nil(err) c.tagMgr.AssertExpectations(c.T()) @@ -76,7 +76,7 @@ func (c *controllerTestSuite) TestEnsureTag() { c.SetupTest() // the tag exists under the repository, but it is attached to other artifact - c.tagMgr.On("List").Return([]*tag.Tag{ + c.tagMgr.On("List", mock.Anything, mock.Anything).Return([]*tag.Tag{ { ID: 1, RepositoryID: 1, @@ -84,11 +84,11 @@ func (c *controllerTestSuite) TestEnsureTag() { Name: "latest", }, }, nil) - c.tagMgr.On("Update").Return(nil) + c.tagMgr.On("Update", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(false, nil) + mock.OnAnything(c.immutableMtr, "Match").Return(false, nil) _, err = c.ctl.Ensure(orm.NewContext(nil, &ormtesting.FakeOrmer{}), 1, 1, "latest") c.Require().Nil(err) c.tagMgr.AssertExpectations(c.T()) @@ -97,26 +97,26 @@ func (c *controllerTestSuite) TestEnsureTag() { c.SetupTest() // the tag doesn't exist under the repository, create it - c.tagMgr.On("List").Return([]*tag.Tag{}, nil) - c.tagMgr.On("Create").Return(1, nil) + c.tagMgr.On("List", mock.Anything, mock.Anything).Return([]*tag.Tag{}, nil) + c.tagMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(false, nil) + mock.OnAnything(c.immutableMtr, "Match").Return(false, nil) _, err = c.ctl.Ensure(orm.NewContext(nil, &ormtesting.FakeOrmer{}), 1, 1, "latest") c.Require().Nil(err) c.tagMgr.AssertExpectations(c.T()) } func (c *controllerTestSuite) TestCount() { - c.tagMgr.On("Count").Return(1, nil) + c.tagMgr.On("Count", mock.Anything, mock.Anything).Return(int64(1), nil) total, err := c.ctl.Count(nil, nil) c.Require().Nil(err) c.Equal(int64(1), total) } func (c *controllerTestSuite) TestList() { - c.tagMgr.On("List").Return([]*tag.Tag{ + c.tagMgr.On("List", mock.Anything, mock.Anything).Return([]*tag.Tag{ { RepositoryID: 1, Name: "testlist", @@ -134,7 +134,7 @@ func (c *controllerTestSuite) TestGet() { getTest.RepositoryID = 1 getTest.Name = "testget" - c.tagMgr.On("Get").Return(getTest, nil) + c.tagMgr.On("Get", mock.Anything, mock.Anything).Return(getTest, nil) tag, err := c.ctl.Get(nil, 1, nil) c.Require().Nil(err) c.tagMgr.AssertExpectations(c.T()) @@ -143,36 +143,36 @@ func (c *controllerTestSuite) TestGet() { } func (c *controllerTestSuite) TestDelete() { - c.tagMgr.On("Get").Return(&tag.Tag{ + c.tagMgr.On("Get", mock.Anything, mock.Anything).Return(&tag.Tag{ RepositoryID: 1, Name: "test", }, nil) c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(false, nil) - c.tagMgr.On("Delete").Return(nil) + mock.OnAnything(c.immutableMtr, "Match").Return(false, nil) + c.tagMgr.On("Delete", mock.Anything, mock.Anything).Return(nil) err := c.ctl.Delete(nil, 1) c.Require().Nil(err) } func (c *controllerTestSuite) TestDeleteImmutable() { - c.tagMgr.On("Get").Return(&tag.Tag{ + c.tagMgr.On("Get", mock.Anything, mock.Anything).Return(&tag.Tag{ RepositoryID: 1, Name: "test", }, nil) c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(true, nil) - c.tagMgr.On("Delete").Return(nil) + mock.OnAnything(c.immutableMtr, "Match").Return(true, nil) + c.tagMgr.On("Delete", mock.Anything, mock.Anything).Return(nil) err := c.ctl.Delete(nil, 1) c.Require().NotNil(err) c.True(errors.IsErr(err, errors.PreconditionCode)) } func (c *controllerTestSuite) TestUpdate() { - c.tagMgr.On("Update").Return(nil) + mock.OnAnything(c.tagMgr, "Update").Return(nil) err := c.ctl.Update(nil, &Tag{ Tag: tag.Tag{ RepositoryID: 1, @@ -184,14 +184,14 @@ func (c *controllerTestSuite) TestUpdate() { } func (c *controllerTestSuite) TestDeleteTags() { - c.tagMgr.On("Get").Return(&tag.Tag{ + c.tagMgr.On("Get", mock.Anything, mock.Anything).Return(&tag.Tag{ RepositoryID: 1, }, nil) c.artMgr.On("Get", mock.Anything, mock.Anything).Return(&pkg_artifact.Artifact{ ID: 1, }, nil) - c.immutableMtr.On("Match").Return(false, nil) - c.tagMgr.On("Delete").Return(nil) + mock.OnAnything(c.immutableMtr, "Match").Return(false, nil) + c.tagMgr.On("Delete", mock.Anything, mock.Anything).Return(nil) ids := []int64{1, 2, 3, 4} err := c.ctl.DeleteTags(nil, ids) c.Require().Nil(err) @@ -218,7 +218,7 @@ func (c *controllerTestSuite) TestAssembleTag() { } c.artMgr.On("Get", mock.Anything, mock.Anything).Return(art, nil) - c.immutableMtr.On("Match").Return(true, nil) + mock.OnAnything(c.immutableMtr, "Match").Return(true, nil) tag := c.ctl.assembleTag(nil, tg, option) c.Require().NotNil(tag) c.Equal(tag.ID, tg.ID) diff --git a/src/jobservice/job/impl/gc/garbage_collection_test.go b/src/jobservice/job/impl/gc/garbage_collection_test.go index 124cff7f98..5aacd737e7 100644 --- a/src/jobservice/job/impl/gc/garbage_collection_test.go +++ b/src/jobservice/job/impl/gc/garbage_collection_test.go @@ -42,8 +42,8 @@ import ( type gcTestSuite struct { htesting.Suite artifactCtl *artifacttesting.Controller - artrashMgr *trashtesting.FakeManager - registryCtlClient *registryctl.Mockclient + artrashMgr *trashtesting.Manager + registryCtlClient *registryctl.Client projectCtl *projecttesting.Controller blobMgr *blob.Manager @@ -54,8 +54,8 @@ type gcTestSuite struct { func (suite *gcTestSuite) SetupTest() { suite.artifactCtl = &artifacttesting.Controller{} - suite.artrashMgr = &trashtesting.FakeManager{} - suite.registryCtlClient = ®istryctl.Mockclient{} + suite.artrashMgr = &trashtesting.Manager{} + suite.registryCtlClient = ®istryctl.Client{} suite.blobMgr = &blob.Manager{} suite.projectCtl = &projecttesting.Controller{} @@ -98,7 +98,7 @@ func (suite *gcTestSuite) TestDeletedArt() { }, }, nil) suite.artifactCtl.On("Delete").Return(nil) - suite.artrashMgr.On("Filter").Return([]model.ArtifactTrash{ + mock.OnAnything(suite.artrashMgr, "Filter").Return([]model.ArtifactTrash{ { ID: 1, Digest: suite.DigestString(), @@ -163,6 +163,8 @@ func (suite *gcTestSuite) TestInit() { "time_window": 1, "workers": float64(3), } + + mock.OnAnything(gc.registryCtlClient, "Health").Return(nil) suite.Nil(gc.init(ctx, params)) suite.True(gc.deleteUntagged) suite.Equal(3, gc.workers) @@ -230,7 +232,7 @@ func (suite *gcTestSuite) TestRun() { }, }, nil) suite.artifactCtl.On("Delete").Return(nil) - suite.artrashMgr.On("Filter").Return([]model.ArtifactTrash{}, nil) + mock.OnAnything(suite.artrashMgr, "Filter").Return([]model.ArtifactTrash{}, nil) mock.OnAnything(suite.projectCtl, "List").Return([]*proModels.Project{ { @@ -271,6 +273,8 @@ func (suite *gcTestSuite) TestRun() { mock.OnAnything(suite.blobMgr, "Delete").Return(nil) + mock.OnAnything(suite.registryCtlClient, "Health").Return(nil) + gc := &GarbageCollector{ artCtl: suite.artifactCtl, artrashMgr: suite.artrashMgr, @@ -284,6 +288,7 @@ func (suite *gcTestSuite) TestRun() { "workers": 3, } + mock.OnAnything(gc.registryCtlClient, "DeleteBlob").Return(nil) suite.Nil(gc.Run(ctx, params)) } @@ -302,7 +307,7 @@ func (suite *gcTestSuite) TestMark() { }, }, nil) suite.artifactCtl.On("Delete").Return(nil) - suite.artrashMgr.On("Filter").Return([]model.ArtifactTrash{ + mock.OnAnything(suite.artrashMgr, "Filter").Return([]model.ArtifactTrash{ { ID: 1, Digest: suite.DigestString(), @@ -381,6 +386,7 @@ func (suite *gcTestSuite) TestSweep() { workers: 3, } + mock.OnAnything(gc.registryCtlClient, "DeleteBlob").Return(nil) suite.Nil(gc.sweep(ctx)) } diff --git a/src/pkg/scan/vulnerability/vul_test.go b/src/pkg/scan/vulnerability/vul_test.go index 2d0dcbe983..be0eb50c8f 100644 --- a/src/pkg/scan/vulnerability/vul_test.go +++ b/src/pkg/scan/vulnerability/vul_test.go @@ -62,12 +62,12 @@ func TestPostScan(t *testing.T) { origRp := &scan.Report{} rawReport := "" - mocker := &postprocessorstesting.ScanReportV1ToV2Converter{} - mocker.On("ToRelationalSchema", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, "original report", nil) + mocker := &postprocessorstesting.NativeScanReportConverter{} + mocker.On("ToRelationalSchema", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("", "original report", nil) postprocessors.Converter = mocker sr := &v1.ScanRequest{Artifact: artifact} refreshedReport, err := v.PostScan(ctx, sr, origRp, rawReport, time.Now(), &model.Robot{}) - assert.Equal(t, "", refreshedReport, "PostScan should return the refreshed report") + assert.Equal(t, "original report", refreshedReport, "PostScan should return the refreshed report") assert.Nil(t, err, "PostScan should not return an error") } @@ -209,6 +209,7 @@ func (suite *VulHandlerTestSuite) TestMakeReportPlaceHolder() { mock.OnAnything(suite.reportMgr, "Create").Return("uuid", nil).Once() mock.OnAnything(suite.reportMgr, "Delete").Return(nil).Once() mock.OnAnything(suite.taskMgr, "ListScanTasksByReportUUID").Return([]*task.Task{{Status: "Success"}}, nil) + mock.OnAnything(suite.handler.reportConverter, "FromRelationalSchema").Return("", nil) rps, err := suite.handler.MakePlaceHolder(ctx, art, r) require.NoError(suite.T(), err) assert.Equal(suite.T(), 1, len(rps)) diff --git a/src/testing/lib/libcache/cache.go b/src/testing/lib/libcache/cache.go deleted file mode 100644 index 8eb215e52d..0000000000 --- a/src/testing/lib/libcache/cache.go +++ /dev/null @@ -1,136 +0,0 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. - -package libcache - -import ( - context "context" - - cache "github.com/goharbor/harbor/src/lib/cache" - - mock "github.com/stretchr/testify/mock" - - time "time" -) - -// Cache is an autogenerated mock type for the Cache type -type Cache struct { - mock.Mock -} - -// Contains provides a mock function with given fields: ctx, key -func (_m *Cache) Contains(ctx context.Context, key string) bool { - ret := _m.Called(ctx, key) - - var r0 bool - if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok { - r0 = rf(ctx, key) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Delete provides a mock function with given fields: ctx, key -func (_m *Cache) Delete(ctx context.Context, key string) error { - ret := _m.Called(ctx, key) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Fetch provides a mock function with given fields: ctx, key, value -func (_m *Cache) Fetch(ctx context.Context, key string, value interface{}) error { - ret := _m.Called(ctx, key, value) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, interface{}) error); ok { - r0 = rf(ctx, key, value) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ping provides a mock function with given fields: ctx -func (_m *Cache) Ping(ctx context.Context) error { - ret := _m.Called(ctx) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Save provides a mock function with given fields: ctx, key, value, expiration -func (_m *Cache) Save(ctx context.Context, key string, value interface{}, expiration ...time.Duration) error { - _va := make([]interface{}, len(expiration)) - for _i := range expiration { - _va[_i] = expiration[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, key, value) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, interface{}, ...time.Duration) error); ok { - r0 = rf(ctx, key, value, expiration...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Scan provides a mock function with given fields: ctx, match -func (_m *Cache) Scan(ctx context.Context, match string) (cache.Iterator, error) { - ret := _m.Called(ctx, match) - - var r0 cache.Iterator - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (cache.Iterator, error)); ok { - return rf(ctx, match) - } - if rf, ok := ret.Get(0).(func(context.Context, string) cache.Iterator); ok { - r0 = rf(ctx, match) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cache.Iterator) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, match) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -type mockConstructorTestingTNewCache interface { - mock.TestingT - Cleanup(func()) -} - -// NewCache creates a new instance of Cache. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCache(t mockConstructorTestingTNewCache) *Cache { - mock := &Cache{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/src/testing/pkg/artifactrash/manager.go b/src/testing/pkg/artifactrash/manager.go index c1a4368032..de70e91a2f 100644 --- a/src/testing/pkg/artifactrash/manager.go +++ b/src/testing/pkg/artifactrash/manager.go @@ -1,38 +1,123 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + package artifactrash import ( - "context" + context "context" - "github.com/stretchr/testify/mock" - - "github.com/goharbor/harbor/src/pkg/artifactrash/model" + model "github.com/goharbor/harbor/src/pkg/artifactrash/model" + mock "github.com/stretchr/testify/mock" ) -// FakeManager is a fake tag manager that implement the src/pkg/tag.Manager interface -type FakeManager struct { +// Manager is an autogenerated mock type for the Manager type +type Manager struct { mock.Mock } -// Create ... -func (f *FakeManager) Create(ctx context.Context, artifactrsh *model.ArtifactTrash) (id int64, err error) { - args := f.Called() - return int64(args.Int(0)), args.Error(1) +// Create provides a mock function with given fields: ctx, artifactrsh +func (_m *Manager) Create(ctx context.Context, artifactrsh *model.ArtifactTrash) (int64, error) { + ret := _m.Called(ctx, artifactrsh) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *model.ArtifactTrash) (int64, error)); ok { + return rf(ctx, artifactrsh) + } + if rf, ok := ret.Get(0).(func(context.Context, *model.ArtifactTrash) int64); ok { + r0 = rf(ctx, artifactrsh) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *model.ArtifactTrash) error); ok { + r1 = rf(ctx, artifactrsh) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Delete ... -func (f *FakeManager) Delete(ctx context.Context, id int64) error { - args := f.Called() - return args.Error(0) +// Delete provides a mock function with given fields: ctx, id +func (_m *Manager) Delete(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 } -// Filter ... -func (f *FakeManager) Filter(ctx context.Context, timeWindow int64) (arts []model.ArtifactTrash, err error) { - args := f.Called() - return args.Get(0).([]model.ArtifactTrash), args.Error(1) +// Filter provides a mock function with given fields: ctx, timeWindow +func (_m *Manager) Filter(ctx context.Context, timeWindow int64) ([]model.ArtifactTrash, error) { + ret := _m.Called(ctx, timeWindow) + + if len(ret) == 0 { + panic("no return value specified for Filter") + } + + var r0 []model.ArtifactTrash + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) ([]model.ArtifactTrash, error)); ok { + return rf(ctx, timeWindow) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) []model.ArtifactTrash); ok { + r0 = rf(ctx, timeWindow) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]model.ArtifactTrash) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, timeWindow) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Flush ... -func (f *FakeManager) Flush(ctx context.Context, timeWindow int64) (err error) { - args := f.Called() - return args.Error(0) +// Flush provides a mock function with given fields: ctx, timeWindow +func (_m *Manager) Flush(ctx context.Context, timeWindow int64) error { + ret := _m.Called(ctx, timeWindow) + + if len(ret) == 0 { + panic("no return value specified for Flush") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, timeWindow) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManager(t interface { + mock.TestingT + Cleanup(func()) +}) *Manager { + mock := &Manager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } diff --git a/src/testing/pkg/chart/operator.go b/src/testing/pkg/chart/operator.go index eecaab4ef0..4ed9e28161 100644 --- a/src/testing/pkg/chart/operator.go +++ b/src/testing/pkg/chart/operator.go @@ -1,33 +1,89 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + package chart import ( - "github.com/stretchr/testify/mock" - helm_chart "helm.sh/helm/v3/pkg/chart" + mock "github.com/stretchr/testify/mock" + chart "helm.sh/helm/v3/pkg/chart" - chartserver "github.com/goharbor/harbor/src/pkg/chart" + pkgchart "github.com/goharbor/harbor/src/pkg/chart" ) -// FakeOpertaor ... -type FakeOpertaor struct { +// Operator is an autogenerated mock type for the Operator type +type Operator struct { mock.Mock } -// GetDetails ... -func (f *FakeOpertaor) GetDetails(content []byte) (*chartserver.VersionDetails, error) { - args := f.Called() - var chartDetails *chartserver.VersionDetails - if args.Get(0) != nil { - chartDetails = args.Get(0).(*chartserver.VersionDetails) +// GetData provides a mock function with given fields: content +func (_m *Operator) GetData(content []byte) (*chart.Chart, error) { + ret := _m.Called(content) + + if len(ret) == 0 { + panic("no return value specified for GetData") } - return chartDetails, args.Error(1) + + var r0 *chart.Chart + var r1 error + if rf, ok := ret.Get(0).(func([]byte) (*chart.Chart, error)); ok { + return rf(content) + } + if rf, ok := ret.Get(0).(func([]byte) *chart.Chart); ok { + r0 = rf(content) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*chart.Chart) + } + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(content) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// GetData ... -func (f *FakeOpertaor) GetData(content []byte) (*helm_chart.Chart, error) { - args := f.Called() - var chartData *helm_chart.Chart - if args.Get(0) != nil { - chartData = args.Get(0).(*helm_chart.Chart) +// GetDetails provides a mock function with given fields: content +func (_m *Operator) GetDetails(content []byte) (*pkgchart.VersionDetails, error) { + ret := _m.Called(content) + + if len(ret) == 0 { + panic("no return value specified for GetDetails") } - return chartData, args.Error(1) + + var r0 *pkgchart.VersionDetails + var r1 error + if rf, ok := ret.Get(0).(func([]byte) (*pkgchart.VersionDetails, error)); ok { + return rf(content) + } + if rf, ok := ret.Get(0).(func([]byte) *pkgchart.VersionDetails); ok { + r0 = rf(content) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*pkgchart.VersionDetails) + } + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(content) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewOperator creates a new instance of Operator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewOperator(t interface { + mock.TestingT + Cleanup(func()) +}) *Operator { + mock := &Operator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } diff --git a/src/testing/pkg/distribution/manifest.go b/src/testing/pkg/distribution/manifest.go index 6250248ecf..7d96ca80e6 100644 --- a/src/testing/pkg/distribution/manifest.go +++ b/src/testing/pkg/distribution/manifest.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package distribution @@ -16,6 +16,10 @@ type Manifest struct { func (_m *Manifest) Payload() (string, []byte, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Payload") + } + var r0 string var r1 []byte var r2 error @@ -49,6 +53,10 @@ func (_m *Manifest) Payload() (string, []byte, error) { func (_m *Manifest) References() []distribution.Descriptor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for References") + } + var r0 []distribution.Descriptor if rf, ok := ret.Get(0).(func() []distribution.Descriptor); ok { r0 = rf() @@ -61,13 +69,12 @@ func (_m *Manifest) References() []distribution.Descriptor { return r0 } -type mockConstructorTestingTNewManifest interface { +// NewManifest creates a new instance of Manifest. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManifest(t interface { mock.TestingT Cleanup(func()) -} - -// NewManifest creates a new instance of Manifest. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewManifest(t mockConstructorTestingTNewManifest) *Manifest { +}) *Manifest { mock := &Manifest{} mock.Mock.Test(t) diff --git a/src/testing/pkg/immutable/matcher.go b/src/testing/pkg/immutable/matcher.go index 2e00b917da..f14c04e2fa 100644 --- a/src/testing/pkg/immutable/matcher.go +++ b/src/testing/pkg/immutable/matcher.go @@ -1,20 +1,58 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + package immutable import ( - "context" + context "context" - "github.com/stretchr/testify/mock" + mock "github.com/stretchr/testify/mock" - "github.com/goharbor/harbor/src/lib/selector" + selector "github.com/goharbor/harbor/src/lib/selector" ) -// FakeMatcher ... +// FakeMatcher is an autogenerated mock type for the ImmutableTagMatcher type type FakeMatcher struct { mock.Mock } -// Match ... -func (f *FakeMatcher) Match(ctx context.Context, pid int64, c selector.Candidate) (bool, error) { - args := f.Called() - return args.Bool(0), args.Error(1) +// Match provides a mock function with given fields: ctx, pid, c +func (_m *FakeMatcher) Match(ctx context.Context, pid int64, c selector.Candidate) (bool, error) { + ret := _m.Called(ctx, pid, c) + + if len(ret) == 0 { + panic("no return value specified for Match") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, selector.Candidate) (bool, error)); ok { + return rf(ctx, pid, c) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, selector.Candidate) bool); ok { + r0 = rf(ctx, pid, c) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, selector.Candidate) error); ok { + r1 = rf(ctx, pid, c) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewFakeMatcher creates a new instance of FakeMatcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFakeMatcher(t interface { + mock.TestingT + Cleanup(func()) +}) *FakeMatcher { + mock := &FakeMatcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } diff --git a/src/testing/pkg/p2p/preheat/instance/manager.go b/src/testing/pkg/p2p/preheat/instance/manager.go index 3c18aada7f..6e0e5233b1 100644 --- a/src/testing/pkg/p2p/preheat/instance/manager.go +++ b/src/testing/pkg/p2p/preheat/instance/manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package instance @@ -7,27 +7,35 @@ import ( mock "github.com/stretchr/testify/mock" - q "github.com/goharbor/harbor/src/lib/q" provider "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/provider" + + q "github.com/goharbor/harbor/src/lib/q" ) -// FakeManager is an autogenerated mock type for the Manager type -type FakeManager struct { +// Manager is an autogenerated mock type for the Manager type +type Manager struct { mock.Mock } // Count provides a mock function with given fields: ctx, query -func (_m *FakeManager) Count(ctx context.Context, query *q.Query) (int64, error) { +func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) { ret := _m.Called(ctx, query) + if len(ret) == 0 { + panic("no return value specified for Count") + } + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok { r0 = rf(ctx, query) } else { r0 = ret.Get(0).(int64) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { r1 = rf(ctx, query) } else { @@ -38,9 +46,13 @@ func (_m *FakeManager) Count(ctx context.Context, query *q.Query) (int64, error) } // Delete provides a mock function with given fields: ctx, id -func (_m *FakeManager) Delete(ctx context.Context, id int64) error { +func (_m *Manager) Delete(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -52,10 +64,18 @@ func (_m *FakeManager) Delete(ctx context.Context, id int64) error { } // Get provides a mock function with given fields: ctx, id -func (_m *FakeManager) Get(ctx context.Context, id int64) (*provider.Instance, error) { +func (_m *Manager) Get(ctx context.Context, id int64) (*provider.Instance, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *provider.Instance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*provider.Instance, error)); ok { + return rf(ctx, id) + } if rf, ok := ret.Get(0).(func(context.Context, int64) *provider.Instance); ok { r0 = rf(ctx, id) } else { @@ -64,7 +84,6 @@ func (_m *FakeManager) Get(ctx context.Context, id int64) (*provider.Instance, e } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { r1 = rf(ctx, id) } else { @@ -75,10 +94,18 @@ func (_m *FakeManager) Get(ctx context.Context, id int64) (*provider.Instance, e } // GetByName provides a mock function with given fields: ctx, name -func (_m *FakeManager) GetByName(ctx context.Context, name string) (*provider.Instance, error) { +func (_m *Manager) GetByName(ctx context.Context, name string) (*provider.Instance, error) { ret := _m.Called(ctx, name) + if len(ret) == 0 { + panic("no return value specified for GetByName") + } + var r0 *provider.Instance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*provider.Instance, error)); ok { + return rf(ctx, name) + } if rf, ok := ret.Get(0).(func(context.Context, string) *provider.Instance); ok { r0 = rf(ctx, name) } else { @@ -87,7 +114,6 @@ func (_m *FakeManager) GetByName(ctx context.Context, name string) (*provider.In } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { r1 = rf(ctx, name) } else { @@ -98,10 +124,18 @@ func (_m *FakeManager) GetByName(ctx context.Context, name string) (*provider.In } // List provides a mock function with given fields: ctx, query -func (_m *FakeManager) List(ctx context.Context, query *q.Query) ([]*provider.Instance, error) { +func (_m *Manager) List(ctx context.Context, query *q.Query) ([]*provider.Instance, error) { ret := _m.Called(ctx, query) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []*provider.Instance + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*provider.Instance, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*provider.Instance); ok { r0 = rf(ctx, query) } else { @@ -110,7 +144,6 @@ func (_m *FakeManager) List(ctx context.Context, query *q.Query) ([]*provider.In } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { r1 = rf(ctx, query) } else { @@ -121,17 +154,24 @@ func (_m *FakeManager) List(ctx context.Context, query *q.Query) ([]*provider.In } // Save provides a mock function with given fields: ctx, inst -func (_m *FakeManager) Save(ctx context.Context, inst *provider.Instance) (int64, error) { +func (_m *Manager) Save(ctx context.Context, inst *provider.Instance) (int64, error) { ret := _m.Called(ctx, inst) + if len(ret) == 0 { + panic("no return value specified for Save") + } + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *provider.Instance) (int64, error)); ok { + return rf(ctx, inst) + } if rf, ok := ret.Get(0).(func(context.Context, *provider.Instance) int64); ok { r0 = rf(ctx, inst) } else { r0 = ret.Get(0).(int64) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *provider.Instance) error); ok { r1 = rf(ctx, inst) } else { @@ -142,7 +182,7 @@ func (_m *FakeManager) Save(ctx context.Context, inst *provider.Instance) (int64 } // Update provides a mock function with given fields: ctx, inst, props -func (_m *FakeManager) Update(ctx context.Context, inst *provider.Instance, props ...string) error { +func (_m *Manager) Update(ctx context.Context, inst *provider.Instance, props ...string) error { _va := make([]interface{}, len(props)) for _i := range props { _va[_i] = props[_i] @@ -152,6 +192,10 @@ func (_m *FakeManager) Update(ctx context.Context, inst *provider.Instance, prop _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *provider.Instance, ...string) error); ok { r0 = rf(ctx, inst, props...) @@ -161,3 +205,17 @@ func (_m *FakeManager) Update(ctx context.Context, inst *provider.Instance, prop return r0 } + +// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManager(t interface { + mock.TestingT + Cleanup(func()) +}) *Manager { + mock := &Manager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/src/testing/pkg/p2p/preheat/policy/manager.go b/src/testing/pkg/p2p/preheat/policy/manager.go index e83524dd89..7c79fcfb38 100644 --- a/src/testing/pkg/p2p/preheat/policy/manager.go +++ b/src/testing/pkg/p2p/preheat/policy/manager.go @@ -1,33 +1,40 @@ -// Code generated by mockery v2.0.3. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package policy import ( context "context" + modelspolicy "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy" mock "github.com/stretchr/testify/mock" q "github.com/goharbor/harbor/src/lib/q" - modelspolicy "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy" ) -// FakeManager is an autogenerated mock type for the Manager type -type FakeManager struct { +// Manager is an autogenerated mock type for the Manager type +type Manager struct { mock.Mock } // Count provides a mock function with given fields: ctx, query -func (_m *FakeManager) Count(ctx context.Context, query *q.Query) (int64, error) { +func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) { ret := _m.Called(ctx, query) + if len(ret) == 0 { + panic("no return value specified for Count") + } + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok { r0 = rf(ctx, query) } else { r0 = ret.Get(0).(int64) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { r1 = rf(ctx, query) } else { @@ -38,17 +45,24 @@ func (_m *FakeManager) Count(ctx context.Context, query *q.Query) (int64, error) } // Create provides a mock function with given fields: ctx, schema -func (_m *FakeManager) Create(ctx context.Context, schema *modelspolicy.Schema) (int64, error) { +func (_m *Manager) Create(ctx context.Context, schema *modelspolicy.Schema) (int64, error) { ret := _m.Called(ctx, schema) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *modelspolicy.Schema) (int64, error)); ok { + return rf(ctx, schema) + } if rf, ok := ret.Get(0).(func(context.Context, *modelspolicy.Schema) int64); ok { r0 = rf(ctx, schema) } else { r0 = ret.Get(0).(int64) } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *modelspolicy.Schema) error); ok { r1 = rf(ctx, schema) } else { @@ -59,9 +73,13 @@ func (_m *FakeManager) Create(ctx context.Context, schema *modelspolicy.Schema) } // Delete provides a mock function with given fields: ctx, id -func (_m *FakeManager) Delete(ctx context.Context, id int64) error { +func (_m *Manager) Delete(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -73,10 +91,18 @@ func (_m *FakeManager) Delete(ctx context.Context, id int64) error { } // Get provides a mock function with given fields: ctx, id -func (_m *FakeManager) Get(ctx context.Context, id int64) (*modelspolicy.Schema, error) { +func (_m *Manager) Get(ctx context.Context, id int64) (*modelspolicy.Schema, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *modelspolicy.Schema + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*modelspolicy.Schema, error)); ok { + return rf(ctx, id) + } if rf, ok := ret.Get(0).(func(context.Context, int64) *modelspolicy.Schema); ok { r0 = rf(ctx, id) } else { @@ -85,7 +111,6 @@ func (_m *FakeManager) Get(ctx context.Context, id int64) (*modelspolicy.Schema, } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { r1 = rf(ctx, id) } else { @@ -95,22 +120,29 @@ func (_m *FakeManager) Get(ctx context.Context, id int64) (*modelspolicy.Schema, return r0, r1 } -// GetByName provides a mock function with given fields: ctx, projectId, name -func (_m *FakeManager) GetByName(ctx context.Context, projectId int64, name string) (*modelspolicy.Schema, error) { - ret := _m.Called(ctx, projectId, name) +// GetByName provides a mock function with given fields: ctx, projectID, name +func (_m *Manager) GetByName(ctx context.Context, projectID int64, name string) (*modelspolicy.Schema, error) { + ret := _m.Called(ctx, projectID, name) + + if len(ret) == 0 { + panic("no return value specified for GetByName") + } var r0 *modelspolicy.Schema + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*modelspolicy.Schema, error)); ok { + return rf(ctx, projectID, name) + } if rf, ok := ret.Get(0).(func(context.Context, int64, string) *modelspolicy.Schema); ok { - r0 = rf(ctx, projectId, name) + r0 = rf(ctx, projectID, name) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*modelspolicy.Schema) } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { - r1 = rf(ctx, projectId, name) + r1 = rf(ctx, projectID, name) } else { r1 = ret.Error(1) } @@ -119,10 +151,18 @@ func (_m *FakeManager) GetByName(ctx context.Context, projectId int64, name stri } // ListPolicies provides a mock function with given fields: ctx, query -func (_m *FakeManager) ListPolicies(ctx context.Context, query *q.Query) ([]*modelspolicy.Schema, error) { +func (_m *Manager) ListPolicies(ctx context.Context, query *q.Query) ([]*modelspolicy.Schema, error) { ret := _m.Called(ctx, query) + if len(ret) == 0 { + panic("no return value specified for ListPolicies") + } + var r0 []*modelspolicy.Schema + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*modelspolicy.Schema, error)); ok { + return rf(ctx, query) + } if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*modelspolicy.Schema); ok { r0 = rf(ctx, query) } else { @@ -131,7 +171,6 @@ func (_m *FakeManager) ListPolicies(ctx context.Context, query *q.Query) ([]*mod } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { r1 = rf(ctx, query) } else { @@ -142,10 +181,18 @@ func (_m *FakeManager) ListPolicies(ctx context.Context, query *q.Query) ([]*mod } // ListPoliciesByProject provides a mock function with given fields: ctx, project, query -func (_m *FakeManager) ListPoliciesByProject(ctx context.Context, project int64, query *q.Query) ([]*modelspolicy.Schema, error) { +func (_m *Manager) ListPoliciesByProject(ctx context.Context, project int64, query *q.Query) ([]*modelspolicy.Schema, error) { ret := _m.Called(ctx, project, query) + if len(ret) == 0 { + panic("no return value specified for ListPoliciesByProject") + } + var r0 []*modelspolicy.Schema + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *q.Query) ([]*modelspolicy.Schema, error)); ok { + return rf(ctx, project, query) + } if rf, ok := ret.Get(0).(func(context.Context, int64, *q.Query) []*modelspolicy.Schema); ok { r0 = rf(ctx, project, query) } else { @@ -154,7 +201,6 @@ func (_m *FakeManager) ListPoliciesByProject(ctx context.Context, project int64, } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, int64, *q.Query) error); ok { r1 = rf(ctx, project, query) } else { @@ -165,7 +211,7 @@ func (_m *FakeManager) ListPoliciesByProject(ctx context.Context, project int64, } // Update provides a mock function with given fields: ctx, schema, props -func (_m *FakeManager) Update(ctx context.Context, schema *modelspolicy.Schema, props ...string) error { +func (_m *Manager) Update(ctx context.Context, schema *modelspolicy.Schema, props ...string) error { _va := make([]interface{}, len(props)) for _i := range props { _va[_i] = props[_i] @@ -175,6 +221,10 @@ func (_m *FakeManager) Update(ctx context.Context, schema *modelspolicy.Schema, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *modelspolicy.Schema, ...string) error); ok { r0 = rf(ctx, schema, props...) @@ -184,3 +234,17 @@ func (_m *FakeManager) Update(ctx context.Context, schema *modelspolicy.Schema, return r0 } + +// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManager(t interface { + mock.TestingT + Cleanup(func()) +}) *Manager { + mock := &Manager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/src/testing/pkg/parser/parser.go b/src/testing/pkg/parser/parser.go index 5144b79445..f533da44e8 100644 --- a/src/testing/pkg/parser/parser.go +++ b/src/testing/pkg/parser/parser.go @@ -1,13 +1,13 @@ -// Code generated by mockery v2.1.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package parser import ( context "context" - mock "github.com/stretchr/testify/mock" - artifact "github.com/goharbor/harbor/src/pkg/artifact" + + mock "github.com/stretchr/testify/mock" ) // Parser is an autogenerated mock type for the Parser type @@ -19,6 +19,10 @@ type Parser struct { func (_m *Parser) Parse(ctx context.Context, _a1 *artifact.Artifact, manifest []byte) error { ret := _m.Called(ctx, _a1, manifest) + if len(ret) == 0 { + panic("no return value specified for Parse") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, []byte) error); ok { r0 = rf(ctx, _a1, manifest) @@ -28,3 +32,17 @@ func (_m *Parser) Parse(ctx context.Context, _a1 *artifact.Artifact, manifest [] return r0 } + +// NewParser creates a new instance of Parser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewParser(t interface { + mock.TestingT + Cleanup(func()) +}) *Parser { + mock := &Parser{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/src/testing/pkg/processor/processor.go b/src/testing/pkg/processor/processor.go index 98dadbff03..9f7896a70b 100644 --- a/src/testing/pkg/processor/processor.go +++ b/src/testing/pkg/processor/processor.go @@ -1,14 +1,15 @@ -// Code generated by mockery v2.1.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package processor import ( context "context" + artifact "github.com/goharbor/harbor/src/pkg/artifact" + mock "github.com/stretchr/testify/mock" processor "github.com/goharbor/harbor/src/controller/artifact/processor" - artifact "github.com/goharbor/harbor/src/pkg/artifact" ) // Processor is an autogenerated mock type for the Processor type @@ -20,7 +21,15 @@ type Processor struct { func (_m *Processor) AbstractAddition(ctx context.Context, _a1 *artifact.Artifact, additionType string) (*processor.Addition, error) { ret := _m.Called(ctx, _a1, additionType) + if len(ret) == 0 { + panic("no return value specified for AbstractAddition") + } + var r0 *processor.Addition + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, string) (*processor.Addition, error)); ok { + return rf(ctx, _a1, additionType) + } if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, string) *processor.Addition); ok { r0 = rf(ctx, _a1, additionType) } else { @@ -29,7 +38,6 @@ func (_m *Processor) AbstractAddition(ctx context.Context, _a1 *artifact.Artifac } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *artifact.Artifact, string) error); ok { r1 = rf(ctx, _a1, additionType) } else { @@ -43,6 +51,10 @@ func (_m *Processor) AbstractAddition(ctx context.Context, _a1 *artifact.Artifac func (_m *Processor) AbstractMetadata(ctx context.Context, _a1 *artifact.Artifact, manifest []byte) error { ret := _m.Called(ctx, _a1, manifest) + if len(ret) == 0 { + panic("no return value specified for AbstractMetadata") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact, []byte) error); ok { r0 = rf(ctx, _a1, manifest) @@ -57,6 +69,10 @@ func (_m *Processor) AbstractMetadata(ctx context.Context, _a1 *artifact.Artifac func (_m *Processor) GetArtifactType(ctx context.Context, _a1 *artifact.Artifact) string { ret := _m.Called(ctx, _a1) + if len(ret) == 0 { + panic("no return value specified for GetArtifactType") + } + var r0 string if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact) string); ok { r0 = rf(ctx, _a1) @@ -71,6 +87,10 @@ func (_m *Processor) GetArtifactType(ctx context.Context, _a1 *artifact.Artifact func (_m *Processor) ListAdditionTypes(ctx context.Context, _a1 *artifact.Artifact) []string { ret := _m.Called(ctx, _a1) + if len(ret) == 0 { + panic("no return value specified for ListAdditionTypes") + } + var r0 []string if rf, ok := ret.Get(0).(func(context.Context, *artifact.Artifact) []string); ok { r0 = rf(ctx, _a1) @@ -82,3 +102,17 @@ func (_m *Processor) ListAdditionTypes(ctx context.Context, _a1 *artifact.Artifa return r0 } + +// NewProcessor creates a new instance of Processor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProcessor(t interface { + mock.TestingT + Cleanup(func()) +}) *Processor { + mock := &Processor{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/src/testing/pkg/scan/dao/scan/vulnerability_record_dao.go b/src/testing/pkg/scan/dao/scan/vulnerability_record_dao.go deleted file mode 100644 index 5c9c771527..0000000000 --- a/src/testing/pkg/scan/dao/scan/vulnerability_record_dao.go +++ /dev/null @@ -1,256 +0,0 @@ -// Code generated by mockery v2.1.0. DO NOT EDIT. - -package scan - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - q "github.com/goharbor/harbor/src/lib/q" - scan "github.com/goharbor/harbor/src/pkg/scan/dao/scan" -) - -// VulnerabilityRecordDao is an autogenerated mock type for the VulnerabilityRecordDao type -type VulnerabilityRecordDao struct { - mock.Mock -} - -// Create provides a mock function with given fields: ctx, vr -func (_m *VulnerabilityRecordDao) Create(ctx context.Context, vr *scan.VulnerabilityRecord) (int64, error) { - ret := _m.Called(ctx, vr) - - var r0 int64 - if rf, ok := ret.Get(0).(func(context.Context, *scan.VulnerabilityRecord) int64); ok { - r0 = rf(ctx, vr) - } else { - r0 = ret.Get(0).(int64) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *scan.VulnerabilityRecord) error); ok { - r1 = rf(ctx, vr) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Delete provides a mock function with given fields: ctx, vr -func (_m *VulnerabilityRecordDao) Delete(ctx context.Context, vr *scan.VulnerabilityRecord) error { - ret := _m.Called(ctx, vr) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *scan.VulnerabilityRecord) error); ok { - r0 = rf(ctx, vr) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DeleteForDigests provides a mock function with given fields: ctx, digests -func (_m *VulnerabilityRecordDao) DeleteForDigests(ctx context.Context, digests ...string) (int64, error) { - _va := make([]interface{}, len(digests)) - for _i := range digests { - _va[_i] = digests[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 int64 - if rf, ok := ret.Get(0).(func(context.Context, ...string) int64); ok { - r0 = rf(ctx, digests...) - } else { - r0 = ret.Get(0).(int64) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, ...string) error); ok { - r1 = rf(ctx, digests...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeleteForReport provides a mock function with given fields: ctx, reportUUID -func (_m *VulnerabilityRecordDao) DeleteForReport(ctx context.Context, reportUUID string) (int64, error) { - ret := _m.Called(ctx, reportUUID) - - var r0 int64 - if rf, ok := ret.Get(0).(func(context.Context, string) int64); ok { - r0 = rf(ctx, reportUUID) - } else { - r0 = ret.Get(0).(int64) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, reportUUID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// DeleteForScanner provides a mock function with given fields: ctx, registrationUUID -func (_m *VulnerabilityRecordDao) DeleteForScanner(ctx context.Context, registrationUUID string) (int64, error) { - ret := _m.Called(ctx, registrationUUID) - - var r0 int64 - if rf, ok := ret.Get(0).(func(context.Context, string) int64); ok { - r0 = rf(ctx, registrationUUID) - } else { - r0 = ret.Get(0).(int64) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, registrationUUID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetForReport provides a mock function with given fields: ctx, reportUUID -func (_m *VulnerabilityRecordDao) GetForReport(ctx context.Context, reportUUID string) ([]*scan.VulnerabilityRecord, error) { - ret := _m.Called(ctx, reportUUID) - - var r0 []*scan.VulnerabilityRecord - if rf, ok := ret.Get(0).(func(context.Context, string) []*scan.VulnerabilityRecord); ok { - r0 = rf(ctx, reportUUID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*scan.VulnerabilityRecord) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, reportUUID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetForScanner provides a mock function with given fields: ctx, registrationUUID -func (_m *VulnerabilityRecordDao) GetForScanner(ctx context.Context, registrationUUID string) ([]*scan.VulnerabilityRecord, error) { - ret := _m.Called(ctx, registrationUUID) - - var r0 []*scan.VulnerabilityRecord - if rf, ok := ret.Get(0).(func(context.Context, string) []*scan.VulnerabilityRecord); ok { - r0 = rf(ctx, registrationUUID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*scan.VulnerabilityRecord) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, registrationUUID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetRecordIdsForScanner provides a mock function with given fields: ctx, registrationUUID -func (_m *VulnerabilityRecordDao) GetRecordIdsForScanner(ctx context.Context, registrationUUID string) ([]int, error) { - ret := _m.Called(ctx, registrationUUID) - - var r0 []int - if rf, ok := ret.Get(0).(func(context.Context, string) []int); ok { - r0 = rf(ctx, registrationUUID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]int) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, registrationUUID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// InsertForReport provides a mock function with given fields: ctx, reportUUID, vulnerabilityRecordIDs -func (_m *VulnerabilityRecordDao) InsertForReport(ctx context.Context, reportUUID string, vulnerabilityRecordIDs ...int64) error { - _va := make([]interface{}, len(vulnerabilityRecordIDs)) - for _i := range vulnerabilityRecordIDs { - _va[_i] = vulnerabilityRecordIDs[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, reportUUID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, ...int64) error); ok { - r0 = rf(ctx, reportUUID, vulnerabilityRecordIDs...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// List provides a mock function with given fields: ctx, query -func (_m *VulnerabilityRecordDao) List(ctx context.Context, query *q.Query) ([]*scan.VulnerabilityRecord, error) { - ret := _m.Called(ctx, query) - - var r0 []*scan.VulnerabilityRecord - if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*scan.VulnerabilityRecord); ok { - r0 = rf(ctx, query) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*scan.VulnerabilityRecord) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { - r1 = rf(ctx, query) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Update provides a mock function with given fields: ctx, vr, cols -func (_m *VulnerabilityRecordDao) Update(ctx context.Context, vr *scan.VulnerabilityRecord, cols ...string) error { - _va := make([]interface{}, len(cols)) - for _i := range cols { - _va[_i] = cols[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, vr) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *scan.VulnerabilityRecord, ...string) error); ok { - r0 = rf(ctx, vr, cols...) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/src/testing/pkg/scan/postprocessors/native_scan_report_converter.go b/src/testing/pkg/scan/postprocessors/native_scan_report_converter.go new file mode 100644 index 0000000000..377f6f29e0 --- /dev/null +++ b/src/testing/pkg/scan/postprocessors/native_scan_report_converter.go @@ -0,0 +1,91 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package postprocessors + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// NativeScanReportConverter is an autogenerated mock type for the NativeScanReportConverter type +type NativeScanReportConverter struct { + mock.Mock +} + +// FromRelationalSchema provides a mock function with given fields: ctx, reportUUID, artifactDigest, reportSummary +func (_m *NativeScanReportConverter) FromRelationalSchema(ctx context.Context, reportUUID string, artifactDigest string, reportSummary string) (string, error) { + ret := _m.Called(ctx, reportUUID, artifactDigest, reportSummary) + + if len(ret) == 0 { + panic("no return value specified for FromRelationalSchema") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (string, error)); ok { + return rf(ctx, reportUUID, artifactDigest, reportSummary) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) string); ok { + r0 = rf(ctx, reportUUID, artifactDigest, reportSummary) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { + r1 = rf(ctx, reportUUID, artifactDigest, reportSummary) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ToRelationalSchema provides a mock function with given fields: ctx, reportUUID, registrationUUID, digest, reportData +func (_m *NativeScanReportConverter) ToRelationalSchema(ctx context.Context, reportUUID string, registrationUUID string, digest string, reportData string) (string, string, error) { + ret := _m.Called(ctx, reportUUID, registrationUUID, digest, reportData) + + if len(ret) == 0 { + panic("no return value specified for ToRelationalSchema") + } + + var r0 string + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) (string, string, error)); ok { + return rf(ctx, reportUUID, registrationUUID, digest, reportData) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) string); ok { + r0 = rf(ctx, reportUUID, registrationUUID, digest, reportData) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) string); ok { + r1 = rf(ctx, reportUUID, registrationUUID, digest, reportData) + } else { + r1 = ret.Get(1).(string) + } + + if rf, ok := ret.Get(2).(func(context.Context, string, string, string, string) error); ok { + r2 = rf(ctx, reportUUID, registrationUUID, digest, reportData) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// NewNativeScanReportConverter creates a new instance of NativeScanReportConverter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNativeScanReportConverter(t interface { + mock.TestingT + Cleanup(func()) +}) *NativeScanReportConverter { + mock := &NativeScanReportConverter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/src/testing/pkg/scan/postprocessors/report_converters.go b/src/testing/pkg/scan/postprocessors/report_converters.go deleted file mode 100644 index 16944a26f5..0000000000 --- a/src/testing/pkg/scan/postprocessors/report_converters.go +++ /dev/null @@ -1,23 +0,0 @@ -package postprocessors - -import ( - "context" - - mock "github.com/stretchr/testify/mock" -) - -// ScanReportV1ToV2Converter is an auto-generated mock type for converting native Harbor report in JSON -// to relational schema -type ScanReportV1ToV2Converter struct { - mock.Mock -} - -// ToRelationalSchema is a mock implementation of the scan report conversion -func (_c *ScanReportV1ToV2Converter) ToRelationalSchema(ctx context.Context, reportUUID string, registrationUUID string, digest string, reportData string) (string, string, error) { - return "mockId", reportData, nil -} - -// ToRelationalSchema is a mock implementation of the scan report conversion -func (_c *ScanReportV1ToV2Converter) FromRelationalSchema(ctx context.Context, reportUUID string, artifactDigest string, reportData string) (string, error) { - return "mockId", nil -} diff --git a/src/testing/pkg/tag/manager.go b/src/testing/pkg/tag/manager.go index 75938f8756..23af9f07c2 100644 --- a/src/testing/pkg/tag/manager.go +++ b/src/testing/pkg/tag/manager.go @@ -1,79 +1,208 @@ -// Copyright Project Harbor 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. +// Code generated by mockery v2.43.2. DO NOT EDIT. package tag import ( - "context" + context "context" - "github.com/stretchr/testify/mock" + modeltag "github.com/goharbor/harbor/src/pkg/tag/model/tag" + mock "github.com/stretchr/testify/mock" - "github.com/goharbor/harbor/src/lib/q" - "github.com/goharbor/harbor/src/pkg/tag/model/tag" + q "github.com/goharbor/harbor/src/lib/q" ) -// FakeManager is a fake tag manager that implement the src/pkg/tag.Manager interface -type FakeManager struct { +// Manager is an autogenerated mock type for the Manager type +type Manager struct { mock.Mock } -// Count ... -func (f *FakeManager) Count(ctx context.Context, query *q.Query) (int64, error) { - args := f.Called() - return int64(args.Int(0)), args.Error(1) -} +// Count provides a mock function with given fields: ctx, query +func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) { + ret := _m.Called(ctx, query) -// List ... -func (f *FakeManager) List(ctx context.Context, query *q.Query) ([]*tag.Tag, error) { - args := f.Called() - var tags []*tag.Tag - if args.Get(0) != nil { - tags = args.Get(0).([]*tag.Tag) + if len(ret) == 0 { + panic("no return value specified for Count") } - return tags, args.Error(1) -} -// Get ... -func (f *FakeManager) Get(ctx context.Context, id int64) (*tag.Tag, error) { - args := f.Called() - var tg *tag.Tag - if args.Get(0) != nil { - tg = args.Get(0).(*tag.Tag) + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok { + return rf(ctx, query) } - return tg, args.Error(1) + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok { + r0 = rf(ctx, query) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Create ... -func (f *FakeManager) Create(ctx context.Context, tag *tag.Tag) (int64, error) { - args := f.Called() - return int64(args.Int(0)), args.Error(1) +// Create provides a mock function with given fields: ctx, _a1 +func (_m *Manager) Create(ctx context.Context, _a1 *modeltag.Tag) (int64, error) { + ret := _m.Called(ctx, _a1) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *modeltag.Tag) (int64, error)); ok { + return rf(ctx, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *modeltag.Tag) int64); ok { + r0 = rf(ctx, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *modeltag.Tag) error); ok { + r1 = rf(ctx, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Update ... -func (f *FakeManager) Update(ctx context.Context, tag *tag.Tag, props ...string) error { - args := f.Called() - return args.Error(0) +// Delete provides a mock function with given fields: ctx, id +func (_m *Manager) Delete(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 } -// Delete ... -func (f *FakeManager) Delete(ctx context.Context, id int64) error { - args := f.Called() - return args.Error(0) +// DeleteOfArtifact provides a mock function with given fields: ctx, artifactID +func (_m *Manager) DeleteOfArtifact(ctx context.Context, artifactID int64) error { + ret := _m.Called(ctx, artifactID) + + if len(ret) == 0 { + panic("no return value specified for DeleteOfArtifact") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, artifactID) + } else { + r0 = ret.Error(0) + } + + return r0 } -// DeleteOfArtifact ... -func (f *FakeManager) DeleteOfArtifact(ctx context.Context, artifactID int64) error { - args := f.Called() - return args.Error(0) +// Get provides a mock function with given fields: ctx, id +func (_m *Manager) Get(ctx context.Context, id int64) (*modeltag.Tag, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *modeltag.Tag + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*modeltag.Tag, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *modeltag.Tag); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*modeltag.Tag) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// List provides a mock function with given fields: ctx, query +func (_m *Manager) List(ctx context.Context, query *q.Query) ([]*modeltag.Tag, error) { + ret := _m.Called(ctx, query) + + if len(ret) == 0 { + panic("no return value specified for List") + } + + var r0 []*modeltag.Tag + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*modeltag.Tag, error)); ok { + return rf(ctx, query) + } + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*modeltag.Tag); ok { + r0 = rf(ctx, query) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*modeltag.Tag) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Update provides a mock function with given fields: ctx, _a1, props +func (_m *Manager) Update(ctx context.Context, _a1 *modeltag.Tag, props ...string) error { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *modeltag.Tag, ...string) error); ok { + r0 = rf(ctx, _a1, props...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManager(t interface { + mock.TestingT + Cleanup(func()) +}) *Manager { + mock := &Manager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } diff --git a/src/testing/registryctl/client.go b/src/testing/registryctl/client.go index 084716ce42..eca5728f16 100644 --- a/src/testing/registryctl/client.go +++ b/src/testing/registryctl/client.go @@ -1,24 +1,78 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + package registryctl -import ( - "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" -type Mockclient struct { +// Client is an autogenerated mock type for the Client type +type Client struct { mock.Mock } -// Health ... -func (c *Mockclient) Health() error { - return nil +// DeleteBlob provides a mock function with given fields: reference +func (_m *Client) DeleteBlob(reference string) error { + ret := _m.Called(reference) + + if len(ret) == 0 { + panic("no return value specified for DeleteBlob") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(reference) + } else { + r0 = ret.Error(0) + } + + return r0 } -// DeleteBlob ... -func (c *Mockclient) DeleteBlob(reference string) (err error) { - return nil +// DeleteManifest provides a mock function with given fields: repository, reference +func (_m *Client) DeleteManifest(repository string, reference string) error { + ret := _m.Called(repository, reference) + + if len(ret) == 0 { + panic("no return value specified for DeleteManifest") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(repository, reference) + } else { + r0 = ret.Error(0) + } + + return r0 } -// DeleteManifest ... -func (c *Mockclient) DeleteManifest(repository, reference string) (err error) { - return nil +// Health provides a mock function with given fields: +func (_m *Client) Health() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Health") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewClient(t interface { + mock.TestingT + Cleanup(func()) +}) *Client { + mock := &Client{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock } From b7f1b594951cbbda06242abbd1ebb507c5cbe2dc Mon Sep 17 00:00:00 2001 From: Wang Yan Date: Tue, 6 Aug 2024 18:29:13 +0800 Subject: [PATCH 34/74] add list project arifacts API (#20803) * add list project arifacts API This API supports listing all artifacts belonging to a specified project. It also allows fetching the latest artifact in each repositry, with the option to filter by either media_type or artifact_type. Signed-off-by: wang yan * resolve the comments Signed-off-by: wang yan --------- Signed-off-by: wang yan --- api/v2.0/swagger.yaml | 88 +++++++++++++++++++ src/controller/artifact/controller.go | 15 ++++ src/controller/artifact/controller_test.go | 38 ++++++++ src/controller/artifact/model.go | 9 +- src/pkg/artifact/dao/dao.go | 49 +++++++++++ src/pkg/artifact/dao/dao_test.go | 69 +++++++++++++++ src/pkg/artifact/manager.go | 18 ++++ src/pkg/artifact/manager_test.go | 27 ++++++ src/pkg/cached/artifact/redis/manager.go | 4 + src/server/v2.0/handler/artifact.go | 13 +-- src/server/v2.0/handler/model/artifact.go | 2 + src/server/v2.0/handler/project.go | 80 +++++++++++++++++ src/testing/controller/artifact/controller.go | 30 +++++++ src/testing/pkg/artifact/manager.go | 30 +++++++ 14 files changed, 462 insertions(+), 10 deletions(-) diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index c9e1e8a50f..b219902e31 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -1548,6 +1548,88 @@ paths: $ref: '#/responses/409' '500': $ref: '#/responses/500' + /projects/{project_name_or_id}/artifacts: + get: + summary: List artifacts + description: List artifacts of the specified project + tags: + - project + operationId: listArtifactsOfProject + parameters: + - $ref: '#/parameters/requestId' + - $ref: '#/parameters/isResourceName' + - $ref: '#/parameters/projectNameOrId' + - $ref: '#/parameters/query' + - $ref: '#/parameters/sort' + - $ref: '#/parameters/page' + - $ref: '#/parameters/pageSize' + - $ref: '#/parameters/acceptVulnerabilities' + - name: with_tag + in: query + description: Specify whether the tags are included inside the returning artifacts + type: boolean + required: false + default: true + - name: with_label + in: query + description: Specify whether the labels are included inside the returning artifacts + type: boolean + required: false + default: false + - name: with_scan_overview + in: query + description: Specify whether the scan overview is included inside the returning artifacts + type: boolean + required: false + default: false + - name: with_sbom_overview + in: query + description: Specify whether the SBOM overview is included in returning artifacts, when this option is true, the SBOM overview will be included in the response + type: boolean + required: false + default: false + - name: with_immutable_status + in: query + description: Specify whether the immutable status is included inside the tags of the returning artifacts. Only works when setting "with_immutable_status=true" + type: boolean + required: false + default: false + - name: with_accessory + in: query + description: Specify whether the accessories are included of the returning artifacts. Only works when setting "with_accessory=true" + type: boolean + required: false + default: false + - name: latest_in_repository + in: query + description: Specify whether only the latest pushed artifact of each repository is included inside the returning artifacts. Only works when either artifact_type or media_type is included in the query. + type: boolean + required: false + default: false + responses: + '200': + description: Success + headers: + X-Total-Count: + description: The total count of artifacts + type: integer + Link: + description: Link refers to the previous page and next page + type: string + schema: + type: array + items: + $ref: '#/definitions/Artifact' + '400': + $ref: '#/responses/400' + '401': + $ref: '#/responses/401' + '403': + $ref: '#/responses/403' + '404': + $ref: '#/responses/404' + '500': + $ref: '#/responses/500' '/projects/{project_name_or_id}/scanner': get: summary: Get project level scanner @@ -6586,6 +6668,9 @@ definitions: manifest_media_type: type: string description: The manifest media type of the artifact + artifact_type: + type: string + description: The artifact_type in the manifest of the artifact project_id: type: integer format: int64 @@ -6594,6 +6679,9 @@ definitions: type: integer format: int64 description: The ID of the repository that the artifact belongs to + repository_name: + type: string + description: The name of the repository that the artifact belongs to digest: type: string description: The digest of the artifact diff --git a/src/controller/artifact/controller.go b/src/controller/artifact/controller.go index 45f6e4f59c..0a28882629 100644 --- a/src/controller/artifact/controller.go +++ b/src/controller/artifact/controller.go @@ -118,6 +118,8 @@ type Controller interface { Walk(ctx context.Context, root *Artifact, walkFn func(*Artifact) error, option *Option) error // HasUnscannableLayer check artifact with digest if has unscannable layer HasUnscannableLayer(ctx context.Context, dgst string) (bool, error) + // ListWithLatest list the artifacts when the latest_in_repository in the query was set + ListWithLatest(ctx context.Context, query *q.Query, option *Option) (artifacts []*Artifact, err error) } // NewController creates an instance of the default artifact controller @@ -782,3 +784,16 @@ func (c *controller) HasUnscannableLayer(ctx context.Context, dgst string) (bool } return false, nil } + +// ListWithLatest ... +func (c *controller) ListWithLatest(ctx context.Context, query *q.Query, option *Option) (artifacts []*Artifact, err error) { + arts, err := c.artMgr.ListWithLatest(ctx, query) + if err != nil { + return nil, err + } + var res []*Artifact + for _, art := range arts { + res = append(res, c.assembleArtifact(ctx, art, option)) + } + return res, nil +} diff --git a/src/controller/artifact/controller_test.go b/src/controller/artifact/controller_test.go index 6521b1f19e..d4b6743db7 100644 --- a/src/controller/artifact/controller_test.go +++ b/src/controller/artifact/controller_test.go @@ -323,6 +323,44 @@ func (c *controllerTestSuite) TestList() { c.Equal(0, len(artifacts[0].Accessories)) } +func (c *controllerTestSuite) TestListWithLatest() { + query := &q.Query{} + option := &Option{ + WithTag: true, + WithAccessory: true, + } + c.artMgr.On("ListWithLatest", mock.Anything, mock.Anything).Return([]*artifact.Artifact{ + { + ID: 1, + RepositoryID: 1, + }, + }, nil) + c.tagCtl.On("List").Return([]*tag.Tag{ + { + Tag: model_tag.Tag{ + ID: 1, + RepositoryID: 1, + ArtifactID: 1, + Name: "latest", + }, + }, + }, nil) + c.repoMgr.On("Get", mock.Anything, mock.Anything).Return(&repomodel.RepoRecord{ + Name: "library/hello-world", + }, nil) + c.repoMgr.On("List", mock.Anything, mock.Anything).Return([]*repomodel.RepoRecord{ + {RepositoryID: 1, Name: "library/hello-world"}, + }, nil) + c.accMgr.On("List", mock.Anything, mock.Anything).Return([]accessorymodel.Accessory{}, nil) + artifacts, err := c.ctl.ListWithLatest(nil, query, option) + c.Require().Nil(err) + c.Require().Len(artifacts, 1) + c.Equal(int64(1), artifacts[0].ID) + c.Require().Len(artifacts[0].Tags, 1) + c.Equal(int64(1), artifacts[0].Tags[0].ID) + c.Equal(0, len(artifacts[0].Accessories)) +} + func (c *controllerTestSuite) TestGet() { c.artMgr.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(&artifact.Artifact{ ID: 1, diff --git a/src/controller/artifact/model.go b/src/controller/artifact/model.go index 6bf731dd75..d24369c986 100644 --- a/src/controller/artifact/model.go +++ b/src/controller/artifact/model.go @@ -102,8 +102,9 @@ type AdditionLink struct { // Option is used to specify the properties returned when listing/getting artifacts type Option struct { - WithTag bool - TagOption *tag.Option // only works when WithTag is set to true - WithLabel bool - WithAccessory bool + WithTag bool + TagOption *tag.Option // only works when WithTag is set to true + WithLabel bool + WithAccessory bool + LatestInRepository bool } diff --git a/src/pkg/artifact/dao/dao.go b/src/pkg/artifact/dao/dao.go index 0e2e79a41c..c59baeb7f5 100644 --- a/src/pkg/artifact/dao/dao.go +++ b/src/pkg/artifact/dao/dao.go @@ -54,6 +54,8 @@ type DAO interface { DeleteReference(ctx context.Context, id int64) (err error) // DeleteReferences deletes the references referenced by the artifact specified by parent ID DeleteReferences(ctx context.Context, parentID int64) (err error) + // ListWithLatest ... + ListWithLatest(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error) } const ( @@ -282,6 +284,53 @@ func (d *dao) DeleteReferences(ctx context.Context, parentID int64) error { return err } +func (d *dao) ListWithLatest(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error) { + ormer, err := orm.FromContext(ctx) + if err != nil { + return nil, err + } + + sql := `SELECT a.* + FROM artifact a + JOIN ( + SELECT repository_name, MAX(push_time) AS latest_push_time + FROM artifact + WHERE project_id = ? and %s = ? + GROUP BY repository_name + ) latest ON a.repository_name = latest.repository_name AND a.push_time = latest.latest_push_time` + + queryParam := make([]interface{}, 0) + var ok bool + var pid interface{} + if pid, ok = query.Keywords["ProjectID"]; !ok { + return nil, errors.New(nil).WithCode(errors.BadRequestCode). + WithMessage(`the value of "ProjectID" must be set`) + } + queryParam = append(queryParam, pid) + + var attributionValue interface{} + if attributionValue, ok = query.Keywords["media_type"]; ok { + sql = fmt.Sprintf(sql, "media_type") + } else if attributionValue, ok = query.Keywords["artifact_type"]; ok { + sql = fmt.Sprintf(sql, "artifact_type") + } + + if attributionValue == "" { + return nil, errors.New(nil).WithCode(errors.BadRequestCode). + WithMessage(`the value of "media_type" or "artifact_type" must be set`) + } + queryParam = append(queryParam, attributionValue) + + sql, queryParam = orm.PaginationOnRawSQL(query, sql, queryParam) + arts := []*Artifact{} + _, err = ormer.Raw(sql, queryParam...).QueryRows(&arts) + if err != nil { + return nil, err + } + + return arts, nil +} + func querySetter(ctx context.Context, query *q.Query, options ...orm.Option) (beegoorm.QuerySeter, error) { qs, err := orm.QuerySetter(ctx, &Artifact{}, query, options...) if err != nil { diff --git a/src/pkg/artifact/dao/dao_test.go b/src/pkg/artifact/dao/dao_test.go index adefcfff72..08b448fba8 100644 --- a/src/pkg/artifact/dao/dao_test.go +++ b/src/pkg/artifact/dao/dao_test.go @@ -472,6 +472,75 @@ func (d *daoTestSuite) TestDeleteReferences() { d.True(errors.IsErr(err, errors.NotFoundCode)) } +func (d *daoTestSuite) TestListWithLatest() { + now := time.Now() + art := &Artifact{ + Type: "IMAGE", + MediaType: v1.MediaTypeImageConfig, + ManifestMediaType: v1.MediaTypeImageIndex, + ProjectID: 1234, + RepositoryID: 1234, + RepositoryName: "library2/hello-world1", + Digest: "digest", + PushTime: now, + PullTime: now, + Annotations: `{"anno1":"value1"}`, + } + id, err := d.dao.Create(d.ctx, art) + d.Require().Nil(err) + + time.Sleep(1 * time.Second) + now = time.Now() + + art2 := &Artifact{ + Type: "IMAGE", + MediaType: v1.MediaTypeImageConfig, + ManifestMediaType: v1.MediaTypeImageIndex, + ProjectID: 1234, + RepositoryID: 1235, + RepositoryName: "library2/hello-world2", + Digest: "digest", + PushTime: now, + PullTime: now, + Annotations: `{"anno1":"value1"}`, + } + id1, err := d.dao.Create(d.ctx, art2) + d.Require().Nil(err) + + time.Sleep(1 * time.Second) + now = time.Now() + + art3 := &Artifact{ + Type: "IMAGE", + MediaType: v1.MediaTypeImageConfig, + ManifestMediaType: v1.MediaTypeImageIndex, + ProjectID: 1234, + RepositoryID: 1235, + RepositoryName: "library2/hello-world2", + Digest: "digest2", + PushTime: now, + PullTime: now, + Annotations: `{"anno1":"value1"}`, + } + id2, err := d.dao.Create(d.ctx, art3) + d.Require().Nil(err) + + latest, err := d.dao.ListWithLatest(d.ctx, &q.Query{ + Keywords: map[string]interface{}{ + "ProjectID": 1234, + "media_type": v1.MediaTypeImageConfig, + }, + }) + + d.Require().Nil(err) + d.Require().Equal(2, len(latest)) + d.Equal("library2/hello-world1", latest[0].RepositoryName) + + defer d.dao.Delete(d.ctx, id) + defer d.dao.Delete(d.ctx, id1) + defer d.dao.Delete(d.ctx, id2) +} + func TestDaoTestSuite(t *testing.T) { suite.Run(t, &daoTestSuite{}) } diff --git a/src/pkg/artifact/manager.go b/src/pkg/artifact/manager.go index b28fd8b253..ec133c341b 100644 --- a/src/pkg/artifact/manager.go +++ b/src/pkg/artifact/manager.go @@ -48,6 +48,8 @@ type Manager interface { ListReferences(ctx context.Context, query *q.Query) (references []*Reference, err error) // DeleteReference specified by ID DeleteReference(ctx context.Context, id int64) (err error) + // ListWithLatest list the artifacts when the latest_in_repository in the query was set + ListWithLatest(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error) } // NewManager returns an instance of the default manager @@ -147,6 +149,22 @@ func (m *manager) DeleteReference(ctx context.Context, id int64) error { return m.dao.DeleteReference(ctx, id) } +func (m *manager) ListWithLatest(ctx context.Context, query *q.Query) ([]*Artifact, error) { + arts, err := m.dao.ListWithLatest(ctx, query) + if err != nil { + return nil, err + } + var artifacts []*Artifact + for _, art := range arts { + artifact, err := m.assemble(ctx, art) + if err != nil { + return nil, err + } + artifacts = append(artifacts, artifact) + } + return artifacts, nil +} + // assemble the artifact with references populated func (m *manager) assemble(ctx context.Context, art *dao.Artifact) (*Artifact, error) { artifact := &Artifact{} diff --git a/src/pkg/artifact/manager_test.go b/src/pkg/artifact/manager_test.go index 9418705cfd..af434d7c22 100644 --- a/src/pkg/artifact/manager_test.go +++ b/src/pkg/artifact/manager_test.go @@ -80,6 +80,11 @@ func (f *fakeDao) DeleteReferences(ctx context.Context, parentID int64) error { return args.Error(0) } +func (f *fakeDao) ListWithLatest(ctx context.Context, query *q.Query) ([]*dao.Artifact, error) { + args := f.Called() + return args.Get(0).([]*dao.Artifact), args.Error(1) +} + type managerTestSuite struct { suite.Suite mgr *manager @@ -135,6 +140,28 @@ func (m *managerTestSuite) TestAssemble() { m.Equal(2, len(artifact.References)) } +func (m *managerTestSuite) TestListWithLatest() { + art := &dao.Artifact{ + ID: 1, + Type: "IMAGE", + MediaType: "application/vnd.oci.image.config.v1+json", + ManifestMediaType: "application/vnd.oci.image.manifest.v1+json", + ProjectID: 1, + RepositoryID: 1, + Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180", + Size: 1024, + PushTime: time.Now(), + PullTime: time.Now(), + ExtraAttrs: `{"attr1":"value1"}`, + Annotations: `{"anno1":"value1"}`, + } + m.dao.On("ListWithLatest", mock.Anything).Return([]*dao.Artifact{art}, nil) + artifacts, err := m.mgr.ListWithLatest(nil, nil) + m.Require().Nil(err) + m.Equal(1, len(artifacts)) + m.Equal(art.ID, artifacts[0].ID) +} + func (m *managerTestSuite) TestList() { art := &dao.Artifact{ ID: 1, diff --git a/src/pkg/cached/artifact/redis/manager.go b/src/pkg/cached/artifact/redis/manager.go index c5371a3a74..11879affde 100644 --- a/src/pkg/cached/artifact/redis/manager.go +++ b/src/pkg/cached/artifact/redis/manager.go @@ -65,6 +65,10 @@ func (m *Manager) List(ctx context.Context, query *q.Query) ([]*artifact.Artifac return m.delegator.List(ctx, query) } +func (m *Manager) ListWithLatest(ctx context.Context, query *q.Query) ([]*artifact.Artifact, error) { + return m.delegator.ListWithLatest(ctx, query) +} + func (m *Manager) Create(ctx context.Context, artifact *artifact.Artifact) (int64, error) { return m.delegator.Create(ctx, artifact) } diff --git a/src/server/v2.0/handler/artifact.go b/src/server/v2.0/handler/artifact.go index dfc457047d..79cf316223 100644 --- a/src/server/v2.0/handler/artifact.go +++ b/src/server/v2.0/handler/artifact.go @@ -95,7 +95,7 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr // set option option := option(params.WithTag, params.WithImmutableStatus, - params.WithLabel, params.WithAccessory) + params.WithLabel, params.WithAccessory, nil) // get the total count of artifacts total, err := a.artCtl.Count(ctx, query) @@ -129,7 +129,7 @@ func (a *artifactAPI) GetArtifact(ctx context.Context, params operation.GetArtif } // set option option := option(params.WithTag, params.WithImmutableStatus, - params.WithLabel, params.WithAccessory) + params.WithLabel, params.WithAccessory, nil) // get the artifact artifact, err := a.artCtl.GetByReference(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName), params.Reference, option) @@ -501,11 +501,12 @@ func (a *artifactAPI) RequireLabelInProject(ctx context.Context, projectID, labe return nil } -func option(withTag, withImmutableStatus, withLabel, withAccessory *bool) *artifact.Option { +func option(withTag, withImmutableStatus, withLabel, withAccessory *bool, latestInRepository *bool) *artifact.Option { option := &artifact.Option{ - WithTag: true, // return the tag by default - WithLabel: lib.BoolValue(withLabel), - WithAccessory: true, // return the accessory by default + WithTag: true, // return the tag by default + WithLabel: lib.BoolValue(withLabel), + WithAccessory: true, // return the accessory by default + LatestInRepository: lib.BoolValue(latestInRepository), } if withTag != nil { diff --git a/src/server/v2.0/handler/model/artifact.go b/src/server/v2.0/handler/model/artifact.go index f931c0abf2..78d4d11baf 100644 --- a/src/server/v2.0/handler/model/artifact.go +++ b/src/server/v2.0/handler/model/artifact.go @@ -49,6 +49,8 @@ func (a *Artifact) ToSwagger() *models.Artifact { PushTime: strfmt.DateTime(a.PushTime), ExtraAttrs: a.ExtraAttrs, Annotations: a.Annotations, + ArtifactType: a.ArtifactType, + RepositoryName: a.RepositoryName, } for _, reference := range a.References { diff --git a/src/server/v2.0/handler/project.go b/src/server/v2.0/handler/project.go index 29286f8ec4..6a133fb30f 100644 --- a/src/server/v2.0/handler/project.go +++ b/src/server/v2.0/handler/project.go @@ -29,6 +29,7 @@ import ( "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/common/security/local" robotSec "github.com/goharbor/harbor/src/common/security/robot" + "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/p2p/preheat" "github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/controller/quota" @@ -52,6 +53,7 @@ import ( "github.com/goharbor/harbor/src/pkg/retention/policy" "github.com/goharbor/harbor/src/pkg/robot" userModels "github.com/goharbor/harbor/src/pkg/user/models" + "github.com/goharbor/harbor/src/server/v2.0/handler/assembler" "github.com/goharbor/harbor/src/server/v2.0/handler/model" "github.com/goharbor/harbor/src/server/v2.0/models" operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/project" @@ -63,6 +65,7 @@ const defaultDaysToRetentionForProxyCacheProject = 7 func newProjectAPI() *projectAPI { return &projectAPI{ auditMgr: audit.Mgr, + artCtl: artifact.Ctl, metadataMgr: pkg.ProjectMetaMgr, userCtl: user.Ctl, repositoryCtl: repository.Ctl, @@ -79,6 +82,7 @@ func newProjectAPI() *projectAPI { type projectAPI struct { BaseAPI auditMgr audit.Manager + artCtl artifact.Controller metadataMgr metadata.Manager userCtl user.Controller repositoryCtl repository.Controller @@ -660,6 +664,82 @@ func (a *projectAPI) SetScannerOfProject(ctx context.Context, params operation.S return operation.NewSetScannerOfProjectOK() } +func (a *projectAPI) ListArtifactsOfProject(ctx context.Context, params operation.ListArtifactsOfProjectParams) middleware.Responder { + if err := a.RequireAuthenticated(ctx); err != nil { + return a.SendError(ctx, err) + } + projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName) + if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionList, rbac.ResourceArtifact); err != nil { + return a.SendError(ctx, err) + } + // set query + pro, err := a.projectCtl.Get(ctx, projectNameOrID) + if err != nil { + return a.SendError(ctx, err) + } + query, err := a.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize) + if err != nil { + return a.SendError(ctx, err) + } + query.Keywords["ProjectID"] = pro.ProjectID + + // set option + option := option(params.WithTag, params.WithImmutableStatus, + params.WithLabel, params.WithAccessory, params.LatestInRepository) + + var total int64 + // list artifacts according to the query and option + var arts []*artifact.Artifact + if option.LatestInRepository { + // ignore page & page_size + _, hasMediaType := query.Keywords["media_type"] + _, hasArtifactType := query.Keywords["artifact_type"] + if hasMediaType == hasArtifactType { + return a.SendError(ctx, errors.BadRequestError(fmt.Errorf("either 'media_type' or 'artifact_type' must be specified, but not both, when querying with latest_in_repository"))) + } + + getCount := func() (int64, error) { + var countQ *q.Query + if query != nil { + countQ = q.New(query.Keywords) + } + allArts, err := a.artCtl.ListWithLatest(ctx, countQ, nil) + if err != nil { + return int64(0), err + } + return int64(len(allArts)), nil + } + total, err = getCount() + if err != nil { + return a.SendError(ctx, err) + } + arts, err = a.artCtl.ListWithLatest(ctx, query, option) + } else { + total, err = a.artCtl.Count(ctx, query) + if err != nil { + return a.SendError(ctx, err) + } + arts, err = a.artCtl.List(ctx, query, option) + } + if err != nil { + return a.SendError(ctx, err) + } + overviewOpts := model.NewOverviewOptions(model.WithSBOM(lib.BoolValue(params.WithSbomOverview)), model.WithVuln(lib.BoolValue(params.WithScanOverview))) + assembler := assembler.NewScanReportAssembler(overviewOpts, parseScanReportMimeTypes(params.XAcceptVulnerabilities)) + var artifacts []*models.Artifact + for _, art := range arts { + artifact := &model.Artifact{} + artifact.Artifact = *art + _ = assembler.WithArtifacts(artifact).Assemble(ctx) + artifacts = append(artifacts, artifact.ToSwagger()) + } + + return operation.NewListArtifactsOfProjectOK(). + WithXTotalCount(total). + WithLink(a.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()). + WithPayload(artifacts) +} + func (a *projectAPI) deletable(ctx context.Context, projectNameOrID interface{}) (*project.Project, *models.ProjectDeletable, error) { p, err := a.getProject(ctx, projectNameOrID) if err != nil { diff --git a/src/testing/controller/artifact/controller.go b/src/testing/controller/artifact/controller.go index 23ed6396f0..3ec563103d 100644 --- a/src/testing/controller/artifact/controller.go +++ b/src/testing/controller/artifact/controller.go @@ -296,6 +296,36 @@ func (_m *Controller) List(ctx context.Context, query *q.Query, option *artifact return r0, r1 } +// ListWithLatest provides a mock function with given fields: ctx, query, option +func (_m *Controller) ListWithLatest(ctx context.Context, query *q.Query, option *artifact.Option) ([]*artifact.Artifact, error) { + ret := _m.Called(ctx, query, option) + + if len(ret) == 0 { + panic("no return value specified for ListWithLatest") + } + + var r0 []*artifact.Artifact + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query, *artifact.Option) ([]*artifact.Artifact, error)); ok { + return rf(ctx, query, option) + } + if rf, ok := ret.Get(0).(func(context.Context, *q.Query, *artifact.Option) []*artifact.Artifact); ok { + r0 = rf(ctx, query, option) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*artifact.Artifact) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *q.Query, *artifact.Option) error); ok { + r1 = rf(ctx, query, option) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RemoveLabel provides a mock function with given fields: ctx, artifactID, labelID func (_m *Controller) RemoveLabel(ctx context.Context, artifactID int64, labelID int64) error { ret := _m.Called(ctx, artifactID, labelID) diff --git a/src/testing/pkg/artifact/manager.go b/src/testing/pkg/artifact/manager.go index 208bfa040a..a189685cc6 100644 --- a/src/testing/pkg/artifact/manager.go +++ b/src/testing/pkg/artifact/manager.go @@ -231,6 +231,36 @@ func (_m *Manager) ListReferences(ctx context.Context, query *q.Query) ([]*artif return r0, r1 } +// ListWithLatest provides a mock function with given fields: ctx, query +func (_m *Manager) ListWithLatest(ctx context.Context, query *q.Query) ([]*artifact.Artifact, error) { + ret := _m.Called(ctx, query) + + if len(ret) == 0 { + panic("no return value specified for ListWithLatest") + } + + var r0 []*artifact.Artifact + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*artifact.Artifact, error)); ok { + return rf(ctx, query) + } + if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*artifact.Artifact); ok { + r0 = rf(ctx, query) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*artifact.Artifact) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Update provides a mock function with given fields: ctx, _a1, props func (_m *Manager) Update(ctx context.Context, _a1 *artifact.Artifact, props ...string) error { _va := make([]interface{}, len(props)) From ec77bd9b12359b7fed1ce0a52fd14a83d6bdfbb8 Mon Sep 17 00:00:00 2001 From: Lichao Xue <68891670+xuelichao@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:51:39 +0800 Subject: [PATCH 35/74] Fixes-20799 can't remove artifact labels (#20816) Signed-off-by: xuelichao --- .../artifact-list-tab/artifact-list-tab.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index ad601cf6d6..d5516f1072 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -139,6 +139,7 @@ }} Date: Thu, 8 Aug 2024 19:02:54 +0800 Subject: [PATCH 37/74] feat: implement bandwidth limit for proxy-cache (#20812) Signed-off-by: Shengwen Yu --- api/v2.0/swagger.yaml | 4 ++ src/controller/proxy/controller.go | 2 +- src/controller/proxy/options.go | 37 +++++++++++++++++++ src/controller/proxy/options_test.go | 33 +++++++++++++++++ src/controller/proxy/remote.go | 17 +++++++-- .../replication/transfer/image/transfer.go | 5 ++- .../transfer => lib}/iothrottler.go | 2 +- src/pkg/project/models/pro_meta.go | 1 + src/pkg/project/models/project.go | 13 +++++++ src/server/middleware/repoproxy/proxy.go | 10 ++--- src/server/middleware/repoproxy/tag.go | 4 +- src/server/v2.0/handler/project.go | 17 +++++++++ src/server/v2.0/handler/project_metadata.go | 6 +++ 13 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 src/controller/proxy/options.go create mode 100644 src/controller/proxy/options_test.go rename src/{controller/replication/transfer => lib}/iothrottler.go (98%) diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index b219902e31..681d0e354c 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -7340,6 +7340,10 @@ definitions: type: string description: 'The ID of the tag retention policy for the project' x-nullable: true + proxy_speed_kb: + type: string + description: 'The bandwidth limit of proxy cache, in Kbps (kilobits per second). It limits the communication between Harbor and the upstream registry, not the client and the Harbor.' + x-nullable: true ProjectSummary: type: object properties: diff --git a/src/controller/proxy/controller.go b/src/controller/proxy/controller.go index 38d55397c3..7138b6f0b0 100644 --- a/src/controller/proxy/controller.go +++ b/src/controller/proxy/controller.go @@ -264,7 +264,7 @@ func (c *controller) HeadManifest(_ context.Context, art lib.ArtifactInfo, remot func (c *controller) ProxyBlob(ctx context.Context, p *proModels.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) { remoteRepo := getRemoteRepo(art) log.Debugf("The blob doesn't exist, proxy the request to the target server, url:%v", remoteRepo) - rHelper, err := NewRemoteHelper(ctx, p.RegistryID) + rHelper, err := NewRemoteHelper(ctx, p.RegistryID, WithSpeed(p.ProxyCacheSpeed())) if err != nil { return 0, nil, err } diff --git a/src/controller/proxy/options.go b/src/controller/proxy/options.go new file mode 100644 index 0000000000..2f81bfc3ff --- /dev/null +++ b/src/controller/proxy/options.go @@ -0,0 +1,37 @@ +// Copyright Project Harbor 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 proxy + +type Option func(*Options) + +type Options struct { + // Speed is the data transfer speed for proxy cache from Harbor to upstream registry, no limit by default. + Speed int32 +} + +func NewOptions(opts ...Option) *Options { + o := &Options{} + for _, opt := range opts { + opt(o) + } + + return o +} + +func WithSpeed(speed int32) Option { + return func(o *Options) { + o.Speed = speed + } +} diff --git a/src/controller/proxy/options_test.go b/src/controller/proxy/options_test.go new file mode 100644 index 0000000000..2b0a4ef801 --- /dev/null +++ b/src/controller/proxy/options_test.go @@ -0,0 +1,33 @@ +// Copyright Project Harbor 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 proxy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewOptions(t *testing.T) { + // test default options + o := NewOptions() + assert.Equal(t, int32(0), o.Speed) + + // test with options + // with speed + withSpeed := WithSpeed(1024) + o = NewOptions(withSpeed) + assert.Equal(t, int32(1024), o.Speed) +} diff --git a/src/controller/proxy/remote.go b/src/controller/proxy/remote.go index ac7f23f28b..4143b81709 100644 --- a/src/controller/proxy/remote.go +++ b/src/controller/proxy/remote.go @@ -21,6 +21,7 @@ import ( "github.com/docker/distribution" + "github.com/goharbor/harbor/src/lib" "github.com/goharbor/harbor/src/pkg/reg" "github.com/goharbor/harbor/src/pkg/reg/adapter" "github.com/goharbor/harbor/src/pkg/reg/model" @@ -43,13 +44,16 @@ type remoteHelper struct { regID int64 registry adapter.ArtifactRegistry registryMgr reg.Manager + opts *Options } // NewRemoteHelper create a remote interface -func NewRemoteHelper(ctx context.Context, regID int64) (RemoteInterface, error) { +func NewRemoteHelper(ctx context.Context, regID int64, opts ...Option) (RemoteInterface, error) { r := &remoteHelper{ regID: regID, - registryMgr: reg.Mgr} + registryMgr: reg.Mgr, + opts: NewOptions(opts...), + } if err := r.init(ctx); err != nil { return nil, err } @@ -83,7 +87,14 @@ func (r *remoteHelper) init(ctx context.Context) error { } func (r *remoteHelper) BlobReader(repo, dig string) (int64, io.ReadCloser, error) { - return r.registry.PullBlob(repo, dig) + sz, bReader, err := r.registry.PullBlob(repo, dig) + if err != nil { + return 0, nil, err + } + if r.opts != nil && r.opts.Speed > 0 { + bReader = lib.NewReader(bReader, r.opts.Speed) + } + return sz, bReader, err } func (r *remoteHelper) Manifest(repo string, ref string) (distribution.Manifest, string, error) { diff --git a/src/controller/replication/transfer/image/transfer.go b/src/controller/replication/transfer/image/transfer.go index 55bda96469..09c1bea27e 100644 --- a/src/controller/replication/transfer/image/transfer.go +++ b/src/controller/replication/transfer/image/transfer.go @@ -30,6 +30,7 @@ import ( common_http "github.com/goharbor/harbor/src/common/http" trans "github.com/goharbor/harbor/src/controller/replication/transfer" + "github.com/goharbor/harbor/src/lib" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/pkg/reg/adapter" "github.com/goharbor/harbor/src/pkg/reg/model" @@ -380,7 +381,7 @@ func (t *transfer) copyBlobByMonolithic(srcRepo, dstRepo, digest string, sizeFro return err } if speed > 0 { - data = trans.NewReader(data, speed) + data = lib.NewReader(data, speed) } defer data.Close() // get size 0 from PullBlob, use size from distribution.Descriptor instead. @@ -435,7 +436,7 @@ func (t *transfer) copyBlobByChunk(srcRepo, dstRepo, digest string, sizeFromDesc } if speed > 0 { - data = trans.NewReader(data, speed) + data = lib.NewReader(data, speed) } // failureEnd will only be used for adjusting content range when issue happened during push the chunk. var failureEnd int64 diff --git a/src/controller/replication/transfer/iothrottler.go b/src/lib/iothrottler.go similarity index 98% rename from src/controller/replication/transfer/iothrottler.go rename to src/lib/iothrottler.go index 828c440357..b0853e0e58 100644 --- a/src/controller/replication/transfer/iothrottler.go +++ b/src/lib/iothrottler.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package transfer +package lib import ( "fmt" diff --git a/src/pkg/project/models/pro_meta.go b/src/pkg/project/models/pro_meta.go index a8a0659fe8..25f7e41bee 100644 --- a/src/pkg/project/models/pro_meta.go +++ b/src/pkg/project/models/pro_meta.go @@ -24,4 +24,5 @@ const ( ProMetaAutoScan = "auto_scan" ProMetaReuseSysCVEAllowlist = "reuse_sys_cve_allowlist" ProMetaAutoSBOMGen = "auto_sbom_generation" + ProMetaProxySpeed = "proxy_speed_kb" ) diff --git a/src/pkg/project/models/project.go b/src/pkg/project/models/project.go index e533bd9112..80318aa21a 100644 --- a/src/pkg/project/models/project.go +++ b/src/pkg/project/models/project.go @@ -156,6 +156,19 @@ func (p *Project) AutoSBOMGen() bool { return isTrue(auto) } +// ProxyCacheSpeed ... +func (p *Project) ProxyCacheSpeed() int32 { + speed, exist := p.GetMetadata(ProMetaProxySpeed) + if !exist { + return 0 + } + speedInt, err := strconv.ParseInt(speed, 10, 32) + if err != nil { + return 0 + } + return int32(speedInt) +} + // FilterByPublic returns orm.QuerySeter with public filter func (p *Project) FilterByPublic(_ context.Context, qs orm.QuerySeter, _ string, value interface{}) orm.QuerySeter { subQuery := `SELECT project_id FROM project_metadata WHERE name = 'public' AND value = '%s'` diff --git a/src/server/middleware/repoproxy/proxy.go b/src/server/middleware/repoproxy/proxy.go index ddb2017843..641638766e 100644 --- a/src/server/middleware/repoproxy/proxy.go +++ b/src/server/middleware/repoproxy/proxy.go @@ -60,7 +60,7 @@ func BlobGetMiddleware() func(http.Handler) http.Handler { func handleBlob(w http.ResponseWriter, r *http.Request, next http.Handler) error { ctx := r.Context() - art, p, proxyCtl, err := preCheck(ctx) + art, p, proxyCtl, err := preCheck(ctx, true) if err != nil { return err } @@ -96,14 +96,14 @@ func handleBlob(w http.ResponseWriter, r *http.Request, next http.Handler) error return nil } -func preCheck(ctx context.Context) (art lib.ArtifactInfo, p *proModels.Project, ctl proxy.Controller, err error) { +func preCheck(ctx context.Context, withProjectMetadata bool) (art lib.ArtifactInfo, p *proModels.Project, ctl proxy.Controller, err error) { none := lib.ArtifactInfo{} art = lib.GetArtifactInfo(ctx) if art == none { return none, nil, nil, errors.New("artifactinfo is not found").WithCode(errors.NotFoundCode) } ctl = proxy.ControllerInstance() - p, err = project.Ctl.GetByName(ctx, art.ProjectName, project.Metadata(false)) + p, err = project.Ctl.GetByName(ctx, art.ProjectName, project.Metadata(withProjectMetadata)) return } @@ -155,7 +155,7 @@ func defaultBlobURL(projectName string, name string, digest string) string { func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) error { ctx := r.Context() - art, p, proxyCtl, err := preCheck(ctx) + art, p, proxyCtl, err := preCheck(ctx, true) if err != nil { return err } @@ -174,7 +174,7 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e next.ServeHTTP(w, r) return nil } - remote, err := proxy.NewRemoteHelper(r.Context(), p.RegistryID) + remote, err := proxy.NewRemoteHelper(r.Context(), p.RegistryID, proxy.WithSpeed(p.ProxyCacheSpeed())) if err != nil { return err } diff --git a/src/server/middleware/repoproxy/tag.go b/src/server/middleware/repoproxy/tag.go index 6e0d3070d4..005a5f7774 100644 --- a/src/server/middleware/repoproxy/tag.go +++ b/src/server/middleware/repoproxy/tag.go @@ -35,7 +35,7 @@ func TagsListMiddleware() func(http.Handler) http.Handler { return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) { ctx := r.Context() - art, p, _, err := preCheck(ctx) + art, p, _, err := preCheck(ctx, false) if err != nil { libhttp.SendError(w, err) return @@ -69,7 +69,7 @@ func TagsListMiddleware() func(http.Handler) http.Handler { util.SendListTagsResponse(w, r, tags) }() - remote, err := proxy.NewRemoteHelper(ctx, p.RegistryID) + remote, err := proxy.NewRemoteHelper(ctx, p.RegistryID, proxy.WithSpeed(p.ProxyCacheSpeed())) if err != nil { logger.Warningf("failed to get remote interface, error: %v, fallback to local tags", err) return diff --git a/src/server/v2.0/handler/project.go b/src/server/v2.0/handler/project.go index 6a133fb30f..0479929540 100644 --- a/src/server/v2.0/handler/project.go +++ b/src/server/v2.0/handler/project.go @@ -159,6 +159,11 @@ func (a *projectAPI) CreateProject(ctx context.Context, params operation.CreateP } } + // ignore metadata.proxy_speed_kb for non-proxy-cache project + if req.RegistryID == nil { + req.Metadata.ProxySpeedKb = nil + } + // ignore enable_content_trust metadata for proxy cache project // see https://github.com/goharbor/harbor/issues/12940 to get more info if req.RegistryID != nil { @@ -551,6 +556,11 @@ func (a *projectAPI) UpdateProject(ctx context.Context, params operation.UpdateP } } + // ignore metadata.proxy_speed_kb for non-proxy-cache project + if params.Project.Metadata != nil && !p.IsProxy() { + params.Project.Metadata.ProxySpeedKb = nil + } + // ignore enable_content_trust metadata for proxy cache project // see https://github.com/goharbor/harbor/issues/12940 to get more info if params.Project.Metadata != nil && p.IsProxy() { @@ -792,6 +802,13 @@ func (a *projectAPI) validateProjectReq(ctx context.Context, req *models.Project if !permitted { return errors.BadRequestError(fmt.Errorf("unsupported registry type %s", string(registry.Type))) } + + // validate metadata.proxy_speed_kb. It should be an int32 + if ps := req.Metadata.ProxySpeedKb; ps != nil { + if _, err := strconv.ParseInt(*ps, 10, 32); err != nil { + return errors.BadRequestError(nil).WithMessage(fmt.Sprintf("metadata.proxy_speed_kb should by an int32, but got: '%s', err: %s", *ps, err)) + } + } } if req.StorageLimit != nil { diff --git a/src/server/v2.0/handler/project_metadata.go b/src/server/v2.0/handler/project_metadata.go index a5bde2e453..7fa297b723 100644 --- a/src/server/v2.0/handler/project_metadata.go +++ b/src/server/v2.0/handler/project_metadata.go @@ -155,6 +155,12 @@ func (p *projectMetadataAPI) validate(metas map[string]string) (map[string]strin return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid value: %s", value) } metas[proModels.ProMetaSeverity] = strings.ToLower(severity.String()) + case proModels.ProMetaProxySpeed: + v, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid value: %s", value) + } + metas[proModels.ProMetaProxySpeed] = strconv.FormatInt(v, 10) default: return nil, errors.New(nil).WithCode(errors.BadRequestCode).WithMessage("invalid key: %s", key) } From eb5193e0ef0cd7911196008c4097c1e35c258b42 Mon Sep 17 00:00:00 2001 From: "stonezdj(Daojun Zhang)" Date: Fri, 9 Aug 2024 15:24:25 +0800 Subject: [PATCH 38/74] Parallel attach ldap group (#20705) Parallel attach LDAP group Add configure LDAP group attach parallel UI Change the /c/login timeout from 60 (nginx default) to 900 seconds in nginx.conf Signed-off-by: stonezdj --- api/v2.0/swagger.yaml | 8 ++ .../templates/nginx/nginx.http.conf.jinja | 3 + src/common/const.go | 1 + src/core/auth/ldap/ldap.go | 95 +++++++++++++++++-- src/lib/config/metadata/metadatalist.go | 1 + src/lib/config/models/model.go | 1 + src/lib/config/userconfig.go | 1 + .../config/auth/config-auth.component.html | 31 ++++++ .../config/auth/config-auth.component.ts | 7 +- .../app/base/left-side-nav/config/config.ts | 1 + src/portal/src/i18n/lang/en-us-lang.json | 4 +- src/portal/src/i18n/lang/zh-cn-lang.json | 5 +- 12 files changed, 144 insertions(+), 14 deletions(-) diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index 681d0e354c..07beb01e9a 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -8989,6 +8989,9 @@ definitions: ldap_group_search_scope: $ref: '#/definitions/IntegerConfigItem' description: The scope to search ldap group. ''0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE'' + ldap_group_attach_parallel: + $ref: '#/definitions/BoolConfigItem' + description: Attach LDAP user group information in parallel. ldap_scope: $ref: '#/definitions/IntegerConfigItem' description: The scope to search ldap users,'0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE' @@ -9179,6 +9182,11 @@ definitions: description: The scope to search ldap group. ''0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE'' x-omitempty: true x-isnullable: true + ldap_group_attach_parallel: + type: boolean + description: Attach LDAP user group information in parallel, the parallel worker count is 5 + x-omitempty: true + x-isnullable: true ldap_scope: type: integer description: The scope to search ldap users,'0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE' diff --git a/make/photon/prepare/templates/nginx/nginx.http.conf.jinja b/make/photon/prepare/templates/nginx/nginx.http.conf.jinja index 6022b3ac94..7e55e72ded 100644 --- a/make/photon/prepare/templates/nginx/nginx.http.conf.jinja +++ b/make/photon/prepare/templates/nginx/nginx.http.conf.jinja @@ -101,6 +101,9 @@ http { proxy_buffering off; proxy_request_buffering off; + + proxy_send_timeout 900; + proxy_read_timeout 900; } location /api/ { diff --git a/src/common/const.go b/src/common/const.go index aaa3c3fbe0..224a2e4f35 100644 --- a/src/common/const.go +++ b/src/common/const.go @@ -134,6 +134,7 @@ const ( OIDCGroupType = 3 LDAPGroupAdminDn = "ldap_group_admin_dn" LDAPGroupMembershipAttribute = "ldap_group_membership_attribute" + LDAPGroupAttachParallel = "ldap_group_attach_parallel" DefaultRegistryControllerEndpoint = "http://registryctl:8080" DefaultPortalURL = "http://portal:8080" DefaultRegistryCtlURL = "http://registryctl:8080" diff --git a/src/core/auth/ldap/ldap.go b/src/core/auth/ldap/ldap.go index 38fa5a6f93..56533b2875 100644 --- a/src/core/auth/ldap/ldap.go +++ b/src/core/auth/ldap/ldap.go @@ -21,6 +21,7 @@ import ( "strings" goldap "github.com/go-ldap/ldap/v3" + "golang.org/x/sync/errgroup" "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/models" @@ -38,6 +39,10 @@ import ( ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model" ) +const ( + workerCount = 5 +) + // Auth implements AuthenticateHelper interface to authenticate against LDAP type Auth struct { auth.DefaultAuthenticateHelper @@ -117,24 +122,94 @@ func (l *Auth) attachLDAPGroup(ctx context.Context, ldapUsers []model.User, u *m return } userGroups := make([]ugModel.UserGroup, 0) + if groupCfg.AttachParallel { + log.Debug("Attach LDAP group in parallel") + l.attachGroupParallel(ctx, ldapUsers, u) + return + } + // Attach LDAP group sequencially for _, dn := range ldapUsers[0].GroupDNList { - lGroups, err := sess.SearchGroupByDN(dn) - if err != nil { - log.Warningf("Can not get the ldap group name with DN %v, error %v", dn, err) - continue + if lgroup, exist := verifyGroupInLDAP(dn, sess); exist { + userGroups = append(userGroups, ugModel.UserGroup{GroupName: lgroup.Name, LdapGroupDN: dn, GroupType: common.LDAPGroupType}) } - if len(lGroups) == 0 { - log.Warningf("Can not get the ldap group name with DN %v", dn) - continue - } - userGroups = append(userGroups, ugModel.UserGroup{GroupName: lGroups[0].Name, LdapGroupDN: dn, GroupType: common.LDAPGroupType}) } u.GroupIDs, err = ugCtl.Ctl.Populate(ctx, userGroups) if err != nil { - log.Warningf("Failed to fetch ldap group configuration:%v", err) + log.Warningf("Failed to populate ldap group, error: %v", err) } } +func (l *Auth) attachGroupParallel(ctx context.Context, ldapUsers []model.User, u *models.User) { + userGroupsList := make([][]ugModel.UserGroup, workerCount) + gdsList := make([][]string, workerCount) + // Divide the groupDNs into workerCount parts + for index, dn := range ldapUsers[0].GroupDNList { + idx := index % workerCount + gdsList[idx] = append(gdsList[idx], dn) + } + g := new(errgroup.Group) + g.SetLimit(workerCount) + + for i := 0; i < workerCount; i++ { + curIndex := i + g.Go(func() error { + userGroups := make([]ugModel.UserGroup, 0) + groups := gdsList[curIndex] + if len(groups) == 0 { + return nil + } + // use different ldap session for each go routine + ldapSession, err := ldapCtl.Ctl.Session(ctx) + if err != nil { + return err + } + if err = ldapSession.Open(); err != nil { + return err + } + defer ldapSession.Close() + log.Debugf("Current worker index is %v", curIndex) + // verify and populate group + for _, dn := range groups { + if lgroup, exist := verifyGroupInLDAP(dn, ldapSession); exist { + userGroups = append(userGroups, ugModel.UserGroup{GroupName: lgroup.Name, LdapGroupDN: dn, GroupType: common.LDAPGroupType}) + } + } + userGroupsList[curIndex] = userGroups + + return nil + }) + } + if err := g.Wait(); err != nil { + log.Warningf("failed to verify and populate ldap group parallel, error %v", err) + } + ugs := make([]ugModel.UserGroup, 0) + for _, userGroups := range userGroupsList { + ugs = append(ugs, userGroups...) + } + + groupIDsList, err := ugCtl.Ctl.Populate(ctx, ugs) + if err != nil { + log.Warningf("Failed to populate user groups :%v", err) + } + u.GroupIDs = groupIDsList +} + +func verifyGroupInLDAP(groupDN string, sess *ldap.Session) (*model.Group, bool) { + if _, err := goldap.ParseDN(groupDN); err != nil { + return nil, false + } + lGroups, err := sess.SearchGroupByDN(groupDN) + if err != nil { + log.Warningf("Can not get the ldap group name with DN %v, error %v", groupDN, err) + return nil, false + } + if len(lGroups) == 0 { + log.Warningf("Can not get the ldap group name with DN %v", groupDN) + return nil, false + } + return &lGroups[0], true +} + func (l *Auth) syncUserInfoFromDB(ctx context.Context, u *models.User) { // Retrieve SysAdminFlag from DB so that it transfer to session dbUser, err := l.userMgr.GetByName(ctx, u.Username) diff --git a/src/lib/config/metadata/metadatalist.go b/src/lib/config/metadata/metadatalist.go index dd2a7f67cd..aab4919fd8 100644 --- a/src/lib/config/metadata/metadatalist.go +++ b/src/lib/config/metadata/metadatalist.go @@ -96,6 +96,7 @@ var ( {Name: common.LDAPURL, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_URL", DefaultValue: "", ItemType: &NonEmptyStringType{}, Editable: false, Description: `The URL of LDAP server`}, {Name: common.LDAPVerifyCert, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_VERIFY_CERT", DefaultValue: "true", ItemType: &BoolType{}, Editable: false, Description: `Whether verify your OIDC server certificate, disable it if your OIDC server is hosted via self-hosted certificate.`}, {Name: common.LDAPGroupMembershipAttribute, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_GROUP_MEMBERSHIP_ATTRIBUTE", DefaultValue: "memberof", ItemType: &StringType{}, Editable: true, Description: `The user attribute to identify the group membership`}, + {Name: common.LDAPGroupAttachParallel, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_GROUP_ATTACH_PARALLEL", DefaultValue: "false", ItemType: &BoolType{}, Editable: true, Description: `Attach LDAP group information to Harbor in parallel`}, {Name: common.MaxJobWorkers, Scope: SystemScope, Group: BasicGroup, EnvKey: "MAX_JOB_WORKERS", DefaultValue: "10", ItemType: &IntType{}, Editable: false}, {Name: common.ScanAllPolicy, Scope: UserScope, Group: BasicGroup, EnvKey: "", DefaultValue: "", ItemType: &MapType{}, Editable: false, Description: `The policy to scan images`}, diff --git a/src/lib/config/models/model.go b/src/lib/config/models/model.go index 51a9c0c2cb..25b41388ac 100644 --- a/src/lib/config/models/model.go +++ b/src/lib/config/models/model.go @@ -94,6 +94,7 @@ type GroupConf struct { SearchScope int `json:"ldap_group_search_scope"` AdminDN string `json:"ldap_group_admin_dn,omitempty"` MembershipAttribute string `json:"ldap_group_membership_attribute,omitempty"` + AttachParallel bool `json:"ldap_group_attach_parallel,omitempty"` } type GDPRSetting struct { diff --git a/src/lib/config/userconfig.go b/src/lib/config/userconfig.go index a0fd5f90ae..4012097c9e 100644 --- a/src/lib/config/userconfig.go +++ b/src/lib/config/userconfig.go @@ -81,6 +81,7 @@ func LDAPGroupConf(ctx context.Context) (*cfgModels.GroupConf, error) { SearchScope: mgr.Get(ctx, common.LDAPGroupSearchScope).GetInt(), AdminDN: mgr.Get(ctx, common.LDAPGroupAdminDn).GetString(), MembershipAttribute: mgr.Get(ctx, common.LDAPGroupMembershipAttribute).GetString(), + AttachParallel: mgr.Get(ctx, common.LDAPGroupAttachParallel).GetBool(), }, nil } diff --git a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html index b64ba7cf51..2b1401d1b5 100644 --- a/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html +++ b/src/portal/src/app/base/left-side-nav/config/auth/config-auth.component.html @@ -498,6 +498,37 @@ + + + + + +
+
+ +
+ + +
+ +
+ + {{ 'PROJECT.SPEED_LIMIT_TIP' | translate }} + +
+