The Architecture of Teatime

In this document we will get to know the design decisions behind Teatime and introduce the library’s primitives to make development more intuitive. There are five components to Teatime that make up its inner workings:

  • Scanner: A scanner executes one or more plugins on a given target
  • Plugin: Plugins are where the magic happens: They perform the checks and generate issues
  • Context: The context object is passed from one scanner to the next and holds report meta data
  • Report: The report object inside the context is where Plugins add their issues
  • Issue: This basic building block holds data about findings such as title, severity, and much more

Scanner

The Scanner class is a user’s entry point to Teatime. It takes an IP, port, node type, and a list of Plugin instances to execute on the target. Behind the scenes, it initializes a fresh Context class, which is passed between the plugins to aggregate report data.

In the current implementation, the Scanner class executes the given plugin list sequentially on the target. The list order is equivalent to the execution order. This means that a plugin could provide meta data in a report that another plugin further down the line can use. While this is not recommended because it introduces implicit dependencies, it can certainly be used to build highly customized and complex scanning pipelines.

After the scan is done, the Scanner class attaches the time elapsed for the scan to the report’s meta data.

Plugin

The Plugin class is a base for all concrete scans of Teatime. A Plugin can execute one or more checks on the given target. To specify your own behaviour, the base Plugin class contains an abstract method _check that can be overridden by the user. This method gets a Context object (hopefully) containing all relevant meta data needed by the plugin.

For RPC interaction specifically, the Plugin class contains a helper method to query RPC endpoints in a robust way and handle connection errors along the way. To prevent Teatime from crashing completely in case of plugin-related errors, it is recommended to raise and reraise a PluginException. This can be caught easily on the top level, e.g. by the routine executing the scanner.

Context

The Context object contains report- and target-related information instructing the Plugin classes. It contains the target, the Report object, node type, and an extra data dictionary for any additional information that e.g. needs to be passed further down the plugin pipeline. Per scan, there is only one Context instance (initialized in the Scanner at the beginning of a scan), which gets shared across Plugin instances as they are executed in the pipeline.

Report

The Report object is essentially a container for Issue objects, along with meta data on the executed scan. It contains a UUID for traceability, the target, a creation timestamp, a list of issues, and a meta data dictionary for any additional information that should be communicated to the user.

The idea of wrapping issues in a report and duplicating information such as the target is that each Report object should be independent. Thinking of developers who might want to pass Teatime report data into a database, or export it as a file, this is a nice property to have, because no additional data apart from the object itself is required.

Furthermore, the Report class contains various helper methods that make serialization and common checks, such as checking for high-severity issues, easier.

Issue

This is the lowest-level primitive. The Issue object can be added to a Report instance by using its add_issue method. Each issue contains a UUID for traceability, a title, description, severity, and a raw data field. The latter one is meant to contain the raw RPC response. For example, if a scan has detected an information leak, the raw data field can be populated with the actual leaking information text, without cluttering the title or description - thus keeping issues readable and allowing the user to omit large strings when presenting an issue to the user.

Just like the Report class, an Issue object contains various helper method for easier serialization, as well as determining whether the issue at hand is severe. Wrapping issues into their own object has the advantage of enforcing a standard format across plugins and requiring them to provide information that help the user make sense of what has been reported.