关于 risk-assessment-summarization
用于 ServiceNow GRC 的风险评估汇总技能,面向风险管理团队和报告编制者。它汇总风险评分、固有与剩余风险、趋势及事件数据,并生成热图数据和缓解建议。
主要功能
- 01汇总风险评分与分类
- 02比较固有风险和剩余风险
- 03生成可能性与影响热图数据
- 04分析风险随时间的趋势
- 05依据风险敞口提出缓解建议
- 06关联风险事件与控制效果
适用场景
- 01编制风险委员会或董事会报告
- 02比较各业务部门的风险状况
- 03评估风险缓解投资效果
MCP 相关
通过 SN-Query-Table 查询风险、定义和事件,并使用 SN-Execute-Background-Script 执行汇总分析;也可调用 SN-Natural-Language-Search 和 SN-Discover-Table-Schema。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ happy-technologies-llc/ happy-platform-skills --skill risk-assessment-summarization安装后在 Claude Code 中输入/risk-assessment-summarization确认已加载。
详细介绍
风险评估摘要
概述
此技能可生成 ServiceNow GRC 风险评估的全面摘要,包括:
- 汇总各档案、类别和业务部门的风险评分
- 对比固有风险与剩余风险,以衡量控制有效性
- 生成热力图数据(可能性 x 影响矩阵),用于可视化报告
- 识别随时间变化的风险趋势(上升、稳定、下降)
- 根据风险处置计划和剩余风险敞口提出缓解策略建议
- 将风险评估关联到底层风险事件和控制有效性
适用场景:
- 准备风险委员会或董事会级别的风险报告
- 完成一个风险评估周期后,需要汇总结果
- 比较不同业务部门或时间段的风险状况
- 在战略规划期间了解企业风险敞口
- 评估风险缓解投资的有效性
前提条件
- 角色:
sn_risk.manager、sn_grc.manager或admin - 插件:
com.sn_risk、com.sn_grc - 访问权限: 对 sn_grc_risk、sn_risk_definition、sn_risk_event、sn_grc_profile 表具有读取权限
- 知识: 了解风险评分方法(可能性 x 影响)和组织的风险偏好
关键风险表
| 表 | 用途 | 关键字段 |
|---|---|---|
sn_grc_risk | 风险登记记录 | number, short_description, risk_score, inherent_risk, residual_risk, state, treatment, likelihood, impact, profile, category, owner |
sn_risk_definition | 风险框架定义 | number, short_description, risk_criteria, scoring_method, appetite |
sn_risk_event | 实际风险事件/事故 | number, short_description, event_date, impact_amount, risk, category |
sn_grc_profile | 用于界定风险范围的实体档案 | number, short_description, profile_type, applies_to |
sn_grc_item | GRC 内容项 | number, short_description, item_type, profile |
流程
步骤 1:检索有效风险记录
查询所有包含评分数据的有效风险。
使用 MCP(Claude Code/Desktop):
Tool: SN-Query-Table
Parameters:
table_name: sn_grc_risk
query: active=true^ORDERBYDESCrisk_score
fields: sys_id,number,short_description,risk_score,inherent_risk,residual_risk,state,treatment,likelihood,impact,profile,category,owner,sys_created_on,sys_updated_on
limit: 100
使用 REST API:
GET /api/now/table/sn_grc_risk?sysparm_query=active=true^ORDERBYDESCrisk_score&sysparm_fields=sys_id,number,short_description,risk_score,inherent_risk,residual_risk,state,treatment,likelihood,impact,profile,category,owner&sysparm_limit=100
步骤 2:检索风险框架定义
了解评分方法和风险偏好阈值。
使用 MCP:
Tool: SN-Query-Table
Parameters:
table_name: sn_risk_definition
query: active=true
fields: sys_id,number,short_description,risk_criteria,scoring_method,appetite,description
limit: 20
使用 REST API:
GET /api/now/table/sn_risk_definition?sysparm_query=active=true&sysparm_fields=sys_id,number,short_description,risk_criteria,scoring_method,appetite,description&sysparm_limit=20
步骤 3:生成风险评估摘要并分析固有风险与剩余风险
生成汇总风险指标和控制有效性:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var summary = {
generated_date: new GlideDateTime().toString(),
total_risks: 0,
by_treatment: {},
by_category: {},
inherent_vs_residual: {
avg_inherent: 0,
avg_residual: 0,
control_effectiveness_pct: 0,
risks_above_appetite: 0
},
severity_distribution: { critical: 0, high: 0, medium: 0, low: 0 },
top_risks: []
};
var inherentSum = 0, residualSum = 0, count = 0;
var riskAppetite = 50; // Default; adjust per organization
var gr = new GlideRecord('sn_grc_risk');
gr.addQuery('active', true);
gr.orderByDesc('risk_score');
gr.query();
while (gr.next()) {
summary.total_risks++;
count++;
var inherent = parseInt(gr.inherent_risk.toString()) || 0;
var residual = parseInt(gr.residual_risk.toString()) || 0;
var score = parseInt(gr.risk_score.toString()) || 0;
inherentSum += inherent;
residualSum += residual;
if (residual > riskAppetite) summary.inherent_vs_residual.risks_above_appetite++;
// Severity distribution
if (score >= 80) summary.severity_distribution.critical++;
else if (score >= 60) summary.severity_distribution.high++;
else if (score >= 30) summary.severity_distribution.medium++;
else summary.severity_distribution.low++;
// Treatment breakdown
var treat = gr.treatment.getDisplayValue() || 'Not Assigned';
summary.by_treatment[treat] = (summary.by_treatment[treat] || 0) + 1;
// Category breakdown
var cat = gr.category.getDisplayValue() || 'Uncategorized';
summary.by_category[cat] = (summary.by_category[cat] || 0) + 1;
// Top 10 risks
if (summary.top_risks.length < 10) {
summary.top_risks.push({
number: gr.number.toString(),
title: gr.short_description.toString(),
risk_score: score,
inherent: inherent,
residual: residual,
treatment: gr.treatment.getDisplayValue(),
owner: gr.owner.getDisplayValue()
});
}
}
if (count > 0) {
summary.inherent_vs_residual.avg_inherent = Math.round(inherentSum / count);
summary.inherent_vs_residual.avg_residual = Math.round(residualSum / count);
if (inherentSum > 0) {
summary.inherent_vs_residual.control_effectiveness_pct =
Math.round(((inherentSum - residualSum) / inherentSum) * 100);
}
}
gs.info('RISK ASSESSMENT SUMMARY:\n' + JSON.stringify(summary, null, 2));
description: "GRC: Generate risk assessment summary with inherent vs residual analysis"
步骤 4:生成热力图数据(可能性 x 影响矩阵)
构建可能性—影响矩阵,用于热力图可视化:
Tool: SN-Execute-Background-Script
Parameters:
script: |
// Heat map: 5x5 matrix (likelihood x impact)
var heatMap = {};
for (var l = 1; l <= 5; l++) {
for (var i = 1; i <= 5; i++) {
heatMap[l + 'x' + i] = { likelihood: l, impact: i, count: 0, risks: [] };
}
}
var gr = new GlideRecord('sn_grc_risk');
gr.addQuery('active', true);
gr.query();
while (gr.next()) {
var likelihood = parseInt(gr.likelihood.toString()) || 0;
var impact = parseInt(gr.impact.toString()) || 0;
// Normalize to 1-5 scale if needed
if (likelihood > 5) likelihood = Math.ceil(likelihood / 20);
if (impact > 5) impact = Math.ceil(impact / 20);
if (likelihood < 1) likelihood = 1;
if (impact < 1) impact = 1;
var key = likelihood + 'x' + impact;
if (heatMap[key]) {
heatMap[key].count++;
if (heatMap[key].risks.length < 3) {
heatMap[key].risks.push(gr.number.toString() + ': ' + gr.short_description.toString());
}
}
}
// Format for output
var matrix = [];
for (var cell in heatMap) {
if (heatMap[cell].count > 0) {
matrix.push(heatMap[cell]);
}
}
matrix.sort(function(a, b) { return (b.likelihood * b.impact) - (a.likelihood * a.impact); });
gs.info('RISK HEAT MAP DATA:\n' + JSON.stringify(matrix, null, 2));
gs.info('\nHEAT MAP LEGEND:');
gs.info(' Critical (Red): Likelihood >= 4 AND Impact >= 4');
gs.info(' High (Orange): Score >= 12');
gs.info(' Medium (Yellow): Score >= 6');
gs.info(' Low (Green): Score < 6');
description: "GRC: Generate risk heat map data (likelihood x impact matrix)"
步骤 5:分析随时间变化的风险趋势
将当前风险状况与历史基线进行比较:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var periods = [
{ label: 'Current', days: 0 },
{ label: '30 Days Ago', days: 30 },
{ label: '60 Days Ago', days: 60 },
{ label: '90 Days Ago', days: 90 }
];
var trends = [];
for (var p = 0; p < periods.length; p++) {
var period = periods[p];
var totalScore = 0, count = 0, critical = 0;
if (period.days === 0) {
var gr = new GlideRecord('sn_grc_risk');
gr.addQuery('active', true);
gr.query();
while (gr.next()) {
var s = parseInt(gr.risk_score.toString()) || 0;
totalScore += s;
count++;
if (s >= 80) critical++;
}
} else {
// Use risk events as proxy for historical risk levels
var ev = new GlideAggregate('sn_risk_event');
ev.addQuery('sys_created_on', '>=', gs.daysAgo(period.days));
ev.addQuery('sys_created_on', '<', gs.daysAgo(period.days - 30));
ev.addAggregate('COUNT');
ev.query();
if (ev.next()) count = parseInt(ev.getAggregate('COUNT'));
}
trends.push({
period: period.label,
total_risks: count,
avg_score: count > 0 ? Math.round(totalScore / count) : 0,
critical_risks: critical
});
}
gs.info('RISK TREND ANALYSIS:\n' + JSON.stringify(trends, null, 2));
description: "GRC: Analyze risk score trends over time"
步骤 6:生成缓解建议
根据风险处置和剩余风险敞口生成可执行建议:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var recommendations = [];
var gr = new GlideRecord('sn_grc_risk');
gr.addQuery('active', true);
gr.addQuery('residual_risk', '>', 50);
gr.orderByDesc('residual_risk');
gr.setLimit(20);
gr.query();
while (gr.next()) {
var inherent = parseInt(gr.inherent_risk.toString()) || 0;
var residual = parseInt(gr.residual_risk.toString()) || 0;
var reduction = inherent > 0 ? Math.round(((inherent - residual) / inherent) * 100) : 0;
var treatment = gr.treatment.getDisplayValue() || 'Not Assigned';
var rec = {
risk_number: gr.number.toString(),
title: gr.short_description.toString(),
inherent_risk: inherent,
residual_risk: residual,
risk_reduction_pct: reduction,
current_treatment: treatment,
recommendations: []
};
// Generate recommendations based on treatment and residual level
if (treatment === 'Accept' && residual >= 70) {
rec.recommendations.push('Re-evaluate acceptance decision; residual risk exceeds organizational appetite');
rec.recommendations.push('Conduct cost-benefit analysis for additional controls');
}
if (treatment === 'Mitigate' && reduction < 30) {
rec.recommendations.push('Current controls are insufficient; risk reduction is only ' + reduction + '%');
rec.recommendations.push('Evaluate additional compensating controls or alternative mitigation strategies');
}
if (treatment === 'Transfer' && residual >= 60) {
rec.recommendations.push('Verify insurance coverage adequacy for residual exposure');
rec.recommendations.push('Review third-party SLAs and liability clauses');
}
if (treatment === 'Not Assigned') {
rec.recommendations.push('URGENT: Assign risk treatment strategy immediately');
rec.recommendations.push('Schedule risk owner meeting to determine treatment approach');
}
if (residual >= 80) {
rec.recommendations.push('CRITICAL: Escalate to executive leadership for immediate action');
}
// Check for related control failures
var ctrl = new GlideRecord('sn_compliance_control');
ctrl.addQuery('profile', gr.profile.toString());
ctrl.addQuery('state', 'NOT IN', 'compliant,passed');
ctrl.query();
if (ctrl.getRowCount() > 0) {
rec.recommendations.push('Address ' + ctrl.getRowCount() + ' failing controls linked to this risk profile');
}
recommendations.push(rec);
}
gs.info('MITIGATION RECOMMENDATIONS:\n' + JSON.stringify(recommendations, null, 2));
description: "GRC: Generate mitigation recommendations for high-residual risks"
步骤 7:查询风险事件以了解损失数据背景
检索实际风险事件,以便根据真实事故进行评估:
使用 MCP:
Tool: SN-Query-Table
Parameters:
table_name: sn_risk_event
query: sys_created_on>=javascript:gs.daysAgo(365)^ORDERBYDESCimpact_amount
fields: sys_id,number,short_description,event_date,impact_amount,risk,category,state
limit: 50
使用 REST API:
GET /api/now/table/sn_risk_event?sysparm_query=sys_created_on>=javascript:gs.daysAgo(365)^ORDERBYDESCimpact_amount&sysparm_fields=sys_id,number,short_description,event_date,impact_amount,risk,category,state&sysparm_limit=50
工具用法
| 操作 | MCP 工具 | REST 端点 |
|---|---|---|
| 查询风险 | SN-Query-Table | GET /api/now/table/sn_grc_risk |
| 查询风险定义 | SN-Query-Table | GET /api/now/table/sn_risk_definition |
| 查询风险事件 | SN-Query-Table | GET /api/now/table/sn_risk_event |
| 搜索风险 | SN-Natural-Language-Search | 不适用 |
| 复杂分析 | SN-Execute-Background-Script | POST /api/now/table/sys_trigger |
| 架构发现 | SN-Discover-Table-Schema | GET /api/now/table/sys_dictionary |
最佳实践
- 固有风险与剩余风险: 始终同时呈现固有风险和剩余风险,以体现控制措施的价值
- 风险偏好背景: 根据组织定义的风险偏好阈值来说明所有评分
- 热力图清晰度: 使用标准化的 5x5 矩阵,并在所有报告中保持颜色编码一致
- 趋势基线: 建立季度基线,以便有效比较趋势
- 风险处置验证: 确认风险处置策略已实际实施,而非仅有文档记录
- 损失数据整合: 纳入实际风险事件数据,以验证评估准确性
- 负责人问责: 在所有摘要中列出风险负责人姓名,明确问责关系
故障排查
风险评分显示为零
症状: 所有 risk_score、inherent_risk 或 residual_risk 字段均返回 0 或为空 原因: 风险评分可能使用由评估工作流填充的计算字段,或自定义评分字段 解决方案:
Tool: SN-Discover-Table-Schema
Parameters:
table_name: sn_grc_risk
检查是否存在其他评分字段,例如 calculated_risk、risk_score_calculated 或 assessment_score。同时确认风险评估已完成。
未填充可能性和影响值
症状: 由于可能性/影响值为空,无法生成热力图
原因: 风险记录可能使用定性评级(High/Medium/Low),而非数值评分
解决方案: 将定性值映射到数值量表:Critical=5、High=4、Medium=3、Low=2、Very Low=1。检查 sys_choice 表中的字段值定义。
风险事件表为空
症状: sn_risk_event 未返回任何记录
原因: 风险事件模块可能尚未配置,或事件记录在自定义表中
解决方案: 检查 com.sn_risk_advanced 插件是否已激活。有些组织会在自定义表或外部系统中跟踪损失事件。
示例
示例 1:季度企业风险摘要
场景: CRO 需要一份综合风险态势报告,供董事会审阅
Tool: SN-Query-Table
Parameters:
table_name: sn_grc_risk
query: active=true^risk_score>=70^ORDERBYcategory
limit: 50
生成的摘要:
- 活跃风险总数: 156
- 风险分布: Critical:12 | High:34 | Medium:72 | Low:38
- 平均固有风险: 62/100 | 平均剩余风险:38/100
- 控制有效性: 控制措施平均降低风险 39%
- 超出风险偏好: 18 项风险超过组织风险偏好(阈值:50)
- 首要类别: 信息安全(42 项风险,占 27%)
- 趋势: 风险数量较上一季度增加 8%;平均剩余风险下降 4%
- 关键建议: 5 项采用“Accept”处置的风险超出风险偏好——重新评估接受决定
示例 2:风险委员会热力图报告
场景: 风险委员会要求查看风险态势图
热力图输出(右上角 = 最高关注度):
Impact → 1 2 3 4 5
Likelihood
5 [ 0] [ 2] [ 5] [ 8] [ 3] ← Highest concern row
4 [ 1] [ 4] [12] [15] [ 6]
3 [ 3] [ 8] [18] [10] [ 4]
2 [ 5] [12] [ 9] [ 6] [ 2]
1 [ 8] [ 7] [ 5] [ 2] [ 1]
- 红色区域(L>=4,I>=4): 32 项风险需要管理层立即关注
- 琥珀色区域(Score>=12): 47 项风险正在积极缓解
- 绿色区域(Score<6): 21 项风险处于可接受容忍范围内
相关技能
grc/issue-action-plan- 为已演变为问题的风险制定行动计划grc/issue-summarization- 总结风险评估中产生的问题grc/control-objective-management- 管理用于缓解已评估风险的控制措施grc/regulatory-alert-analysis- 评估影响风险态势的监管变化security/audit-compliance- 审计支持风险缓解的控制措施