-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Leiðangr Phase 2 Backstage skeleton (DevEx envelope, OpenBao-to-Gitea catalog, TDD/BDD) #1
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
a7ea751
feat(envelope): tested doctor + Makefile DevEx targets
Cervator ea60b11
feat(config): local-override + env templates; config-check on the base
Cervator 2ca488b
test(bdd): checkpoint-1 stub-boot acceptance via jest-cucumber
Cervator fdc2584
feat(secrets): TDD'd dev-secrets logic + OpenBao OIDC orchestrator
Cervator 9f525f7
feat(gitea): Gitea catalog source overlay + checkpoint-2 BDD
Cervator d3d8044
docs(adr): capture skeleton architecture decisions (MADR v3)
Cervator d24cf8b
docs(dev): OpenBao to Gitea live-setup runbook (the @live checkpoint)
Cervator f1f8fa3
docs: human README + testing guide (DevEx onboarding)
Cervator 012af37
feat(gitea): live OpenBao to Gitea run wired + headless smoke + hosts…
Cervator 084b39a
chore(review): address CodeRabbit round 1 (security, correctness, doc…
Cervator a82b686
chore(review): address CodeRabbit + Copilot round 2 (fail-closed secr…
Cervator c3a885c
chore(review): assert fixture entity names + harden smoke-gitea (roun…
Cervator 0231cc3
fix(test): anchor the fixture-name contract assertions to the full line
Cervator 548baa8
test(contract): assert GITEA_USER wiring + exercise the missing-token…
Cervator File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # .env.example | ||
| # | ||
| # Environment variables referenced by app-config.yaml (${VAR}). | ||
| # Copy to .env.local (gitignored). In normal use the real values are rendered into | ||
| # .env.local by `make secrets` (OpenBao via browser OIDC) rather than hand-edited. | ||
| # | ||
| # Stub mode needs NONE of these — the app boots zero-secret without a .env.local. | ||
| # | ||
| # Gitea catalog source (local-secrets mode; rendered into .env.local by `make secrets`). | ||
| # Gitea auth is username + access-token-as-password: | ||
| GITEA_TOKEN= | ||
| GITEA_USER= | ||
| # | ||
| # GitHub integration (optional; the integration is simply inactive without a token): | ||
| GITHUB_TOKEN= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Shell scripts must stay LF so they run under bash on any checkout (incl. Windows). | ||
| *.sh text eol=lf | ||
| scripts/dev-secrets text eol=lf |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # AGENTS.md — Leiðangr (Backstage) | ||
|
|
||
| Agent-facing guidance for this component. The human entry point is [`README.md`](README.md); this file covers the conventions an agent should follow when changing the repo. | ||
|
|
||
| ## What this is | ||
|
|
||
| The Backstage control-plane for the Leiðangr stack — a local-first skeleton. Two run modes: **stub** (zero secrets, the default/CI path) and **Gitea** (catalog sourced from a private Gitea repo, authenticated by an OpenBao-sourced token). See [`README.md`](README.md) for the full picture and [`docs/adrs/`](docs/adrs/) for why. | ||
|
|
||
| ## Working here | ||
|
|
||
| - **Yarn runs through Corepack** — never assume a global `yarn`; use `make` / `corepack yarn`. (`corepack enable` needs admin on Windows; the Makefile avoids it.) | ||
| - **One command per workflow** via the `Makefile` (`doctor`/`dev`/`dev-gitea`/`smoke-gitea`/`test`/`test-app`/`lint`/`config-check`/`secrets`/`ci`). In the GDD workspace, `ws test leidangr` / `ws lint leidangr` run the same suites (allowlisted). | ||
| - **Secrets** only ever come from `make secrets` (OpenBao → gitignored `.env.local`); never hand-edit or commit secrets. The app reads only `${ENV}` references. | ||
| - **Gitea mode needs `gitea.localhost` in your hosts file** (Node doesn't resolve `*.localhost` like curl/git); `make dev-gitea` / `make smoke-gitea` preflight-check it and print the fix. | ||
|
|
||
| ## Testing | ||
|
|
||
| - **TDD** the pure tooling in `scripts/lib/*.ts` (`doctor`, `dev-secrets`) — tests are `*.test.ts`, write the test first. | ||
| - **BDD** acceptance specs are `tests/acceptance/*.feature` + `*.steps.ts` (jest-cucumber). Keep the Gherkin step text identical between feature and steps. Scenarios that assert on source/config/fixtures are named as *contract* checks; the real live behavior is `make smoke-gitea` (the `@live` path, tag-excluded from `make test`). | ||
| - Both run on `jest.envelope.config.cjs`, separate from `backstage-cli repo test` (`make test-app`). | ||
|
|
||
| ## Architecture Decision Records | ||
|
|
||
| **Capture durable architecture decisions as MADR ADRs in [`docs/adrs/`](docs/adrs/).** | ||
|
|
||
| Write an ADR when a decision is **costly to reverse** or a future contributor would otherwise **re-litigate** it — framework/system choices, the secret/auth model, the catalog source, the test strategy, the deployment shape. Do **not** ADR routine fixes, refactors, or bug fixes; those belong in the commit message. | ||
|
|
||
| Number sequentially (`NNNN-kebab-title.md`), use the MADR v3 shape (Context / Considered Options / Decision Outcome / Consequences), and add a row to [`docs/adrs/README.md`](docs/adrs/README.md). The `@backstage-community/plugin-adr` is deferred (GitHub-only today); ADRs live as files until a GitHub-readable source exists. | ||
|
|
||
| ## Pointers | ||
|
|
||
| - [`README.md`](README.md) — human quickstart, run modes, command table. | ||
| - [`docs/adrs/`](docs/adrs/) — decisions (start here to understand *why*). | ||
| - [`docs/development/openbao-setup.md`](docs/development/openbao-setup.md) — the live OpenBao → Gitea setup. | ||
| - [`docs/development/testing.md`](docs/development/testing.md) — the two test stacks and how to add a test. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # Leiðangr Backstage — DevEx envelope. | ||
| # One command per workflow. `yarn` is invoked via `corepack` so it works | ||
| # without a global install (Node ships Corepack; the pinned Yarn is in | ||
| # package.json `packageManager`). | ||
|
|
||
| # Recipes use bash so dotenv sourcing (dev-gitea) is portable across platforms. | ||
| SHELL := bash | ||
|
|
||
| COREPACK_ENABLE_DOWNLOAD_PROMPT ?= 0 | ||
| export COREPACK_ENABLE_DOWNLOAD_PROMPT | ||
|
|
||
| .PHONY: doctor deps dev dev-gitea smoke-gitea test test-app lint config-check secrets ci | ||
|
|
||
| ## doctor — check Node, Corepack, bao, and required dev ports (no secret values printed) | ||
| doctor: | ||
| node --disable-warning=MODULE_TYPELESS_PACKAGE_JSON scripts/lib/run-doctor.mjs | ||
|
|
||
| ## deps — install dependencies (immutable) | ||
| deps: | ||
| corepack yarn install --immutable | ||
|
|
||
| ## dev — start Backstage in stub mode (zero secrets) | ||
| dev: | ||
| corepack yarn start | ||
|
|
||
| ## dev-gitea — start Backstage with the Gitea catalog source (after `make secrets`) | ||
| dev-gitea: | ||
| node scripts/preflight-gitea.mjs | ||
| test -f .env.local || { echo "dev-gitea: no .env.local — run 'make secrets' first." >&2; exit 1; } | ||
| set -a; . ./.env.local; set +a; ROOT="$$(cygpath -m "$$PWD" 2>/dev/null || pwd)"; corepack yarn start --config "$$ROOT/app-config.yaml" --config "$$ROOT/app-config.gitea.yaml" | ||
|
|
||
| ## smoke-gitea — headless @live check: assert the Gitea entities ingest, then tear down | ||
| smoke-gitea: | ||
| node scripts/preflight-gitea.mjs | ||
| bash scripts/smoke-gitea.sh | ||
|
|
||
| ## test — envelope tooling + BDD acceptance (jest-cucumber) | ||
| test: | ||
| corepack yarn jest --config jest.envelope.config.cjs | ||
|
|
||
| ## test-app — the generated app/backend unit tests (backstage-cli) | ||
| test-app: | ||
| corepack yarn backstage-cli repo test | ||
|
|
||
| ## lint — repo lint across all workspaces | ||
| lint: | ||
| corepack yarn backstage-cli repo lint | ||
|
|
||
| ## config-check — validate the app-config (the base is the zero-secret dev/stub config) | ||
| config-check: | ||
| corepack yarn backstage-cli config:check --config app-config.yaml | ||
|
|
||
| ## secrets — render .env.local from OpenBao (browser OIDC login) | ||
| secrets: | ||
| bash scripts/dev-secrets | ||
|
|
||
| ## ci — the gate: config-check, lint, envelope tests | ||
| ci: config-check lint test | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,83 @@ | ||
| # [Backstage](https://backstage.io) | ||
| # Leiðangr (Backstage) | ||
|
|
||
| This is your newly scaffolded Backstage App, Good Luck! | ||
| The Backstage control-plane for the Leiðangr community-coordination stack. This is the Phase 2 **skeleton**: a fresh, modern Backstage instance with a strong local DevEx envelope. It runs entirely on your machine — with **zero secrets** by default — and can optionally pull a real secret from OpenBao to authenticate a Gitea-backed software catalog. | ||
|
|
||
| To start the app, run: | ||
| > `leidangr` is a working codename for this component; it may be renamed later. | ||
|
|
||
| ## What's here | ||
|
|
||
| - A modern Backstage app (new frontend + backend systems, Yarn 4 via Corepack). | ||
| - A thin **DevEx envelope** — one `make` command per workflow. | ||
| - Two run modes: **stub** (no secrets, the default) and **Gitea** (catalog sourced from an in-cluster Gitea repo, authenticated by a token fetched from OpenBao). | ||
| - Tests: TDD'd envelope tooling + BDD acceptance specs (jest-cucumber). | ||
| - Architecture decisions in [`docs/adrs/`](docs/adrs/). | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Node** Active LTS — 22 or 24 (see `.nvmrc`). Corepack ships with Node, so you do **not** need a global Yarn install; the `make` targets run Yarn through Corepack. | ||
| - **GNU Make** (the command entry points). | ||
| - *(Gitea mode only)* `kubectl` with access to the cluster running OpenBao/Keycloak/Gitea, and the **`bao`** CLI. The backend (Node) also needs **`gitea.localhost` to resolve** — unlike curl/git, Node does not special-case `*.localhost`, so add `127.0.0.1 gitea.localhost` to your hosts file. `make dev-gitea`/`make smoke-gitea` preflight-check this and print the exact fix if it's missing. See [`docs/development/openbao-setup.md`](docs/development/openbao-setup.md). | ||
| - *(Optional)* Docker, only if you want the prod-like Postgres instead of the default in-memory SQLite. | ||
|
|
||
| Run `make doctor` to check your toolchain. | ||
|
|
||
| ## Quickstart (stub mode — zero secrets) | ||
|
|
||
| ```sh | ||
| yarn install | ||
| yarn start | ||
| make deps # install dependencies (Corepack-managed Yarn) | ||
| make dev # start Backstage | ||
| ``` | ||
|
|
||
| Open http://localhost:3000. You're signed in as a guest and the example catalog is populated. No secrets, no cluster, no network required. | ||
|
|
||
| ## Run modes | ||
|
|
||
| | Mode | Command | What it is | | ||
| |---|---|---| | ||
| | **Stub** (default) | `make dev` | SQLite, guest auth, generated example catalog. Offline, zero secrets — the CI/contributor path. | | ||
| | **Gitea** | `make secrets` then `make dev-gitea` | Fetches a Gitea token from OpenBao (browser OIDC login via Keycloak) into a gitignored `.env.local`, then loads the Gitea catalog overlay so the catalog is sourced from a real Gitea repo. | | ||
| | **Deployed** | — | Future: in-cluster via External-Secrets-projected secrets. Out of scope for the skeleton. | | ||
|
|
||
| Gitea mode needs one-time setup (unseal OpenBao, seed the repo + KV) — see [`docs/development/openbao-setup.md`](docs/development/openbao-setup.md). | ||
|
|
||
| ### Secrets | ||
|
|
||
| Secrets are **never** committed and **never** hand-edited into config. `make secrets` is the only supported path: it logs you into OpenBao via your browser and renders a gitignored `.env.local`. The app reads only `${ENV}` references, so it never knows (or cares) which OpenBao — local or remote — the secret came from. Non-secret personal overrides go in `app-config.local.yaml` (copy from the `.example`). | ||
|
|
||
| ## Commands | ||
|
|
||
| | Command | Does | | ||
| |---|---| | ||
| | `make doctor` | Check Node, Corepack, `bao`, dev ports (never prints secret values) | | ||
| | `make deps` | Install dependencies | | ||
| | `make dev` | Start Backstage in stub mode | | ||
| | `make dev-gitea` | Start with the Gitea catalog overlay (after `make secrets`) | | ||
| | `make smoke-gitea` | Headless `@live` check: assert the Gitea entities ingest, then tear down | | ||
| | `make secrets` | Render `.env.local` from OpenBao (browser OIDC) | | ||
| | `make test` | Envelope tooling + BDD acceptance tests | | ||
| | `make test-app` | The generated app/backend unit tests | | ||
| | `make lint` | Lint the app workspaces | | ||
| | `make config-check` | Validate `app-config.yaml` | | ||
| | `make ci` | `config-check` + `lint` + `test` | | ||
|
|
||
| ## Testing | ||
|
|
||
| `make test` runs the **envelope** suite — the TDD'd tooling (`scripts/lib/*.ts`) and the BDD acceptance specs (`tests/acceptance/*.feature`, via jest-cucumber). It's a separate jest config from Backstage's own tests (`make test-app`). See [`docs/development/testing.md`](docs/development/testing.md) for how the two stacks fit together and how to add a test. | ||
|
|
||
| ## Layout | ||
|
|
||
| ```text | ||
| Makefile # DevEx entry points | ||
| app-config.yaml # base = zero-secret stub config | ||
| app-config.gitea.yaml # Gitea catalog overlay (Gitea mode only) | ||
| packages/app # frontend | ||
| packages/backend # backend | ||
| scripts/ # envelope tooling (doctor, dev-secrets) + lib tests | ||
| tests/acceptance/ # BDD feature files + step definitions | ||
| docs/adrs/ # architecture decision records (MADR) | ||
| docs/development/ # setup + testing guides | ||
| ``` | ||
|
|
||
| ## Using it in the GDD workspace (optional) | ||
|
|
||
| Inside the Yggdrasil/GDD workspace, `ws test leidangr` and `ws lint leidangr` run the same suites (allowlisted). Nothing here *depends* on the workspace, though — every command above works from a plain clone of this repo. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # app-config.gitea.yaml — Gitea catalog source overlay. | ||
| # | ||
| # Loaded ONLY in local-secrets mode (after `make secrets` renders .env.local with | ||
| # GITEA_USER + GITEA_TOKEN): run `make dev-gitea`. Deliberately kept OUT of the base | ||
| # app-config.yaml so the zero-secret stub boot never tries to reach Gitea. | ||
| # | ||
| # Backstage's Gitea integration authenticates with username + password; a Gitea | ||
| # access token is supplied as the password. | ||
| integrations: | ||
| gitea: | ||
| - host: gitea.localhost | ||
| baseUrl: http://gitea.localhost | ||
| username: ${GITEA_USER} | ||
| password: ${GITEA_TOKEN} | ||
|
|
||
| catalog: | ||
| locations: | ||
| - type: url | ||
| target: http://gitea.localhost/leidangr/catalog-seed/raw/branch/main/catalog-info.yaml | ||
| rules: | ||
| - allow: [Component, System, API, Resource, Location] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # app-config.local.yaml.example | ||
| # | ||
| # Copy to app-config.local.yaml (gitignored) for your PERSONAL, NON-SECRET local | ||
| # overrides. Backstage loads app-config.local.yaml automatically after app-config.yaml. | ||
| # | ||
| # Do NOT put secrets here. Secrets are rendered into .env.local by `make secrets` | ||
| # (from OpenBao) and consumed via ${ENV_VAR} references in app-config.yaml. | ||
| # | ||
| # Example overrides: | ||
| # | ||
| # app: | ||
| # title: Leiðangr (local) | ||
| # organization: | ||
| # name: SiliconSaga |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Modern Backstage systems + Corepack toolchain | ||
|
|
||
| - Status: accepted | ||
| - Date: 2026-06-27 | ||
| - Deciders: Cervator, Claude (Opus 4.8) | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| A fresh Backstage instance can start on the legacy or the new frontend/backend systems, and Yarn can be installed globally or run via Corepack. We want a modern, upgradeable base that a contributor can build without admin rights. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - New frontend + new backend systems (the `@backstage/create-app` defaults). | ||
| - Legacy/hybrid frontend with a compatibility bridge. | ||
| - Global Yarn install vs. Corepack-managed Yarn. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen: scaffold with `@backstage/create-app` on the **new frontend and backend systems**, Yarn 4 pinned via `package.json` `packageManager` and run through **Corepack** (no global install). Node is the current Active LTS (24; `engines: 22 || 24`), pinned via `.nvmrc`. | ||
|
|
||
| ### Consequences | ||
|
|
||
| - Good: modern, well-supported base; smaller upgrade debt; Corepack avoids the `corepack enable` admin write to `C:\Program Files\nodejs` (which fails without elevation) — every Makefile target invokes `corepack yarn`. | ||
| - Good: contributors need only Node; Yarn is provisioned on first use. | ||
| - Neutral: all envelope commands carry the `corepack yarn` prefix rather than a bare `yarn`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Zero-secret stub mode is the default | ||
|
|
||
| - Status: accepted | ||
| - Date: 2026-06-27 | ||
| - Deciders: Cervator, Claude (Opus 4.8) | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| Developers cloning only this repo, CI, and offline work all need Backstage to boot without secrets or a cluster. We must decide where the dev/stub configuration lives. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - Treat the base `app-config.yaml` as the stub/dev config. | ||
| - Add a separate `app-config.development.yaml` overlay for dev defaults. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen: **the base `app-config.yaml` is the zero-secret stub config** — SQLite (`:memory:`), `guest` auth, the generated example catalog, and the only env ref (`${GITHUB_TOKEN}`) optional. No separate `app-config.development.yaml`: `backstage-cli start` does not auto-load it, so it would be a dead file. Secrets and external integrations are additive overlays (see ADR 0004), never in the base. | ||
|
|
||
| ### Consequences | ||
|
|
||
| - Good: `git clone` → `make dev` boots offline with no secrets; CI and the BDD suite run against this mode. | ||
| - Good: one obvious config to reason about; deviates from the original plan's dev-overlay only because that overlay would never load. | ||
| - Bad/deferred: the base carries dev-only settings (guest auth, localhost CORS) that a future production deployment must override; production hardening is out of scope for the skeleton. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Provider-agnostic secrets via dev-secrets (OpenBao OIDC) | ||
|
|
||
| - Status: accepted | ||
| - Date: 2026-06-27 | ||
| - Deciders: Cervator, Claude (Opus 4.8) | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The local app needs a real secret (a Gitea token) from a central, multi-consumer OpenBao that may run on local k3s or on GKE. The app must not be coupled to the secret store; the zero-secret stub boot works without OpenBao, but `dev-secrets` still requires one reachable OpenBao (direct `BAO_ADDR` or a port-forward) to retrieve the secret. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - A `dev-secrets` script renders a gitignored `.env.local`; the app reads only `${ENV}`. | ||
| - External Secrets Operator projects a Kubernetes Secret that the app reads. | ||
| - The app reads OpenBao directly at runtime. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen: a single supported path, **`scripts/dev-secrets`**. It resolves the OpenBao target itself — a direct `BAO_ADDR` URL when set (the contributor path), else a `kubectl` port-forward (the cluster-owner path) — runs `bao login -method=oidc` (browser → the existing Keycloak), and renders the gitignored `.env.local`. The app consumes only environment variables and never learns which OpenBao backs it. The resolution/validation/render logic is pure and TDD'd; the orchestrator is thin IO glue. The ESO-projected-Secret approach is the future *deployed* path, not local dev; runtime-direct reads were rejected (couples the app to the store). | ||
|
|
||
| ### Consequences | ||
|
|
||
| - Good: the same Backstage runs against homelab or GKE (stub mode covers the no-OpenBao case); reproduces the "run one command, log in via browser, get a local secrets file" UX using infrastructure already run. No Consul — Backstage `$env`/`$file` replace runtime templating. | ||
| - Good: secrets only ever land in gitignored `.env.local`; key presence is logged, values never are. | ||
| - Note: the contributor (no-port-forward) path requires OpenBao itself reachable at a URL, so the live/GKE phase must expose OpenBao (TLS via the shipped wildcard, a Keycloak-group → read-only policy, short tokens, or Tailscale-only) — recorded for that phase, out of skeleton scope. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Gitea as the catalog source (overlay; GitHub deferred) | ||
|
|
||
| - Status: accepted | ||
| - Date: 2026-06-27 | ||
| - Deciders: Cervator, Claude (Opus 4.8) | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The skeleton needs a real catalog source that is authenticated by the OpenBao-sourced token, runs locally, and does not compromise the zero-secret stub boot (ADR 0002). | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - In-cluster Gitea as the source (token-authenticated), in an overlay. | ||
| - GitHub catalog discovery as the source. | ||
| - Put the Gitea location in the base config. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen: **in-cluster Gitea**, configured in `app-config.gitea.yaml` and loaded only in local-secrets mode (`make dev-gitea`). The Gitea integration authenticates with `username` + `password` (a Gitea access token is the password — the integration has no `token` field), from `${GITEA_USER}` / `${GITEA_TOKEN}`. The overlay is kept **out of the base** so the stub boot never tries to reach Gitea. GitHub integration is deferred to a later slice. | ||
|
|
||
| ### Consequences | ||
|
|
||
| - Good: local-first; the OpenBao secret is naturally a Gitea credential; stub mode is unaffected. | ||
| - Bad: the Backstage ADR plugin is GitHub-only today, so it cannot render these ADRs while Gitea is the only source (see docs/adrs/README.md) — the ADRs stay as files until a GitHub source exists. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Guest auth first; Keycloak sign-in deferred | ||
|
|
||
| - Status: accepted | ||
| - Date: 2026-06-27 | ||
| - Deciders: Cervator, Claude (Opus 4.8) | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The skeleton's focus is the OpenBao → Gitea catalog loop. Keycloak is already running (it backs OpenBao's OIDC auth). We must decide whether to also wire Keycloak as Backstage's sign-in now. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen: Backstage **sign-in stays `guest`** for the skeleton; wiring Keycloak's generic OIDC provider as Backstage's sign-in is a later slice. This keeps the first slice small and focused. | ||
|
|
||
| Important distinction: Keycloak **is** used in this slice — as the OIDC provider for OpenBao's `bao login -method=oidc` in `dev-secrets` (ADR 0003). What is deferred is Keycloak as the *Backstage user sign-in*, which is a separate concern. | ||
|
|
||
| ### Consequences | ||
|
|
||
| - Good: smaller first slice; no auth-resolver/sign-in-page wiring yet. | ||
| - Neutral: the distinction between "OpenBao OIDC auth (used)" and "Backstage sign-in (deferred)" must be kept clear in docs so the deferral isn't read as "Keycloak unused." |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.