Skip to content

Activity Runner is a framework to test telemetry apps. It reads a JSON list of activities and executes them.

Notifications You must be signed in to change notification settings

soniaconnolly/activity-runner

Repository files navigation

Activity Runner

Introduction

Activity Runner is a framework to test telemetry apps. It reads a JSON list of activities and executes them. A log in JSON format tracks the executed activities for comparison with telemetry app behaviors.

Supported activities:

  • Start a process, given a path to an executable file and the desired (optional) command-line arguments
  • Create a file of a specified type at a specified location
  • Modify a file
  • Delete a file
  • Establish a network connection and transmit data

Setup

Install Ruby if needed.

Ruby version: 3.3.5

Install gems:

bundle install

Docker build:

docker compose build

JSON list of activities

Using the provided activities.json as a template, create a list of activities. It is an array of JSON objects, each specifying an action, a path, and any additional arguments.

The valid actions are:

  • run_process, properties: action, path, (optional) args
  • create_file, properties: action, path
  • modify_file, properties: action, path, data
  • delete_file, properties: action, path
  • network_request, properties: action, path, data, (optional) protocol

Actions

Run the test suite

bundle exec rspec

Run the script

The provided script takes the activities file as an argument. The script logs to the default logfile, activity_runner_log.json. Note that log timestamps are in UTC.

./run_activities.rb <your activities.json file>

Call ActivityRunner

Call ActivityRunner from irb or another Ruby program. Optionally specify an alternate logfile with the logfile named argument.

ActivityRunner.new(activity_file, logfile: './activity_runner_log.json')

Run a bash shell under Linux in Docker

docker-compose run --rm --service-ports app

Discussion

Security

Running arbitrary processes, file operations, and network requests is a big security risk. For a production version, the user that runs the new processes should have carefully limited permissions. Possibly, file operations should be limited to an application subdirectory instead of being full paths.

Currently, no API keys are in use. If they are needed they should be added in a .env file and the dotenv gem can be added to the project. Also add env_file: .env to docker-compose.yml

Object Decomposition and Design Patterns

  • ActivityRunner reads in a json file of activities, creates Activity objects, and runs them.
  • Activity is the parent class for all types of activities. It can run a process because most activities use that capability. Inheritance and the Factory pattern are used to make this framework easily extensible.
    • CreateFileActivity, ModifyFileActivity, DeleteFileActivity, and NetworkActivity are subclasses of Activity. They override the command method and possibly the run method.
    • NullFileActivity is used when the specified action property is invalid or 'path' is missing.
  • ActivityFactory creates the correct Activity subclass for the specified action.

Gems

  • json_logger - logging in json format
  • faraday - network requests
  • vcr - record network requests for specs
  • sys-proctable - cross-platform information about running processes
  • get_process_start_time - returns process start time (Linux only). I ended up using ps instead because it just works on both Mac and Linux, but it's slow. In a production system, the Linux side should use this gem, and the Mac side should figure out the start time from ProcTable.ps(pid: process_id).start_tvsec and .start_tvusec.

Specs

For a production system, more specs should be added to check error paths, such as invalid JSON files, missing properties, etc.

Specs pass on both Mac and Linux.

NetworkActivity implementation

At first I used curl in a new process to implement a network request. However, I did not have access to requested properties such as amount of data sent and source address and port. I reimplemented the network requests with faraday (which also allowed me to add the vcr gem to prevent network connections from specs). This puts the network request in the same process as the overall activity runner.

Regarding source address and port, I looked at X-Forwarded-For, Origin, and Referer, but those are request headers, not response headers. Per this StackOverflow answer it would be possible to implement custom middleware to get access to the request to log those headers if they are present.

About

Activity Runner is a framework to test telemetry apps. It reads a JSON list of activities and executes them.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published