Compare commits

..
Author SHA1 Message Date
Kilian BouteandClaude Opus 5.5 3cf8e63e53 feat(hub): split the OTel sampler for hub-api and trace workflow stages
opentelemetry.sampler now applies only to the services downstream of the Vault
(hub-workflows, pipe-*, workflow stages), which continue the Vault's trace and
should run parentbased_always_off; hub-api, which starts its own traces for
user requests, gets opentelemetry.apiSampler. Workflow stages (hub-stage.yaml)
had no OTEL_EXPORTER_OTLP_ENDPOINT, so their tracing ran in no-op mode; they
now get the endpoint and the downstream sampler when opentelemetry is enabled.

Defaults are empty, so the only rendered change is the stage endpoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:45:24 +00:00
KilianandClaude Opus 5.5 331df9d4af docs(hub): document email template variables (#198)
Explain how email templates are selected (SMTP files under
/mail/templates vs built-in vs Mailgun), how the base and tenant URLs
are built from kerberoshub.frontend, and which value each {{variable}}
gets in the alert, camera status, account and sharing emails.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:08:18 +02:00
KilianandClaude Opus 5.5 17dd600872 feat(hub): make analysis thumbnail regeneration opt-in (0.163.0) (#197)
Add kerberospipeline.analysis.thumbnailRegeneration.enabled (default
false), passed to pipe-analysis as THUMBNAIL_REGENERATION_ENABLED. When
enabled, analysis regenerates thumbnails from the first frame of a
classified moving object, adding one thumbnail job per classified
recording. Requires an analysis image that reads the flag.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:22:29 +02:00
KilianandClaude Opus 5.5 4880dc1197 feat(hub): allow defining the classification catalog inline in values (0.162.0) (#196)
Restore the optional classificationCatalog values key removed in 0.155.0.
A nonempty list ({key, label, icon?}, unique keys) replaces the bundled
defaults in the chart's classification-catalog ConfigMap, so Hub API and
the bundled catalogs/classifications.json share it. Omitted or null keeps
the defaults; [] is rejected. Combining it with classificationCatalogEnabled:
false, classificationCatalogExistingConfigMap or a classifications.json
replacement fails rendering.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:24:00 +02:00
KilianandClaude Opus 5.5 805dfe405b feat(hub): add frontend Google Places API selector (0.161.0) (#195)
Add kerberoshub.frontend.googlemaps.placesApi, rendered as
GOOGLEMAPS_PLACES_API on the hub-frontend and hub-frontend-demo
deployments. Defaults to "legacy" so existing keys keep working; "new"
switches address autocomplete to Places API (New) with the same apikey.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:14:23 +02:00
Kilian e861dbecc3 Merge pull request #194 from kerberos-io/feat/workflow-label-triggers
feat(hub): device system tags and system-tag global workflows (0.160.0)
2026-10-16 13:57:39 +02:00
Kilian BouteandClaude Opus 5.5 a35e701cb2 feat(hub): align the system tag catalog with the chart's catalog conventions
- Catalog entries use the Hub shared choice catalog format (key, label) plus
  an optional description, as catalogs/classifications.json does.
- values.schema.json now validates deviceTags (enabled boolean; entries with
  a stored-form key, a label, an optional description; no unknown keys), so
  mistakes fail like other values; templates keep the uniqueness and
  workflow cross-checks.
- The catalog stays inline in values (Helm checks workflow systemTags against
  it) but reaches hub-api like the classification catalog: the
  device-system-tags ConfigMap mounted at /etc/kerberos/device-tags, named by
  DEVICE_SYSTEM_TAGS_FILE, with a checksum annotation. The DEVICE_SYSTEM_TAGS
  JSON env var is gone (hub-api#672 reads the file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:24:21 +00:00
Kilian BouteandClaude Opus 5.5 7cddafbe93 feat(hub): harden the system tag gate for workflow definitions
The engine reads JSON keys case-insensitively and ignores unknown ones, so
the previous exact-path checks could be bypassed (SystemTags, nested or
shared conditions, nested stage needs) and a typo (systemTag:, trigger:)
silently removed a workflow's device scope.

- While deviceTags.system.enabled is false, any mention of system tags in a
  definition (case-insensitive, any depth) fails rendering.
- Definitions may only use id, enabled, triggers and stages, and triggers
  only the models.WorkflowTrigger fields, spelled exactly.
- deviceTags.system.enabled must be a boolean; the string "false" enabled it.

Production's definitions still render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:07:41 +00:00
Kilian BouteandClaude Opus 5.5 5c6198eff2 feat(hub): rename device labels to typed device tags (system tags)
Root deviceLabelsEnabled/deviceLabels become deviceTags.system.enabled and
deviceTags.system.catalog, leaving room for more tag types. hub-api gets
DEVICE_SYSTEM_TAGS, and workflow triggers select devices with systemTags
(condition path device.systemTags). Matches uug-ai/models#284.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:47:47 +00:00
Kilian BouteandClaude Opus 5.5 f2ab8c8505 feat(hub): gate device labels with a root deviceLabelsEnabled flag
Replace kerberoshub.workflows.labelTriggers (and hub-workflows'
WORKFLOW_LABEL_TRIGGERS_ENABLED) with one deployment-wide switch next to
the catalog. While it is off, hub-api gets an empty catalog and rendering
fails on any workflow that selects devices by label (trigger labels or
device.labels conditions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:12:52 +00:00
Kilian BouteandClaude Opus 5.5 7472d44683 feat(hub): add the device label catalog
Root deviceLabels is the deployment's device label catalog: the only
labels owners can assign to devices (value, name, description). It is
rendered as DEVICE_LABELS on hub-api; empty (the default) disables
device labels.

Labels are a device concept, so the catalog lives at the root next to
the classification catalog; workflows only refer to it. Rendering fails
when a catalog value is invalid or duplicated, or when a workflow
trigger selects a label that is not in the catalog, so a typo cannot
silently match no device. labelTriggers stays the separate trust switch
for global workflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:47:14 +00:00
Kilian BouteandClaude Opus 5.5 004377e69d feat(hub): allow label-scoped global workflows (0.160.0)
Add kerberoshub.workflows.labelTriggers (default false), rendered as
WORKFLOW_LABEL_TRIGGERS_ENABLED on hub-workflows. It lets global workflow
definitions select devices across organisations by owner-set device
label (trigger `labels`); the engine refuses such definitions until it
is enabled. Owners set labels, so enable it only where owners are
trusted administrators (self-hosted), never on multi-tenant SaaS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:16:11 +00:00
16 changed files with 481 additions and 44 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.159.0
version: 0.164.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
+164 -22
View File
@@ -99,6 +99,51 @@ workflow engine. These deployment-global, ops-managed workflows are read-only
through the API; manage them in Helm values. There are no per-project on/off
overrides.
To run a global workflow on specific devices across organisations, select them
by system tag. Enable `deviceTags.system` and define the tags in its catalog;
owners assign them to devices in Hub (only catalog tags can be assigned):
```yaml
deviceTags:
system:
enabled: true
catalog:
- key: anpr-pilot
label: ANPR pilot
description: Runs licence plate recognition on this camera
kerberoshub:
workflows:
definitions:
anpr-pilot:
id: "6720f3a1c2d4e5f60718293a"
enabled: true
triggers:
- type: automatic
systemTags: ["anpr-pilot"]
stages:
- operation: anpr
```
Every tag a trigger selects must be in the catalog; otherwise rendering fails,
so a typo cannot silently match no device. Because owners set system tags, any
owner could enroll devices into such a workflow, so `deviceTags.system.enabled`
is `false` by default. When it is on, the catalog is rendered into the
`device-system-tags` ConfigMap and mounted into Hub API
(`DEVICE_SYSTEM_TAGS_FILE`), like the classification catalog. While it is off,
Hub API gets no catalog (system tags cannot be set) and rendering fails on any workflow that mentions system
tags anywhere (trigger `systemTags`, or a `device.systemTags` condition at any
depth, in any key casing). Enable it only on deployments whose owners are
trusted administrators (self-hosted), never on multi-tenant SaaS.
The engine reads keys case-insensitively and ignores unknown ones, so a typo
could silently widen a workflow to every device. Workflow definitions may
therefore only use the keys `id`, `enabled`, `triggers` and `stages`, and
triggers only the trigger fields the engine knows, spelled exactly; anything
else fails rendering. System-tag workflows also need a hub-workflows image
that understands `systemTags` (uug-ai/hub-workflows#87 or later): an older
engine drops the field and would run the workflow on every device.
Supply an explicit, stable `id` for new definitions:
```yaml
@@ -223,8 +268,10 @@ kerberospipeline:
| `opentelemetry.enabled` | Enable or disable OpenTelemetry instrumentation. | `false` |
| `opentelemetry.routingEnabled` | Enable or disable OpenTelemetry routing/export behavior. | `false` |
| `opentelemetry.collector.endpoint` | OpenTelemetry collector endpoint used for trace export. | `"http://otel-collector:4317"` |
| `opentelemetry.sampler.type` | Trace sampler, exported as `OTEL_TRACES_SAMPLER` (e.g. `parentbased_traceidratio`). Empty keeps the SDK default (sample everything). | `""` |
| `opentelemetry.sampler.arg` | Sampler argument, exported as `OTEL_TRACES_SAMPLER_ARG` (e.g. `"0.1"` for ~10% of traces). | `""` |
| `opentelemetry.sampler.type` | Trace sampler for the services downstream of the Vault (hub-workflows, `pipe-*`, workflow stages), exported as `OTEL_TRACES_SAMPLER`. They continue the Vault's trace, so use `parentbased_always_off` and sample at the Vault. Empty keeps the SDK default (sample everything). | `""` |
| `opentelemetry.sampler.arg` | Sampler argument for those services, exported as `OTEL_TRACES_SAMPLER_ARG`. | `""` |
| `opentelemetry.apiSampler.type` | Trace sampler for hub-api, which starts its own traces for user requests (e.g. `parentbased_traceidratio`). Empty keeps the SDK default. | `""` |
| `opentelemetry.apiSampler.arg` | Sampler argument for hub-api (e.g. `"0.1"` for ~10% of requests). | `""` |
| `openai.enabled` | Enable or disable OpenAI-backed semantic features. | `false` |
| `openai.apikey` | OpenAI API key used when OpenAI integration is enabled. | `"xxx"` |
| `kerberosvault.uri` | The default Kerberos Vault uri (you can add multiple within the app), by default `'https://api.storage.yourdomain.com'` | `"https://api.vault.yourdomain.com"` |
@@ -332,6 +379,7 @@ kerberospipeline:
| `kerberoshub.frontend.sentry.url` | No longer used. | `"https://xxx@sentry.io/xxx"` |
| `kerberoshub.frontend.stripe.publicKey` | Public key for `kerberoshub.frontend.stripe`. | `""` |
| `kerberoshub.frontend.googlemaps.apikey` | Within Kerberos Hub frontend a couple of maps are being used, the google maps is leveraged for that. | `"xxxx"` |
| `kerberoshub.frontend.googlemaps.placesApi` | Google Places API used for address autocomplete with the same `apikey`: `"legacy"` (Places API) or `"new"` (Places API (New), required for keys that cannot enable the legacy Places API). | `"legacy"` |
| `kerberoshub.frontend.zendesk.url` | No longer used. | `"yourdomain.zendesk.com"` |
| `kerberoshub.frontend.posthog.key` | The API key retrieved from the Posthog instance. | `"xxx"` |
| `kerberoshub.frontend.posthog.url` | Posthog's endpoint (http/https). | `"https://posthog.domain.com"` |
@@ -546,6 +594,7 @@ kerberospipeline:
| `kerberospipeline.analysis.tag` | The Docker image tag/version. | `"v1.7.8"` |
| `kerberospipeline.analysis.replicas` | Number of replicas for `kerberospipeline.analysis`. | `1` |
| `kerberospipeline.analysis.logLevel` | Log verbosity level for `kerberospipeline.analysis`. | `"info"` |
| `kerberospipeline.analysis.thumbnailRegeneration.enabled` | Regenerate thumbnails from the first frame of a classified moving object (`THUMBNAIL_REGENERATION_ENABLED`). Adds one thumbnail job per classified recording. Requires an analysis image that reads the flag. | `false` |
| `kerberospipeline.analysis.dbCache.enabled` | Cache hot-path MongoDB lookups (site vault per device) in memory. Site changes apply after at most one TTL. | `false` |
| `kerberospipeline.analysis.dbCache.ttl` | Lifetime of a cached lookup, as a Go duration (e.g. `"30s"`, `"5m"`). | `"5m"` |
| `kerberospipeline.analysis.resources.requests.memory` | Memory request for `kerberospipeline.analysis`. | `"10Mi"` |
@@ -635,6 +684,87 @@ kerberospipeline:
| `kerberoshub.frontend.ssoDomain` | The domain that's being used to activate SSO from the login page. | `""` |
| `kerberoshub.frontend.stripe.apikey` | If using the public version, `stripe` can be used for automated billing and subscriptions. | `""` |
### Email templates and variables
Every email Hub sends is a template: an HTML file, plus a plain-text `.txt` version, containing `{{variable}}` placeholders that are filled in just before sending. This section lists which value each placeholder gets.
#### Which template is used
- `email.templates.<name>` sets the template name for each email (for example `email.templates.detection: "detection"`).
- With `email.provider: smtp`, Hub reads `/mail/templates/<name>.html` and `/mail/templates/<name>.txt` from the container. If the files are not there, it uses its built-in template with that name. To use your own, mount a volume at `/mail` (see the commented `custom-email-templates` volume in `values.yaml`). The [`custom-layout/templates`](custom-layout/templates) folder holds a complete set to start from.
- With `email.provider: mailgun`, `<name>` is a template stored in your Mailgun account. Mailgun receives `user`, `text`, `link`, `numberOfMedia`, `dataUsage` and the email-specific values below as template variables. The computed values (dates, camera, sites, groups, thumbnail) are only filled in with `smtp`.
- Alert emails (`detection`) are only sent when `email.provider` is `smtp`.
- A placeholder that has no value for that email stays in the email as literal text, so only use the placeholders listed for it. The bundled templates contain `{{tab1_href}}`, `{{tab1_title}}`, `{{tab2_href}}` and `{{tab2_title}}`; these are not filled in.
#### Links
- The **base URL** is `kerberoshub.frontend.schema` + `://` + `kerberoshub.frontend.url` (the `PUBLIC_URL` environment variable), for example `https://app.example.com`.
- A **tenant URL** is the base URL with the first part of the host replaced by the recipient account's domain. With base URL `https://app.example.com` and account domain `acme`, the tenant URL is `https://acme.example.com`. Accounts without a domain use the base URL. Only the last two parts of the host are kept, so a base URL on `app.example.co.uk` becomes `acme.co.uk`.
#### Alerts: `detection`
Sent by the notification pipeline (`kerberospipeline.notify`) when a custom alert or the generic detection alert fires. The subject is `email.templates.alertTitle`; for a custom alert it is prefixed with the alert's name in brackets, for example `[Front door] Hub detected an event.`
| Placeholder | Value |
|---|---|
| `{{user}}` | Name of the account that receives the alert: first and last name, or the username when both are empty. This is the account the camera belongs to, not the user who created the alert. |
| `{{title}}` | The email subject. |
| `{{text}}` | The alert message: what was detected, on which camera and when. |
| `{{link}}` | **Custom alerts**: a signed link to the recording file. It stops working when the storage link expires. **Generic detection alert**: the recording's page in Hub, `<tenant URL>/media/<id>`. |
| `{{medialink}}` | `https://app.kerberos.io/media/<id>`. Always this host; it does not follow `kerberoshub.frontend.url`. |
| `{{thumbnail}}` | An `<img>` of the recording: embedded in the email for custom alerts, a signed thumbnail URL for the generic detection alert. |
| `{{date}}`, `{{time}}`, `{{datetime}}` | Start of the recording, in the account's timezone. |
| `{{eventdate}}`, `{{eventtime}}`, `{{eventdatetime}}` | When the alert was sent, in the account's timezone. |
| `{{timezone}}` | The account's timezone. |
| `{{devicename}}`, `{{deviceid}}` | Camera name and camera key. |
| `{{sites}}`, `{{groups}}` | Comma-separated names of the sites and groups the camera belongs to. |
| `{{classifications}}` | Comma-separated objects detected in the recording. |
#### Camera status: `device`
Sent by `hub-monitor-device` when a camera goes online, offline or idle. The subject is `email.templates.deviceTitle`.
| Placeholder | Value |
|---|---|
| `{{user}}` | Username of the account the camera belongs to. |
| `{{title}}` | The email subject. |
| `{{text}}` | The status change, for example "`<camera>` is online, but the camera stream is not connected." |
| `{{status}}` | `online`, `offline` or `idle`. |
| `{{devicename}}`, `{{deviceid}}` | Camera name and camera key. |
| `{{eventdate}}`, `{{eventtime}}`, `{{eventdatetime}}` | When the status changed, in the server's timezone (normally UTC), not the account's. |
| `{{link}}` | Not set; replaced with an empty value. |
#### Account and sharing emails
Sent by the API (`kerberoshub.api`). The subject of each email is the matching `email.templates.<name>Title` value.
| Email (`email.templates.*`) | Placeholder | Value |
|---|---|---|
| Registration (`welcome`) | `{{user}}` | New user's first and last name, or username. |
| | `{{link}}` | Activation link: `<base URL>/login/activate/<token>`. |
| | `{{token}}` | The activation token. |
| Account activated (`activate`) | `{{user}}` | User's first and last name, or username. |
| | `{{link}}` | `<base URL>/login`. |
| Password reset (`forgot`) | `{{user}}` | User's first and last name, or username. |
| | `{{password}}` | The newly generated password. |
| | `{{ipaddress}}` | IP address the reset was requested from. |
| Recording shared (`share`) | `{{user}}` | Sender's first and last name, or username. |
| | `{{url}}` | Signed link to the recording file. |
| | `{{title}}` | The email subject (`email.templates.shareTitle`). The share's own title is only used when that value is empty. |
| | `{{body}}` | The notes the sender added to the share. |
| Case shared (`share_case`) | `{{user}}` | Sender's first and last name, or email address. |
| | `{{firstname}}`, `{{lastname}}` | Sender's first and last name. |
| | `{{url}}` | `<base URL>/share/<token>`. |
| | `{{expiry}}` | How long the share stays valid, for example "2 days" or "1 week". |
| Case share code (`share_case_otp`) | `{{code}}` | One-time code to open the shared case. |
| | `{{expiry}}` | How long the code stays valid. |
| Task assigned (`assign_task`) | `{{assignee}}` | Assigned user's first and last name, or username. |
| | `{{user}}` | Name of the user who assigned the task. |
| | `{{task_name}}` | The task title. |
| | `{{link}}` | `<tenant URL>/tasks/`, using the assigned user's domain. |
The `newip`, `disable` and `highupload` templates are included, but no service currently sends them.
### Post installation
After the installation you'll need to initialise the Mongodb with some objects. Have a look at the `mongodb/` folder, you'll find three files available:
@@ -673,19 +803,37 @@ Within the Kerberos Hub front-end you'll see the option to filter through classi
The default shared classification list lives in
[`templates/configMaps/catalogs/classifications.yaml`](templates/configMaps/catalogs/classifications.yaml),
independently of workflow contracts. The chart uses this bundled definition
unless a deployer provides a ConfigMap override. Each entry contains the stable classifier output
unless a deployer defines the catalog inline or provides a ConfigMap override. Each entry contains the stable classifier output
`key`, the user-facing `label`, and an `icon` key. Hub API exposes this catalog
to alerts and filters. When the mounted catalog is unavailable, compatible Hub
API versions fall back to the legacy `settings` document and then the built-in
classification list. Set `classificationCatalogEnabled: false` to omit the
ConfigMap and make Hub API use that fallback directly.
Starting with chart **0.155.0**, the inline `classificationCatalog` values key is
removed. Supplying it fails validation, including `null` and `[]`; it is never
silently ignored or replaced with bundled defaults.
The simplest way to customize the catalog is to define the complete list inline
in your values (restored in chart **0.162.0** after its removal in 0.155.0):
To customize the catalog, create a ConfigMap in the release namespace containing
the complete JSON array, then use the per-file replacement interface:
```yaml
classificationCatalog:
- key: car
label: Car
icon: car
- key: forklift
label: Forklift
```
The list replaces the bundled defaults entirely (entries are not merged) and is
rendered into the chart's `classification-catalog` ConfigMap, so Hub API and the
bundled `catalogs/classifications.json` of workflow packaging use the same list
and a change rolls the API pod. Each entry needs a `key` and `label`, `icon` is
optional, and keys must be unique. Omitting the key (or `null`) keeps the bundled
defaults; `[]` is rejected, so use `classificationCatalogEnabled: false` for the
API fallback. An inline list cannot be combined with
`classificationCatalogEnabled: false`, `classificationCatalogExistingConfigMap` or
a per-file catalog replacement.
Alternatively, create a ConfigMap in the release namespace containing the complete
JSON array, then use the per-file replacement interface:
```yaml
classificationCatalogEnabled: true
@@ -700,13 +848,8 @@ workflowConfiguration:
replace: true
```
To migrate, copy the existing list exactly (preserving keys, labels and icons)
into the ConfigMap's JSON data, remove `classificationCatalog` from every values
overlay and command-line override, and deploy the ConfigMap before the chart
upgrade. A `null` value is not a migration: remove the key. The bundled list
remains the default when no override is configured. If an old `[]` intentionally
selected the API's runtime fallback, use `classificationCatalogEnabled: false`
and configure workflow packaging without bundled defaults instead.
Deploy that ConfigMap before the chart upgrade. The bundled list remains the
default when no override is configured.
The existing `classificationCatalogExistingConfigMap: hub-classification-catalog`
option remains supported, including for deployments without workflow packaging.
@@ -1051,12 +1194,12 @@ not owned by workflows. A library may ship a catalog without implementing an API
**effective** classification list under `/etc/kerberos/configuration`, using
the directory layout above. The projected volume reuses the existing
classification ConfigMap, including `classificationCatalogExistingConfigMap`
overrides or explicit per-file replacements, rather
overrides, an inline `classificationCatalog` or explicit per-file replacements, rather
than storing another copy in the workflow ConfigMap.
The default classification ConfigMap name, mount path, `CLASSIFICATION_CATALOG_FILE`
and API endpoint remain unchanged. Inline `classificationCatalog` values,
including `[]` and `null`, are rejected from chart 0.155.0 onward. The current API
and API endpoint remain unchanged. An inline `classificationCatalog` list is
rendered into that ConfigMap; `[]` is rejected. The current API
still falls back to settings/built-in values for an empty/invalid mounted catalog. The preparatory
bundle does not reproduce that runtime fallback and must not be treated as a
resolved API catalog. The Start-specific loader shares the existing classification
@@ -1143,10 +1286,9 @@ A replacement for `catalogs/classifications.json` also supplies the standalone
classification API. Both mounts use that ConfigMap and key, even when its key
is not named `classifications.json`. The chart does not generate or checksum the
replaced ConfigMap. To avoid two competing sources, do not combine this
replacement with a nonempty `classificationCatalogExistingConfigMap`. That
existing ConfigMap option remains supported when no per-file catalog replacement
is configured. The retired inline `classificationCatalog` key is rejected
regardless of the selected configuration.
replacement with a nonempty `classificationCatalogExistingConfigMap` or an inline
`classificationCatalog`. Those options remain supported when no per-file catalog
replacement is configured.
`classificationCatalogEnabled` must remain true when including defaults.
This is whole-file replacement, not field-level YAML merging or catalog-entry
@@ -1,7 +1,6 @@
# Create these ConfigMaps in the release namespace before deploying the chart.
# Keys contain complete contracts/catalogs; they are not merged with chart data.
# Remove the retired classificationCatalog key from every values overlay.
# Do not also set classificationCatalogExistingConfigMap.
# Do not also set classificationCatalog or classificationCatalogExistingConfigMap.
classificationCatalogEnabled: true
workflowConfiguration:
enabled: true
+11 -3
View File
@@ -22,9 +22,6 @@
{{/* Normalize both interfaces without changing the caller's values. */}}
{{- define "hub.workflowConfiguration.settings" -}}
{{- if hasKey .Values "classificationCatalog" -}}
{{- fail "classificationCatalog is no longer supported; remove the values key and place the complete catalog in a ConfigMap, then use workflowConfiguration.configMaps with path: catalogs/classifications.json and replace: true" -}}
{{- end -}}
{{- $config := .Values.workflowConfiguration | default dict -}}
{{- $unified := or (hasKey $config "includeDefaults") (hasKey $config "configMaps") -}}
{{- $legacy := or (hasKey $config "existingConfigMap") (hasKey $config "items") (hasKey $config "extraConfigMaps") -}}
@@ -78,6 +75,17 @@
{{- fail "a classifications.json replacement cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- if not (kindIs "invalid" .Values.classificationCatalog) -}}
{{- if not .Values.classificationCatalogEnabled -}}
{{- fail "classificationCatalog requires classificationCatalogEnabled; remove the inline list to use the API fallback" -}}
{{- end -}}
{{- if .Values.classificationCatalogExistingConfigMap -}}
{{- fail "classificationCatalog cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- if hasKey $replacements "catalogs/classifications.json" -}}
{{- fail "classificationCatalog cannot be combined with a classifications.json replacement; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- dict "enabled" $enabled "includeDefaults" $includeDefaults "configMaps" $normalizedSources "replacements" $replacements | toYaml -}}
{{- end -}}
+51
View File
@@ -0,0 +1,51 @@
{{/*
The system tag catalog (deviceTags.system.catalog) uses the Hub shared choice
catalog format: {key, label, description?}. values.schema.json validates each
entry (key in stored device tag form, models.NormalizeDeviceTags: 1-64
characters of a-z, 0-9, ".", "_", ":" and "-", starting and ending with a
letter or digit) and that enabled is a boolean; keys must also be unique.
*/}}
{{- define "kerberoshub.deviceTags.system.validate" -}}
{{- $seen := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $key := toString $tag.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "deviceTags.system.catalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- end -}}
{{/*
The configured system tag catalog as a JSON array, whether or not system tags
are enabled (missing values read as empty).
*/}}
{{- define "kerberoshub.deviceTags.system.catalog" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- $system.catalog | default list | toJson -}}
{{- end -}}
{{/*
Whether system tags are enabled (deviceTags.system.enabled): "true" or "".
*/}}
{{- define "kerberoshub.deviceTags.system.enabled" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- if and (kindIs "bool" $system.enabled) $system.enabled -}}true{{- end -}}
{{- end -}}
{{/*
The system tag catalog file hub-api reads (DEVICE_SYSTEM_TAGS_FILE), rendered
from deviceTags.system.catalog into the device-system-tags ConfigMap.
*/}}
{{- define "kerberoshub.deviceTags.system.json" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $tags := list -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $entry := dict "key" $tag.key "label" $tag.label -}}
{{- with $tag.description }}{{- $_ := set $entry "description" . -}}{{- end }}
{{- $tags = append $tags $entry -}}
{{- end -}}
{{- $tags | toJson -}}
{{- end -}}
+15 -2
View File
@@ -86,14 +86,27 @@ Usage: {{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-api") | nin
{{/*
OpenTelemetry sampler env entries, rendered only when configured. The OTel SDKs
read these natively; unset keeps the SDK default (parentbased_always_on).
"hub.opentelemetry.samplerEnv" renders opentelemetry.sampler, the sampler of the
services downstream of the Vault (pipeline, workflows engine and stages), which
continue the Vault's trace; "hub.opentelemetry.apiSamplerEnv" renders
opentelemetry.apiSampler for hub-api, which starts its own traces for user
requests.
Usage: {{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
*/}}
{{- define "hub.opentelemetry.samplerEnv" -}}
{{- with .Values.opentelemetry.sampler.type }}
{{- include "hub.opentelemetry.samplerEnvFrom" .Values.opentelemetry.sampler -}}
{{- end -}}
{{- define "hub.opentelemetry.apiSamplerEnv" -}}
{{- include "hub.opentelemetry.samplerEnvFrom" (.Values.opentelemetry.apiSampler | default dict) -}}
{{- end -}}
{{- define "hub.opentelemetry.samplerEnvFrom" -}}
{{- with .type }}
- name: OTEL_TRACES_SAMPLER
value: {{ . | quote }}
{{- end }}
{{- with .Values.opentelemetry.sampler.arg }}
{{- with .arg }}
- name: OTEL_TRACES_SAMPLER_ARG
value: {{ . | quote }}
{{- end }}
@@ -11,6 +11,28 @@
{"key": "cell phone", "label": "Cell phone", "icon": "cell phone"}
]
{{- end -}}
{{/*
The effective chart-rendered catalog: the inline classificationCatalog values
list when set, otherwise the bundled defaults above. values.schema.json
validates each entry ({key, label, icon?}); keys must also be unique.
*/}}
{{- define "hub.classificationCatalog.json" -}}
{{- if kindIs "invalid" .Values.classificationCatalog -}}
{{- include "hub.classificationCatalog.defaults" . | mustFromJson | toJson -}}
{{- else if and (kindIs "slice" .Values.classificationCatalog) .Values.classificationCatalog -}}
{{- $seen := dict -}}
{{- range $entry := .Values.classificationCatalog -}}
{{- $key := toString $entry.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "classificationCatalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- .Values.classificationCatalog | toJson -}}
{{- else -}}
{{- fail "classificationCatalog must be omitted (bundled defaults) or a nonempty list; to use the API fallback set classificationCatalogEnabled: false" -}}
{{- end -}}
{{- end -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not (hasKey $config.replacements "catalogs/classifications.json")) }}
apiVersion: v1
@@ -20,5 +42,5 @@ metadata:
namespace: {{ .Release.Namespace }}
data:
classifications.json: |-
{{- include "hub.classificationCatalog.defaults" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- include "hub.classificationCatalog.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
@@ -0,0 +1,12 @@
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
apiVersion: v1
kind: ConfigMap
metadata:
name: device-system-tags
namespace: {{ .Release.Namespace }}
data:
# Rendered from deviceTags.system.catalog; hub-api reads it through
# DEVICE_SYSTEM_TAGS_FILE.
system-tags.json: |-
{{- include "kerberoshub.deviceTags.system.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
+23 -3
View File
@@ -125,6 +125,9 @@ spec:
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not $catalogReplacement) }}
checksum/classification-catalog: {{ include (print $.Template.BasePath "/configMaps/catalogs/classifications.yaml") . | sha256sum }}
{{- end }}
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
checksum/device-system-tags: {{ include (print $.Template.BasePath "/configMaps/catalogs/device-system-tags.yaml") . | sha256sum }}
{{- end }}
{{- if and $workflowConfiguration.enabled $workflowConfiguration.includeDefaults (not (hasKey $workflowConfiguration.replacements "workflow-contracts/start.yaml")) }}
checksum/workflow-configuration: {{ include (print $.Template.BasePath "/configMaps/workflow-contracts/start.yaml") . | sha256sum }}
{{- end }}
@@ -147,7 +150,8 @@ spec:
{{- $serverTLS := .Values.kerberoshub.api.serverTLS }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- $classificationCatalogEnabled := .Values.classificationCatalogEnabled }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- $deviceSystemTagsEnabled := include "kerberoshub.deviceTags.system.enabled" . }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
@@ -200,6 +204,11 @@ spec:
path: classifications.json
{{- end }}
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
configMap:
name: device-system-tags
{{- end }}
{{- with .Values.kerberoshub.api.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -227,7 +236,7 @@ spec:
ports:
- containerPort: 80
name: http
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
@@ -239,6 +248,11 @@ spec:
mountPath: /etc/kerberos/classifications
readOnly: true
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
mountPath: /etc/kerberos/device-tags
readOnly: true
{{- end }}
{{- with .Values.kerberoshub.api.volumeMounts}}
{{- toYaml . | nindent 12 }}
{{- end }}
@@ -261,6 +275,12 @@ spec:
- name: CLASSIFICATION_CATALOG_FILE
value: /etc/kerberos/classifications/classifications.json
{{- end }}
{{- if $deviceSystemTagsEnabled }}
# System tag catalog (deviceTags.system.catalog): the only system
# tags owners can assign. Unset (disabled) disables system tags.
- name: DEVICE_SYSTEM_TAGS_FILE
value: /etc/kerberos/device-tags/system-tags.json
{{- end }}
- name: ENVIRONMENT
value: "{{ .Values.environment }}"
- name: READ_ONLY
@@ -577,6 +597,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 12 }}
{{- include "hub.opentelemetry.apiSamplerEnv" $ | trim | nindent 12 }}
{{- end }}
{{- end }}
@@ -192,6 +192,8 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# features > chart
- name: CHART_COLORS
@@ -275,6 +275,8 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# Zendesk for support
- name: ZENDESK_URL
@@ -21,6 +21,64 @@ workflow later cannot silently alias another workflow's runs or references.
{{- end -}}
{{- $_ := set $identities $id $name -}}
{{- end -}}
{{- include "kerberoshub.workflows.validateSystemTags" . -}}
{{- end -}}
{{/*
Guard the definitions that can select devices by system tag. The engine reads
JSON keys case-insensitively and ignores unknown ones, so a misspelled or
re-cased key silently changes what a definition selects (a dropped
systemTags scope makes a global workflow run on every device). Therefore:
- definitions and triggers may only use the keys the engine knows, spelled
exactly (definition: id, enabled, triggers, stages; trigger: the
models.WorkflowTrigger fields);
- while deviceTags.system.enabled is false, no definition may mention system
tags anywhere (trigger systemTags, or a device.systemTags condition at any
depth, in triggers, shared conditions or stage needs), matched
case-insensitively on the whole definition;
- every system tag a trigger selects must be in deviceTags.system.catalog,
so a typo fails rendering instead of never matching a device.
Disabled definitions are checked too, so enabling one cannot fail later.
*/}}
{{- define "kerberoshub.workflows.validateSystemTags" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $catalog := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $_ := set $catalog (toString $tag.key) true -}}
{{- end -}}
{{- $enabled := include "kerberoshub.deviceTags.system.enabled" . -}}
{{- $definitionKeys := list "id" "enabled" "triggers" "stages" -}}
{{- $triggerKeys := list "type" "edgeId" "sharedConditions" "devices" "siteIds" "groupIds" "systemTags" "classifications" "conditionMode" "conditions" "weeklySchedule" "surfaces" -}}
{{- range $name, $wf := .Values.kerberoshub.workflows.definitions -}}
{{- if $wf -}}
{{- if not (kindIs "map" $wf) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] must be an object" $name) -}}
{{- end -}}
{{- if and (not $enabled) (contains "systemtags" (lower (toJson $wf))) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] selects devices by system tag (systemTags or a device.systemTags condition), but deviceTags.system.enabled is false" $name) -}}
{{- end -}}
{{- range $key, $_ := $wf -}}
{{- if not (has $key $definitionKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored" $name $key (join ", " $definitionKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $i, $trigger := ($wf.triggers | default list) -}}
{{- if not (kindIs "map" $trigger) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d] must be an object" $name $i) -}}
{{- end -}}
{{- range $key, $_ := $trigger -}}
{{- if not (has $key $triggerKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored and widen the trigger" $name $i $key (join ", " $triggerKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $tag := ($trigger.systemTags | default list) -}}
{{- if not (hasKey $catalog (toString $tag)) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d].systemTags: %q is not in deviceTags.system.catalog; add it to the system tag catalog" $name $i (toString $tag)) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
@@ -117,6 +117,14 @@ spec:
- name: KERBEROS_STORAGE_PROVIDER
value: {{ . | quote }}
{{- end }}
{{- if $root.Values.opentelemetry.enabled }}
# OpenTelemetry tracing: the stage continues the engine's dispatch span
# (the run's traceparent) and follows its sampling decision.
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ $root.Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $root | trim | nindent 8 }}
{{- end }}
# Per-stage tuning knobs. Any key/value under services.<name>.env is
# rendered verbatim as container env, so a worker can be tuned from
@@ -126,6 +126,10 @@ spec:
- name: DOMINANTCOLOR_ENABLED
value: "{{ .Values.kerberospipeline.dominantColor.enabled }}"
# Thumbnail regeneration from classified frames (opt-in)
- name: THUMBNAIL_REGENERATION_ENABLED
value: {{ .Values.kerberospipeline.analysis.thumbnailRegeneration.enabled | default false | quote }}
# In-memory cache for hot-path MongoDB lookups
- name: DB_CACHE_ENABLED
value: {{ .Values.kerberospipeline.analysis.dbCache.enabled | default false | quote }}
+47 -2
View File
@@ -8,8 +8,53 @@
"pattern": "^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
},
"classificationCatalog": {
"not": {},
"description": "Removed in 0.155.0. Store the complete catalog in a ConfigMap and use workflowConfiguration.configMaps with replace: true at catalogs/classifications.json."
"type": ["array", "null"],
"minItems": 1,
"description": "Optional inline classification catalog in the Hub shared choice catalog format; replaces the bundled defaults in the chart's classification-catalog ConfigMap. Omit (or null) for the bundled defaults. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {"type": "string", "minLength": 1},
"label": {"type": "string", "minLength": 1},
"icon": {"type": "string", "minLength": 1}
}
}
},
"deviceTags": {
"type": "object",
"additionalProperties": false,
"properties": {
"system": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean",
"description": "Owners may assign system tags and global workflows may select devices by them. Only for deployments whose owners are trusted (self-hosted)."
},
"catalog": {
"type": "array",
"description": "The system tags owners can assign, in the Hub shared choice catalog format (key, label) plus an optional description. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {
"type": "string",
"maxLength": 64,
"pattern": "^[a-z0-9]([a-z0-9._:-]*[a-z0-9])?$"
},
"label": {"type": "string", "minLength": 1},
"description": {"type": "string"}
}
}
}
}
}
}
},
"kerberoshub": {
"type": "object",
+59 -8
View File
@@ -82,8 +82,39 @@ classificationCatalogEnabled: true
# When set, do not create a catalog ConfigMap; this replaces bundled defaults.
classificationCatalogExistingConfigMap: ""
# Defaults live in templates/configMaps/catalogs/classifications.yaml.
# Inline classificationCatalog values are no longer accepted (including null/[]).
# Use a ConfigMap item with path: catalogs/classifications.json and replace: true.
# Optionally define the complete catalog inline instead; it replaces the
# defaults in the chart's classification-catalog ConfigMap (and so the bundled
# catalogs/classifications.json). Entries are {key, label, icon?} with unique
# keys. Do not combine it with classificationCatalogExistingConfigMap or a
# catalogs/classifications.json replacement in workflowConfiguration.
# classificationCatalog:
# - key: car
# label: Car
# icon: car
# Device tags, grouped by type. System tags are defined here and assigned by
# owners (a multi-select on the device page); global workflows select devices
# across organisations by system tag (`systemTags` in a trigger). Owners set
# them, so any owner could enroll devices into such a workflow: enable only
# where owners are the deployment's administrators (self-hosted), never on
# multi-tenant SaaS. While disabled, hub-api gets an empty catalog (system tags
# cannot be set) and rendering fails on workflows that select devices by
# system tag.
deviceTags:
system:
enabled: false # a boolean (true/false), not a string
# The only system tags owners can assign, in the Hub shared choice catalog
# format (as catalogs/classifications.json) plus an optional description.
# Rendered into the device-system-tags ConfigMap for hub-api.
# key stored tag: 1-64 characters of a-z, 0-9, ".", "_", ":" or
# "-", starting and ending with a letter or digit; unique.
# label display name.
# description optional help text shown with the tag.
# Workflow trigger systemTags must exist here; otherwise rendering fails.
catalog: []
# - key: anpr-pilot
# label: ANPR pilot
# description: Runs licence plate recognition on this camera
# Configuration packaging only: consuming contracts requires a compatible
# API/frontend. Enabling this mounts files but does not register stage workers.
@@ -97,7 +128,7 @@ workflowConfiguration:
# Replacement requires includeDefaults: true and a known bundled destination path.
# Unmarked collisions and repeated custom destinations are rejected.
# Replacing catalogs/classifications.json also supplies the classification API:
# do not combine it with classificationCatalogExistingConfigMap.
# do not combine it with classificationCatalogExistingConfigMap or classificationCatalog.
# Legacy existingConfigMap/items/extraConfigMaps remain supported, but cannot
# be mixed with includeDefaults/configMaps. Both interfaces are omitted here
# so Helm's default merging does not introduce a false mixed configuration.
@@ -180,15 +211,26 @@ opentelemetry:
endpoint: "http://otel-collector:4318"
# Trace sampling, passed to the services as OTEL_TRACES_SAMPLER and
# OTEL_TRACES_SAMPLER_ARG. Leave empty to keep the SDK default, which records
# every trace. Example: keep ~10% of traces, and follow the parent's decision
# for spans that continue an upstream trace:
# type: "parentbased_traceidratio"
# arg: "0.1"
# every trace.
# Supported types: always_on, always_off, traceidratio, parentbased_always_on,
# parentbased_always_off, parentbased_traceidratio.
#
# sampler applies to the services downstream of the Vault: hub-workflows, the
# pipe-* services and the workflow stages. They continue the trace the Vault
# starts for an upload, so head sampling belongs at the Vault
# (parentbased_traceidratio on the Vault deployment) and these follow its
# decision without starting traces of their own:
# type: "parentbased_always_off"
sampler:
type: ""
arg: ""
# apiSampler applies to hub-api, which starts its own traces for user
# requests. Example: keep ~10% of them:
# type: "parentbased_traceidratio"
# arg: "0.1"
apiSampler:
type: ""
arg: ""
############################################
# OpenAI configuration (semantic search)
#
@@ -678,6 +720,7 @@ kerberoshub:
publicKey: ""
googlemaps: # Google maps is used inside the application to visualise cameras and sites.
apikey: "xxxx"
placesApi: "legacy" # Places API for address autocomplete: "legacy" (default) or "new" for keys with Places API (New) enabled. Uses the same apikey.
zendesk: # We can use different support tools, for now we use Zendesk but others can be integrated
url: "yourdomain.zendesk.com"
posthog: # Posthog is used for auditing and user interaction logging
@@ -839,7 +882,9 @@ kerberoshub:
# triggers how a run OPENS. Omit for a single bare automatic trigger
# (opens for every recording); the per-stage `needs` then decide
# which stages FIRE. Narrow with device/schedule triggers, e.g.
# `- {type: automatic, devices: [{key: <device-key>}]}`.
# `- {type: automatic, devices: [{key: <device-key>}]}`, or by
# device label across organisations, e.g.
# `- {type: automatic, systemTags: [anpr-pilot]}` (see deviceTags).
# stages the executable stages, each {operation, dispatch?, needs?,
# needsMode?}. dispatch is "always" (default) or "conditional";
# a conditional stage's `needs` are upstream dependencies, each
@@ -1243,6 +1288,12 @@ kerberospipeline:
# - name: extra
# mountPath: /data
logLevel: "info" # possible values: trace, debug, info, warn, error
# Opt-in: after classification, re-enqueue the recording on the thumbnail
# queue to regenerate its thumbnail from the first frame of a tracked moving
# object (THUMBNAIL_REGENERATION_ENABLED). Adds one thumbnail job per
# classified recording; size pipe-thumbnail accordingly before enabling.
thumbnailRegeneration:
enabled: false
# In-memory cache for hot-path MongoDB lookups (site vault per device).
# Site changes apply after at most one TTL; each replica caches separately.
dbCache: