Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: add audit filter and update the default AuditCleanInterval #6166

Merged
merged 9 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions apistructs/audits.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,37 +366,59 @@

// AuditsListRequest GET /api/audits/actions/list 审计事件查询请求结构
type AuditsListRequest struct {
// +required 是否是查看系统的事件
// +optional if sys event to get audit log
Sys bool `schema:"sys"`
// +required 企业ID
OrgID uint64 `schema:"orgId"`
// +required 事件开始时间
// +optional List of organization IDS
OrgID []uint64 `schema:"orgId"`
// +required Start time of the query event
StartAt string `schema:"startAt"`
// +required 事件结束事件
// +required End time of the query event
EndAt string `schema:"endAt"`
// +optional fdp项目id
FDPProjectID string `schema:"fdpProjectId"`
// +optional 通过用户id过滤事件
// +optional List of FDP project IDs
FDPProjectID []string `schema:"fdpProjectId"`
// +optional List of user IDs
UserID []string `schema:"userId"`
// default 1
// +optional List of log template name
TemplateName []TemplateName `schema:"templateName"`
// +optional List of client IP address
ClientIP []string `schema:"clientIP"`
// +optional List of application IDs
AppID []uint64 `schema:"appId"`
// +optional List of project IDs
ProjectID []uint64 `schema:"projectId"`
// +optional Scope type for visibility
ScopeType []ScopeType `schema:"scopeType"`
//default 1
PageNo int `schema:"pageNo"`
// default 20
PageSize int `schema:"pageSize"`
}

// Check 检查 AuditsListRequest 是否合法
func (a *AuditsListRequest) Check() error {
// 看系统事件则允许orgID为空
if !a.Sys && a.OrgID == 0 {
return errors.Errorf("invalid request, sys and orgid cann't be empty at the same time")
func (a *AuditsListRequest) Check(headerOrgID uint64) error {

Check warning on line 398 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L398

Added line #L398 was not covered by tests
// if OrgID is empty, use the OrgID from the request header
if !a.Sys && len(a.OrgID) == 0 {
a.OrgID = []uint64{headerOrgID}

Check warning on line 401 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L400-L401

Added lines #L400 - L401 were not covered by tests
}

if !a.Sys && len(a.OrgID) >= 1 {

Check warning on line 404 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L404

Added line #L404 was not covered by tests
// if it is not sys scope, the OrgID can't exceed 1
if len(a.OrgID) > 1 {
return errors.Errorf("invalid request, when sys is false, the OrgID can't exceed 1")

Check warning on line 407 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L406-L407

Added lines #L406 - L407 were not covered by tests
}

// if the OrgID in the request param does not match the one in the header
if a.OrgID[0] != headerOrgID {
return errors.Errorf("invaid request, when sys is false, the OrgID should match your origanization ID")

Check warning on line 412 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L411-L412

Added lines #L411 - L412 were not covered by tests
}
}

if a.StartAt == "" {
return errors.Errorf("invalid request, startAt cann't be empty")
return errors.Errorf("invalid request, startAt can't be empty")

Check warning on line 417 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L417

Added line #L417 was not covered by tests
}

if a.EndAt == "" {
return errors.Errorf("invalid request, endAt cann't be empty")
return errors.Errorf("invalid request, endAt can't be empty")

Check warning on line 421 in apistructs/audits.go

View check run for this annotation

Codecov / codecov/patch

apistructs/audits.go#L421

Added line #L421 was not covered by tests
}

if a.PageNo == 0 {
Expand Down
2 changes: 1 addition & 1 deletion bundle/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (b *Bundle) ListAuditEvent(orgID string, userID string, params url.Values)
return nil, apierrors.ErrInvoke.InternalError(
fmt.Errorf("failed to list Audit, status code: %d, body: %v",
resp.StatusCode(),
resp.Body(),
string(resp.Body()),
))
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/erda-server/conf/i18n/i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ zh:
APPLICATION: 应用
ErrAddMemberOwner: "添加所有者失败,数量超过上限"

# audit error
ErrInvalidOrg: "OrgID 非法,可能是不存在 OrgID 或者多个 OrgID"
ErrInvalidProjectInOrg: "所选项目错误,用户所选择的项目不属于其组织"
ErrInvalidAppInOrg: "所选应用错误,用户所选择的应用不属于其组织"
ErrInvalidAppInProject: "所选应用错误,用户所选择的应用不属于其选择的项目"

en:
AvailableIsLessThanQuota: The actual available resource on this workspace in the cluster is less than the quota. Please ask the Ops to allocate project resources reasonably
NoResourceForTheWorkspace: No allocatable resources on this workspace in the cluster, please check the workspace labels for the nodes
Expand All @@ -43,3 +49,9 @@ en:
PROJECT: project
APPLICATION: application
ErrAddMemberOwner: "failed to add project owner, quantity exceeds limit"

# audit error
ErrInvalidOrgID: "Invalid OrgID, it may not exist or multiple OrgIDs"
ErrInvalidProjectInOrg: "Invalid selected project. The project does not belong to the user's organization"
ErrInvalidAppInOrg: "Invalid selected application. The application does not belong to user's organization."
ErrInvalidAppInProject: "Invalid selected application. The application does not belong to the selected project"
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ require (
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.3.2
gorm.io/driver/sqlite v1.3.1
gorm.io/gorm v1.23.5
gorm.io/driver/sqlite v1.5.3
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
gorm.io/plugin/soft_delete v1.1.0
gotest.tools v2.2.0+incompatible
helm.sh/helm/v3 v3.6.2
Expand Down
9 changes: 4 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,6 @@ github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71
github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
Expand Down Expand Up @@ -2815,13 +2814,13 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.3.2 h1:QJryWiqQ91EvZ0jZL48NOpdlPdMjdip1hQ8bTgo4H7I=
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c=
gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk=
gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg=
gorm.io/driver/sqlite v1.5.3 h1:7/0dUgX28KAcopdfbRWWl68Rflh6osa4rDh+m51KL2g=
gorm.io/driver/sqlite v1.5.3/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4=
gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/plugin/soft_delete v1.1.0 h1:LcE4L+GD29RkkMLxMYHpT4wQCJ/9945FsdU/mHGaDuE=
gorm.io/plugin/soft_delete v1.1.0/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
Expand Down
45 changes: 45 additions & 0 deletions internal/core/legacy/common/ctxhelper/audit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2021 Terminus, 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 ctxhelper

import (
"context"

"github.com/erda-project/erda-infra/providers/i18n"
)

const languageKey = "language"
const zh = "zh-CN"
const en = "en-US"

func GetAuditLanguage(ctx context.Context) (i18n.LanguageCodes, bool) {
langCodes, ok := ctx.Value(languageKey).(i18n.LanguageCodes)
if !ok {
return nil, false
}
if langCodes == nil {
return i18n.LanguageCodes{
&i18n.LanguageCode{
Code: zh,
Quality: 1,
},
}, true

Check warning on line 38 in internal/core/legacy/common/ctxhelper/audit.go

View check run for this annotation

Codecov / codecov/patch

internal/core/legacy/common/ctxhelper/audit.go#L33-L38

Added lines #L33 - L38 were not covered by tests
}
return langCodes, true
}

func PutAuditLanguage(ctx context.Context, language i18n.LanguageCodes) context.Context {
return context.WithValue(ctx, languageKey, language)
}
91 changes: 91 additions & 0 deletions internal/core/legacy/common/ctxhelper/audit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2021 Terminus, 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 ctxhelper

import (
"context"
"testing"

"github.com/stretchr/testify/assert"

"github.com/erda-project/erda-infra/providers/i18n"
)

func TestAuditContext(t *testing.T) {

type resp struct {
language i18n.LanguageCodes
flag bool
}
testCase := []struct {
name string
lang any
want resp
}{
{
name: "invalid language",
lang: 1,
want: resp{
language: nil,
flag: false,
},
},
{
name: "language is nil",
lang: []*i18n.LanguageCode{},
want: resp{
language: nil,
flag: false,
},
},
{
name: "success get language",
lang: i18n.LanguageCodes{
&i18n.LanguageCode{
Code: en,
Quality: 1,
},
},
want: resp{
language: i18n.LanguageCodes{
&i18n.LanguageCode{
Code: en,
Quality: 1,
},
},
flag: true,
},
},
}

for _, tt := range testCase {
t.Run(tt.name, func(t *testing.T) {
var lang i18n.LanguageCodes
var flag bool
if tt.lang == 1 {
ctx := context.WithValue(context.Background(), languageKey, tt.lang)
lang, flag = GetAuditLanguage(ctx)

} else if tt.name == "language is nil" {
lang, flag = GetAuditLanguage(context.Background())
} else {
ctx := PutAuditLanguage(context.Background(), tt.lang.(i18n.LanguageCodes))
lang, flag = GetAuditLanguage(ctx)
}
assert.Equal(t, tt.want.language, lang)
assert.Equal(t, tt.want.flag, flag)
})
}
}
10 changes: 5 additions & 5 deletions internal/core/legacy/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ type Conf struct {
// --- 文件管理 end ---

// audit
AuditCleanCron string `env:"AUDIT_CLEAN_CRON" default:"0 0 3 * * ?"` // audit soft delete cron
AuditArchiveCron string `env:"AUDIT_ARCHIVE_CRON" default:"0 0 4 * * ?"` // audit archive cron
SysAuditCleanInterval int `env:"SYS_AUDIT_CLEAN_INTERVAL" default:"-7"` // sys audit clean interval
OrgAuditMaxRetentionDays uint64 `env:"ORG_AUDIT_MAX_RETENTION_DAYS" default:"180"` // org level audit max retention days
OrgAuditDefaultRetentionDays uint64 `env:"ORG_AUDIT_DEFAULT_RETENTION_DAYS" default:"30"` // org level audit default retention days
AuditCleanCron string `env:"AUDIT_CLEAN_CRON" default:"0 0 3 * * ?"` // audit soft delete cron
AuditArchiveCron string `env:"AUDIT_ARCHIVE_CRON" default:"0 0 4 * * ?"` // audit archive cron
SysAuditCleanInterval int `env:"SYS_AUDIT_CLEAN_INTERVAL" default:"-30"` // sys audit clean interval
OrgAuditMaxRetentionDays uint64 `env:"ORG_AUDIT_MAX_RETENTION_DAYS" default:"500"` // org level audit max retention days
OrgAuditDefaultRetentionDays uint64 `env:"ORG_AUDIT_DEFAULT_RETENTION_DAYS" default:"365"` // org level audit default retention days

// erda-configs
ErdaConfigsBasePath string `env:"ERDA_CONFIGS_BASE_PATH" default:"common-conf/erda-configs"`
Expand Down
2 changes: 1 addition & 1 deletion internal/core/legacy/conf/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ func TestLoad(t *testing.T) {
f.Close()
os.Setenv("ERDA_CONFIGS_BASE_PATH", baseDir)
Load()
assert.Equal(t, uint64(30), OrgAuditDefaultRetentionDays())
assert.Equal(t, uint64(365), OrgAuditDefaultRetentionDays())
}
6 changes: 6 additions & 0 deletions internal/core/legacy/dao/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,9 @@ func (client *DBClient) GetApplicationsByNames(projectID uint64, names []string)
err := client.Where("project_id = ?", projectID).Where("name in (?)", names).Find(&applications).Error
return applications, err
}

func (client *DBClient) GetApplicationsByOrgId(orgID uint64) ([]model.Application, error) {
var applications []model.Application
err := client.Where("org_id = ?", orgID).Find(&applications).Error
return applications, err
}
35 changes: 26 additions & 9 deletions internal/core/legacy/dao/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (

"github.com/jinzhu/gorm"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/core/legacy/conf"
"github.com/erda-project/erda/internal/core/legacy/model"
)
Expand All @@ -36,23 +35,41 @@ func (client *DBClient) BatchCreateAudit(audits []model.Audit) error {
}

// GetAuditsByParam 通过参数查询成员
func (client *DBClient) GetAuditsByParam(param *apistructs.AuditsListRequest) (int, []model.Audit, error) {
func (client *DBClient) GetAuditsByParam(param *model.ListAuditParam) (int, []model.Audit, error) {
var audits []model.Audit
var total int
db := client.Table("dice_audit").Scopes(NotDeleted).Where("start_time >= ? AND start_time <= ?", param.StartAt, param.EndAt)

if !param.Sys {
db = db.Where("org_id = ?", param.OrgID)
} else {
db = db.Where("scope_type = 'sys'")
if len(param.ScopeType) > 0 {
db = db.Where("scope_type in ( ? )", param.ScopeType)
}
if len(param.OrgID) > 0 {
db = db.Where("org_id in ( ? )", param.OrgID)
}

if param.UserID != nil {
if len(param.ScopeID) > 0 {
db = db.Where("scope_id in ( ? )", param.ScopeID)
}
if len(param.AppID) > 0 {
db = db.Where("app_id in ( ? )", param.AppID)
}
if len(param.ProjectID) > 0 {
db = db.Where("project_id in ( ? )", param.ProjectID)
}
if len(param.UserID) > 0 {
db = db.Where("user_id in ( ? )", param.UserID)
}
if len(param.TemplateName) > 0 {
db = db.Where("template_name in ( ? )", param.TemplateName)
}
if len(param.ClientIP) > 0 {
for _, ip := range param.ClientIP {
db = db.Or("client_ip LIKE ?", "%"+ip+"%")
}
}

if param.FDPProjectID != "" {
db = db.Where("fdp_project_id = ?", param.FDPProjectID)
if len(param.FDPProjectID) > 0 {
db = db.Where("fdp_project_id in ( ? )", param.FDPProjectID)
} else {
db = db.Where("fdp_project_id = ? or fdp_project_id is NULL", "")
}
Expand Down
Loading
Loading