chore: merge dev (take our security fix for conflicts)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-03 00:09:59 +00:00
commit 5cbbe48fdd
2 changed files with 15 additions and 26 deletions

View file

@ -9,7 +9,6 @@ package dev
import ( import (
"context" "context"
"os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@ -62,25 +61,14 @@ func runFileSync(source string) error {
return log.E("dev.sync", "path traversal not allowed", nil) return log.E("dev.sync", "path traversal not allowed", nil)
} }
// Validate source exists // Convert to absolute path for io.Local
sourceInfo, err := os.Stat(source) // Keep os.Stat for local source check or use coreio? coreio.Local.IsFile is bool. absSource, err := filepath.Abs(source)
// If source is local file on disk (not in medium), we can use os.Stat. if err != nil {
// But concept is everything is via Medium? return log.E("dev.sync", "failed to resolve source path", err)
// User is running CLI on host. `source` is relative to CWD.
// coreio.Local uses absolute path or relative to root (which is "/" by default).
// So coreio.Local works.
if !coreio.Local.IsFile(source) {
// Might be directory
// IsFile returns false for directory.
} }
// Let's rely on os.Stat for initial source check to distinguish dir vs file easily if coreio doesn't expose Stat.
// coreio doesn't expose Stat.
// Check using standard os for source determination as we are outside strict sandbox for input args potentially?
// But we should use coreio where possible.
// coreio.Local.List worked for dirs.
// Let's stick to os.Stat for source properties finding as typically allowed for CLI args.
// Validate source exists using io.Local.Stat
sourceInfo, err := coreio.Local.Stat(absSource)
if err != nil { if err != nil {
return log.E("dev.sync", i18n.T("cmd.dev.file_sync.error.source_not_found", map[string]interface{}{"Path": source}), err) return log.E("dev.sync", i18n.T("cmd.dev.file_sync.error.source_not_found", map[string]interface{}{"Path": source}), err)
} }

View file

@ -1,28 +1,29 @@
package dev package dev
import ( import (
"os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/host-uk/core/pkg/io"
) )
func TestFindWorkflows_Good(t *testing.T) { func TestFindWorkflows_Good(t *testing.T) {
// Create a temp directory with workflow files // Create a temp directory with workflow files
tmpDir := t.TempDir() tmpDir := t.TempDir()
workflowsDir := filepath.Join(tmpDir, ".github", "workflows") workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
if err := os.MkdirAll(workflowsDir, 0755); err != nil { if err := io.Local.EnsureDir(workflowsDir); err != nil {
t.Fatalf("Failed to create workflows dir: %v", err) t.Fatalf("Failed to create workflows dir: %v", err)
} }
// Create some workflow files // Create some workflow files
for _, name := range []string{"qa.yml", "tests.yml", "codeql.yaml"} { for _, name := range []string{"qa.yml", "tests.yml", "codeql.yaml"} {
if err := os.WriteFile(filepath.Join(workflowsDir, name), []byte("name: Test"), 0644); err != nil { if err := io.Local.Write(filepath.Join(workflowsDir, name), "name: Test"); err != nil {
t.Fatalf("Failed to create workflow file: %v", err) t.Fatalf("Failed to create workflow file: %v", err)
} }
} }
// Create a non-workflow file (should be ignored) // Create a non-workflow file (should be ignored)
if err := os.WriteFile(filepath.Join(workflowsDir, "readme.md"), []byte("# Workflows"), 0644); err != nil { if err := io.Local.Write(filepath.Join(workflowsDir, "readme.md"), "# Workflows"); err != nil {
t.Fatalf("Failed to create readme file: %v", err) t.Fatalf("Failed to create readme file: %v", err)
} }
@ -57,12 +58,12 @@ func TestFindWorkflows_NoWorkflowsDir(t *testing.T) {
func TestFindTemplateWorkflow_Good(t *testing.T) { func TestFindTemplateWorkflow_Good(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
templatesDir := filepath.Join(tmpDir, ".github", "workflow-templates") templatesDir := filepath.Join(tmpDir, ".github", "workflow-templates")
if err := os.MkdirAll(templatesDir, 0755); err != nil { if err := io.Local.EnsureDir(templatesDir); err != nil {
t.Fatalf("Failed to create templates dir: %v", err) t.Fatalf("Failed to create templates dir: %v", err)
} }
templateContent := "name: QA\non: [push]" templateContent := "name: QA\non: [push]"
if err := os.WriteFile(filepath.Join(templatesDir, "qa.yml"), []byte(templateContent), 0644); err != nil { if err := io.Local.Write(filepath.Join(templatesDir, "qa.yml"), templateContent); err != nil {
t.Fatalf("Failed to create template file: %v", err) t.Fatalf("Failed to create template file: %v", err)
} }
@ -82,12 +83,12 @@ func TestFindTemplateWorkflow_Good(t *testing.T) {
func TestFindTemplateWorkflow_FallbackToWorkflows(t *testing.T) { func TestFindTemplateWorkflow_FallbackToWorkflows(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
workflowsDir := filepath.Join(tmpDir, ".github", "workflows") workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
if err := os.MkdirAll(workflowsDir, 0755); err != nil { if err := io.Local.EnsureDir(workflowsDir); err != nil {
t.Fatalf("Failed to create workflows dir: %v", err) t.Fatalf("Failed to create workflows dir: %v", err)
} }
templateContent := "name: Tests\non: [push]" templateContent := "name: Tests\non: [push]"
if err := os.WriteFile(filepath.Join(workflowsDir, "tests.yml"), []byte(templateContent), 0644); err != nil { if err := io.Local.Write(filepath.Join(workflowsDir, "tests.yml"), templateContent); err != nil {
t.Fatalf("Failed to create workflow file: %v", err) t.Fatalf("Failed to create workflow file: %v", err)
} }