Finish audit remediation and prepare v0.6.0
This commit is contained in:
@@ -1441,6 +1441,29 @@ func TestPromptRepositoryReadFailureMapsToPromptLoad(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptDefinitionReadFailureMapsToPromptLoad(t *testing.T) {
|
||||
readErr := errors.New("definition read failed")
|
||||
source := &publicDefinitionReadFailureFS{
|
||||
FS: fstest.MapFS{
|
||||
"prompts/target.yaml": &fstest.MapFile{Data: []byte("unread")},
|
||||
},
|
||||
target: "prompts/target.yaml",
|
||||
err: readErr,
|
||||
}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{}, promptkit.WithPromptFS(source, "prompts"))
|
||||
if err != nil {
|
||||
t.Fatalf("construct engine: %v", err)
|
||||
}
|
||||
|
||||
inspection, err := engine.InspectPrompt(context.Background(), "target", "1")
|
||||
if inspection != nil || !errors.Is(err, promptkit.ErrPromptLoad) || !errors.Is(err, readErr) {
|
||||
t.Fatalf("InspectPrompt() = (%#v, %v), want nil with prompt-load and read-error identities", inspection, err)
|
||||
}
|
||||
if errors.Is(err, promptkit.ErrPromptNotFound) {
|
||||
t.Fatalf("definition read error was classified as absence: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectedProfileRepositoryReadFailureMapsToProfileLoad(t *testing.T) {
|
||||
missingProfileDir := filepath.Join(t.TempDir(), "missing-profiles")
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{
|
||||
@@ -2696,6 +2719,35 @@ func TestPreparePreservesValidationCancellationIdentity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareRejectsExcessivelyDeepStructuredOutputSchema(t *testing.T) {
|
||||
schema, err := json.Marshal(excessivelyDeepStructuredOutputSchema())
|
||||
if err != nil {
|
||||
t.Fatalf("marshal schema: %v", err)
|
||||
}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{},
|
||||
promptkit.WithPromptFS(publicStructuredPromptFS("schema.deep.prompt", "schema.json"), "prompts"),
|
||||
promptkit.WithSchemaFS(fstest.MapFS{
|
||||
"schemas/schema.json": &fstest.MapFile{Data: schema},
|
||||
}, "schemas"),
|
||||
promptkit.WithProfiles(promptkit.Profile{
|
||||
ID: "contract-fast", Endpoint: "http://example.test/v1", Model: "schema-model",
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("construct engine: %v", err)
|
||||
}
|
||||
|
||||
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
|
||||
PromptID: "schema.deep.prompt",
|
||||
Inputs: map[string]promptkit.ArtifactRef{
|
||||
"transcript": promptkit.Inline("Rin opens the gate."),
|
||||
},
|
||||
})
|
||||
if prepared != nil || !errors.Is(err, promptkit.ErrValidation) {
|
||||
t.Fatalf("Prepare() = (%#v, %v), want nil with ErrValidation", prepared, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreparedStructuredOutputRetainsExactSchemaNumbers(t *testing.T) {
|
||||
const schema = `{
|
||||
"type": "number",
|
||||
@@ -3124,6 +3176,15 @@ func excessivelyDeepJSONValue() any {
|
||||
return value
|
||||
}
|
||||
|
||||
func excessivelyDeepStructuredOutputSchema() any {
|
||||
const clearlyUnsafeSchemaNesting = 128
|
||||
schema := any(map[string]any{"type": "object"})
|
||||
for level := 0; level < clearlyUnsafeSchemaNesting; level++ {
|
||||
schema = map[string]any{"allOf": []any{schema}}
|
||||
}
|
||||
return schema
|
||||
}
|
||||
|
||||
func excessivelyLargeJSONValue() any {
|
||||
const clearlyUnsafeSharedOccurrences = 60_000
|
||||
shared := []any{true}
|
||||
@@ -3373,6 +3434,19 @@ type countingSchemaFS struct {
|
||||
reads map[string]int
|
||||
}
|
||||
|
||||
type publicDefinitionReadFailureFS struct {
|
||||
fs.FS
|
||||
target string
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *publicDefinitionReadFailureFS) Open(name string) (fs.File, error) {
|
||||
if name == f.target {
|
||||
return nil, f.err
|
||||
}
|
||||
return f.FS.Open(name)
|
||||
}
|
||||
|
||||
type cancelingPublicSchemaFS struct {
|
||||
fs.FS
|
||||
mu sync.Mutex
|
||||
|
||||
Reference in New Issue
Block a user