mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-09-11 11:18:36 +00:00
* ci: schedule dependency audit daily
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: track scheduled dependency audit failures
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: avoid duplicate post-merge secret scans
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: use native secret protection
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: extract dependency audit issue tracking
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: harden scheduled audit tracking
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* refactor(ci): simplify scheduled security checks
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): address dependency audit review feedback
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): fail closed on unknown audit results
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: stream the audit output instead of capturing it
With an 8-minute cap and one retry this step can now run for sixteen
minutes. Capturing into a variable and printing after each attempt
returns leaves the job silent for that whole time and then emits
everything at once, already labelled a failure. `tee` puts the output in
the log as npm produces it.
`${PIPESTATUS[0]}` rather than the pipeline's own status: `defaults: run:
shell: bash` sets pipefail, so the pipeline would carry npm's code today,
but nothing in the file says the classifier depends on that. Reading
npm's slot directly means a successful `tee` can never stand in for it.
Scope note, because the review that asked for this expected more from it:
streaming does not rescue an advisory from a killed attempt. npm emits
its report at the end, so an attempt killed before that point has nothing
to show either way — verified by A/B-ing both shapes against a stub that
reports only at exit: the progress line survives in both, the advisory in
neither. What keeps advisories in the log is the 8m cap sitting above
npm's own 422s error ceiling, which is already in this branch. This
commit is a log-legibility change, not a correctness one.
Behaviour is unchanged on every arm, driven with a stub npm against the
`run:` block extracted from the YAML: clean exits 0 after one call; a
genuine high-severity finding exits 1 after one call and is not retried;
an endpoint error and a timeout each retry once and exit 1 and 124.
The contract test pins `| tee "$log"`, `${PIPESTATUS[0]}` and the absence
of the old capture, so a silent regression to buffering fails.
Not run locally: the vitest suites and actionlint; CI is the authority.
* fix(ci): quote the explicit audit shell
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
122 lines
3.7 KiB
JavaScript
122 lines
3.7 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2026 Qwen Team
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { createRequire } from 'node:module';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const updateDependencyAuditIssue = require('../../.github/scripts/update-dependency-audit-issue.cjs');
|
|
|
|
describe('update dependency audit issue', () => {
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
});
|
|
|
|
it('creates, updates, and closes the deduplicated tracking issue', async () => {
|
|
vi.stubEnv('GITHUB_SERVER_URL', 'https://github.com');
|
|
vi.stubEnv('GITHUB_REPOSITORY', 'QwenLM/qwen-code');
|
|
vi.stubEnv('GITHUB_RUN_ID', '123');
|
|
|
|
const api = {
|
|
listForRepo: vi.fn(),
|
|
createComment: vi.fn(),
|
|
create: vi.fn(),
|
|
update: vi.fn(),
|
|
};
|
|
const github = {
|
|
paginate: vi.fn(),
|
|
rest: { issues: api },
|
|
};
|
|
const context = {
|
|
repo: { owner: 'QwenLM', repo: 'qwen-code' },
|
|
runId: 123,
|
|
};
|
|
|
|
vi.stubEnv('AUDIT_RESULT', 'failure');
|
|
github.paginate.mockResolvedValueOnce([]);
|
|
await updateDependencyAuditIssue({ github, context });
|
|
expect(api.create).toHaveBeenCalledOnce();
|
|
expect(api.create.mock.calls[0][0]).toMatchObject({
|
|
title: 'Daily dependency CVE audit failed',
|
|
body: expect.stringContaining(
|
|
'<!-- qwen-dependency-cve-audit-failure -->',
|
|
),
|
|
labels: ['scope/ci-cd', 'status/needs-triage'],
|
|
});
|
|
expect(api.create.mock.calls[0][0].body).toContain(
|
|
'a setup or dependency-install failure',
|
|
);
|
|
expect(api.createComment).not.toHaveBeenCalled();
|
|
expect(api.update).not.toHaveBeenCalled();
|
|
|
|
const issue = {
|
|
number: 42,
|
|
body: '<!-- qwen-dependency-cve-audit-failure -->',
|
|
};
|
|
const newerDecoy = {
|
|
number: 84,
|
|
body: `Quoted ${issue.body}`,
|
|
};
|
|
const pullRequestShadow = {
|
|
number: 900,
|
|
body: issue.body,
|
|
pull_request: {},
|
|
};
|
|
github.paginate.mockResolvedValueOnce([
|
|
newerDecoy,
|
|
pullRequestShadow,
|
|
issue,
|
|
]);
|
|
await updateDependencyAuditIssue({ github, context });
|
|
expect(api.createComment).toHaveBeenLastCalledWith(
|
|
expect.objectContaining({
|
|
issue_number: 42,
|
|
body: expect.stringContaining('failed again'),
|
|
}),
|
|
);
|
|
expect(api.update).not.toHaveBeenCalled();
|
|
|
|
vi.stubEnv('AUDIT_RESULT', 'success');
|
|
github.paginate.mockResolvedValueOnce([newerDecoy, issue]);
|
|
await updateDependencyAuditIssue({ github, context });
|
|
expect(api.createComment).toHaveBeenLastCalledWith(
|
|
expect.objectContaining({
|
|
issue_number: 42,
|
|
body: expect.stringContaining('recovered'),
|
|
}),
|
|
);
|
|
expect(api.update).toHaveBeenCalledWith(
|
|
expect.objectContaining({ issue_number: 42, state: 'closed' }),
|
|
);
|
|
|
|
api.create.mockClear();
|
|
api.createComment.mockClear();
|
|
api.update.mockClear();
|
|
github.paginate.mockResolvedValueOnce([]);
|
|
await updateDependencyAuditIssue({ github, context });
|
|
expect(api.create).not.toHaveBeenCalled();
|
|
expect(api.createComment).not.toHaveBeenCalled();
|
|
expect(api.update).not.toHaveBeenCalled();
|
|
expect(github.paginate).toHaveBeenCalledWith(
|
|
api.listForRepo,
|
|
expect.objectContaining({
|
|
state: 'open',
|
|
sort: 'created',
|
|
direction: 'desc',
|
|
}),
|
|
);
|
|
|
|
github.paginate.mockClear();
|
|
vi.stubEnv('AUDIT_RESULT', 'cancelled');
|
|
await updateDependencyAuditIssue({ github, context });
|
|
vi.unstubAllEnvs();
|
|
await updateDependencyAuditIssue({ github, context });
|
|
expect(github.paginate).not.toHaveBeenCalled();
|
|
expect(api.create).not.toHaveBeenCalled();
|
|
expect(api.createComment).not.toHaveBeenCalled();
|
|
expect(api.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|