Skip to content

Commit

Permalink
implement scoring and basic tests
Browse files Browse the repository at this point in the history
  • Loading branch information
john681611 committed Aug 24, 2023
1 parent f16a8d8 commit be06e31
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ export const BrowseRootCres = () => {
<LoadingAndErrorIndicator loading={loading} error={error} />
{!loading && !error && (
<div className="ui grid">
<div className="wide column">
{display && <SearchResults results={display} />}
</div>
<div className="wide column">{display && <SearchResults results={display} />}</div>
</div>
)}
</div>
Expand Down
122 changes: 62 additions & 60 deletions application/frontend/src/pages/GapAnalysis/GapAnalysis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ export const GapAnalysis = () => {
}, [BaseStandard, CompareStandard, setGapAnalysis]);

const handleAccordionClick = (e, titleProps) => {
const { index } = titleProps
const newIndex = activeIndex === index ? -1 : index
SetActiveIndex(newIndex)
}
const { index } = titleProps;
const newIndex = activeIndex === index ? -1 : index;
SetActiveIndex(newIndex);
};

return (
<div>
Expand Down Expand Up @@ -107,65 +107,67 @@ export const GapAnalysis = () => {
</Table.Cell>
<Table.Cell>
<Accordion>
<Accordion.Title
active={activeIndex === key}
index={key}
onClick={handleAccordionClick}
>
<Icon name='dropdown' />
{gapAnalysis[key].paths.sort((a, b) => a.score - b.score).slice(0, 3).map((path) => {
let segmentID = gapAnalysis[key].start.id;
return (
<>
<Popup
wide="very"
hoverable
content={path.path
.map((segment) => {
const { text, nextID } = GetSegmentText(segment, segmentID);
segmentID = nextID;
return text;
})
.join('')}
trigger={
<span>
{path.end.name} {path.end.sectionID} {path.end.section} {path.end.subsection}{' '}
{path.end.description}{' '}({path.score})
</span>
}
/>
<br />
</>
);
})}
<Accordion.Title active={activeIndex === key} index={key} onClick={handleAccordionClick}>
<Icon name="dropdown" />
{gapAnalysis[key].paths
.sort((a, b) => a.score - b.score)
.slice(0, 3)
.map((path) => {
let segmentID = gapAnalysis[key].start.id;
return (
<>
<Popup
wide="very"
hoverable
content={path.path
.map((segment) => {
const { text, nextID } = GetSegmentText(segment, segmentID);
segmentID = nextID;
return text;
})
.join('')}
trigger={
<span>
{path.end.name} {path.end.sectionID} {path.end.section}{' '}
{path.end.subsection} {path.end.description} ({path.score})
</span>
}
/>
<br />
</>
);
})}
(Total Links: {gapAnalysis[key].paths.length})
</Accordion.Title>
<Accordion.Content active={activeIndex === key}>
{gapAnalysis[key].paths.sort((a, b) => a.score - b.score).slice(2, gapAnalysis[key].paths.length).map((path) => {
let segmentID = gapAnalysis[key].start.id;
return (
<>
<Popup
wide="very"
hoverable
content={path.path
.map((segment) => {
const { text, nextID } = GetSegmentText(segment, segmentID);
segmentID = nextID;
return text;
})
.join('')}
trigger={
<span>
{path.end.name} {path.end.sectionID} {path.end.section} {path.end.subsection}{' '}
{path.end.description}{' '}({path.score})
</span>
}
/>
<br />
</>
);
})}
{gapAnalysis[key].paths
.sort((a, b) => a.score - b.score)
.slice(2, gapAnalysis[key].paths.length)
.map((path) => {
let segmentID = gapAnalysis[key].start.id;
return (
<>
<Popup
wide="very"
hoverable
content={path.path
.map((segment) => {
const { text, nextID } = GetSegmentText(segment, segmentID);
segmentID = nextID;
return text;
})
.join('')}
trigger={
<span>
{path.end.name} {path.end.sectionID} {path.end.section}{' '}
{path.end.subsection} {path.end.description} ({path.score})
</span>
}
/>
<br />
</>
);
})}
</Accordion.Content>
</Accordion>
</Table.Cell>
Expand Down
31 changes: 15 additions & 16 deletions application/frontend/src/pages/Search/components/BodyText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ export const SearchBody = () => {
topics.
</b>
</p>
<h3>Do you have an OWASP account? Try talking to our <a href='/chatbot'>CRE Chatbot</a></h3>
<h3>
Do you have an OWASP account? Try talking to our <a href="/chatbot">CRE Chatbot</a>
</h3>
<h2>HOW?</h2>
<p>
OpenCRE links each section of a resource (like a standard or guideline) to a shared topic, known as a
Common Requirement, causing that section to also link with all other resources that link to the same
topic. This 1) enables users to find all combined information from relevant sources, 2) facilitates
a shared and better understanding of cyber security, and 3) allows standard makers to have links
that keep working and offer all the information that readers need, alleviating their need to cover
topic. This 1) enables users to find all combined information from relevant sources, 2) facilitates a
shared and better understanding of cyber security, and 3) allows standard makers to have links that
keep working and offer all the information that readers need, alleviating their need to cover
everything themselves. OpenCRE maintains itself: links to OpenCRE in the standard text are scanned
automatically. Furthermore, topics are linked with related other topics, creating a semantic web for
security to explore.
Expand All @@ -43,17 +45,17 @@ export const SearchBody = () => {
</p>
<h2>WHO?</h2>
<p>
OpenCRE is the independent brainchild of software security professionals Spyros Gasteratos and Rob
van der Veer, who joined forces to tackle the complexities and segmentation in current security
standards and guidelines. They collaborated closely with many initiatives, including SKF, OpenSSF and the Owasp Top 10
project. OpenCRE is an open-source platform overseen by the OWASP foundation through the
OpenCRE is the independent brainchild of software security professionals Spyros Gasteratos and Rob van
der Veer, who joined forces to tackle the complexities and segmentation in current security standards
and guidelines. They collaborated closely with many initiatives, including SKF, OpenSSF and the Owasp
Top 10 project. OpenCRE is an open-source platform overseen by the OWASP foundation through the
<a href="https://owasp.org/www-project-integration-standards/"> OWASP Integration standard project</a>
. The goal is to foster better coordination among security initiatives.
</p>
<p>
OpenCRE currently links OWASP standards (Top 10, ASVS, Proactive Controls, Cheat sheets, Testing
guide, ZAP, Juice shop, SAMM), plus several other sources (CWE, CAPEC, NIST-800 53, NIST-800 63b, Cloud Control
Matrix, ISO27001, ISO27002, and NIST SSDF).
guide, ZAP, Juice shop, SAMM), plus several other sources (CWE, CAPEC, NIST-800 53, NIST-800 63b,
Cloud Control Matrix, ISO27001, ISO27002, and NIST SSDF).
</p>
<p>
Contact us via (rob.vanderveer [at] owasp.org) to join the movement. Currently, a stakeholder group is
Expand All @@ -65,12 +67,9 @@ export const SearchBody = () => {
<a href="https://github.com/OWASP/www-project-integration-standards/raw/master/writeups/CRE-Explained6.pdf">
{' '}
CRE explanation document{' '}
</a>, follow our
<a href="https://www.linkedin.com/company/96695329">
{' '}
LinkedIn page{' '}
</a>{' '}
or click the diagram below.
</a>
, follow our
<a href="https://www.linkedin.com/company/96695329"> LinkedIn page </a> or click the diagram below.
</p>

<a href="/opencregraphic2.png" target="_blank">
Expand Down
15 changes: 12 additions & 3 deletions application/frontend/src/utils/document.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { DOCUMENT_TYPES, DOCUMENT_TYPE_NAMES, TYPE_IS_PART_OF, TYPE_LINKED_FROM, TYPE_LINKED_TO } from '../const';
import {
DOCUMENT_TYPES,
DOCUMENT_TYPE_NAMES,
TYPE_IS_PART_OF,
TYPE_LINKED_FROM,
TYPE_LINKED_TO,
} from '../const';
import { Document, LinkedDocument } from '../types';

export const getDocumentDisplayName = (document: Document) => {
Expand Down Expand Up @@ -73,10 +79,13 @@ export const getApiEndpoint = (doc: Document, apiUrl: string): string => {
return `${apiUrl}/id/${doc.id}`;
};

export const getDocumentTypeText = (linkType, docType, parentDocType = ""): string => {
export const getDocumentTypeText = (linkType, docType, parentDocType = ''): string => {
let docText = DOCUMENT_TYPE_NAMES[linkType];
if (linkType === TYPE_LINKED_TO && docType === DOCUMENT_TYPES.TYPE_CRE) {
docText = parentDocType === DOCUMENT_TYPES.TYPE_STANDARD ? DOCUMENT_TYPE_NAMES[TYPE_LINKED_FROM] : DOCUMENT_TYPE_NAMES[TYPE_IS_PART_OF];
docText =
parentDocType === DOCUMENT_TYPES.TYPE_STANDARD
? DOCUMENT_TYPE_NAMES[TYPE_LINKED_FROM]
: DOCUMENT_TYPE_NAMES[TYPE_IS_PART_OF];
}
return docText;
};
103 changes: 103 additions & 0 deletions application/tests/gap_analysis_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import unittest

from application.utils.gap_analysis import (
get_path_score,
get_relation_direction,
get_next_id,
PENALTIES
)


class TestGapAnalysis(unittest.TestCase):
def tearDown(self) -> None:
return None

def setUp(self) -> None:
return None

def test_get_relation_direction_UP(self):
step = {"start": {"id": "123"}, "end": {"id": "234"}}
self.assertEqual(get_relation_direction(step, "123"), "UP")

def test_get_relation_direction_DOWN(self):
step = {"start": {"id": "123"}, "end": {"id": "234"}}
self.assertEqual(get_relation_direction(step, "234"), "DOWN")

def test_get_next_id_start(self):
step = {"start": {"id": "123"}, "end": {"id": "234"}}
self.assertEqual(get_next_id(step, "234"), "123")

def test_get_next_id_end(self):
step = {"start": {"id": "123"}, "end": {"id": "234"}}
self.assertEqual(get_next_id(step, "123"), "234")

def test_get_path_score_direct_siblings_zero(self):
path = {
"start": {
"id": "029f7cd7-ef2f-4f25-b0d2-3227cde4b34b",
},
"end": {
"id": "7d030730-14cc-4c43-8927-f2d0f5fbcf5d",
},
"path": [
{
"end": {
"id": "029f7cd7-ef2f-4f25-b0d2-3227cde4b34b",
},
"relationship": "LINKED_TO",
"start": {
"id": "07bc9f6f-5387-4dc6-b277-0022ed76049f",
},
},
{
"end": {
"id": "7d030730-14cc-4c43-8927-f2d0f5fbcf5d",
},
"relationship": "LINKED_TO",
"start": {
"id": "e2ac59b2-c1d8-4525-a6b3-155d480aecc9",
},
},
],
}
self.assertEqual(get_path_score(path), 0)

def test_get_path_score_one_up_zero(self):
path = {
"start": {
"id": "029f7cd7-ef2f-4f25-b0d2-3227cde4b34b",
},
"end": {
"id": "7d030730-14cc-4c43-8927-f2d0f5fbcf5d",
},
"path": [
{
"end": {
"id": "029f7cd7-ef2f-4f25-b0d2-3227cde4b34b",
},
"relationship": "LINKED_TO",
"start": {
"id": "07bc9f6f-5387-4dc6-b277-0022ed76049f",
},
},
{
"end": {
"id": "123",
},
"relationship": "CONTAINS",
"start": {
"id": "07bc9f6f-5387-4dc6-b277-0022ed76049f",
},
},
{
"end": {
"id": "7d030730-14cc-4c43-8927-f2d0f5fbcf5d",
},
"relationship": "LINKED_TO",
"start": {
"id": "123",
},
},
],
}
self.assertEqual(get_path_score(path), PENALTIES['CONTAINS_UP'])
27 changes: 24 additions & 3 deletions application/utils/gap_analysis.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
import random
PENALTIES = {"RELATED": 20, "CONTAINS_UP": 2, "CONTAINS_DOWN": 1, "LINKED_TO": 0}


def get_path_score(path):
return random.randint(10, 100)
def get_path_score(path, start_id):
score = 0
previous_id = start_id
for step in path["path"]:
penalty_type = step["relationship"]

if step["relationship"] == "CONTAINS":
penalty_type = f"CONTAINS_{get_relation_direction(step, previous_id)}"
score += PENALTIES[penalty_type]
previous_id = get_next_id(step, previous_id)
return score


def get_relation_direction(step, previous_id):
if step["start"]["id"] == previous_id:
return "UP"
return "DOWN"


def get_next_id(step, previous_id):
if step["start"]["id"] == previous_id:
return step["end"]["id"]
return step["start"]["id"]
2 changes: 1 addition & 1 deletion application/web/web_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def gap_analysis() -> Any: # TODO (spyros): add export result to spreadsheet
key = path["start"]["id"]
if key not in grouped_paths:
grouped_paths[key] = {"start": path["start"], "paths": []}
path['score'] = get_path_score(path)
path["score"] = get_path_score(path)
del path["start"]
grouped_paths[key]["paths"].append(path)

Expand Down

0 comments on commit be06e31

Please sign in to comment.