Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Flight Control UI configuration

This document describes all environment variables and configuration options available for the Flight Control UI.

## Feature toggles

| Variable | Description | Default | Values |
| ---------------------- | ----------------------------------------- | ------- | --------------- |
| `ENABLE_ORGANIZATIONS` | Enable/disable organizations support | `false` | `true`, `false` |
| `ENABLE_CLI_ARTIFACTS` | Enable/disable CLI download functionality | `true` | `true`, `false` |
| `ENABLE_ALERTMANAGER` | Enable/disable alerts functionality | `true` | `true`, `false` |

## Backend configuration

| Variable | Description | Default | Values |
| --------------------------------------- | ------------------------------------ | ------------------------ | -------------------------------------- |
| `BASE_UI_URL` | Base URL for UI application | `http://localhost:9000` | `https://ui.flightctl.example.com` |
| `FLIGHTCTL_SERVER` | Flight Control API server URL | `https://localhost:3443` | `https://api.flightctl.example.com` |
| `FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY` | Skip backend server TLS verification | `false` | `true`, `false` |
| `FLIGHTCTL_CLI_ARTIFACTS_SERVER` | CLI artifacts server URL | `http://localhost:8090` | `https://cli.flightctl.example.com` |
| `FLIGHTCTL_ALERTMANAGER_PROXY` | AlertManager proxy server URL | `https://localhost:8443` | `https://alerts.flightctl.example.com` |
| `INTERNAL_AUTH_URL` | Internal authentication URL | _(empty)_ | `https://auth.internal.example.com` |
| `AUTH_INSECURE_SKIP_VERIFY` | Skip auth server TLS verification | `false` | `true`, `false` |
| `AUTH_CLIENT_ID` | OAuth client ID for authentication | `flightctl` | Custom client ID |
| `TLS_CERT` | Path to TLS certificate | _(empty)_ | `/path/to/server.crt` |
| `TLS_KEY` | Path to TLS private key | _(empty)_ | `/path/to/server.key` |
| `API_PORT` | UI proxy server port | `3001` | `8080`, `3000`, etc. |
| `K8S_RBAC_NS` | Kubernetes RBAC namespace | _(empty)_ | `flightctl` |
| `IS_OCP_PLUGIN` | Run as OpenShift Console plugin | `false` | `true`, `false` |
| `IS_RHEM` | Red Hat Enterprise Mode | _(empty)_ | `true`, `false` |
Comment on lines +5 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Well-structured and comprehensive variable documentation.

The tables clearly document all configuration options with descriptions, defaults, and acceptable values. Variable naming is consistent and conventions are followed throughout.

Verify that all documented variables are actually supported and autodetected by the apps/standalone/scripts/setup_env.sh script, and that all environment variables used in that script are documented here.


🏁 Script executed:

#!/bin/bash
# Description: Verify all documented variables match those exported in setup_env.sh

# Extract documented variables from CONFIGURATION.md
echo "=== Variables in CONFIGURATION.md ==="
grep -E '^\| `[A-Z_]+`' CONFIGURATION.md | sed -E 's/^\| `([A-Z_]+)`.*/\1/' | sort | uniq

# Extract exported variables from setup_env.sh
echo ""
echo "=== Variables exported in setup_env.sh ==="
grep -E 'export [A-Z_]+=' apps/standalone/scripts/setup_env.sh | sed -E 's/.*export ([A-Z_]+)=.*/\1/' | sort | uniq

# Show differences
echo ""
echo "=== Documented but not in script (check for stale/unused vars) ==="
comm -23 <(grep -E '^\| `[A-Z_]+`' CONFIGURATION.md | sed -E 's/^\| `([A-Z_]+)`.*/\1/' | sort | uniq) <(grep -E 'export [A-Z_]+=' apps/standalone/scripts/setup_env.sh | sed -E 's/.*export ([A-Z_]+)=.*/\1/' | sort | uniq)

echo ""
echo "=== In script but not documented (check for missing documentation) ==="
comm -13 <(grep -E '^\| `[A-Z_]+`' CONFIGURATION.md | sed -E 's/^\| `([A-Z_]+)`.*/\1/' | sort | uniq) <(grep -E 'export [A-Z_]+=' apps/standalone/scripts/setup_env.sh | sed -E 's/.*export ([A-Z_]+)=.*/\1/' | sort | uniq)

Length of output: 742



🏁 Script executed:

#!/bin/bash
# Extract documented variables from CONFIGURATION.md
echo "=== Documented variables (from CONFIGURATION.md) ==="
doc_vars=$(grep -E '^\| `[A-Z_]+`' CONFIGURATION.md | sed -E 's/^\| `([A-Z_]+)`.*/\1/')
echo "$doc_vars" | sort

# Extract all variable references in setup_env.sh (exports, assignments, references)
echo ""
echo "=== Variables in setup_env.sh (all patterns) ==="
script_vars=$(grep -oE '[A-Z_]+(?==|})' apps/standalone/scripts/setup_env.sh | sort | uniq)
echo "$script_vars" | sort

# Check for specific variable name matches
echo ""
echo "=== Checking specific variables ==="
echo "ENABLE_ORGANIZATIONS in docs: $(echo "$doc_vars" | grep -c 'ENABLE_ORGANIZATIONS')"
echo "ORGANIZATIONS_ENABLED in script: $(grep -c 'ORGANIZATIONS_ENABLED' apps/standalone/scripts/setup_env.sh)"
echo "ENABLE_ORGANIZATIONS in script: $(grep -c 'ENABLE_ORGANIZATIONS' apps/standalone/scripts/setup_env.sh)"

# Show excerpt of setup_env.sh to understand structure
echo ""
echo "=== First 50 lines of setup_env.sh ==="
head -50 apps/standalone/scripts/setup_env.sh

Length of output: 2360



🏁 Script executed:

#!/bin/bash
# Get complete setup_env.sh
echo "=== Complete setup_env.sh ==="
cat apps/standalone/scripts/setup_env.sh

Length of output: 4501


Missing documentation for exported variable and scope mismatch between setup script and configuration documentation.

The verification revealed critical discrepancies:

  1. Undocumented variable: The setup script exports ORGANIZATIONS_ENABLED (line exporting it based on ENABLE_ORGANIZATIONS), but this variable is not documented in CONFIGURATION.md. Add it to the Feature toggles table.

  2. Incomplete coverage: Nine documented variables are not set by setup_env.sh: BASE_UI_URL, INTERNAL_AUTH_URL, AUTH_INSECURE_SKIP_VERIFY, AUTH_CLIENT_ID, TLS_CERT, TLS_KEY, API_PORT, K8S_RBAC_NS, IS_OCP_PLUGIN, IS_RHEM. Either these require separate configuration outside this script, or the CONFIGURATION.md scope needs clarification (e.g., add a note explaining which variables are auto-detected vs. manually configured).

🤖 Prompt for AI Agents
In CONFIGURATION.md around lines 5 to 30, the Feature toggles table is missing
the exported variable ORGANIZATIONS_ENABLED and the Backend configuration
section implies variables are set by the setup script when nine of them are not;
add a new row to the Feature toggles table documenting `ORGANIZATIONS_ENABLED`
(description, default and values) and add a brief note in the Backend
configuration header clarifying scope: explicitly list which variables are not
exported by setup_env.sh (BASE_UI_URL, INTERNAL_AUTH_URL,
AUTH_INSECURE_SKIP_VERIFY, AUTH_CLIENT_ID, TLS_CERT, TLS_KEY, API_PORT,
K8S_RBAC_NS, IS_OCP_PLUGIN, IS_RHEM) and state they must be configured
externally or provide defaults/exports in setup_env.sh if you intend them to be
auto-configured.


## Configuration examples

```shell
# Use auto-detection of all configuration settings
npm run dev:kind
```

```shell
# Use auto-detection and override desired settings
ENABLE_CLI_ARTIFACTS=false npm run dev:kind
```

```shell
# Use remote backend and custom settings
FLIGHTCTL_SERVER=https://flightctl.prod.example.com \
ENABLE_ORGANIZATIONS=false \
ENABLE_CLI_ARTIFACTS=false \
npm run dev
```
46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
# Flight Control UI

Monorepo containing UIs for [flightctl](https://github.com/flightctl/flightctl)
Monorepo containing UIs for [Flight Control](https://github.com/flightctl/flightctl)

### Prerequisites:
* `Git`, `Node.js v22.x`, `npm v10.x`, `rsync`, `go` (>= 1.23)
## Prerequisites

- `Git`, `Node.js v22.x`, `npm v10.x`, `rsync`, `go` (>= 1.23)

## Building

### Checkout the repo and from within the repo run:
### Checkout the repository and run

```
```shell
cd flightctl-ui
npm ci
npm run build
```

### Running Standalone UI with backend running in Kind

Choose one of the two options to run the UI application
If backend is running in your Kind cluster, use the following command to start the UI application.
It will automatically detect your Flight Control deployment settings and it will configure the UI accordingly. (Requires `kind`, `kubectl`)

```
npm run dev:kind
```
```shell
npm run dev:kind
```

See [CONFIGURATION.md](CONFIGURATION.md) for complete configuration options.

### Running Standalone UI with backend not running in Kind
- If backend is not running in your Kind cluster, you need to specify the API endpoint

```
If backend is not running in your Kind cluster, you need to specify your Flight Control deployment settings.

```shell
FLIGHTCTL_SERVER=<api_server_url> npm run dev
```

If the backend, or Auth provider is running self-signed certs, you will need to disable the verification via env variables:
If the backend, or Auth provider is running self-signed certs, you will need to disable the verification via environment variables:

- `FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY='true'` - to disable verification of backend certs
- `AUTH_INSECURE_SKIP_VERIFY='true'` - to disable verification of auth server certs
- `FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY='true'` - to disable verification of backend certs
- `AUTH_INSECURE_SKIP_VERIFY='true'` - to disable verification of auth server certs

or provide the CA certs:

- copy backend `ca.crt` to `./certs/ca.crt`
- copy Auth `ca.crt` to `./certs/ca_auth.crt`
- copy backend `ca.crt` to `./certs/ca.crt`
- copy Auth `ca.crt` to `./certs/ca_auth.crt`

See [CONFIGURATION.md](CONFIGURATION.md) for complete configuration options.

### Running UI as OCP plugin

Expand All @@ -47,15 +54,14 @@ With this option, the Flight Control UI will run as a Plugin in the OCP console.

Login to OCP cluster and run:

```
npm run dev:ocp
```shell
npm run dev:ocp
```

By default, the latest available OpenShift console image will be used. To specify a different console version, set the `CONSOLE_VERSION` environment variable.

The following console versions are confirmed to be compatible: 4.16 to 4.20.

<br><br>
<br />

[![Watch the demo](demo-thumbnail.png)](https://www.youtube.com/watch?v=WzNG_uWnmzk)

2 changes: 1 addition & 1 deletion apps/standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"build": "NODE_ENV=production npm run ts-node ../../node_modules/.bin/webpack --mode=production",
"start-prod": "npm run ts-node ../../node_modules/.bin/webpack serve --mode=production --color --progress",
"dev": "concurrently \"npm run dev:proxy\" \"npm run dev:ui\"",
"dev:kind": "ENABLE_ORGANIZATIONS=true ENABLE_CLI_ARTIFACTS=true ENABLE_ALERTMANAGER=true source ./scripts/setup_env.sh && npm run dev",
"dev:kind": ". ./scripts/setup_env.sh && npm run dev",
"dev:proxy": "cd ../../proxy && nodemon --watch 'proxy/**/*' --exec 'go run' app.go --signal SIGTERM",
"dev:ui": "npm run ts-node ../../node_modules/.bin/webpack serve --mode=development --color --progress",
"lint": "eslint --ext .tsx,.ts ./src/ && prettier --check './src/**/*.{tsx,ts}' && npm run i18n",
Expand Down
99 changes: 81 additions & 18 deletions apps/standalone/scripts/setup_env.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
#!/usr/bin/env bash
#!/bin/sh

flightctl_namespace="flightctl-external"

# Validates that the script can run properly to detect the backend deployment setttings
validate_prerequisites() {
if ! command -v kubectl >/dev/null 2>&1; then
echo "❌ Error: kubectl not found. " >&2
exit 1
fi

if ! kubectl config get-contexts kind-kind >/dev/null 2>&1; then
echo "❌ Error: kind-kind context not found. Please deploy flightctl first." >&2
exit 1
fi

if ! kubectl get namespaces --context kind-kind >/dev/null 2>&1; then
echo "❌ Error: Cannot connect to kind cluster. Please check your setup." >&2
exit 1
fi
}

# Function to get external IP address
get_external_ip() {
Expand All @@ -11,6 +31,43 @@ get_external_ip() {
fi
}

# Function that determines if a setting is enabled based on the presence of a service in the kind cluster
detect_service_setting() {
setting_name="$1"
service_name="$2"

if kubectl get service "$service_name" -n "$flightctl_namespace" --context kind-kind >/dev/null 2>&1; then
echo "Autodetected: $setting_name enabled ✅" >&2
echo "true"
else
echo "Autodetected: $setting_name disabled ❌" >&2
echo "false"
fi
return 0
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment on lines +35 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Better distinguish between "service not found" and kubectl errors.

Line 39 silently suppresses all error output from kubectl get service, which means unexpected failures (permission denied, network issues, invalid context) are indistinguishable from a legitimate "service not found" result. This could mask configuration problems and cause the UI to degrade silently.

Consider capturing the exit code to differentiate between actual "not found" (exit 1 with "NotFound" message) and other errors that should be surfaced to the user.

-detect_service_setting() {
-    setting_name="$1"
-    service_name="$2"
-    
-    if kubectl get service "$service_name" -n "$flightctl_namespace" --context kind-kind >/dev/null 2>&1; then
+detect_service_setting() {
+    setting_name="$1"
+    service_name="$2"
+    
+    if kubectl get service "$service_name" -n "$flightctl_namespace" --context kind-kind >/dev/null 2>&1; then
         echo "Autodetected: $setting_name enabled ✅" >&2
         echo "true"
     else
         echo "Autodetected: $setting_name disabled ❌" >&2
         echo "false"
     fi

Alternatively, if the current behavior is acceptable for development, add a comment explaining why all errors are treated as "not found".

Committable suggestion skipped: line range outside the PR's diff.


# Function that determines if organizations are enabled based on the "organizations.enabled" setting from "flightctl-api-config" ConfigMap
detect_organizations_setting() {
SETTING_VALUE=$(kubectl get configmap flightctl-api-config -n "$flightctl_namespace" --context kind-kind -o jsonpath='{.data.config\.yaml}' 2>/dev/null | grep -A1 "organizations:" | grep "enabled:" | awk '{print $2}' | tr -d ' ')

if [ -n "$SETTING_VALUE" ]; then
if [ "$SETTING_VALUE" = "true" ]; then
echo "Autodetected: Organizations enabled ✅" >&2
else
echo "Autodetected: Organizations disabled ❌" >&2
fi
echo "$SETTING_VALUE"
else
echo "Autodetected: Organizations disabled ❌ (no setting found in ConfigMap)" >&2
echo "false"
fi
return 0
}
Comment on lines +50 to +65

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Strengthen the ConfigMap YAML parsing with defensive coding.

Line 51 uses a fragile grep chain that assumes a specific YAML format. If the ConfigMap structure varies (different spacing, comments, format changes), the parsing silently fails and defaults to "false", potentially disabling organizations features even when enabled in the backend.

The pattern also assumes enabled: is always on the line immediately after organizations:, which is brittle YAML parsing.

Consider using a more robust approach. If yq is available in the environment, use it for reliable YAML querying:

-detect_organizations_setting() {
-    SETTING_VALUE=$(kubectl get configmap flightctl-api-config -n "$flightctl_namespace" --context kind-kind -o jsonpath='{.data.config\.yaml}' 2>/dev/null | grep -A1 "organizations:" | grep "enabled:" | awk '{print $2}' | tr -d ' ')
+detect_organizations_setting() {
+    SETTING_VALUE=$(kubectl get configmap flightctl-api-config -n "$flightctl_namespace" --context kind-kind -o jsonpath='{.data.config\.yaml}' 2>/dev/null | grep -oP 'organizations:\s+enabled:\s+\K(true|false)' | head -n1)
     
     if [ -n "$SETTING_VALUE" ]; then
         if [ "$SETTING_VALUE" = "true" ]; then
             echo "Autodetected: Organizations enabled ✅" >&2
         else
             echo "Autodetected: Organizations disabled ❌" >&2
         fi
         echo "$SETTING_VALUE"
     else
         echo "Autodetected: Organizations disabled ❌ (no setting found in ConfigMap)" >&2
         echo "false"
     fi
     return 0
 }

Alternatively, use yq if available for authoritative YAML parsing, or add logging to help debug parsing failures.

Committable suggestion skipped: line range outside the PR's diff.



# Check that the Backend is running in a kind cluster and we can access it
validate_prerequisites

# Get the external IP address
EXTERNAL_IP=$(get_external_ip)

Expand All @@ -21,42 +78,48 @@ fi

echo "Using external IP: $EXTERNAL_IP" >&2

# Read configuration flags from environment variables (with defaults)
ENABLE_CLI_ARTIFACTS=${ENABLE_CLI_ARTIFACTS:-false}
ENABLE_ALERTMANAGER=${ENABLE_ALERTMANAGER:-false}
ENABLE_ORGANIZATIONS=${ENABLE_ORGANIZATIONS:-false}

# Set core environment variables for kind development
export FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY='true'
export FLIGHTCTL_SERVER="https://$EXTERNAL_IP:3443"

# CLI Artifacts - conditionally set or unset
# Organizations - get setting from kind cluster, unless it has been configured already
if [ -z "$ENABLE_ORGANIZATIONS" ]; then
ENABLE_ORGANIZATIONS=$(detect_organizations_setting)
fi
export ENABLE_ORGANIZATIONS
if [ "$ENABLE_ORGANIZATIONS" = "true" ]; then
export ORGANIZATIONS_ENABLED="true"
else
export ORGANIZATIONS_ENABLED="false"
fi

# CLI artifacts - get setting from kind cluster, unless it has been configured already
if [ -z "$ENABLE_CLI_ARTIFACTS" ]; then
ENABLE_CLI_ARTIFACTS=$(detect_service_setting "CLI artifacts" "flightctl-cli-artifacts")
fi
export ENABLE_CLI_ARTIFACTS
if [ "$ENABLE_CLI_ARTIFACTS" = "true" ]; then
export FLIGHTCTL_CLI_ARTIFACTS_SERVER="http://$EXTERNAL_IP:8090"
else
unset FLIGHTCTL_CLI_ARTIFACTS_SERVER
fi

# AlertManager - conditionally set or unset
# AlertManager - get setting from kind cluster, unless it has been configured already
if [ -z "$ENABLE_ALERTMANAGER" ]; then
ENABLE_ALERTMANAGER=$(detect_service_setting "AlertManager" "flightctl-alertmanager-proxy")
fi
export ENABLE_ALERTMANAGER
if [ "$ENABLE_ALERTMANAGER" = "true" ]; then
export FLIGHTCTL_ALERTMANAGER_PROXY="https://$EXTERNAL_IP:8443"
else
unset FLIGHTCTL_ALERTMANAGER_PROXY
fi

# Organizations - conditionally set or unset
if [ "$ENABLE_ORGANIZATIONS" = "true" ]; then
export ORGANIZATIONS_ENABLED="true"
else
export ORGANIZATIONS_ENABLED="false"
fi

echo "Environment variables set:" >&2
echo ""
echo "🌐 Environment variables set:" >&2
echo " FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY=$FLIGHTCTL_SERVER_INSECURE_SKIP_VERIFY" >&2
echo " FLIGHTCTL_SERVER=$FLIGHTCTL_SERVER" >&2
echo " FLIGHTCTL_CLI_ARTIFACTS_SERVER=${FLIGHTCTL_CLI_ARTIFACTS_SERVER:-'(disabled)'}" >&2
echo " FLIGHTCTL_ALERTMANAGER_PROXY=${FLIGHTCTL_ALERTMANAGER_PROXY:-'(disabled)'}" >&2
echo " ORGANIZATIONS_ENABLED=$ORGANIZATIONS_ENABLED" >&2
echo >&2