feature/backstage #13
@@ -34,6 +34,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||||
|
|
||||||
- name: Run inline review
|
- name: Run inline review
|
||||||
uses: docker://nikitafilonov/ai-review:v0.64.0
|
uses: docker://nikitafilonov/ai-review:v0.64.0
|
||||||
|
|||||||
43
cluster-resources/backstage-keycloak-client-config.yaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Self-service Keycloak client config for Backstage.
|
||||||
|
# Kyverno clones this to the keycloak namespace, where the
|
||||||
|
# keycloak-client-registrar CronJob processes it and creates
|
||||||
|
# the backstage-oidc-credentials Secret in the backstage namespace.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: keycloak-client-backstage
|
||||||
|
namespace: backstage
|
||||||
|
labels:
|
||||||
|
keycloak.forteapps.net/client-config: "true"
|
||||||
|
stringData:
|
||||||
|
client.json: |
|
||||||
|
{
|
||||||
|
"clientId": "backstage",
|
||||||
|
"name": "Backstage Developer Portal",
|
||||||
|
"redirectUris": ["https://backstage.forteapps.net/api/auth/oidc/handler/frame"],
|
||||||
|
Ghost marked this conversation as resolved
|
|||||||
|
"webOrigins": ["https://backstage.forteapps.net"],
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Consider using a variable or ConfigMap for the domain to make this configuration environment-agnostic. #ai-review-inline Consider using a variable or ConfigMap for the domain to make this configuration environment-agnostic.
#ai-review-inline
|
|||||||
|
"defaultClientScopes": ["openid", "email", "profile"],
|
||||||
|
"protocolMappers": [
|
||||||
|
{
|
||||||
|
"name": "email_verified",
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"protocolMapper": "oidc-hardcoded-claim-mapper",
|
||||||
|
"config": {
|
||||||
|
"claim.name": "email_verified",
|
||||||
|
"claim.value": "true",
|
||||||
|
"jsonType.label": "boolean",
|
||||||
|
"id.token.claim": "true",
|
||||||
|
"access.token.claim": "true",
|
||||||
|
"userinfo.token.claim": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"secret": {
|
||||||
|
"namespace": "backstage",
|
||||||
|
"name": "backstage-oidc-credentials",
|
||||||
|
"keys": {
|
||||||
|
"clientId": "AUTH_OIDC_CLIENT_ID",
|
||||||
|
"clientSecret": "AUTH_OIDC_CLIENT_SECRET"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -965,6 +965,83 @@ ignore:
|
|||||||
- Check Gitea Actions tab for workflow run status and logs
|
- Check Gitea Actions tab for workflow run status and logs
|
||||||
- Monitor Anthropic usage dashboard for token consumption
|
- Monitor Anthropic usage dashboard for token consumption
|
||||||
|
|
||||||
|
### Backstage / RHDH (Developer Portal)
|
||||||
|
|
||||||
|
**Chart**: `backstage` (RHDH — Red Hat Developer Hub)
|
||||||
|
**Version**: `5.8.0`
|
||||||
|
**Namespace**: `backstage`
|
||||||
|
**Helm Repo**: `https://redhat-developer.github.io/rhdh-chart`
|
||||||
|
**Image**: `quay.io/rhdh-community/rhdh:next`
|
||||||
|
|
||||||
|
**Purpose**: Internal developer portal where teams register and broadcast themselves, their applications, APIs, and systems. Provides a unified catalog, templates, and documentation hub.
|
||||||
|
|
||||||
|
**Why RHDH over vanilla Backstage**: Ships 27+ plugins pre-bundled (ArgoCD, Kubernetes, Keycloak, GitHub, GitLab, Jira, SonarQube, Tekton, Jenkins, Quay, and more). Supports dynamic plugin installation at runtime — no image rebuilds needed.
|
||||||
|
|
||||||
|
**Configuration** (`infra/values/base/backstage-values.yaml`):
|
||||||
|
- OpenShift Route disabled (`route.enabled: false`) — uses Traefik ingress instead
|
||||||
|
- PostgreSQL subchart enabled for persistence (2Gi)
|
||||||
|
- SecurityContext configured for vanilla Kubernetes (non-OpenShift)
|
||||||
|
- Traefik ingress with `websecure` entrypoint
|
||||||
|
- App title: "Forte Developer Portal"
|
||||||
|
- Dynamic plugins: loads `dynamic-plugins.default.yaml` (all 27+ bundled plugins)
|
||||||
|
- Catalog rules: Component, System, API, Resource, Location, Template, Group, User, Domain
|
||||||
|
|
||||||
|
**Authentication** (Keycloak OIDC):
|
||||||
|
- Uses the self-service registrar pattern (see [Keycloak Client Registrar](#keycloak-client-registrar))
|
||||||
|
- Config Secret: `cluster-resources/backstage-keycloak-client-config.yaml`
|
||||||
|
- Kyverno clones it → registrar creates `backstage-oidc-credentials` Secret in `backstage` namespace
|
||||||
|
- Credential keys: `AUTH_OIDC_CLIENT_ID`, `AUTH_OIDC_CLIENT_SECRET` (loaded via `extraEnvVarsSecrets`)
|
||||||
|
- Redirect URI: `https://backstage.forteapps.net/api/auth/oidc/handler/frame`
|
||||||
|
- Sign-in resolver: `emailMatchingUserEntityProfileEmail`
|
||||||
|
|
||||||
|
**Catalog Discovery** (Gitea):
|
||||||
|
- Auto-discovers `catalog-info.yaml` from all repos in the `Forte` organization
|
||||||
|
- Scans every 30 minutes via the Gitea catalog provider plugin
|
||||||
|
- Gitea SCM integration configured for URL resolution (`git.forteapps.net`)
|
||||||
|
|
||||||
|
**Catalog Registration**:
|
||||||
|
Teams register services by adding a `catalog-info.yaml` to their repo root:
|
||||||
|
```yaml
|
||||||
|
apiVersion: backstage.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: my-service
|
||||||
|
description: My service description
|
||||||
|
annotations:
|
||||||
|
backstage.io/source-location: url:https://git.forteapps.net/Forte/my-service
|
||||||
|
spec:
|
||||||
|
type: service
|
||||||
|
lifecycle: production
|
||||||
|
owner: team-name
|
||||||
|
```
|
||||||
|
|
||||||
|
Repos with this file are auto-discovered — no manual registration needed.
|
||||||
|
|
||||||
|
**Dynamic Plugins**:
|
||||||
|
Add plugins at runtime via `global.dynamic.plugins` in values — no image rebuild:
|
||||||
|
```yaml
|
||||||
|
global:
|
||||||
|
dynamic:
|
||||||
|
plugins:
|
||||||
|
- package: "@scope/my-plugin@1.0.0"
|
||||||
|
integrity: "sha512-..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Per-cluster Configuration** (`infra/values/upc-dev/backstage-values.yaml`):
|
||||||
|
```yaml
|
||||||
|
global:
|
||||||
|
host: backstage.forteapps.net
|
||||||
|
upstream:
|
||||||
|
backstage:
|
||||||
|
appConfig:
|
||||||
|
app:
|
||||||
|
baseUrl: https://backstage.forteapps.net
|
||||||
|
backend:
|
||||||
|
baseUrl: https://backstage.forteapps.net
|
||||||
|
ingress:
|
||||||
|
host: backstage.forteapps.net
|
||||||
|
```
|
||||||
|
|
||||||
### Keycloak Client Registrar
|
### Keycloak Client Registrar
|
||||||
|
|
||||||
**Type**: CronJob (deployed via Keycloak Helm chart `extraDeploy`)
|
**Type**: CronJob (deployed via Keycloak Helm chart `extraDeploy`)
|
||||||
|
|||||||
43
infra/base/backstage.yaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: backstage
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: backstage
|
||||||
|
app.kubernetes.io/part-of: developer-portal
|
||||||
|
app.kubernetes.io/managed-by: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- repoURL: https://redhat-developer.github.io/rhdh-chart
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
External Helm repository should be verified for security and reliability. #ai-review-inline External Helm repository should be verified for security and reliability.
#ai-review-inline
|
|||||||
|
chart: backstage
|
||||||
|
targetRevision: "5.8.0"
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Consider pinning to a specific chart version digest instead of semantic version for better security and reproducibility. #ai-review-inline Consider pinning to a specific chart version digest instead of semantic version for better security and reproducibility.
#ai-review-inline
|
|||||||
|
helm:
|
||||||
|
releaseName: backstage
|
||||||
|
valueFiles:
|
||||||
|
- $values/infra/values/base/backstage-values.yaml
|
||||||
|
- $values/infra/values/upc-dev/backstage-values.yaml
|
||||||
|
|
||||||
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
SSH Git URL exposes internal infrastructure details and may create dependency issues. #ai-review-inline SSH Git URL exposes internal infrastructure details and may create dependency issues.
#ai-review-inline
|
|||||||
|
targetRevision: HEAD
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Using HEAD for targetRevision can cause unexpected deployments when main branch changes. #ai-review-inline Using HEAD for targetRevision can cause unexpected deployments when main branch changes.
```suggestion
targetRevision: "main"
```
#ai-review-inline
|
|||||||
|
ref: values
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: backstage
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
allowEmpty: false
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- Validate=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -22,3 +22,4 @@ resources:
|
|||||||
- tempo.yaml
|
- tempo.yaml
|
||||||
- grafana-dashboards.yaml
|
- grafana-dashboards.yaml
|
||||||
- network-policies-application.yaml
|
- network-policies-application.yaml
|
||||||
|
- backstage.yaml
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Consider verifying that backstage.yaml exists in the same directory to avoid kustomize build errors. #ai-review-inline Consider verifying that backstage.yaml exists in the same directory to avoid kustomize build errors.
#ai-review-inline
|
|||||||
|
|||||||
128
infra/values/base/backstage-values.yaml
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# Red Hat Developer Hub (RHDH) - Internal Developer Portal
|
||||||
|
# Helm chart: https://github.com/redhat-developer/rhdh-chart
|
||||||
|
# Includes 27+ plugins out of the box: ArgoCD, Kubernetes, Keycloak,
|
||||||
|
# GitHub, GitLab, Jira, SonarQube, Tekton, Jenkins, and more.
|
||||||
|
|
||||||
|
global:
|
||||||
|
auth:
|
||||||
|
backend:
|
||||||
|
enabled: true
|
||||||
|
dynamic:
|
||||||
|
includes:
|
||||||
|
- dynamic-plugins.default.yaml
|
||||||
|
plugins: []
|
||||||
|
|
||||||
|
# Disable OpenShift Route (not on OpenShift)
|
||||||
|
route:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
upstream:
|
||||||
|
backstage:
|
||||||
|
image:
|
||||||
|
registry: quay.io
|
||||||
|
repository: rhdh-community/rhdh
|
||||||
|
tag: next
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Using 'next' tag is unstable for production deployments; prefer a specific version tag or digest. #ai-review-inline Using 'next' tag is unstable for production deployments; prefer a specific version tag or digest.
```suggestion
tag: "1.0.0" # Replace with specific stable version
```
#ai-review-inline
|
|||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
runAsUser: 1001
|
||||||
|
runAsGroup: 1001
|
||||||
|
fsGroup: 1001
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 1Gi
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 2560Mi
|
||||||
|
|
||||||
|
extraEnvVarsSecrets:
|
||||||
|
- backstage-oidc-credentials
|
||||||
|
|
||||||
|
appConfig:
|
||||||
|
app:
|
||||||
|
title: "Forte Backstage"
|
||||||
|
baseUrl: http://localhost:7007
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Hardcoded localhost URL will break in Kubernetes deployment; use proper ingress URL or environment variable. #ai-review-inline Hardcoded localhost URL will break in Kubernetes deployment; use proper ingress URL or environment variable.
```suggestion
baseUrl: https://backstage.forteapps.net
```
#ai-review-inline
|
|||||||
|
|
||||||
|
backend:
|
||||||
|
baseUrl: http://localhost:7007
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Hardcoded localhost URL will break in Kubernetes deployment; use proper service URL or environment variable. #ai-review-inline Hardcoded localhost URL will break in Kubernetes deployment; use proper service URL or environment variable.
```suggestion
baseUrl: https://backstage.forteapps.net
```
#ai-review-inline
|
|||||||
|
|
||||||
|
# -- Keycloak OIDC authentication
|
||||||
|
signInPage: oidc
|
||||||
|
auth:
|
||||||
|
environment: production
|
||||||
|
providers:
|
||||||
|
oidc:
|
||||||
|
production:
|
||||||
|
metadataUrl: https://id.forteapps.net/realms/forte/.well-known/openid-configuration
|
||||||
|
clientId: ${AUTH_OIDC_CLIENT_ID}
|
||||||
|
clientSecret: ${AUTH_OIDC_CLIENT_SECRET}
|
||||||
|
prompt: auto
|
||||||
|
signIn:
|
||||||
|
resolvers:
|
||||||
|
- resolver: emailMatchingUserEntityProfileEmail
|
||||||
|
|
||||||
|
# -- Gitea SCM integration (for catalog URL resolution)
|
||||||
|
integrations:
|
||||||
|
gitea:
|
||||||
|
- host: git.forteapps.net
|
||||||
|
|
||||||
|
# -- Software catalog
|
||||||
|
catalog:
|
||||||
|
rules:
|
||||||
|
- allow:
|
||||||
|
- Component
|
||||||
|
- System
|
||||||
|
- API
|
||||||
|
- Resource
|
||||||
|
- Location
|
||||||
|
- Template
|
||||||
|
- Group
|
||||||
|
- User
|
||||||
|
- Domain
|
||||||
|
providers:
|
||||||
|
# Auto-discover catalog-info.yaml from all Forte org repos
|
||||||
|
gitea:
|
||||||
|
forte:
|
||||||
|
organization: Forte
|
||||||
|
host: git.forteapps.net
|
||||||
|
catalogPath: catalog-info.yaml
|
||||||
|
schedule:
|
||||||
|
frequency: { minutes: 30 }
|
||||||
|
timeout: { minutes: 3 }
|
||||||
|
locations:
|
||||||
|
# Backstage's own org data (bootstrap teams, systems, domains)
|
||||||
|
# - type: url
|
||||||
|
# target: https://git.forteapps.net/Forte/backstage-catalog/raw/branch/main/org.yaml
|
||||||
|
# rules:
|
||||||
|
# - allow: [Group, User, System, Domain]
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: traefik
|
||||||
|
annotations:
|
||||||
|
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: true
|
||||||
|
gitea_admin
commented
Missing TLS redirect configuration for secure HTTPS access. #ai-review-inline Missing TLS redirect configuration for secure HTTPS access.
```suggestion
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
```
#ai-review-inline
|
|||||||
|
image:
|
||||||
|
registry: docker.io
|
||||||
|
repository: library/postgres
|
||||||
|
tag: "15"
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 2Gi
|
||||||
|
podSecurityContext:
|
||||||
|
enabled: true
|
||||||
|
fsGroup: 26
|
||||||
|
runAsUser: 26
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
volumePermissions:
|
||||||
|
enabled: true
|
||||||
12
infra/values/upc-dev/backstage-values.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
global:
|
||||||
|
host: backstage.forteapps.net
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Host configuration appears twice which may cause conflicts or confusion in the Helm chart. #ai-review-inline Host configuration appears twice which may cause conflicts or confusion in the Helm chart.
#ai-review-inline
|
|||||||
|
|
||||||
|
upstream:
|
||||||
|
backstage:
|
||||||
|
appConfig:
|
||||||
|
app:
|
||||||
|
baseUrl: https://backstage.forteapps.net
|
||||||
|
Ghost marked this conversation as resolved
gitea_admin
commented
Backend baseUrl should typically use a different path or port than the frontend app baseUrl to avoid routing conflicts. #ai-review-inline Backend baseUrl should typically use a different path or port than the frontend app baseUrl to avoid routing conflicts.
```suggestion
baseUrl: https://backstage.forteapps.net/api
```
#ai-review-inline
|
|||||||
|
backend:
|
||||||
|
baseUrl: https://backstage.forteapps.net
|
||||||
|
ingress:
|
||||||
|
host: backstage.forteapps.net
|
||||||
Consider using a variable or ConfigMap for the domain to make this configuration environment-agnostic.
#ai-review-inline