diff --git a/docs/internals/requirements/requirements.rst b/docs/internals/requirements/requirements.rst index 382cb8f03..bc35248df 100644 --- a/docs/internals/requirements/requirements.rst +++ b/docs/internals/requirements/requirements.rst @@ -136,9 +136,9 @@ This section provides an overview of current process requirements and their clar :parent_covered: NO: Can not cover 'ISO/IEC/IEEE/29148' :version: 1 :implemented: YES - :satisfies: gd_req__req_attr_description, gd_req__req_check_mandatory, + :satisfies: gd_req__req_attr_description, gd_req__req_check_mandatory, gd_req__sec_argument - Docs-as-Code shall enforce that each need of type :need:`tool_req__docs_req_types` has a description (content) + Enforce that each need of type :need:`tool_req__docs_req_types` has a description (content) .. tool_req:: Enforces description wording rules @@ -1156,15 +1156,82 @@ Testing Docs-As-Code shall enforce that every Safety Analysis has a short description of the failure effect (e.g. failure lead to an unintended actuation of the analysed element) ----------------------------------------------------------------- -Safety Analysis (DFA + FMEA) Process to Tool Requirement Mapping ----------------------------------------------------------------- -.. needtable:: - :style: table - :types: gd_req - :columns: id;satisfies_back as "tool_req" - :filter: "gd_req__saf" in id +πŸ”’ Security Analysis +##################### + + +.. tool_req:: Security Analysis Need Types + :id: tool_req__docs_sec_types + :implemented: YES + :tags: Security Analysis + :version: 1 + :satisfies: + gd_req__sec_attr_uid, + gd_req__sec_attr_title, + :parent_covered: YES + + Docs-As-Code shall support the following need types: + + * Feature Security Analysis Threat (STRIDE) -> ``feat_sec_threat`` + * Component Security Analysis Threat (STRIDE) -> ``comp_sec_threat`` + * Platform Security Analysis Threat (STRIDE) -> ``plat_sec_threat`` + * Feature Security Analysis (Threat Scenario) -> ``feat_sec_ana`` + * Component Security Analysis (Threat Scenario) -> ``comp_sec_ana`` + * Platform Security Analysis (Threat Scenario) -> ``plat_sec_ana`` + + +.. tool_req:: Security Analysis: STRIDE Threat ID Attribute + :id: tool_req__docs_sec_attr_stride_threat_id + :implemented: YES + :tags: Security Analysis + :version: 1 + :satisfies: gd_req__sec_attr_stride_threat_id + :parent_covered: YES + + Docs-As-Code shall enforce that STRIDE threat needs + (``feat_sec_threat``, ``comp_sec_threat``, ``plat_sec_threat``) + have a mandatory ``threat_id`` attribute. + + +.. tool_req:: Security Analysis Threat Scenario Mandatory Attributes + :id: tool_req__docs_sec_attrs_mandatory + :implemented: YES + :tags: Security Analysis + :version: 1 + :satisfies: + gd_req__sec_attr_threat_scenario_id, + gd_req__sec_attr_status, + gd_req__sec_attr_sufficient, + gd_req__sec_attr_teffect, + :parent_covered: YES + + Enforce that threat scenario needs + (``feat_sec_ana``, ``comp_sec_ana``, ``plat_sec_ana``) + have the following mandatory attributes: + + * ``threat_scenario_id`` + * ``status``: ``valid`` or ``invalid`` + * ``sufficient``: ``yes`` or ``no`` + * ``threat_effect``: short description of the threat impact + + +.. tool_req:: Security Analysis Optional Attributes + :id: tool_req__docs_sec_attrs_optional + :implemented: YES + :tags: Security Analysis + :version: 1 + :satisfies: + gd_req__sec_attr_mitigation_issue, + gd_req__sec_attr_aou, + :parent_covered: YES + + Allow threat scenario needs + (``feat_sec_ana``, ``comp_sec_ana``, ``plat_sec_ana``) + to have the following optional attributes and links: + + * ``mitigation_issue``: link to a GitHub issue + * ``mitigated_by``: link to ``aou_req`` πŸ—ΊοΈ Full Mapping diff --git a/src/extensions/score_metamodel/__init__.py b/src/extensions/score_metamodel/__init__.py index 7f26c9b83..594fdcf04 100644 --- a/src/extensions/score_metamodel/__init__.py +++ b/src/extensions/score_metamodel/__init__.py @@ -327,6 +327,15 @@ def setup(app: Sphinx) -> dict[str, str | bool]: app.config.needs_types += metamodel.needs_types app.config.needs_links.update(metamodel.needs_links) app.config.needs_fields.update(metamodel.needs_fields) + app.config.needs_string_links.setdefault( + "mitigation_issue_linker", + { + "regex": r"(?Phttps://github\.com/[^/]+/(?P[^/]+)/issues/(?P\d+))", + "link_url": "{{url}}", + "link_name": "{{repo}}#{{number}}", + "options": ["mitigation_issue"], + }, + ) app.config.graph_checks = metamodel.needs_graph_check app.config.prohibited_words_checks = metamodel.prohibited_words_checks diff --git a/src/extensions/score_metamodel/metamodel.yaml b/src/extensions/score_metamodel/metamodel.yaml index 7d82bde3b..21785ab92 100644 --- a/src/extensions/score_metamodel/metamodel.yaml +++ b/src/extensions/score_metamodel/metamodel.yaml @@ -127,6 +127,7 @@ needs_types: gd_req: title: Process Requirements mandatory_options: + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ optional_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -289,6 +290,7 @@ needs_types: safety: ^(QM|ASIL_B)$ # req-Id: tool_req__docs_common_attr_status status: ^(valid|invalid)$ + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ mandatory_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -325,6 +327,7 @@ needs_types: safety: ^(QM|ASIL_B)$ # req-Id: tool_req__docs_common_attr_status status: ^(valid|invalid)$ + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ mandatory_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -350,6 +353,7 @@ needs_types: tool_req: title: Tool Requirement mandatory_options: + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ optional_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -385,6 +389,7 @@ needs_types: safety: ^(QM|ASIL_B)$ # req-Id: tool_req__docs_common_attr_status status: ^(valid|invalid)$ + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ optional_options: codelink: ^.*$ @@ -738,11 +743,12 @@ needs_types: failure_effect: ^.*$ sufficient: ^(yes|no)$ status: ^(valid|invalid)$ + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ mandatory_links: violates: feat_arc_sta optional_options: - mitigation_issue: ^https://github.com/.*$ + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ optional_links: mitigated_by: stkh_req, aou_req parts: 3 @@ -758,13 +764,14 @@ needs_types: sufficient: ^(yes|no)$ status: ^(valid|invalid)$ # req-Id: tool_req__docs_saf_attrs_content + # req-Id: tool_req__docs_common_attr_description content: ^[\s\S]+$ mandatory_links: # req-Id: tool_req__docs_saf_attrs_violates violates: feat_arc_sta optional_options: # req-Id: tool_req__docs_saf_attrs_mitigation_issue - mitigation_issue: ^https://github.com/.*$ + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ optional_links: # req-Id: tool_req__docs_saf_attrs_mitigated_by # (only mandatory once valid status == valid) @@ -788,7 +795,7 @@ needs_types: content: ^[\s\S]+$ optional_options: # req-Id: tool_req__docs_saf_attrs_mitigation_issue - mitigation_issue: ^https://github.com/.*$ + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ mandatory_links: # req-Id: tool_req__docs_saf_attrs_violates violates: comp_arc_sta @@ -816,7 +823,7 @@ needs_types: content: ^[\s\S]+$ optional_options: # req-Id: tool_req__docs_saf_attrs_mitigation_issue - mitigation_issue: ^https://github.com/.*$ + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ mandatory_links: # req-Id: tool_req__docs_saf_attrs_violates violates: feat_arc_dyn, feat_arc_sta @@ -843,7 +850,7 @@ needs_types: content: ^[\s\S]+$ optional_options: # req-Id: tool_req__docs_saf_attrs_mitigation_issue - mitigation_issue: ^https://github.com/.*$ + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ mandatory_links: # req-Id: tool_req__docs_saf_attrs_violates violates: comp_arc_dyn, comp_arc_sta @@ -854,6 +861,109 @@ needs_types: - safety_analysis parts: 3 + # Security Analysis + # req-Id: tool_req__docs_sec_types + feat_sec_threat: + title: Feature Security Analysis Threat (STRIDE) + mandatory_options: + # req-Id: tool_req__docs_sec_attr_stride_threat_id + threat_id: ^(AU_01_0[1-3]|AZ_01_0[1-3]|CT_01_0[1-2]|DS_01_0[1-3]|EX_01_0[1-6]|LA_01_0[1-3]|MT_01_0[1-7])$ + status: ^(valid|invalid)$ + content: ^[\s\S]+$ + tags: + - stride_threat + - security_analysis + parts: 3 + + # req-Id: tool_req__docs_sec_types + comp_sec_threat: + title: Component Security Analysis Threat (STRIDE) + mandatory_options: + # req-Id: tool_req__docs_sec_attr_stride_threat_id + threat_id: ^(AU_01_0[1-3]|AZ_01_0[1-3]|CT_01_0[1-2]|DS_01_0[1-3]|EX_01_0[1-6]|LA_01_0[1-3]|MT_01_0[1-7])$ + status: ^(valid|invalid)$ + content: ^[\s\S]+$ + tags: + - stride_threat + - security_analysis + parts: 3 + + # req-Id: tool_req__docs_sec_types + plat_sec_threat: + title: Platform Security Analysis Threat (STRIDE) + mandatory_options: + # req-Id: tool_req__docs_sec_attr_stride_threat_id + threat_id: ^(AU_01_0[1-3]|AZ_01_0[1-3]|CT_01_0[1-2]|DS_01_0[1-3]|EX_01_0[1-6]|LA_01_0[1-3]|MT_01_0[1-7])$ + status: ^(valid|invalid)$ + content: ^[\s\S]+$ + tags: + - stride_threat + - security_analysis + parts: 3 + + # req-Id: tool_req__docs_sec_types + feat_sec_ana: + title: Feature Security Analysis (Threat Scenario) + mandatory_options: + # req-Id: tool_req__docs_sec_attrs_mandatory + threat_scenario_id: ^(AS_01_(01|02|04|05|06|07|09|10)|CO_01_0[1-7]|SC_01_0[2-5]|SI_01_0[2-5]|UI_01_(0[1-9]|1[0-2]))$ + # req-Id: tool_req__docs_sec_attrs_mandatory + status: ^(valid|invalid)$ + # req-Id: tool_req__docs_sec_attrs_mandatory + sufficient: ^(yes|no)$ + # req-Id: tool_req__docs_sec_attrs_mandatory + threat_effect: ^.+$ + # req-Id: tool_req__docs_common_attr_description + content: ^[\s\S]+$ + optional_options: + # req-Id: tool_req__docs_sec_attrs_optional + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ + optional_links: + # req-Id: tool_req__docs_sec_attrs_optional + mitigated_by: feat_req, aou_req + tags: + - threat_scenario + - security_analysis + parts: 3 + + # req-Id: tool_req__docs_sec_types + comp_sec_ana: + title: Component Security Analysis (Threat Scenario) + mandatory_options: + threat_scenario_id: ^(AS_01_(01|02|04|05|06|07|09|10)|CO_01_0[1-7]|SC_01_0[2-5]|SI_01_0[2-5]|UI_01_(0[1-9]|1[0-2]))$ + status: ^(valid|invalid)$ + sufficient: ^(yes|no)$ + threat_effect: ^.+$ + # req-Id: tool_req__docs_common_attr_description + content: ^[\s\S]+$ + optional_options: + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ + optional_links: + mitigated_by: comp_req, aou_req + tags: + - threat_scenario + - security_analysis + parts: 3 + + # req-Id: tool_req__docs_sec_types + plat_sec_ana: + title: Platform Security Analysis (Threat Scenario) + mandatory_options: + threat_scenario_id: ^(AS_01_(01|02|04|05|06|07|09|10)|CO_01_0[1-7]|SC_01_0[2-5]|SI_01_0[2-5]|UI_01_(0[1-9]|1[0-2]))$ + status: ^(valid|invalid)$ + sufficient: ^(yes|no)$ + threat_effect: ^.+$ + # req-Id: tool_req__docs_common_attr_description + content: ^[\s\S]+$ + optional_options: + mitigation_issue: ^https://github\.com/[^/]+/[^/]+/issues/\d+$ + optional_links: + mitigated_by: feat_req, aou_req + tags: + - threat_scenario + - security_analysis + parts: 3 + testcase: title: Testcase Needs parsed from test.xml files optional_options: diff --git a/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst b/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst index 014e1e25d..ca1357192 100644 --- a/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst +++ b/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst @@ -535,3 +535,130 @@ Expect no errors related to "violates" field. We need to be generic for expect-n .. feat_req:: milestone must be a version :id: feat_req__random_id4 :valid_until: 2035-03 + + +.. Security Analysis: feat_sec_threat + +#EXPECT: feat_sec_threat__test__bad_1: is missing required attribute: `threat_id`. + +.. feat_sec_threat:: Missing threat_id + :id: feat_sec_threat__test__bad_1 + :status: valid + + Some content. + + +#EXPECT: feat_sec_threat__test__bad_2.status (done): does not follow pattern `^(valid|invalid)$`. + +.. feat_sec_threat:: Invalid status + :id: feat_sec_threat__test__bad_2 + :threat_id: MT_01_03 + :status: done + + Some content. + + +#EXPECT-NOT: feat_sec_threat__test__ok_3 + +.. feat_sec_threat:: Valid threat + :id: feat_sec_threat__test__ok_3 + :threat_id: MT_01_03 + :status: valid + + message timing is manipulated (Tampering) + + +.. Security Analysis: feat_sec_ana + +#EXPECT: feat_sec_ana__test__bad_4: is missing required attribute: `threat_scenario_id`. + +.. feat_sec_ana:: Missing threat_scenario_id + :id: feat_sec_ana__test__bad_4 + :status: invalid + :sufficient: no + :threat_effect: Unauthorized access to stored data. + + Argument why mitigation is insufficient. + + +#EXPECT: feat_sec_ana__test__bad_5.sufficient (maybe): does not follow pattern `^(yes|no)$`. + +.. feat_sec_ana:: Invalid sufficient value + :id: feat_sec_ana__test__bad_5 + :threat_scenario_id: SC_01_02 + :status: valid + :sufficient: maybe + :threat_effect: Unauthorized access to stored data. + + Argument why mitigation is insufficient. + + +#EXPECT: feat_sec_ana__test__bad_6.status (done): does not follow pattern `^(valid|invalid)$`. + +.. feat_sec_ana:: Invalid status value + :id: feat_sec_ana__test__bad_6 + :threat_scenario_id: SC_01_02 + :status: done + :sufficient: no + :threat_effect: Unauthorized access to stored data. + + Argument why mitigation is insufficient. + + +#EXPECT: feat_sec_ana__test__bad_7: is missing required attribute: `threat_effect`. + +.. feat_sec_ana:: Missing threat_effect + :id: feat_sec_ana__test__bad_7 + :threat_scenario_id: SC_01_02 + :status: invalid + :sufficient: no + + Argument why mitigation is insufficient. + + +#EXPECT-NOT: feat_sec_ana__test__ok_8 + +.. feat_sec_ana:: Valid threat scenario + :id: feat_sec_ana__test__ok_8 + :threat_scenario_id: SC_01_02 + :status: valid + :sufficient: yes + :threat_effect: Unauthorized access to stored data. + + Mitigation is sufficient because access controls are in place. + + +#EXPECT-NOT: feat_sec_ana__test__ok_9 + +.. feat_sec_ana:: Valid threat scenario with optional mitigation_issue + :id: feat_sec_ana__test__ok_9 + :threat_scenario_id: SC_01_03 + :status: invalid + :sufficient: no + :threat_effect: Data integrity violation via tampering. + :mitigation_issue: https://github.com/eclipse-score/score/issues/1 + + Mitigation not yet implemented. + + +#EXPECT: feat_sec_ana__test__bad_10.mitigation_issue (https://github.com/eclipse-score/docs-as-code/pull/508): does not follow pattern + +.. feat_sec_ana:: Invalid mitigation_issue (pull request, not issue) + :id: feat_sec_ana__test__bad_10 + :threat_scenario_id: SC_01_04 + :status: invalid + :sufficient: no + :threat_effect: Unauthorized data access. + :mitigation_issue: https://github.com/eclipse-score/docs-as-code/pull/508 + + Mitigation not yet implemented. + + +#EXPECT: feat_sec_ana__test__bad_11: is missing required attribute: `content`. + +.. feat_sec_ana:: Missing argument content + :id: feat_sec_ana__test__bad_11 + :threat_scenario_id: SC_01_04 + :status: invalid + :sufficient: no + :threat_effect: Unauthorized data access.