mirror of
https://github.com/harness/drone.git
synced 2025-05-04 15:19:26 +08:00

* [AH-310]: Updated secret flows * [AH-310]: Updated secret flows so removing foreign key constraints
446 lines
14 KiB
Go
446 lines
14 KiB
Go
// Copyright 2023 Harness, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/harness/gitness/app/api/request"
|
|
corestore "github.com/harness/gitness/app/store"
|
|
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
|
"github.com/harness/gitness/registry/app/store"
|
|
"github.com/harness/gitness/registry/app/store/database/util"
|
|
"github.com/harness/gitness/registry/types"
|
|
gitness_store "github.com/harness/gitness/store"
|
|
databaseg "github.com/harness/gitness/store/database"
|
|
"github.com/harness/gitness/store/database/dbtx"
|
|
|
|
"github.com/Masterminds/squirrel"
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type UpstreamproxyDao struct {
|
|
registryDao store.RegistryRepository
|
|
db *sqlx.DB
|
|
spacePathStore corestore.SpacePathStore
|
|
}
|
|
|
|
func NewUpstreamproxyDao(
|
|
db *sqlx.DB, registryDao store.RegistryRepository, spacePathStore corestore.SpacePathStore,
|
|
) store.UpstreamProxyConfigRepository {
|
|
return &UpstreamproxyDao{
|
|
registryDao: registryDao,
|
|
db: db,
|
|
spacePathStore: spacePathStore,
|
|
}
|
|
}
|
|
|
|
// upstreamProxyConfigDB holds the record of an upstream_proxy_config in DB.
|
|
type upstreamProxyConfigDB struct {
|
|
ID int64 `db:"upstream_proxy_config_id"`
|
|
RegistryID int64 `db:"upstream_proxy_config_registry_id"`
|
|
Source string `db:"upstream_proxy_config_source"`
|
|
URL string `db:"upstream_proxy_config_url"`
|
|
AuthType string `db:"upstream_proxy_config_auth_type"`
|
|
UserName string `db:"upstream_proxy_config_user_name"`
|
|
SecretIdentifier sql.NullString `db:"upstream_proxy_config_secret_identifier"`
|
|
SecretSpaceID sql.NullInt32 `db:"upstream_proxy_config_secret_space_id"`
|
|
Token string `db:"upstream_proxy_config_token"`
|
|
CreatedAt int64 `db:"upstream_proxy_config_created_at"`
|
|
UpdatedAt int64 `db:"upstream_proxy_config_updated_at"`
|
|
CreatedBy int64 `db:"upstream_proxy_config_created_by"`
|
|
UpdatedBy int64 `db:"upstream_proxy_config_updated_by"`
|
|
}
|
|
|
|
type upstreamProxyDB struct {
|
|
ID int64 `db:"id"`
|
|
RegistryID int64 `db:"registry_id"`
|
|
RepoKey string `db:"repo_key"`
|
|
ParentID string `db:"parent_id"`
|
|
PackageType artifact.PackageType `db:"package_type"`
|
|
AllowedPattern sql.NullString `db:"allowed_pattern"`
|
|
BlockedPattern sql.NullString `db:"blocked_pattern"`
|
|
Source string `db:"source"`
|
|
RepoURL string `db:"repo_url"`
|
|
RepoAuthType string `db:"repo_auth_type"`
|
|
UserName string `db:"user_name"`
|
|
SecretIdentifier sql.NullString `db:"secret_identifier"`
|
|
SecretSpaceID sql.NullInt32 `db:"secret_space_id"`
|
|
Token string `db:"token"`
|
|
CreatedAt int64 `db:"created_at"`
|
|
UpdatedAt int64 `db:"updated_at"`
|
|
CreatedBy sql.NullInt64 `db:"created_by"`
|
|
UpdatedBy sql.NullInt64 `db:"updated_by"`
|
|
}
|
|
|
|
func getUpstreamProxyQuery() squirrel.SelectBuilder {
|
|
return databaseg.Builder.Select(
|
|
" u.upstream_proxy_config_id as id," +
|
|
" r.registry_id as registry_id," +
|
|
" r.registry_name as repo_key," +
|
|
" r.registry_parent_id as parent_id," +
|
|
" r.registry_package_type as package_type," +
|
|
" r.registry_allowed_pattern as allowed_pattern," +
|
|
" r.registry_blocked_pattern as blocked_pattern," +
|
|
" u.upstream_proxy_config_url as repo_url," +
|
|
" u.upstream_proxy_config_source as source," +
|
|
" u.upstream_proxy_config_auth_type as repo_auth_type," +
|
|
" u.upstream_proxy_config_user_name as user_name," +
|
|
" u.upstream_proxy_config_secret_identifier as secret_identifier," +
|
|
" u.upstream_proxy_config_secret_space_id as secret_space_id," +
|
|
" u.upstream_proxy_config_token as token," +
|
|
" r.registry_created_at as created_at," +
|
|
" r.registry_updated_at as updated_at ").
|
|
From("registries r ").
|
|
LeftJoin("upstream_proxy_configs u ON r.registry_id = u.upstream_proxy_config_registry_id ")
|
|
}
|
|
|
|
func (r UpstreamproxyDao) Get(ctx context.Context, id int64) (upstreamProxy *types.UpstreamProxy, err error) {
|
|
q := getUpstreamProxyQuery()
|
|
q = q.Where("r.registry_id = ? AND r.registry_type = 'UPSTREAM'", id)
|
|
|
|
sql, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
dst := new(upstreamProxyDB)
|
|
if err = db.GetContext(ctx, dst, sql, args...); err != nil {
|
|
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to get tag detail")
|
|
}
|
|
|
|
return r.mapToUpstreamProxy(ctx, dst)
|
|
}
|
|
|
|
func (r UpstreamproxyDao) GetByRegistryIdentifier(
|
|
ctx context.Context,
|
|
parentID int64,
|
|
repoKey string,
|
|
) (upstreamProxy *types.UpstreamProxy, err error) {
|
|
q := getUpstreamProxyQuery()
|
|
q = q.Where("r.registry_parent_id = ? AND r.registry_name = ? AND r.registry_type = 'UPSTREAM'",
|
|
parentID, repoKey)
|
|
|
|
sql, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
dst := new(upstreamProxyDB)
|
|
if err = db.GetContext(ctx, dst, sql, args...); err != nil {
|
|
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to get tag detail")
|
|
}
|
|
|
|
return r.mapToUpstreamProxy(ctx, dst)
|
|
}
|
|
|
|
func (r UpstreamproxyDao) GetByParentID(ctx context.Context, parentID string) (
|
|
upstreamProxies *[]types.UpstreamProxy, err error,
|
|
) {
|
|
q := getUpstreamProxyQuery()
|
|
q = q.Where("r.registry_parent_id = ? AND r.registry_type = 'UPSTREAM'",
|
|
parentID)
|
|
|
|
sql, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
dst := []*upstreamProxyDB{}
|
|
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
|
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to get tag detail")
|
|
}
|
|
|
|
return r.mapToUpstreamProxyList(ctx, dst)
|
|
}
|
|
|
|
func (r UpstreamproxyDao) Create(
|
|
ctx context.Context,
|
|
upstreamproxyRecord *types.UpstreamProxyConfig,
|
|
) (id int64, err error) {
|
|
const sqlQuery = `
|
|
INSERT INTO upstream_proxy_configs (
|
|
upstream_proxy_config_registry_id
|
|
,upstream_proxy_config_source
|
|
,upstream_proxy_config_url
|
|
,upstream_proxy_config_auth_type
|
|
,upstream_proxy_config_user_name
|
|
,upstream_proxy_config_secret_identifier
|
|
,upstream_proxy_config_secret_space_id
|
|
,upstream_proxy_config_token
|
|
,upstream_proxy_config_created_at
|
|
,upstream_proxy_config_updated_at
|
|
,upstream_proxy_config_created_by
|
|
,upstream_proxy_config_updated_by
|
|
) VALUES (
|
|
:upstream_proxy_config_registry_id
|
|
,:upstream_proxy_config_source
|
|
,:upstream_proxy_config_url
|
|
,:upstream_proxy_config_auth_type
|
|
,:upstream_proxy_config_user_name
|
|
,:upstream_proxy_config_secret_identifier
|
|
,:upstream_proxy_config_secret_space_id
|
|
,:upstream_proxy_config_token
|
|
,:upstream_proxy_config_created_at
|
|
,:upstream_proxy_config_updated_at
|
|
,:upstream_proxy_config_created_by
|
|
,:upstream_proxy_config_updated_by
|
|
) RETURNING upstream_proxy_config_registry_id`
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
query, arg, err := db.BindNamed(sqlQuery, r.mapToInternalUpstreamProxy(ctx, upstreamproxyRecord))
|
|
if err != nil {
|
|
return -1, databaseg.ProcessSQLErrorf(ctx,
|
|
err, "Failed to bind upstream proxy object")
|
|
}
|
|
|
|
if err = db.QueryRowContext(ctx, query, arg...).Scan(&upstreamproxyRecord.ID); err != nil {
|
|
return -1, databaseg.ProcessSQLErrorf(ctx, err, "Insert query failed")
|
|
}
|
|
|
|
return upstreamproxyRecord.ID, nil
|
|
}
|
|
|
|
func (r UpstreamproxyDao) Delete(ctx context.Context, parentID int64, repoKey string) (err error) {
|
|
stmt := databaseg.Builder.Delete("upstream_proxy_configs").
|
|
Where("upstream_proxy_config_registry_id in (SELECT registry_id from registries"+
|
|
" WHERE registry_parent_id = ? AND registry_name = ?)", parentID, repoKey)
|
|
|
|
sql, args, err := stmt.ToSql()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to convert purge registry query to sql: %w", err)
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
_, err = db.ExecContext(ctx, sql, args...)
|
|
if err != nil {
|
|
return databaseg.ProcessSQLErrorf(ctx, err, "the delete query failed")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r UpstreamproxyDao) Update(
|
|
ctx context.Context,
|
|
upstreamProxyRecord *types.UpstreamProxyConfig,
|
|
) (err error) {
|
|
var sqlQuery = " UPDATE upstream_proxy_configs SET " +
|
|
util.GetSetDBKeys(upstreamProxyConfigDB{}, "upstream_proxy_config_id") +
|
|
" WHERE upstream_proxy_config_id = :upstream_proxy_config_id "
|
|
|
|
upstreamProxy := r.mapToInternalUpstreamProxy(ctx, upstreamProxyRecord)
|
|
|
|
// update Version (used for optimistic locking) and Updated time
|
|
upstreamProxy.UpdatedAt = time.Now().UnixMilli()
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
query, arg, err := db.BindNamed(sqlQuery, upstreamProxy)
|
|
if err != nil {
|
|
return databaseg.ProcessSQLErrorf(ctx, err, "Failed to bind repo object")
|
|
}
|
|
|
|
result, err := db.ExecContext(ctx, query, arg...)
|
|
if err != nil {
|
|
return databaseg.ProcessSQLErrorf(ctx, err, "Failed to update repository")
|
|
}
|
|
|
|
count, err := result.RowsAffected()
|
|
if err != nil {
|
|
return databaseg.ProcessSQLErrorf(ctx, err, "Failed to get number of updated rows")
|
|
}
|
|
|
|
if count == 0 {
|
|
return gitness_store.ErrVersionConflict
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r UpstreamproxyDao) GetAll(
|
|
ctx context.Context, parentID int64,
|
|
packageTypes []string, sortByField string, sortByOrder string, limit int,
|
|
offset int, search string,
|
|
) (upstreamProxies *[]types.UpstreamProxy, err error) {
|
|
q := getUpstreamProxyQuery()
|
|
q = q.Where("r.registry_parent_id = ? AND r.registry_type = 'UPSTREAM'",
|
|
parentID)
|
|
|
|
if search != "" {
|
|
q = q.Where(" r.registry_name LIKE ?", sqlPartialMatch(search))
|
|
}
|
|
|
|
if len(packageTypes) > 0 {
|
|
q = q.Where(" AND r.registry_package_type in ? ", packageTypes)
|
|
}
|
|
|
|
q = q.OrderBy(" r.registry_" + sortByField + " " + sortByOrder).Limit(uint64(limit)).Offset(uint64(offset))
|
|
|
|
sql, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
dst := []*upstreamProxyDB{}
|
|
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
|
return nil, databaseg.ProcessSQLErrorf(ctx, err, "Failed to get tag detail")
|
|
}
|
|
return r.mapToUpstreamProxyList(ctx, dst)
|
|
}
|
|
|
|
func (r UpstreamproxyDao) CountAll(
|
|
ctx context.Context, parentID string,
|
|
packageTypes []string, search string,
|
|
) (count int64, err error) {
|
|
q := databaseg.Builder.Select(" COUNT(*) ").
|
|
From(" registries r").
|
|
LeftJoin(" upstream_proxy_configs u ON r.registry_id = u.upstream_proxy_config_registry_id ").
|
|
Where("r.registry_parent_id = ? AND r.registry_type = 'UPSTREAM'",
|
|
parentID)
|
|
|
|
if search != "" {
|
|
q = q.Where(" r.registry_name LIKE '%" + search + "%' ")
|
|
}
|
|
|
|
if len(packageTypes) > 0 {
|
|
q = q.Where(" AND r.registry_package_type in ? ", packageTypes)
|
|
}
|
|
|
|
sql, args, err := q.ToSql()
|
|
if err != nil {
|
|
return -1, errors.Wrap(err, "Failed to convert query to sql")
|
|
}
|
|
|
|
db := dbtx.GetAccessor(ctx, r.db)
|
|
|
|
var total int64
|
|
if err = db.QueryRowContext(ctx, sql, args...).Scan(&total); err != nil {
|
|
return -1, databaseg.ProcessSQLErrorf(ctx, err, "Failed to get upstream proxy count")
|
|
}
|
|
return total, nil
|
|
}
|
|
|
|
func (r UpstreamproxyDao) mapToInternalUpstreamProxy(
|
|
ctx context.Context,
|
|
in *types.UpstreamProxyConfig,
|
|
) *upstreamProxyConfigDB {
|
|
if in.CreatedAt.IsZero() {
|
|
in.CreatedAt = time.Now()
|
|
}
|
|
in.UpdatedAt = time.Now()
|
|
session, _ := request.AuthSessionFrom(ctx)
|
|
if in.CreatedBy == 0 {
|
|
in.CreatedBy = session.Principal.ID
|
|
}
|
|
in.UpdatedBy = session.Principal.ID
|
|
|
|
return &upstreamProxyConfigDB{
|
|
ID: in.ID,
|
|
RegistryID: in.RegistryID,
|
|
Source: in.Source,
|
|
URL: in.URL,
|
|
AuthType: in.AuthType,
|
|
UserName: in.UserName,
|
|
SecretIdentifier: util.GetEmptySQLString(in.SecretIdentifier),
|
|
SecretSpaceID: util.GetEmptySQLInt32(in.SecretSpaceID),
|
|
Token: in.Token,
|
|
CreatedAt: in.CreatedAt.UnixMilli(),
|
|
UpdatedAt: in.UpdatedAt.UnixMilli(),
|
|
CreatedBy: in.CreatedBy,
|
|
UpdatedBy: in.UpdatedBy,
|
|
}
|
|
}
|
|
|
|
func (r UpstreamproxyDao) mapToUpstreamProxy(
|
|
ctx context.Context,
|
|
dst *upstreamProxyDB,
|
|
) (*types.UpstreamProxy, error) {
|
|
createdBy := int64(-1)
|
|
updatedBy := int64(-1)
|
|
secretIdentifier := ""
|
|
secretSpaceID := int64(-1)
|
|
if dst.CreatedBy.Valid {
|
|
createdBy = dst.CreatedBy.Int64
|
|
}
|
|
if dst.UpdatedBy.Valid {
|
|
updatedBy = dst.UpdatedBy.Int64
|
|
}
|
|
if dst.SecretIdentifier.Valid {
|
|
secretIdentifier = dst.SecretIdentifier.String
|
|
}
|
|
if dst.SecretSpaceID.Valid {
|
|
secretSpaceID = int64(dst.SecretSpaceID.Int32)
|
|
}
|
|
|
|
secretSpacePath := ""
|
|
if dst.SecretSpaceID.Valid {
|
|
primary, err := r.spacePathStore.FindPrimaryBySpaceID(ctx, int64(dst.SecretSpaceID.Int32))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get secret space path: %w", err)
|
|
}
|
|
secretSpacePath = primary.Value
|
|
}
|
|
|
|
return &types.UpstreamProxy{
|
|
ID: dst.ID,
|
|
RegistryID: dst.RegistryID,
|
|
RepoKey: dst.RepoKey,
|
|
ParentID: dst.ParentID,
|
|
PackageType: dst.PackageType,
|
|
AllowedPattern: util.StringToArr(dst.AllowedPattern.String),
|
|
BlockedPattern: util.StringToArr(dst.BlockedPattern.String),
|
|
Source: dst.Source,
|
|
RepoURL: dst.RepoURL,
|
|
RepoAuthType: dst.RepoAuthType,
|
|
UserName: dst.UserName,
|
|
SecretIdentifier: secretIdentifier,
|
|
SecretSpaceID: secretSpaceID,
|
|
SecretSpacePath: secretSpacePath,
|
|
Token: dst.Token,
|
|
CreatedAt: time.UnixMilli(dst.CreatedAt),
|
|
UpdatedAt: time.UnixMilli(dst.UpdatedAt),
|
|
CreatedBy: createdBy,
|
|
UpdatedBy: updatedBy,
|
|
}, nil
|
|
}
|
|
|
|
func (r UpstreamproxyDao) mapToUpstreamProxyList(
|
|
ctx context.Context,
|
|
dst []*upstreamProxyDB,
|
|
) (*[]types.UpstreamProxy, error) {
|
|
upstreamProxies := make([]types.UpstreamProxy, 0, len(dst))
|
|
for _, d := range dst {
|
|
upstreamProxy, err := r.mapToUpstreamProxy(ctx, d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
upstreamProxies = append(upstreamProxies, *upstreamProxy)
|
|
}
|
|
return &upstreamProxies, nil
|
|
}
|