Compare commits

..
Author SHA1 Message Date
d087472e63 Add forte-cli public device-code Keycloak client
AI Code Review / ai-review (pull_request) Skipped
scan.yaml / test (pull_request) Successful in 27s
Add a shared public client `forte-cli` to the `forte` realm so downloaded
skills (forte-drop first) can do RFC 8628 device-code login through the
Auth Sidecar. Today no client in the realm has the device grant enabled,
so the flow cannot start.

Client (inline in forte-realm.json, imported verbatim by keycloak-config-cli):
- publicClient: true, standardFlowEnabled: false,
  directAccessGrantsEnabled: false
- attributes: oauth2.device.authorization.grant.enabled=true
- no secret, no redirectUris/webOrigins, no k8s.secret.sync

It has to go in the realm JSON because the self-service registrar
hardcodes publicClient:false/standardFlowEnabled:true and drops
attributes. Also add forte-cli to the cleanup CronJob's protected list
(belt-and-braces; it does not match the UUID pattern anyway).

Additive only: gitea/grafana/argocd and all other realm settings are
unchanged. Keycloak is deployed only via the upc-dev overlay, which
inherits base values, so this lands on id.forteapps.net.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciXev3MtCxo3eomcfrDRW
2026-10-01 10:37:49 +00:00
21 changed files with 28 additions and 65 deletions
+2 -2
View File
@@ -41,11 +41,11 @@ jobs:
run: git submodule update --remote --merge run: git submodule update --remote --merge
- name: Run inline review - name: Run inline review
uses: docker://nikitafilonov/ai-review:v1.4.0 uses: docker://nikitafilonov/ai-review:v1.1.0
with: with:
args: ai-review run-inline args: ai-review run-inline
- name: Run summary review - name: Run summary review
uses: docker://nikitafilonov/ai-review:v1.4.0 uses: docker://nikitafilonov/ai-review:v1.1.0
with: with:
args: ai-review run-summary args: ai-review run-summary
+1 -1
View File
@@ -4,7 +4,7 @@ terraform {
required_providers { required_providers {
azurerm = { azurerm = {
source = "hashicorp/azurerm" source = "hashicorp/azurerm"
version = "~> 5.0" version = "~> 4.0"
} }
} }
} }
@@ -4,7 +4,7 @@ terraform {
required_providers { required_providers {
azurerm = { azurerm = {
source = "hashicorp/azurerm" source = "hashicorp/azurerm"
version = "~> 5.0" version = "~> 4.0"
} }
azuread = { azuread = {
source = "hashicorp/azuread" source = "hashicorp/azuread"
+1 -1
View File
@@ -4,7 +4,7 @@ terraform {
required_providers { required_providers {
azurerm = { azurerm = {
source = "hashicorp/azurerm" source = "hashicorp/azurerm"
version = "~> 5.0" version = "~> 4.0"
} }
} }
} }
+1 -1
View File
@@ -4,7 +4,7 @@ terraform {
required_providers { required_providers {
azurerm = { azurerm = {
source = "hashicorp/azurerm" source = "hashicorp/azurerm"
version = "~> 5.0" version = "~> 4.0"
} }
random = { random = {
source = "hashicorp/random" source = "hashicorp/random"
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 6.0" version = "~> 5.0"
} }
tls = { tls = {
source = "hashicorp/tls" source = "hashicorp/tls"
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 6.0" version = "~> 5.0"
} }
tls = { tls = {
source = "hashicorp/tls" source = "hashicorp/tls"
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 6.0" version = "~> 5.0"
} }
tls = { tls = {
source = "hashicorp/tls" source = "hashicorp/tls"
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 6.0" version = "~> 5.0"
} }
tls = { tls = {
source = "hashicorp/tls" source = "hashicorp/tls"
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
google = { google = {
source = "hashicorp/google" source = "hashicorp/google"
version = "~> 8.0" version = "~> 6.0"
} }
} }
} }
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
google = { google = {
source = "hashicorp/google" source = "hashicorp/google"
version = "~> 8.0" version = "~> 6.0"
} }
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
google = { google = {
source = "hashicorp/google" source = "hashicorp/google"
version = "~> 8.0" version = "~> 6.0"
} }
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@ terraform {
required_providers { required_providers {
google = { google = {
source = "hashicorp/google" source = "hashicorp/google"
version = "~> 8.0" version = "~> 6.0"
} }
} }
} }
+1 -1
View File
@@ -29,7 +29,7 @@ spec:
topologyKey: kubernetes.io/hostname topologyKey: kubernetes.io/hostname
initContainers: initContainers:
- name: gitea-dump - name: gitea-dump
image: gitea/gitea:28.0.0 image: gitea/gitea:1.27.3
command: command:
- sh - sh
- -c - -c
+1 -1
View File
@@ -17,7 +17,7 @@ spec:
sources: sources:
- repoURL: https://fluent.github.io/helm-charts - repoURL: https://fluent.github.io/helm-charts
chart: fluent-bit chart: fluent-bit
targetRevision: 0.58.3 targetRevision: 0.58.2
helm: helm:
releaseName: fluent-bit releaseName: fluent-bit
valueFiles: valueFiles:
+1 -1
View File
@@ -17,7 +17,7 @@ spec:
sources: sources:
- repoURL: https://grafana.github.io/helm-charts - repoURL: https://grafana.github.io/helm-charts
chart: grafana chart: grafana
targetRevision: "10.5.15" targetRevision: "8.15.0"
helm: helm:
releaseName: grafana releaseName: grafana
valueFiles: valueFiles:
+1 -1
View File
@@ -17,7 +17,7 @@ spec:
sources: sources:
- repoURL: https://prometheus-community.github.io/helm-charts - repoURL: https://prometheus-community.github.io/helm-charts
chart: prometheus chart: prometheus
targetRevision: "29.35.0" targetRevision: "28.16.0"
helm: helm:
releaseName: prometheus releaseName: prometheus
valueFiles: valueFiles:
@@ -24,7 +24,7 @@ spec:
sources: sources:
- repoURL: https://traefik.github.io/charts - repoURL: https://traefik.github.io/charts
chart: traefik chart: traefik
targetRevision: "41.6.0" targetRevision: "28.3.0"
helm: helm:
releaseName: traefik releaseName: traefik
valueFiles: valueFiles:
-14
View File
@@ -200,22 +200,8 @@ keycloakConfigCli:
"webOrigins": [], "webOrigins": [],
"attributes": { "attributes": {
"oauth2.device.authorization.grant.enabled": "true" "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", "browserFlow": "browser-auto-idp",
"authenticationFlows": [ "authenticationFlows": [
+2 -5
View File
@@ -4,17 +4,14 @@ opencost:
extraEnv: extraEnv:
EMIT_KSM_V1_METRICS: "false" EMIT_KSM_V1_METRICS: "false"
EMIT_KSM_V1_METRICS_ONLY: "true" EMIT_KSM_V1_METRICS_ONLY: "true"
# Cloud-specific pricing is in per-cluster value overrides
# (e.g. infra/values/upc-dev/opencost-values.yaml)
# NOTE: `prometheus` is a sibling of `exporter` under `opencost` in the
# chart's values schema - nesting it inside `exporter` silently falls back
# to the chart default namespace (prometheus-system).
prometheus: prometheus:
internal: internal:
enabled: true enabled: true
serviceName: prometheus-server serviceName: prometheus-server
namespaceName: monitoring namespaceName: monitoring
port: 80 port: 80
# Cloud-specific pricing is in per-cluster value overrides
# (e.g. infra/values/upc-dev/opencost-values.yaml)
ui: ui:
enabled: false enabled: false
service: service:
+2 -22
View File
@@ -4,12 +4,6 @@ server:
service: service:
servicePort: 80 servicePort: 80
strategy:
type: Recreate
retention: 7d
retentionSize: 6GB
resources: resources:
requests: requests:
cpu: 150m cpu: 150m
@@ -24,7 +18,7 @@ server:
extraScrapeConfigs: | extraScrapeConfigs: |
- job_name: kyverno - job_name: kyverno
scrape_interval: 60s scrape_interval: 15s
metrics_path: /metrics metrics_path: /metrics
kubernetes_sd_configs: kubernetes_sd_configs:
- role: endpoints - role: endpoints
@@ -41,16 +35,9 @@ extraScrapeConfigs: |
target_label: pod target_label: pod
- source_labels: [__meta_kubernetes_namespace] - source_labels: [__meta_kubernetes_namespace]
target_label: namespace target_label: namespace
metric_relabel_configs:
- source_labels: [__name__]
regex: 'kyverno_(http_requests_duration_seconds|controller_.+_duration_seconds|admission_review_duration_seconds)_bucket'
action: drop
- source_labels: [__name__]
regex: 'go_.*|process_.*'
action: drop
- job_name: traefik - job_name: traefik
scrape_interval: 60s scrape_interval: 15s
metrics_path: /metrics metrics_path: /metrics
kubernetes_sd_configs: kubernetes_sd_configs:
- role: endpoints - role: endpoints
@@ -67,13 +54,6 @@ extraScrapeConfigs: |
target_label: pod target_label: pod
- source_labels: [__meta_kubernetes_namespace] - source_labels: [__meta_kubernetes_namespace]
target_label: namespace target_label: namespace
metric_relabel_configs:
- source_labels: [__name__]
regex: 'traefik_(router|service|entrypoint)_request_duration_seconds_bucket'
action: drop
- source_labels: [__name__]
regex: 'go_.*|process_.*'
action: drop
alertmanager: alertmanager:
enabled: false enabled: false