|
| 1 | +# X2Ansible Backstage Plugin |
| 2 | + |
| 3 | +Backstage plugin workspace providing a web UI for the [X2Ansible](https://github.com/x2ansible/x2a-convertor) project — LLM-powered migration of applications to Ansible playbooks. |
| 4 | + |
| 5 | +## Dev Environment |
| 6 | + |
| 7 | +Prerequisites: Node.js 22 or 24, Yarn. |
| 8 | + |
| 9 | +```sh |
| 10 | +yarn install |
| 11 | +``` |
| 12 | + |
| 13 | +Optional environment variables for OAuth sign-in (see `app-config.yaml` `auth:` section): |
| 14 | + |
| 15 | +```sh |
| 16 | +export AUTH_GITHUB_CLIENT_ID=... |
| 17 | +export AUTH_GITHUB_CLIENT_SECRET=... |
| 18 | +export AUTH_GITLAB_CLIENT_ID=... |
| 19 | +export AUTH_GITLAB_CLIENT_SECRET=... |
| 20 | +export AUTH_BITBUCKET_CLIENT_ID=... |
| 21 | +export AUTH_BITBUCKET_CLIENT_SECRET=... |
| 22 | +``` |
| 23 | + |
| 24 | +Start the frontend and backend plugins only: |
| 25 | + |
| 26 | +```sh |
| 27 | +yarn dev |
| 28 | +``` |
| 29 | + |
| 30 | +Start the full Backstage application (includes scaffolder, RBAC, catalog): |
| 31 | + |
| 32 | +```sh |
| 33 | +yarn start |
| 34 | +``` |
| 35 | + |
| 36 | +Frontend: `http://localhost:3000`, backend: `http://localhost:7007`. |
| 37 | + |
| 38 | +## Build |
| 39 | + |
| 40 | +```sh |
| 41 | +yarn build:all # Build all packages |
| 42 | +yarn build:backend # Build backend only |
| 43 | +yarn tsc:full # Full TypeScript check (no incremental) |
| 44 | +``` |
| 45 | + |
| 46 | +Build dynamic plugin OCI images: |
| 47 | + |
| 48 | +```sh |
| 49 | +./scripts/build-dynamic-plugins.sh # Build all |
| 50 | +./scripts/build-dynamic-plugins.sh --report # Print image report (no build) |
| 51 | +``` |
| 52 | + |
| 53 | +## Test |
| 54 | + |
| 55 | +Unit tests use Jest via `backstage-cli`. Backend tests require `NODE_OPTIONS='--experimental-vm-modules'` (already set in per-package scripts). |
| 56 | + |
| 57 | +```sh |
| 58 | +yarn test # Unit tests (SQLite only) |
| 59 | +yarn test:pg # Unit tests (SQLite + PostgreSQL via testcontainers, requires Docker/Podman) |
| 60 | +yarn test:all # Full suite: openapi-generate + prettier + lint + test --coverage |
| 61 | +yarn test:all:pg # Full suite with PostgreSQL |
| 62 | +``` |
| 63 | + |
| 64 | +Run a single package's tests: |
| 65 | + |
| 66 | +```sh |
| 67 | +yarn workspace @red-hat-developer-hub/backstage-plugin-x2a-backend test |
| 68 | +``` |
| 69 | + |
| 70 | +PostgreSQL tests use `testcontainers` and need `CI=true` plus a running Docker/Podman daemon. On Fedora/RHEL with Podman: |
| 71 | + |
| 72 | +```sh |
| 73 | +systemctl --user enable --now podman.socket |
| 74 | +export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock |
| 75 | +``` |
| 76 | + |
| 77 | +Test files live next to the source they test, named `*.test.ts` / `*.test.tsx`. |
| 78 | + |
| 79 | +E2E tests use Playwright (`packages/app/e2e-tests/`). Currently a placeholder — the scaffold is in place but no real tests yet. |
| 80 | + |
| 81 | +```sh |
| 82 | +yarn test:e2e # (skipped until tests exist) |
| 83 | +``` |
| 84 | + |
| 85 | +## Code Style |
| 86 | + |
| 87 | +Prettier config: `@backstage/cli/config/prettier`. ESLint config inherits from `../../.eslintrc.cjs` (root repo). |
| 88 | + |
| 89 | +```sh |
| 90 | +yarn prettier:check # Check formatting |
| 91 | +yarn prettier:fix # Fix formatting |
| 92 | +yarn lint # Lint changed packages (since origin/main) |
| 93 | +yarn lint:all # Lint all packages |
| 94 | +yarn lint:all --fix # Auto-fix lint issues |
| 95 | +``` |
| 96 | + |
| 97 | +Key lint rules (from root `.eslintrc.cjs`): |
| 98 | + |
| 99 | +- Copyright header required: `Copyright (The Backstage Authors|Red Hat, Inc.|...)`. |
| 100 | +- Use `.toLocaleLowerCase('en-US')` / `.toLocaleUpperCase('en-US')` instead of `.toLowerCase()` / `.toUpperCase()`. |
| 101 | +- Production code: avoid raw `<button>`, `<p>`, `<span>` — use Material UI components. |
| 102 | +- Avoid implicit globals — prefix with `window.`. |
| 103 | + |
| 104 | +Changesets are required for every user-facing change. Config: `.changeset/config.json`. |
| 105 | + |
| 106 | +## OpenAPI Code Generation |
| 107 | + |
| 108 | +The backend plugin defines its API in `plugins/x2a-backend/src/schema/openapi.yaml`. After editing, regenerate types: |
| 109 | + |
| 110 | +```sh |
| 111 | +yarn openapi-generate |
| 112 | +``` |
| 113 | + |
| 114 | +This generates: |
| 115 | + |
| 116 | +- Server types in `plugins/x2a-backend/src/schema/openapi/generated/` |
| 117 | +- Client types in `plugins/x2a-common/client/src/schema/openapi/generated/` |
| 118 | + |
| 119 | +Implement new endpoints in `plugins/x2a-backend/src/router/`. Import generated types from `./schema/openapi`. |
| 120 | + |
| 121 | +## Architecture |
| 122 | + |
| 123 | +This is a Yarn workspaces monorepo (`packages/*`, `plugins/*`). |
| 124 | + |
| 125 | +### Packages |
| 126 | + |
| 127 | +| Package | Role | npm name | |
| 128 | +| ------------------ | ---------------------- | --------- | |
| 129 | +| `packages/app` | Backstage frontend app | (private) | |
| 130 | +| `packages/backend` | Backstage backend app | (private) | |
| 131 | + |
| 132 | +### Plugins |
| 133 | + |
| 134 | +| Directory | Role | npm name | |
| 135 | +| --------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------- | |
| 136 | +| `plugins/x2a` | Frontend plugin | `@red-hat-developer-hub/backstage-plugin-x2a` | |
| 137 | +| `plugins/x2a-backend` | Backend plugin (REST API, K8s jobs, DB) | `@red-hat-developer-hub/backstage-plugin-x2a-backend` | |
| 138 | +| `plugins/x2a-common` | Shared library (types, domain objects, CSV parsing) | `@red-hat-developer-hub/backstage-plugin-x2a-common` | |
| 139 | +| `plugins/x2a-node` | Backend node library (service interfaces, refs) | `@red-hat-developer-hub/backstage-plugin-x2a-node` | |
| 140 | +| `plugins/x2a-dcr` | Frontend plugin for OAuth Dynamic Client Registration | `@red-hat-developer-hub/backstage-plugin-x2a-dcr` | |
| 141 | +| `plugins/x2a-mcp-extras` | Backend plugin exposing MCP tools | `@red-hat-developer-hub/backstage-plugin-x2a-mcp-extras` | |
| 142 | +| `plugins/scaffolder-backend-module-x2a` | Scaffolder module for project creation templates | `@red-hat-developer-hub/backstage-plugin-scaffolder-backend-module-x2a` | |
| 143 | + |
| 144 | +### Key directories inside plugins |
| 145 | + |
| 146 | +- `plugins/x2a-backend/src/router/` — REST API route handlers |
| 147 | +- `plugins/x2a-backend/src/services/` — Business logic (database, Kubernetes, etc.) |
| 148 | +- `plugins/x2a-backend/src/schema/openapi.yaml` — OpenAPI spec (source of truth for the API) |
| 149 | +- `plugins/x2a-backend/migrations/` — Knex database migrations (run automatically on start) |
| 150 | +- `plugins/x2a/src/components/` — React UI components |
| 151 | +- `plugins/x2a/src/hooks/` — React hooks |
| 152 | +- `plugins/x2a/src/translations/` — i18n translation strings |
| 153 | +- `plugins/x2a-common/src/domain/` — Domain value objects (`Phase`, `JobStatus`, `ArtifactKind`, `ProjectState`) |
| 154 | +- `plugins/x2a-common/src/scm/` — SCM provider detection logic |
| 155 | +- `plugins/x2a-common/src/csv/` — CSV bulk import parsing |
| 156 | + |
| 157 | +### Database |
| 158 | + |
| 159 | +Default: SQLite in-memory (local dev). Supports PostgreSQL via Knex.js. Config in `app-config.yaml` under `backend.database`. Migrations in `plugins/x2a-backend/migrations/` — naming pattern: `YYYYMMDDHH_description.ts`. |
| 160 | + |
| 161 | +### RBAC / Permissions |
| 162 | + |
| 163 | +Permission framework is enabled (`permission.enabled: true`). Two permission types: |
| 164 | + |
| 165 | +- `x2a.admin` — read/update all projects |
| 166 | +- `x2a.user` — read/update own projects |
| 167 | + |
| 168 | +Example policy: `examples/example-rbac-policy.csv`. |
| 169 | + |
| 170 | +## PR and Commit Conventions |
| 171 | + |
| 172 | +Commit messages follow `type(scope): description` — e.g. `feat(x2a): ...`, `fix(x2a): ...`, `chore(x2a): ...`. |
| 173 | + |
| 174 | +Every PR that changes published packages must include a changeset (`.changeset/`). Releases are managed via `@changesets/cli`. The `baseBranch` is `main`. |
| 175 | + |
| 176 | +## CI |
| 177 | + |
| 178 | +CI runs via `.github/workflows/ci.yml` on pull requests. For each changed workspace it runs (on Node 22 and 24): |
| 179 | + |
| 180 | +1. `yarn install --immutable` |
| 181 | +2. `yarn fix --check` |
| 182 | +3. `yarn backstage-cli config:check --lax` |
| 183 | +4. `yarn tsc:full` |
| 184 | +5. `yarn prettier:check` |
| 185 | +6. `yarn build:api-reports:only --ci` |
| 186 | +7. `yarn backstage-cli repo build --all` |
| 187 | +8. `yarn backstage-cli repo lint --since origin/main` |
| 188 | +9. `yarn backstage-cli repo fix --check --publish` |
| 189 | +10. `yarn test:all` (with coverage) |
| 190 | +11. Playwright tests (if `playwright.config.ts` exists) |
| 191 | +12. Clean working directory check |
| 192 | + |
| 193 | +A separate verify job checks lockfile duplicates and changesets. |
| 194 | + |
| 195 | +Run the full pre-CI check locally: |
| 196 | + |
| 197 | +```sh |
| 198 | +yarn chores # prettier:fix + lint:all --fix + tsc:full + build:api-reports + test:all:pg |
| 199 | +``` |
| 200 | + |
| 201 | +## Security |
| 202 | + |
| 203 | +- Credential management (LLM keys, AAP passwords) is handled via Kubernetes secrets — see `plugins/x2a-backend/src/services/`. Changes here require careful review. |
| 204 | +- RBAC permission checks live in `plugins/x2a-node/src/` and `plugins/x2a-backend/src/router/`. Verify permission logic when adding or changing endpoints. |
| 205 | +- OAuth token handling for SCM providers is in `plugins/x2a/src/repoAuth/` and `plugins/x2a/src/scaffolder/`. Tokens are stored as scaffolder secrets. |
0 commit comments