diff --git a/.gitea/workflows/ai-review.yaml b/.gitea/workflows/ai-review.yaml index 667884c..bb03c3a 100644 --- a/.gitea/workflows/ai-review.yaml +++ b/.gitea/workflows/ai-review.yaml @@ -41,11 +41,11 @@ jobs: run: git submodule update --remote --merge - name: Run inline review - uses: docker://nikitafilonov/ai-review:v0.77.0 + uses: docker://nikitafilonov/ai-review:v1.4.0 with: args: ai-review run-inline - name: Run summary review - uses: docker://nikitafilonov/ai-review:v0.77.0 + uses: docker://nikitafilonov/ai-review:v1.4.0 with: args: ai-review run-summary diff --git a/.tofu/platforms/aks/dev/providers.tf b/.tofu/platforms/aks/dev/providers.tf index f24c50e..e27ada4 100644 --- a/.tofu/platforms/aks/dev/providers.tf +++ b/.tofu/platforms/aks/dev/providers.tf @@ -4,7 +4,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 4.0" + version = "~> 5.0" } } } diff --git a/.tofu/platforms/aks/modules/cluster/providers.tf b/.tofu/platforms/aks/modules/cluster/providers.tf index 0be1288..82fbaea 100644 --- a/.tofu/platforms/aks/modules/cluster/providers.tf +++ b/.tofu/platforms/aks/modules/cluster/providers.tf @@ -4,7 +4,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 4.0" + version = "~> 5.0" } azuread = { source = "hashicorp/azuread" diff --git a/.tofu/platforms/aks/prod/providers.tf b/.tofu/platforms/aks/prod/providers.tf index f24c50e..e27ada4 100644 --- a/.tofu/platforms/aks/prod/providers.tf +++ b/.tofu/platforms/aks/prod/providers.tf @@ -4,7 +4,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 4.0" + version = "~> 5.0" } } } diff --git a/.tofu/platforms/aks/workload/providers.tf b/.tofu/platforms/aks/workload/providers.tf index 29f7a8f..8f7110d 100644 --- a/.tofu/platforms/aks/workload/providers.tf +++ b/.tofu/platforms/aks/workload/providers.tf @@ -4,7 +4,7 @@ terraform { required_providers { azurerm = { source = "hashicorp/azurerm" - version = "~> 4.0" + version = "~> 5.0" } random = { source = "hashicorp/random" diff --git a/.tofu/platforms/gke/dev/providers.tf b/.tofu/platforms/gke/dev/providers.tf index 517d9eb..223966f 100644 --- a/.tofu/platforms/gke/dev/providers.tf +++ b/.tofu/platforms/gke/dev/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 6.0" + version = "~> 8.0" } } } diff --git a/.tofu/platforms/gke/modules/cluster/providers.tf b/.tofu/platforms/gke/modules/cluster/providers.tf index 3138f12..19a8321 100644 --- a/.tofu/platforms/gke/modules/cluster/providers.tf +++ b/.tofu/platforms/gke/modules/cluster/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 6.0" + version = "~> 8.0" } } } diff --git a/.tofu/platforms/gke/prod/providers.tf b/.tofu/platforms/gke/prod/providers.tf index f306689..cd7b10a 100644 --- a/.tofu/platforms/gke/prod/providers.tf +++ b/.tofu/platforms/gke/prod/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 6.0" + version = "~> 8.0" } } } diff --git a/.tofu/platforms/gke/workload/providers.tf b/.tofu/platforms/gke/workload/providers.tf index 1503c79..1a348af 100644 --- a/.tofu/platforms/gke/workload/providers.tf +++ b/.tofu/platforms/gke/workload/providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 6.0" + version = "~> 8.0" } } } diff --git a/cluster-resources/gitea-backup-cronjob.yaml b/cluster-resources/gitea-backup-cronjob.yaml index 41bdd55..4b817b2 100644 --- a/cluster-resources/gitea-backup-cronjob.yaml +++ b/cluster-resources/gitea-backup-cronjob.yaml @@ -29,7 +29,7 @@ spec: topologyKey: kubernetes.io/hostname initContainers: - name: gitea-dump - image: gitea/gitea:1.27.3 + image: gitea/gitea:28.0.0 command: - sh - -c diff --git a/docs/DEVELOPER-GUIDE.md b/docs/DEVELOPER-GUIDE.md index 0e9f5aa..0dfb810 100644 --- a/docs/DEVELOPER-GUIDE.md +++ b/docs/DEVELOPER-GUIDE.md @@ -1469,6 +1469,12 @@ ArgoCD will sync the Keycloak config, and the registrar CronJob will pick up the | `k8s.secret.client-id-key` | No | `client-id` | Field name for the client ID in the K8s Secret | | `k8s.secret.client-secret-key` | No | `client-secret` | Field name for the client secret in the K8s Secret | +#### Public CLI Client (Device-Code Login) + +`forte-cli` is a shared **public** client (no secret) with the RFC 8628 device-authorization grant enabled (`oauth2.device.authorization.grant.enabled: "true"`, `standardFlowEnabled: false`, `directAccessGrantsEnabled: false`). Downloaded skills and CLI tools that log in through the Auth Sidecar (forte-drop first) use it with `_CLIENT_ID=forte-cli`; nothing per-tool needs to be registered in Keycloak. + +It must be defined in `forte-realm.json` (this legacy path): the self-service registrar hardcodes `publicClient: false` / `standardFlowEnabled: true` and drops `attributes`, so a `client-config` Secret cannot produce a public device-code client. It carries no `k8s.secret.sync` attribute (the registrar's secret sync skips it) and is listed in the cleanup CronJob's protected clients. + ### Retrieving Secrets for External Deployments The registrar always writes a **central copy** of every synced secret to the `secrets` namespace, in addition to the target namespace. This allows operators to retrieve client credentials for applications deployed outside this cluster: diff --git a/infra/base/fluent-bit/fluent-bit.yaml b/infra/base/fluent-bit/fluent-bit.yaml index 8cca075..538c133 100644 --- a/infra/base/fluent-bit/fluent-bit.yaml +++ b/infra/base/fluent-bit/fluent-bit.yaml @@ -17,7 +17,7 @@ spec: sources: - repoURL: https://fluent.github.io/helm-charts chart: fluent-bit - targetRevision: 0.58.2 + targetRevision: 0.58.3 helm: releaseName: fluent-bit valueFiles: diff --git a/infra/base/opencost/opencost.yaml b/infra/base/opencost/opencost.yaml index e9ae10d..73b53a1 100644 --- a/infra/base/opencost/opencost.yaml +++ b/infra/base/opencost/opencost.yaml @@ -17,7 +17,7 @@ spec: sources: - repoURL: https://opencost.github.io/opencost-helm-chart chart: opencost - targetRevision: "1.43.2" + targetRevision: "2.5.32" helm: releaseName: opencost valueFiles: diff --git a/infra/values/base/keycloak-values.yaml b/infra/values/base/keycloak-values.yaml index 2e838a6..9e01070 100644 --- a/infra/values/base/keycloak-values.yaml +++ b/infra/values/base/keycloak-values.yaml @@ -186,6 +186,35 @@ keycloakConfigCli: } } ] + }, + { + "clientId": "forte-cli", + "name": "Forte CLI", + "description": "Shared public client for RFC 8628 device-code login from downloaded skills/CLI tools (forte-drop first) against services behind Auth Sidecar. No client secret.", + "enabled": true, + "protocol": "openid-connect", + "standardFlowEnabled": false, + "directAccessGrantsEnabled": false, + "publicClient": true, + "redirectUris": [], + "webOrigins": [], + "attributes": { + "oauth2.device.authorization.grant.enabled": "true" + }, + "protocolMappers": [ + { + "name": "audience-forte-drop-mcp", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.custom.audience": "https://mcp.drop.forteapps.net/mcp", + "access.token.claim": "true", + "id.token.claim": "false", + "introspection.token.claim": "true" + } + } + ] } ], "browserFlow": "browser-auto-idp", @@ -671,7 +700,7 @@ extraDeploy: MIN_AGE_SEC=$((MIN_AGE_DAYS * 86400)) # Hardcoded protected clients (never delete these) - PROTECTED_JSON='["gitea","grafana","argocd","vaultwarden","account","account-console","admin-cli","broker","realm-management","security-admin-console"]' + PROTECTED_JSON='["gitea","grafana","argocd","forte-cli","vaultwarden","account","account-console","admin-cli","broker","realm-management","security-admin-console"]' echo "Fetching clients from realm '${REALM}'..." CLIENTS=$(curl -sf -H "Authorization: Bearer ${TOKEN}" \