Skip to main content

Create relationships between owned and non-owned assets

When forming relationships between assets you own and assets you don't (e.g., assets ingested by an integration), you will need to use a _key and include a _source and _scope of the existing entities in the graph. This guide explains the correct way to create relationships between assets you own and those you do not. By following the instructions outlined below, you will be able to successfully create relationships and view the desired data in the graph.

It is important to note that when seeking to pass a source or scope via API, it should be done so as source or scope–without underscores. When retrieving the metadata property or querying an existing source or scope, it will need to be notated as _source or _scope–with underscores.

When providing a source or scope via graphQL query (without underscores), JupiterOne adds the underscores when the source or scope is added to the entity properties, as this is our standard pattern for metadata properties.

Ownership and subgraphs

The concept of ownership in JupiterOne determines what you see. What is not obvious when viewing the graph is that the graph you see is the aggregation of many subgraphs. There are subgraphs for the AWS integration, the system mapper, and API ingested data among other things.

All of these different subgraphs provide a cohesive set of results. These subgraphs denote ownership. For example, if a certain subgraph owns entity A, it means that entity A is in that subgraph. Ownership is important because it is how JupiterOne interprets datasets.

A subgraph is created by fusing the source and the scope of an entity together. For example, api:your-api-call could be a subgraph. These subgraphs provide identity to your data in the JupiterOne. When interacting with assets that are owned by various subgraphs, you must be specific in your interactions so the resulting graph is how you expect it to look.

Getting started

For this guide, we'll be working with the an example available within our JupiterOne Node.js client repo, here.

Running this example provides you with the necessary ephemeral data owned by an integration-managed source. The example creates data controlled by the integration-managed and api sources, and it also creates a relationship between those two assets.

Acquiring Assets in the Graph to Form Relationships

After you have compiled the assets that you want to upload to JupiterOne, you still must acquire assets from the JupiterOne graph in order to form the relationships. Therefore, the first step is to acquire our integration-managed data.

If you have run the example scenario above, you should have newly-created CodeRepos in your graph to query. The example code uploads assets into JupiterOne in an integration-managed scope. This upload enables us to work with assets that is outside of your scope (api).

To acquire the integration-managed data, you can use the following query to retrieve the newly-created CodeRepos:

FIND github_repository
WITH from = 'testing'

Here is an example response payload from one of the CodeRepos:

{
"_class": [
"CodeRepo"
],
"_type": [
"github_repository"
],
"_key": "MDEwOlJlcG9zaXRvcnkxNjkzMzI3NTQ=",
"displayName": "ibzibid",
"_integrationType": "github",
"_integrationClass": [
"ITS",
"SCM",
"VCS",
"VersionControl"
],
"_integrationDefinitionId": "1babe084-d58d-4ff0-9d98-e0d9bb8499be",
"_integrationName": "JupiterOne",
"_beginOn": "2022-01-19T20:26:17.842Z",
"_id": "2218b983-139b-4447-9889-f04f48761b15",
"_integrationInstanceId": "40d8cd20-054e-4b77-82bd-f01af7593170",
"_rawDataHashes": "eyJkZWZhdWx0IjoiMUlKVFNaT00vM2FwQmtWTWt0alYxcml6ZjZsRGFNa1VTRHBvakxIR2sxVT0ifQ==",
"_version": 18,
"_accountId": "j1dev",
"_deleted": false,
"_source": "integration-managed",
"_createdOn": "2020-03-23T19:10:09.298Z"
}

Forming the Relationship

The next step is to form relationships between assets you own and assets you do not. There are two primary options for creating a relationship:

{
_fromEntityKey: string;
_toEntityKey: string;
_fromEntityId: string;
_toEntityId: string;
}

You can form the relationship in the following ways:

  • CodeRepo _key -> CodeModule _key
  • CodeRepo _id -> CodeModule _key

Keep in mind that you do not have the CodeModule _id yet, which is important because these two options are NOT equal in how they behave.

Forming a relationship using the _id of the CodeRepo and the _key of the CodeModule works because the _id is unique in all of the data in your account. The _key value is NOT globally unique, meaning that two assets can have the same _key.

When you form a relationship with two _key values and you do not specify the source and the scope of the data that already exists in the graph, JupiterOne does not understand which asset you are referencing and, therefore, does not create the relationship. Because two assets could have the same _key, the software needs more information to be able to identify the asset you are referencing.

Acquiring more information

To acquire more information, use the source and scope of your JupiterOne data with the _key!

{
_fromEntitySource: string;
_toEntitySource: string;
_fromEntityScope: string;
_toEntityScope: string;
}

This:

  • CodeRepo _key -> CodeModule _key
  • CodeRepo _id -> CodeModule _key

Should actually be:

  • CodeRepo _key, _source, _scope -> CodeModule _key
  • CodeRepo _id -> CodeModule _key

In JSON, it looks like this:

{
_fromEntitySource: entityFrom.entity._source,
_fromEntityScope: entityFrom.entity._integrationInstanceId,
_fromEntityKey: entityFrom.entity._key,
_toEntityKey: entityTo.entity._key,
}

Putting It Together

Now that you know how to form relationships with assets that you do not own, here is what your bulk upload payload should look like put together:

{
"entities": [
{
"_key": "npm_package:hizurur",
"_class": "CodeModule",
"_type": "npm_package",
"displayName": "hizurur",
"from": "testing"
},
{...}
],
relationships: [
{
_key: "codeRepo:USES:codeModule",
_type: "codeRepo:USES:codeModule",
_class: "USES",
displayName: "USES v3.4.3",
_fromEntitySource: "integration-managed"
_fromEntityScope: "integration_id"
_fromEntityKey: "codeRepo_key"
_toEntityKey: "npm_package:hizurur"
},
{...}
]
}

After you have uploaded the data, use the query posted earlier in the guide in JupiterOne to view your results:

FIND CodeModule
WITH displayName = ('hizurur' OR 'carnud' OR 'vici' OR 'iti' OR 'jifguilo' OR 'kiwoj' OR 'juvhove')
AND from = 'testing'
THAT USES << CodeRepo

Conclusion

By following this guide, you can successfully create relationships between assets you own and those you do not. This will allow you to effectively manage your data and leverage the full capabilities of JupiterOne's graph.