The checking program's seat answer is the judging view of a seat, with digests or without (issue 1921, milestone 47/G, the lead's ruling after the group check of 616c42434ac2)
mesh/delivery-group group feat/registry-milestone checking: 7 of 7 member(s) ready
mesh/delivery closed: a newer head of the same pull request
mesh/check failed (4): unit: git.novox.be/novox/mesh-catalog/checks/gitignored.TestNoProgramABuildLeavesIsC…; and 3 more | 599046805156 on bab05c66b3cb
mesh/delivery-group group feat/registry-milestone checking: 7 of 7 member(s) ready
mesh/delivery closed: a newer head of the same pull request
mesh/check failed (4): unit: git.novox.be/novox/mesh-catalog/checks/gitignored.TestNoProgramABuildLeavesIsC…; and 3 more | 599046805156 on bab05c66b3cb
A group that changes mesh-vault's, node-launcher's or operator-channel's definition would otherwise meet the step state's credential guard again; the laid list goes only to the manifest validator and the composer, which read no verb's or message's schema. The test digests the definitions whole, as the reader holds them. Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -2,9 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -14,6 +17,7 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliverycheckerclient"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/seatdefs"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
)
|
||||
|
||||
@@ -158,12 +162,8 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
|
||||
if err != nil || len(whole.Seats) < 10 {
|
||||
t.Fatalf("the repository's own definitions: %d, %v", len(whole.Seats), err)
|
||||
}
|
||||
group.SeatDigests = map[string]string{}
|
||||
for _, raw := range whole.Seats {
|
||||
var d struct{ Seat string }
|
||||
_ = json.Unmarshal(raw, &d)
|
||||
group.SeatDigests[d.Seat] = rules.SeatDigest(raw)
|
||||
}
|
||||
// The reader's digests are of each definition whole, as the seat mesh-catalog answers it; the answer is its judging view.
|
||||
group.SeatDigests = wholeDigests(t, real, "novox/mesh-delivery")
|
||||
same, err := rules.SeatsOf(real, group)
|
||||
answer, _ := json.Marshal(same)
|
||||
if err != nil || len(same.Seats) != 0 || same.Same != len(whole.Seats) || len(answer) > buildstep.RunInputBound {
|
||||
@@ -218,6 +218,13 @@ func TestTheCheckingProgramAnswersTheVerdictOfItsFacts(t *testing.T) {
|
||||
t.Errorf("one changed definition: answered %d, %v", len(one.Seats), err)
|
||||
}
|
||||
})
|
||||
// The lead's ruling after G's group check of 616c42434ac2: with digests given too, a changed definition whose verb input
|
||||
// has a property named credentials is answered as the validator and the composer read it, with no such field.
|
||||
changed, err := rules.SeatsOf(os.DirFS(heads), rules.Facts{V: rules.FactsVersion, Members: facts.Members,
|
||||
SeatDigests: map[string]string{"node-build-x": "changed"}})
|
||||
if err != nil || len(changed.Seats) != 1 || bytes.Contains(changed.Seats[0], []byte("credentials")) || bytes.Contains(changed.Seats[0], []byte("Sealed")) {
|
||||
t.Errorf("a changed definition with digests given: %d answered, %s, %v; want it alone, with no verb's schema", len(changed.Seats), changed.Seats, err)
|
||||
}
|
||||
// Review round 1 of milestone 47/B0: the module graph's cycle rule is the program's (ADR 0603 §2, ADR 0656 §5), over the
|
||||
// edges the running checker gathers. A cycle the change makes fails; one the trunk has among the same modules is noted.
|
||||
web, mail := rules.Edge{From: "web", To: "mail", Kind: rules.EdgeAwaits}, rules.Edge{From: "mail", To: "web", Kind: rules.EdgeAwaits}
|
||||
@@ -270,3 +277,66 @@ func mustJSON(t *testing.T, v any) []byte {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// wholeDigests are the digests of a head's seat definitions whole (rules.SeatDigest), read by the domain SDK as the
|
||||
// indexer reads them: what a checker's reader holds for heads that change none.
|
||||
func wholeDigests(t *testing.T, root fs.FS, repository string) map[string]string {
|
||||
t.Helper()
|
||||
head, err := fs.Sub(root, repository)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
manifests := map[string]string{}
|
||||
_ = fs.WalkDir(head, ".", func(p string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() && (d.Name() == ".git" || d.Name() == "testdata" || d.Name() == "node_modules") {
|
||||
return fs.SkipDir
|
||||
}
|
||||
if !d.IsDir() && d.Name() == "module.json" {
|
||||
raw, _ := fs.ReadFile(head, p)
|
||||
manifests[path.Dir(p)] = string(raw)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
forge := seatdefs.Forge{
|
||||
Files: func(_ context.Context, _, _ string, dirs []string) (map[string]map[string]string, error) {
|
||||
out := map[string]map[string]string{}
|
||||
for _, dir := range dirs {
|
||||
files := map[string]string{}
|
||||
if err := fs.WalkDir(head, dir, func(p string, d fs.DirEntry, err error) error {
|
||||
if err == nil && !d.IsDir() {
|
||||
files[strings.TrimPrefix(p, dir+"/")] = ""
|
||||
}
|
||||
return err
|
||||
}); err == nil {
|
||||
out[dir] = files
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
},
|
||||
File: func(_ context.Context, _, _, file string) ([]byte, error) {
|
||||
raw, err := fs.ReadFile(head, file)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return raw, err
|
||||
},
|
||||
}
|
||||
out := map[string]string{}
|
||||
if len(manifests) == 0 {
|
||||
t.Fatalf("no manifest at the head of %s", repository)
|
||||
}
|
||||
for _, c := range seatdefs.ContractsModules(manifests) {
|
||||
defs, _, err := forge.Read(context.Background(), repository, "h", c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for seat, d := range defs {
|
||||
raw, _ := json.Marshal(d)
|
||||
out[seat] = rules.SeatDigest(raw)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -137,14 +137,15 @@ func SeatsOf(heads fs.FS, f Facts) (SeatsAnswer, error) {
|
||||
continue
|
||||
}
|
||||
raw := by[seat].raw
|
||||
// The answer is the judging view of a seat, what the manifest validator and the composer read (the lead's ruling after
|
||||
// the group check of 616c42434ac2), with digests or without: no verb's or message's schema, which neither reads, and
|
||||
// which the build seat's step state, keeping this answer, would refuse where a property is named like a credential
|
||||
// (mesh-vault's verb input `credentials`).
|
||||
raw = withoutMessageSchemas(raw)
|
||||
if f.SeatDigests == nil {
|
||||
// A checker from before G hands no digests, so every definition is answered: whole they are over a run answer's
|
||||
// bound, so every description but the seat's own is left out, of its verbs, events and their schemas, which
|
||||
// decides no verdict (neither the manifest validator nor the composer reads one); review round 2 of G. Nor do they
|
||||
// read a verb's or a message's schema, and the build seat's step state, which keeps this answer, refuses a value
|
||||
// carrying a field named like a credential, as a schema's property may be named (the group check of
|
||||
// 616c42434ac2: mesh-vault's verb input property `credentials`): those schemas are left out too.
|
||||
raw = withoutMessageSchemas(withoutInnerDescriptions(raw))
|
||||
// bound, so every description but the seat's own is left out too, which decides no verdict; review round 2 of G.
|
||||
raw = withoutInnerDescriptions(raw)
|
||||
}
|
||||
out.Seats = append(out.Seats, raw)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user