============ Coding Style ============ To contribute code to the project, you must diligently follow the style rules describe in this chapter. Having a clean and structured code is very important for our development lifecycle, and not compliant code will most likely be rejected. Essentially CAPE's code style is based on `PEP 8 - Style Guide for Python Code `_ and `PEP 257 -- Docstring Conventions `_. Formatting ========== Copyright header ---------------- All source code files must start with the following copyright header:: # Copyright (C) 2010-2015 X. # This file is part of CAPE Sandbox - https://capesandbox.com # See the file 'docs/LICENSE' for copying permission. Indentation ----------- The code must have a 4-spaces-tabs indentation. Since Python enforces the indentation, make sure to configure your editor properly or your code might cause malfunctioning. Maximum Line Length ------------------- Limit all lines to a maximum of 132 characters. Blank Lines ----------- Separate the class definition and the top-level function with one blank line. Methods definitions inside a class are separated by a single blank line:: class MyClass: """Doing something.""" def __init__(self): """Initialize""" pass def do_it(self, what): """Do it. @param what: do what. """ pass Use blank lines in functions, sparingly, to isolate logic sections. Import blocks are separated by a single blank line, import blocks are separated from classes by one blank line. Imports ------- Imports must be on separate lines. If you're importing multiple objects from a package, use a single line:: from lib import a, b, c **NOT**:: from lib import a from lib import b from lib import c Always specify explicitly the objects to import:: from lib import a, b, c **NOT**:: from lib import * Strings ------- Strings must be delimited by double quotes ("). Printing and Logging -------------------- We discourage the use of ``print()``: if you need to log an event please use Python's ``logging`` which is already initialized by CAPE. In your module add:: import logging log = logging.getLogger(__name__) And use the ``log`` handle, for more details refer to the Python documentation. In case you need to print a string to standard output, use the ``print()`` function:: print("foo") **NOT** the statement:: print "foo" Checking for keys in data structures ------------------------------------ When checking for a key in a data structure, use the clause "in" for example:: if "bar" in foo: do_something(foo["bar"]) Exceptions ========== Custom exceptions must be defined in the *lib/cuckoo/common/exceptions.py* file or the local module if the exception should not be global. The following is the current CAPE exceptions chain:: .-- CuckooCriticalError | |-- CuckooStartupError | |-- CuckooDatabaseError | |-- CuckooMachineError | `-- CuckooDependencyError |-- CuckooOperationalError | |-- CuckooAnalysisError | |-- CuckooProcessingError | `-- CuckooReportError `-- CuckooGuestError Beware that the use of ``CuckooCriticalError`` and its child exceptions will cause CAPE to terminate. Naming ------ Custom exception names must start with "Cuckoo" and end with "Error" if it represents an unexpected malfunction. Exception handling ------------------ When catching an exception and accessing its handle, use ``as e``:: try: foo() except Exception as e: bar() **NOT**:: try: foo() except Exception, something: bar() It's a good practice to use "e" instead of "e.message". Documentation ============= All code must be documented in docstring format, see `PEP 257 -- Docstring Conventions `_. Additional comments may be added in logical blocks to make the code easier to understand. Automated testing ================= We believe in automated testing to provide high-quality code and avoid dumb bugs. When possible, all code must be committed with proper unit tests. Particular attention must be placed when fixing bugs: it's good practice to write unit tests to reproduce the bug. All unit tests and fixtures are placed in the tests folder in the CAPE root. We adopted `pytest `_ as the unit testing framework. Github actions ============== Automated tests run as `github actions `_ ; see the ``.github`` directory. You may wish to run github actions locally. A tool that may help is `Nektos act `_. One of the installation options for ``act`` is as a plugin for the `github CLI, `_ and the actions are then triggered by ``gh act``. As input for ``act`` it's often helpful to create a simulated github event, and save it as an input file. Example:: { "act": true, "repository" : { "default_branch": "master" } } So to run the actions that normally are triggered by a push event:: gh act -s GITHUB_TOKEN="$(gh auth token)" --eventpath /tmp/github-event.json and to run the actions that are scheduled:: gh act schedule -s GITHUB_TOKEN="$(gh auth token)" --eventpath /tmp/github-event.json We created a file ``.actrc`` containing ``--env CAPE_AS_ROOT=1`` because ``act`` runs the tests as root, and otherwise the tests would exit saying you cannot run CAPE as root. Poetry and pre-commit hooks =========================== After cloning the git repository, the first commands that you should do:: poetry install poetry run pre-commit install This will install the pre-commit hooks, ensuring that all files have to conform to black and isort.