收口审计治理与套餐任务进展
Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展 Confidence: medium Scope-risk: broad Directive: 后续修改需保持审计事件与业务事务边界一致 Tested: git diff --cached --check Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
This commit is contained in:
@@ -167,7 +167,7 @@ func (w *Writer) WriteAccessChange(ctx context.Context, tx *gorm.DB, change acce
|
||||
}
|
||||
|
||||
func accessResources(change accessauditapp.ChangeAudit, primaryResource string) ([]ResourceInput, error) {
|
||||
resources := make([]ResourceInput, 0, 2+len(change.Accounts)+len(change.Cards)+len(change.CardAuthorizations)+len(change.Devices)+len(change.DeviceBindings)+len(change.DeviceAuthorizations)+len(change.PersonalPhones)+len(change.PersonalOpenIDs)+len(change.Roles)+len(change.Permissions))
|
||||
resources := make([]ResourceInput, 0, 2+len(change.Accounts)+len(change.Cards)+len(change.CardAuthorizations)+len(change.Devices)+len(change.DeviceBindings)+len(change.DeviceAuthorizations)+len(change.PersonalPhones)+len(change.PersonalOpenIDs)+len(change.PersonalDevices)+len(change.PersonalICCIDs)+len(change.Roles)+len(change.Permissions))
|
||||
switch primaryResource {
|
||||
case constants.AuditResourceAccount:
|
||||
if change.Account == nil || (change.Account.ID == 0 && change.Account.Username == "") {
|
||||
@@ -392,6 +392,46 @@ func accessResources(change accessauditapp.ChangeAudit, primaryResource string)
|
||||
SubjectVisibility: constants.AuditSubjectInternalOnly, SortOrder: index + 1,
|
||||
})
|
||||
}
|
||||
for index, item := range change.PersonalDevices {
|
||||
if item.Binding == nil || item.Binding.ID == 0 {
|
||||
return nil, pkgerrors.New(pkgerrors.CodeInvalidParam, "个人客户设备绑定审计资源不完整")
|
||||
}
|
||||
relation := item.Relation
|
||||
if relation == "" {
|
||||
relation = constants.AuditResourceRelationAffected
|
||||
}
|
||||
role := item.Role
|
||||
if role == "" {
|
||||
role = constants.AuditResourceRolePersonalCustomerAssetBinding
|
||||
}
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourcePersonalCustomerDevice, ID: optionalResourceID(item.Binding.ID),
|
||||
Key: strconv.FormatUint(uint64(item.Binding.ID), 10), DisplayName: item.Binding.VirtualNo,
|
||||
Relation: relation, Role: role, IdentitySnapshot: personalCustomerDeviceIdentity(item.Binding),
|
||||
BeforeData: item.BeforeData, AfterData: item.AfterData,
|
||||
SubjectVisibility: constants.AuditSubjectInternalOnly, SortOrder: index + 1,
|
||||
})
|
||||
}
|
||||
for index, item := range change.PersonalICCIDs {
|
||||
if item.Binding == nil || item.Binding.ID == 0 {
|
||||
return nil, pkgerrors.New(pkgerrors.CodeInvalidParam, "个人客户 ICCID 绑定审计资源不完整")
|
||||
}
|
||||
relation := item.Relation
|
||||
if relation == "" {
|
||||
relation = constants.AuditResourceRelationAffected
|
||||
}
|
||||
role := item.Role
|
||||
if role == "" {
|
||||
role = constants.AuditResourceRolePersonalCustomerAssetBinding
|
||||
}
|
||||
resources = append(resources, ResourceInput{
|
||||
Type: constants.AuditResourcePersonalCustomerICCID, ID: optionalResourceID(item.Binding.ID),
|
||||
Key: strconv.FormatUint(uint64(item.Binding.ID), 10), DisplayName: item.Binding.ICCID,
|
||||
Relation: relation, Role: role, IdentitySnapshot: personalCustomerICCIDIdentity(item.Binding),
|
||||
BeforeData: item.BeforeData, AfterData: item.AfterData,
|
||||
SubjectVisibility: constants.AuditSubjectInternalOnly, SortOrder: index + 1,
|
||||
})
|
||||
}
|
||||
if primaryResource == constants.AuditResourceRole {
|
||||
if change.Role == nil || (change.Role.ID == 0 && change.Role.RoleName == "") {
|
||||
return nil, pkgerrors.New(pkgerrors.CodeInvalidParam, "角色审计资源不完整")
|
||||
@@ -482,6 +522,16 @@ func iotCardIdentity(card *model.IotCard) map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
// IotCardIdentitySnapshot 返回统一 Registry 允许的 IoT 卡身份快照。
|
||||
func IotCardIdentitySnapshot(card *model.IotCard) map[string]any {
|
||||
return iotCardIdentity(card)
|
||||
}
|
||||
|
||||
// IotCardResourceKey 返回 IoT 卡审计使用的稳定资源 Key。
|
||||
func IotCardResourceKey(card *model.IotCard) string {
|
||||
return iotCardResourceKey(card)
|
||||
}
|
||||
|
||||
func deviceResourceKey(device *model.Device) string {
|
||||
if device.ID != 0 {
|
||||
return strconv.FormatUint(uint64(device.ID), 10)
|
||||
@@ -492,10 +542,22 @@ func deviceResourceKey(device *model.Device) string {
|
||||
func deviceIdentity(device *model.Device) map[string]any {
|
||||
return map[string]any{
|
||||
"id": device.ID, "virtual_no": device.VirtualNo, "imei": device.IMEI,
|
||||
"sn": device.SN, "generation": device.Generation,
|
||||
"sn": device.SN, "device_name": device.DeviceName, "device_model": device.DeviceModel,
|
||||
"device_type": device.DeviceType, "manufacturer": device.Manufacturer,
|
||||
"shop_id": device.ShopID, "series_id": device.SeriesID, "generation": device.Generation,
|
||||
}
|
||||
}
|
||||
|
||||
// DeviceIdentitySnapshot 返回统一 Registry 允许的设备身份快照。
|
||||
func DeviceIdentitySnapshot(device *model.Device) map[string]any {
|
||||
return deviceIdentity(device)
|
||||
}
|
||||
|
||||
// DeviceResourceKey 返回设备审计使用的稳定资源 Key。
|
||||
func DeviceResourceKey(device *model.Device) string {
|
||||
return deviceResourceKey(device)
|
||||
}
|
||||
|
||||
func deviceSimBindingIdentity(binding *model.DeviceSimBinding) map[string]any {
|
||||
return map[string]any{
|
||||
"id": binding.ID, "device_id": binding.DeviceID, "slot_position": binding.SlotPosition,
|
||||
@@ -541,6 +603,21 @@ func personalCustomerOpenIDIdentity(openID *model.PersonalCustomerOpenID) map[st
|
||||
}
|
||||
}
|
||||
|
||||
func personalCustomerDeviceIdentity(binding *model.PersonalCustomerDevice) map[string]any {
|
||||
return map[string]any{
|
||||
"id": binding.ID, "customer_id": binding.CustomerID, "virtual_no": binding.VirtualNo,
|
||||
"bind_at": binding.BindAt, "last_used_at": binding.LastUsedAt, "status": binding.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func personalCustomerICCIDIdentity(binding *model.PersonalCustomerICCID) map[string]any {
|
||||
return map[string]any{
|
||||
"id": binding.ID, "customer_id": binding.CustomerID, "iccid": binding.ICCID,
|
||||
"iccid_19": binding.ICCID19, "bind_at": binding.BindAt,
|
||||
"last_used_at": binding.LastUsedAt, "status": binding.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func roleResource(role *model.Role, beforeData, afterData map[string]any) ResourceInput {
|
||||
return ResourceInput{
|
||||
Type: constants.AuditResourceRole, ID: optionalResourceID(role.ID), Key: roleResourceKey(role), DisplayName: role.RoleName,
|
||||
@@ -706,6 +783,14 @@ func (w *Writer) WriteConfigChange(ctx context.Context, tx *gorm.DB, change syst
|
||||
if result == "" {
|
||||
result = constants.AuditResultSuccess
|
||||
}
|
||||
displayName := change.DisplayName
|
||||
if displayName == "" {
|
||||
displayName = change.ConfigKey
|
||||
}
|
||||
identity := change.Identity
|
||||
if identity == nil {
|
||||
identity = map[string]any{"config_key": change.ConfigKey, "module": change.Module}
|
||||
}
|
||||
return w.Append(ctx, tx, AppendInput{
|
||||
ActionCode: action.Code, Summary: change.Description,
|
||||
Actor: ActorInput{
|
||||
@@ -719,9 +804,9 @@ func (w *Writer) WriteConfigChange(ctx context.Context, tx *gorm.DB, change syst
|
||||
ErrorCode: change.ErrorCode, ErrorSummary: change.ErrorSummary,
|
||||
RequestID: change.RequestID, CorrelationID: change.CorrelationID,
|
||||
Resources: []ResourceInput{{
|
||||
Type: action.PrimaryResource, Key: change.ConfigKey, DisplayName: change.ConfigKey,
|
||||
Type: action.PrimaryResource, ID: change.ResourceID, Key: change.ConfigKey, DisplayName: displayName,
|
||||
Relation: constants.AuditResourceRelationPrimary, Role: constants.AuditResourceRoleConfig,
|
||||
IdentitySnapshot: map[string]any{"config_key": change.ConfigKey, "module": change.Module},
|
||||
IdentitySnapshot: identity,
|
||||
BeforeData: change.BeforeData, AfterData: change.AfterData,
|
||||
SubjectVisibility: action.DefaultVisibility,
|
||||
}},
|
||||
@@ -795,7 +880,7 @@ func (w *Writer) Append(ctx context.Context, tx *gorm.DB, input AppendInput) err
|
||||
if !ok {
|
||||
return pkgerrors.New(pkgerrors.CodeInvalidParam, "审计动作未注册")
|
||||
}
|
||||
if input.Actor.Kind != action.AllowedActor || input.Actor.ID == "" || input.Source != action.Source {
|
||||
if !actionAllowsOrigin(action, input.Actor.Kind, input.Source) || input.Actor.ID == "" {
|
||||
return pkgerrors.New(pkgerrors.CodeInvalidParam, "审计操作者或入口不符合动作注册规则")
|
||||
}
|
||||
if !validResult(input.Result) || len(input.Resources) == 0 {
|
||||
@@ -853,6 +938,18 @@ func (w *Writer) Append(ctx context.Context, tx *gorm.DB, input AppendInput) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func actionAllowsOrigin(action ActionDefinition, actor, source string) bool {
|
||||
if action.AllowedActor == actor && action.Source == source {
|
||||
return true
|
||||
}
|
||||
for _, origin := range action.AllowedOrigins {
|
||||
if origin.Actor == actor && origin.Source == source {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fillFromContext(ctx context.Context, input AppendInput) AppendInput {
|
||||
value := auditcontext.From(ctx)
|
||||
if input.Actor.Kind == "" {
|
||||
|
||||
Reference in New Issue
Block a user