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. Port half only: this chart offers no networkPolicy.probeSources - its probes put no packet on the network - so there is no redirected probe to allow and an ipBlock for one would match nothing while making the rule look like it did something. ci/run-networkpolicy-test.sh ties that exemption to the absence of probeSources, not to a chart name.
377 lines
15 KiB
JSON
377 lines
15 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
|
"title": "minecraft-server values",
|
|
"description": "Strict values schema (issue #68 pilot). 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, 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). Both halves are needed and cover different cases: for a key WITH a chart default Helm's coalescing deletes the null before validation ever sees it, and only the defaultedDict fallback in _helpers.tpl catches that; for a key WITHOUT one (e.g. server.resources.limits) the null survives into validation, where a strict \"object\" would abort the render. Everything else stays strictly typed.",
|
|
"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": {
|
|
"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"
|
|
}
|
|
},
|
|
"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"]
|
|
}
|
|
}
|
|
},
|
|
"egress": {
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"extraPorts": {
|
|
"description": "Additional outbound TCP ports, to ANY destination - ports and not destinations, because a NetworkPolicy cannot express a hostname. DNS is always allowed and has no switch. Without an entry here an outbound port the chart does not already derive is blocked, which is the cap's whole purpose and also its upgrade risk.",
|
|
"type": ["array", "null"],
|
|
"items": {
|
|
"type": "integer"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"scaleDown": {
|
|
"type": "boolean"
|
|
},
|
|
"image": {
|
|
"description": "May be null / empty: the effective tag then falls back to the chart's appVersion, which is the pre-5.0.0 behaviour.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"tagOverride": {
|
|
"description": "Tag of the itzg/minecraft-server image. Empty or null means the chart's appVersion. Deliberately not called \"tag\": it decouples the running image from the chart version and is not managed by Renovate. The Java line of the effective tag is validated against minecraft.version at render time; a tag without a recognizable \"java<N>\" part is let through on purpose.",
|
|
"type": ["string", "null"]
|
|
}
|
|
}
|
|
},
|
|
"secrets": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"minecraftServerRef": {
|
|
"description": "op:// item path for the 1Password operator. Required even when RCON and the CurseForge downloader are both off: the OnePasswordItem is rendered unconditionally. The item's CONTENT may be empty in that case, the reference may not. Enforced by required() in the template, not here: the null default keeps this type widened, and a schema \"required\" entry could never fire against a key that is present with value null.",
|
|
"type": ["string", "null"]
|
|
}
|
|
}
|
|
},
|
|
"server": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"replicas": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"port": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 65535
|
|
},
|
|
"service": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"type": {
|
|
"type": "string",
|
|
"enum": ["ClusterIP", "NodePort"]
|
|
},
|
|
"port": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 65535
|
|
},
|
|
"outwardPort": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 65535
|
|
}
|
|
}
|
|
},
|
|
"motd": {
|
|
"type": "string"
|
|
},
|
|
"rcon": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"port": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 65535
|
|
}
|
|
}
|
|
},
|
|
"initImage": {
|
|
"type": "string"
|
|
},
|
|
"resources": {
|
|
"description": "May be null / empty: the chart then falls back to its default requests and computed limits (issue #99) instead of rendering the server container without resource accounting. The memory request stays deliberately unset in that fallback, as in values.yaml, so it keeps being derived from the JVM heap (minecraft.resources.memory).",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"limitFactor": {
|
|
"type": "number",
|
|
"exclusiveMinimum": 0
|
|
},
|
|
"requests": {
|
|
"$ref": "#/definitions/resourceList"
|
|
},
|
|
"limits": {
|
|
"$ref": "#/definitions/resourceList"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"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"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"livenessProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"readinessProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"startupProbe": {
|
|
"$ref": "#/definitions/probe"
|
|
},
|
|
"securityContext": {
|
|
"description": "May be null / empty at any level: the chart then falls back to its hardening defaults (issue #99) instead of rendering an unhardened workload. The pod context is consumed twice - as the pod's securityContext and by the serverpack init script, which chowns the migrated files to runAsUser:runAsGroup; both reads go through the same helper.",
|
|
"type": ["object", "null"],
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"pod": {
|
|
"description": "Merged onto the chart's pod hardening defaults 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 hardening defaults and rendered as the securityContext of the server container and the serverpack init container; kept open because the chart does not interpret the individual fields.",
|
|
"type": ["object", "null"]
|
|
}
|
|
}
|
|
},
|
|
"minecraft": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"difficulty": {
|
|
"type": "string",
|
|
"enum": ["peaceful", "easy", "normal", "hard"]
|
|
},
|
|
"whitelist": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"description": "Wired to the image's ENABLE_WHITELIST in both positions: true sets white-list=true (and enforce-whitelist=true), false rewrites white-list=false into an existing server.properties on the volume. true without players locks everyone out - that is the image's semantics and it is intended.",
|
|
"type": "boolean"
|
|
},
|
|
"overridePolicy": {
|
|
"description": "EXISTING_WHITELIST_FILE - how an already existing whitelist.json is treated. Only applies while enabled is true.",
|
|
"type": "string",
|
|
"enum": ["SKIP", "MERGE", "SYNCHRONIZE"]
|
|
},
|
|
"players": {
|
|
"description": "Comma-separated players, passed as WHITELIST only while enabled is true (a non-empty WHITELIST would otherwise enable the whitelist despite ENABLE_WHITELIST=false).",
|
|
"type": ["string", "null"]
|
|
}
|
|
}
|
|
},
|
|
"management": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"opPlayers": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"maxPlayers": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"forceGameMode": {
|
|
"type": "boolean"
|
|
},
|
|
"gameMode": {
|
|
"type": "string",
|
|
"enum": ["creative", "survival", "adventure", "spectator"]
|
|
},
|
|
"worldSaveName": {
|
|
"type": "string"
|
|
},
|
|
"serverName": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"resources": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"storage": {
|
|
"type": "string"
|
|
},
|
|
"storageClassName": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"memory": {
|
|
"description": "JVM heap in gigabytes, passed to the image as MEMORY with a G suffix appended.",
|
|
"type": ["string", "number"]
|
|
}
|
|
}
|
|
},
|
|
"version": {
|
|
"type": ["string", "number"]
|
|
}
|
|
}
|
|
},
|
|
"curseforge": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"forceReload": {
|
|
"type": "boolean"
|
|
},
|
|
"modpack": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"slug": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"versionId": {
|
|
"type": ["string", "integer", "null"]
|
|
},
|
|
"exclude": {
|
|
"type": ["string", "integer", "null"]
|
|
},
|
|
"excludeOverride": {
|
|
"type": ["string", "integer", "null"]
|
|
},
|
|
"include": {
|
|
"type": ["string", "integer", "null"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ftb": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"modpackId": {
|
|
"type": ["string", "integer", "null"]
|
|
},
|
|
"versionId": {
|
|
"type": ["string", "integer", "null"]
|
|
}
|
|
}
|
|
},
|
|
"curseforgeServerpack": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"downloadUrl": {
|
|
"type": ["string", "null"]
|
|
},
|
|
"workingDirectory": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"definitions": {
|
|
"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"]
|
|
}
|
|
}
|
|
},
|
|
"keyRef": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "key"],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"key": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"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. The defaults carry the probe's context, not just its timings: all three run the image's mc-health script as an exec probe, which is the only health check this image offers.",
|
|
"type": ["object", "null"]
|
|
}
|
|
}
|
|
}
|