From 424f11e69748e9d81cade968ab793f657fc202a2 Mon Sep 17 00:00:00 2001 From: wang yan Date: Fri, 18 Oct 2019 11:43:58 +0800 Subject: [PATCH 1/8] add immutable match in the repository/tag delete api Signed-off-by: wang yan --- docs/swagger.yaml | 2 + src/common/models/repo.go | 1 + src/core/api/repository.go | 32 ++++-- src/core/middlewares/config.go | 2 +- src/core/middlewares/immutable/builder.go | 54 ++++++++++ src/core/middlewares/immutable/handler.go | 102 +++++++++--------- .../interceptor/immutable/deletemf.go | 65 +++++++++++ .../interceptor/immutable/pushmf.go | 65 +++++++++++ src/core/middlewares/util/error/immutable.go | 20 ++++ 9 files changed, 283 insertions(+), 60 deletions(-) create mode 100644 src/core/middlewares/immutable/builder.go create mode 100644 src/core/middlewares/interceptor/immutable/deletemf.go create mode 100644 src/core/middlewares/interceptor/immutable/pushmf.go create mode 100644 src/core/middlewares/util/error/immutable.go diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6b85f001b..3bd2de958 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1089,6 +1089,8 @@ paths: description: Forbidden. '404': description: Repository not found. + '412': + description: Precondition Failed. put: summary: Update description of the repository. description: | diff --git a/src/common/models/repo.go b/src/common/models/repo.go index 6562e9531..aa2bc24ec 100644 --- a/src/common/models/repo.go +++ b/src/common/models/repo.go @@ -73,6 +73,7 @@ type TagDetail struct { Author string `json:"author"` Created time.Time `json:"created"` Config *TagCfg `json:"config"` + Immutable bool `json:"immutable"` } // TagCfg ... diff --git a/src/core/api/repository.go b/src/core/api/repository.go index 6d9a1f7f5..ac3284bea 100755 --- a/src/core/api/repository.go +++ b/src/core/api/repository.go @@ -28,7 +28,7 @@ import ( "github.com/goharbor/harbor/src/jobservice/logger" "github.com/goharbor/harbor/src/pkg/scan/api/scan" - v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1" + "github.com/goharbor/harbor/src/pkg/scan/rest/v1" "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" @@ -45,6 +45,8 @@ import ( "github.com/goharbor/harbor/src/core/config" notifierEvt "github.com/goharbor/harbor/src/core/notifier/event" coreutils "github.com/goharbor/harbor/src/core/utils" + "github.com/goharbor/harbor/src/pkg/art" + "github.com/goharbor/harbor/src/pkg/immutabletag/match/rule" "github.com/goharbor/harbor/src/replication" "github.com/goharbor/harbor/src/replication/event" "github.com/goharbor/harbor/src/replication/model" @@ -283,11 +285,6 @@ func (ra *RepositoryAPI) Delete() { } for _, t := range tags { - image := fmt.Sprintf("%s:%s", repoName, t) - if err = dao.DeleteLabelsOfResource(common.ResourceTypeImage, image); err != nil { - ra.SendInternalServerError(fmt.Errorf("failed to delete labels of image %s: %v", image, err)) - return - } if err = rc.DeleteTag(t); err != nil { if regErr, ok := err.(*commonhttp.Error); ok { if regErr.Code == http.StatusNotFound { @@ -298,6 +295,11 @@ func (ra *RepositoryAPI) Delete() { return } log.Infof("delete tag: %s:%s", repoName, t) + image := fmt.Sprintf("%s:%s", repoName, t) + if err = dao.DeleteLabelsOfResource(common.ResourceTypeImage, image); err != nil { + ra.SendInternalServerError(fmt.Errorf("failed to delete labels of image %s: %v", image, err)) + return + } go func(tag string) { e := &event.Event{ @@ -711,6 +713,9 @@ func assembleTag(c chan *models.TagResp, client *registry.Repository, projectID } } + // get immutable status + item.Immutable = isImmutable(projectID, repository, tag) + c <- item } @@ -791,6 +796,21 @@ func populateAuthor(detail *models.TagDetail) { } } +// check whether the tag is immutable +func isImmutable(projectID int64, repo string, tag string) bool { + _, repoName := utils.ParseRepository(repo) + matched, err := rule.NewRuleMatcher(projectID).Match(art.Candidate{ + Repository: repoName, + Tag: tag, + NamespaceID: projectID, + }) + if err != nil { + log.Error(err) + return false + } + return matched +} + // GetManifests returns the manifest of a tag func (ra *RepositoryAPI) GetManifests() { repoName := ra.GetString(":splat") diff --git a/src/core/middlewares/config.go b/src/core/middlewares/config.go index adc2a75c4..fa2b536f5 100644 --- a/src/core/middlewares/config.go +++ b/src/core/middlewares/config.go @@ -35,4 +35,4 @@ var ChartMiddlewares = []string{CHART} var Middlewares = []string{READONLY, URL, MUITIPLEMANIFEST, LISTREPO, CONTENTTRUST, VULNERABLE, SIZEQUOTA, IMMUTABLE, COUNTQUOTA} // MiddlewaresLocal ... -var MiddlewaresLocal = []string{SIZEQUOTA, COUNTQUOTA} +var MiddlewaresLocal = []string{SIZEQUOTA, IMMUTABLE, COUNTQUOTA} diff --git a/src/core/middlewares/immutable/builder.go b/src/core/middlewares/immutable/builder.go new file mode 100644 index 000000000..30707299d --- /dev/null +++ b/src/core/middlewares/immutable/builder.go @@ -0,0 +1,54 @@ +package immutable + +import ( + "fmt" + "github.com/goharbor/harbor/src/core/middlewares/interceptor" + "github.com/goharbor/harbor/src/core/middlewares/interceptor/immutable" + "github.com/goharbor/harbor/src/core/middlewares/util" + "net/http" +) + +var ( + defaultBuilders = []interceptor.Builder{ + &manifestDeletionBuilder{}, + &manifestCreationBuilder{}, + } +) + +type manifestDeletionBuilder struct{} + +func (*manifestDeletionBuilder) Build(req *http.Request) (interceptor.Interceptor, error) { + if match, _, _ := util.MatchDeleteManifest(req); !match { + return nil, nil + } + + info, ok := util.ManifestInfoFromContext(req.Context()) + if !ok { + var err error + info, err = util.ParseManifestInfoFromPath(req) + if err != nil { + return nil, fmt.Errorf("failed to parse manifest, error %v", err) + } + } + + return immutable.NewDeleteMFInteceptor(info), nil +} + +type manifestCreationBuilder struct{} + +func (*manifestCreationBuilder) Build(req *http.Request) (interceptor.Interceptor, error) { + if match, _, _ := util.MatchPushManifest(req); !match { + return nil, nil + } + + info, ok := util.ManifestInfoFromContext(req.Context()) + if !ok { + var err error + info, err = util.ParseManifestInfoFromReq(req) + if err != nil { + return nil, fmt.Errorf("failed to parse manifest, error %v", err) + } + } + + return immutable.NewPushMFInteceptor(info), nil +} diff --git a/src/core/middlewares/immutable/handler.go b/src/core/middlewares/immutable/handler.go index 0566d9df0..e9deb2dbf 100644 --- a/src/core/middlewares/immutable/handler.go +++ b/src/core/middlewares/immutable/handler.go @@ -16,78 +16,74 @@ package immutable import ( "fmt" - "github.com/goharbor/harbor/src/common/dao" - "github.com/goharbor/harbor/src/common/models" - common_util "github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/common/utils/log" + "github.com/goharbor/harbor/src/core/middlewares/interceptor" "github.com/goharbor/harbor/src/core/middlewares/util" - "github.com/goharbor/harbor/src/pkg/art" - "github.com/goharbor/harbor/src/pkg/immutabletag/match/rule" + middlerware_err "github.com/goharbor/harbor/src/core/middlewares/util/error" "net/http" ) type immutableHandler struct { - next http.Handler + builders []interceptor.Builder + next http.Handler } // New ... -func New(next http.Handler) http.Handler { +func New(next http.Handler, builders ...interceptor.Builder) http.Handler { + if len(builders) == 0 { + builders = defaultBuilders + } + return &immutableHandler{ - next: next, + builders: builders, + next: next, } } // ServeHTTP ... -func (rh immutableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if match, _, _ := util.MatchPushManifest(req); !match { +func (rh *immutableHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + + interceptor, err := rh.getInterceptor(req) + if err != nil { + log.Warningf("Error occurred when to handle request in immutable handler: %v", err) + http.Error(rw, util.MarshalError("InternalError", fmt.Sprintf("Error occurred when to handle request in immutable handler: %v", err)), + http.StatusInternalServerError) + return + } + + if interceptor == nil { rh.next.ServeHTTP(rw, req) return } - info, ok := util.ManifestInfoFromContext(req.Context()) - if !ok { - var err error - info, err = util.ParseManifestInfoFromPath(req) - if err != nil { - log.Error(err) - rh.next.ServeHTTP(rw, req) + + if err := interceptor.HandleRequest(req); err != nil { + log.Warningf("Error occurred when to handle request in immutable handler: %v", err) + if _, ok := err.(middlerware_err.ErrImmutable); ok { + http.Error(rw, util.MarshalError("DENIED", + fmt.Sprintf("The tag is immutable, cannot be overwrite: %v", err)), http.StatusPreconditionFailed) return } + http.Error(rw, util.MarshalError("InternalError", fmt.Sprintf("Error occurred when to handle request in immutable handler: %v", err)), + http.StatusInternalServerError) + return + } + + rh.next.ServeHTTP(rw, req) + + interceptor.HandleResponse(rw, req) +} + +func (rh *immutableHandler) getInterceptor(req *http.Request) (interceptor.Interceptor, error) { + for _, builder := range rh.builders { + interceptor, err := builder.Build(req) + if err != nil { + return nil, err + } + + if interceptor != nil { + return interceptor, nil + } } - _, repoName := common_util.ParseRepository(info.Repository) - matched, err := rule.NewRuleMatcher(info.ProjectID).Match(art.Candidate{ - Repository: repoName, - Tag: info.Tag, - NamespaceID: info.ProjectID, - }) - if err != nil { - log.Error(err) - rh.next.ServeHTTP(rw, req) - return - } - if !matched { - rh.next.ServeHTTP(rw, req) - return - } - - artifactQuery := &models.ArtifactQuery{ - PID: info.ProjectID, - Repo: info.Repository, - Tag: info.Tag, - } - afs, err := dao.ListArtifacts(artifactQuery) - if err != nil { - log.Error(err) - rh.next.ServeHTTP(rw, req) - return - } - if len(afs) == 0 { - rh.next.ServeHTTP(rw, req) - return - } - - // rule matched and non-existent is a immutable tag - http.Error(rw, util.MarshalError("DENIED", - fmt.Sprintf("The tag:%s:%s is immutable, cannot be overwrite.", info.Repository, info.Tag)), http.StatusPreconditionFailed) - return + return nil, nil } diff --git a/src/core/middlewares/interceptor/immutable/deletemf.go b/src/core/middlewares/interceptor/immutable/deletemf.go new file mode 100644 index 000000000..b1b8e2495 --- /dev/null +++ b/src/core/middlewares/interceptor/immutable/deletemf.go @@ -0,0 +1,65 @@ +package immutable + +import ( + "github.com/goharbor/harbor/src/common/dao" + "github.com/goharbor/harbor/src/common/models" + common_util "github.com/goharbor/harbor/src/common/utils" + "github.com/goharbor/harbor/src/common/utils/log" + "github.com/goharbor/harbor/src/core/middlewares/interceptor" + "github.com/goharbor/harbor/src/core/middlewares/util" + middlerware_err "github.com/goharbor/harbor/src/core/middlewares/util/error" + "github.com/goharbor/harbor/src/pkg/art" + "github.com/goharbor/harbor/src/pkg/immutabletag/match/rule" + "net/http" +) + +// NewDeleteMFInteceptor .... +func NewDeleteMFInteceptor(mf *util.ManifestInfo) interceptor.Interceptor { + return &delmfInterceptor{ + mf: mf, + } +} + +type delmfInterceptor struct { + mf *util.ManifestInfo +} + +// HandleRequest ... +func (dmf *delmfInterceptor) HandleRequest(req *http.Request) (err error) { + + artifactQuery := &models.ArtifactQuery{ + Digest: dmf.mf.Digest, + } + var afs []*models.Artifact + afs, err = dao.ListArtifacts(artifactQuery) + if err != nil { + log.Error(err) + return + } + if len(afs) == 0 { + return + } + + for _, af := range afs { + _, repoName := common_util.ParseRepository(dmf.mf.Repository) + var matched bool + matched, err = rule.NewRuleMatcher(dmf.mf.ProjectID).Match(art.Candidate{ + Repository: repoName, + Tag: af.Tag, + NamespaceID: dmf.mf.ProjectID, + }) + if err != nil { + log.Error(err) + return + } + if matched { + return middlerware_err.NewErrImmutable(repoName) + } + } + + return +} + +// HandleRequest ... +func (dmf *delmfInterceptor) HandleResponse(w http.ResponseWriter, r *http.Request) { +} diff --git a/src/core/middlewares/interceptor/immutable/pushmf.go b/src/core/middlewares/interceptor/immutable/pushmf.go new file mode 100644 index 000000000..307579bd5 --- /dev/null +++ b/src/core/middlewares/interceptor/immutable/pushmf.go @@ -0,0 +1,65 @@ +package immutable + +import ( + "github.com/goharbor/harbor/src/common/dao" + "github.com/goharbor/harbor/src/common/models" + common_util "github.com/goharbor/harbor/src/common/utils" + "github.com/goharbor/harbor/src/common/utils/log" + "github.com/goharbor/harbor/src/core/middlewares/interceptor" + "github.com/goharbor/harbor/src/core/middlewares/util" + middlerware_err "github.com/goharbor/harbor/src/core/middlewares/util/error" + "github.com/goharbor/harbor/src/pkg/art" + "github.com/goharbor/harbor/src/pkg/immutabletag/match/rule" + "net/http" +) + +// NewPushMFInteceptor .... +func NewPushMFInteceptor(mf *util.ManifestInfo) interceptor.Interceptor { + return &pushmfInterceptor{ + mf: mf, + } +} + +type pushmfInterceptor struct { + mf *util.ManifestInfo +} + +// HandleRequest ... +func (pmf *pushmfInterceptor) HandleRequest(req *http.Request) (err error) { + + _, repoName := common_util.ParseRepository(pmf.mf.Repository) + var matched bool + matched, err = rule.NewRuleMatcher(pmf.mf.ProjectID).Match(art.Candidate{ + Repository: repoName, + Tag: pmf.mf.Tag, + NamespaceID: pmf.mf.ProjectID, + }) + if err != nil { + log.Error(err) + return + } + if !matched { + return + } + + artifactQuery := &models.ArtifactQuery{ + PID: pmf.mf.ProjectID, + Repo: pmf.mf.Repository, + Tag: pmf.mf.Tag, + } + var afs []*models.Artifact + afs, err = dao.ListArtifacts(artifactQuery) + if err != nil { + log.Error(err) + return + } + if len(afs) == 0 { + return + } + + return middlerware_err.NewErrImmutable(repoName) +} + +// HandleRequest ... +func (pmf *pushmfInterceptor) HandleResponse(w http.ResponseWriter, r *http.Request) { +} diff --git a/src/core/middlewares/util/error/immutable.go b/src/core/middlewares/util/error/immutable.go new file mode 100644 index 000000000..a7789300d --- /dev/null +++ b/src/core/middlewares/util/error/immutable.go @@ -0,0 +1,20 @@ +package error + +import ( + "fmt" +) + +// ErrImmutable ... +type ErrImmutable struct { + repo string +} + +// Error ... +func (ei ErrImmutable) Error() string { + return fmt.Sprintf("Failed to process request, due to immutable. '%s'", ei.repo) +} + +// NewErrImmutable ... +func NewErrImmutable(msg string) ErrImmutable { + return ErrImmutable{repo: msg} +} From d22e6899f870ced3a9c6e0d044e604e1b067334a Mon Sep 17 00:00:00 2001 From: Michael Michael Date: Mon, 21 Oct 2019 06:16:06 -0500 Subject: [PATCH 2/8] Update ROADMAP.md --- ROADMAP.md | 53 ++++++++++++----------------------------------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 18738072a..9fc478bb2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,41 +1,12 @@ -## Harbor Roadmap - -### About this document - -This document provides description of items that are gathered from the community and planned in Harbor's roadmap. This should serve as a reference point for Harbor users and contributors to understand where the project is heading, and help determine if a contribution could be conflicting with a longer term plan. - -### How to help? - -Discussion on the roadmap can take place in threads under [Issues](https://github.com/vmware/harbor/issues). Please open and comment on an issue if you want to provide suggestions and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort. - -### How to add an item to the roadmap? -Please open an issue to track any initiative on the roadmap of Harbor. We will work with and rely on our community to focus our efforts to improve Harbor. - - ---- - -### 1. Notary -The notary feature allows publishers to sign their images offline and to push the signed content to a notary server. This ensures the authenticity of images. - -### 2. Vulnerability Scanning -The capability to scan images for vulnerability. - -### 3. Image replication enhancement -To provide more sophisticated rule for image replication. -- Image filtering by tags -- Replication can be scheduled at a certain time using a rule like: one time only, daily, weekly, etc. -- Image deletion can have the option not to be replicated to a remote instance. -- Global replication rule: Instead of setting the rule of individual project, system admin can set a global rule for all projects. -- Project admin can set replication policy of the project. - -### 4. Authentication (OAuth2) -In addition to LDAP/AD and local users, OAuth 2.0 can be used to authenticate a user. - -### 5. High Availability -Support multi-node deployment of Harbor for high availability, scalability and load-balancing purposes. - -### 6. Statistics and description for repositories -User can add a description to a repository. The access count of a repo can be aggregated and displayed. - -### 7. Migration tool to move from an existing registry to Harbor -A tool to migrate images from a vanilla registry server to Harbor, without the need to export/import a large amount of data. +## Harbor Roadmap + +### About this document + +This document provides a link to the [Harbor Project board](https://github.com/orgs/goharbor/projects/1) that serves as the up to date description of items that are in the Harbor release pipeline. The board has separate swim lanes for each release. Most items are gathered from the community or include a feedback loop with the community. This should serve as a reference point for Harbor users and contributors to understand where the project is heading, and help determine if a contribution could be conflicting with a longer term plan. + +### How to help? + +Discussion on the roadmap can take place in threads under [Issues](https://github.com/vmware/harbor/issues) or in [community meetings](https://github.com/goharbor/community/blob/master/MEETING_SCHEDULE.md). Please open and comment on an issue if you want to provide suggestions and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort. + +### How to add an item to the roadmap? +Please open an issue to track any initiative on the roadmap of Harbor (Usually driven by new feature requests). We will work with and rely on our community to focus our efforts to improve Harbor. From 2bf77fc599f53265193e9906c1210312336842c7 Mon Sep 17 00:00:00 2001 From: Michael Michael Date: Mon, 21 Oct 2019 15:37:19 -0700 Subject: [PATCH 3/8] Update installation_guide.md --- docs/installation_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation_guide.md b/docs/installation_guide.md index d424464b5..c78c7606d 100644 --- a/docs/installation_guide.md +++ b/docs/installation_guide.md @@ -12,7 +12,7 @@ This guide describes the steps to install and configure Harbor by using the onli If you run a previous version of Harbor, you may need to update ```harbor.yml``` and migrate the data to fit the new database schema. For more details, please refer to **[Harbor Migration Guide](migration_guide.md)**. -In addition, the deployment instructions on Kubernetes has been created by the community. Refer to [Harbor on Kubernetes](kubernetes_deployment.md) for details. +In addition, the deployment instructions on Kubernetes has been created by the community. Refer to [Harbor on Kubernetes using Helm](https://github.com/goharbor/harbor-helm) for details. ## Harbor Components From 3f15a38141d14684874c3ead14f04b0b8f614eab Mon Sep 17 00:00:00 2001 From: Michael Michael Date: Mon, 21 Oct 2019 16:01:55 -0700 Subject: [PATCH 4/8] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7e0264fa4..040b0de15 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,16 @@ |![notification](docs/img/bell-outline-badged.svg)Community Meeting| |------------------| -|The Harbor Project holds bi-weekly community calls, to join them and watch previous meeting notes and recordings, please see [meeting schedule](https://github.com/goharbor/community/blob/master/MEETING_SCHEDULE.md).| +|The Harbor Project holds bi-weekly community calls in two different timezones. To join the community calls or to watch previous meeting notes and recordings, please visit the [meeting schedule](https://github.com/goharbor/community/blob/master/MEETING_SCHEDULE.md).| -Welcome to join below Harbor community events and meet with project maintainers and users: +We welcome you to join the below Harbor community events and meet with project maintainers and users: -**May 20-24, 2019**, [KubeCon EU, Barcelona](https://events.linuxfoundation.org/events/kubecon-cloudnativecon-europe-2019/): Harbor Community Reception, Intro and Deep-dive sessions. +**November 18-21, 2019**, [KubeCon US, San Diego](https://events19.linuxfoundation.org/events/kubecon-cloudnativecon-north-america-2019): Harbor Lunch & Learn led by Joe Beda, Intro and Deep-dive sessions. -**June 24-26, 2019**, [KubeCon Shanghai](https://www.lfasiallc.com/events/kubecon-cloudnativecon-china-2019/): Harbor community meetup, Harbor session.

**Note**: The `master` branch may be in an *unstable or even broken state* during development. -Please use [releases](https://github.com/vmware/harbor/releases) instead of the `master` branch in order to get stable binaries. +Please use [releases](https://github.com/vmware/harbor/releases) instead of the `master` branch in order to get a stable set of binaries. Harbor From 7b93e845e177acaad13b83987516cb4328b0e66d Mon Sep 17 00:00:00 2001 From: Yogi_Wang Date: Tue, 22 Oct 2019 10:11:25 +0800 Subject: [PATCH 5/8] Modify the words of setting cli secret Signed-off-by: Yogi_Wang --- tests/resources/Harbor-Pages/OIDC_Auth.robot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/Harbor-Pages/OIDC_Auth.robot b/tests/resources/Harbor-Pages/OIDC_Auth.robot index 021c2bb4d..866cbc19c 100644 --- a/tests/resources/Harbor-Pages/OIDC_Auth.robot +++ b/tests/resources/Harbor-Pages/OIDC_Auth.robot @@ -54,6 +54,6 @@ Generate And Return Secret Retry Element Click ${more_btn} Retry Element Click ${generate_secret_btn} Retry Double Keywords When Error Retry Element Click ${confirm_btn} Retry Wait Until Page Not Contains Element ${confirm_btn} - Retry Wait Until Page Contains generate CLI secret success + Retry Wait Until Page Contains Cli secret setting is successful ${secret}= Get Secrete By API ${url} [Return] ${secret} \ No newline at end of file From 3e826c4e80cc0cc4608615ea99ed45b2a26269ca Mon Sep 17 00:00:00 2001 From: wang yan Date: Tue, 22 Oct 2019 18:30:03 +0800 Subject: [PATCH 6/8] update query in the immutable delete manifest middleware Signed-off-by: wang yan --- src/core/middlewares/interceptor/immutable/deletemf.go | 2 ++ tests/apitests/python/test_project_quota.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/middlewares/interceptor/immutable/deletemf.go b/src/core/middlewares/interceptor/immutable/deletemf.go index b1b8e2495..6fb2e659a 100644 --- a/src/core/middlewares/interceptor/immutable/deletemf.go +++ b/src/core/middlewares/interceptor/immutable/deletemf.go @@ -29,6 +29,8 @@ func (dmf *delmfInterceptor) HandleRequest(req *http.Request) (err error) { artifactQuery := &models.ArtifactQuery{ Digest: dmf.mf.Digest, + Repo: dmf.mf.Repository, + PID: dmf.mf.ProjectID, } var afs []*models.Artifact afs, err = dao.ListArtifacts(artifactQuery) diff --git a/tests/apitests/python/test_project_quota.py b/tests/apitests/python/test_project_quota.py index 8ab8c842b..820568411 100644 --- a/tests/apitests/python/test_project_quota.py +++ b/tests/apitests/python/test_project_quota.py @@ -73,7 +73,7 @@ class TestProjects(unittest.TestCase): #5. Get project quota quota = self.system.get_project_quota("project", TestProjects.project_test_quota_id, **ADMIN_CLIENT) self.assertEqual(quota[0].used["count"], 1) - self.assertEqual(quota[0].used["storage"], 2791709) + self.assertEqual(quota[0].used["storage"], 2789174) #6. Delete repository(RA) by user(UA); self.repo.delete_repoitory(TestProjects.repo_name, **ADMIN_CLIENT) From d111cae9d20fd98c37209011839172527fb7d3b7 Mon Sep 17 00:00:00 2001 From: Michael Michael Date: Tue, 22 Oct 2019 11:16:09 -0700 Subject: [PATCH 7/8] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 9fc478bb2..00cbc8c5b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,7 +6,7 @@ This document provides a link to the [Harbor Project board](https://github.com/o ### How to help? -Discussion on the roadmap can take place in threads under [Issues](https://github.com/vmware/harbor/issues) or in [community meetings](https://github.com/goharbor/community/blob/master/MEETING_SCHEDULE.md). Please open and comment on an issue if you want to provide suggestions and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort. +Discussion on the roadmap can take place in threads under [Issues](https://github.com/goharbor/harbor/issues) or in [community meetings](https://github.com/goharbor/community/blob/master/MEETING_SCHEDULE.md). Please open and comment on an issue if you want to provide suggestions and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort. ### How to add an item to the roadmap? Please open an issue to track any initiative on the roadmap of Harbor (Usually driven by new feature requests). We will work with and rely on our community to focus our efforts to improve Harbor. From f38fff8eff3a082eaf24fbc9ca4cb1b6c9d780e2 Mon Sep 17 00:00:00 2001 From: Yogi_Wang Date: Tue, 22 Oct 2019 16:04:11 +0800 Subject: [PATCH 8/8] Modify the permission when add Limited Guest Signed-off-by: Yogi_Wang --- .../create-edit-rule.component.ts | 2 +- .../replication/replication.component.html | 2 +- .../replication/replication.component.scss | 5 ++- .../repository/repository.component.spec.ts | 20 +++++------ src/portal/lib/src/tag/tag.component.spec.ts | 23 +++++++----- src/portal/lib/src/tag/tag.component.ts | 36 +++++++++---------- 6 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/portal/lib/src/create-edit-rule/create-edit-rule.component.ts b/src/portal/lib/src/create-edit-rule/create-edit-rule.component.ts index 283a49ed2..0a9279a0b 100644 --- a/src/portal/lib/src/create-edit-rule/create-edit-rule.component.ts +++ b/src/portal/lib/src/create-edit-rule/create-edit-rule.component.ts @@ -253,7 +253,7 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy { dest_registry: rule.dest_registry, trigger: rule.trigger, deletion: rule.deletion, - enabled: true, + enabled: rule.enabled, override: rule.override }); let filtersArray = this.getFilterArray(rule); diff --git a/src/portal/lib/src/replication/replication.component.html b/src/portal/lib/src/replication/replication.component.html index f02d19304..b140f27d7 100644 --- a/src/portal/lib/src/replication/replication.component.html +++ b/src/portal/lib/src/replication/replication.component.html @@ -24,7 +24,7 @@
{{'REPLICATION.REPLICATION_EXECUTIONS' | translate}}
-
+