// Command publish-mirrors pushes a signed distribution document to ≥3 mirrors // and verifies every mirror serves byte-identical content (doc/05 §1/§5). // // Subcommands: // // publish -in doc.json -config mirrors.json [-name endpoints.v1.json] [-verify-only] // fetch -config mirrors.json -name endpoints.v1.json [-keys "id=b64"] [-type endpoints|notices] // // The mirrors config lists each destination's local content root (dir) and an // optional fetch_url used for read-back verification / failover fetch. The // per-mirror sync_cmd (e.g. wrangler / aws s3 cp) is recorded for the operator // but never executed here — publishing writes the object into dir, and the // deploy ships dir to its platform out of band. package main import ( "encoding/json" "errors" "flag" "fmt" "os" "path/filepath" "github.com/wangjia/pangolin/infra/domains/tools/internal/endpoint" "github.com/wangjia/pangolin/infra/domains/tools/internal/mirror" "github.com/wangjia/pangolin/infra/domains/tools/internal/sign" ) func main() { if len(os.Args) < 2 { usage() os.Exit(2) } var err error switch os.Args[1] { case "publish": err = cmdPublish(os.Args[2:]) case "fetch": err = cmdFetch(os.Args[2:]) case "-h", "--help", "help": usage() return default: fmt.Fprintf(os.Stderr, "unknown subcommand %q\n", os.Args[1]) usage() os.Exit(2) } if err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) } } func usage() { fmt.Fprint(os.Stderr, `publish-mirrors — push signed docs to ≥3 mirrors and verify consistency publish -in doc.json -config mirrors.json [-name endpoints.v1.json] [-verify-only] fetch -config mirrors.json -name endpoints.v1.json [-keys "id=b64"] [-type endpoints|notices] `) } func loadConfig(path string) (mirror.Config, error) { var cfg mirror.Config raw, err := os.ReadFile(path) if err != nil { return cfg, err } if err := json.Unmarshal(raw, &cfg); err != nil { return cfg, fmt.Errorf("parse mirrors config: %w", err) } if len(cfg.Mirrors) < 3 { return cfg, fmt.Errorf("at least 3 mirrors required, got %d", len(cfg.Mirrors)) } return cfg, nil } func cmdPublish(args []string) error { fs := flag.NewFlagSet("publish", flag.ContinueOnError) in := fs.String("in", "", "signed document to publish") cfgPath := fs.String("config", "", "mirrors config JSON") name := fs.String("name", "", "published object name (default: basename of -in)") verifyOnly := fs.Bool("verify-only", false, "skip writing; only verify existing mirror content matches -in") if err := fs.Parse(args); err != nil { return err } if *in == "" || *cfgPath == "" { return errors.New("-in and -config are required") } cfg, err := loadConfig(*cfgPath) if err != nil { return err } content, err := os.ReadFile(*in) if err != nil { return err } objectName := *name if objectName == "" { objectName = filepath.Base(*in) } want := mirror.SHA256Hex(content) if !*verifyOnly { results, perr := mirror.Publish(content, objectName, cfg.Mirrors) for _, r := range results { if r.Err != nil { fmt.Printf(" ✗ %-16s %v\n", r.Name, r.Err) } else { fmt.Printf(" ✓ %-16s %s sha256=%s\n", r.Name, r.Path, r.SHA256) } } if perr != nil { return fmt.Errorf("publish had failures: %w", perr) } } if err := mirror.VerifyConsistency(objectName, cfg.Mirrors, want); err != nil { return err } fmt.Printf("consistency OK: %d/%d mirrors serve sha256=%s\n", len(cfg.Mirrors), len(cfg.Mirrors), want) return nil } func cmdFetch(args []string) error { fs := flag.NewFlagSet("fetch", flag.ContinueOnError) cfgPath := fs.String("config", "", "mirrors config JSON") name := fs.String("name", "", "object name to fetch") keys := fs.String("keys", "", "optional key ring id=base64pub[,...] to verify signature on fetch") docType := fs.String("type", "endpoints", "payload type when -keys given: endpoints|notices") out := fs.String("out", "", "write fetched content here (default: stdout)") if err := fs.Parse(args); err != nil { return err } if *cfgPath == "" || *name == "" { return errors.New("-config and -name are required") } cfg, err := loadConfig(*cfgPath) if err != nil { return err } var validate func([]byte) error if *keys != "" { ring, err := sign.ParseKeyRing([]string{*keys}) if err != nil { return err } validate = func(b []byte) error { if *docType == "endpoints" { _, _, e := endpoint.VerifyDocument(b, ring, 0) return e } env, e := sign.Parse(b) if e != nil { return e } return sign.Verify(env, ring) } } content, winner, err := mirror.Fetch(*name, cfg.Mirrors, validate) if err != nil { return err } fmt.Fprintf(os.Stderr, "fetched from mirror %q\n", winner) if *out == "" { _, err = os.Stdout.Write(content) return err } return os.WriteFile(*out, content, 0o644) }