From cfacee91b260f2a45c54b4fec9aea6bf08f1d3f4 Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 10:09:42 -0400 Subject: [PATCH 1/7] refactor outcome documentation and group imports for clarity --- docs/reference/code/outcomes.md | 16 ++++++++-- src/ssvc/outcomes/__init__.py | 18 +++++++---- src/ssvc/outcomes/base.py | 32 -------------------- src/ssvc/outcomes/basic/__init__.py | 2 ++ src/ssvc/outcomes/cisa/__init__.py | 32 ++++++++++++-------- src/ssvc/outcomes/cvss/__init__.py | 32 ++++++++++++-------- src/ssvc/outcomes/groups.py | 0 src/ssvc/outcomes/ssvc/__init__.py | 2 ++ src/ssvc/outcomes/x_com_yahooinc/__init__.py | 2 ++ src/ssvc/policy_generator.py | 2 +- src/test/decision_tables/test_base.py | 5 +-- src/test/outcomes/test_outcomes.py | 3 +- 12 files changed, 77 insertions(+), 69 deletions(-) delete mode 100644 src/ssvc/outcomes/base.py delete mode 100644 src/ssvc/outcomes/groups.py diff --git a/docs/reference/code/outcomes.md b/docs/reference/code/outcomes.md index f1a2d15c..7b1bf447 100644 --- a/docs/reference/code/outcomes.md +++ b/docs/reference/code/outcomes.md @@ -1,5 +1,15 @@ -# Outcome Values and Outcome Groups +# Outcome Decision Points -::: ssvc.outcomes.base +::: ssvc.outcomes -::: ssvc.outcomes.groups +## DecisionPoints often used as Outcomes + +Following is a list of DecisionPoints often used as Outcomes in SSVC. + +```python exec="true" idprefix="" +from ssvc.outcomes import ALL +from ssvc.doc_helpers import example_block + +for dp in ALL: + print(example_block(dp)) +``` \ No newline at end of file diff --git a/src/ssvc/outcomes/__init__.py b/src/ssvc/outcomes/__init__.py index 499a1243..cf1e83db 100644 --- a/src/ssvc/outcomes/__init__.py +++ b/src/ssvc/outcomes/__init__.py @@ -17,14 +17,20 @@ # subject to its own license. # DM24-0278 """ -Provides SSVC outcome group objects. +This module provides SSVC outcome group objects. -SSVC outcome groups are functionally equivalent to Decision Points. -The only difference is that Outcome Groups are primarily intended to be used -as the outputs of a decision, whereas Decision Points are the inputs to a decision. +SSVC outcome groups are Decision Point objects. +The only distinction is that Outcome Groups are usually intended to be used +as the *outputs* of a decision, whereas most other Decision Points are intended to serve as *inputs* to a decision. However, there are use cases where an outcome of one decision may feed into another decision, so the distinction is somewhat arbitrary. Hence, we chose to use the same data structure for both. - -Outcome groups are organized by namespace. """ + +from .basic import ALL as BASIC_ALL +from .cisa import ALL as CISA_ALL +from .ssvc import ALL as SSVC_ALL +from .x_com_yahooinc import ALL as X_COM_YAHOOINC_ALL + +# put SSVC and CISA first since these are the most commonly used +ALL = SSVC_ALL + CISA_ALL + BASIC_ALL + X_COM_YAHOOINC_ALL \ No newline at end of file diff --git a/src/ssvc/outcomes/base.py b/src/ssvc/outcomes/base.py deleted file mode 100644 index 82c9da08..00000000 --- a/src/ssvc/outcomes/base.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2023-2025 Carnegie Mellon University. -# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE -# ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. -# CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, -# EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT -# NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR -# MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE -# OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE -# ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM -# PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. -# Licensed under a MIT (SEI)-style license, please see LICENSE or contact -# permission@sei.cmu.edu for full terms. -# [DISTRIBUTION STATEMENT A] This material has been approved for -# public release and unlimited distribution. Please see Copyright notice -# for non-US Government use and distribution. -# This Software includes and/or makes use of Third-Party Software each -# subject to its own license. -# DM24-0278 -""" -Provides outcome group and outcome value classes for SSVC. -""" - -from ssvc.decision_points.base import DecisionPoint, DecisionPointValue -from ssvc.decision_points.cisa.base import CisaDecisionPoint -from ssvc.decision_points.cvss.base import CvssDecisionPoint -from ssvc.decision_points.ssvc.base import SsvcDecisionPoint - -OutcomeValue = DecisionPointValue -OutcomeGroup = DecisionPoint -SsvcOutcomeGroup = SsvcDecisionPoint -CvssOutcomeGroup = CvssDecisionPoint -CisaOutcomeGroup = CisaDecisionPoint diff --git a/src/ssvc/outcomes/basic/__init__.py b/src/ssvc/outcomes/basic/__init__.py index 1444ae29..c9ab5321 100644 --- a/src/ssvc/outcomes/basic/__init__.py +++ b/src/ssvc/outcomes/basic/__init__.py @@ -25,3 +25,5 @@ from .mscw import LATEST as MSCW from .value_complexity import LATEST as VALUE_COMPLEXITY from .yn import LATEST as YES_NO + +ALL = (EISENHOWER, LMH, MSCW, VALUE_COMPLEXITY, YES_NO) \ No newline at end of file diff --git a/src/ssvc/outcomes/cisa/__init__.py b/src/ssvc/outcomes/cisa/__init__.py index ae8acaa4..2d91bedf 100644 --- a/src/ssvc/outcomes/cisa/__init__.py +++ b/src/ssvc/outcomes/cisa/__init__.py @@ -1,16 +1,24 @@ -# Copyright (c) 2025 Carnegie Mellon University and Contributors. -# - see Contributors.md for a full list of Contributors -# - see ContributionInstructions.md for information on how you can Contribute to this project -# Stakeholder Specific Vulnerability Categorization (SSVC) is -# licensed under a MIT (SEI)-style license, please see LICENSE.md distributed -# with this Software or contact permission@sei.cmu.edu for full terms. -# Created, in part, with funding and support from the United States Government -# (see Acknowledgments file). This program may include and/or can make use of -# certain third party source code, object code, documentation and other files -# (“Third Party Software”). See LICENSE.md for more details. -# Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the -# U.S. Patent and Trademark Office by Carnegie Mellon University +# Copyright (c) 2025 Carnegie Mellon University. +# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE +# ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. +# CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT +# NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR +# MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE +# OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE +# ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM +# PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +# Licensed under a MIT (SEI)-style license, please see LICENSE or contact +# permission@sei.cmu.edu for full terms. +# [DISTRIBUTION STATEMENT A] This material has been approved for +# public release and unlimited distribution. Please see Copyright notice +# for non-US Government use and distribution. +# This Software includes and/or makes use of Third-Party Software each +# subject to its own license. +# DM24-0278 """ Provides SSVC outcome groups for the cisa namespace """ from .scoring import LATEST as CISA_SCORING + +ALL = (CISA_SCORING,) \ No newline at end of file diff --git a/src/ssvc/outcomes/cvss/__init__.py b/src/ssvc/outcomes/cvss/__init__.py index 6f4e34fc..b3aa6634 100644 --- a/src/ssvc/outcomes/cvss/__init__.py +++ b/src/ssvc/outcomes/cvss/__init__.py @@ -1,16 +1,24 @@ -# Copyright (c) 2025 Carnegie Mellon University and Contributors. -# - see Contributors.md for a full list of Contributors -# - see ContributionInstructions.md for information on how you can Contribute to this project -# Stakeholder Specific Vulnerability Categorization (SSVC) is -# licensed under a MIT (SEI)-style license, please see LICENSE.md distributed -# with this Software or contact permission@sei.cmu.edu for full terms. -# Created, in part, with funding and support from the United States Government -# (see Acknowledgments file). This program may include and/or can make use of -# certain third party source code, object code, documentation and other files -# (“Third Party Software”). See LICENSE.md for more details. -# Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the -# U.S. Patent and Trademark Office by Carnegie Mellon University +# Copyright (c) 2025 Carnegie Mellon University. +# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE +# ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. +# CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT +# NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR +# MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE +# OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE +# ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM +# PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. +# Licensed under a MIT (SEI)-style license, please see LICENSE or contact +# permission@sei.cmu.edu for full terms. +# [DISTRIBUTION STATEMENT A] This material has been approved for +# public release and unlimited distribution. Please see Copyright notice +# for non-US Government use and distribution. +# This Software includes and/or makes use of Third-Party Software each +# subject to its own license. +# DM24-0278 """ Provides outcome group objects in the cvss namespace """ from .lmhc import LATEST as LMHC + +ALL = (LMHC,) \ No newline at end of file diff --git a/src/ssvc/outcomes/groups.py b/src/ssvc/outcomes/groups.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/ssvc/outcomes/ssvc/__init__.py b/src/ssvc/outcomes/ssvc/__init__.py index 55937544..13d6e40e 100644 --- a/src/ssvc/outcomes/ssvc/__init__.py +++ b/src/ssvc/outcomes/ssvc/__init__.py @@ -23,3 +23,5 @@ from .coordinate import LATEST as COORDINATE from .dsoi import LATEST as DSOI from .publish import LATEST as PUBLISH + +ALL = (COORDINATE, DSOI, PUBLISH) \ No newline at end of file diff --git a/src/ssvc/outcomes/x_com_yahooinc/__init__.py b/src/ssvc/outcomes/x_com_yahooinc/__init__.py index 6dfa27be..99f544b7 100644 --- a/src/ssvc/outcomes/x_com_yahooinc/__init__.py +++ b/src/ssvc/outcomes/x_com_yahooinc/__init__.py @@ -21,3 +21,5 @@ """ from .paranoids import LATEST as THE_PARANOIDS + +ALL = (THE_PARANOIDS,) \ No newline at end of file diff --git a/src/ssvc/policy_generator.py b/src/ssvc/policy_generator.py index 7f4dba3e..ae8eb7f6 100644 --- a/src/ssvc/policy_generator.py +++ b/src/ssvc/policy_generator.py @@ -30,8 +30,8 @@ import pandas as pd from ssvc import csv_analyzer +from ssvc.decision_points.base import DecisionPoint as OutcomeGroup from ssvc.dp_groups.base import DecisionPointGroup -from ssvc.outcomes.base import OutcomeGroup logger = logging.getLogger(__name__) diff --git a/src/test/decision_tables/test_base.py b/src/test/decision_tables/test_base.py index e494a9cc..7b204f61 100644 --- a/src/test/decision_tables/test_base.py +++ b/src/test/decision_tables/test_base.py @@ -24,6 +24,7 @@ import pandas as pd +from ssvc.decision_points.base import DecisionPoint from ssvc.decision_points.base import DecisionPointValue from ssvc.decision_tables.base import ( DecisionTable, @@ -32,8 +33,8 @@ decision_table_to_longform_df, dpdict_to_combination_list, ) -from ssvc.dp_groups.base import DecisionPoint -from ssvc.outcomes.base import OutcomeGroup + +OutcomeGroup = DecisionPoint class TestDecisionTableBase(unittest.TestCase): diff --git a/src/test/outcomes/test_outcomes.py b/src/test/outcomes/test_outcomes.py index 79b8545e..4d2392b8 100644 --- a/src/test/outcomes/test_outcomes.py +++ b/src/test/outcomes/test_outcomes.py @@ -19,7 +19,8 @@ import unittest -from ssvc.outcomes.base import OutcomeGroup, OutcomeValue +from ssvc.decision_points.base import DecisionPoint as OutcomeGroup +from ssvc.decision_points.base import DecisionPointValue as OutcomeValue ALPHABET = "abcdefghijklmnopqrstuvwxyz" From c98abd0d06b68b57b8789ab7bfec68e07d6cc9ff Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 10:42:24 -0400 Subject: [PATCH 2/7] refactor outcome docs into decision point docs folder since they're the same thing --- docs/reference/code/index.md | 6 +++++- docs/reference/code/outcomes.md | 15 --------------- docs/reference/decision_points/outcomes.md | 19 +++++++++++++++++++ docs/topics/decision_points_as_bricks.md | 4 ++-- mkdocs.yml | 2 +- 5 files changed, 27 insertions(+), 19 deletions(-) delete mode 100644 docs/reference/code/outcomes.md create mode 100644 docs/reference/decision_points/outcomes.md diff --git a/docs/reference/code/index.md b/docs/reference/code/index.md index a3498ba0..eb82311c 100644 --- a/docs/reference/code/index.md +++ b/docs/reference/code/index.md @@ -1,10 +1,14 @@ # SSVC Code Documentation This section provides documentation for the SSVC Python modules. + These include: -- [Decision Points](decision_points.md) and [Outcomes](outcomes.md) +- [Decision Points](decision_points.md) - [Decision Tables](decision_tables.md) +- [Decision Point Groups](decision_point_groups.md) (Deprecated) +- [Namespaces](namespaces.md) +- [Selections](selection.md) - [CSV Analyzer](analyze_csv.md) - [Policy Generator](policy_generator.md) - [Namespaces](namespaces.md) diff --git a/docs/reference/code/outcomes.md b/docs/reference/code/outcomes.md deleted file mode 100644 index 7b1bf447..00000000 --- a/docs/reference/code/outcomes.md +++ /dev/null @@ -1,15 +0,0 @@ -# Outcome Decision Points - -::: ssvc.outcomes - -## DecisionPoints often used as Outcomes - -Following is a list of DecisionPoints often used as Outcomes in SSVC. - -```python exec="true" idprefix="" -from ssvc.outcomes import ALL -from ssvc.doc_helpers import example_block - -for dp in ALL: - print(example_block(dp)) -``` \ No newline at end of file diff --git a/docs/reference/decision_points/outcomes.md b/docs/reference/decision_points/outcomes.md new file mode 100644 index 00000000..5a5eb759 --- /dev/null +++ b/docs/reference/decision_points/outcomes.md @@ -0,0 +1,19 @@ +# Outcome Decision Points + +SSVC outcomes are just Decision Point objects. +The only distinction is that these Decision Points are usually intended to be used +as the *outputs* of a decision, whereas most other Decision Points are intended to serve as *inputs* to a decision. +However, there are use cases (e.g., [compound decision points](compound_decision_points.md)) +where an outcome of one decision may feed into another decision, so the +distinction between *input* and *output* is somewhat arbitrary. Hence, we chose to use the same +data structure for both. + +Following is a list of Decision Points often used as outcomes in SSVC decision models. + +```python exec="true" idprefix="" +from ssvc.outcomes import ALL +from ssvc.doc_helpers import example_block + +for dp in ALL: + print(example_block(dp)) +``` \ No newline at end of file diff --git a/docs/topics/decision_points_as_bricks.md b/docs/topics/decision_points_as_bricks.md index 2b7cd890..bfe6ba3f 100644 --- a/docs/topics/decision_points_as_bricks.md +++ b/docs/topics/decision_points_as_bricks.md @@ -2,7 +2,7 @@ As we have continued to refine our concept of SSVC, we have an increasing understanding of the importance of [*Decision Points*](../reference/decision_points/index.md) as the foundational blocks from which the rest of the -SSVC concept is built. A second, but less foundational, concept are the [*Outcomes*](../reference/code/outcomes.md) that +SSVC concept is built. A second, but less foundational, concept are the [*Outcomes*](../reference/decision_points/outcomes.md) that provide a vocabulary to describe the results of a decision. ## Decision Points and Outcomes as Bricks @@ -77,7 +77,7 @@ to decide how much of that flexibility to use. ## SSVC Decision Models as Kits Similarly, SSVC provides a set of "bricks" in the form of [decision points](../reference/decision_points/index.md) -and [outcomes](../reference/code/outcomes.md). +and [outcomes](../reference/decision_points/outcomes.md). We have provided a set of [example decision models](../howto/index.md) and [decision tables](../howto/index.md) to get you started. You might choose to simply use what we've provided as a starting point. Or you might already recognize that our example gets the structure of the decision model right, diff --git a/mkdocs.yml b/mkdocs.yml index 3fa4a8ab..cc6be163 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -119,12 +119,12 @@ nav: - Report Confidence: 'reference/decision_points/cvss/report_confidence.md' - Scope: 'reference/decision_points/cvss/scope.md' - Target Distribution: 'reference/decision_points/cvss/target_distribution.md' + - Outcomes: 'reference/decision_points/outcomes.md' - Code: - Intro: 'reference/code/index.md' - Decision Points: 'reference/code/decision_points.md' - Decision Tables: 'reference/code/decision_tables.md' - Decision Point Groups: 'reference/code/decision_point_groups.md' - - Outcomes: 'reference/code/outcomes.md' - Namespaces: 'reference/code/namespaces.md' - Selections: 'reference/code/selection.md' - CSV Analyzer: 'reference/code/analyze_csv.md' From b829b3a288b7ede816801e4a4d8a6a541e9ae935 Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 12:38:51 -0400 Subject: [PATCH 3/7] rearrange the old "Learning SSVC" page back into the "overview" section --- docs/index.md | 4 +- docs/tutorials/other_resources.md | 39 +++++++++++++++++++ docs/{ => tutorials}/ssvc_overview.md | 22 +++++------ .../{index.md => starting_points.md} | 31 ++------------- mkdocs.yml | 8 ++-- 5 files changed, 60 insertions(+), 44 deletions(-) create mode 100644 docs/tutorials/other_resources.md rename docs/{ => tutorials}/ssvc_overview.md (86%) rename docs/tutorials/{index.md => starting_points.md} (51%) diff --git a/docs/index.md b/docs/index.md index 9b54bac7..496a1125 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,14 +10,14 @@ We have organized the SSVC documentation into four main sections:
-- :fontawesome-regular-eye:{ .lg .middle } [**SSVC Overview**](ssvc_overview.md) +- :fontawesome-regular-eye:{ .lg .middle } [**SSVC Overview**](tutorials/ssvc_overview.md) --- A beginner's guide to SSVC. This section is for people who have never heard of SSVC. - [:octicons-arrow-right-24: An Overview of SSVC](ssvc_overview.md) + [:octicons-arrow-right-24: An Overview of SSVC](tutorials/ssvc_overview.md) - :material-clipboard-check:{ .lg .middle } [**SSVC How To**](howto/index.md) diff --git a/docs/tutorials/other_resources.md b/docs/tutorials/other_resources.md new file mode 100644 index 00000000..e660144b --- /dev/null +++ b/docs/tutorials/other_resources.md @@ -0,0 +1,39 @@ +# Other Resources + +Below are links to other resources that provide additional information about SSVC. + +!!! tip "SSVC Sightings" + + We keep a running list of articles and other SSVC sightings in a [GitHub Discussion](https://github.com/CERTCC/SSVC/discussions/291) + + +## Videos + +Provided below are videos that provide an overview of SSVC and the implementation of decision models. + +| Source | Video | +| ------ |----------------------------------------------------------------------------------------------------------------------------------| +| SEI Podcast Series | [A Stakeholder-Specific Approach to Vulnerability Management](https://youtu.be/wbUTizBaXA0) | +| CISA | [SSVC On-Demand Training](https://youtu.be/NqiwyUPLy6I) | +| Nucleus Security | [SSVC and Decision Trees](https://youtu.be/BKVvmAaCnSs) | +| Nucleus Security | Panel Discussion: [Using Decision Trees for Vulnerability Prioritization with SSVC](https://youtu.be/25RHdcSwHCg) | +| Nucleus Security | [What is SSVC?](https://youtu.be/LV6PclEQ3QA) | +| ICS Cybersecurity Academy | [Create your own SSVC decision tree for ICS patching](https://youtu.be/MLkA2N3aXK4) | +| ICS Cybersecurity Academy | [SSVC: A great replacement for CVSS in ICS?](https://youtu.be/1T36ieOqzNw) | +| Waterfall Security Solutions | Industrial Security Podcast Eps. 102: [Stakeholder-Specific Vulnerability Categorization (SSVC)](https://youtu.be/n5tVYjGxFj0) | + +## Other Content + +We've collected a list of articles and blog posts that provide additional information about SSVC. + +| Source | Link | +|- -------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| SEI | [Prioritizing Vulnerability Response with a Stakeholder-Specific Vulnerability Categorization](https://insights.sei.cmu.edu/blog/prioritizing-vulnerability-response-with-a-stakeholder-specific-vulnerability-categorization/) | +| CISA | [Stakeholder-Specific Vulnerability Categorization (SSVC)](https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc) | +| Qualys | [Effective Vulnerability Management with Stakeholder Specific Vulnerability Categorization (SSVC) and Qualys TruRisk](https://blog.qualys.com/product-tech/2022/11/30/effective-vulnerability-management-with-ssvc-and-qualys-trurisk) | +| Vulcan Cyber | [The SSVC risk prioritization method: what it is, when to use it, and alternatives](https://vulcan.io/blog/the-ssvc-risk-prioritization-method-what-it-is-when-to-use-it-and-alternatives/) | + + +!!! question "Missing Something?" + + Have a link to something we missed? Let us know in an [issue](https://github.com/CERTCC/SSVC/issues/new). diff --git a/docs/ssvc_overview.md b/docs/tutorials/ssvc_overview.md similarity index 86% rename from docs/ssvc_overview.md rename to docs/tutorials/ssvc_overview.md index f95a49b9..81f49c89 100644 --- a/docs/ssvc_overview.md +++ b/docs/tutorials/ssvc_overview.md @@ -212,15 +212,15 @@ The below decision points are modeled on [CERT/CC Coordinated Vulnerability Dis The first two questions help the CERT/CC determine if our help is required. -- [Report Public](reference/decision_points/report_public.md): If a report is already public, then CERT/CC will decline the case unless there are multiple suppliers, [*super effective*](reference/decision_points/system_exposure.md) [Utility](reference/decision_points/utility.md), and [*significant*](reference/decision_points/public_safety_impact.md) [Public Safety Impact](reference/decision_points/public_safety_impact.md). -- [Supplier Contacted](reference/decision_points/supplier_contacted.md): If no suppliers have been contacted, then CERT/CC will decline the case unless there are multiple suppliers, [*super effective*](reference/decision_points/system_exposure.md) [Utility](reference/decision_points/utility.md), and [*significant*](reference/decision_points/public_safety_impact.md) [Public Safety Impact](reference/decision_points/public_safety_impact.md). +- [Report Public](../reference/decision_points/report_public.md): If a report is already public, then CERT/CC will decline the case unless there are multiple suppliers, [*super effective*](../reference/decision_points/system_exposure.md) [Utility](../reference/decision_points/utility.md), and [*significant*](../reference/decision_points/public_safety_impact.md) [Public Safety Impact](../reference/decision_points/public_safety_impact.md). +- [Supplier Contacted](../reference/decision_points/supplier_contacted.md): If no suppliers have been contacted, then CERT/CC will decline the case unless there are multiple suppliers, [*super effective*](../reference/decision_points/system_exposure.md) [Utility](../reference/decision_points/utility.md), and [*significant*](../reference/decision_points/public_safety_impact.md) [Public Safety Impact](../reference/decision_points/public_safety_impact.md). In this case, CERT/CC may encourage the reporter to contact the supplier and submit a new case request if the supplier is unresponsive. -- [Report Credibility](reference/decision_points/report_credibility.md): If the report is not credible, then CERT/CC will decline the case. +- [Report Credibility](../reference/decision_points/report_credibility.md): If the report is not credible, then CERT/CC will decline the case. Please see the [CERT® Guide to Coordinated Vulnerability Disclosure](https://certcc.github.io/CERT-Guide-to-CVD/howto/coordination/_report_credibility) for more information about assessing credibility. -- [Supplier Cardinality](reference/decision_points/supplier_cardinality.md): Cases involving multiple suppliers can get complicated very quickly, so we are more likely to get involved in those cases. -- [Supplier Engagement](reference/decision_points/supplier_engagement.md): If the suppliers are already engaged in a case, there is usually less for a coordinator to do, making it less likely that we will coordinate a case. -- [Utility](reference/decision_points/utility.md): If the vulnerability has high utility, then CERT/CC is more likely to coordinate the case. -- [Public Safety Impact](reference/decision_points/public_safety_impact.md): If the vulnerability has significant +- [Supplier Cardinality](../reference/decision_points/supplier_cardinality.md): Cases involving multiple suppliers can get complicated very quickly, so we are more likely to get involved in those cases. +- [Supplier Engagement](../reference/decision_points/supplier_engagement.md): If the suppliers are already engaged in a case, there is usually less for a coordinator to do, making it less likely that we will coordinate a case. +- [Utility](../reference/decision_points/utility.md): If the vulnerability has high utility, then CERT/CC is more likely to coordinate the case. +- [Public Safety Impact](../reference/decision_points/public_safety_impact.md): If the vulnerability has significant public safety impact, then CERT/CC is more likely to coordinate the case. The last two questions, *Utility* and *Public Safety Impact*, are the same as asked in the Supplier decision model. @@ -233,16 +233,16 @@ height = "600" /> At the CERT/CC, a decision to publish is determined after criteria for Publication are met. SSVC adds value by codifying publication criteria so that the decision is explainable. Publishing a vulnerability should add public value, and a Coordinator must decide why they should publish instead of or in addition to the Supplier. Again, the below decision points are modeled on the [CERT/CC Coordinated Vulnerability Disclosure (CVD) project](../howto/coordination_triage_decision/#coordinator-triage-units-of-work), but we encourage Coordinators to define their own rationales for publication based on their missions. -The publication decision reuses the [*Exploitation*](reference/decision_points/exploitation.md) decision point and adds two new ones ([*Supplier Involvement*](reference/decision_points/supplier_involvement.md) and [*Public Value Added*](reference/decision_points/public_value_added.md)). +The publication decision reuses the [*Exploitation*](../reference/decision_points/exploitation.md) decision point and adds two new ones ([*Supplier Involvement*](../reference/decision_points/supplier_involvement.md) and [*Public Value Added*](../reference/decision_points/public_value_added.md)). !!! tip inline end *Exploitation* was first described in this document under the *Supplier* model, and the definition is the same regardless of the stakeholder. -- [Supplier Involvement](reference/decision_points/supplier_involvement.md) - If the supplier is involved and likely to publish already, there is less need for the CERT/CC to publish. -- [Exploitation](reference/decision_points/exploitation.md) - If the vulnerability is being actively exploited, the CERT/CC is more likely to publish. +- [Supplier Involvement](../reference/decision_points/supplier_involvement.md) - If the supplier is involved and likely to publish already, there is less need for the CERT/CC to publish. +- [Exploitation](../reference/decision_points/exploitation.md) - If the vulnerability is being actively exploited, the CERT/CC is more likely to publish. -- [Public Value Added](reference/decision_points/public_value_added.md) - If there is already significant public discussion of the vulnerability, there might not be much for the CERT/CC to add, making us less likely to publish. +- [Public Value Added](../reference/decision_points/public_value_added.md) - If there is already significant public discussion of the vulnerability, there might not be much for the CERT/CC to add, making us less likely to publish. !!! note "What is the difference between *Supplier Engagement* and *Supplier Involvement*?" diff --git a/docs/tutorials/index.md b/docs/tutorials/starting_points.md similarity index 51% rename from docs/tutorials/index.md rename to docs/tutorials/starting_points.md index 0f9d6a0b..d4a67ae3 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/starting_points.md @@ -1,4 +1,4 @@ -# Learning SSVC +# Starting Out with SSVC SSVC stands for Stakeholder-Specific Vulnerability Categorization. It is a methodology for prioritizing vulnerabilities based on the needs of the stakeholders involved in the vulnerability management process. @@ -42,37 +42,12 @@ SSVC can be used in conjunction with other tools and methodologies to help prior CVSS vector can be applied to SSVC decision models. For example, the [Technical Impact](../reference/decision_points/technical_impact.md) decision point in the [Supplier](../howto/supplier_tree.md) decision model can be informed by the CVSS vector. + See the [CVSS v4 Assessment With SSVC](../howto/cvss_v4/index.md) section for more information. !!! example "EPSS and SSVC" The Exploit Prediction Scoring System (EPSS) provides information regarding the likelihood of a vulnerability being exploited in the wild. This information can be used to inform the [Exploitation](../reference/decision_points/exploitation.md) decision point in the [Supplier](../howto/supplier_tree.md), [Deployer](../howto/deployer_tree.md), and [Coordinator Publication](../howto/publication_decision.md) decision models. + See the [EPSS and SSVC](../howto/using_epss/index.md) section for more information. -## Videos - -Provided below are videos that provide an overview of SSVC and the implementation of decision models. - -| Source | Video | -| ------ |----------------------------------------------------------------------------------------------------------------------------------| -| SEI Podcast Series | [A Stakeholder-Specific Approach to Vulnerability Management](https://youtu.be/wbUTizBaXA0) | -| CISA | [SSVC On-Demand Training](https://youtu.be/NqiwyUPLy6I) | -| Nucleus Security | [SSVC and Decision Trees](https://youtu.be/BKVvmAaCnSs) | -| Nucleus Security | Panel Discussion: [Using Decision Trees for Vulnerability Prioritization with SSVC](https://youtu.be/25RHdcSwHCg) | -| Nucleus Security | [What is SSVC?](https://youtu.be/LV6PclEQ3QA) | -| ICS Cybersecurity Academy | [Create your own SSVC decision tree for ICS patching](https://youtu.be/MLkA2N3aXK4) | -| ICS Cybersecurity Academy | [SSVC: A great replacement for CVSS in ICS?](https://youtu.be/1T36ieOqzNw) | -| Waterfall Security Solutions | Industrial Security Podcast Eps. 102: [Stakeholder-Specific Vulnerability Categorization (SSVC)](https://youtu.be/n5tVYjGxFj0) | - -## Other Content - -We've collected a list of articles and blog posts that provide additional information about SSVC. - -| Source | Link | -|- -------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| SEI | [Prioritizing Vulnerability Response with a Stakeholder-Specific Vulnerability Categorization](https://insights.sei.cmu.edu/blog/prioritizing-vulnerability-response-with-a-stakeholder-specific-vulnerability-categorization/) | -| CISA | [Stakeholder-Specific Vulnerability Categorization (SSVC)](https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc) | -| Qualys | [Effective Vulnerability Management with Stakeholder Specific Vulnerability Categorization (SSVC) and Qualys TruRisk](https://blog.qualys.com/product-tech/2022/11/30/effective-vulnerability-management-with-ssvc-and-qualys-trurisk) | -| Vulcan Cyber | [The SSVC risk prioritization method: what it is, when to use it, and alternatives](https://vulcan.io/blog/the-ssvc-risk-prioritization-method-what-it-is-when-to-use-it-and-alternatives/) | - -Have a link to something we missed? Let us know in an [issue](https://github.com/CERTCC/SSVC/issues/new). diff --git a/mkdocs.yml b/mkdocs.yml index cc6be163..6c12703f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,7 +5,11 @@ site_author: 'CERT Coordination Center' nav: - Home: 'https://certcc.github.io/' - SSVC: 'index.md' - - SSVC Overview: 'ssvc_overview.md' + - SSVC Overview: + - 'tutorials/ssvc_overview.md' + - Starting out with SSVC: 'tutorials/starting_points.md' + - Other Resources: 'tutorials/other_resources.md' + - SSVC How-To: - Overview: 'howto/index.md' - Getting Started with SSVC: @@ -130,8 +134,6 @@ nav: - CSV Analyzer: 'reference/code/analyze_csv.md' - Policy Generator: 'reference/code/policy_generator.md' - Doctools: 'reference/code/doctools.md' - - Learning SSVC: - - Tutorials: 'tutorials/index.md' - Calculator: 'ssvc-calc/index.md' - Policy Explorer: 'ssvc-explorer/index.md' - About: From 6400c98b6419a013bba6499ce17e80068f9512bb Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 12:42:09 -0400 Subject: [PATCH 4/7] fix links to pdfs --- docs/tutorials/ssvc_overview.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/ssvc_overview.md b/docs/tutorials/ssvc_overview.md index 81f49c89..430c07f9 100644 --- a/docs/tutorials/ssvc_overview.md +++ b/docs/tutorials/ssvc_overview.md @@ -64,7 +64,7 @@ While we encourage stakeholders to customize SSVC to their needs, in the interes ### Supplier decision points - @@ -137,7 +137,7 @@ print(example_block(LATEST, include_json=False)) ### Deployer decision points - @@ -204,7 +204,7 @@ print(example_block(LATEST, include_json=False)) ### Coordinator decision points for Triage - @@ -227,7 +227,7 @@ The last two questions, *Utility* and *Public Safety Impact*, are the same as as ### Coordinator decision points for Publication - From e924c1b3bcbcf841e43f958582bfbf8441155a38 Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 12:48:24 -0400 Subject: [PATCH 5/7] black formatter --- src/ssvc/decision_points/base.py | 2 +- .../basic/quantiles/__init__.py | 2 +- src/ssvc/decision_tables/base.py | 4 +- src/ssvc/decision_tables/example/__init__.py | 3 +- src/ssvc/decision_tables/example/base.py | 4 +- src/ssvc/decision_tables/helpers.py | 60 ++++++++++++------- src/ssvc/outcomes/__init__.py | 2 +- src/ssvc/outcomes/basic/__init__.py | 2 +- src/ssvc/outcomes/cisa/__init__.py | 2 +- src/ssvc/outcomes/cvss/__init__.py | 2 +- src/ssvc/outcomes/ssvc/__init__.py | 2 +- src/ssvc/outcomes/x_com_yahooinc/__init__.py | 2 +- src/ssvc/utils/misc.py | 2 - src/ssvc/utils/schema.py | 2 +- src/test/api/response_models/__init__.py | 3 +- src/test/test_schema.py | 1 + 16 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/ssvc/decision_points/base.py b/src/ssvc/decision_points/base.py index f9f91629..13dac927 100644 --- a/src/ssvc/decision_points/base.py +++ b/src/ssvc/decision_points/base.py @@ -78,6 +78,7 @@ class DecisionPoint( - key (str): A key (a short, unique string within the namespace) that can be used to identify the decision point in a shorthand way - values (tuple): A tuple of DecisionPointValue objects """ + _schema_version: ClassVar[str] = SCHEMA_VERSION schemaVersion: Literal[SCHEMA_VERSION] values: tuple[DecisionPointValue, ...] @@ -156,7 +157,6 @@ def value_summaries(self) -> list[str]: return list(self.value_dict.keys()) - def main(): print( "Please use doctools.py for schema generation and unit tests for verification" diff --git a/src/ssvc/decision_points/basic/quantiles/__init__.py b/src/ssvc/decision_points/basic/quantiles/__init__.py index 33c37cdc..a72ff825 100644 --- a/src/ssvc/decision_points/basic/quantiles/__init__.py +++ b/src/ssvc/decision_points/basic/quantiles/__init__.py @@ -23,4 +23,4 @@ from .quartiles import LATEST as QUARTILES from .quintiles import LATEST as QUINTILES -DECISION_POINTS = {dp.id: dp for dp in (MEDIAN, QUARTILES, QUINTILES)} \ No newline at end of file +DECISION_POINTS = {dp.id: dp for dp in (MEDIAN, QUARTILES, QUINTILES)} diff --git a/src/ssvc/decision_tables/base.py b/src/ssvc/decision_tables/base.py index 9f547e65..f8e49fea 100644 --- a/src/ssvc/decision_tables/base.py +++ b/src/ssvc/decision_tables/base.py @@ -702,7 +702,9 @@ def check_topological_order(dt: DecisionTable) -> list[dict]: df, target=target, target_value_order=target_value_order ) + def ascii_tree(dt: DecisionTable, df: pd.DataFrame | None = None) -> str: - """ Function moved to helpers.py see there for details """ + """Function moved to helpers.py see there for details""" from . import helpers + return helpers.ascii_tree(dt, df) diff --git a/src/ssvc/decision_tables/example/__init__.py b/src/ssvc/decision_tables/example/__init__.py index 5aca7de6..67090098 100644 --- a/src/ssvc/decision_tables/example/__init__.py +++ b/src/ssvc/decision_tables/example/__init__.py @@ -1,4 +1,3 @@ - # Copyright (c) 2025 Carnegie Mellon University. # NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE # ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. @@ -18,4 +17,4 @@ # subject to its own license. # DM24-0278 -"""Provides example decision tables for SSVC.""" \ No newline at end of file +"""Provides example decision tables for SSVC.""" diff --git a/src/ssvc/decision_tables/example/base.py b/src/ssvc/decision_tables/example/base.py index 60af34a4..85d8ac07 100644 --- a/src/ssvc/decision_tables/example/base.py +++ b/src/ssvc/decision_tables/example/base.py @@ -28,5 +28,5 @@ class ExampleDecisionTable(DecisionTable): - namespace:str = NameSpace.EXAMPLE - registered:bool = False \ No newline at end of file + namespace: str = NameSpace.EXAMPLE + registered: bool = False diff --git a/src/ssvc/decision_tables/helpers.py b/src/ssvc/decision_tables/helpers.py index 76f4639a..aadcfda7 100644 --- a/src/ssvc/decision_tables/helpers.py +++ b/src/ssvc/decision_tables/helpers.py @@ -235,38 +235,39 @@ def dt2df_md( df.index.rename("Row", inplace=True) return df.to_markdown(index=True) -def dt2df_html( - dt: DecisionTable, - longform: bool = True) -> str: + +def dt2df_html(dt: DecisionTable, longform: bool = True) -> str: """ Converts a Decision Tree and represent it in friendly HTML Code Args: decision_table (DecisionTable): The decision table to convert. - longform (bool): Whether to return the longform or shortform DataFram, defaults to true + longform (bool): Whether to return the longform or shortform DataFram, defaults to true Returns: - str: A string representation of the DataFrame in HTML format. + str: A string representation of the DataFrame in HTML format. """ if longform: df = decision_table_to_longform_df(dt) else: df = decision_table_to_shortform_df(dt) - + df = decision_table_to_longform_df(dt) ncols = len(df.columns) nrows = len(df) # Precompute rowspan info for every cell # rowspan[i][j] = number of rows this cell should span; 0 means skip (because merged above) - rowspan = [[1]*ncols for _ in range(nrows)] + rowspan = [[1] * ncols for _ in range(nrows)] for col in range(ncols): r = 0 while r < nrows: start = r - val = df.iat[r, col] #data_rows[r][col] + val = df.iat[r, col] # data_rows[r][col] # Count how many subsequent rows have same value - while r + 1 < nrows and df.iat[r + 1, col] == val:#data_rows[r + 1][col] == val: + while ( + r + 1 < nrows and df.iat[r + 1, col] == val + ): # data_rows[r + 1][col] == val: r += 1 span = r - start + 1 if span > 1: @@ -277,26 +278,32 @@ def dt2df_html( r += 1 # Build HTML - html = [""""""] - html.append("") - html.append(" " + "".join(f"" for h in df.columns) + "") +""" + ] + html.append('
{h}
') + html.append( + " " + "".join(f"" for h in df.columns) + "" + ) - for i, row in df.iterrows(): #for i, row in enumerate(df): + for i, row in df.iterrows(): # for i, row in enumerate(df): cells = [] j = 0 - for _, val in row.items(): #enumerate(row): + for _, val in row.items(): # enumerate(row): tdtype = "decision_point" if j == len(row) - 1: tdtype = "outcome" if rowspan[i][j] > 0: span = rowspan[i][j] if span > 1: - cells.append(f'') + cells.append( + f'' + ) else: cells.append(f'') j = j + 1 @@ -305,7 +312,10 @@ def dt2df_html( html.append("
{h}
{val}{val}{val}
") return "".join(html) -def build_tree(df: pd.DataFrame, columns: pd.Index | list[str]) -> dict[str, dict[str, str] | list[str]] | list[str]: + +def build_tree( + df: pd.DataFrame, columns: pd.Index | list[str] +) -> dict[str, dict[str, str] | list[str]] | list[str]: """ Helper function recursively build a nested dict: {feature_value: subtree_or_list_of_outcomes} @@ -330,7 +340,10 @@ def build_tree(df: pd.DataFrame, columns: pd.Index | list[str]) -> dict[str, dic return tree -def draw_tree(node: dict | list, prefix: str="", lines: list | None = None) -> list: + +def draw_tree( + node: dict | list, prefix: str = "", lines: list | None = None +) -> list: """ Pretty-print nested dict/list as a tree. """ @@ -345,7 +358,9 @@ def draw_tree(node: dict | list, prefix: str="", lines: list | None = None) -> l lines.append(prefix + branch + k + " " * 4) # Calculate the prefix for the next level of the tree. - next_prefix = prefix + (" " * 16 if i == len(items) - 1 else "│" + " " * 15) + next_prefix = prefix + ( + " " * 16 if i == len(items) - 1 else "│" + " " * 15 + ) # Recursively draw the subtree. draw_tree(v, next_prefix, lines) else: # list of outcomes @@ -356,6 +371,7 @@ def draw_tree(node: dict | list, prefix: str="", lines: list | None = None) -> l return lines + def ascii_tree(dt: DecisionTable, df: pd.DataFrame | None = None) -> str: """ Reads a Pandas data frame, builds a decision tree, and returns its ASCII representation. @@ -364,12 +380,12 @@ def ascii_tree(dt: DecisionTable, df: pd.DataFrame | None = None) -> str: if df == None: df = decision_table_to_longform_df(dt) - if 'row' in df.columns: - df.drop(columns='row', inplace=True) + if "row" in df.columns: + df.drop(columns="row", inplace=True) # Separate feature columns from the outcome column. feature_cols = list(df.columns[:-1]) - outcome_col = df.columns[-1] + outcome_col = df.columns[-1] # Build the tree structure. tree = build_tree(df, feature_cols + [outcome_col]) diff --git a/src/ssvc/outcomes/__init__.py b/src/ssvc/outcomes/__init__.py index cf1e83db..072d55a6 100644 --- a/src/ssvc/outcomes/__init__.py +++ b/src/ssvc/outcomes/__init__.py @@ -33,4 +33,4 @@ from .x_com_yahooinc import ALL as X_COM_YAHOOINC_ALL # put SSVC and CISA first since these are the most commonly used -ALL = SSVC_ALL + CISA_ALL + BASIC_ALL + X_COM_YAHOOINC_ALL \ No newline at end of file +ALL = SSVC_ALL + CISA_ALL + BASIC_ALL + X_COM_YAHOOINC_ALL diff --git a/src/ssvc/outcomes/basic/__init__.py b/src/ssvc/outcomes/basic/__init__.py index c9ab5321..6682cf82 100644 --- a/src/ssvc/outcomes/basic/__init__.py +++ b/src/ssvc/outcomes/basic/__init__.py @@ -26,4 +26,4 @@ from .value_complexity import LATEST as VALUE_COMPLEXITY from .yn import LATEST as YES_NO -ALL = (EISENHOWER, LMH, MSCW, VALUE_COMPLEXITY, YES_NO) \ No newline at end of file +ALL = (EISENHOWER, LMH, MSCW, VALUE_COMPLEXITY, YES_NO) diff --git a/src/ssvc/outcomes/cisa/__init__.py b/src/ssvc/outcomes/cisa/__init__.py index 2d91bedf..c358bf53 100644 --- a/src/ssvc/outcomes/cisa/__init__.py +++ b/src/ssvc/outcomes/cisa/__init__.py @@ -21,4 +21,4 @@ """ from .scoring import LATEST as CISA_SCORING -ALL = (CISA_SCORING,) \ No newline at end of file +ALL = (CISA_SCORING,) diff --git a/src/ssvc/outcomes/cvss/__init__.py b/src/ssvc/outcomes/cvss/__init__.py index b3aa6634..95371d45 100644 --- a/src/ssvc/outcomes/cvss/__init__.py +++ b/src/ssvc/outcomes/cvss/__init__.py @@ -21,4 +21,4 @@ """ from .lmhc import LATEST as LMHC -ALL = (LMHC,) \ No newline at end of file +ALL = (LMHC,) diff --git a/src/ssvc/outcomes/ssvc/__init__.py b/src/ssvc/outcomes/ssvc/__init__.py index 13d6e40e..22df73bf 100644 --- a/src/ssvc/outcomes/ssvc/__init__.py +++ b/src/ssvc/outcomes/ssvc/__init__.py @@ -24,4 +24,4 @@ from .dsoi import LATEST as DSOI from .publish import LATEST as PUBLISH -ALL = (COORDINATE, DSOI, PUBLISH) \ No newline at end of file +ALL = (COORDINATE, DSOI, PUBLISH) diff --git a/src/ssvc/outcomes/x_com_yahooinc/__init__.py b/src/ssvc/outcomes/x_com_yahooinc/__init__.py index 99f544b7..1985dd7b 100644 --- a/src/ssvc/outcomes/x_com_yahooinc/__init__.py +++ b/src/ssvc/outcomes/x_com_yahooinc/__init__.py @@ -22,4 +22,4 @@ from .paranoids import LATEST as THE_PARANOIDS -ALL = (THE_PARANOIDS,) \ No newline at end of file +ALL = (THE_PARANOIDS,) diff --git a/src/ssvc/utils/misc.py b/src/ssvc/utils/misc.py index e8b684d8..9cdef197 100644 --- a/src/ssvc/utils/misc.py +++ b/src/ssvc/utils/misc.py @@ -83,5 +83,3 @@ def filename_friendly(name: str, replacement="_", to_lower=True) -> str: name = re.sub(rf"{re.escape(replacement)}+", replacement, name) return name - - diff --git a/src/ssvc/utils/schema.py b/src/ssvc/utils/schema.py index fbfa7c42..175c40d5 100644 --- a/src/ssvc/utils/schema.py +++ b/src/ssvc/utils/schema.py @@ -86,7 +86,7 @@ def strip_nullable_anyof(schema: dict) -> dict: generated by Pydantic that use "anyOf" to represent nullable strings. This functions also preserves the "title" field of each property it modifies if it exists in the parent schema. - + Args: schema: A (possibly nested) dictionary representing a JSON Schema, typically generated by Pydantic BaseModel.model_json_schema(). The function expects diff --git a/src/test/api/response_models/__init__.py b/src/test/api/response_models/__init__.py index f18e5308..49ba3463 100644 --- a/src/test/api/response_models/__init__.py +++ b/src/test/api/response_models/__init__.py @@ -25,9 +25,10 @@ # subject to its own license. # DM24-0278 + def main(): pass -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/test/test_schema.py b/src/test/test_schema.py index 2788e099..d4c94795 100644 --- a/src/test/test_schema.py +++ b/src/test/test_schema.py @@ -27,6 +27,7 @@ from referencing import Registry, Resource import ssvc.decision_points # noqa F401 + # importing these causes the decision points to register themselves from ssvc.dp_groups.ssvc.collections import SSVCv1, SSVCv2, SSVCv2_1 # noqa from ssvc.registry import get_registry From 31af4af15f690967d0422502ce5623ef800fae62 Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 12:49:57 -0400 Subject: [PATCH 6/7] markdownlint --fix --- data/schema/v2/README.md | 6 +++--- docs/adr/0013-ssvc-project-versions.md | 3 +++ docs/howto/tools/containers.md | 1 - docs/howto/using_epss/epss_percentiles.md | 1 - docs/reference/code/decision_point_groups.md | 4 ++-- docs/reference/code/decision_points.md | 2 +- docs/reference/code/decision_tables.md | 2 +- docs/reference/code/index.md | 2 +- docs/reference/code/namespaces.md | 11 ++--------- docs/reference/decision_points/human_impact.md | 1 - docs/reference/decision_points/outcomes.md | 6 +++--- .../decision_points/public_safety_impact.md | 2 -- docs/reference/decision_points/utility.md | 1 - docs/tutorials/other_resources.md | 4 +--- docs/tutorials/starting_points.md | 1 - obsolete/README.md | 2 +- src/README.md | 16 +++++++++------- 17 files changed, 27 insertions(+), 38 deletions(-) diff --git a/data/schema/v2/README.md b/data/schema/v2/README.md index ef92a659..bdb73b27 100644 --- a/data/schema/v2/README.md +++ b/data/schema/v2/README.md @@ -4,6 +4,6 @@ We are now automatically generating the schema files for SSVC based on their corresponding Pydantic models. This allows us to keep the schema files in sync -with the code more easily. However, it required us to make some changes to the -file names. So we've left behind some soft links from the original file names -to help ease the transition. \ No newline at end of file +with the code more easily. However, it required us to make some changes to the +file names. So we've left behind some soft links from the original file names +to help ease the transition. diff --git a/docs/adr/0013-ssvc-project-versions.md b/docs/adr/0013-ssvc-project-versions.md index d07efcfc..6b7b5d7c 100644 --- a/docs/adr/0013-ssvc-project-versions.md +++ b/docs/adr/0013-ssvc-project-versions.md @@ -29,6 +29,7 @@ For the overall SSVC project and documentation, we need a scheme that better ref - **Patch** = subsequent updates in the same month or smaller corrections **Significant updates** include: + - Adding or restructuring sections in ways that affect usability - Adding/revising decision points, tables, or other SSVC objects - Adding features that change how SSVC is applied @@ -39,6 +40,7 @@ Months use single digits (`2025.6`) to keep versions concise. ## Rationale CalVer suits SSVC’s character as a living framework: + - Clearly signals recency (date in the version number) - Fits both documentation-focused and object-focused updates - Avoids SemVer debates over what counts as “major” or “minor” @@ -61,6 +63,7 @@ The CalVer scheme will be applied via Git tags and GitHub releases. ## Alternatives Rejected **Continue SemVer for project/docs** + - **Good:** Maintains continuity - **Bad:** Cannot easily express documentation updates independent of object versions diff --git a/docs/howto/tools/containers.md b/docs/howto/tools/containers.md index dc274daf..fff6e750 100644 --- a/docs/howto/tools/containers.md +++ b/docs/howto/tools/containers.md @@ -50,4 +50,3 @@ docker-compose --project-directory=docker up api ``` Then browse to `http://localhost:8001/docs` to access the API documentation. - diff --git a/docs/howto/using_epss/epss_percentiles.md b/docs/howto/using_epss/epss_percentiles.md index 525a35b4..c528921c 100644 --- a/docs/howto/using_epss/epss_percentiles.md +++ b/docs/howto/using_epss/epss_percentiles.md @@ -160,7 +160,6 @@ the prioritization of vulnerabilities based on their EPSS percentiles. This way, even if multiple vulnerabilities fall into the same SSVC category, you can still prioritize them based on their predicted likelihood of exploitation. - ## Conclusion In this how-to, we've demonstrated how to use EPSS percentiles as an amplifier diff --git a/docs/reference/code/decision_point_groups.md b/docs/reference/code/decision_point_groups.md index da805033..3152a200 100644 --- a/docs/reference/code/decision_point_groups.md +++ b/docs/reference/code/decision_point_groups.md @@ -3,7 +3,7 @@ Decision Point groups provide collections of related Decision Points for some specific purpose. -With the introduction of [Decision Tables](decision_tables.md), +With the introduction of [Decision Tables](decision_tables.md), Decision Point groups are less important than they once were, and may be removed in a future release. However, they can still be useful for documentation and @@ -17,4 +17,4 @@ for some programmatic uses. ## CVSS Decision Point Groups -::: ssvc.dp_groups.cvss.collections \ No newline at end of file +::: ssvc.dp_groups.cvss.collections diff --git a/docs/reference/code/decision_points.md b/docs/reference/code/decision_points.md index 914ac5ac..6e23fe5a 100644 --- a/docs/reference/code/decision_points.md +++ b/docs/reference/code/decision_points.md @@ -4,4 +4,4 @@ ::: ssvc.decision_points.base -::: ssvc.decision_points.helpers \ No newline at end of file +::: ssvc.decision_points.helpers diff --git a/docs/reference/code/decision_tables.md b/docs/reference/code/decision_tables.md index 66ab6abb..a7b280b5 100644 --- a/docs/reference/code/decision_tables.md +++ b/docs/reference/code/decision_tables.md @@ -4,4 +4,4 @@ ::: ssvc.decision_tables.base -::: ssvc.decision_tables.helpers \ No newline at end of file +::: ssvc.decision_tables.helpers diff --git a/docs/reference/code/index.md b/docs/reference/code/index.md index eb82311c..1485b64d 100644 --- a/docs/reference/code/index.md +++ b/docs/reference/code/index.md @@ -4,7 +4,7 @@ This section provides documentation for the SSVC Python modules. These include: -- [Decision Points](decision_points.md) +- [Decision Points](decision_points.md) - [Decision Tables](decision_tables.md) - [Decision Point Groups](decision_point_groups.md) (Deprecated) - [Namespaces](namespaces.md) diff --git a/docs/reference/code/namespaces.md b/docs/reference/code/namespaces.md index d0118a76..01ac1d45 100644 --- a/docs/reference/code/namespaces.md +++ b/docs/reference/code/namespaces.md @@ -58,7 +58,7 @@ end ``` !!! warning "Reserved Namespace Strings" - + The SSVC project has _reserved_ the following namespace strings: - `example` and `x_example`are _reserved_ for use in documentation or as @@ -74,7 +74,6 @@ end object using either of these strings will result in an error in the Python implementation of SSVC. - !!! info inline end "Current Registered Namespaces" The SSVC project currently has a set of registered namespaces that are @@ -89,8 +88,6 @@ end print(f"- {ns.value}") ``` - - #### Registered Namespace Registered namespaces are those that are explicitly defined in the SSVC project. @@ -145,7 +142,7 @@ Registered namespaces are intended to be used as follows: context within the same namespace. !!! example "Fragment Usage in Registered Namespaces" - + We use the `nist` namespace for decision points based on NIST standards, and fragments to differentiate between decision points based on different NIST publications, e.g., `nist#800-30` for decision points based on NIST Special Publication 800-30. @@ -196,7 +193,6 @@ we expect that this will rarely lead to conflicts in practice. `x_example.test#test`, and there are no guarantees of global uniqueness for the decision points in the `x_example.test#test` namespace. - !!! info "Documentation and Test Namespaces" Any namespace starting with `x_example` can be used in documentation or as examples, @@ -220,7 +216,6 @@ Extensions are optional and may be used to refine or clarify existing decision p Extensions allow SSVC users to create decision points that are specific to their constituencies or to provide translations of existing decision points. - !!! info "Namespace Extension Semantic Requirements" Extensions must follow the following requirements: @@ -246,7 +241,6 @@ constituencies or to provide translations of existing decision points. as described above instead of an extension. Extensions are not intended to be used to create new decision points. - #### Namespace Extension Structure The first extension segment is reserved for an optional BCP-47 language tag, which may be left empty. @@ -347,7 +341,6 @@ base_ns -->|/| first The structure of the namespace string is intended to show inheritance for variations on SSVC objects. - !!! tip "Extension Order Matters" SSVC namespace extension order carries semantic meaning. diff --git a/docs/reference/decision_points/human_impact.md b/docs/reference/decision_points/human_impact.md index 33eabd78..dfa1acb9 100644 --- a/docs/reference/decision_points/human_impact.md +++ b/docs/reference/decision_points/human_impact.md @@ -51,7 +51,6 @@ from ssvc.decision_tables.helpers import dt2df_md print(dt2df_md(DT)) ``` - [^1]: In pilot implementations of SSVC, we received feedback that organizations tend to think of mission and safety impacts as if they were combined into a single factor: in other words, the priority increases regardless which of the two impact factors was increased. We therefore combine [Safety Impact](safety_impact.md) and diff --git a/docs/reference/decision_points/outcomes.md b/docs/reference/decision_points/outcomes.md index 5a5eb759..7d40f17d 100644 --- a/docs/reference/decision_points/outcomes.md +++ b/docs/reference/decision_points/outcomes.md @@ -3,8 +3,8 @@ SSVC outcomes are just Decision Point objects. The only distinction is that these Decision Points are usually intended to be used as the *outputs* of a decision, whereas most other Decision Points are intended to serve as *inputs* to a decision. -However, there are use cases (e.g., [compound decision points](compound_decision_points.md)) -where an outcome of one decision may feed into another decision, so the +However, there are use cases (e.g., [compound decision points](compound_decision_points.md)) +where an outcome of one decision may feed into another decision, so the distinction between *input* and *output* is somewhat arbitrary. Hence, we chose to use the same data structure for both. @@ -16,4 +16,4 @@ from ssvc.doc_helpers import example_block for dp in ALL: print(example_block(dp)) -``` \ No newline at end of file +``` diff --git a/docs/reference/decision_points/public_safety_impact.md b/docs/reference/decision_points/public_safety_impact.md index 0710afac..32d23e8b 100644 --- a/docs/reference/decision_points/public_safety_impact.md +++ b/docs/reference/decision_points/public_safety_impact.md @@ -9,7 +9,6 @@ print(example_block(LATEST)) {% include-markdown "../../_includes/safety_cvss_ssvc.md" %} - Suppliers necessarily have a rather coarse-grained perspective on the broadly defined [Safety Impact](safety_impact.md) Decision Point. Therefore we simplify the above into a binary categorization: @@ -36,7 +35,6 @@ from ssvc.decision_tables.helpers import dt2df_md print(dt2df_md(DT)) ``` - ## Prior Versions ```python exec="true" idprefix="" diff --git a/docs/reference/decision_points/utility.md b/docs/reference/decision_points/utility.md index a32aa6e4..360ed883 100644 --- a/docs/reference/decision_points/utility.md +++ b/docs/reference/decision_points/utility.md @@ -48,7 +48,6 @@ from ssvc.decision_tables.helpers import dt2df_md print(dt2df_md(DT)) ``` - ## Alternative Utility Outputs Alternative heuristics can plausibly be used as proxies for adversary utility. diff --git a/docs/tutorials/other_resources.md b/docs/tutorials/other_resources.md index e660144b..af8356be 100644 --- a/docs/tutorials/other_resources.md +++ b/docs/tutorials/other_resources.md @@ -3,9 +3,8 @@ Below are links to other resources that provide additional information about SSVC. !!! tip "SSVC Sightings" - - We keep a running list of articles and other SSVC sightings in a [GitHub Discussion](https://github.com/CERTCC/SSVC/discussions/291) + We keep a running list of articles and other SSVC sightings in a [GitHub Discussion](https://github.com/CERTCC/SSVC/discussions/291) ## Videos @@ -33,7 +32,6 @@ We've collected a list of articles and blog posts that provide additional inform | Qualys | [Effective Vulnerability Management with Stakeholder Specific Vulnerability Categorization (SSVC) and Qualys TruRisk](https://blog.qualys.com/product-tech/2022/11/30/effective-vulnerability-management-with-ssvc-and-qualys-trurisk) | | Vulcan Cyber | [The SSVC risk prioritization method: what it is, when to use it, and alternatives](https://vulcan.io/blog/the-ssvc-risk-prioritization-method-what-it-is-when-to-use-it-and-alternatives/) | - !!! question "Missing Something?" Have a link to something we missed? Let us know in an [issue](https://github.com/CERTCC/SSVC/issues/new). diff --git a/docs/tutorials/starting_points.md b/docs/tutorials/starting_points.md index d4a67ae3..2c187555 100644 --- a/docs/tutorials/starting_points.md +++ b/docs/tutorials/starting_points.md @@ -50,4 +50,3 @@ SSVC can be used in conjunction with other tools and methodologies to help prior This information can be used to inform the [Exploitation](../reference/decision_points/exploitation.md) decision point in the [Supplier](../howto/supplier_tree.md), [Deployer](../howto/deployer_tree.md), and [Coordinator Publication](../howto/publication_decision.md) decision models. See the [EPSS and SSVC](../howto/using_epss/index.md) section for more information. - diff --git a/obsolete/README.md b/obsolete/README.md index 460f59b3..f50978ca 100644 --- a/obsolete/README.md +++ b/obsolete/README.md @@ -2,6 +2,6 @@ Items in this directory were once part of the tooling we used to produce older PDF versions of the SSVC documentation. However, now that we're hosting -the site at https://certcc.github.io/SSVC/, we no longer need these tools. +the site at , we no longer need these tools. We're keeping them here for historical reference just in case, but they might be removed in the future. diff --git a/src/README.md b/src/README.md index 2029adf4..0e070feb 100644 --- a/src/README.md +++ b/src/README.md @@ -5,12 +5,14 @@ This is the official Python package for the CERT/CC Stakeholder-Specific Vulnera Installation ------------ + You can install the latest release from PyPI: pip install certcc-ssvc Demo to explore SSVC decision making ----- + After installation, import the package and explore the examples: import ssvc @@ -37,9 +39,9 @@ This demo is a simple decision tree that provides an Outcome based on two condit Imagine the decision tree as a series of questions. To find the outcome (the YesNo column), you start at the first question (Decision Point), which is the root node of the tree: What is the Weather Forecast? -* Step 1: Look at the Weather Forecast column (e.g., rain, overcast, sunny). -* Step 2: Look at the Humidity Value above 40% column (e.g., high, low). -* Step 3: Based on the combination of these two conditions, the YesNo column will give you the Decision as "Yes" to play and "No" to not to play. +- Step 1: Look at the Weather Forecast column (e.g., rain, overcast, sunny). +- Step 2: Look at the Humidity Value above 40% column (e.g., high, low). +- Step 3: Based on the combination of these two conditions, the YesNo column will give you the Decision as "Yes" to play and "No" to not to play. The YesNo column is the Outcome Decision Point, and the other two Decision Points are inputs that will be collected. This decision tree looks like below in ascii form @@ -95,14 +97,14 @@ For usage in vulnerability management scenarios consider the following popular S from ssvc.decision_tables.helpers import ascii_tree print(ascii_tree(CISACoordinate)) - Resources --------- + Source code and full documentation: -https://github.com/CERTCC/SSVC + SSVC Policy Explorer: -https://certcc.github.io/SSVC/ssvc-explorer/ + SSVC Calculator: -https://certcc.github.io/SSVC/ssvc-calc/ + From d4372643b83cf803e05493c35947ef0367eed185 Mon Sep 17 00:00:00 2001 From: "Allen D. Householder" Date: Wed, 17 Sep 2025 13:11:06 -0400 Subject: [PATCH 7/7] fix broken links --- docs/howto/index.md | 2 +- docs/reference/index.md | 2 +- docs/topics/index.md | 2 +- docs/tutorials/ssvc_overview.md | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/howto/index.md b/docs/howto/index.md index 17946887..5e974b34 100644 --- a/docs/howto/index.md +++ b/docs/howto/index.md @@ -7,7 +7,7 @@ - An interest in using SSVC in a vulnerability management process - Basic familiarity with SSVC - If you are unfamiliar with SSVC, we suggest you start with the [Learning SSVC](../tutorials/index.md) section. + If you are unfamiliar with SSVC, we suggest you start with the [SSVC Overview](../tutorials/ssvc_overview.md) section. [Understanding SSVC](../topics/index.md) provides necessary background detail. For technical reference, see [Reference](../reference/index.md). diff --git a/docs/reference/index.md b/docs/reference/index.md index 26a2efc0..d87b8feb 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -4,7 +4,7 @@ This section assumes that you are already familiar with SSVC and want to look up specific details. - If you are new to SSVC, you may want to start with the [Learning SSVC](../tutorials/index.md) section. + If you are new to SSVC, you may want to start with the [Learning SSVC](../tutorials/ssvc_overview.md) section. If you are already familiar with SSVC and want to learn more, you may want to start with either the [Understanding SSVC](../topics/index.md) or [SSVC How To](../howto/index.md) sections. diff --git a/docs/topics/index.md b/docs/topics/index.md index 52a6d9f2..ca9f184e 100644 --- a/docs/topics/index.md +++ b/docs/topics/index.md @@ -7,7 +7,7 @@ - Basic familiarity with SSVC - An interest in learning more about the details of SSVC - If you are unfamiliar with SSVC, we suggest you start with the [Learning SSVC](../tutorials/index.md) section. + If you are unfamiliar with SSVC, we suggest you start with the [SSVC Overview](../tutorials/ssvc_overview.md) section. [SSVC How-To](../howto/index.md) provides practical guidance for implementing SSVC in your organization. For technical reference, see [Reference](../reference/index.md). diff --git a/docs/tutorials/ssvc_overview.md b/docs/tutorials/ssvc_overview.md index 430c07f9..eb734452 100644 --- a/docs/tutorials/ssvc_overview.md +++ b/docs/tutorials/ssvc_overview.md @@ -29,7 +29,7 @@ All three stakeholders, even if within the same organization, will have differen ## How vulnerabilities are categorized in SSVC -SSVC categorizes vulnerabilities by priority based on risk that varies among stakeholders. These categories reflect the timeliness of action to be taken. Suppliers and Deployers have different end-categories than Coordinators because they are making different decisions at different points in their responses. [Decision Trees](../topics/decision_trees/) are used when asking the series of questions to categorize a vulnerability's priority. There will be more information on decision points (tree nodes) in the next section. +SSVC categorizes vulnerabilities by priority based on risk that varies among stakeholders. These categories reflect the timeliness of action to be taken. Suppliers and Deployers have different end-categories than Coordinators because they are making different decisions at different points in their responses. [Decision Trees](../topics/decision_trees.md) are used when asking the series of questions to categorize a vulnerability's priority. There will be more information on decision points (tree nodes) in the next section. ### Prioritization categories for Suppliers and Deployers @@ -44,7 +44,7 @@ Many Suppliers and Deployers will want to resolve *Defer* vulnerabilities in due ### Prioritization categories for Coordinators -Our advice for Coordinators is based on the [CERT/CC Coordinated Vulnerability Disclosure (CVD) project](../howto/coordination_triage_decision/#coordinator-triage-units-of-work). Because we make separate decisions for triage and publication, we provide separate example decision tables, each of which has different prioritizations at the end. These decision tables represent how we apply SSVC to our needs, and other coordinators might make *different* decisions based on different inputs and output scales. The following categories are listed in increasing order of involvement. +Our advice for Coordinators is based on the [CERT/CC Coordinated Vulnerability Disclosure (CVD) project](../howto/coordination_triage_decision.md). Because we make separate decisions for triage and publication, we provide separate example decision tables, each of which has different prioritizations at the end. These decision tables represent how we apply SSVC to our needs, and other coordinators might make *different* decisions based on different inputs and output scales. The following categories are listed in increasing order of involvement. A triage decision table might have: @@ -208,7 +208,7 @@ print(example_block(LATEST, include_json=False)) style="width: 100%;" height = "700" /> -The below decision points are modeled on [CERT/CC Coordinated Vulnerability Disclosure (CVD) practice](../howto/coordination_triage_decision/#coordinator-triage-decision-outcomes), but we encourage Coordinators to define their own criteria for Triage. +The below decision points are modeled on [CERT/CC Coordinated Vulnerability Disclosure (CVD) practice](../howto/coordination_triage_decision.md), but we encourage Coordinators to define their own criteria for Triage. The first two questions help the CERT/CC determine if our help is required. @@ -231,7 +231,7 @@ The last two questions, *Utility* and *Public Safety Impact*, are the same as as style="width: 100%;" height = "600" /> -At the CERT/CC, a decision to publish is determined after criteria for Publication are met. SSVC adds value by codifying publication criteria so that the decision is explainable. Publishing a vulnerability should add public value, and a Coordinator must decide why they should publish instead of or in addition to the Supplier. Again, the below decision points are modeled on the [CERT/CC Coordinated Vulnerability Disclosure (CVD) project](../howto/coordination_triage_decision/#coordinator-triage-units-of-work), but we encourage Coordinators to define their own rationales for publication based on their missions. +At the CERT/CC, a decision to publish is determined after criteria for Publication are met. SSVC adds value by codifying publication criteria so that the decision is explainable. Publishing a vulnerability should add public value, and a Coordinator must decide why they should publish instead of or in addition to the Supplier. Again, the below decision points are modeled on the [CERT/CC Coordinated Vulnerability Disclosure (CVD) project](../howto/coordination_triage_decision.md), but we encourage Coordinators to define their own rationales for publication based on their missions. The publication decision reuses the [*Exploitation*](../reference/decision_points/exploitation.md) decision point and adds two new ones ([*Supplier Involvement*](../reference/decision_points/supplier_involvement.md) and [*Public Value Added*](../reference/decision_points/public_value_added.md)). @@ -259,10 +259,10 @@ Naturally, a stakeholder will have multiple vulnerabilities at any given time, a ### Communicating results -Coordinators will be especially concerned with communicating information about vulnerabilities, but Suppliers will be just as concerned about communicating to Deployers. Because information changes over time, SSVC decisions should always be timestamped and marked with the version of SSVC that was used. We provide a self-contained, machine-readable [JSON schema](../howto/bootstrap/use/). +Coordinators will be especially concerned with communicating information about vulnerabilities, but Suppliers will be just as concerned about communicating to Deployers. Because information changes over time, SSVC decisions should always be timestamped and marked with the version of SSVC that was used. We provide a self-contained, machine-readable [JSON schema](../howto/bootstrap/use.md). ### Further reading -[Reference material](../reference/) +[Reference material](../reference/index.md) -[Guidance for customizing a Decision Tree](../howto/tree_customization) +[Guidance for customizing a Decision Tree](../howto/tree_customization.md)