Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs-site/src/content/docs/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ Ensure your `$GOPATH/bin` (typically `~/go/bin`) is in your system `$PATH`.
If you have the repository cloned, you can use the provided `Makefile`:

```bash
make build
# This creates a 'scion' binary in the build directory.
# You can move it to a directory in your PATH:
sudo mv ./build/scion /usr/local/bin/
make all
# This builds the web frontend and installs the 'scion' binary
# to ~/.local/bin/ with the UI assets embedded.
# You can add ~/.local/bin/ to your PATH, or `mv` the binary to another directory in your PATH
```

Alternatively, if you don't need the web UI, you can use `make build` to only compile the CLI into `./build/scion` (the web UI will show a placeholder page).
Comment thread
Jberlinsky marked this conversation as resolved.
Outdated

To verify your installation, run:

```bash
Expand Down
15 changes: 13 additions & 2 deletions pkg/hub/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -870,9 +870,20 @@ func (ws *WebServer) prefetchPageData(r *http.Request) template.JS {
}

// hasWebAssets reports whether the server has web assets available to serve,
// either from an embedded FS or a filesystem directory.
// either from an embedded FS or a filesystem directory. It verifies the
// presence of the core entry point (assets/main.js) to ensure the UI is
// actually built and ready to serve.
func (ws *WebServer) hasWebAssets() bool {
return ws.assets != nil || ws.assetsDisk != ""
if ws.assetsDisk != "" {
p := filepath.Join(ws.assetsDisk, "assets", "main.js")
_, err := os.Stat(p)
return err == nil
}
if ws.assets != nil {
_, err := fs.Stat(ws.assets, "assets/main.js")
return err == nil
}
return false
}

// spaHandler returns the SPA shell HTML for any route not matched by other handlers.
Expand Down
19 changes: 17 additions & 2 deletions pkg/hub/web_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"time"

"github.com/GoogleCloudPlatform/scion/pkg/store"
"github.com/GoogleCloudPlatform/scion/web"
"github.com/gorilla/securecookie"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -40,6 +41,15 @@ type mockWebStore struct {

func newTestWebServer(t *testing.T, cfg WebServerConfig) *WebServer {
t.Helper()
// Ensure hasWebAssets() returns true for tests unless they explicitly want
// to test the "no assets" case.
if cfg.AssetsDir == "" && !web.AssetsEmbedded {
tmpDir := t.TempDir()
assetsDir := filepath.Join(tmpDir, "assets")
os.MkdirAll(assetsDir, 0755)
os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644)
Comment on lines +49 to +50

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Error handling is missing for these file operations. Using require.NoError ensures the test fails immediately with a clear message if the environment setup fails.

Suggested change
os.MkdirAll(assetsDir, 0755)
os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644)
require.NoError(t, os.MkdirAll(assetsDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644))

cfg.AssetsDir = tmpDir
}
return NewWebServer(cfg)
}

Expand All @@ -53,7 +63,7 @@ func newDevAuthWebServer(t *testing.T, overrides ...func(*WebServerConfig)) *Web
for _, fn := range overrides {
fn(&cfg)
}
return NewWebServer(cfg)
return newTestWebServer(t, cfg)
}

func TestSPAShellHandler(t *testing.T) {
Expand Down Expand Up @@ -286,8 +296,13 @@ func TestSPAHandler_NoAssets_APIStillWorks(t *testing.T) {
}

func TestSPAHandler_WithAssets_ServesNormalShell(t *testing.T) {
tmpDir := t.TempDir()
assetsDir := filepath.Join(tmpDir, "assets")
os.MkdirAll(assetsDir, 0755)
os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644)
Comment on lines +301 to +302

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Error handling is missing for these file operations. Using require.NoError ensures the test fails immediately with a clear message if the environment setup fails.

Suggested change
os.MkdirAll(assetsDir, 0755)
os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644)
require.NoError(t, os.MkdirAll(assetsDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(assetsDir, "main.js"), []byte("// test"), 0644))


ws := newDevAuthWebServer(t, func(cfg *WebServerConfig) {
cfg.AssetsDir = t.TempDir()
cfg.AssetsDir = tmpDir
})

req := httptest.NewRequest("GET", "/", nil)
Expand Down
10 changes: 10 additions & 0 deletions web/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,15 @@ import "embed"
//go:embed all:dist/client
var ClientAssets embed.FS

// sentinel forces a compile-time error if the web assets have not been built.
// If you see an error here, run 'make web' or build with '-tags no_embed_web'.
//
//go:embed dist/client/assets/main.js
var sentinel []byte

// AssetsEmbedded indicates whether client assets are embedded in the binary.
var AssetsEmbedded = true

func init() {
_ = sentinel // Mark as used
}