Conversation
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
araujof
left a comment
There was a problem hiding this comment.
Nice work! This will be a great improvement to code base stability.
A few things we should address before merging:
-
src/smith/test_generation/convert_test_case.py:16: ReturningNonedoes not omit the field;_fill_templatewrites it as JSONnull. OPA treatsnulldifferently from a missing field, so generated cases can test the wrong policy outcome. Skip null-valued fields when filling the template. -
src/smith/test_generation/generate_promptfoo_config.py:249: The duplicate-block fix only recognizes the new marker. Existing configs have unmarked generated blocks, so the next run keeps those blocks and appends another. The old block also remains when the current tool list is empty. Remove legacy blocks and strip generated instructions before checking the current tool list. -
src/smith/test_generation/variable_extraction.py:73: Using a local filtered copy stops the mutation, but later stages now receiveaction_listandaction_description.case_generationincludes them in the system-variable prompt, allowing internal metadata to leak into generated test subjects. Pass a filtered copy to later stages too. -
Makefile:188: The new unit suite is added tomake ci, but the GitHub workflow never runsmake ciormake unit. PR checks therefore pass without running the 356 new tests. Add a unit-test job to.github/workflows/ci.yml.
|
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Should we also remove the job the CI workflow? smith/.github/workflows/ci.yml Lines 53 to 68 in 13b6c16 |
Signed-off-by: Hailun Ding <hailun.ding@ibm.com>
Summary
A cleanup and bug-fix pass over the test-generation pipeline, and test scripts creation, plus the unit and integration test suites.
Closes
#12 #46 #49
Changes
1. args-migration.
argumentsindocs/policy_creation.md,docs/test_generation.md,policy_cross_validation.md,README.md, and the two docs guides toargsfor cpex compatibility. (problems left in last PR)2. agent's default value changes in promptfoo config.
3. made adjusts to cpex hr-agent example
4. delete usage of top-k
5. null values handling in
convert_test_case.py._convert_varinsrc/smith/test_generation/convert_test_case.pycalledint(None) / float(None)when a generated case supplied null for a numeric system variable, raisingTypeError. Most often triggered by adversarial Promptfoo cases that omit an integer field (e.g. queries_this_session). Now returnsNone, leaving the field absent so OPA treats it as unset.6. remove any previously-appended tool-parameter block in promptfoo config generation (problems left in last PR)
generate_promptfoo_config.pyre-appended the tool-parameter block on every run, so the prompt grew each update. Added a sentinel marker and a strip step so the block is replaced instead of duplicated.Problem identified when writing unit and integration tests.
7. Missing env setup values
.env_templateomitted. Added variables:TEST_OUTPUT_DIR,TEST_PATH,MCP_URL,TOP_P,MAX_LLM_CALLS.8. Two modules read the environment themselves
attack.pyandattack_promptfoo.pycalledload_dotenv()/os.getenvinside the function the CLI invokes. Both now take the value as a parameter, resolved incli.pywith every other path. Three functions gained required parameters;cli.pyis their only caller.9. AST graph indices inherited across calls
init_graphnow clears them first.10.
convert_test_coverage.pyran its whole pipeline at importpolicy_testingunit lane. Environment resolution and I/O moved intomain(); the transformation logic extracted into importable functions. Output byte-identical, so the frozen coverage numbers still hold.11.
apply_cross_validatecrashed when the destination didn't existshutil.movedoesn't create directories, so promoting a case into an absentallow/raisedFileNotFoundErrormid-loop, leaving the tree partially applied. Addedos.makedirs(..., exist_ok=True)before each move.12. Whitespace-only lines now dropped in
decompose.pyremove_empty_linetestedlen(strr) != 0, so a line of spaces survived and became a rule, spending an LLM call to produce a meaningless record. Now judged with.strip(); line content untouched.13. Discarded exit code hid Regal failures
subprocess.runran withoutcheck=Trueand its result was thrown away, and the shell pipeline reportedsed's status anyway. So a missingregalbinary produced an empty report and a successful flag: the same answer as a clean policy. Regal is now invoked directly and its exit code classified (0clean,3violations, anything else a failure).check=Truewould have been wrong — it raises on3, the normal result. Output byte-identical wherever Regal actually runs.Tests
make unitmake integration