-
Notifications
You must be signed in to change notification settings - Fork 43
docs(backstage-plugins): fix install guide inaccuracies found in end-to-end test #818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,29 +21,49 @@ OpenChoreo plugins are published to **GitHub Packages** under the [`@openchoreo` | |
|
|
||
| ::: | ||
|
|
||
| :::tip Tracking the upcoming 1.2.0 release | ||
| :::tip Tracking prereleases | ||
|
|
||
| The install commands on this page reference `@openchoreo/<pkg>@^1.2.0`, which will be the GA dist-tag of the next plugin release. While `1.2.0` is still under active development, install via the `next` dist-tag to get the latest prerelease today: | ||
| The install commands on this page reference `@openchoreo/<pkg>@^1.2.0`, which resolves to the newest stable `1.2.x` release. Stable releases are published under the `latest` dist-tag; prereleases go to `next`. To track the cutting edge instead: | ||
|
|
||
| ```bash | ||
| yarn workspace app add @openchoreo/backstage-plugin@next | ||
| ``` | ||
|
|
||
| Once `1.2.0` GA is announced, swap `@next` for `@^1.2.0` to pin to the stable release. | ||
|
|
||
| ::: | ||
|
|
||
| ## 1. Prerequisites | ||
|
|
||
| - A Backstage workspace on the [supported Backstage version](./compatibility-matrix.mdx). This guide pins to **Backstage `1.51.0`**. | ||
| - The workspace must be scaffolded with the **default NFS scaffold**: `npx @backstage/create-app@latest`. (Do NOT pass `--legacy`. If you must stay on legacy, see [Section 9](#9-legacy-frontend-system-fallback).) | ||
| - Node.js **20 or 22**, Yarn **4.13.x** (the current `create-app` scaffold ships Yarn 4.13.0 in `.yarn/releases/`). | ||
| - The workspace must be scaffolded with the **default NFS scaffold** (do NOT pass `--legacy`; if you must stay on legacy, see [Section 9](#9-legacy-frontend-system-fallback)). | ||
| - Node.js **22 or 24** — the scaffold declares `"engines": { "node": "22 || 24" }`, so Node 20 will not work. | ||
| - Yarn **4.4.1** if you scaffold at `1.51.0` as described below. (`create-app@latest` ships a newer Yarn — see [Section 3](#authenticate-to-github-packages).) | ||
| - Access to a running OpenChoreo control plane (local `k3d` or a deployed cluster). | ||
| - OAuth client credentials for the OpenChoreo Identity Provider (used by the catalog sync and user sign-in). On `k3d` the helm chart pre-seeds these; for a deployed cluster see [Identity configuration](../identity-configuration.mdx). | ||
|
|
||
| :::tip Backstage version | ||
| :::tip Getting Backstage 1.51.0 without a downgrade | ||
|
|
||
| `create-app@latest` gives you whatever Backstage release is current, which is newer than the tested `1.51.0`. Pin the scaffolder to the matching release instead, and there is nothing to undo afterwards: | ||
|
|
||
| ```bash | ||
| npx @backstage/create-app@0.8.3 | ||
| cat backstage.json # -> { "version": "1.51.0" } | ||
| ``` | ||
|
|
||
| `@backstage/create-app@0.8.3` is the release that ships Backstage `1.51.0`. If you already have an app on a different release line, use `versions:bump` instead — see [Section 2](#2-pin-backstage-versions). | ||
|
|
||
| `create-app` has no `--name` flag, so the command prompts for one. To script it: `printf 'my-app\n' | npx @backstage/create-app@0.8.3 --path ./my-app`. | ||
|
|
||
| ::: | ||
|
|
||
| :::info Optional tab packs need cluster-side planes | ||
|
|
||
| If you plan to install the Observability (Section 5) or CI/Build and Workflows (Sections 6–7) packs, the corresponding OpenChoreo planes must exist in the cluster. On the `k3d` quick start they are opt-in: | ||
|
|
||
| ```bash | ||
| ./install.sh --with-observability --with-build | ||
| ``` | ||
|
|
||
| `create-app@latest` will likely give you Backstage `1.52.x` or newer at the time you read this. After scaffolding, run `yarn backstage-cli versions:bump --release 1.51.0` (covered in [Section 2](#2-pin-backstage-versions)) to align with the tested combination. | ||
| Without them the tabs install and render, but have no data behind them. | ||
|
|
||
| ::: | ||
|
|
||
|
|
@@ -70,32 +90,60 @@ yarn backstage-cli versions:bump --release 1.51.0 | |
| yarn install | ||
| ``` | ||
|
|
||
| …to align before adding the OpenChoreo packages. | ||
| …to align before adding the OpenChoreo packages. `versions:bump` handles downgrades as well as upgrades, so this works from a newer release line too. | ||
|
|
||
| :::note | ||
|
|
||
| If you are creating a brand-new app, prefer `create-app@0.8.3` ([Section 1](#1-prerequisites)) over scaffolding at the latest release and bumping down. Scaffolding at the right version keeps the `@backstage/*` version churn out of your first commit, so the diff that adds OpenChoreo contains only OpenChoreo changes. | ||
|
|
||
| ::: | ||
|
|
||
| ## 3. Authenticate to GitHub Packages {#authenticate-to-github-packages} | ||
|
|
||
| GitHub Packages requires authentication even for `read:packages`-only operations. Create a [classic Personal Access Token](https://github.com/settings/tokens/new) with the `read:packages` scope, then wire it into your package manager. | ||
|
|
||
| **Yarn 4 (Berry)** — the current `create-app` scaffold's `.yarnrc.yml` enables a 3-day [npm minimum-age gate](https://yarnpkg.com/configuration/yarnrc#npmMinimalAgeGate) that blocks newly published packages. Update `.yarnrc.yml` to both add the `@openchoreo` scope auth **and** pre-approve the scope so fresh OpenChoreo releases install immediately: | ||
| **Yarn 4 (Berry)** — add the `@openchoreo` scope to `.yarnrc.yml`. Keep the `nodeLinker` and `yarnPath` lines your scaffold already generated and append the `npmScopes` block: | ||
|
|
||
| ```yaml title=".yarnrc.yml" | ||
| nodeLinker: node-modules | ||
| npmMinimalAgeGate: 3d | ||
| npmPreapprovedPackages: | ||
| - "@backstage/*" | ||
| - "@openchoreo/*" | ||
|
|
||
| yarnPath: .yarn/releases/yarn-4.13.0.cjs | ||
| # Leave this at whatever your scaffold generated. The Backstage 1.51.0 scaffold | ||
| # ships Yarn 4.4.1; newer scaffolds ship a newer release. | ||
| yarnPath: .yarn/releases/yarn-4.4.1.cjs | ||
|
|
||
| npmScopes: | ||
| openchoreo: | ||
| npmRegistryServer: "https://npm.pkg.github.com" | ||
| npmAlwaysAuth: true | ||
| npmAuthToken: "${GITHUB_PACKAGES_TOKEN}" | ||
| npmAuthToken: "${GITHUB_PACKAGES_TOKEN:-}" | ||
| ``` | ||
|
|
||
| …then `export GITHUB_PACKAGES_TOKEN=<your-pat>` before running `yarn install`. Berry expands the `${...}` placeholder from the environment so the token never lands in the repo. | ||
|
|
||
| :::warning Keep the `:-` in `${GITHUB_PACKAGES_TOKEN:-}` | ||
|
|
||
| Yarn expands `.yarnrc.yml` variables on **every** invocation, not just `yarn install`. With a bare `"${GITHUB_PACKAGES_TOKEN}"`, any yarn command run without the variable exported — `yarn tsc`, `yarn start`, `yarn lint` — aborts before doing anything: | ||
|
|
||
| ```text | ||
| Usage Error: Environment variable not found (GITHUB_PACKAGES_TOKEN) in /path/to/.yarnrc.yml | ||
| ``` | ||
|
|
||
| The `:-` suffix supplies an empty default, so day-to-day commands work unauthenticated and only install/fetch needs the real token. | ||
|
|
||
| ::: | ||
|
|
||
| :::note Newly published releases and the minimum-age gate | ||
|
|
||
| Scaffolds newer than Backstage 1.51.0 set a 3-day [npm minimum-age gate](https://yarnpkg.com/configuration/yarnrc#npmMinimalAgeGate) in `.yarnrc.yml`. It only blocks packages published within the last three days, so it rarely affects a normal install. If you are installing an OpenChoreo release that fresh and Yarn refuses it, pre-approve the scope: | ||
|
|
||
| ```yaml title=".yarnrc.yml" | ||
| npmPreapprovedPackages: | ||
| - "@backstage/*" | ||
| - "@openchoreo/*" | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| In **CI**, GitHub Actions can use the auto-issued `GITHUB_TOKEN` instead of a PAT, provided the workflow has `permissions: { packages: read }` and the running repo is in (or a fork of) an org the package is published from. | ||
|
|
||
| --- | ||
|
|
@@ -586,7 +634,9 @@ openchoreo: | |
| permission: | ||
| enabled: true # required for the OpenChoreo permission policy to run | ||
|
|
||
| # The catalog must accept Domain entities from the OpenChoreo provider. | ||
| # Only needed for static `catalog.locations` you add yourself. Entities emitted by | ||
| # an EntityProvider — which is how the OpenChoreo sync works — bypass catalog.rules | ||
| # entirely, so this block does not gate the OpenChoreo entities. | ||
|
Comment on lines
+637
to
+639
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: In Backstage v1.51.0, entities submitted through EntityProviderConnection.applyMutation are not subject to catalog.rules validation [1][2][3]. Catalog rules are primarily designed to control the ingestion of entities originating from locations (such as those defined in catalog.locations) [1][4][2]. They are enforced by the DefaultCatalogProcessingOrchestrator within the processing pipeline [3], specifically applying to entities that have an associated location spec [1][3]. Entities submitted directly via an EntityProvider through applyMutation bypass this location-based rule enforcement [1]. As outlined in the official Backstage documentation, EntityProviders provide entities directly to the catalog engine [5][6]. While these entities undergo standard catalog processing steps (such as validation by EntityPolicies and processors), they do not trigger the catalog.rules check that applies to file-based or URL-based location ingestion [1][4][3]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
for f in \
docs/platform-engineer-guide/backstage-plugins/installing-into-existing-backstage.mdx \
docs/platform-engineer-guide/backstage-plugins/troubleshooting.mdx \
docs/platform-engineer-guide/backstage-plugins/catalog-sync.mdx
do
echo "=== $f ==="
wc -l "$f"
case "$f" in
*installing-into-existing-backstage.mdx) sed -n '620,650p' "$f" ;;
*troubleshooting.mdx) sed -n '265,295p' "$f" ;;
*catalog-sync.mdx) sed -n '25,55p' "$f" ;;
esac
done
echo "=== references to catalog.rules and EntityProvider ==="
rg -n -C 3 'catalog\.rules|EntityProvider|applyMutation' docs/platform-engineer-guide/backstage-pluginsRepository: openchoreo/openchoreo.github.io Length of output: 8990 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
import urllib.request
base = "https://raw.githubusercontent.com/backstage/backstage/v1.51.0/"
paths = [
"plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts",
"plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts",
"plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts",
]
for path in paths:
url = base + path
print(f"=== {url} ===")
try:
with urllib.request.urlopen(url, timeout=20) as response:
text = response.read().decode()
except Exception as exc:
print(f"FETCH_ERROR: {exc}")
continue
lines = text.splitlines()
for i, line in enumerate(lines, 1):
if any(term in line for term in ("rules", "applyMutation", "location")):
lo, hi = max(1, i - 5), min(len(lines), i + 8)
print("\n".join(f"{n}: {lines[n-1]}" for n in range(lo, hi + 1)))
print("---")
PYRepository: openchoreo/openchoreo.github.io Length of output: 1037 🏁 Script executed: #!/bin/bash
set -eu
base='https://raw.githubusercontent.com/backstage/backstage/v1.51.0'
for path in \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts \
plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts
do
url="$base/$path"
echo "=== $url ==="
body="$(curl -ksSfL "$url" || true)"
if [ -z "$body" ]; then
echo "FETCH_ERROR_OR_EMPTY"
continue
fi
printf '%s\n' "$body" | nl -ba | grep -E -C 8 'catalog\.rules|rules|applyMutation|EntityProvider|location' || true
doneRepository: openchoreo/openchoreo.github.io Length of output: 889 🏁 Script executed: #!/bin/bash
set -eu
base='https://raw.githubusercontent.com/backstage/backstage/v1.51.0'
for path in \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts \
plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts \
plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts
do
url="$base/$path"
echo "=== $url ==="
curl -ksSfL "$url" | grep -E -C 8 'catalog\.rules|rules|applyMutation|EntityProvider|location' || true
doneRepository: openchoreo/openchoreo.github.io Length of output: 8904 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json, ssl, urllib.request
ctx = ssl._create_unverified_context()
url = 'https://api.github.com/repos/backstage/backstage/git/trees/v1.51.0?recursive=1'
req = urllib.request.Request(url, headers={'User-Agent': 'review-inspection'})
with urllib.request.urlopen(req, context=ctx, timeout=30) as response:
tree = json.load(response)['tree']
for item in tree:
path = item.get('path', '')
if 'catalog-backend' in path and (
'EntityProvider' in path or 'entityProvider' in path or
'EntitiesCatalog' in path or 'CatalogService' in path or
'rules' in path.lower()
):
print(path)
PYRepository: openchoreo/openchoreo.github.io Length of output: 965 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import ssl, urllib.request
ctx = ssl._create_unverified_context()
base = 'https://raw.githubusercontent.com/backstage/backstage/v1.51.0/'
paths = [
'plugins/catalog-backend/src/service/DefaultCatalogService.ts',
'plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts',
'plugins/catalog-backend/src/providers/EntityProviderConnection.ts',
'plugins/catalog-backend/src/providers/EntityProviderManager.ts',
]
for path in paths:
url = base + path
print(f'=== {url} ===')
try:
req = urllib.request.Request(url, headers={'User-Agent': 'review-inspection'})
with urllib.request.urlopen(req, context=ctx, timeout=20) as response:
lines = response.read().decode().splitlines()
except Exception as exc:
print(f'FETCH_ERROR: {exc}')
continue
for i, line in enumerate(lines, 1):
if any(term in line for term in ('applyMutation', 'rulesEnforcer', 'deferredEntities', 'locationKey', 'originLocation')):
lo, hi = max(1, i - 12), min(len(lines), i + 18)
print('\n'.join(f'{n}: {lines[n-1]}' for n in range(lo, hi + 1)))
print('---')
PYRepository: openchoreo/openchoreo.github.io Length of output: 10922 🏁 Script executed: #!/bin/bash
set -eu
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -tzf "$tmp" |
grep -E 'catalog-backend/.+(EntityProvider|CatalogService|ProcessingManager|Database|rules)' |
head -80Repository: openchoreo/openchoreo.github.io Length of output: 2115 🏁 Script executed: #!/bin/bash
set -eu
tmp="$(mktemp)"
dir="$(mktemp -d)"
trap 'rm -f "$tmp"; rm -rf "$dir"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -xzf "$tmp" -C "$dir"
root="$(find "$dir" -maxdepth 1 -type d -name 'backstage-*' -print -quit)"
grep -R -n -E -C 8 'applyMutation|rulesEnforcer|deferredEntities|locationKey' \
"$root/plugins/catalog-backend" \
--include='*.ts' --include='*.tsx' | head -300Repository: openchoreo/openchoreo.github.io Length of output: 38424 🏁 Script executed: #!/bin/bash
set -eu
tmp="$(mktemp)"
dir="$(mktemp -d)"
trap 'rm -f "$tmp"; rm -rf "$dir"' EXIT
curl -ksSfL 'https://codeload.github.com/backstage/backstage/tar.gz/refs/tags/v1.51.0' -o "$tmp"
tar -xzf "$tmp" -C "$dir"
root="$(find "$dir" -maxdepth 1 -type d -name 'backstage-*' -print -quit)"
echo '=== applyMutation and provider connection ==='
grep -R -n -E -C 15 'applyMutation|EntityProviderConnection|connectEntityProviders' \
"$root/plugins/catalog-backend" "$root/packages/catalog-node" \
--include='*.ts' --include='*.tsx' | head -500
echo '=== relevant catalog service files ==='
find "$root/plugins/catalog-backend/src" -type f \
\( -iname '*catalog*' -o -iname '*provider*' -o -iname '*refresh*' \) \
-print | sortRepository: openchoreo/openchoreo.github.io Length of output: 50387 Remove the Backstage 1.51.0 does not apply 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| catalog: | ||
| rules: | ||
| - allow: [Component, System, Domain, API, Resource, Location, Group, User] | ||
|
|
@@ -633,6 +683,16 @@ Expected: | |
| 5. Click into any project (`kind=system`) → **CELL DIAGRAM** and **DEFINITION** tabs are present and render real data. | ||
| 6. Click into any component → **DEPLOY** and **DEFINITION** tabs are present and render real data. | ||
|
|
||
| :::warning Complete step 3 before judging steps 4–6 | ||
|
|
||
| With `permission.enabled: true`, the catalog looks **empty** until OpenChoreo sign-in has completed. This is expected: the OpenChoreo permission policy authorizes catalog reads against the signed-in user's IDP token, and a guest session (or any service credential) has no OpenChoreo identity to evaluate, so the OpenChoreo entities are filtered out of every read. | ||
|
|
||
| What makes this easy to misread is that nothing reports it. There is no error and no warning, the provider still logs `Successfully processed N entities`, and the provider's `Template` entities are **not** filtered — so the Scaffolder fills with OpenChoreo templates while the catalog looks empty. | ||
|
|
||
| To confirm the sync itself is healthy, set `permission.enabled: false`, restart, and the full entity set appears. Set it back to `true` afterwards. | ||
|
|
||
| ::: | ||
|
|
||
| If you get a 401 on tab data fetches, your `customAppModule`'s `ApiBlueprint` for `fetchApiRef` isn't being registered — check that `customAppModule` is in the `features: [...]` array in `App.tsx`. If you get "No permissions" on Deploy, same check for the `permissionApiRef` `ApiBlueprint`. See [Troubleshooting](./troubleshooting.mdx) for the full failure-mode index. | ||
|
|
||
| --- | ||
|
|
@@ -798,7 +858,18 @@ The plugin contributes the standalone `/workflows` page as a `PageBlueprint` — | |
|
|
||
| Optionally add a sidebar entry in `packages/app/src/modules/nav/Sidebar.tsx` so users can navigate to it. | ||
|
|
||
| ### 7.4 Verify | ||
| ### 7.4 Configure | ||
|
|
||
| This pack shares the same feature flag as the CI/Build tab in [Section 6](#6-add-cibuild-tab-optional). If you installed Section 6 it is already set; if you are installing Section 7 on its own, add it: | ||
|
|
||
| ```yaml | ||
| openchoreo: | ||
| features: | ||
| workflows: | ||
| enabled: true | ||
| ``` | ||
|
|
||
| ### 7.5 Verify | ||
|
|
||
| Restart `yarn start`. Navigate to `http://localhost:3000/workflows` → see the org-level workflow list. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: openchoreo/openchoreo.github.io
Length of output: 6626
🏁 Script executed:
Repository: openchoreo/openchoreo.github.io
Length of output: 50389
🏁 Script executed:
Repository: openchoreo/openchoreo.github.io
Length of output: 16683
Restrict OpenChoreo package ranges to the tested minor.
The compatibility matrix supports only plugin set
1.2.x, but^1.2.0accepts1.3.0through<2.0.0. Use~1.2.0or1.2.xin all OpenChoreo install and upgrade commands, including the migration guide.🤖 Prompt for AI Agents