21074 Commits

Author SHA1 Message Date
Patrik Oldsberg 177a1c1af6 Clarify plugin-app changeset message in isolation
Explain page-based nav discovery and legacy nav-item compatibility together.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:21:23 +02:00
Patrik Oldsberg 2ba8c10106 Split plugin-app into its own changeset
Keep legacy nav-item compatibility note on plugin-app only; other
plugins get a changeset focused on page title/icon for sidebar entries.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:20:28 +02:00
Patrik Oldsberg fe72a38768 Mark renderInTestApp nav removal as breaking in changeset
Bump frontend-test-utils as minor with user-facing impact guidance.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:16:14 +02:00
Patrik Oldsberg 269c4f9f0d Remove legacy nav stub from renderInTestApp
Disable app/nav in the minimal test shell instead of rendering
legacy nav-item extensions. Use renderTestApp when nav behavior matters.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:15:31 +02:00
Patrik Oldsberg 483297f845 Trim Remix icon migration diff in changeset
Show only import and icon param changes for the Remix Icon example.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:13:45 +02:00
Patrik Oldsberg 7089280c6e Add Remix icon migration notes to NavItemBlueprint changeset
Document switching from MUI IconComponent nav items to Remix Icon
elements on PageBlueprint.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:03:20 +02:00
Patrik Oldsberg 44d77e9680 Split nav item removal into separate changesets
Use dedicated changesets for the breaking frontend-plugin-api removal,
plugin migrations, and frontend-test-utils update.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:01:58 +02:00
Patrik Oldsberg 10e5d6f8aa Remove NavItemBlueprint in favor of page-based nav discovery
Drop the deprecated NavItemBlueprint from the public API and migrate core
plugins to set title and icon on PageBlueprint instead. AppNav keeps
backward compatibility for legacy nav-item extensions via an internal
core.nav-item.target data ref.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 11:00:46 +02:00
Patrik Oldsberg 9a88d85d50 Merge pull request #34089 from backstage/otel/mcp-tools-call
feat: Instrument MCP tool calls with semantically appropriate span
2026-05-19 10:53:13 +02:00
Fredrik Adelöw bc32c13de6 catalog-backend: add missing index on relations.target_entity_ref
The relations table had indexes on originating_entity_id and
source_entity_ref but none on target_entity_ref. Several query paths
join or filter on this column:

- Orphan deletion (LEFT JOIN relations ON target_entity_ref)
- Entity ancestry (INNER JOIN relations ON target_entity_ref)
- Eager pruning (JOIN relations ON target_entity_ref)

Without an index these queries seq-scan the full table (~3.5M rows,
714 MB heap). On a production replica, a single point lookup takes
~122ms via seq scan. With the index it drops to <1ms.

The index is ~141 MB based on column width (~35 bytes avg) across
~3.5M rows. On PostgreSQL it's created with CONCURRENTLY to avoid
blocking reads/writes.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-19 10:50:06 +02:00
benjdlambert 333b10c2ab refactor: move AiResource types to @backstage/catalog-model alpha
Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 10:42:49 +02:00
benjdlambert 46fbd60aef refactor: rename package to @backstage/plugin-catalog-backend-module-ai-model
Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 10:42:49 +02:00
benjdlambert cf29736923 refactor: rename AIResource to AiResource for PascalCase consistency
Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 10:42:48 +02:00
benjdlambert 3664148c2e feat: add AIResource catalog entity kind as opt-in module
Introduces @backstage/plugin-catalog-backend-module-ai-resource-entity-model,
a new backend module that registers the AIResource kind with the catalog.

Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 10:42:41 +02:00
MT Lewis 2bd0450cb4 feat(catalog-backend-module-msgraph): filter out disabled users by default (#34165)
* feat(catalog-backend-module-msgraph): filter out disabled users by default

The Microsoft Graph provider now always applies an `accountEnabled eq true`
base filter when fetching users. Any custom `user.filter` is combined with
the base filter using `and`, so adopters no longer need to manually add
`accountEnabled eq true` to their configuration.

Also removes the legacy mutual exclusivity check between `userFilter` and
`userGroupMemberFilter` — these serve orthogonal purposes (user-level
filtering vs group selection) and the downstream code already handles
both being set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>

* chore: mark msgraph disabled-user filtering as breaking change

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>

* docs(catalog-backend-module-msgraph): clarify automatic accountEnabled filter in docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>

---------

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 10:30:30 +02:00
Fredrik Adelöw 98f496a1ad Merge pull request #34265 from backstage/freben/stable-multi-org-order
github: stabilize entity order in multi-org provider
2026-05-19 10:23:43 +02:00
Ben Lambert 782a819e4d fix: correct changeset bump level for scaffolder-backend (#34297)
Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 10:05:53 +02:00
Ben Lambert 29d398b57c fix(auth-backend): harden default allowed patterns for CIMD and DCR (#34260)
* fix(auth-backend): harden default allowed patterns for CIMD and DCR

Signed-off-by: benjdlambert <ben@blam.sh>

* address PR review feedback for OIDC defaults

- narrow CLI client ID pattern to exact cli.json path
- add BREAKING prefix to changeset
- add IPv6 [::1] to docs examples
- add loopback redirect URI tests for IPv6 and 127.0.0.1

Signed-off-by: benjdlambert <ben@blam.sh>

* remove dead ['*'] fallback when features are disabled

The restrictive defaults are now always used regardless of the enabled
flag, since the patterns are only consulted on code paths that require
the feature to be enabled.

Signed-off-by: benjdlambert <ben@blam.sh>

* add default pattern tests and fix docs cli example

Signed-off-by: benjdlambert <ben@blam.sh>

* use URL constructor for CLI client ID

Signed-off-by: benjdlambert <ben@blam.sh>

* use string templating for cliClientId to match OidcRouter

Signed-off-by: benjdlambert <ben@blam.sh>

* fix docs: remove misleading CLI client_id URL example

Signed-off-by: benjdlambert <ben@blam.sh>

---------

Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-19 09:45:31 +02:00
Fredrik Adelöw 50d97e714e Merge pull request #34258 from backstage/freben/mock-credentials-version
backend-test-utils: add version field to mock credentials
2026-05-19 09:24:41 +02:00
Fredrik Adelöw d325ee31d0 Merge pull request #34225 from backstage/fix/filter-predicate-mixed-operator-keys
fix(filter-predicates): reject operator keys mixed with other keys
2026-05-19 09:24:31 +02:00
Patrik Oldsberg 5f14aba359 Merge pull request #34285 from backstage/rugvip/cimd-metadata-size-cap
auth-backend: cap CIMD metadata response size
2026-05-18 17:53:32 +02:00
Ben Lambert 07ec25de2c fix(catalog-backend): move generateStableHash out of shared util to fix Storybook build (#34284)
* fix(catalog-backend): move generateStableHash out of shared util to fix Storybook build

The util.ts file mixed Node.js-only code (createHash from node:crypto)
with pure constants. Since InMemoryCatalogClient reaches into
buildEntitySearch via a relative import, and buildEntitySearch imports
from util.ts, the node:crypto dependency leaked into Vite's browser
bundle causing the Storybook build to fail.

Signed-off-by: benjdlambert <ben@blam.sh>

* add changeset

Signed-off-by: benjdlambert <ben@blam.sh>

---------

Signed-off-by: benjdlambert <ben@blam.sh>
2026-05-18 16:57:26 +02:00
Patrik Oldsberg 9f269d73ed auth-backend: cap CIMD metadata response size
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 16:38:46 +02:00
Fredrik Adelöw 97515d8356 Merge pull request #33788 from benjidotsh/app/fix-disabled-nav-items
fix(app): add check for disabled nav items to discovery of pages
2026-05-18 16:04:24 +02:00
Eric Peterson b70f13990b Bring tracing service more in line with upstream APIs
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
2026-05-18 15:20:09 +02:00
Fredrik Adelöw 17a9550f13 catalog-backend: deprecate immediate mode stitching
Mark immediate mode stitching as deprecated in config.d.ts, the
StitchingStrategy type, and log a warning on startup when it is
detected. This is a precursor to removing immediate mode entirely
in the next release.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-18 14:19:57 +02:00
renovate[bot] 8007b58dcd chore(deps): update dependency embedded-postgres to v18.3.0-beta.17
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-18 10:00:37 +00:00
Fredrik Adelöw aa313f099c github: stabilize entity order in multi-org provider
When using GithubMultiOrgEntityProvider with alwaysUseDefaultNamespace
and teams with identical slugs across orgs, the emitted entity order
was non-deterministic. Since the catalog's upsert path uses last-write-
wins for duplicate entity refs, this caused the winning org to flip
randomly on every refresh cycle, producing constant unnecessary
stitching and flickering entity data.

Sort the emitted entities by entity ref (primary) and location
annotation (tiebreaker) so that the same org consistently wins when
duplicate refs exist.

Fixes #34263

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-18 11:36:30 +02:00
Patrik Oldsberg 735af6c8c0 Merge pull request #34142 from backstage/session/suspicious-heron-9w2p
feat(auth-backend): validate catalog user existence on refresh token usage
2026-05-18 11:17:21 +02:00
Eric Peterson 6209065f00 Add support for async context propagation and baggage in tracing service.
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
2026-05-18 10:28:09 +02:00
Eric Peterson 8916f83bee Instrument MCP tool calls with semantically appropriate span
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
2026-05-18 10:28:09 +02:00
Fredrik Adelöw 2f0519cba3 permission: cache user info and parallelize resolution
The permission backend previously resolved userInfo and minted a plugin
request token sequentially for every authorize request with user
credentials. On high-traffic endpoints this meant two serial internal
HTTP round-trips per request, even when the same user made many
requests in quick succession.

This change:

1. Adds a 5-second TTL cache to DefaultUserInfoService so that repeated
   getUserInfo() calls for the same user return the cached result
   without an HTTP call to the auth backend.

2. Parallelises the getUserInfo() and getPluginRequestToken() calls in
   the permission backend's handleRequest via Promise.all, saving one
   sequential round-trip on cache misses.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-16 17:39:50 +02:00
Fredrik Adelöw ada7df7929 backend-test-utils: add version field to mock credentials
The mock credentials created by mockCredentials.none(), .user(), and
.service() were missing the internal version: 'v1' field. This caused
toInternalBackstageCredentials() to throw when used with mock
credentials in tests.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-16 17:39:31 +02:00
Fredrik Adelöw eab8f7a510 Merge pull request #34256 from backstage/cursor/ui-field-flex
fix(ui): allow fields to grow in flex layouts
2026-05-16 16:53:46 +02:00
Fredrik Adelöw e51af8cced Merge pull request #33602 from elaine-mattos/feat/allow-empty-commits 2026-05-16 10:13:59 +02:00
Fredrik Adelöw 379c3a8264 Merge pull request #34113 from its-mitesh-kumar/fix/user-settings-theme-toggle-i18n-priority
fix(user-settings): Prioritize i18n translation for built-in theme names
2026-05-15 20:31:13 +02:00
Fredrik Adelöw c667c2bf90 Merge pull request #34262 from backstage/chore/upgrade-storybook-10.4 2026-05-15 19:10:05 +02:00
Charles de Dreuille 18aa6e4d56 Merge pull request #34151 from backstage/password
Style PasswordField like TextField
2026-05-15 14:22:17 +01:00
Charles de Dreuille b67a862f8e chore: add storybook ui changeset
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-05-15 10:35:24 +01:00
Charles de Dreuille 5520e07992 fix(ui): allow fields to grow in flex layouts
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-05-14 15:39:41 +01:00
Fredrik Adelöw ac07705ac9 Merge pull request #34232 from backstage/cursor/header-container-alignment
fix(ui): align header sections with container
2026-05-13 21:17:40 +02:00
Fredrik Adelöw e477bdc83b Merge pull request #34229 from backstage/freben/rel
exit prerelease mode
2026-05-13 20:57:10 +02:00
Charles de Dreuille 3e0ff6c240 fix(ui): align header sections with container
Add container layout to Header sections so the title, actions, tags, metadata, and tabs align with surrounding page content.

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
2026-05-13 17:44:07 +01:00
Fredrik Adelöw d701652b4c exit prerelease mode
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
2026-05-13 17:41:10 +02:00
Andre Wanlin 86c6e5abf6 Merge pull request #34027 from adobejmong/feat-add-util-to-get-octokit-client
feat: add util to get octokit client which support retries via octokit/plugin-retry
2026-05-13 10:33:03 -05:00
Fredrik Adelöw 691da8dcd0 add changeset
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@spotify.com>
2026-05-13 16:02:45 +02:00
github-actions[bot] 42a2f56e61 Version Packages (next) 2026-05-12 18:28:01 +00:00
Fredrik Adelöw add5d1ace7 catalog-backend: drive paginated entity ordering from search-by-key (#34162)
* draft: restructure entities() ordering to drive from search-by-key

When a sort field is specified, build the query so the search table
filtered by that key is the driving relation, instead of left-joining
search onto final_entities and sorting after. The planner can then walk
the (key, value, entity_id) index in already-sorted order and short
circuit on LIMIT.

Measured against a production replica, the catalog UI's default
"first page of components ordered by metadata.name" query goes from
~940 ms to ~8 ms. See PR description for the full numbers.

Known caveats this draft does not yet address:
- Entities lacking the order field are excluded; the previous shape
  put them at the end with NULLS LAST. A UNION ALL pattern can
  preserve the old semantics.
- Multi-field order falls back to the OLD shape (only the first field
  is taken when present today; subsequent fields acted as
  tie-breakers). Restoring tie-breakers needs additional joins or a
  CTE.
- queryEntities (/entities/by-query) is left untouched; the same
  optimization applies but the CTE/cursor structure makes the rewrite
  more involved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@spotify.com>

* two-phase entities() ordering: fast path + NULLs-last fallback

When an order field is specified, run a fast path first that drives
from the search-by-key index (excluding entities without the field).
If that path doesn't produce enough rows to cover offset+limit+1, run
a fallback that picks up the no-field entities in entity_id order.
This preserves NULLs-LAST semantics while keeping the fast plan for
the common case where every entity has the order field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@spotify.com>

* fix: multi-field order fallback + MySQL quoting in entities()

Fall back to the original LEFT JOIN shape when multiple order fields
are specified, since tie-breaking on secondary fields inherently
requires materialization. The fast INNER-JOIN-driven path is used only
for single-field order (the typical UI case).

Fix the phase 2 NOT EXISTS clause to use knex's ?? identifier escaping
instead of hardcoded double-quotes, which broke on MySQL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@spotify.com>

* catalog-backend: fix phase 2 ordering and update changeset

Fix two issues raised in review:

- Phase 2 (entities lacking the sort field) now always sorts by
  entity_id ASC regardless of the primary sort direction, matching the
  original NULLS-LAST behaviour where the NULL group was always
  entity_id ASC.

- Update changeset to describe the actual two-phase behaviour (NULLS
  LAST preserved) instead of the stale description that said entities
  without the field are excluded.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* catalog-backend: apply offset when limit is undefined in runOrderedEntitiesQuery

Previously the fast-path returned the full combined array when no limit
was specified, silently ignoring any pagination offset. The old
implementation always pushed offset to SQL independently of limit.
Restore parity by slicing the combined array by the offset even when
limit is absent.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* catalog-backend: add pagination and phase-boundary tests for entities() ordering

Add two new test cases that cover the parts of runOrderedEntitiesQuery not
exercised before:

- "paginates correctly through single-field ordering": exercises limit, offset,
  and hasNextPage through the fast path (Phase 1 only) across all DB engines.

- "paginates across the Phase 1 / Phase 2 boundary": exercises the case where
  the requested page straddles entities that have the sort field (Phase 1) and
  those that do not (Phase 2), and verifies that Phase 2 entities are always
  ordered ASC by entity_id regardless of the primary sort direction.

Also fixes a double-space caught by prettier in DefaultEntitiesCatalog.ts.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* catalog-backend: treat null sort-field value the same as a missing sort field

buildEntitySearch stores value=NULL for entity fields that are explicitly
null or exceed MAX_VALUE_LENGTH. Previously, Phase 1 included those rows via
the INNER JOIN (key matches, value IS NULL), causing them to sort ahead of
entities that have no row for the key at all — changing semantics vs the old
LEFT JOIN shape where both cases landed in the same NULLS-LAST bucket.

Fix Phase 1 to require order_0.value IS NOT NULL, and fix Phase 2's NOT EXISTS
to check for no non-null value (value IS NOT NULL) so that both null-valued
and missing-key entities are collected in Phase 2 and ordered together by
entity_id ASC.

Adds a regression test covering an entity with spec.b=null alongside one with
no spec.b, asserting both appear after sorted entities regardless of direction.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Signed-off-by: Fredrik Adelöw <freben@spotify.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 20:20:14 +02:00
asheen fe6b868308 Merge branch 'master' into gitlab-repo-owner-picker
Signed-off-by: asheen <sergeantnumnumz@gmail.com>
2026-05-12 10:48:17 -04:00
Fredrik Adelöw ab690eea30 Merge pull request #34190 from backstage/freben/facets-count-optimization
fix(catalog-backend): simplify facets COUNT(DISTINCT) to COUNT(*)
2026-05-12 15:32:08 +02:00