Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/qwen-autofix.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name: 'Qwen Autofix'

# One workflow for the whole autonomous-fix lifecycle:
Expand Down Expand Up @@ -5219,6 +5219,7 @@
WORKDIR="${WORKDIR}" \
BRANCH="${BRANCH}" \
GITHUB_OUTPUT="${GITHUB_OUTPUT}" \
CI="${CI:-true}" \
Comment thread
doudouOUC marked this conversation as resolved.
Resolved
KISS_AUDIT="${KISS_AUDIT:-false}" \
FOOTPRINT_ENFORCE="${FOOTPRINT_ENFORCE:-advisory}" \
bash --norc "${RUNNER_TEMP}/run-autofix-review-verification.sh"
Expand Down Expand Up @@ -5428,6 +5429,7 @@
WORKDIR="${WORKDIR}" \
BRANCH="${BRANCH}" \
GITHUB_OUTPUT="${GITHUB_OUTPUT}" \
CI="${CI:-true}" \
KISS_AUDIT="${KISS_AUDIT:-false}" \
FOOTPRINT_ENFORCE="${FOOTPRINT_ENFORCE:-advisory}" \
bash --norc "${RUNNER_TEMP}/run-autofix-review-verification.sh"
Expand Down
37 changes: 36 additions & 1 deletion scripts/tests/qwen-autofix-workflow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11183,6 +11183,41 @@ exit 1
expect(reviewVerificationGateStep).not.toContain(
'bash .github/scripts/run-autofix-review-verification.sh',
);
// The gate launches through an env -i clean child with a SANCTIONED
// allowlist (R5-1): every variable the gate's own build/test checks need
// must be passed, and the runner-provided CI=true is one of them — without
// it the gate's checks run with inverted CI semantics and the 18
// deliberately-skipped TUI-input tests un-skip inside the gate (one flakes
// ~5s, reject_fix fires retryable on a fix the PR's own CI passes green).
// A contains-only pin accepts a symmetric DROP, so enumerate the full
// allowlist of BOTH gate launches (first pass + repair pass) as a sorted
// multiset — a symmetric duplicate or a dropped entry both fail here.
const gateAllowlist = (step) => {
const argStart = step.indexOf('/usr/bin/env -i \\');
expect(argStart, 'gate step lacks the env -i launch').toBeGreaterThan(-1);
const argList = step.slice(argStart, step.indexOf('bash --norc'));
const passed = (
argList.match(/[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|[^\s\\]*)/g) ?? []
)
.map((m) => m.split('=')[0])
.sort();
expect(passed).toEqual(
[
'PATH',
'HOME',
'RUNNER_TEMP',
'WORKDIR',
'BRANCH',
'GITHUB_OUTPUT',
'CI',
'KISS_AUDIT',
'FOOTPRINT_ENFORCE',
].sort(),
);
expect(argList).toContain('CI="${CI:-true}"');
};
gateAllowlist(reviewVerificationGateStep);
gateAllowlist(repairVerificationGateStep);
expect(
reviewVerifyGate.indexOf(
'bash "${RUNNER_TEMP}/check-autofix-contracts.sh"',
Expand Down Expand Up @@ -12775,7 +12810,7 @@ exit 1
// Delimited tokens, not substrings: match `NAME=value` up to the line
// continuation, so a value swap or an extra entry is visible.
const assignments = (
argList.match(/[A-Z_][A-Z0-9_]*=(?:"[^"]*"|[^\s\\]*)/g) ?? []
argList.match(/[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|[^\s\\]*)/g) ?? []
).map((m) => m.trim());
const passed = assignments.map((m) => m.split('=')[0]);
// Sorted multiset, not a Set: a symmetric duplicate entry is exactly
Expand Down
Loading