固化七月迭代审计治理进展以隔离线上热修

Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。

Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。

Confidence: medium

Scope-risk: broad

Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。

Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。

Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
This commit is contained in:
2026-08-03 09:47:22 +08:00
parent cf2ff0ac1c
commit b3499adfca
114 changed files with 16961 additions and 2782 deletions

View File

@@ -0,0 +1,41 @@
package audit
import (
"context"
"gorm.io/gorm"
pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
)
// BatchInput 描述一条批次根事件及每个已识别资源的子事件。
type BatchInput struct {
Root AppendInput
Children []AppendInput
}
// AppendBatch 在同一事务内追加批次根事件和资源子事件。
func (w *Writer) AppendBatch(ctx context.Context, tx *gorm.DB, input BatchInput) error {
if input.Root.EventID == "" {
return pkgerrors.New(pkgerrors.CodeInvalidParam, "批次根事件缺少稳定事件ID")
}
if err := w.Append(ctx, tx, input.Root); err != nil {
return err
}
for index := range input.Children {
child := input.Children[index]
if child.EventID == "" {
return pkgerrors.New(pkgerrors.CodeInvalidParam, "批次子事件缺少稳定事件ID")
}
if child.ParentEventID == "" {
child.ParentEventID = input.Root.EventID
}
if child.CorrelationID == "" {
child.CorrelationID = input.Root.CorrelationID
}
if err := w.Append(ctx, tx, child); err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,410 @@
// Package audit 实现统一 Audit Event 的注册表与持久化 Adapter。
package audit
import "github.com/break/junhong_cmp_fiber/pkg/constants"
// ActionDefinition 是受控审计动作的写入契约。
type ActionDefinition struct {
Code string
Name string
Category string
Risk string
PrimaryResource string
AllowedActor string
Source string
RequireTransaction bool
DefaultVisibility string
AllowedVisibility []string
SubjectFields []string
SensitiveRead bool
}
// ResourceDefinition 是受控审计资源的快照契约。
type ResourceDefinition struct {
Type string
Name string
IdentityFields []string
}
// Registry 保存首批已评审的动作与资源定义。
type Registry struct {
actionsByOperation map[string]ActionDefinition
actionsByCode map[string]ActionDefinition
resources map[string]ResourceDefinition
}
// NewRegistry 创建首批统一审计注册表。
func NewRegistry() *Registry {
accountCreated := accountLifecycleAction(constants.AuditActionAccountCreated, "创建账号", constants.AuditRiskNormal)
accountUpdated := accountLifecycleAction(constants.AuditActionAccountUpdated, "更新账号", constants.AuditRiskNormal)
accountDeleted := accountLifecycleAction(constants.AuditActionAccountDeleted, "删除账号", constants.AuditRiskHigh)
accountPasswordReset := accountSecurityAction(constants.AuditActionAccountPasswordReset, "重置账号密码", constants.AuditRiskHigh)
accountPasswordChanged := accountSecurityAction(constants.AuditActionAccountPasswordChanged, "修改账号密码", constants.AuditRiskHigh)
accountWeComBound := accountSecurityAction(constants.AuditActionAccountWeComBound, "绑定账号企业微信身份", constants.AuditRiskNormal)
authLogin := accountSecurityAction(constants.AuditActionAuthLogin, "后台账号登录", constants.AuditRiskNormal)
authLogout := accountSecurityAction(constants.AuditActionAuthLogout, "后台账号退出登录", constants.AuditRiskNormal)
authTokenRefreshed := accountSecurityAction(constants.AuditActionAuthTokenRefreshed, "刷新后台访问令牌", constants.AuditRiskNormal)
accountRolesAssigned := accessAction(constants.AuditActionAccountRolesAssigned, "分配账号角色", constants.AuditResourceAccount)
accountRoleRemoved := accessAction(constants.AuditActionAccountRoleRemoved, "移除账号角色", constants.AuditResourceAccount)
shopRolesAssigned := accessAction(constants.AuditActionShopRolesAssigned, "分配店铺角色", constants.AuditResourceShop)
shopRoleDeleted := accessAction(constants.AuditActionShopRoleDeleted, "移除店铺角色", constants.AuditResourceShop)
shopRolesAssigned.Category = constants.AuditCategoryBusiness
shopRoleDeleted.Category = constants.AuditCategoryBusiness
shopCreated := shopIdentityAction(constants.AuditActionShopCreated, "创建店铺")
shopUpdated := shopIdentityAction(constants.AuditActionShopUpdated, "更新店铺基础资料")
shopEnabled := shopStateAction(constants.AuditActionShopEnabled, "启用店铺", constants.AuditRiskNormal)
shopDisabled := shopStateAction(constants.AuditActionShopDisabled, "禁用店铺", constants.AuditRiskNormal)
shopDeleted := shopStateAction(constants.AuditActionShopDeleted, "删除店铺", constants.AuditRiskHigh)
shopBusinessOwnerUpdated := shopStateAction(constants.AuditActionShopBusinessOwnerUpdated, "更新店铺业务员归属", constants.AuditRiskNormal)
shopClientLoginLimitUpdated := shopStateAction(constants.AuditActionShopClientLoginLimitUpdated, "更新店铺 C 端登录限制", constants.AuditRiskHigh)
enterpriseCreated := enterpriseAction(constants.AuditActionEnterpriseCreated, "创建企业", constants.AuditCategoryBusiness, constants.AuditRiskNormal)
enterpriseUpdated := enterpriseAction(constants.AuditActionEnterpriseUpdated, "更新企业基础资料", constants.AuditCategoryBusiness, constants.AuditRiskNormal)
enterpriseStatusUpdated := enterpriseAction(constants.AuditActionEnterpriseStatusUpdated, "更新企业状态", constants.AuditCategoryBusiness, constants.AuditRiskNormal)
enterprisePasswordUpdated := enterpriseAction(constants.AuditActionEnterprisePasswordUpdated, "更新企业账号密码", constants.AuditCategoryBusiness, constants.AuditRiskHigh)
enterpriseCardsAllocated := enterpriseCardAction(constants.AuditActionEnterpriseCardsAllocated, "向企业授权卡")
enterpriseCardsRecalled := enterpriseCardAction(constants.AuditActionEnterpriseCardsRecalled, "回收企业卡授权")
enterpriseCardRemarkUpdated := enterpriseCardAction(constants.AuditActionEnterpriseCardRemarkUpdated, "更新企业卡授权备注")
enterpriseDevicesAllocated := enterpriseCardAction(constants.AuditActionEnterpriseDevicesAllocated, "向企业授权设备")
enterpriseDevicesRecalled := enterpriseCardAction(constants.AuditActionEnterpriseDevicesRecalled, "回收企业设备授权")
personalProfileUpdated := personalAction(constants.AuditActionPersonalCustomerProfileUpdated, "更新个人资料", []string{"nickname", "avatar_url"})
personalPhoneBound := personalAction(constants.AuditActionPersonalCustomerPhoneBound, "绑定个人手机号", []string{"phone"})
personalPhoneChanged := personalAction(constants.AuditActionPersonalCustomerPhoneChanged, "更换个人手机号", []string{"phone"})
personalWechatIdentityUpdated := personalAction(constants.AuditActionPersonalCustomerWechatIdentityUpdated, "同步个人微信主体", []string{"app_id", "app_type"})
systemConfigUpdated := ActionDefinition{
Code: constants.AuditActionSystemConfigUpdated, Name: "更新受控系统配置",
Category: constants.AuditCategoryConfiguration, Risk: constants.AuditRiskHigh,
PrimaryResource: constants.AuditResourceSystemConfig, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
outboxReplayed := outboxRecoveryAction(
constants.AuditActionOutboxReplayed,
"人工重放 Outbox 事件",
)
outboxExpiredLeaseReleased := outboxRecoveryAction(
constants.AuditActionOutboxExpiredLeaseReleased,
"人工释放 Outbox 过期租约",
)
deviceBatchCompleted := deviceBatchAction(
constants.AuditActionDeviceBatchAllocationCompleted,
"完成设备批量分配",
constants.AuditResourceDeviceBatchTask,
)
deviceBatchItem := deviceBatchAction(
constants.AuditActionDeviceBatchAllocationItem,
"处理设备批量分配项",
constants.AuditResourceDevice,
)
deviceBatchItem.AllowedVisibility = []string{constants.AuditSubjectInternalOnly, constants.AuditSubjectResult}
wecomCredentialsRead := ActionDefinition{
Code: constants.AuditActionWeComCredentialsRead, Name: "读取企业微信应用明文凭据",
Category: constants.AuditCategorySecurity, Risk: constants.AuditRiskHigh,
PrimaryResource: constants.AuditResourceWeComApplication, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly}, SensitiveRead: true,
}
roleCreated := accessAction(constants.AuditActionRoleCreated, "创建角色", constants.AuditResourceRole)
roleUpdated := accessAction(constants.AuditActionRoleUpdated, "更新角色", constants.AuditResourceRole)
roleStatusUpdated := accessAction(constants.AuditActionRoleStatusUpdated, "更新角色状态", constants.AuditResourceRole)
roleDefaultCreditUpdated := accessAction(constants.AuditActionRoleDefaultCreditUpdated, "更新角色默认信用额度", constants.AuditResourceRole)
roleDeleted := accessAction(constants.AuditActionRoleDeleted, "删除角色", constants.AuditResourceRole)
rolePermissionsAssigned := accessAction(constants.AuditActionRolePermissionsAssigned, "配置角色权限", constants.AuditResourceRole)
rolePermissionRemoved := accessAction(constants.AuditActionRolePermissionRemoved, "移除角色权限", constants.AuditResourceRole)
rolePermissionsBatchRemoved := accessAction(constants.AuditActionRolePermissionsBatchRemoved, "批量移除角色权限", constants.AuditResourceRole)
permissionCreated := accessAction(constants.AuditActionPermissionCreated, "创建权限", constants.AuditResourcePermission)
permissionUpdated := accessAction(constants.AuditActionPermissionUpdated, "更新权限", constants.AuditResourcePermission)
permissionDeleted := accessAction(constants.AuditActionPermissionDeleted, "删除权限", constants.AuditResourcePermission)
return &Registry{
actionsByOperation: map[string]ActionDefinition{
constants.AuditOperationSystemConfigUpdate: systemConfigUpdated,
constants.AuditOperationOutboxReplay: outboxReplayed,
constants.AuditOperationOutboxReleaseExpiredLease: outboxExpiredLeaseReleased,
},
actionsByCode: map[string]ActionDefinition{
constants.AuditActionAccountCreated: accountCreated,
constants.AuditActionAccountUpdated: accountUpdated,
constants.AuditActionAccountDeleted: accountDeleted,
constants.AuditActionAccountPasswordReset: accountPasswordReset,
constants.AuditActionAccountPasswordChanged: accountPasswordChanged,
constants.AuditActionAccountWeComBound: accountWeComBound,
constants.AuditActionAuthLogin: authLogin,
constants.AuditActionAuthLogout: authLogout,
constants.AuditActionAuthTokenRefreshed: authTokenRefreshed,
constants.AuditActionAccountRolesAssigned: accountRolesAssigned,
constants.AuditActionAccountRoleRemoved: accountRoleRemoved,
constants.AuditActionShopRolesAssigned: shopRolesAssigned,
constants.AuditActionShopRoleDeleted: shopRoleDeleted,
constants.AuditActionShopCreated: shopCreated,
constants.AuditActionShopUpdated: shopUpdated,
constants.AuditActionShopEnabled: shopEnabled,
constants.AuditActionShopDisabled: shopDisabled,
constants.AuditActionShopDeleted: shopDeleted,
constants.AuditActionShopBusinessOwnerUpdated: shopBusinessOwnerUpdated,
constants.AuditActionShopClientLoginLimitUpdated: shopClientLoginLimitUpdated,
constants.AuditActionEnterpriseCreated: enterpriseCreated,
constants.AuditActionEnterpriseUpdated: enterpriseUpdated,
constants.AuditActionEnterpriseStatusUpdated: enterpriseStatusUpdated,
constants.AuditActionEnterprisePasswordUpdated: enterprisePasswordUpdated,
constants.AuditActionEnterpriseCardsAllocated: enterpriseCardsAllocated,
constants.AuditActionEnterpriseCardsRecalled: enterpriseCardsRecalled,
constants.AuditActionEnterpriseCardRemarkUpdated: enterpriseCardRemarkUpdated,
constants.AuditActionEnterpriseDevicesAllocated: enterpriseDevicesAllocated,
constants.AuditActionEnterpriseDevicesRecalled: enterpriseDevicesRecalled,
constants.AuditActionPersonalCustomerProfileUpdated: personalProfileUpdated,
constants.AuditActionPersonalCustomerPhoneBound: personalPhoneBound,
constants.AuditActionPersonalCustomerPhoneChanged: personalPhoneChanged,
constants.AuditActionPersonalCustomerWechatIdentityUpdated: personalWechatIdentityUpdated,
constants.AuditActionSystemConfigUpdated: systemConfigUpdated,
constants.AuditActionOutboxReplayed: outboxReplayed,
constants.AuditActionOutboxExpiredLeaseReleased: outboxExpiredLeaseReleased,
constants.AuditActionDeviceBatchAllocationCompleted: deviceBatchCompleted,
constants.AuditActionDeviceBatchAllocationItem: deviceBatchItem,
constants.AuditActionWeComCredentialsRead: wecomCredentialsRead,
constants.AuditActionRoleCreated: roleCreated,
constants.AuditActionRoleUpdated: roleUpdated,
constants.AuditActionRoleStatusUpdated: roleStatusUpdated,
constants.AuditActionRoleDefaultCreditUpdated: roleDefaultCreditUpdated,
constants.AuditActionRoleDeleted: roleDeleted,
constants.AuditActionRolePermissionsAssigned: rolePermissionsAssigned,
constants.AuditActionRolePermissionRemoved: rolePermissionRemoved,
constants.AuditActionRolePermissionsBatchRemoved: rolePermissionsBatchRemoved,
constants.AuditActionPermissionCreated: permissionCreated,
constants.AuditActionPermissionUpdated: permissionUpdated,
constants.AuditActionPermissionDeleted: permissionDeleted,
},
resources: map[string]ResourceDefinition{
constants.AuditResourceAccount: {
Type: constants.AuditResourceAccount, Name: "账号",
IdentityFields: []string{"id", "username", "phone", "user_type", "shop_id", "enterprise_id", "wecom_userid", "wecom_name"},
},
constants.AuditResourceRole: {
Type: constants.AuditResourceRole, Name: "角色",
IdentityFields: []string{"id", "role_name", "role_type", "status", "default_credit_enabled", "default_credit_limit"},
},
constants.AuditResourcePermission: {
Type: constants.AuditResourcePermission, Name: "权限",
IdentityFields: []string{"id", "perm_name", "perm_code", "perm_type", "platform", "available_for_role_types", "parent_id", "status"},
},
constants.AuditResourceSystemConfig: {
Type: constants.AuditResourceSystemConfig, Name: "受控系统配置",
IdentityFields: []string{"config_key", "module"},
},
constants.AuditResourceOutboxEvent: {
Type: constants.AuditResourceOutboxEvent, Name: "Outbox 事件",
IdentityFields: []string{
"event_id", "event_type", "aggregate_type", "aggregate_id",
"resource_type", "resource_id", "business_key",
},
},
constants.AuditResourceDeviceBatchTask: {
Type: constants.AuditResourceDeviceBatchTask, Name: "设备批量分配任务",
IdentityFields: []string{"task_no", "operation_type"},
},
constants.AuditResourceDevice: {
Type: constants.AuditResourceDevice, Name: "设备",
IdentityFields: []string{"id", "virtual_no", "imei", "sn", "generation"},
},
constants.AuditResourceIotCard: {
Type: constants.AuditResourceIotCard, Name: "IoT卡",
IdentityFields: []string{"id", "iccid", "iccid_19", "iccid_20", "virtual_no", "msisdn", "carrier_type", "shop_id", "series_id", "generation"},
},
constants.AuditResourceShop: {
Type: constants.AuditResourceShop, Name: "店铺",
IdentityFields: []string{"id", "shop_code", "shop_name", "parent_id", "level"},
},
constants.AuditResourceOrder: {
Type: constants.AuditResourceOrder, Name: "订单",
IdentityFields: []string{"id", "order_no", "buyer_type", "buyer_id", "asset_identifier", "total_amount", "payment_method", "payment_status"},
},
constants.AuditResourceRefund: {
Type: constants.AuditResourceRefund, Name: "退款单",
IdentityFields: []string{"id", "refund_no", "order_id", "order_no", "asset_identifier", "shop_id", "requested_refund_amount", "status"},
},
constants.AuditResourceEnterprise: {
Type: constants.AuditResourceEnterprise, Name: "企业",
IdentityFields: []string{"id", "enterprise_code", "enterprise_name", "owner_shop_id"},
},
constants.AuditResourceDeviceSIMBinding: {
Type: constants.AuditResourceDeviceSIMBinding, Name: "设备卡槽绑定",
IdentityFields: []string{"id", "device_id", "device_virtual_no", "slot_position", "iot_card_id", "iccid", "virtual_no", "is_current"},
},
constants.AuditResourceAssetAllocationRecord: {
Type: constants.AuditResourceAssetAllocationRecord, Name: "资产分配记录",
IdentityFields: []string{"id", "allocation_no", "asset_type", "asset_id", "asset_identifier", "from_owner_type", "from_owner_id", "to_owner_type", "to_owner_id"},
},
constants.AuditResourceExchangeOrder: {
Type: constants.AuditResourceExchangeOrder, Name: "换货单",
IdentityFields: []string{"id", "exchange_no", "old_asset_type", "old_asset_id", "new_asset_type", "new_asset_id", "shop_id", "status"},
},
constants.AuditResourceAgentRecharge: {
Type: constants.AuditResourceAgentRecharge, Name: "代理充值单",
IdentityFields: []string{"id", "recharge_no", "shop_id", "agent_wallet_id", "approval_instance_id", "status"},
},
constants.AuditResourceAssetWallet: {
Type: constants.AuditResourceAssetWallet, Name: "资产钱包",
IdentityFields: []string{"id", "resource_type", "resource_id", "currency"},
},
constants.AuditResourceApprovalInstance: {
Type: constants.AuditResourceApprovalInstance, Name: "审批实例",
IdentityFields: []string{"id", "business_type", "business_id", "provider", "external_ref", "status"},
},
constants.AuditResourceWeComApplication: {
Type: constants.AuditResourceWeComApplication, Name: "企业微信应用配置",
IdentityFields: []string{"id", "corp_id", "agent_id", "name", "status", "credentials_configured"},
},
constants.AuditResourceAuthentication: {
Type: constants.AuditResourceAuthentication, Name: "认证状态",
IdentityFields: []string{"account_id", "device", "auth_method", "state", "wecom_corp_id", "wecom_userid", "wecom_name"},
},
constants.AuditResourceEnterpriseCardAuthorization: {
Type: constants.AuditResourceEnterpriseCardAuthorization, Name: "企业卡授权记录",
IdentityFields: []string{"id", "enterprise_id", "card_id", "authorized_by", "authorizer_type", "authorized_at", "revoked_by", "revoked_at", "device_auth_id"},
},
constants.AuditResourceEnterpriseDeviceAuthorization: {
Type: constants.AuditResourceEnterpriseDeviceAuthorization, Name: "企业设备授权记录",
IdentityFields: []string{"id", "enterprise_id", "device_id", "authorized_by", "authorizer_type", "authorized_at", "revoked_by", "revoked_at"},
},
constants.AuditResourcePersonalCustomer: {
Type: constants.AuditResourcePersonalCustomer, Name: "个人客户",
IdentityFields: []string{"id", "nickname", "wx_open_id", "wx_union_id", "status"},
},
constants.AuditResourcePersonalCustomerPhone: {
Type: constants.AuditResourcePersonalCustomerPhone, Name: "个人客户手机号",
IdentityFields: []string{"id", "customer_id", "phone", "is_primary", "verified_at", "status"},
},
constants.AuditResourcePersonalCustomerOpenID: {
Type: constants.AuditResourcePersonalCustomerOpenID, Name: "个人客户微信主体",
IdentityFields: []string{"id", "customer_id", "app_id", "open_id", "union_id", "app_type"},
},
},
}
}
func accountSecurityAction(code, name, risk string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategorySecurity, Risk: risk,
PrimaryResource: constants.AuditResourceAccount, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func accessAction(code, name, primaryResource string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategorySecurity, Risk: constants.AuditRiskHigh,
PrimaryResource: primaryResource, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func shopIdentityAction(code, name string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryBusiness, Risk: constants.AuditRiskNormal,
PrimaryResource: constants.AuditResourceShop, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func shopStateAction(code, name, risk string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryBusiness, Risk: risk,
PrimaryResource: constants.AuditResourceShop, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectResult,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly, constants.AuditSubjectResult},
}
}
func enterpriseAction(code, name, category, risk string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: category, Risk: risk,
PrimaryResource: constants.AuditResourceEnterprise, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func enterpriseCardAction(code, name string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryAsset, Risk: constants.AuditRiskNormal,
PrimaryResource: constants.AuditResourceEnterprise, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly, constants.AuditSubjectResult},
}
}
func personalAction(code, name string, subjectFields []string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryIdentity, Risk: constants.AuditRiskNormal,
PrimaryResource: constants.AuditResourcePersonalCustomer, AllowedActor: constants.AuditActorPersonalCustomer,
Source: constants.AuditSourcePersonalAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectDetail,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly, constants.AuditSubjectDetail},
SubjectFields: subjectFields,
}
}
func accountLifecycleAction(code, name, risk string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryIdentity, Risk: risk,
PrimaryResource: constants.AuditResourceAccount, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func deviceBatchAction(code, name, primaryResource string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryAsset, Risk: constants.AuditRiskNormal,
PrimaryResource: primaryResource, AllowedActor: constants.AuditActorSystemTask,
Source: constants.AuditSourceWorker, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
func outboxRecoveryAction(code, name string) ActionDefinition {
return ActionDefinition{
Code: code, Name: name, Category: constants.AuditCategoryReliability, Risk: constants.AuditRiskHigh,
PrimaryResource: constants.AuditResourceOutboxEvent, AllowedActor: constants.AuditActorAccount,
Source: constants.AuditSourceAdminAPI, RequireTransaction: true,
DefaultVisibility: constants.AuditSubjectInternalOnly,
AllowedVisibility: []string{constants.AuditSubjectInternalOnly},
}
}
// Action 返回已注册动作定义。
func (r *Registry) Action(code string) (ActionDefinition, bool) {
if r == nil {
return ActionDefinition{}, false
}
action, ok := r.actionsByCode[code]
return action, ok
}
// ActionByOperation 返回旧应用接缝操作类型对应的受控动作。
func (r *Registry) ActionByOperation(operation string) (ActionDefinition, bool) {
if r == nil {
return ActionDefinition{}, false
}
action, ok := r.actionsByOperation[operation]
return action, ok
}
// Resource 返回已注册资源定义。
func (r *Registry) Resource(resourceType string) (ResourceDefinition, bool) {
if r == nil {
return ResourceDefinition{}, false
}
resource, ok := r.resources[resourceType]
return resource, ok
}

View File

@@ -0,0 +1,57 @@
package audit
import (
"testing"
"github.com/bytedance/sonic"
"github.com/break/junhong_cmp_fiber/pkg/constants"
)
// TestSecurityActionsRegistered 验证账号安全动作不会绕过注册表。
func TestSecurityActionsRegistered(t *testing.T) {
registry := NewRegistry()
for _, code := range []string{
constants.AuditActionAccountPasswordReset,
constants.AuditActionAccountPasswordChanged,
constants.AuditActionAccountWeComBound,
constants.AuditActionAuthLogin,
constants.AuditActionAuthLogout,
constants.AuditActionAuthTokenRefreshed,
} {
action, ok := registry.Action(code)
if !ok {
t.Fatalf("安全动作未注册:%s", code)
}
if action.PrimaryResource != constants.AuditResourceAccount || action.Category != constants.AuditCategorySecurity {
t.Fatalf("安全动作注册错误:%s", code)
}
}
}
// TestSecurityAuditRemovesCredentials 验证安全凭据不会进入审计 JSON。
func TestSecurityAuditRemovesCredentials(t *testing.T) {
encoded, err := safeObject(map[string]any{
"password": "secret",
"verification_code": "123456",
"access_token": "token",
"cookie": "session=value",
"credentials_configured": true,
"state": "changed",
})
if err != nil {
t.Fatalf("清理审计 JSON 失败:%v", err)
}
var value map[string]any
if err := sonic.Unmarshal(encoded, &value); err != nil {
t.Fatalf("解析审计 JSON 失败:%v", err)
}
for _, field := range []string{"password", "verification_code", "access_token", "cookie"} {
if _, exists := value[field]; exists {
t.Fatalf("安全凭据未删除:%s", field)
}
}
if value["credentials_configured"] != true || value["state"] != "changed" {
t.Fatalf("安全业务事实被错误删除:%v", value)
}
}

File diff suppressed because it is too large Load Diff