forked from wangziqi/gongxue-base
feat: add content asset security scanning
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
alter table public.content_assets
|
||||
add column if not exists security_scan_status text not null default 'not_required',
|
||||
add column if not exists security_scanned_at timestamptz,
|
||||
add column if not exists security_scan_provider text,
|
||||
add column if not exists security_scan_summary jsonb not null default '{}'::jsonb;
|
||||
|
||||
update public.content_assets
|
||||
set security_scan_status = case
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
and upload_status = 'verified'
|
||||
then 'passed'
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
and upload_status = 'failed'
|
||||
then 'skipped'
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
then 'pending'
|
||||
else 'not_required'
|
||||
end,
|
||||
security_scanned_at = case
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
and upload_status = 'verified'
|
||||
then coalesce(security_scanned_at, verified_at, updated_at, created_at, now())
|
||||
else security_scanned_at
|
||||
end,
|
||||
security_scan_provider = case
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
and upload_status = 'verified'
|
||||
then coalesce(security_scan_provider, 'legacy_backfill')
|
||||
else security_scan_provider
|
||||
end,
|
||||
security_scan_summary = case
|
||||
when storage_provider in ('local_dev', 'supabase_storage', 'aliyun_oss', 'tencent_cos')
|
||||
and object_key is not null
|
||||
and upload_status = 'verified'
|
||||
then coalesce(security_scan_summary, '{}'::jsonb)
|
||||
|| jsonb_build_object(
|
||||
'riskLevel', 'none',
|
||||
'issueCodes', '[]'::jsonb,
|
||||
'backfilled', true,
|
||||
'backfilledAt', now()
|
||||
)
|
||||
else coalesce(security_scan_summary, '{}'::jsonb)
|
||||
end
|
||||
where security_scan_status = 'not_required'
|
||||
or security_scan_summary = '{}'::jsonb;
|
||||
|
||||
do $$
|
||||
begin
|
||||
if not exists (select 1 from pg_constraint where conname = 'content_assets_security_scan_status_check') then
|
||||
alter table public.content_assets
|
||||
add constraint content_assets_security_scan_status_check
|
||||
check (security_scan_status in ('not_required', 'pending', 'scanning', 'passed', 'failed', 'skipped'));
|
||||
end if;
|
||||
end $$;
|
||||
|
||||
create table if not exists public.content_asset_security_scan_events (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
||||
asset_id uuid references public.content_assets(id) on delete set null,
|
||||
provider text not null,
|
||||
scan_status text not null
|
||||
check (scan_status in ('pending', 'scanning', 'passed', 'failed', 'skipped')),
|
||||
risk_level text not null default 'none'
|
||||
check (risk_level in ('none', 'low', 'medium', 'high', 'critical')),
|
||||
issue_codes text[] not null default '{}',
|
||||
details jsonb not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
comment on table public.content_asset_security_scan_events is
|
||||
'内容资源安全扫描事件。用于记录托管对象的内置规则扫描、杀毒/内容安全 provider 扫描结果、失败原因和审计轨迹。';
|
||||
|
||||
create index if not exists idx_asset_security_scan_events_asset
|
||||
on public.content_asset_security_scan_events(tenant_id, asset_id, created_at desc);
|
||||
|
||||
create index if not exists idx_asset_security_scan_events_status
|
||||
on public.content_asset_security_scan_events(tenant_id, scan_status, risk_level, created_at desc);
|
||||
|
||||
create index if not exists idx_content_assets_security_scan_status
|
||||
on public.content_assets(tenant_id, security_scan_status, upload_status, status, updated_at desc);
|
||||
|
||||
alter table public.content_asset_security_scan_events enable row level security;
|
||||
|
||||
drop policy if exists tenant_isolation on public.content_asset_security_scan_events;
|
||||
create policy tenant_isolation on public.content_asset_security_scan_events
|
||||
for all
|
||||
using (tenant_id = app.current_tenant_id() or app.is_platform_admin())
|
||||
with check (tenant_id = app.current_tenant_id() or app.is_platform_admin());
|
||||
Reference in New Issue
Block a user