Prove the controller composes and checks shares on an s3-bucket requirement (issue 1593)
mesh/merge-gate head 64c1996a5e9d merged into trunk ff42f2183900 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head 64c1996a5e9d merged into trunk ff42f2183900 — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/merge-gate head 64c1996a5e9d merged into trunk ff42f2183900 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head 64c1996a5e9d merged into trunk ff42f2183900 — pass: its merge-check.sh passed
mesh/delivery delivered
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/compose"
|
||||
"git.novox.be/novox/mesh-sdk/go/overlay"
|
||||
)
|
||||
|
||||
// Issue 1593 (novox/hq ADR 0468 §8): `shares` on a requirement of s3-bucket, taken in with mesh-sdk 465beb4. The fixture's
|
||||
// shape is mesh-sdk's go/catalogue/bucket_shares_test.go (issue 1591) and go/compose/resolve_test.go theObjectsMesh.
|
||||
|
||||
const filesRequiringShares = `{"module":"files","version":"1","requires":[
|
||||
{"name":"s3-bucket","shares":[{"to":"seat:node-files","methods":["put"]}]}]}`
|
||||
|
||||
func aKey(t *testing.T) string {
|
||||
t.Helper()
|
||||
k, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(k.PublicKey().Bytes())
|
||||
}
|
||||
|
||||
// 1593/AC1 unit: composing the provider's machine, the file it receives for the consumer carries the shares.
|
||||
func TestTheProvidersMachineReceivesTheSharesOfAnS3BucketRequirement(t *testing.T) {
|
||||
var overlayModule catalogue.Manifest
|
||||
raw, err := json.Marshal(overlay.Manifest())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal(raw, &overlayModule); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
consumer, err := catalogue.ParseManifest([]byte(filesRequiringShares))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
provider := catalogue.Manifest{Module: "objects", Version: "1",
|
||||
Provides: []catalogue.Offer{{Name: "s3-bucket", Scope: catalogue.ScopeMesh,
|
||||
Identity: &catalogue.OfferIdentity{Max: 20, In: "an S3 access key"}}},
|
||||
Receives: map[string]string{"s3-bucket": "/var/lib/mesh/objects/mesh.json"}}
|
||||
in := compose.Input{
|
||||
Catalogue: map[string]catalogue.Manifest{overlay.Name: overlayModule, "objects": provider, "files": consumer},
|
||||
Issued: []compose.Issued{{Provision: "s3-bucket", Consumer: "laptop", ConsumerModule: "files",
|
||||
Provider: "anchor", ForProvider: "sealed-to-anchor"}},
|
||||
}
|
||||
for i, name := range []string{"anchor", "laptop"} {
|
||||
assigned := []string{overlay.Name, "objects"}
|
||||
if name == "laptop" {
|
||||
assigned = []string{overlay.Name, "files"}
|
||||
}
|
||||
in.Nodes = append(in.Nodes, compose.Node{Name: name, SealingKey: name + "-key", Assigned: assigned,
|
||||
Place: compose.Place{Key: aKey(t), Endpoint: name + ".example:51820", Site: "here", Hub: name == "anchor",
|
||||
Address: []string{"10.77.0.1", "10.77.0.2"}[i]},
|
||||
Capabilities: map[string]bool{"container-runtime": true, "wireguard": true, "systemd": true}})
|
||||
}
|
||||
rendered, err := compose.Render(in, "anchor", compose.Foreseeing)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(rendered.Rendering.Grants) != 1 {
|
||||
t.Fatalf("grants are %+v", rendered.Rendering.Grants)
|
||||
}
|
||||
got, err := json.Marshal(rendered.Rendering.Grants[0].Values["shares"])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := `[{"methods":["put"],"to":"seat:node-files"}]`; string(got) != want {
|
||||
t.Fatalf("the provider's grant for the consumer carries shares %s, want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// 1593/AC2 unit: the module check accepts a manifest with shares and refuses an unknown method, citing ADR 0468 §8.
|
||||
func TestModuleCheckAcceptsSharesAndRefusesAnUnknownMethod(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
write := func(name, body string) string {
|
||||
p := filepath.Join(dir, name+".json")
|
||||
if err := os.WriteFile(p, []byte(body), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
var out bytes.Buffer
|
||||
if err := moduleCheckFor([]string{write("files", filesRequiringShares)}, 6, &out); err != nil {
|
||||
t.Fatalf("a manifest with shares was refused: %v\n%s", err, out.String())
|
||||
}
|
||||
out.Reset()
|
||||
bad := write("bad", `{"module":"bad","version":"1","requires":[
|
||||
{"name":"s3-bucket","shares":[{"to":"seat:node-files","methods":["delete"]}]}]}`)
|
||||
err := moduleCheckFor([]string{bad}, 6, &out)
|
||||
if err == nil || !strings.Contains(out.String(), "ADR 0468 §8") {
|
||||
t.Fatalf("an unknown method passed or the refusal does not cite the ADR: %v\n%s", err, out.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user