11import sys
2-
32import click
43
4+ from secomlint .message import Message
5+ from secomlint .config import Config
6+ from secomlint .ruler import Ruler
7+ from secomlint .section import Body
8+
9+
10+ def compliance_score (ruler , warnings ):
11+ no_rules = len (ruler .rules )
12+ rules_not_in_compliance = sum (
13+ [warning .result for warning in warnings ])
14+ return ((no_rules - rules_not_in_compliance ) / no_rules ) * 100
15+
16+
17+ def get_symbol (result , wtype , sep = " " ):
18+ if result == 0 :
19+ return f"✅{ sep } "
20+ if wtype == 1 :
21+ return f"❌{ sep } "
22+ else :
23+ return f"🟡{ sep } "
24+
25+
26+ def print_summary (ruler , warnings , alerts , problems , print_score = False ):
27+ color = 'green' if alerts == 0 and problems == 0 else 'yellow'
28+ summary = f"\n found { problems } problem(s), { alerts } warning(s);"
29+ if print_score :
30+ score = compliance_score (ruler , warnings )
31+ secom_link = f"[\u001b ]8;;https://tqrg.github.io/secom\u001b \\ SECOM\u001b ]8;;\u001b \\ ]"
32+ click .echo (
33+ click .style (
34+ (summary
35+ + f" 🎯 Commit message is { score :.2f} % in compliance with { secom_link } convention." ),
36+ fg = color ,
37+ bold = True ))
38+ else :
39+ click .echo (
40+ click .style (summary , fg = color , bold = True ))
41+
42+
43+ def print_body_analysis (message ):
44+ body_section = [
45+ section for section in message .sections if type (section ) == Body ]
46+ if len (body_section ) == 1 :
47+ secwords , count = [], 0
48+ for entity in body_section [0 ].entities :
49+ entity_list = list (entity )
50+ if entity_list [1 ] == 'SECWORD' :
51+ secwords .append (entity_list [0 ])
52+ count += 1
53+ if secwords :
54+ click .echo (
55+ """👍 Good to go! Extractor found the following security related words in the message's body:""" )
56+ for word in secwords :
57+ click .echo (click .style (f" - { word } " , fg = "green" ))
58+ else :
59+ click .echo (
60+ """🧐 The message's body is not informative enough. Try improving the message's body by adding more security related words!""" )
61+ else :
62+ click .echo (
63+ """❌ The message's body is missing! Don't forget the what, why and how structure.""" )
64+
65+
566@click .command ()
6- def main ():
7- """Simple program that greets NAME for a total of COUNT times."""
8- commit_msg = [line for line in sys .stdin ]
9- print ('' .join (commit_msg ))
67+ @click .option ("--no-compliance" , is_flag = True , default = False , help = "Show missing compliance." )
68+ @click .option ("--is-body-informative" , is_flag = True , default = False , help = "Checks body for security information." )
69+ @click .option ("--score" , is_flag = True , default = False , help = "Show compliance score." )
70+ @click .option ("--config" , help = "Rule configuration file path name." )
71+ def main (no_compliance , is_body_informative , score , config ):
72+ """Linter to check compliance against SECOM (https://tqrg.github.io/secom/)."""
73+ if not sys .stdin .isatty ():
74+ commit_msg = [line for line in sys .stdin ]
75+ if commit_msg :
76+ message = Message (commit_msg )
77+ message .get_sections ()
78+ if len (message .text ) > 0 :
79+ config_ = Config (path = config )
80+ else :
81+ # TODO: raise error saying it couldn't
82+ # get sections or msg is empty
83+ return
84+
85+ ruler = Ruler (config_ )
86+ warnings = []
87+ for section in message .sections :
88+ warnings += ruler .compliance (section )
89+
90+ alerts , problems = 0 , 0
91+
92+ # TODO: order it by (result == 1, type == 1),
93+ # (result == 1, type == 0), (result == 0)
94+ for warning in warnings :
95+ if warning .result == 1 and warning .type == 1 :
96+ click .echo (get_symbol (warning .result , warning .type )
97+ + warning .message + ' ' +
98+ click .style (warning .link , fg = "blue" ))
99+ problems += 1
100+ for warning in warnings :
101+ if warning .result == 1 and warning .type == 0 :
102+ click .echo (get_symbol (warning .result , warning .type )
103+ + warning .message + ' ' +
104+ click .style (warning .link , fg = "blue" ))
105+ alerts += 1
106+ if not no_compliance :
107+ for warning in warnings :
108+ if warning .result == 0 :
109+ click .echo (get_symbol (warning .result , warning .type )
110+ + warning .message + ' ' +
111+ click .style (warning .link , fg = "blue" ))
112+
113+ print_summary (ruler , warnings , alerts , problems , print_score = score )
114+
115+ if is_body_informative :
116+ print_body_analysis (message )
117+
118+ return
10119
11120
12121if __name__ == '__main__' :
13- main ()
122+ main ()
0 commit comments