Community
Questions Library
Docs
Blog
Events
Swag
Github
Slack
JupiterOne
Discussions
Release Notes
Creating Relationships Between Assets You Own and Assets You Do Not - AskJ1 Community
<main> <article class="userContent"> <h2 data-id="overview">Overview</h2> <p>If you want to form a relationship using a <code class="code codeInline" spellcheck="false" tabindex="0">_key</code>, you must include the<br><code class="code codeInline" spellcheck="false" tabindex="0">_source</code> and <code class="code codeInline" spellcheck="false" tabindex="0">_scope</code> of the entity that already exists in the graph.</p> <p>If the entity you are uploading is the <code class="code codeInline" spellcheck="false" tabindex="0">to</code>, then the entity that you<br> are forming a relationship with, which already exists in the graph, is, therefore, the<br><code class="code codeInline" spellcheck="false" tabindex="0">from</code>:</p> <p>This does <em>NOT</em> work:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ _fromEntityKey: entityFrom.entity._key, _toEntityKey: entityTo.entity._key, } </pre> <p>This works:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ _fromEntitySource: entityFrom.entity._source, _fromEntityScope: entityFrom.entity._integrationInstanceId, _fromEntityKey: entityFrom.entity._key, _toEntityKey: entityTo.entity._key, } </pre> <p>This guide teaches you how to create relationships between an asset that you own<br> and one you do not own. Adding new data to the J1 graph and forming relationships <br> with that data is a common use case. If you are not specific with how you form relationships, <br> you might not see the data in the graph after you have uploaded it.</p> <p>The concept of ownership in the J1 platform determines what you see. <br> What is not obvious when viewing the graph is that the graph you see is the <br> aggregation of many subgraphs. There are subgraphs for the AWS integration, the <br> system mapper, and API ingested data among other things. All of these different subgraphs <br> provide a cohesive set of results. These subgraphs denote ownership. For example,<br> if a certain subgraph owns <code class="code codeInline" spellcheck="false" tabindex="0">entity A</code>, it means that <code class="code codeInline" spellcheck="false" tabindex="0">entity A</code> is in that subgraph. Ownership<br> is important because it is how J1 understands the state of everything.</p> <p>A subgraph is created by fusing the <code class="code codeInline" spellcheck="false" tabindex="0">source</code> and the <code class="code codeInline" spellcheck="false" tabindex="0">scope</code> of an entity together. For example, <br><code class="code codeInline" spellcheck="false" tabindex="0">api:your-api-call</code> could be a subgraph. These subgraphs provide identity to your data in the J1. <br> When interacting with assets that are owned by various subgraphs, you must be<br> specific in your interactions so the resulting graph is how you expect it to look.</p> <p>At the end of this guide, you should be able to run this query and see your results:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">FIND CodeModule WITH displayName = ('hizurur' OR 'carnud' OR 'vici' OR 'iti' OR 'jifguilo' OR 'kiwoj' OR 'juvhove') AND from = 'testing' THAT USES << CodeRepo </pre> <p>An example of this use case is available at: <a href="https://github.com/JupiterOne/jupiterone-client-nodejs/tree/main/examples/sync-api" rel="nofollow">https://github.com/JupiterOne/jupiterone-client-nodejs/tree/main/examples/sync-api</a></p> <p>This guide assumes that you have run the example above so that you have the necessary<br> ephemeral data that is owned by an <code class="code codeInline" spellcheck="false" tabindex="0">integration-managed</code> source. The example <br> creates data that is controlled by the <code class="code codeInline" spellcheck="false" tabindex="0">integration-managed</code> source, creates data that <br> is controlled the <code class="code codeInline" spellcheck="false" tabindex="0">api</code> source, and creates a relationship between those two assets.</p> <h2 data-id="acquiring-assets-in-the-graph-to-form-relationships">Acquiring Assets in the Graph to Form Relationships</h2> <p>After you have compiled the assets that you want to upload to J1, you still must acquire assets from <br> the J1 graph so that you can form relationships with it. Therefore, the first step in this guide is <br> to acquire <code class="code codeInline" spellcheck="false" tabindex="0">integration-managed</code> data from J1.</p> <p>If you have run the example scenario above, you should have newly-created <a rel="nofollow" href="https://github.com/JupiterOne/jupiterone-client-nodejs/blob/main/examples/sync-api/src/data/code-repos.json">CodeRepos</a> in your graph to query. The example code uploads assets into J1 <br> in an <code class="code codeInline" spellcheck="false" tabindex="0">integration-managed</code> scope. This upload enables us to work with assets that is outside of your scope (<code class="code codeInline" spellcheck="false" tabindex="0">api</code>).</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">FIND github_repository WITH from = 'testing' </pre> <p>You now have <code class="code codeInline" spellcheck="false" tabindex="0">CodeRepos</code> that you can form relationships with.</p> <p>An example query response payload from one of the <code class="code codeInline" spellcheck="false" tabindex="0">CodeRepos</code>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "_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" } </pre> <h2 data-id="forming-the-relationship">Forming the Relationship</h2> <p>The next step is to form relationships between assets you own and assets you do not. <br> There are two primary options for creating a relationship:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ _fromEntityKey: string; _toEntityKey: string; _fromEntityId: string; _toEntityId: string; } </pre> <p>You can form the relationship in the following ways:</p> <ul><li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> <li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> </ul><p>Keep in mind that you do not have the <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> yet, which<br> is important because these two options are <em>NOT</em> equal in how they behave.<br> Forming a relationship using the <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> of the <code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> and the <code class="code codeInline" spellcheck="false" tabindex="0">_key</code> of the<br> CodeModule works because the <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> is unique in all of the data in your<br> account. The <code class="code codeInline" spellcheck="false" tabindex="0">_key</code> value is <em>NOT</em> globally unique, meaning that two assets can have<br> the same <code class="code codeInline" spellcheck="false" tabindex="0">_key</code>.</p> <p>When you form a relationship with two <code class="code codeInline" spellcheck="false" tabindex="0">_key</code> values and you do not specify the<br><code class="code codeInline" spellcheck="false" tabindex="0">source</code> and the <code class="code codeInline" spellcheck="false" tabindex="0">scope</code> of the data that already exists in the graph, J1 does not <br> understand which asset you are referencing and, therefore, does not create the <br> relationship. Because two assets could have the same <code class="code codeInline" spellcheck="false" tabindex="0">_key</code>, the software needs more <br> information to be able to identify the asset you are referencing.</p> <h3 data-id="how-to-get-more-information">How to Get More Information</h3> <p>Use the <code class="code codeInline" spellcheck="false" tabindex="0">source</code> and <code class="code codeInline" spellcheck="false" tabindex="0">scope</code> of your J1 data with the <code class="code codeInline" spellcheck="false" tabindex="0">_key</code>!</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ _fromEntitySource: string; _toEntitySource: string; _fromEntityScope: string; _toEntityScope: string; } </pre> <p>This:</p> <ul><li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> <li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> </ul><p>Must actually be:</p> <ul><li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code>, <code class="code codeInline" spellcheck="false" tabindex="0">_source</code>, <code class="code codeInline" spellcheck="false" tabindex="0">_scope</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> <li><code class="code codeInline" spellcheck="false" tabindex="0">CodeRepo</code> <code class="code codeInline" spellcheck="false" tabindex="0">_id</code> -> <code class="code codeInline" spellcheck="false" tabindex="0">CodeModule</code> <code class="code codeInline" spellcheck="false" tabindex="0">_key</code></li> </ul><p>In JSON, it looks like this:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ _fromEntitySource: entityFrom.entity._source, _fromEntityScope: entityFrom.entity._integrationInstanceId, _fromEntityKey: entityFrom.entity._key, _toEntityKey: entityTo.entity._key, } </pre> <h2 data-id="putting-it-together">Putting It Together</h2> <p>Now that you know how to form relationships with assets that you do not own, here is what <br> your <a rel="nofollow" href="https://community.askj1.com/kb/articles/786-jupiterone-bulk-upload-schema">sync api</a> payload should look like put together:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "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" }, {...} ] } </pre> <p>After you have uploaded the data, use the query posted earlier in the guide in J1 to view your results:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">FIND CodeModule WITH displayName = ('hizurur' OR 'carnud' OR 'vici' OR 'iti' OR 'jifguilo' OR 'kiwoj' OR 'juvhove') AND from = 'testing' THAT USES << CodeRepo </pre> </article> </main>