Gitea #143. Additive, default false, so the render is byte-identical to the previous release - proven by diffing both renders against origin/main rather than asserted. Switched on it adds 15008/TCP, ztunnel's HBONE tunnel, to the rule carrying the probe port, and - inside that rule's source-restricted branch - 169.254.7.127/32, the address the kubelet's probes arrive from once the pod is in the mesh. Ambient does not bypass NetworkPolicy enforcement, so without the port a pod whose namespace has joined the mesh is unreachable. The two halves are one value because the second is the one nobody thinks of: 15008 added by hand leaves a policy that passes review and drops every probe the first time probeSources is narrowed, and a pod that never becomes Ready reads as a broken application rather than as a policy. Minor, not major: additive value, unchanged default, unchanged render.
281 lines
14 KiB
JSON
281 lines
14 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
|
"title": "homeassistant values",
|
|
"description": "Strict values schema (issue #68). additionalProperties is false on every chart-owned object level, so a key that the chart does not read is rejected at render time instead of being silently ignored. The only objects that stay open are the ones passed verbatim into the Kubernetes pod spec (probes, security contexts, volumes, scheduling, global) - the chart does not interpret their contents, so it cannot judge which keys are meaningful. The hardening, probe and resources blocks additionally accept null, because an erased block falls back to the chart defaults (issue #99). Note that this chart keeps replicas, resources, probes and securityContext at the TOP level, and that its ingress block deliberately follows the upstream host/tls style (documented exception in the README).",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"global": {
|
|
"description": "Helm's conventional cross-chart values. Unused by this chart, kept open so an umbrella install cannot break on it.",
|
|
"type": "object"
|
|
},
|
|
"networkPolicy": {
|
|
"description": "The chart's NetworkPolicy (Gitea #5), on by default. A ceiling on reachability and not an authentication layer: only the declared container ports are reachable at all, egress is capped by PORT (a NetworkPolicy matches CIDRs and selectors, never hostnames, so a destination host cannot be expressed), and ingress is capped by source for every port no network probe touches. Only a boundary where the cluster's CNI enforces policies - an unenforced policy is accepted by the API server and filters nothing. The template's header carries the full list of what it does not do.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"ingress": {
|
|
"description": "The policy's INBOUND side. Three names here overlap as substrings and are not the same thing: the top-level ingress is the Ingress OBJECT this chart renders, networkPolicy.ingress is this block, and networkPolicy.ingressController is the SOURCE SELECTOR for the ingress controller's pods - a SIBLING of this block and no part of it.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"ambientMesh": {
|
|
"description": "Opens the pod for Istio's ambient mesh; off by default and additive, so the render is byte-identical while it is false. Renders 15008/TCP inbound - ztunnel's HBONE tunnel, which ambient explicitly does not let bypass NetworkPolicy enforcement - AND, where probeSources is non-empty, 169.254.7.127/32 as an additional probe source, because inside the mesh the kubelet's probes are redirected away from the worker node's address. The two halves are inseparable on purpose: whoever opens 15008 by hand has not added the probe address, and the first narrowed probeSources then drops every probe, so the pod never becomes Ready and the symptom reads as a broken application rather than as a policy. Unproven in operation: that 15008 alone suffices comes from Istio's documentation, and no namespace of this cluster carries istio.io/dataplane-mode yet.",
|
|
"type": ["boolean", "null"]
|
|
}
|
|
}
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"allowedNamespaces": {
|
|
"description": "Namespaces whose pods may reach this workload, in addition to the release's own namespace, which is always allowed. Matched on the kubernetes.io/metadata.name label Kubernetes sets on every namespace itself, so no labelling work is needed - and no typo protection either: a name that does not exist matches nothing and is silently ineffective. An entry opens the port to EVERY pod in that namespace; for the ingress controller use ingressController instead.",
|
|
"type": ["array", "null"],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"probeSources": {
|
|
"description": "Source CIDRs allowed to reach the port the network probes address. EMPTY MEANS OPEN, not blocked: with no entry that rule is rendered without a \"from\" selector. The kubelet's probes come from the IP of the worker node running the pod, an address the chart cannot know and must not guess - a guessed CIDR that excludes the real node blocks every probe and the pod never becomes Ready, which reads as a broken application rather than as a policy. Setting this restricts the rule, which is why the chart adds the own namespace, ingressController and allowedNamespaces to the same rule.",
|
|
"type": ["array", "null"],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"scaleDown": {
|
|
"type": "boolean"
|
|
},
|
|
"replicas": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"service": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"type": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"port": {
|
|
"type": ["integer", "null"],
|
|
"minimum": 1,
|
|
"maximum": 65535
|
|
}
|
|
}
|
|
},
|
|
"ingress": {
|
|
"description": "Documented exception (README): this chart keeps the upstream-style flexible ingress values - host and tls lists instead of the repo's required domain/clusterIssuer pair. The list entries go verbatim into the Ingress spec, so they stay open. Mutually exclusive with httpRoute.enabled (Gitea #114) - the render aborts when both are true.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"className": {
|
|
"description": "Set to \"\" to omit ingressClassName from the rendered Ingress. Not read in Gateway mode: the class is a property of the Gateway there, and the Gateway belongs to the platform.",
|
|
"type": ["string", "null"]
|
|
},
|
|
"annotations": {
|
|
"description": "Not read in Gateway mode: the Gateway API has no annotation channel for controller behaviour, so anything set here is gone in that mode. The chart sets nothing itself.",
|
|
"type": "object"
|
|
},
|
|
"hosts": {
|
|
"description": "The public names of this release, READ IN BOTH MODES - this chart has no ingress.domain, so there is no httpRoute.hostnames either and the hostnames live here. In Gateway mode the chart renders one HTTPRoute per entry, with one rule per path of that entry. pathType maps Exact to Exact and Prefix to PathPrefix; ImplementationSpecific (the default below) has no Gateway-API counterpart and is rendered as PathPrefix on \"/\" only - on any other path the render aborts rather than silently changing how the path matches, because in ingress-nginx an ImplementationSpecific sub-path is a regex. RegularExpression is not offered: its support level is Implementation-specific.",
|
|
"type": ["array", "null"]
|
|
},
|
|
"tls": {
|
|
"description": "Not read in Gateway mode: the certificate sits on the Gateway's listener and belongs to the platform.",
|
|
"type": ["array", "null"]
|
|
}
|
|
}
|
|
},
|
|
"httpRoute": {
|
|
"description": "Gateway-API alternative to the Ingress (Gitea #114). Mutually exclusive with ingress.enabled - the render aborts when both are true, naming both value paths. The chart renders only HTTPRoutes with parentRefs; class and certificate sit on the Gateway and belong to the platform. TWO KEYS ONLY, and the missing hostnames key is deliberate: this chart is the documented ingress exception and has no ingress.domain, so the hostnames and paths come from ingress.hosts and the chart renders ONE route per entry there (the freesailarr shape from group 2 of the sweep). Reordering ingress.hosts renames routes, which recreates rather than edits them - harmless, since a route holds no state. The Gateway-API CRDs must be present in the cluster, because the chart cannot detect them.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"parentRefs": {
|
|
"description": "The Gateway(s) every route of this release attaches to. Required while httpRoute.enabled is true, enforced by required()-equivalent in the template (an empty list aborts the render) - a JSON Schema \"required\" cannot do it, because the key ships as an empty list and is therefore present. Entries are the Gateway API's ParentReference and are passed through unchanged. The same list is used for every route; the hosts differ, the Gateway does not.",
|
|
"type": "array",
|
|
"items": { "$ref": "#/definitions/parentRef" }
|
|
}
|
|
}
|
|
},
|
|
"securityContext": {
|
|
"$ref": "#/definitions/securityContext"
|
|
},
|
|
"resources": {
|
|
"$ref": "#/definitions/resources"
|
|
},
|
|
"livenessProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"readinessProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"startupProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"env": {
|
|
"$ref": "#/definitions/env"
|
|
},
|
|
"volumes": {
|
|
"description": "Additional volumes, rendered verbatim into the pod spec.",
|
|
"type": ["array", "null"]
|
|
},
|
|
"volumeMounts": {
|
|
"description": "Additional volumeMounts, rendered verbatim into the container.",
|
|
"type": ["array", "null"]
|
|
},
|
|
"nodeSelector": {
|
|
"description": "Rendered verbatim into the pod spec.",
|
|
"type": ["object", "null"]
|
|
},
|
|
"tolerations": {
|
|
"description": "Rendered verbatim into the pod spec.",
|
|
"type": ["array", "null"]
|
|
},
|
|
"affinity": {
|
|
"description": "Rendered verbatim into the pod spec.",
|
|
"type": ["object", "null"]
|
|
},
|
|
"core": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"timezone": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"storage": {
|
|
"description": "The config PVC. Not null-safe on purpose: an erased block yields an invalid PVC rather than a silently degraded workload.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"size": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"storageClass": {
|
|
"type": ["string", "null"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"secrets": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"configSecretRef": {
|
|
"description": "op:// item path holding config, http-config and recorder-config. Changing the PATH restarts the pod via the checksum/secret-ref annotation; changing the item CONTENT does not - see the note in values.yaml (#82).",
|
|
"type": ["string", "null"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"definitions": {
|
|
"parentRef": {
|
|
"description": "A Gateway API ParentReference, passed verbatim into HTTPRoute.spec.parentRefs. Deliberately left OPEN (no additionalProperties: false), for the same reason probes and security contexts are: Kubernetes owns this schema, the Gateway API adds fields to it across releases, and a closed list here would reject a field only upstream knows about. What the chart can assert is that \"name\" is there - it is required by the API and a reference without it attaches to nothing, which is the silent failure this chart aborts the render over.",
|
|
"type": "object",
|
|
"required": ["name"]
|
|
},
|
|
"resources": {
|
|
"description": "May be null / empty: the chart then falls back to its default requests and computed limits (issue #99) instead of rendering a container without resource accounting.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"limitFactor": {
|
|
"type": "number",
|
|
"exclusiveMinimum": 0
|
|
},
|
|
"requests": {
|
|
"$ref": "#/definitions/resourceList"
|
|
},
|
|
"limits": {
|
|
"$ref": "#/definitions/resourceList"
|
|
}
|
|
}
|
|
},
|
|
"resourceList": {
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"cpu": {
|
|
"type": ["string", "number", "null"]
|
|
},
|
|
"memory": {
|
|
"type": ["string", "number", "null"]
|
|
},
|
|
"ephemeral-storage": {
|
|
"type": ["string", "number", "null"]
|
|
},
|
|
"ephemeralStorage": {
|
|
"type": ["string", "number", "null"]
|
|
}
|
|
}
|
|
},
|
|
"env": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name"],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"value": {
|
|
"type": "string"
|
|
},
|
|
"valueFrom": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"secretKeyRef": {
|
|
"$ref": "#/definitions/keyRef"
|
|
},
|
|
"configMapKeyRef": {
|
|
"$ref": "#/definitions/keyRef"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"keyRef": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "key"],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"key": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"securityContext": {
|
|
"description": "May be null / empty at any level: the chart then falls back to its hardening defaults (issue #99). Note that this chart's hardening is a documented deviation - the pod context is deliberately empty because the image must start as root (s6-overlay), and capabilities.add keeps NET_RAW for device discovery.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"pod": {
|
|
"description": "Merged onto the chart's pod defaults (empty by design) and rendered as the pod's securityContext; kept open because the chart does not interpret the individual fields.",
|
|
"type": ["object", "null"]
|
|
},
|
|
"container": {
|
|
"description": "Merged onto the chart's container defaults and rendered as the container's securityContext; kept open because the chart does not interpret the individual fields.",
|
|
"type": ["object", "null"]
|
|
}
|
|
}
|
|
},
|
|
"probe": {
|
|
"description": "Merged onto the chart's probe defaults and rendered as a container probe; kept open because the chart does not interpret the individual fields. May be null / empty, which means the defaults apply (issue #99) rather than the probe disappearing.",
|
|
"type": ["object", "null"]
|
|
}
|
|
}
|
|
}
|