mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-06 23:35:34 +00:00
* ci: run Windows merge queue tests on ECS
* test(channels): skip POSIX mode assertion on Windows
* ci: expose Git Bash on Windows ECS runner
* ci: scope Windows ECS tuning to self-hosted and restore full test:ci
Review feedback on the Windows ECS routing: dropping test:scripts removed the only Windows execution of 9 Windows-only install-script tests, and the job-wide PowerShell default plus narrowed test command changed the kill-switch fallback away from the known-good hosted configuration.
Restore the full npm run test:ci on both paths (bash is available: pre-installed on hosted runners, exposed via the Git Bash PATH entry on ECS) and gate every ECS-specific adjustment on runner.environment: the PowerShell setup step (now also skip_ci-guarded), TEMP/TMP/LC_ALL env writes, and the Linux-style Node setup split that fails with an actionable error naming MAINTAINER_ECS_RUNNER_DISABLED. The windows-2022 fallback is byte-for-byte the pre-ECS job again.
* test: make Windows CI suites platform-aware
* ci: add stale-checkout guard to Windows ECS test job
* test(core): compare canonical directory identity
* ci: add fork guard and review follow-ups to Windows ECS job
* test(core): exercise real directory identity change
* test(core): wait for killed lease process exit
* test(scripts): avoid cmd echo trailing spaces
* test(scripts): use unambiguous cmd echo syntax
* test(cli): avoid sidecar I/O in truncation test
* test: fix Windows script-suite gaps and unify platform gating
- Fix missed trailing-space cmd stub in package-scripts.test.js so the
'runs prepare steps in order' assertion passes on Windows.
- Add qwen-pr-review-workflow.test.js and pr-self-report-label.test.js to
the win32 exclude list (both test Linux-only workflows and are not
portable to Windows).
- Replace local itPosix/describeOnNonWindows consts with vitest's built-in
it.skipIf/it.runIf/describe.skipIf, matching the codebase idiom.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(scripts): restore Windows workflow coverage
* test(scripts): re-exclude Windows-incompatible workflow tests on win32
Re-add pr-self-report-label.test.js and qwen-pr-review-workflow.test.js to
the win32 exclude list. Both fail on a Windows runner for reasons the code
still carries: qwen-pr-review-workflow.test.js calls execFileSync('mkdir'),
which has no executable to resolve there, and pr-self-report-label.test.js
joins PATH with ':', corrupting the ';'-separated Windows PATH so its gh
stub never resolves. Excluding them restores a green Windows gate; Linux CI
remains their authoritative coverage. Document the criterion inline.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: extract checkout-head guard into composite action, pin Windows gate (#8386)
Address review round 2: move the stale-checkout guard shared by the four CI gates into .github/actions/verify-checkout-head so the copies cannot drift, pin the Windows gate kill-switch routing and guard wiring in the script tests, re-enable lint.test.js on Windows via separator normalization and a lazy linter setup in scripts/lint.js, unify the platform skips on it.skipIf(process.platform === 'win32'), and document the queued-run behavior of the ECS kill switch.
* ci: fail fast in Windows gate environment setup (#8386)
* ci: dedupe self-hosted runner steps into actions, pin gate mutations (#8386)
* fix(ci): checkout before repository-local actions in Windows gates (#8386)
* fix(ci): configure Windows runner before bash guard
* test(ci): pin remaining shared-action wiring in script tests (#8386)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): skip zip-dependent packaging tests when zip is missing (#8386)
* fix(ci): validate full Windows smoke path
* fix(ci): match Windows smoke shell to gate and drop dead runs-on guard (#8386)
* fix(ci): make SIGTERM escalation test Windows-aware and tighten pins (#8386)
The CDP acceptance test asserted a POSIX-only SIGKILL escalation, which
fails deterministically on Windows where kill('SIGTERM') terminates the
child directly — blocking the Windows merge-queue gate. Assert the
platform-appropriate signal instead.
Also address review suggestions: probe `unzip` alongside `zip`, pin the
integration_cli guard's missing step-level `if:`, stop getWorkflowStep
at unnamed steps, pin install-script.test.js out of the win32 excludes,
add the stale-checkout guard to windows-runner-smoke.yml, pin the
Node preflight warning branch and the guard reject path contiguously,
and extend the smoke shell-parity loop to the npm cache step.
* docs(ci): clarify Windows runner trust boundary
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
135 lines
5.1 KiB
JavaScript
135 lines
5.1 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2026 Qwen Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
import { dirname, join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
|
|
import { classifyAuditOutput } from '../audit-runtime-critical.js';
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
|
|
describe('scripts/audit-runtime-critical.js', () => {
|
|
it('separates a real audit from a registry that never answered', () => {
|
|
// npm exits 1 for BOTH, so the exit code cannot gate a merge on its own.
|
|
// This payload is what the retiring `security/audits/quick` endpoint
|
|
// actually returned on 2026-07-26, when it 400'd for every PR in the repo.
|
|
const endpointFailure = JSON.stringify({
|
|
message:
|
|
'400 Bad Request - POST https://registry.npmjs.org/-/npm/v1/security/audits/quick - Bad Request',
|
|
method: 'POST',
|
|
uri: 'https://registry.npmjs.org/-/npm/v1/security/audits/quick',
|
|
statusCode: 400,
|
|
error: 'Bad Request',
|
|
});
|
|
expect(classifyAuditOutput(endpointFailure)).toBe('unreachable');
|
|
|
|
// A real audit always carries the counts, whether or not anything was found.
|
|
const clean = JSON.stringify({
|
|
vulnerabilities: {},
|
|
metadata: { vulnerabilities: { critical: 0, high: 0, total: 0 } },
|
|
});
|
|
expect(classifyAuditOutput(clean)).toBe('audited');
|
|
|
|
const vulnerable = JSON.stringify({
|
|
vulnerabilities: { evil: {} },
|
|
metadata: { vulnerabilities: { critical: 2, high: 0, total: 2 } },
|
|
});
|
|
expect(classifyAuditOutput(vulnerable)).toBe('audited');
|
|
});
|
|
|
|
it('fails closed on output it does not recognise', () => {
|
|
// If npm changes its payload shape, the gate must go red and get a human
|
|
// to look — never quietly report success and retire itself.
|
|
expect(classifyAuditOutput('')).toBe('unreadable');
|
|
expect(classifyAuditOutput('not json at all')).toBe('unreadable');
|
|
expect(classifyAuditOutput(JSON.stringify({ unexpected: true }))).toBe(
|
|
'unreadable',
|
|
);
|
|
// Shape-only: an object without counts and without an error is NOT an
|
|
// excuse to pass, even though it parses.
|
|
expect(classifyAuditOutput(JSON.stringify({ metadata: {} }))).toBe(
|
|
'unreadable',
|
|
);
|
|
});
|
|
|
|
it.skipIf(process.platform === 'win32')(
|
|
'still fails the build on a real critical vulnerability',
|
|
() => {
|
|
// The whole risk of this change is shipping a gate that never fires again.
|
|
// Drive the real script end to end against a stubbed `npm` on PATH, so the
|
|
// exit code being asserted is the one CI would actually see.
|
|
const shimDir = mkdtempSync(join(tmpdir(), 'audit-shim-'));
|
|
const runWithNpmStub = (payload, npmExit) => {
|
|
writeFileSync(
|
|
join(shimDir, 'npm'),
|
|
`#!/usr/bin/env bash\ncat <<'JSON'\n${payload}\nJSON\nexit ${npmExit}\n`,
|
|
{ mode: 0o755 },
|
|
);
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[join(root, 'scripts', 'audit-runtime-critical.js')],
|
|
{
|
|
encoding: 'utf8',
|
|
env: { ...process.env, PATH: `${shimDir}:${process.env.PATH}` },
|
|
},
|
|
);
|
|
return result.status;
|
|
};
|
|
|
|
try {
|
|
const counts = (critical) =>
|
|
JSON.stringify({
|
|
vulnerabilities: {},
|
|
metadata: {
|
|
vulnerabilities: { critical, high: 0, total: critical },
|
|
},
|
|
});
|
|
// A finding still blocks the merge...
|
|
expect(runWithNpmStub(counts(2), 1)).toBe(1);
|
|
// ...a clean audit still passes...
|
|
expect(runWithNpmStub(counts(0), 0)).toBe(0);
|
|
// ...only an unreachable endpoint is waved through...
|
|
expect(
|
|
runWithNpmStub(
|
|
JSON.stringify({ statusCode: 400, error: 'Bad Request' }),
|
|
1,
|
|
),
|
|
).toBe(0);
|
|
// ...and unrecognised output fails closed even when npm exits 0, so a
|
|
// payload-shape change can never silently retire the gate.
|
|
expect(runWithNpmStub('totally not json', 1)).toBe(1);
|
|
expect(runWithNpmStub('totally not json', 0)).toBe(1);
|
|
} finally {
|
|
rmSync(shimDir, { recursive: true, force: true });
|
|
}
|
|
},
|
|
);
|
|
|
|
it('is wired into the audit script and stays runnable', () => {
|
|
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
|
expect(pkg.scripts['audit:runtime:critical']).toBe(
|
|
'node scripts/audit-runtime-critical.js',
|
|
);
|
|
// Importing the module must not shell out to npm — the main guard is what
|
|
// keeps this test file from running a real audit on import.
|
|
const printed = execFileSync(
|
|
process.execPath,
|
|
[
|
|
'-e',
|
|
`import(${JSON.stringify(
|
|
pathToFileURL(join(root, 'scripts', 'audit-runtime-critical.js'))
|
|
.href,
|
|
)}).then((m) => console.log(typeof m.classifyAuditOutput))`,
|
|
],
|
|
{ encoding: 'utf8' },
|
|
);
|
|
expect(printed.trim()).toBe('function');
|
|
});
|
|
});
|