eleven / ocho Public

server: stage forces the version dir 0755; uploadBlob logs store errors (#1050)

Two robustness fixes surfaced while verifying the blob mirror on a canary:

- stageVersion's MkdirAll mode is umask-masked, so a hardened operator shell
  (umask 077) left /opt/lchat/versions/<ver> at 0700 — the sandboxed instance
  user then couldn't traverse in to exec its binary (systemd 203/EXEC
  'Permission denied'), and only root could clean it up. Force 0755
  explicitly, exactly as copyFileAtomic already forces the binary's +x.
- uploadBlob answered a bare 500 on any store create/commit error, which made
  a misconfigured object store an opaque failure (cost real debugging time on
  the canary). Log the underlying error; the member-facing message stays
  generic.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell f5365cb87eba565d6491cfe6d71230f19e6aa622 parent 94c7a0c
2 files changed, +12 −1
  • main.go +2 −0
  • versions.go +10 −1
diff --git a/main.go b/main.go
index 46def25..c69f4fd 100644
--- a/main.go
+++ b/main.go
@@ -2925,6 +2925,7 @@ func (s *Server) uploadBlob(w http.ResponseWriter, r *http.Request) {
// integrity anchor the blob mirror/audit sweeps verify against (#992).
blob, err := s.db.blobs.create()
if err != nil {
+ log.Printf("upload: blob create: %v", err)
httpError(w, http.StatusInternalServerError, "storage error")
return
}
@@ -2948,6 +2949,7 @@ func (s *Server) uploadBlob(w http.ResponseWriter, r *http.Request) {
return
}
if err := blob.commit(id); err != nil {
+ log.Printf("upload: blob commit %s: %v", id, err)
httpError(w, http.StatusInternalServerError, "storage error")
return
}
diff --git a/versions.go b/versions.go
index 001799e..ec3c655 100644
--- a/versions.go
+++ b/versions.go
@@ -114,7 +114,16 @@ func stageVersion(srcPath, ver string) error {
if !validVersion(ver) {
return fmt.Errorf("invalid version %q (allowed: letters, digits, . _ -)", ver)
}
- if err := os.MkdirAll(filepath.Join(versionsDir(), ver), 0o755); err != nil {
+ dir := filepath.Join(versionsDir(), ver)
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ return err
+ }
+ // MkdirAll's mode is masked by the caller's umask, so a tight operator
+ // umask (e.g. 077 from a hardened shell) leaves the version dir 0700 —
+ // the sandboxed instance user then can't traverse in to exec its binary
+ // (203/EXEC "Permission denied", found staging a canary). Force it, like
+ // copyFileAtomic already forces the binary's +x.
+ if err := os.Chmod(dir, 0o755); err != nil {
return err
}
return copyFileAtomic(srcPath, versionBinPath(ver), 0o755)