feat: 接入 Instance 原生管理观测与删除保护
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package postgresql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.ddupan.top/panxiao81/ayatori/internal/database/application"
|
||||
"git.ddupan.top/panxiao81/ayatori/internal/database/domain/instance"
|
||||
)
|
||||
|
||||
// 只读取当前执行角色的属性,不能从可继承的角色成员关系推导 CREATEDB/CREATEROLE。
|
||||
// 所有事实来自同一条语句;不创建探针数据库,不修改管理账号或持久 schema。
|
||||
const inspectManagementStatement = `
|
||||
SELECT
|
||||
pg_catalog.current_setting('server_version'),
|
||||
ARRAY(SELECT name::text FROM pg_catalog.pg_available_extensions ORDER BY name),
|
||||
role.rolsuper,
|
||||
role.rolcreaterole,
|
||||
role.rolcreatedb,
|
||||
pg_catalog.pg_is_in_recovery() OR
|
||||
pg_catalog.current_setting('transaction_read_only')::boolean
|
||||
FROM pg_catalog.pg_roles AS role
|
||||
WHERE role.rolname = current_user`
|
||||
|
||||
func (d *database) InspectManagement(ctx context.Context) (application.DatabaseMetadata, error) {
|
||||
var metadata application.DatabaseMetadata
|
||||
var superuser, createRole, createDatabase, readOnly bool
|
||||
err := d.pool.QueryRow(ctx, inspectManagementStatement).Scan(
|
||||
&metadata.Version, &metadata.AvailableExtensions,
|
||||
&superuser, &createRole, &createDatabase, &readOnly,
|
||||
)
|
||||
if err != nil {
|
||||
return application.DatabaseMetadata{}, safeError(err, application.ErrObservation)
|
||||
}
|
||||
checks := instance.ManagementChecks{
|
||||
Connection: instance.CheckPassed,
|
||||
Metadata: instance.CheckPassed,
|
||||
Roles: nativePrivilege(createRole && !superuser),
|
||||
Databases: nativePrivilege(createDatabase && !superuser),
|
||||
// CREATEROLE 可管理自己新建角色的 membership;供应时必须显式取得 SET 权限,
|
||||
// 再以 owner 操作数据库 ACL。这里不授权操作任意导入角色或他人数据库。
|
||||
Grants: nativePrivilege(createRole && createDatabase && !superuser),
|
||||
// 新建数据库 owner 可安装 trusted 扩展。具体扩展仍需逐请求执行和回读,
|
||||
// 非 trusted 扩展不能因出现在 available 列表就视为可安装。
|
||||
Extensions: nativePrivilege(createRole && createDatabase && !superuser),
|
||||
}
|
||||
if readOnly {
|
||||
checks.Databases = instance.CheckUnavailable
|
||||
}
|
||||
metadata.Management = checks
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func nativePrivilege(allowed bool) instance.CheckResult {
|
||||
if allowed {
|
||||
return instance.CheckPassed
|
||||
}
|
||||
return instance.CheckInsufficientPrivileges
|
||||
}
|
||||
Reference in New Issue
Block a user