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.