Harden manifest cache access
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

This commit is contained in:
Snider 2026-04-17 20:29:26 +01:00
parent 18437891e7
commit b2b28e1fe5
2 changed files with 81 additions and 3 deletions

View file

@ -50,12 +50,16 @@ type loadedManifest struct {
}
func (s *Service) loadManifestForOrigin(pageURL string) (*loadedManifest, error) {
s.manifestMu.Lock()
if s.manifestCache == nil {
s.manifestCache = make(map[string]*loadedManifest)
}
if cached, ok := s.manifestCache[pageURL]; ok {
s.manifestMu.Unlock()
return cached, nil
}
s.manifestMu.Unlock()
path, err := discoverManifestPath(pageURL)
if err != nil {
return nil, err
@ -81,7 +85,13 @@ func (s *Service) loadManifestForOrigin(pageURL string) (*loadedManifest, error)
BaseDir: manifestBaseDir(path),
Manifest: manifest,
}
s.manifestMu.Lock()
if s.manifestCache == nil {
s.manifestCache = make(map[string]*loadedManifest)
}
s.manifestCache[pageURL] = loaded
s.manifestMu.Unlock()
return loaded, nil
}
@ -183,13 +193,18 @@ func discoverManifestPath(pageURL string) (string, error) {
}
func (s *Service) manifestWindowConfig(pageURL string) map[string]ManifestWindow {
s.manifestMu.Lock()
defer s.manifestMu.Unlock()
loaded, err := s.loadManifestForOrigin(pageURL)
if err != nil || loaded == nil {
return nil
}
return loaded.Manifest.Windows
if len(loaded.Manifest.Windows) == 0 {
return nil
}
windows := make(map[string]ManifestWindow, len(loaded.Manifest.Windows))
for name, cfg := range loaded.Manifest.Windows {
windows[name] = cfg
}
return windows
}
func (s *Service) readManifestPreload(baseDir, preloadPath string) ([]byte, error) {

View file

@ -4,6 +4,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
@ -157,6 +158,30 @@ func TestManifest_ManifestWindowConfig_Ugly(t *testing.T) {
assert.Nil(t, got)
}
func TestManifest_ManifestWindowConfig_ReturnsCopy(t *testing.T) {
root := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(root, ".core"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(root, "index.html"), []byte("<html></html>"), 0o644))
require.NoError(t, os.WriteFile(filepath.Join(root, ".core", "view.yaml"), []byte(strings.Join([]string{
"windows:",
" main:",
" title: Core GUI",
" width: 1280",
" height: 720",
}, "\n")), 0o644))
svc, err := New()
require.NoError(t, err)
first := svc.manifestWindowConfig(filepath.Join(root, "index.html"))
require.NotNil(t, first)
first["main"] = ManifestWindow{Title: "mutated"}
second := svc.manifestWindowConfig(filepath.Join(root, "index.html"))
require.NotNil(t, second)
assert.Equal(t, "Core GUI", second["main"].Title)
}
func TestManifest_LoadManifestForOrigin_RejectsOversizedFile(t *testing.T) {
root := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(root, ".core"), 0o755))
@ -171,6 +196,44 @@ func TestManifest_LoadManifestForOrigin_RejectsOversizedFile(t *testing.T) {
assert.Contains(t, err.Error(), "exceeds")
}
func TestManifest_LoadManifestForOrigin_Concurrent(t *testing.T) {
root := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(root, ".core"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(root, "index.html"), []byte("<html></html>"), 0o644))
require.NoError(t, os.WriteFile(filepath.Join(root, ".core", "view.yaml"), []byte(strings.Join([]string{
"name: demo",
"windows:",
" main:",
" title: Core GUI",
}, "\n")), 0o644))
svc, err := New()
require.NoError(t, err)
var wg sync.WaitGroup
errs := make(chan error, 16)
for i := 0; i < 16; i++ {
wg.Add(1)
go func() {
defer wg.Done()
loaded, loadErr := svc.loadManifestForOrigin(filepath.Join(root, "index.html"))
if loadErr != nil {
errs <- loadErr
return
}
if loaded == nil || loaded.Manifest.Name != "demo" {
errs <- assert.AnError
}
}()
}
wg.Wait()
close(errs)
for err := range errs {
require.NoError(t, err)
}
}
func TestManifest_ManifestBaseDir_Good(t *testing.T) {
assert.Equal(t, "/tmp/app", manifestBaseDir("/tmp/app/.core/view.yaml"))
assert.Equal(t, "/tmp/app/assets", manifestBaseDir("/tmp/app/assets/view.yaml"))