Skip to content

fix: track file-backed default tests - #982

Closed
mldangelo-oai wants to merge 81 commits into
mainfrom
mdangelo/codex/sec-file-backed-default-test
Closed

fix: track file-backed default tests#982
mldangelo-oai wants to merge 81 commits into
mainfrom
mdangelo/codex/sec-file-backed-default-test

Conversation

@mldangelo-oai

@mldangelo-oai mldangelo-oai commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Codex Security finding csf_e8e50025fd2fff98d4dfaecc (occ_ae71e8315ee711bbd56a6b8c).

Promptfoo accepts defaultTest inline or through file://, and can recursively consume provider configs, schemas/tools, assertions, and external vars. The action previously missed several of those backing files and could incorrectly skip an evaluation when only a dependency changed.

This patch:

  • tracks file-backed and inline default tests plus scalar/list/glob/generator/CSV/XLS/XLSX tests and runtime-valid external scenario files, both top-level providers/targets, per-test providers/options/scoring, nested/assert-set providers, ProviderOptionsMap keys, exec and language providers/prompts, HTTP auth/credential/TLS/multipart/signature files, assertion config, response formats, schemas, tools, vars maps/generators/spreadsheets, runtime-valid selectors, and changed/deleted glob or directory matches;
  • keeps traversal bounded and repository-contained with capped pre-enumeration brace validation, a linear numeric-range preflight (signed, stepped, nested-product, padded, character-class, mutually-exclusive-arm, and backslash-parity cases), balanced glob delimiters, 64-KiB/NUL-safe glob and template handling with distinct constant NUL/delimiter diagnostics, a once-compiled POSIX-stable repository matcher, nearest-ancestor lstat/realpath checks, context-aware cycle guards across normal tests and scalar/array scenario imports, bounded nested structured-file reads, per-match symlink containment with lazily cached workspace/working roots, atomic binary handling, YAML/JSON-only transitive inspection, JSON-escaped and one-time unsafe-path warnings, safe legacy YAML tags, conservative root watchers for dynamic paths, parse/read failures, and every glob detection/expansion/enumeration failure, and directory-prefix fallback when glob detection rejects an unusual valid path;
  • preserves lossless GitHub/git/manual filenames and renamed-away dependencies (previous_filename, --no-renames -z, trimWhitespace: false), treats the workspace-root dependency as the ./ full-eval sentinel, validates explicit prompt glob/match containment, canonically deduplicates overlapping absolute/relative prompt globs and emits repository-relative matches, preserves runtime-valid literal Ruby/Go vars colon filenames, anchors structured-prompt extension detection while retaining JSON/YAML glob inspection, scopes the CR/LF prompt guard to selected evaluation prompts before workflow-command sinks, avoids narrowing evaluation when a shared config/dependency changes with a prompt, and accurately and safely labels config/dependency/full-scan PR comments, workflow summaries, and manual logs;
  • applies the exact-source trusted GitHub Check dist bundle from artifact 8354967307 in run 29444790386, built for source 9df84aa77a86b6056719ff35fcc3ba7066702dd5 and committed at final head 3db0f7688d349d33b73a66742b7f6f08ac2a8f8e.

Verification

  • failing-first regressions cover every review finding plus runtime-backed provider/auth/config, selector, template, vars-generator, spreadsheet-sheet, binary, root-glob, structured-prompt, and external test/scenario cases;
  • Promptfoo 0.121.17 runtime fixtures confirm nested provider, response-format/schema, tools, vars, literal Ruby/Go colon filenames, unmatched-bracket literals, and scalar-vs-array scenario base behavior;
  • focused config/main suites: 431/431 passing;
  • full local suite: 537/537 passing with 100% statement/branch/function/line coverage (1,435 statements, 1,270 branches, 113 functions, 1,359 lines); the 2 MB decoded-binary regression remained under 81 MB RSS;
  • compiled runtime probes reject billion-entry/class/padded/parity ranges before expansion, preserve escaped and literal-dollar braces plus exactly 1,024 mutually-exclusive expansions, and match 2,999 changed files with a single compiled dependency glob in 63 ms; a 512-prompt call-count regression confirms containment roots are resolved once, and an independent 30,000-pattern differential check found zero false positives or negatives;
  • build and Biome checks pass; trusted CI artifact hashes and source-map parity were verified before the final bundle commit.

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact head c4ff31444296d0c7d7f80fe9754399da55d98474, focusing on whether the supported file-backed defaultTest form always enters dependency change detection, unsupported strings and repository escapes remain safe, inline default variable/assertion behavior is preserved, and the committed dist/ bundle matches source and current-main packaging.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a dependency-tracking gap in the GitHub Action by ensuring defaultTest dependencies are detected when defaultTest is specified as a file://... reference (not just an inline object), preventing relevant PRs from being incorrectly skipped.

Changes:

  • Extend PromptfooConfig.defaultTest typing to allow either a string (including file://...) or an inline object.
  • Update dependency extraction to process file-backed defaultTest via the existing repository-containment-aware file visitor.
  • Add unit tests covering file-backed defaultTest, repository-escape rejection, and ignoring unsupported strings; regenerate dist/ bundle.

Reviewed changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/utils/config.ts Add support for defaultTest: file://... in dependency extraction and update config typing.
tests/utils/config.test.ts Add coverage for file-backed defaultTest dependency extraction and containment rejection.
dist/index.js Regenerated bundled output reflecting the source change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/utils/config.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: c4ff314442

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…le-backed-default-test

# Conflicts:
#	__tests__/utils/config.test.ts
#	dist/index.js.map
@mldangelo
mldangelo force-pushed the mdangelo/codex/sec-file-backed-default-test branch from cfeabbb to b4931a0 Compare July 9, 2026 07:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b4931a0d43

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/utils/config.ts
@mldangelo-oai
mldangelo-oai requested a review from Copilot July 15, 2026 01:01
@mldangelo-oai

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact head ba354e12466d878f89dc2e8a000d144beeaaea1e, focusing on file-backed defaultTest dependency discovery and change gating: nested/provider/options/assertion/vars references, function selectors, relative/absolute/Windows/brace/root globs and deletion/new-match sentinels, workspace/realpath containment and warning redaction, cycles/malformed shapes, and the GitHub-built dist/ bundle after the dependency restack. Local full gate passes 274 tests with 100% coverage; exact-head check-dist passes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/utils/config.ts Outdated
@mldangelo-oai
mldangelo-oai requested a review from Copilot July 15, 2026 01:09
@mldangelo-oai

Copy link
Copy Markdown
Contributor Author

@codex review

Please re-review exact head b95f96af087f8fd687b897cf4e488478737781e1. The fresh Copilot finding is fixed: file-backed default-test wrapper glob detection now shares windowsPathsNoEscape and magicalBraces with expansion, with a failing-first brace/backslash regression proving the glob is never passed to realpathSync/readFileSync and produces no misleading warning. All historical review threads are resolved. Local full gate passes 275 tests with 100% coverage, and the exact-head GitHub-built check-dist bundle passes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/utils/config.ts Outdated
@mldangelo

Copy link
Copy Markdown
Member

Review (current head 63a4b3a) — no code change pushed

Re-reviewed against the current head. I did not push a change: the file is clean of the duplication patterns I fixed elsewhere (no duplicated GLOB_MAGIC_OPTIONS copy in main.ts, no repeated dependency-root sentinel), and I found no simplification that's both safe and clearly worth the churn.

Assessment

Structurally consistent with the rest of the family — same MAX_BRACE_EXPANSIONS bound, isPathInside containment, and fail-open return [] catch. The defaultTest file-backing and bounded glob traversal look correct on my read. Like its siblings it inherits the base's unguarded provider.id?.startsWith(...) (a null providers[] entry would throw), but since this PR keeps the fail-open catch, that degrades to return [] rather than failing the action — so it's a latent robustness nit, not a bug this PR introduces.

Top recommendation: consolidate the family

One of seven independent config.ts rewrites (#974/#977/#979/#981/#982/#983/#987). They conflict and don't share an error policy. Folding defaultTest handling into a single consolidated rewrite would make it a small, easy-to-review delta instead of a seventh full rewrite of the same function.

Original inline comments predate a restack and may show as "outdated".

A dangling YAML list item (prompts:\n  - file://a.txt\n  -) parses to a null
entry; the prompts loop then hit `typeof null === 'object' && null.file` and
threw, which the outer catch turned into a ['./'] whole-repo watch, discarding
the precise dependencies and disabling filtering. Skip null/undefined entries
at the top of the loop, matching the tests/assert paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mldangelo

Copy link
Copy Markdown
Member

Correction: a real bug was here — fix pushed (770d9bf)

My earlier comment said "no code change" — that was based on a pattern scan. A fresh, adversarially-verified correctness pass on the current head then found a genuine P3 bug, now fixed. npm run all passes (9 files, 542 tests, 100% coverage).

The bug

A dangling YAML list item in prompts: parses to a null entry:

prompts:
  - file://a.txt
  -

config.prompts = ['file://a.txt', null]. The prompts loop reaches } else if (typeof prompt === 'object' && prompt.file); since typeof null === 'object' is true, it evaluates null.file and throws TypeError. The outer catch (with parsedConfig already true) then returns ['./'], discarding the precise provider/prompt dependencies and collapsing to a whole-repo watch — so dependency filtering is silently disabled and every change re-runs the full eval. The tests/assert paths already guard null (if (!test || typeof test !== 'object') continue); prompts didn't.

The fix

if (configuredPrompt == null) continue; at the top of the loop, matching the tests/assert paths, plus a regression test (a null prompt entry alongside real ones, asserting the real deps are still returned). Safe direction (it over-watched rather than missing), hence P3.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 770d9bf87d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/utils/config.ts Outdated
}
}

if (config.nunjucksFilters) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track top-level env file configs

When a prompt-gated workflow uses Promptfoo's documented modular form env: file://configs/env-prod.yaml (see https://www.promptfoo.dev/docs/configuration/modular-configs/#environment-specific-configurations), this traversal reaches the top-level passes for scenarios and Nunjucks filters without ever visiting config.env. A PR that changes only the env file can therefore leave dependencyChanged false and hit the skip path even though Promptfoo will load different environment values for the eval; add an env pass that records file-backed env configs before returning dependencies.

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts Outdated

// Process tests
if (config.tests) {
if (Array.isArray(config.tests)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track top-level assertion dependencies

When a config uses top-level assert entries, which the Promptfoo config reference supports, this code goes from defaultTest straight into tests and never walks config.assert. In prompt-gated runs, changing only a file used by a global assertion such as assert: [{ type: 'javascript', value: 'file://validators/global.js' }] can leave dependencyChanged false and skip evaluation even though Promptfoo will execute the changed assertion for the suite.

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts Outdated
/\.(?:json|ya?ml)$/i.test(fileUrl) ||
getGlobMagic(fileUrl.slice('file://'.length)) === true
) {
inspectNestedConfigFile(fileUrl);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reuse prompt-specific handling for imported prompt configs

When prompts points at a YAML prompt list and that file contains object-form prompts like - raw: exec:./generator.sh, Promptfoo supports executing that script, but this branch delegates the imported list to the generic config walker instead of the prompt-specific logic below that understands raw/exec: prompts. A PR changing only generator.sh can therefore be missed by dependency gating while the generated prompts used by the eval change; parse imported prompt config entries with the same prompt handling used for top-level prompt objects.

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts Outdated

// Process tests
if (config.tests) {
if (Array.isArray(config.tests)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track top-level assertScoringFunction files

When a suite-level assertScoringFunction: file://scoring.js is configured, the Promptfoo config reference says that file supplies the custom score combiner, but this traversal only handles assertScoringFunction inside tests and defaultTest. A PR that changes only scoring.js can therefore be skipped even though the same model outputs may now pass or fail differently; visit the top-level scoring function before moving on to tests.

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts Outdated
}
}

if (config.nunjucksFilters) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track commandLineOptions file defaults

When the config sets file-backed CLI defaults such as commandLineOptions: { promptPrefix: 'prefix.txt', envPath: '.env.evals' }, Promptfoo applies those defaults during eval, but this dependency scan never visits config.commandLineOptions. In prompt-gated runs, a change limited to the prefix or env file can leave dependencyChanged false and skip an evaluation whose rendered prompts or provider settings would change; add a bounded pass for file-valued command-line defaults.

Useful? React with 👍 / 👎.

A directory dependency emitted without a trailing slash was only prefix-matched
when isDirectory(dep) was true, so a PR that deletes the directory (isDirectory
false) skipped the eval even though a watched child file changed. Always test
the directory-prefix form; a file dependency has no children so it never
false-matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mldangelo

Copy link
Copy Markdown
Member

Correctness fix pushed — deleted directory dependency

An extended adversarial pass over the main.ts dependency-matching logic found a real missed-re-eval bug (P3, the under-inclusive/dangerous direction), now fixed. npm run all passes with 100% coverage and CI is green.

A directory dependency emitted without a trailing slash was only prefix-matched when isDirectory(dep) was true. In a PR that deletes the directory, isDirectory returns false, so the dep.endsWith('/') || isDirectory(dep) block was skipped and a changed child file failed to trigger the eval. Fixed by always testing the directory-prefix form (a file dep has no children, so it never false-matches). This shared-matcher bug also affected #974/#987/#979/#982/#983 and is now fixed across all of them.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-24T08:30:48.798098Z 343a6ff New commits
🔒 Security Review Completed 2026-08-24T08:31:33.765234Z 343a6ff New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72ac19fa49

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve absolute defaultTest file URLs

When defaultTest uses an absolute URL such as file:///home/runner/work/repo/defaults/default.yaml, processFileUrl() passes the absolute portion through path.join(configDir, filePath), which turns it into a path beneath the config directory (for example evals/home/runner/...) instead of preserving the absolute path. Consequently, a change to the actual default-test file is absent from the dependency set and a prompt-gated run can incorrectly skip evaluation; handle absolute paths before joining them to configDir.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 72ac19fa49

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rebuild the distributed action bundle

When consumers invoke this action, action.yml executes dist/index.js, but this commit leaves that file byte-identical to its parent; the bundled defaultTest block still directly reads .vars and .assert, so the new string-handling branch is never executed by the distributed action. Regenerate and commit /dist/ with the source change.

AGENTS.md reference: AGENTS.md:L94-L98

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track contained symlink targets for default-test files

When the configured default-test file is a repository symlink, such as defaults/current.yaml -> v2.yaml, this records only the lexical symlink path. A commit that changes defaults/v2.yaml without changing defaults/current.yaml therefore does not match the dependency list, even though Promptfoo follows the symlink and consumes the changed contents, so the action can skip the evaluation. Resolve the target, verify that its real path remains inside the workspace, and record that contained target as a dependency as well.

AGENTS.md reference: AGENTS.md:L56-L60

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2db2f0ce4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Watch dynamic default-test paths conservatively

When a prompt-gated config uses a templated wrapper such as defaultTest: file://{{ env.DEFAULT_TEST_PATH }}, this new string branch passes the unresolved template to processFileUrl(). It is then recorded as a literal/glob path rather than the concrete runtime-selected file (and a root-level template may produce no dependency at all), so changing only the selected default-test file can incorrectly skip evaluation; dynamic wrapper paths should conservatively register the repository-root watcher.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99f693ff5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts
Comment on lines +72 to +74
const absolutePath = path.isAbsolute(filePath)
? path.normalize(filePath)
: path.resolve(path.join(configDir, filePath));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the base of absolute dependency globs

When an absolute file:// glob is used, such as an inline default-test var pointing to file:///workspace/repo/fixtures/*.txt, and a PR adds a new matching file, the glob is now expanded from the correct absolute path but the watcher calculation at lines 120-129 drops the leading root and rejoins the base beneath configDir. Because the newly added file is absent from the current expansion and the recorded base points somewhere like configDir/workspace/repo/fixtures, dependency gating can still skip the evaluation; derive the watcher from the absolute glob base rather than rejoining it to the config directory.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e7fc880dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts Outdated
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
if (config.defaultTest.includes('{{')) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat Nunjucks block tags as dynamic paths

When a file-backed default test selects its wrapper with a Nunjucks block, such as file://{% if env.CI %}defaults/ci.yaml{% else %}defaults/dev.yaml{% endif %}, Promptfoo renders the block but this condition recognizes only {{ expressions. The path therefore falls through to processFileUrl() as literal template text, so changing only the selected wrapper can fail to match any dependency and the prompt-gated action may skip evaluation; conservatively watch the dependency root for {% ... %} paths as well.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b10476d1a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts Outdated
if (/\{[{%]/.test(config.defaultTest)) {
dependencies.add(`${dependencyRoot}${path.sep}`);
} else {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Watch the config directory for root-level default-test globs

When defaultTest is a root-level glob such as file://*.yaml and a matching file is deleted, this call expands only files that remain, while processFileUrl() records no base watcher because the first path segment already contains glob magic. The deleted path is therefore absent from dependencies, so a prompt-gated run can incorrectly skip evaluation; record configDir when a glob has no literal prefix.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 582e2b7d8c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts Outdated
extractAssertFiles(config.defaultTest.assert);
if (typeof config.defaultTest === 'string') {
if (config.defaultTest.startsWith('file://')) {
if (/\{[{%]/.test(config.defaultTest)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recognize Nunjucks comment tags in default-test paths

When a file-backed default-test path contains a Nunjucks comment, such as file://defaults/{# selected environment #}ci.yaml, Nunjucks removes the comment before loading defaults/ci.yaml, but this regex recognizes only {{ ... }} and {% ... %} tags. Fresh evidence beyond the prior block-tag case is the unhandled {# ... #} syntax: the scanner records the literal comment-bearing path, so changing only the rendered target can leave dependencyChanged false and incorrectly skip evaluation; treat comment tags as templated paths as well.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

Comment thread src/utils/config.ts Outdated
const globPath = isAbsoluteGlob
? path.relative(dependencyRoot, filePath)
: filePath;
const pathParts = globPath.split(/[\\/]/);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve POSIX backslashes in glob watch roots

On POSIX runners, a repository directory may legitimately contain a backslash, and glob syntax represents that literal character with an escaped backslash (for example a pattern targeting fixtures\set/*.yaml). Splitting the pattern on both slash types rewrites that literal directory into fixtures/set when deriving the base watcher; existing matches are recorded individually, but adding a new matching file under fixtures\set/ will not match the incorrect watcher and can cause the action to skip evaluation. Split on the platform separator, or parse escaped glob characters without treating POSIX backslashes as directory separators.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 045f9dfbb6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/config.ts Outdated
if (/\{[{%#]/.test(config.defaultTest)) {
dependencies.add(`${dependencyRoot}${path.sep}`);
} else {
processFileUrl(config.defaultTest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Inspect dependencies inside file-backed default tests

When defaultTest points to a YAML/JSON file whose contents reference another file (for example, vars.context: file://fixtures/context.txt), this branch records only the default-test wrapper and never loads it through extractVarFiles/extractAssertFiles. If only fixtures/context.txt changes, no dependency matches and the prompt-gated action can skip an evaluation even though Promptfoo consumes the changed file; inspect the file-backed default test and add its nested dependencies as well.

AGENTS.md reference: AGENTS.md:L7-L9

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants