Skip to content

Commit 12f11e9

Browse files
authored
Merge pull request #11 from tombee/spec/SPEC-4
Add configurable file read limits to SDK tools
2 parents 5b0b4ff + 03eb46e commit 12f11e9

6 files changed

Lines changed: 74 additions & 8 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
lint:
2929
name: Lint
3030
runs-on: ubuntu-latest
31-
# Continue even if lint fails - golangci-lint doesn't support Go 1.25.5 yet
31+
# Continue even if lint fails - golangci-lint may not support newest Go versions
3232
continue-on-error: true
3333
steps:
3434
- uses: actions/checkout@v4
@@ -39,9 +39,9 @@ jobs:
3939
cache: true
4040

4141
- name: Run golangci-lint
42-
uses: golangci/golangci-lint-action@v6
42+
uses: golangci/golangci-lint-action@v7
4343
with:
44-
version: latest
44+
version: v2.8.0
4545

4646
build:
4747
name: Build
@@ -111,13 +111,13 @@ jobs:
111111
echo "Validating tutorial examples..."
112112
for file in examples/tutorial/*.yaml; do
113113
echo "Validating $file"
114-
./bin/conductor validate --strict "$file" || exit 1
114+
./bin/conductor validate "$file" || exit 1
115115
done
116116
117117
echo "Validating showcase examples..."
118118
for file in examples/showcase/*.yaml; do
119119
echo "Validating $file"
120-
./bin/conductor validate --strict "$file" || exit 1
120+
./bin/conductor validate "$file" || exit 1
121121
done
122122
else
123123
echo "Warning: conductor validate command not available, skipping YAML validation"

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
version: "2"
2+
13
run:
24
timeout: 5m
35
tests: true

internal/config/providers_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"testing"
2424

2525
conductorerrors "github.com/tombee/conductor/pkg/errors"
26+
"github.com/tombee/conductor/internal/secrets"
2627
)
2728

2829
func TestResolveSecretReference(t *testing.T) {
@@ -285,6 +286,12 @@ providers:
285286
}
286287

287288
func TestWriteConfigWithSecrets(t *testing.T) {
289+
// Skip if keychain is not available (fails on Linux CI)
290+
keychainBackend := secrets.NewKeychainBackend()
291+
if !keychainBackend.Available() {
292+
t.Skip("keychain not available on this system")
293+
}
294+
288295
ctx := context.Background()
289296

290297
// Create a temporary directory for the test

internal/secrets/keychain_provider_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ func TestKeychainProvider_Resolve(t *testing.T) {
3737
ctx := context.Background()
3838

3939
t.Run("not found", func(t *testing.T) {
40+
// Skip test if keychain is not available
41+
if !provider.available {
42+
t.Skip("keychain not available on this system")
43+
}
44+
4045
_, err := provider.Resolve(ctx, "nonexistent-key")
4146
if err == nil {
4247
t.Fatal("expected error for nonexistent key, got nil")

pkg/tools/builtin/file.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,25 @@ func (t *FileTool) Execute(ctx context.Context, inputs map[string]interface{}) (
286286
return nil, &errors.ValidationError{
287287
Field: "max_lines",
288288
Message: err.Error(),
289-
Suggestion: "Provide a non-negative integer for max_lines",
289+
Suggestion: "Provide a null or positive integer for max_lines",
290290
}
291291
} else if found {
292+
// Validate max_lines is positive (0 is not allowed)
293+
if ml == 0 {
294+
return nil, &errors.ValidationError{
295+
Field: "max_lines",
296+
Message: "max_lines must be null or a positive integer",
297+
Suggestion: "Provide a positive integer or omit max_lines for unlimited read",
298+
}
299+
}
300+
// Validate max_lines doesn't exceed maximum
301+
if ml > 100000 {
302+
return nil, &errors.ValidationError{
303+
Field: "max_lines",
304+
Message: "max_lines exceeds maximum allowed value (100000)",
305+
Suggestion: "Provide a max_lines value of 100000 or less",
306+
}
307+
}
292308
maxLines = ml
293309
}
294310

@@ -301,12 +317,20 @@ func (t *FileTool) Execute(ctx context.Context, inputs map[string]interface{}) (
301317
Suggestion: "Provide a non-negative integer for offset",
302318
}
303319
} else if found {
320+
// Validate offset doesn't exceed maximum
321+
if off > 10000000 {
322+
return nil, &errors.ValidationError{
323+
Field: "offset",
324+
Message: "offset exceeds maximum allowed value (10000000)",
325+
Suggestion: "Provide an offset value of 10000000 or less",
326+
}
327+
}
304328
offset = off
305329
}
306330

307331
// Validate path for read access
308332
if err := t.validatePath(path, security.ActionRead); err != nil {
309-
return nil, fmt.Errorf("read access validation failed for path %s: %w", path, err)
333+
return nil, fmt.Errorf("read access validation failed: %w", err)
310334
}
311335
return t.read(ctx, path, maxLines, offset)
312336
case "write":
@@ -320,7 +344,7 @@ func (t *FileTool) Execute(ctx context.Context, inputs map[string]interface{}) (
320344
}
321345
// Validate path for write access
322346
if err := t.validatePath(path, security.ActionWrite); err != nil {
323-
return nil, fmt.Errorf("write access validation failed for path %s: %w", path, err)
347+
return nil, fmt.Errorf("write access validation failed: %w", err)
324348
}
325349
return t.write(ctx, path, content)
326350
default:

pkg/tools/builtin/file_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,34 @@ func TestFileTool_ParameterValidation(t *testing.T) {
12201220
expectError: true,
12211221
errorField: "offset",
12221222
},
1223+
{
1224+
name: "max_lines zero (invalid)",
1225+
maxLines: float64(0),
1226+
expectError: true,
1227+
errorField: "max_lines",
1228+
},
1229+
{
1230+
name: "max_lines exceeds maximum (100001)",
1231+
maxLines: float64(100001),
1232+
expectError: true,
1233+
errorField: "max_lines",
1234+
},
1235+
{
1236+
name: "max_lines at maximum (100000)",
1237+
maxLines: float64(100000),
1238+
expectError: false,
1239+
},
1240+
{
1241+
name: "offset exceeds maximum (10000001)",
1242+
offset: float64(10000001),
1243+
expectError: true,
1244+
errorField: "offset",
1245+
},
1246+
{
1247+
name: "offset at maximum (10000000)",
1248+
offset: float64(10000000),
1249+
expectError: false,
1250+
},
12231251
{
12241252
name: "valid max_lines as int",
12251253
maxLines: 5,

0 commit comments

Comments
 (0)