From d168915d4f1194aef7025760bac1b723be5b0897 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Sun, 21 Jun 2026 19:45:04 -0700 Subject: [PATCH 01/14] Fix shallow clone in release workflow --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aaf3c7b..5da772b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,8 @@ jobs: steps: - name: Checkout source code uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 From fca5266957177a848e82e94e9ba529fe5174ce2a Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Sun, 21 Jun 2026 19:46:23 -0700 Subject: [PATCH 02/14] Bump to 1.25.1 --- README.md | 8 ++++---- setup.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index caf4da7..23d4ff7 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ For any hook in this repo you wish to use, add the following to your pre-commit ```yaml - repo: https://github.com/homebysix/pre-commit-macadmin - rev: v1.25.0 + rev: v1.25.1 hooks: - id: check-plists # - id: ... @@ -148,7 +148,7 @@ When combining arguments that take lists (for example: `--required-keys`, `--cat ```yaml - repo: https://github.com/homebysix/pre-commit-macadmin - rev: v1.25.0 + rev: v1.25.1 hooks: - id: check-munki-pkgsinfo args: ['--catalogs', 'testing', 'stable', '--'] @@ -158,7 +158,7 @@ But if you also use the `--categories` argument, you would move the trailing `-- ```yaml - repo: https://github.com/homebysix/pre-commit-macadmin - rev: v1.25.0 + rev: v1.25.1 hooks: - id: check-munki-pkgsinfo args: ['--catalogs', 'testing', 'stable', '--categories', 'Design', 'Engineering', 'Web Browsers', '--'] @@ -170,7 +170,7 @@ If it looks better to your eye, feel free to use a multi-line list for long argu ```yaml - repo: https://github.com/homebysix/pre-commit-macadmin - rev: v1.25.0 + rev: v1.25.1 hooks: - id: check-munki-pkgsinfo args: [ diff --git a/setup.py b/setup.py index 2520557..e33c8aa 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name="pre-commit-macadmin", description="Pre-commit hooks for Mac admins, client engineers, and IT consultants.", url="https://github.com/homebysix/pre-commit-macadmin", - version="1.25.0", + version="1.25.1", author="Elliot Jordan", author_email="elliot@elliotjordan.com", packages=["pre_commit_macadmin_hooks"], From 1b3f59ac0437212365c3efa7bb1f90721c361483 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Tue, 30 Jun 2026 11:50:02 -0700 Subject: [PATCH 03/14] Reverify pkginfo types against Munki wiki --- pre_commit_macadmin_hooks/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre_commit_macadmin_hooks/util.py b/pre_commit_macadmin_hooks/util.py index de6328a..01e629d 100644 --- a/pre_commit_macadmin_hooks/util.py +++ b/pre_commit_macadmin_hooks/util.py @@ -213,7 +213,7 @@ def validate_pkginfo_key_types(pkginfo: dict[str, Any], filename: str) -> bool: # Pkginfo keys and their known types. Omitted keys are left unvalidated. # Source: https://github.com/munki/munki/wiki/Supported-Pkginfo-Keys - # Last updated 2019-03-13. + # Last verified complete against the wiki 2026-06-30. pkginfo_types = { "additional_startosinstall_options": list, "apple_item": bool, From c98d376de88d018b4272beff700055816b12761e Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Tue, 14 Jul 2026 23:28:41 -0700 Subject: [PATCH 04/14] Fix miscalculated minimum AutoPkg versions --- CHANGELOG.md | 4 ++- .../autopkg_processor_versions.py | 36 ++++--------------- .../generate_autopkg_processor_versions.py | 3 +- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83f2501..73c4bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] -Nothing yet. +### Fixed + +- Fixed a bug in `generate_autopkg_processor_versions.py` that caused argument-introduction versions to be miscalculated for any AutoPkg release with Python 2-only syntax. The regex/tokenizer fallback parser used for those releases only recognized the first key of each `input_variables` dict, so most arguments were misattributed to whichever later release first became parseable by Python 3's `ast` module (typically reported as AutoPkg 1.1), causing `check-autopkg-recipes` to falsely flag long-standing recipes. ## [1.25.0] - 2026-06-21 diff --git a/pre_commit_macadmin_hooks/autopkg_processor_versions.py b/pre_commit_macadmin_hooks/autopkg_processor_versions.py index 14019be..fc7bde0 100644 --- a/pre_commit_macadmin_hooks/autopkg_processor_versions.py +++ b/pre_commit_macadmin_hooks/autopkg_processor_versions.py @@ -7,10 +7,6 @@ }, "AppPkgCreator": { "_introduced_": "1.0", - "bundleid": "1.1", - "force_pkg_build": "1.1", - "pkg_path": "1.1", - "version": "1.1", "version_key": "2.4.1", }, "BrewCaskInfoProvider": { @@ -40,8 +36,6 @@ }, "Copier": { "_introduced_": "0.1.0", - "destination_path": "1.1", - "overwrite": "1.1", }, "DeprecationWarning": { "_introduced_": "1.1", @@ -61,7 +55,7 @@ }, "FileCreator": { "_introduced_": "0.1.0", - "file_mode": "1.1", + "file_mode": "0.5.0", }, "FileFinder": { "_introduced_": "0.2.3", @@ -74,7 +68,6 @@ }, "FlatPkgPacker": { "_introduced_": "0.2.4", - "destination_pkg": "1.1", }, "FlatPkgUnpacker": { "_introduced_": "0.1.0", @@ -101,20 +94,14 @@ "MunkiImporter": { "_introduced_": "0.1.0", "MUNKILIB_DIR": "2.2", - "MUNKI_PKGINFO_FILE_EXTENSION": "1.1", + "MUNKI_PKGINFO_FILE_EXTENSION": "0.3.0", "MUNKI_REPO": "0.2.5", "MUNKI_REPO_PLUGIN": "2.2", - "additional_makepkginfo_options": "1.1", "extract_icon": "2.2", "force_munki_repo_lib": "2.2", - "force_munkiimport": "1.1", "metadata_additions": "1.1", - "munkiimport_appname": "1.1", - "munkiimport_pkgname": "1.1", - "pkginfo": "1.1", - "repo_subdirectory": "1.1", - "uninstaller_pkg_path": "1.1", - "version_comparison_key": "1.1", + "uninstaller_pkg_path": "1.0.0", + "version_comparison_key": "0.3.0", }, "MunkiInfoCreator": { "_introduced_": "0.1.0", @@ -148,7 +135,6 @@ }, "PkgExtractor": { "_introduced_": "0.1.0", - "extract_root": "1.1", }, "PkgInfoCreator": { "_introduced_": "0.1.0", @@ -161,12 +147,9 @@ }, "PlistEditor": { "_introduced_": "0.1.0", - "output_plist_path": "1.1", - "plist_data": "1.1", }, "PlistReader": { "_introduced_": "0.2.5", - "plist_keys": "0.4.0", }, "SignToolVerifier": { "_introduced_": "2.3", @@ -187,14 +170,10 @@ }, "URLDownloader": { "_introduced_": "0.1.0", - "CHECK_FILESIZE_ONLY": "1.1", - "CURL_PATH": "1.1", - "PKG": "1.1", - "curl_opts": "1.1", - "download_dir": "1.1", - "filename": "1.1", + "CHECK_FILESIZE_ONLY": "0.6.0", + "CURL_PATH": "0.6.0", + "curl_opts": "1.0.4", "prefetch_filename": "1.4", - "request_headers": "1.1", }, "URLDownloaderPython": { "_introduced_": "2.4.1", @@ -217,7 +196,6 @@ }, "Versioner": { "_introduced_": "0.1.0", - "plist_version_key": "1.1", "skip_single_root_dir": "2.3", }, } diff --git a/scripts/generate_autopkg_processor_versions.py b/scripts/generate_autopkg_processor_versions.py index 9933520..3ab595e 100644 --- a/scripts/generate_autopkg_processor_versions.py +++ b/scripts/generate_autopkg_processor_versions.py @@ -286,8 +286,7 @@ def string_keys_at_top_dict_level(dict_source: str) -> set[str]: level += 1 elif token.string in "}])": level -= 1 - if token.string not in ",\n": - previous_significant = token.string + previous_significant = token.string continue if token.type == tokenize.STRING and level == 1: try: From d006dfd83dbd598c3bd0a1f09cd0d4b02d408f5a Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:15:30 -0700 Subject: [PATCH 05/14] Prepare 1.25.1 release --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73c4bb0..5c029c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] +Nothing yet. + +## [1.25.1] - 2026-07-15 + ### Fixed - Fixed a bug in `generate_autopkg_processor_versions.py` that caused argument-introduction versions to be miscalculated for any AutoPkg release with Python 2-only syntax. The regex/tokenizer fallback parser used for those releases only recognized the first key of each `input_variables` dict, so most arguments were misattributed to whichever later release first became parseable by Python 3's `ast` module (typically reported as AutoPkg 1.1), causing `check-autopkg-recipes` to falsely flag long-standing recipes. @@ -506,7 +510,8 @@ All notable changes to this project will be documented in this file. This projec - Initial release -[Unreleased]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.25.0...HEAD +[Unreleased]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.25.1...HEAD +[1.25.1]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.25.0...v1.25.1 [1.25.0]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.24.1...v1.25.0 [1.24.1]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.24.0...v1.24.1 [1.24.0]: https://github.com/homebysix/pre-commit-macadmin/compare/v1.23.0...v1.24.0 From d659857ebf9d1862db2d0c26048e516e8691a49a Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:37:53 -0700 Subject: [PATCH 06/14] Gate release publishing on tests passing --- .github/workflows/release.yml | 25 +++++++++++++++++++++++++ CHANGELOG.md | 4 +++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5da772b..80fddd5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,8 +10,33 @@ on: - ".github/workflows/release.yml" jobs: + test: + name: Run tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + run: | + python -m pip install --upgrade pip + pip install -e . + + - name: Run tests + run: python -m unittest discover -s tests -v + release: name: Create GitHub Release + needs: test runs-on: ubuntu-latest steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c029c5..966e4b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] -Nothing yet. +### Fixed + +- The release workflow now runs the test suite and requires it to pass before publishing a release. ## [1.25.1] - 2026-07-15 From 7202ad143a180a421bf0ef43f71b474e01b6c3c7 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:39:48 -0700 Subject: [PATCH 07/14] Add regression test for Python 2 fallback parser --- ...est_generate_autopkg_processor_versions.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/test_generate_autopkg_processor_versions.py b/tests/test_generate_autopkg_processor_versions.py index 98e9e5f..fbef1b9 100644 --- a/tests/test_generate_autopkg_processor_versions.py +++ b/tests/test_generate_autopkg_processor_versions.py @@ -1,4 +1,5 @@ import argparse +import ast import subprocess import tempfile import unittest @@ -87,6 +88,41 @@ def generate_text(self, repo, output_path, **overrides): def test_normalize_tag_version_accepts_bare_tags(self): self.assertEqual(generator.normalize_tag_version("v1.1")[0], "1.1") + def test_fallback_parses_all_keys_from_python2_only_source(self): + source = "\n".join( + [ + "from autopkglib import Processor", + "", + "class ExampleProcessor(Processor):", + " input_variables = {", + ' "url": {"required": True},', + ' "download_dir": {"required": False},', + ' "filename": {"required": False},', + ' "PKG": {"required": False},', + " }", + "", + " def main(self):", + " try:", + " pass", + " except Exception, e:", + " pass", + "", + ] + ) + + # Confirm this source needs the regex/tokenizer fallback, i.e. it + # reproduces the conditions of the regression (Python-2-only syntax + # that ast.parse cannot handle). + with self.assertRaises(SyntaxError): + ast.parse(source) + + info = generator.parse_processor_source(source) + + self.assertEqual( + info["ExampleProcessor"].args, + {"url", "download_dir", "filename", "PKG"}, + ) + def test_full_generation_detects_argument_added_after_file_move(self): with tempfile.TemporaryDirectory() as tmp: tmp_path = Path(tmp) From ca780da6c6aebdc71abb84e2a626017f928b04e2 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:41:19 -0700 Subject: [PATCH 08/14] Clarify release version determination in docs --- CHANGELOG.md | 4 ++++ RELEASING.md | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 966e4b8..3890413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] +### Changed + +- Clarified RELEASING.md on which version to use when preparing a release, since the release workflow auto-bumps `setup.py` on `dev` to the next patch version after each release. + ### Fixed - The release workflow now runs the test suite and requires it to pass before publishing a release. diff --git a/RELEASING.md b/RELEASING.md index 7d0dabd..aa305d8 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -4,6 +4,8 @@ Releases are largely automated via GitHub Actions. The workflow triggers when `s ## Release Process +1. Determine the version to release. After each release, the workflow auto-bumps `setup.py` on `dev` to the next **patch** version — so for a normal patch release, `setup.py` on `dev` already holds the correct next version; use that value as-is in the steps below. Only edit `setup.py` yourself first if you're bumping the **minor** or **major** version instead (see [Version Numbering](#version-numbering)). + 1. On the `dev` branch, check unit tests: .venv/bin/python -m coverage run -m unittest discover -vs tests @@ -15,7 +17,7 @@ Releases are largely automated via GitHub Actions. The workflow triggers when `s Use `--full` when the generator logic changes, historical AutoPkg tags are added or corrected, or you need to rebuild from AutoPkg `0.1.0`. The default mode appends stable releases newer than the checked-in `last_walked_version`. -1. Prepare CHANGELOG.md for release by moving `[Unreleased]` changes to a new version section: +1. Prepare CHANGELOG.md for release by moving `[Unreleased]` changes to a new version section, using the version determined in step 1 above for `X.Y.Z`: ## [Unreleased] @@ -32,7 +34,7 @@ Releases are largely automated via GitHub Actions. The workflow triggers when `s [X.Y.Z]: https://github.com/homebysix/pre-commit-macadmin/compare/vPREVIOUS...vX.Y.Z -1. Update the version in `setup.py` to match the CHANGELOG version (e.g., `2.3.6`). +1. Confirm the version in `setup.py` matches the CHANGELOG version (e.g., `2.3.6`). For a normal patch release this should already be true from the auto-bump; only change it here if you're doing a minor/major release. 1. Update the version in `README.md` examples to match (e.g., `rev: v2.3.6`). From ccbb9ce88ed0ed6527b90533ddeadcb9466e4562 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:43:30 -0700 Subject: [PATCH 09/14] Fix crash on invalid MinimumVersion string --- CHANGELOG.md | 1 + pre_commit_macadmin_hooks/check_autopkg_recipes.py | 13 ++++++++++--- tests/test_check_autopkg_recipes.py | 11 +++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3890413..65c4dfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. This projec ### Fixed - The release workflow now runs the test suite and requires it to pass before publishing a release. +- `check-autopkg-recipes` now reports an invalid `MinimumVersion` string as a lint error instead of crashing with an uncaught exception. ## [1.25.1] - 2026-07-15 diff --git a/pre_commit_macadmin_hooks/check_autopkg_recipes.py b/pre_commit_macadmin_hooks/check_autopkg_recipes.py index ef50ccf..ebaddc3 100755 --- a/pre_commit_macadmin_hooks/check_autopkg_recipes.py +++ b/pre_commit_macadmin_hooks/check_autopkg_recipes.py @@ -8,7 +8,7 @@ import sys from typing import Any -from packaging.version import Version +from packaging.version import InvalidVersion, Version from pre_commit_macadmin_hooks.autopkg_processor_versions import PROC_VERSIONS from pre_commit_macadmin_hooks.util import ( @@ -190,7 +190,14 @@ def validate_minimumversion(process, min_vers, ignore_min_vers_before, filename) # Validate that the MinimumVersion value is a string if not isinstance(min_vers, str): print(f"{filename}: MinimumVersion should be a string.") - passed = False + return False + + # Validate that the MinimumVersion value is a parseable version string. + try: + min_vers_version = Version(min_vers) + except InvalidVersion: + print(f"{filename}: MinimumVersion {min_vers!r} is not a valid version string.") + return False # Validate that the MinimumVersion value fits the processors and processor # arguments used. Unknown processors and unknown arguments fail open. @@ -213,7 +220,7 @@ def validate_minimumversion(process, min_vers, ignore_min_vers_before, filename) if Version(required_version) < Version(ignore_min_vers_before): continue - if Version(str(min_vers)) < Version(required_version): + if min_vers_version < Version(required_version): print( f"{filename}: {proc_name} processor requires minimum AutoPkg " f"version {required_version}" diff --git a/tests/test_check_autopkg_recipes.py b/tests/test_check_autopkg_recipes.py index fc5fc36..0efcc48 100644 --- a/tests/test_check_autopkg_recipes.py +++ b/tests/test_check_autopkg_recipes.py @@ -127,6 +127,17 @@ def test_validate_minimumversion_non_string(self): self.assertFalse(result) mock_print.assert_called_with("file.recipe: MinimumVersion should be a string.") + def test_validate_minimumversion_invalid_string(self): + process = [{"Processor": "AppPkgCreator"}] + with mock.patch("builtins.print") as mock_print: + result = target.validate_minimumversion( + process, "not-a-version", "1.0", "file.recipe" + ) + self.assertFalse(result) + mock_print.assert_called_with( + "file.recipe: MinimumVersion 'not-a-version' is not a valid version string." + ) + def test_validate_minimumversion_too_low(self): process = [{"Processor": "AppPkgCreator"}] with mock.patch("builtins.print") as mock_print: From 7d5b2e8401cc5d5c10af3cf4874014fcca600d3d Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:45:29 -0700 Subject: [PATCH 10/14] Fix crash on wrongly typed supported_architectures --- CHANGELOG.md | 1 + pre_commit_macadmin_hooks/util.py | 12 +++++++++--- tests/test_util.py | 12 ++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65c4dfe..7b9c38e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to this project will be documented in this file. This projec - The release workflow now runs the test suite and requires it to pass before publishing a release. - `check-autopkg-recipes` now reports an invalid `MinimumVersion` string as a lint error instead of crashing with an uncaught exception. +- `validate_supported_architectures` no longer crashes with a `TypeError` when `supported_architectures` is present but not a list; the type mismatch is still reported by `validate_pkginfo_key_types`. ## [1.25.1] - 2026-07-15 diff --git a/pre_commit_macadmin_hooks/util.py b/pre_commit_macadmin_hooks/util.py index 01e629d..7c3a791 100644 --- a/pre_commit_macadmin_hooks/util.py +++ b/pre_commit_macadmin_hooks/util.py @@ -192,9 +192,15 @@ def validate_supported_architectures( """ passed = True allowed_values = ("arm64", "x86_64") - if "supported_architectures" in pkginfo: - for arch in pkginfo["supported_architectures"]: - if recipe_mode and arch.startswith("%") and arch.endswith("%"): + architectures = pkginfo.get("supported_architectures") + if isinstance(architectures, list): + for arch in architectures: + if ( + recipe_mode + and isinstance(arch, str) + and arch.startswith("%") + and arch.endswith("%") + ): # Skip values that are substituted during AutoPkg recipe runs continue if arch not in allowed_values: diff --git a/tests/test_util.py b/tests/test_util.py index 9c484be..beb51d8 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -137,6 +137,18 @@ def test_validate_supported_architectures(self): d = {} self.assertTrue(validate_supported_architectures(d, "file")) + def test_validate_supported_architectures_wrong_type_does_not_crash(self): + # A wrongly typed value is reported separately by + # validate_pkginfo_key_types; this should fail open rather than crash. + d = {"supported_architectures": "arm64"} + self.assertTrue(validate_supported_architectures(d, "file")) + d = {"supported_architectures": None} + self.assertTrue(validate_supported_architectures(d, "file")) + d = {"supported_architectures": 1} + self.assertTrue(validate_supported_architectures(d, "file")) + d = {"supported_architectures": ["arm64", 1]} + self.assertFalse(validate_supported_architectures(d, "file", recipe_mode=True)) + def test_validate_pkginfo_key_types(self): d = { "catalogs": ["foo"], From 74dc2ad1277a4e14a5009b3e2360469b06a2d5e3 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:46:38 -0700 Subject: [PATCH 11/14] Declare python_requires>=3.10 in setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index e33c8aa..f91f0e7 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ author="Elliot Jordan", author_email="elliot@elliotjordan.com", packages=["pre_commit_macadmin_hooks"], + python_requires=">=3.10", install_requires=["ruamel.yaml>=0.15", "packaging>=23.2"], entry_points={ "console_scripts": [ From 69daa7ff678208dd5f2132cce09cb2e7ba082583 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 04:47:35 -0700 Subject: [PATCH 12/14] Move Unreleased changelog items into 1.25.1 --- CHANGELOG.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b9c38e..5c60831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,22 +12,21 @@ All notable changes to this project will be documented in this file. This projec ## [Unreleased] +Nothing yet. + +## [1.25.1] - 2026-07-15 + ### Changed - Clarified RELEASING.md on which version to use when preparing a release, since the release workflow auto-bumps `setup.py` on `dev` to the next patch version after each release. ### Fixed +- Fixed a bug in `generate_autopkg_processor_versions.py` that caused argument-introduction versions to be miscalculated for any AutoPkg release with Python 2-only syntax. The regex/tokenizer fallback parser used for those releases only recognized the first key of each `input_variables` dict, so most arguments were misattributed to whichever later release first became parseable by Python 3's `ast` module (typically reported as AutoPkg 1.1), causing `check-autopkg-recipes` to falsely flag long-standing recipes. - The release workflow now runs the test suite and requires it to pass before publishing a release. - `check-autopkg-recipes` now reports an invalid `MinimumVersion` string as a lint error instead of crashing with an uncaught exception. - `validate_supported_architectures` no longer crashes with a `TypeError` when `supported_architectures` is present but not a list; the type mismatch is still reported by `validate_pkginfo_key_types`. -## [1.25.1] - 2026-07-15 - -### Fixed - -- Fixed a bug in `generate_autopkg_processor_versions.py` that caused argument-introduction versions to be miscalculated for any AutoPkg release with Python 2-only syntax. The regex/tokenizer fallback parser used for those releases only recognized the first key of each `input_variables` dict, so most arguments were misattributed to whichever later release first became parseable by Python 3's `ast` module (typically reported as AutoPkg 1.1), causing `check-autopkg-recipes` to falsely flag long-standing recipes. - ## [1.25.0] - 2026-06-21 ### Added From 2292370bd42e18863e472b6db1b13d5a6ba0c802 Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 05:05:38 -0700 Subject: [PATCH 13/14] Add pkginfo type checks for 5 undocumented keys --- CHANGELOG.md | 4 ++++ pre_commit_macadmin_hooks/util.py | 12 ++++++++++-- tests/test_util.py | 9 +++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c60831..14648a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ Nothing yet. ## [1.25.1] - 2026-07-15 +### Added + +- `check-munki-pkgsinfo` and `check-autopkg-recipes` now validate the type of `allow_untrusted`, `icon_hash`, `installed_size_staged`, `uninstaller_item_hash`, and `uninstaller_item_size` pkginfo keys. These are set by current Munki 7 code but aren't yet documented on the Munki wiki. + ### Changed - Clarified RELEASING.md on which version to use when preparing a release, since the release workflow auto-bumps `setup.py` on `dev` to the next patch version after each release. diff --git a/pre_commit_macadmin_hooks/util.py b/pre_commit_macadmin_hooks/util.py index 7c3a791..8fbbf7c 100644 --- a/pre_commit_macadmin_hooks/util.py +++ b/pre_commit_macadmin_hooks/util.py @@ -218,10 +218,14 @@ def validate_pkginfo_key_types(pkginfo: dict[str, Any], filename: str) -> bool: """ # Pkginfo keys and their known types. Omitted keys are left unvalidated. - # Source: https://github.com/munki/munki/wiki/Supported-Pkginfo-Keys - # Last verified complete against the wiki 2026-06-30. + # Source: https://github.com/munki/munki/wiki/Supported-Pkginfo-Keys, plus + # keys confirmed against the Munki 7 Swift source that aren't yet + # documented on the wiki (allow_untrusted, icon_hash, installed_size_staged, + # uninstaller_item_hash, uninstaller_item_size). + # Last verified complete against the wiki 2026-06-30 and Munki source 2026-07-15. pkginfo_types = { "additional_startosinstall_options": list, + "allow_untrusted": bool, "apple_item": bool, "autoremove": bool, "blocking_applications": list, @@ -238,10 +242,12 @@ def validate_pkginfo_key_types(pkginfo: dict[str, Any], filename: str) -> bool: "force_install_after_date": datetime, "forced_install": bool, "forced_uninstall": bool, + "icon_hash": str, "icon_name": str, "installable_condition": str, "installcheck_script": str, "installed_size": int, + "installed_size_staged": int, "installer_choices_xml": list, "installer_environment": dict, "installer_item_hash": str, @@ -279,7 +285,9 @@ def validate_pkginfo_key_types(pkginfo: dict[str, Any], filename: str) -> bool: "uninstall_script": str, "uninstallable": bool, "uninstallcheck_script": str, + "uninstaller_item_hash": str, "uninstaller_item_location": str, + "uninstaller_item_size": int, "update_for": list, "version": str, "version_script": str, diff --git a/tests/test_util.py b/tests/test_util.py index beb51d8..761aa1b 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -159,6 +159,11 @@ def test_validate_pkginfo_key_types(self): "display_name_staged": "Example Installer", "minimum_os_version": "10.15.0", "OnDemand": True, + "allow_untrusted": True, + "icon_hash": "abc123", + "installed_size_staged": 1024, + "uninstaller_item_hash": "def456", + "uninstaller_item_size": 2048, } self.assertTrue(validate_pkginfo_key_types(d, "file")) d = {"description_staged": ["Ready to install"]} @@ -172,6 +177,10 @@ def test_validate_pkginfo_key_types(self): "OnDemand": True, } self.assertFalse(validate_pkginfo_key_types(d, "file")) + d = {"allow_untrusted": "true"} # should be bool + self.assertFalse(validate_pkginfo_key_types(d, "file")) + d = {"uninstaller_item_size": "2048"} # should be int + self.assertFalse(validate_pkginfo_key_types(d, "file")) def test_validate_shebangs(self): valid_script = "#!/bin/bash\nsomething" From be8d11b09869dd56c64a20dea3b7b49eca09bc5a Mon Sep 17 00:00:00 2001 From: Elliot Jordan Date: Wed, 15 Jul 2026 05:11:34 -0700 Subject: [PATCH 14/14] Fix regression test fixture for Python 3.14 grammar change --- tests/test_generate_autopkg_processor_versions.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_generate_autopkg_processor_versions.py b/tests/test_generate_autopkg_processor_versions.py index fbef1b9..881eaec 100644 --- a/tests/test_generate_autopkg_processor_versions.py +++ b/tests/test_generate_autopkg_processor_versions.py @@ -102,10 +102,7 @@ def test_fallback_parses_all_keys_from_python2_only_source(self): " }", "", " def main(self):", - " try:", - " pass", - " except Exception, e:", - " pass", + ' print "downloading"', "", ] )