mcpField
R
risk-assessment-summarization

risk-assessment-summarization

github.com/happy-technologies-llcデータ・データベース4141 回インストール2 日前に更新
リポジトリ

risk-assessment-summarization について

ServiceNow GRC のリスク管理チームやレポート作成者向けのリスク評価要約スキルです。スコア、固有リスクと残余リスク、傾向、イベントデータを集約し、ヒートマップ用データと軽減策を作成します。

主な機能

  1. 01リスクスコアと分類の集約
  2. 02固有リスクと残余リスクの比較
  3. 03可能性・影響ヒートマップデータの生成
  4. 04リスク傾向の時系列分析
  5. 05リスクエクスポージャーに基づく軽減策の提案
  6. 06リスクイベントと統制有効性の関連付け

活用シーン

  1. 01リスク委員会や取締役会向け報告書の作成
  2. 02事業部門間のリスク状況の比較
  3. 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_itemGRC コンテンツ項目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-TableGET /api/now/table/sn_grc_risk
リスク定義のクエリSN-Query-TableGET /api/now/table/sn_risk_definition
リスクイベントのクエリSN-Query-TableGET /api/now/table/sn_risk_event
リスクの検索SN-Natural-Language-SearchN/A
複雑な分析SN-Execute-Background-ScriptPOST /api/now/table/sys_trigger
スキーマの検出SN-Discover-Table-SchemaGET /api/now/table/sys_dictionary

ベストプラクティス

  • 固有リスクと残余リスク: 管理の効果を示すため、固有リスクと残余リスクの両方を必ず提示します
  • リスク許容度の文脈: すべてのスコアを、組織が定めたリスク許容度のしきい値に照らして示します
  • ヒートマップの明確さ: レポート全体で一貫した色分けを使用する、標準化された5×5マトリックスを使用します
  • トレンドの基準値: 有意義なトレンド比較を行うため、四半期ごとに基準値を設定します
  • 対応策の検証: リスク対応策が文書化されているだけでなく、実際に実施されていることを確認します
  • 損失データの統合: 評価の精度を検証するため、実際のリスクイベントデータを取り入れます
  • オーナーの説明責任: 説明責任を明確にするため、すべての概要にリスクオーナーの名前を含めます

トラブルシューティング

リスクスコアがゼロと表示される

症状: すべての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などの代替スコアリングフィールドを確認してください。また、リスク評価が完了していることも確認してください。

発生可能性と影響が入力されていない

症状: 発生可能性/影響の値が空のため、ヒートマップの生成に失敗します
原因: リスクレコードでは、数値スコアではなく定性的な評価(高/中/低)が使用されている可能性があります
解決策: 定性的な値を数値スケールに対応付けます:Critical=5、High=4、Medium=3、Low=2、Very Low=1。フィールド値の定義については、sys_choiceテーブルを確認してください。

リスクイベントテーブルが空である

症状: sn_risk_eventからレコードが返されません
原因: Risk Eventsモジュールが設定されていないか、イベントがカスタムテーブルで追跡されている可能性があります
解決策: 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%低下
  • 主な推奨事項: 「Accept」を対応策とする5件のリスクが許容度を超過しています。受容の判断を再評価してください
例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 - リスク軽減を支えるコントロールを監査します

参考資料

コメント