internal/httpd/control.go

e4fa4034379ae93e3cf6f1084ed577a7e02b530c
gitbay/internal/httpd/control.go history · blame · raw

75 lines · 2067 bytes

 1package httpd
 2
 3import (
 4	"bytes"
 5	"encoding/json"
 6	"strings"
 7
 8	"gitbay.org/gitbay/internal/control"
 9	"gitbay.org/gitbay/internal/protocol"
10	"gitbay.org/gitbay/internal/store"
11)
12
13// runControl executes a control command as the browser session's user,
14// through the same registry the CLI and the JSON API reach. Web writes
15// never reimplement command logic — merge gates, review rules, and audit
16// entries stay in one place — so the surfaces cannot drift apart.
17//
18// ViaAPI is set, which refuses SSHOnly commands: anything whose input is a
19// credential (secrets, mirror tokens, session minting) stays on SSH.
20func (s *Server) runControl(u store.User, argv []string) (out string, msg string, ok bool) {
21	var stdout, stderr bytes.Buffer
22	ctx := &control.Ctx{
23		User:   u,
24		Source: "web",
25		Scope:  "full",
26		Store:  s.st,
27		Cfg:    s.cfg,
28		Stdin:  strings.NewReader(""),
29		Stdout: &stdout,
30		Stderr: &stderr,
31		ViaAPI: true,
32	}
33	code := control.Dispatch(ctx, argv)
34	m := strings.TrimSpace(stderr.String())
35	if m == "" {
36		m = strings.TrimSpace(stdout.String())
37	}
38	return stdout.String(), m, code == protocol.ExitOK
39}
40
41// runControlJSON runs a command in JSON mode and returns its data object.
42// In JSON mode a failure is an envelope carrying the message rather than
43// stderr text, so both paths are read from the same envelope.
44func (s *Server) runControlJSON(u store.User, argv []string) (data map[string]any, msg string, ok bool) {
45	var stdout, stderr bytes.Buffer
46	ctx := &control.Ctx{
47		User:   u,
48		Source: "web",
49		Scope:  "full",
50		Store:  s.st,
51		Cfg:    s.cfg,
52		Stdin:  strings.NewReader(""),
53		Stdout: &stdout,
54		Stderr: &stderr,
55		JSON:   true,
56		ViaAPI: true,
57	}
58	code := control.Dispatch(ctx, argv)
59	var env struct {
60		Data  map[string]any `json:"data"`
61		Error string         `json:"error"`
62	}
63	json.Unmarshal(stdout.Bytes(), &env)
64	if code != protocol.ExitOK {
65		m := env.Error
66		if m == "" {
67			m = strings.TrimSpace(stderr.String())
68		}
69		if m == "" {
70			m = "the command failed"
71		}
72		return nil, m, false
73	}
74	return env.Data, "", true
75}