2 Commits

Author SHA1 Message Date
5679dac549 pip fix 2026-04-18 20:35:54 +02:00
949c86eed0 docs 2026-04-18 20:29:43 +02:00
27 changed files with 272 additions and 515 deletions

View File

@@ -1,46 +0,0 @@
name: AI Code Review
on:
pull_request:
types: [ labeled, synchronize ]
jobs:
ai-review:
if: >-
(github.event.action == 'synchronized' && contains(toJSON(github.event.pull_request.labels), 'ai-review')) || contains(toJSON(gitea.event.changes.added_labels), 'ai-review')
runs-on: ubuntu-latest
env:
AI_REVIEW_CONFIG_FILE_YAML: ./shared-prompts/iac/.ai-review.yaml
# VCS configuration
VCS__PROVIDER: GITEA
VCS__PIPELINE__OWNER: ${{ github.repository_owner }}
VCS__PIPELINE__REPO: ${{ github.event.repository.name }}
VCS__PIPELINE__PULL_NUMBER: ${{ github.event.pull_request.number }}
VCS__HTTP_CLIENT__API_URL: https://git.forteapps.net/api/v1
VCS__HTTP_CLIENT__API_TOKEN: ${{ secrets.AI_REVIEW_TOKEN }}
# Review — disable fallback to see real Gitea API errors
REVIEW__INLINE_COMMENT_FALLBACK: "false"
# LLM configuration
LLM__PROVIDER: CLAUDE
LLM__META__MODEL: claude-sonnet-4-20250514
LLM__META__MAX_TOKENS: "4096"
LLM__HTTP_CLIENT__API_URL: https://api.anthropic.com
LLM__HTTP_CLIENT__API_TOKEN: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Run inline review
uses: docker://nikitafilonov/ai-review:v0.64.0
with:
args: ai-review run-inline
- name: Run summary review
uses: docker://nikitafilonov/ai-review:v0.64.0
with:
args: ai-review run-summary

View File

@@ -0,0 +1,32 @@
name: Deploy Gitea Pages
on:
push:
branches: [ main ]
paths:
- 'docs/**'
- 'mkdocs.yml'
- 'Dockerfile.docs'
- 'nginx.conf'
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: pip install mkdocs mkdocs-material
- run: mkdocs build
- name: Deploy to Gitea Pages
run: |
cd site
git init
git config user.name "gitea-actions"
git config user.email "actions@forteapps.net"
git add .
git commit -m "Deploy docs"
git push --force "https://x-token:${{ gitea.token }}@git.forteapps.net/Forte/launchpad.git" HEAD:gitea-pages

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "shared-prompts"]
path = shared-prompts
url = https://git.forteapps.net/Forte/ai-review-prompts.git

7
.project-standards.yaml Normal file
View File

@@ -0,0 +1,7 @@
standards_version: "2025.1"
last_configured: "2026-04-18"
components:
gitea-pages: "2025.1"
gitea-pages-generator: "mkdocs"
gitea-pages-source: "docs/"
gitea-pages-theme: "material"

View File

@@ -4,6 +4,7 @@
[![GitOps](https://img.shields.io/badge/GitOps-ArgoCD-blue)](https://argoproj.github.io/cd/) [![GitOps](https://img.shields.io/badge/GitOps-ArgoCD-blue)](https://argoproj.github.io/cd/)
[![Kubernetes](https://img.shields.io/badge/Kubernetes-UpCloud-orange)](https://upcloud.com/) [![Kubernetes](https://img.shields.io/badge/Kubernetes-UpCloud-orange)](https://upcloud.com/)
[![Docs](https://img.shields.io/badge/Docs-Gitea%20Pages-green)](https://git.forteapps.net/Forte/launchpad/pages/)
--- ---
@@ -11,6 +12,8 @@
**New developers and operators**: Please refer to our comprehensive documentation for detailed guides and references: **New developers and operators**: Please refer to our comprehensive documentation for detailed guides and references:
### 🌐 [**Live Documentation Site**](https://git.forteapps.net/Forte/launchpad/pages/) (Gitea Pages)
### 🎯 [**START HERE: Documentation Index**](docs/README.md) ### 🎯 [**START HERE: Documentation Index**](docs/README.md)
| Document | Description | Audience | | Document | Description | Audience |
@@ -82,6 +85,10 @@ This repository contains the complete GitOps configuration for our Kubernetes cl
. .
├── bootstrap.sh # Cluster initialization script ├── bootstrap.sh # Cluster initialization script
├── _app-of-apps.yaml # Root ArgoCD Application (App-of-Apps pattern) ├── _app-of-apps.yaml # Root ArgoCD Application (App-of-Apps pattern)
├── mkdocs.yml # MkDocs configuration (Gitea Pages)
├── .gitea/workflows/ # Gitea Actions CI workflows
│ └── docs.yaml # Build & deploy MkDocs to Gitea Pages
├── infra/ # Infrastructure ArgoCD Applications (Kustomize multi-cluster) ├── infra/ # Infrastructure ArgoCD Applications (Kustomize multi-cluster)
│ ├── base/ # Base ArgoCD Application manifests (EU defaults) │ ├── base/ # Base ArgoCD Application manifests (EU defaults)
@@ -146,12 +153,12 @@ This repository contains the complete GitOps configuration for our Kubernetes cl
|------------|---------|-----------|-----------| |------------|---------|-----------|-----------|
| **[launchpad](https://git.forteapps.net/Forte/launchpad)** (this repo) | ArgoCD Applications, cluster resources | Platform / DevOps engineers | ✅ Often | | **[launchpad](https://git.forteapps.net/Forte/launchpad)** (this repo) | ArgoCD Applications, cluster resources | Platform / DevOps engineers | ✅ Often |
| **[forte-helm](https://git.forteapps.net/Forte/forte-helm)** | Generic Helm chart templates | Platform engineers | ❌ Rarely | | **[forte-helm](https://git.forteapps.net/Forte/forte-helm)** | Generic Helm chart templates | Platform engineers | ❌ Rarely |
| **[helm-prod-values](ssh://git@git.forteapps.net:2222/Forte/helm-prod-values.git)** | App-specific configuration & versions | Developers / CI pipelines | ✅ Sometimes | | **[helm-values](ssh://git@git.forteapps.net:2222/Forte/helm-prod-values.git)** | App-specific configuration & versions | Developers / CI pipelines | ✅ Sometimes |
### GitOps Workflow ### GitOps Workflow
``` ```
Developer commits code → CI/CD builds image → Updates helm-prod-values → ArgoCD syncs → Deployed to cluster Developer commits code → CI/CD builds image → Updates helm-values → ArgoCD syncs → Deployed to cluster
``` ```
**Learn more**: [GitOps Architecture - GitOps Workflow](docs/GITOPS-ARCHITECTURE.md#gitops-workflow) **Learn more**: [GitOps Architecture - GitOps Workflow](docs/GITOPS-ARCHITECTURE.md#gitops-workflow)
@@ -166,7 +173,7 @@ Developer commits code → CI/CD builds image → Updates helm-prod-values → A
**Quick version**: **Quick version**:
1. Create `apps/myapp.yaml` (ArgoCD Application manifest) 1. Create `apps/myapp.yaml` (ArgoCD Application manifest)
2. Create `helm-prod-values/myapp/values.yaml` (configuration) 2. Create `helm-values/myapp/values.yaml` (configuration)
3. Create sealed secrets if needed 3. Create sealed secrets if needed
4. Commit and push - ArgoCD auto-syncs! 4. Commit and push - ArgoCD auto-syncs!
@@ -175,8 +182,8 @@ Developer commits code → CI/CD builds image → Updates helm-prod-values → A
**See detailed guide**: [Developer Guide - Updating an Existing Application](docs/DEVELOPER-GUIDE.md#updating-an-existing-application) **See detailed guide**: [Developer Guide - Updating an Existing Application](docs/DEVELOPER-GUIDE.md#updating-an-existing-application)
**Quick version**: **Quick version**:
- **Update code**: Push to app repo → CI/CD updates image tag in helm-prod-values - **Update code**: Push to app repo → CI/CD updates image tag in helm-values
- **Update config**: Edit `helm-prod-values/myapp/values.yaml` → commit → push - **Update config**: Edit `helm-values/myapp/values.yaml` → commit → push
### Manage Secrets ### Manage Secrets
@@ -204,7 +211,7 @@ git push
**Quick version**: **Quick version**:
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
# Token-based auth (simple) # Token-based auth (simple)
auth: auth:
@@ -344,6 +351,7 @@ kubectl patch application myapp -n argocd \
| **OpenCost** | Cost monitoring | `monitoring` | 1 | | **OpenCost** | Cost monitoring | `monitoring` | 1 |
| **Renovate** | Dependency updates | `renovate` | CronJob | | **Renovate** | Dependency updates | `renovate` | CronJob |
| **Trivy** | Vulnerability scanning | `trivy-system` | 1 | | **Trivy** | Vulnerability scanning | `trivy-system` | 1 |
| **Gitea Pages** | Documentation hosting | N/A (Gitea built-in) | N/A |
**Full specs**: [Technical Reference - Infrastructure Components](docs/REFERENCE.md#infrastructure-components) **Full specs**: [Technical Reference - Infrastructure Components](docs/REFERENCE.md#infrastructure-components)
@@ -366,7 +374,7 @@ kubectl patch application myapp -n argocd \
### Multi-Source Pattern ### Multi-Source Pattern
Applications reference both: Applications reference both:
1. **Helm charts** from `forte-helm` (templates) 1. **Helm charts** from `forte-helm` (templates)
2. **Values** from `helm-prod-values` (configuration) 2. **Values** from `helm-values` (configuration)
This separates reusable templates from environment-specific config. This separates reusable templates from environment-specific config.
@@ -435,7 +443,7 @@ Applications deploy in order using `argocd.argoproj.io/sync-wave`:
### Adding a New Application ### Adding a New Application
1. Read [Developer Guide - Deploying Your First Application](docs/DEVELOPER-GUIDE.md#deploying-your-first-application) 1. Read [Developer Guide - Deploying Your First Application](docs/DEVELOPER-GUIDE.md#deploying-your-first-application)
2. Create ArgoCD Application manifest in `apps/` 2. Create ArgoCD Application manifest in `apps/`
3. Create Helm values in `helm-prod-values/` 3. Create Helm values in `helm-values/`
4. Create sealed secrets if needed 4. Create sealed secrets if needed
5. Commit and push - ArgoCD handles the rest! 5. Commit and push - ArgoCD handles the rest!
@@ -485,8 +493,8 @@ Documentation lives in `docs/`. To update:
- [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) - [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets)
### Related Repositories ### Related Repositories
- [forte-helm](https://git.forteapps.net/Forte/forte-helm) - Helm chart templates - [forte-helm](https://github.com/fortedigital/forte-helm) - Helm chart templates
- [helm-prod-values](git@github.com:fortedigital/helm-prod-values.git) - Application values - [helm-values](git@github.com:fortedigital/helm-values.git) - Application values
--- ---
@@ -504,7 +512,7 @@ Internal use only. Not for public distribution.
--- ---
**Last Updated**: 2026-03-16 **Last Updated**: 2026-04-18
**Documentation Version**: 1.0.0 **Documentation Version**: 1.0.0
**🚀 Ready to get started? Check out the [Documentation Index](docs/README.md)!** **🚀 Ready to get started? Check out the [Documentation Index](docs/README.md)!**

View File

@@ -4,5 +4,5 @@ resources:
- dot-ai-stack.yaml - dot-ai-stack.yaml
- mcp10x.yaml - mcp10x.yaml
- musicman.yaml - musicman.yaml
- ts-mcp.yaml - mcpcoder.yaml
- argo-mcp.yaml - argo-mcp.yaml

View File

@@ -21,9 +21,9 @@ spec:
helm: helm:
releaseName: opencost releaseName: opencost
valueFiles: valueFiles:
- $values/infra/values/base/opencost-values.yaml - $values/infra/values/opencost-values.yaml
- repoURL: git@github.com:fortedigital/sturdy-adventure.git - repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
targetRevision: HEAD targetRevision: HEAD
ref: values ref: values

View File

@@ -1,40 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ts-mcp
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "11"
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: ""
notifications.argoproj.io/subscribe.on-sync-failed.slack: ""
notifications.argoproj.io/subscribe.on-degraded.slack: ""
labels:
app.kubernetes.io/name: ts-mcp
app.kubernetes.io/part-of: apps
app.kubernetes.io/managed-by: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
sources:
- repoURL: ssh://git@git.forteapps.net:2222/Forte/forte-helm.git
path: forteapp
targetRevision: HEAD
helm:
valueFiles:
- $values/ts-mcp/values.yaml
- repoURL: ssh://git@git.forteapps.net:2222/Forte/helm-prod-values.git
targetRevision: HEAD
ref: values
destination:
server: https://kubernetes.default.svc
namespace: ts-mcp
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

View File

@@ -2,7 +2,7 @@
# in case of $'\r': command not found error, run command below first # in case of $'\r': command not found error, run command below first
# sed -i 's/\r$//' ./bootstrap.sh # sed -i 's/\r$//' ./bootstrap.sh
CLUSTER="${1:?Usage: ./bootstrap.sh <cluster> (upc-dev|upc-prod)}" CLUSTER="${1:?Usage: ./bootstrap.sh <cluster> (eu|us)}"
echo "running $0 for cluster: ${CLUSTER}..." echo "running $0 for cluster: ${CLUSTER}..."
@@ -17,18 +17,18 @@ echo "Bootstrapping cluster: ${clusterName} (${CLUSTER})..."
Bootstrap() Bootstrap()
{ {
ArgoCd ArgoCd
# Gitea # Github
} }
############################################################ ############################################################
# Gitea # # Github #
############################################################ ############################################################
Gitea() Github()
{ {
echo "Installing secret..." echo "Installing secret..."
kubectl apply -f private/gitea-repo-main.yaml kubectl apply -f private/github-${CLUSTER}.yaml
kubectl apply -f private/main.key kubectl apply -f private/main-${CLUSTER}.key
} }
############################################################ ############################################################

View File

@@ -1,10 +1,10 @@
clusterName: prod-fd-no-svg1 clusterName: dev-fd-us-east1
domain: fortedigital.com domain: us.forteapps.net
argocdDomain: argocd.127.0.0.1.nip.io argocdDomain: argocd.us.forteapps.net
grafanaDomain: grafana.fortedigital.com grafanaDomain: grafana.us.forteapps.net
keycloakDomain: id.fortedigital.com keycloakDomain: id.us.forteapps.net
dotaiDomain: kubemcp.fortedigital.com dotaiDomain: kubemcp.us.forteapps.net
dotaiUiDomain: kubemcpui.fortedigital.com dotaiUiDomain: kubemcpui.us.forteapps.net
letsencryptEmail: danijel.simeunovic@fortedigital.com letsencryptEmail: danijels@gmail.com
trustedIPs: "172.16.1.0/24" trustedIPs: "10.0.0.0/16"
cloudProvider: upcloud cloudProvider: tbd

View File

@@ -11,6 +11,7 @@
- [Enabling Authentication for Applications](#enabling-authentication-for-applications) - [Enabling Authentication for Applications](#enabling-authentication-for-applications)
- [Adding a New Keycloak Client](#adding-a-new-keycloak-client) - [Adding a New Keycloak Client](#adding-a-new-keycloak-client)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Documentation](#documentation)
- [Best Practices](#best-practices) - [Best Practices](#best-practices)
--- ---
@@ -96,10 +97,10 @@ You'll need read/write access to these repositories:
cd launchpad cd launchpad
``` ```
2. **helm-prod-values** (Values repo) 2. **helm-values** (Values repo)
```bash ```bash
git clone https://git.forteapps.net/Forte/helm-prod-values.git git clone https://git.forteapps.net/Forte/helm-prod-values.git
cd helm-prod-values cd helm-values
``` ```
3. **forte-helm** (Chart repo - read-only for most developers) 3. **forte-helm** (Chart repo - read-only for most developers)
@@ -175,13 +176,13 @@ npm run dev
│ - GitHub Actions builds image │ │ - GitHub Actions builds image │
│ - Pushes to container registry (GHCR, Docker Hub) │ │ - Pushes to container registry (GHCR, Docker Hub) │
│ - Tags with version (e.g., v2.0.4) │ │ - Tags with version (e.g., v2.0.4) │
│ - Updates helm-prod-values repository with new tag │ │ - Updates helm-values repository with new tag │
└─────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────┐
│ Step 3: GitOps Sync (Automated) │ │ Step 3: GitOps Sync (Automated) │
│ - ArgoCD detects change in helm-prod-values │ │ - ArgoCD detects change in helm-values │
│ - Pulls updated configuration │ │ - Pulls updated configuration │
│ - Syncs to Kubernetes cluster │ │ - Syncs to Kubernetes cluster │
│ - Sends Slack notification on success/failure │ │ - Sends Slack notification on success/failure │
@@ -201,7 +202,7 @@ Our setup uses three repositories:
| Repository | Purpose | Who Edits | How Often | | Repository | Purpose | Who Edits | How Often |
|------------|---------|-----------|-----------| |------------|---------|-----------|-----------|
| **forte-helm** | Helm chart templates (generic, reusable) | Platform engineers | ❌ Rarely | | **forte-helm** | Helm chart templates (generic, reusable) | Platform engineers | ❌ Rarely |
| **helm-prod-values** | Application configuration (image tag, env vars) | Developers / CI pipelines | ✅ Sometimes | | **helm-values** | Application configuration (image tag, env vars) | Developers / CI pipelines | ✅ Sometimes |
| **launchpad** | ArgoCD Applications (what gets deployed) | Platform / DevOps engineers | ✅ Per new app | | **launchpad** | ArgoCD Applications (what gets deployed) | Platform / DevOps engineers | ✅ Per new app |
### Example: Deploying "myapp" ### Example: Deploying "myapp"
@@ -223,7 +224,7 @@ spec:
value: {{ .Values.app.port }} value: {{ .Values.app.port }}
``` ```
#### Repository: `helm-prod-values` (Your App Config) #### Repository: `helm-values` (Your App Config)
```yaml ```yaml
# myapp/values.yaml # myapp/values.yaml
# Your app's specific configuration # Your app's specific configuration
@@ -248,13 +249,13 @@ metadata:
namespace: argocd namespace: argocd
spec: spec:
sources: sources:
- repoURL: https://git.forteapps.net/Forte/forte-helm - repoURL: https://github.com/fortedigital/forte-helm
path: forteapp path: forteapp
helm: helm:
valueFiles: valueFiles:
- $values/myapp/values.yaml - $values/myapp/values.yaml
- repoURL: git@github.com:fortedigital/helm-prod-values.git - repoURL: git@github.com:fortedigital/helm-values.git
ref: values ref: values
destination: destination:
@@ -316,10 +317,10 @@ Ensure your app repository has:
docker build -t ghcr.io/fortedigital/hello-world:${{ steps.version.outputs.VERSION }} . docker build -t ghcr.io/fortedigital/hello-world:${{ steps.version.outputs.VERSION }} .
docker push ghcr.io/fortedigital/hello-world:${{ steps.version.outputs.VERSION }} docker push ghcr.io/fortedigital/hello-world:${{ steps.version.outputs.VERSION }}
- name: Update helm-prod-values - name: Update helm-values
run: | run: |
git clone git@github.com:fortedigital/helm-prod-values.git git clone git@github.com:fortedigital/helm-values.git
cd helm-prod-values cd helm-values
mkdir -p hello-world mkdir -p hello-world
cat > hello-world/values.yaml <<EOF cat > hello-world/values.yaml <<EOF
app: app:
@@ -334,7 +335,7 @@ Ensure your app repository has:
### Step 2: Create Helm Values ### Step 2: Create Helm Values
Create a folder in `helm-prod-values` repository: Create a folder in `helm-values` repository:
```bash ```bash
cd ~/dev/k8s/helm-prod-values cd ~/dev/k8s/helm-prod-values
@@ -412,7 +413,7 @@ spec:
sources: sources:
# Source 1: Helm chart templates # Source 1: Helm chart templates
- repoURL: https://git.forteapps.net/Forte/forte-helm - repoURL: https://github.com/fortedigital/forte-helm
path: forteapp path: forteapp
targetRevision: HEAD targetRevision: HEAD
helm: helm:
@@ -420,7 +421,7 @@ spec:
- $values/hello-world/values.yaml - $values/hello-world/values.yaml
# Source 2: Helm values # Source 2: Helm values
- repoURL: git@github.com:fortedigital/helm-prod-values.git - repoURL: git@github.com:fortedigital/helm-values.git
targetRevision: HEAD targetRevision: HEAD
ref: values ref: values
@@ -528,7 +529,7 @@ git push origin main
2. ✅ Builds new Docker image 2. ✅ Builds new Docker image
3. ✅ Tags with new version (e.g., `v20260316-143022`) 3. ✅ Tags with new version (e.g., `v20260316-143022`)
4. ✅ Pushes to container registry 4. ✅ Pushes to container registry
5. ✅ Updates `helm-prod-values/myapp/values.yaml` with new tag 5. ✅ Updates `helm-values/myapp/values.yaml` with new tag
6. ✅ ArgoCD detects change 6. ✅ ArgoCD detects change
7. ✅ Syncs new version to cluster 7. ✅ Syncs new version to cluster
8. ✅ Sends Slack notification 8. ✅ Sends Slack notification
@@ -683,7 +684,7 @@ git push
#### Step 4: Reference Secret in Application #### Step 4: Reference Secret in Application
Update your `helm-prod-values/myapp/values.yaml`: Update your `helm-values/myapp/values.yaml`:
```yaml ```yaml
app: app:
@@ -791,7 +792,7 @@ Three authentication modes are supported:
#### Step 1: Configure Helm Values #### Step 1: Configure Helm Values
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
auth: auth:
enabled: true enabled: true
type: token # Token mode (default) type: token # Token mode (default)
@@ -913,7 +914,7 @@ rm private/myapp-auth-oidc.yaml
#### Step 3: Configure Helm Values #### Step 3: Configure Helm Values
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
auth: auth:
enabled: true enabled: true
type: oidc # OIDC mode type: oidc # OIDC mode
@@ -962,46 +963,6 @@ User sees application (authenticated)
--- ---
### Accessing Authenticated User Information
The auth sidecar handles all authentication before requests reach your application. Your app never sees unauthenticated traffic — the sidecar returns 401 or redirects to the IdP first.
After successful authentication, the sidecar forwards the request to your application with user identity injected as HTTP headers:
| Header | Description | Available in |
|--------|-------------|-------------|
| `X-Auth-User` | Username or display name | Token, OIDC, MCP |
| `X-Auth-Email` | User email address | OIDC |
| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP |
| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if scope includes `groups`) |
| `X-Auth-Token` | The validated access token | All modes |
**Your application reads these headers — no auth library needed:**
```javascript
// Express.js example
app.get('/profile', (req, res) => {
const user = req.headers['x-auth-user'];
const email = req.headers['x-auth-email'];
res.json({ user, email });
});
```
```python
# Flask example
@app.route('/profile')
def profile():
user = request.headers.get('X-Auth-User')
email = request.headers.get('X-Auth-Email')
return jsonify(user=user, email=email)
```
**Why this is safe**: The Kyverno-generated NetworkPolicy restricts ingress to the sidecar port only. Traffic cannot bypass the sidecar to reach the application port directly, so the `X-Auth-*` headers can be trusted unconditionally.
**Key principle**: Your application is zero-trust-unaware by design. It reads headers and renders UI. All authentication complexity lives in the sidecar and Kyverno policy.
---
### Authentication Configuration Reference ### Authentication Configuration Reference
#### Helm Values Schema #### Helm Values Schema
@@ -1089,7 +1050,7 @@ policies.forteapps.io/auth-image-version: "v1.2.3"
#### Example 1: Internal API with Token Auth #### Example 1: Internal API with Token Auth
```yaml ```yaml
# helm-prod-values/internal-api/values.yaml # helm-values/internal-api/values.yaml
app: app:
image: image:
repository: ghcr.io/company/internal-api repository: ghcr.io/company/internal-api
@@ -1117,7 +1078,7 @@ curl -H "Authorization: Bearer d4f88f..." \
#### Example 2: User-Facing App with OIDC #### Example 2: User-Facing App with OIDC
```yaml ```yaml
# helm-prod-values/web-app/values.yaml # helm-values/web-app/values.yaml
app: app:
image: image:
repository: ghcr.io/company/web-app repository: ghcr.io/company/web-app
@@ -1152,7 +1113,7 @@ kubectl create secret generic auth-oidc \
#### Example 3: MCP Server with OAuth 2.0 #### Example 3: MCP Server with OAuth 2.0
```yaml ```yaml
# helm-prod-values/mcp-server/values.yaml # helm-values/mcp-server/values.yaml
app: app:
image: image:
repository: ghcr.io/company/mcp-server repository: ghcr.io/company/mcp-server
@@ -1176,7 +1137,7 @@ The MCP auth mode implements RFC 9728 (OAuth 2.0 Protected Resource Metadata) fo
#### Example 4: Disabling Authentication #### Example 4: Disabling Authentication
```yaml ```yaml
# helm-prod-values/public-api/values.yaml # helm-values/public-api/values.yaml
auth: auth:
enabled: false # No authentication enabled: false # No authentication
@@ -1540,7 +1501,7 @@ kubectl exec -n myapp <pod-name> -- env
# Check if secrets exist # Check if secrets exist
kubectl get secrets -n myapp kubectl get secrets -n myapp
# Increase resources in helm-prod-values # Increase resources in helm-values
vim ~/dev/k8s/helm-prod-values/myapp/values.yaml vim ~/dev/k8s/helm-prod-values/myapp/values.yaml
``` ```
@@ -1667,6 +1628,47 @@ If you're stuck:
--- ---
## Documentation
This repository's documentation is built with [MkDocs](https://www.mkdocs.org/) using the [Material](https://squidfund.github.io/mkdocs-material/) theme and published automatically to Gitea Pages.
### Viewing the Docs
The live documentation site is available at:
**https://git.forteapps.net/Forte/launchpad/pages/**
### Editing Documentation
All documentation source files live in the `docs/` directory as Markdown. To make changes:
1. Edit the relevant `.md` file in `docs/`
2. Commit and push to `main`
3. The Gitea Actions workflow automatically rebuilds and deploys the site
### Local Preview
To preview documentation changes locally before pushing:
```bash
# Install dependencies (one-time)
pip install mkdocs mkdocs-material
# Start the local dev server
mkdocs serve
```
Then open `http://127.0.0.1:8000` in your browser. The server live-reloads on file changes.
### How It Works
- **Workflow**: `.gitea/workflows/docs.yaml` triggers on pushes to `main` that change `docs/**`, `mkdocs.yml`, `Dockerfile.docs`, or `nginx.conf`
- **Build**: Installs MkDocs + Material theme, runs `mkdocs build`
- **Deploy**: Force-pushes the built `site/` directory to the `gitea-pages` branch
- **Serve**: Gitea Pages serves the static site from the `gitea-pages` branch
---
## Best Practices ## Best Practices
### Development Workflow ### Development Workflow
@@ -1689,7 +1691,7 @@ If you're stuck:
### Configuration Management ### Configuration Management
✅ **DO**: ✅ **DO**:
- Keep configuration in `helm-prod-values` repository - Keep configuration in `helm-values` repository
- Use environment variables for config - Use environment variables for config
- Document what each value does - Document what each value does
- Use reasonable resource limits - Use reasonable resource limits

View File

@@ -47,7 +47,7 @@ This Kubernetes cluster uses a **GitOps approach** powered by **ArgoCD**, where
│ │ │ │ │ │
│ │ │ │ │ │
└────────► Update image tag ─┴──────────────────────────┘ └────────► Update image tag ─┴──────────────────────────┘
in helm-prod-values │ in helm-values │
┌────────────────────────────────┐ ┌────────────────────────────────┐
@@ -184,7 +184,7 @@ launchpad/
--- ---
### 2. **Helm Charts Repository** ### 2. **Helm Charts Repository**
**Repository**: `https://git.forteapps.net/Forte/forte-helm` **Repository**: `https://github.com/fortedigital/forte-helm`
**Purpose**: Reusable Helm chart templates for Forte applications **Purpose**: Reusable Helm chart templates for Forte applications
**Location**: `C:\dev\k8s\forte-helm` **Location**: `C:\dev\k8s\forte-helm`
@@ -218,7 +218,7 @@ forte-helm/
--- ---
### 3. **Helm Values Repository** ### 3. **Helm Values Repository**
**Repository**: `git@github.com:fortedigital/helm-prod-values.git` **Repository**: `git@github.com:fortedigital/helm-values.git`
**Purpose**: Environment-specific configuration for each application **Purpose**: Environment-specific configuration for each application
**Location**: `C:\dev\k8s\helm-prod-values` **Location**: `C:\dev\k8s\helm-prod-values`
@@ -228,6 +228,8 @@ helm-prod-values/
│ └── values.yaml # MCP 10X configuration │ └── values.yaml # MCP 10X configuration
├── musicman/ ├── musicman/
│ └── values.yaml # Music Man configuration │ └── values.yaml # Music Man configuration
├── mcpcoder/
│ └── values.yaml # MCP Coder configuration
└── argocd-mcp/ └── argocd-mcp/
└── values.yaml # ArgoCD MCP configuration └── values.yaml # ArgoCD MCP configuration
``` ```
@@ -277,7 +279,7 @@ app-repository/
2. Build Docker image 2. Build Docker image
3. Tag with version (e.g., `v2.0.4`) 3. Tag with version (e.g., `v2.0.4`)
4. Push to container registry (GHCR, Docker Hub, etc.) 4. Push to container registry (GHCR, Docker Hub, etc.)
5. Update image tag in `helm-prod-values` repository 5. Update image tag in `helm-values` repository
6. ArgoCD detects change and syncs automatically 6. ArgoCD detects change and syncs automatically
--- ---
@@ -338,13 +340,13 @@ Applications like `mcp10x` and `musicman` use multiple sources:
```yaml ```yaml
spec: spec:
sources: sources:
- repoURL: https://git.forteapps.net/Forte/forte-helm - repoURL: https://github.com/fortedigital/forte-helm
path: forteapp # Helm chart templates path: forteapp # Helm chart templates
helm: helm:
valueFiles: valueFiles:
- $values/mcp10x/values.yaml # Reference to second source - $values/mcp10x/values.yaml # Reference to second source
- repoURL: git@github.com:fortedigital/helm-prod-values.git - repoURL: git@github.com:fortedigital/helm-values.git
targetRevision: HEAD targetRevision: HEAD
ref: values # Named reference ref: values # Named reference
``` ```
@@ -412,8 +414,8 @@ jobs:
- name: Update Helm values - name: Update Helm values
run: | run: |
git clone git@github.com:fortedigital/helm-prod-values.git git clone git@github.com:fortedigital/helm-values.git
cd helm-prod-values/app cd helm-values/app
sed -i "s/tag: .*/tag: $VERSION/" values.yaml sed -i "s/tag: .*/tag: $VERSION/" values.yaml
git commit -am "Update app to $VERSION" git commit -am "Update app to $VERSION"
git push git push
@@ -430,7 +432,7 @@ jobs:
- Syncs application to cluster - Syncs application to cluster
2. **Helm Values Change**: 2. **Helm Values Change**:
- CI/CD updates `helm-prod-values/myapp/values.yaml` - CI/CD updates `helm-values/myapp/values.yaml`
- ArgoCD detects change - ArgoCD detects change
- Pulls new Helm chart with updated values - Pulls new Helm chart with updated values
- Applies to cluster - Applies to cluster
@@ -637,7 +639,7 @@ Notifications include:
✅ **DO**: ✅ **DO**:
- Follow the `forteapp` chart pattern - Follow the `forteapp` chart pattern
- Use semantic versioning for image tags - Use semantic versioning for image tags
- Update helm-prod-values via CI/CD - Update helm-values via CI/CD
- Test locally with Docker Compose - Test locally with Docker Compose
- Document environment variables - Document environment variables

View File

@@ -85,8 +85,7 @@ kubectl get applications -n argocd
1. **Configure DNS** for ingress domains: 1. **Configure DNS** for ingress domains:
- `argocd.127.0.0.1.nip.io` (local dev) - `argocd.127.0.0.1.nip.io` (local dev)
- `*.forteapps.net` (dev) - `*.forteapps.net` (production)
- `*.fortedigital.com` (production)
2. **Verify Let's Encrypt certificates**: 2. **Verify Let's Encrypt certificates**:
```bash ```bash
@@ -108,7 +107,7 @@ kubectl get applications -n argocd
### ArgoCD Repository Access Setup ### ArgoCD Repository Access Setup
ArgoCD needs SSH access to private Git repositories to pull manifests and Helm values. This section covers setting up deploy keys for Gitea repositories. ArgoCD needs SSH access to private Git repositories to pull manifests and Helm values. This section covers setting up deploy keys for GitHub repositories.
#### Why Deploy Keys? #### Why Deploy Keys?
@@ -120,7 +119,7 @@ ArgoCD needs SSH access to private Git repositories to pull manifests and Helm v
#### Prerequisites #### Prerequisites
- kubectl access to the cluster - kubectl access to the cluster
- Write access to the Gitea repository - Write access to the GitHub repository
- ArgoCD installed and running - ArgoCD installed and running
#### Setup Procedure #### Setup Procedure
@@ -139,16 +138,16 @@ ssh-keygen -t rsa -b 4096 -C "argocd-deploy-key-launchpad" -f argocd-deploy-key
This creates two files: This creates two files:
- `argocd-deploy-key` - Private key (keep secret) - `argocd-deploy-key` - Private key (keep secret)
- `argocd-deploy-key.pub` - Public key (add to Gitea) - `argocd-deploy-key.pub` - Public key (add to GitHub)
**Step 2: Add Public Key to Gitea** **Step 2: Add Public Key to GitHub**
1. Copy the public key: 1. Copy the public key:
```bash ```bash
cat argocd-deploy-key.pub cat argocd-deploy-key.pub
``` ```
2. Go to Gitea repository settings: 2. Go to GitHub repository settings:
- Navigate to: `https://git.forteapps.net/Forte/launchpad/settings/keys` - Navigate to: `https://git.forteapps.net/Forte/launchpad/settings/keys`
- Or: Repository → Settings → Deploy keys - Or: Repository → Settings → Deploy keys
@@ -158,12 +157,12 @@ This creates two files:
- ☐ Allow write access (leave unchecked - read-only is sufficient) - ☐ Allow write access (leave unchecked - read-only is sufficient)
- Click **"Add key"** - Click **"Add key"**
4. Repeat for the `helm-prod-values` repository if it's private: 4. Repeat for the `helm-values` repository if it's private:
```bash ```bash
# Generate separate key for helm-prod-values repo # Generate separate key for helm-values repo
ssh-keygen -t ed25519 -C "argocd-deploy-key-helm-prod-values" -f argocd-helm-prod-values-key -N "" ssh-keygen -t ed25519 -C "argocd-deploy-key-helm-values" -f argocd-helm-values-key -N ""
# Add to: https://git.forteapps.net/Forte/helm-prod-values/settings/keys # Add to: https://github.com/fortedigital/helm-values/settings/keys
``` ```
**Step 3: Create Kubernetes Secret** **Step 3: Create Kubernetes Secret**
@@ -271,7 +270,7 @@ rm /tmp/test-repo-access.yaml
# Generate new key # Generate new key
ssh-keygen -t ed25519 -C "argocd-deploy-key-$(date +%Y%m)" -f argocd-new-key -N "" ssh-keygen -t ed25519 -C "argocd-deploy-key-$(date +%Y%m)" -f argocd-new-key -N ""
# Add new public key to Gitea (keep old key for now) # Add new public key to GitHub (keep old key for now)
# Update Kubernetes secret # Update Kubernetes secret
kubectl create secret generic repo-launchpad \ kubectl create secret generic repo-launchpad \
@@ -279,7 +278,7 @@ rm /tmp/test-repo-access.yaml
--namespace=argocd \ --namespace=argocd \
--dry-run=client -o yaml | kubectl apply -f - --dry-run=client -o yaml | kubectl apply -f -
# Test access, then remove old deploy key from Gitea # Test access, then remove old deploy key from GitHub
# Clean up # Clean up
shred -u argocd-new-key shred -u argocd-new-key
@@ -290,7 +289,7 @@ rm /tmp/test-repo-access.yaml
# List all repository secrets # List all repository secrets
kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository kubectl get secrets -n argocd -l argocd.argoproj.io/secret-type=repository
# Review deploy keys in Gitea # Review deploy keys in GitHub
# Visit: https://git.forteapps.net/Forte/launchpad/settings/keys # Visit: https://git.forteapps.net/Forte/launchpad/settings/keys
``` ```
@@ -313,16 +312,16 @@ kubectl get secret repo-launchpad -n argocd -o yaml | grep argocd.argoproj.io/se
# Check ArgoCD application controller logs # Check ArgoCD application controller logs
kubectl logs -n argocd deployment/argocd-application-controller | grep -i "permission denied" kubectl logs -n argocd deployment/argocd-application-controller | grep -i "permission denied"
# Verify deploy key is added to Gitea # Verify deploy key is added to GitHub
# Visit: https://git.forteapps.net/Forte/launchpad/settings/keys # Visit: https://git.forteapps.net/Forte/launchpad/settings/keys
``` ```
**Issue: "Host key verification failed"** **Issue: "Host key verification failed"**
```bash ```bash
# Add Gitea to known_hosts # Add GitHub to known_hosts
kubectl exec -n argocd deployment/argocd-repo-server -- \ kubectl exec -n argocd deployment/argocd-repo-server -- \
ssh-keyscan git.forteapps.net >> ~/.ssh/known_hosts ssh-keyscan github.com >> ~/.ssh/known_hosts
# Or disable strict host key checking (less secure) # Or disable strict host key checking (less secure)
kubectl patch secret repo-launchpad -n argocd \ kubectl patch secret repo-launchpad -n argocd \
@@ -347,16 +346,16 @@ kubectl rollout restart deployment argocd-application-controller -n argocd
#### Multiple Repository Setup #### Multiple Repository Setup
For the three-repository pattern (launchpad, forte-helm, helm-prod-values): For the three-repository pattern (launchpad, forte-helm, helm-values):
```bash ```bash
# 1. launchpad (main config repo) # 1. launchpad (main config repo)
ssh-keygen -t ed25519 -C "argocd-launchpad" -f key-sturdy -N "" ssh-keygen -t ed25519 -C "argocd-launchpad" -f key-sturdy -N ""
# Add key-sturdy.pub to: https://git.forteapps.net/Forte/launchpad/settings/keys # Add key-sturdy.pub to: https://git.forteapps.net/Forte/launchpad/settings/keys
# 2. helm-prod-values (private values repo) # 2. helm-values (private values repo)
ssh-keygen -t ed25519 -C "argocd-helm-prod-values" -f key-helm-prod-values -N "" ssh-keygen -t ed25519 -C "argocd-helm-values" -f key-helm-values -N ""
# Add key-helm-prod-values.pub to: https://git.forteapps.net/Forte/helm-prod-values/settings/keys # Add key-helm-values.pub to: https://github.com/fortedigital/helm-values/settings/keys
# 3. forte-helm (private helm charts repo) # 3. forte-helm (private helm charts repo)
@@ -367,14 +366,14 @@ kubectl create secret generic repo-launchpad \
kubectl label --local -f - argocd.argoproj.io/secret-type=repository --dry-run=client -o yaml | \ kubectl label --local -f - argocd.argoproj.io/secret-type=repository --dry-run=client -o yaml | \
kubectl apply -f - kubectl apply -f -
kubectl create secret generic repo-helm-prod-values \ kubectl create secret generic repo-helm-values \
--from-file=sshPrivateKey=key-helm-prod-values \ --from-file=sshPrivateKey=key-helm-values \
--namespace=argocd --dry-run=client -o yaml | \ --namespace=argocd --dry-run=client -o yaml | \
kubectl label --local -f - argocd.argoproj.io/secret-type=repository --dry-run=client -o yaml | \ kubectl label --local -f - argocd.argoproj.io/secret-type=repository --dry-run=client -o yaml | \
kubectl apply -f - kubectl apply -f -
# Clean up keys # Clean up keys
shred -u key-sturdy key-helm-prod-values shred -u key-sturdy key-helm-values
``` ```
#### Converting HTTPS to SSH #### Converting HTTPS to SSH
@@ -391,7 +390,7 @@ If you're currently using HTTPS and want to switch to SSH:
# repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git # repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
# 3. Update and commit # 3. Update and commit
find . -name "*.yaml" -type f -exec sed -i 's|https://git.forteapps.net/Forte/|git@git.forteapps.net:Forte/|g' {} + find . -name "*.yaml" -type f -exec sed -i 's|https://github.com/fortedigital/|git@github.com:fortedigital/|g' {} +
git add . git add .
git commit -m "Switch from HTTPS to SSH for repository access" git commit -m "Switch from HTTPS to SSH for repository access"
@@ -495,7 +494,7 @@ spec:
See [Developer Guide](DEVELOPER-GUIDE.md#deploying-your-first-application) for detailed steps. See [Developer Guide](DEVELOPER-GUIDE.md#deploying-your-first-application) for detailed steps.
**Quick checklist:** **Quick checklist:**
- [ ] Create `helm-prod-values/myapp/values.yaml` - [ ] Create `helm-values/myapp/values.yaml`
- [ ] Create `apps/myapp.yaml` in config repo - [ ] Create `apps/myapp.yaml` in config repo
- [ ] Create SealedSecret if needed - [ ] Create SealedSecret if needed
- [ ] Commit and push changes - [ ] Commit and push changes
@@ -560,7 +559,7 @@ kubectl scale deployment myapp -n myapp --replicas=3
#### GitOps Scaling #### GitOps Scaling
Update `helm-prod-values/myapp/values.yaml`: Update `helm-values/myapp/values.yaml`:
```yaml ```yaml
app: app:
@@ -574,7 +573,7 @@ Commit and push - ArgoCD will sync.
Enable Horizontal Pod Autoscaler: Enable Horizontal Pod Autoscaler:
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
app: app:
hpa: hpa:
enabled: true enabled: true
@@ -623,7 +622,7 @@ kubectl rollout undo deployment myapp -n myapp
#### Option 3: Change Image Tag #### Option 3: Change Image Tag
```bash ```bash
# Edit helm-prod-values # Edit helm-values
cd ~/dev/k8s/helm-prod-values cd ~/dev/k8s/helm-prod-values
vim myapp/values.yaml vim myapp/values.yaml
@@ -643,7 +642,7 @@ git push
#### Update Resource Limits #### Update Resource Limits
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
app: app:
resources: resources:
requests: requests:
@@ -657,7 +656,7 @@ app:
#### Enable Database #### Enable Database
```yaml ```yaml
# In helm-prod-values/myapp/values.yaml # In helm-values/myapp/values.yaml
db: db:
enabled: true enabled: true
persistence: persistence:
@@ -1267,7 +1266,7 @@ spec:
**What Needs Backup**: **What Needs Backup**:
- ❌ Cluster state (not backed up - recreate via GitOps) - ❌ Cluster state (not backed up - recreate via GitOps)
- ❌ Persistent volumes (currently not critical) - ❌ Persistent volumes (currently not critical)
- ✅ Git repositories (Gitea provides backup) - ✅ Git repositories (GitHub provides backup)
- ⚠️ Secrets (sealed secrets in Git, unseal keys need safekeeping) - ⚠️ Secrets (sealed secrets in Git, unseal keys need safekeeping)
### Cluster Rebuild ### Cluster Rebuild
@@ -1562,7 +1561,7 @@ git push
kubectl scale deployment myapp -n myapp --replicas=0 kubectl scale deployment myapp -n myapp --replicas=0
# Update Git # Update Git
vim helm-prod-values/myapp/values.yaml vim helm-values/myapp/values.yaml
# Set replicaCount: 0 # Set replicaCount: 0
git commit -am "Scale down myapp for maintenance" git commit -am "Scale down myapp for maintenance"
git push git push
@@ -1635,7 +1634,7 @@ echo "Remember to delete: $SECRET_FILE"
- [ ] Application code repository created - [ ] Application code repository created
- [ ] Dockerfile created and tested - [ ] Dockerfile created and tested
- [ ] Gitea Actions workflow configured - [ ] GitHub Actions workflow configured
- [ ] Helm values created in `helm-prod-values/` - [ ] Helm values created in `helm-prod-values/`
- [ ] ArgoCD application manifest created in `apps/` - [ ] ArgoCD application manifest created in `apps/`
- [ ] Secrets created and sealed - [ ] Secrets created and sealed

View File

@@ -190,7 +190,7 @@ spec:
### Helm Charts Repository: `forte-helm` ### Helm Charts Repository: `forte-helm`
**URL**: `https://git.forteapps.net/Forte/forte-helm` **URL**: `https://github.com/fortedigital/forte-helm`
#### Chart: `forteapp` #### Chart: `forteapp`
@@ -337,18 +337,20 @@ configmap: [] # Application ConfigMap key-value pairs
--- ---
### Helm Values Repository: `helm-prod-values` ### Helm Values Repository: `helm-values`
**URL**: `https://git.forteapps.net/Forte/helm-prod-values.git` **URL**: `https://github.com/fortedigital/helm-values.git`
#### Structure #### Structure
``` ```
helm-prod-values/ helm-values/
├── mcp10x/ ├── mcp10x/
│ └── values.yaml │ └── values.yaml
├── musicman/ ├── musicman/
│ └── values.yaml │ └── values.yaml
├── mcpcoder/
│ └── values.yaml
└── argocd-mcp/ └── argocd-mcp/
└── values.yaml └── values.yaml
``` ```
@@ -524,14 +526,14 @@ spec:
# Multi-source configuration # Multi-source configuration
sources: sources:
- repoURL: https://git.forteapps.net/Forte/forte-helm - repoURL: https://github.com/fortedigital/forte-helm
path: forteapp path: forteapp
targetRevision: HEAD targetRevision: HEAD
helm: helm:
valueFiles: valueFiles:
- $values/<app-name>/values.yaml - $values/<app-name>/values.yaml
- repoURL: git@github.com:fortedigital/helm-prod-values.git - repoURL: git@github.com:fortedigital/helm-values.git
targetRevision: HEAD targetRevision: HEAD
ref: values ref: values
@@ -602,15 +604,6 @@ retry:
4. 40 seconds 4. 40 seconds
5. 80 seconds (capped at 3 minutes) 5. 80 seconds (capped at 3 minutes)
### Global Settings (`argocd-cm`)
| Setting | Value | Purpose |
|---------|-------|---------|
| `application.resourceTrackingMethod` | `annotation` | Track resources via annotations |
| `timeout.reconciliation` | `60s` | Reconciliation interval |
| `admin.enabled` | `true` | Enable admin account |
| `git.submodule.enabled` | `false` | Disable git submodule checkout — submodules are not needed for manifest generation |
--- ---
## Infrastructure Components ## Infrastructure Components
@@ -824,21 +817,12 @@ postgresql:
**Authentication**: Keycloak OIDC via `forte` realm (client ID: `gitea`). Protocol mapper: `email_verified` hardcoded claim (`true`, boolean) on ID token, Access token, and Userinfo. **Authentication**: Keycloak OIDC via `forte` realm (client ID: `gitea`). Protocol mapper: `email_verified` hardcoded claim (`true`, boolean) on ID token, Access token, and Userinfo.
**External User Sync**: Disabled (`cron.sync_external_users.ENABLED: false`). This Gitea cron job is designed for LDAP and deactivates OIDC-only users because it cannot enumerate them — causing "Sign-in prohibited" errors after the sync runs.
**Email Notifications**: Enabled (`ENABLE_NOTIFY_MAIL: true`). SMTP credentials injected via `gitea-smtp-secret` using `additionalConfigFromEnvs` with `GITEA__mailer__USER` / `GITEA__mailer__PASSWD` environment variables.
**Auto-Watch**: Disabled (`AUTO_WATCH_ON_CHANGES: false`, `AUTO_WATCH_NEW_REPOS: false`). Prevents contributors from being auto-subscribed to repo notifications on push, reducing email noise from CI bots (e.g., ai-review PR comments). Users who were already watching before this change need to manually unwatch or switch to "Only participating".
**Endpoints**: **Endpoints**:
- Web UI: `https://git.forteapps.net` - Web UI: `https://git.forteapps.net`
- SSH: port 22 (ClusterIP) - SSH: port 22 (ClusterIP)
- Metrics: `/metrics` (Prometheus scrape) - Metrics: `/metrics` (Prometheus scrape)
**Secrets**: **Secrets**: `gitea-credentials` (SealedSecret) containing `admin-password`, `postgres-password`, `secret` (OIDC client secret)
- `gitea-credentials` (SealedSecret) — admin password
- `gitea-oidc-credentials` (registrar-managed) — OIDC client ID + secret
- `gitea-smtp-secret` (SealedSecret) — SMTP username + password
### Gitea Actions Runners ### Gitea Actions Runners
@@ -887,84 +871,6 @@ dind:
- Gitea admin panel (`/admin/runners`) — runners show as Online - Gitea admin panel (`/admin/runners`) — runners show as Online
- Create test workflow in `.gitea/workflows/test.yml` — job executes - Create test workflow in `.gitea/workflows/test.yml` — job executes
### AI Code Review (ai-review)
**Type**: Gitea Actions workflow (`.gitea/workflows/ai-review.yaml`)
**Trigger**: `pull_request` events (`opened`, `synchronize`)
**Runner**: `ubuntu-latest` (container: `nikitafilonov/ai-review:latest`)
**Purpose**: Automated AI-powered code review on pull requests using Claude (Anthropic). Posts inline comments on changed lines and a PR summary comment highlighting infrastructure impact.
**Architecture**:
- Uses [xai-review](https://github.com/nicktechnologies/xai-review) Docker image
- Shared configuration and prompts live in the `shared-prompts` Git submodule (→ `Forte/ai-review-prompts`)
- Review mode: `ONLY_ADDED_WITH_CONTEXT` — reviews only new/changed lines plus surrounding context (token-efficient)
- Agent mode: disabled (one-shot review, no multi-turn reasoning)
- LLM: Claude Sonnet (`claude-sonnet-4-20250514`)
**Shared Prompts Structure** (submodule: `Forte/ai-review-prompts`):
```
shared-prompts/
base/
security.md # org-wide security rules (all profiles)
iac/
.ai-review.yaml # IaC/GitOps profile config
inline.md # inline review prompt
summary.md # PR summary prompt
# future profiles: backend/, frontend/, etc.
```
**Configuration** (`shared-prompts/iac/.ai-review.yaml`):
```yaml
llm:
provider: CLAUDE
model: claude-sonnet-4-20250514
vcs:
provider: GITEA
review:
mode: ONLY_ADDED_WITH_CONTEXT
agent:
enabled: false
prompt:
inline_prompt_files: # concatenated in order
- ./shared-prompts/base/security.md
- ./shared-prompts/iac/inline.md
summary_prompt_files:
- ./shared-prompts/iac/summary.md
ignore:
- "*.sealed.yaml"
- "*.lock"
- "docs/**"
```
**Custom Prompts** (IaC profile):
- `shared-prompts/base/security.md` — org-wide security rules, concatenated before every inline review prompt
- `shared-prompts/iac/inline.md` — IaC-specific inline review (YAML, Helm, K8s manifests, shell scripts), max 7 comments
- `shared-prompts/iac/summary.md` — PR summary: affected services/namespaces, infrastructure impact, security flags
**Prompt composition**: ai-review does not support Jinja includes. Instead, list multiple files under `inline_prompt_files` / `summary_prompt_files` — they are concatenated in order with double newlines.
**Adding a new profile**: Create a new directory (e.g., `backend/`) with its own `.ai-review.yaml`, `inline.md`, and `summary.md`. The `inline_prompt_files` list should include `base/security.md` first, then the profile-specific prompt. Reference it in the consuming repo's workflow: `AI_REVIEW_CONFIG_FILE_YAML=./shared-prompts/backend/.ai-review.yaml`
**Required Secrets** (configure in Gitea repo or org settings):
| Secret | Purpose |
|--------|---------|
| `ANTHROPIC_API_KEY` | Claude API key (from Anthropic console) |
| `AI_REVIEW_TOKEN` | Gitea API token with `write:repository` + `read:repository` scopes (use a bot/service account) |
**Setup Steps**:
1. Create a Gitea bot/service account and generate an API token with `write:repository` + `read:repository` scopes
2. Add `AI_REVIEW_TOKEN` secret in Gitea repo settings → Actions → Secrets
3. Add `ANTHROPIC_API_KEY` secret with your Anthropic API key
4. Ensure the `shared-prompts` submodule is initialized (`git submodule update --init`)
5. Push the workflow file — it triggers automatically on PR creation/update
**Verification**:
- Open a PR with infrastructure changes → workflow runs → inline comments + summary appear
- Check Gitea Actions tab for workflow run status and logs
- Monitor Anthropic usage dashboard for token consumption
### Keycloak Client Registrar ### Keycloak Client Registrar
**Type**: CronJob (deployed via Keycloak Helm chart `extraDeploy`) **Type**: CronJob (deployed via Keycloak Helm chart `extraDeploy`)
@@ -1078,33 +984,6 @@ kubectl get secret keycloak-client-<app> -n keycloak -o jsonpath='{.metadata.ann
**See**: [Developer Guide - Adding a New Keycloak Client](DEVELOPER-GUIDE.md#adding-a-new-keycloak-client) **See**: [Developer Guide - Adding a New Keycloak Client](DEVELOPER-GUIDE.md#adding-a-new-keycloak-client)
### Karpor
**Chart**: `karpor` from `https://kusionstack.github.io/charts`
**Version**: 0.7.6 (app v0.6.4)
**Namespace**: `karpor`
**Sync Wave**: 1
**Purpose**: Kubernetes visualization and intelligence tool. Provides cross-cluster resource search, compliance checking, and topology visualization. Gives platform engineers a unified view of all cluster resources and their relationships.
**Architecture** (4 components):
- **Server** — main Karpor API/UI (port 7443)
- **Syncer** — syncs cluster state into the search index
- **ElasticSearch** — search backend for resource indexing
- **etcd** — persistent key-value store (10Gi PVC)
**Configuration** (`infra/values/base/karpor-values.yaml`):
- `namespaceEnabled: false` — ArgoCD manages namespace creation
- Default resource limits tuned for small clusters
- ElasticSearch: 2 CPU / 4Gi memory (the heaviest component)
- AI features available but not enabled (requires `server.ai.authToken` + backend config)
**Access**: Port-forward to reach the UI:
```bash
kubectl port-forward svc/karpor-release-server -n karpor 7443:7443
# Open https://localhost:7443
```
### Renovate ### Renovate
**Chart**: `renovate` (OCI: `ghcr.io/renovatebot/charts`) **Chart**: `renovate` (OCI: `ghcr.io/renovatebot/charts`)
@@ -1159,6 +1038,29 @@ resources:
- `kubectl create job --from=cronjob/renovate renovate-test -n renovate` — manual trigger - `kubectl create job --from=cronjob/renovate renovate-test -n renovate` — manual trigger
- `kubectl logs -n renovate job/renovate-test` — check logs - `kubectl logs -n renovate job/renovate-test` — check logs
### Gitea Pages
**Purpose**: Hosts the MkDocs documentation site for this repository.
**How It Works**:
- A Gitea Actions workflow (`.gitea/workflows/docs.yaml`) builds MkDocs on push to `main`
- The built site is force-pushed to the `gitea-pages` branch
- Gitea serves the static site from that branch
**URL**: `https://git.forteapps.net/Forte/launchpad/pages/`
**Configuration**:
- Gitea server config: `ENABLE_GITEA_PAGES: true` (in gitea-values.yaml)
- MkDocs config: `mkdocs.yml` (repo root)
- Source files: `docs/` directory
- Theme: Material for MkDocs
**Trigger Paths**:
- `docs/**`
- `mkdocs.yml`
- `Dockerfile.docs`
- `nginx.conf`
--- ---
## Kyverno Policies ## Kyverno Policies
@@ -1552,23 +1454,7 @@ Forward to Application (localhost:3000)
Application processes request Application processes request
``` ```
#### Forwarded Headers **See**: [Developer Guide - Enabling Authentication](DEVELOPER-GUIDE.md#enabling-authentication-for-applications) for usage examples.
After successful authentication, the sidecar injects user identity as HTTP headers before forwarding the request to the application container:
| Header | Description | Auth Modes |
|--------|-------------|------------|
| `X-Auth-User` | Username or display name | Token, OIDC, MCP |
| `X-Auth-Email` | User email address | OIDC |
| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP |
| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if `groups` scope) |
| `X-Auth-Token` | The validated access token | All modes |
These headers are trustworthy because the auto-generated `NetworkPolicy` restricts pod ingress to the sidecar port only — external traffic cannot reach the application container directly, so headers cannot be spoofed.
Applications should read these headers to obtain authenticated user information (e.g. for display, authorisation decisions, or audit logging) instead of implementing their own authentication.
**See**: [Developer Guide - Accessing Authenticated User Information](DEVELOPER-GUIDE.md#accessing-authenticated-user-information) for code examples.
--- ---

View File

@@ -1,42 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: karpor
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "1"
labels:
app.kubernetes.io/name: karpor
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://kusionstack.github.io/charts
chart: karpor
targetRevision: "0.7.6"
helm:
releaseName: karpor
valueFiles:
- $values/infra/values/base/karpor-values.yaml
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
targetRevision: HEAD
ref: values
destination:
server: https://kubernetes.default.svc
namespace: karpor
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- Validate=true
- ServerSideApply=true

View File

@@ -17,9 +17,7 @@ resources:
- secrets.yaml - secrets.yaml
- gitea.yaml - gitea.yaml
- gitea-actions.yaml - gitea-actions.yaml
- opencost.yaml
- renovate.yaml - renovate.yaml
- tempo.yaml - tempo.yaml
- grafana-dashboards.yaml - grafana-dashboards.yaml
- network-policies-application.yaml - network-policies-application.yaml
- karpor.yaml

View File

@@ -2,21 +2,12 @@ configs:
secret: secret:
createSecret: true createSecret: true
argocdServerAdminPassword: "$2b$12$Tmb1jH7ADvwWoUoNPXXsfOf6JqEluqhq8mL06a8DGT2AP1GzbNsCm" argocdServerAdminPassword: "$2b$12$Tmb1jH7ADvwWoUoNPXXsfOf6JqEluqhq8mL06a8DGT2AP1GzbNsCm"
ssh:
knownHosts: |
[git.forteapps.net]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDTwi40de8yTGUuRT0i/XGicQ672BLhYR6D/lDquJrp/tdrWoZhVVPy0wxSkWsq1V92iiAUuQnXagOGsLBGZT9uDLWKvEmNDnCfjzTMq3J1iA3vk2rQ8WBlCzhvmeCV/r0ufl6vsgfwxSRomLZeqa2UkLHx69gy2Njb1S2/aZK1Q53f466hCUfDULZrTn2Nn5Sj8cEbJ8EyvVN2YG9HYBxQdzKRPZEmS1vyzmn8YrYIkZseIRQElabzWGh86owuaaqnwJhTJj1j2sEUeIet04sGKJcnxx2UL4H90N66LKMldmMiuli+ve/CjJmMwDl0zGkjIniT3XR8CyEXYHli7B1hR8Z+dbK6DBgjz+28lFgMIRY70KkZJNsJcBNZLZ5fHwCI13a9U3Uhg3Pu/6s0zlosM4CrAQNQCRe95ZPtCpdFhlGrOl4m1rdSK2meL6rND0TBBuZbaFF6Py7TawLCAiO2KRaVqhu9OFVjwJ/nifgLzFGwWj+WcYmpuR+DwozrF/Hl7QYsz1x4GO1SONY07KbIFkUCHOMAh0AELY5YE4eGI4mtG6SecdPaAdLREGZYK4IcyP5i1QW9g0wmfRSsV9jy+r0ivBxixxh4yJiNpkg6NXak40gQtGIme9EJ+DxrRLruNsfDILWcdSuH/wvuorv56NpQFGB0FzB6LXMloSYptQ==
cm: cm:
application.resourceTrackingMethod: annotation application.resourceTrackingMethod: annotation
timeout.reconciliation: 60s timeout.reconciliation: 60s
admin.enabled: "true" admin.enabled: "true"
params: params:
"server.insecure": true "server.insecure": true
repoServer:
env:
# Disable git submodule checkout - submodules (e.g. shared-prompts)
# are not needed for K8s manifest generation
- name: ARGOCD_GIT_MODULES_ENABLED
value: "false"
server: server:
ingress: ingress:
enabled: false enabled: false

View File

@@ -29,10 +29,7 @@ gitea:
ALLOW_ONLY_EXTERNAL_REGISTRATION: true ALLOW_ONLY_EXTERNAL_REGISTRATION: true
ENABLE_BASIC_AUTHENTICATION: true ENABLE_BASIC_AUTHENTICATION: true
ENABLE_PASSWORD_SIGNIN_FORM: false ENABLE_PASSWORD_SIGNIN_FORM: false
AUTO_WATCH_ON_CHANGES: false ENABLE_NOTIFY_MAIL: true
AUTO_WATCH_NEW_REPOS: false
ENABLE_NOTIFY_MAIL: false
ENABLE_TIMETRACKING: false
openid: openid:
ENABLE_OPENID_SIGNIN: false ENABLE_OPENID_SIGNIN: false

View File

@@ -1,44 +0,0 @@
# Karpor - Kubernetes Visualization & Intelligence Tool
# Helm chart: https://github.com/KusionStack/charts/tree/master/charts/karpor
# Let the ArgoCD Application manage the namespace
namespaceEnabled: false
server:
replicas: 1
port: 7443
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 1Gi
syncer:
replicas: 1
port: 7443
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 1Gi
elasticsearch:
replicas: 1
port: 9200
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
cpu: "2"
memory: 4Gi
etcd:
replicas: 1
port: 2379
persistence:
size: 5Gi

View File

@@ -2,8 +2,6 @@ providers:
kubernetesIngress: kubernetesIngress:
publishedService: # Fixes ArgoCD health checks for LoadBalancer services publishedService: # Fixes ArgoCD health checks for LoadBalancer services
enabled: true enabled: true
kubernetesCRD:
allowCrossNamespace: true
deployment: deployment:
replicas: 2 replicas: 2
@@ -50,26 +48,3 @@ ports:
accessLogs: true accessLogs: true
metrics: true metrics: true
tracing: true tracing: true
gitea-ssh:
port: 2222
expose:
default: true
exposedPort: 2222
protocol: TCP
# -- IngressRouteTCP for Gitea SSH (cross-namespace to gitea/gitea-ssh service)
extraObjects:
- apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: gitea-ssh
spec:
entryPoints:
- gitea-ssh
routes:
- match: HostSNI(`*`)
services:
- name: gitea-ssh
namespace: gitea
port: 22

View File

@@ -10,10 +10,6 @@ service:
{ {
"name": "websecure", "name": "websecure",
"mode": "tcp" "mode": "tcp"
},
{
"name": "gitea-ssh",
"mode": "tcp"
} }
], ],
"backends": [ "backends": [
@@ -28,9 +24,6 @@ service:
"properties": { "properties": {
"outbound_proxy_protocol": "v2" "outbound_proxy_protocol": "v2"
} }
},
{
"name": "gitea-ssh"
} }
] ]
} }

View File

@@ -1,5 +1,5 @@
global: global:
domain: argocd.fortedigital.com domain: argocd.us.forteapps.net
notifications: notifications:
context: context:
clusterName: "prod-fd-no-svg1" clusterName: "dev-fd-us-east1"

View File

@@ -1,8 +1,8 @@
dot-ai: dot-ai:
ingress: ingress:
host: kubemcp.fortedigital.com host: kubemcp.us.forteapps.net
webUI: webUI:
baseUrl: http://kubemcpui.fortedigital.com baseUrl: http://kubemcpui.us.forteapps.net
dot-ai-ui: dot-ai-ui:
ingress: ingress:
host: kubemcpui.fortedigital.com host: kubemcpui.us.forteapps.net

View File

@@ -1,3 +1,3 @@
ingress: ingress:
hosts: hosts:
- grafana.fortedigital.com - grafana.us.forteapps.net

View File

@@ -1,2 +1,2 @@
ingress: ingress:
hostname: id.fortedigital.com hostname: id.us.forteapps.net

43
mkdocs.yml Normal file
View File

@@ -0,0 +1,43 @@
site_name: K8s Launchpad
site_description: Documentation for the GitOps-managed Kubernetes cluster
repo_url: https://git.forteapps.net/Forte/launchpad
repo_name: Forte/launchpad
theme:
name: material
palette:
- scheme: default
primary: indigo
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: slate
primary: indigo
toggle:
icon: material/brightness-4
name: Switch to light mode
features:
- navigation.instant
- navigation.sections
- navigation.top
- search.highlight
- content.code.copy
nav:
- Home: README.md
- GitOps Architecture: GITOPS-ARCHITECTURE.md
- Developer Guide: DEVELOPER-GUIDE.md
- Operations Runbook: OPERATIONS-RUNBOOK.md
- Technical Reference: REFERENCE.md
markdown_extensions:
- tables
- toc:
permalink: true
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- admonition
- pymdownx.details

Submodule shared-prompts deleted from c5bc55b3d7