Only allow local folder uploads when SHOW_LOCAL=true
Local folder jobs are now refused with 403 unless the server runs with SHOW_LOCAL=true, and job kinds other than local or github are rejected. /api/health reports localFolders so the frontend can hide the option. Tests enable it explicitly where they index local folders.
This commit is contained in:
@@ -71,6 +71,7 @@ type Server struct {
|
|||||||
github githubApp
|
github githubApp
|
||||||
authMu sync.Mutex
|
authMu sync.Mutex
|
||||||
auth map[string]*githubAuth // by session ID
|
auth map[string]*githubAuth // by session ID
|
||||||
|
showLocal bool // SHOW_LOCAL=true allows uploading local folders
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -93,6 +94,7 @@ func NewServer(workspace string) *Server {
|
|||||||
indexSlots: make(chan struct{}, maxIndexing),
|
indexSlots: make(chan struct{}, maxIndexing),
|
||||||
github: githubAppFromEnv(),
|
github: githubAppFromEnv(),
|
||||||
auth: map[string]*githubAuth{},
|
auth: map[string]*githubAuth{},
|
||||||
|
showLocal: os.Getenv("SHOW_LOCAL") == "true",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +140,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
case r.Method == http.MethodOptions:
|
case r.Method == http.MethodOptions:
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
case path == "/api/health" && r.Method == http.MethodGet:
|
case path == "/api/health" && r.Method == http.MethodGet:
|
||||||
writeJSON(w, 200, map[string]any{"ok": true, "version": "0.1.0"})
|
writeJSON(w, 200, map[string]any{"ok": true, "version": "0.1.0", "localFolders": s.showLocal})
|
||||||
case path == "/api/jobs" && r.Method == http.MethodPost:
|
case path == "/api/jobs" && r.Method == http.MethodPost:
|
||||||
s.createJob(w, r)
|
s.createJob(w, r)
|
||||||
case strings.HasPrefix(path, "/api/jobs/"):
|
case strings.HasPrefix(path, "/api/jobs/"):
|
||||||
@@ -164,6 +166,14 @@ func (s *Server) createJob(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeError(w, 400, "Invalid job request")
|
writeError(w, 400, "Invalid job request")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
switch {
|
||||||
|
case request.Kind == "local" && !s.showLocal:
|
||||||
|
writeError(w, 403, "Local folders are disabled on this server")
|
||||||
|
return
|
||||||
|
case request.Kind != "local" && request.Kind != "github":
|
||||||
|
writeError(w, 400, "Invalid job request")
|
||||||
|
return
|
||||||
|
}
|
||||||
owner := sessionID(w, r)
|
owner := sessionID(w, r)
|
||||||
url := ""
|
url := ""
|
||||||
if request.Kind == "github" {
|
if request.Kind == "github" {
|
||||||
|
|||||||
+27
-1
@@ -107,6 +107,7 @@ func (c client) json(method, path, body string, wantStatus int, out any) {
|
|||||||
|
|
||||||
func newTestServer(t *testing.T) (*Server, client) {
|
func newTestServer(t *testing.T) (*Server, client) {
|
||||||
server := NewServer(filepath.Join(t.TempDir(), "codenavigator"))
|
server := NewServer(filepath.Join(t.TempDir(), "codenavigator"))
|
||||||
|
server.showLocal = true // most tests index local folders
|
||||||
ts := httptest.NewServer(server)
|
ts := httptest.NewServer(server)
|
||||||
t.Cleanup(ts.Close)
|
t.Cleanup(ts.Close)
|
||||||
return server, client{t, ts.URL, nil}.stranger()
|
return server, client{t, ts.URL, nil}.stranger()
|
||||||
@@ -240,7 +241,7 @@ func TestRoutesAndHeaders(t *testing.T) {
|
|||||||
t.Fatalf("preflight = %d %v", res.StatusCode, res.Header)
|
t.Fatalf("preflight = %d %v", res.StatusCode, res.Header)
|
||||||
}
|
}
|
||||||
|
|
||||||
for path, contentType := range map[string]string{"/": "text/html", "/api.mjs": "text/javascript", "/styles.css": "text/css", "/config.js": "text/javascript", "/inter-latin.woff2": "font/woff2"} {
|
for path, contentType := range map[string]string{"/": "text/html", "/api.mjs": "text/javascript", "/styles.css": "text/css", "/config.js": "text/javascript", "/fonts/archivo-black.woff2": "font/woff2"} {
|
||||||
res, err := http.Get(c.url + path)
|
res, err := http.Get(c.url + path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -434,3 +435,28 @@ func TestProgressStreamSendsKeepAlivesWhileQueued(t *testing.T) {
|
|||||||
t.Fatalf("stream ended without a snapshot: %+v", job)
|
t.Fatalf("stream ended without a snapshot: %+v", job)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocalFoldersDisabledByDefault(t *testing.T) {
|
||||||
|
t.Setenv("SHOW_LOCAL", "")
|
||||||
|
server := NewServer(filepath.Join(t.TempDir(), "codenavigator"))
|
||||||
|
ts := httptest.NewServer(server)
|
||||||
|
defer ts.Close()
|
||||||
|
c := client{t, ts.URL, nil}.stranger()
|
||||||
|
var health map[string]any
|
||||||
|
c.json("GET", "/api/health", "", 200, &health)
|
||||||
|
if health["localFolders"] != false {
|
||||||
|
t.Fatalf("health = %v", health)
|
||||||
|
}
|
||||||
|
c.json("POST", "/api/jobs", `{"kind":"local"}`, 403, nil)
|
||||||
|
c.json("POST", "/api/jobs", `{"kind":"mystery"}`, 400, nil)
|
||||||
|
|
||||||
|
t.Setenv("SHOW_LOCAL", "true")
|
||||||
|
enabled := httptest.NewServer(NewServer(filepath.Join(t.TempDir(), "codenavigator")))
|
||||||
|
defer enabled.Close()
|
||||||
|
on := client{t, enabled.URL, nil}.stranger()
|
||||||
|
on.json("GET", "/api/health", "", 200, &health)
|
||||||
|
if health["localFolders"] != true {
|
||||||
|
t.Fatalf("health with SHOW_LOCAL=true = %v", health)
|
||||||
|
}
|
||||||
|
on.json("POST", "/api/jobs", `{"kind":"local"}`, 201, nil)
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user