Refuse the grants step when its send would change more than the bus's user list (review of #230)
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without …
mesh/repo-check fail: its merge-check.sh failed: --- FAIL: TestTheGrantsStepSendsTheUserListAndNothingElse (1.68s)
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without …
mesh/repo-check fail: its merge-check.sh failed: --- FAIL: TestTheGrantsStepSendsTheUserListAndNothingElse (1.68s)
Kept builds are not the whole declaration: a new assignment, settings or a provision's logins went out as the mesh holds them now. The step now compares what it would send with the last send's summary and fails, said, when anything but the user list differs; ungatedIn reads the kept builds instead of passing the step unread.
This commit is contained in:
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -239,11 +240,6 @@ var machineMoves = func(ctx context.Context, open *stores, f moveFacts, node str
|
||||
// ungatedIn refuses a send whose machines would move a build no gate has seen, outside its scope: the
|
||||
// machines named, and why; the machine holding the bus, added only for its user list, is left instead.
|
||||
func ungatedIn(ctx context.Context, open *stores, names []string, addedHolder string) ([]string, error) {
|
||||
// The grants step moves no build: every module is composed at the build its machine runs (novox/hq
|
||||
// issue 490), so there is nothing here for a gate to judge.
|
||||
if everyBuildKept(ctx) {
|
||||
return names, nil
|
||||
}
|
||||
scope := scopeOf(ctx)
|
||||
if scope.person {
|
||||
return names, nil
|
||||
@@ -258,8 +254,19 @@ func ungatedIn(ctx context.Context, open *stores, names []string, addedHolder st
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The grants step composes every module at the build its machine was last sent (novox/hq issue 490):
|
||||
// a move it keeps is not made. Read, not assumed, so a move it could not keep is still refused here.
|
||||
var keeps map[string]string
|
||||
if everyBuildKept(ctx) {
|
||||
if keeps, err = recordedKept(ctx, open, n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var waiting []string
|
||||
for _, mv := range moves {
|
||||
if was, kept := keeps[mv.Module]; kept && sameCommit(was, mv.From) {
|
||||
continue
|
||||
}
|
||||
if !scope.judged[n] && !scope.modules[mv.Module] {
|
||||
waiting = append(waiting, fmt.Sprintf("%s %s → %s", mv.Module, short(mv.From), short(mv.To)))
|
||||
}
|
||||
@@ -961,6 +968,19 @@ func grantsStep(ctx context.Context, open *stores, node string) *inventory.Grant
|
||||
// list is the one already sent.
|
||||
return nil
|
||||
}
|
||||
// **The user list and nothing else**: checked before it is sent, against what the machine was last sent.
|
||||
// Kept builds are not the whole of a declaration — a new assignment, a settings change, an assignment
|
||||
// taken away, a provision's logins are composed as the mesh holds them now — and a step that carried any
|
||||
// of it would be the unjudged change this step exists to avoid.
|
||||
if other, err := grantsOnlyOf(ctx, open, holder); err != nil || other != "" {
|
||||
why := other
|
||||
if err != nil {
|
||||
why = err.Error()
|
||||
}
|
||||
fmt.Printf("grants step: %s is not sent its user list ahead of %s, which is sent without it: %s\n",
|
||||
holder, node, why)
|
||||
return &inventory.GrantsStep{Node: holder, Failed: why}
|
||||
}
|
||||
if _, err := sendRollout(keepingEveryBuild(withScope(ctx, sendScope{})), open, []string{holder}); err != nil {
|
||||
fmt.Printf("grants step: the bus's user list could not be sent to %s ahead of %s, which is sent without "+
|
||||
"it — the bus may refuse what the send newly grants: %v\n", holder, node, err)
|
||||
@@ -972,6 +992,87 @@ func grantsStep(ctx context.Context, open *stores, node string) *inventory.Grant
|
||||
return &inventory.GrantsStep{Node: holder, At: &now}
|
||||
}
|
||||
|
||||
// grantsOnlyOf is grantsOnly: a variable so a test of the walk needs no store.
|
||||
var grantsOnlyOf = grantsOnly
|
||||
|
||||
// grantsOnly is what the grants step's send to the machine holding the bus would change there besides its
|
||||
// user list, against what it was last sent (novox/hq issue 490); empty when nothing else. Composed as the
|
||||
// step's send composes it, without allocating anything (Foreseeing), and compared resource by resource
|
||||
// with the summary the last send kept (ADR 0217): exact, rather than a list of the cases that can differ.
|
||||
// A module there that was never sent is a new assignment, and refused too, whatever its resources.
|
||||
func grantsOnly(ctx context.Context, open *stores, holder string) (string, error) {
|
||||
inv := open.inventory
|
||||
kept := keepingEveryBuild(keepingRecorded(ctx))
|
||||
plan, settings, err := planFor(kept, open, holder)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sent, known, err := inv.SentBuilds(ctx, holder)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !known {
|
||||
return fmt.Sprintf("what %s was last sent is not known", holder), nil
|
||||
}
|
||||
var other []string
|
||||
listID := ""
|
||||
for _, m := range plan.Modules {
|
||||
if _, was := sent[m.Module]; !was {
|
||||
other = append(other, m.Module+" newly assigned")
|
||||
}
|
||||
if m.BusUsers != "" && m.ClaimsSeat(catalogue.BrokerSeat) {
|
||||
listID = m.Module + "." + catalogue.BusUsersID()
|
||||
}
|
||||
}
|
||||
gens, err := generators(kept, open)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
declared, err := declarationWith(kept, open, holder, plan, settings, gens, Foreseeing)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, f := range declared.foreseen {
|
||||
other = append(other, f+" would be minted")
|
||||
}
|
||||
body, err := declared.Body()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
after, err := summarize(body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
prev, err := inv.SentSummary(ctx, holder)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(prev) == 0 {
|
||||
return fmt.Sprintf("what %s was last sent is not kept for comparison", holder), nil
|
||||
}
|
||||
var before []sentResource
|
||||
if err := json.Unmarshal(prev, &before); err != nil {
|
||||
return "", fmt.Errorf("what %s was last sent is kept in a form this version does not read: %w", holder, err)
|
||||
}
|
||||
d := diffSent(before, after)
|
||||
for _, id := range d.Added {
|
||||
other = append(other, "+"+id)
|
||||
}
|
||||
for _, id := range d.Removed {
|
||||
other = append(other, "-"+id)
|
||||
}
|
||||
for _, c := range d.Changed {
|
||||
if c.ID == listID {
|
||||
continue
|
||||
}
|
||||
other = append(other, fmt.Sprintf("~%s (%s)", c.ID, strings.Join(c.Fields, ", ")))
|
||||
}
|
||||
if len(other) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
return "its send would change more than the bus's user list: " + strings.Join(other, "; "), nil
|
||||
}
|
||||
|
||||
// sendJudged is a gated send's sends: the grants step when the user list changed, then the machine judged.
|
||||
func sendJudged(ctx context.Context, open *stores, node string) ([]string, *inventory.GrantsStep, error) {
|
||||
grants := grantsStep(ctx, open, node)
|
||||
|
||||
Reference in New Issue
Block a user