mesh-delivery-sdk kept: the version check, CheckName and IsHex64 are mesh-sdk keys' now; kept keeps Decode and CheckDigest (ruling 2, ADR 0634 §1; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
checker "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/kept"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
// The states of a verdict, the levels of a check and the compositions' states.
|
||||
@@ -44,10 +44,10 @@ func CheckRepository(repository string) error {
|
||||
if !ok || strings.Contains(name, "/") {
|
||||
return fmt.Errorf("meshdeliverycheckerclient: the repository %q is not <owner>/<name>, with exactly one slash", repository)
|
||||
}
|
||||
if err := kept.CheckName("repository owner", owner); err != nil {
|
||||
if err := keys.CheckName("repository owner", owner); err != nil {
|
||||
return fmt.Errorf("meshdeliverycheckerclient: the repository %q: %w", repository, err)
|
||||
}
|
||||
if err := kept.CheckName("repository name", name); err != nil {
|
||||
if err := keys.CheckName("repository name", name); err != nil {
|
||||
return fmt.Errorf("meshdeliverycheckerclient: the repository %q: %w", repository, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -65,7 +65,7 @@ const (
|
||||
// being the fingerprint's key part (fingerprint.KeyPart), since a bus key may not hold ':'. A module holding a dot or a
|
||||
// character a key refuses, and a fingerprint not of the new form, are refused, naming them.
|
||||
func BuilderBuildKey(module, fp string) (string, error) {
|
||||
if err := kept.CheckName("module", module); err != nil {
|
||||
if err := keys.CheckName("module", module); err != nil {
|
||||
return "", err
|
||||
}
|
||||
part, err := fingerprint.KeyPart(fp)
|
||||
@@ -81,7 +81,7 @@ func ParseBuilderBuildKey(key string) (module, fp string, err error) {
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("builds: %q is not a builder build key, <module>.<fingerprint hex>", key)
|
||||
}
|
||||
if err := kept.CheckName("module", module); err != nil {
|
||||
if err := keys.CheckName("module", module); err != nil {
|
||||
return "", "", fmt.Errorf("builds: %q is not a builder build key: %w", key, err)
|
||||
}
|
||||
if fp, err = fingerprint.ParseKeyPart(part); err != nil {
|
||||
@@ -265,7 +265,7 @@ func (b BuilderBuild) check() error {
|
||||
return fmt.Errorf("builds: the build state %q is not queued, building, done or failed", b.State)
|
||||
}
|
||||
if b.Manifest != "" {
|
||||
if !kept.IsHex64(b.Manifest) {
|
||||
if !keys.IsHex64(b.Manifest) {
|
||||
return fmt.Errorf("builds: %q is not a manifest digest, 64 lowercase hex digits", b.Manifest)
|
||||
}
|
||||
}
|
||||
@@ -355,7 +355,7 @@ func EncodeBuilderBuild(b BuilderBuild) ([]byte, error) {
|
||||
return json.Marshal(b)
|
||||
}
|
||||
|
||||
// DecodeBuilderBuild reads a builder build value; it refuses an unknown version (kept.ErrUnknownVersion) and what
|
||||
// DecodeBuilderBuild reads a builder build value; it refuses an unknown version (keys.ErrUnknownVersion) and what
|
||||
// EncodeBuilderBuild refuses.
|
||||
func DecodeBuilderBuild(data []byte) (BuilderBuild, error) {
|
||||
var b BuilderBuild
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/buildrecord"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/kept"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
@@ -177,10 +176,10 @@ func TestBuilderBuildNamesItsToolchains(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1358/AC5: a value of another version, or none, is refused with kept.ErrUnknownVersion.
|
||||
// 1358/AC5: a value of another version, or none, is refused with keys.ErrUnknownVersion.
|
||||
func TestBuilderBuildVersion(t *testing.T) {
|
||||
for _, in := range []string{`{"v":2,"state":"queued"}`, `{"state":"queued"}`} {
|
||||
if _, err := DecodeBuilderBuild([]byte(in)); !errors.Is(err, kept.ErrUnknownVersion) {
|
||||
if _, err := DecodeBuilderBuild([]byte(in)); !errors.Is(err, keys.ErrUnknownVersion) {
|
||||
t.Errorf("DecodeBuilderBuild(%s) = %v", in, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/kept"
|
||||
"git.novox.be/novox/mesh-delivery/sdk/trunk"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
@@ -36,7 +35,7 @@ const (
|
||||
// BuildLogKey is the key of a module's entries in the builder's log: the module's name, refused when a log key could not
|
||||
// hold it.
|
||||
func BuildLogKey(module string) (string, error) {
|
||||
if err := kept.CheckName("module", module); err != nil {
|
||||
if err := keys.CheckName("module", module); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return module, nil
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/sdk/kept"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
@@ -26,7 +25,7 @@ func TestATakenValueRoundTripsAndRefusesWhatLacksARepositoryOrAMerge(t *testing.
|
||||
t.Errorf("taken without merge: %v", err)
|
||||
}
|
||||
for _, in := range []string{`{"v":2,"repository":"a/b","merge":"c"}`, `{"repository":"a/b","merge":"c"}`} {
|
||||
if _, err := DecodeTaken([]byte(in)); !errors.Is(err, kept.ErrUnknownVersion) {
|
||||
if _, err := DecodeTaken([]byte(in)); !errors.Is(err, keys.ErrUnknownVersion) {
|
||||
t.Errorf("decode of %s = %v, want ErrUnknownVersion", in, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ func EncodeViewAnswer(a ViewAnswer) ([]byte, error) {
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
// DecodeViewAnswer reads an answer; it refuses an unknown version (kept.ErrUnknownVersion) and what EncodeViewAnswer refuses.
|
||||
// DecodeViewAnswer reads an answer; it refuses an unknown version (keys.ErrUnknownVersion) and what EncodeViewAnswer refuses.
|
||||
func DecodeViewAnswer(data []byte) (ViewAnswer, error) {
|
||||
var a ViewAnswer
|
||||
if err := kept.Decode(data, &a); err != nil {
|
||||
|
||||
+5
-44
@@ -1,59 +1,20 @@
|
||||
// Package kept holds what the layouts of the Delivery domain's kept values share: the version check on reading one, the
|
||||
// rule a name must keep to be a key part, and the form of a digest. It names no seat and no module (ADR 0634 §2). The
|
||||
// version itself (keys.Version) and the escaping of a name (keys.EscapeName) are mesh-sdk's, since more than one domain uses
|
||||
// them.
|
||||
// Package kept holds what the layouts of the Delivery domain's kept values share: the reading of one at its version and the form
|
||||
// of a digest. It names no seat and no module (ADR 0634 §2). The version (keys.Version, keys.CheckVersion), the rule a name
|
||||
// must keep to be a key part (keys.CheckName), keys.IsHex64 and the escaping of a name (keys.EscapeName) are mesh-sdk's,
|
||||
// since more than one domain uses them.
|
||||
package kept
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
)
|
||||
|
||||
// ErrUnknownVersion is what Decode returns for a value whose version is missing or not keys.Version. Test it with errors.Is.
|
||||
var ErrUnknownVersion = errors.New("kept: unknown value version")
|
||||
|
||||
var nameOK = regexp.MustCompile(`^[-/_=a-zA-Z0-9]+$`)
|
||||
|
||||
// CheckName refuses a name that is empty or holds a dot, a wildcard, whitespace or a character a bus key refuses.
|
||||
func CheckName(kind, name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("kept: the %s name is empty", kind)
|
||||
}
|
||||
if !nameOK.MatchString(name) {
|
||||
return fmt.Errorf("kept: the %s name %q holds a dot, a wildcard, whitespace or a character a key refuses", kind, name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var hex64 = regexp.MustCompile(`^[0-9a-f]{64}$`)
|
||||
|
||||
// IsHex64 says whether s is 64 lowercase hex digits.
|
||||
func IsHex64(s string) bool { return hex64.MatchString(s) }
|
||||
|
||||
// CheckVersion refuses a value with no version or one this reader does not read.
|
||||
func CheckVersion(data []byte) error {
|
||||
var probe struct {
|
||||
V *int `json:"v"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &probe); err != nil {
|
||||
return fmt.Errorf("kept: value is not JSON: %w", err)
|
||||
}
|
||||
if probe.V == nil {
|
||||
return fmt.Errorf("%w: no version in the value, this reader reads %d", ErrUnknownVersion, keys.Version)
|
||||
}
|
||||
if *probe.V != keys.Version {
|
||||
return fmt.Errorf("%w: the value is version %d, this reader reads %d", ErrUnknownVersion, *probe.V, keys.Version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode reads data into into after CheckVersion.
|
||||
func Decode(data []byte, into any) error {
|
||||
if err := CheckVersion(data); err != nil {
|
||||
if err := keys.CheckVersion(data); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, into); err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package kept
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.novox.be/novox/mesh-sdk/go/keys"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -10,21 +11,13 @@ func TestAKeptValueIsReadOnlyAtItsVersionAndAKeyPartOnlyOfKeyCharacters(t *testi
|
||||
var v struct{ V int }
|
||||
for data, ok := range map[string]bool{`{"v":1}`: true, `{"v":2}`: false, `{}`: false} {
|
||||
err := Decode([]byte(data), &v)
|
||||
if (err == nil) != ok || (!ok && !errors.Is(err, ErrUnknownVersion)) {
|
||||
if (err == nil) != ok || (!ok && !errors.Is(err, keys.ErrUnknownVersion)) {
|
||||
t.Errorf("Decode(%s) = %v", data, err)
|
||||
}
|
||||
}
|
||||
if Decode([]byte(`nope`), &v) == nil {
|
||||
t.Error("a value that is no JSON is read")
|
||||
}
|
||||
for name, ok := range map[string]bool{"a-b_c/d=": true, "": false, "a.b": false, "a b": false, "a*": false} {
|
||||
if (CheckName("module", name) == nil) != ok {
|
||||
t.Errorf("CheckName(%q) = %v", name, CheckName("module", name))
|
||||
}
|
||||
}
|
||||
if !IsHex64(strings.Repeat("a", 64)) || IsHex64(strings.Repeat("A", 64)) || IsHex64("a") {
|
||||
t.Error("IsHex64 reads a wrong form")
|
||||
}
|
||||
if CheckDigest("sha256:"+strings.Repeat("0", 64), "x") != nil || CheckDigest("sha256:0", "x") == nil {
|
||||
t.Error("CheckDigest reads a wrong form")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user