Norviq has been deployed.

To access the UI (default access — the Grafana/Istio convention: port-forward, no ingress required):
  kubectl port-forward svc/norviq-ui 3000:80 -n {{ .Release.Namespace }}
  Then open: http://localhost:3000
{{- if .Values.ingress.enabled }}

  Ingress is ENABLED — the console is also reachable at {{ if .Values.ingress.tls }}https{{ else }}http{{ end }}://{{ .Values.ingress.host }}
  (requires an ingress controller for class "{{ .Values.ingress.className | default "nginx" }}" in the cluster).
  {{- if .Values.ingress.tls }}
  TLS is BRING-YOUR-OWN — the chart does NOT generate an ingress certificate (same as Grafana/Istio).
  Ensure the secret "{{ .Values.ingress.tlsSecretName | default "norviq-ingress-tls" }}" exists (pre-created,
  or issued by a cert-manager annotation in ingress.annotations), or the ingress serves the controller's
  default self-signed certificate — not a trusted one.
  {{- end }}
{{- end }}

FIRST LOGIN
{{- if .Values.auth.enabled }}
  Local login (default): open the console and sign in as
      username: {{ .Values.auth.adminUsername | default "admin" }}
{{- if eq (.Values.auth.adminPassword | default "norviq") "norviq" }}
  {{- /* Mirror templates/secret.yaml: "norviq" is a SENTINEL, not the password. When it is in effect the
       chart reuses the existing secret or generates randAlphaNum 20, so printing the sentinel here would
       hand every default install a credential that cannot work -- and auth.loginMaxAttempts retries
       would then trip the brute-force lockout (429). Print how to READ the real one instead. */}}
      password: auto-generated by the chart -- read it with:
          kubectl get secret norviq-secrets -n {{ .Release.Namespace }} \
            -o jsonpath='{.data.NRVQ_AUTH_ADMIN_PASSWORD}' | base64 -d ; echo
  (A strong random password is generated on first install and preserved across `helm upgrade`. Pin your
  own instead by setting auth.adminPassword.)
{{- else }}
      password: the auth.adminPassword you set
{{- end }}
  You will be prompted to change it on first login (must_change=true), so this credential is single-use.
{{- end }}

  SSO (recommended for teams): enable OIDC (see docs/onboarding-login.md), then the console also shows
  "Sign in with SSO". Your IdP group maps to a Norviq role + namespace (Entra / Okta / Auth0 / Keycloak).

  Automation/CI: mint a short-lived admin token in-cluster (no password, key never leaves the cluster):
      norviq login -n {{ .Release.Namespace }} --console-url http://localhost:3000
  It prints a sign-in link (or paste the printed token under the console login's "Use a token / CLI" field).

To access the API:
  kubectl port-forward svc/norviq-api 8080:{{ .Values.api.port }} -n {{ .Release.Namespace }}
  Then: curl http://localhost:8080/healthz

{{- if .Values.webhook.injection.enabled }}

Sidecar injection is ENABLED (mode: {{ .Values.webhook.injection.sidecarMode | default "proxy" }}). TLS was
auto-bootstrapped by the norviq-webhook-cert hook Job (self-signed cert -> norviq-webhook-tls secret ->
patched webhook caBundle).
  Opt a namespace in:  kubectl label ns <ns> norviq-injection=enabled
  Then label each AGENT pod:  norviq.io/agent-class=<class>
  A pod WITHOUT that label is not injected. This is deliberate (webhook.injection.gateOnlyAgentPods,
  default true): with failurePolicy: Fail, routing every pod in the namespace through the webhook
  would make a Norviq outage a precondition for starting the namespace's database and ingress too.
  Set gateOnlyAgentPods=false for the older namespace-wide behaviour.
  Opt a single pod OUT:  set the pod label  norviq-injection=disabled  (or annotation
                         norviq.io/skip-injection=true).
  The agent-class label above is REQUIRED for injection under the default, and it is also what
  class-tier policy matches on.
{{- else }}

Sidecar injection is DISABLED. Turn it on (turnkey, auto-TLS, no cert-manager needed):
  helm upgrade --install norviq ./helm/norviq --set webhook.injection.enabled=true
  kubectl label ns <ns> norviq-injection=enabled
{{- end }}

To check status:
  kubectl get pods -n {{ .Release.Namespace }}

To view logs:
  kubectl logs -f deployment/norviq-api -n {{ .Release.Namespace }}
  kubectl logs -f deployment/norviq-engine -n {{ .Release.Namespace }}

UPGRADING
  Use `-f your-values.yaml` (or `--reset-then-reuse-values` on Helm >= 3.14) rather than
  `--reuse-values`. `--reuse-values` replays only the values YOU supplied last time and does not merge
  in values a newer chart added, so a chart that gains a value can fail the upgrade outright.

  A partial image upgrade does NOT fully upgrade Norviq. The bundled Rego baselines are materialized
  into the database by the WEBHOOK image, and enforcement reads what is in the database — so pinning
  only images.api/images.engine to a new tag leaves the OLD policy enforcing while every version
  string reports the new one. Move all four image tags together (api, engine, ui, webhook) unless you
  have a specific reason not to.

Production reminder:
  api.secretKey and the datastore passwords are AUTO-GENERATED on first install and reused on upgrade —
  nothing to override for them. Read the admin password with:
      kubectl get secret norviq-secrets -n {{ .Release.Namespace }} -o jsonpath='{.data.NRVQ_AUTH_ADMIN_PASSWORD}' | base64 -d
  Set postgresql/redis.password explicitly only to bring your own credential (required when
  postgresql.ha.enabled / redis.ha.enabled), or point postgresql/redis.existingSecret at a Secret you
  manage — the production path, since a --set password lands in `helm history`. For an EXTERNAL managed
  datastore set postgresql.enabled=false + postgresql.host=<host> (same for redis).
  Set values.policyQuotaNamespaces to include every tenant namespace (for example: default, chatbot-prod, analytics); quotas and baseline policies render from this list.
  A baseline high-priority policy is installed for EACH namespace in policyQuotaNamespaces (values.baselineClusterPolicy.*). It ships in audit mode: it records non-compliance and does not block. Set baselineClusterPolicy.enforcementMode=block to enforce it. NOTE: with baselineClusterPolicy.enabled=true, an EMPTY policyQuotaNamespaces now FAILS the install (it would otherwise render no baseline at all) — list your tenant namespaces, or set enabled=false to opt out explicitly.
  Bind ClusterRoles to your tenant/admin groups (this chart ships roles but not subject-specific bindings).
  Policies with permissive preset and/or enforcementMode=audit provide visibility only and do not enforce blocks.
