ci: pin black and flake8, let the bandit hook fail, cache npm in the JS job (#352)
The lint job installs black==26.10.1 and flake8==7.4.1 from requirements-dev.txt (the versions CI resolved on main today), so a new release cannot turn CI red with no code change. The local bandit hook ran 'bash -c ... "$@"; true': it could never fail, and bash bound the first staged file to $0 so it was never scanned. It now runs 'bandit -lll -q' directly, failing on high severity exactly like code-quality.yml. The frontend modules job's setup-node caches npm keyed on tools/vendor/package-lock.json.
This commit is contained in:
@@ -221,7 +221,10 @@ jobs:
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: pip install black flake8
|
||||
cache: pip
|
||||
cache-dependency-path: requirements-dev.txt
|
||||
# The exact black and flake8 pins from requirements-dev.txt, so a new release cannot turn CI red.
|
||||
- run: pip install $(grep -E '^(black|flake8)==' requirements-dev.txt)
|
||||
- run: black --check .
|
||||
- run: flake8 .
|
||||
|
||||
@@ -235,6 +238,8 @@ jobs:
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: npm
|
||||
cache-dependency-path: tools/vendor/package-lock.json
|
||||
|
||||
- name: Check shipped extension and page modules parse
|
||||
run: |
|
||||
|
||||
@@ -13,9 +13,11 @@ repos:
|
||||
language: system
|
||||
types: [python]
|
||||
|
||||
# Fails at the severity CI enforces (code-quality.yml: -lll, high only), never stricter.
|
||||
# pre-commit appends the staged files, so no shell wrapper can drop the first one.
|
||||
- id: bandit
|
||||
name: bandit
|
||||
entry: bash -c 'bandit "$@" -ll -q 2>&1; true'
|
||||
entry: bandit -lll -q
|
||||
language: system
|
||||
types: [python]
|
||||
exclude: ^(tests/|reference/)
|
||||
|
||||
@@ -8,8 +8,8 @@ coverage>=7.16.2
|
||||
numpy>=2.2.6 # WD14 engine tests
|
||||
|
||||
# Code quality
|
||||
black>=26.10.1
|
||||
flake8>=7.4.1
|
||||
black==26.10.1
|
||||
flake8==7.4.1
|
||||
|
||||
# Security scanning
|
||||
bandit[toml]>=1.9.4
|
||||
|
||||
Vendored
+29
@@ -247,3 +247,32 @@ test('the Python matrix and coverage run the suite through the watchdog runner',
|
||||
assert.doesNotMatch(found.get(id), /unittest discover/, `${id} no longer runs the bare unittest discover`);
|
||||
}
|
||||
});
|
||||
|
||||
// CI hygiene (#352): lint tools are pinned, the bandit hook can fail, the JS job caches npm.
|
||||
const readRepoFile = path => readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8');
|
||||
|
||||
test('black and flake8 are pinned exactly and the lint job installs those pins', () => {
|
||||
const requirements = readRepoFile('requirements-dev.txt');
|
||||
assert.match(requirements, /^black==\d+\.\d+\.\d+$/m, 'black is pinned exactly');
|
||||
assert.match(requirements, /^flake8==\d+\.\d+\.\d+$/m, 'flake8 is pinned exactly');
|
||||
const lint = jobs(readWorkflow('test.yml')).get('lint');
|
||||
assert.match(lint, /pip install \$\(grep -E '\^\(black\|flake8\)==' requirements-dev\.txt\)/);
|
||||
assert.doesNotMatch(lint, /pip install black flake8/, 'lint no longer installs the latest releases');
|
||||
});
|
||||
|
||||
test('the frontend modules job caches npm keyed on the vendor lockfile', () => {
|
||||
const setupNode = steps(jobs(readWorkflow('test.yml')).get('js-test'))
|
||||
.find(step => /uses: actions\/setup-node@v\d+/.test(step));
|
||||
assert.match(setupNode, /^ {10}cache: npm$/m);
|
||||
assert.match(setupNode, /^ {10}cache-dependency-path: tools\/vendor\/package-lock\.json$/m);
|
||||
});
|
||||
|
||||
test('the bandit pre-commit hook fails at the severity CI enforces and passes every file', () => {
|
||||
const quality = readWorkflow('code-quality.yml');
|
||||
assert.match(quality, /^ {8}run: bandit -r \. -lll -q --exclude /m, 'CI fails on high severity');
|
||||
const hook = /- id: bandit\n([\s\S]*?)(?=\n {6}(?:- id:|#)|\n*$)/.exec(readRepoFile('.pre-commit-config.yaml'))?.[1];
|
||||
assert.ok(hook, 'the bandit hook exists');
|
||||
assert.match(hook, /^ {8}entry: bandit -lll -q$/m, 'the hook enforces the same -lll level as CI');
|
||||
assert.doesNotMatch(hook, /true|exit-zero|bash -c/, 'nothing masks the exit code or drops a file');
|
||||
assert.doesNotMatch(hook, /pass_filenames: false/, 'the hook scans the staged files');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user