mesh-build-go decodes the manifest it builds from and judges none (ADR 0578 §3)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -92,7 +92,7 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("no module in %q of workspace %s: %w", module, workspace, err)
|
return nil, fmt.Errorf("no module in %q of workspace %s: %w", module, workspace, err)
|
||||||
}
|
}
|
||||||
manifest, err := catalogue.ParseManifestForInputs(raw)
|
manifest, err := catalogue.Decode(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("the manifest in %q: %w", module, err)
|
return nil, fmt.Errorf("the manifest in %q: %w", module, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,8 +239,8 @@ func TestABuildOutputDirectoryLinkedOutsideTheModuleIsRefused(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Issue 1751 (ADR 0514 §2, the review's K2): a manifest whose config value falls back to a predefined key builds. The
|
// Issue 1751 (ADR 0514 §2, the review's K2): a manifest whose config value falls back to a predefined key builds. The
|
||||||
// builder holds no published list of the keys, so it reads the manifest for its inputs (ParseManifestForInputs), not
|
// builder holds no published list of the keys, so it decodes the manifest for its inputs (catalogue.Decode), and judges
|
||||||
// as a judge of config values; claude-code's real manifest (capturedClaudeCodeManifest) is the fixture.
|
// no config value (ADR 0578 §3); claude-code's real manifest (capturedClaudeCodeManifest) is the fixture.
|
||||||
func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) {
|
func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) {
|
||||||
raw := []byte(capturedClaudeCodeManifest)
|
raw := []byte(capturedClaudeCodeManifest)
|
||||||
if !strings.Contains(string(raw), `"predefined": "agent-managed-settings"`) {
|
if !strings.Contains(string(raw), `"predefined": "agent-managed-settings"`) {
|
||||||
|
|||||||
@@ -16,15 +16,26 @@ const (
|
|||||||
moduleDir = "../.."
|
moduleDir = "../.."
|
||||||
)
|
)
|
||||||
|
|
||||||
func readManifest(t *testing.T) catalogue.Manifest {
|
// decodeTree is the manifest in a module's directory, decoded and judged by nothing: the checker judges every change's
|
||||||
|
// manifests (novox/hq ADR 0578 §2), and a module's own tests read what it declares.
|
||||||
|
func decodeTree(t *testing.T, dir string) catalogue.Manifest {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
m, err := catalogue.ReadTreeManifest(catalogueRoot, moduleDir)
|
raw, err := os.ReadFile(filepath.Join(dir, "module.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("mesh-sdk's validator refuses module.json: %v", err)
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
m, err := catalogue.Decode(raw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("module.json does not decode: %v", err)
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readManifest(t *testing.T) catalogue.Manifest {
|
||||||
|
t.Helper()
|
||||||
|
return decodeTree(t, moduleDir)
|
||||||
|
}
|
||||||
|
|
||||||
func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any {
|
func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
for _, r := range m.Resources {
|
for _, r := range m.Resources {
|
||||||
@@ -36,13 +47,10 @@ func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1483/AC1: mesh-sdk's validator accepts the module (alone on a shelf too), and it runs as mesh-build-go with its
|
// 1483/AC1: the module runs as mesh-build-go with its home at mode 0700, requires user-namespaces and declares the four
|
||||||
// home at mode 0700, requires user-namespaces and declares the four packages.
|
// packages.
|
||||||
func TestManifestIsValidAndDeclaresTheAccountTheCapabilityAndThePackages(t *testing.T) {
|
func TestManifestDeclaresTheAccountTheCapabilityAndThePackages(t *testing.T) {
|
||||||
m := readManifest(t)
|
m := readManifest(t)
|
||||||
if problems := catalogue.CatalogueProblems(catalogue.Shelf{m.Module: m}); len(problems) > 0 {
|
|
||||||
t.Errorf("the catalogue's rules refuse it: %v", problems)
|
|
||||||
}
|
|
||||||
if m.Module != "mesh-build-go" || m.RunsAs != "mesh-build-go" {
|
if m.Module != "mesh-build-go" || m.RunsAs != "mesh-build-go" {
|
||||||
t.Errorf("module %q runs as %q, want mesh-build-go as itself", m.Module, m.RunsAs)
|
t.Errorf("module %q runs as %q, want mesh-build-go as itself", m.Module, m.RunsAs)
|
||||||
}
|
}
|
||||||
@@ -128,22 +136,10 @@ func TestTheToolsServedAreTheToolsTheManifestNames(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1482/AC4: gitea's manifest reads the keys state of both build modules, and the catalogue's validator accepts it with the
|
// 1482/AC4: gitea's manifest reads the keys state of both build modules (whether a read names a state its owner keeps is
|
||||||
// build modules beside it: each owner present declares the state read (a read of a state its owner does not keep is
|
// the judge's, ADR 0578 §2).
|
||||||
// refused).
|
func TestGiteaReadsTheBuildModulesKeys(t *testing.T) {
|
||||||
func TestGiteaReadsTheBuildModulesKeysAndTheCatalogueAcceptsThemTogether(t *testing.T) {
|
gitea := decodeTree(t, filepath.Join(catalogueRoot, "modules", "gitea"))
|
||||||
var all []catalogue.Manifest
|
|
||||||
var gitea catalogue.Manifest
|
|
||||||
for _, name := range []string{"gitea", "mesh-build-go", "mesh-build-node"} {
|
|
||||||
m, err := catalogue.ReadTreeManifest(catalogueRoot, filepath.Join(catalogueRoot, "modules", name))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("mesh-sdk's validator refuses modules/%s/module.json: %v", name, err)
|
|
||||||
}
|
|
||||||
all = append(all, m)
|
|
||||||
if name == "gitea" {
|
|
||||||
gitea = m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, want := range []string{"mesh-build-go.keys", "mesh-build-node.keys", "ssh-client.keys"} {
|
for _, want := range []string{"mesh-build-go.keys", "mesh-build-node.keys", "ssh-client.keys"} {
|
||||||
if !slices.Contains(gitea.Reads, want) {
|
if !slices.Contains(gitea.Reads, want) {
|
||||||
t.Errorf("gitea reads %v, lacks %s", gitea.Reads, want)
|
t.Errorf("gitea reads %v, lacks %s", gitea.Reads, want)
|
||||||
@@ -171,8 +167,8 @@ func TestTheModuleRequiresTheArtifactStoreAndIsToldItsAddress(t *testing.T) {
|
|||||||
t.Errorf("requires %v lack artifact-store", m.Requires)
|
t.Errorf("requires %v lack artifact-store", m.Requires)
|
||||||
}
|
}
|
||||||
r := resource(t, m, "registry")
|
r := resource(t, m, "registry")
|
||||||
// The validator reads the template (files/registry) into the resource's content.
|
// The template (files/registry) is read below; decoding leaves it unread in the resource.
|
||||||
if content, _ := r["content"].(string); r["type"] != "file" || r["path"] != "${dir:state}/registry" || !strings.Contains(content, "${seat:mesh-artifact-store:reach}") {
|
if r["type"] != "file" || r["path"] != "${dir:state}/registry" || r["template"] != "files/registry" {
|
||||||
t.Errorf("the registry resource is %v", r)
|
t.Errorf("the registry resource is %v", r)
|
||||||
}
|
}
|
||||||
raw, err := os.ReadFile(filepath.Join(moduleDir, "files", "registry"))
|
raw, err := os.ReadFile(filepath.Join(moduleDir, "files", "registry"))
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
||||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||||
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
||||||
)
|
)
|
||||||
@@ -134,9 +133,6 @@ func TestTheUnitLevelIsNotGivenTheNodeToolchains(t *testing.T) {
|
|||||||
// 1891 (ADR 0533 §1, §2): the place bound is the Node build module's own: its manifest's cache directory joined with
|
// 1891 (ADR 0533 §1, §2): the place bound is the Node build module's own: its manifest's cache directory joined with
|
||||||
// toolchain, and that cache directory lets other accounts enter it without listing it (0711).
|
// toolchain, and that cache directory lets other accounts enter it without listing it (0711).
|
||||||
func TestTheNodeToolchainsAreTheNodeBuildModulesCache(t *testing.T) {
|
func TestTheNodeToolchainsAreTheNodeBuildModulesCache(t *testing.T) {
|
||||||
if _, err := catalogue.ReadTreeManifest(catalogueRoot, filepath.Join(catalogueRoot, "modules", "mesh-build-node")); err != nil {
|
|
||||||
t.Fatalf("mesh-sdk's validator refuses mesh-build-node's manifest: %v", err)
|
|
||||||
}
|
|
||||||
raw, err := os.ReadFile(filepath.Join(catalogueRoot, "modules", "mesh-build-node", "module.json"))
|
raw, err := os.ReadFile(filepath.Join(catalogueRoot, "modules", "mesh-build-node", "module.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# What these tests read outside their package, as paths from the repository's root (a glob, or a directory read whole;
|
# What these tests read outside their package, as paths from the repository's root (a glob, or a directory read whole;
|
||||||
# ? before a path whose absence is read). mesh-build-go hashes them into the package's digest, so its verdict is kept
|
# ? before a path whose absence is read). mesh-build-go hashes them into the package's digest, so its verdict is kept
|
||||||
# until one of them changes (issue 1936). An empty list, or a line matching nothing, keeps nothing.
|
# until one of them changes (issue 1936). An empty list, or a line matching nothing, keeps nothing.
|
||||||
# the manifests through mesh-sdk's validator (the predefined keys), gitea's and mesh-build-node's.
|
# the manifests gitea's and mesh-build-node's, decoded.
|
||||||
predefined.json
|
|
||||||
modules/gitea
|
modules/gitea
|
||||||
modules/mesh-build-node
|
modules/mesh-build-node
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import (
|
|||||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Issue 1657/AC1 unit: the manifest parse build.go uses reads a requires entry that names shares. The fixture is
|
// Issue 1657/AC1 unit: the manifest decode build.go uses reads a requires entry that names shares. The fixture is
|
||||||
// the shape of mesh-sdk's go/catalogue/bucket_shares_test.go (filesWithShares). The shares are checked through the
|
// the shape of mesh-sdk's go/catalogue/bucket_shares_test.go (filesWithShares). The shares are checked through the
|
||||||
// manifest's stored form, so the test compiles against a pin that predates them and fails on the assertion.
|
// manifest's stored form, so the test compiles against a pin that predates them and fails on the assertion.
|
||||||
func TestBuildReadsManifestWithShares(t *testing.T) {
|
func TestBuildReadsManifestWithShares(t *testing.T) {
|
||||||
raw := []byte(`{"module":"files","version":"1","requires":["shell",
|
raw := []byte(`{"module":"files","version":"1","requires":["shell",
|
||||||
{"name":"s3-bucket","shares":[{"to":"seat:node-files","methods":["put"]}]}]}`)
|
{"name":"s3-bucket","shares":[{"to":"seat:node-files","methods":["put"]}]}]}`)
|
||||||
m, err := catalogue.ParseManifest(raw)
|
m, err := catalogue.Decode(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("the manifest is refused: %v", err)
|
t.Fatalf("the manifest does not decode: %v", err)
|
||||||
}
|
}
|
||||||
stored, err := json.Marshal(m)
|
stored, err := json.Marshal(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module meshbuildgo
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101012031-7cab079e2ec3
|
||||||
github.com/distribution/distribution/v3 v3.1.2
|
github.com/distribution/distribution/v3 v3.1.2
|
||||||
github.com/nats-io/nats-server/v2 v2.11.17
|
github.com/nats-io/nats-server/v2 v2.11.17
|
||||||
github.com/nats-io/nats.go v1.54.0
|
github.com/nats-io/nats.go v1.54.0
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a h1:DcSvfEmdPBKqCg5OmXRNb269EkkPe7BsEp+RykEhkgE=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a h1:DcSvfEmdPBKqCg5OmXRNb269EkkPe7BsEp+RykEhkgE=
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101012031-7cab079e2ec3 h1:an2f0MLx9OhaDLu5i51OMPBbuGwX+aoTzqOkFLMpVfE=
|
||||||
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101012031-7cab079e2ec3/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
||||||
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||||
|
|||||||
Reference in New Issue
Block a user