Compare commits

...
Author SHA1 Message Date
Cédric VerstraetenandCopilot 711ace1f15 docs: show all continuous deployment badges
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-04 19:16:38 +00:00
Cédric Verstraeten 4d5d7e3c18 Merge pull request #42 from uug-ai/chore/hub-chart-0.170.1
Upgrade Hub chart to 0.170.1 with hardened API defaults
2026-11-04 18:42:49 +01:00
Cédric Verstraeten c643012993 Merge pull request #44 from uug-ai/chore/hardened-factory-release
Deploy verified hardened Factory v2.0.13
2026-11-04 18:42:40 +01:00
Cédric VerstraetenandCopilot 913706fe3f Deploy verified hardened Factory v2.0.13 with coordinated runtime settings
Pin the signed multiarchitecture digest, route unchanged external ports to HTTP 8080, enforce restricted security context and mount writable config/tmp volumes. Exercise a legacy upgrade and ConfigMap-backed settings after pod replacement on kind.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-04 17:16:29 +00:00
Cédric Verstraeten d41b425035 Merge pull request #43 from uug-ai/docs/deployment-diagrams-vault-hardening
Refresh deployment diagrams and harden Vault
2026-11-04 17:33:07 +01:00
Cédric VerstraetenandCopilot 718fdbe302 Pin Hub chart 0.170.1 and verify hardened API runtime
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-04 14:53:34 +00:00
15 changed files with 265 additions and 22 deletions
+2 -1
View File
@@ -99,8 +99,9 @@ jobs:
id: install-hub
run: |
helm repo add kerberos https://charts.kerberos.io
bash scripts/check-hub-runtime.sh
kubectl create namespace kerberos-hub
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
sleep 10
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
kubectl get pods -A -o wide
+1 -1
View File
@@ -102,7 +102,7 @@ jobs:
run: |
helm repo add kerberos https://charts.kerberos.io
kubectl create namespace kerberos-hub
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
sleep 10
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
kubectl get pods -A -o wide
+23 -1
View File
@@ -1,4 +1,4 @@
name: Validate Kustomize and Garage on kind
name: Validate Kustomize, Garage and Factory on kind
on:
workflow_dispatch:
@@ -45,6 +45,28 @@ jobs:
bash scripts/install-garage.sh
test "$credential_hash" = "$(kubectl -n garage get secret garage-credentials -o jsonpath='{.data}' | sha256sum)"
bash scripts/check-garage.sh --restart
- name: Install legacy Factory and upgrade the actual base
run: |
kubectl apply -f base/namespaces/kerberos-factory.yaml
kubectl apply -f base/factory/kerberos-factory-clusterrole.yaml
kubectl create --dry-run=client -n kerberos-factory -f base/factory/kerberos-factory-deployment.yaml -o json |
jq '
del(.spec.template.spec.securityContext, .spec.template.spec.volumes) |
.spec.template.spec.containers[0] |= (
.image = "ghcr.io/uug-ai/factory:v2.0.11" |
.ports = [{"containerPort":80,"protocol":"TCP"}] |
del(.securityContext, .volumeMounts, .startupProbe, .readinessProbe, .livenessProbe) |
.env |= map(
if .name == "K8S_PROXY" then .value = "http://localhost:80"
elif .name == "PORT" then .value = "80"
else . end))' |
kubectl apply -n kerberos-factory -f -
kubectl create --dry-run=client -n kerberos-factory -f base/factory/kerberos-factory-service.yaml -o json |
jq '.spec.ports[0].targetPort = 80' |
kubectl apply -n kerberos-factory -f -
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
kubectl apply -k base/factory
bash scripts/check-factory.sh
- name: Collect deployment diagnostics
if: failure()
run: bash scripts/diagnose-deployment.sh
+2 -1
View File
@@ -90,8 +90,9 @@ jobs:
id: install-hub
run: |
helm repo add kerberos https://charts.kerberos.io
bash scripts/check-hub-runtime.sh
kubectl create namespace kerberos-hub
helm install hub kerberos/hub --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
helm install hub kerberos/hub --version 0.170.1 --values ./base/hub/kerberos-hub-values.yaml -n kerberos-hub --create-namespace
sleep 10
kubectl wait --for=condition=available deployment --all -n kerberos-hub --timeout=300s
kubectl get pods -A -o wide
+19 -4
View File
@@ -15,9 +15,15 @@ The ecosystem offers flexible installation options, supporting deployment in hyb
## Continuous deployment
[<img src="https://github.com/kerberos-io/deployment/workflows/Deploy%20on%20Microk8s/badge.svg"/>](https://github.com/kerberos-io/deployment/actions/workflows/microk8s.yaml) [<img src="https://github.com/kerberos-io/deployment/workflows/Deploy%20on%20Kubernetes/badge.svg"/>](https://github.com/kerberos-io/deployment/actions/workflows/kind.yaml)
[![Deploy on kind](https://github.com/uug-ai/deployment/actions/workflows/kind.yaml/badge.svg?branch=main)](https://github.com/uug-ai/deployment/actions/workflows/kind.yaml)
[![Deploy on k3d](https://github.com/uug-ai/deployment/actions/workflows/k3d.yaml/badge.svg?branch=main)](https://github.com/uug-ai/deployment/actions/workflows/k3d.yaml)
[![Deploy on MicroK8s](https://github.com/uug-ai/deployment/actions/workflows/microk8s.yaml/badge.svg?branch=main)](https://github.com/uug-ai/deployment/actions/workflows/microk8s.yaml)
[![Validate Kustomize, Garage and Factory on kind](https://github.com/uug-ai/deployment/actions/workflows/kustomize.yaml/badge.svg?branch=main)](https://github.com/uug-ai/deployment/actions/workflows/kustomize.yaml)
This repository continuously tests the ecosystem deployment using GitHub Actions across various platforms. Refer to the badges for an overview of the operating systems and Kubernetes distributions we are deploying to. We welcome suggestions for additional automations to consider.
These badges show the latest status of each GitHub Actions workflow on `main`.
Select a badge to view its runs and platform-specific results. The deployment
workflows continuously test the ecosystem across kind, k3d, and MicroK8s; the
Kustomize workflow validates the Kustomize, Garage, and Factory setup.
Kubernetes examples and CI now use **Garage S3** for local object storage.
See the [Garage setup guide](./base/garage/README.md) for generated credentials,
@@ -32,7 +38,16 @@ example on fork PRs), CI emits a warning and skips delivery without masking
deployment failures. Configured webhook delivery errors still fail the step.
Failed deployment jobs collect pod events and bounded logs for diagnosis.
### Hardened Hub frontend
### Hardened Hub API and frontend
The Kubernetes overlays and full deployment workflows pin Hub chart **0.170.1**.
It supplies Hub API container/pod security contexts for the promoted
`ghcr.io/uug-ai/hub-api:v1.11.31`: UID/GID `65532`, read-only root filesystem,
no privilege escalation, dropped capabilities and RuntimeDefault seccomp.
A disk-backed `hub-api-tmp` emptyDir at `/tmp` provides writable upload scratch
space with pod `fsGroup: 65532`; it is not persistent storage.
Retain this volume and mount when adding custom API mounts, because Helm
replaces lists rather than appending to them.
The promoted frontend image requires Hub chart **0.170.0 or newer**, which
provides port `8080`, non-root/read-only runtime settings and a writable `/tmp`
@@ -41,7 +56,7 @@ legacy image and port `80`. Keep `global.imageRegistry` empty for the supplied
fully qualified `ghcr.io` image names. Service ports remain `80` and the frontend
NodePort remains `32080`, targeting the container port named `http`.
Run `bash scripts/check-hub-runtime.sh` to check the published chart with these
Run `bash scripts/check-hub-runtime.sh` to check published chart `0.170.1` with these
values before installation, or pass a local chart path as the first argument.
When adding custom branding mounts, preserve the chart's `frontend-tmp` volume
and `/tmp` mount. Existing deployments may require the explicit
+44 -3
View File
@@ -15,7 +15,7 @@ deploy, configure and observe Agents (one Deployment + Service per camera).
| File | Kind | Purpose |
| ---- | ---- | ------- |
| [`kerberos-factory-deployment.yaml`](./kerberos-factory-deployment.yaml) | `Deployment` | The Factory web app/API (`uugai/factory`), container port `80`. |
| [`kerberos-factory-deployment.yaml`](./kerberos-factory-deployment.yaml) | `Deployment` | Hardened `ghcr.io/uug-ai/factory:v2.0.13`, pinned to its verified multi-architecture digest, container port `8080`. |
| [`kerberos-factory-service.yaml`](./kerberos-factory-service.yaml) | `Service` | Exposes Factory on `NodePort` **30079** (a `LoadBalancer` variant is included, commented out). |
| [`kerberos-factory-clusterrole.yaml`](./kerberos-factory-clusterrole.yaml) | `ClusterRole` + `ClusterRoleBinding` | Grants the `default` ServiceAccount in `kerberos-factory` the API access Factory needs to manage Agents. |
@@ -50,7 +50,47 @@ Other relevant environment variables:
| `KERBEROS_AGENT_IMAGE` | `kerberos/agent:latest` | Image used when Factory creates an Agent. |
| `KERBEROS_AGENT_MEMORY_LIMIT` | `256Mi` | Default memory limit for created Agents. |
| `NAMESPACE` | `kerberos-factory` | Namespace Factory schedules Agents into. |
| `K8S_PROXY` | `http://localhost:80` | Internal proxy address Factory calls for the `/kubernetes` API. |
| `PORT` | `8080` | Unprivileged HTTP listener used by the hardened image. |
| `K8S_PROXY` | `http://localhost:8080` | Internal proxy address Factory calls for the `/kubernetes` API. |
## Hardened runtime and upgrades
The image runs as UID/GID `65532:65532`, with a read-only root filesystem,
all Linux capabilities dropped, privilege escalation disabled and the
`RuntimeDefault` seccomp profile. The UI login named `root` is independent
of the container's operating-system user.
Two disk-backed `emptyDir` volumes are writable:
- `/home/factory/config` receives missing seed configuration files.
- `/tmp` is scratch space, including multipart uploads.
The pod's `fsGroup: 65532` makes these volumes writable without a root
init container. They survive a container restart but are replaced with the
pod. In this base's `configmap` mode, the global configuration is restored
from the existing Kubernetes ConfigMap on startup; existing global/template
ConfigMaps are not overwritten by image defaults. Keep the existing
ServiceAccount token and RBAC: Factory manages Agents through the Kubernetes
API even though its process is non-root.
Apply the Deployment and Service together when upgrading from a legacy
port-80 image. The external Service port `80` and NodePort `30079` are unchanged;
the Service now targets the named `http` port on container port `8080`.
Startup, readiness and liveness probes use `/healthz`; this endpoint checks
the HTTP process, not all downstream Kubernetes dependencies.
Back up any legacy configuration stored only in the old container before
replacing its pod. For `FACTORY_CONFIGURATION=json`, replace the config
`emptyDir` with a writable PVC and preserve its existing JSON files before
upgrading. A PVC must support access by UID/GID `65532`; storage backends that
do not honor `fsGroup` need matching permissions provisioned separately.
CI upgrades the last legacy release (`v2.0.11`) to these actual base manifests
on kind. It checks the restricted runtime, Service routing, UI/login,
ConfigMap bootstrap, saving settings and persistence after pod replacement.
The [smoke test](../../scripts/check-factory.sh) changes settings and restarts
Factory, so it refuses non-CI invocation and is intended only for disposable
test clusters.
## Prerequisites
@@ -122,7 +162,8 @@ supports other stores via `FACTORY_CONFIGURATION`:
- `configmap` *(default here)* — config in ConfigMaps, no MongoDB.
- `secret` — same as `configmap` but sensitive values are kept in Kubernetes Secrets
(add `secrets` to the ClusterRole resources for this mode).
- `json` — config in local JSON files on the pod, no MongoDB.
- `json` — config in local JSON files, no MongoDB. Use a PVC at
`/home/factory/config`; the default `emptyDir` is not durable across pods.
- `mongodb` — legacy behaviour: Factory and Agents read config from MongoDB. For this
you also need a reachable MongoDB and the corresponding `MONGODB_*` environment
variables (e.g. via a `mongodb` ConfigMap mounted with `envFrom`).
+48 -4
View File
@@ -18,9 +18,21 @@ spec:
labels:
app: factory
spec:
securityContext:
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
containers:
- name: factory
image: ghcr.io/uug-ai/factory:v2.0.4
image: ghcr.io/uug-ai/factory:v2.0.13@sha256:ade073660d911ca66d75b2abc298f1ddcbfbfe43aeed44e60fc1984b49b73d95
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
requests:
memory: 128Mi
@@ -29,8 +41,36 @@ spec:
memory: 128Mi
cpu: 100m
ports:
- containerPort: 80
- name: http
containerPort: 8080
protocol: TCP
startupProbe:
httpGet:
path: /healthz
port: http
failureThreshold: 30
periodSeconds: 2
timeoutSeconds: 2
readinessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 5
timeoutSeconds: 2
livenessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10
timeoutSeconds: 2
volumeMounts:
- name: factory-config
mountPath: /home/factory/config
- name: factory-tmp
mountPath: /tmp
env:
- name: PORT
value: "8080"
- name: GIN_MODE
value: release
- name: KERBEROS_LOGIN_USERNAME
@@ -55,5 +95,9 @@ spec:
- name: FACTORY_ENVIRONMENT
value: "kubernetes"
- name: K8S_PROXY
value: http://localhost:80
value: http://localhost:8080
volumes:
- name: factory-config
emptyDir: {}
- name: factory-tmp
emptyDir: {}
+2 -2
View File
@@ -10,7 +10,7 @@ spec:
type: NodePort
ports:
- port: 80
targetPort: 80
targetPort: http
nodePort: 30079 # You can specify a port in the range 30000-32767 or let Kubernetes assign one automatically
name: frontend
protocol: TCP
@@ -27,7 +27,7 @@ spec:
# type: LoadBalancer
# ports:
# - port: 80
# targetPort: 80
# targetPort: http
# name: frontend
# protocol: TCP
# selector:
+2
View File
@@ -155,6 +155,8 @@ kerberoshub:
memory: 100Mi
cpu: 100m
api:
# Chart 0.170.1 supplies non-root security contexts and writable /tmp.
# Retain hub-api-tmp when overriding the chart's volume/mount lists.
repository: ghcr.io/uug-ai/hub-api
pullPolicy: IfNotPresent
tag: "v1.11.31"
+1 -1
View File
@@ -36,7 +36,7 @@ helmCharts:
releaseName: hub
namespace: kerberos-hub
repo: https://charts.kerberos.io
version: 0.84.0
version: 0.170.1
valuesFile: ../../base/hub/kerberos-hub-values.yaml
valuesInline:
license: "L/+FAwEBB2xpY2Vuc2UB/4YAAQIBB1BheWxvYWQBCgABCVNpZ25hdHVyZQEKAAAA/gMw/4YB/gEl/8wQACxnaXRodWIuY29tL3V1Zy1haS9odWItbGljZW5zZS9tb2RlbHMuTGljZW5zZf+BAwEBB0xpY2Vuc2UB/4IAAQwBAklkAf+EAAEDS2V5AQwAAQdDb21wYW55AQwAAQdFeHBUaW1lAQQAAQREYXlzAQQAAQdDYW1lcmFzAQQAAQVTaXRlcwEEAAEGVmF1bHRzAQQAAQpNZWRpYUxpbWl0AQQAAQlQZXJwZXR1YWwBAgABBkFjdGl2ZQECAAEJSXBBZGRyZXNzAQwAAAAY/4MBAQEIT2JqZWN0SUQB/4QAAQYBGAAAPf+COgEMAAAAAAAAAAAAAAAAAg9nZW5lcmljLWxpY2Vuc2UB+AJl6LAHsRMYAfoB0alKIAABEAEUARQDAQAB/gIAFlQqo9yJj1a3OH1+5iGjCPcz9VtrRuGfz/iuQEFohbCfSiZGAdHh16gEc59Z2kPaey+eJcwY0BQsBoipW7SwFRmcHkrWLuxt+Yzi2kvwmL4TN0quWqM4xxBzH1sejS6kZpPm7bw11JBsBuaNOYMbl5lgpPCFajWUH6GzfmuQlptNQKosocacI/9PaaqEUUM0ALjDZNSqqFwZPPsFh9WTeaHGbRbmwQRMPFDgaPCxiHnCCUagbvuVZeOQbKaR5gPTUfPQY/L4mrN9QnMxdzwUJgqm7FbTH4UhoZn6EEzNGTN6DbHhpx8lezzCRW8dzMNuK8R1igiORV5gdWOPzBMZlTgodIZRD07e8iAo2XqT/BWcqaJXutdqXltaiJKshh2QzStdv2WZUynVTguYIQJyBNhrXEkewKZA0UftcSemDPkCmp6VovMMveV4X3Cpzkm7ZHtE7j39At/kpuqY/icTEzRWYuQqEDtqXMVar84VOpgVhxeNrrqZniLq8o3ezRdwy0BJG5xT9cuMxq13ZB3Am9iqTSjx2mh5VZZeB33GjLVAtLscj8NoKWy7BThchXB9xwoiy2RLO8nE+EI8wPbg+ajb2Ta7AFyxHgJJU6cea+zEpiBMARwjPKqk2nn02xdfdqMzQ+E9e115sIqhotBM5RI7uBIf8DDwT93HLsJZRBAA"
+1 -1
View File
@@ -26,7 +26,7 @@ helmCharts:
releaseName: hub
namespace: kerberos-hub
repo: https://charts.kerberos.io
version: 0.170.0
version: 0.170.1
valuesFile: ../../base/hub/kerberos-hub-values.yaml
valuesInline:
mqtt:
+1 -1
View File
@@ -8,7 +8,7 @@ helmCharts:
releaseName: hub
namespace: kerberos-hub
repo: https://charts.kerberos.io
version: 0.170.0
version: 0.170.1
valuesFile: ../../base/hub/kerberos-hub-values.yaml
valuesInline:
kerberoshub:
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "${CI:-false}" != true ]]; then
echo "This smoke test changes Factory settings and restarts its pod. Run it only in a disposable CI cluster (CI=true)." >&2
exit 1
fi
temporary="$(mktemp -d)"
pid=""
stop_forward() {
if [[ -n "$pid" ]]; then
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
wait "$pid" || [[ "$?" == 143 ]]
fi
pid=""
fi
}
cleanup() {
stop_forward
rm -f "$temporary/port-forward.log" "$temporary/login.json" "$temporary/config.json" "$temporary/saved.json" "$temporary/index.html"
rmdir "$temporary"
}
trap cleanup EXIT
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
kubectl -n kerberos-factory get deployment factory -o json | jq -e '
.spec.template.spec as $pod |
$pod.securityContext.fsGroup == 65532 and
$pod.securityContext.seccompProfile.type == "RuntimeDefault" and
($pod.containers[] | select(.name == "factory") |
.securityContext.runAsNonRoot == true and
.securityContext.runAsUser == 65532 and .securityContext.runAsGroup == 65532 and
.securityContext.readOnlyRootFilesystem == true and
.securityContext.allowPrivilegeEscalation == false and
.securityContext.capabilities.drop == ["ALL"] and
.ports == [{"name":"http","containerPort":8080,"protocol":"TCP"}] and
any(.volumeMounts[]; .mountPath == "/home/factory/config") and
any(.volumeMounts[]; .mountPath == "/tmp") and
.startupProbe.httpGet.path == "/healthz" and
.readinessProbe.httpGet.port == "http" and
.livenessProbe.httpGet.port == "http")'
kubectl -n kerberos-factory get service factory-nodeport -o json |
jq -e '.spec.ports | any(.port == 80 and .targetPort == "http" and .nodePort == 30079)'
kubectl -n kerberos-factory get configmap agent-global-config agent-template-config
kubectl -n kerberos-factory exec deployment/factory -- /app/main healthcheck
forward() {
kubectl -n kerberos-factory port-forward service/factory-nodeport 13979:80 > "$temporary/port-forward.log" 2>&1 &
pid=$!
for attempt in {1..30}; do
if curl --fail --silent http://127.0.0.1:13979/healthz >/dev/null; then return; fi
if ! kill -0 "$pid" 2>/dev/null; then break; fi
sleep 1
done
cat "$temporary/port-forward.log" >&2
echo "Factory Service port-forward did not become healthy." >&2
exit 1
}
login() {
curl --fail --silent --show-error -H 'Content-Type: application/json' \
-d '{"username":"root","password":"kerberos"}' \
http://127.0.0.1:13979/api/login > "$temporary/login.json"
token="$(jq -er '.token | select(length > 0)' "$temporary/login.json")"
if [[ "${GITHUB_ACTIONS:-false}" == true ]]; then echo "::add-mask::$token"; fi
}
forward
curl --fail --silent --show-error http://127.0.0.1:13979/ > "$temporary/index.html"
grep -qi '<html' "$temporary/index.html"
test "$(curl --silent --output /dev/null --write-out '%{http_code}' http://127.0.0.1:13979/api/config)" = 401
login
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
http://127.0.0.1:13979/api/config > "$temporary/config.json"
jq -e '.data.type == "global"' "$temporary/config.json"
jq '.data | .timezone = (if .timezone == "UTC" then "Etc/GMT+1" else "UTC" end)' \
"$temporary/config.json" > "$temporary/saved.json"
timezone="$(jq -r '.timezone' "$temporary/saved.json")"
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
-H 'Content-Type: application/json' --data-binary "@$temporary/saved.json" \
http://127.0.0.1:13979/api/config | jq -e --arg timezone "$timezone" '.data.timezone == $timezone'
kubectl -n kerberos-factory get configmap agent-global-config -o json |
jq -e --arg timezone "$timezone" '.data["_source.json"] | fromjson | .timezone == $timezone'
pod_uid() {
kubectl -n kerberos-factory get pods -l app=factory -o json |
jq -er '[.items[] | select(.metadata.deletionTimestamp == null)][0].metadata.uid'
}
old_pod="$(pod_uid)"
stop_forward
kubectl -n kerberos-factory rollout restart deployment/factory
kubectl -n kerberos-factory rollout status deployment/factory --timeout=300s
test "$old_pod" != "$(pod_uid)"
forward
login
curl --fail --silent --show-error -H "Authorization: Bearer $token" \
http://127.0.0.1:13979/api/config | jq -e --arg timezone "$timezone" '.data.timezone == $timezone'
kubectl -n kerberos-factory exec deployment/factory -- /app/main healthcheck
echo "Factory passed: restricted runtime, Service routing, UI/auth/config, ConfigMap bootstrap and persisted settings after pod replacement."
+19 -1
View File
@@ -3,6 +3,8 @@ set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CHART="${1:-kerberos/hub}"
version=()
if [[ "$CHART" == kerberos/hub ]]; then version=(--version 0.170.1); fi
assert_contains() {
if ! grep -Eq -- "$2" <<< "$1"; then
@@ -19,7 +21,7 @@ nodeport="$(awk '
assert_contains "$nodeport" 'targetPort: http$'
assert_contains "$nodeport" 'nodePort: 32080'
rendered="$(helm template hub "$CHART" --values "$ROOT/base/hub/kerberos-hub-values.yaml" \
rendered="$(helm template hub "$CHART" "${version[@]}" --values "$ROOT/base/hub/kerberos-hub-values.yaml" \
--set mode=ui --set kerberoshub.frontend.demoEnabled=true)"
if grep -q 'image: "docker.io/ghcr.io/' <<< "$rendered"; then
echo "Fully qualified GHCR image was prefixed with docker.io" >&2
@@ -41,4 +43,20 @@ for name in hub-frontend hub-frontend-demo; do
assert_contains "$deployment" 'image: "ghcr.io/uug-ai/hub-frontend:v1.19.28"$'
echo "OK: $name uses the promoted image and matching hardened runtime"
done
api="$(awk '
function emit() { if (deployment && matched) printf "%s", block }
/^---$/ { emit(); block=""; deployment=0; matched=0 }
{ block=block $0 "\n" }
/^kind: Deployment$/ { deployment=1 }
/^ name: hub-api$/ { matched=1 }
END { emit() }
' <<< "$rendered")"
for setting in 'runAsNonRoot: true' 'runAsUser: 65532' 'runAsGroup: 65532' \
'fsGroup: 65532' 'readOnlyRootFilesystem: true' 'allowPrivilegeEscalation: false' \
'type: RuntimeDefault' 'drop:' '- ALL' 'name: hub-api-tmp' \
'emptyDir: \{\}' 'mountPath: /tmp'; do
assert_contains "$api" "^[[:space:]]*(- )?$setting$"
done
assert_contains "$api" 'image: "ghcr.io/uug-ai/hub-api:v1.11.31"$'
echo "OK: hub-api uses the promoted image, hardened security and writable scratch"
echo "Deployment Hub runtime preflight passed."
+1 -1
View File
@@ -3,7 +3,7 @@ set -uo pipefail
kubectl get pods,pvc -A -o wide
kubectl get events -A --sort-by=.lastTimestamp
for namespace in garage mongodb rabbitmq vernemq kerberos-vault kerberos-agent kerberos-hub; do
for namespace in garage mongodb rabbitmq vernemq kerberos-vault kerberos-agent kerberos-hub kerberos-factory; do
if ! pods="$(kubectl -n "$namespace" get pods -o name)"; then
echo "::warning::Could not list pods in $namespace."
continue