Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title": "DecisionPointGroup",
"description": "**DEPRECATED:** `DecisionPointGroup` has been superseded by `DecisionTable`.\nNew development should use `DecisionTable` instead.\nWe are keeping this class around for backward compatibility, but it may be removed in future releases.\n\nModels a group of decision points as a dictionary, keyed by their ID.",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/DecisionPointGroup_2_0_0.schema.json",
"description": "**DEPRECATED:** `DecisionPointGroup` has been superseded by `DecisionTable`.\nNew development should use `DecisionTable` instead.\nWe are keeping this class around for backward compatibility, but it may be removed in future releases.\n\nThis schema defines the structure to represent an SSVC DecisionPointGroup object.",
"type": "object",
"$defs": {
"DecisionPoint": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title": "DecisionPoint",
"description": "Models a single decision point as a list of values.\n\nDecision points should have the following attributes:\n\n- name (str): The name of the decision point\n- description (str): A description of the decision point\n- version (str): A semantic version string for the decision point\n- namespace (str): The namespace (a short, unique string): For example, \"ssvc\" or \"cvss\" to indicate the source of the decision point\n- key (str): A key (a short, unique string within the namespace) that can be used to identify the decision point in a shorthand way\n- values (tuple): A tuple of DecisionPointValue objects",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/DecisionPoint_2_0_0.schema.json",
"description": "This schema defines the structure to represent an SSVC DecisionPoint object.",
"type": "object",
"$defs": {
"DecisionPointValue": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title": "DecisionTable",
"description": "DecisionTable: A flexible, serializable SSVC decision table model.\n\nThis model represents a decision table that can be used to map combinations of decision point values\nto outcomes. It allows for flexible mapping and can be used with helper methods to generate DataFrame and CSV representations\nof the decision table.\n\nAttributes:",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/DecisionTable_2_0_0.schema.json",
"description": "This schema defines the structure to represent an SSVC DecisionTable object.",
"type": "object",
"$defs": {
"DecisionPoint": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"title": "Decision Point Value Selection List",
"title": "SelectionList",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/Decision_Point_Value_Selection-2-0-0.schema.json",
"description": "This schema defines the structure for representing selected values from SSVC Decision Points. Each selection list can have multiple selection objects, each representing a decision point, and each selection object can have multiple selected values when full certainty (i.e., a singular value selection) is not available.",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/SelectionList_2_0_0.schema.json",
"description": "This schema defines the structure to represent an SSVC SelectionList object.",
"type": "object",
"$defs": {
"MinimalDecisionPointValue": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"title": "SsvcObjectRegistry",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://certcc.github.io/SSVC/data/schema/v2/SsvcObjectRegistry_2_0_0.schema.json",
"description": "This schema defines the structure to represent an SSVC SsvcObjectRegistry object.",
"type": "object",
"$defs": {
"DecisionPoint": {
Expand Down
76 changes: 72 additions & 4 deletions src/ssvc/_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This module provides mixin classes for adding features to SSVC objects.
"""

# Copyright (c) 2023-2025 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,
Expand All @@ -22,9 +22,12 @@
# subject to its own license.
# DM24-0278

import os
from datetime import datetime, timezone
from typing import Any, Optional
from typing import Any, ClassVar, Optional
from urllib.parse import urljoin

import semver
from pydantic import (
BaseModel,
ConfigDict,
Expand All @@ -36,8 +39,13 @@

from ssvc.namespaces import NameSpace
from ssvc.registry.events import notify_registration
from ssvc.utils.defaults import DEFAULT_VERSION, SCHEMA_VERSION
from ssvc.utils.defaults import (
DEFAULT_VERSION,
SCHEMA_BASE_URL,
SCHEMA_VERSION,
)
from ssvc.utils.field_specs import NamespaceString, VersionString
from ssvc.utils.misc import filename_friendly, order_schema


class _Versioned(BaseModel):
Expand Down Expand Up @@ -70,6 +78,7 @@ class _SchemaVersioned(BaseModel):
Mixin class for version
"""

_schema_version: ClassVar[str] = SCHEMA_VERSION
schemaVersion: str = Field(
..., description="Schema version of the SSVC object"
)
Expand All @@ -80,9 +89,68 @@ def set_schema_version(cls, data):
Set the schema version to the default if not provided.
"""
if "schemaVersion" not in data:
data["schemaVersion"] = SCHEMA_VERSION
data["schemaVersion"] = cls._schema_version
return data

@classmethod
def model_json_schema(cls, **kwargs):
"""
Overrides schema generation to ensure it's the way we want it
"""
schema = super().model_json_schema(**kwargs)

schema["$schema"] = "https://json-schema.org/draft/2020-12/schema"
schema["$id"] = cls.schema_url()
schema["description"] = (
f"This schema defines the structure to represent an SSVC {cls.__name__} object."
)

return order_schema(schema)

@classmethod
def schema_version_relpath(cls):
"""
Return the schema version relative path for the object.
"""
ver = semver.Version.parse(cls._schema_version)
verpath = f"v{ver.major}/"

return verpath

@classmethod
def schema_filename(cls):
"""
Return the schema filename for the object.
"""
ver = semver.Version.parse(cls._schema_version)

# construct the filename
filename_base = f"{cls.__name__}-{str(ver)}"
filename_base = filename_friendly(filename_base, to_lower=False)
ext = ".schema.json"
filename = f"{filename_base}{ext}"
return filename

@classmethod
def schema_relpath(cls):
"""
Return the schema relative path for the object.
"""
verpath = cls.schema_version_relpath()
filename = cls.schema_filename()

relpath = os.path.join(verpath, filename)
return relpath

@classmethod
def schema_url(cls) -> str:
"""
Return the schema URL for the object.
"""
base_url = SCHEMA_BASE_URL
id_url = urljoin(base_url, cls.schema_relpath())
return id_url


class _Namespaced(BaseModel):
"""
Expand Down
5 changes: 3 additions & 2 deletions src/ssvc/decision_points/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# DM24-0278

import logging
from typing import Literal
from typing import ClassVar, Literal

from pydantic import BaseModel, ConfigDict, model_validator

Expand Down Expand Up @@ -78,7 +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, ...]
model_config = ConfigDict(revalidate_instances="always")
Expand Down Expand Up @@ -156,6 +156,7 @@ 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"
Expand Down
15 changes: 1 addition & 14 deletions src/ssvc/decision_tables/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class DecisionTable(
"""

key_prefix: ClassVar[str] = "DT"

_schema_version: ClassVar[str] = SCHEMA_VERSION
schemaVersion: Literal[SCHEMA_VERSION]

decision_points: DecisionPointDict
Expand Down Expand Up @@ -121,19 +121,6 @@ def validate_key(cls, value: str) -> str:
key = f"{cls.key_prefix}_{value}"
return key

# validator to set schemaVersion
@model_validator(mode="before")
def set_schema_version(cls, data):
"""
Set the schema version to 2.0.0 if it is not already set.
This ensures that the model is always compatible with the latest schema version.
"""
# we don't set this as a default because we want to ensure that the schema
# version is required in the JSON schema
if "schemaVersion" not in data:
data["schemaVersion"] = SCHEMA_VERSION
return data

@model_validator(mode="after")
def populate_mapping_if_empty(self):
"""
Expand Down
Loading