Exposes the scenario engine (platform.System.RunScenario, added earlier) in the web UI instead of only the `bee run` CLI: a new nav item lists every scenarios/*.json found on mounted removable media (GET /api/scenario/list) and runs one with a click (POST /api/scenario/run), enqueued as a normal Task with target "scenario" — progress/logs live in Tasks like any other SAT pack, no separate live-output UI needed. - app.go: satRunner gains RunScenario, exportManager gains ListScenarioFilesOnRemovableMedia/ReadScenarioFromRemovableMedia — both already implemented on platform.System, just newly exposed through App. - webui/tasks.go: taskParams.ScenarioName; runTask's "scenario" case reads the file from removable media, parses it, and runs it. - webui/page_scenario.go: the page itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
91 lines
2.9 KiB
Go
91 lines
2.9 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"bee/audit/internal/platform"
|
|
)
|
|
|
|
func (a *App) ListRemovableTargets() ([]platform.RemovableTarget, error) {
|
|
return a.exports.ListRemovableTargets()
|
|
}
|
|
|
|
// ListScenarioFilesOnRemovableMedia lists scenarios/*.json found on any
|
|
// mounted removable target (e.g. the blackbox USB stick) — see
|
|
// platform.System.ListScenarioFilesOnRemovableMedia.
|
|
func (a *App) ListScenarioFilesOnRemovableMedia() ([]platform.ScenarioFileOnRemovableMedia, error) {
|
|
return a.exports.ListScenarioFilesOnRemovableMedia()
|
|
}
|
|
|
|
// ReadScenarioFromRemovableMedia reads scenarios/<name>.json from whichever
|
|
// mounted removable target has it — see
|
|
// platform.System.ReadScenarioFromRemovableMedia.
|
|
func (a *App) ReadScenarioFromRemovableMedia(name string) ([]byte, error) {
|
|
return a.exports.ReadScenarioFromRemovableMedia(name)
|
|
}
|
|
|
|
func (a *App) ExportLatestAudit(target platform.RemovableTarget) (string, error) {
|
|
if _, err := os.Stat(DefaultAuditJSONPath); err != nil {
|
|
return "", err
|
|
}
|
|
filename := fmt.Sprintf("audit-%s-%s.json", sanitizeFilename(hostnameOr("unknown")), time.Now().UTC().Format("20060102-150405"))
|
|
tmpPath := filepath.Join(os.TempDir(), filename)
|
|
data, err := readFileLimited(DefaultAuditJSONPath, 100<<20)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if normalized, normErr := ApplySATOverlay(data); normErr == nil {
|
|
data = normalized
|
|
}
|
|
if err := os.WriteFile(tmpPath, data, 0644); err != nil {
|
|
return "", err
|
|
}
|
|
defer os.Remove(tmpPath)
|
|
return a.exports.ExportFileToTarget(tmpPath, target)
|
|
}
|
|
|
|
func (a *App) ExportLatestAuditResult(target platform.RemovableTarget) (ActionResult, error) {
|
|
path, err := a.ExportLatestAudit(target)
|
|
body := "Audit export failed."
|
|
if err == nil {
|
|
body = "Audit exported."
|
|
}
|
|
if err == nil && path != "" {
|
|
body = "Audit exported to " + path
|
|
}
|
|
return ActionResult{Title: "Export audit", Body: body}, err
|
|
}
|
|
|
|
func (a *App) ExportSupportBundle(target platform.RemovableTarget) (string, error) {
|
|
archive, err := BuildSupportBundle(DefaultExportDir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer os.Remove(archive)
|
|
return a.exports.ExportFileToTarget(archive, target)
|
|
}
|
|
|
|
func (a *App) ExportSupportBundleResult(target platform.RemovableTarget) (ActionResult, error) {
|
|
path, err := a.ExportSupportBundle(target)
|
|
body := "Support bundle export failed."
|
|
if err == nil {
|
|
body = "Support bundle exported. USB target unmounted and safe to remove."
|
|
}
|
|
if err == nil && path != "" {
|
|
body = "Support bundle exported to " + path + ".\n\nUSB target unmounted and safe to remove."
|
|
}
|
|
return ActionResult{Title: "Export support bundle", Body: body}, err
|
|
}
|
|
|
|
func (a *App) ListInstallDisks() ([]platform.InstallDisk, error) {
|
|
return a.installer.ListInstallDisks()
|
|
}
|
|
|
|
func (a *App) InstallToDisk(ctx context.Context, device string, logFile string) error {
|
|
return a.installer.InstallToDisk(ctx, device, logFile)
|
|
}
|