97 lines
3.6 KiB
Go
97 lines
3.6 KiB
Go
// Package credentialform refuses an offer that does not say the form of its credential: an own secret, an issuer, or
|
|
// `form` pair or none (the lead, 2026-10-29). It reads every modules/*/module.json through mesh-sdk's
|
|
// CredentialFormProblems.
|
|
//
|
|
// It refuses a route received as a file too (issue 774, research 072 row 34, the operator on 2026-10-31: "there is only
|
|
// 1 path, the other is simply deprecated/invalid"): a route is a provision, served from the seat mesh-provisioner's
|
|
// plans alone, and a manifest's `receives.route` is the deprecated path. A module still moving off it is listed in
|
|
// stillReceivingRoutes with why; every refusal names them all, and a listed module that no longer receives one is
|
|
// refused too, so the list only shrinks.
|
|
package credentialform
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// Problems is every offer of the manifests under root/modules that says no credential form, one line each.
|
|
func Problems(root string) ([]string, error) {
|
|
files, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(files)
|
|
var out []string
|
|
var receiving []string
|
|
reads := map[string]bool{}
|
|
var binders []string
|
|
for _, f := range files {
|
|
raw, err := os.ReadFile(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var m catalogue.Manifest
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
return nil, fmt.Errorf("%s: %w", f, err)
|
|
}
|
|
out = append(out, catalogue.CredentialFormProblems(m)...)
|
|
if _, received := m.Receives["route"]; received {
|
|
receiving = append(receiving, m.Module)
|
|
} else if _, listed := stillReceivingRoutes[m.Module]; listed {
|
|
out = append(out, fmt.Sprintf("%s no longer receives route; take it off stillReceivingRoutes", m.Module))
|
|
}
|
|
var kept struct {
|
|
Reads []string `json:"reads"`
|
|
State []json.RawMessage `json:"state"`
|
|
}
|
|
_ = json.Unmarshal(raw, &kept) // reads may hold objects in another module; only the provisioner's are read
|
|
if m.Module == "mesh-provisioner" {
|
|
for _, r := range kept.Reads {
|
|
reads[r] = true
|
|
}
|
|
}
|
|
if len(m.Provides) > 0 && keepsBound(kept.State) {
|
|
binders = append(binders, m.Module)
|
|
}
|
|
}
|
|
for _, module := range binders {
|
|
if !reads[module+".bound"] {
|
|
out = append(out, fmt.Sprintf("%s provides and keeps a `bound` state, and mesh-provisioner's manifest does not read %s.bound", module, module))
|
|
}
|
|
}
|
|
for _, module := range receiving {
|
|
if _, listed := stillReceivingRoutes[module]; !listed {
|
|
out = append(out, fmt.Sprintf("%s receives route as a file: a route is a provision, served from the seat "+
|
|
"mesh-provisioner's plans alone (issue 774); still on the deprecated path: %s", module,
|
|
strings.Join(receiving, ", ")))
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// stillReceivingRoutes is every module still receiving its routes as a file, and why it has not moved yet.
|
|
var stillReceivingRoutes = map[string]string{
|
|
"route-adapter": "migration scaffolding writing into a predecessor's proxy (novox/hq ADR 0104), deleted when that " +
|
|
"migration ends; it reads the received file its TypeScript adapter turns into the predecessor's route files",
|
|
}
|
|
|
|
// keepsBound says whether a manifest's `state` names `bound`, as a plain name or an object with a name.
|
|
func keepsBound(state []json.RawMessage) bool {
|
|
for _, s := range state {
|
|
var name string
|
|
var obj struct {
|
|
Name string `json:"name"`
|
|
}
|
|
if json.Unmarshal(s, &name) == nil && name == "bound" || json.Unmarshal(s, &obj) == nil && obj.Name == "bound" {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|