Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add proposal cosign integration #172

Merged
merged 6 commits into from
Mar 21, 2022
Merged

add proposal cosign integration #172

merged 6 commits into from
Mar 21, 2022

Conversation

wy65701436
Copy link
Contributor

The proposal is for cosign and harbor integration story

Signed-off-by: Wang Yan wangyan@vmware.com

@dlorenc
Copy link

dlorenc commented Jul 27, 2021

This is awesome and I would love to help out anyway possible! (I'm a maintainer on cosign)

The proposal is for cosign and harbor integration story

Signed-off-by: Wang Yan <wangyan@vmware.com>
the type of the accessory, like signature.cosign.
*/
type varchar(1024),
digest varchar(1024),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this column needed? it's a dup of artifact.digest?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

@wy65701436 wy65701436 Aug 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To show the pull command of signature, it can reduce the sql join.

"subject_artifact_id":81,
"digest":"sha256:94788818ad901025c81f8696f3ee61619526b963b7dc36435ac284f4497aa7ca",
"type":"signature.cosign",
"icon":"sha256:0048162a053eef4d4ce3fe7518615bef084403614f8bca43b40ae2e762e11e06",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may need to refresh my memory about this but do all the icons stored as blobs now, even the preset ones like container images?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the cosign scenario, we can add a default icon in Harbor.


```yaml

GET /api/v2.0/projects/library/repositories/hello-world/artifacts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to add a querystring for accessories?

**Delete artifact signature(specific)**

```rest
DELETE /api/v2.0/projects/library/repositories/hello-world/artifacts/sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792/accessory?type=signature.cosign&digtest=sha256:94788818ad901025c81f8696f3ee61619526b963b7dc36435ac284f4497aa7cb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the sha256:94788818ad901025c81f8696f3ee61619526b963b7dc36435ac284f4497aa7cb is not a accessory of sha256:1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792?

Do you wanna support both digest and artifact_id when managing an accessory?


- You will have an option indicate that whether you want to replicate the signature between Harbor instances.
1. Replication the artifact to the target Harbor.
2. Replication the signature to the target Harbor, then the target Harbor will build the reference.
Copy link
Contributor

@reasonerjt reasonerjt Jul 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you introduced the accessory abstraction layer you should describe the replication scenario in accessory terms.

For simplicity if possible IMO all accessories should be replicated considering artifact+accessories is one entity.

We also need to check if the "docker-reference" in the signature blob is always empty, if it's not, data will be inconsistent after copy/replication.

What if the target Harbor does not set to cosign mode? I think in that case the signature should not be replicated?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the root artifact is successfully replicated and the signature artifact replication is failed, is that counted as a success or a failure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can assume that the transation of repliation should contain artifact and signature, and it's failure and the repliated artifact should be removed from the target.


![Signature_replication](../images/cosign/signature_replication.png)

#### Tag Retention
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed, this is an enhancement to tag retention policy that is out of the scope of cosign integration.


1. Signed images:
- Notary: If user sign an image with notary and restart Harbor without notary enabled, the image will be acted as un-signed.
- Cosign: If user sign an image with cosign, unless user removes the signature from the artifact, the image will be acted as signed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we wanna support notary and cosign at the same time?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense.

### Signature checker Interface

```go
type PublicKey crypto.PublicKey
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the PublicKey related stuff?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for further design.

- build the reference in the database


### Request Artifact Accessory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a section for API change, note that we also need to determine what to do with the existing APIs:
Do we list accessories in GET /artifacts API?
What about DELETE ...


4. **Index Signing**

Cosign can sign a multi-platform `Index`, but the signature is attached to the index digest. Should we see all the references are signed?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to handle that when you check the signature in a pull command?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to check that any content you're using as a consumer is signed - i.e. the manifest list (index) and any arch-specific content too.

/*
the artifact id of the accessory itself.
*/
artifact_id int,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel seeing accessory as an artifact make things more complicated in the API to handle artifacts you need to add a lot of if statements b/c accessories are different from regular artifacts.

### To be discussed

1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
2. Cosign can specify the signature repository, do we support it?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need more context about signature repository

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is a client-side option only and wouldn't affect the server-side aspects of Harbor?

See https://github.com/sigstore/cosign#specifying-registry for info on what this does.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For integration with Harbor, living in the same repository seems much better and simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to support it, it will involve the permission things(AZ).


1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
2. Cosign can specify the signature repository, do we support it?
3. Can the signature be added/removed tag or label like other artifact?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's something to think about for all accessories, see my comment in the table schema for accessory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, as it's an accessory of the root artifacts, it seems there are no use cases to require treating accessory artifacts as general ones。 They're just additional things of the root artifacts.


User can specify anything for the tag attribute, even the tag does not exist.

Do we need to support this scenario?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to extract the blob to support it right? If the answer is yes, I suggest not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1.

Conflict with the `To-be-discussed item 1?


- Immutable Repository

Cosign's model of "appending" signatures won't work for multiple signatures.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean if a repository is immutable in Harbor you can't push any signatures?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd be able to push an initial signature manifest, but not any additional signatures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the signatures shares one tag name, if the immutable enabled, the following push will be rejected.


As the multiple signatures share one tag, the previously pushed becomes the untagged artifact. If user run GC with untagged checked, all of these untagged signatures will be removed.

```json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need more context about this JSON.


```

Solution: For GC, the untagged artifact means that one artifact without any tag and are not an accessory.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you'll need to make sure the accessory table is in sync, which can be messy to handle.

Copy link

@ncdc ncdc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing this up!

/*
Read all the public key from system.
*/
PublicKeyes(ctx context.Context) ([]PublicKey, error)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PublicKeyes(ctx context.Context) ([]PublicKey, error)
PublicKeys(ctx context.Context) ([]PublicKey, error)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case of this method?

PublicKey(ctx context.Context, artifact Artifact) (PublicKey, error)

/*
Read all the public key from system.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want this at the system level, or per repository, or maybe both?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a draft design and for the phase 2. But, I suppose it's at the system level.


1. Signed images:
- Notary: If user sign an image with notary and restart Harbor without notary enabled, the image will be acted as un-signed.
- Cosign: If user sign an image with cosign, unless user removes the signature from the artifact, the image will be acted as signed.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense.

### To be discussed

1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
2. Cosign can specify the signature repository, do we support it?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is a client-side option only and wouldn't affect the server-side aspects of Harbor?

See https://github.com/sigstore/cosign#specifying-registry for info on what this does.


4. **Index Signing**

Cosign can sign a multi-platform `Index`, but the signature is attached to the index digest. Should we see all the references are signed?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to check that any content you're using as a consumer is signed - i.e. the manifest list (index) and any arch-specific content too.


- Immutable Repository

Cosign's model of "appending" signatures won't work for multiple signatures.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd be able to push an initial signature manifest, but not any additional signatures.


## Non Goal

1. Do not manage Public keys in Harbor side.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a future goal?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not likely unless tool chain supports push a public key as OCI artifacts.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a Harbor API for it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or pubkeys as artifacts could work too

4. As a project admin & user, I cannot GC an artifact's cosign signature individually.
5. As a system admin, I can copy an artifact and its signature to another repository.
6. As a system & project admin, I can reserve an artifact and its signature via retention policy.
7. As a system & project admin, I can set the content trust policy to block the un-signed artifact pulling.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without storing public keys, Harbor won't be able to verify the signatures. Would you allow a user to pull an image with a signature when Harbor can't tell if the signature is valid or not?

Copy link
Contributor

@reasonerjt reasonerjt Jul 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, it depends on whether a client chooses to trust the public key or not.

At phase 1, this policy may only check if the signature exists and check if the metadata(if any) matches the artifact. With the cosign model whether the client should trust it or not is beyond the scope of Harbor.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could go either way. Harbor could block if no signature exists and allow if any signature exists.

It could also go further and block if it can't verify the signature. It mostly depends on if we want to require public keys to be uploaded to Harbor so Harbor can verify.

For a first step (and possibly only), we can go with the first approach (Harbor doesn't verify signatures because it doesn't know about public keys).


### To be discussed

1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't do this. The signature was created for an image with a specific digest (potentially associated with a specific tag at a point in time).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He means the case where different tags associate with one digest.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, thanks for the clarification. In that case, I would say yes, display the signature for all tags pointing to the same digest.

@reasonerjt reasonerjt marked this pull request as draft July 30, 2021 16:13
Copy link
Contributor

@steven-zou steven-zou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's cool.

/*
Read all the public key from system.
*/
PublicKeyes(ctx context.Context) ([]PublicKey, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case of this method?


- You will have an option indicate that whether you want to replicate the signature between Harbor instances.
1. Replication the artifact to the target Harbor.
2. Replication the signature to the target Harbor, then the target Harbor will build the reference.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the root artifact is successfully replicated and the signature artifact replication is failed, is that counted as a success or a failure?

### To be discussed

1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
2. Cosign can specify the signature repository, do we support it?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For integration with Harbor, living in the same repository seems much better and simpler.


1. Cosign attaches signature to digest by default, should we apply the signature to all tags of an artifact?
2. Cosign can specify the signature repository, do we support it?
3. Can the signature be added/removed tag or label like other artifact?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, as it's an accessory of the root artifacts, it seems there are no use cases to require treating accessory artifacts as general ones。 They're just additional things of the root artifacts.


User can specify anything for the tag attribute, even the tag does not exist.

Do we need to support this scenario?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1.

Conflict with the `To-be-discussed item 1?


```

![Build Reference](../images/cosign/build_reference.png)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leverage the current metadata extracting processor framework?

Signed-off-by: Wang Yan <wangyan@vmware.com>
1. Do not manage Public keys in Harbor side.
2. Do not support multiple signers in a deployment.
3. Do not support cosign clean/delete(as the delete operation leverages the tag deletion API which is not a required implementation defined by OCI spec, and Harbor does not allow it).
4. Do not support cosign copy(cosign pushes the signature firstly to the destination, and then the artifact, Harbor cannot build the reference.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the description is already in the non-goal section, we don't need to add the " Do not" in the sub clause.

Copy link

@rszumlakowski rszumlakowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does there need to be a user story to confirm that end users will be able to see images with Cosign signatures in the Harbor User Interface?

Something like:

As a project admin & user, I can see which tags for an artifact have valid cosign signatures

@tianon
Copy link
Member

tianon commented Aug 25, 2021

The biggest concern I have with this proposal right now is that the "accessory" that's defined here is very similar to the references work that's happening in the OCI right now (for example opencontainers/tob#96, which has a lot of links to other discussions too).

I'd hate to see Harbor implement something that's very close to something the OCI eventually ratifies, but specific to cosign and not quite matching the OCI implementation (creating the need for a migration process for both Harbor and the users of it, assuming the thing that gets ratified is compatible enough to be something we could migrate users to directly).

@dlorenc
Copy link

dlorenc commented Aug 25, 2021

I don't really have a preference either way on waiting, but I don't think it's safe to assume the OCI is actually close to ratifying anything. That link is to a draft proposal that's been open since April and still hasn't been submitted as a real proposal for a vote.

After that vote, the WG would then need to actually start, design and prototype different options. Then the spec changes would need to get written, debated and approved. Then enough registries would need to implement those changes for it to be safe for clients to rely on them.

I'm (pessimistically) guessing it's going to be mid to late 2022 at the earliest before there's enough widespread adoption of the new changes for clients to rely on them.

The cosign spec is defined here, with a goal of working with existing registries; https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md and is already implemented by a few other clients so it's not really cosign specific.

@tianon
Copy link
Member

tianon commented Aug 25, 2021

Thanks @dlorenc for providing your thoughts -- I guess that changes the question a little bit for me then. 😄

Why does adding "cosign support" to Harbor require creating this special "accessory" type? Is the goal of doing so to make it more usable/useful to end users, or is there a deeper reason?

@dlorenc
Copy link

dlorenc commented Aug 25, 2021

Why does adding "cosign support" to Harbor require creating this special "accessory" type? Is the goal of doing so to make it more usable/useful to end users,

My understanding is that this is for extra features, like UI integration and policy support on top of the signatures. Basic sign/verify/upload/download operations all work with harbor out of the box.

@wy65701436
Copy link
Contributor Author

wy65701436 commented Aug 25, 2021

Thanks @dlorenc for providing your thoughts -- I guess that changes the question a little bit for me then. 😄

Why does adding "cosign support" to Harbor require creating this special "accessory" type? Is the goal of doing so to make it more usable/useful to end users, or is there a deeper reason?

For the case of cosign, to add the accessory is just to let Habor knows the relationship of artifact and its signature. Otherwise, from the perspective of Harbor, the cosign signature is just another irrelevant artifact.

Through the relationship, Harbor can treat the artifact and its signature as a whloe, and then determine the behavior of GC/Remove/Replication/....

In addition, the accessory is abstract conception, and signature is only one implementation of it.

@SteveLasker
Copy link

Hey folks,
Per agreement with the OCI TOB, the Reference Type work is proceeding under https://github.com/oras-project/artifacts-spec/ and will hit a draft in the next few weeks, with a production level RC spec available shortly after.

This Artifact Reference Type support incorporates:

The manifest and API are part of the larger goals: https://stevelasker.blog/2021/08/26/artifact-services/

The reference implementation under CNCF distribution is also available at: https://github.com/oras-project/distribution which we're working to merge into https://github.com/distribution/distribution per: distribution/distribution#3482, which should facilitate distribution based projects like harbor to contribute and consume quickly.

Please feel free to reach out to one of the Artifact owners who can provide accurate information to the projects status.

Signed-off-by: Wang Yan <wangyan@vmware.com>
@SteveLasker
Copy link

JFYI, the ORAS Artifacts Draft Specification has been released. It generalizes the way references can be pushed, discovered and pulled, enabling a standard across all distribution-spec based registries:

Signed-off-by: Wang Yan <wangyan@vmware.com>

format

Signed-off-by: Wang Yan <wangyan@vmware.com>
Copy link
Member

@chlins chlins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm


Beside to store an artifact into registry, there are requirements on storing secure chain artifacts, like Software Bill of Materials (SBoM) and signatures to provide rich rich functionality of an artifact.

The proposal is to introduce an abstract definition -- accessory -- to enable Harbor to extend the capabilities for storing artifact with additional stuff.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tianon you as a native speaker, do you think the term accessory is correct here or would you use a better suited term?

I would like to critically question the "term", as it will stick on forever and generation of Harbor developers and users would need lookup the manual and the code just to understand what it means.

IMHO an artifact artifact attachment or attachment would be a better suited term because:

  1. It is a common and well know term for an object that can be (optionally) attached to another object. It is known to many user and developers from email, documents and files.
  2. A good word that denotes the common use correctly will save thousand hours of time for many many users and developers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm certainly not an expert, but I am "native" so I'll do my best! 😇

I'll start by saying I find it a little amusing that "attachment" is the very word I've been using to describe this feature to colleagues. 😅 🙈

To be clear, I think "accessory" is ok, but I do agree that "attachment" would be a better word for what this is.

An "accessory" is usually something that's only useful or thought about in the context of the thing it's connected to (for example, jewelry is commonly called an "accessory" because something like a necklace is not terribly useful in isolation). Another way to put that is that it "enhances" the thing it's connected to ("accessory to a crime" for example -- someone who helped the crime be committed but wasn't the person who did the crime directly), and this is the usage that makes me OK with this as a term for this feature.

Conversely, "attachment" only implies a connection between the things, not necessarily that the attached thing improves the thing it's attached to in any way - the attached item is (more) often useful/meaningful in isolation too.

(IMO the word "attachment" is also more closely related to the word "reference" that the OCI is working with/around than "accessory" is.)

So I guess my conclusion would be that if we expect this feature to grow beyond just things like signatures or SBOMs that "enhance" the thing they're attached to, then yes, "attachment" is a better term for it, but if we don't want this feature to grow into more use cases we haven't thought of yet (where there might be a softer relationship between the OCI artifact and the attachment), then "accessory" is probably fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @Vad1mo and @tianon, firstly, we'd like to extend the accessory into more cases, like SBoM, Nydus(converted images).

I know the OCI or Oras community uses the attachement to describe the linkage of subject manifest and its things. IMO, in Harbor, I'd like to use different term to descirbe, we can say, the same thing to avoid confusion. A typical example is label, in Harbor we have this term to help user to filter artifact. However, in docker community, labels are an key-value pair.

And since we've reached the RC stage and all the source code has been merged, we have to draw an conclusion soon.

@wy65701436 wy65701436 marked this pull request as ready for review February 11, 2022 06:57
Copy link
Contributor

@steven-zou steven-zou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wy65701436 wy65701436 merged commit 74f3d64 into goharbor:main Mar 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.