IR-20261111-baohelper: bao-operator-token writes the token to a 0600 file, never to stdout #943
Open
pi-landing
wants to merge 5 commits from
plane/IR-20261111-baohelper into live
pull from: plane/IR-20261111-baohelper
merge into: Homelab:live
Homelab:main
Homelab:live
Homelab:sso/zitadel-guest-users
Homelab:sso/argocd-readonly-groups
Homelab:lr-20261111-025/amendment-4
Homelab:ld/IR-20261112-phase1guard
Homelab:ld/IR-20261112-kimipool
Homelab:lr-20261111-017-a24
Homelab:plane/IR-20261112-relayalert
Homelab:plane/IR-20261112-sbxdisk
Homelab:lr-20261111-025/seat-template
Homelab:plane/IR-20261112-mgmtdns
Homelab:plane/IR-20261112-r10-openbao-loki
Homelab:plane/f-r2-d6-sbx-reviewer-out
Homelab:plane/R39-forgejo-access-log-sink
Homelab:plane/R39-forgejo-access-log-auth
Homelab:plane/IR-20261111-extdel-v2
Homelab:plane/f-r2-d6-gits-reviewer-removal
Homelab:plane/R39-forgejo-access-log
Homelab:plane/R1-localbin
Homelab:plane/IR-20261111-r25offdisk
Homelab:plane/IR-20261112-runners8
Homelab:plane/EXTDEL-4918-forgejo-ext
Homelab:plane/IR-20261112-npmcache
Homelab:lr-20261111-016-launchcap
Homelab:plane/IR-20261111-runners10
Homelab:plane/IR-20261111-c8brief
Homelab:IR-20261111-runnercap
Homelab:plane/IR-20261111-gitsemu
Homelab:plane/IR-20261111-runnerlock
Homelab:plane/IR-20261111-c8grants
Homelab:lr-20261111-017-n9
Homelab:lr-20261111-025/seatpost
Homelab:ld/LR-20261111-024-seat-ban
Homelab:lr-20261111-017-seatlookup
Homelab:spec-014-skill-sync
Homelab:ld-spec-009/relay-fixforward
Homelab:ld/spec-016-launch-cap
Homelab:ld-spec-009/relay-a3
Homelab:plane/LR-20261111-018-seat-posting
Homelab:plane/LR-20261111-012-sbx-lab-transcripts
Homelab:spec-010-fit2
Homelab:ld-spec-009/relay
Homelab:plane/HOMELAB-C3C-epic-supervisor
Homelab:plane/dircfg-c3b-work-pointer
Homelab:plane/HOMELAB-2479-sbx-ffmpeg
Homelab:plane/dircfg-c5-epic-supervisor
Homelab:plane/dircfg-c4-opening
Homelab:plane/dircfg-c3-work-md
Homelab:plane/dircfg-c2-brief-metodo
Homelab:plane/dircfg-c6-sbx-sendrast-skills
Homelab:plane/HOMELAB-2479-zitadel-display-name
Homelab:plane/dircfg-c1-director-gitinit
Homelab:plane/HOMELAB-2479-sbx-sendrast-9gi
Homelab:plane/HOMELAB-2479-invite-list-reader
Homelab:plane/HOMELAB-2479-sbx-lab-wk02-affinity
Homelab:plane/HOMELAB-2479-wk02-sbx-lab-limit
Homelab:plane/HOMELAB-2479-zitadel-user-drift
Homelab:plane/HOMELAB-2479-zitadel-h2c
Homelab:spec-008-b-sbxlab-pin
Homelab:spec-008-a-sbxfleet-base-bump
Homelab:spec-007-ld-implement-skill
Homelab:archive/plane/HOMELAB-2658-omniroute-containment-wip-20261110
Homelab:archive/plane/HOMELAB-2446-wk01-requests-wip-20261110
Homelab:plane/HOMELAB-2479-gits-fixture-vendor
Homelab:ld-spec-004
Homelab:plane/HOMELAB-2479-plane-smtp-chart
Homelab:ld-spec-003
Homelab:plane/HOMELAB-2479-aaron-site-zitadel
Homelab:plane/HOMELAB-2479-runner-requests
Homelab:plane/ld-stopnow-gits-pin
Homelab:plane/ld-stopnow-alias-retire
Homelab:plane/HOMELAB-2479-sbx-gits-probe-tmp
Homelab:plane/HOMELAB-2479-gits-toolcache
Homelab:plane/ld-stopnow-sbxlab-pin
Homelab:plane/ld-stopnow-sbxfleet-base2
Homelab:plane/ld-stopnow-sbxfleet-base
Homelab:plane/ld-stopnow-item2-skill-rule
Homelab:plane/HOMELAB-88-cm-ssa-syncopt
Homelab:plane/HOMELAB-88-sandbox-telemetry
Homelab:plane/HOMELAB-88-sbx-gits-16g
Homelab:plane/HOMELAB-88-whisper-cuda
Homelab:plane/HOMELAB-2479-secretscan-fixture-allowlist
Homelab:plane/HOMELAB-2479-registry-backup
Homelab:plane/HOMELAB-2682-sandbox-init-tmpfix
Homelab:plane/HOMELAB-2479-fix-port-gate
Homelab:plane/HOMELAB-2479-emulator-gate
Homelab:plane/HOMELAB-2479-fixture-resync
Homelab:plane/HOMELAB-2682-forgejo-ext-pin-cd50fbc6
Homelab:plane/HOMELAB-2479-openbao-raft-verify
Homelab:plane/HOMELAB-2682-forgejo-ext-pin-96437d4a
Homelab:plane/HOMELAB-2479-moore-disk-alert
Homelab:plane/HOMELAB-2479-harbor-pin-secrets
Homelab:plane/HOMELAB-2682-relief-threshold-p1
Homelab:archive/plane/HOMELAB-2682-relief-threshold-20261109
Homelab:plane/HOMELAB-2682-relief-threshold
Homelab:plane/HOMELAB-2682-sbx-gits-seed-pin
Homelab:plane/HOMELAB-2479-ci-trim
Homelab:plane/HOMELAB-2682-ok0
Homelab:plane/HOMELAB-2479-liveness-window-120s
Homelab:plane/HOMELAB-2682-seed-bump
Homelab:plane/HOMELAB-2682-transcripts
Homelab:plane/HOMELAB-2682-pin-bump
Homelab:plane/HOMELAB-2682-declaration
Homelab:plane/HOMELAB-2682-gradle-daemon-gen
Homelab:plane/HOMELAB-2682-tools-pin
Homelab:plane/HOMELAB-2479-harbor-db-backup
Homelab:plane/HOMELAB-2682-suite-relpath
Homelab:plane/HOMELAB-2682-revert-859-delivery
Homelab:plane/HOMELAB-2479-volume-floor
Homelab:plane/HOMELAB-2682-check-anchor
Homelab:dev/cockpit
Homelab:plane/HOMELAB-2479-nic-roster
Homelab:plane/HOMELAB-2479-nic-roster-rehome
Homelab:ld-1/truth-fixes
Homelab:ld-1/remove-open-chat
Homelab:ld-1/gate-cut
Homelab:plane/HOMELAB-2479-nic-critical
Homelab:plane/HOMELAB-2479-startup-probe
Homelab:ld-1/dev-route-1
Homelab:plane/HOMELAB-2479-factory-token
Homelab:plane/HOMELAB-2682-evidence-fixes
Homelab:ld-1/gate-dev-route
Homelab:plane/HOMELAB-2479-sbx-resources
Homelab:plane/HOMELAB-2479-factory-pr-series
Homelab:plane/HOMELAB-2682-preclean-optout
Homelab:plane/HOMELAB-2479-measurement
Homelab:plane/sbx-gits-resources-20261105
Homelab:plane/sbx-lab-resources-20261105
Homelab:plane/HOMELAB-2682-emu-proof
Homelab:plane/HOMELAB-2682-sbxgits-pin
Homelab:plane/HOMELAB-2682-ssh-image
Homelab:archive/plane/HOMELAB-2694-sandbox-mem-page-20261110
Homelab:plane/HOMELAB-2694-sandbox-mem-page
Homelab:plane/HOMELAB-2537-jvm-proof-mode
Homelab:plane/HOMELAB-2694-sbx-lab-memory
Homelab:plane/HOMELAB-2694-psi-memory-alert
Homelab:plane/HOMELAB-2682-lab-env
Homelab:plane/HOMELAB-2694-sandbox-oom-alerts
Homelab:plane/HOMELAB-2682-quote-rule
Homelab:plane/HOMELAB-2481-sandbox-log-reader
Homelab:plane/HOMELAB-2682-sbx-lab-ext
Homelab:plane/HOMELAB-2688-longhorn-alerts
Homelab:plane/HOMELAB-2682-sbx-lab-idents
Homelab:plane/HOMELAB-2682-ct-skills
Homelab:plane/GITS-492-tablet-build-delivery
Homelab:epic/ld-1
Homelab:plane/HOMELAB-2680-sandbox-redact
Homelab:plane/HOMELAB-2683-sbx-lab-pin
Homelab:plane/HOMELAB-2685-outage-alerts
Homelab:plane/HOMELAB-2683-gcc-sbx-lab
Homelab:plane/HOMELAB-2658-omniroute-containment
Homelab:plane/HOMELAB-2440-sbx-lab-cpu
Homelab:plane/HOMELAB-2673-ci-pending-paging
Homelab:plane/HOMELAB-2675-sbx-gits-alerts
Homelab:plane/HOMELAB-2440-sbx-lab-request
Homelab:plane/HOMELAB-2445-sbx-lab-offpve
Homelab:plane/HOMELAB-2445-wk06-requests
Homelab:plane/HOMELAB-2658-liveness
Homelab:plane/HOMELAB-2655-sbx-sendrast-pin-54c78dd
Homelab:plane/HOMELAB-2655-sbx-sendrast-t7
Homelab:plane/HOMELAB-2626-h9-voz-sandbox
Homelab:plane/HOMELAB-2636-android-emu-b
Homelab:plane/GITS-401-drain-envelope
Homelab:plane/HOMELAB-2492-volume-attach-alerts
Homelab:plane/HOMELAB-2626-h8e-skill-hipervisor
Homelab:plane/HOMELAB-2488-io-psi-alerts
Homelab:plane/HOMELAB-2626-h8d-skills-pi
Homelab:plane/HOMELAB-2626-h8c-skills-pi-pulido
Homelab:plane/HOMELAB-2626-h8b-skills-pi-fixes
Homelab:plane/HOMELAB-2489-longhorn-tgtd-alerts
Homelab:plane/HOMELAB-2626-h8-skills-pi
Homelab:plane/HOMELAB-2618-h3-checklist
Homelab:plane/HOMELAB-2547-sbx-sendrast-pin7
Homelab:plane/HOMELAB-2618-h7-sbx-sendrast-kubectl
Homelab:plane/HOMELAB-2618-h6-sbx-lab-viewer
Homelab:plane/HOMELAB-2547-sbx-sendrast-pin6
Homelab:plane/HOMELAB-2614-etcd-leader-alert
Homelab:plane/HOMELAB-2547-sbx-sendrast-r59
Homelab:plane/HOMELAB-2618-h4-ci-reader
Homelab:plane/HOMELAB-2618-h2v3-sbx-sendrast
Homelab:plane/HOMELAB-2546-sbx-sendrast-pin5
Homelab:plane/HOMELAB-2547-sbx-sendrast-pidir
Homelab:plane/HOMELAB-2547-sbx-sendrast-pooldir
Homelab:plane/HOMELAB-2618-h5c-bump
Homelab:plane/HOMELAB-2547-sbx-sendrast-credhelper
Homelab:plane/HOMELAB-2618-h1fix-kustomize
Homelab:plane/HOMELAB-2618-h5-sbx-fleet
Homelab:plane/HOMELAB-2618-h1-fuente-unica
Homelab:plane/HOMELAB-2618-h2-sendrast
Homelab:plane/HOMELAB-2547-sbx-sendrast-rbac
Homelab:plane/HOMELAB-2618-h0-ondelete
Homelab:plane/HOMELAB-2446-wk01-requests
Homelab:plane/HOMELAB-2570-idle-liveness
Homelab:plane/HOMELAB-2511-step-alert
Homelab:plane/HOMELAB-2546-sbx-sendrast-pin4
Homelab:plane/HOMELAB-2546-sbx-sendrast-health2
Homelab:plane/HOMELAB-2546-sbx-sendrast-pin3
Homelab:plane/HOMELAB-2546-sbx-sendrast-health
Homelab:plane/HOMELAB-2546-sbx-sendrast-gotoolchain
Homelab:plane/HOMELAB-2546-sbx-sendrast-pin2
Homelab:plane/HOMELAB-2546-sbx-sendrast-r43
Homelab:plane/HOMELAB-2445-descheduler-repause
Homelab:plane/HOMELAB-2546-sbx-sendrast-psa
Homelab:plane/HOMELAB-2537-sbx-gits-post-humo
Homelab:plane/HOMELAB-2546-sbx-sendrast-wk03
Homelab:plane/HOMELAB-2537-sbx-gits-fix-perm
Homelab:plane/HOMELAB-2546-sbx-sendrast-pin
Homelab:plane/HOMELAB-2546-sbx-sendrast-platform
Homelab:plane/HOMELAB-2546-sbx-sendrast
Homelab:plane/HOMELAB-2537-sbx-gits
Homelab:plane/HOMELAB-2481-dind-gc-tightening
Homelab:archive/plane/HOMELAB-2481-node-local-dind-20261110
Homelab:plane/HOMELAB-2481-node-local-dind
Homelab:plane/HOMELAB-2535-sbx-lab-gitops
Homelab:plane/HOMELAB-2483-volume-usage-alert
Homelab:plane/HOMELAB-2482-slice-B-prepare
Homelab:plane/HOMELAB-2482-slice-C-ephemeral-ceilings
Homelab:plane/HOMELAB-2483-retention
Homelab:plane/HOMELAB-2483-alerts
Homelab:plane/GITS-395-emulator-adb-v2
Homelab:plane/GITS-395-emulator-adb
Homelab:plane/HOMELAB-2472-dor-newtest
Homelab:plane/GITS-403-emu-env-drift
Homelab:plane/HOMELAB-2467-gitleaks-scan
Homelab:plane/GITS-401-dind-digest
Homelab:plane/GITS-371-android-emu-prestop-command
Homelab:plane/GITS-371-android-emu-dind-drain
Homelab:plane/GITS-371-android-emu-shutdown-grace
Homelab:plane/HOMELAB-2196-speed-batch
Homelab:plane/HOMELAB-2442-android-ci-raise
Homelab:plane/HOMELAB-2442-runner-pool
Homelab:plane/HOMELAB-2442-mem-rightsize
Homelab:plane/HOMELAB-2443-ldpush-memory
Homelab:plane/HOMELAB-2444-fpr
Homelab:plane/GITS-364-emu-drift-fix
Homelab:plane/GITS-362-release-upload-mount
Homelab:plane/HOMELAB-2432-alerts
Homelab:plane/HOMELAB-1945-landing-step
Homelab:plane/HOMELAB-2421-dashboard
Homelab:plane/HOMELAB-2417-baseline
Homelab:plane/HOMELAB-2418-runners
Homelab:plane/HOMELAB-2415-budget-kill-scope
Homelab:plane/GITS-33-e0r-t3-android-release-lane
Homelab:plane/HOMELAB-2412-pernode-cap
Homelab:plane/GITS-281-android-ci-pin
Homelab:plane/HOMELAB-2407-gate-creation-exempt
Homelab:plane/GITS-281-android-ci-image-emulator
Homelab:plane/HOMELAB-2406-panel-artifact
Homelab:plane/GITS-22-e0-t13
Homelab:plane/HOMELAB-2402-node-keys
Homelab:plane/GITS-21-e0-t12
Homelab:plane/GITS-19-e0-t10
Homelab:plane/GITS-18-e0-t9
Homelab:plane/HOMELAB-1941-b13-slice2
Homelab:plane/HOMELAB-2400-active-rows
Homelab:plane/HOMELAB-2395-trim-manage-key
Homelab:plane/HOMELAB-1944-panel-gateway
Homelab:plane/HOMELAB-2392-diff-fetch
Homelab:plane/HOMELAB-1940-caps-accounting
Homelab:plane/HOMELAB-2390-diff-git
Homelab:plane/HOMELAB-1944-panel-runtime
Homelab:plane/HOMELAB-2329-gate-decision
Homelab:plane/HOMELAB-2381-claim-retry
Homelab:plane/record-sql-test-fix
Homelab:plane/HOMELAB-2373-tailscale-1.104.4
Homelab:plane/HOMELAB-2357-resume-inflight
Homelab:plane/HOMELAB-2372-fail-closed
Homelab:plane/HOMELAB-2278-freshness
Homelab:plane/HOMELAB-2356-runtime-verdicts
Homelab:plane/HOMELAB-2281-objectlock
Homelab:plane/HOMELAB-2340-pane-loss
Homelab:plane/HOMELAB-1943-frozen-charters
Homelab:plane/HOMELAB-2348-replay-refusal
Homelab:plane/HOMELAB-1944-review-panel
Homelab:plane/HOMELAB-2341-reauthorize-anchor
Homelab:plane/HOMELAB-1942-workflow-knobs
Homelab:plane/HOMELAB-2327-signing-dispatch
Homelab:plane/HOMELAB-2280-pacing
Homelab:plane/HOMELAB-2195-f9-dor
Homelab:plane/HOMELAB-2249-orphan-alert
Homelab:plane/HOMELAB-2311-runbook
Homelab:plane/HOMELAB-2302-argocd-reader
Homelab:plane/HOMELAB-2273-etcd-snapshot-b2
Homelab:plane/HOMELAB-2298-eso-repo-password
Homelab:plane/HOMELAB-2274-raft-b2
Homelab:plane/HOMELAB-2249-alerts
Homelab:plane/HOMELAB-2258-xhost-sc
Homelab:plane/HOMELAB-2259-strict-local
Homelab:plane/HOMELAB-2195-f4-workflow-id
Homelab:plane/HOMELAB-2260-node-labels
Homelab:plane/HOMELAB-2257-zone-labels
Homelab:plane/HOMELAB-2195-b2-drain-rule
Homelab:plane/HOMELAB-2195-b3-records
Homelab:plane/HOMELAB-2195-b5-fragility
Homelab:plane/HOMELAB-2195-b1-dor-pickup
Homelab:plane/HOMELAB-1939-bumpupdate
Homelab:plane/HOMELAB-1939-mergedecode
Homelab:plane/HOMELAB-1939-agentwait
Homelab:plane/HOMELAB-2240-lane
Homelab:plane/HOMELAB-2246-runner-1rep
Homelab:plane/HOMELAB-1980-b11-pane-hold
Homelab:plane/HOMELAB-2235-argocd-memory
Homelab:plane/HOMELAB-2232-proxmox-module
Homelab:plane/HOMELAB-gitops-atlantis
Homelab:plane/HOMELAB-2210-docker-config-seed2
Homelab:plane/HOMELAB-2210-runner-pin
Homelab:plane/HOMELAB-2210-runner-buildx
Homelab:plane/HOMELAB-1932-ld-runners
Homelab:plane/HOMELAB-2200-snapshot-retain
Homelab:plane/HOMELAB-2199-cnpg-backup-stale
Homelab:plane/HOMELAB-2201-runner-gc
Homelab:plane/HOMELAB-1926-plane-rabbitmq-resources
Homelab:plane/HOMELAB-1905-cnpg-ha-docs
Homelab:plane/HOMELAB-1906-cronjob-ttl-rules
Homelab:plane/HOMELAB-1904-longhorn-fixes
Homelab:plane/HOMELAB-1908-annotation-fix
Homelab:plane/HOMELAB-1904-cnpg-ha-rules
Homelab:plane/HOMELAB-1904-recyclarr-netpol
Homelab:plane/HOMELAB-1904-cpu-rightsize
Homelab:plane/HOMELAB-1893-alertintake-plane-storm
Homelab:plane/HOMELAB-1878-retention
Homelab:epic/LD4
Homelab:plane/HOMELAB-1885-cockpit-e2e
Homelab:plane/HOMELAB-1727-skillhealth
Homelab:plane/HOMELAB-1728-signals
Homelab:plane/HOMELAB-1731-fitness
Homelab:plane/HOMELAB-1859-gateway
Homelab:plane/HOMELAB-1847-oncall
Homelab:plane/HOMELAB-1690-l7
Homelab:plane/HOMELAB-1850-tempo
Homelab:plane/HOMELAB-1850-attribution
Homelab:plane/HOMELAB-1686-meetings
Homelab:epic/LD3
Homelab:plane/HOMELAB-1684-derived-state
Homelab:plane/HOMELAB-1871-oidc-entrypoint-fix
Homelab:plane/HOMELAB-1871-oidc-sync
Homelab:plane/HOMELAB-1865-atlantis-leg
Homelab:plane/HOMELAB-1730-readiness
Homelab:plane/HOMELAB-1681b-image-dispatch
Homelab:plane/HOMELAB-1682-gates-backend
Homelab:plane/HOMELAB-1848-alert-audit
Homelab:plane/HOMELAB-1729-planfresh
Homelab:plane/HOMELAB-1848-contract-demo
Homelab:plane/HOMELAB-1854-longhorn-guard
Homelab:plane/HOMELAB-1685-intake
Homelab:plane/HOMELAB-1688-routines
Homelab:plane/HOMELAB-1687-el-director
Homelab:plane/HOMELAB-1827-prepull
Homelab:plane/HOMELAB-1827-livez
Homelab:plane/HOMELAB-1835-alert-rule
Homelab:plane/HOMELAB-1831-plane-vendor
Homelab:plane/HOMELAB-1746-es-newt-next
Homelab:plane/HOMELAB-1841-kubeprism
Homelab:plane/HOMELAB-1825-sandbox-pullsecrets
Homelab:plane/HOMELAB-1828-outline-minio
Homelab:plane/HOMELAB-1828-cnpg-alert
Homelab:plane/HOMELAB-1711-compile-before-claim
Homelab:plane/HOMELAB-1711-image-smoke
Homelab:epic/ld2
Homelab:plane/HOMELAB-1711-dispatcher-deploy
Homelab:plane/HOMELAB-1711-sweep-heart
Homelab:plane/HOMELAB-1824-omni-liveness
Homelab:plane/HOMELAB-1746-idp-redirect
Homelab:plane/HOMELAB-1711-sweep-control
Homelab:plane/HOMELAB-1711-raceprobe
Homelab:plane/HOMELAB-1711-dispatcher-image
Homelab:plane/HOMELAB-1720-identity
Homelab:plane/HOMELAB-1678-bashguard-fix
Homelab:plane/HOMELAB-1746-pangolin-oidc
Homelab:plane/HOMELAB-1680-custodian
Homelab:plane/HOMELAB-1678-scheduler
Homelab:plane/HOMELAB-1676-sentinel
Homelab:plane/HOMELAB-1677-rcbridge
Homelab:plane/HOMELAB-1796-teardown
Homelab:plane/HOMELAB-1794-spawn
Homelab:plane/HOMELAB-1797-claims
Homelab:plane/HOMELAB-1808-1809-fixes
Homelab:plane/HOMELAB-1791-sandbox-init
Homelab:plane/HOMELAB-1795-watch
Homelab:plane/HOMELAB-1798-compiler
Homelab:plane/HOMELAB-1674-claude-image
Homelab:plane/HOMELAB-1672-job-contract
Homelab:plane/HOMELAB-1698-meet-ai-namespace
Homelab:plane/HOMELAB-1635-cp01-pins
Homelab:plane/HOMELAB-1585-argocd-repo-creds
Homelab:plane/HOMELAB-1766-gateway-alerts
Homelab:epic/LD1
Homelab:plane/HOMELAB-1735-env-fix
Homelab:plane/HOMELAB-1735-harbor-robot
Homelab:plane/HOMELAB-1666-agent-sandbox
Homelab:plane/HOMELAB-1665-pi-image
Homelab:archive/epic/LD0-20261109
Homelab:plane/HOMELAB-1634-dind-harbor-auth
Homelab:plane/HOMELAB-1634-runner-cleanup
Homelab:plane/HOMELAB-1634-review-followups
Homelab:homelab/HOMELAB-1630-runner-resources
Homelab:plane/HOMELAB-1621-cpu-barchart
Homelab:plane/HOMELAB-1619-mgmt-vm-dashboard
Homelab:plane/HOMELAB-1598-oidc
Homelab:plane/HOMELAB-1574-plane-image-bump
Homelab:plane/HOMELAB-1535-outline-prestop
Homelab:plane/HOMELAB-1535-outline-ha
Homelab:plane/HOMELAB-1534-reviewer-fetch-auth
Homelab:plane/HOMELAB-1518-longhorn-rule-fix
Homelab:plane/HOMELAB-1527-tempo-pipeline
Homelab:plane/HOMELAB-1526-mqttx-web
Homelab:plane/HOMELAB-1511-prowlarr-qbit
No reviewers
Labels
No labels
operator-review
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
Homelab/infra-core!943
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/IR-20261111-baohelper"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
IR-20261111-baohelper — the helper writes the token to a 0600 file and never prints it
Branch
plane/IR-20261111-baohelper->live. One commit (b69148ce), lasttrailer
Lab-Run: IR-20261111-baohelper.Why
/usr/local/bin/bao-operator-tokenis hand-installed on the mgmt host (mode755, root:root, dated 2026-10-14) and no repo has ever managed it —
infra-corelivehas zero hits for the helper or its role. Its old contract was: print anOpenBao token on stdout, so every caller captured it with
$(...)/.stdout.strip(). A token on stdout is a token in a log, a transcript,a
set -xtrace or a process boundary; the IR-20261111 leak came from exactlythat shape.
This PR puts the helper under management and removes the stdout sink:
core/ansible/roles/mgmt-tools/files/bao-operator-token(git mode100755) — the managed replacement.
core/ansible/roles/mgmt-tools/tasks/main.yml— a final taskInstall bao-operator-token helper(copy,root:root,0755).The role task is not applied by this PR. Installing on the host is a separate,
deliberate step.
Contract implemented
-,/dev/stdout,/dev/fd/1|2,/dev/stderr,/dev/tty,/dev/console,/proc/*/fd/1|2, and a tty on stdout are all refused before anything isminted.
O_CREAT|O_EXCLat mode0600, so the file is 0600from birth and an existing path — regular file, symlink including a dangling
one, directory, device — is refused.
never appears on this program's stdout.
written <path> ttl <n>(ttlfromauth.lease_duration).openbao-operator,key
~/.config/openbao-operator-key.json) ->jwt-bearerexchange ->OpenBao
sa-operatorOIDC login.finish. A refused run never touches the caller's path (an earlier draft did;
that was a real bug found while testing this branch and fixed in it).
Test evidence
Success path — PROVEN (on the branch head, 2026-11-11T18:1xZ)
The pause note recorded this path as blocked (Zitadel
jwt-bearerreturnedHTTP 500 Errors.Internaltwice at ~16:44Z/~16:48Z). Re-tested on resume:mktemp -ddirectory, mode0700; helper exited 0 in ~1s, stderrempty;
written <tmpdir>/tok ttl 3600— path matches the argument,ttl
3600; re-checked with a strict full-match regex;OpenBao
client_token+ one trailing newline. Prefixs.Sp…(first fourcharacters only; the value was never printed) and the token string does not
occur in stdout;
shred -u) and the path is gone;lookup-self(this run permits no OpenBao read route). The helper's ownsuccess criterion is a non-empty
client_tokeninside a 200 OIDC loginresponse, which it now gets — it exits non-zero on an empty token, and it did
not.
Refusals — PROVEN
Re-run on resume as a smoke check: a pre-existing
0640file with content ->non-zero exit, stderr
refusing: output path already exists (no overwrite, symlinks included), the file's mode and content intact, zero bytes onstdout.
Carried forward from the original test round, each non-zero exit with the
filesystem untouched: no-arg,
-,/dev/stdout,/dev/fd/1, tty-on-stdout,pre-existing file, symlink to
/dev/stdout, dangling symlink, directory, twoarguments, missing parent directory. Mint-path failure cleanup: with
BAO_ADDR=https://127.0.0.1:1the claimed file is created and then removed andnothing is printed.
bash -nandshellcheck -S warningare clean on the helper.Callers
The two repo-managed callers are in
Homelab/prod, so they cannot land inthis PR; they come in the paired PR from branch
plane/IR-20261111-baohelper-callers:scripts/maintenance/window-run.sh(pve_load_creds) — passes an output fileinside the existing 0700
$PVE_TMP, reads it back, shreds it before thebao kv get;values/forgejo/artifact-retention-evidence.md— doc prose, new invocationform.
Roughly 80 further references live under
working-files/, which is not a gitrepository: the executable ones are probe/rotation scripts and reports. They are
not migrated here and will break on stdout capture once the host helper is
replaced — that inventory is recorded on the run's ticketing and is follow-up
work, not a claim of this PR.
Rollout / risk
live behaviour until the role task is applied (or the file copied by hand).
prodcaller PR must land afterthe new helper is on the host, or
pve_load_credsfails closed (no PVEcredentials, phase blocked). It cannot leak: it never echoes the helper's
stdout, only its byte count.
logic in this branch is unchanged from the hand-installed original, so the old
and new helper are interchangeable apart from the output sink.
Review
Two independent census seats are requested on this head (see the run's seat
briefs). No merge is performed by the worker that opened this PR.
Fix round (review-93 / homelab-93 seat) — head
714522c9The independent seat review (working-files/security-hypervisor/pr943/review-93.md)
raised one blocking finding and three should/minor fixes. All six items are
addressed on this head, as two new commits on top of
b69148ce:9318f68: any argument startingwith
-(--help,-h, anything) is refused before any mint, usage tostderr, rc 2. Also required: absolute path; parent dir must exist, be owned
by the caller's uid, and be mode 0700 (the swap window from S2).
reach curl inside 0600 temp files via
-d @file; revoke-self runs in-processover urllib. No token material ever appears in any process argv.
in ONE python process; any failure after the mint (unparseable ttl, write
error, closed stdout, SIGTERM/SIGHUP/SIGINT) revokes the token (revoke-self
with the minted token) and removes the file before a non-zero exit.
was O_EXCL-created; no path re-open between claim and write.
bao-helper(install with
--tags bao-helper; the whole role no longer has to run first);any existing host copy is backed up to
/usr/local/bin/bao-operator-token.pre-943before replacement.
roles/mgmt-tools/README.mddocuments the one-filesha256-checked manual install as the runbook alternative, plus a post-install
proof.
(
roles/mgmt-tools/tests/test-bao-operator-token.sh) — a stubcurlfirst inPATH records every argv; PATH excludes the host copy entirely (plus a
tripwire stub); a 127.0.0.1 recorder stands in for the vault address on the
revoke path. 39/39 checks pass: every refusal path (zero mint attempts),
argv-freedom (recorded stub argv proven free of assertion/id_token/token),
-d @fileusage, revoke-self ordering with the minted token + file removal,a live symlink-swap attack leaving the victim untouched (same-fd proof),
O_EXCL structural assertions,
bash -nandshellcheckclean. No real mintwas executed in any test.
Old-form callers (~20 out-of-repo scripts/docs) are inventoried at
working-files/security-hypervisor/orch/old-form-callers.mdfor follow-up; thecritical landing routes never called this helper (review-93 §4a) and are
unaffected.
Fix round 2 — head
27b52f38(review-93 N1–N6)Second reviewer pass on
714522c9found six items; all are addressed in newcommit
27b52f38(trailerLab-Run: IR-20261111-baohelper):token-on-stdout helper runnable: it goes to
/root/bao-operator-token.pre-943(root:root, 0400, outside PATH) via
stat+when, so a fresh VM skipsit cleanly; the README manual route uses
install -m 0400(nocp -a).on_signalnowrmtrees the temp dir (key.pem copy of the operatorkey, zform assertion, login.json id_token) before
os._exit; no morecopies piling up in
/tmpafter SIGINT/SIGTERM/SIGHUP.sys.stdout.flush()inside thetry: a caller-closed stdout nowraises at flush, so the failure is caught in-run (rc 1, token revoked, file
removed) instead of surfacing as rc 120 at interpreter exit with a live
token left in the file; stdout is dup2'd to /dev/null first so shutdown
re-flush cannot overwrite the honest rc. A catch-all after the mint revokes
and unlinks on any non-
fail()failure (e.g. ENOSPC on the fd write).claimedflag: the output file is only removed if this runcreated it.
file's sha256 against
git show <merge-sha>:core/ansible/roles/mgmt-tools/ files/bao-operator-token | sha256sum(merged-blob provenance, not transferintegrity).
BAO_ADDR=http://127.0.0.1:9for the wholesuite; new SIGTERM-cleanup and closed-stdout-revoke tests (fake curl
hangmode, fake clock not needed); fake-binary matrix extended.Verification:
bash -n+shellcheckclean; hermetic offline run(
unshare -rn, stub curl, dead 127.0.0.1 BAO_ADDR, /usr/local/bin excluded,real helper never executed): pass=50 fail=0.
Fix round 3 — head
c251af61(review-3c S1/S2/n1/n2/n4/n6)Third reviewer pass (seat 3c, round 3) on
27b52f38had no blocking hole; itstwo should-fixes and four nits are addressed in new commit
c251af61(trailer
Lab-Run: IR-20261111-baohelper), citingreview-3c-r3.md:fail(),on_signal()and the post-mint catch-all: the claimed output file isunlinked and the temp dir (key.pem copy, zform assertion, login.json
id_token) rmtree'd first; only then the blocking revoke-self (urlopen,
15 s timeout). A TERM→KILL grace window shorter than the revoke wait can no
longer leave the token file or key material on disk.
sha256 check of
/usr/local/bin/bao-operator-tokenagainstgit show <merge-sha>:core/ansible/roles/mgmt-tools/files/bao-operator-token | sha256sum, stopping on mismatch BEFORE any invocation (--helpincluded) — the host may still run the old token-on-stdout helper, and any
invocation of a not-actually-installed file would leak a live token.
revoked=Trueis set only after a successful revoke-self; onfailure the helper prints exactly one stderr line
warning: revoke-self failed; token expires at its ttl(guarded againstdouble-print from the catch-all re-entry).
state["claimed"](and the tokenreference), so a signal landing in the finally/shutdown window keeps the
caller's delivered file and revokes nothing; token ownership passed to the
caller at delivery.
sudo install(0400 would fail closed but non-executable); the manualroute's backup-exists check uses
sudo test -f(/root is 0700, so the oldunprivileged check always read "absent" and a second runbook pass could
overwrite the backup).
on the first
bao-op-*unlink/rmdir keeps the helper in the post-deliveryfinallywindow; asserts the caller's file survives, temp dir rmtree'd, norevoke attempted) and the catch-all with
client_tokenas an int (assertsrc 1, TypeError surfaced, file removed, revoke-self carried the minted
token).
Worktree hygiene: the untracked Syncthing draft
files/bao-operator-token.sync-conflict-20261111-144623-P5KCD5R(statted:0755, 12020 B, in no commit) was deleted, not committed (review-3c n5).
Verification:
bash -n+shellcheckclean; hermetic offline run(
unshare -rnm, stub curl,BAO_ADDR=http://127.0.0.1:9, /usr/local/binexcluded, real helper never executed): pass=58 fail=0.
APPROVE — ld-reviewer — head
b69148ce30VERDICT: APPROVED. Independent census read: fetched
refs/pull/943/headover the seat read route →b69148ce303523e34b8f6e924d71066e6e02f9d3, exact match to the pin (no HEAD-MISMATCH). Single commit, parent35a336157, last non-empty line of the message is exactlyLab-Run: IR-20261111-baohelper. CI on this sha: 13/13 contextssuccess, combined statesuccess(incl.Lint & Validate / shellcheckandyaml-lint). Scope: 2 files, +139/−0, new file mode 100755,tasks/main.ymlat 100644. I ranbash -n(parse only) and the helper was NOT executed — nothing minted by this seat.(a) Sink contract — PASS. Lines 48–58 run in this order: arg count == 1, non-empty,
-, then the case glob/dev/stdout|/dev/fd/1|/dev/fd/2|/dev/stderr|/dev/tty|/dev/console|/proc/*/fd/1|/proc/*/fd/2, then[ -t 1 ]— all before any network call or key read, so no reachable path mints before sink validation. The claim (lines 64–81) is the real backstop:islink(path) or exists(path)refuses, thenos.open(O_WRONLY|O_CREAT|O_EXCL, 0o600). A symlink (dangling or not), directory and device all tripexists/islinkorFileExistsError;-t 1refuses the tty-on-stdout case; missing parent falls into the caughtOSError(non-zero, nothing created).OUT_CLAIMEDis set only after the claim returns 0, so a refusal cannot arm cleanup.(b) Token to stdout — PASS for the stated contract. Whole chain walked: JWT build (py, writes only
$TMPD/inand$TMPD/key.pem),openssl dgst -signwith-out(no stdout),IDTcaptured from the jwt-bearer response via$( ), and the login response pipedcurl -> python -> filewith no intermediate shell var. Only stdout-producing statements are thewritten %s ttl %dline (123) and$( )-internal prints;dieand the$KEY not foundmessage go to>&2. Underset -euo pipefail: openssl failure exits, jwt-bearer failure empties python's stdin (traceback on stderr, pipefail exits), and a mid-write orprintfailure leavesOUT_WRITTEN=0so cleanup deletes the token file — fail-closed throughout.(c) Only output — PASS:
print("written %s ttl %d" % (path, ttl))withttl = int(auth.get("lease_duration") or 0)(122–123), no other stdout on the success path.(d) Cleanup safety — PASS:
TMPDis only ever amktemp -dvalue and is-n-guarded beforerm -rf -- "$TMPD"(35), so it cannot escape its own dir; the removal (38) requiresOUT_CLAIMED -eq 1ANDOUT_WRITTEN -ne 1, so a refused run leaves a pre-existing path untouched (traced: everydieprecedesOUT_CLAIMED=1) and a completed run leaves the caller's file in place.trap - EXIT INT TERM HUP PIPEbefore re-exitprevents recursion; INT/TERM/HUP/PIPE map to 130/143 and still land in cleanup.(e) Mint logic — UNCHANGED as described:
$HOME/.config/openbao-operator-key.json→ RS256 machine-jwt →POST /oauth/v2/tokengrant_type=…jwt-bearer→POST ${BAO_ADDR:-https://openbao.aaron.reynoza.org}/v1/auth/oidc/loginwithrole: sa-operator. No change to auth flow, role, audience or key path.(f) Ansible task — PASS:
src: bao-operator-tokenresolves to the role'sfiles/dir (that tree already existed),dest: /usr/local/bin/bao-operator-tokenmatches the hand-installed path,owner/group: root,mode: "0755"quoted, copy is checksum-idempotent, appended as the last of the now-24 tasks with nowhen/command, so it cannot mint at playbook time and depends on nothing the earlier tasks must provide. Honestly NOT applied: no workflow, ArgoCD app or scheduled job runs it —mgmt-toolsis included only bycore/ansible/playbooks/setup-mgmt-vm.yml, which is invoked from a manual runbook.(g) Test evidence vs what the code allows — consistent, no overstatement.
written <path> ttl 3600is exactly what 123 emits fromlease_duration; 27 bytes = token +"\n"(119); 0600 from birth holds because theopenmode is masked by umask but line 79 (and 118) chmod it back up to exactly 0600; the carried-forward refusal matrix maps 1:1 onto thecase/-t 1/claim branches; the0640pre-existing-file case is exactly theislink or existsrefusal withOUT_CLAIMED=0; theBAO_ADDR=127.0.0.1:1cleanup case is theOUT_CLAIMED=1, OUT_WRITTEN=0branch. The "usability not proven by lookup-self" caveat is present and correctly scoped.bash -nclean (re-verified) and shellcheck green in CI.Blast radius / callers — honest, no false claim. Nothing is installed by this merge, and the body explicitly does NOT claim all callers are migrated: it names the ~80
working-files/references as un-migrated follow-up that will break on stdout capture. I confirmed this repo has zero references to the helper outside the two added files, so "callers live in Homelab/prod" checks out. Ordering (prod caller PR after the helper is on the host) is stated, not glossed.FLAGS — non-blocking, for follow-up (none of these change this verdict):
IDT(99–101) and the signed JWT assertionASSERTION(98) do enter shell variables and, worse, curl argv via-d "assertion=$ASSERTION"(101) and-d "…\"jwt\":\"$IDT\""(105) — visible in/proc/<pid>/cmdlineandpsfor the life of those two POSTs, on the host where this mints a kv-wide token. The id_token is exchangeable 1:1 for that token, so it is credential-equivalent, and the commit message itself condemns "a process boundary". The body's "The token … never enters a shell variable" is accurate for theclient_tokenonly. Not blocking here because this is the unchanged original mint chain (leg e puts auth-flow changes out of scope) and the incident vector was stdout capture; the fix is transport-level only — feed curl from stdin (--data @-) and the exposure disappears. Worth a ticket on HOMELAB-1893.pathby name withO_WRONLY|O_TRUNCand noO_NOFOLLOW, after the claim closed its fd at 78. Harmless in the documentedmktemp -d0700 dir, but in a dir writable by another user the claimed file can be swapped for a symlink or FIFO and the token lands on an attacker-selected target (thefchmodbounds mode, not the target). Cleanest fix: keep the claim fd and hand it to the writer (os.fdopen(int(sys.argv[2]), "w")).export BAO_TOKEN="$(cat …)", which keeps the token in the caller's environment for the process lifetime (children,envdumps, core files). A one-line caveat preferring a short-lived read would be more honest about the residual exposure.Operational note (disclosed, not a defect): because the copy task now sits in
mgmt-tools, the next manualsetup-mgmt-vm.ymlrun swaps the host helper — at that instant the ~80 un-migrated callers fail closed. The body says exactly this and it matches the role's inclusion graph; just sequence the caller migration before the next mgmt-vm playbook run.model: omniroute/deepseek-flash
session: IR-20261111-baohelper-seatB-20261111T1820Z
APPROVE — ld-reviewer — head
b69148ce30APPROVED (legs a–g pass; four non-blocking follow-ups).
Preflight — head is
b69148ce30, one commit, last trailer exactlyLab-Run: IR-20261111-baohelper. Combined commit status on this exact sha: success, 13 contexts (Lint & Validate / shellcheck, yaml-lint, terraform-validate, CI Review suite). New blobbao-operator-tokenis git mode 100755, 5385 B, 125 lines — two files only. Review was read-only: I parsed the fetched blob (bash -nrc 0, grep) and never ran the helper or minted anything.(a) Sink contract — PASS.
[ "$#" -eq 1 ]rejects 0 and 2+;-, /dev/stdout, /dev/fd/1, /dev/fd/2, /dev/stderr, /dev/tty, /dev/console, /proc/*/fd/1|2 are refused, plus[ -t 1 ]. The claim step runs before the key read,mktempand any network call: pythonislink/existspre-check, thenos.open(path, O_WRONLY|O_CREAT|O_EXCL, 0o600)+chmod 0600.islinkcatches a dangling symlink;existscatches regular file, directory, device (and every stdout/tty alias, so an EXISTS refusal is a genuine backstop even for an alias the case list missed);O_EXCLcovers a path created between the pre-check and the open. There is no mint-then-validate ordering anywhere, so "minted before sink validation" is unreachable. Refusals are non-zero (die=2, python=1).(b) Token never on stdout — PASS. Walked the whole chain: JWT built in a quoted heredoc python (writes
$TMPD/in,$TMPD/key.pem0600 — no prints);openssl dgst -sha256 -sign -out "$TMPD/sig"(nothing on stdout); assertion/id_token captured by$(...); login response piped curl → python → file, and the writer prints only thewritten …line. Noset -x/-v, notee, no echo of any token;dieand all error paths go to stderr; a python traceback (e.g. fsync failure) prints source lines, never values;fsyncprecedes the print andOUT_WRITTEN=1follows the pipeline, so a failure after the write deletes the claimed file and exits non-zero; withpipefaila curl failure aborts before anything is printed.(c) Only output — PASS. Exactly one
print("written %s ttl %d" % (path, ttl)),ttl = int(auth.get("lease_duration") or 0).(d) Cleanup does not damage the caller — PASS. EXIT trap clears the traps, preserves and re-exits
$?;rm -rf -- "$TMPD"is guarded on non-empty (a failedmktemp -dcan never expand to/); the output file is removed only whenOUT_CLAIMED=1 && OUT_WRITTEN != 1 && -f "$OUT". A refused run leavesOUT_CLAIMED=0, so a pre-existing path is untouched — andmktemp/key failures happen after the claim but before a write, which correctly removes the empty claimed file.(e) Mint logic — PASS against the description: self-signed RS256 machine-user JWT (iss/sub = userId, aud Zitadel, exp +600) from
~/.config/openbao-operator-key.json→jwt-bearergrant →/v1/auth/oidc/loginrolesa-operator. No auth-flow, role, audience or key-path change in the diff. Caveat recorded: the hand-installed original is not in the repo, so "unchanged" is verified against the PR's description, not against a literal old file.(f) Ansible task — PASS.
copy src: bao-operator-token(the file this same commit adds, so the role cannot run ahead of its source) →/usr/local/bin/bao-operator-token,owner/group root,mode: "0755"quoted; no shell, no handler, no mint at playbook time, idempotent. It is the final task, so prerequisites run first. "Not applied" is true:core/ansible/playbooks/setup-mgmt-vm.yml(hosts: mgmt) does includerole: mgmt-tools, but no.forgejo/workflows/*job runsansible-playbook/that playbook, so merging installs nothing.(g) Evidence vs what the code allows — PASS, no overstatement. Output shape/ttl, 27 B = 26-char
s.*token + newline, the refusal stderr string quoted in the body matches the code byte-for-byte, every entry of the carried-forward refusal matrix is reachable in the code (missing-parent = ENOENT on the claim open,OUT_CLAIMED=0, zero stdout), and theBAO_ADDR=https://127.0.0.1:1case matches the cleanup rule. The usability caveat is stated honestly. Callers: the body does not claim migration or zero breakage — it says the ~80working-files/references will break and are follow-up, and that the prod caller PR must land after the helper is on the host. Ordering is correct, blast-radius is accurate (no manifests, ArgoCD, systemd or timer).Non-blocking observations (follow-up, none block this head):
os.open(path, O_WRONLY|O_TRUNC)withoutO_NOFOLLOW, so a writer in the parent directory could swap the claimed file for a symlink between claim and write (TOCTOU). Callers use a 0700mktemp -d, so the exposure needs a hostile user in a shared parent; one flag (or keeping the claim fd) closes it.-d "assertion=$ASSERTION",-d '…"jwt":"'"$IDT"'"'), visible inpsfor those calls. That is the short-lived JWT, not the OpenBao client_token;--data-binary @-would remove it but would change mint plumbing, which this PR deliberately does not touch. The body's "the token … never enters a shell variable" is accurate as written about the client_token.Lint & Validate / shellcheckscans onlycore/scripts/*.shand chart scripts, so this extension-less role file is never shellchecked. The body'sbash -n/shellcheck -S warningclean is a manual self-report and consistent with the code (mybash -non the fetched blob: rc 0); adding the file to the lint set is a worthwhile follow-up.Blocker legs: none.
model: omniroute/deepseek-flash
session: IR-20261111-baohelper-seatA-20261111T1820Z
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.