agent (unreleased): root files older than the agent are not a trust problem on a pinned box (a false operator mail at every box's update)
gates / gates (push) Successful in 41s
gates / gates (push) Successful in 41s
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
1 parent
3ea208b8fb
commit
5ecdd3d521
3 files changed
+64
No files matched your search
@@ -1,3 +1,11 @@
|
||||
## Unreleased (after v0.175.0, 2026-11-15) — root files older than the agent are not a trust problem
|
||||
|
||||
- **`pvetrust.Ensure`: the wrapper's „unknown mode” refusal on a PINNED box names no problem.** Between the signed
|
||||
agent update and the signed root-files job, the box's wrapper does not know `pve-ca-copy`. 0.175.0 reported
|
||||
`ca_copy_unavailable` for those minutes and the hub mailed the operator (seen on Tester 1, 2026-11-15 10:04). The
|
||||
pin works, so nothing is wrong; the bundle install runs the move. An unpinned box, and every other refusal, still
|
||||
names the problem. Test `TestRootStepOlderThanTheAgent_IsNotATrustProblem`; 3 mutations seen red.
|
||||
|
||||
## v0.175.0 (2026-11-15) — trust in Proxmox by a copy of the box's own root CA (R-1380, release 2b); the agent tells the hub its clock, a refused job, a give-up and what a clean-up did (release 3); a boot key a clock step cannot move (R-1395) — RELEASED 2026-11-15 (release-agent.sh from the clean working clone at `db01ae0`, CI run id 2671; agent sha256 d1a30ed51f6663d96369ad3e88c221194af92773addf4fbb48852ee58be4b19a, bundle sha256 3b4a8b78155fc4385148c98c229da2e61e7c6b02bad9ed9f1fdc4a9ea1370d95); NOT vouched yet
|
||||
|
||||
`configs/` changed (the wrapper's `pve-ca-copy` mode), so a box needs BOTH signed jobs: `agent_update`, then
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -246,6 +247,15 @@ func (m *Manager) Ensure(ctx context.Context, why string) bool {
|
||||
c, err := m.EnsureCopy(cctx)
|
||||
ccancel()
|
||||
if err != nil {
|
||||
if rootStepTooOld(err) && cur.Fingerprint != "" {
|
||||
// The agent is newer than the box's root files: between the agent update and the root-files job the
|
||||
// wrapper does not know the step yet. The pinned certificate works; this is not a trust problem, and
|
||||
// naming one mailed the operator at every box's update (seen on Tester 1, 2026-11-15). The bundle
|
||||
// install calls Ensure again.
|
||||
lg.Info("pvetrust: the root files are older than this agent (no CA-copy step yet) — the pinned certificate stays; the next root-files update moves the box", "err", err)
|
||||
set(modeOf(cur), "", "", nil)
|
||||
return false
|
||||
}
|
||||
lg.Warn("pvetrust: the root step gave no CA copy — the trust stays as it is", "err", err)
|
||||
set(modeOf(cur), ProblemCopyUnavailable, truncate(err.Error(), 240), nil)
|
||||
return false
|
||||
@@ -404,3 +414,10 @@ func (m *Manager) writeConfig(caPath string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rootStepTooOld says whether the root step refused because it does not know the CA-copy mode at all (the wrapper's
|
||||
// R11 „unknown mode”): the box's root files are older than the agent. Pinned by
|
||||
// TestRootStepOlderThanTheAgent_IsNotATrustProblem.
|
||||
func rootStepTooOld(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "unknown mode")
|
||||
}
|
||||
@@ -487,3 +487,42 @@ func TestProofCannotBeMadeNow_NoCauseNamed(t *testing.T) {
|
||||
t.Fatalf("status = %+v moved=%v", st, b.m.Moved())
|
||||
}
|
||||
}
|
||||
|
||||
// Between the agent update and the root-files job the wrapper does not know the CA-copy step. A pinned box then has
|
||||
// NO trust problem (the pin works): naming one mails the operator at every box's update. A box with NO working pin
|
||||
// that gets the same refusal still names the problem.
|
||||
func TestRootStepOlderThanTheAgent_IsNotATrustProblem(t *testing.T) {
|
||||
p := newPKI(t, "PVE CA")
|
||||
leaf := p.leaf()
|
||||
srv := newPVE(t, leaf)
|
||||
old := errors.New(`pve-ca-copy refused: {"code": "R11", "reason": "unknown mode 'pve-ca-copy'"}`)
|
||||
|
||||
b := newBox(t, srv, proxmox.TLSConfig{Fingerprint: fp(leaf)}, nil)
|
||||
b.m.EnsureCopy = func(context.Context) (Copy, error) { return Copy{}, old }
|
||||
before, _ := os.ReadFile(b.cfgPath)
|
||||
if b.m.Ensure(context.Background(), "start") {
|
||||
t.Fatal("the trust changed with no copy")
|
||||
}
|
||||
if st := b.m.Status(); st.Problem != "" || st.Mode != "fingerprint" {
|
||||
t.Fatalf("a pinned box with older root files reports a trust problem: %+v", st)
|
||||
}
|
||||
if after, _ := os.ReadFile(b.cfgPath); string(after) != string(before) {
|
||||
t.Fatal("the config was written")
|
||||
}
|
||||
|
||||
// the same refusal on a box that is NOT pinned is still a problem: nothing else holds its trust up
|
||||
b2 := newBox(t, srv, proxmox.TLSConfig{}, nil)
|
||||
b2.m.EnsureCopy = func(context.Context) (Copy, error) { return Copy{}, old }
|
||||
b2.m.Ensure(context.Background(), "start")
|
||||
if st := b2.m.Status(); st.Problem != ProblemCopyUnavailable {
|
||||
t.Fatalf("an unpinned box with no copy step must name the problem: %+v", st)
|
||||
}
|
||||
|
||||
// and another refusal on a pinned box is still named
|
||||
b3 := newBox(t, srv, proxmox.TLSConfig{Fingerprint: fp(leaf)}, nil)
|
||||
b3.m.EnsureCopy = func(context.Context) (Copy, error) { return Copy{}, errors.New(`pve-ca-copy refused: {"code": "T3"}`) }
|
||||
b3.m.Ensure(context.Background(), "start")
|
||||
if st := b3.m.Status(); st.Problem != ProblemCopyUnavailable {
|
||||
t.Fatalf("a real refusal lost its name: %+v", st)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user