Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions .github/workflows/python_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ jobs:
if: steps.changed-files-py.outputs.any_changed == 'true'
run: python admin/scripts/check_source_path.py

# scripts/vendor/ holds code copied verbatim from another repository, so it
# drifts in two directions and both are silent: an edit here looks like a fix
# until the next re-vendor reverts it, and an upstream release leaves this copy
# quietly old. Unconditional rather than gated on changed Python files, because
# the recorded hashes live in a .json and a stale record is the same defect.
- name: Check vendored files match what was vendored
run: python admin/scripts/check_vendored.py

# Fails only on warnings this pull request introduces. vleapp.py and
# vleappGUI.py carry pre-existing warnings that are structural rather than
# fixable -- wildcard imports are how those modules are put together -- so
Expand Down
100 changes: 100 additions & 0 deletions admin/scripts/check_vendored.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Confirm the vendored third-party files still match what was vendored.

Vendored code is a copy, so it drifts in two directions and both are silent. A
local edit looks like a fix until the next re-vendor reverts it, and an upstream
release leaves this copy quietly old. Neither shows up in a diff of this repo.

The recorded hash lives in scripts/vendor/vendored.json, written when the file was
vendored. This compares the file on disk against that record, and can additionally
diff against a checkout of the upstream repository.

python3 admin/scripts/check_vendored.py # CI: has the copy changed?
python3 admin/scripts/check_vendored.py --upstream ../qnxprobe
python3 admin/scripts/check_vendored.py --update # after a deliberate re-vendor
"""

from __future__ import annotations

import argparse
import hashlib
import json
import os
import sys

REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
MANIFEST = os.path.join(REPO, 'scripts', 'vendor', 'vendored.json')


def sha256(path):
with open(path, 'rb') as handle:
return hashlib.sha256(handle.read()).hexdigest()


def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--upstream', metavar='DIR',
help='a checkout of the upstream repo, to compare against as well')
parser.add_argument('--update', action='store_true',
help='rewrite the recorded hashes from the files on disk, '
'for use only after a deliberate re-vendor')
args = parser.parse_args()

with open(MANIFEST, encoding='utf-8') as handle:
manifest = json.load(handle)

problems = []
for entry in manifest['vendored']:
path = os.path.join(REPO, entry['path'])
if not os.path.isfile(path):
problems.append(f"{entry['path']}: recorded in the manifest but not on disk")
continue
actual = sha256(path)
if args.update:
entry['sha256'] = actual
print(f" recorded {entry['path']} at {actual}")
continue
if actual != entry['sha256']:
problems.append(
f"{entry['path']}: does not match what was vendored\n"
f" recorded {entry['sha256']}\n"
f" on disk {actual}\n"
f" Either it was edited here, which is not the place to fix it, or it was\n"
f" re-vendored without running --update.")
continue
print(f" {entry['path']} matches {entry['name']} {entry['version']} "
f"({entry['commit'][:7]})")

if args.upstream:
up = os.path.join(args.upstream, entry['upstream_file'])
if not os.path.isfile(up):
problems.append(f"{entry['path']}: --upstream given but {up} is not there")
elif sha256(up) != actual:
problems.append(
f"{entry['path']}: upstream has moved on\n"
f" vendored {actual}\n"
f" upstream {sha256(up)}\n"
f" Re-vendor if the upstream change is wanted here.")
else:
print(f" and matches the upstream checkout at {args.upstream}")

if args.update:
with open(MANIFEST, 'w', encoding='utf-8') as handle:
json.dump(manifest, handle, indent=2)
handle.write('\n')
print('manifest updated')
return 0

if problems:
print('\nVendored files have drifted:\n')
for p in problems:
print(f' {p}\n')
return 1

print(f"\n{len(manifest['vendored'])} vendored file(s), all matching what was recorded.")
return 0


if __name__ == '__main__':
sys.exit(main())
17 changes: 16 additions & 1 deletion admin/scripts/lint_changed.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
PYLINT_ARGS = ['--disable=C,R', '--persistent=no', '--output-format=json']


VENDOR_PREFIX = 'scripts/vendor/'


def run_pylint(repo_dir, paths):
"""Return Counter keyed by (path, symbol) for paths that exist in repo_dir."""
present = [p for p in paths if os.path.exists(os.path.join(repo_dir, p))]
Expand Down Expand Up @@ -73,8 +76,20 @@ def main():
args = parser.parse_args()

paths = [p for p in args.paths if p.endswith('.py')]

# scripts/vendor/ is code copied verbatim from another repository. Linting it
# would fail this job on warnings that are not ours to fix, and the only ways to
# silence them are editing the copy or adding a file-level disable, both of which
# make the next re-vendor a merge instead of a copy. check_vendored.py is what
# guards that directory, by hash rather than by style.
skipped = [p for p in paths if p.replace(os.sep, '/').startswith(VENDOR_PREFIX)]
if skipped:
print('Not linting vendored files (guarded by check_vendored.py instead):\n'
+ '\n'.join(f' {p}' for p in skipped) + '\n')
paths = [p for p in paths if p not in skipped]

if not paths:
print('No Python files changed.')
print('No Python files to lint.')
return 0

print('Linting:\n' + '\n'.join(f' {p}' for p in paths) + '\n')
Expand Down
21 changes: 21 additions & 0 deletions scripts/vendor/LICENSE-qnxprobe
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Alexis Brignoni

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
34 changes: 34 additions & 0 deletions scripts/vendor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Vendored third-party readers

Code copied in from another repository, unmodified, so VLEAPP can read image
formats without asking the examiner to install anything.

## qnxprobe.py

| | |
| --- | --- |
| upstream | https://github.com/abrignoni/qnxprobe |
| commit | `3c3259a3f89a953af156eddbd0727313ccf8281f` |
| dated | 2026-08-27T02:27:13-05:00 |
| version | qnxprobe 1.3 |
| sha256 | 9f163a18db2c7b2f66cf6be09a8c6a260ead4d993f0311c56ee55945dfe0863c |
| licence | MIT, kept beside it as LICENSE-qnxprobe |

Reads QNX6 and ext2/3/4 volumes out of a raw image without mounting and with no
administrator rights. Python 3 standard library only, so vendoring it adds no
dependency to requirements.txt.

**It is copied verbatim. Do not edit it here.** Fix upstream, then re-vendor, or
the next sync silently reverts the change.

### Re-vendoring

cp ../qnxprobe/qnxprobe.py scripts/vendor/qnxprobe.py
python3 admin/scripts/check_vendored.py --update

### Checking for drift

`admin/scripts/check_vendored.py` compares this copy against the sha256 recorded
above and fails when they differ. It runs in CI, so a local edit or a stale copy
after an upstream release is caught rather than noticed later. Pass
`--upstream <path>` to also diff against a checkout of the upstream repo.
Loading
Loading