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
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
--charts charts/ingress-controller \
--charts charts/aisix-cp \
--charts charts/aisix \
--charts charts/developer-portal-fe \
Comment thread
coderabbitai[bot] marked this conversation as resolved.
--charts charts/ngxdig'

- name: Verify Chart.lock files
Expand Down
8 changes: 7 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Operational rule: **on any `release/*` branch, only bump the charts you actually
- `CR_SKIP_EXISTING: true`: already-released versions are skipped and the index is merged (not overwritten), so multiple branches are safe.
- the GitHub Release tag is `<chart>-<version>` (e.g. `gateway-3.9.0`); the numbering rule keeps it unique across lines.
- `ci.yaml` (lint / ct install / helm-docs) also covers `release/**`.
- after editing a chart, regenerate each chart's `README.md` with `helm-docs --chart-search-root=charts`, or the helm-docs CI check fails.
- after editing a chart, regenerate each chart's `README.md` with `helm-docs --chart-search-root=charts`, or the helm-docs CI check fails. Use **v1.13.1**, the version CI installs: 1.14.x appends an `Autogenerated from chart metadata...` footer that CI then rejects, and the `helm-docs` pre-commit hook runs whatever `helm-docs` is on `PATH` — so it happily rewrites every chart README into a form CI fails on. Put a v1.13.1 binary first on `PATH` when committing.

## Gateway chart: which config to expose

Expand All @@ -73,6 +73,12 @@ The gateway chart's `values.yaml`/configmap mirror the gateway's `conf/config-de

When adding values, keep defaults identical to `config-default.yaml` so a default render changes nothing. To verify a rendered config is valid, extract `config.yaml` from the rendered configmap and run it through the real image: `docker run --rm --entrypoint sh -v $PWD/config.yaml:/usr/local/apisix/conf/config.yaml api7/api7-ee-3-gateway:<ver> -c 'apisix init'` — the config schema is validated at init.

## developer-portal-fe chart: config is a pass-through

`config.yaml` is rendered from `developerPortal.config`, which carries the application's whole config schema. **Do not add per-field `.Values` keys for it** — the schema lives in `api7/api7ee-developer-portal` (`apps/site/src/lib/config/schema.ts`) and mirroring it drifts on every application release. Only the connection settings the chart itself owns are templated, and they are merged over the block so a user cannot move the Secret-backed `${PORTAL_TOKEN}` / `${DB_URL}` / `${AUTH_SECRET}` placeholders into the ConfigMap.

To verify a rendered config, run it through the image's own loader: `docker run --rm -v $PWD/config.yaml:/app/apps/site/config.yaml -e PORTAL_TOKEN=x -e DB_URL=x -e AUTH_SECRET=$(head -c 32 /dev/zero | tr '\0' a) --entrypoint sh api7/api7-ee-developer-portal-fe:<ver> -c 'node preflight.js'` — reaching the `Portal URL:` line means the config validated (the portal/database checks after it need a live backend). That mount path is fixed: the standalone server chdirs into `apps/site`, and preflight looks there.

## User upgrade guidance

- Follow the latest line: `helm repo update && helm upgrade <release> api7/<chart>` (picks the highest version, always the newest EE line).
Expand Down
2 changes: 2 additions & 0 deletions charts/developer-portal-fe/.helmignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
.idea/
*.tmproj
.vscode/
README.md.gotmpl
ci/
4 changes: 2 additions & 2 deletions charts/developer-portal-fe/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: developer-portal-fe
description: A Helm chart for API7 Developer Portal Frontend
type: application
version: 0.1.0
appVersion: "0.5.7"
version: 0.2.0
appVersion: "0.14.0"
maintainers:
- name: API7
email: support@api7.ai
Expand Down
118 changes: 116 additions & 2 deletions charts/developer-portal-fe/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# developer-portal-fe

![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.7](https://img.shields.io/badge/AppVersion-0.5.7-informational?style=flat-square)
![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.14.0](https://img.shields.io/badge/AppVersion-0.14.0-informational?style=flat-square)

A Helm chart for API7 Developer Portal Frontend

Expand All @@ -16,6 +16,107 @@ A Helm chart for API7 Developer Portal Frontend
|------------|------|---------|
| https://charts.bitnami.com/bitnami | postgresql | 12.12.10 |

## Install

```sh
helm repo add api7 https://charts.api7.ai
helm repo update

helm install developer-portal-fe api7/developer-portal-fe --namespace api7 --create-namespace
```

## Configuring the portal application

The chart renders the application's `config.yaml` from `developerPortal.config`:
the block is copied into the file as it is written, and the connection settings
below are then merged over it. Any field the application's config schema accepts
can be set there — `app.name`, `app.desc`, `auth.emailAndPassword`,
`auth.genericOAuthProviders`, `db.ssl`, and so on — without waiting for a chart
release. Which fields exist depends on the deployed application version
(`developerPortal.image.tag`).

These are the paths the chart owns. They are merged in last, so they always win
over `developerPortal.config` and setting them there has no effect:

| Config path | Comes from |
| :--- | :--- |
| `portal.url` | `portal.url` |
| `portal.token` | `${PORTAL_TOKEN}` — Secret (`portal.existingSecret`) |
| `db.url` | `${DB_URL}` — Secret (`db.existingSecret`) |
| `auth.secret` | `${AUTH_SECRET}` — Secret (`auth.existingSecret`) |
| `app.baseURL`, `app.trustedOrigins` | `app.baseURL`, `app.trustedOrigins` |

Changing `developerPortal.config` rolls the Pods automatically — the Deployment
carries a checksum of the rendered ConfigMap.

### Keep credentials out of the ConfigMap

`developerPortal.config` is rendered into a ConfigMap, so it is the wrong place
for a client secret or a database password. The application substitutes
`${VAR}` and `${VAR:default}` in every string value of `config.yaml` at startup,
so put a placeholder in the config and inject the real value as an environment
variable with `developerPortal.extraEnvVars`:

```yaml
developerPortal:
config:
auth:
genericOAuthProviders:
- providerId: keycloak
discoveryUrl: https://sso.example.com/realms/main/.well-known/openid-configuration
clientId: devportal
clientSecret: ${OIDC_CLIENT_SECRET}
extraEnvVars:
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: devportal-oidc
key: client-secret
```

A missing variable is a startup error, not an empty string — the Pod fails
fast instead of running with a blank secret.

### Examples

Name and describe the portal:

```yaml
developerPortal:
config:
app:
name: "Example APIs"
desc: "Everything you need to build on Example."
```

Turn off password sign-in and require two-factor authentication:

```yaml
developerPortal:
config:
auth:
emailAndPassword:
enabled: false
twoFactor:
enabled: true
required: true
```

Connect to a managed PostgreSQL that requires TLS, in its own schema:

```yaml
developerPortal:
config:
db:
schema: portal
ssl:
rejectUnauthorized: true
ca: ${DB_CA_PEM}
pool:
max: 30
min: 2
```

## Values

| Key | Type | Default | Description |
Expand All @@ -29,12 +130,13 @@ A Helm chart for API7 Developer Portal Frontend
| db.existingSecret | string | `""` | |
| db.existingSecretKey | string | `"db-url"` | |
| db.url | string | `"postgres://portal:portal123@developer-portal-fe-postgresql:5432/portal"` | |
| developerPortal.config | object | `{"app":{"name":"Developer Portal"}}` | Developer Portal application config, copied into `config.yaml` with the chart-owned connection settings merged over it |
| developerPortal.extraEnvVars | list | `[]` | |
| developerPortal.extraVolumeMounts | list | `[]` | |
| developerPortal.extraVolumes | list | `[]` | |
| developerPortal.image.pullPolicy | string | `"IfNotPresent"` | |
| developerPortal.image.repository | string | `"api7/api7-ee-developer-portal-fe"` | |
| developerPortal.image.tag | string | `"v0.5.7"` | |
| developerPortal.image.tag | string | `"v0.14.0"` | |
| developerPortal.livenessProbe.failureThreshold | int | `10` | |
| developerPortal.livenessProbe.initialDelaySeconds | int | `30` | |
| developerPortal.livenessProbe.path | string | `"/"` | |
Expand Down Expand Up @@ -89,3 +191,15 @@ A Helm chart for API7 Developer Portal Frontend
| tolerations | list | `[]` | |
| topologySpreadConstraints | list | `[]` | |

## Upgrading

### To 0.2.0

The bundled application moves from 0.5.7 to 0.14.0, which requires `auth.secret`
to be at least 32 characters — a shorter secret fails validation at startup.
Rotate it before upgrading (`openssl rand -base64 32`); rotating signs existing
users out, so they will have to sign in again.

`auth.socialProviders` is the one config field to avoid on this application
version: its schema is mis-declared upstream and the Pod fails to start when the
field is set. Use `auth.genericOAuthProviders` instead.
125 changes: 125 additions & 0 deletions charts/developer-portal-fe/README.md.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{{ template "chart.header" . }}

{{ template "chart.badgesSection" . }}

{{ template "chart.description" . }}

{{ template "chart.maintainersSection" . }}

{{ template "chart.requirementsSection" . }}

## Install

```sh
helm repo add api7 https://charts.api7.ai
helm repo update

helm install developer-portal-fe api7/developer-portal-fe --namespace api7 --create-namespace
```

## Configuring the portal application

The chart renders the application's `config.yaml` from `developerPortal.config`:
the block is copied into the file as it is written, and the connection settings
below are then merged over it. Any field the application's config schema accepts
can be set there — `app.name`, `app.desc`, `auth.emailAndPassword`,
`auth.genericOAuthProviders`, `db.ssl`, and so on — without waiting for a chart
release. Which fields exist depends on the deployed application version
(`developerPortal.image.tag`).

These are the paths the chart owns. They are merged in last, so they always win
over `developerPortal.config` and setting them there has no effect:

| Config path | Comes from |
| :--- | :--- |
| `portal.url` | `portal.url` |
| `portal.token` | `${PORTAL_TOKEN}` — Secret (`portal.existingSecret`) |
| `db.url` | `${DB_URL}` — Secret (`db.existingSecret`) |
| `auth.secret` | `${AUTH_SECRET}` — Secret (`auth.existingSecret`) |
| `app.baseURL`, `app.trustedOrigins` | `app.baseURL`, `app.trustedOrigins` |

Changing `developerPortal.config` rolls the Pods automatically — the Deployment
carries a checksum of the rendered ConfigMap.

### Keep credentials out of the ConfigMap

`developerPortal.config` is rendered into a ConfigMap, so it is the wrong place
for a client secret or a database password. The application substitutes
`${VAR}` and `${VAR:default}` in every string value of `config.yaml` at startup,
so put a placeholder in the config and inject the real value as an environment
variable with `developerPortal.extraEnvVars`:

```yaml
developerPortal:
config:
auth:
genericOAuthProviders:
- providerId: keycloak
discoveryUrl: https://sso.example.com/realms/main/.well-known/openid-configuration
clientId: devportal
clientSecret: ${OIDC_CLIENT_SECRET}
extraEnvVars:
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: devportal-oidc
key: client-secret
```

A missing variable is a startup error, not an empty string — the Pod fails
fast instead of running with a blank secret.

### Examples

Name and describe the portal:

```yaml
developerPortal:
config:
app:
name: "Example APIs"
desc: "Everything you need to build on Example."
```

Turn off password sign-in and require two-factor authentication:

```yaml
developerPortal:
config:
auth:
emailAndPassword:
enabled: false
twoFactor:
enabled: true
required: true
```

Connect to a managed PostgreSQL that requires TLS, in its own schema:

```yaml
developerPortal:
config:
db:
schema: portal
ssl:
rejectUnauthorized: true
ca: ${DB_CA_PEM}
pool:
max: 30
min: 2
```

{{ template "chart.valuesSection" . }}

## Upgrading

### To 0.2.0

The bundled application moves from 0.5.7 to 0.14.0, which requires `auth.secret`
to be at least 32 characters — a shorter secret fails validation at startup.
Rotate it before upgrading (`openssl rand -base64 32`); rotating signs existing
users out, so they will have to sign in again.

`auth.socialProviders` is the one config field to avoid on this application
version: its schema is mis-declared upstream and the Pod fails to start when the
field is set. Use `auth.genericOAuthProviders` instead.
76 changes: 76 additions & 0 deletions charts/developer-portal-fe/ci/full-config-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Renders every part of the Developer Portal config surface through
# developerPortal.config, so a template change that breaks the pass-through is
# caught by `ct lint`. Credentials are ${ENV} placeholders on purpose — that is
# the documented way to keep them out of the ConfigMap.
portal:
url: "https://api7-developer-portal:4321"

app:
baseURL: "https://portal.example.com"
trustedOrigins:
- "https://portal.example.com"

developerPortal:
config:
db:
schema: portal
pool:
max: 30
min: 2
idleTimeout: 60000
connectionTimeout: 5000
allowExitOnIdle: false
ssl:
rejectUnauthorized: true
ca: ${DB_CA_PEM}
auth:
adminUserIds:
- usr_admin
session:
expiresIn: 604800
updateAge: 86400
emailAndPassword:
enabled: false
requireEmailVerification: true
revokeSessionsOnPasswordReset: true
twoFactor:
enabled: true
required: true
# auth.socialProviders is deliberately absent: the application's own
# schema mis-declares it and fails to parse a config that sets it
# (fixed after 0.14.0). genericOAuthProviders covers the same ground.
genericOAuthProviders:
- providerId: keycloak
discoveryUrl: https://sso.example.com/realms/main/.well-known/openid-configuration
clientId: devportal
clientSecret: ${OIDC_CLIENT_SECRET}
scopes: ["openid", "profile", "email"]
sso:
providers:
- providerId: keycloak
domains:
- '@example\.com$'
app:
name: "Example APIs"
desc: "Everything you need to build on Example."
signUpConsentLabel: 'I agree to the <a href="https://example.com/tos">Terms</a>.'
applicationDetail:
subscriptions: true
usage: false
credentialsTabs:
keyAuth: true
basicAuth: false
oauth: false
apiHub:
enabled: true
extraEnvVars:
- name: DB_CA_PEM
valueFrom:
secretKeyRef:
name: devportal-db-ca
key: ca.crt
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: devportal-oidc
key: client-secret
Loading
Loading