diff --git a/.dockerignore b/.dockerignore index 4f0222bd..e69de29b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +0,0 @@ -.go-skynet/ diff --git a/.github/workflows/oci-dist-spec-content-discovery.yml b/.github/workflows/oci-dist-spec-content-discovery.yml index 0dc5f81f..bda734ed 100644 --- a/.github/workflows/oci-dist-spec-content-discovery.yml +++ b/.github/workflows/oci-dist-spec-content-discovery.yml @@ -1,28 +1,23 @@ name: OCI Distribution Spec - Content Discovery - on: pull_request: push: - branches: - - main + branches: [main] workflow_dispatch: inputs: debug_enabled: type: boolean - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate) required: false default: false - concurrency: group: content-discovery-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true - env: PGUSER: postgres POSTGRES_DB: open_registry POSTGRES_PASSWORD: Qwerty@123 POSTGRES_USER: postgres - jobs: conformance: runs-on: ubuntu-latest @@ -39,9 +34,9 @@ jobs: --health-interval 10s --health-timeout 5s --health-retries 5 - ports: - - 5432:5432 + ports: [5432:5432] steps: + - run: sudo snap install --edge --classic just - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: @@ -58,7 +53,7 @@ jobs: yq e -i '.dfs.mock.type = "FS"' config.yaml go mod download go build - make certs + just certs ./OpenRegistry migrations init \ --admin-db="postgres" \ --admin-db-username="postgres" \ @@ -93,7 +88,7 @@ jobs: OCI_DEBUG: 0 - name: Setup tmate session if mode is debug and OpenRegistry or OCI Tests Fail uses: mxschmitt/action-tmate@v3 - if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} + if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} - name: Set output report name id: vars run: echo "short_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/oci-dist-spec-content-management.yml b/.github/workflows/oci-dist-spec-content-management.yml index b2aeb0be..44ad807a 100644 --- a/.github/workflows/oci-dist-spec-content-management.yml +++ b/.github/workflows/oci-dist-spec-content-management.yml @@ -1,28 +1,23 @@ name: OCI Distribution Spec - Content Management - on: pull_request: push: - branches: - - main + branches: [main] workflow_dispatch: inputs: debug_enabled: type: boolean - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate) required: false default: false - concurrency: group: content-management-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true - env: PGUSER: postgres POSTGRES_DB: open_registry POSTGRES_PASSWORD: Qwerty@123 POSTGRES_USER: postgres - jobs: conformance: runs-on: ubuntu-latest @@ -39,9 +34,9 @@ jobs: --health-interval 10s --health-timeout 5s --health-retries 5 - ports: - - 5432:5432 + ports: [5432:5432] steps: + - run: sudo snap install --edge --classic just - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: @@ -58,7 +53,7 @@ jobs: yq e -i '.dfs.mock.type = "FS"' config.yaml go mod download go build - make certs + just certs ./OpenRegistry migrations init \ --admin-db="postgres" \ --admin-db-username="postgres" \ @@ -92,7 +87,7 @@ jobs: OCI_DEBUG: 0 - name: Setup tmate session if mode is debug and OpenRegistry or OCI Tests Fail uses: mxschmitt/action-tmate@v3 - if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} + if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} - name: Set output report name id: vars run: echo "short_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT diff --git a/.github/workflows/oci-dist-spec-pull.yml b/.github/workflows/oci-dist-spec-pull.yml index cadef52a..a94e0545 100644 --- a/.github/workflows/oci-dist-spec-pull.yml +++ b/.github/workflows/oci-dist-spec-pull.yml @@ -42,6 +42,7 @@ jobs: ports: - 5432:5432 steps: + - run: sudo snap install --edge --classic just - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: @@ -58,7 +59,7 @@ jobs: yq e -i '.dfs.mock.type = "FS"' config.yaml go mod download go build - make certs + just certs ./OpenRegistry migrations init \ --admin-db="postgres" \ --admin-db-username="postgres" \ diff --git a/.github/workflows/oci-dist-spec-push.yml b/.github/workflows/oci-dist-spec-push.yml index 4eca519e..746e09d3 100644 --- a/.github/workflows/oci-dist-spec-push.yml +++ b/.github/workflows/oci-dist-spec-push.yml @@ -1,28 +1,24 @@ +--- name: OCI Distribution Spec - Push Image - on: pull_request: push: - branches: - - main + branches: [main] workflow_dispatch: inputs: debug_enabled: type: boolean - description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)' + description: Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate) required: false default: false - concurrency: group: push-${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true - env: PGUSER: postgres POSTGRES_DB: open_registry POSTGRES_PASSWORD: Qwerty@123 POSTGRES_USER: postgres - jobs: conformance: runs-on: ubuntu-latest @@ -39,9 +35,9 @@ jobs: --health-interval 10s --health-timeout 5s --health-retries 5 - ports: - - 5432:5432 + ports: [5432:5432] steps: + - run: sudo snap install --edge --classic just - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: @@ -58,7 +54,7 @@ jobs: yq e -i '.dfs.mock.type = "FS"' config.yaml go mod download go build - make certs + just certs ./OpenRegistry migrations init \ --admin-db="postgres" \ --admin-db-username="postgres" \ @@ -93,7 +89,7 @@ jobs: OCI_DEBUG: 0 - name: Setup tmate session if mode is debug and OpenRegistry or OCI Tests Fail uses: mxschmitt/action-tmate@v3 - if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} + if: ${{ always() && (github.event_name == 'workflow_dispatch') && inputs.debug_enabled }} - name: Set output report name id: vars run: echo "short_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT diff --git a/Makefile b/Makefile deleted file mode 100644 index 71efa572..00000000 --- a/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -POSTGRESQL_URL='postgres://postgres:postgres@0.0.0.0:5432/open_registry?sslmode=disable' - -psql_grants: - @psql -d open_registry -c 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO open_registry_user;' - -mock-images: - bash ./scripts/mock-images.sh - -tools: - pip3 install ggshield pre-commit - pre-commit install - -certs: - mkdir .certs - openssl req -x509 -newkey rsa:4096 -keyout .certs/registry.local -out .certs/registry.local.crt -sha256 -days 365 \ - -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=registry.local" -nodes diff --git a/api/users/users.go b/api/users/users.go index 3887842f..157d4735 100644 --- a/api/users/users.go +++ b/api/users/users.go @@ -1,8 +1,11 @@ package users import ( + "fmt" "net/http" + "time" + "github.com/containerish/OpenRegistry/auth" "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/store/v1/users" "github.com/containerish/OpenRegistry/telemetry" @@ -12,6 +15,8 @@ import ( type ( UserApi interface { SearchUsers(echo.Context) error + CreateUserToken(ctx echo.Context) error + ListUserToken(ctx echo.Context) error } api struct { @@ -47,3 +52,116 @@ func (a *api) SearchUsers(ctx echo.Context) error { a.logger.Log(ctx, nil).Send() return echoErr } + +func (a *api) CreateUserToken(ctx echo.Context) error { + ctx.Set(types.HandlerStartTime, time.Now()) + + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) + if !ok { + err := fmt.Errorf("missing authentication credentials") + echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + var body types.CreateAuthTokenRequest + if err := ctx.Bind(&body); err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + if body.Name == "" { + err := fmt.Errorf("token name is a required field") + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + token, err := types.CreateNewAuthToken() + if err != nil { + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + hashedToken, err := auth.GenerateSafeHash([]byte(token.RawString())) + if err != nil { + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + authToken := &types.AuthTokens{ + CreatedAt: time.Now(), + ExpiresAt: body.ExpiresAt, + Name: body.Name, + AuthToken: hashedToken, + OwnerID: user.ID, + } + + if err = a.userStore.AddAuthToken(ctx.Request().Context(), authToken); err != nil { + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + echoErr := ctx.JSON(http.StatusOK, echo.Map{ + "token": token.String(), + }) + + a.logger.Log(ctx, nil).Str("client_token", token.String()).Str("stored_token", hashedToken).Send() + return echoErr +} + +func (a *api) ListUserToken(ctx echo.Context) error { + ctx.Set(types.HandlerStartTime, time.Now()) + + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) + if !ok { + err := fmt.Errorf("missing authentication credentials") + echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + tokens, err := a.userStore.ListAuthTokens(ctx.Request().Context(), user.ID) + if err != nil { + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ + "error": err.Error(), + }) + + a.logger.Log(ctx, err).Send() + return echoErr + } + + if len(tokens) == 0 { + tokens = make([]*types.AuthTokens, 0) + } + + echoErr := ctx.JSON(http.StatusOK, tokens) + + a.logger.Log(ctx, nil).Send() + return echoErr +} diff --git a/auth/basic_auth.go b/auth/basic_auth.go index 3134f1e4..1921f1c1 100644 --- a/auth/basic_auth.go +++ b/auth/basic_auth.go @@ -1,6 +1,7 @@ package auth import ( + "context" "encoding/base64" "fmt" "net/http" @@ -28,7 +29,6 @@ func (a *auth) BasicAuth() echo.MiddlewareFunc { return func(ctx echo.Context) error { if a.SkipBasicAuth(ctx) { - a.logger.DebugWithContext(ctx).Bool("skip_basic_auth", true).Send() // Note: there might be other middlewares attached to this handler return handler(ctx) } @@ -72,6 +72,10 @@ func (a *auth) BasicAuth() echo.MiddlewareFunc { func (a *auth) SkipBasicAuth(ctx echo.Context) bool { authHeader := ctx.Request().Header.Get(echo.HeaderAuthorization) + if strings.HasPrefix(ctx.Request().URL.Path, "/v2/ext/") { + return true + } + hasJWT := a.checkJWT(authHeader, ctx.Request().Cookies()) if hasJWT { return true @@ -157,6 +161,27 @@ func (a *auth) validateBasicAuthCredentials(auth string) (*types.User, error) { basicAuthCredentials := strings.Split(string(decodedCredentials), ":") username, password := basicAuthCredentials[0], basicAuthCredentials[1] + // try login with GitHub PAT + // 1. "github_pat_" prefix is for the new fine-grained, repo scoped tokens + // 2. "ghp_" prefix is for the old (classic) github tokens + if strings.HasPrefix(password, "github_pat_") || strings.HasPrefix(password, "ghp_") { + user, ghErr := a.getUserWithGithubOauthToken(context.Background(), password) + if ghErr != nil { + return nil, fmt.Errorf("ERR_READ_USER_WITH_GITHUB_TOKEN: %w", ghErr) + } + + return user, nil + } + + if strings.HasPrefix(password, types.OpenRegistryAuthTokenPrefix) { + user, err := a.validateUserWithPAT(context.Background(), username, password) + if err != nil { + return nil, err + } + + return user, nil + } + user, err := a.validateUser(username, password) if err != nil { return nil, err diff --git a/auth/bcrypt.go b/auth/bcrypt.go index c6e6b430..7dc2cd0c 100644 --- a/auth/bcrypt.go +++ b/auth/bcrypt.go @@ -1,17 +1,20 @@ package auth import ( + "crypto/sha256" + "fmt" + "golang.org/x/crypto/bcrypt" ) -const bcryptMinCost = 6 +const BcryptMinCost = 6 func (a *auth) hashPassword(password string) (string, error) { // Convert password string to byte slice var passwordBytes = []byte(password) // Hash password with Bcrypt's min cost - hashedPasswordBytes, err := bcrypt.GenerateFromPassword(passwordBytes, bcryptMinCost) + hashedPasswordBytes, err := bcrypt.GenerateFromPassword(passwordBytes, BcryptMinCost) return string(hashedPasswordBytes), err } @@ -20,3 +23,12 @@ func (a *auth) verifyPassword(hashedPassword, currPassword string) bool { err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(currPassword)) return err == nil } + +func GenerateSafeHash(input []byte) (string, error) { + hash := sha256.New() + if n, err := hash.Write(input); err != nil || n != len(input) { + return "", fmt.Errorf("error generating hash") + } + + return fmt.Sprintf("%x", hash.Sum(nil)), nil +} diff --git a/auth/github.go b/auth/github.go index e1f40b26..0422eb51 100644 --- a/auth/github.go +++ b/auth/github.go @@ -8,13 +8,13 @@ import ( "strings" "time" - "github.com/containerish/OpenRegistry/config" - v2_types "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/containerish/OpenRegistry/types" "github.com/google/go-github/v56/github" "github.com/google/uuid" "github.com/labstack/echo/v4" "golang.org/x/oauth2" + + "github.com/containerish/OpenRegistry/config" + "github.com/containerish/OpenRegistry/store/v1/types" ) func (a *auth) LoginWithGithub(ctx echo.Context) error { @@ -116,6 +116,11 @@ func (a *auth) GithubLoginCallbackHandler(ctx echo.Context) error { } if user.GithubConnected { + ghIdentity := user.Identities.GetGitHubIdentity() + ghIdentity.Email = ghUser.GetEmail() + ghIdentity.Username = ghUser.GetLogin() + user.Identities[types.IdentityProviderGitHub] = ghIdentity + _, err = a.userStore.UpdateUser(ctx.Request().Context(), user) if err != nil { uri := a.getGitHubErrorURI(ctx, http.StatusConflict, err.Error()) @@ -136,7 +141,7 @@ func (a *auth) GithubLoginCallbackHandler(ctx echo.Context) error { return err } - user.Identities[v2_types.IdentityProviderGitHub] = &v2_types.UserIdentity{ + user.Identities[types.IdentityProviderGitHub] = &types.UserIdentity{ ID: fmt.Sprint(ghUser.GetID()), Name: ghUser.GetName(), Username: ghUser.GetLogin(), @@ -172,18 +177,12 @@ func (a *auth) createCookie( ) *http.Cookie { secure := true sameSite := http.SameSiteNoneMode - domain := "" - url, err := url.Parse(a.c.WebAppConfig.GetAllowedURLFromEchoContext(ctx, a.c.Environment)) - if err != nil { - domain = a.c.Registry.FQDN - } else { - domain = url.Hostname() - } + domain := a.c.Registry.FQDN - if a.c.Environment == config.Local { + if a.c.Environment == config.Local && domain == "" { secure = false sameSite = http.SameSiteLaxMode - url, err = url.Parse(a.c.WebAppConfig.GetAllowedURLFromEchoContext(ctx, a.c.Environment)) + url, err := url.Parse(a.c.WebAppConfig.GetAllowedURLFromEchoContext(ctx, a.c.Environment)) if err != nil { domain = "localhost" } else { @@ -211,14 +210,14 @@ func (a *auth) createCookie( } // makes an http request to get user info from token, if it's valid, it's all good :) -func (a *auth) getUserWithGithubOauthToken(ctx context.Context, token string) (*v2_types.User, error) { +func (a *auth) getUserWithGithubOauthToken(ctx context.Context, token string) (*types.User, error) { req, err := a.ghClient.NewRequest(http.MethodGet, "/user", nil) if err != nil { return nil, fmt.Errorf("GH_AUTH_REQUEST_ERROR: %w", err) } req.Header.Set(AuthorizationHeaderKey, "token "+token) - var oauthUser v2_types.User + var oauthUser github.User resp, err := a.ghClient.Do(ctx, req, &oauthUser) if err != nil { return nil, fmt.Errorf("GH_AUTH_ERROR: %w", err) @@ -228,7 +227,7 @@ func (a *auth) getUserWithGithubOauthToken(ctx context.Context, token string) (* return nil, fmt.Errorf("GHO_UNAUTHORIZED") } - user, err := a.userStore.GetUserByEmail(ctx, oauthUser.Email) + user, err := a.userStore.GetUserByEmail(ctx, oauthUser.GetEmail()) if err != nil { return nil, fmt.Errorf("PG_GET_USER_ERR: %w", err) } @@ -245,7 +244,7 @@ func (a *auth) getGitHubErrorURI(ctx echo.Context, status int, err string) strin return fmt.Sprintf("%s%s?%s", webAppEndoint, a.c.WebAppConfig.ErrorRedirectPath, queryParams.Encode()) } -func (a *auth) finishGitHubCallback(ctx echo.Context, user *v2_types.User, oauthToken *oauth2.Token) error { +func (a *auth) finishGitHubCallback(ctx echo.Context, user *types.User, oauthToken *oauth2.Token) error { sessionId, err := uuid.NewRandom() if err != nil { return err @@ -279,7 +278,7 @@ func (a *auth) finishGitHubCallback(ctx echo.Context, user *v2_types.User, oauth return nil } -func (a *auth) storeGitHubUserIfDoesntExist(ctx context.Context, pgErr error, user *v2_types.User) error { +func (a *auth) storeGitHubUserIfDoesntExist(ctx context.Context, pgErr error, user *types.User) error { if strings.HasSuffix(pgErr.Error(), "no rows in result set") { id, err := uuid.NewRandom() if err != nil { diff --git a/auth/helpers.go b/auth/helpers.go index a2a3c6ec..7d7c29bb 100644 --- a/auth/helpers.go +++ b/auth/helpers.go @@ -118,7 +118,7 @@ func NewWebLoginToken(opts *WebLoginJWTOptions) (string, error) { hasher := sha256.New() hasher.Write(pubkeyDER) - raw := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + raw := jwt.NewWithClaims(jwt.SigningMethodRS256, &claims) raw.Header["kid"] = KeyIDEncode(hasher.Sum(nil)[:30]) token, err := raw.SignedString(opts.Privkey) if err != nil { diff --git a/auth/jwt.go b/auth/jwt.go index 0f806b9d..018a87c8 100644 --- a/auth/jwt.go +++ b/auth/jwt.go @@ -1,12 +1,7 @@ package auth import ( - "bytes" - "crypto/sha256" - "crypto/x509" - "encoding/base32" "fmt" - "strings" "time" "github.com/containerish/OpenRegistry/store/v1/types" @@ -43,19 +38,6 @@ type ServiceClaims struct { Access AccessList } -func (a *auth) keyIDEncode(b []byte) string { - s := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=") - var buf bytes.Buffer - var i int - for i = 0; i < len(s)/4-1; i++ { - start := i * 4 - end := start + 4 - buf.WriteString(s[start:end] + ":") - } - buf.WriteString(s[i*4:]) - return buf.String() -} - func (a *auth) SignOAuthToken(userId uuid.UUID, payload *oauth2.Token) (string, string, error) { return a.newOAuthToken(userId, payload) } @@ -64,23 +46,12 @@ func (a *auth) newOAuthToken(userId uuid.UUID, payload *oauth2.Token) (string, s accessClaims := a.createOAuthClaims(userId, payload) refreshClaims := a.createRefreshClaims(userId) - pubKeyDerBz, err := x509.MarshalPKIXPublicKey(a.c.Registry.Auth.JWTSigningPubKey) - if err != nil { - return "", "", err - } - - hasher := sha256.New() - hasher.Write(pubKeyDerBz) - accessToken := jwt.NewWithClaims(jwt.SigningMethodRS256, &accessClaims) - accessToken.Header["kid"] = a.keyIDEncode(hasher.Sum(nil)[:30]) - accessSign, err := accessToken.SignedString(a.c.Registry.Auth.JWTSigningPrivateKey) + accessSign, err := a.c.Registry.Auth.SignWithPubKey(&accessClaims) if err != nil { return "", "", fmt.Errorf("ERR_ACCESS_TOKEN_SIGN: %w", err) } - refreshToken := jwt.NewWithClaims(jwt.SigningMethodRS256, &refreshClaims) - refreshToken.Header["kid"] = a.keyIDEncode(hasher.Sum(nil)[:30]) - refreshSign, err := refreshToken.SignedString(a.c.Registry.Auth.JWTSigningPrivateKey) + refreshSign, err := a.c.Registry.Auth.SignWithPubKey(&refreshClaims) if err != nil { return "", "", fmt.Errorf("ERR_REFRESH_TOKEN_SIGN: %w", err) } @@ -105,17 +76,7 @@ func (a *auth) newServiceToken(u types.User) (string, error) { Acl: acl, } claims := CreateClaims(opts) - - pubKeyDerBz, err := x509.MarshalPKIXPublicKey(a.c.Registry.Auth.JWTSigningPubKey) - if err != nil { - return "", err - } - - hasher := sha256.New() - hasher.Write(pubKeyDerBz) - token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) - token.Header["kid"] = a.keyIDEncode(hasher.Sum(nil)[:30]) - sign, err := token.SignedString(a.c.Registry.Auth.JWTSigningPrivateKey) + sign, err := a.c.Registry.Auth.SignWithPubKey(&claims) if err != nil { return "", fmt.Errorf("error signing secret %w", err) } @@ -132,17 +93,7 @@ func (a *auth) newOCIToken(userID uuid.UUID, scopes types.OCITokenPermissonClaim Acl: scopes, } claims := CreateOCIClaims(opts) - - pubKeyDerBz, err := x509.MarshalPKIXPublicKey(a.c.Registry.Auth.JWTSigningPubKey) - if err != nil { - return "", err - } - - hasher := sha256.New() - hasher.Write(pubKeyDerBz) - token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) - token.Header["kid"] = a.keyIDEncode(hasher.Sum(nil)[:30]) - sign, err := token.SignedString(a.c.Registry.Auth.JWTSigningPrivateKey) + sign, err := a.c.Registry.Auth.SignWithPubKey(&claims) if err != nil { return "", fmt.Errorf("error signing secret %w", err) } diff --git a/auth/jwt_middleware.go b/auth/jwt_middleware.go index f84c2aa3..276c3563 100644 --- a/auth/jwt_middleware.go +++ b/auth/jwt_middleware.go @@ -5,23 +5,30 @@ import ( "net/http" "time" - "github.com/containerish/OpenRegistry/store/v1/types" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" echo_jwt "github.com/labstack/echo-jwt/v4" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/store/v1/types" ) const ( - AccessCookieKey = "access_token" - RefreshCookKey = "refresh_token" - Service = "service" - QueryToken = "token" + AccessCookieKey = "access_token" + SessionCookieKey = "session_id" + RefreshCookKey = "refresh_token" + Service = "service" + QueryToken = "token" ) // JWT basically uses the default JWT middleware by echo, but has a slightly different skipper func func (a *auth) JWTRest() echo.MiddlewareFunc { return echo_jwt.WithConfig(echo_jwt.Config{ + Skipper: func(ctx echo.Context) bool { + p := ctx.Request().URL.Path + isPublicRepoDetailApi := p == "/v2/ext/catalog/repository" && ctx.QueryParam("public") == "true" + return p == "/v2/ext/catalog/detail" || p == "/v2/_catalog/public" || isPublicRepoDetailApi + }, ErrorHandler: func(ctx echo.Context, err error) error { ctx.Set(types.HandlerStartTime, time.Now()) diff --git a/auth/jwt_oci_middleware.go b/auth/jwt_oci_middleware.go index 15bc54c2..de340b5d 100644 --- a/auth/jwt_oci_middleware.go +++ b/auth/jwt_oci_middleware.go @@ -3,6 +3,7 @@ package auth import ( "fmt" "net/http" + "strings" "time" "github.com/containerish/OpenRegistry/common" @@ -23,6 +24,10 @@ func (a *auth) JWT() echo.MiddlewareFunc { ctx.Set(types.HandlerStartTime, time.Now()) } + if strings.HasPrefix(ctx.Request().URL.Path, "/v2/ext/") { + return true + } + // public read is allowed readOp := ctx.Request().Method == http.MethodGet || ctx.Request().Method == http.MethodHead // repository should be present at this step since the BasicAuth Middleware sets it diff --git a/auth/oci_token.go b/auth/oci_token.go index 07c59f0c..3d8e22e1 100644 --- a/auth/oci_token.go +++ b/auth/oci_token.go @@ -25,6 +25,100 @@ const ( DefaultOCITokenLifetime = time.Minute * 10 ) +// Request format: https://openregistry.dev/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push +func (a *auth) Token(ctx echo.Context) error { + // TODO (jay-dee7) - check for all valid query params here like serive, client_id, offline_token, etc + // more at this link - https://docs.docker.com/registry/spec/auth/token/ + ctx.Set(types.HandlerStartTime, time.Now()) + + scopes, err := ParseOCITokenPermissionRequest(ctx.Request().URL) + if err != nil { + registryErr := common.RegistryErrorResponse(registry.RegistryErrorCodeUnknown, "invalid scope provided", echo.Map{ + "error": err.Error(), + }) + echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) + a.logger.Log(ctx, registryErr).Send() + return echoErr + } + + // when scopes only have one action, and that action is pull + isPullRequest := len(scopes) == 1 && len(scopes[0].Actions) == 1 && scopes[0].HasPullAccess() + if isPullRequest { + repo, repoErr := a.registryStore.GetRepositoryByNamespace(ctx.Request().Context(), scopes[0].Name) + if repoErr != nil { + registryErr := common.RegistryErrorResponse( + registry.RegistryErrorCodeNameInvalid, + "requested resource does not exist on the registry", + echo.Map{ + "error": repoErr.Error(), + }, + ) + echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) + a.logger.Log(ctx, registryErr).Send() + return echoErr + } + user := ctx.Get(string(types.UserContextKey)).(*types.User) + + if repo.Visibility == types.RepositoryVisibilityPublic { + token, tokenErr := a.newOCIToken(user.ID, scopes) + if tokenErr != nil { + registryErr := common.RegistryErrorResponse( + registry.RegistryErrorCodeNameInvalid, + "error creating oci token", + echo.Map{ + "error": tokenErr.Error(), + }, + ) + echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) + a.logger.Log(ctx, registryErr).Send() + return echoErr + } + now := time.Now() + echoErr := ctx.JSON(http.StatusOK, echo.Map{ + "token": token, + "expires_in": now.Add(DefaultOCITokenLifetime).Unix(), + "issued_at": now, + }) + a.logger.Log(ctx, nil).Send() + return echoErr + } + } + + authHeader := ctx.Request().Header.Get(AuthorizationHeaderKey) + if authHeader != "" && len(scopes) != 0 { + token, authErr := a.tryBasicAuthFlow(ctx, scopes) + if authErr != nil { + registryErr := common.RegistryErrorResponse( + registry.RegistryErrorCodeUnauthorized, + "authentication failed", + echo.Map{ + "error": authErr.Error(), + }, + ) + echoErr := ctx.JSONBlob(http.StatusUnauthorized, registryErr.Bytes()) + a.logger.Log(ctx, authErr).Send() + return echoErr + } + now := time.Now() + echoErr := ctx.JSON(http.StatusOK, echo.Map{ + "token": token, + "expires_in": now.Add(DefaultOCITokenLifetime).Unix(), + "issued_at": now, + }) + a.logger.Log(ctx, nil).Send() + return echoErr + } + + registryErr := common.RegistryErrorResponse( + registry.RegistryErrorCodeUnauthorized, + "authentication failed", + nil, + ) + err = ctx.JSONBlob(http.StatusUnauthorized, registryErr.Bytes()) + a.logger.Log(ctx, registryErr).Send() + return err +} + func isOCILoginRequest(url *url.URL) types.OCITokenPermissonClaimList { account := url.Query().Get(OCITokenQueryParamAccount) if account != "" { @@ -157,102 +251,6 @@ func (a *auth) tryBasicAuthFlow(ctx echo.Context, scopes types.OCITokenPermisson return "", nil } -// Token -// request basically comes for -// https://openregistry.dev/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push -func (a *auth) Token(ctx echo.Context) error { - // TODO (jay-dee7) - check for all valid query params here like serive, client_id, offline_token, etc - // more at this link - https://docs.docker.com/registry/spec/auth/token/ - ctx.Set(types.HandlerStartTime, time.Now()) - - scopes, err := ParseOCITokenPermissionRequest(ctx.Request().URL) - if err != nil { - registryErr := common.RegistryErrorResponse(registry.RegistryErrorCodeUnknown, "invalid scope provided", echo.Map{ - "error": err.Error(), - }) - echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) - a.logger.Log(ctx, registryErr).Send() - return echoErr - } - - // when scopes only have one action, and that action is pull - isPullRequest := len(scopes) == 1 && len(scopes[0].Actions) == 1 && scopes[0].HasPullAccess() - if isPullRequest { - repo, repoErr := a.registryStore.GetRepositoryByNamespace(ctx.Request().Context(), scopes[0].Name) - if repoErr != nil { - registryErr := common.RegistryErrorResponse( - registry.RegistryErrorCodeNameInvalid, - "requested resource does not exist on the registry", - echo.Map{ - "error": repoErr.Error(), - }, - ) - echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) - a.logger.Log(ctx, registryErr).Send() - return echoErr - } - user := ctx.Get(string(types.UserContextKey)).(*types.User) - - if repo.Visibility == types.RepositoryVisibilityPublic { - token, tokenErr := a.newOCIToken(user.ID, scopes) - if tokenErr != nil { - registryErr := common.RegistryErrorResponse( - registry.RegistryErrorCodeNameInvalid, - "error creating oci token", - echo.Map{ - "error": tokenErr.Error(), - }, - ) - echoErr := ctx.JSONBlob(http.StatusBadRequest, registryErr.Bytes()) - a.logger.Log(ctx, registryErr).Send() - return echoErr - } - now := time.Now() - echoErr := ctx.JSON(http.StatusOK, echo.Map{ - "token": token, - "expires_in": now.Add(DefaultOCITokenLifetime).Unix(), - "issued_at": now, - }) - a.logger.Log(ctx, nil).Send() - return echoErr - } - } - - authHeader := ctx.Request().Header.Get(AuthorizationHeaderKey) - if authHeader != "" && len(scopes) != 0 { - token, authErr := a.tryBasicAuthFlow(ctx, scopes) - if authErr != nil { - registryErr := common.RegistryErrorResponse( - registry.RegistryErrorCodeUnauthorized, - "authentication failed", - echo.Map{ - "error": authErr.Error(), - }, - ) - echoErr := ctx.JSONBlob(http.StatusUnauthorized, registryErr.Bytes()) - a.logger.Log(ctx, authErr).Send() - return echoErr - } - now := time.Now() - echoErr := ctx.JSON(http.StatusOK, echo.Map{ - "token": token, - "expires_in": now.Add(DefaultOCITokenLifetime).Unix(), - "issued_at": now, - }) - a.logger.Log(ctx, nil).Send() - return echoErr - } - - registryErr := common.RegistryErrorResponse( - registry.RegistryErrorCodeUnauthorized, - "authentication failed", - nil, - ) - err = ctx.JSONBlob(http.StatusUnauthorized, registryErr.Bytes()) - a.logger.Log(ctx, registryErr).Send() - return err -} - func (a *auth) getCredsFromHeader(r *http.Request) (string, string, error) { authHeader := r.Header.Get(AuthorizationHeaderKey) if authHeader == "" { diff --git a/auth/permissions.go b/auth/permissions.go index 256677ea..ce1b6177 100644 --- a/auth/permissions.go +++ b/auth/permissions.go @@ -11,44 +11,6 @@ import ( "github.com/labstack/echo/v4" ) -func (a *auth) getImageNamespace(ctx echo.Context) (string, error) { - if ctx.Request().URL.Path == "/token" { - scope, err := a.getScopeFromQueryParams(ctx.QueryParam("scope")) - if err != nil { - return "", err - } - - return scope.Name, nil - } - username := ctx.Param("username") - imageName := ctx.Param("imagename") - return username + "/" + imageName, nil -} - -func (a *auth) populateUserFromPermissionsCheck(ctx echo.Context) error { - auth := ctx.Request().Header.Get(echo.HeaderAuthorization) - isTokenRequest := ctx.Request().URL.Path == "/token" - - if len(auth) > len(authSchemeBasic)+1 && strings.EqualFold(auth[:len(authSchemeBasic)], authSchemeBasic) { - user, err := a.validateBasicAuthCredentials(auth) - if err != nil { - return err - } - - ctx.Set(string(types.UserContextKey), user) - return nil - } - - // Check if it's an OCI request - if !isTokenRequest { - if _, ok := ctx.Get(string(types.UserContextKey)).(*types.User); ok { - return nil - } - } - - return fmt.Errorf("invalid user credentials: %s", auth) -} - func (a *auth) RepositoryPermissionsMiddleware() echo.MiddlewareFunc { return func(handler echo.HandlerFunc) echo.HandlerFunc { return func(ctx echo.Context) error { @@ -125,14 +87,50 @@ func (a *auth) RepositoryPermissionsMiddleware() echo.MiddlewareFunc { } } +func (a *auth) getImageNamespace(ctx echo.Context) (string, error) { + if ctx.Request().URL.Path == "/token" { + scope, err := a.getScopeFromQueryParams(ctx.QueryParam("scope")) + if err != nil { + return "", err + } + + return scope.Name, nil + } + username := ctx.Param("username") + imageName := ctx.Param("imagename") + return username + "/" + imageName, nil +} + +func (a *auth) populateUserFromPermissionsCheck(ctx echo.Context) error { + auth := ctx.Request().Header.Get(echo.HeaderAuthorization) + isTokenRequest := ctx.Request().URL.Path == "/token" + + if len(auth) > len(authSchemeBasic)+1 && strings.EqualFold(auth[:len(authSchemeBasic)], authSchemeBasic) { + user, err := a.validateBasicAuthCredentials(auth) + if err != nil { + return fmt.Errorf("ERR_USER_PERM_CHECK: %w", err) + } + + ctx.Set(string(types.UserContextKey), user) + return nil + } + + // Check if it's an OCI request + if !isTokenRequest { + if _, ok := ctx.Get(string(types.UserContextKey)).(*types.User); ok { + return nil + } + } + + return fmt.Errorf("invalid user credentials: %s", auth) +} + func (a *auth) handleTokenRequest(ctx echo.Context, handler echo.HandlerFunc) (error, bool) { if err := a.populateUserFromPermissionsCheck(ctx); err != nil { registryErr := common.RegistryErrorResponse( registry.RegistryErrorCodeUnauthorized, - "missing user credentials in request", - echo.Map{ - "error": err.Error(), - }, + err.Error(), + nil, ) echoErr := ctx.JSONBlob(http.StatusUnauthorized, registryErr.Bytes()) diff --git a/auth/reset_password.go b/auth/reset_password.go index b79931e2..c47b153d 100644 --- a/auth/reset_password.go +++ b/auth/reset_password.go @@ -7,13 +7,13 @@ import ( "net/http" "time" - "github.com/containerish/OpenRegistry/services/email" - v2_types "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/containerish/OpenRegistry/types" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" "github.com/jackc/pgx/v4" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/services/email" + "github.com/containerish/OpenRegistry/store/v1/types" ) func (a *auth) ResetForgottenPassword(ctx echo.Context) error { @@ -41,7 +41,7 @@ func (a *auth) ResetForgottenPassword(ctx echo.Context) error { return echoErr } - var pwd *types.Password + var pwd *types.ResetPasswordRequest if err := json.NewDecoder(ctx.Request().Body).Decode(&pwd); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), @@ -72,7 +72,7 @@ func (a *auth) ResetForgottenPassword(ctx echo.Context) error { return echoErr } - if err = v2_types.ValidatePassword(pwd.NewPassword); err != nil { + if err = types.ValidatePassword(pwd.NewPassword); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), "message": `password must be alphanumeric, at least 8 chars long, must have at least one special character @@ -122,29 +122,17 @@ and an uppercase letter`, func (a *auth) ResetPassword(ctx echo.Context) error { ctx.Set(types.HandlerStartTime, time.Now()) - token, ok := ctx.Get("user").(*jwt.Token) + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) if !ok { - err := fmt.Errorf("ERR_EMPTY_TOKEN") + err := fmt.Errorf("unauthorized: missing user auth credentials") echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ - "error": err.Error(), - "message": "JWT token can not be empty", - }) - a.logger.Log(ctx, err).Send() - return echoErr - } - - c, ok := token.Claims.(*Claims) - if !ok { - err := fmt.Errorf("ERR_INVALID_CLAIMS") - echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ - "error": err.Error(), - "message": "invalid claims in JWT", + "error": err.Error(), }) a.logger.Log(ctx, err).Send() return echoErr } - var pwd *types.Password + var pwd types.ResetPasswordRequest err := json.NewDecoder(ctx.Request().Body).Decode(&pwd) if err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ @@ -156,26 +144,6 @@ func (a *auth) ResetPassword(ctx echo.Context) error { } defer ctx.Request().Body.Close() - userId, err := uuid.Parse(c.ID) - if err != nil { - echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ - "error": err.Error(), - "message": "invalid user id format", - }) - a.logger.Log(ctx, err).Send() - return echoErr - } - - user, err := a.userStore.GetUserByID(ctx.Request().Context(), userId) - if err != nil { - echoErr := ctx.JSON(http.StatusNotFound, echo.Map{ - "error": err.Error(), - "message": "error getting user by ID from DB", - }) - a.logger.Log(ctx, err).Send() - return echoErr - } - // compare the current password with password hash from DB if !a.verifyPassword(user.Password, pwd.OldPassword) { err = fmt.Errorf("ERR_WRONG_PASSWORD") @@ -208,7 +176,7 @@ func (a *auth) ResetPassword(ctx echo.Context) error { return echoErr } - if err = v2_types.ValidatePassword(pwd.NewPassword); err != nil { + if err = types.ValidatePassword(pwd.NewPassword); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), "message": `password must be alphanumeric, at least 8 chars long, must have at least one special character @@ -218,7 +186,7 @@ and an uppercase letter`, return echoErr } - if err = a.userStore.UpdateUserPWD(ctx.Request().Context(), userId, hashPassword); err != nil { + if err = a.userStore.UpdateUserPWD(ctx.Request().Context(), user.ID, hashPassword); err != nil { echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), "message": "error updating new password", @@ -267,9 +235,13 @@ func (a *auth) ForgotPassword(ctx echo.Context) error { } if !user.IsActive { - return ctx.JSON(http.StatusUnauthorized, echo.Map{ - "message": "account is inactive, please check your email and verify your account", + err = fmt.Errorf("account is inactive, please check your email and verify your account") + echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ + "message": err.Error(), }) + + a.logger.Log(ctx, err).Send() + return echoErr } opts := &WebLoginJWTOptions{ diff --git a/auth/server/webauthn_server.go b/auth/server/webauthn_server.go index a8fc789a..84f1c6f3 100644 --- a/auth/server/webauthn_server.go +++ b/auth/server/webauthn_server.go @@ -5,21 +5,20 @@ import ( "encoding/json" "fmt" "net/http" - "net/url" "strings" "time" + "github.com/google/uuid" + "github.com/labstack/echo/v4" + "github.com/uptrace/bun" + "github.com/containerish/OpenRegistry/auth" "github.com/containerish/OpenRegistry/auth/webauthn" "github.com/containerish/OpenRegistry/config" - v2_types "github.com/containerish/OpenRegistry/store/v1/types" + "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/store/v1/users" webauthn_store "github.com/containerish/OpenRegistry/store/v1/webauthn" "github.com/containerish/OpenRegistry/telemetry" - "github.com/containerish/OpenRegistry/types" - "github.com/google/uuid" - "github.com/labstack/echo/v4" - "github.com/uptrace/bun" ) type ( @@ -86,7 +85,7 @@ func (wa *webauthn_server) webAuthNTxnCleanup() { func (wa *webauthn_server) BeginRegistration(ctx echo.Context) error { ctx.Set(types.HandlerStartTime, time.Now()) - user := v2_types.User{} + user := types.User{} if err := json.NewDecoder(ctx.Request().Body).Decode(&user); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ @@ -97,7 +96,7 @@ func (wa *webauthn_server) BeginRegistration(ctx echo.Context) error { return echoErr } defer ctx.Request().Body.Close() - user.Identities = make(v2_types.Identities) + user.Identities = make(types.Identities) err := user.Validate(false) if err != nil { @@ -131,7 +130,8 @@ func (wa *webauthn_server) BeginRegistration(ctx echo.Context) error { user.ID = uuid.New() user.IsActive = true user.WebauthnConnected = true - user.Identities[v2_types.IdentityProviderWebauthn] = &v2_types.UserIdentity{ + user.UserType = types.UserTypeRegular.String() + user.Identities[types.IdentityProviderWebauthn] = &types.UserIdentity{ ID: user.ID.String(), Username: user.Username, Email: user.Email, @@ -459,19 +459,11 @@ func (wa *webauthn_server) FinishLogin(ctx echo.Context) error { return echoErr } - domain := "" - url, err := url.Parse(wa.cfg.WebAuthnConfig.GetAllowedURLFromEchoContext(ctx, wa.cfg.Environment)) - if err != nil { - domain = wa.cfg.WebAuthnConfig.RPOrigins[0] - } else { - domain = url.Hostname() - } - sessionIdCookie := auth.CreateCookie(&auth.CreateCookieOptions{ - ExpiresAt: time.Now().Add(time.Hour * 750), //one month + ExpiresAt: time.Now().Add(time.Hour * 750), // one month Name: "session_id", Value: sessionId, - FQDN: domain, + FQDN: wa.cfg.Registry.FQDN, Environment: wa.cfg.Environment, HTTPOnly: false, }) @@ -480,16 +472,16 @@ func (wa *webauthn_server) FinishLogin(ctx echo.Context) error { ExpiresAt: time.Now().Add(time.Hour * 750), Name: auth.AccessCookieKey, Value: accessToken, - FQDN: domain, + FQDN: wa.cfg.Registry.FQDN, Environment: wa.cfg.Environment, HTTPOnly: true, }) refreshTokenCookie := auth.CreateCookie(&auth.CreateCookieOptions{ - ExpiresAt: time.Now().Add(time.Hour * 750), //one month + ExpiresAt: time.Now().Add(time.Hour * 750), // one month Name: auth.RefreshCookKey, Value: refreshToken, - FQDN: domain, + FQDN: wa.cfg.Registry.FQDN, Environment: wa.cfg.Environment, HTTPOnly: true, }) diff --git a/auth/signin.go b/auth/signin.go index c665a693..cc643044 100644 --- a/auth/signin.go +++ b/auth/signin.go @@ -7,10 +7,11 @@ import ( "net/http" "time" - "github.com/containerish/OpenRegistry/store/v1/types" "github.com/google/uuid" "github.com/jackc/pgx/v4" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/store/v1/types" ) func (a *auth) SignIn(ctx echo.Context) error { @@ -170,7 +171,7 @@ func (a *auth) SignIn(ctx echo.Context) error { } sessionId := fmt.Sprintf("%s:%s", id, userFromDb.ID) - sessionCookie := a.createCookie(ctx, "session_id", sessionId, false, time.Now().Add(time.Hour*750)) + sessionCookie := a.createCookie(ctx, SessionCookieKey, sessionId, false, time.Now().Add(time.Hour*750)) accessCookie := a.createCookie(ctx, AccessCookieKey, access, true, time.Now().Add(time.Hour*750)) refreshCookie := a.createCookie(ctx, RefreshCookKey, refresh, true, time.Now().Add(time.Hour*750)) @@ -178,8 +179,9 @@ func (a *auth) SignIn(ctx echo.Context) error { ctx.SetCookie(refreshCookie) ctx.SetCookie(sessionCookie) err = ctx.JSON(http.StatusOK, echo.Map{ - "token": access, - "refresh": refresh, + SessionCookieKey: sessionId, + AccessCookieKey: access, + RefreshCookKey: refresh, }) a.logger.Log(ctx, err).Send() return err diff --git a/auth/signup.go b/auth/signup.go index 407fb130..0c53b506 100644 --- a/auth/signup.go +++ b/auth/signup.go @@ -8,12 +8,13 @@ import ( "strings" "time" + "github.com/google/uuid" + "github.com/labstack/echo/v4" + "github.com/containerish/OpenRegistry/config" "github.com/containerish/OpenRegistry/services/email" store_err "github.com/containerish/OpenRegistry/store/v1" "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/google/uuid" - "github.com/labstack/echo/v4" ) func (a *auth) parseSignUpRequest(ctx echo.Context) (*types.User, error) { @@ -95,7 +96,7 @@ func (a *auth) SignUp(ctx echo.Context) error { if strings.Contains(err.Error(), store_err.ErrDuplicateConstraintEmail) { echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), - "message": "this email already taken, try sign in?", + "message": "this email is already taken, try sign in?", }) a.logger.Log(ctx, err).Send() return echoErr diff --git a/auth/user.go b/auth/user.go index dddb555c..d7f6b97e 100644 --- a/auth/user.go +++ b/auth/user.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/containerish/OpenRegistry/types" + "github.com/containerish/OpenRegistry/store/v1/types" "github.com/labstack/echo/v4" ) diff --git a/auth/validate_user.go b/auth/validate_user.go index 0d4eceb1..26400f01 100644 --- a/auth/validate_user.go +++ b/auth/validate_user.go @@ -28,3 +28,28 @@ func (a *auth) validateUser(username, password string) (*types.User, error) { return user, nil } + +func (a *auth) validateUserWithPAT(ctx context.Context, username, authToken string) (*types.User, error) { + user, err := a.userStore.GetUserByUsername(ctx, username) + if err != nil { + return nil, err + } + + token, err := (&types.AuthToken{}).FromString(authToken) + if err != nil { + return nil, fmt.Errorf("ERR_PARSE_AUTH_TOKEN: %w", err) + } + + hashedToken, err := GenerateSafeHash([]byte(token.RawString())) + if err != nil { + return nil, err + } + + _, err = a.userStore.GetAuthToken(ctx, user.ID, hashedToken) + if err != nil { + return nil, err + } + + return user, nil + +} diff --git a/auth/webauthn/webauthn.go b/auth/webauthn/webauthn.go index a687f681..3d13c887 100644 --- a/auth/webauthn/webauthn.go +++ b/auth/webauthn/webauthn.go @@ -234,6 +234,10 @@ func (wa *webAuthnService) FinishRegistration(ctx context.Context, opts *FinishR return fmt.Errorf("ERR_WEBAUTHN_ADD_CREDENTIAL: %w", err) } + if err = wa.store.RemoveWebAuthSessionData(ctx, opts.User.ID); err != nil { + return fmt.Errorf("ERR_WEBAUTHN_ADD_CREDENTIAL: RemoveWebAuthSessionData: %w", err) + } + return nil } @@ -304,5 +308,9 @@ func (wa *webAuthnService) FinishLogin(ctx context.Context, opts *FinishLoginOpt return fmt.Errorf("ERR_VALIDATE_WEBAUTHN_LOGIN: %w", err) } + if err = wa.store.RemoveWebAuthSessionData(ctx, opts.User.ID); err != nil { + return fmt.Errorf("ERR_WEBAUTHN_ADD_CREDENTIAL: RemoveWebAuthSessionData: %w", err) + } + return nil } diff --git a/buf.gen.yaml b/buf.gen.yaml index 3bfec575..d185fc17 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -1,16 +1,13 @@ -version: v1 +version: v2 managed: enabled: true plugins: - - plugin: buf.build/protocolbuffers/go + - remote: buf.build/protocolbuffers/go out: . - opt: - - paths=source_relative - - plugin: buf.build/bufbuild/validate-go + opt: paths=source_relative + - remote: buf.build/bufbuild/validate-go out: . - opt: - - paths=source_relative - - plugin: buf.build/bufbuild/connect-go + opt: paths=source_relative + - remote: buf.build/connectrpc/go out: . - opt: - - paths=source_relative + opt: paths=source_relative diff --git a/buf.lock b/buf.lock new file mode 100644 index 00000000..4286171e --- /dev/null +++ b/buf.lock @@ -0,0 +1,9 @@ +# Generated by buf. DO NOT EDIT. +version: v2 +deps: + - name: buf.build/envoyproxy/protoc-gen-validate + commit: 6607b10f00ed4a3d98f906807131c44a + digest: b5:ade405ac4328bd0a2cf83c93bcb4bc389d4897afd86a0096df4537b180916882da4e4f0c2d45f0b1554d7a6c87f6c5bc94b71b3555ca71cc31a9a8baed26a9f9 + - name: buf.build/googleapis/googleapis + commit: 5ae7f88519b04fe1965da0f8a375a088 + digest: b5:ac717f02b210c53aeaa5d8801b118cae7a1883dab531034859889622dcb389979ee731ab42192c16c3cdb39b40f2dda72a8c1ebeefa3bcdf95f9e5739dc30cca diff --git a/buf.work.yaml b/buf.work.yaml deleted file mode 100644 index 4bddfe67..00000000 --- a/buf.work.yaml +++ /dev/null @@ -1,3 +0,0 @@ -version: v1 -directories: - - protos diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 00000000..567d9738 --- /dev/null +++ b/buf.yaml @@ -0,0 +1,20 @@ +version: v2 +modules: + - path: protos + name: buf.build/containerish/openregistry +deps: + - buf.build/envoyproxy/protoc-gen-validate + - buf.build/googleapis/googleapis +lint: + use: + - STANDARD + except: + - FIELD_NOT_REQUIRED + - PACKAGE_NO_IMPORT_CYCLE + disallow_comment_ignores: true +breaking: + use: + - FILE + except: + - EXTENSION_NO_DELETE + - FIELD_SAME_DEFAULT diff --git a/cmd/migrations/migrations.go b/cmd/migrations/migrations.go index 7bd03bb1..734b7a52 100644 --- a/cmd/migrations/migrations.go +++ b/cmd/migrations/migrations.go @@ -156,6 +156,14 @@ func createOpenRegistryTables(ctx *cli.Context, db *bun.DB) error { } color.Green(`Table "permissions" created ✔︎`) + _, err = db.NewCreateTable().Model(&types.AuthTokens{}).Table().IfNotExists().Exec(ctx.Context) + if err != nil { + return errors.New( + color.RedString("Table=auth_tokens Created=❌ Error=%s", err), + ) + } + color.Green(`Table "auth_tokens" created ✔︎`) + return nil } @@ -223,7 +231,7 @@ func createOpenRegistryDatabase(ctx *cli.Context, opts *databaseOptions) (*bun.D _, err = adminDB. ExecContext( ctx.Context, - "GRANT ALL PRIVILEGES ON DATABASE ?0 to ?1", + "GRANT ALL PRIVILEGES ON DATABASE ? to ?", bun.Ident(opts.database), bun.Ident(opts.username), ) diff --git a/cmd/registry/registry.go b/cmd/registry/registry.go index 36797807..9125b136 100644 --- a/cmd/registry/registry.go +++ b/cmd/registry/registry.go @@ -100,9 +100,10 @@ func RunRegistryServer(ctx *cli.Context) error { registryStore, usersStore, automationStore, + dfs, ) - otelShutdownFunc := otel.ConfigureOtel(cfg.Telemetry, "openregistry-api", baseRouter) + otelShutdownFunc := otel.ConfigureOtel(cfg.Telemetry.Honeycomb, "openregistry-api", baseRouter) if otelShutdownFunc != nil { defer otelShutdownFunc() } diff --git a/config/config.go b/config/config.go index d32a4c0b..0357a794 100644 --- a/config/config.go +++ b/config/config.go @@ -1,19 +1,26 @@ package config import ( + "bytes" "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base32" "errors" "fmt" "strings" "time" + "github.com/fatih/color" "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" enTranslations "github.com/go-playground/validator/v10/translations/en" + "github.com/golang-jwt/jwt/v5" "github.com/hashicorp/go-multierror" "github.com/labstack/echo/v4" "github.com/spf13/viper" + "gopkg.in/yaml.v3" ) type ( @@ -76,7 +83,7 @@ type ( MockStorageBackend int // just so that we can retrieve values easily - Integrations []*Integration + Integrations map[string]any Registry struct { DNSAddress string `yaml:"dns_address" mapstructure:"dns_address" validate:"required"` @@ -134,7 +141,8 @@ type ( Enabled bool `yaml:"enabled" mapstructure:"enabled"` Timeout time.Duration `yaml:"timeout" mapstructure:"timeout"` } - Integration struct { + + GithubIntegration struct { Name string `yaml:"name" mapstructure:"name"` ClientSecret string `yaml:"client_secret" mapstructure:"client_secret"` ClientID string `yaml:"client_id" mapstructure:"client_id"` @@ -148,6 +156,14 @@ type ( Enabled bool `yaml:"enabled" mapstructure:"enabled"` } + ClairIntegration struct { + ClairEndpoint string `yaml:"clair_endpoint" mapstructure:"clair_endpoint"` + AuthToken string `yaml:"auth_token" mapstructure:"auth_token"` + Host string `yaml:"host" mapstructure:"host"` + Port int `yaml:"port" mapstructure:"port"` + Enabled bool `yaml:"enabled" mapstructure:"enabled"` + } + Auth struct { JWTSigningPrivateKey *rsa.PrivateKey `yaml:"priv_key" mapstructure:"priv_key"` JWTSigningPubKey *rsa.PublicKey `yaml:"pub_key" mapstructure:"pub_key"` @@ -183,9 +199,16 @@ type ( } Telemetry struct { - Logging Logging `yaml:"logging" mapstructure:"logging"` - Otel Otel `yaml:"otel" mapstructure:"otel"` - Enabled bool `yaml:"enabled" mapstructure:"enabled"` + Honeycomb Honeycomb `yaml:"honeycomb" mapstructure:"honeycomb"` + Logging Logging `yaml:"logging" mapstructure:"logging"` + Otel Otel `yaml:"otel" mapstructure:"otel"` + Enabled bool `yaml:"enabled" mapstructure:"enabled"` + } + + Honeycomb struct { + ServiceName string `yaml:"service_name" mapstructure:"service_name"` + ApiKey string `yaml:"api_key" mapstructure:"api_key"` + Enabled bool `yaml:"enabled" mapstructure:"enabled"` } IpfsDFS struct { @@ -292,23 +315,70 @@ func (oc *OpenRegistryConfig) Endpoint() string { } } -func (itg Integrations) GetGithubConfig() *Integration { - for _, cfg := range itg { - if cfg.Name == "github" && cfg.Enabled { - return cfg - } +func (itg Integrations) GetClairConfig() *ClairIntegration { + cfg := ClairIntegration{ + Enabled: false, + } + clairCfg, ok := itg["clair"] + if !ok { + return &cfg + } + + bz, err := yaml.Marshal(clairCfg) + if err != nil { + color.Red("error reading clair integration config as json: %s", err) + return nil } - return &Integration{} + if err = yaml.Unmarshal(bz, &cfg); err != nil { + color.Red("error parsing Clair integration config: %s", err) + return nil + } + + if cfg.Host == "" { + cfg.Host = "localhost" + } + + if cfg.Port == 0 { + cfg.Port = 5004 + } + + return &cfg } -func (itg Integrations) SetGithubConfig(config *Integration) { - for i, cfg := range itg { - if cfg.Name == "github" { - itg[i] = config - break - } +func (itg Integrations) GetGithubConfig() *GithubIntegration { + cfg := GithubIntegration{ + Enabled: false, + } + ghCfg, ok := itg["github"] + if !ok { + return &cfg + } + + bz, err := yaml.Marshal(ghCfg) + if err != nil { + color.Red("error reading github integration config as json: %s", err) + return nil + } + + if err = yaml.Unmarshal(bz, &cfg); err != nil { + color.Red("error parsing GitHub integration config: %s", err) + return nil + } + + if cfg.Host == "" { + cfg.Host = "localhost" } + + if cfg.Port == 0 { + cfg.Port = 5001 + } + + return &cfg +} + +func (itg Integrations) SetGithubConfig(config map[string]any) { + itg["github"] = config } type Environment int @@ -378,7 +448,11 @@ func (cfg *WebAppConfig) GetAllowedURLFromEchoContext(ctx echo.Context, env Envi return cfg.AllowedEndpoints[0] } -func (itg *Integration) GetAllowedURLFromEchoContext(ctx echo.Context, env Environment, allowedURLs []string) string { +func (itg *GithubIntegration) GetAllowedURLFromEchoContext( + ctx echo.Context, + env Environment, + allowedURLs []string, +) string { origin := ctx.Request().Header.Get("Origin") if env == Staging { return origin @@ -419,3 +493,34 @@ func (wan *WebAuthnConfig) GetAllowedURLFromEchoContext(ctx echo.Context, env En return wan.RPOrigins[0] } + +func (a *Auth) keyIDEncode(b []byte) string { + s := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=") + var buf bytes.Buffer + var i int + for i = 0; i < len(s)/4-1; i++ { + start := i * 4 + end := start + 4 + buf.WriteString(s[start:end] + ":") + } + buf.WriteString(s[i*4:]) + return buf.String() +} + +func (a *Auth) SignWithPubKey(claims jwt.Claims) (string, error) { + pubKeyDerBz, err := x509.MarshalPKIXPublicKey(a.JWTSigningPubKey) + if err != nil { + return "", err + } + + hasher := sha256.New() + hasher.Write(pubKeyDerBz) + token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + token.Header["kid"] = a.keyIDEncode(hasher.Sum(nil)[:30]) + signed, err := token.SignedString(a.JWTSigningPrivateKey) + if err != nil { + return "", fmt.Errorf("error signing secret %w", err) + } + + return signed, nil +} diff --git a/config/yaml.go b/config/yaml.go index b5056b15..6fafc46c 100644 --- a/config/yaml.go +++ b/config/yaml.go @@ -11,7 +11,7 @@ import ( "github.com/fatih/color" "github.com/golang-jwt/jwt/v5" "github.com/spf13/viper" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) func ReadYamlConfig(configPath string) (*OpenRegistryConfig, error) { @@ -77,7 +77,7 @@ func ReadYamlConfig(configPath string) (*OpenRegistryConfig, error) { githubConfig.Port = 5001 } - cfg.Integrations.SetGithubConfig(githubConfig) + // cfg.Integrations.SetGithubConfig(githubConfig) if err := cfg.Validate(); err != nil { return nil, err @@ -150,6 +150,16 @@ func setDefaultsForDatabaseStore(cfg *OpenRegistryConfig) { } func parseAndSetMockStorageDriverOptions(cfg *OpenRegistryConfig) { + mockConfig := viper.GetStringMap("dfs.mock") + keys := make([]string, 0, len(mockConfig)) + for k := range mockConfig { + keys = append(keys, k) + } + + // skip is mock config is absent + if len(keys) == 0 { + return + } mockDFSType := viper.GetString("dfs.mock.type") if mockDFSType == "MemMapped" { viper.Set("dfs.mock.type", MockStorageBackendMemMapped) diff --git a/dfs/filebase/filebase.go b/dfs/filebase/filebase.go index 41507c2e..531e4e50 100644 --- a/dfs/filebase/filebase.go +++ b/dfs/filebase/filebase.go @@ -16,7 +16,6 @@ import ( "github.com/containerish/OpenRegistry/config" "github.com/containerish/OpenRegistry/dfs" "github.com/containerish/OpenRegistry/store/v1/types" - core_types "github.com/containerish/OpenRegistry/types" ) type filebase struct { @@ -234,7 +233,7 @@ func (fb *filebase) Metadata(layer *types.ContainerImageLayer) (*types.ObjectMet var resp *s3.HeadObjectOutput var err error - identifier := core_types.GetLayerIdentifier(layer.ID) + identifier := types.GetLayerIdentifier(layer.ID) for i := 3; i > 0; i-- { resp, err = fb.client.HeadObject(context.Background(), &s3.HeadObjectInput{ Bucket: &fb.bucket, @@ -300,21 +299,8 @@ func (fb *filebase) AbortMultipartUpload(ctx context.Context, layerKey, uploadId } func (fb *filebase) GeneratePresignedURL(ctx context.Context, key string) (string, error) { - opts := &s3.GetObjectInput{ - Bucket: &fb.bucket, - Key: aws.String("layers/" + key), - } - - duration := func(o *s3.PresignOptions) { - o.Expires = time.Minute * 20 - } - - resp, err := fb.preSigner.PresignGetObject(ctx, opts, duration) - if err != nil { - return "", fmt.Errorf("ERR_FILEBASE_GENERATE_PRESIGNED_URL: %w", err) - } - - return resp.URL, nil + // Filebase+IPFS content can be directly resolved over an IPFS gateway + return fmt.Sprintf("%s/%s", fb.config.DFSLinkResolver, key), nil } func (fb *filebase) Config() *config.S3CompatibleDFS { diff --git a/dfs/ipfs/p2p/p2p.go b/dfs/ipfs/p2p/p2p.go index c32465f8..fd2795fe 100644 --- a/dfs/ipfs/p2p/p2p.go +++ b/dfs/ipfs/p2p/p2p.go @@ -11,7 +11,7 @@ import ( "strings" "time" - hexmap "github.com/alphadose/haxmap" + "github.com/alphadose/haxmap" "github.com/aws/aws-sdk-go-v2/aws" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/fatih/color" @@ -35,8 +35,8 @@ type ( ipfsP2p struct { node *rpc.HttpApi config *config.IpfsDFS - uploadSession *hexmap.Map[string, *multipartSession] - uploadParts *hexmap.Map[string, *uploadParts] + uploadSession *haxmap.Map[string, *multipartSession] + uploadParts *haxmap.Map[string, *uploadParts] } multipartSession struct { @@ -89,8 +89,8 @@ func New(config *config.IpfsDFS) dfs.DFS { dfs := &ipfsP2p{ node: node, config: config, - uploadSession: hexmap.New[string, *multipartSession](), - uploadParts: hexmap.New[string, *uploadParts](), + uploadSession: haxmap.New[string, *multipartSession](), + uploadParts: haxmap.New[string, *uploadParts](), } // run garbage collection in background diff --git a/dfs/mock/memMappedSystem.go b/dfs/mock/memMappedSystem.go index 236aea1b..a34b59ad 100644 --- a/dfs/mock/memMappedSystem.go +++ b/dfs/mock/memMappedSystem.go @@ -10,6 +10,7 @@ import ( "net/url" "os" "strings" + "sync" "github.com/aws/aws-sdk-go-v2/aws" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" @@ -22,7 +23,6 @@ import ( "github.com/containerish/OpenRegistry/dfs" types "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/telemetry" - core_types "github.com/containerish/OpenRegistry/types" ) type memMappedMockStorage struct { @@ -30,6 +30,7 @@ type memMappedMockStorage struct { logger telemetry.Logger uploadSession map[string]string config *config.S3CompatibleDFS + mutex *sync.RWMutex serviceEndpoint string } @@ -55,6 +56,7 @@ func newMemMappedMockStorage( config: cfg, serviceEndpoint: net.JoinHostPort(parsedHost.Hostname(), "5002"), logger: logger, + mutex: &sync.RWMutex{}, } go mocker.FileServer() @@ -63,7 +65,9 @@ func newMemMappedMockStorage( func (ms *memMappedMockStorage) CreateMultipartUpload(layerKey string) (string, error) { sessionId := uuid.NewString() + ms.mutex.Lock() ms.uploadSession[sessionId] = sessionId + defer ms.mutex.Unlock() return sessionId, nil } @@ -112,7 +116,9 @@ func (ms *memMappedMockStorage) CompleteMultipartUpload( layerDigest string, completedParts []s3types.CompletedPart, ) (string, error) { + ms.mutex.Lock() delete(ms.uploadSession, layerKey) + defer ms.mutex.Unlock() return layerKey, nil } @@ -165,7 +171,7 @@ func (ms *memMappedMockStorage) Metadata(layer *types.ContainerImageLayer) (*typ err error ) - identifier := core_types.GetLayerIdentifier(layer.ID) + identifier := types.GetLayerIdentifier(layer.ID) parts := strings.Split(identifier, "/") if len(parts) > 1 { fd, err = ms.memFs.Open(parts[1]) @@ -246,7 +252,9 @@ func (ms *memMappedMockStorage) AbortMultipartUpload(ctx context.Context, layerK return err } + ms.mutex.Lock() delete(ms.uploadSession, uploadId) + defer ms.mutex.Unlock() return nil } @@ -268,16 +276,22 @@ func (ms *memMappedMockStorage) FileServer() { } fd, err := ms.memFs.Open(fileID) if err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) + + ms.logger.Log(ctx, err).Send() + return echoErr } bz, _ := io.ReadAll(fd) fd.Close() - return ctx.Blob(http.StatusOK, "", bz) + echoErr := ctx.Blob(http.StatusOK, "", bz) + ms.logger.Log(ctx, err).Send() + return echoErr }) + color.Yellow("Started Mock MemMapped DFS on %s", ms.serviceEndpoint) if err := e.Start(ms.serviceEndpoint); err != nil { color.Red("MockStorage service failed: %s", err) os.Exit(1) diff --git a/dfs/mock/mockFileSystem.go b/dfs/mock/mockFileSystem.go index 594dc325..42a4f1bf 100644 --- a/dfs/mock/mockFileSystem.go +++ b/dfs/mock/mockFileSystem.go @@ -10,6 +10,7 @@ import ( "net/url" "os" "strings" + "sync" "github.com/aws/aws-sdk-go-v2/aws" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" @@ -23,7 +24,6 @@ import ( "github.com/containerish/OpenRegistry/dfs" types "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/telemetry" - core_types "github.com/containerish/OpenRegistry/types" ) type fileBasedMockStorage struct { @@ -31,6 +31,7 @@ type fileBasedMockStorage struct { logger telemetry.Logger uploadSession map[string]string config *config.S3CompatibleDFS + mutex *sync.RWMutex serviceEndpoint string } @@ -58,6 +59,7 @@ func newFileBasedMockStorage( config: cfg, serviceEndpoint: net.JoinHostPort(parsedHost.Hostname(), "5002"), logger: logger, + mutex: &sync.RWMutex{}, } go mocker.FileServer() @@ -66,7 +68,9 @@ func newFileBasedMockStorage( func (ms *fileBasedMockStorage) CreateMultipartUpload(layerKey string) (string, error) { sessionId := uuid.NewString() + ms.mutex.Lock() ms.uploadSession[sessionId] = sessionId + defer ms.mutex.Unlock() return sessionId, nil } @@ -116,7 +120,9 @@ func (ms *fileBasedMockStorage) CompleteMultipartUpload( layerDigest string, completedParts []s3types.CompletedPart, ) (string, error) { + ms.mutex.Lock() delete(ms.uploadSession, layerKey) + defer ms.mutex.Unlock() return layerKey, nil } @@ -180,7 +186,7 @@ func (ms *fileBasedMockStorage) Metadata(layer *types.ContainerImageLayer) (*typ err error ) - identifier := core_types.GetLayerIdentifier(layer.ID) + identifier := types.GetLayerIdentifier(layer.ID) parts := strings.Split(identifier, "/") if len(parts) > 1 { fd, err = ms.fs.Open(parts[1]) @@ -245,7 +251,9 @@ func (ms *fileBasedMockStorage) AbortMultipartUpload(ctx context.Context, layerK return err } + ms.mutex.Lock() delete(ms.uploadSession, uploadId) + defer ms.mutex.Unlock() return nil } diff --git a/dfs/storj/storj.go b/dfs/storj/storj.go index 25756c44..8f122791 100644 --- a/dfs/storj/storj.go +++ b/dfs/storj/storj.go @@ -16,7 +16,6 @@ import ( "github.com/containerish/OpenRegistry/config" "github.com/containerish/OpenRegistry/dfs" "github.com/containerish/OpenRegistry/store/v1/types" - core_types "github.com/containerish/OpenRegistry/types" ) type storj struct { @@ -209,7 +208,7 @@ func (sj *storj) AddImage(ns string, mf, l map[string][]byte) (string, error) { func (sj *storj) Metadata(layer *types.ContainerImageLayer) (*types.ObjectMetadata, error) { var resp *s3.HeadObjectOutput var err error - id := core_types.GetLayerIdentifier(layer.ID) + id := types.GetLayerIdentifier(layer.ID) for i := 3; i > 0; i-- { resp, err = sj.client.HeadObject(context.Background(), &s3.HeadObjectInput{ Bucket: &sj.bucket, diff --git a/dfs/storj/uplink/uplink.go b/dfs/storj/uplink/uplink.go index 7b4a93ec..3408d913 100644 --- a/dfs/storj/uplink/uplink.go +++ b/dfs/storj/uplink/uplink.go @@ -17,7 +17,6 @@ import ( "github.com/containerish/OpenRegistry/config" "github.com/containerish/OpenRegistry/dfs" "github.com/containerish/OpenRegistry/store/v1/types" - core_types "github.com/containerish/OpenRegistry/types" ) type storjUplink struct { @@ -178,7 +177,7 @@ func (u *storjUplink) GetUploadProgress(identifier string, uploadID string) (*ty // Metadata implements dfs.DFS func (u *storjUplink) Metadata(layer *types.ContainerImageLayer) (*types.ObjectMetadata, error) { - identifier := core_types.GetLayerIdentifier(layer.ID) + identifier := types.GetLayerIdentifier(layer.ID) metadata, err := u.client.StatObject(context.Background(), u.bucket, identifier) if err != nil { diff --git a/docs/contributing/development-environment-setup.md b/docs/contributing/development-environment-setup.md index 56dfe460..ba2a8460 100644 --- a/docs/contributing/development-environment-setup.md +++ b/docs/contributing/development-environment-setup.md @@ -3,12 +3,14 @@ ## Clone the repository We recommend using the Git method to clone the repository: + ```bash git clone git@github.com:containerish/OpenRegistry.git cd OpenRegistry ``` ## Configuration File + OpenRegistry uses the standard yaml based configuration. This configuration file is named `config.yaml` and can be either in the current directory or `$HOME/.openregistry/config.yaml` directory. Some of the features are disabled by default just to keep the on-boarding process simple. @@ -22,39 +24,39 @@ web_app_url: "http://localhost:3000" web_app_redirect_url: "/" web_app_error_redirect_path: "/auth/unhandled" registry: - dns_address: registry.local - version: master - fqdn: registry.local - host: registry.local - port: 5000 - tls: - enabled: true - key: .certs/openregistry.key - cert: .certs/openregistry.cert - services: - - github - - token + dns_address: registry.local + version: master + fqdn: registry.local + host: registry.local + port: 5000 + tls: + enabled: true + key: .certs/openregistry.key + cert: .certs/openregistry.cert + services: + - github + - token dfs: - s3_any: - access_key: - secret_key: - endpoint: - bucket_name: - dfs_link_resolver: + s3_any: + access_key: + secret_key: + endpoint: + bucket_name: + dfs_link_resolver: database: - kind: postgres - host: 0.0.0.0 - port: 5432 - username: postgres - password: Qwerty@123 - name: open_registry + kind: postgres + host: 0.0.0.0 + port: 5432 + username: postgres + password: Qwerty@123 + name: open_registry ``` If you check the `registry.tls` section, you'll notice that we have enabled the TLS configuration, but we need to generate the TLS certificates before we move forward: ```bash -make certs +just certs ``` ## Database Setup @@ -79,12 +81,13 @@ Exit the Postgres shell. ### Create the tables We have a simple Makefile, which exposes the following commands: + - `migup` - Populate all the migrations, create tables, schema changes - `migdown` - Teardown all the tables, schemas, etc - `cleanup` - Runs `migdown` first and then `migup` Before we begin setting up tables in our database, we need to use another tool called `golang-migrate`. -This is a database migration tool that makes database migrations dead simple. Use either of the following links to +This is a database migration tool that makes database migrations dead simple. Use either of the following links to install `golang-migrate`: - [Homebrew Link](https://formulae.brew.sh/formula/golang-migrate#default) @@ -93,7 +96,7 @@ install `golang-migrate`: To make sure that OpenRegistry can find all the required tables, schemas, etc, run the following command: ```bash -make migup +just migup ``` ```bash diff --git a/go.mod b/go.mod index 92728810..f2045eb5 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23 toolchain go1.23.0 require ( + connectrpc.com/connect v1.17.0 github.com/alexliesenfeld/health v0.8.0 github.com/alphadose/haxmap v1.4.0 github.com/aws/aws-sdk-go-v2 v1.32.2 @@ -14,7 +15,6 @@ require ( github.com/aws/smithy-go v1.22.0 github.com/axiomhq/axiom-go v0.21.1 github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 - github.com/bufbuild/connect-go v1.10.0 github.com/fatih/color v1.17.0 github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 @@ -25,19 +25,21 @@ require ( github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 github.com/honeycombio/otel-config-go v1.17.0 - github.com/ipfs/boxo v0.24.0 + github.com/ipfs/boxo v0.23.0 github.com/ipfs/kubo v0.30.0 - github.com/jackc/pgx/v4 v4.18.3 + github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c github.com/labstack/echo-contrib v0.17.1 github.com/labstack/echo-jwt/v4 v4.2.0 github.com/labstack/echo/v4 v4.12.0 github.com/multiformats/go-multiaddr v0.13.0 + github.com/oklog/ulid/v2 v2.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 + github.com/rs/cors v1.10.1 github.com/rs/zerolog v1.33.0 github.com/sendgrid/sendgrid-go v3.16.0+incompatible github.com/spf13/afero v1.11.0 - github.com/spf13/viper v1.19.0 + github.com/spf13/viper v1.18.2 github.com/uptrace/bun v1.2.3 github.com/uptrace/bun/dialect/pgdialect v1.2.3 github.com/uptrace/bun/dialect/sqlitedialect v1.2.3 @@ -48,11 +50,11 @@ require ( go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.55.0 go.opentelemetry.io/contrib/processors/baggagecopy v0.3.0 go.opentelemetry.io/otel v1.31.0 - golang.org/x/crypto v0.28.0 - golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.23.0 - google.golang.org/protobuf v1.35.1 - gopkg.in/yaml.v2 v2.4.0 + golang.org/x/crypto v0.27.0 + golang.org/x/net v0.29.0 + golang.org/x/oauth2 v0.22.0 + google.golang.org/protobuf v1.34.2 + gopkg.in/yaml.v3 v3.0.1 storj.io/uplink v1.13.1 ) @@ -127,7 +129,7 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgtype v1.14.1 // indirect + github.com/jackc/pgtype v1.14.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jtolio/noiseconn v0.0.0-20230111204749-d7ec1a08b0b8 // indirect @@ -135,7 +137,6 @@ require ( github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-libp2p v0.36.4 // indirect @@ -178,7 +179,6 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rs/cors v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -241,7 +241,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/grpc v1.66.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect mellium.im/sasl v0.3.1 // indirect modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect diff --git a/go.sum b/go.sum index 30b432eb..253055e0 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk= +connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= @@ -79,8 +81,6 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 h1:R9d0v+iobRHSaE4wKUnXFiZp53AL4ED5MzgEMwGTZag= github.com/bradleyfalzon/ghinstallation/v2 v2.11.0/go.mod h1:0LWKQwOHewXO/1acI6TtyE0Xc4ObDb2rFN7eHBAG71M= -github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg= -github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo= github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -290,8 +290,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.24.0 h1:D9gTU3QdxyjPMlJ6QfqhHTG3TIJPplKzjXLO2J30h9U= -github.com/ipfs/boxo v0.24.0/go.mod h1:iP7xUPpHq2QAmVAjwtQvsNBTxTwLpFuy6ZpiRFwmzDA= +github.com/ipfs/boxo v0.23.0 h1:dY1PpcvPJ//VuUQ1TUd5TZvmaGuzxJ8dOP6mXaw+ke8= +github.com/ipfs/boxo v0.23.0/go.mod h1:ulu5I6avTmgGmvjuCaBRKwsaOOKjBfQw1EiOOQp8M6E= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= @@ -413,14 +413,13 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.1 h1:LyDar7M2K0tShCWqzJ/ctzF1QC3Wzc9c8a6cHE0PFdc= -github.com/jackc/pgtype v1.14.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c h1:Dznn52SgVIVst9UyOT9brctYUgxs+CvVfPaC3jKrA50= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= -github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -473,9 +472,8 @@ github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjS github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 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/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -580,6 +578,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= +github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -594,6 +594,7 @@ github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7s github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= @@ -664,8 +665,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq 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= -github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= -github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -717,8 +718,8 @@ 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.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= 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= @@ -912,8 +913,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= 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= @@ -969,15 +970,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.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= @@ -1143,8 +1144,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/justfile b/justfile new file mode 100644 index 00000000..36e1e295 --- /dev/null +++ b/justfile @@ -0,0 +1,22 @@ +POSTGRESQL_URL := 'postgres://postgres:postgres@0.0.0.0:5432/open_registry?sslmode=disable' + +psql_grants: + @psql -d open_registry -c 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO open_registry_user;' + +mock-images: + bash ./scripts/mock-images.sh + +certs: + mkdir .certs + openssl req -x509 -newkey rsa:4096 -keyout .certs/registry.local -out .certs/registry.local.crt -sha256 -days 365 \ + -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=registry.local" -nodes + +dummy_users: + sh ./scripts/load_dummy_users.sh + +reset: + psql -c 'drop database open_registry' && \ + psql -c 'drop role open_registry_user' && \ + go build && \ + ./OpenRegistry migrations init --database="open_registry" --admin-db="postgres" --admin-db-username="postgres" --host="0.0.0.0" --password="Qwerty@123" --insecure=true && \ + ./OpenRegistry start diff --git a/orgmode/admin.go b/orgmode/admin.go index 13039372..daee9c9a 100644 --- a/orgmode/admin.go +++ b/orgmode/admin.go @@ -6,9 +6,10 @@ import ( "net/http" "strings" - "github.com/containerish/OpenRegistry/store/v1/types" "github.com/google/uuid" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/store/v1/types" ) func (o *orgMode) AllowOrgAdmin() echo.MiddlewareFunc { @@ -26,8 +27,8 @@ func (o *orgMode) AllowOrgAdmin() echo.MiddlewareFunc { p := ctx.Request().URL.Path switch { - case p == "/org/migrate": - var body MigrateToOrgRequest + case p == "/api/org/migrate": + var body types.MigrateToOrgRequest if err := json.NewDecoder(ctx.Request().Body).Decode(&body); err != nil { echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ "error": err.Error(), @@ -49,10 +50,10 @@ func (o *orgMode) AllowOrgAdmin() echo.MiddlewareFunc { ctx.Set(string(types.OrgModeRequestBodyContextKey), &body) return handler(ctx) - case p == "/org/users" || strings.HasPrefix(p, "/org/permissions/users"): + case p == "/api/org/users" || strings.HasPrefix(p, "/api/org/permissions/users"): orgOwner, err := o.userStore.GetOrgAdmin(ctx.Request().Context(), user.ID) if err != nil { - echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ + echoErr := ctx.JSON(http.StatusForbidden, echo.Map{ "error": err.Error(), "message": "user does not have permission to add users to organization", }) @@ -61,9 +62,17 @@ func (o *orgMode) AllowOrgAdmin() echo.MiddlewareFunc { } switch ctx.Request().Method { - case http.MethodPost, http.MethodPatch: + case http.MethodPost: + if err = o.parseAddUsersToOrgRequest(ctx, user, orgOwner); err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + o.logger.Log(ctx, err).Send() + return echoErr + } + case http.MethodPatch: if err = o.handleOrgModePermissionRequests(ctx, user, orgOwner); err != nil { - echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) o.logger.Log(ctx, err).Send() @@ -85,6 +94,38 @@ func (o *orgMode) AllowOrgAdmin() echo.MiddlewareFunc { } } +func (o *orgMode) parseAddUsersToOrgRequest(ctx echo.Context, user *types.User, orgOwner *types.User) error { + var body types.AddUsersToOrgRequest + if err := ctx.Bind(&body); err != nil { + return err + } + defer ctx.Request().Body.Close() + + // @TODO(jay-dee7) - Use a better comparison method + if !strings.EqualFold(orgOwner.ID.String(), body.OrganizationID.String()) { + return fmt.Errorf("organization id mismatch, invalid organization id") + } + + parsedBody := types.AddUsersToOrgRequest{ + OrganizationID: body.OrganizationID, + } + for _, perm := range body.Users { + if perm.Pull && perm.Push && !perm.IsAdmin { + perm.IsAdmin = true + } + + if perm.IsAdmin { + perm.Pull = true + perm.Push = true + } + + parsedBody.Users = append(parsedBody.Users, perm) + } + + ctx.Set(string(types.OrgModeRequestBodyContextKey), &parsedBody) + return nil +} + func (o *orgMode) handleOrgModePermissionRequests(ctx echo.Context, user *types.User, orgOwner *types.User) error { var perms types.Permissions if err := json.NewDecoder(ctx.Request().Body).Decode(&perms); err != nil { @@ -101,12 +142,22 @@ func (o *orgMode) handleOrgModePermissionRequests(ctx echo.Context, user *types. if strings.EqualFold(perms.UserID.String(), perms.OrganizationID.String()) { return fmt.Errorf("user id and organization id can not be the same") } + + if perms.Pull && perms.Push && !perms.IsAdmin { + perms.IsAdmin = true + } + + if perms.IsAdmin { + perms.Pull = true + perms.Push = true + } + ctx.Set(string(types.OrgModeRequestBodyContextKey), &perms) return nil } func (o *orgMode) handleOrgModeRemoveUser(ctx echo.Context, p string, orgOwner *types.User) error { - if strings.HasPrefix(p, fmt.Sprintf("/org/permissions/users/%s/", orgOwner.ID.String())) { + if strings.HasPrefix(p, fmt.Sprintf("/api/org/permissions/users/%s/", orgOwner.ID.String())) { orgID, err := uuid.Parse(ctx.Param("orgId")) if err != nil { return err @@ -120,7 +171,7 @@ func (o *orgMode) handleOrgModeRemoveUser(ctx echo.Context, p string, orgOwner * return echoErr } - body := &RemoveUserFromOrgRequest{ + body := &types.RemoveUserFromOrgRequest{ UserID: userID, OrganizationID: orgID, } diff --git a/orgmode/orgmode.go b/orgmode/orgmode.go index 59af2b93..d271b083 100644 --- a/orgmode/orgmode.go +++ b/orgmode/orgmode.go @@ -1,6 +1,7 @@ package orgmode import ( + "fmt" "net/http" "time" @@ -18,18 +19,10 @@ type ( AddUserToOrg(ctx echo.Context) error RemoveUserFromOrg(ctx echo.Context) error UpdateUserPermissions(ctx echo.Context) error + GetOrgUsers(ctx echo.Context) error AllowOrgAdmin() echo.MiddlewareFunc } - MigrateToOrgRequest struct { - UserID uuid.UUID `json:"user_id"` - } - - RemoveUserFromOrgRequest struct { - UserID uuid.UUID `json:"user_id"` - OrganizationID uuid.UUID `json:"organization_id"` - } - orgMode struct { logger telemetry.Logger permissionsStore permissions.PermissionsStore @@ -49,7 +42,7 @@ func New(permStore permissions.PermissionsStore, usersStore users.UserStore, log func (o *orgMode) MigrateToOrg(ctx echo.Context) error { ctx.Set(types.HandlerStartTime, time.Now()) - body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*MigrateToOrgRequest) + body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*types.MigrateToOrgRequest) if err := o.userStore.ConvertUserToOrg(ctx.Request().Context(), body.UserID); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), @@ -67,20 +60,18 @@ func (o *orgMode) MigrateToOrg(ctx echo.Context) error { // AddUserToOrg implements OrgMode. func (o *orgMode) AddUserToOrg(ctx echo.Context) error { - body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*types.Permissions) + body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*types.AddUsersToOrgRequest) - user, err := o.userStore.GetUserByID(ctx.Request().Context(), body.UserID) - if err != nil { - echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ - "error": err.Error(), - }) - o.logger.Log(ctx, err).Send() - return echoErr + userIdsToCheck := make([]uuid.UUID, len(body.Users)) + for i, u := range body.Users { + userIdsToCheck[i] = u.ID } - if user.UserType != types.UserTypeRegular.String() { + ok := o.userStore.MatchUserType(ctx.Request().Context(), types.UserTypeRegular, userIdsToCheck...) + if !ok { + err := fmt.Errorf("invalid user ids in the request") echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ - "error": "only regular users can be added to an organization", + "error": err.Error(), }) o.logger.Log(ctx, err).Send() return echoErr @@ -103,7 +94,7 @@ func (o *orgMode) AddUserToOrg(ctx echo.Context) error { // RemoveUserFromOrg implements OrgMode. func (o *orgMode) RemoveUserFromOrg(ctx echo.Context) error { - body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*RemoveUserFromOrgRequest) + body := ctx.Get(string(types.OrgModeRequestBodyContextKey)).(*types.RemoveUserFromOrgRequest) if err := o.permissionsStore.RemoveUserFromOrg(ctx.Request().Context(), body.OrganizationID, body.UserID); err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ @@ -138,3 +129,31 @@ func (o *orgMode) UpdateUserPermissions(ctx echo.Context) error { return echoErr } + +func (o *orgMode) GetOrgUsers(ctx echo.Context) error { + orgID, err := uuid.Parse(ctx.QueryParam("org_id")) + if err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + o.logger.Log(ctx, err).Send() + return echoErr + } + + orgMembers, err := o.userStore.GetOrgUsersByOrgID(ctx.Request().Context(), orgID) + if err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + o.logger.Log(ctx, err).Send() + return echoErr + } + + if len(orgMembers) == 0 { + orgMembers = make([]*types.Permissions, 0) + } + + echoErr := ctx.JSON(http.StatusOK, orgMembers) + o.logger.Log(ctx, nil).Send() + return echoErr +} diff --git a/protos/buf.lock b/protos/buf.lock deleted file mode 100644 index 4cb0aef5..00000000 --- a/protos/buf.lock +++ /dev/null @@ -1,11 +0,0 @@ -# Generated by buf. DO NOT EDIT. -version: v1 -deps: - - remote: buf.build - owner: envoyproxy - repository: protoc-gen-validate - commit: 6607b10f00ed4a3d98f906807131c44a - - remote: buf.build - owner: googleapis - repository: googleapis - commit: 5ae7f88519b04fe1965da0f8a375a088 diff --git a/protos/buf.yaml b/protos/buf.yaml deleted file mode 100644 index e6b4e5c4..00000000 --- a/protos/buf.yaml +++ /dev/null @@ -1,11 +0,0 @@ -version: v1 -name: buf.build/containerish/openregistry -lint: - use: - - STANDARD -deps: - - buf.build/googleapis/googleapis - - buf.build/envoyproxy/protoc-gen-validate -breaking: - use: - - FILE diff --git a/protos/services/kon/github_actions/v1/build_project.proto b/protos/services/kon/github_actions/v1/build_project.proto index e20e0e38..e2671a91 100644 --- a/protos/services/kon/github_actions/v1/build_project.proto +++ b/protos/services/kon/github_actions/v1/build_project.proto @@ -25,11 +25,12 @@ message ListProjectsResponse { message CreateProjectRequest { common.v1.UUID id = 1; common.v1.UUID owner_id = 2; - string project_name = 3; - string production_branch = 4; - ProjectBuildSettingsMessage build_settings = 5; - ProjectEnvironmentVariableListMessage environment_variables = 6; - google.protobuf.Timestamp created_at = 7; + common.v1.UUID repository_id = 3; + string project_name = 4; + string production_branch = 5; + ProjectBuildSettingsMessage build_settings = 6; + ProjectEnvironmentVariableListMessage environment_variables = 7; + google.protobuf.Timestamp created_at = 8; } message GetProjectRequest { @@ -52,6 +53,8 @@ message GetProjectResponse { ProjectEnvironmentVariableListMessage environment_variables = 5; google.protobuf.Timestamp created_at = 6; common.v1.UUID owner_id = 7; + common.v1.UUID repository_id = 8; + string repository_name = 9; } message ProjectEnvironmentVariableListMessage { diff --git a/protos/services/yor/clair/v1/clair.proto b/protos/services/yor/clair/v1/clair.proto new file mode 100644 index 00000000..c5fcd0d0 --- /dev/null +++ b/protos/services/yor/clair/v1/clair.proto @@ -0,0 +1,138 @@ +syntax = "proto3"; + +package services.yor.clair.v1; + +import "common/v1/id.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/containerish/OpenRegistry/services/yor/clair/v1;clair"; + +service ClairService { + rpc SubmitManifestToScan(SubmitManifestToScanRequest) returns (SubmitManifestToScanResponse) {} + rpc GetVulnerabilityReport(GetVulnerabilityReportRequest) returns (GetVulnerabilityReportResponse) {} + rpc EnableVulnerabilityScanning(EnableVulnerabilityScanningRequest) returns (EnableVulnerabilityScanningResponse) {} +} + +message EnableVulnerabilityScanningRequest { + common.v1.UUID repository_id = 1; +} + +message EnableVulnerabilityScanningResponse { + string message = 1; +} + +message ClairReportPackage { + string id = 1; + string name = 2; + string version = 3; + string kind = 4; + string arch = 5; + ClairPackageSource source = 6; +} + +message SubmitManifestToScanResponse { + bool success = 1; + string manifest_hash = 2; + string state = 3; + string err = 4; + map packages = 5; + map distributions = 6; + map repository = 7; + map environments = 8; +} + +message ClairDescriptor { + string hash = 1; + string uri = 2; + map headers = 3; +} + +message SubmitManifestToScanRequest { + string hash = 1; +} + +message GetVulnerabilityReportRequest { + string manifest_id = 1; +} + +message ClairIndexManifestRequest { + string hash = 1; + repeated ClairDescriptor layers = 2; +} + +message ClairPackageSource { + string id = 1; + string name = 2; + string version = 3; + string kind = 4; +} + +message ClairPackage { + string id = 1; + string name = 2; + string version = 3; + string kind = 4; + ClairPackageSource source = 5; + string arch = 6; +} + +message ClairDistribution { + string id = 1; + string did = 2; + string name = 3; + string version = 4; + string version_code_name = 5; + string version_id = 6; + string arch = 7; + string cpe = 8; + string pretty_name = 9; +} + +message ClairEnvironmentItem { + string package_db = 1; + string introduced_in = 2; + string distribution_id = 3; + repeated string repository_ids = 4; +} + +message ClairRepository { + string id = 1; +} + +message ClairVulnerability { + string id = 1; + string updater = 2; + string name = 3; + string description = 4; + google.protobuf.Timestamp issued = 5; + string links = 6; + string severity = 7; + string normalized_severity = 8; + ClairPackage package = 9; + ClairDistribution distribution = 10; + ClairRepository repository = 11; + string fixed_in_version = 12; +} + +message ClairEnrichment { + string id = 1; +} + +message ClairVulnerabilityIdList { + repeated string ids = 1; +} + +message GetVulnerabilityReportResponse { + string manifest_hash = 1; + string state = 2; + string err = 3; + bool success = 4; + map packages = 5; + map distributions = 6; + map environments = 7; + map package_vulnerabilities = 8; + ClairEnrichment enrichments = 9; + map repository = 10; + map vulnerabilities = 11; +} diff --git a/registry/v2/blobs.go b/registry/v2/blobs.go index 36048034..253ab891 100644 --- a/registry/v2/blobs.go +++ b/registry/v2/blobs.go @@ -13,7 +13,7 @@ import ( "github.com/labstack/echo/v4" oci_digest "github.com/opencontainers/go-digest" - "github.com/containerish/OpenRegistry/types" + "github.com/containerish/OpenRegistry/store/v1/types" ) func (b *blobs) errorResponse(code, msg string, detail map[string]interface{}) []byte { diff --git a/registry/v2/extensions/analytics.go b/registry/v2/extensions/analytics.go index 828077e8..93b76f7f 100644 --- a/registry/v2/extensions/analytics.go +++ b/registry/v2/extensions/analytics.go @@ -1,6 +1,7 @@ package extensions import ( + "fmt" "net/http" "time" @@ -46,17 +47,31 @@ func (ext *extension) AddRepositoryToFavorites(ctx echo.Context) error { func (ext *extension) RemoveRepositoryFromFavorites(ctx echo.Context) error { ctx.Set(types.HandlerStartTime, time.Now()) - var body FavoriteRepositoryRequest - if err := ctx.Bind(&body); err != nil { + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) + if !ok { + err := fmt.Errorf("missing authentication credentials") + echoErr := ctx.JSON(http.StatusForbidden, echo.Map{ + "error": err.Error(), + }) + ext.logger.Log(ctx, err).Send() + return echoErr + } + + repositoryID, err := uuid.Parse(ctx.Param("repository_id")) + if err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) ext.logger.Log(ctx, err).Send() return echoErr } - defer ctx.Request().Body.Close() - err := ext.store.RemoveRepositoryFromFavorites(ctx.Request().Context(), body.RepositoryID, body.UserID) + body := FavoriteRepositoryRequest{ + RepositoryID: repositoryID, + UserID: user.ID, + } + + err = ext.store.RemoveRepositoryFromFavorites(ctx.Request().Context(), body.RepositoryID, body.UserID) if err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), @@ -71,3 +86,27 @@ func (ext *extension) RemoveRepositoryFromFavorites(ctx echo.Context) error { ext.logger.Log(ctx, nil).Send() return echoErr } + +func (ext *extension) ListFavoriteRepositories(ctx echo.Context) error { + ctx.Set(types.HandlerStartTime, time.Now()) + + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) + if !ok { + err := fmt.Errorf("missing authentication credentials") + echoErr := ctx.JSON(http.StatusForbidden, echo.Map{ + "error": err.Error(), + }) + ext.logger.Log(ctx, err).Send() + return echoErr + } + + repos, err := ext.store.ListFavoriteRepositories(ctx.Request().Context(), user.ID) + if err != nil { + repos = make([]*types.ContainerImageRepository, 0) + } + + echoErr := ctx.JSON(http.StatusOK, repos) + + ext.logger.Log(ctx, nil).Send() + return echoErr +} diff --git a/registry/v2/extensions/catalog_detail.go b/registry/v2/extensions/catalog_detail.go index 0b884f97..8db429d3 100644 --- a/registry/v2/extensions/catalog_detail.go +++ b/registry/v2/extensions/catalog_detail.go @@ -20,6 +20,7 @@ type Extenion interface { GetUserCatalog(ctx echo.Context) error AddRepositoryToFavorites(ctx echo.Context) error RemoveRepositoryFromFavorites(ctx echo.Context) error + ListFavoriteRepositories(ctx echo.Context) error } type extension struct { @@ -198,15 +199,21 @@ func (ext *extension) PublicCatalog(ctx echo.Context) error { repositories, total, err := ext.store.GetPublicRepositories(ctx.Request().Context(), pageSize, offset) if err != nil { - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), }) + + ext.logger.Log(ctx, err).Send() + return echoErr } - return ctx.JSON(http.StatusOK, echo.Map{ + echoErr := ctx.JSON(http.StatusOK, echo.Map{ "repositories": repositories, "total": total, }) + + ext.logger.Log(ctx, nil).Send() + return echoErr } func (ext *extension) GetUserCatalog(ctx echo.Context) error { @@ -259,23 +266,27 @@ func (ext *extension) GetUserCatalog(ctx echo.Context) error { visibility = types.RepositoryVisibilityPrivate } - repositories, total, err := ext. - store. - GetUserRepositories( - ctx.Request().Context(), - user.ID, - visibility, - pageSize, - offset, - ) + repositories, total, err := ext.store.GetUserRepositories( + ctx.Request().Context(), + user.ID, + visibility, + pageSize, + offset, + ) if err != nil { - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), }) + + ext.logger.Log(ctx, err).Send() + return echoErr } - return ctx.JSON(http.StatusOK, echo.Map{ + echoErr := ctx.JSON(http.StatusOK, echo.Map{ "repositories": repositories, "total": total, }) + + ext.logger.Log(ctx, nil).Send() + return echoErr } diff --git a/registry/v2/extensions/private_images.go b/registry/v2/extensions/private_images.go index 189a0548..38a56fb6 100644 --- a/registry/v2/extensions/private_images.go +++ b/registry/v2/extensions/private_images.go @@ -1,7 +1,6 @@ package extensions import ( - "encoding/json" "net/http" "time" @@ -14,21 +13,28 @@ func (ext *extension) ChangeContainerImageVisibility(ctx echo.Context) error { var body types.ContainerImageVisibilityChangeRequest - if err := json.NewDecoder(ctx.Request().Body).Decode(&body); err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + if err := ctx.Bind(&body); err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": "invalid request body", }) + + ext.logger.Log(ctx, err).Send() + return echoErr } defer ctx.Request().Body.Close() - err := ext.store.SetContainerImageVisibility(ctx.Request().Context(), body.ImageManifestUUID, body.Visibility) + err := ext.store.SetContainerImageVisibility(ctx.Request().Context(), body.RepositoryID, body.Visibility) if err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) + ext.logger.Log(ctx, err).Send() + return echoErr } - return ctx.JSON(http.StatusOK, echo.Map{ + echoErr := ctx.JSON(http.StatusOK, echo.Map{ "message": "container image visibility mode changed successfully", }) + ext.logger.Log(ctx, nil).Send() + return echoErr } diff --git a/registry/v2/registry.go b/registry/v2/registry.go index ef5c22e8..77b008ee 100644 --- a/registry/v2/registry.go +++ b/registry/v2/registry.go @@ -15,6 +15,7 @@ import ( "time" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/google/uuid" "github.com/labstack/echo/v4" oci_digest "github.com/opencontainers/go-digest" img_spec_v1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -23,9 +24,8 @@ import ( "github.com/containerish/OpenRegistry/config" dfsImpl "github.com/containerish/OpenRegistry/dfs" store_v2 "github.com/containerish/OpenRegistry/store/v1/registry" - types_v2 "github.com/containerish/OpenRegistry/store/v1/types" + "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/telemetry" - "github.com/containerish/OpenRegistry/types" ) func NewRegistry( @@ -87,8 +87,9 @@ func (r *registry) ManifestExists(ctx echo.Context) error { } errMsg := common.RegistryErrorResponse(RegistryErrorCodeManifestBlobUnknown, err.Error(), details) - r.logger.Log(ctx, fmt.Errorf("%s", errMsg)).Send() - return ctx.NoContent(http.StatusNotFound) + echoErr := ctx.JSONBlob(http.StatusNotFound, errMsg.Bytes()) + r.logger.Log(ctx, errMsg).Send() + return echoErr } ctx.Response().Header().Set("Content-Length", fmt.Sprintf("%d", manifest.Size)) @@ -360,7 +361,7 @@ func (r *registry) MonolithicUpload(ctx echo.Context) error { return echoErr } - layerV2 := &types_v2.ContainerImageLayer{ + layerV2 := &types.ContainerImageLayer{ MediaType: ctx.Request().Header.Get("content-type"), Digest: imageDigest, DFSLink: dfsLink, @@ -552,7 +553,7 @@ func (r *registry) MonolithicPut(ctx echo.Context) error { return echoErr } - layer := &types_v2.ContainerImageLayer{ + layer := &types.ContainerImageLayer{ CreatedAt: time.Now(), ID: layerKey, Digest: digest, @@ -683,7 +684,7 @@ func (r *registry) CompleteUpload(ctx echo.Context) error { return echoErr } - layer := &types_v2.ContainerImageLayer{ + layer := &types.ContainerImageLayer{ MediaType: ctx.Request().Header.Get("content-type"), Digest: digest, DFSLink: dfsLink, @@ -766,17 +767,17 @@ func (r *registry) PushManifest(ctx echo.Context) error { } - repository = &types_v2.ContainerImageRepository{ + repository = &types.ContainerImageRepository{ CreatedAt: time.Now(), OwnerID: user.ID, ID: repositoryID, Name: strings.Split(namespace, "/")[1], - Visibility: types_v2.RepositoryVisibilityPrivate, + Visibility: types.RepositoryVisibilityPrivate, } // IPFS P2P repositories are public - if user.Username == types_v2.SystemUsernameIPFS { - repository.Visibility = types_v2.RepositoryVisibilityPublic + if user.Username == types.SystemUsernameIPFS { + repository.Visibility = types.RepositoryVisibilityPublic } idErr = r.store.CreateRepository(ctx.Request().Context(), repository) @@ -793,10 +794,13 @@ func (r *registry) PushManifest(ctx echo.Context) error { buf := &bytes.Buffer{} _, err = io.Copy(buf, ctx.Request().Body) if err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), "message": "failed in push manifest while io Copy", }) + + r.logger.Log(ctx, nil).Send() + return echoErr } defer ctx.Request().Body.Close() @@ -812,7 +816,7 @@ func (r *registry) PushManifest(ctx echo.Context) error { return echoErr } - manifest := types_v2.ImageManifest{ + manifest := types.ImageManifest{ CreatedAt: time.Now(), ID: uuid, RepositoryID: repository.ID, @@ -884,7 +888,7 @@ func (r *registry) PushManifest(ctx echo.Context) error { func (r *registry) setPushManifestHaeders( ctx echo.Context, namespace, ref, digest string, - manifest *types_v2.ImageManifest, + manifest *types.ImageManifest, ) { locationHeader := fmt.Sprintf("%s/v2/%s/manifests/%s", r.config.Endpoint(), namespace, ref) ctx.Response().Header().Set("Location", locationHeader) @@ -1003,37 +1007,60 @@ func (r *registry) ApiVersion(ctx echo.Context) error { func (r *registry) GetImageNamespace(ctx echo.Context) error { ctx.Set(types.HandlerStartTime, time.Now()) + userId := uuid.NullUUID{}.UUID + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) + if ok { + userId = user.ID + } + searchQuery := ctx.QueryParam("search_query") if searchQuery == "" { - return ctx.JSON(http.StatusBadRequest, echo.Map{ - "error": "search query must not be empty", + errMsg := fmt.Errorf("search query must not be empty") + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": errMsg.Error(), }) + + r.logger.Log(ctx, errMsg).Send() + return echoErr + } + + var visibility types.RepositoryVisibility + if ctx.QueryParam("public") == "true" { + visibility = types.RepositoryVisibilityPublic } - result, err := r.store.GetImageNamespace(ctx.Request().Context(), searchQuery) + + result, err := r.store.GetImageNamespace(ctx.Request().Context(), searchQuery, visibility, userId) if err != nil { - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), "message": "error getting image namespace", }) + + r.logger.Log(ctx, err).Send() + return echoErr } // empty namespace to pull full catalog list total, err := r.store.GetCatalogCount(ctx.Request().Context(), "") if err != nil { - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), "message": "ERR_GET_CATALOG_COUNT", }) + r.logger.Log(ctx, err).Send() + return echoErr } - return ctx.JSON(http.StatusOK, echo.Map{ + echoErr := ctx.JSON(http.StatusOK, echo.Map{ "repositories": result, "total": total, }) + r.logger.Log(ctx, nil).Send() + return echoErr } -func (r *registry) GetUserFromCtx(ctx echo.Context) (*types_v2.User, error) { - user, ok := ctx.Get(string(types_v2.UserContextKey)).(*types_v2.User) +func (r *registry) GetUserFromCtx(ctx echo.Context) (*types.User, error) { + user, ok := ctx.Get(string(types.UserContextKey)).(*types.User) if !ok { return nil, fmt.Errorf("ERR_USER_NOT_PRESENT_IN_REQUEST_CTX") } @@ -1041,8 +1068,8 @@ func (r *registry) GetUserFromCtx(ctx echo.Context) (*types_v2.User, error) { return user, nil } -func (r *registry) GetRepositoryFromCtx(ctx echo.Context) *types_v2.ContainerImageRepository { - if repository, ok := ctx.Get(string(types_v2.UserRepositoryContextKey)).(*types_v2.ContainerImageRepository); ok { +func (r *registry) GetRepositoryFromCtx(ctx echo.Context) *types.ContainerImageRepository { + if repository, ok := ctx.Get(string(types.UserRepositoryContextKey)).(*types.ContainerImageRepository); ok { return repository } return nil diff --git a/registry/v2/repository.go b/registry/v2/repository.go index b2bfcbd8..3c8ff7b1 100644 --- a/registry/v2/repository.go +++ b/registry/v2/repository.go @@ -31,18 +31,24 @@ func (r *registry) CreateRepository(ctx echo.Context) error { var body CreateRepositoryRequest err := json.NewDecoder(ctx.Request().Body).Decode(&body) if err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), "message": "error parsing request input", }) + + r.logger.Log(ctx, err).Send() + return echoErr } defer ctx.Request().Body.Close() if err = body.Validate(); err != nil { - return ctx.JSON(http.StatusBadRequest, echo.Map{ + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), "message": "invalid request body", }) + + r.logger.Log(ctx, err).Send() + return echoErr } user := ctx.Get(string(types.UserContextKey)).(*types.User) @@ -55,13 +61,19 @@ func (r *registry) CreateRepository(ctx echo.Context) error { OwnerID: user.ID, } if err := r.store.CreateRepository(ctx.Request().Context(), repository); err != nil { - return ctx.JSON(http.StatusBadGateway, echo.Map{ + echoErr := ctx.JSON(http.StatusBadGateway, echo.Map{ "error": err.Error(), "message": "error creating repository", }) + + r.logger.Log(ctx, err).Send() + return echoErr } - return ctx.JSON(http.StatusCreated, echo.Map{ + echoErr := ctx.JSON(http.StatusCreated, echo.Map{ "message": "repository created successfully", }) + + r.logger.Log(ctx, nil).Send() + return echoErr } diff --git a/router/github.go b/router/github.go index 438b2164..7e39aac0 100644 --- a/router/github.go +++ b/router/github.go @@ -2,7 +2,15 @@ package router import ( "fmt" + "net" "net/http" + "strings" + + "github.com/fatih/color" + "github.com/labstack/echo/v4" + "github.com/rs/cors" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" "github.com/containerish/OpenRegistry/config" github_actions_server "github.com/containerish/OpenRegistry/services/kon/github_actions/v1/server" @@ -10,21 +18,19 @@ import ( "github.com/containerish/OpenRegistry/telemetry" "github.com/containerish/OpenRegistry/vcs" "github.com/containerish/OpenRegistry/vcs/github" - "github.com/fatih/color" - "github.com/labstack/echo/v4" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" ) func RegisterGitHubRoutes( router *echo.Group, - cfg *config.Integration, + cfg *config.GithubIntegration, env config.Environment, authConfig *config.Auth, logger telemetry.Logger, allowedEndpoints []string, usersStore vcs.VCSStore, automationStore automation.BuildAutomationStore, + allowedOrigins []string, + registryEndpoint string, ) { if cfg != nil && cfg.Enabled { ghAppApi := github.NewGithubApp( @@ -33,6 +39,7 @@ func RegisterGitHubRoutes( logger, allowedEndpoints, env, + registryEndpoint, ) ghAppApi.RegisterRoutes(router) @@ -44,10 +51,35 @@ func RegisterGitHubRoutes( usersStore, ) go func() { - hostPort := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) - color.Green("connect-go gRPC running on: %s", hostPort) - if err := http.ListenAndServe(hostPort, h2c.NewHandler(githubMux, &http2.Server{})); err != nil { - color.Red("gRPC listen error: %s", err) + addr := net.JoinHostPort(cfg.Host, fmt.Sprintf("%d", cfg.Port)) + color.Green("connectrpc GitHub Automation gRPC service running on: %s", addr) + ghCors := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowOriginFunc: func(origin string) bool { + return strings.HasSuffix(origin, "openregistry.dev") || + strings.HasSuffix(origin, "cntr.sh") || + strings.HasSuffix(origin, "openregistry-web.pages.dev") || + strings.Contains(origin, "localhost") + }, + AllowedMethods: []string{ + http.MethodOptions, http.MethodGet, http.MethodPost, + }, + AllowedHeaders: []string{ + "Origin", + "Content-Type", + "Authorization", + "Connect-Protocol-Version", + "Connect-Timeout-Ms", + "Grpc-Timeout", + "X-Grpc-Web", + "X-User-Agent", + }, + AllowCredentials: true, + Debug: true, + }) + handler := ghCors.Handler(h2c.NewHandler(githubMux, &http2.Server{})) + if err := http.ListenAndServe(addr, handler); err != nil { + color.Red("connectrpc GitHub Automation service listen error: %s", err) } }() } diff --git a/router/helpers.go b/router/helpers.go index 0c6351ae..49fef37c 100644 --- a/router/helpers.go +++ b/router/helpers.go @@ -19,7 +19,7 @@ func RegisterAuthRoutes(authRouter *echo.Group, authSvc auth.Authentication) { authRouter.Add(http.MethodGet, "/sessions/me", authSvc.ReadUserWithSession) authRouter.Add(http.MethodDelete, "/sessions", authSvc.ExpireSessions) authRouter.Add(http.MethodGet, "/renew", authSvc.RenewAccessToken) - authRouter.Add(http.MethodPost, "/reset-password", authSvc.ResetPassword, authSvc.JWT()) + authRouter.Add(http.MethodPost, "/reset-password", authSvc.ResetPassword, authSvc.JWTRest()) authRouter.Add(http.MethodPost, "/reset-forgotten-password", authSvc.ResetForgottenPassword, authSvc.JWT()) authRouter.Add(http.MethodGet, "/forgot-password", authSvc.ForgotPassword) } diff --git a/router/middlewares.go b/router/middlewares.go index 55fd2ec7..114a7c08 100644 --- a/router/middlewares.go +++ b/router/middlewares.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "regexp" + "strings" "github.com/containerish/OpenRegistry/common" "github.com/containerish/OpenRegistry/registry/v2" @@ -20,12 +21,12 @@ func registryNamespaceValidator(logger telemetry.Logger) echo.MiddlewareFunc { return func(handler echo.HandlerFunc) echo.HandlerFunc { return func(ctx echo.Context) error { // we skip the /v2/ path since it isn't a namespaced path - if ctx.Request().URL.Path == "/v2/" { + if ctx.Request().URL.Path == "/v2/" || strings.HasPrefix(ctx.Request().URL.Path, "/v2/ext/") { return handler(ctx) } namespace := ctx.Param("username") + "/" + ctx.Param("imagename") - if namespace != "/" && !nsRegex.MatchString(namespace) { + if !nsRegex.MatchString(namespace) { registryErr := common.RegistryErrorResponse( registry.RegistryErrorCodeNameInvalid, "invalid user namespace", diff --git a/router/orgmode.go b/router/orgmode.go index bd6d50a8..f254dbc7 100644 --- a/router/orgmode.go +++ b/router/orgmode.go @@ -8,6 +8,7 @@ import ( func RegisterOrgModeRoutes(router *echo.Group, svc orgmode.OrgMode) { router.POST("/migrate", svc.MigrateToOrg) router.POST("/users", svc.AddUserToOrg) + router.GET("/users", svc.GetOrgUsers) router.PATCH("/permissions/users", svc.UpdateUserPermissions) router.DELETE("/permissions/users/:orgId/:userId", svc.RemoveUserFromOrg) } diff --git a/router/registry.go b/router/registry.go index 8352baea..41d84df5 100644 --- a/router/registry.go +++ b/router/registry.go @@ -105,5 +105,6 @@ func RegisterExtensionsRoutes( group.Add(http.MethodPost, ChangeRepositoryVisibility, ext.ChangeContainerImageVisibility, middlewares...) group.Add(http.MethodPost, CreateRepository, reg.CreateRepository, middlewares...) group.Add(http.MethodPost, RepositoryFavorites, ext.AddRepositoryToFavorites, middlewares...) - group.Add(http.MethodDelete, RepositoryFavorites, ext.RemoveRepositoryFromFavorites, middlewares...) + group.Add(http.MethodGet, RepositoryFavorites, ext.ListFavoriteRepositories, middlewares...) + group.Add(http.MethodDelete, RemoveRepositoryFavorites, ext.RemoveRepositoryFromFavorites, middlewares...) } diff --git a/router/route_names.go b/router/route_names.go index bdba115a..ba10fa50 100644 --- a/router/route_names.go +++ b/router/route_names.go @@ -75,4 +75,5 @@ const ( ChangeRepositoryVisibility = Ext + "/repository/visibility" CreateRepository = Ext + "/repository/create" RepositoryFavorites = Ext + "/repository/favorites" + RemoveRepositoryFavorites = Ext + "/repository/favorites/:repository_id" ) diff --git a/router/router.go b/router/router.go index abb5ba4f..dfcda3db 100644 --- a/router/router.go +++ b/router/router.go @@ -9,6 +9,7 @@ import ( "github.com/containerish/OpenRegistry/auth" auth_server "github.com/containerish/OpenRegistry/auth/server" "github.com/containerish/OpenRegistry/config" + "github.com/containerish/OpenRegistry/dfs" "github.com/containerish/OpenRegistry/orgmode" "github.com/containerish/OpenRegistry/registry/v2" "github.com/containerish/OpenRegistry/registry/v2/extensions" @@ -37,6 +38,7 @@ func Register( registryStore registry_store.RegistryStore, usersStore users_store.UserStore, automationStore automation.BuildAutomationStore, + dfs dfs.DFS, ) *echo.Echo { e := setDefaultEchoOptions(cfg.WebAppConfig, healthCheckApi) @@ -44,7 +46,7 @@ func Register( githubRouter := e.Group("/github") authRouter := e.Group(Auth) webauthnRouter := e.Group(Webauthn) - orgModeRouter := e.Group("/org", authApi.JWTRest(), orgModeApi.AllowOrgAdmin()) + orgModeRouter := baseAPIRouter.Group("/org", authApi.JWTRest(), orgModeApi.AllowOrgAdmin()) ociRouter := e.Group(V2, registryNamespaceValidator(logger), authApi.BasicAuth(), authApi.JWT()) userApiRouter := baseAPIRouter.Group("/users", authApi.JWTRest()) nsRouter := ociRouter.Group(Namespace, authApi.RepositoryPermissionsMiddleware()) @@ -58,9 +60,18 @@ func Register( RegisterUserRoutes(userApiRouter, usersApi) RegisterNSRoutes(nsRouter, registryApi, registryStore, logger) RegisterAuthRoutes(authRouter, authApi) - RegisterExtensionsRoutes(ociRouter, registryApi, extensionsApi) + RegisterExtensionsRoutes(ociRouter, registryApi, extensionsApi, authApi.JWTRest()) RegisterWebauthnRoutes(webauthnRouter, webauthnApi) RegisterOrgModeRoutes(orgModeRouter, orgModeApi) + RegisterVulnScaningRoutes( + usersStore, + cfg.Integrations.GetClairConfig(), + &cfg.Registry.Auth, + logger, + registryStore.GetLayersLinksForManifest, + dfs.GeneratePresignedURL, + cfg.WebAppConfig.AllowedEndpoints, + ) if cfg.Integrations.GetGithubConfig() != nil && cfg.Integrations.GetGithubConfig().Enabled { RegisterGitHubRoutes( @@ -72,11 +83,13 @@ func Register( cfg.WebAppConfig.AllowedEndpoints, usersStore, automationStore, + cfg.WebAppConfig.AllowedEndpoints, + cfg.Endpoint(), ) } //catch-all will redirect user back to the web interface - e.Add(http.MethodGet, "/", func(ctx echo.Context) error { + e.Add(http.MethodGet, "", func(ctx echo.Context) error { webAppURL := "" for _, url := range cfg.WebAppConfig.AllowedEndpoints { if url == ctx.Request().Header.Get("Origin") { @@ -89,7 +102,18 @@ func Register( webAppURL = ctx.Request().Header.Get("Origin") } - return ctx.Redirect(http.StatusTemporaryRedirect, webAppURL) + if webAppURL != "" { + echoErr := ctx.Redirect(http.StatusTemporaryRedirect, webAppURL) + logger.Log(ctx, nil).Send() + return echoErr + } + + echoErr := ctx.JSON(http.StatusOK, echo.Map{ + "API": "running", + }) + + logger.Log(ctx, nil).Send() + return echoErr }) return e diff --git a/router/users.go b/router/users.go index e8595753..487252ad 100644 --- a/router/users.go +++ b/router/users.go @@ -7,6 +7,8 @@ import ( "github.com/labstack/echo/v4" ) -func RegisterUserRoutes(router *echo.Group, api users.UserApi) { - router.Add(http.MethodGet, "/search", api.SearchUsers) +func RegisterUserRoutes(router *echo.Group, api users.UserApi, middlewares ...echo.MiddlewareFunc) { + router.Add(http.MethodGet, "/search", api.SearchUsers, middlewares...) + router.Add(http.MethodPost, "/token", api.CreateUserToken, middlewares...) + router.Add(http.MethodGet, "/token", api.ListUserToken, middlewares...) } diff --git a/router/vuln_scanning_routes.go b/router/vuln_scanning_routes.go new file mode 100644 index 00000000..cb01bf0d --- /dev/null +++ b/router/vuln_scanning_routes.go @@ -0,0 +1,72 @@ +package router + +import ( + "fmt" + "net" + "net/http" + "strings" + + "github.com/fatih/color" + "github.com/rs/cors" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + + "github.com/containerish/OpenRegistry/config" + "github.com/containerish/OpenRegistry/services/yor/clair/v1/server" + "github.com/containerish/OpenRegistry/store/v1/users" + "github.com/containerish/OpenRegistry/telemetry" +) + +func RegisterVulnScaningRoutes( + userStore users.UserStore, + clairConfig *config.ClairIntegration, + authConfig *config.Auth, + logger telemetry.Logger, + layerLinkReader server.LayerLinkReader, + prePresignedURLGenerator server.PresignedURLGenerator, + allowedOrigins []string, +) { + if clairConfig != nil && clairConfig.Enabled { + clairApi := server.NewClairClient( + userStore, + clairConfig, + authConfig, + logger, + layerLinkReader, + prePresignedURLGenerator, + ) + go func() { + addr := net.JoinHostPort(clairConfig.Host, fmt.Sprintf("%d", clairConfig.Port)) + vulnScanningCors := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowOriginFunc: func(origin string) bool { + return strings.HasSuffix(origin, "openregistry.dev") || + strings.HasSuffix(origin, "cntr.sh") || + strings.HasSuffix(origin, "openregistry-web.pages.dev") || + strings.Contains(origin, "localhost") + }, + AllowedMethods: []string{ + http.MethodOptions, http.MethodGet, http.MethodPost, + }, + AllowedHeaders: []string{ + "Origin", + "Content-Type", + "Authorization", + "Connect-Protocol-Version", + "Connect-Timeout-Ms", + "Grpc-Timeout", + "X-Grpc-Web", + "X-User-Agent", + }, + AllowCredentials: true, + Debug: true, + }) + + handler := h2c.NewHandler(vulnScanningCors.Handler(clairApi), &http2.Server{}) + color.Green("connectrpc Clair gRPC service running on: %s", addr) + if err := http.ListenAndServe(addr, handler); err != nil { + color.Red("connectrpc listen error: %s", err) + } + }() + } +} diff --git a/scripts/load_dummy_users.sh b/scripts/load_dummy_users.sh new file mode 100644 index 00000000..83325c8e --- /dev/null +++ b/scripts/load_dummy_users.sh @@ -0,0 +1,14 @@ +#!/bin/sh + + curl -sSL -XPOST -d '{"email": "me@example.com", "username": "johndoe", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "asta@example.com", "username": "asta", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "yuno@example.com", "username": "yuno", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "noelle@example.com", "username": "noelle", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "mimosa@example.com", "username": "mimosa", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "klaus@example.com", "username": "klaus", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "finral@example.com", "username": "finral", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "yami@example.com", "username": "yami", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "vangeance@example.com", "username": "vangeance", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "leopold@example.com", "username": "leopold", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "vanessa@example.com", "username": "vanessa", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq + curl -sSL -XPOST -d '{"email": "charmy@example.com", "username": "charmy", "password": "Qwerty@123"}' 'http://localhost:5000/auth/signup' | jq diff --git a/services/kon/github_actions/v1/build_job.pb.go b/services/kon/github_actions/v1/build_job.pb.go index 7a593fa1..65943548 100644 --- a/services/kon/github_actions/v1/build_job.pb.go +++ b/services/kon/github_actions/v1/build_job.pb.go @@ -917,11 +917,11 @@ var file_services_kon_github_actions_v1_build_job_proto_rawDesc = []byte{ 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6a, 0x6f, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, - 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x64, 0x2e, + 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x64, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x90, 0x01, 0x0a, 0x1a, 0x42, 0x75, 0x6c, 0x6b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, diff --git a/services/kon/github_actions/v1/build_project.pb.go b/services/kon/github_actions/v1/build_project.pb.go index b24e236d..ebf5e271 100644 --- a/services/kon/github_actions/v1/build_project.pb.go +++ b/services/kon/github_actions/v1/build_project.pb.go @@ -119,11 +119,12 @@ type CreateProjectRequest struct { Id *v1.UUID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` OwnerId *v1.UUID `protobuf:"bytes,2,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` - ProjectName string `protobuf:"bytes,3,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` - ProductionBranch string `protobuf:"bytes,4,opt,name=production_branch,json=productionBranch,proto3" json:"production_branch,omitempty"` - BuildSettings *ProjectBuildSettingsMessage `protobuf:"bytes,5,opt,name=build_settings,json=buildSettings,proto3" json:"build_settings,omitempty"` - EnvironmentVariables *ProjectEnvironmentVariableListMessage `protobuf:"bytes,6,opt,name=environment_variables,json=environmentVariables,proto3" json:"environment_variables,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + RepositoryId *v1.UUID `protobuf:"bytes,3,opt,name=repository_id,json=repositoryId,proto3" json:"repository_id,omitempty"` + ProjectName string `protobuf:"bytes,4,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` + ProductionBranch string `protobuf:"bytes,5,opt,name=production_branch,json=productionBranch,proto3" json:"production_branch,omitempty"` + BuildSettings *ProjectBuildSettingsMessage `protobuf:"bytes,6,opt,name=build_settings,json=buildSettings,proto3" json:"build_settings,omitempty"` + EnvironmentVariables *ProjectEnvironmentVariableListMessage `protobuf:"bytes,7,opt,name=environment_variables,json=environmentVariables,proto3" json:"environment_variables,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` } func (x *CreateProjectRequest) Reset() { @@ -170,6 +171,13 @@ func (x *CreateProjectRequest) GetOwnerId() *v1.UUID { return nil } +func (x *CreateProjectRequest) GetRepositoryId() *v1.UUID { + if x != nil { + return x.RepositoryId + } + return nil +} + func (x *CreateProjectRequest) GetProjectName() string { if x != nil { return x.ProjectName @@ -352,6 +360,8 @@ type GetProjectResponse struct { EnvironmentVariables *ProjectEnvironmentVariableListMessage `protobuf:"bytes,5,opt,name=environment_variables,json=environmentVariables,proto3" json:"environment_variables,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` OwnerId *v1.UUID `protobuf:"bytes,7,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` + RepositoryId *v1.UUID `protobuf:"bytes,8,opt,name=repository_id,json=repositoryId,proto3" json:"repository_id,omitempty"` + RepositoryName string `protobuf:"bytes,9,opt,name=repository_name,json=repositoryName,proto3" json:"repository_name,omitempty"` } func (x *GetProjectResponse) Reset() { @@ -433,6 +443,20 @@ func (x *GetProjectResponse) GetOwnerId() *v1.UUID { return nil } +func (x *GetProjectResponse) GetRepositoryId() *v1.UUID { + if x != nil { + return x.RepositoryId + } + return nil +} + +func (x *GetProjectResponse) GetRepositoryName() string { + if x != nil { + return x.RepositoryName + } + return "" +} + type ProjectEnvironmentVariableListMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -661,10 +685,10 @@ var file_services_kon_github_actions_v1_build_project_proto_rawDesc = []byte{ 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, - 0x2f, 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x13, 0x4c, 0x69, 0x73, + 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, + 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x41, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, @@ -675,157 +699,166 @@ var file_services_kon_github_actions_v1_build_project_proto_rawDesc = []byte{ 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x22, 0xce, 0x03, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, + 0x65, 0x63, 0x74, 0x73, 0x22, 0x84, 0x04, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, - 0x44, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, - 0x11, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x72, 0x61, 0x6e, - 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x62, 0x0a, 0x0e, 0x62, 0x75, - 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, - 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x7a, - 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, - 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, + 0x44, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, + 0x49, 0x44, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, + 0x12, 0x62, 0x0a, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x12, 0x7a, 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, + 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, + 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, + 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, + 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, + 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x34, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, + 0x64, 0x22, 0x37, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, 0x31, 0x0a, 0x15, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xab, 0x04, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, + 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x62, 0x0a, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x34, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, 0x37, 0x0a, 0x14, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, - 0x52, 0x02, 0x69, 0x64, 0x22, 0x31, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xcc, 0x03, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, - 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, - 0x62, 0x0a, 0x0e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x7a, 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, - 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, - 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72, - 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, - 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x08, 0x6f, 0x77, - 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x07, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x98, 0x01, 0x0a, 0x25, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, - 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x6f, 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x3a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x14, 0x65, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x22, 0x62, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, - 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0x84, 0x01, 0x0a, 0x1b, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, - 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x54, 0x6f, 0x6f, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x78, 0x65, 0x63, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x66, 0x6b, - 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x77, 0x6f, 0x72, 0x66, 0x6b, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x52, 0x0a, 0x15, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, - 0x32, 0x91, 0x04, 0x0a, 0x1b, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x34, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, - 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x75, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x31, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x32, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, - 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x34, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x7a, 0x0a, 0x15, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x33, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x73, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x2a, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x55, 0x49, 0x44, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x0d, + 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x55, 0x49, 0x44, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x98, 0x01, 0x0a, 0x25, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x6f, 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x22, 0x62, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22, 0x84, 0x01, 0x0a, 0x1b, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x78, 0x65, + 0x63, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x65, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x23, 0x0a, 0x0d, + 0x77, 0x6f, 0x72, 0x66, 0x6b, 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, 0x72, 0x66, 0x6b, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x6c, + 0x65, 0x22, 0x52, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, + 0x44, 0x52, 0x02, 0x69, 0x64, 0x32, 0x91, 0x04, 0x0a, 0x1b, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x34, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x75, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x12, 0x31, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, + 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x0d, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x34, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, + 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x0c, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x33, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x42, 0xa5, 0x02, 0x0a, 0x22, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x69, 0x73, 0x68, 0x2f, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, - 0x6b, 0x6f, 0x6e, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x53, 0x4b, 0x47, 0xaa, 0x02, 0x1d, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x6f, 0x6e, 0x2e, 0x47, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x1d, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5c, 0x4b, 0x6f, 0x6e, 0x5c, 0x47, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x29, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5c, 0x4b, 0x6f, 0x6e, 0x5c, 0x47, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x3a, 0x3a, 0x4b, 0x6f, 0x6e, 0x3a, 0x3a, 0x47, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x34, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, + 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xa5, 0x02, 0x0a, 0x22, 0x63, 0x6f, + 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x6b, 0x6f, 0x6e, 0x2e, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, + 0x42, 0x11, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x69, 0x73, 0x68, 0x2f, 0x4f, + 0x70, 0x65, 0x6e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2f, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2f, 0x6b, 0x6f, 0x6e, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x53, + 0x4b, 0x47, 0xaa, 0x02, 0x1d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x6f, + 0x6e, 0x2e, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x56, 0x31, 0xca, 0x02, 0x1d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5c, 0x4b, 0x6f, + 0x6e, 0x5c, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x29, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5c, 0x4b, 0x6f, + 0x6e, 0x5c, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5c, + 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x3a, 0x4b, 0x6f, 0x6e, 0x3a, 0x3a, + 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -861,31 +894,33 @@ var file_services_kon_github_actions_v1_build_project_proto_depIdxs = []int32{ 6, // 1: services.kon.github_actions.v1.ListProjectsResponse.projects:type_name -> services.kon.github_actions.v1.GetProjectResponse 11, // 2: services.kon.github_actions.v1.CreateProjectRequest.id:type_name -> common.v1.UUID 11, // 3: services.kon.github_actions.v1.CreateProjectRequest.owner_id:type_name -> common.v1.UUID - 9, // 4: services.kon.github_actions.v1.CreateProjectRequest.build_settings:type_name -> services.kon.github_actions.v1.ProjectBuildSettingsMessage - 7, // 5: services.kon.github_actions.v1.CreateProjectRequest.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage - 12, // 6: services.kon.github_actions.v1.CreateProjectRequest.created_at:type_name -> google.protobuf.Timestamp - 11, // 7: services.kon.github_actions.v1.GetProjectRequest.id:type_name -> common.v1.UUID - 11, // 8: services.kon.github_actions.v1.DeleteProjectRequest.id:type_name -> common.v1.UUID - 11, // 9: services.kon.github_actions.v1.GetProjectResponse.id:type_name -> common.v1.UUID - 9, // 10: services.kon.github_actions.v1.GetProjectResponse.build_settings:type_name -> services.kon.github_actions.v1.ProjectBuildSettingsMessage - 7, // 11: services.kon.github_actions.v1.GetProjectResponse.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage - 12, // 12: services.kon.github_actions.v1.GetProjectResponse.created_at:type_name -> google.protobuf.Timestamp - 11, // 13: services.kon.github_actions.v1.GetProjectResponse.owner_id:type_name -> common.v1.UUID - 8, // 14: services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariable - 11, // 15: services.kon.github_actions.v1.CreateProjectResponse.id:type_name -> common.v1.UUID - 2, // 16: services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject:input_type -> services.kon.github_actions.v1.CreateProjectRequest - 3, // 17: services.kon.github_actions.v1.GitHubActionsProjectService.GetProject:input_type -> services.kon.github_actions.v1.GetProjectRequest - 4, // 18: services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject:input_type -> services.kon.github_actions.v1.DeleteProjectRequest - 0, // 19: services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects:input_type -> services.kon.github_actions.v1.ListProjectsRequest - 10, // 20: services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject:output_type -> services.kon.github_actions.v1.CreateProjectResponse - 6, // 21: services.kon.github_actions.v1.GitHubActionsProjectService.GetProject:output_type -> services.kon.github_actions.v1.GetProjectResponse - 5, // 22: services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject:output_type -> services.kon.github_actions.v1.DeleteProjectResponse - 1, // 23: services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects:output_type -> services.kon.github_actions.v1.ListProjectsResponse - 20, // [20:24] is the sub-list for method output_type - 16, // [16:20] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 11, // 4: services.kon.github_actions.v1.CreateProjectRequest.repository_id:type_name -> common.v1.UUID + 9, // 5: services.kon.github_actions.v1.CreateProjectRequest.build_settings:type_name -> services.kon.github_actions.v1.ProjectBuildSettingsMessage + 7, // 6: services.kon.github_actions.v1.CreateProjectRequest.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage + 12, // 7: services.kon.github_actions.v1.CreateProjectRequest.created_at:type_name -> google.protobuf.Timestamp + 11, // 8: services.kon.github_actions.v1.GetProjectRequest.id:type_name -> common.v1.UUID + 11, // 9: services.kon.github_actions.v1.DeleteProjectRequest.id:type_name -> common.v1.UUID + 11, // 10: services.kon.github_actions.v1.GetProjectResponse.id:type_name -> common.v1.UUID + 9, // 11: services.kon.github_actions.v1.GetProjectResponse.build_settings:type_name -> services.kon.github_actions.v1.ProjectBuildSettingsMessage + 7, // 12: services.kon.github_actions.v1.GetProjectResponse.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage + 12, // 13: services.kon.github_actions.v1.GetProjectResponse.created_at:type_name -> google.protobuf.Timestamp + 11, // 14: services.kon.github_actions.v1.GetProjectResponse.owner_id:type_name -> common.v1.UUID + 11, // 15: services.kon.github_actions.v1.GetProjectResponse.repository_id:type_name -> common.v1.UUID + 8, // 16: services.kon.github_actions.v1.ProjectEnvironmentVariableListMessage.environment_variables:type_name -> services.kon.github_actions.v1.ProjectEnvironmentVariable + 11, // 17: services.kon.github_actions.v1.CreateProjectResponse.id:type_name -> common.v1.UUID + 2, // 18: services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject:input_type -> services.kon.github_actions.v1.CreateProjectRequest + 3, // 19: services.kon.github_actions.v1.GitHubActionsProjectService.GetProject:input_type -> services.kon.github_actions.v1.GetProjectRequest + 4, // 20: services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject:input_type -> services.kon.github_actions.v1.DeleteProjectRequest + 0, // 21: services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects:input_type -> services.kon.github_actions.v1.ListProjectsRequest + 10, // 22: services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject:output_type -> services.kon.github_actions.v1.CreateProjectResponse + 6, // 23: services.kon.github_actions.v1.GitHubActionsProjectService.GetProject:output_type -> services.kon.github_actions.v1.GetProjectResponse + 5, // 24: services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject:output_type -> services.kon.github_actions.v1.DeleteProjectResponse + 1, // 25: services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects:output_type -> services.kon.github_actions.v1.ListProjectsResponse + 22, // [22:26] is the sub-list for method output_type + 18, // [18:22] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name } func init() { file_services_kon_github_actions_v1_build_project_proto_init() } diff --git a/services/kon/github_actions/v1/build_project.pb.validate.go b/services/kon/github_actions/v1/build_project.pb.validate.go index 9c70837d..a1f2344b 100644 --- a/services/kon/github_actions/v1/build_project.pb.validate.go +++ b/services/kon/github_actions/v1/build_project.pb.validate.go @@ -382,6 +382,35 @@ func (m *CreateProjectRequest) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetRepositoryId()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CreateProjectRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CreateProjectRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRepositoryId()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CreateProjectRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + } + } + } + // no validation rules for ProjectName // no validation rules for ProductionBranch @@ -1090,6 +1119,37 @@ func (m *GetProjectResponse) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetRepositoryId()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetProjectResponseValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetProjectResponseValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRepositoryId()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetProjectResponseValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for RepositoryName + if len(errors) > 0 { return GetProjectResponseMultiError(errors) } diff --git a/services/kon/github_actions/v1/github_actions_v1connect/build_job.connect.go b/services/kon/github_actions/v1/github_actions_v1connect/build_job.connect.go index 26f5817b..0723f9cc 100644 --- a/services/kon/github_actions/v1/github_actions_v1connect/build_job.connect.go +++ b/services/kon/github_actions/v1/github_actions_v1connect/build_job.connect.go @@ -5,9 +5,9 @@ package github_actions_v1connect import ( + connect "connectrpc.com/connect" context "context" errors "errors" - connect_go "github.com/bufbuild/connect-go" v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" http "net/http" strings "strings" @@ -18,7 +18,7 @@ import ( // generated with a version of connect newer than the one compiled into your binary. You can fix the // problem by either regenerating this code with an older version of connect or updating the connect // version compiled into your binary. -const _ = connect_go.IsAtLeastVersion0_1_0 +const _ = connect.IsAtLeastVersion1_13_0 const ( // GithubActionsBuildServiceName is the fully-qualified name of the GithubActionsBuildService @@ -57,16 +57,28 @@ const ( GithubActionsBuildServiceBulkDeleteBuildJobsProcedure = "/services.kon.github_actions.v1.GithubActionsBuildService/BulkDeleteBuildJobs" ) +// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. +var ( + githubActionsBuildServiceServiceDescriptor = v1.File_services_kon_github_actions_v1_build_job_proto.Services().ByName("GithubActionsBuildService") + githubActionsBuildServiceStoreJobMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("StoreJob") + githubActionsBuildServiceGetBuildJobMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("GetBuildJob") + githubActionsBuildServiceTriggerBuildMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("TriggerBuild") + githubActionsBuildServiceCancelBuildMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("CancelBuild") + githubActionsBuildServiceDeleteJobMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("DeleteJob") + githubActionsBuildServiceListBuildJobsMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("ListBuildJobs") + githubActionsBuildServiceBulkDeleteBuildJobsMethodDescriptor = githubActionsBuildServiceServiceDescriptor.Methods().ByName("BulkDeleteBuildJobs") +) + // GithubActionsBuildServiceClient is a client for the // services.kon.github_actions.v1.GithubActionsBuildService service. type GithubActionsBuildServiceClient interface { - StoreJob(context.Context, *connect_go.Request[v1.StoreJobRequest]) (*connect_go.Response[v1.StoreJobResponse], error) - GetBuildJob(context.Context, *connect_go.Request[v1.GetBuildJobRequest]) (*connect_go.Response[v1.GetBuildJobResponse], error) - TriggerBuild(context.Context, *connect_go.Request[v1.TriggerBuildRequest]) (*connect_go.Response[v1.TriggerBuildResponse], error) - CancelBuild(context.Context, *connect_go.Request[v1.CancelBuildRequest]) (*connect_go.Response[v1.CancelBuildResponse], error) - DeleteJob(context.Context, *connect_go.Request[v1.DeleteJobRequest]) (*connect_go.Response[v1.DeleteJobResponse], error) - ListBuildJobs(context.Context, *connect_go.Request[v1.ListBuildJobsRequest]) (*connect_go.Response[v1.ListBuildJobsResponse], error) - BulkDeleteBuildJobs(context.Context, *connect_go.Request[v1.BulkDeleteBuildJobsRequest]) (*connect_go.Response[v1.BulkDeleteBuildJobsResponse], error) + StoreJob(context.Context, *connect.Request[v1.StoreJobRequest]) (*connect.Response[v1.StoreJobResponse], error) + GetBuildJob(context.Context, *connect.Request[v1.GetBuildJobRequest]) (*connect.Response[v1.GetBuildJobResponse], error) + TriggerBuild(context.Context, *connect.Request[v1.TriggerBuildRequest]) (*connect.Response[v1.TriggerBuildResponse], error) + CancelBuild(context.Context, *connect.Request[v1.CancelBuildRequest]) (*connect.Response[v1.CancelBuildResponse], error) + DeleteJob(context.Context, *connect.Request[v1.DeleteJobRequest]) (*connect.Response[v1.DeleteJobResponse], error) + ListBuildJobs(context.Context, *connect.Request[v1.ListBuildJobsRequest]) (*connect.Response[v1.ListBuildJobsResponse], error) + BulkDeleteBuildJobs(context.Context, *connect.Request[v1.BulkDeleteBuildJobsRequest]) (*connect.Response[v1.BulkDeleteBuildJobsResponse], error) } // NewGithubActionsBuildServiceClient constructs a client for the @@ -77,104 +89,111 @@ type GithubActionsBuildServiceClient interface { // // The URL supplied here should be the base URL for the Connect or gRPC server (for example, // http://api.acme.com or https://acme.com/grpc). -func NewGithubActionsBuildServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) GithubActionsBuildServiceClient { +func NewGithubActionsBuildServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) GithubActionsBuildServiceClient { baseURL = strings.TrimRight(baseURL, "/") return &githubActionsBuildServiceClient{ - storeJob: connect_go.NewClient[v1.StoreJobRequest, v1.StoreJobResponse]( + storeJob: connect.NewClient[v1.StoreJobRequest, v1.StoreJobResponse]( httpClient, baseURL+GithubActionsBuildServiceStoreJobProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceStoreJobMethodDescriptor), + connect.WithClientOptions(opts...), ), - getBuildJob: connect_go.NewClient[v1.GetBuildJobRequest, v1.GetBuildJobResponse]( + getBuildJob: connect.NewClient[v1.GetBuildJobRequest, v1.GetBuildJobResponse]( httpClient, baseURL+GithubActionsBuildServiceGetBuildJobProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceGetBuildJobMethodDescriptor), + connect.WithClientOptions(opts...), ), - triggerBuild: connect_go.NewClient[v1.TriggerBuildRequest, v1.TriggerBuildResponse]( + triggerBuild: connect.NewClient[v1.TriggerBuildRequest, v1.TriggerBuildResponse]( httpClient, baseURL+GithubActionsBuildServiceTriggerBuildProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceTriggerBuildMethodDescriptor), + connect.WithClientOptions(opts...), ), - cancelBuild: connect_go.NewClient[v1.CancelBuildRequest, v1.CancelBuildResponse]( + cancelBuild: connect.NewClient[v1.CancelBuildRequest, v1.CancelBuildResponse]( httpClient, baseURL+GithubActionsBuildServiceCancelBuildProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceCancelBuildMethodDescriptor), + connect.WithClientOptions(opts...), ), - deleteJob: connect_go.NewClient[v1.DeleteJobRequest, v1.DeleteJobResponse]( + deleteJob: connect.NewClient[v1.DeleteJobRequest, v1.DeleteJobResponse]( httpClient, baseURL+GithubActionsBuildServiceDeleteJobProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceDeleteJobMethodDescriptor), + connect.WithClientOptions(opts...), ), - listBuildJobs: connect_go.NewClient[v1.ListBuildJobsRequest, v1.ListBuildJobsResponse]( + listBuildJobs: connect.NewClient[v1.ListBuildJobsRequest, v1.ListBuildJobsResponse]( httpClient, baseURL+GithubActionsBuildServiceListBuildJobsProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceListBuildJobsMethodDescriptor), + connect.WithClientOptions(opts...), ), - bulkDeleteBuildJobs: connect_go.NewClient[v1.BulkDeleteBuildJobsRequest, v1.BulkDeleteBuildJobsResponse]( + bulkDeleteBuildJobs: connect.NewClient[v1.BulkDeleteBuildJobsRequest, v1.BulkDeleteBuildJobsResponse]( httpClient, baseURL+GithubActionsBuildServiceBulkDeleteBuildJobsProcedure, - opts..., + connect.WithSchema(githubActionsBuildServiceBulkDeleteBuildJobsMethodDescriptor), + connect.WithClientOptions(opts...), ), } } // githubActionsBuildServiceClient implements GithubActionsBuildServiceClient. type githubActionsBuildServiceClient struct { - storeJob *connect_go.Client[v1.StoreJobRequest, v1.StoreJobResponse] - getBuildJob *connect_go.Client[v1.GetBuildJobRequest, v1.GetBuildJobResponse] - triggerBuild *connect_go.Client[v1.TriggerBuildRequest, v1.TriggerBuildResponse] - cancelBuild *connect_go.Client[v1.CancelBuildRequest, v1.CancelBuildResponse] - deleteJob *connect_go.Client[v1.DeleteJobRequest, v1.DeleteJobResponse] - listBuildJobs *connect_go.Client[v1.ListBuildJobsRequest, v1.ListBuildJobsResponse] - bulkDeleteBuildJobs *connect_go.Client[v1.BulkDeleteBuildJobsRequest, v1.BulkDeleteBuildJobsResponse] + storeJob *connect.Client[v1.StoreJobRequest, v1.StoreJobResponse] + getBuildJob *connect.Client[v1.GetBuildJobRequest, v1.GetBuildJobResponse] + triggerBuild *connect.Client[v1.TriggerBuildRequest, v1.TriggerBuildResponse] + cancelBuild *connect.Client[v1.CancelBuildRequest, v1.CancelBuildResponse] + deleteJob *connect.Client[v1.DeleteJobRequest, v1.DeleteJobResponse] + listBuildJobs *connect.Client[v1.ListBuildJobsRequest, v1.ListBuildJobsResponse] + bulkDeleteBuildJobs *connect.Client[v1.BulkDeleteBuildJobsRequest, v1.BulkDeleteBuildJobsResponse] } // StoreJob calls services.kon.github_actions.v1.GithubActionsBuildService.StoreJob. -func (c *githubActionsBuildServiceClient) StoreJob(ctx context.Context, req *connect_go.Request[v1.StoreJobRequest]) (*connect_go.Response[v1.StoreJobResponse], error) { +func (c *githubActionsBuildServiceClient) StoreJob(ctx context.Context, req *connect.Request[v1.StoreJobRequest]) (*connect.Response[v1.StoreJobResponse], error) { return c.storeJob.CallUnary(ctx, req) } // GetBuildJob calls services.kon.github_actions.v1.GithubActionsBuildService.GetBuildJob. -func (c *githubActionsBuildServiceClient) GetBuildJob(ctx context.Context, req *connect_go.Request[v1.GetBuildJobRequest]) (*connect_go.Response[v1.GetBuildJobResponse], error) { +func (c *githubActionsBuildServiceClient) GetBuildJob(ctx context.Context, req *connect.Request[v1.GetBuildJobRequest]) (*connect.Response[v1.GetBuildJobResponse], error) { return c.getBuildJob.CallUnary(ctx, req) } // TriggerBuild calls services.kon.github_actions.v1.GithubActionsBuildService.TriggerBuild. -func (c *githubActionsBuildServiceClient) TriggerBuild(ctx context.Context, req *connect_go.Request[v1.TriggerBuildRequest]) (*connect_go.Response[v1.TriggerBuildResponse], error) { +func (c *githubActionsBuildServiceClient) TriggerBuild(ctx context.Context, req *connect.Request[v1.TriggerBuildRequest]) (*connect.Response[v1.TriggerBuildResponse], error) { return c.triggerBuild.CallUnary(ctx, req) } // CancelBuild calls services.kon.github_actions.v1.GithubActionsBuildService.CancelBuild. -func (c *githubActionsBuildServiceClient) CancelBuild(ctx context.Context, req *connect_go.Request[v1.CancelBuildRequest]) (*connect_go.Response[v1.CancelBuildResponse], error) { +func (c *githubActionsBuildServiceClient) CancelBuild(ctx context.Context, req *connect.Request[v1.CancelBuildRequest]) (*connect.Response[v1.CancelBuildResponse], error) { return c.cancelBuild.CallUnary(ctx, req) } // DeleteJob calls services.kon.github_actions.v1.GithubActionsBuildService.DeleteJob. -func (c *githubActionsBuildServiceClient) DeleteJob(ctx context.Context, req *connect_go.Request[v1.DeleteJobRequest]) (*connect_go.Response[v1.DeleteJobResponse], error) { +func (c *githubActionsBuildServiceClient) DeleteJob(ctx context.Context, req *connect.Request[v1.DeleteJobRequest]) (*connect.Response[v1.DeleteJobResponse], error) { return c.deleteJob.CallUnary(ctx, req) } // ListBuildJobs calls services.kon.github_actions.v1.GithubActionsBuildService.ListBuildJobs. -func (c *githubActionsBuildServiceClient) ListBuildJobs(ctx context.Context, req *connect_go.Request[v1.ListBuildJobsRequest]) (*connect_go.Response[v1.ListBuildJobsResponse], error) { +func (c *githubActionsBuildServiceClient) ListBuildJobs(ctx context.Context, req *connect.Request[v1.ListBuildJobsRequest]) (*connect.Response[v1.ListBuildJobsResponse], error) { return c.listBuildJobs.CallUnary(ctx, req) } // BulkDeleteBuildJobs calls // services.kon.github_actions.v1.GithubActionsBuildService.BulkDeleteBuildJobs. -func (c *githubActionsBuildServiceClient) BulkDeleteBuildJobs(ctx context.Context, req *connect_go.Request[v1.BulkDeleteBuildJobsRequest]) (*connect_go.Response[v1.BulkDeleteBuildJobsResponse], error) { +func (c *githubActionsBuildServiceClient) BulkDeleteBuildJobs(ctx context.Context, req *connect.Request[v1.BulkDeleteBuildJobsRequest]) (*connect.Response[v1.BulkDeleteBuildJobsResponse], error) { return c.bulkDeleteBuildJobs.CallUnary(ctx, req) } // GithubActionsBuildServiceHandler is an implementation of the // services.kon.github_actions.v1.GithubActionsBuildService service. type GithubActionsBuildServiceHandler interface { - StoreJob(context.Context, *connect_go.Request[v1.StoreJobRequest]) (*connect_go.Response[v1.StoreJobResponse], error) - GetBuildJob(context.Context, *connect_go.Request[v1.GetBuildJobRequest]) (*connect_go.Response[v1.GetBuildJobResponse], error) - TriggerBuild(context.Context, *connect_go.Request[v1.TriggerBuildRequest]) (*connect_go.Response[v1.TriggerBuildResponse], error) - CancelBuild(context.Context, *connect_go.Request[v1.CancelBuildRequest]) (*connect_go.Response[v1.CancelBuildResponse], error) - DeleteJob(context.Context, *connect_go.Request[v1.DeleteJobRequest]) (*connect_go.Response[v1.DeleteJobResponse], error) - ListBuildJobs(context.Context, *connect_go.Request[v1.ListBuildJobsRequest]) (*connect_go.Response[v1.ListBuildJobsResponse], error) - BulkDeleteBuildJobs(context.Context, *connect_go.Request[v1.BulkDeleteBuildJobsRequest]) (*connect_go.Response[v1.BulkDeleteBuildJobsResponse], error) + StoreJob(context.Context, *connect.Request[v1.StoreJobRequest]) (*connect.Response[v1.StoreJobResponse], error) + GetBuildJob(context.Context, *connect.Request[v1.GetBuildJobRequest]) (*connect.Response[v1.GetBuildJobResponse], error) + TriggerBuild(context.Context, *connect.Request[v1.TriggerBuildRequest]) (*connect.Response[v1.TriggerBuildResponse], error) + CancelBuild(context.Context, *connect.Request[v1.CancelBuildRequest]) (*connect.Response[v1.CancelBuildResponse], error) + DeleteJob(context.Context, *connect.Request[v1.DeleteJobRequest]) (*connect.Response[v1.DeleteJobResponse], error) + ListBuildJobs(context.Context, *connect.Request[v1.ListBuildJobsRequest]) (*connect.Response[v1.ListBuildJobsResponse], error) + BulkDeleteBuildJobs(context.Context, *connect.Request[v1.BulkDeleteBuildJobsRequest]) (*connect.Response[v1.BulkDeleteBuildJobsResponse], error) } // NewGithubActionsBuildServiceHandler builds an HTTP handler from the service implementation. It @@ -182,41 +201,48 @@ type GithubActionsBuildServiceHandler interface { // // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. -func NewGithubActionsBuildServiceHandler(svc GithubActionsBuildServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { - githubActionsBuildServiceStoreJobHandler := connect_go.NewUnaryHandler( +func NewGithubActionsBuildServiceHandler(svc GithubActionsBuildServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + githubActionsBuildServiceStoreJobHandler := connect.NewUnaryHandler( GithubActionsBuildServiceStoreJobProcedure, svc.StoreJob, - opts..., + connect.WithSchema(githubActionsBuildServiceStoreJobMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceGetBuildJobHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceGetBuildJobHandler := connect.NewUnaryHandler( GithubActionsBuildServiceGetBuildJobProcedure, svc.GetBuildJob, - opts..., + connect.WithSchema(githubActionsBuildServiceGetBuildJobMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceTriggerBuildHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceTriggerBuildHandler := connect.NewUnaryHandler( GithubActionsBuildServiceTriggerBuildProcedure, svc.TriggerBuild, - opts..., + connect.WithSchema(githubActionsBuildServiceTriggerBuildMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceCancelBuildHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceCancelBuildHandler := connect.NewUnaryHandler( GithubActionsBuildServiceCancelBuildProcedure, svc.CancelBuild, - opts..., + connect.WithSchema(githubActionsBuildServiceCancelBuildMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceDeleteJobHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceDeleteJobHandler := connect.NewUnaryHandler( GithubActionsBuildServiceDeleteJobProcedure, svc.DeleteJob, - opts..., + connect.WithSchema(githubActionsBuildServiceDeleteJobMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceListBuildJobsHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceListBuildJobsHandler := connect.NewUnaryHandler( GithubActionsBuildServiceListBuildJobsProcedure, svc.ListBuildJobs, - opts..., + connect.WithSchema(githubActionsBuildServiceListBuildJobsMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - githubActionsBuildServiceBulkDeleteBuildJobsHandler := connect_go.NewUnaryHandler( + githubActionsBuildServiceBulkDeleteBuildJobsHandler := connect.NewUnaryHandler( GithubActionsBuildServiceBulkDeleteBuildJobsProcedure, svc.BulkDeleteBuildJobs, - opts..., + connect.WithSchema(githubActionsBuildServiceBulkDeleteBuildJobsMethodDescriptor), + connect.WithHandlerOptions(opts...), ) return "/services.kon.github_actions.v1.GithubActionsBuildService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { @@ -243,30 +269,30 @@ func NewGithubActionsBuildServiceHandler(svc GithubActionsBuildServiceHandler, o // UnimplementedGithubActionsBuildServiceHandler returns CodeUnimplemented from all methods. type UnimplementedGithubActionsBuildServiceHandler struct{} -func (UnimplementedGithubActionsBuildServiceHandler) StoreJob(context.Context, *connect_go.Request[v1.StoreJobRequest]) (*connect_go.Response[v1.StoreJobResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.StoreJob is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) StoreJob(context.Context, *connect.Request[v1.StoreJobRequest]) (*connect.Response[v1.StoreJobResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.StoreJob is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) GetBuildJob(context.Context, *connect_go.Request[v1.GetBuildJobRequest]) (*connect_go.Response[v1.GetBuildJobResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.GetBuildJob is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) GetBuildJob(context.Context, *connect.Request[v1.GetBuildJobRequest]) (*connect.Response[v1.GetBuildJobResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.GetBuildJob is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) TriggerBuild(context.Context, *connect_go.Request[v1.TriggerBuildRequest]) (*connect_go.Response[v1.TriggerBuildResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.TriggerBuild is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) TriggerBuild(context.Context, *connect.Request[v1.TriggerBuildRequest]) (*connect.Response[v1.TriggerBuildResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.TriggerBuild is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) CancelBuild(context.Context, *connect_go.Request[v1.CancelBuildRequest]) (*connect_go.Response[v1.CancelBuildResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.CancelBuild is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) CancelBuild(context.Context, *connect.Request[v1.CancelBuildRequest]) (*connect.Response[v1.CancelBuildResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.CancelBuild is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) DeleteJob(context.Context, *connect_go.Request[v1.DeleteJobRequest]) (*connect_go.Response[v1.DeleteJobResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.DeleteJob is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) DeleteJob(context.Context, *connect.Request[v1.DeleteJobRequest]) (*connect.Response[v1.DeleteJobResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.DeleteJob is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) ListBuildJobs(context.Context, *connect_go.Request[v1.ListBuildJobsRequest]) (*connect_go.Response[v1.ListBuildJobsResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.ListBuildJobs is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) ListBuildJobs(context.Context, *connect.Request[v1.ListBuildJobsRequest]) (*connect.Response[v1.ListBuildJobsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.ListBuildJobs is not implemented")) } -func (UnimplementedGithubActionsBuildServiceHandler) BulkDeleteBuildJobs(context.Context, *connect_go.Request[v1.BulkDeleteBuildJobsRequest]) (*connect_go.Response[v1.BulkDeleteBuildJobsResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.BulkDeleteBuildJobs is not implemented")) +func (UnimplementedGithubActionsBuildServiceHandler) BulkDeleteBuildJobs(context.Context, *connect.Request[v1.BulkDeleteBuildJobsRequest]) (*connect.Response[v1.BulkDeleteBuildJobsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GithubActionsBuildService.BulkDeleteBuildJobs is not implemented")) } diff --git a/services/kon/github_actions/v1/github_actions_v1connect/build_logs.connect.go b/services/kon/github_actions/v1/github_actions_v1connect/build_logs.connect.go index 8fcf879f..e6a5def3 100644 --- a/services/kon/github_actions/v1/github_actions_v1connect/build_logs.connect.go +++ b/services/kon/github_actions/v1/github_actions_v1connect/build_logs.connect.go @@ -5,9 +5,9 @@ package github_actions_v1connect import ( + connect "connectrpc.com/connect" context "context" errors "errors" - connect_go "github.com/bufbuild/connect-go" v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" http "net/http" strings "strings" @@ -18,7 +18,7 @@ import ( // generated with a version of connect newer than the one compiled into your binary. You can fix the // problem by either regenerating this code with an older version of connect or updating the connect // version compiled into your binary. -const _ = connect_go.IsAtLeastVersion0_1_0 +const _ = connect.IsAtLeastVersion1_13_0 const ( // GitHubActionsLogsServiceName is the fully-qualified name of the GitHubActionsLogsService service. @@ -41,11 +41,18 @@ const ( GitHubActionsLogsServiceDumpLogsProcedure = "/services.kon.github_actions.v1.GitHubActionsLogsService/DumpLogs" ) +// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. +var ( + gitHubActionsLogsServiceServiceDescriptor = v1.File_services_kon_github_actions_v1_build_logs_proto.Services().ByName("GitHubActionsLogsService") + gitHubActionsLogsServiceStreamWorkflowRunLogsMethodDescriptor = gitHubActionsLogsServiceServiceDescriptor.Methods().ByName("StreamWorkflowRunLogs") + gitHubActionsLogsServiceDumpLogsMethodDescriptor = gitHubActionsLogsServiceServiceDescriptor.Methods().ByName("DumpLogs") +) + // GitHubActionsLogsServiceClient is a client for the // services.kon.github_actions.v1.GitHubActionsLogsService service. type GitHubActionsLogsServiceClient interface { - StreamWorkflowRunLogs(context.Context, *connect_go.Request[v1.StreamWorkflowRunLogsRequest]) (*connect_go.ServerStreamForClient[v1.StreamWorkflowRunLogsResponse], error) - DumpLogs(context.Context, *connect_go.Request[v1.DumpLogsRequest]) (*connect_go.Response[v1.DumpLogsResponse], error) + StreamWorkflowRunLogs(context.Context, *connect.Request[v1.StreamWorkflowRunLogsRequest]) (*connect.ServerStreamForClient[v1.StreamWorkflowRunLogsResponse], error) + DumpLogs(context.Context, *connect.Request[v1.DumpLogsRequest]) (*connect.Response[v1.DumpLogsResponse], error) } // NewGitHubActionsLogsServiceClient constructs a client for the @@ -56,44 +63,46 @@ type GitHubActionsLogsServiceClient interface { // // The URL supplied here should be the base URL for the Connect or gRPC server (for example, // http://api.acme.com or https://acme.com/grpc). -func NewGitHubActionsLogsServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) GitHubActionsLogsServiceClient { +func NewGitHubActionsLogsServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) GitHubActionsLogsServiceClient { baseURL = strings.TrimRight(baseURL, "/") return &gitHubActionsLogsServiceClient{ - streamWorkflowRunLogs: connect_go.NewClient[v1.StreamWorkflowRunLogsRequest, v1.StreamWorkflowRunLogsResponse]( + streamWorkflowRunLogs: connect.NewClient[v1.StreamWorkflowRunLogsRequest, v1.StreamWorkflowRunLogsResponse]( httpClient, baseURL+GitHubActionsLogsServiceStreamWorkflowRunLogsProcedure, - opts..., + connect.WithSchema(gitHubActionsLogsServiceStreamWorkflowRunLogsMethodDescriptor), + connect.WithClientOptions(opts...), ), - dumpLogs: connect_go.NewClient[v1.DumpLogsRequest, v1.DumpLogsResponse]( + dumpLogs: connect.NewClient[v1.DumpLogsRequest, v1.DumpLogsResponse]( httpClient, baseURL+GitHubActionsLogsServiceDumpLogsProcedure, - opts..., + connect.WithSchema(gitHubActionsLogsServiceDumpLogsMethodDescriptor), + connect.WithClientOptions(opts...), ), } } // gitHubActionsLogsServiceClient implements GitHubActionsLogsServiceClient. type gitHubActionsLogsServiceClient struct { - streamWorkflowRunLogs *connect_go.Client[v1.StreamWorkflowRunLogsRequest, v1.StreamWorkflowRunLogsResponse] - dumpLogs *connect_go.Client[v1.DumpLogsRequest, v1.DumpLogsResponse] + streamWorkflowRunLogs *connect.Client[v1.StreamWorkflowRunLogsRequest, v1.StreamWorkflowRunLogsResponse] + dumpLogs *connect.Client[v1.DumpLogsRequest, v1.DumpLogsResponse] } // StreamWorkflowRunLogs calls // services.kon.github_actions.v1.GitHubActionsLogsService.StreamWorkflowRunLogs. -func (c *gitHubActionsLogsServiceClient) StreamWorkflowRunLogs(ctx context.Context, req *connect_go.Request[v1.StreamWorkflowRunLogsRequest]) (*connect_go.ServerStreamForClient[v1.StreamWorkflowRunLogsResponse], error) { +func (c *gitHubActionsLogsServiceClient) StreamWorkflowRunLogs(ctx context.Context, req *connect.Request[v1.StreamWorkflowRunLogsRequest]) (*connect.ServerStreamForClient[v1.StreamWorkflowRunLogsResponse], error) { return c.streamWorkflowRunLogs.CallServerStream(ctx, req) } // DumpLogs calls services.kon.github_actions.v1.GitHubActionsLogsService.DumpLogs. -func (c *gitHubActionsLogsServiceClient) DumpLogs(ctx context.Context, req *connect_go.Request[v1.DumpLogsRequest]) (*connect_go.Response[v1.DumpLogsResponse], error) { +func (c *gitHubActionsLogsServiceClient) DumpLogs(ctx context.Context, req *connect.Request[v1.DumpLogsRequest]) (*connect.Response[v1.DumpLogsResponse], error) { return c.dumpLogs.CallUnary(ctx, req) } // GitHubActionsLogsServiceHandler is an implementation of the // services.kon.github_actions.v1.GitHubActionsLogsService service. type GitHubActionsLogsServiceHandler interface { - StreamWorkflowRunLogs(context.Context, *connect_go.Request[v1.StreamWorkflowRunLogsRequest], *connect_go.ServerStream[v1.StreamWorkflowRunLogsResponse]) error - DumpLogs(context.Context, *connect_go.Request[v1.DumpLogsRequest]) (*connect_go.Response[v1.DumpLogsResponse], error) + StreamWorkflowRunLogs(context.Context, *connect.Request[v1.StreamWorkflowRunLogsRequest], *connect.ServerStream[v1.StreamWorkflowRunLogsResponse]) error + DumpLogs(context.Context, *connect.Request[v1.DumpLogsRequest]) (*connect.Response[v1.DumpLogsResponse], error) } // NewGitHubActionsLogsServiceHandler builds an HTTP handler from the service implementation. It @@ -101,16 +110,18 @@ type GitHubActionsLogsServiceHandler interface { // // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. -func NewGitHubActionsLogsServiceHandler(svc GitHubActionsLogsServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { - gitHubActionsLogsServiceStreamWorkflowRunLogsHandler := connect_go.NewServerStreamHandler( +func NewGitHubActionsLogsServiceHandler(svc GitHubActionsLogsServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + gitHubActionsLogsServiceStreamWorkflowRunLogsHandler := connect.NewServerStreamHandler( GitHubActionsLogsServiceStreamWorkflowRunLogsProcedure, svc.StreamWorkflowRunLogs, - opts..., + connect.WithSchema(gitHubActionsLogsServiceStreamWorkflowRunLogsMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - gitHubActionsLogsServiceDumpLogsHandler := connect_go.NewUnaryHandler( + gitHubActionsLogsServiceDumpLogsHandler := connect.NewUnaryHandler( GitHubActionsLogsServiceDumpLogsProcedure, svc.DumpLogs, - opts..., + connect.WithSchema(gitHubActionsLogsServiceDumpLogsMethodDescriptor), + connect.WithHandlerOptions(opts...), ) return "/services.kon.github_actions.v1.GitHubActionsLogsService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { @@ -127,10 +138,10 @@ func NewGitHubActionsLogsServiceHandler(svc GitHubActionsLogsServiceHandler, opt // UnimplementedGitHubActionsLogsServiceHandler returns CodeUnimplemented from all methods. type UnimplementedGitHubActionsLogsServiceHandler struct{} -func (UnimplementedGitHubActionsLogsServiceHandler) StreamWorkflowRunLogs(context.Context, *connect_go.Request[v1.StreamWorkflowRunLogsRequest], *connect_go.ServerStream[v1.StreamWorkflowRunLogsResponse]) error { - return connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsLogsService.StreamWorkflowRunLogs is not implemented")) +func (UnimplementedGitHubActionsLogsServiceHandler) StreamWorkflowRunLogs(context.Context, *connect.Request[v1.StreamWorkflowRunLogsRequest], *connect.ServerStream[v1.StreamWorkflowRunLogsResponse]) error { + return connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsLogsService.StreamWorkflowRunLogs is not implemented")) } -func (UnimplementedGitHubActionsLogsServiceHandler) DumpLogs(context.Context, *connect_go.Request[v1.DumpLogsRequest]) (*connect_go.Response[v1.DumpLogsResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsLogsService.DumpLogs is not implemented")) +func (UnimplementedGitHubActionsLogsServiceHandler) DumpLogs(context.Context, *connect.Request[v1.DumpLogsRequest]) (*connect.Response[v1.DumpLogsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsLogsService.DumpLogs is not implemented")) } diff --git a/services/kon/github_actions/v1/github_actions_v1connect/build_project.connect.go b/services/kon/github_actions/v1/github_actions_v1connect/build_project.connect.go index 3f7f1890..609c29e8 100644 --- a/services/kon/github_actions/v1/github_actions_v1connect/build_project.connect.go +++ b/services/kon/github_actions/v1/github_actions_v1connect/build_project.connect.go @@ -5,9 +5,9 @@ package github_actions_v1connect import ( + connect "connectrpc.com/connect" context "context" errors "errors" - connect_go "github.com/bufbuild/connect-go" v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" http "net/http" strings "strings" @@ -18,7 +18,7 @@ import ( // generated with a version of connect newer than the one compiled into your binary. You can fix the // problem by either regenerating this code with an older version of connect or updating the connect // version compiled into your binary. -const _ = connect_go.IsAtLeastVersion0_1_0 +const _ = connect.IsAtLeastVersion1_13_0 const ( // GitHubActionsProjectServiceName is the fully-qualified name of the GitHubActionsProjectService @@ -48,13 +48,22 @@ const ( GitHubActionsProjectServiceListProjectsProcedure = "/services.kon.github_actions.v1.GitHubActionsProjectService/ListProjects" ) +// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. +var ( + gitHubActionsProjectServiceServiceDescriptor = v1.File_services_kon_github_actions_v1_build_project_proto.Services().ByName("GitHubActionsProjectService") + gitHubActionsProjectServiceCreateProjectMethodDescriptor = gitHubActionsProjectServiceServiceDescriptor.Methods().ByName("CreateProject") + gitHubActionsProjectServiceGetProjectMethodDescriptor = gitHubActionsProjectServiceServiceDescriptor.Methods().ByName("GetProject") + gitHubActionsProjectServiceDeleteProjectMethodDescriptor = gitHubActionsProjectServiceServiceDescriptor.Methods().ByName("DeleteProject") + gitHubActionsProjectServiceListProjectsMethodDescriptor = gitHubActionsProjectServiceServiceDescriptor.Methods().ByName("ListProjects") +) + // GitHubActionsProjectServiceClient is a client for the // services.kon.github_actions.v1.GitHubActionsProjectService service. type GitHubActionsProjectServiceClient interface { - CreateProject(context.Context, *connect_go.Request[v1.CreateProjectRequest]) (*connect_go.Response[v1.CreateProjectResponse], error) - GetProject(context.Context, *connect_go.Request[v1.GetProjectRequest]) (*connect_go.Response[v1.GetProjectResponse], error) - DeleteProject(context.Context, *connect_go.Request[v1.DeleteProjectRequest]) (*connect_go.Response[v1.DeleteProjectResponse], error) - ListProjects(context.Context, *connect_go.Request[v1.ListProjectsRequest]) (*connect_go.Response[v1.ListProjectsResponse], error) + CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) + GetProject(context.Context, *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) + DeleteProject(context.Context, *connect.Request[v1.DeleteProjectRequest]) (*connect.Response[v1.DeleteProjectResponse], error) + ListProjects(context.Context, *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) } // NewGitHubActionsProjectServiceClient constructs a client for the @@ -65,67 +74,71 @@ type GitHubActionsProjectServiceClient interface { // // The URL supplied here should be the base URL for the Connect or gRPC server (for example, // http://api.acme.com or https://acme.com/grpc). -func NewGitHubActionsProjectServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) GitHubActionsProjectServiceClient { +func NewGitHubActionsProjectServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) GitHubActionsProjectServiceClient { baseURL = strings.TrimRight(baseURL, "/") return &gitHubActionsProjectServiceClient{ - createProject: connect_go.NewClient[v1.CreateProjectRequest, v1.CreateProjectResponse]( + createProject: connect.NewClient[v1.CreateProjectRequest, v1.CreateProjectResponse]( httpClient, baseURL+GitHubActionsProjectServiceCreateProjectProcedure, - opts..., + connect.WithSchema(gitHubActionsProjectServiceCreateProjectMethodDescriptor), + connect.WithClientOptions(opts...), ), - getProject: connect_go.NewClient[v1.GetProjectRequest, v1.GetProjectResponse]( + getProject: connect.NewClient[v1.GetProjectRequest, v1.GetProjectResponse]( httpClient, baseURL+GitHubActionsProjectServiceGetProjectProcedure, - opts..., + connect.WithSchema(gitHubActionsProjectServiceGetProjectMethodDescriptor), + connect.WithClientOptions(opts...), ), - deleteProject: connect_go.NewClient[v1.DeleteProjectRequest, v1.DeleteProjectResponse]( + deleteProject: connect.NewClient[v1.DeleteProjectRequest, v1.DeleteProjectResponse]( httpClient, baseURL+GitHubActionsProjectServiceDeleteProjectProcedure, - opts..., + connect.WithSchema(gitHubActionsProjectServiceDeleteProjectMethodDescriptor), + connect.WithClientOptions(opts...), ), - listProjects: connect_go.NewClient[v1.ListProjectsRequest, v1.ListProjectsResponse]( + listProjects: connect.NewClient[v1.ListProjectsRequest, v1.ListProjectsResponse]( httpClient, baseURL+GitHubActionsProjectServiceListProjectsProcedure, - opts..., + connect.WithSchema(gitHubActionsProjectServiceListProjectsMethodDescriptor), + connect.WithClientOptions(opts...), ), } } // gitHubActionsProjectServiceClient implements GitHubActionsProjectServiceClient. type gitHubActionsProjectServiceClient struct { - createProject *connect_go.Client[v1.CreateProjectRequest, v1.CreateProjectResponse] - getProject *connect_go.Client[v1.GetProjectRequest, v1.GetProjectResponse] - deleteProject *connect_go.Client[v1.DeleteProjectRequest, v1.DeleteProjectResponse] - listProjects *connect_go.Client[v1.ListProjectsRequest, v1.ListProjectsResponse] + createProject *connect.Client[v1.CreateProjectRequest, v1.CreateProjectResponse] + getProject *connect.Client[v1.GetProjectRequest, v1.GetProjectResponse] + deleteProject *connect.Client[v1.DeleteProjectRequest, v1.DeleteProjectResponse] + listProjects *connect.Client[v1.ListProjectsRequest, v1.ListProjectsResponse] } // CreateProject calls services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject. -func (c *gitHubActionsProjectServiceClient) CreateProject(ctx context.Context, req *connect_go.Request[v1.CreateProjectRequest]) (*connect_go.Response[v1.CreateProjectResponse], error) { +func (c *gitHubActionsProjectServiceClient) CreateProject(ctx context.Context, req *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) { return c.createProject.CallUnary(ctx, req) } // GetProject calls services.kon.github_actions.v1.GitHubActionsProjectService.GetProject. -func (c *gitHubActionsProjectServiceClient) GetProject(ctx context.Context, req *connect_go.Request[v1.GetProjectRequest]) (*connect_go.Response[v1.GetProjectResponse], error) { +func (c *gitHubActionsProjectServiceClient) GetProject(ctx context.Context, req *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) { return c.getProject.CallUnary(ctx, req) } // DeleteProject calls services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject. -func (c *gitHubActionsProjectServiceClient) DeleteProject(ctx context.Context, req *connect_go.Request[v1.DeleteProjectRequest]) (*connect_go.Response[v1.DeleteProjectResponse], error) { +func (c *gitHubActionsProjectServiceClient) DeleteProject(ctx context.Context, req *connect.Request[v1.DeleteProjectRequest]) (*connect.Response[v1.DeleteProjectResponse], error) { return c.deleteProject.CallUnary(ctx, req) } // ListProjects calls services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects. -func (c *gitHubActionsProjectServiceClient) ListProjects(ctx context.Context, req *connect_go.Request[v1.ListProjectsRequest]) (*connect_go.Response[v1.ListProjectsResponse], error) { +func (c *gitHubActionsProjectServiceClient) ListProjects(ctx context.Context, req *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) { return c.listProjects.CallUnary(ctx, req) } // GitHubActionsProjectServiceHandler is an implementation of the // services.kon.github_actions.v1.GitHubActionsProjectService service. type GitHubActionsProjectServiceHandler interface { - CreateProject(context.Context, *connect_go.Request[v1.CreateProjectRequest]) (*connect_go.Response[v1.CreateProjectResponse], error) - GetProject(context.Context, *connect_go.Request[v1.GetProjectRequest]) (*connect_go.Response[v1.GetProjectResponse], error) - DeleteProject(context.Context, *connect_go.Request[v1.DeleteProjectRequest]) (*connect_go.Response[v1.DeleteProjectResponse], error) - ListProjects(context.Context, *connect_go.Request[v1.ListProjectsRequest]) (*connect_go.Response[v1.ListProjectsResponse], error) + CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) + GetProject(context.Context, *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) + DeleteProject(context.Context, *connect.Request[v1.DeleteProjectRequest]) (*connect.Response[v1.DeleteProjectResponse], error) + ListProjects(context.Context, *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) } // NewGitHubActionsProjectServiceHandler builds an HTTP handler from the service implementation. It @@ -133,26 +146,30 @@ type GitHubActionsProjectServiceHandler interface { // // By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf // and JSON codecs. They also support gzip compression. -func NewGitHubActionsProjectServiceHandler(svc GitHubActionsProjectServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { - gitHubActionsProjectServiceCreateProjectHandler := connect_go.NewUnaryHandler( +func NewGitHubActionsProjectServiceHandler(svc GitHubActionsProjectServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + gitHubActionsProjectServiceCreateProjectHandler := connect.NewUnaryHandler( GitHubActionsProjectServiceCreateProjectProcedure, svc.CreateProject, - opts..., + connect.WithSchema(gitHubActionsProjectServiceCreateProjectMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - gitHubActionsProjectServiceGetProjectHandler := connect_go.NewUnaryHandler( + gitHubActionsProjectServiceGetProjectHandler := connect.NewUnaryHandler( GitHubActionsProjectServiceGetProjectProcedure, svc.GetProject, - opts..., + connect.WithSchema(gitHubActionsProjectServiceGetProjectMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - gitHubActionsProjectServiceDeleteProjectHandler := connect_go.NewUnaryHandler( + gitHubActionsProjectServiceDeleteProjectHandler := connect.NewUnaryHandler( GitHubActionsProjectServiceDeleteProjectProcedure, svc.DeleteProject, - opts..., + connect.WithSchema(gitHubActionsProjectServiceDeleteProjectMethodDescriptor), + connect.WithHandlerOptions(opts...), ) - gitHubActionsProjectServiceListProjectsHandler := connect_go.NewUnaryHandler( + gitHubActionsProjectServiceListProjectsHandler := connect.NewUnaryHandler( GitHubActionsProjectServiceListProjectsProcedure, svc.ListProjects, - opts..., + connect.WithSchema(gitHubActionsProjectServiceListProjectsMethodDescriptor), + connect.WithHandlerOptions(opts...), ) return "/services.kon.github_actions.v1.GitHubActionsProjectService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { @@ -173,18 +190,18 @@ func NewGitHubActionsProjectServiceHandler(svc GitHubActionsProjectServiceHandle // UnimplementedGitHubActionsProjectServiceHandler returns CodeUnimplemented from all methods. type UnimplementedGitHubActionsProjectServiceHandler struct{} -func (UnimplementedGitHubActionsProjectServiceHandler) CreateProject(context.Context, *connect_go.Request[v1.CreateProjectRequest]) (*connect_go.Response[v1.CreateProjectResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject is not implemented")) +func (UnimplementedGitHubActionsProjectServiceHandler) CreateProject(context.Context, *connect.Request[v1.CreateProjectRequest]) (*connect.Response[v1.CreateProjectResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.CreateProject is not implemented")) } -func (UnimplementedGitHubActionsProjectServiceHandler) GetProject(context.Context, *connect_go.Request[v1.GetProjectRequest]) (*connect_go.Response[v1.GetProjectResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.GetProject is not implemented")) +func (UnimplementedGitHubActionsProjectServiceHandler) GetProject(context.Context, *connect.Request[v1.GetProjectRequest]) (*connect.Response[v1.GetProjectResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.GetProject is not implemented")) } -func (UnimplementedGitHubActionsProjectServiceHandler) DeleteProject(context.Context, *connect_go.Request[v1.DeleteProjectRequest]) (*connect_go.Response[v1.DeleteProjectResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject is not implemented")) +func (UnimplementedGitHubActionsProjectServiceHandler) DeleteProject(context.Context, *connect.Request[v1.DeleteProjectRequest]) (*connect.Response[v1.DeleteProjectResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.DeleteProject is not implemented")) } -func (UnimplementedGitHubActionsProjectServiceHandler) ListProjects(context.Context, *connect_go.Request[v1.ListProjectsRequest]) (*connect_go.Response[v1.ListProjectsResponse], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects is not implemented")) +func (UnimplementedGitHubActionsProjectServiceHandler) ListProjects(context.Context, *connect.Request[v1.ListProjectsRequest]) (*connect.Response[v1.ListProjectsResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubActionsProjectService.ListProjects is not implemented")) } diff --git a/services/kon/github_actions/v1/github_actions_v1connect/events.connect.go b/services/kon/github_actions/v1/github_actions_v1connect/events.connect.go deleted file mode 100644 index 9662c14e..00000000 --- a/services/kon/github_actions/v1/github_actions_v1connect/events.connect.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by protoc-gen-connect-go. DO NOT EDIT. -// -// Source: services/kon/github_actions/v1/events.proto - -package github_actions_v1connect - -import ( - context "context" - errors "errors" - connect_go "github.com/bufbuild/connect-go" - _ "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" - emptypb "google.golang.org/protobuf/types/known/emptypb" - structpb "google.golang.org/protobuf/types/known/structpb" - http "net/http" - strings "strings" -) - -// This is a compile-time assertion to ensure that this generated file and the connect package are -// compatible. If you get a compiler error that this constant is not defined, this code was -// generated with a version of connect newer than the one compiled into your binary. You can fix the -// problem by either regenerating this code with an older version of connect or updating the connect -// version compiled into your binary. -const _ = connect_go.IsAtLeastVersion0_1_0 - -const ( - // GitHubWebhookListenerServiceName is the fully-qualified name of the GitHubWebhookListenerService - // service. - GitHubWebhookListenerServiceName = "services.kon.github_actions.v1.GitHubWebhookListenerService" -) - -// These constants are the fully-qualified names of the RPCs defined in this package. They're -// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. -// -// Note that these are different from the fully-qualified method names used by -// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to -// reflection-formatted method names, remove the leading slash and convert the remaining slash to a -// period. -const ( - // GitHubWebhookListenerServiceListenProcedure is the fully-qualified name of the - // GitHubWebhookListenerService's Listen RPC. - GitHubWebhookListenerServiceListenProcedure = "/services.kon.github_actions.v1.GitHubWebhookListenerService/Listen" -) - -// GitHubWebhookListenerServiceClient is a client for the -// services.kon.github_actions.v1.GitHubWebhookListenerService service. -type GitHubWebhookListenerServiceClient interface { - Listen(context.Context, *connect_go.Request[structpb.Struct]) (*connect_go.Response[emptypb.Empty], error) -} - -// NewGitHubWebhookListenerServiceClient constructs a client for the -// services.kon.github_actions.v1.GitHubWebhookListenerService service. By default, it uses the -// Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends -// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or -// connect.WithGRPCWeb() options. -// -// The URL supplied here should be the base URL for the Connect or gRPC server (for example, -// http://api.acme.com or https://acme.com/grpc). -func NewGitHubWebhookListenerServiceClient(httpClient connect_go.HTTPClient, baseURL string, opts ...connect_go.ClientOption) GitHubWebhookListenerServiceClient { - baseURL = strings.TrimRight(baseURL, "/") - return &gitHubWebhookListenerServiceClient{ - listen: connect_go.NewClient[structpb.Struct, emptypb.Empty]( - httpClient, - baseURL+GitHubWebhookListenerServiceListenProcedure, - opts..., - ), - } -} - -// gitHubWebhookListenerServiceClient implements GitHubWebhookListenerServiceClient. -type gitHubWebhookListenerServiceClient struct { - listen *connect_go.Client[structpb.Struct, emptypb.Empty] -} - -// Listen calls services.kon.github_actions.v1.GitHubWebhookListenerService.Listen. -func (c *gitHubWebhookListenerServiceClient) Listen(ctx context.Context, req *connect_go.Request[structpb.Struct]) (*connect_go.Response[emptypb.Empty], error) { - return c.listen.CallUnary(ctx, req) -} - -// GitHubWebhookListenerServiceHandler is an implementation of the -// services.kon.github_actions.v1.GitHubWebhookListenerService service. -type GitHubWebhookListenerServiceHandler interface { - Listen(context.Context, *connect_go.Request[structpb.Struct]) (*connect_go.Response[emptypb.Empty], error) -} - -// NewGitHubWebhookListenerServiceHandler builds an HTTP handler from the service implementation. It -// returns the path on which to mount the handler and the handler itself. -// -// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf -// and JSON codecs. They also support gzip compression. -func NewGitHubWebhookListenerServiceHandler(svc GitHubWebhookListenerServiceHandler, opts ...connect_go.HandlerOption) (string, http.Handler) { - mux := http.NewServeMux() - mux.Handle(GitHubWebhookListenerServiceListenProcedure, connect_go.NewUnaryHandler( - GitHubWebhookListenerServiceListenProcedure, - svc.Listen, - opts..., - )) - return "/services.kon.github_actions.v1.GitHubWebhookListenerService/", mux -} - -// UnimplementedGitHubWebhookListenerServiceHandler returns CodeUnimplemented from all methods. -type UnimplementedGitHubWebhookListenerServiceHandler struct{} - -func (UnimplementedGitHubWebhookListenerServiceHandler) Listen(context.Context, *connect_go.Request[structpb.Struct]) (*connect_go.Response[emptypb.Empty], error) { - return nil, connect_go.NewError(connect_go.CodeUnimplemented, errors.New("services.kon.github_actions.v1.GitHubWebhookListenerService.Listen is not implemented")) -} diff --git a/services/kon/github_actions/v1/server/build_job.go b/services/kon/github_actions/v1/server/build_job.go index 14277adb..b9d936fb 100644 --- a/services/kon/github_actions/v1/server/build_job.go +++ b/services/kon/github_actions/v1/server/build_job.go @@ -4,25 +4,26 @@ import ( "context" "fmt" - connect_go "github.com/bufbuild/connect-go" + "connectrpc.com/connect" + "github.com/google/go-github/v56/github" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + common_v1 "github.com/containerish/OpenRegistry/common/v1" v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/google/go-github/v56/github" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) // BulkDeleteBuildJobs implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) BulkDeleteBuildJobs( ctx context.Context, - req *connect_go.Request[v1.BulkDeleteBuildJobsRequest], + req *connect.Request[v1.BulkDeleteBuildJobsRequest], ) ( - *connect_go.Response[v1.BulkDeleteBuildJobsResponse], + *connect.Response[v1.BulkDeleteBuildJobsResponse], error, ) { // githubClient := gha.getGithubClientFromContext(ctx) // if err := req.Msg.Validate(); err != nil { - // return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + // return nil, connect.NewError(connect.CodeInvalidArgument, err) // } // // errList := []error{} @@ -34,16 +35,16 @@ func (gha *GitHubActionsServer) BulkDeleteBuildJobs( // } // // if len(errList) > 0 { - // return nil, connect_go.NewError(connect_go.CodeInternal, fmt.Errorf("%v", errList)) + // return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("%v", errList)) // } // - // return connect_go.NewResponse(&v1.BulkDeleteBuildJobsResponse{ + // return connect.NewResponse(&v1.BulkDeleteBuildJobsResponse{ // Message: fmt.Sprintf("%d build jobs deleted successfully", len(req.Msg.GetJobIds())), // }), nil gha.logger.Debug().Str("procedure", req.Spec().Procedure).Bool("method_not_implemented", true).Send() return nil, - connect_go.NewError( - connect_go.CodeUnimplemented, + connect.NewError( + connect.CodeUnimplemented, fmt.Errorf("bulk job deletion is not supported by GitHub Actions integration"), ) } @@ -51,9 +52,9 @@ func (gha *GitHubActionsServer) BulkDeleteBuildJobs( // CancelBuild implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) CancelBuild( ctx context.Context, - req *connect_go.Request[v1.CancelBuildRequest], + req *connect.Request[v1.CancelBuildRequest], ) ( - *connect_go.Response[v1.CancelBuildResponse], + *connect.Response[v1.CancelBuildResponse], error, ) { logEvent := gha.logger.Debug().Str("procedure", req.Spec().Procedure) @@ -62,7 +63,7 @@ func (gha *GitHubActionsServer) CancelBuild( if err := req.Msg.Validate(); err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } _, err := githubClient.Actions.CancelWorkflowRunByID( @@ -73,11 +74,11 @@ func (gha *GitHubActionsServer) CancelBuild( ) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(&v1.CancelBuildResponse{ + return connect.NewResponse(&v1.CancelBuildResponse{ Message: "build job canceled successfully", }), nil } @@ -87,26 +88,26 @@ func (gha *GitHubActionsServer) CancelBuild( // or deleting them isn't the best we can provide to the user. func (gha *GitHubActionsServer) DeleteJob( ctx context.Context, - req *connect_go.Request[v1.DeleteJobRequest], + req *connect.Request[v1.DeleteJobRequest], ) ( - *connect_go.Response[v1.DeleteJobResponse], + *connect.Response[v1.DeleteJobResponse], error, ) { // githubClient := gha.getGithubClientFromContext(ctx) // user := ctx.Value(OpenRegistryUserContextKey).(*types.User) // if err := req.Msg.Validate(); err != nil { - // return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + // return nil, connect.NewError(connect.CodeInvalidArgument, err) // } // _, err := githubClient.Actions.DeleteWorkflowRun(ctx, user.Username, req.Msg.GetRepo(), req.Msg.GetRunId()) // if err != nil { - // return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + // return nil, connect.NewError(connect.CodeInvalidArgument, err) // } gha.logger.Debug().Str("procedure", req.Spec().Procedure).Bool("method_not_implemented", true).Send() return nil, - connect_go.NewError( - connect_go.CodeUnimplemented, + connect.NewError( + connect.CodeUnimplemented, fmt.Errorf("job deletion is not supported by GitHub Actions integration"), ) } @@ -114,16 +115,16 @@ func (gha *GitHubActionsServer) DeleteJob( // GetBuildJob implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) GetBuildJob( ctx context.Context, - req *connect_go.Request[v1.GetBuildJobRequest], + req *connect.Request[v1.GetBuildJobRequest], ) ( - *connect_go.Response[v1.GetBuildJobResponse], + *connect.Response[v1.GetBuildJobResponse], error, ) { logEvent := gha.logger.Debug().Str("procedure", req.Spec().Procedure) err := req.Msg.Validate() if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } user := ctx.Value(OpenRegistryUserContextKey).(*types.User) @@ -139,10 +140,10 @@ func (gha *GitHubActionsServer) GetBuildJob( ) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } - resp := connect_go.NewResponse(&v1.GetBuildJobResponse{ + resp := connect.NewResponse(&v1.GetBuildJobResponse{ // Id: job.GetID(), LogsUrl: job.GetLogsURL(), Status: job.GetStatus(), @@ -161,16 +162,16 @@ func (gha *GitHubActionsServer) GetBuildJob( // ListBuildJobs implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) ListBuildJobs( ctx context.Context, - req *connect_go.Request[v1.ListBuildJobsRequest], + req *connect.Request[v1.ListBuildJobsRequest], ) ( - *connect_go.Response[v1.ListBuildJobsResponse], + *connect.Response[v1.ListBuildJobsResponse], error, ) { logEvent := gha.logger.Debug().Str("procedure", req.Spec().Procedure) err := req.Msg.Validate() if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } user := ctx.Value(OpenRegistryUserContextKey).(*types.User) @@ -183,10 +184,9 @@ func (gha *GitHubActionsServer) ListBuildJobs( ListOptions: github.ListOptions{Page: 0, PerPage: 75}, }, ) - if err != nil { logEvent.Err(err).Any("request_body", req.Msg).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } jobs := []*v1.GetBuildJobResponse{} @@ -210,31 +210,31 @@ func (gha *GitHubActionsServer) ListBuildJobs( } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(&v1.ListBuildJobsResponse{Jobs: jobs}), nil + return connect.NewResponse(&v1.ListBuildJobsResponse{Jobs: jobs}), nil } // StoreJob implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) StoreJob( ctx context.Context, - req *connect_go.Request[v1.StoreJobRequest], -) (*connect_go.Response[v1.StoreJobResponse], error) { + req *connect.Request[v1.StoreJobRequest], +) (*connect.Response[v1.StoreJobResponse], error) { // err := req.Msg.Validate() // if err != nil { - // return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + // return nil, connect.NewError(connect.CodeInvalidArgument, err) // } // // req.Msg.TriggeredAt = timestamppb.New(time.Now()) // if err = gha.store.StoreJob(ctx, req.Msg); err != nil { - // return nil, connect_go.NewError(connect_go.CodeInternal, err) + // return nil, connect.NewError(connect.CodeInternal, err) // } - // return connect_go.NewResponse(&v1.StoreJobResponse{ + // return connect.NewResponse(&v1.StoreJobResponse{ // Message: "job stored successfully", // }), nil gha.logger.Debug().Str("procedure", req.Spec().Procedure).Bool("method_not_implemented", true).Send() - return nil, connect_go.NewError( - connect_go.CodeUnimplemented, + return nil, connect.NewError( + connect.CodeUnimplemented, fmt.Errorf("job storing is not supported by GitHub Actions integration"), ) } @@ -242,9 +242,9 @@ func (gha *GitHubActionsServer) StoreJob( // TriggerBuild implements github_actions_v1connect.GithubActionsBuildServiceHandler func (gha *GitHubActionsServer) TriggerBuild( ctx context.Context, - req *connect_go.Request[v1.TriggerBuildRequest], + req *connect.Request[v1.TriggerBuildRequest], ) ( - *connect_go.Response[v1.TriggerBuildResponse], + *connect.Response[v1.TriggerBuildResponse], error, ) { logEvent := gha.logger.Debug().Str("procedure", req.Spec().Procedure) @@ -253,7 +253,7 @@ func (gha *GitHubActionsServer) TriggerBuild( if err := req.Msg.Validate(); err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } _, err := githubClient.Actions.RerunWorkflowByID( @@ -263,14 +263,13 @@ func (gha *GitHubActionsServer) TriggerBuild( 0, // req.Msg.GetRunId(), ) - if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(&v1.TriggerBuildResponse{ + return connect.NewResponse(&v1.TriggerBuildResponse{ Message: "job triggered successfully", }), nil } diff --git a/services/kon/github_actions/v1/server/build_logs.go b/services/kon/github_actions/v1/server/build_logs.go index a6b507e3..6a8abd4c 100644 --- a/services/kon/github_actions/v1/server/build_logs.go +++ b/services/kon/github_actions/v1/server/build_logs.go @@ -1,22 +1,22 @@ package server import ( - "net/url" - "archive/zip" "bytes" "context" "fmt" "net/http" + "net/url" "strconv" "strings" "time" + "connectrpc.com/connect" "github.com/bradleyfalzon/ghinstallation/v2" - connect_go "github.com/bufbuild/connect-go" + "github.com/google/go-github/v56/github" + github_actions_v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" github_impl "github.com/containerish/OpenRegistry/vcs/github" - "github.com/google/go-github/v56/github" ) type WorkflowStep struct { @@ -27,8 +27,8 @@ type WorkflowStep struct { func (ghs *GitHubActionsServer) streamPreviousRunLogs( ctx context.Context, - req *connect_go.Request[github_actions_v1.StreamWorkflowRunLogsRequest], - stream *connect_go.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], + req *connect.Request[github_actions_v1.StreamWorkflowRunLogsRequest], + stream *connect.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], githubClient *github.Client, ) error { logEvent := ghs.logger.Debug().Str("method", "streamPreviousRunLogs") @@ -44,19 +44,19 @@ func (ghs *GitHubActionsServer) streamPreviousRunLogs( ) if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeUnavailable, err) + return connect.NewError(connect.CodeUnavailable, err) } if len(runs.WorkflowRuns) < 1 { errMsg := fmt.Errorf("no github actions run found for this id") logEvent.Err(errMsg).Send() - return connect_go.NewError(connect_go.CodeInvalidArgument, errMsg) + return connect.NewError(connect.CodeInvalidArgument, errMsg) } workflowSteps, err := ghs.getLogsToStream(ctx, githubClient, runs.WorkflowRuns[0].GetLogsURL()) if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeInvalidArgument, err) + return connect.NewError(connect.CodeInvalidArgument, err) } for _, step := range workflowSteps { @@ -71,12 +71,12 @@ func (ghs *GitHubActionsServer) streamPreviousRunLogs( func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( ctx context.Context, - req *connect_go.Request[github_actions_v1.StreamWorkflowRunLogsRequest], - stream *connect_go.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], + req *connect.Request[github_actions_v1.StreamWorkflowRunLogsRequest], + stream *connect.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], ) error { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) if err := req.Msg.Validate(); err != nil { - return connect_go.NewError(connect_go.CodeInvalidArgument, err) + return connect.NewError(connect.CodeInvalidArgument, err) } logEvent. @@ -89,8 +89,8 @@ func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( if !ok { errMsg := fmt.Errorf("github app installation id not found for user") logEvent.Err(errMsg).Send() - return connect_go.NewError( - connect_go.CodeInvalidArgument, errMsg, + return connect.NewError( + connect.CodeInvalidArgument, errMsg, ) } @@ -106,7 +106,7 @@ func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( err := ghs.waitForJobToFinish(ctx, githubClient, req, stream) if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeInvalidArgument, err) + return connect.NewError(connect.CodeInvalidArgument, err) } delete(ghs.activeLogStreamJobs, ghs.getLogsEventKey(req.Msg)) @@ -119,7 +119,7 @@ func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( if !ok { errMsg := fmt.Errorf("missing GitHub App installation ID") logEvent.Err(errMsg).Send() - return connect_go.NewError(connect_go.CodeInternal, errMsg) + return connect.NewError(connect.CodeInternal, errMsg) } client := ghs.refreshGHClient(githubAppInstallation) @@ -134,17 +134,16 @@ func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( }, }, ) - if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeInternal, err) + return connect.NewError(connect.CodeInternal, err) } runID := actionRuns.WorkflowRuns[0].GetID() uri, err := ghs.getWorkflowRunLogsURL(ctx, req.Msg.GetRepoOwner(), req.Msg.GetRepoName(), runID) if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeNotFound, err) + return connect.NewError(connect.CodeNotFound, err) } workflowSteps, err := ghs.getLogsToStream(ctx, githubClient, uri.String()) @@ -158,7 +157,6 @@ func (ghs *GitHubActionsServer) StreamWorkflowRunLogs( LogMessage: step.Buf.String(), MsgType: github_actions_v1.StreamWorkflowRunMessageType_STREAM_WORKFLOW_RUN_MESSAGE_TYPE_STEP, }) - } logEvent.Bool("success", true).Send() @@ -220,7 +218,6 @@ func (ghs *GitHubActionsServer) retryGetWorkflowRunLogsURL( } return logsUrl, logsErr - } func (ghs *GitHubActionsServer) getWorkflowRunLogsURL( @@ -236,22 +233,22 @@ func (ghs *GitHubActionsServer) getWorkflowRunLogsURL( func (ghs *GitHubActionsServer) DumpLogs( ctx context.Context, - req *connect_go.Request[github_actions_v1.DumpLogsRequest], + req *connect.Request[github_actions_v1.DumpLogsRequest], ) ( - *connect_go.Response[github_actions_v1.DumpLogsResponse], + *connect.Response[github_actions_v1.DumpLogsResponse], error, ) { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) if err := req.Msg.Validate(); err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } ghAppInstallationID, ok := ctx.Value(github_impl.GithubInstallationIDContextKey).(int64) if !ok { errMsg := fmt.Errorf("github app installation id not found for user") logEvent.Err(errMsg).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, errMsg) + return nil, connect.NewError(connect.CodeInvalidArgument, errMsg) } githubClient := ghs.refreshGHClient(ghAppInstallationID) @@ -268,19 +265,19 @@ func (ghs *GitHubActionsServer) DumpLogs( ) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeUnavailable, err) + return nil, connect.NewError(connect.CodeUnavailable, err) } if len(runs.WorkflowRuns) < 1 { errMsg := fmt.Errorf("no github actions run found for this id") logEvent.Err(errMsg).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, errMsg) + return nil, connect.NewError(connect.CodeInvalidArgument, errMsg) } workflowSteps, err := ghs.getLogsToStream(ctx, githubClient, runs.WorkflowRuns[0].GetLogsURL()) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } var logs []string for _, step := range workflowSteps { @@ -288,7 +285,7 @@ func (ghs *GitHubActionsServer) DumpLogs( } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(&github_actions_v1.DumpLogsResponse{Logs: logs}), nil + return connect.NewResponse(&github_actions_v1.DumpLogsResponse{Logs: logs}), nil } func (ghs *GitHubActionsServer) getLogsEventKey(job *github_actions_v1.StreamWorkflowRunLogsRequest) string { @@ -312,11 +309,15 @@ func (ghs *GitHubActionsServer) getFileInfo(fi *zip.File) (string, int64) { func (ghs *GitHubActionsServer) waitForJobToFinish( ctx context.Context, githubClient *github.Client, - req *connect_go.Request[github_actions_v1.StreamWorkflowRunLogsRequest], - stream *connect_go.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], + req *connect.Request[github_actions_v1.StreamWorkflowRunLogsRequest], + stream *connect.ServerStream[github_actions_v1.StreamWorkflowRunLogsResponse], ) error { now := time.Now() - logEvent := ghs.logger.Debug().Str("method", "waitForJobToFinish") + logEvent := ghs.logger.Debug(). + Str("method", "waitForJobToFinish"). + Int64("run_id", req.Msg.GetRunId()). + Str("repo_name", req.Msg.GetRepoName()). + Str("repo_owner", req.Msg.GetRepoOwner()) workflowRun, _, err := githubClient.Actions.GetWorkflowRunByID( ctx, @@ -326,7 +327,7 @@ func (ghs *GitHubActionsServer) waitForJobToFinish( ) if err != nil { logEvent.Err(err).Send() - return connect_go.NewError(connect_go.CodeInvalidArgument, err) + return connect.NewError(connect.CodeInvalidArgument, err) } logEvent.Str("status", workflowRun.GetStatus()) diff --git a/services/kon/github_actions/v1/server/build_project.go b/services/kon/github_actions/v1/server/build_project.go index a72b69f7..8147aad6 100644 --- a/services/kon/github_actions/v1/server/build_project.go +++ b/services/kon/github_actions/v1/server/build_project.go @@ -2,45 +2,41 @@ package server import ( "context" - "time" - connect_go "github.com/bufbuild/connect-go" + "connectrpc.com/connect" + "github.com/google/uuid" + "google.golang.org/protobuf/types/known/timestamppb" + common_v1 "github.com/containerish/OpenRegistry/common/v1" github_actions_v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/containerish/OpenRegistry/vcs/github" - "github.com/google/uuid" - "google.golang.org/protobuf/types/known/timestamppb" ) // CreateProject implements github_actions_v1connect.GitHubActionsProjectServiceHandler func (ghs *GitHubActionsServer) CreateProject( ctx context.Context, - req *connect_go.Request[github_actions_v1.CreateProjectRequest], + req *connect.Request[github_actions_v1.CreateProjectRequest], ) ( - *connect_go.Response[github_actions_v1.CreateProjectResponse], + *connect.Response[github_actions_v1.CreateProjectResponse], error, ) { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) err := req.Msg.Validate() if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) - } - - if err = req.Msg.GetCreatedAt().CheckValid(); err != nil { - req.Msg.CreatedAt = timestamppb.New(time.Now()) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } req.Msg.Id = &common_v1.UUID{ Value: uuid.New().String(), } + req.Msg.CreatedAt = timestamppb.Now() if err = ghs.store.StoreProject(ctx, req.Msg); err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } - resp := connect_go.NewResponse(&github_actions_v1.CreateProjectResponse{ + resp := connect.NewResponse(&github_actions_v1.CreateProjectResponse{ Message: "project created successfully", Id: req.Msg.GetId(), }) @@ -52,24 +48,24 @@ func (ghs *GitHubActionsServer) CreateProject( // DeleteProject implements github_actions_v1connect.GitHubActionsProjectServiceHandler func (ghs *GitHubActionsServer) DeleteProject( ctx context.Context, - req *connect_go.Request[github_actions_v1.DeleteProjectRequest], + req *connect.Request[github_actions_v1.DeleteProjectRequest], ) ( - *connect_go.Response[github_actions_v1.DeleteProjectResponse], + *connect.Response[github_actions_v1.DeleteProjectResponse], error, ) { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) err := req.Msg.Validate() if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } if err = ghs.store.DeleteProject(ctx, req.Msg); err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } - resp := connect_go.NewResponse(&github_actions_v1.DeleteProjectResponse{ + resp := connect.NewResponse(&github_actions_v1.DeleteProjectResponse{ Message: "project deleted successfully", }) @@ -80,41 +76,40 @@ func (ghs *GitHubActionsServer) DeleteProject( // GetProject implements github_actions_v1connect.GitHubActionsProjectServiceHandler func (ghs *GitHubActionsServer) GetProject( ctx context.Context, - req *connect_go.Request[github_actions_v1.GetProjectRequest], + req *connect.Request[github_actions_v1.GetProjectRequest], ) ( - *connect_go.Response[github_actions_v1.GetProjectResponse], + *connect.Response[github_actions_v1.GetProjectResponse], error, ) { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) if err := req.Msg.Validate(); err != nil { - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } project, err := ghs.store.GetProject(ctx, req.Msg) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(project), nil + return connect.NewResponse(project), nil } // ListProjects implements github_actions_v1connect.GitHubActionsProjectServiceHandler func (ghs *GitHubActionsServer) ListProjects( ctx context.Context, - req *connect_go.Request[github_actions_v1.ListProjectsRequest], + req *connect.Request[github_actions_v1.ListProjectsRequest], ) ( - *connect_go.Response[github_actions_v1.ListProjectsResponse], + *connect.Response[github_actions_v1.ListProjectsResponse], error, ) { logEvent := ghs.logger.Debug().Str("procedure", req.Spec().Procedure) - user := ctx.Value(github.UserContextKey).(*types.User) - ghs.logger.Debug().Any("user", user).Send() + user := ctx.Value(types.UserContextKey).(*types.User) err := req.Msg.Validate() if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInvalidArgument, err) + return nil, connect.NewError(connect.CodeInvalidArgument, err) } req.Msg.OwnerId = &common_v1.UUID{ @@ -124,9 +119,9 @@ func (ghs *GitHubActionsServer) ListProjects( projects, err := ghs.store.ListProjects(ctx, req.Msg) if err != nil { logEvent.Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } logEvent.Bool("success", true).Send() - return connect_go.NewResponse(projects), nil + return connect.NewResponse(projects), nil } diff --git a/services/kon/github_actions/v1/server/github_action_logs.go b/services/kon/github_actions/v1/server/github_action_logs.go index 86e6239e..547c8fc4 100644 --- a/services/kon/github_actions/v1/server/github_action_logs.go +++ b/services/kon/github_actions/v1/server/github_action_logs.go @@ -9,7 +9,7 @@ import ( "net/http" "sort" - connect_go "github.com/bufbuild/connect-go" + "connectrpc.com/connect" "github.com/google/go-github/v56/github" ) @@ -21,14 +21,14 @@ func (ghs *GitHubActionsServer) getLogsToStream( downloadLogsReq, err := http.NewRequestWithContext(ctx, http.MethodGet, logsURL, nil) if err != nil { ghs.logger.Debug().Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } downloadLogsReq.Header.Set("Accept", "application/json") downloadLogsResp, err := githubClient.BareDo(ctx, downloadLogsReq) if err != nil { ghs.logger.Debug().Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } defer downloadLogsResp.Body.Close() @@ -36,14 +36,14 @@ func (ghs *GitHubActionsServer) getLogsToStream( _, err = io.Copy(&buf, downloadLogsResp.Body) if err != nil { ghs.logger.Debug().Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } reader := bytes.NewReader(buf.Bytes()) zipReader, err := zip.NewReader(reader, int64(buf.Len())) if err != nil { ghs.logger.Debug().Err(err).Send() - return nil, connect_go.NewError(connect_go.CodeInternal, err) + return nil, connect.NewError(connect.CodeInternal, err) } logEvent := ghs.logger.Debug().Int("zip_file_count", len(zipReader.File)) @@ -80,7 +80,7 @@ func (ghs *GitHubActionsServer) getLogsToStream( sort.SliceStable(workflowSteps, func(i, j int) bool { return workflowSteps[i].StepPosition < workflowSteps[j].StepPosition }) - ghs.logger.Log(nil, nil).Str("done_slice_sort", "true").Send() + ghs.logger.Debug().Str("done_slice_sort", "true").Send() if len(errList) > 0 { return nil, fmt.Errorf("%v", errList) } diff --git a/services/kon/github_actions/v1/server/github_event_listener.go b/services/kon/github_actions/v1/server/github_event_listener.go index 8edf31e3..7f12b0fd 100644 --- a/services/kon/github_actions/v1/server/github_event_listener.go +++ b/services/kon/github_actions/v1/server/github_event_listener.go @@ -21,7 +21,7 @@ func (ghs *GitHubActionsServer) Listen(resp http.ResponseWriter, req *http.Reque ) if err != nil { - ghs.logger.Log(nil, nil). + ghs.logger.Debug(). Str("method", "Listen"). Str("error", err.Error()). Send() @@ -31,7 +31,7 @@ func (ghs *GitHubActionsServer) Listen(resp http.ResponseWriter, req *http.Reque event, err := github.ParseWebHook(github.WebHookType(req), payload) if err != nil { - ghs.logger.Log(nil, nil). + ghs.logger.Debug(). Str("method", "Listen"). Str("error", err.Error()). Send() @@ -51,7 +51,7 @@ func (ghs *GitHubActionsServer) Listen(resp http.ResponseWriter, req *http.Reque action: event.GetAction(), } eventKey := ghs.getLogsEventKey(val.req) - ghs.logger.Log(nil, nil). + ghs.logger.Debug(). Str("method", "Listen"). Str("github_event", "WorkflowRunEvent"). Int64("workflow_id", event.GetWorkflowRun().GetID()). diff --git a/services/kon/github_actions/v1/server/interceptor.go b/services/kon/github_actions/v1/server/interceptor.go index 78015897..069aec9f 100644 --- a/services/kon/github_actions/v1/server/interceptor.go +++ b/services/kon/github_actions/v1/server/interceptor.go @@ -4,8 +4,10 @@ import ( "context" "fmt" - "github.com/bufbuild/connect-go" + "connectrpc.com/connect" + "github.com/containerish/OpenRegistry/config" + "github.com/containerish/OpenRegistry/store/v1/types" "github.com/containerish/OpenRegistry/telemetry" "github.com/containerish/OpenRegistry/vcs" "github.com/containerish/OpenRegistry/vcs/github" @@ -38,7 +40,7 @@ func NewGitHubAppUsernameInterceptor( } logEvent.Bool("success", true).Send() - ctx = context.WithValue(ctx, github.UsernameContextKey, user.Username) + ctx = context.WithValue(ctx, types.UserContextKey, user) return next(ctx, req) }) }) @@ -64,7 +66,7 @@ func PopulateContextWithUserInterceptor( } logEvent.Bool("success", true).Send() - ctx = context.WithValue(ctx, github.UsernameContextKey, user.Username) + ctx = context.WithValue(ctx, types.UserContextKey, user) return next(ctx, req) }) }) @@ -106,8 +108,7 @@ func (i *githubAppStreamingInterceptor) WrapUnary(next connect.UnaryFunc) connec ctx = context.WithValue(ctx, OpenRegistryUserContextKey, user) logEvent.Bool("success", true) - ctx = context.WithValue(ctx, github.UsernameContextKey, user.Username) - ctx = context.WithValue(ctx, github.UserContextKey, user) + ctx = context.WithValue(ctx, types.UserContextKey, user) skip := false for _, r := range i.routesToSkip { if req.Spec().Procedure == r { @@ -119,6 +120,7 @@ func (i *githubAppStreamingInterceptor) WrapUnary(next connect.UnaryFunc) connec logEvent.Bool("skip_check", true).Str("Procedure", req.Spec().Procedure).Send() return next(ctx, req) } + githubIdentity := user.Identities.GetGitHubIdentity() if githubIdentity == nil { errMsg := fmt.Errorf("github identity is not available") @@ -165,7 +167,7 @@ func (i *githubAppStreamingInterceptor) WrapStreamingHandler( } logEvent.Bool("success", true).Send() - ctx = context.WithValue(ctx, github.UsernameContextKey, user.Username) + ctx = context.WithValue(ctx, types.UserContextKey, user) skip := false for _, r := range i.routesToSkip { if conn.Spec().Procedure == r { diff --git a/services/kon/github_actions/v1/server/interceptor_helpers.go b/services/kon/github_actions/v1/server/interceptor_helpers.go index 4d3cad0f..331b3392 100644 --- a/services/kon/github_actions/v1/server/interceptor_helpers.go +++ b/services/kon/github_actions/v1/server/interceptor_helpers.go @@ -7,11 +7,12 @@ import ( "net/url" "strings" - "github.com/bufbuild/connect-go" - "github.com/containerish/OpenRegistry/auth" - "github.com/containerish/OpenRegistry/telemetry" + "connectrpc.com/connect" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" + + "github.com/containerish/OpenRegistry/auth" + "github.com/containerish/OpenRegistry/telemetry" ) func getTokenFromReq(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) { diff --git a/services/kon/github_actions/v1/server/server.go b/services/kon/github_actions/v1/server/server.go index 82e49197..b25e66cc 100644 --- a/services/kon/github_actions/v1/server/server.go +++ b/services/kon/github_actions/v1/server/server.go @@ -5,21 +5,22 @@ import ( "net/http" "sync" + "connectrpc.com/connect" "github.com/bradleyfalzon/ghinstallation/v2" - "github.com/bufbuild/connect-go" + "github.com/fatih/color" + "github.com/google/go-github/v56/github" + "github.com/containerish/OpenRegistry/config" github_actions_v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" connect_v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1/github_actions_v1connect" "github.com/containerish/OpenRegistry/store/v1/automation" "github.com/containerish/OpenRegistry/telemetry" "github.com/containerish/OpenRegistry/vcs" - "github.com/fatih/color" - "github.com/google/go-github/v56/github" ) type GitHubActionsServer struct { logger telemetry.Logger - config *config.Integration + config *config.GithubIntegration github *github.Client transport *ghinstallation.AppsTransport store automation.BuildAutomationStore @@ -33,7 +34,7 @@ type streamLogsJob struct { } func NewGithubActionsServer( - config *config.Integration, + config *config.GithubIntegration, authConfig *config.Auth, logger telemetry.Logger, store automation.BuildAutomationStore, diff --git a/services/yor/clair/v1/clair.pb.go b/services/yor/clair/v1/clair.pb.go new file mode 100644 index 00000000..786acd1a --- /dev/null +++ b/services/yor/clair/v1/clair.pb.go @@ -0,0 +1,1690 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc (unknown) +// source: services/yor/clair/v1/clair.proto + +package clair + +import ( + v1 "github.com/containerish/OpenRegistry/common/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type EnableVulnerabilityScanningRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RepositoryId *v1.UUID `protobuf:"bytes,1,opt,name=repository_id,json=repositoryId,proto3" json:"repository_id,omitempty"` +} + +func (x *EnableVulnerabilityScanningRequest) Reset() { + *x = EnableVulnerabilityScanningRequest{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EnableVulnerabilityScanningRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnableVulnerabilityScanningRequest) ProtoMessage() {} + +func (x *EnableVulnerabilityScanningRequest) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EnableVulnerabilityScanningRequest.ProtoReflect.Descriptor instead. +func (*EnableVulnerabilityScanningRequest) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{0} +} + +func (x *EnableVulnerabilityScanningRequest) GetRepositoryId() *v1.UUID { + if x != nil { + return x.RepositoryId + } + return nil +} + +type EnableVulnerabilityScanningResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *EnableVulnerabilityScanningResponse) Reset() { + *x = EnableVulnerabilityScanningResponse{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EnableVulnerabilityScanningResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnableVulnerabilityScanningResponse) ProtoMessage() {} + +func (x *EnableVulnerabilityScanningResponse) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EnableVulnerabilityScanningResponse.ProtoReflect.Descriptor instead. +func (*EnableVulnerabilityScanningResponse) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{1} +} + +func (x *EnableVulnerabilityScanningResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type ClairReportPackage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Kind string `protobuf:"bytes,4,opt,name=kind,proto3" json:"kind,omitempty"` + Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"` + Source *ClairPackageSource `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *ClairReportPackage) Reset() { + *x = ClairReportPackage{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairReportPackage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairReportPackage) ProtoMessage() {} + +func (x *ClairReportPackage) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairReportPackage.ProtoReflect.Descriptor instead. +func (*ClairReportPackage) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{2} +} + +func (x *ClairReportPackage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ClairReportPackage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ClairReportPackage) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ClairReportPackage) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *ClairReportPackage) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +func (x *ClairReportPackage) GetSource() *ClairPackageSource { + if x != nil { + return x.Source + } + return nil +} + +type SubmitManifestToScanResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + ManifestHash string `protobuf:"bytes,2,opt,name=manifest_hash,json=manifestHash,proto3" json:"manifest_hash,omitempty"` + State string `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + Err string `protobuf:"bytes,4,opt,name=err,proto3" json:"err,omitempty"` + Packages map[string]*ClairReportPackage `protobuf:"bytes,5,rep,name=packages,proto3" json:"packages,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Distributions map[string]*ClairDistribution `protobuf:"bytes,6,rep,name=distributions,proto3" json:"distributions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Repository map[string]*ClairRepository `protobuf:"bytes,7,rep,name=repository,proto3" json:"repository,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Environments map[string]*structpb.ListValue `protobuf:"bytes,8,rep,name=environments,proto3" json:"environments,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SubmitManifestToScanResponse) Reset() { + *x = SubmitManifestToScanResponse{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitManifestToScanResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitManifestToScanResponse) ProtoMessage() {} + +func (x *SubmitManifestToScanResponse) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitManifestToScanResponse.ProtoReflect.Descriptor instead. +func (*SubmitManifestToScanResponse) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{3} +} + +func (x *SubmitManifestToScanResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *SubmitManifestToScanResponse) GetManifestHash() string { + if x != nil { + return x.ManifestHash + } + return "" +} + +func (x *SubmitManifestToScanResponse) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *SubmitManifestToScanResponse) GetErr() string { + if x != nil { + return x.Err + } + return "" +} + +func (x *SubmitManifestToScanResponse) GetPackages() map[string]*ClairReportPackage { + if x != nil { + return x.Packages + } + return nil +} + +func (x *SubmitManifestToScanResponse) GetDistributions() map[string]*ClairDistribution { + if x != nil { + return x.Distributions + } + return nil +} + +func (x *SubmitManifestToScanResponse) GetRepository() map[string]*ClairRepository { + if x != nil { + return x.Repository + } + return nil +} + +func (x *SubmitManifestToScanResponse) GetEnvironments() map[string]*structpb.ListValue { + if x != nil { + return x.Environments + } + return nil +} + +type ClairDescriptor struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Uri string `protobuf:"bytes,2,opt,name=uri,proto3" json:"uri,omitempty"` + Headers map[string]*structpb.ListValue `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ClairDescriptor) Reset() { + *x = ClairDescriptor{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairDescriptor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairDescriptor) ProtoMessage() {} + +func (x *ClairDescriptor) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairDescriptor.ProtoReflect.Descriptor instead. +func (*ClairDescriptor) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{4} +} + +func (x *ClairDescriptor) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *ClairDescriptor) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *ClairDescriptor) GetHeaders() map[string]*structpb.ListValue { + if x != nil { + return x.Headers + } + return nil +} + +type SubmitManifestToScanRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (x *SubmitManifestToScanRequest) Reset() { + *x = SubmitManifestToScanRequest{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitManifestToScanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitManifestToScanRequest) ProtoMessage() {} + +func (x *SubmitManifestToScanRequest) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitManifestToScanRequest.ProtoReflect.Descriptor instead. +func (*SubmitManifestToScanRequest) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{5} +} + +func (x *SubmitManifestToScanRequest) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +type GetVulnerabilityReportRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ManifestId string `protobuf:"bytes,1,opt,name=manifest_id,json=manifestId,proto3" json:"manifest_id,omitempty"` +} + +func (x *GetVulnerabilityReportRequest) Reset() { + *x = GetVulnerabilityReportRequest{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetVulnerabilityReportRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVulnerabilityReportRequest) ProtoMessage() {} + +func (x *GetVulnerabilityReportRequest) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVulnerabilityReportRequest.ProtoReflect.Descriptor instead. +func (*GetVulnerabilityReportRequest) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{6} +} + +func (x *GetVulnerabilityReportRequest) GetManifestId() string { + if x != nil { + return x.ManifestId + } + return "" +} + +type ClairIndexManifestRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Layers []*ClairDescriptor `protobuf:"bytes,2,rep,name=layers,proto3" json:"layers,omitempty"` +} + +func (x *ClairIndexManifestRequest) Reset() { + *x = ClairIndexManifestRequest{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairIndexManifestRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairIndexManifestRequest) ProtoMessage() {} + +func (x *ClairIndexManifestRequest) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairIndexManifestRequest.ProtoReflect.Descriptor instead. +func (*ClairIndexManifestRequest) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{7} +} + +func (x *ClairIndexManifestRequest) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +func (x *ClairIndexManifestRequest) GetLayers() []*ClairDescriptor { + if x != nil { + return x.Layers + } + return nil +} + +type ClairPackageSource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Kind string `protobuf:"bytes,4,opt,name=kind,proto3" json:"kind,omitempty"` +} + +func (x *ClairPackageSource) Reset() { + *x = ClairPackageSource{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairPackageSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairPackageSource) ProtoMessage() {} + +func (x *ClairPackageSource) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairPackageSource.ProtoReflect.Descriptor instead. +func (*ClairPackageSource) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{8} +} + +func (x *ClairPackageSource) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ClairPackageSource) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ClairPackageSource) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ClairPackageSource) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +type ClairPackage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Kind string `protobuf:"bytes,4,opt,name=kind,proto3" json:"kind,omitempty"` + Source *ClairPackageSource `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` + Arch string `protobuf:"bytes,6,opt,name=arch,proto3" json:"arch,omitempty"` +} + +func (x *ClairPackage) Reset() { + *x = ClairPackage{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairPackage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairPackage) ProtoMessage() {} + +func (x *ClairPackage) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairPackage.ProtoReflect.Descriptor instead. +func (*ClairPackage) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{9} +} + +func (x *ClairPackage) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ClairPackage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ClairPackage) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ClairPackage) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *ClairPackage) GetSource() *ClairPackageSource { + if x != nil { + return x.Source + } + return nil +} + +func (x *ClairPackage) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +type ClairDistribution struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Did string `protobuf:"bytes,2,opt,name=did,proto3" json:"did,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + VersionCodeName string `protobuf:"bytes,5,opt,name=version_code_name,json=versionCodeName,proto3" json:"version_code_name,omitempty"` + VersionId string `protobuf:"bytes,6,opt,name=version_id,json=versionId,proto3" json:"version_id,omitempty"` + Arch string `protobuf:"bytes,7,opt,name=arch,proto3" json:"arch,omitempty"` + Cpe string `protobuf:"bytes,8,opt,name=cpe,proto3" json:"cpe,omitempty"` + PrettyName string `protobuf:"bytes,9,opt,name=pretty_name,json=prettyName,proto3" json:"pretty_name,omitempty"` +} + +func (x *ClairDistribution) Reset() { + *x = ClairDistribution{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairDistribution) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairDistribution) ProtoMessage() {} + +func (x *ClairDistribution) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairDistribution.ProtoReflect.Descriptor instead. +func (*ClairDistribution) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{10} +} + +func (x *ClairDistribution) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ClairDistribution) GetDid() string { + if x != nil { + return x.Did + } + return "" +} + +func (x *ClairDistribution) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ClairDistribution) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ClairDistribution) GetVersionCodeName() string { + if x != nil { + return x.VersionCodeName + } + return "" +} + +func (x *ClairDistribution) GetVersionId() string { + if x != nil { + return x.VersionId + } + return "" +} + +func (x *ClairDistribution) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +func (x *ClairDistribution) GetCpe() string { + if x != nil { + return x.Cpe + } + return "" +} + +func (x *ClairDistribution) GetPrettyName() string { + if x != nil { + return x.PrettyName + } + return "" +} + +type ClairEnvironmentItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PackageDb string `protobuf:"bytes,1,opt,name=package_db,json=packageDb,proto3" json:"package_db,omitempty"` + IntroducedIn string `protobuf:"bytes,2,opt,name=introduced_in,json=introducedIn,proto3" json:"introduced_in,omitempty"` + DistributionId string `protobuf:"bytes,3,opt,name=distribution_id,json=distributionId,proto3" json:"distribution_id,omitempty"` + RepositoryIds []string `protobuf:"bytes,4,rep,name=repository_ids,json=repositoryIds,proto3" json:"repository_ids,omitempty"` +} + +func (x *ClairEnvironmentItem) Reset() { + *x = ClairEnvironmentItem{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairEnvironmentItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairEnvironmentItem) ProtoMessage() {} + +func (x *ClairEnvironmentItem) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairEnvironmentItem.ProtoReflect.Descriptor instead. +func (*ClairEnvironmentItem) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{11} +} + +func (x *ClairEnvironmentItem) GetPackageDb() string { + if x != nil { + return x.PackageDb + } + return "" +} + +func (x *ClairEnvironmentItem) GetIntroducedIn() string { + if x != nil { + return x.IntroducedIn + } + return "" +} + +func (x *ClairEnvironmentItem) GetDistributionId() string { + if x != nil { + return x.DistributionId + } + return "" +} + +func (x *ClairEnvironmentItem) GetRepositoryIds() []string { + if x != nil { + return x.RepositoryIds + } + return nil +} + +type ClairRepository struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ClairRepository) Reset() { + *x = ClairRepository{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairRepository) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairRepository) ProtoMessage() {} + +func (x *ClairRepository) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairRepository.ProtoReflect.Descriptor instead. +func (*ClairRepository) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{12} +} + +func (x *ClairRepository) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type ClairVulnerability struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Updater string `protobuf:"bytes,2,opt,name=updater,proto3" json:"updater,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + Issued *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=issued,proto3" json:"issued,omitempty"` + Links string `protobuf:"bytes,6,opt,name=links,proto3" json:"links,omitempty"` + Severity string `protobuf:"bytes,7,opt,name=severity,proto3" json:"severity,omitempty"` + NormalizedSeverity string `protobuf:"bytes,8,opt,name=normalized_severity,json=normalizedSeverity,proto3" json:"normalized_severity,omitempty"` + Package *ClairPackage `protobuf:"bytes,9,opt,name=package,proto3" json:"package,omitempty"` + Distribution *ClairDistribution `protobuf:"bytes,10,opt,name=distribution,proto3" json:"distribution,omitempty"` + Repository *ClairRepository `protobuf:"bytes,11,opt,name=repository,proto3" json:"repository,omitempty"` + FixedInVersion string `protobuf:"bytes,12,opt,name=fixed_in_version,json=fixedInVersion,proto3" json:"fixed_in_version,omitempty"` +} + +func (x *ClairVulnerability) Reset() { + *x = ClairVulnerability{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairVulnerability) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairVulnerability) ProtoMessage() {} + +func (x *ClairVulnerability) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairVulnerability.ProtoReflect.Descriptor instead. +func (*ClairVulnerability) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{13} +} + +func (x *ClairVulnerability) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ClairVulnerability) GetUpdater() string { + if x != nil { + return x.Updater + } + return "" +} + +func (x *ClairVulnerability) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ClairVulnerability) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *ClairVulnerability) GetIssued() *timestamppb.Timestamp { + if x != nil { + return x.Issued + } + return nil +} + +func (x *ClairVulnerability) GetLinks() string { + if x != nil { + return x.Links + } + return "" +} + +func (x *ClairVulnerability) GetSeverity() string { + if x != nil { + return x.Severity + } + return "" +} + +func (x *ClairVulnerability) GetNormalizedSeverity() string { + if x != nil { + return x.NormalizedSeverity + } + return "" +} + +func (x *ClairVulnerability) GetPackage() *ClairPackage { + if x != nil { + return x.Package + } + return nil +} + +func (x *ClairVulnerability) GetDistribution() *ClairDistribution { + if x != nil { + return x.Distribution + } + return nil +} + +func (x *ClairVulnerability) GetRepository() *ClairRepository { + if x != nil { + return x.Repository + } + return nil +} + +func (x *ClairVulnerability) GetFixedInVersion() string { + if x != nil { + return x.FixedInVersion + } + return "" +} + +type ClairEnrichment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ClairEnrichment) Reset() { + *x = ClairEnrichment{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairEnrichment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairEnrichment) ProtoMessage() {} + +func (x *ClairEnrichment) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairEnrichment.ProtoReflect.Descriptor instead. +func (*ClairEnrichment) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{14} +} + +func (x *ClairEnrichment) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type ClairVulnerabilityIdList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` +} + +func (x *ClairVulnerabilityIdList) Reset() { + *x = ClairVulnerabilityIdList{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClairVulnerabilityIdList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClairVulnerabilityIdList) ProtoMessage() {} + +func (x *ClairVulnerabilityIdList) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClairVulnerabilityIdList.ProtoReflect.Descriptor instead. +func (*ClairVulnerabilityIdList) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{15} +} + +func (x *ClairVulnerabilityIdList) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type GetVulnerabilityReportResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ManifestHash string `protobuf:"bytes,1,opt,name=manifest_hash,json=manifestHash,proto3" json:"manifest_hash,omitempty"` + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + Err string `protobuf:"bytes,3,opt,name=err,proto3" json:"err,omitempty"` + Success bool `protobuf:"varint,4,opt,name=success,proto3" json:"success,omitempty"` + Packages map[string]*ClairPackage `protobuf:"bytes,5,rep,name=packages,proto3" json:"packages,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Distributions map[string]*ClairDistribution `protobuf:"bytes,6,rep,name=distributions,proto3" json:"distributions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Environments map[string]*structpb.ListValue `protobuf:"bytes,7,rep,name=environments,proto3" json:"environments,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + PackageVulnerabilities map[string]*structpb.ListValue `protobuf:"bytes,8,rep,name=package_vulnerabilities,json=packageVulnerabilities,proto3" json:"package_vulnerabilities,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Enrichments *ClairEnrichment `protobuf:"bytes,9,opt,name=enrichments,proto3" json:"enrichments,omitempty"` + Repository map[string]*ClairRepository `protobuf:"bytes,10,rep,name=repository,proto3" json:"repository,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Vulnerabilities map[string]*ClairVulnerability `protobuf:"bytes,11,rep,name=vulnerabilities,proto3" json:"vulnerabilities,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *GetVulnerabilityReportResponse) Reset() { + *x = GetVulnerabilityReportResponse{} + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetVulnerabilityReportResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetVulnerabilityReportResponse) ProtoMessage() {} + +func (x *GetVulnerabilityReportResponse) ProtoReflect() protoreflect.Message { + mi := &file_services_yor_clair_v1_clair_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetVulnerabilityReportResponse.ProtoReflect.Descriptor instead. +func (*GetVulnerabilityReportResponse) Descriptor() ([]byte, []int) { + return file_services_yor_clair_v1_clair_proto_rawDescGZIP(), []int{16} +} + +func (x *GetVulnerabilityReportResponse) GetManifestHash() string { + if x != nil { + return x.ManifestHash + } + return "" +} + +func (x *GetVulnerabilityReportResponse) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *GetVulnerabilityReportResponse) GetErr() string { + if x != nil { + return x.Err + } + return "" +} + +func (x *GetVulnerabilityReportResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *GetVulnerabilityReportResponse) GetPackages() map[string]*ClairPackage { + if x != nil { + return x.Packages + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetDistributions() map[string]*ClairDistribution { + if x != nil { + return x.Distributions + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetEnvironments() map[string]*structpb.ListValue { + if x != nil { + return x.Environments + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetPackageVulnerabilities() map[string]*structpb.ListValue { + if x != nil { + return x.PackageVulnerabilities + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetEnrichments() *ClairEnrichment { + if x != nil { + return x.Enrichments + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetRepository() map[string]*ClairRepository { + if x != nil { + return x.Repository + } + return nil +} + +func (x *GetVulnerabilityReportResponse) GetVulnerabilities() map[string]*ClairVulnerability { + if x != nil { + return x.Vulnerabilities + } + return nil +} + +var File_services_yor_clair_v1_clair_proto protoreflect.FileDescriptor + +var file_services_yor_clair_v1_clair_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x79, 0x6f, 0x72, 0x2f, 0x63, + 0x6c, 0x61, 0x69, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, + 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5a, 0x0a, + 0x22, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x55, 0x49, 0x44, 0x52, 0x0c, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x23, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbd, 0x01, 0x0a, 0x12, 0x43, + 0x6c, 0x61, 0x69, 0x72, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, + 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x41, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x61, 0x69, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xba, 0x07, 0x0a, 0x1c, 0x53, + 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, + 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, + 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, + 0x72, 0x72, 0x12, 0x5d, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x63, 0x61, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x73, 0x12, 0x6c, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, + 0x6f, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x63, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, + 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x63, 0x61, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x12, 0x69, 0x0a, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x54, 0x6f, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, + 0x66, 0x0a, 0x0d, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, + 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x6a, 0x0a, 0x12, 0x44, 0x69, 0x73, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, + 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x44, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x65, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x61, 0x69, 0x72, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5b, 0x0a, 0x11, 0x45, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xde, 0x01, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, + 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, + 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, + 0x69, 0x12, 0x4d, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, + 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x1a, 0x56, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x31, 0x0a, 0x1b, 0x53, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x63, 0x61, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x40, 0x0a, 0x1d, 0x47, + 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0x6f, 0x0a, + 0x19, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x6e, 0x69, 0x66, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x3e, + 0x0a, 0x06, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, + 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x22, 0x66, + 0x0a, 0x12, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0xb7, 0x01, 0x0a, 0x0c, 0x43, 0x6c, 0x61, 0x69, 0x72, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x41, 0x0a, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x61, 0x72, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, + 0x22, 0xf5, 0x01, 0x0a, 0x11, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x63, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x65, 0x74, 0x74, + 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, + 0x65, 0x74, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x14, 0x43, 0x6c, 0x61, + 0x69, 0x72, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x74, 0x65, + 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x62, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x62, + 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x5f, 0x69, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x65, 0x64, 0x49, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25, + 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x49, 0x64, 0x73, 0x22, 0x21, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x52, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x8a, 0x04, 0x0a, 0x12, 0x43, 0x6c, 0x61, + 0x69, 0x72, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x32, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x12, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x53, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x61, 0x69, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x07, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6c, 0x61, 0x69, 0x72, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, + 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x66, + 0x69, 0x78, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x66, 0x69, 0x78, 0x65, 0x64, 0x49, 0x6e, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x21, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x45, 0x6e, + 0x72, 0x69, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x18, 0x43, 0x6c, 0x61, 0x69, + 0x72, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0xe1, 0x0b, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x56, 0x75, + 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, + 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x5f, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, + 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, + 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x73, 0x12, 0x6e, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x6b, 0x0a, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x8a, + 0x01, 0x0a, 0x17, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x65, + 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x51, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, + 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, + 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, + 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x16, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x75, 0x6c, 0x6e, + 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x0b, 0x65, + 0x6e, 0x72, 0x69, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, + 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x45, 0x6e, + 0x72, 0x69, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x65, 0x6e, 0x72, 0x69, 0x63, 0x68, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x65, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x74, 0x0a, 0x0f, + 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, + 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x75, 0x6c, + 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, + 0x65, 0x73, 0x1a, 0x60, 0x0a, 0x0d, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, + 0x69, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x6a, 0x0a, 0x12, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3e, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x5b, 0x0a, 0x11, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x65, 0x0a, + 0x1b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x65, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x6d, 0x0a, 0x14, 0x56, + 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x61, + 0x69, 0x72, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xb5, 0x03, 0x0a, 0x0c, 0x43, + 0x6c, 0x61, 0x69, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x14, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, + 0x53, 0x63, 0x61, 0x6e, 0x12, 0x32, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x63, 0x61, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x54, + 0x6f, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x87, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x34, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x35, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, + 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x75, 0x6c, 0x6e, + 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x96, 0x01, 0x0a, 0x1b, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x39, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0xe0, 0x01, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x79, 0x6f, 0x72, 0x2e, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x76, 0x31, + 0x42, 0x0a, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x40, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x69, 0x73, 0x68, 0x2f, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x79, 0x6f, + 0x72, 0x2f, 0x63, 0x6c, 0x61, 0x69, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6c, 0x61, 0x69, 0x72, + 0xa2, 0x02, 0x03, 0x53, 0x59, 0x43, 0xaa, 0x02, 0x15, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x59, 0x6f, 0x72, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x2e, 0x56, 0x31, 0xca, 0x02, + 0x15, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5c, 0x59, 0x6f, 0x72, 0x5c, 0x43, 0x6c, + 0x61, 0x69, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x21, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x5c, 0x59, 0x6f, 0x72, 0x5c, 0x43, 0x6c, 0x61, 0x69, 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x18, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x3a, 0x59, 0x6f, 0x72, 0x3a, 0x3a, 0x43, 0x6c, 0x61, 0x69, + 0x72, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_services_yor_clair_v1_clair_proto_rawDescOnce sync.Once + file_services_yor_clair_v1_clair_proto_rawDescData = file_services_yor_clair_v1_clair_proto_rawDesc +) + +func file_services_yor_clair_v1_clair_proto_rawDescGZIP() []byte { + file_services_yor_clair_v1_clair_proto_rawDescOnce.Do(func() { + file_services_yor_clair_v1_clair_proto_rawDescData = protoimpl.X.CompressGZIP(file_services_yor_clair_v1_clair_proto_rawDescData) + }) + return file_services_yor_clair_v1_clair_proto_rawDescData +} + +var file_services_yor_clair_v1_clair_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_services_yor_clair_v1_clair_proto_goTypes = []any{ + (*EnableVulnerabilityScanningRequest)(nil), // 0: services.yor.clair.v1.EnableVulnerabilityScanningRequest + (*EnableVulnerabilityScanningResponse)(nil), // 1: services.yor.clair.v1.EnableVulnerabilityScanningResponse + (*ClairReportPackage)(nil), // 2: services.yor.clair.v1.ClairReportPackage + (*SubmitManifestToScanResponse)(nil), // 3: services.yor.clair.v1.SubmitManifestToScanResponse + (*ClairDescriptor)(nil), // 4: services.yor.clair.v1.ClairDescriptor + (*SubmitManifestToScanRequest)(nil), // 5: services.yor.clair.v1.SubmitManifestToScanRequest + (*GetVulnerabilityReportRequest)(nil), // 6: services.yor.clair.v1.GetVulnerabilityReportRequest + (*ClairIndexManifestRequest)(nil), // 7: services.yor.clair.v1.ClairIndexManifestRequest + (*ClairPackageSource)(nil), // 8: services.yor.clair.v1.ClairPackageSource + (*ClairPackage)(nil), // 9: services.yor.clair.v1.ClairPackage + (*ClairDistribution)(nil), // 10: services.yor.clair.v1.ClairDistribution + (*ClairEnvironmentItem)(nil), // 11: services.yor.clair.v1.ClairEnvironmentItem + (*ClairRepository)(nil), // 12: services.yor.clair.v1.ClairRepository + (*ClairVulnerability)(nil), // 13: services.yor.clair.v1.ClairVulnerability + (*ClairEnrichment)(nil), // 14: services.yor.clair.v1.ClairEnrichment + (*ClairVulnerabilityIdList)(nil), // 15: services.yor.clair.v1.ClairVulnerabilityIdList + (*GetVulnerabilityReportResponse)(nil), // 16: services.yor.clair.v1.GetVulnerabilityReportResponse + nil, // 17: services.yor.clair.v1.SubmitManifestToScanResponse.PackagesEntry + nil, // 18: services.yor.clair.v1.SubmitManifestToScanResponse.DistributionsEntry + nil, // 19: services.yor.clair.v1.SubmitManifestToScanResponse.RepositoryEntry + nil, // 20: services.yor.clair.v1.SubmitManifestToScanResponse.EnvironmentsEntry + nil, // 21: services.yor.clair.v1.ClairDescriptor.HeadersEntry + nil, // 22: services.yor.clair.v1.GetVulnerabilityReportResponse.PackagesEntry + nil, // 23: services.yor.clair.v1.GetVulnerabilityReportResponse.DistributionsEntry + nil, // 24: services.yor.clair.v1.GetVulnerabilityReportResponse.EnvironmentsEntry + nil, // 25: services.yor.clair.v1.GetVulnerabilityReportResponse.PackageVulnerabilitiesEntry + nil, // 26: services.yor.clair.v1.GetVulnerabilityReportResponse.RepositoryEntry + nil, // 27: services.yor.clair.v1.GetVulnerabilityReportResponse.VulnerabilitiesEntry + (*v1.UUID)(nil), // 28: common.v1.UUID + (*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp + (*structpb.ListValue)(nil), // 30: google.protobuf.ListValue +} +var file_services_yor_clair_v1_clair_proto_depIdxs = []int32{ + 28, // 0: services.yor.clair.v1.EnableVulnerabilityScanningRequest.repository_id:type_name -> common.v1.UUID + 8, // 1: services.yor.clair.v1.ClairReportPackage.source:type_name -> services.yor.clair.v1.ClairPackageSource + 17, // 2: services.yor.clair.v1.SubmitManifestToScanResponse.packages:type_name -> services.yor.clair.v1.SubmitManifestToScanResponse.PackagesEntry + 18, // 3: services.yor.clair.v1.SubmitManifestToScanResponse.distributions:type_name -> services.yor.clair.v1.SubmitManifestToScanResponse.DistributionsEntry + 19, // 4: services.yor.clair.v1.SubmitManifestToScanResponse.repository:type_name -> services.yor.clair.v1.SubmitManifestToScanResponse.RepositoryEntry + 20, // 5: services.yor.clair.v1.SubmitManifestToScanResponse.environments:type_name -> services.yor.clair.v1.SubmitManifestToScanResponse.EnvironmentsEntry + 21, // 6: services.yor.clair.v1.ClairDescriptor.headers:type_name -> services.yor.clair.v1.ClairDescriptor.HeadersEntry + 4, // 7: services.yor.clair.v1.ClairIndexManifestRequest.layers:type_name -> services.yor.clair.v1.ClairDescriptor + 8, // 8: services.yor.clair.v1.ClairPackage.source:type_name -> services.yor.clair.v1.ClairPackageSource + 29, // 9: services.yor.clair.v1.ClairVulnerability.issued:type_name -> google.protobuf.Timestamp + 9, // 10: services.yor.clair.v1.ClairVulnerability.package:type_name -> services.yor.clair.v1.ClairPackage + 10, // 11: services.yor.clair.v1.ClairVulnerability.distribution:type_name -> services.yor.clair.v1.ClairDistribution + 12, // 12: services.yor.clair.v1.ClairVulnerability.repository:type_name -> services.yor.clair.v1.ClairRepository + 22, // 13: services.yor.clair.v1.GetVulnerabilityReportResponse.packages:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.PackagesEntry + 23, // 14: services.yor.clair.v1.GetVulnerabilityReportResponse.distributions:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.DistributionsEntry + 24, // 15: services.yor.clair.v1.GetVulnerabilityReportResponse.environments:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.EnvironmentsEntry + 25, // 16: services.yor.clair.v1.GetVulnerabilityReportResponse.package_vulnerabilities:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.PackageVulnerabilitiesEntry + 14, // 17: services.yor.clair.v1.GetVulnerabilityReportResponse.enrichments:type_name -> services.yor.clair.v1.ClairEnrichment + 26, // 18: services.yor.clair.v1.GetVulnerabilityReportResponse.repository:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.RepositoryEntry + 27, // 19: services.yor.clair.v1.GetVulnerabilityReportResponse.vulnerabilities:type_name -> services.yor.clair.v1.GetVulnerabilityReportResponse.VulnerabilitiesEntry + 2, // 20: services.yor.clair.v1.SubmitManifestToScanResponse.PackagesEntry.value:type_name -> services.yor.clair.v1.ClairReportPackage + 10, // 21: services.yor.clair.v1.SubmitManifestToScanResponse.DistributionsEntry.value:type_name -> services.yor.clair.v1.ClairDistribution + 12, // 22: services.yor.clair.v1.SubmitManifestToScanResponse.RepositoryEntry.value:type_name -> services.yor.clair.v1.ClairRepository + 30, // 23: services.yor.clair.v1.SubmitManifestToScanResponse.EnvironmentsEntry.value:type_name -> google.protobuf.ListValue + 30, // 24: services.yor.clair.v1.ClairDescriptor.HeadersEntry.value:type_name -> google.protobuf.ListValue + 9, // 25: services.yor.clair.v1.GetVulnerabilityReportResponse.PackagesEntry.value:type_name -> services.yor.clair.v1.ClairPackage + 10, // 26: services.yor.clair.v1.GetVulnerabilityReportResponse.DistributionsEntry.value:type_name -> services.yor.clair.v1.ClairDistribution + 30, // 27: services.yor.clair.v1.GetVulnerabilityReportResponse.EnvironmentsEntry.value:type_name -> google.protobuf.ListValue + 30, // 28: services.yor.clair.v1.GetVulnerabilityReportResponse.PackageVulnerabilitiesEntry.value:type_name -> google.protobuf.ListValue + 12, // 29: services.yor.clair.v1.GetVulnerabilityReportResponse.RepositoryEntry.value:type_name -> services.yor.clair.v1.ClairRepository + 13, // 30: services.yor.clair.v1.GetVulnerabilityReportResponse.VulnerabilitiesEntry.value:type_name -> services.yor.clair.v1.ClairVulnerability + 5, // 31: services.yor.clair.v1.ClairService.SubmitManifestToScan:input_type -> services.yor.clair.v1.SubmitManifestToScanRequest + 6, // 32: services.yor.clair.v1.ClairService.GetVulnerabilityReport:input_type -> services.yor.clair.v1.GetVulnerabilityReportRequest + 0, // 33: services.yor.clair.v1.ClairService.EnableVulnerabilityScanning:input_type -> services.yor.clair.v1.EnableVulnerabilityScanningRequest + 3, // 34: services.yor.clair.v1.ClairService.SubmitManifestToScan:output_type -> services.yor.clair.v1.SubmitManifestToScanResponse + 16, // 35: services.yor.clair.v1.ClairService.GetVulnerabilityReport:output_type -> services.yor.clair.v1.GetVulnerabilityReportResponse + 1, // 36: services.yor.clair.v1.ClairService.EnableVulnerabilityScanning:output_type -> services.yor.clair.v1.EnableVulnerabilityScanningResponse + 34, // [34:37] is the sub-list for method output_type + 31, // [31:34] is the sub-list for method input_type + 31, // [31:31] is the sub-list for extension type_name + 31, // [31:31] is the sub-list for extension extendee + 0, // [0:31] is the sub-list for field type_name +} + +func init() { file_services_yor_clair_v1_clair_proto_init() } +func file_services_yor_clair_v1_clair_proto_init() { + if File_services_yor_clair_v1_clair_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_services_yor_clair_v1_clair_proto_rawDesc, + NumEnums: 0, + NumMessages: 28, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_services_yor_clair_v1_clair_proto_goTypes, + DependencyIndexes: file_services_yor_clair_v1_clair_proto_depIdxs, + MessageInfos: file_services_yor_clair_v1_clair_proto_msgTypes, + }.Build() + File_services_yor_clair_v1_clair_proto = out.File + file_services_yor_clair_v1_clair_proto_rawDesc = nil + file_services_yor_clair_v1_clair_proto_goTypes = nil + file_services_yor_clair_v1_clair_proto_depIdxs = nil +} diff --git a/services/yor/clair/v1/clair.pb.validate.go b/services/yor/clair/v1/clair.pb.validate.go new file mode 100644 index 00000000..c98cb754 --- /dev/null +++ b/services/yor/clair/v1/clair.pb.validate.go @@ -0,0 +1,2643 @@ +// Code generated by protoc-gen-validate. DO NOT EDIT. +// source: services/yor/clair/v1/clair.proto + +package clair + +import ( + "bytes" + "errors" + "fmt" + "net" + "net/mail" + "net/url" + "regexp" + "sort" + "strings" + "time" + "unicode/utf8" + + "google.golang.org/protobuf/types/known/anypb" +) + +// ensure the imports are used +var ( + _ = bytes.MinRead + _ = errors.New("") + _ = fmt.Print + _ = utf8.UTFMax + _ = (*regexp.Regexp)(nil) + _ = (*strings.Reader)(nil) + _ = net.IPv4len + _ = time.Duration(0) + _ = (*url.URL)(nil) + _ = (*mail.Address)(nil) + _ = anypb.Any{} + _ = sort.Sort +) + +// Validate checks the field values on EnableVulnerabilityScanningRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *EnableVulnerabilityScanningRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on EnableVulnerabilityScanningRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// EnableVulnerabilityScanningRequestMultiError, or nil if none found. +func (m *EnableVulnerabilityScanningRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *EnableVulnerabilityScanningRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetRepositoryId()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, EnableVulnerabilityScanningRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, EnableVulnerabilityScanningRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRepositoryId()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return EnableVulnerabilityScanningRequestValidationError{ + field: "RepositoryId", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return EnableVulnerabilityScanningRequestMultiError(errors) + } + + return nil +} + +// EnableVulnerabilityScanningRequestMultiError is an error wrapping multiple +// validation errors returned by +// EnableVulnerabilityScanningRequest.ValidateAll() if the designated +// constraints aren't met. +type EnableVulnerabilityScanningRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m EnableVulnerabilityScanningRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m EnableVulnerabilityScanningRequestMultiError) AllErrors() []error { return m } + +// EnableVulnerabilityScanningRequestValidationError is the validation error +// returned by EnableVulnerabilityScanningRequest.Validate if the designated +// constraints aren't met. +type EnableVulnerabilityScanningRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e EnableVulnerabilityScanningRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e EnableVulnerabilityScanningRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e EnableVulnerabilityScanningRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e EnableVulnerabilityScanningRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e EnableVulnerabilityScanningRequestValidationError) ErrorName() string { + return "EnableVulnerabilityScanningRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e EnableVulnerabilityScanningRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sEnableVulnerabilityScanningRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = EnableVulnerabilityScanningRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = EnableVulnerabilityScanningRequestValidationError{} + +// Validate checks the field values on EnableVulnerabilityScanningResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *EnableVulnerabilityScanningResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on EnableVulnerabilityScanningResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// EnableVulnerabilityScanningResponseMultiError, or nil if none found. +func (m *EnableVulnerabilityScanningResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *EnableVulnerabilityScanningResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Message + + if len(errors) > 0 { + return EnableVulnerabilityScanningResponseMultiError(errors) + } + + return nil +} + +// EnableVulnerabilityScanningResponseMultiError is an error wrapping multiple +// validation errors returned by +// EnableVulnerabilityScanningResponse.ValidateAll() if the designated +// constraints aren't met. +type EnableVulnerabilityScanningResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m EnableVulnerabilityScanningResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m EnableVulnerabilityScanningResponseMultiError) AllErrors() []error { return m } + +// EnableVulnerabilityScanningResponseValidationError is the validation error +// returned by EnableVulnerabilityScanningResponse.Validate if the designated +// constraints aren't met. +type EnableVulnerabilityScanningResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e EnableVulnerabilityScanningResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e EnableVulnerabilityScanningResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e EnableVulnerabilityScanningResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e EnableVulnerabilityScanningResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e EnableVulnerabilityScanningResponseValidationError) ErrorName() string { + return "EnableVulnerabilityScanningResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e EnableVulnerabilityScanningResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sEnableVulnerabilityScanningResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = EnableVulnerabilityScanningResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = EnableVulnerabilityScanningResponseValidationError{} + +// Validate checks the field values on ClairReportPackage with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairReportPackage) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairReportPackage with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairReportPackageMultiError, or nil if none found. +func (m *ClairReportPackage) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairReportPackage) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for Name + + // no validation rules for Version + + // no validation rules for Kind + + // no validation rules for Arch + + if all { + switch v := interface{}(m.GetSource()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairReportPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairReportPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSource()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairReportPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return ClairReportPackageMultiError(errors) + } + + return nil +} + +// ClairReportPackageMultiError is an error wrapping multiple validation errors +// returned by ClairReportPackage.ValidateAll() if the designated constraints +// aren't met. +type ClairReportPackageMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairReportPackageMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairReportPackageMultiError) AllErrors() []error { return m } + +// ClairReportPackageValidationError is the validation error returned by +// ClairReportPackage.Validate if the designated constraints aren't met. +type ClairReportPackageValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairReportPackageValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairReportPackageValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairReportPackageValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairReportPackageValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairReportPackageValidationError) ErrorName() string { + return "ClairReportPackageValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairReportPackageValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairReportPackage.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairReportPackageValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairReportPackageValidationError{} + +// Validate checks the field values on SubmitManifestToScanResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *SubmitManifestToScanResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on SubmitManifestToScanResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// SubmitManifestToScanResponseMultiError, or nil if none found. +func (m *SubmitManifestToScanResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *SubmitManifestToScanResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Success + + // no validation rules for ManifestHash + + // no validation rules for State + + // no validation rules for Err + + { + sorted_keys := make([]string, len(m.GetPackages())) + i := 0 + for key := range m.GetPackages() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetPackages()[key] + _ = val + + // no validation rules for Packages[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetDistributions())) + i := 0 + for key := range m.GetDistributions() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetDistributions()[key] + _ = val + + // no validation rules for Distributions[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetRepository())) + i := 0 + for key := range m.GetRepository() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetRepository()[key] + _ = val + + // no validation rules for Repository[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetEnvironments())) + i := 0 + for key := range m.GetEnvironments() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetEnvironments()[key] + _ = val + + // no validation rules for Environments[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SubmitManifestToScanResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + if len(errors) > 0 { + return SubmitManifestToScanResponseMultiError(errors) + } + + return nil +} + +// SubmitManifestToScanResponseMultiError is an error wrapping multiple +// validation errors returned by SubmitManifestToScanResponse.ValidateAll() if +// the designated constraints aren't met. +type SubmitManifestToScanResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m SubmitManifestToScanResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m SubmitManifestToScanResponseMultiError) AllErrors() []error { return m } + +// SubmitManifestToScanResponseValidationError is the validation error returned +// by SubmitManifestToScanResponse.Validate if the designated constraints +// aren't met. +type SubmitManifestToScanResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e SubmitManifestToScanResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e SubmitManifestToScanResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e SubmitManifestToScanResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e SubmitManifestToScanResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e SubmitManifestToScanResponseValidationError) ErrorName() string { + return "SubmitManifestToScanResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e SubmitManifestToScanResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sSubmitManifestToScanResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = SubmitManifestToScanResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = SubmitManifestToScanResponseValidationError{} + +// Validate checks the field values on ClairDescriptor with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *ClairDescriptor) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairDescriptor with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairDescriptorMultiError, or nil if none found. +func (m *ClairDescriptor) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairDescriptor) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Hash + + // no validation rules for Uri + + { + sorted_keys := make([]string, len(m.GetHeaders())) + i := 0 + for key := range m.GetHeaders() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetHeaders()[key] + _ = val + + // no validation rules for Headers[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairDescriptorValidationError{ + field: fmt.Sprintf("Headers[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairDescriptorValidationError{ + field: fmt.Sprintf("Headers[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairDescriptorValidationError{ + field: fmt.Sprintf("Headers[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + if len(errors) > 0 { + return ClairDescriptorMultiError(errors) + } + + return nil +} + +// ClairDescriptorMultiError is an error wrapping multiple validation errors +// returned by ClairDescriptor.ValidateAll() if the designated constraints +// aren't met. +type ClairDescriptorMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairDescriptorMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairDescriptorMultiError) AllErrors() []error { return m } + +// ClairDescriptorValidationError is the validation error returned by +// ClairDescriptor.Validate if the designated constraints aren't met. +type ClairDescriptorValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairDescriptorValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairDescriptorValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairDescriptorValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairDescriptorValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairDescriptorValidationError) ErrorName() string { return "ClairDescriptorValidationError" } + +// Error satisfies the builtin error interface +func (e ClairDescriptorValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairDescriptor.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairDescriptorValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairDescriptorValidationError{} + +// Validate checks the field values on SubmitManifestToScanRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *SubmitManifestToScanRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on SubmitManifestToScanRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// SubmitManifestToScanRequestMultiError, or nil if none found. +func (m *SubmitManifestToScanRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *SubmitManifestToScanRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Hash + + if len(errors) > 0 { + return SubmitManifestToScanRequestMultiError(errors) + } + + return nil +} + +// SubmitManifestToScanRequestMultiError is an error wrapping multiple +// validation errors returned by SubmitManifestToScanRequest.ValidateAll() if +// the designated constraints aren't met. +type SubmitManifestToScanRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m SubmitManifestToScanRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m SubmitManifestToScanRequestMultiError) AllErrors() []error { return m } + +// SubmitManifestToScanRequestValidationError is the validation error returned +// by SubmitManifestToScanRequest.Validate if the designated constraints +// aren't met. +type SubmitManifestToScanRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e SubmitManifestToScanRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e SubmitManifestToScanRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e SubmitManifestToScanRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e SubmitManifestToScanRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e SubmitManifestToScanRequestValidationError) ErrorName() string { + return "SubmitManifestToScanRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e SubmitManifestToScanRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sSubmitManifestToScanRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = SubmitManifestToScanRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = SubmitManifestToScanRequestValidationError{} + +// Validate checks the field values on GetVulnerabilityReportRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetVulnerabilityReportRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetVulnerabilityReportRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// GetVulnerabilityReportRequestMultiError, or nil if none found. +func (m *GetVulnerabilityReportRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetVulnerabilityReportRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ManifestId + + if len(errors) > 0 { + return GetVulnerabilityReportRequestMultiError(errors) + } + + return nil +} + +// GetVulnerabilityReportRequestMultiError is an error wrapping multiple +// validation errors returned by GetVulnerabilityReportRequest.ValidateAll() +// if the designated constraints aren't met. +type GetVulnerabilityReportRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetVulnerabilityReportRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetVulnerabilityReportRequestMultiError) AllErrors() []error { return m } + +// GetVulnerabilityReportRequestValidationError is the validation error +// returned by GetVulnerabilityReportRequest.Validate if the designated +// constraints aren't met. +type GetVulnerabilityReportRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetVulnerabilityReportRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetVulnerabilityReportRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetVulnerabilityReportRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetVulnerabilityReportRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetVulnerabilityReportRequestValidationError) ErrorName() string { + return "GetVulnerabilityReportRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetVulnerabilityReportRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetVulnerabilityReportRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = GetVulnerabilityReportRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetVulnerabilityReportRequestValidationError{} + +// Validate checks the field values on ClairIndexManifestRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairIndexManifestRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairIndexManifestRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairIndexManifestRequestMultiError, or nil if none found. +func (m *ClairIndexManifestRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairIndexManifestRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Hash + + for idx, item := range m.GetLayers() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairIndexManifestRequestValidationError{ + field: fmt.Sprintf("Layers[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairIndexManifestRequestValidationError{ + field: fmt.Sprintf("Layers[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairIndexManifestRequestValidationError{ + field: fmt.Sprintf("Layers[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ClairIndexManifestRequestMultiError(errors) + } + + return nil +} + +// ClairIndexManifestRequestMultiError is an error wrapping multiple validation +// errors returned by ClairIndexManifestRequest.ValidateAll() if the +// designated constraints aren't met. +type ClairIndexManifestRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairIndexManifestRequestMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairIndexManifestRequestMultiError) AllErrors() []error { return m } + +// ClairIndexManifestRequestValidationError is the validation error returned by +// ClairIndexManifestRequest.Validate if the designated constraints aren't met. +type ClairIndexManifestRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairIndexManifestRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairIndexManifestRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairIndexManifestRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairIndexManifestRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairIndexManifestRequestValidationError) ErrorName() string { + return "ClairIndexManifestRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairIndexManifestRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairIndexManifestRequest.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairIndexManifestRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairIndexManifestRequestValidationError{} + +// Validate checks the field values on ClairPackageSource with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairPackageSource) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairPackageSource with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairPackageSourceMultiError, or nil if none found. +func (m *ClairPackageSource) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairPackageSource) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for Name + + // no validation rules for Version + + // no validation rules for Kind + + if len(errors) > 0 { + return ClairPackageSourceMultiError(errors) + } + + return nil +} + +// ClairPackageSourceMultiError is an error wrapping multiple validation errors +// returned by ClairPackageSource.ValidateAll() if the designated constraints +// aren't met. +type ClairPackageSourceMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairPackageSourceMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairPackageSourceMultiError) AllErrors() []error { return m } + +// ClairPackageSourceValidationError is the validation error returned by +// ClairPackageSource.Validate if the designated constraints aren't met. +type ClairPackageSourceValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairPackageSourceValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairPackageSourceValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairPackageSourceValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairPackageSourceValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairPackageSourceValidationError) ErrorName() string { + return "ClairPackageSourceValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairPackageSourceValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairPackageSource.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairPackageSourceValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairPackageSourceValidationError{} + +// Validate checks the field values on ClairPackage with the rules defined in +// the proto definition for this message. If any rules are violated, the first +// error encountered is returned, or nil if there are no violations. +func (m *ClairPackage) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairPackage with the rules defined +// in the proto definition for this message. If any rules are violated, the +// result is a list of violation errors wrapped in ClairPackageMultiError, or +// nil if none found. +func (m *ClairPackage) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairPackage) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for Name + + // no validation rules for Version + + // no validation rules for Kind + + if all { + switch v := interface{}(m.GetSource()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetSource()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairPackageValidationError{ + field: "Source", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for Arch + + if len(errors) > 0 { + return ClairPackageMultiError(errors) + } + + return nil +} + +// ClairPackageMultiError is an error wrapping multiple validation errors +// returned by ClairPackage.ValidateAll() if the designated constraints aren't met. +type ClairPackageMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairPackageMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairPackageMultiError) AllErrors() []error { return m } + +// ClairPackageValidationError is the validation error returned by +// ClairPackage.Validate if the designated constraints aren't met. +type ClairPackageValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairPackageValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairPackageValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairPackageValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairPackageValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairPackageValidationError) ErrorName() string { return "ClairPackageValidationError" } + +// Error satisfies the builtin error interface +func (e ClairPackageValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairPackage.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairPackageValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairPackageValidationError{} + +// Validate checks the field values on ClairDistribution with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *ClairDistribution) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairDistribution with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairDistributionMultiError, or nil if none found. +func (m *ClairDistribution) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairDistribution) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for Did + + // no validation rules for Name + + // no validation rules for Version + + // no validation rules for VersionCodeName + + // no validation rules for VersionId + + // no validation rules for Arch + + // no validation rules for Cpe + + // no validation rules for PrettyName + + if len(errors) > 0 { + return ClairDistributionMultiError(errors) + } + + return nil +} + +// ClairDistributionMultiError is an error wrapping multiple validation errors +// returned by ClairDistribution.ValidateAll() if the designated constraints +// aren't met. +type ClairDistributionMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairDistributionMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairDistributionMultiError) AllErrors() []error { return m } + +// ClairDistributionValidationError is the validation error returned by +// ClairDistribution.Validate if the designated constraints aren't met. +type ClairDistributionValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairDistributionValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairDistributionValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairDistributionValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairDistributionValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairDistributionValidationError) ErrorName() string { + return "ClairDistributionValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairDistributionValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairDistribution.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairDistributionValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairDistributionValidationError{} + +// Validate checks the field values on ClairEnvironmentItem with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairEnvironmentItem) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairEnvironmentItem with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairEnvironmentItemMultiError, or nil if none found. +func (m *ClairEnvironmentItem) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairEnvironmentItem) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for PackageDb + + // no validation rules for IntroducedIn + + // no validation rules for DistributionId + + if len(errors) > 0 { + return ClairEnvironmentItemMultiError(errors) + } + + return nil +} + +// ClairEnvironmentItemMultiError is an error wrapping multiple validation +// errors returned by ClairEnvironmentItem.ValidateAll() if the designated +// constraints aren't met. +type ClairEnvironmentItemMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairEnvironmentItemMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairEnvironmentItemMultiError) AllErrors() []error { return m } + +// ClairEnvironmentItemValidationError is the validation error returned by +// ClairEnvironmentItem.Validate if the designated constraints aren't met. +type ClairEnvironmentItemValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairEnvironmentItemValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairEnvironmentItemValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairEnvironmentItemValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairEnvironmentItemValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairEnvironmentItemValidationError) ErrorName() string { + return "ClairEnvironmentItemValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairEnvironmentItemValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairEnvironmentItem.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairEnvironmentItemValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairEnvironmentItemValidationError{} + +// Validate checks the field values on ClairRepository with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *ClairRepository) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairRepository with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairRepositoryMultiError, or nil if none found. +func (m *ClairRepository) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairRepository) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + if len(errors) > 0 { + return ClairRepositoryMultiError(errors) + } + + return nil +} + +// ClairRepositoryMultiError is an error wrapping multiple validation errors +// returned by ClairRepository.ValidateAll() if the designated constraints +// aren't met. +type ClairRepositoryMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairRepositoryMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairRepositoryMultiError) AllErrors() []error { return m } + +// ClairRepositoryValidationError is the validation error returned by +// ClairRepository.Validate if the designated constraints aren't met. +type ClairRepositoryValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairRepositoryValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairRepositoryValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairRepositoryValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairRepositoryValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairRepositoryValidationError) ErrorName() string { return "ClairRepositoryValidationError" } + +// Error satisfies the builtin error interface +func (e ClairRepositoryValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairRepository.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairRepositoryValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairRepositoryValidationError{} + +// Validate checks the field values on ClairVulnerability with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairVulnerability) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairVulnerability with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairVulnerabilityMultiError, or nil if none found. +func (m *ClairVulnerability) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairVulnerability) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for Updater + + // no validation rules for Name + + // no validation rules for Description + + if all { + switch v := interface{}(m.GetIssued()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Issued", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Issued", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetIssued()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairVulnerabilityValidationError{ + field: "Issued", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for Links + + // no validation rules for Severity + + // no validation rules for NormalizedSeverity + + if all { + switch v := interface{}(m.GetPackage()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Package", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Package", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetPackage()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairVulnerabilityValidationError{ + field: "Package", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetDistribution()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Distribution", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Distribution", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetDistribution()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairVulnerabilityValidationError{ + field: "Distribution", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetRepository()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Repository", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ClairVulnerabilityValidationError{ + field: "Repository", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetRepository()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ClairVulnerabilityValidationError{ + field: "Repository", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for FixedInVersion + + if len(errors) > 0 { + return ClairVulnerabilityMultiError(errors) + } + + return nil +} + +// ClairVulnerabilityMultiError is an error wrapping multiple validation errors +// returned by ClairVulnerability.ValidateAll() if the designated constraints +// aren't met. +type ClairVulnerabilityMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairVulnerabilityMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairVulnerabilityMultiError) AllErrors() []error { return m } + +// ClairVulnerabilityValidationError is the validation error returned by +// ClairVulnerability.Validate if the designated constraints aren't met. +type ClairVulnerabilityValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairVulnerabilityValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairVulnerabilityValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairVulnerabilityValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairVulnerabilityValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairVulnerabilityValidationError) ErrorName() string { + return "ClairVulnerabilityValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairVulnerabilityValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairVulnerability.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairVulnerabilityValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairVulnerabilityValidationError{} + +// Validate checks the field values on ClairEnrichment with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *ClairEnrichment) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairEnrichment with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairEnrichmentMultiError, or nil if none found. +func (m *ClairEnrichment) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairEnrichment) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + if len(errors) > 0 { + return ClairEnrichmentMultiError(errors) + } + + return nil +} + +// ClairEnrichmentMultiError is an error wrapping multiple validation errors +// returned by ClairEnrichment.ValidateAll() if the designated constraints +// aren't met. +type ClairEnrichmentMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairEnrichmentMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairEnrichmentMultiError) AllErrors() []error { return m } + +// ClairEnrichmentValidationError is the validation error returned by +// ClairEnrichment.Validate if the designated constraints aren't met. +type ClairEnrichmentValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairEnrichmentValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairEnrichmentValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairEnrichmentValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairEnrichmentValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairEnrichmentValidationError) ErrorName() string { return "ClairEnrichmentValidationError" } + +// Error satisfies the builtin error interface +func (e ClairEnrichmentValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairEnrichment.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairEnrichmentValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairEnrichmentValidationError{} + +// Validate checks the field values on ClairVulnerabilityIdList with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ClairVulnerabilityIdList) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ClairVulnerabilityIdList with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// ClairVulnerabilityIdListMultiError, or nil if none found. +func (m *ClairVulnerabilityIdList) ValidateAll() error { + return m.validate(true) +} + +func (m *ClairVulnerabilityIdList) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return ClairVulnerabilityIdListMultiError(errors) + } + + return nil +} + +// ClairVulnerabilityIdListMultiError is an error wrapping multiple validation +// errors returned by ClairVulnerabilityIdList.ValidateAll() if the designated +// constraints aren't met. +type ClairVulnerabilityIdListMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ClairVulnerabilityIdListMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ClairVulnerabilityIdListMultiError) AllErrors() []error { return m } + +// ClairVulnerabilityIdListValidationError is the validation error returned by +// ClairVulnerabilityIdList.Validate if the designated constraints aren't met. +type ClairVulnerabilityIdListValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ClairVulnerabilityIdListValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ClairVulnerabilityIdListValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ClairVulnerabilityIdListValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ClairVulnerabilityIdListValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ClairVulnerabilityIdListValidationError) ErrorName() string { + return "ClairVulnerabilityIdListValidationError" +} + +// Error satisfies the builtin error interface +func (e ClairVulnerabilityIdListValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sClairVulnerabilityIdList.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ClairVulnerabilityIdListValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ClairVulnerabilityIdListValidationError{} + +// Validate checks the field values on GetVulnerabilityReportResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetVulnerabilityReportResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetVulnerabilityReportResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// GetVulnerabilityReportResponseMultiError, or nil if none found. +func (m *GetVulnerabilityReportResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetVulnerabilityReportResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ManifestHash + + // no validation rules for State + + // no validation rules for Err + + // no validation rules for Success + + { + sorted_keys := make([]string, len(m.GetPackages())) + i := 0 + for key := range m.GetPackages() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetPackages()[key] + _ = val + + // no validation rules for Packages[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Packages[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetDistributions())) + i := 0 + for key := range m.GetDistributions() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetDistributions()[key] + _ = val + + // no validation rules for Distributions[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Distributions[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetEnvironments())) + i := 0 + for key := range m.GetEnvironments() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetEnvironments()[key] + _ = val + + // no validation rules for Environments[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Environments[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetPackageVulnerabilities())) + i := 0 + for key := range m.GetPackageVulnerabilities() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetPackageVulnerabilities()[key] + _ = val + + // no validation rules for PackageVulnerabilities[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("PackageVulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("PackageVulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("PackageVulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + if all { + switch v := interface{}(m.GetEnrichments()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: "Enrichments", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: "Enrichments", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetEnrichments()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: "Enrichments", + reason: "embedded message failed validation", + cause: err, + } + } + } + + { + sorted_keys := make([]string, len(m.GetRepository())) + i := 0 + for key := range m.GetRepository() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetRepository()[key] + _ = val + + // no validation rules for Repository[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Repository[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + { + sorted_keys := make([]string, len(m.GetVulnerabilities())) + i := 0 + for key := range m.GetVulnerabilities() { + sorted_keys[i] = key + i++ + } + sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] }) + for _, key := range sorted_keys { + val := m.GetVulnerabilities()[key] + _ = val + + // no validation rules for Vulnerabilities[key] + + if all { + switch v := interface{}(val).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Vulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Vulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(val).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetVulnerabilityReportResponseValidationError{ + field: fmt.Sprintf("Vulnerabilities[%v]", key), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + + if len(errors) > 0 { + return GetVulnerabilityReportResponseMultiError(errors) + } + + return nil +} + +// GetVulnerabilityReportResponseMultiError is an error wrapping multiple +// validation errors returned by GetVulnerabilityReportResponse.ValidateAll() +// if the designated constraints aren't met. +type GetVulnerabilityReportResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetVulnerabilityReportResponseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetVulnerabilityReportResponseMultiError) AllErrors() []error { return m } + +// GetVulnerabilityReportResponseValidationError is the validation error +// returned by GetVulnerabilityReportResponse.Validate if the designated +// constraints aren't met. +type GetVulnerabilityReportResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetVulnerabilityReportResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetVulnerabilityReportResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetVulnerabilityReportResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetVulnerabilityReportResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetVulnerabilityReportResponseValidationError) ErrorName() string { + return "GetVulnerabilityReportResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetVulnerabilityReportResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetVulnerabilityReportResponse.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = GetVulnerabilityReportResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetVulnerabilityReportResponseValidationError{} diff --git a/services/yor/clair/v1/clairconnect/clair.connect.go b/services/yor/clair/v1/clairconnect/clair.connect.go new file mode 100644 index 00000000..3af942a5 --- /dev/null +++ b/services/yor/clair/v1/clairconnect/clair.connect.go @@ -0,0 +1,173 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: services/yor/clair/v1/clair.proto + +package clairconnect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/containerish/OpenRegistry/services/yor/clair/v1" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion1_13_0 + +const ( + // ClairServiceName is the fully-qualified name of the ClairService service. + ClairServiceName = "services.yor.clair.v1.ClairService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // ClairServiceSubmitManifestToScanProcedure is the fully-qualified name of the ClairService's + // SubmitManifestToScan RPC. + ClairServiceSubmitManifestToScanProcedure = "/services.yor.clair.v1.ClairService/SubmitManifestToScan" + // ClairServiceGetVulnerabilityReportProcedure is the fully-qualified name of the ClairService's + // GetVulnerabilityReport RPC. + ClairServiceGetVulnerabilityReportProcedure = "/services.yor.clair.v1.ClairService/GetVulnerabilityReport" + // ClairServiceEnableVulnerabilityScanningProcedure is the fully-qualified name of the + // ClairService's EnableVulnerabilityScanning RPC. + ClairServiceEnableVulnerabilityScanningProcedure = "/services.yor.clair.v1.ClairService/EnableVulnerabilityScanning" +) + +// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package. +var ( + clairServiceServiceDescriptor = v1.File_services_yor_clair_v1_clair_proto.Services().ByName("ClairService") + clairServiceSubmitManifestToScanMethodDescriptor = clairServiceServiceDescriptor.Methods().ByName("SubmitManifestToScan") + clairServiceGetVulnerabilityReportMethodDescriptor = clairServiceServiceDescriptor.Methods().ByName("GetVulnerabilityReport") + clairServiceEnableVulnerabilityScanningMethodDescriptor = clairServiceServiceDescriptor.Methods().ByName("EnableVulnerabilityScanning") +) + +// ClairServiceClient is a client for the services.yor.clair.v1.ClairService service. +type ClairServiceClient interface { + SubmitManifestToScan(context.Context, *connect.Request[v1.SubmitManifestToScanRequest]) (*connect.Response[v1.SubmitManifestToScanResponse], error) + GetVulnerabilityReport(context.Context, *connect.Request[v1.GetVulnerabilityReportRequest]) (*connect.Response[v1.GetVulnerabilityReportResponse], error) + EnableVulnerabilityScanning(context.Context, *connect.Request[v1.EnableVulnerabilityScanningRequest]) (*connect.Response[v1.EnableVulnerabilityScanningResponse], error) +} + +// NewClairServiceClient constructs a client for the services.yor.clair.v1.ClairService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewClairServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ClairServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + return &clairServiceClient{ + submitManifestToScan: connect.NewClient[v1.SubmitManifestToScanRequest, v1.SubmitManifestToScanResponse]( + httpClient, + baseURL+ClairServiceSubmitManifestToScanProcedure, + connect.WithSchema(clairServiceSubmitManifestToScanMethodDescriptor), + connect.WithClientOptions(opts...), + ), + getVulnerabilityReport: connect.NewClient[v1.GetVulnerabilityReportRequest, v1.GetVulnerabilityReportResponse]( + httpClient, + baseURL+ClairServiceGetVulnerabilityReportProcedure, + connect.WithSchema(clairServiceGetVulnerabilityReportMethodDescriptor), + connect.WithClientOptions(opts...), + ), + enableVulnerabilityScanning: connect.NewClient[v1.EnableVulnerabilityScanningRequest, v1.EnableVulnerabilityScanningResponse]( + httpClient, + baseURL+ClairServiceEnableVulnerabilityScanningProcedure, + connect.WithSchema(clairServiceEnableVulnerabilityScanningMethodDescriptor), + connect.WithClientOptions(opts...), + ), + } +} + +// clairServiceClient implements ClairServiceClient. +type clairServiceClient struct { + submitManifestToScan *connect.Client[v1.SubmitManifestToScanRequest, v1.SubmitManifestToScanResponse] + getVulnerabilityReport *connect.Client[v1.GetVulnerabilityReportRequest, v1.GetVulnerabilityReportResponse] + enableVulnerabilityScanning *connect.Client[v1.EnableVulnerabilityScanningRequest, v1.EnableVulnerabilityScanningResponse] +} + +// SubmitManifestToScan calls services.yor.clair.v1.ClairService.SubmitManifestToScan. +func (c *clairServiceClient) SubmitManifestToScan(ctx context.Context, req *connect.Request[v1.SubmitManifestToScanRequest]) (*connect.Response[v1.SubmitManifestToScanResponse], error) { + return c.submitManifestToScan.CallUnary(ctx, req) +} + +// GetVulnerabilityReport calls services.yor.clair.v1.ClairService.GetVulnerabilityReport. +func (c *clairServiceClient) GetVulnerabilityReport(ctx context.Context, req *connect.Request[v1.GetVulnerabilityReportRequest]) (*connect.Response[v1.GetVulnerabilityReportResponse], error) { + return c.getVulnerabilityReport.CallUnary(ctx, req) +} + +// EnableVulnerabilityScanning calls services.yor.clair.v1.ClairService.EnableVulnerabilityScanning. +func (c *clairServiceClient) EnableVulnerabilityScanning(ctx context.Context, req *connect.Request[v1.EnableVulnerabilityScanningRequest]) (*connect.Response[v1.EnableVulnerabilityScanningResponse], error) { + return c.enableVulnerabilityScanning.CallUnary(ctx, req) +} + +// ClairServiceHandler is an implementation of the services.yor.clair.v1.ClairService service. +type ClairServiceHandler interface { + SubmitManifestToScan(context.Context, *connect.Request[v1.SubmitManifestToScanRequest]) (*connect.Response[v1.SubmitManifestToScanResponse], error) + GetVulnerabilityReport(context.Context, *connect.Request[v1.GetVulnerabilityReportRequest]) (*connect.Response[v1.GetVulnerabilityReportResponse], error) + EnableVulnerabilityScanning(context.Context, *connect.Request[v1.EnableVulnerabilityScanningRequest]) (*connect.Response[v1.EnableVulnerabilityScanningResponse], error) +} + +// NewClairServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewClairServiceHandler(svc ClairServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + clairServiceSubmitManifestToScanHandler := connect.NewUnaryHandler( + ClairServiceSubmitManifestToScanProcedure, + svc.SubmitManifestToScan, + connect.WithSchema(clairServiceSubmitManifestToScanMethodDescriptor), + connect.WithHandlerOptions(opts...), + ) + clairServiceGetVulnerabilityReportHandler := connect.NewUnaryHandler( + ClairServiceGetVulnerabilityReportProcedure, + svc.GetVulnerabilityReport, + connect.WithSchema(clairServiceGetVulnerabilityReportMethodDescriptor), + connect.WithHandlerOptions(opts...), + ) + clairServiceEnableVulnerabilityScanningHandler := connect.NewUnaryHandler( + ClairServiceEnableVulnerabilityScanningProcedure, + svc.EnableVulnerabilityScanning, + connect.WithSchema(clairServiceEnableVulnerabilityScanningMethodDescriptor), + connect.WithHandlerOptions(opts...), + ) + return "/services.yor.clair.v1.ClairService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case ClairServiceSubmitManifestToScanProcedure: + clairServiceSubmitManifestToScanHandler.ServeHTTP(w, r) + case ClairServiceGetVulnerabilityReportProcedure: + clairServiceGetVulnerabilityReportHandler.ServeHTTP(w, r) + case ClairServiceEnableVulnerabilityScanningProcedure: + clairServiceEnableVulnerabilityScanningHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedClairServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedClairServiceHandler struct{} + +func (UnimplementedClairServiceHandler) SubmitManifestToScan(context.Context, *connect.Request[v1.SubmitManifestToScanRequest]) (*connect.Response[v1.SubmitManifestToScanResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.yor.clair.v1.ClairService.SubmitManifestToScan is not implemented")) +} + +func (UnimplementedClairServiceHandler) GetVulnerabilityReport(context.Context, *connect.Request[v1.GetVulnerabilityReportRequest]) (*connect.Response[v1.GetVulnerabilityReportResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.yor.clair.v1.ClairService.GetVulnerabilityReport is not implemented")) +} + +func (UnimplementedClairServiceHandler) EnableVulnerabilityScanning(context.Context, *connect.Request[v1.EnableVulnerabilityScanningRequest]) (*connect.Response[v1.EnableVulnerabilityScanningResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("services.yor.clair.v1.ClairService.EnableVulnerabilityScanning is not implemented")) +} diff --git a/services/yor/clair/v1/server/clair.go b/services/yor/clair/v1/server/clair.go new file mode 100644 index 00000000..fbb3b737 --- /dev/null +++ b/services/yor/clair/v1/server/clair.go @@ -0,0 +1,201 @@ +package server + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "connectrpc.com/connect" + "github.com/golang-jwt/jwt/v5" + "google.golang.org/protobuf/encoding/protojson" + + clair_v1 "github.com/containerish/OpenRegistry/services/yor/clair/v1" +) + +func (c *clair) EnableVulnerabilityScanning( + ctx context.Context, + req *connect.Request[clair_v1.EnableVulnerabilityScanningRequest], +) ( + *connect.Response[clair_v1.EnableVulnerabilityScanningResponse], + error, +) { + return nil, connect.NewError(connect.CodeUnimplemented, fmt.Errorf("UNIMPLEMENTED")) +} + +func (c *clair) GetVulnerabilityReport( + ctx context.Context, + req *connect.Request[clair_v1.GetVulnerabilityReportRequest], +) ( + *connect.Response[clair_v1.GetVulnerabilityReportResponse], + error, +) { + logEvent := c.logger.Debug().Str("method", "GetVulnerabilityReport") + + err := req.Msg.Validate() + if err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + manifestID := req.Msg.GetManifestId() + logEvent.Str("manifest", manifestID) + reportBz, err := c.getVulnReport(ctx, manifestID) + if err != nil { + var errMap map[string]any + _ = json.Unmarshal(reportBz, &errMap) + logEvent.Err(err).Any("get_manifest_err", errMap).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + resp := &clair_v1.GetVulnerabilityReportResponse{} + if err = (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(reportBz, resp); err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInternal, err) + } + + logEvent.Bool("success", true).Send() + return connect.NewResponse(resp), nil +} + +// SubmitManifestToScan implements clairconnect.ClairServiceHandler. +func (c *clair) SubmitManifestToScan( + ctx context.Context, + req *connect.Request[clair_v1.SubmitManifestToScanRequest], +) ( + *connect.Response[clair_v1.SubmitManifestToScanResponse], + error, +) { + logEvent := c.logger.Debug().Str("method", "SubmitManifestToScan") + + err := req.Msg.Validate() + if err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + logEvent.Str("manifest", req.Msg.GetHash()) + + dfsLinks, err := c.layerLinkReader(ctx, req.Msg.GetHash()) + if err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + layers := make([]*clair_v1.ClairDescriptor, len(dfsLinks)) + for i, link := range dfsLinks { + presignedURL, signErr := c.prePresignedURLGenerator(ctx, link.DFSLink) + if signErr != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + layers[i] = &clair_v1.ClairDescriptor{ + Hash: link.Digest, + Uri: presignedURL, + } + } + + body := &clair_v1.ClairIndexManifestRequest{ + Hash: req.Msg.GetHash(), + Layers: layers, + } + + resultBz, err := c.submitManifest(ctx, body) + if err != nil { + var errMap map[string]any + _ = json.Unmarshal(resultBz, &errMap) + logEvent.Err(err).Any("manifest_submit_err", errMap).Send() + return nil, connect.NewError(connect.CodeInvalidArgument, err) + } + + msg := &clair_v1.SubmitManifestToScanResponse{} + if err = (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(resultBz, msg); err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeInternal, err) + } + + logEvent.Bool("success", true).Send() + + return connect.NewResponse(msg), nil +} + +func (c *clair) getVulnReport(ctx context.Context, manifestID string) ([]byte, error) { + uri := fmt.Sprintf("%s/matcher/api/v1/vulnerability_report/%s", c.config.ClairEndpoint, manifestID) + + req, err := c.newClairRequest(ctx, http.MethodGet, uri, nil) + if err != nil { + return nil, err + } + + resp, err := c.http.Do(req) + if err != nil { + return nil, err + } + + bz, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("ERR_GET_VULN_REPORT: READ_RESPONSE: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode >= 200 && resp.StatusCode <= 299 { + return bz, nil + } + + return bz, fmt.Errorf("ERR_GET_VULN_REPORT: INVALID_RESPONSE: %d", resp.StatusCode) +} + +func (c *clair) submitManifest( + ctx context.Context, + manifest *clair_v1.ClairIndexManifestRequest, +) ([]byte, error) { + uri := fmt.Sprintf("%s/indexer/api/v1/index_report", c.config.ClairEndpoint) + + bz, err := protojson.Marshal(manifest) + if err != nil { + return nil, err + } + req, err := c.newClairRequest(ctx, http.MethodPost, uri, bytes.NewBuffer(bz)) + if err != nil { + return nil, err + } + + res, err := c.http.Do(req) + if err != nil { + return nil, err + } + + bz, err = io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf("ERR_SUBMIT_MANIFEST_TO_SCAN: READ_RESPONSE: %w", err) + } + defer res.Body.Close() + + if res.StatusCode >= 200 && res.StatusCode <= 300 { + return bz, nil + } + + return bz, fmt.Errorf("ERR_SUBMIT_MANIFEST_TO_SCAN: CODE: %d", res.StatusCode) +} + +func (c *clair) newClairRequest(ctx context.Context, method string, url string, body io.Reader) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, method, url, body) + if err != nil { + return nil, fmt.Errorf("ERR_NEW_CLAIR_REQ: %w", err) + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{ + Issuer: "quay", + }) + + authToken, err := token.SignedString([]byte(c.config.AuthToken)) + if err != nil { + return nil, fmt.Errorf("ERR_NEW_CLAIR_REQ: SignAuthToken: %w - AuthToken: %s", err, c.config.AuthToken) + } + + req.Header.Set("Authorization", "Bearer "+authToken) + + return req, nil +} diff --git a/services/yor/clair/v1/server/interceptors.go b/services/yor/clair/v1/server/interceptors.go new file mode 100644 index 00000000..9a1c54ca --- /dev/null +++ b/services/yor/clair/v1/server/interceptors.go @@ -0,0 +1,129 @@ +package server + +import ( + "context" + "crypto/rsa" + "fmt" + "net/http" + "net/url" + "strings" + + "connectrpc.com/connect" + "github.com/golang-jwt/jwt/v5" + "github.com/google/uuid" + + "github.com/containerish/OpenRegistry/auth" + "github.com/containerish/OpenRegistry/store/v1/types" +) + +// NewJWTInterceptor is a UnaryInterceptorFunc that inspects and tries to parse a JWT from the request. +// If the JWT is invalid, an Unauthorized error is returned +func (c *clair) NewJWTInterceptor() connect.UnaryInterceptorFunc { + return connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { + return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { + logEvent := c.logger.Debug().Str("procedure", req.Spec().Procedure) + + userID, err := c.getTokenFromReq(req, c.authConfig.JWTSigningPubKey) + if err != nil { + logEvent.Err(err).Send() + return nil, err + } + + user, err := c.userGetter.GetUserByID(ctx, userID) + if err != nil { + logEvent.Err(err).Send() + return nil, connect.NewError(connect.CodeFailedPrecondition, err) + } + + logEvent.Bool("success", true).Send() + ctx = context.WithValue(ctx, types.UserContextKey, user) + return next(ctx, req) + }) + }) +} + +func (c *clair) getTokenFromReq(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) { + tokenFromHeaders, headerErr := c.tryTokenFromReqHeaders(req, jwtSigningPubKey) + if headerErr != nil { + tokenFromCookies, cookieErr := c.tryTokenFromReqCookies(req, jwtSigningPubKey) + if cookieErr != nil { + return uuid.Nil, fmt.Errorf( + "getTokenFromReq: tryTokenFromReqCookies: %w - tryTokenFromReqHeaders: %w", cookieErr, headerErr, + ) + } + return tokenFromCookies, nil + } + + return tokenFromHeaders, nil +} + +func (c *clair) tryTokenFromReqCookies(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) { + tmpReq := http.Request{Header: req.Header()} + sessionCookie, err := tmpReq.Cookie("access") + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqCookies: ERR_NO_COOKIE: %w", err) + } + + authToken, err := url.QueryUnescape(sessionCookie.Value) + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqCookies: ERR_WRONG_ENCODING: %w", err) + } + + if authToken != "" { + claims := &auth.Claims{} + token, err := jwt.ParseWithClaims(authToken, claims, func(t *jwt.Token) (interface{}, error) { + return jwtSigningPubKey, nil + }) + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: ERR_JWT_CLAIM_PARSE: %w", err) + } + + claims, ok := token.Claims.(*auth.Claims) + if !ok { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: error parsing claims from token") + } + + parsedID, err := uuid.Parse(claims.Subject) + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: ERR_UUID_PARSE: %w", err) + } + + return parsedID, nil + } + + errMsg := fmt.Errorf("auth token contains invalid parts") + return uuid.Nil, errMsg +} + +func (c *clair) tryTokenFromReqHeaders(req connect.AnyRequest, jwtSigningPubKey *rsa.PublicKey) (uuid.UUID, error) { + authToken := req.Header().Get("Authorization") + tokenParts := strings.Split(authToken, " ") + if len(tokenParts) == 2 { + if !strings.EqualFold(tokenParts[0], "Bearer") { + errMsg := fmt.Errorf("tryTokenFromReqHeaders: invalid authorization scheme") + return uuid.Nil, errMsg + } + + claims := &auth.Claims{} + token, err := jwt.ParseWithClaims(tokenParts[1], claims, func(t *jwt.Token) (interface{}, error) { + return jwtSigningPubKey, nil + }) + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: ERR_JWT_CLAIM_PARSE: %w", err) + } + + claims, ok := token.Claims.(*auth.Claims) + if !ok { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: error parsing claims from token") + } + + parsedID, err := uuid.Parse(claims.Subject) + if err != nil { + return uuid.Nil, fmt.Errorf("tryTokenFromReqHeaders: ERR_UUID_PARSE: %w", err) + } + return parsedID, nil + } + + errMsg := fmt.Errorf("auth token contains invalid parts") + return uuid.Nil, errMsg +} diff --git a/services/yor/clair/v1/server/server.go b/services/yor/clair/v1/server/server.go new file mode 100644 index 00000000..e592c30b --- /dev/null +++ b/services/yor/clair/v1/server/server.go @@ -0,0 +1,66 @@ +package server + +import ( + "context" + "net/http" + "sync" + "time" + + "connectrpc.com/connect" + + "github.com/containerish/OpenRegistry/config" + connect_v1 "github.com/containerish/OpenRegistry/services/yor/clair/v1/clairconnect" + "github.com/containerish/OpenRegistry/store/v1/types" + "github.com/containerish/OpenRegistry/store/v1/users" + "github.com/containerish/OpenRegistry/telemetry" +) + +type ( + clair struct { + http *http.Client + logger telemetry.Logger + config *config.ClairIntegration + userGetter users.UserStore + authConfig *config.Auth + mu *sync.RWMutex + layerLinkReader LayerLinkReader + prePresignedURLGenerator PresignedURLGenerator + } + + LayerLinkReader func(ctx context.Context, manifestDigest string) ([]*types.ContainerImageLayer, error) + PresignedURLGenerator func(ctx context.Context, path string) (string, error) +) + +func NewClairClient( + userStore users.UserStore, + config *config.ClairIntegration, + authConfig *config.Auth, + logger telemetry.Logger, + layerLinkReader LayerLinkReader, + prePresignedURLGenerator PresignedURLGenerator, +) *http.ServeMux { + if !config.Enabled { + return nil + } + + httpClient := &http.Client{ + Timeout: time.Minute * 3, + Transport: http.DefaultTransport, + } + + server := &clair{ + logger: logger, + config: config, + mu: &sync.RWMutex{}, + http: httpClient, + userGetter: userStore, + authConfig: authConfig, + layerLinkReader: layerLinkReader, + prePresignedURLGenerator: prePresignedURLGenerator, + } + + interceptors := connect.WithInterceptors(server.NewJWTInterceptor()) + mux := http.NewServeMux() + mux.Handle(connect_v1.NewClairServiceHandler(server, interceptors)) + return mux +} diff --git a/store/v1/automation/projects.go b/store/v1/automation/projects.go index bd108a14..d3020558 100644 --- a/store/v1/automation/projects.go +++ b/store/v1/automation/projects.go @@ -5,11 +5,13 @@ import ( "fmt" "time" + "github.com/google/uuid" + "google.golang.org/protobuf/types/known/timestamppb" + common_v1 "github.com/containerish/OpenRegistry/common/v1" github_actions_v1 "github.com/containerish/OpenRegistry/services/kon/github_actions/v1" + v1 "github.com/containerish/OpenRegistry/store/v1" "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/google/uuid" - "google.golang.org/protobuf/types/known/timestamppb" ) // DeleteProject implements BuildAutomationStore @@ -18,7 +20,7 @@ func (s *store) DeleteProject(ctx context.Context, project *github_actions_v1.De db. NewDelete(). Model(&types.RepositoryBuildProject{}). - Where("id = ?", project.GetId()). + Where("id = ?", project.GetId().GetValue()). Exec(ctx); err != nil { return fmt.Errorf("ERR_DELETE_PROJECT: %w", err) } @@ -64,16 +66,25 @@ func (s *store) GetProject( // ListProjects implements BuildAutomationStore func (s *store) ListProjects( ctx context.Context, - project *github_actions_v1.ListProjectsRequest, + req *github_actions_v1.ListProjectsRequest, ) (*github_actions_v1.ListProjectsResponse, error) { projects := make([]*types.RepositoryBuildProject, 0) - if err := s.db.NewSelect().Model(&projects).Scan(ctx); err != nil { + + err := s. + db. + NewSelect(). + Model(&projects). + Relation("Repository"). + Where("owner_id = ?", req.GetOwnerId().GetValue()). + Scan(ctx) + if err != nil { return nil, fmt.Errorf("ERR_LIST_PROJECTS: %w", err) } protoProjects := &github_actions_v1.ListProjectsResponse{ Projects: make([]*github_actions_v1.GetProjectResponse, len(projects)), } + for i, p := range projects { proj := &github_actions_v1.GetProjectResponse{ Id: &common_v1.UUID{ @@ -87,6 +98,13 @@ func (s *store) ListProjects( WorfklowFile: p.WorkflowFile, }, CreatedAt: timestamppb.New(p.CreatedAt), + OwnerId: &common_v1.UUID{ + Value: p.RepositoryOwnerID.String(), + }, + RepositoryId: &common_v1.UUID{ + Value: p.RepositoryID.String(), + }, + RepositoryName: p.Repository.Name, } for key, value := range p.EnvironmentVariables { @@ -108,15 +126,30 @@ func (s *store) ListProjects( // StoreProject implements BuildAutomationStore func (s *store) StoreProject(ctx context.Context, project *github_actions_v1.CreateProjectRequest) error { + projectID, err := uuid.Parse(project.GetId().GetValue()) + if err != nil { + return v1.WrapDatabaseError(err, v1.DatabaseOperationWrite) + } + ownerID, err := uuid.Parse(project.GetOwnerId().GetValue()) + if err != nil { + return v1.WrapDatabaseError(err, v1.DatabaseOperationWrite) + } + + repositoryID, err := uuid.Parse(project.GetRepositoryId().GetValue()) + if err != nil { + return v1.WrapDatabaseError(err, v1.DatabaseOperationWrite) + } + proj := &types.RepositoryBuildProject{ - CreatedAt: time.Now(), - Name: project.GetProjectName(), - ProductionBranch: project.GetProductionBranch(), - BuildTool: project.GetBuildSettings().GetBuildTool(), - ExecCommand: project.GetBuildSettings().GetExecCommand(), - WorkflowFile: project.GetBuildSettings().GetWorfklowFile(), - ID: uuid.MustParse(project.GetId().GetValue()), - RepositoryID: uuid.MustParse(project.GetOwnerId().GetValue()), + CreatedAt: time.Now(), + Name: project.GetProjectName(), + ProductionBranch: project.GetProductionBranch(), + BuildTool: project.GetBuildSettings().GetBuildTool(), + ExecCommand: project.GetBuildSettings().GetExecCommand(), + WorkflowFile: project.GetBuildSettings().GetWorfklowFile(), + ID: projectID, + RepositoryOwnerID: ownerID, + RepositoryID: repositoryID, } for _, envVar := range project.GetEnvironmentVariables().GetEnvironmentVariables() { diff --git a/store/v1/emails/emails_impl.go b/store/v1/emails/emails_impl.go index 03dfd0fb..6acc3a19 100644 --- a/store/v1/emails/emails_impl.go +++ b/store/v1/emails/emails_impl.go @@ -34,7 +34,7 @@ func (es *emailStore) AddVerifyEmail(ctx context.Context, userID uuid.UUID, toke } func (es *emailStore) DeleteVerifyEmail(ctx context.Context, userID uuid.UUID) error { - if _, err := es.db.NewDelete().Model(&types.Email{}).Where("user_id = ?1", userID).Exec(ctx); err != nil { + if _, err := es.db.NewDelete().Model(&types.Email{}).Where("user_id = ?", userID).Exec(ctx); err != nil { return v2.WrapDatabaseError(err, v2.DatabaseOperationDelete) } @@ -42,8 +42,9 @@ func (es *emailStore) DeleteVerifyEmail(ctx context.Context, userID uuid.UUID) e } func (es *emailStore) GetVerifyEmail(ctx context.Context, userID uuid.UUID) (uuid.UUID, error) { - email := &types.Email{} - if err := es.db.NewSelect().Model(email).Where("user_id = ?1", userID).Scan(ctx); err != nil { + var email *types.Email + + if err := es.db.NewSelect().Model(email).Where("user_id = ?", userID).Scan(ctx); err != nil { return uuid.UUID{}, v2.WrapDatabaseError(err, v2.DatabaseOperationRead) } diff --git a/store/v1/permissions/permissions.go b/store/v1/permissions/permissions.go index e7df1290..a1fa2a6f 100644 --- a/store/v1/permissions/permissions.go +++ b/store/v1/permissions/permissions.go @@ -17,7 +17,7 @@ type ( // It doesn't return any errors. If the user has permissions, they're be reflect in the returned // *types.Permissions struct, otherwise, the returned type will be an empty, non-nil struct GetUserPermissionsForNamespace(ctx context.Context, ns string, userID uuid.UUID) *types.Permissions - AddPermissions(ctx context.Context, perm *types.Permissions) error + AddPermissions(ctx context.Context, perm *types.AddUsersToOrgRequest) error UpdatePermissions(ctx context.Context, perm *types.Permissions) error RemoveUserFromOrg(ctx context.Context, orgID, userID uuid.UUID) error } diff --git a/store/v1/permissions/permissions_impl.go b/store/v1/permissions/permissions_impl.go index 682714c9..156e0926 100644 --- a/store/v1/permissions/permissions_impl.go +++ b/store/v1/permissions/permissions_impl.go @@ -14,14 +14,31 @@ import ( // AddPermission implements PermissionsStore. func (p *permissionStore) AddPermissions( ctx context.Context, - perm *types.Permissions, + input *types.AddUsersToOrgRequest, ) error { - err := p.validatePermissionInput(perm) + err := p.validateAddOrgMembersInput(input) if err != nil { return v1.WrapDatabaseError(err, v1.DatabaseOperationWrite) } + perms := make([]*types.Permissions, len(input.Users)) + + for i, p := range input.Users { + perm := &types.Permissions{ + UserID: p.ID, + OrganizationID: input.OrganizationID, + Push: p.Push, + Pull: p.Pull, + IsAdmin: p.IsAdmin, + } + if p.IsAdmin { + perm.Pull = true + perm.Push = true + } + + perms[i] = perm + } - if _, err = p.db.NewInsert().Model(perm).Exec(ctx); err != nil { + if _, err = p.db.NewInsert().Model(&perms).Exec(ctx); err != nil { return err } @@ -48,12 +65,12 @@ func (p *permissionStore) GetUserPermissionsForOrg( orgID uuid.UUID, userID uuid.UUID, ) (*types.Permissions, error) { - var perm types.Permissions + perm := &types.Permissions{} err := p. db. NewSelect(). - Model(&perm). + Model(perm). Where("user_id = ?", userID.String()). Where("organization_id = ?", orgID). Scan(ctx) @@ -62,7 +79,7 @@ func (p *permissionStore) GetUserPermissionsForOrg( return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } - return &perm, nil + return perm, nil } func (p *permissionStore) UpdatePermissions(ctx context.Context, perm *types.Permissions) error { @@ -101,12 +118,30 @@ func (p *permissionStore) validatePermissionInput(perm *types.Permissions) error return nil } +func (p *permissionStore) validateAddOrgMembersInput(input *types.AddUsersToOrgRequest) error { + if input == nil { + return fmt.Errorf("permission set is nil") + } + + if input.OrganizationID.String() == "" { + return fmt.Errorf("invalid organization id") + } + + for _, u := range input.Users { + if u.ID.String() == "" { + return fmt.Errorf("invalid user id") + } + } + + return nil +} + func (p *permissionStore) RemoveUserFromOrg(ctx context.Context, orgID, userID uuid.UUID) error { - var perm types.Permissions + perm := &types.Permissions{} _, err := p. db. NewDelete(). - Model(&perm). + Model(perm). Where("organization_id = ?", orgID.String()). Where("user_id = ?", userID.String()). Exec(ctx) @@ -122,18 +157,18 @@ func (p *permissionStore) GetUserPermissionsForNamespace( ns string, userID uuid.UUID, ) *types.Permissions { - perms := types.Permissions{} + perms := &types.Permissions{} nsParts := strings.Split(ns, "/") if len(nsParts) != 2 { - return &perms + return perms } orgName := nsParts[0] q := p. db. NewSelect(). - Model(&perms). + Model(perms). Relation("Organization", func(sq *bun.SelectQuery) *bun.SelectQuery { return sq. Where(`"organization"."username" = ?`, orgName). @@ -146,9 +181,9 @@ func (p *permissionStore) GetUserPermissionsForNamespace( }) if err := q.Scan(ctx); err != nil { - return &perms + return perms } - return &perms + return perms } diff --git a/store/v1/registry/registry_impl.go b/store/v1/registry/registry_impl.go index fa5ed923..1dbdfd1f 100644 --- a/store/v1/registry/registry_impl.go +++ b/store/v1/registry/registry_impl.go @@ -114,11 +114,11 @@ func (s *registryStore) GetRepositoryByName( Str("name", name). Str("user_id", userId.String()) - var repository types.ContainerImageRepository + repository := &types.ContainerImageRepository{} err := s. db. NewSelect(). - Model(&repository). + Model(repository). WhereGroup(" AND ", func(sq *bun.SelectQuery) *bun.SelectQuery { return sq.Where("name = ?", name) }). @@ -132,7 +132,7 @@ func (s *registryStore) GetRepositoryByName( } logEvent.Bool("success", true).Send() - return &repository, nil + return repository, nil } func (s *registryStore) DeleteLayerByDigestWithTxn(ctx context.Context, txn *bun.Tx, digest string) error { @@ -205,7 +205,7 @@ func (s *registryStore) GetCatalog( pageSize int, offset int, ) ([]string, error) { - var catalog []types.ContainerImageRepository + var catalog []*types.ContainerImageRepository repositoryName := strings.Split(namespace, "/")[1] err := s. @@ -260,6 +260,9 @@ func (s *registryStore) GetUserRepositories( db. NewSelect(). Model(&repositories). + Relation("User", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq.ExcludeColumn("password").ExcludeColumn("github_connected").ExcludeColumn("webauthn_connected") + }). WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery { if visibility != "" { return q.Where("visibility = ?", visibility) @@ -289,7 +292,7 @@ func (s *registryStore) GetCatalogCount(ctx context.Context, namespace string) ( repositoryName = parts[1] } - stmnt := s. + q := s. db. NewSelect(). Model(&types.ImageManifest{}). @@ -297,10 +300,10 @@ func (s *registryStore) GetCatalogCount(ctx context.Context, namespace string) ( Where("visibility = ?", types.RepositoryVisibilityPublic) if repositoryName != "" { - stmnt.Where("name = ?", repositoryName) + q.Where("name = ?", repositoryName) } - count, err := stmnt.Count(ctx) + count, err := q.Count(ctx) if err != nil { logEvent.Err(err).Send() return 0, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) @@ -326,20 +329,21 @@ func (s *registryStore) GetCatalogDetail( repositoryName = parts[1] } - stmnt := s. + q := s. db. NewSelect(). Model(&repositoryList). + Relation("User"). Relation("ImageManifests"). Limit(pageSize). Offset(offset). Where("visibility = ?", types.RepositoryVisibilityPublic) if repositoryName != "" { - stmnt.Where("name = ?", repositoryName) + q.Where("name = ?", repositoryName) } - err := stmnt.Scan(ctx) + err := q.Scan(ctx) if err != nil { logEvent.Err(err).Send() return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) @@ -363,19 +367,48 @@ func (s *registryStore) GetContentHashById(ctx context.Context, uuid string) (st return dfsLink, nil } +func (s *registryStore) excludeUserSensitiveFieldsOnJoin(sq *bun.SelectQuery) *bun.SelectQuery { + return sq.ExcludeColumn("password").ExcludeColumn("created_at").ExcludeColumn("updated_at") +} + // GetImageNamespace implements registry.RegistryStore. -func (s *registryStore) GetImageNamespace(ctx context.Context, search string) ([]*types.ImageManifest, error) { +func (s *registryStore) GetImageNamespace( + ctx context.Context, + search string, + visibility types.RepositoryVisibility, + userID uuid.UUID, +) ([]*types.ContainerImageRepository, error) { logEvent := s.logger.Debug().Str("method", "GetImageNamespace").Str("search_query", search) - var manifests []*types.ImageManifest + var repos []*types.ContainerImageRepository - err := s.db.NewSelect().Model(&manifests).Where("substr(namespace, 1, 50) LIKE ?", bun.Ident(search)).Scan(ctx) - if err != nil { + q := s. + db. + NewSelect(). + Model(&repos). + Relation("User", func(sq *bun.SelectQuery) *bun.SelectQuery { + return s.excludeUserSensitiveFieldsOnJoin(sq) + }). + WhereGroup(" AND ", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq. + WhereOr("visibility = ?", types.RepositoryVisibilityPublic.String()). + WhereOr("owner_id = ?", userID) + }). + WhereGroup(" AND ", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq.WhereOr("substr(username, 1, 50) ILIKE ?", search). + WhereOr("substr(name, 1, 50) ILIKE ?", search) + }) + + if visibility == types.RepositoryVisibilityPublic { + q.Where("visibility = ? ", visibility.String()) + } + + if err := q.Scan(ctx); err != nil { logEvent.Err(err).Send() return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } logEvent.Bool("success", true).Send() - return manifests, nil + return repos, nil } // GetImageTags implements registry.RegistryStore. @@ -409,27 +442,27 @@ func (s *registryStore) GetImageTags(ctx context.Context, namespace string) ([]s // GetLayer implements registry.RegistryStore. func (s *registryStore) GetLayer(ctx context.Context, digest string) (*types.ContainerImageLayer, error) { logEvent := s.logger.Debug().Str("method", "GetLayer").Str("digest", digest) - var layer types.ContainerImageLayer - if err := s.db.NewSelect().Model(&layer).Where("digest = ?", digest).Scan(ctx); err != nil { + layer := &types.ContainerImageLayer{} + if err := s.db.NewSelect().Model(layer).Where("digest = ?", digest).Scan(ctx); err != nil { logEvent.Err(err).Send() return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } logEvent.Bool("success", true).Send() - return &layer, nil + return layer, nil } // GetManifest implements registry.RegistryStore. func (s *registryStore) GetManifest(ctx context.Context, id string) (*types.ImageManifest, error) { logEvent := s.logger.Debug().Str("method", "GetManifest").Str("id", id) - var manifest types.ImageManifest - if err := s.db.NewSelect().Model(&manifest).Where("id = ?", id).Scan(ctx); err != nil { + manifest := &types.ImageManifest{} + if err := s.db.NewSelect().Model(manifest).Where("id = ?", id).Scan(ctx); err != nil { logEvent.Err(err).Send() return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } logEvent.Bool("success", true).Send() - return &manifest, nil + return manifest, nil } // GetManifestByReference implements registry.RegistryStore. @@ -444,11 +477,11 @@ func (s *registryStore) GetManifestByReference( nsParts := strings.Split(namespace, "/") username, repoName := nsParts[0], nsParts[1] - var manifest types.ImageManifest + manifest := &types.ImageManifest{} q := s. db. NewSelect(). - Model(&manifest). + Model(manifest). Relation("Repository", func(sq *bun.SelectQuery) *bun.SelectQuery { return sq.Column("name") }). @@ -472,7 +505,7 @@ func (s *registryStore) GetManifestByReference( } logEvent.Bool("success", true).Send() - return &manifest, nil + return manifest, nil } // GetRepoDetail implements registry.RegistryStore. @@ -483,13 +516,13 @@ func (s *registryStore) GetRepoDetail( offset int, ) (*types.ContainerImageRepository, error) { logEvent := s.logger.Debug().Str("method", "GetRepoDetail") - var repoDetail types.ContainerImageRepository + repoDetail := &types.ContainerImageRepository{} repositoryName := strings.Split(namespace, "/")[1] err := s. db. NewSelect(). - Model(&repoDetail). + Model(repoDetail). Relation("ImageManifests"). Where("name = ?", repositoryName). Limit(pageSize). @@ -502,13 +535,13 @@ func (s *registryStore) GetRepoDetail( } logEvent.Bool("success", true).Send() - return &repoDetail, nil + return repoDetail, nil } // SetContainerImageVisibility implements registry.RegistryStore. func (s *registryStore) SetContainerImageVisibility( ctx context.Context, - imageId string, + imageId uuid.UUID, visibility types.RepositoryVisibility, ) error { logEvent := s.logger.Debug().Str("method", "SetContainerImageVisibility") @@ -516,9 +549,9 @@ func (s *registryStore) SetContainerImageVisibility( _, err := s. db. NewUpdate(). - Model(&types.ContainerImageRepository{}). - Set("visibility = ?", visibility). - WherePK(imageId). + Model(&types.ContainerImageRepository{ID: imageId}). + Set("visibility = ?", visibility.String()). + WherePK(). Where("name != ?", types.SystemUsernameIPFS). // IPFS repositories cannot be set to private since they are P2P Exec(ctx) if err != nil { @@ -704,11 +737,11 @@ func (s *registryStore) GetImageSizeByLayerIds(ctx context.Context, layerIDs []s } func (s *registryStore) IncrementRepositoryPullCounter(ctx context.Context, repoID uuid.UUID) error { - repo := types.ContainerImageRepository{ + repo := &types.ContainerImageRepository{ ID: repoID, } - _, err := s.db.NewUpdate().Model(&repo).WherePK().Set("pull_count = pull_count + 1").Exec(ctx) + _, err := s.db.NewUpdate().Model(repo).WherePK().Set("pull_count = pull_count + 1").Exec(ctx) if err != nil { return v1.WrapDatabaseError(err, v1.DatabaseOperationUpdate) } @@ -717,12 +750,12 @@ func (s *registryStore) IncrementRepositoryPullCounter(ctx context.Context, repo } func (s *registryStore) AddRepositoryToFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error { - user := types.User{} + user := &types.User{} q := s. db. NewUpdate(). - Model(&user). + Model(user). Set("favorite_repositories = array_append(favorite_repositories, ?)", repoID). Where("id = ?", userID). Where("NOT (? = ANY(favorite_repositories))", repoID) @@ -738,11 +771,11 @@ func (s *registryStore) AddRepositoryToFavorites(ctx context.Context, repoID uui } if rowsAffected == 1 { - repo := types.ContainerImageRepository{ + repo := &types.ContainerImageRepository{ ID: repoID, } - _, err = s.db.NewUpdate().Model(&repo).WherePK().Set("favorite_count = favorite_count + 1").Exec(ctx) + _, err = s.db.NewUpdate().Model(repo).WherePK().Set("favorite_count = favorite_count + 1").Exec(ctx) if err != nil { return v1.WrapDatabaseError(err, v1.DatabaseOperationUpdate) } @@ -754,11 +787,11 @@ func (s *registryStore) AddRepositoryToFavorites(ctx context.Context, repoID uui } func (s *registryStore) RemoveRepositoryFromFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error { - user := types.User{} + user := &types.User{} q := s. db. NewUpdate(). - Model(&user). + Model(user). Set("favorite_repositories = array_remove(favorite_repositories, ?)", repoID). Where("id = ?", userID). Where("? = ANY(favorite_repositories)", repoID) @@ -770,11 +803,11 @@ func (s *registryStore) RemoveRepositoryFromFavorites(ctx context.Context, repoI rowsAffected, err := result.RowsAffected() if err == nil && rowsAffected == 1 { - repo := types.ContainerImageRepository{ + repo := &types.ContainerImageRepository{ ID: repoID, } - _, err = s.db.NewUpdate().Model(&repo).WherePK().Set("favorite_count = favorite_count - 1").Exec(ctx) + _, err = s.db.NewUpdate().Model(repo).WherePK().Set("favorite_count = favorite_count - 1").Exec(ctx) if err != nil { return v1.WrapDatabaseError(err, v1.DatabaseOperationUpdate) } @@ -786,3 +819,74 @@ func (s *registryStore) RemoveRepositoryFromFavorites(ctx context.Context, repoI v1.DatabaseOperationUpdate, ) } + +func (s *registryStore) GetLayersLinksForManifest( + ctx context.Context, + manifestDigest string, +) ([]*types.ContainerImageLayer, error) { + logEvent := s.logger.Debug().Str("method", "GetLayersLinksForManifest").Str("digest", manifestDigest) + + manifest := &types.ImageManifest{} + err := s.db.NewSelect().Model(manifest).Where("digest = ?", manifestDigest).Scan(ctx) + if err != nil { + return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) + } + + layerDigests := make([]string, len(manifest.Layers)) + for i, l := range manifest.Layers { + layerDigests[i] = l.Digest.String() + } + + var layers []*types.ContainerImageLayer + if err = s. + db. + NewSelect(). + Model(&layers). + Where("digest in (?)", bun.In(layerDigests)). + Scan(ctx); err != nil { + logEvent.Err(err).Send() + return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) + } + + logEvent.Bool("success", true).Send() + return layers, nil +} +func (s *registryStore) ListFavoriteRepositories( + ctx context.Context, + userID uuid.UUID, +) ([]*types.ContainerImageRepository, error) { + logEvent := s.logger.Debug().Str("method", "ListFavoriteRepositories") + + repositories := []*types.ContainerImageRepository{} + user := &types.User{ID: userID} + err := s. + db. + NewSelect(). + Model(user). + WherePK(). + Scan(ctx) + + if err != nil { + return nil, err + } + + if len(user.FavoriteRepositories) == 0 { + return repositories, nil + } + + q := s. + db. + NewSelect(). + Model(&repositories). + Where(`"r"."id" in (?)`, bun.In(user.FavoriteRepositories)). + Relation("User", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq.ExcludeColumn("password").ExcludeColumn("github_connected").ExcludeColumn("webauthn_connected") + }) + + if err := q.Scan(ctx); err != nil { + logEvent.Err(err).Send() + return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) + } + + return repositories, nil +} diff --git a/store/v1/registry/store.go b/store/v1/registry/store.go index b1a526f1..ed044452 100644 --- a/store/v1/registry/store.go +++ b/store/v1/registry/store.go @@ -64,7 +64,12 @@ type RegistryStore interface { offset int, ) (*types.ContainerImageRepository, error) GetCatalogCount(ctx context.Context, ns string) (int64, error) - GetImageNamespace(ctx context.Context, search string) ([]*types.ImageManifest, error) + GetImageNamespace( + ctx context.Context, + search string, + visibility types.RepositoryVisibility, + userId uuid.UUID, + ) ([]*types.ContainerImageRepository, error) DeleteLayerByDigest(ctx context.Context, digest string) error GetPublicRepositories(ctx context.Context, pageSize int, offset int) ([]*types.ContainerImageRepository, int, error) GetUserRepositories( @@ -77,7 +82,7 @@ type RegistryStore interface { DeleteLayerByDigestWithTxn(ctx context.Context, txn *bun.Tx, digest string) error DeleteManifestOrTag(ctx context.Context, reference string) error DeleteManifestOrTagWithTxn(ctx context.Context, txn *bun.Tx, reference string) error - SetContainerImageVisibility(ctx context.Context, imageId string, visibility types.RepositoryVisibility) error + SetContainerImageVisibility(ctx context.Context, imageId uuid.UUID, visibility types.RepositoryVisibility) error CreateRepository(ctx context.Context, repository *types.ContainerImageRepository) error GetRepositoryByID(ctx context.Context, ID uuid.UUID) (*types.ContainerImageRepository, error) @@ -87,4 +92,6 @@ type RegistryStore interface { IncrementRepositoryPullCounter(ctx context.Context, repoID uuid.UUID) error AddRepositoryToFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error RemoveRepositoryFromFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error + GetLayersLinksForManifest(ctx context.Context, manifestDigest string) ([]*types.ContainerImageLayer, error) + ListFavoriteRepositories(ctx context.Context, userID uuid.UUID) ([]*types.ContainerImageRepository, error) } diff --git a/store/v1/sessions/sessions_impl.og b/store/v1/sessions/sessions_impl.og deleted file mode 100644 index 5dd3be9b..00000000 --- a/store/v1/sessions/sessions_impl.og +++ /dev/null @@ -1,11 +0,0 @@ - -// DeleteAllSessions implements UserStore. -func (u *userStore) DeleteAllSessions(ctx context.Context, userId string) error { - panic("unimplemented") -} - -// DeleteSession implements UserStore. -func (u *userStore) DeleteSession(ctx context.Context, sessionId string, userId string) error { - panic("unimplemented") -} - diff --git a/store/v1/types/auth.go b/store/v1/types/auth.go index be611b29..539a6b50 100644 --- a/store/v1/types/auth.go +++ b/store/v1/types/auth.go @@ -19,6 +19,11 @@ type ( Type string Name string } + + ResetPasswordRequest struct { + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` + } ) func (c *OCITokenPermissonClaim) HasPushAccess() bool { diff --git a/store/v1/types/auth_tokens.go b/store/v1/types/auth_tokens.go new file mode 100644 index 00000000..0dac1ad9 --- /dev/null +++ b/store/v1/types/auth_tokens.go @@ -0,0 +1,58 @@ +package types + +import ( + "crypto/rand" + "fmt" + "strings" + "time" + + "github.com/oklog/ulid/v2" +) + +type AuthToken struct { + id ulid.ULID +} + +const ( + OpenRegistryAuthTokenPrefix = "oreg_pat_" +) + +func (at *AuthToken) String() string { + return fmt.Sprintf("%s%s", OpenRegistryAuthTokenPrefix, at.id.String()) +} + +func (at *AuthToken) Bytes() []byte { + return at.id.Bytes() +} + +func (at *AuthToken) Compare(other ulid.ULID) int { + return at.id.Compare(other) +} + +func (at *AuthToken) FromString(token string) (*AuthToken, error) { + token = strings.TrimPrefix(token, OpenRegistryAuthTokenPrefix) + + id, err := ulid.Parse(token) + if err != nil { + return nil, err + } + + return &AuthToken{id: id}, nil +} + +func (at *AuthToken) RawString() string { + return at.id.String() +} + +func CreateNewAuthToken() (*AuthToken, error) { + now := time.Now() + ms := ulid.Timestamp(now) + id, err := ulid.New(ms, rand.Reader) + if err != nil { + return nil, err + } + + return &AuthToken{ + id: id, + }, nil +} diff --git a/store/v1/types/automation.go b/store/v1/types/automation.go index 05484ed7..35218f6f 100644 --- a/store/v1/types/automation.go +++ b/store/v1/types/automation.go @@ -32,6 +32,7 @@ type ( CreatedAt time.Time `bun:"created_at" json:"created_at,omitempty" validate:"-"` EnvironmentVariables map[string]string `bun:"environment_variables,type:jsonb" json:"environment_variables"` Repository *ContainerImageRepository `bun:"rel:belongs-to,join:repository_id=id" json:"-"` + User *User `bun:"rel:belongs-to,join:repository_owner_id=id" json:"-"` Name string `bun:"name" json:"name"` ProductionBranch string `bun:"production_branch" json:"production_branch"` BuildTool string `bun:"build_tool" json:"build_tool"` @@ -39,5 +40,6 @@ type ( WorkflowFile string `bun:"workflow_file" json:"workflow_file"` ID uuid.UUID `bun:"id,type:uuid,pk" json:"id,omitempty" validate:"-"` RepositoryID uuid.UUID `bun:"repository_id,type:uuid" json:"repository_id"` + RepositoryOwnerID uuid.UUID `bun:"repository_owner_id,type:uuid" json:"repository_owner_id"` } ) diff --git a/store/v1/types/permissions.go b/store/v1/types/permissions.go index 9cdfb5ce..f4a118eb 100644 --- a/store/v1/types/permissions.go +++ b/store/v1/types/permissions.go @@ -13,9 +13,9 @@ type ( Permissions struct { bun.BaseModel `bun:"table:permissions,alias:p" json:"-"` - UpdatedAt time.Time `bun:"updated_at" json:"updated_at,omitempty" validate:"-"` - CreatedAt time.Time `bun:"created_at" json:"created_at,omitempty" validate:"-"` - User *User `bun:"rel:belongs-to,join:user_id=id" json:"-"` + UpdatedAt time.Time `bun:"updated_at" json:"updated_at,omitempty"` + CreatedAt time.Time `bun:"created_at" json:"created_at,omitempty"` + User *User `bun:"rel:belongs-to,join:user_id=id" json:"user"` Organization *User `bun:"rel:belongs-to,join:organization_id=id" json:"-"` UserID uuid.UUID `bun:"user_id,type:uuid" json:"user_id"` OrganizationID uuid.UUID `bun:"organization_id,type:uuid" json:"organization_id"` @@ -23,6 +23,25 @@ type ( Pull bool `bun:"pull" json:"pull"` IsAdmin bool `bun:"is_admin" json:"is_admin"` } + + MigrateToOrgRequest struct { + UserID uuid.UUID `json:"user_id"` + } + + RemoveUserFromOrgRequest struct { + UserID uuid.UUID `json:"user_id"` + OrganizationID uuid.UUID `json:"organization_id"` + } + + AddUsersToOrgRequest struct { + Users []struct { + ID uuid.UUID `json:"id"` + Pull bool `json:"pull"` + Push bool `json:"push"` + IsAdmin bool `json:"is_admin"` + } `json:"users"` + OrganizationID uuid.UUID `json:"organization_id"` + } ) var _ bun.AfterCreateTableHook = (*Permissions)(nil) diff --git a/store/v1/types/registry.go b/store/v1/types/registry.go index 19e27a27..0dc9f2ff 100644 --- a/store/v1/types/registry.go +++ b/store/v1/types/registry.go @@ -33,8 +33,8 @@ func (v RepositoryVisibility) String() string { type ( ContainerImageVisibilityChangeRequest struct { - ImageManifestUUID string `json:"image_manifest_uuid"` - Visibility RepositoryVisibility `json:"visibility_mode"` + Visibility RepositoryVisibility `json:"visibility_mode"` + RepositoryID uuid.UUID `json:"repository_id"` } ImageManifest struct { @@ -42,7 +42,7 @@ type ( CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"createdAt"` UpdatedAt time.Time `bun:"updated_at,nullzero" json:"updatedAt"` - Repository *ContainerImageRepository `bun:"rel:belongs-to,join:repository_id=id" json:"-"` + Repository *ContainerImageRepository `bun:"rel:belongs-to,join:repository_id=id" json:"repository"` User *User `bun:"rel:belongs-to,join:owner_id=id" json:"-"` Subject *img_spec_v1.Descriptor `bun:"embed:subject_" json:"subject,omitempty"` Config *img_spec_v1.Descriptor `bun:"embed:config_" json:"config"` @@ -93,17 +93,17 @@ type ( CreatedAt time.Time `bun:"created_at" json:"created_at"` UpdatedAt time.Time `bun:"updated_at" json:"updated_at"` MetaTags map[string]any `bun:"meta_tags" json:"meta_tags"` - User *User `bun:"rel:belongs-to,join:owner_id=id" json:"-"` + User *User `bun:"rel:belongs-to,join:owner_id=id" json:"user"` Project *RepositoryBuild `bun:"rel:has-one,join:id=repository_id" json:"-"` - Description string `bun:"description" json:"description"` - Visibility RepositoryVisibility `bun:"visibility,notnull" json:"visibility"` Name string `bun:"name,notnull" json:"name"` + Visibility RepositoryVisibility `bun:"visibility,notnull" json:"visibility"` + Description string `bun:"description" json:"description"` ImageManifests []*ImageManifest `bun:"rel:has-many,join:id=repository_id" json:"image_manifests,omitempty"` Builds []*RepositoryBuild `bun:"rel:has-many,join:id=repository_id" json:"-"` - ID uuid.UUID `bun:"id,pk,type:uuid,default:gen_random_uuid()" json:"id"` - OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"owner_id"` PullCount uint64 `bun:"pull_count" json:"pull_count"` FavoriteCount uint64 `bun:"favorite_count" json:"favorite_count"` + ID uuid.UUID `bun:"id,pk,type:uuid,default:gen_random_uuid()" json:"id"` + OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"owner_id"` } RepositoryVisibility string diff --git a/store/v1/types/users.go b/store/v1/types/users.go index 9443fdcb..825ce5bd 100644 --- a/store/v1/types/users.go +++ b/store/v1/types/users.go @@ -55,10 +55,12 @@ type ( Sessions []*Session `bun:"rel:has-many,join:id=owner_id" json:"-"` WebauthnSessions []*WebauthnSession `bun:"rel:has-many,join:id=user_id" json:"-"` WebauthnCredentials []*WebauthnCredential `bun:"rel:has-many,join:id=credential_owner_id" json:"-"` - Permissions []*Permissions `bun:"rel:has-many,join:id=user_id" json:"-"` + Permissions []*Permissions `bun:"rel:has-many,join:id=user_id" json:"permissions"` Repositories []*ContainerImageRepository `bun:"rel:has-many,join:id=owner_id" json:"-"` + Projects []*RepositoryBuildProject `bun:"rel:has-many,join:id=repository_owner_id" json:"-"` + AuthTokens []*AuthTokens `bun:"rel:has-many,join:id=owner_id" json:"-"` // nolint:lll - FavoriteRepositories []uuid.UUID `bun:"favorite_repositories,type:uuid[],default:'{}'" json:"favorite_repositories"` + FavoriteRepositories []uuid.UUID `bun:"favorite_repositories,nullzero,type:uuid[],default:'{}'" json:"favorite_repositories"` ID uuid.UUID `bun:"id,type:uuid,pk" json:"id,omitempty" validate:"-"` IsActive bool `bun:"is_active" json:"is_active,omitempty" validate:"-"` WebauthnConnected bool `bun:"webauthn_connected" json:"webauthn_connected"` @@ -66,6 +68,16 @@ type ( IsOrgOwner bool `bun:"is_org_owner" json:"is_org_owner,omitempty"` } + AuthTokens struct { + bun.BaseModel `bun:"table:auth_tokens,alias:s" json:"-"` + + CreatedAt time.Time `bun:"created_at" json:"created_at,omitempty" validate:"-"` + ExpiresAt time.Time `bun:"expires_at" json:"expires_at,omitempty" validate:"-"` + Name string `bun:"name" json:"name"` + AuthToken string `bun:"auth_token,type:text,pk" json:"-"` + OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"-"` + } + // type here is string so that we can use it with echo.Context & std context.Context ContextKey string @@ -94,6 +106,11 @@ type ( Token uuid.UUID `bun:"token,pk,type:uuid" json:"-"` UserId uuid.UUID `bun:"user_id,type:uuid" json:"-"` } + + CreateAuthTokenRequest struct { + ExpiresAt time.Time `json:"expires_at"` + Name string `json:"name"` + } ) const ( @@ -119,6 +136,7 @@ func (*User) NewUserFromGitHubUser(ghUser github.User) *User { Email: ghUser.GetEmail(), IsActive: true, GithubConnected: true, + UserType: UserTypeRegular.String(), Identities: map[string]*UserIdentity{ IdentityProviderGitHub: { ID: fmt.Sprintf("%d", ghUser.GetID()), diff --git a/types/uuid.go b/store/v1/types/uuid.go similarity index 100% rename from types/uuid.go rename to store/v1/types/uuid.go diff --git a/store/v1/users/store.go b/store/v1/users/store.go index daca0e04..aa2d1055 100644 --- a/store/v1/users/store.go +++ b/store/v1/users/store.go @@ -32,19 +32,28 @@ type UserStore interface { } type UserReader interface { + UserGetter + GetIPFSUser(ctx context.Context) (*types.User, error) - GetUserByID(ctx context.Context, userID uuid.UUID) (*types.User, error) GetUserByIDWithTxn(ctx context.Context, id uuid.UUID, txn *bun.Tx) (*types.User, error) - GetUserByUsername(ctx context.Context, username string) (*types.User, error) GetUserByUsernameWithTxn(ctx context.Context, username string, txn *bun.Tx) (*types.User, error) - GetUserByEmail(ctx context.Context, email string) (*types.User, error) - GetUserWithSession(ctx context.Context, sessionId string) (*types.User, error) GetGitHubUser(ctx context.Context, identifier string, txn *bun.Tx) (*types.User, error) IsActive(ctx context.Context, identifier uuid.UUID) bool - // ID can be either a username, oauth login (GitHub username) or the user id (uuid) - UserExists(ctx context.Context, username, email string) (bool, bool) GetOrgAdmin(ctx context.Context, orgID uuid.UUID) (*types.User, error) Search(ctx context.Context, query string) ([]*types.User, error) + GetOrgUsersByOrgID(ctx context.Context, orgID uuid.UUID) ([]*types.Permissions, error) + MatchUserType(ctx context.Context, userType types.UserType, userIds ...uuid.UUID) bool + AddAuthToken(ctx context.Context, token *types.AuthTokens) error + ListAuthTokens(ctx context.Context, ownerID uuid.UUID) ([]*types.AuthTokens, error) + GetAuthToken(ctx context.Context, ownerID uuid.UUID, hashedToken string) (*types.AuthTokens, error) +} + +type UserGetter interface { + GetUserByID(ctx context.Context, userID uuid.UUID) (*types.User, error) + GetUserByUsername(ctx context.Context, username string) (*types.User, error) + GetUserByEmail(ctx context.Context, email string) (*types.User, error) + GetUserWithSession(ctx context.Context, sessionId string) (*types.User, error) + UserExists(ctx context.Context, username, email string) (bool, bool) } type UserWriter interface { diff --git a/store/v1/users/users_impl.go b/store/v1/users/users_impl.go index c8574ff3..0daa3094 100644 --- a/store/v1/users/users_impl.go +++ b/store/v1/users/users_impl.go @@ -3,7 +3,9 @@ package users import ( "context" "database/sql" + "fmt" "strings" + "time" v1 "github.com/containerish/OpenRegistry/store/v1" "github.com/containerish/OpenRegistry/store/v1/types" @@ -62,12 +64,14 @@ func (us *userStore) DeleteUser(ctx context.Context, identifier uuid.UUID) error // GetGitHubUser implements UserStore. func (us *userStore) GetGitHubUser(ctx context.Context, githubEmail string, txn *bun.Tx) (*types.User, error) { user := &types.User{} - selectFn := us.db.NewSelect().Model(user) + q := us.db.NewSelect().Model(user) if txn != nil { - selectFn = txn.NewSelect().Model(user) + q = txn.NewSelect().Model(user) } - if err := selectFn.Where("coalesce(identities->'github'->>'email', '') = ?", githubEmail).Scan(ctx); err != nil { + q.Where("coalesce(identities->'github'->>'email', '') = ?", githubEmail) + + if err := q.Scan(ctx); err != nil { return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } @@ -121,12 +125,12 @@ func (us *userStore) GetUserByUsernameWithTxn(ctx context.Context, username stri } func (us *userStore) GetIPFSUser(ctx context.Context) (*types.User, error) { - var user types.User - if err := us.db.NewSelect().Model(&user).Where("username = ?", types.SystemUsernameIPFS).Scan(ctx); err != nil { + user := &types.User{} + if err := us.db.NewSelect().Model(user).Where("username = ?", types.SystemUsernameIPFS).Scan(ctx); err != nil { return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) } - return &user, nil + return user, nil } // GetUserWithSession implements UserStore. @@ -189,7 +193,7 @@ func (us *userStore) githubUserExists(ctx context.Context, username, email strin NewSelect(). Model(&types.User{}). Where( - "identities->'github'->>'email' = ?1 or identities->'github'->>'username' = ?", + "identities->'github'->>'email' = ? or identities->'github'->>'username' = ?", bun.Ident(email), bun.Ident(username), ). @@ -208,7 +212,7 @@ func (us *userStore) webAuthnUserExists(ctx context.Context, username, email str NewSelect(). Model(&types.User{}). Where( - "identities->'webauthn'->>'email' = ?1 or identities->'webauthn'->>'username' = ?", + "identities->'webauthn'->>'email' = ? or identities->'webauthn'->>'username' = ?", bun.Ident(email), bun.Ident(username), ). @@ -221,12 +225,12 @@ func (us *userStore) webAuthnUserExists(ctx context.Context, username, email str } func (us *userStore) ConvertUserToOrg(ctx context.Context, userID uuid.UUID) error { - user := types.User{ID: userID} + user := &types.User{ID: userID} _, err := us. db. NewUpdate(). - Model(&user). + Model(user). WherePK(). Set("user_type = ?", types.UserTypeOrganization.String()). Set("is_org_owner = ?", true). @@ -255,7 +259,7 @@ func (us *userStore) GetOrgAdmin(ctx context.Context, orgID uuid.UUID) (*types.U } func (us *userStore) Search(ctx context.Context, query string) ([]*types.User, error) { - var users []*types.User + users := []*types.User{} b := strings.Builder{} b.WriteString("%") @@ -286,3 +290,88 @@ func (us *userStore) Search(ctx context.Context, query string) ([]*types.User, e return users, nil } + +// GetOrgUsersByOrgID returns a list of Permission structs, which also has the user to which the permissions belongs to +func (us *userStore) GetOrgUsersByOrgID(ctx context.Context, orgID uuid.UUID) ([]*types.Permissions, error) { + var perms []*types.Permissions + + q := us.db.NewSelect().Model(&perms).Relation("User", func(sq *bun.SelectQuery) *bun.SelectQuery { + return sq.ExcludeColumn("password") + }).Where("organization_id = ?", orgID) + + if err := q.Scan(ctx); err != nil { + return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead) + } + + return perms, nil +} + +func (us *userStore) MatchUserType(ctx context.Context, userType types.UserType, userIds ...uuid.UUID) bool { + var users []*types.User + + q := us. + db. + NewSelect(). + Model(&users). + Where("user_type = ?", types.UserTypeRegular.String()). + Where("id in (?)", bun.In(userIds)) + + count, err := q.Count(ctx) + if err != nil { + return false + } + + return len(userIds) == count +} + +func (us *userStore) AddAuthToken(ctx context.Context, token *types.AuthTokens) error { + if token.ExpiresAt.IsZero() { + token.ExpiresAt = time.Now().AddDate(1, 0, 0) + } + + _, err := us.db.NewInsert().Model(token).Exec(ctx) + return err +} + +func (us *userStore) ListAuthTokens(ctx context.Context, ownerID uuid.UUID) ([]*types.AuthTokens, error) { + var tokens []*types.AuthTokens + + err := us. + db. + NewSelect(). + Model(&tokens). + ExcludeColumn("auth_token"). + ExcludeColumn("owner_id"). + Where("owner_id = ?", ownerID). + Scan(ctx) + if err != nil { + return nil, err + } + + return tokens, nil +} + +func (us *userStore) GetAuthToken( + ctx context.Context, + ownerID uuid.UUID, + hashedToken string, +) (*types.AuthTokens, error) { + var token types.AuthTokens + + err := us. + db. + NewSelect(). + Model(&token). + Where("owner_id = ?", ownerID). + Where("auth_token = ?", hashedToken). + Scan(ctx) + if err != nil { + return nil, err + } + + if token.ExpiresAt.Unix() < time.Now().Unix() { + return nil, fmt.Errorf("token has expired, please generate a new one") + } + + return &token, nil +} diff --git a/store/v1/webauthn/webauthn_impl.go b/store/v1/webauthn/webauthn_impl.go index e1674070..b5ae8765 100644 --- a/store/v1/webauthn/webauthn_impl.go +++ b/store/v1/webauthn/webauthn_impl.go @@ -158,7 +158,7 @@ func (ws *webauthnStore) WebauthnUserExists(ctx context.Context, email, username NewSelect(). Model(&types.User{}). Where( - "identities->'webauthn'->>'email' = ?1 or identities->'webauthn'->>'username' = ?", + "identities->'webauthn'->>'email' = ? or identities->'webauthn'->>'username' = ?", bun.Ident(email), bun.Ident(username), ). diff --git a/telemetry/otel/otel.go b/telemetry/otel/otel.go index 7c2e425f..6cd6fc56 100644 --- a/telemetry/otel/otel.go +++ b/telemetry/otel/otel.go @@ -13,7 +13,7 @@ import ( "github.com/containerish/OpenRegistry/config" ) -func ConfigureOtel(config config.Telemetry, service string, e *echo.Echo) func() { +func ConfigureOtel(config config.Honeycomb, service string, e *echo.Echo) func() { if config.Enabled { color.Green("OpenTelemetry: Enabled") bsp := baggagecopy.NewSpanProcessor(func(member baggage.Member) bool { return true }) diff --git a/types/types.go b/types/types.go index 1686d805..589b5b12 100644 --- a/types/types.go +++ b/types/types.go @@ -137,11 +137,6 @@ type ( Namespace string `json:"namespace"` Tags []*ConfigV2 `json:"tags"` } - - Password struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` - } ) func (md Metadata) GetManifestByRef(ref string) (*Config, error) { diff --git a/vcs/github/actions.go b/vcs/github/actions.go index f23255eb..04f57d3f 100644 --- a/vcs/github/actions.go +++ b/vcs/github/actions.go @@ -9,6 +9,7 @@ import ( "time" "github.com/google/go-github/v56/github" + "gopkg.in/yaml.v3" ) func (gh *ghAppService) doesWorkflowExist(ctx context.Context, client *github.Client, r *github.Repository) bool { @@ -72,7 +73,18 @@ func (gh *ghAppService) createBranch(ctx context.Context, client *github.Client, return nil } -func (gh *ghAppService) createWorkflowFile(ctx context.Context, client *github.Client, r *github.Repository) error { +type WorkflowProperties struct { + RegistryEndpoint string + RepositoryOwner string + RepositoryName string +} + +func (gh *ghAppService) createWorkflowFile( + ctx context.Context, + client *github.Client, + r *github.Repository, + props *WorkflowProperties, +) error { msg := "build(ci): OpenRegistry build and push" tpl, err := template.New("github-actions-workflow").Delims("[[", "]]").Parse(buildAndPushTemplate) @@ -81,13 +93,23 @@ func (gh *ghAppService) createWorkflowFile(ctx context.Context, client *github.C } buf := &bytes.Buffer{} - if err = tpl.Execute(buf, r.GetDefaultBranch()); err != nil { + if err = tpl.Execute(buf, props); err != nil { return fmt.Errorf("ERR_EXECUTE_TEMPLATE: %w", err) } + yamlWorkflow := make(map[any]any) + if err = yaml.Unmarshal(buf.Bytes(), &yamlWorkflow); err != nil { + return fmt.Errorf("ERR_ENCODE_YAML_WORKFLOW: %w", err) + } + + yamlWorkflowBz, err := yaml.Marshal(yamlWorkflow) + if err != nil { + return err + } + opts := &github.RepositoryContentFileOptions{ Message: github.String(msg), - Content: buf.Bytes(), + Content: yamlWorkflowBz, Branch: github.String(gh.automationBranchName), } _, _, err = client.Repositories.CreateFile(ctx, r.GetOwner().GetLogin(), r.GetName(), gh.workflowFilePath, opts) diff --git a/vcs/github/github.go b/vcs/github/github.go index e8abd6f1..a6e83544 100644 --- a/vcs/github/github.go +++ b/vcs/github/github.go @@ -9,34 +9,37 @@ import ( "time" "github.com/bradleyfalzon/ghinstallation/v2" - "github.com/containerish/OpenRegistry/config" - "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/containerish/OpenRegistry/telemetry" - "github.com/containerish/OpenRegistry/vcs" "github.com/fatih/color" "github.com/google/go-github/v56/github" "github.com/google/uuid" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/config" + "github.com/containerish/OpenRegistry/store/v1/types" + "github.com/containerish/OpenRegistry/telemetry" + "github.com/containerish/OpenRegistry/vcs" ) type ghAppService struct { store vcs.VCSStore logger telemetry.Logger - config *config.Integration + config *config.GithubIntegration ghClient *github.Client ghAppTransport *ghinstallation.AppsTransport automationBranchName string workflowFilePath string + registryEndpoint string webInterfaceURLs []string env config.Environment } func NewGithubApp( - cfg *config.Integration, + cfg *config.GithubIntegration, store vcs.VCSStore, logger telemetry.Logger, webInterfaceURLs []string, env config.Environment, + registryEndpoint string, ) vcs.VCS { ghAppTransport, ghClient, err := newGHClient(cfg.AppID, cfg.PrivateKeyPem) if err != nil { @@ -53,6 +56,7 @@ func NewGithubApp( automationBranchName: OpenRegistryAutomationBranchName, webInterfaceURLs: webInterfaceURLs, env: env, + registryEndpoint: registryEndpoint, } } @@ -69,66 +73,69 @@ func (gh *ghAppService) ListHandlers() []echo.HandlerFunc { // RegisterRoutes takes in a echo.Group (aka sub router) which is prefix with VCS name // eg: for GitHub, the sub router would be prefixed with "/github" -func (gh *ghAppService) RegisterRoutes(r *echo.Group) { - r.Use( +func (gh *ghAppService) RegisterRoutes(router *echo.Group) { + router.Use( gh.getUsernameMiddleware(), gh.getGitubInstallationID(vcs.HandleAppFinishEndpoint, vcs.HandleSetupCallbackEndpoint), ) - r.Add(http.MethodGet, vcs.ListAuthorisedRepositoriesEndpoint, gh.ListAuthorisedRepositories) - r.Add(http.MethodGet, vcs.HandleSetupCallbackEndpoint, gh.HandleSetupCallback) - r.Add(http.MethodPost, vcs.HandleWebhookEventsEndpoint, gh.HandleWebhookEvents) - r.Add(http.MethodPost, vcs.HandleAppFinishEndpoint, gh.HandleAppFinish) - r.Add(http.MethodPost, vcs.CreateInitialPREndpoint, gh.CreateInitialPR) + router.Add(http.MethodGet, vcs.ListAuthorisedRepositoriesEndpoint, gh.ListAuthorisedRepositories) + router.Add(http.MethodGet, vcs.HandleSetupCallbackEndpoint, gh.HandleSetupCallback) + router.Add(http.MethodPost, vcs.HandleWebhookEventsEndpoint, gh.HandleWebhookEvents) + router.Add(http.MethodPost, vcs.HandleAppFinishEndpoint, gh.HandleAppFinish) + router.Add(http.MethodPost, vcs.CreateInitialPREndpoint, gh.CreateInitialPR) } func (gh *ghAppService) getUsernameMiddleware() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - if c.Path() == "/github"+vcs.HandleWebhookEventsEndpoint { - return next(c) + return func(ctx echo.Context) error { + // skip if it's a webhook call + // if c.Path() == "/github"+vcs.HandleWebhookEventsEndpoint || c.Path() == "/github/app/callback" { + if ctx.Path() == "/github"+vcs.HandleWebhookEventsEndpoint { + return next(ctx) } - sessionCookie, err := c.Cookie("session_id") + + sessionCookie, err := ctx.Cookie("session_id") if err != nil { - echoErr := c.JSON(http.StatusNotAcceptable, echo.Map{ + echoErr := ctx.JSON(http.StatusNotAcceptable, echo.Map{ "error": err.Error(), "cookie_id": "session_id", }) - gh.logger.Log(c, err).Send() + gh.logger.Log(ctx, err).Send() return echoErr } // session is :, and ":" is url encoded sessionID, err := url.QueryUnescape(sessionCookie.Value) if err != nil { - echoErr := c.JSON(http.StatusNotAcceptable, echo.Map{ + echoErr := ctx.JSON(http.StatusNotAcceptable, echo.Map{ "error": err.Error(), "cookie_id": "session_id", }) - gh.logger.Log(c, err).Send() + gh.logger.Log(ctx, err).Send() return echoErr } userID := strings.Split(sessionID, ":")[1] parsedID, err := uuid.Parse(userID) if err != nil { - echoErr := c.JSON(http.StatusForbidden, echo.Map{ - "error": err.Error(), + echoErr := ctx.JSON(http.StatusForbidden, echo.Map{ + "error": fmt.Errorf("ERR_PARSE_USER_ID: %w", err), }) - gh.logger.Log(c, err).Send() + gh.logger.Log(ctx, err).Send() return echoErr } - user, err := gh.store.GetUserByID(c.Request().Context(), parsedID) + + user, err := gh.store.GetUserByID(ctx.Request().Context(), parsedID) if err != nil { - echoErr := c.JSON(http.StatusNotAcceptable, echo.Map{ - "error": err.Error(), + echoErr := ctx.JSON(http.StatusForbidden, echo.Map{ + "error": fmt.Errorf("ERR_GET_AUTHZ_USER: %w", err), }) - gh.logger.Log(c, err).Send() + gh.logger.Log(ctx, err).Send() return echoErr } - c.Set(string(UsernameContextKey), user.Username) - c.Set(string(UserContextKey), user) - return next(c) + ctx.Set(string(types.UserContextKey), user) + return next(ctx) } } } @@ -139,12 +146,13 @@ func (gh *ghAppService) getGitubInstallationID(skipRoutes ...string) echo.Middle if c.Path() == "/github"+vcs.HandleWebhookEventsEndpoint { return next(c) } - user, ok := c.Get(string(UserContextKey)).(*types.User) + user, ok := c.Get(string(types.UserContextKey)).(*types.User) if !ok { + err := fmt.Errorf("GH_MDW_ERR: username is not present in context") echoErr := c.JSON(http.StatusNotAcceptable, echo.Map{ - "error": "GH_MDW_ERR: username is not present in context", + "error": err.Error(), }) - gh.logger.Log(c, echoErr).Send() + gh.logger.Log(c, err).Send() return echoErr } @@ -159,6 +167,15 @@ func (gh *ghAppService) getGitubInstallationID(skipRoutes ...string) echo.Middle return next(c) } + if user.Identities == nil || user.Identities.GetGitHubIdentity() == nil { + err := fmt.Errorf("GH_MDW_ERR: GitHub identity not found") + echoErr := c.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + gh.logger.Log(c, err).Send() + return echoErr + } + c.Set(string(GithubInstallationIDContextKey), user.Identities.GetGitHubIdentity().InstallationID) return next(c) } @@ -168,7 +185,7 @@ func (gh *ghAppService) getGitubInstallationID(skipRoutes ...string) echo.Middle func newGHClient(appID int64, privKeyPem string) (*ghinstallation.AppsTransport, *github.Client, error) { transport, err := ghinstallation.NewAppsTransportKeyFromFile(http.DefaultTransport, appID, privKeyPem) if err != nil { - return nil, nil, fmt.Errorf("ERR_CREATE_NEW_TRANSPORT: %w", err) + return nil, nil, fmt.Errorf("ERR_CREATE_NEW_TRANSPORT: %w - file: %s", err, privKeyPem) } client := github.NewClient(&http.Client{Transport: transport, Timeout: time.Second * 30}) @@ -188,10 +205,9 @@ type AuthorizedRepository struct { type ContextKey string const ( - UsernameContextKey ContextKey = "USERNAME" - UserContextKey ContextKey = "USER" - GithubInstallationIDContextKey ContextKey = "GITHUB_INSTALLATION_ID" - WorkflowFilePath = ".github/workflows/openregistry.yml" - OpenRegistryAutomationBranchName = "openregistry-build-automation" - MaxGitHubRedirects = 3 + GithubInstallationIDContextKey ContextKey = "GITHUB_INSTALLATION_ID" + + WorkflowFilePath = ".github/workflows/openregistry.yml" + OpenRegistryAutomationBranchName = "openregistry-build-automation" + MaxGitHubRedirects = 3 ) diff --git a/vcs/github/handlers.go b/vcs/github/handlers.go index 6ccc6902..0cde8197 100644 --- a/vcs/github/handlers.go +++ b/vcs/github/handlers.go @@ -11,14 +11,15 @@ import ( "text/template" "time" - "github.com/containerish/OpenRegistry/store/v1/types" - "github.com/containerish/OpenRegistry/vcs" "github.com/google/go-github/v56/github" "github.com/labstack/echo/v4" + + "github.com/containerish/OpenRegistry/store/v1/types" + "github.com/containerish/OpenRegistry/vcs" ) func (gh *ghAppService) HandleAppFinish(ctx echo.Context) error { - user := ctx.Get(string(UserContextKey)).(*types.User) + user := ctx.Get(string(types.UserContextKey)).(*types.User) installationID, err := strconv.ParseInt(ctx.QueryParam("installation_id"), 10, 64) if err != nil { @@ -50,6 +51,10 @@ func (gh *ghAppService) HandleAppFinish(ctx echo.Context) error { return echoErr } + if user.Identities == nil { + user.Identities = types.Identities{} + } + if user.Identities.GetGitHubIdentity() == nil { user.Identities[types.IdentityProviderGitHub] = &types.UserIdentity{ ID: fmt.Sprintf("%d", ghUser.GetID()), @@ -59,6 +64,9 @@ func (gh *ghAppService) HandleAppFinish(ctx echo.Context) error { Avatar: ghUser.GetAvatarURL(), InstallationID: installationID, } + } else { + user.Identities[types.IdentityProviderGitHub].Username = ghUser.GetEmail() + user.Identities[types.IdentityProviderGitHub].Email = ghUser.GetLogin() } if _, err = gh.store.UpdateUser(ctx.Request().Context(), user); err != nil { @@ -76,7 +84,7 @@ func (gh *ghAppService) HandleAppFinish(ctx echo.Context) error { // HandleSetupCallback implements vcs.VCS func (gh *ghAppService) HandleSetupCallback(ctx echo.Context) error { - user := ctx.Get(string(UserContextKey)).(*types.User) + user := ctx.Get(string(types.UserContextKey)).(*types.User) installationID, err := strconv.ParseInt(ctx.QueryParam("installation_id"), 10, 64) if err != nil { @@ -87,23 +95,42 @@ func (gh *ghAppService) HandleSetupCallback(ctx echo.Context) error { return echoErr } + if user.Identities == nil { + user.Identities = types.Identities{} + } + if user.Identities.GetGitHubIdentity() == nil { user.Identities[types.IdentityProviderGitHub] = &types.UserIdentity{} } + installation, _, err := gh.ghClient.Apps.GetInstallation(ctx.Request().Context(), installationID) if err != nil { - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{ "error": err.Error(), "message": "could not find the GitHub App installation", }) + + gh.logger.Log(ctx, err).Send() + return echoErr + } + + ghClient := gh.refreshGHClient(installationID) + ghUser, _, err := ghClient.Users.Get(ctx.Request().Context(), installation.GetAccount().GetLogin()) + if err != nil { + echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ + "error": err.Error(), + }) + + gh.logger.Log(ctx, err).Send() + return echoErr } user.Identities[types.IdentityProviderGitHub] = &types.UserIdentity{ ID: fmt.Sprintf("%d", installation.GetID()), - Name: installation.GetAccount().GetName(), - Username: installation.GetAccount().GetLogin(), - Email: installation.GetAccount().GetEmail(), - Avatar: installation.GetAccount().GetAvatarURL(), + Name: ghUser.GetName(), + Username: ghUser.GetLogin(), + Email: ghUser.GetEmail(), + Avatar: ghUser.GetAvatarURL(), InstallationID: installationID, } @@ -160,7 +187,9 @@ func (gh *ghAppService) HandleWebhookEvents(ctx echo.Context) error { case *github.InstallationEvent: } - return ctx.NoContent(http.StatusNoContent) + echoErr := ctx.NoContent(http.StatusNoContent) + gh.logger.Log(ctx, nil).Send() + return echoErr } // @TODO pending implementation (@jay-dee7) @@ -231,13 +260,14 @@ func (gh *ghAppService) ListAuthorisedRepositories(ctx echo.Context) error { }) } - err = ctx.JSON(http.StatusOK, repoList) - gh.logger.Log(ctx, err).Send() - return err + echoErr := ctx.JSON(http.StatusOK, repoList) + gh.logger.Log(ctx, nil).Send() + return echoErr } func (gh *ghAppService) CreateInitialPR(ctx echo.Context) error { installationID := ctx.Get(string(GithubInstallationIDContextKey)).(int64) + user := ctx.Get(string(types.UserContextKey)).(*types.User) var req vcs.InitialPRRequest if err := json.NewDecoder(ctx.Request().Body).Decode(&req); err != nil { @@ -277,12 +307,22 @@ func (gh *ghAppService) CreateInitialPR(ctx echo.Context) error { workflowExists := gh.doesWorkflowExist(ctx.Request().Context(), client, &repository) if workflowExists { - echoErr := ctx.NoContent(http.StatusAccepted) + echoErr := ctx.NoContent(http.StatusNoContent) gh.logger.Log(ctx, echoErr).Send() return echoErr } - if err = gh.createGitubActionsWorkflow(ctx.Request().Context(), client, &repository); err != nil { + err = gh.createGitubActionsWorkflow( + ctx.Request().Context(), + client, + &repository, + &WorkflowProperties{ + RegistryEndpoint: gh.registryEndpoint, + RepositoryOwner: user.Username, + RepositoryName: req.RepositoryName, + }, + ) + if err != nil { echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) @@ -353,6 +393,7 @@ func (gh *ghAppService) createGitubActionsWorkflow( ctx context.Context, client *github.Client, repo *github.Repository, + props *WorkflowProperties, ) error { ctx, cancel := context.WithTimeout(ctx, time.Second*30) defer cancel() @@ -362,5 +403,5 @@ func (gh *ghAppService) createGitubActionsWorkflow( return err } - return gh.createWorkflowFile(ctx, client, repo) + return gh.createWorkflowFile(ctx, client, repo, props) } diff --git a/vcs/github/workflow.go b/vcs/github/workflow.go index 467bdd18..69ed289d 100644 --- a/vcs/github/workflow.go +++ b/vcs/github/workflow.go @@ -2,7 +2,7 @@ package github const ( buildAndPushTemplate = `name: "Build Container Image" -on: [push, pull_request] +on: [ push, pull_request ] defaults: run: @@ -16,30 +16,25 @@ jobs: name: "Build Container image" runs-on: ubuntu-latest env: - CONTAINER_IMAGE_NAME: openregistry.dev/${{ github.repository }}:${{ github.sha }} + CONTAINER_IMAGE_NAME: "[[.RegistryEndpoint]]/[[.RepositoryOwner]]/[[.RepositoryName]]:${{ github.sha }}" steps: - name: Checkout the branch - uses: actions/checkout@v3 - with: - fetch-depth: 0 - + uses: actions/checkout@v4 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 id: buildx with: install: true version: latest - - name: Login to OpenRegistry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: - registry: openregistry.dev - username: ${{ github.repository_owner }} + registry: [[.RegistryEndpoint]] + username: [[.RepositoryOwner]] password: ${{ secrets.GITHUB_TOKEN }} - - name: Build image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: context: . file: Dockerfile