The 2026-09-29 session found the merge gate did not exist -- no branch protection, no runner -- while the tree asserted both. This corrects the documents that carried, and in several cases CAUSED, that belief. CLAUDE.md gains section 2b: never infer platform state from this repository. It carries the specific API and kubectl checks for protection, runners, CI status, workloads and Flux revisions, and the rule that a green tick is not proof anything ran (a skipped Gitea job reports success). This is the rule whose absence produced every other finding. .gitea/workflows/README.md and merge-gate.yaml both said "there is no remote git host, this file is dormant". Gitea had been live for weeks. Both were written as plans and never revisited once the plan completed. The Transition section is now marked COMPLETE and says what is genuinely still outstanding (CLUSTER_AVAILABLE unset, so L2/L3 never runs in CI). DECISIONS-LOG 2026-08-31 is annotated IN PLACE. Anyone reading chronologically previously hit "required status check; runner incluster-dind online" with nothing marking it false until a month later. The correction now sits on the bullet itself. ci/README.md, clusters/README.md and both conformance READMEs carry a status banner: they speak as though no cluster exists, which makes a live L2/L3 coverage gap read as an expected phase. That framing is why the gap went unexamined. apps/wave-1/gitea-actions-runner-secret.sops.yaml: fixed a wrong path, replaced advice to `sops -d` into a terminal (which CLAUDE.md forbids) with the rotation script, and recorded that a fresh token alone does not re-register a runner holding a stale /data/.runner. apps/wave-0/plex-claim-secret.sops.yaml: the header claimed the file ships the placeholder. It has not since the claim -- it holds the spent token, which is inert and deliberately left in place. catalog/plex.yaml and the plex secret both asserted a "~4-minute TTL" as fact. It was uncited, upstream documents no expiry, and it was the basis for a since-disproven claim that the pipeline was too slow to fit inside it. Measured: ~2m45s. Both .sops.yaml files were verified to still decrypt after the comment edits (`sops -d > /dev/null`), and render==golden confirms the catalog comment does not propagate into the rendered manifest. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
78 lines
4.9 KiB
YAML
78 lines
4.9 KiB
YAML
# Plex plex.tv server-claim token (WS-APPS). SOPS-encrypted (age).
|
|
# Consumed by catalog/plex.yaml as env PLEX_CLAIM via valueFrom.secretKeyRef.
|
|
#
|
|
# NOTE ON THESE COMMENTS: they carry NO dollar-brace expressions, deliberately. This file is applied
|
|
# by the apps-wave-0 Flux Kustomization, which runs envsubst over the built output, and kustomize
|
|
# preserves body comments into that stream (see conformance/tests/l0-static/flux-postbuild-
|
|
# substitution). A braced token quoted from the upstream shell script would be a live hazard here,
|
|
# not prose, so the upstream conditions below are described in words.
|
|
#
|
|
# THIS FILE NO LONGER HOLDS THE PLACEHOLDER. Corrected 2026-09-29: the server was CLAIMED on that
|
|
# date, and the value here is the SPENT token from that claim. It is inert and safe to leave --
|
|
# upstream gates the exchange on PlexOnlineToken being ABSENT from /config, and it is now present on
|
|
# the plex-config PVC, so this value is a NO-OP on every start whatever it holds. Deleting the Secret
|
|
# would NOT be safe (see below), which is why a spent token stays here rather than being blanked.
|
|
#
|
|
# The claim token is SHORT-LIVED -- minutes. Read the countdown that plex.tv/claim renders when it
|
|
# issues one; do NOT budget against a number written in this tree. Earlier revisions of this comment
|
|
# asserted a "~4-minute TTL" as established fact with no citation, and upstream plexinc/pms-docker
|
|
# documents no expiry at all. That uncited number was load-bearing for the whole procedure design.
|
|
#
|
|
# This file exists to make the Secret — and therefore the env reference — ALWAYS RESOLVABLE IN THE
|
|
# FLUX GRAPH, not to carry a working token. Re-claiming (only needed after a /config wipe) is
|
|
# scripted: infra/plex/claim-ship.sh, measured at ~2m45s end to end.
|
|
#
|
|
# WHY SHIPPING A PLACEHOLDER IS SAFE (verified against plexinc/pms-docker branch `master`, the
|
|
# s6-overlay v2 script root/etc/cont-init.d/40-plex-first-run, cross-checked byte-identical against
|
|
# the same file extracted from the running `plexinc/pms-docker:latest` image):
|
|
# - line 106 guards the claim exchange on TWO conditions: PLEX_CLAIM non-empty AND the
|
|
# PlexOnlineToken pref read out of /config empty. Once the server is claimed that block is
|
|
# skipped entirely, so whatever this Secret holds is a NO-OP on every later start. Upstream
|
|
# README: "If server is already logged in, this parameter is ignored."
|
|
# - on a still-UNCLAIMED /config, an invalid or expired token makes plex.tv answer 403 with an
|
|
# empty body. curl's exit status is never checked, the sed for the authentication-token element
|
|
# yields the empty string, and the success branch at line 120 simply does not fire. There is no
|
|
# else branch and no non-zero exit; the script has no `set -e` and ends by touching
|
|
# /.firstRunComplete and echoing, so it exits 0. The server comes up UNCLAIMED and serving.
|
|
# It does NOT crashloop.
|
|
# - the image never sets S6_BEHAVIOUR_IF_STAGE2_FAILS, whose default is 0 ("continue silently even
|
|
# if a cont-init script failed"), so even a hypothetical non-zero exit would not halt startup.
|
|
# A MISSING Secret would NOT be safe: the ServiceDefinition schema's valueFrom.secretKeyRef shape
|
|
# has no `optional` field, so an absent Secret is a hard CreateContainerConfigError. That is exactly
|
|
# why this file is committed and listed in apps/wave-0/kustomization.yaml instead of being created
|
|
# by hand at claim time.
|
|
#
|
|
# INJECTION / ROTATION (operator, not agents) — runbooks/plex-claim.md has the timed procedure:
|
|
# infra/devcontainer/dev.sh run sops apps/wave-0/plex-claim-secret.sops.yaml
|
|
# Never decrypt this file into a shell, a log, or a shared terminal.
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: plex-claim
|
|
namespace: plex
|
|
labels:
|
|
app.kubernetes.io/name: plex
|
|
type: Opaque
|
|
stringData:
|
|
PLEX_CLAIM: ENC[AES256_GCM,data:nLmzeUBWRhRjUakrGiGzQpQuqZNcIYvRH6M=,iv:z0on/dArsNejNLrp3V1nSiNLFzKcREhPuMO1634CwQw=,tag:Ih23CT1JYna/5lfYQUb1Dw==,type:str]
|
|
sops:
|
|
kms: []
|
|
gcp_kms: []
|
|
azure_kv: []
|
|
hc_vault: []
|
|
age:
|
|
- recipient: age175l8mdpdfu7hq0aml3exs3gykarwjmuvr23sq56s3wjejnyk44wsp4mfzg
|
|
enc: |
|
|
-----BEGIN AGE ENCRYPTED FILE-----
|
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2dWtqOVNQalZ2QlRxOXJa
|
|
cDc1MTdtWENkdWIxS1JId3dIU1JDSmk0ODNrCk1YUzhFWXR3bUxyV2NNcmFOakdz
|
|
THl1Q284dFJxTy9Rd1h0eXJJaVZtdmcKLS0tIERuN0ZFeW9zdi9aNFRYNWxmUS9s
|
|
QUtYdHEvN042ajNoNktOLzlYQmQrc1kK4NHozMbXVzNGYbUBRbK6a9Uw/sVPAfe6
|
|
RW5KWzZ4I/hloqjN3zzVISoSMieMkBGDnF5qZS5N6FqIc6/HrsDD8A==
|
|
-----END AGE ENCRYPTED FILE-----
|
|
lastmodified: "2026-09-29T06:31:16Z"
|
|
mac: ENC[AES256_GCM,data:62BmBAq45CD2g6LDyx+Ho4bTfrhJcaro/RB/iM+OaRc4a/D83MhjbcBL11Uz/O726inqhkvCKDJ/fFemoc50JDbtC79cYMaxrGJNjFM0sdckWrowPvh6ie7HHHUBRBaefl+gNfnc+pbvcncvRzwA4RyzcZse1wbxKfHN8FjEopE=,iv:h0cMShs3tIgnY6eruUYymYrcLFzQZLk/uXQJ/Jsd5ek=,tag:nZ9Pau7p4xWT1QCN1vv2vA==,type:str]
|
|
pgp: []
|
|
encrypted_regex: ^(data|stringData)$
|
|
version: 3.9.4
|