Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions labs/lab-02-users-roles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ This step also demonstrates Backstage's declarative frontend extension system:
No new packages are required — all imports are already installed in the Backstage instance
from Lab 1.

#### Create the module directory
#### Step 2b.1 — Create the module directory

| Platform | Command |
|----------|---------|
Expand All @@ -317,7 +317,7 @@ from Lab 1.
Run this command from inside your Backstage root directory
(`labs/lab-01-base-backstage/backstage/`).

#### Create `ApiVisibilityCard.tsx`
#### Step 2b.2 — Create `ApiVisibilityCard.tsx`

Create `packages/app/src/modules/apiVisibility/ApiVisibilityCard.tsx` — its full content is
committed alongside this README at
Expand All @@ -326,7 +326,7 @@ copy it in as-is. It reads the `example.com/visibility` annotation off the entit
"Shared"/"Private" chip, with a fallback message when the annotation is absent (treated as
private by the permission policy).

#### Create `index.ts`
#### Step 2b.3 — Create `index.ts`

Create `packages/app/src/modules/apiVisibility/index.ts` — its full content is committed at
[`code/packages/app/src/modules/apiVisibility/index.ts`](./code/packages/app/src/modules/apiVisibility/index.ts);
Expand All @@ -340,7 +340,7 @@ it into a `createFrontendModule`.
> but it is stable enough for this lab and follows the same pattern Backstage itself uses
> internally.

#### Update `App.tsx`
#### Step 2b.4 — Update `App.tsx`

Open `packages/app/src/App.tsx` and update it as follows:

Expand Down
24 changes: 16 additions & 8 deletions labs/lab-03-api-quality/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ Replace `<user>` and `<branch>` with your GitHub username and branch name.

## Step 7 — Install the Spectral Linter Plugin

### Step 7a — Run the install command

Unlike the api-grade plugins, `@dweber019/backstage-plugin-api-docs-spectral-linter` IS
published to npm and can be installed directly:

Expand All @@ -238,7 +240,7 @@ yarn --cwd packages/app add @dweber019/backstage-plugin-api-docs-spectral-linter
No source build is required. The package is compatible with React 18 and react-router-dom 6,
both already present in this Backstage instance.

### Dedupe two Spectral libraries so linting works in the browser (required)
### Step 7b — Dedupe conflicting Spectral libraries (required)

The Spectral linter (`0.5.2`) pins **exact** versions of two `@stoplight` libraries, so yarn
installs a second, *nested* copy of each under the plugin's own `node_modules`. Both nested
Expand Down Expand Up @@ -337,11 +339,17 @@ mode. Importing it directly sidesteps the incompatibility entirely instead of wo
it.

Because this subpath has no TypeScript declaration file, add a small ambient module
declaration. Create `packages/app/src/modules/spectralLinter/spectral-linter-content.d.ts` — its
declaration.

### Step 8a — Create `spectral-linter-content.d.ts`

Create `packages/app/src/modules/spectralLinter/spectral-linter-content.d.ts` — its
full content is committed alongside this README at
[`code/packages/app/src/modules/spectralLinter/spectral-linter-content.d.ts`](./code/packages/app/src/modules/spectralLinter/spectral-linter-content.d.ts);
copy it in as-is.

### Step 8b — Create `SpectralLinterContent.tsx`

Create the file `packages/app/src/modules/spectralLinter/SpectralLinterContent.tsx` — its full
content is committed at
[`code/packages/app/src/modules/spectralLinter/SpectralLinterContent.tsx`](./code/packages/app/src/modules/spectralLinter/SpectralLinterContent.tsx);
Expand Down Expand Up @@ -454,9 +462,9 @@ for `group:default/platform-team`'s member list. Since the group entity is defin
second `platform-team` Group descriptor in Lab 3 would produce a duplicate entity error in
the catalog.

The Lab 2 file at `labs/lab-02-users-roles/catalog/teams.yaml` has already been updated to
add `eve` to `platform-team`'s members list. Backstage will pick this up on the next catalog
refresh.
The Lab 2 file at `labs/lab-02-users-roles/catalog/teams.yaml` already includes `eve` in
`platform-team`'s `members` list — no changes are needed to that file. Backstage will pick
up the updated membership on the next catalog refresh.

Add the following catalog location to `app-config.yaml`:

Expand All @@ -478,7 +486,7 @@ Replace `<user>` and `<branch>` with your GitHub username and branch name.

---

## Step 12a — Grant the Platform Team Catalog Read Access
## Step 13 — Grant the Platform Team Catalog Read Access

**Why this step is needed**: Registering Eve as a `platform-team` member (Step 12) and
configuring `apiGrade.visibility.groups` (Step 6) are not enough on their own. Lab 2's
Expand Down Expand Up @@ -677,7 +685,7 @@ verify Charlie is not a member of platform-team
her in the APIs catalog list and search
**Fail (Museum/Streetlights don't appear in the APIs catalog list or search for Eve, or her
entity-page requests 404)**: This is a catalog *read* permission problem, not an `apiGrade`
display problem — Eve can't reach the entity at all. Confirm Step 12a's platform-team rule was
display problem — Eve can't reach the entity at all. Confirm Step 13's platform-team rule was
added to `permissionPolicy.ts` and that it checks `user.info.ownershipEntityRefs` (populated
from Eve's `memberOf: [platform-team]`) before falling through to the ownership-only
conditional decision; restart the backend after editing
Expand Down Expand Up @@ -744,7 +752,7 @@ condition. Because Backstage can't even load a private entity a user isn't allow
it never appears in the catalog list, search, or a direct-link entity page — and `apiGrade`'s
own summary/detail visibility split never gets a chance to run.

**Fix**: Add the platform-team check to `permissionPolicy.ts` from Step 12a: before falling
**Fix**: Add the platform-team check to `permissionPolicy.ts` from Step 13: before falling
through to the existing `anyOf` conditional decision, unconditionally allow `catalog-entity`
reads when `user.info.ownershipEntityRefs` includes `group:default/platform-team`. Restart
the backend after editing — permission policy changes require a backend restart to take
Expand Down
13 changes: 10 additions & 3 deletions labs/lab-04-auto-registration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ this provider, the provider skips its own auto-sourced candidate for that name e
lets you hand-author precise metadata for a specific API — pinning an owner, tightening
visibility — without the auto-registration mechanism fighting you for it every cycle.

### Step 2a — Create the database migration file

Create the database migration first, at
`packages/backend/src/extensions/autoApiRegistrationMigrations/001_scan_state_cache.ts`. Its full
content is committed alongside this README —
Expand All @@ -116,6 +118,8 @@ content is committed alongside this README —
since this file lives alongside the module's TypeScript source rather than in a package-level
`migrations/` folder resolved at runtime.

### Step 2b — Create the auto-registration module

Now the module itself, at `packages/backend/src/extensions/autoApiRegistration.ts` — this is the
heart of the lab. Its full content (~750 lines: config normalization, filesystem discovery and
YAML parsing, `x-*` candidate mapping with owner/visibility/collision validation, the scan-state
Expand Down Expand Up @@ -167,10 +171,11 @@ or vendor namespace it never opted into.

---

## Step 5 — Add the Sample API Files
## Step 5 — Review the Sample API Files and Register the Precedence Demo

Two sample files are already committed alongside this README (nothing to create in this step —
just take a look):
Two sample files are already committed alongside this README — review them to understand
the auto-discovery and precedence concepts, then register the precedence demo's hand-authored
catalog entry as described below:

- **`apis/galaxy/galaxy-openapi.yaml`** — a vendored copy of the MIT-licensed
[Scalar Galaxy API](https://github.com/scalar/scalar), with an `info.x-examplecorp` object
Expand All @@ -182,6 +187,8 @@ just take a look):
values (owner `platform-team`, `visibility: shared`). This demonstrates the precedence rule:
the hand-authored file wins.

### Step 5a — Register the precedence demo catalog location

The hand-authored `precedence-demo-catalog-info.yaml` needs its own catalog location, the same way
Lab 2/3's hand-authored files do — add it to `app-config.yaml`'s `catalog.locations`, replacing
`<user>` and `<branch>` with your fork and the current branch name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ spec:
lifecycle: production
owner: group:default/museum-team
definition:
$text: https://raw.githubusercontent.com/DawMatt/backstage-apiportal-lab/004-lab-4-auto-registration/labs/lab-04-auto-registration/apis/precedence-demo/precedence-demo-openapi.yaml
$text: https://raw.githubusercontent.com/DawMatt/backstage-apiportal-lab/main/labs/lab-04-auto-registration/apis/precedence-demo/precedence-demo-openapi.yaml
23 changes: 17 additions & 6 deletions labs/lab-05-mocking-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ credential below) — do not reach for this setting for a proxy target that fron
In the root `package.json`:

```json
"start": "concurrently -n app,mocks \"backstage-cli repo start\" \"node scripts/mock-gateway.mjs\""
"start": "concurrently -n front,back,mocks \"yarn workspace app start\" \"yarn workspace backend start\" \"node scripts/mock-gateway.mjs\""
```

No `wait-on` sequencing is needed — the gateway's port and proxy target are static, committed
Expand All @@ -177,9 +177,15 @@ prevent by tearing down the whole session the moment the gateway exits.

## Step 5 — Add the `apiMocking` Frontend Module

### Step 5a — Copy the module file

Copy [`code/packages/app/src/modules/apiMocking/index.tsx`](code/packages/app/src/modules/apiMocking/index.tsx)
to `packages/app/src/modules/apiMocking/index.tsx`, then register it in `packages/app/src/App.tsx`
alongside Lab 3's modules:
to `packages/app/src/modules/apiMocking/index.tsx`.

### Step 5b — Register the module in `App.tsx`

In `packages/app/src/App.tsx`, add the import and module to the `features` array alongside
Lab 3's modules:

```ts
import { apiMockingModule } from './modules/apiMocking';
Expand Down Expand Up @@ -214,8 +220,11 @@ confirmed by reading its source rather than assumed:
`<SwaggerUI>`, *after* its own internal `spec={definitionString}` — so an extra `spec` prop
passed through the widget wins over the string-derived one.

This new config key also needs to be declared visible to the frontend bundle. Add
`packages/app/config.d.ts`:
This new config key also needs to be declared visible to the frontend bundle.

### Step 5c — Create `packages/app/config.d.ts`

Add `packages/app/config.d.ts`:

```ts
export interface Config {
Expand All @@ -230,7 +239,9 @@ export interface Config {
}
```

and add `"configSchema": "config.d.ts"` to `packages/app/package.json`. Without both, Backstage's
### Step 5d — Declare the config schema in `packages/app/package.json`

Add `"configSchema": "config.d.ts"` to `packages/app/package.json`. Without both Steps 5c and 5d, Backstage's
config-visibility filter silently strips `mocking.defaultCredential` before it reaches the
browser — `configApi.getOptional(...)` will just return `undefined`, with no error anywhere. This
was found by checking the `<script type="backstage.io/config">` payload the backend actually
Expand Down
Loading
Loading