aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/mbf/main.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-06-07 17:15:27 +0900
committerOphestra <cat@gensokyo.uk>2026-06-07 19:25:11 +0900
commite8bb5a622d0c1895b1768a90d0b422ec084db73f (patch)
tree46011917ee77bc70c2f6d473b85cee24dfe3e152 /cmd/mbf/main.go
parent22e508fe17cdf6be6240e6b73ac5b90bc6bfd77e (diff)
internal/rosa: mirror service via external cache
This provides an authenticated implementation of the external cache. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/mbf/main.go')
-rw-r--r--cmd/mbf/main.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go
index 86496f98..ae835500 100644
--- a/cmd/mbf/main.go
+++ b/cmd/mbf/main.go
@@ -14,6 +14,7 @@ package main
import (
"context"
+ "crypto/ed25519"
"crypto/sha512"
"errors"
"fmt"
@@ -47,6 +48,19 @@ import (
"hakurei.app/cmd/mbf/internal/pkgserver/ui"
)
+// writeFileExcl is like [os.WriteFile], but sets [os.O_EXCL] instead.
+func writeFileExcl(name string, data []byte, perm os.FileMode) error {
+ f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
+ if err != nil {
+ return err
+ }
+ _, err = f.Write(data)
+ if err1 := f.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ return err
+}
+
func main() {
container.TryArgv0(nil)
@@ -187,6 +201,10 @@ func main() {
"d", command.StringFlag("$MBF_CACHE_DIR"),
"Directory to store cured artifacts",
).Flag(
+ &cm.mirror,
+ "r", command.StringFlag("$MBF_REMOTE"),
+ "URL of mirror service",
+ ).Flag(
&cm.idle,
"sched-idle", command.BoolFlag(false),
"Set SCHED_IDLE scheduling policy",
@@ -462,6 +480,70 @@ func main() {
},
)
+ c.NewCommand(
+ "keygen",
+ "Create keypair for local cache",
+ func([]string) error {
+ pub, priv, err := ed25519.GenerateKey(nil)
+ if err != nil {
+ return err
+ }
+
+ return errors.Join(writeFileExcl(filepath.Join(
+ cm.base,
+ "ed25519.pub",
+ ), pub, 0444), writeFileExcl(filepath.Join(
+ cm.base,
+ "ed25519",
+ ), priv, 0400))
+ },
+ )
+
+ c.NewCommand(
+ "serve",
+ "Export local cache as mirror",
+ func(args []string) error {
+ const shutdownTimeout = 15 * time.Second
+
+ if len(args) != 1 {
+ return errors.New("serve requires 1 argument")
+ }
+
+ var key ed25519.PrivateKey
+ if p, err := os.ReadFile(filepath.Join(cm.base, "ed25519")); err != nil {
+ return err
+ } else if len(p) != ed25519.PrivateKeySize {
+ return errors.New("invalid private key")
+ } else {
+ key = p
+ }
+
+ var h http.Handler
+ if base, err := os.OpenRoot(cm.base); err != nil {
+ return err
+ } else {
+ h = rosa.NewMirror(msg, base, key)
+ }
+
+ server := http.Server{Addr: args[0], Handler: h}
+ go func() {
+ <-ctx.Done()
+ cc, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
+ defer cancel()
+ if err := server.Shutdown(cc); err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ msg.Verbosef("listening on %q", args[0])
+ err := server.ListenAndServe()
+ if errors.Is(err, http.ErrServerClosed) {
+ err = nil
+ }
+ return err
+ },
+ )
+
{
var (
flagGentoo string