Skip to content

Release 1.4.15 (2026-05-05)

Bug fixes

  • add explicit type annotations to read_json() for mypy
  • include enabled field in actions permissions PUT body

Chores

  • sweep post-1.4.14 dependency updates (#492)
  • Fix ci-security.yml pin: @v1.4.7 -> @v1.4 (patch-level pin should be floating major.minor)
  • All Python dependencies confirmed at latest via uv lock --upgrade (no changes)
  • All CI action pins confirmed at latest major versions
  • No anchored dependency records to review

Features

  • add desired state data model Dataclasses for DesiredRepoSettings, DesiredSecuritySettings, DesiredActionsPermissions, DesiredRuleset, and DesiredState. These represent the canonical GitHub configuration that the derivation engine computes and the CLI enforces.

  • add read_json() helper for gh api calls Wraps read_output() with JSON parsing. Used by the upcoming st-github-config tool for all GitHub API interactions. Ref #173

  • add [ci] section to standard-tooling.toml schema Adds CiConfig dataclass with versions (required list of language version strings) and integration-tests (optional bool). The [ci] section is optional for backward compatibility during rollout.

  • add [github] override section to TOML schema Adds GithubOverrides dataclass with skip-rulesets flag for repos that intentionally deviate from the standard (e.g., mq-rest-admin-template). Defaults to false — overrides are rare and their presence is a signal for review.

  • add fixed desired state functions Implement desired_security_settings(), desired_actions_permissions(), desired_branch_protection_ruleset(), and desired_tag_protection_ruleset(). These return the canonical config that is uniform across all repos.

  • add per-language command registry Centrally defines lint/typecheck/test/audit commands for each supported language (python, go, java, ruby, rust). Derived from audit of actual scripts/dev/*.sh across all managed repos.

  • add CI gates ruleset derivation Computes required status checks from project identity and CI config. Check names follow the canonical registry: uniform {category} / {name} or {category} / {name} / {version} format. Versioned checks consult the per-language command registry.

  • add compute_desired_state() top-level function Assembles full desired state from StConfig. Handles skip-rulesets override and gracefully omits CI gates when [ci] is absent.

  • add fetch_actual_state() for GitHub API reads Fetches repo settings, security settings, Actions permissions, and rulesets via gh api. Returns a DesiredState for comparison against the computed desired state.

  • add diff computation engine Compares desired vs actual DesiredState objects field-by-field, including ruleset-level comparison by name. Returns a ConfigDiff with is_compliant() for audit exit codes.

  • add st-github-config CLI with audit and diff modes Creates the st-github-config entry point with audit/diff/apply subcommands and --repo / --owner+--project targeting. Audit mode fetches remote config, computes desired state, compares to actual, and exits 1 if non-compliant. Diff mode always exits 0.

Extracts _parse_raw_config() from read_config() to support remote config parsing without local file I/O.

  • implement apply mode for st-github-config CLI Adds the ability to enforce desired GitHub configuration by applying changes via the GitHub API. Covers repo settings, security settings, actions permissions, and ruleset CRUD (create/update/delete by name).

  • Add write_json() and delete() helpers to github.py

  • Add apply_desired_state() orchestrator to github_config.py
  • Wire up apply subcommand with confirmation prompt (--yes to skip)
  • 662 tests, 100% branch coverage

  • add classic branch protection cleanup during apply When applying desired state, legacy branch protection rules are now detected and removed for branches covered by the new rulesets. This completes the migration path from classic branch protection to the repository rulesets API.

  • Add delete_if_exists() helper to github.py (returns bool for 404 vs success)

  • Add _cleanup_classic_branch_protection() to remove legacy rules
  • apply_desired_state() now returns list of branches where legacy protection was removed
  • CLI reports which branches had legacy protection cleared
  • 671 tests, 100% branch coverage

Part of #173

Styling

  • format test_config.py with ruff
  • apply ruff format to new files

Testing

  • cover _lang_has_check unknown check kind branch