Since 13:55 the client refused every plan with credential-form none (gitea's forge-account, the artifact store), and g14 and shanks placed no files for mesh-build-go, mesh-build-node, mesh-build-image or ssh-client. Second meeting of the credential-form list kind: the controller's copy was fixed alone before. Thorough: one list in mesh-sdk; this client drops its copy and pins mesh-sdk 9379e9a. A none entry is never a holder's issued value: its bound values come from the provider's entry, and a secret named for it fails loudly instead of waiting on a vault that mints nothing.
128 lines
6.7 KiB
Go
128 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A plan names, for each provision its module requires, the provider serving it (design 57 V5a, issue 760): the
|
|
// client reads that strictly, before the controller writes it, and fills nothing from an entry with no credential;
|
|
// the vault acts on it.
|
|
func TestAPlanNamingItsProvidersIsRead(t *testing.T) {
|
|
value := `{"node":"g14","module":"app","provisioning":{` +
|
|
`"templates":{"source":"x","digest":"sha256:` + strings.Repeat("0", 64) + `"},` +
|
|
`"files":[{"id":"conf","path":"/etc/app.conf","template":"app.conf","owner-at-runtime":"owned"}],` +
|
|
`"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres"},` +
|
|
`{"provision":"s3-bucket","local":"hot","provider":"ace","provider-module":"minio"},` +
|
|
`{"name":"forge-read","provision":"forge-read","provider":"novox","provider-module":"forge",` +
|
|
`"path":"/var/lib/app/forge.secret"}]}}`
|
|
_, p, err := planOf("g14", "g14.app", []byte(value))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := []PlannedProvision{{Provision: "postgres-database", Provider: "novox", ProviderModule: "postgres"},
|
|
{Provision: "s3-bucket", Local: "hot", Provider: "ace", ProviderModule: "minio"},
|
|
{Name: "forge-read", Provision: "forge-read", Provider: "novox", ProviderModule: "forge",
|
|
Path: "/var/lib/app/forge.secret"}}
|
|
if len(p.Provisions) != len(want) {
|
|
t.Fatalf("the plan's provisions are read as %+v, want %+v", p.Provisions, want)
|
|
}
|
|
for i := range want {
|
|
if !reflect.DeepEqual(p.Provisions[i], want[i]) {
|
|
t.Fatalf("the plan's provisions are read as %+v, want %+v", p.Provisions, want)
|
|
}
|
|
}
|
|
// Only the credential is a file to fill: an entry naming a provider alone fills nothing.
|
|
targets, why := fillTargets(p, map[string]string{"app.conf": "x"})
|
|
if why != "" || len(targets) != 2 || targets[1].Path != "/var/lib/app/forge.secret" {
|
|
t.Fatalf("the files filled are %+v (%s)", targets, why)
|
|
}
|
|
for why, provisions := range map[string][]PlannedProvision{
|
|
"a file and no credential's name": {{Provision: "p", Provider: "a", ProviderModule: "m", Path: "/var/lib/p"}},
|
|
"one provision and local twice": {{Provision: "p", Local: "l", Provider: "a", ProviderModule: "m"},
|
|
{Provision: "p", Local: "l", Provider: "b", ProviderModule: "m"}},
|
|
"no provider": {{Provision: "p", ProviderModule: "m"}},
|
|
} {
|
|
bad := p
|
|
bad.Provisions = provisions
|
|
if len(bad.problems()) == 0 {
|
|
t.Errorf("a plan with %s was taken", why)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Each entry names the credential form of its provider's offer (issue 768), which the vault acts on: the client
|
|
// reads it strictly, before the controller writes it, and refuses a form it does not know.
|
|
func TestAPlanNamingEachProvidersCredentialFormIsRead(t *testing.T) {
|
|
value := `{"node":"g14","module":"app","provisioning":{` +
|
|
`"templates":{"source":"x","digest":"sha256:` + strings.Repeat("0", 64) + `"},` +
|
|
`"files":[{"id":"conf","path":"/etc/app.conf","template":"app.conf","owner-at-runtime":"owned"}],` +
|
|
`"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` +
|
|
`"credential-form":"pair"},` +
|
|
`{"provision":"sonarr-api","provider":"ace","provider-module":"sonarr","credential-form":"shared"},` +
|
|
`{"name":"forge-read","provision":"forge-read","provider":"novox","provider-module":"forge",` +
|
|
`"credential-form":"issued","path":"/var/lib/app/forge.secret"},` +
|
|
`{"provision":"smtp-relay","provider":"ace","provider-module":"relay","credential-form":"given"},` +
|
|
// An offer with no credential (issue 774), as design 47's catalogue declares gitea's forge-account.
|
|
`{"provision":"forge-account","provider":"novox","provider-module":"gitea","credential-form":"none"}]}}`
|
|
_, p, err := planOf("g14", "g14.app", []byte(value))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var forms []string
|
|
for _, pr := range p.Provisions {
|
|
forms = append(forms, pr.CredentialForm)
|
|
}
|
|
if strings.Join(forms, ",") != "pair,shared,issued,given,none" {
|
|
t.Fatalf("the credential forms are read as %v", forms)
|
|
}
|
|
// A none entry places no file of its own and is never a holder's issued value: its bound values are read from
|
|
// its provider's entry, and the plan's files are placed as they are.
|
|
targets, fail := fillTargets(p, map[string]string{"app.conf": "x"})
|
|
var paths []string
|
|
for _, f := range targets {
|
|
paths = append(paths, f.Path)
|
|
}
|
|
if fail != "" || strings.Join(paths, ",") != "/etc/app.conf,/var/lib/app/forge.secret" {
|
|
t.Fatalf("the plan places %v (%s)", paths, fail)
|
|
}
|
|
if none := (PlannedProvision{Name: "forge-account", CredentialForm: "none"}); none.issuedForHolder() {
|
|
t.Fatal("a credential of an offer with none is read as a holder's issued value")
|
|
}
|
|
// A template naming such a credential fails loudly, and the vault, which mints nothing for it, is never asked.
|
|
named := Plan{Provisions: []PlannedProvision{{Name: "forge-account", Provision: "forge-account", Provider: "novox",
|
|
CredentialForm: "none"}}}
|
|
if _, wait, fail := (&Client{Node: "g14"}).secretOf(context.Background(), nil, "app", named,
|
|
Need{Kind: "secret", Name: "forge-account"}); wait != "" || !strings.Contains(fail, "no credential (form none)") {
|
|
t.Fatalf("a secret of an offer with none: wait %q, fail %q", wait, fail)
|
|
}
|
|
bad := strings.Replace(value, `"credential-form":"pair"`, `"credential-form":"one-for-all"`, 1)
|
|
if _, _, err := planOf("g14", "g14.app", []byte(bad)); err == nil || !strings.Contains(err.Error(), "one-for-all") {
|
|
t.Fatalf("a credential form the client does not know was taken: %v", err)
|
|
}
|
|
}
|
|
|
|
// A consumer's plan entry may carry what its module contributes to the provider (issue 776): the client reads it
|
|
// strictly, keeps it on the entry, and still refuses any other field it does not know.
|
|
func TestAPlanEntryCarryingItsContributionIsRead(t *testing.T) {
|
|
value := `{"node":"g14","module":"app","provisioning":{` +
|
|
`"templates":{"source":"x","digest":"sha256:` + strings.Repeat("0", 64) + `"},` +
|
|
`"files":[{"id":"conf","path":"/etc/app.conf","template":"app.conf","owner-at-runtime":"owned"}],` +
|
|
`"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` +
|
|
`"contributes":{"name":"nextcloud","extensions":["pg_trgm"]}}]}}`
|
|
_, p, err := planOf("g14", "g14.app", []byte(value))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := map[string]any{"name": "nextcloud", "extensions": []any{"pg_trgm"}}
|
|
if len(p.Provisions) != 1 || !reflect.DeepEqual(p.Provisions[0].Contributes, want) {
|
|
t.Fatalf("the plan's provisions are read as %+v, want the contribution %v kept", p.Provisions, want)
|
|
}
|
|
bad := strings.Replace(value, `"contributes":`, `"contribution":`, 1)
|
|
if _, _, err := planOf("g14", "g14.app", []byte(bad)); err == nil {
|
|
t.Error("a plan entry with a field the client does not know was taken")
|
|
}
|
|
}
|