Hub audit log

As part of the Hub configuration you can specify multiple file- or UDP-based log sinks that will receive detailed logging events.

These events are structured JSON objects that will allow network administrators to monitor activity on the Hub for either problems or suspicious behaviour.

Structure of Events

Every event shares a set of common fields plus an arbitrary payload who's contents depends on the type of event (see Event Types below).

Here's an example storage event showing the structure and common fields:

{
  "id": "4de3bbac-174a-4815-8580-37f1c66ca31a",
  "parent_id": "5090702b-c568-4027-9449-38ad2b964e6a",
  "depth": 1,
  "remote_addr": "100.111.184.97",
  "request_id": "169ee728c0030d56.9deb2e.00001d81",
  "timestamp": "2021-08-26T16:11:17.361006Z",
  "type": "storage",
  "severity": "trace",
  "request": {
    "content_length": 0,
    "method": "GET",
    "path": "/northwind-traders/credit-risk-rating/metrics",
    "query_params": {
      "model_id": "01FDCR0WGGJAW52QYQWJE2Q6AP",
      "subtab_name": "similarity",
      "table_name": "null",
      "version": "20210818T134314"
    },
    "uri": "https://hub.hazy.com/northwind-traders/credit-risk-rating/metrics?version=20210818T134314&model_id=01FDCR0WGGJAW52QYQWJE2Q6AP&subtab_name=similarity&table_name=null"
  },
  "user": {
    "email": "garry@hazy.com",
    "id": 2,
    "name": "Garry Hill"
  },
  "organisation": {
    "id": 2,
    "name": "Northwind Traders",
    "slug": "northwind-traders"
  },
  "storage": {
    "action": "read",
    "bytes": 34802,
    "encrypted": false,
    "uri": "file:///Users/garry/hazy/repos/hazy/mnt/hazmat/generator/cb/cb921604-f1ef-4087-9f9e-b16c9cf07938/model/2021/20210721T084436/01FB45B3XM8JWSR2B4HZ9W37A9.manifest.json"
  }
}
  • id. This is a UUID that identifies every event

  • parent_id. Events belong in a shallow tree structure, with most being triggered as secondary actions as part of a single request. The parent_id of the original request/response event will be null (or not included) and all secondary events that happen as a result of this request will point to that request/response event via their parent_id. See Event Hierarchy and History

  • depth. This will either be 0 for request or system events but increases as events cascade through the system. See Event Hierarchy and History

  • remote_addr. The IP address of the client that triggered this event (if relevant)

  • request_id. All events generated as a consequence of a HTTP request via the UI or API will share a single request_id. In this sense it can be considered equivalent to the "span" concept used in some distributed tracing systems.

  • timestamp. The time of the event, in ISO8601 format.

  • type. The type of the event. See Event Types below

  • severity. The importance of the event, from trace (the lowest) to critical (the highest). See Event Severity below

  • request. Any event triggered by some user interaction via HTTP will include information about the request that triggered the event.

  • user. If the originating request was authenticated, then the user field will include information about the user making the request.

  • organisation. If the originating request relates to some organisation within the Hub then its details will be included here.

In this event there is also a storage field that contains more information about the actual event that occurred. Every event of type x will include a field "x": {...} containing information specific to that type of event (see Event Types below)

Event Types

Every event has a type field that specifies the activity that the event is tracking.

The event structure is like this:

{
  "type": "event_type"
  "event_type": {
     // type specific information
  }
}

Below is the current set of event types, roughly categorised in order of importance.

Errors

error

Error events capture exceptions within the application. The payload of these events includes information such as the stacktrace that should help with diagnosing the problem.

Error events have a severity of error.

Example

"error": {
    "module": "Hazy.Hub.ImportSynthesizerTask",
    "action": "import",
    "description": "Unable to import Synthesiser Image",
    "message": "something went wrong",
    "stacktrace": [
        "(hazy_hub 0.1.0) lib/hazy/hub/import_synthesizer_task.ex:47: Hazy.Hub.ImportSynthesizerTask.import_images/1",
        "(elixir 1.12.2) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2",
        "(elixir 1.12.2) lib/task/supervised.ex:35: Task.Supervised.reply/5",
        "(stdlib 3.15) proc_lib.erl:226: :proc_lib.init_p_do_apply/3"
    ]
}

Potential Abuse

unauthenticated

Emitted when a user tries to login and fails. The event payload contains the username that was entered into the login form.

These messages have severity notice.

Example

"unauthenticated": {
"email": "username@northwind-traders.com"
}

forbidden

Emitted when an authenticated user attempts to perform an action that they are not authorized to perform according to their role. Examples include:

  • Attempting to download a model their administrator role or Team memberships do not allow them to access.
  • Attempting to perform some action, such as create a new Generator, which their organisation role does not permit.

The event payload contains an action. This is the permission that the user didn't have. See below for a full list of possible values for action.

Example

"unauthorized": {
"action": "entity.generators.downloadModel"
}

System Administration

bootstrap

Emitted as part of the Hub bootstrap process. Every bootstrap event includes an action. These actions represent the various stages of the bootstrap process:

  1. enter-unlock-code

    Example

    "bootstrap": {
        "action": "enter-unlock-code" 
    }
    
  2. create-admin-user

    Example

    "bootstrap": {
        "action": "create-admin-user", 
        "user": {
            "id": 1,
            "email": "admin@northwind-traders.com",
            "name": "Admin User"
        }
    }
    
  3. create-organisation

    Example

    "bootstrap": {
        "action": "create-organisation", 
        "organisation": {
            "id": 1,
            "name": "Admin User",
            "slug": "northwind-traders"
        }
    }
    

system

System events are not connected to user activity. They are caused by lifecycle events of the application or scheduled activity. Every system event includes the uptime of the application in seconds and the pid of the Hub process.

  • startup. Emitted when the Hub is initialised.

    Example

    "system": {
        "pid": 2623,
        "uptime_seconds": 34983,
        "event": "startup"
    }
    
  • cron. The Hub runs some background jobs periodically, in particular to perform a base-backup of the embedded Postgresql instance and a cleanup of the archive WAL files. These jobs will emit an event of type cron.

    The event payload will also include the exit status of the job process (which will be 0 if the job was successful), a description of the job, a duration_ms of the job and a capture of the stdout.

    Example

    "system": {
        "pid": 2623,
        "uptime_seconds": 34983,
        "event": "cron",
        "job": "backup",
        "description": "Perform a base backup of the database",
        "duration_ms": 673,
        "status": 0,
        stdout: "..."
    }
    
  • signal. Records UNIX signals received by the Hub process.

    The event payload will contain the name of the signal received, which will be one of:

    • SIGABRT
    • SIGALRM
    • SIGCHLD
    • SIGHUP
    • SIGQUIT
    • SIGSTOP
    • SIGTERM
    • SIGTSTP
    • SIGUSR1
    • SIGUSR2

    Example

    "system": {
        "pid": 2623,
        "uptime_seconds": 34983,
        "event": "signal",
        "signal": "SIGTERM"
    }
    
  • shutdown. If the Hub receives a termination signal such as SIGTERM or SIGQUIT then it will exit. Before it exits it will emit an event of type shutdown. Note that this event may fail to be emitted depending on the shutdown process.

    Example

    "system": {
        "pid": 2623,
        "uptime_seconds": 34983,
        "event": "shutdown"
    }
    

hub-admin

  • create_user. The Hub administrator has created a new user.

    Example

    "hub-admin": {
    "action":"create_user",
    "user": {
        "email":"new.user@northwind-traders.com",
        "id":201,
        "name":"New User"
    }
    }
    
  • edit_user. The Hub administrator has edited a user.

    Example

    "hub-admin": {
        "action": "edit_user",
        "modified": ["name"],
        "user": {
            "id":201,
            "name":"New User"
        }
    }
    
  • delete_user. The Hub administrator has deleted a user.

    Example

    "hub-admin": {
        "action": "delete_user",
        "user": {
            "id":201,
            "name":"New User"
        }
    }
    
  • reset_password. The Hub administrator as reset the password on a User.

    Example

    "hub-admin": {
    "action": "reset_password",
    "force_password_change": true,
    "user": {
        "email": "new.user@northwind-traders.com",
            "id":201,
            "name":"New User"
    }
    }
    
  • create_organisation. The Hub administrator has created a new organisation.

    Example

    "hub-admin": {
    "action":"create_organisation",
    "organisation": {
        "slug":"northwind-traders",
        "id":201,
        "name":"Northwind Traders"
    }
    }
    
  • edit_organisation. The Hub administrator has updated an Organisation's details.

    Example

    "hub-admin": {
        "action": "edit_organisation",
        "modified": ["name"],
        "organisation": {
            "slug":"northwind-traders",
            "id":201,
            "name":"Northwind Traders"
        }
    }
    
  • delete_organisation. The Hub administrator has deleted an organisation.

    Example

    "hub-admin": {
        "action": "delete_organisation",
        "organisation": {
            "slug":"northwind-traders",
            "id":201,
            "name":"Northwind Traders"
        }
    }
    

User, Access or Permissions Changes

login

Generated by a user logging in to their account. The user logging in is shown in the top-level user attribute on the event. These events have severity notice

Example

"login": {}

logout

Generated by a user logging out of their account. The user logging out is shown in the top-level user attribute on the event. These events have severity notice

Example

"logout": {}

team

Record changes to Team members or permissions. Because they relate to security-sensitive actions, these events have severity notice. Team events have an associated action. This action is either update_memberships or update_permissions.

Editing a Team may cause two events to be emitted, one for each action.

  • update_memberships. Records changes to team memberships. Includes a list of memberships added and memberships removed.

    Example

    "team": {
        "action": "update_memberships",
        "organisation": {
            "id": 2,
            "name": "Northwind Traders",
            "slug": "northwind-traders"
        },
        "team": {
            "id": 100,
            "name": "Data Scientists"
        },
        "user_memberships": {
            "added": [
                "user": {
                    "id": 5,
                    "name": "James May"
                }
            ], 
            "removed": [
                "user": {
                    "id": 9,
                    "name": "John Smith"
                }
            ]
        }
    }
    
  • update_permissions. Records changes to a Team's permissions, that is a Team's access to Generator Models. Includes a list of new Generators the Team has been given access to -- and the restrictions on that access, a list of permissions that have been removed from the Team and a list of permissions that have been updated.

    Example

    "team": {
        "action": "update_permissions",
        "organisation": {
            "id": 2,
            "name": "Northwind Traders",
            "slug": "northwind-traders"
        },
        "team": {
            "id": 100,
            "name": "Data Scientists"
        },
        "generator_permissions": {
            "added": [
                "user": {
                    "id": 5,
                    "name": "James May"
                }
            ], 
            "removed": [
                "user": {
                    "id": 9,
                    "name": "John Smith"
                }
            ]
        }
    }
    

account

Events of type account record changes to Users. Because they relate to security-sensitive actions, they have a severity of notice.

Account events have an associated action:

  • role_change. Emitted when a User's role within an Organisation is changed. Includes information on the User who's role was updated, the Organisation their role pertains to and the names of the old and new role.

    Example

    "action": "role_change",
    "user": {
        "id": 393,
        "name": "James May"
    },
    "organisation": {
        "id": 1234,
        "name": "Northwind Traders",
        "slug": "northwind-traders"
    },
    "old_role": "Team member",
    "new_role": "Admin"
    
  • add_member. Emitted when a User is added to an Organisation. Includes details of the Organisation, the User being added and their new role.

    Example

    "action": "add_member",
    "user": {
        "id": 393,
        "name": "James May"
    },
    "organisation": {
        "id": 1234,
        "name": "Northwind Traders",
        "slug": "northwind-traders"
    },
    "role": "Owner"
    
  • add_user. Emitted when a new User is created, either by an Organisation or Hub administrator. Includes information on the user and their assigned Organisation and Team memberships.

    Example

    "action": "add_user",
    "user": {
        "id": 393,
        "name": "James May",
        "email": "james@northwind-traders.com"
    },
    "memberships": [
        {
            "organisation": {
                "id": 1234,
                "name": "Northwind Traders",
                "slug": "northwind-traders"
            },
            "role": "Owner"
        }
    ],
    "teams": [
        {
            "name": "Data Scientists",
            "id": 93
        }
    ]
    
  • remove_member. Emitted when a user is removed from an organisation.

    Example

    "action": "remove_member",
    "user": {
        "id": 393,
        "name": "James May"
    },
    "organisation": {
        "id": 1234,
        "name": "Northwind Traders",
        "slug": "northwind-traders"
    }
    
  • regenerate_api_key. Emitted when a user or administrator regenerates a user's API key.

    Example

    "action": "regenerate_api_key",
    "user": {
        "id": 393,
        "name": "James May"
    }
    
  • reset_password. Emitted when an administrator resets another user's password.

    Example

    "action": "reset_password",
    "user": {
        "id": 393,
        "name": "James May",
        "email": "james@northwind-traders.com"
    }
    
  • change_password. Emitted when an user changes their password.

    Example

    "action": "change_password",
    "user": {
        "id": 393,
        "name": "James May"
    }
    

Normal User Activity

request

Every HTTP request to the Hub generates an event of type request (and its corresponding response event). As such they form the root of the tree of events associated with normal Hub activity therefore their depth will always be 0 and parent_id will always be null. See Event Hierarchy and History.

The request payload is included in all subsequent events, and has the following structure:

"request": { 
    "content_length":135,
    "method":"POST",
    "path":"/hurry/users/6/password_reset",
    "query_params":{},
    "uri":"http://hub.hazy.com/northwind-traders/users/6/password_reset"
}

For POST, PUT etc type requests, the content_length field holds the size of the request body (not the subsequent response body).

The query_params field holds the parsed request query (the part of the URL after the ?).

Requests to GET static assets such as Javascript files, CSS stylesheets and images are filtered from the logs for simplicity.

Also health probe requests, generated by container runtimes such as Docker or Kubernetes, are also excluded.

response

Every request event will have a corresponding response event.

The response payload tracks useful information about the duration of the request and the returned status code. Paired with the matching request entry in the event, it provides a full description of the HTTP request.

Most response type events have a severity of info, but if the response status is 400-499 or higher (client-error) then the severity will be raised to warn and if the status is greater than 500 the severity will be raised to error.

Response payloads have the following attributes:

  • status. The HTTP status code of the response
  • duration_us. The duration of the request-response cycle in microseconds

Example

"response":{
    "duration_us": 235639,
    "status": 200
}

upload

Generated when a user uploads a file to the Hub. These can be either model files when creating a new Generator Version or exported Synthesiser images in TAR-gzip format when adding Synthesiser images.

Upload payloads have the following attributes:

  • type. Either synthesiser or generator_model.
  • size. The filesize (in bytes) of the uploaded file.
  • filename. The original name of the uploaded file.

Example

"upload": {
"filename": "presence-test_project-tabular_20210305T122053-e0.001.hazymodel",
"size": 528126,
"type": "generator_model"
}

model

Represents any interaction with a Generator Model. The aim is to provide an easy way to track use of a particular generator model by a specific user.

Model events have an associated action. This action is either create or download. Model creation events both are generated either via the API or the Hub user interface.

Both the create and download action share the same model metadata payload:

  • model. Information about the model itself including its id, the similarity, utility and privacy metrics, model metadata including the release and parameter_inputs training parameters and version the associated Generator Version.
  • generator. Details of the Generator that owns the model file, its id, name and uri which is the unique path identifier in the Hub UI.

Download events also include:

  • size. The filesize of the model file in bytes
  • path. The relative path of the model file within the Hub's data volume

Example

"model": {
    "id": "01FE3JJDWZQ9SA3C1M1JRNY50C",
    "metadata": {
    "parameter_inputs": {
        "development_only": false,
        "dtypes_path": "/mount/dtypes_20210305120858173774.json",
        "epsilon": 0.001,
        "evaluate": true,
        "evaluation_exclude_columns": [],
        "evaluation_generate_params": {
        "implementation_override": true,
        "params": {
            "num_rows": 1000
        }
        },
        "input_path": "/mount/data_20210305120858173774.csv",
        "label_columns": [
        "Risk"
        ],
        "model_output": "/mount/credit_risk_model_0.001.hmf",
        "n_bins": 100,
        "predictors": [
        "lgbm"
        ],
        "sample_generate_params": {
        "implementation_override": false,
        "params": {
            "num_rows": 25
        }
        },
        "train_test_split": true
    },
    "release": {
        "base_tag": "develop",
        "branch": "master",
        "built-at": "2021-03-05T08:56:23.150973",
        "commit": "18ab25275a50c5f67ec1b41b612a4e52a657cd51",
        "id": "20210305T085623",
        "image": "hazyai.azurecr.io/project/tabular:20210305T085623",
        "name": "tabular"
    }
    },
    "privacy": 100,
    "similarity": 58,
    "utility": 77,
    "version": "20210827T103008"
},
"path": "generator/bb/bbbfd22e-6238-4bbf-b84d-5fbd6fb827ed/model/2021/20210827T103008/01FE3JJDWZQ9SA3C1M1JRNY50C.hazymodel",
"size": 528126
}

docker

Represent actions involving the Docker images hosted on the Hub

  • import. Generated when a Hub administrator uploads and imports a new Synthesiser image

    Example

    "docker": {
        "action": "import",
        "image": "project/tabular:20210305T085623"
    }
    
  • login. A user has run docker login hub.hazy.com or equivalent. In this case the user attribute of the event will be set to the user who has logged in. Unlike other docker events which have a severity of info, the login action has a severity of notice.

    Example

    "docker": {
        "action": "login"
    }
    
  • pull. A user has run docker pull hub.hazy.com/project/tabluar:20210305T085623 or equivalent.

    Example

    "docker": {
        "action": "pull",
        "image": "project/tabular:20210305T085623"
    }
    

invalid

These events represent some kind of validation error within the Hub user interface. That is that a user has tried to create some object but has provided some invalid input, an example would be attempting to create a user without a name. Individually these don't represent any kind of problem, but repeated invalid errors by the same user may highlight some malicious activity. invalid events are assigned a severity of notice.

These events have the following attributes:

  • action. Either create or update
  • errors. An array of validation failures in the form of a map from field name to list of problems with the given input.
  • type. The type of the entity that generated the validation failure
  • id. Events with an action of update will also have the ID of the entity being updated

Example

"invalid": {
"action": "create",
"errors": {
    "name": [
    "can't be blank"
    ],
    "slug": [
    "can't be blank"
    ]
},
"type": "generator"
}

Low-level

Low level events all have either trace or debug severity and represent normal database and file storage access. These events should be useful in the event of a problem with the Hub, so should be ignored by setting the level of audit log sinks to info for everyday usage.

As with most other events, the user, request, request_id and parent_id fields allow for associating these low-level events with user actions.

storage

Storage events are generated whenever a model is downloaded or model metadata (such as metrics) are accessed. The storage payload contains the following attributes:

  • action. One of read, write, delete
  • uri. A fully specified file:// type URI giving the path to the file being accessed or modified. This path is relative to the container, so will start with file:///mnt/data/... rather than the host path.
  • encrypted. The Hub can optionally encrypt all data on the filesystem. This is disabled by default (unless requested by the customer) so this will be false
  • bytes. In the case of read and write actions, this will contain the number of bytes being read or written.
  • range. The Hub will occasionally read only part of a file. In that case the range attribute will give [start_byte, length] information

Example

"storage": {
    "action": "read",
    "bytes": 2152,
    "encrypted": false,
    "range": [3453, 5605],
    "uri": "file:///mnt/data/generator/cb/cb921604-f1ef-4087-9f9e-b16c9cf07938/model/2021/20210721T084436/01FB45B407KE6N3AHD59RZW7TY.hazymodel"
}

The following events trace database modifications.

create

  • type. The type of the object being created.
  • id. The primary key of the row being created.

Example

"create": {
    "id": "811735fb-a9dd-4eb4-83f2-234d0c47669e",
    "type": "generator"
}

update

Update events are generated when a database row is updated. They have the following attributes in the update field:

  • type. The type of the object being modified.
  • id. The primary key of the row being modified
  • modified. The columns being updated

Example

"update": {
    "id": 2,
    "modified": [
        "description"
    ],
    "type": "organisation"
}

delete

Issued when a database row is deleted.

  • type. The type of the object being deleted.
  • id. The primary key of the row being deleted.

Example

"delete": {
    "id": "811735fb-a9dd-4eb4-83f2-234d0c47669e",
    "type": "generator"
}

Event Hierarchy and History

Most events -- except for system type events -- are generated by user interactions. Every user interaction begins with a request event and ends with a response type event, signifying that the associated request was completed.

Requests to the Hub may cause a set of associated events to be generated, for instance in the case of an update, each of these events will fit into a hierarchy defined by the event fields depth and parent_id but will all share the same request_id.

This makes is possible -- if the audit log level is set to trace -- to track all actions related to a user request.

The following is a list of all the events generated by an update to a User's account information. The event data below only shows the fields relevant to the event hierarchy, the real events would also carry payload information detailing the actual action that occurred, as well as shared details such as the logged in user, remote IP etc.

  1. request event. depth is 0, parent_id is null.

    {
        "type": "request",
        "id": "67dbf389-3596-4b35-a9c7-e3370263d263",
        "parent_id": null, // this is the first event in the chain
        "depth": 0,
        "request_id": "16a1462024c1b15e.63191d.00002e06",
        "severity": "info",
        // other fields
    }
    
  2. update. The request is an update to some user account, so generates a database update event

    {
        "type": "update",
        "id": "7fe6e04a-27c9-495b-a083-eef37caa0613",
        "parent_id": "67dbf389-3596-4b35-a9c7-e3370263d263", // this event is a child of the original request
        "depth": 1,
        "request_id": "16a1462024c1b15e.63191d.00002e06",    // the request_id is shared with the original request
        "severity": "trace",
        // other fields
    }
    
  3. account. The update to the user's account has been recognised and upgraded to an event of type account with severity notice. This account event is a child of the update event, so has a depth of 2 and refers to the update event as its parent. Again the request_id is constant.

    {
        "type": "account",
        "id": "21f85e37-5c2a-412a-974b-089f3e7d697e",
        "parent_id": "7fe6e04a-27c9-495b-a083-eef37caa0613", // this event is a child of the update event
        "depth": 2,
        "request_id": "16a1462024c1b15e.63191d.00002e06",    // the request_id is shared with the original request
        "severity": "notice",
        // other fields
    }
    
  4. response. The response event is the last in the chain and includes information such as the total time taken.

    {
        "type": "response",
        "id": "361e75dc-07e6-4605-b1b2-8ac4aa7fca21",
        "parent_id": "67dbf389-3596-4b35-a9c7-e3370263d263", // this event is a child of the original request
        "depth": 1,
        "request_id": "16a1462024c1b15e.63191d.00002e06",
        "severity": "info",
        // other fields
    }
    

The request_id can be used much like the span id in distributed tracing systems to tie all events into a coherent series.

Event Severity

Every event has an attached severity, ranging from trace at the lowest level of importance, up to critical.

The full list of event severity is as follows:

  • trace. Lowest level of event, including e.g. database actions such as insertion, updates and deletion of rows. We don't recommend using trace level sinks as the volume of log messages will be large.
  • debug. Emits messages concerned with the basic operations of the Hub. Again this level is too low for day-to-day monitoring.
  • info. Basic information on activity on the hub, e.g. HTTP requests
  • notice. Significant security-related events such as changes to user passwords, API keys, memberships and roles
  • warn. Information about some kind of abnormal event that nevertheless hasn't prevented the operation of the system
  • error. Notification of some kind of abnormal event that prevented normal functioning of the Hub.
  • critical. The Hub has encountered a problem that has prevents core functionality

Permissions List

Every action performed on the Hub requires the user to hold some fine-grained permission. These permissions are surfaced in the event of a forbidden type event.

Below is a list of all available permissions within the Hub.

User management

  • entity.users.list
  • entity.users.show
  • entity.users.create
  • entity.users.delete
  • entity.users.changePassword
  • entity.users.changeEmail
  • entity.users.changeName
  • entity.users.regenerateAPIToken

Manage Generators and Generator Models

  • entity.generators.list
  • entity.generators.show
  • entity.generators.create
  • entity.generators.edit
  • entity.generators.delete
  • entity.generators.createVersion
  • entity.generators.createModel
  • entity.generators.deleteVersion
  • entity.generators.deleteModel
  • entity.generators.editVersion
  • entity.generators.downloadModel
  • entity.generators.queryModel

Team management

  • entity.teams.list
  • entity.teams.show
  • entity.teams.create
  • entity.teams.edit
  • entity.teams.delete

Organisation role mangagement

  • entity.roles.list
  • entity.roles.show
  • entity.roles.create
  • entity.roles.edit
  • entity.roles.delete

Organisation management

  • entity.self.show
  • entity.self.edit
  • entity.self.editMemberships

Hub management

  • hub.orgs.list
  • hub.orgs.show
  • hub.orgs.create
  • hub.orgs.edit
  • hub.orgs.delete
  • hub.users.list
  • hub.users.show
  • hub.users.create
  • hub.users.edit
  • hub.users.delete
  • hub.synthesizers.list
  • hub.synthesizers.upload
  • hub.synthesizers.delete