Skip to main content

Unit 6

Development team project: Design document

[Download PDF]

Summative assessment reflection

The goal of the assignment was to design a secure application for one of the suggested domains. The system had to support authentication, role-based access, store user data, and include measures against common attack vectors. A key requirement was that security features could be toggled on and off to demonstrate their effectiveness. Besides, it was a team assignment, which also added a coordination component.

The team was assigned by the tutor, but organizing the team cooperation was up to us. Initially, no one took the lead, so I decided to show some initiative and reached out to my teammates. A few responded and joined the Discord server I created for our communication, but others remained silent until I eventually asked the module tutor to contact them directly. That finally helped get the full team on board. Most communication happened asynchronously due to different time zones, but we also managed a couple of group calls, which I found especially helpful. In my experience, synchronous discussions are often more effective for making decisions quickly and avoiding misunderstandings.

Overall, it was great to interact more informally with other students from the course. However, it was frustrating when some members did not participate or respond to messages at all, without any explanation. That said, we still managed to complete the assignment on time, and I’d describe the collaboration as mostly positive — certainly a valuable learning experience.

The most challenging aspect of the system design was deciding on how and what security features could be turned off to make the application vulnerable. This requirement influenced several design decisions: we had to structure the system, so that its weaknesses were exposed when protections were disabled.

One of my key takeaways from this project was about the team dynamics. Waiting for others to take initiative leads to unnecessary delays, so it might be better to step up early, even if it feels uncomfortable. At the same time, it was challenging to find a balance between being proactive and not feeling like I was overstepping, especially when no one in the group held a formal leadership role.

Another important lesson was about pacing and time management in group projects. The actual timeline didn’t match the expectations we had when we were first planning the work, and instead we resorted to an even more flexible approach that we initially expected. I think in future group projects, both I and the other students will know what to expect and how to plan the team work realistically.

Exploring linters to support testing in Python

Assignment

The following questions will be discussed during this week’s seminar. These questions are provided in the 'testing-with-python' zip file with instructions provided in the 'Secure Software Development' PDF file. These activities should be completed on your chosen Jupyter Notebook workspace.

Question 1

Assignment

Run styleLint.py.

What happens when the code is run? Can you modify this code for a more favourable outcome? What amendments have you made to the code?

Original version of styleLint.py

# CODE SOURCE: SOFTWARE ARCHITECTURE WITH PYTHON

def factorial(n):
""" Return factorial of n """
if n == 0:
return 1
else:
return n*factorial(n-1)

An attempt to run this Python code fails; the reason is incorrect code formatting: function body must be properly indented:

Execuition result
  File "/Users/sergei.lebedev/Downloads/testing-with-python/styleLint.py", line 5
""" Return factorial of n """
^
IndentationError: expected an indented block after function definition on line 4

To make this code run, a few changes are required to properly reflect the code structure via indentation:

Corrected version of styleLint.py
# CODE SOURCE: SOFTWARE ARCHITECTURE WITH PYTHON 

def factorial(n):
""" Return factorial of n """
if n == 0:
return 1
else:
return n * factorial(n - 1)

The code now can be successfully executed.

Question 2

Assignment
pip install pylint

Run

 pylint 

on pylintTest.py

Review each of the code errors returned. Can you correct each of the errors identified by pylint?

Before correcting the code errors, save the pylintTest.py file with a new name (it will be needed again in the next question).

Original version of pylintTest.py

# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html

import string

shift = 3
choice = raw_input("would you like to encode or decode?")
word = (raw_input("Please enter text"))
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded=encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]

print encoded

Running the command pylint pylintTest.py yields the following result:

pylintTest.py:26:1: E0001: Parsing failed: 'Missing parentheses in call to 'print'. Did you mean print(...)? (pylintTest, line 26)' (syntax-error)

This indicates issues with the syntax used in the print() function invocation on the line 26:

print encoded

To resolve the issue, the function call must look as follows:

print(encoded)

This change allows pylint to be run and return the following list of issues for the file:

************* Module pylintTest
pylintTest.py:8:0: C0325: Unnecessary parens after '=' keyword (superfluous-parens)
pylintTest.py:12:0: W0311: Bad indentation. Found 2 spaces, expected 4 (bad-indentation)
pylintTest.py:13:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:14:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:15:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:16:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:17:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:18:0: W0311: Bad indentation. Found 4 spaces, expected 8 (bad-indentation)
pylintTest.py:19:0: W0311: Bad indentation. Found 6 spaces, expected 12 (bad-indentation)
pylintTest.py:20:0: W0311: Bad indentation. Found 8 spaces, expected 16 (bad-indentation)
pylintTest.py:21:0: W0311: Bad indentation. Found 12 spaces, expected 20 (bad-indentation)
pylintTest.py:22:0: W0311: Bad indentation. Found 8 spaces, expected 16 (bad-indentation)
pylintTest.py:23:0: W0311: Bad indentation. Found 10 spaces, expected 20 (bad-indentation)
pylintTest.py:24:0: W0311: Bad indentation. Found 10 spaces, expected 20 (bad-indentation)
pylintTest.py:26:0: C0304: Final newline missing (missing-final-newline)
pylintTest.py:1:0: C0114: Missing module docstring (missing-module-docstring)
pylintTest.py:1:0: C0103: Module name "pylintTest" doesn't conform to snake_case naming style (invalid-name)
pylintTest.py:6:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:7:9: E0602: Undefined variable 'raw_input' (undefined-variable)
pylintTest.py:8:8: E0602: Undefined variable 'raw_input' (undefined-variable)
pylintTest.py:9:0: C0103: Constant name "letters" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:10:0: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:14:6: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:16:6: C0103: Constant name "x" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:17:6: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:21:12: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:23:10: C0103: Constant name "x" doesn't conform to UPPER_CASE naming style (invalid-name)
pylintTest.py:24:10: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)

The following changes are required to fix the problems with the file:

  • Rename pylintTest.py into pylint_test.py to comply with snake naming convention for modules;
  • Remove unnecessary parentheses in the word variable definition;
  • Apply proper indentation with four spaces;
  • Insert a trailing empty line;
  • Introduce the main() function to avoid C0101 warnings caused by the variables being declared globally;
  • Add docstring for the module and the main() function;
  • Replace raw_input() from Python 2 with input() from Python 3.

As a result, pylint runs without reporting any problems:

-------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 9.55/10, +0.45)

The script looks as follows after all necessary corrections:

pylint_test.py after following pylint's recommendations
# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html  
"""
Pylint demo
"""

import string


def main():
"""
Main function
"""
shift = 3
choice = input("would you like to encode or decode?")
word = input("Please enter text")
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded = encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]

print(encoded)


if __name__ == "__main__":
main()

Question 3

Assignment
pip install flake8

Run

flake8 

on pylintTest.py

Review the errors returned. In what way does this error message differ from the error message returned by pylint?

Run flake8 on metricTest.py. Can you correct each of the errors returned by flake8? What amendments have you made to the code?

Similarly to the previous question, flake8 fails due to incorrect print() function call:

pylintTest.py:26:2: E999 SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

After this issue is resolved, the following set of problems is reported:

pylintTest.py:7:10: F821 undefined name 'raw_input'
pylintTest.py:8:9: F821 undefined name 'raw_input'
pylintTest.py:12:3: E111 indentation is not a multiple of 4
pylintTest.py:14:7: E111 indentation is not a multiple of 4
pylintTest.py:16:7: E111 indentation is not a multiple of 4
pylintTest.py:17:7: E111 indentation is not a multiple of 4
pylintTest.py:17:14: E225 missing whitespace around operator
pylintTest.py:19:7: E111 indentation is not a multiple of 4
pylintTest.py:23:11: E111 indentation is not a multiple of 4
pylintTest.py:24:11: E111 indentation is not a multiple of 4
pylintTest.py:26:15: W292 no newline at end of file

After these issues are resolved and the file looks as below, flake8 does not report any further problems, indicating that the set of issues that this tool detects is smaller. Besides, pylint appears to be more opinionated in terms of code style.

pylintTest.py after following flake8's recommendations
# SOURCE OF CODE: https://docs.pylint.org/en/1.6.0/tutorial.html  

import string

shift = 3
choice = input("would you like to encode or decode?")
word = (input("Please enter text"))
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) + shift
encoded = encoded + letters[x]
if choice == "decode":
for letter in word:
if letter == ' ':
encoded = encoded + ' '
else:
x = letters.index(letter) - shift
encoded = encoded + letters[x]

print(encoded)

Question 4

Assignment
pip install mccabe

Run

mccabe 

on sums.py. What is the result?

Run

mccabe 

on sums2.py. What is the result?

What are the contributors to the cyclomatic complexity in each piece of code?

Source code for sums.py and the result of mccabe tool execution for the file:

sums.py
# SOURCE OF CODE: https://realpython.com/python-testing/  

def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"


if __name__ == "__main__":
test_sum()
print("Everything passed")
mccabe results for sums.py
3:0: 'test_sum' 1
If 7 2

Source code for sums2.py and the result of mccabe tool execution for the file:

sums2.py
# SOURCE OF CODE: https://realpython.com/python-testing/  

def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"


def test_sum_tuple():
assert sum((1, 2, 2)) == 6, "Should be 6"


if __name__ == "__main__":
test_sum()
test_sum_tuple()
print("Everything passed")
mccabe results for sums2.py
3:0: 'test_sum' 1
7:0: 'test_sum_tuple' 1
If 11 2

Both files have a pretty similar structure and similar scores. All declared functions have a linear execution path, therefore they have a score of one. The if blocks in each of the files are also included in the report. As if conditions offer branching, they introduce a McCabe complexity of two.