> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Backstage

Backstage iconBackstage icon
Loading version...

Port's Backstage integration allows you to ingest Backstage entities into your context lake so that agents, workflows, and your team members can access and act on them.

Prerequisites​

Create a Backstage token​

Port will authenticate to Backstage via static tokens. Configure a token for Port using the following Backstage configuration:

backend:
auth:
externalAccess:
- type: static
options:
token: YOUR-TOKEN
subject: port-ocean-access

Replace YOUR-TOKEN with your Backstage token. To create a token, Backstage recommends to use the following command:

node -p 'require("crypto").randomBytes(24).toString("base64")'

Setup​

Choose one of the following installation methods: Not sure which method is right for your use case? Check the available installation methods.

Configuration​

Port integrations use a YAML mapping block to ingest data from the third-party api into Port.

The mapping makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from the integration API.

Default mapping configuration​

This is the default mapping configuration for this integration:

Default mapping configuration (click to expand)
resources:
- kind: component
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"component"'
properties:
type: .spec.type
lifecycle: .spec.lifecycle
language: .spec.language
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
subcomponentOf: .relations[] | select(.type == "subcomponentOf" and (.targetRef | startswith("component:"))) | .targetRef
providesApis: .relations[] | select(.type == "providesApi" and (.targetRef | startswith("api:"))) | .targetRef
consumesApis: .relations[] | select(.type == "consumesApi" and (.targetRef | startswith("api:"))) | .targetRef
dependsOnComponent: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("component:"))) | .targetRef
dependsOnResource: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("resource:"))) | .targetRef
- kind: API
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"api"'
properties:
type: .spec.type
lifecycle: .spec.lifecycle
definition: .spec.definition | tostring
definitionOpenAPI: if .spec.type == "open-api" then .spec.definition else null end
definitionAsyncAPI: if .spec.type == "async-api" then .spec.definition else null end
definitionGRPC: if .spec.type == "grpc" then .spec.definition else null end
definitionGraphQL: if .spec.type == "graphql" then .spec.definition else null end
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
- kind: group
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"group"'
properties:
description: .metadata.description
type: .metadata.type
email: .metadata.email
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
parent: .relations[] | select(.type == "childOf" and (.targetRef | startswith("group:"))) | .targetRef
members: .relations[] | select(.type == "hasMember" and (.targetRef | startswith("user:"))) | .targetRef
- kind: user
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"user"'
properties:
email: .metadata.email
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
- kind: resource
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"resource"'
properties:
type: .spec.type
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
system: '"system:" + (.metadata.namespace // "default") + "/" + .spec.system'
dependsOnResource: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("resource:"))) | .targetRef
dependsOnComponent: .relations[] | select(.type == "dependsOn" and (.targetRef | startswith("component:"))) | .targetRef
- kind: system
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"system"'
properties:
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef
domain: .relations[] | select(.type == "partOf" and (.targetRef | startswith("domain:"))) | .targetRef
- kind: domain
selector:
query: 'true'
port:
entity:
mappings:
identifier: .metadata.identifier
title: .metadata.title // .metadata.name
blueprint: '"domain"'
properties:
description: .metadata.description
labels: .metadata.labels
annotations: .metadata.annotations
links: .metadata.links
tags: .metadata.tags
relations:
owningUser: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("user:"))) | .targetRef
owningGroup: .relations[] | select(.type == "ownedBy" and (.targetRef | startswith("group:"))) | .targetRef

Monitoring and sync status​

To learn more about how to monitor and check the sync status of your integration, see the relevant documentation.

Mapping & selectors per resource​

To view and test the integration's mapping against examples of the third-party API responses, use the jq playground in your connectors page. Find the integration in the list of connectors and click on it to open the playground.

Additional examples of blueprints and the relevant integration configurations:

Limitations​

Currently, the integration does not support custom entity kinds.