Skip to content

Fix Codex threat-detection config.toml emitting model_provider under [history]#47832

Merged
pelikhan merged 6 commits into
mainfrom
copilot/fix-codex-history-table-issue
Jul 24, 2026
Merged

Fix Codex threat-detection config.toml emitting model_provider under [history]#47832
pelikhan merged 6 commits into
mainfrom
copilot/fix-codex-history-table-issue

Conversation

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

The Codex external detector generated a config.toml where the top-level model_provider = "openai-proxy" selector was emitted after the [history] table header. TOML then binds it as history.model_provider, which Codex ignores — falling back to the default openai provider, bypassing the AWF api-proxy sidecar, and failing detection runs with 401 Unauthorized.

Changes

  • buildExternalDetectorCodexConfig (pkg/workflow/threat_detection_external.go): moved model_provider to the first line, ahead of any table header, so TOML assigns it to the document root. Added a comment documenting the ordering constraint.
  • Regression test (threat_detection_isolation_test.go): asserts model_provider precedes any table header and that the [history] table body contains no model_provider key.

Before → after:

# before (parsed as history.model_provider — ignored by Codex)
[history]
persistence = "none"

model_provider = "openai-proxy"

# after (document-root selector, honored by Codex)
model_provider = "openai-proxy"

[history]
persistence = "none"

The agent Codex config path was already correct and is unchanged. Existing string-based assertion style is kept; no new TOML parser dependency introduced.


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 8.47 AIC · ⌖ 7.95 AIC · ⊞ 7K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 15.5 AIC · ⌖ 7.01 AIC · ⊞ 7K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 9.6 AIC · ⌖ 7.02 AIC · ⊞ 7K ·
Comment /souschef to run again

Co-authored-by: davidslater <12449447+davidslater@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix config.toml emission of model_provider in detection job Fix Codex threat-detection config.toml emitting model_provider under [history] Jul 24, 2026
Copilot AI requested a review from davidslater July 24, 2026 17:42
@davidslater
davidslater marked this pull request as ready for review July 24, 2026 17:44
Copilot AI review requested due to automatic review settings July 24, 2026 17:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes Codex external threat detection routing through the AWF API proxy by placing model_provider at the TOML document root.

Changes:

  • Moves model_provider before all TOML table headers.
  • Adds regression coverage for root-level placement.
Show a summary per file
File Description
pkg/workflow/threat_detection_external.go Corrects Codex detector configuration ordering.
pkg/workflow/threat_detection_isolation_test.go Verifies the selector remains outside [history].

Review details

Tip

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

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #47832 does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (51 additions, threshold 100).

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The fix is correct and well-tested.

  • model_provider is moved to the document root before any table header — this is the right TOML fix.
  • The regression test robustly validates both that model_provider precedes [, and that [history] body does not contain model_provider.
  • The inline comment clearly documents the ordering constraint for future maintainers.

No issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 11.5 AIC · ⌖ 4.47 AIC · ⊞ 5K

@github-actions github-actions Bot mentioned this pull request Jul 24, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — approving with one minor suggestion.

📋 Key Themes & Highlights

Root Cause & Fix

The bug was precisely diagnosed: TOML assigns bare keys to the most-recently-opened table, so emitting model_provider after [history] silently bound it as history.model_provider, which Codex ignores. Moving it before any table header is the minimal, correct fix. The added code comment documenting the ordering constraint is exactly the right mitigation for future editors.

Test Coverage

The regression test covers the two relevant invariants (key precedes all table headers; [history] body contains no model_provider key). One minor hardening suggestion is left as an inline comment on the boundary-extraction logic.

Positive Highlights

  • ✅ Root cause fixed, not just the symptom
  • ✅ Regression test added alongside the fix
  • ✅ Clear comment documents the TOML scoping constraint
  • ✅ No new dependencies introduced; existing assertion style preserved

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 25.5 AIC · ⌖ 4.65 AIC · ⊞ 6.7K
Comment /matt to run again

// model_provider key. Extract the [history] table body and assert.
historyIndex := strings.Index(toml, "[history]")
if historyIndex == -1 {
t.Fatalf("Expected [history] table in detection config, got:\n%s", toml)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The [history] body extraction searches for the next [ character, which could match a bracket inside a quoted string value (e.g. a base_url like `(host/redacted) Low risk today, but fragile as the config evolves.

💡 Suggested hardening

Scan for [ instead to avoid matching brackets inside quoted values:

if nextTable := strings.Index(historyBody[len("[history]"):], "
["); nextTable != -1 {
    historyBody = historyBody[:len("[history]")+nextTable]
}

The current assertion is correct for the existing config — this is a minor defensive improvement.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in the latest commit. The historyBody is now built by a line-by-line scan that stops as soon as it encounters a line whose trimmed content starts with [, so [ inside quoted values or arrays can't cause premature truncation.

@github-actions

Copy link
Copy Markdown
Contributor

hello

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 61.5 AIC · ⌖ 7.73 AIC · ⊞ 7K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100 — Excellent

Analyzed 1 test(s): 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 1, JS: 0)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation YES — 44 test additions / 7 prod additions ≈ 6.3:1 (justified)
🚨 Violations 0
Test File Classification Issues
TestExternalDetectorCodexConfigModelProviderAtRoot pkg/workflow/threat_detection_isolation_test.go:402 design_test / behavioral_contract Test inflation (6.3:1)
⚠️ Flagged Tests (1 — inflation only)

TestExternalDetectorCodexConfigModelProviderAtRoot (threat_detection_isolation_test.go:402) — test inflation (6.3:1). 44 test lines vs 7 production lines exceeds the 2:1 threshold. This is justified: the test encodes a multi-part TOML structural contract (positive root-placement assertion + negative regression guard ensuring [history] never absorbs model_provider) that requires indentation trimming setup and multiple assertions to fully verify the bug fix.

Verdict

Passed. 0% implementation tests (threshold: 30%). No guideline violations.

TestExternalDetectorCodexConfigModelProviderAtRoot is a high-value design test that encodes the exact TOML ordering invariant fixed by this PR. It calls buildExternalDetectorCodexConfig directly, strips emitted indentation, and makes two orthogonal assertions: (1) model_provider must precede any [table] header, and (2) the [history] table body must not contain model_provider. This is the kind of invariant test that would have caught the original regression automatically.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review: Non-blocking issues in the regression test

The production fix in threat_detection_external.go is correct — moving model_provider before any TOML table header is the right call and the comment explaining the ordering constraint is helpful.

The regression test has four medium-severity issues that reduce its future reliability without breaking it today.

Issues found (all non-blocking)
  1. Hardcoded "openai-proxy" string (line 415) — uses the literal value instead of codexOpenAIProxyProviderID; silent false-negative if the constant is renamed.
  2. Magic 10-space indent (line 408) — strings.TrimPrefix silently becomes a no-op if the indentation in the production function changes.
  3. Fragile historyBody slice (line 430) — strings.Index(..., "[") truncates on the first [ in any value (arrays, inline strings), potentially hiding a model_provider key.
  4. firstTableIndex matches [ in comments (line 419) — should find the first line-starting [ to avoid false matches from TOML comments.

None of these cause the test to pass incorrectly today, but together they make the test brittle under future config changes. The suggested fixes in the inline comments are straightforward.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 · 43.5 AIC · ⌖ 5.04 AIC · ⊞ 5.7K
Comment /review to run again

Comment thread pkg/workflow/threat_detection_isolation_test.go
// Trim the shared 10-space indentation so the config reads as plain TOML.
var trimmedLines []string
for _, line := range strings.Split(config, "\n") {
trimmedLines = append(trimmedLines, strings.TrimPrefix(line, " "))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Magic indentation string is silently fragile: the 10-space trim prefix is a bare string literal. If the indentation in buildExternalDetectorCodexConfig ever changes (e.g. tabs, different count), strings.TrimPrefix becomes a no-op, all subsequent strings.Index calls operate on still-indented text, and the ordering assertions give wrong results without any obvious failure signal.

💡 Suggested fix

Extract the indent as a named constant or derive it from the actual output:

const codexConfigIndent = "          " // 10 spaces, matches buildExternalDetectorCodexConfig

Or make the test resilient by using strings.TrimLeft(line, " ") instead of TrimPrefix, so it strips whatever leading whitespace is present regardless of exact count.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in the latest commit. The loop now uses strings.TrimLeft(line, " \t") so it strips any leading whitespace regardless of exact count or type, and the magic 10-space literal is gone. Also switched to strings.SplitSeq per the modernize lint rule.

// model_provider key. Extract the [history] table body and assert.
historyIndex := strings.Index(toml, "[history]")
if historyIndex == -1 {
t.Fatalf("Expected [history] table in detection config, got:\n%s", toml)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

historyBody slicing can prematurely truncate on [ in values or arrays: strings.Index(historyBody[len("[history]"):], "[") finds the first [ after the header, but TOML values can contain [ (e.g. array values like allowed = ["a", "b"]). This would truncate historyBody before the end of the [history] section, potentially hiding a model_provider key that appears after the array.

💡 Suggested fix

Scan line-by-line and stop at the next line that starts a new table header:

var historyLines []string
inHistory := false
for _, line := range strings.Split(toml, "
") {
    if line == "[history]" {
        inHistory = true
        continue
    }
    if inHistory {
        if strings.HasPrefix(line, "[") {
            break
        }
        historyLines = append(historyLines, line)
    }
}
historyBody := strings.Join(historyLines, "
")
if strings.Contains(historyBody, "model_provider") {
    t.Errorf("[history] table must NOT contain a model_provider key, got:
%s", historyBody)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in the latest commit. The historyBody extraction now uses a line-by-line scan (via strings.SplitSeq) that stops at the next line beginning with [, so array literals like allowed = ["a", "b"] can't truncate the section prematurely.

Comment thread pkg/workflow/threat_detection_isolation_test.go
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Copilot AI and others added 2 commits July 24, 2026 18:15
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
…ne scanning

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI requested a review from gh-aw-bot July 24, 2026 18:23
@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category bug
Risk 🟡 Medium
Score 76/100
Score breakdown impact=38, urgency=24, quality=14
Recommended action fast_track

Rationale: Fixes a critical TOML config ordering bug that causes Codex threat-detection to use the wrong model provider (openai instead of openai-proxy), resulting in 401 errors on detection runs. Includes regression test. AI reviewer approved. No CI data available yet.

Next step: CI green → human review → merge.

Generated by 🔧 PR Triage Agent · sonnet46 · 39.2 AIC · ⌖ 4.9 AIC · ⊞ 5.7K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, confirm the branch is up to date, address the remaining unresolved review feedback, and rerun or retrigger checks as needed.

Unresolved review feedback:

Run: https://github.com/github/gh-aw/actions/runs/30120416243

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 15.5 AIC · ⌖ 7.01 AIC · ⊞ 7K ·
Comment /souschef to run again

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, confirm the branch is up to date, address the remaining unresolved review feedback, and rerun or retrigger checks as needed.

Unresolved review feedback:...

The branch is up to date. All actionable items from the unresolved review (PRR_kwDOPc1QR88AAAABHKTvmw — the PR Code Quality Reviewer's "Non-blocking issues" review) were addressed in commit 85342e1:

  • All 5 inline threads have been replied to and the underlying code issues fixed:
    1. codexOpenAIProxyProviderID constant used instead of hardcoded literal
    2. strings.TrimLeft(line, " \t") instead of magic 10-space prefix
    3. Line-by-line scan for firstTableIndex (no false match on [ in comments)
    4. Line-by-line scan for historyBody (no premature truncation on [ in values/arrays)
    5. strings.SplitSeq throughout (also fixed the modernize lint CI failure)
  • The lint-go CI failure is fixed locally (golangci-lint reports 0 issues on the changed package)
  • make fmt, make lint, and make agent-report-progress-no-test all pass locally

The 3 outdated threads will appear collapsed in the UI. The 2 non-outdated threads have been replied to; they remain technically unresolved because that requires human action in the GitHub UI.

CI must be re-triggered by a maintainer (close/reopen PR, workflow_dispatch, or a push) since the agent's pushes do not trigger workflows.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot refresh wasm golden

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot refresh wasm golden

Done. Updated the testCheckoutPinRE normalization in wasm_golden_test.go to the current actions/checkout@3d3c42e5... # v7.0.1 pin, regenerated all 9 Go golden files, and updated the 4 WasmBinary/ golden files used by the Node.js WASM test. Commit: $(git rev-parse --short HEAD).

Copilot AI requested a review from pelikhan July 24, 2026 20:26
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, confirm the branch is up to date, address any still-unresolved review feedback, and rerun or retrigger checks as needed.

Unresolved review feedback:...

Branch is up to date (merge commit 5cd9b79). Local validation passes: make fmt, make lint, make test-unit, and ./pkg/workflow tests all green.

Review threads status:

  • 2 threads resolved ✅
  • 3 threads are unresolved but outdated — the fixes for all three were committed in 85342e1 (line-by-line scanning for historyBody and firstTableIndex, TrimLeft instead of magic 10-space prefix). Each thread has a reply. They can't be resolved programmatically from this environment — a maintainer needs to mark them resolved in the GitHub UI.

CI:

  • Prior build-wasm failures (checkout v7.0.0 pin mismatch) were fixed in 2358366.
  • Prior lint-go failure (strings.SplitSeq) was fixed in 85342e1.
  • Current HEAD runs are action_required — CI must be re-triggered by a maintainer (close/reopen PR or push) to confirm the fixes.

  • ✅ Reviews — All code issues addressed and replied to. 3 outdated threads need human resolve in the GitHub UI.
  • ✅ Checks (local) — make fmt, make lint, ./pkg/workflow tests all pass.
  • ❓ Checks (CI) — Stale after agent push; needs human re-trigger. Prior failures (build-wasm, lint-go) fixed in 85342e1 + 2358366.
  • ✅ Mergeable — Branch is up to date, not behind main.

Hand-off: A maintainer needs to (1) resolve the 3 outdated review threads in the GitHub UI, and (2) re-trigger CI (close/reopen PR or push) before merge.

@pelikhan
pelikhan merged commit d719cec into main Jul 24, 2026
24 checks passed
@pelikhan
pelikhan deleted the copilot/fix-codex-history-table-issue branch July 24, 2026 21:00
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.3

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex threat-detection config.toml emits model_provider under [history] table (breaks AWF proxy routing)

5 participants