Skip to content

Commit 9f7cd15

Browse files
authored
Fix framework load precedence and gosec path warning (#10)
1 parent 7ec1233 commit 9f7cd15

File tree

2 files changed

+70
-8
lines changed

2 files changed

+70
-8
lines changed

core/framework/framework.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,39 @@ func List() ([]Info, error) {
6767
}
6868

6969
func Load(idOrFile string) (*Framework, error) {
70-
if info, err := os.Stat(idOrFile); err == nil {
70+
if isLikelyPath(idOrFile) {
71+
info, err := os.Stat(idOrFile)
72+
if err != nil {
73+
return nil, fmt.Errorf("load framework file %s: %w", idOrFile, err)
74+
}
7175
if info.IsDir() {
72-
if isLikelyPath(idOrFile) {
73-
return nil, fmt.Errorf("load framework file %s: path is a directory", idOrFile)
74-
}
75-
} else {
76-
return LoadFile(idOrFile)
76+
return nil, fmt.Errorf("load framework file %s: path is a directory", idOrFile)
7777
}
78-
} else if isLikelyPath(idOrFile) {
78+
return LoadFile(idOrFile)
79+
}
80+
81+
embedded, embeddedErr := loadEmbedded(idOrFile)
82+
if embeddedErr == nil {
83+
return embedded, nil
84+
}
85+
86+
info, err := os.Stat(idOrFile)
87+
if err == nil {
88+
if info.IsDir() {
89+
return nil, fmt.Errorf("load framework file %s: path is a directory", idOrFile)
90+
}
91+
return LoadFile(idOrFile)
92+
}
93+
if !os.IsNotExist(err) {
7994
return nil, fmt.Errorf("load framework file %s: %w", idOrFile, err)
8095
}
96+
return nil, embeddedErr
97+
}
8198

99+
func loadEmbedded(idOrFile string) (*Framework, error) {
82100
name := idOrFile
83101
if !strings.HasSuffix(name, ".yaml") {
84-
name = name + ".yaml"
102+
name += ".yaml"
85103
}
86104
raw, err := frameworkFS.ReadFile(name)
87105
if err != nil {
@@ -91,6 +109,7 @@ func Load(idOrFile string) (*Framework, error) {
91109
}
92110

93111
func LoadFile(path string) (*Framework, error) {
112+
// #nosec G304 -- path is intentionally caller-provided for runtime custom framework loading.
94113
raw, err := os.ReadFile(path)
95114
if err != nil {
96115
return nil, fmt.Errorf("load framework file %s: %w", path, err)

core/framework/framework_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,49 @@ func TestLoadMissingFilesystemPath(t *testing.T) {
5757
require.ErrorContains(t, err, "load framework file")
5858
}
5959

60+
func TestLoadPrefersEmbeddedOverLocalCollision(t *testing.T) {
61+
dir := t.TempDir()
62+
t.Chdir(dir)
63+
require.NoError(t, os.WriteFile("eu-ai-act.yaml", []byte("not: valid: yaml: ["), 0o644))
64+
65+
f, err := Load("eu-ai-act.yaml")
66+
require.NoError(t, err)
67+
require.Equal(t, "eu-ai-act", f.Framework.ID)
68+
require.Equal(t, "2024-final", f.Framework.Version)
69+
70+
list, err := List()
71+
require.NoError(t, err)
72+
var found bool
73+
for _, info := range list {
74+
if info.ID == "eu-ai-act" {
75+
found = true
76+
require.Equal(t, 3, info.ControlCount)
77+
}
78+
}
79+
require.True(t, found)
80+
}
81+
82+
func TestLoadFilenameFallbackForCustomFramework(t *testing.T) {
83+
dir := t.TempDir()
84+
t.Chdir(dir)
85+
require.NoError(t, os.WriteFile("custom-framework.yaml", []byte(`
86+
framework:
87+
id: custom-framework
88+
version: "1"
89+
title: Custom Framework
90+
controls:
91+
- id: custom-control
92+
title: Custom Control
93+
required_record_types: [decision]
94+
required_fields: [record_id]
95+
minimum_frequency: continuous
96+
`), 0o644))
97+
98+
f, err := Load("custom-framework.yaml")
99+
require.NoError(t, err)
100+
require.Equal(t, "custom-framework", f.Framework.ID)
101+
}
102+
60103
func TestValidateControls(t *testing.T) {
61104
valid := []Control{
62105
{

0 commit comments

Comments
 (0)