Skip to content

ci(python): add advisory ty type checking with SARIF reporting - #3752

Draft
mcosgriff wants to merge 13 commits into
mainfrom
add-python-type-checking-astral-ty
Draft

ci(python): add advisory ty type checking with SARIF reporting#3752
mcosgriff wants to merge 13 commits into
mainfrom
add-python-type-checking-astral-ty

Conversation

@mcosgriff

@mcosgriff mcosgriff commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 1 of #3651 — bring-up only. ty runs on every Python PR with --exit-zero, so it reports but cannot block a merge.

  • Results publish as SARIF to code scanning, appearing as a ty check run beside CodeQL. Rule ids are namespaced ty/ so they're distinguishable in the Rule filter, and each links to its rule docs.
  • tools/ty_report.py converts ty's GitLab JSON to SARIF, since ty can't emit it and its github format uses absolute paths that never attach to a diff.
  • tools/generate_singleton_stubs.py plus the five .pyi it generates take the count 820 → 679, by teaching ty that the singleton metaclasses forward to cls.instance(). just stubs-check fails CI if a stub goes stale.
  • CI hardening: one composite action holds the uv version (three were in effect), --frozen is enforced rather than caller-supplied, and the static-analysis jobs build no source distributions.
  • tool_version_check files a tracking issue for the pins dependabot can't see — Actions inputs, Dockerfile ARGs, PEP 723 headers.

The remaining 679 are deliberately untouched; roughly half trace to ~30 declarations rather than 679 distinct problems. Phase 2 in #3651 covers the fixes and removing --exit-zero.

Test plan

  • just stubs-check passes, and just stubs twice produces no diff
  • just typecheck reports 679
  • uv run --frozen pytest green (2820 tests) — stubs must not affect runtime
  • just verify clean, including the new .pyi and tools/
  • ty check run appears on this PR; annotations only on lines the PR touched
  • the ty steps do not fail the build with diagnostics present

Refs #3651
Associated https://github.com/OpenC3/cosmos-enterprise/pull/716

- Add python_type_check.yml alongside python_lint, running ty with
  --exit-zero so it annotates but never fails the build yet
- Add tools/ty_report.py to convert ty's GitLab JSON into SARIF for
  code scanning, since ty cannot emit SARIF and its paths need
  rewriting to be repo-root relative
- Add tools/generate_singleton_stubs.py and the five .pyi it emits, so
  metaclass-forwarded calls like Logger.info("msg") check correctly;
  drops diagnostics from 816 to 675
- Pass --no-build and --no-install-project to every uv step, so no
  build backend executes in CI
- Add ty dev dependency plus just stubs and typecheck recipes

Co-Authored-By: Claude noreply@anthropic.com
@mcosgriff mcosgriff self-assigned this Aug 20, 2026
@socket-security

socket-security Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​ty@​0.0.73100100100100100
Updatedpypi/​ruff@​0.16.1 ⏵ 0.16.4100 +1100100100100

View full report

@github-advanced-security

Copy link
Copy Markdown
Contributor

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.10%. Comparing base (dbff03d) to head (0d8eeef).
⚠️ Report is 57 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3752      +/-   ##
==========================================
- Coverage   80.01%   79.10%   -0.91%     
==========================================
  Files         885      894       +9     
  Lines       65382    66857    +1475     
  Branches     2543     2543              
==========================================
+ Hits        52313    52885     +572     
- Misses      12407    13310     +903     
  Partials      662      662              
Flag Coverage Δ
frontend 66.02% <ø> (-0.06%) ⬇️
python 79.28% <ø> (-2.58%) ⬇️
ruby-api 81.68% <ø> (-0.50%) ⬇️
ruby-backend 84.44% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Lock the PEP 723 dependencies of both tools scripts and pass --locked
  everywhere, so a new mypy or ruff release cannot silently change what
  runs or make stubs-check report spurious drift
- Validate --input, --sarif and --markdown in ty_report.py before
  touching the file system, confining them to the repo, cwd, temp dir
  and the paths the runner declares via GITHUB_STEP_SUMMARY and friends
- Reject traversing arguments, symlinks, directories and missing
  parents with a clear message and exit 1 instead of writing

Co-Authored-By: Claude noreply@anthropic.com
- Constrain every field ty_report.py parses from ty's JSON: rule names
  must be kebab-case or become unknown-rule, helpUri is emitted only for
  names that matched, and line/column are clamped to SARIF positions
- Drop diagnostics whose path escapes the repository, which previously
  leaked the runner's absolute filesystem paths into the SARIF
- Escape values interpolated into the markdown summary, so a crafted
  rule name cannot close the link and inject its own into the summary
- Reject non-list input and malformed entries with a specific message
  instead of raising TypeError partway through the report
- Add tools to the ty check paths and group _typeshed with the standard
  library, so the generated stubs sort the way a reader expects

Co-Authored-By: Claude noreply@anthropic.com
- Replace the ruff and ty version ranges with exact pins: ruff's
  formatter decides whether the generated stubs still match, and any ty
  0.0.x release can change which diagnostics are reported
- Pin the stub generator's script dependencies the same way, which
  bumps mypy 1.20.2 to 2.3.1 now that a <2 cap no longer holds it back
- Hold ruff at 0.16.4 in both uv.lock and the script lockfile, so
  just format and just stubs cannot disagree about formatting

Co-Authored-By: Claude noreply@anthropic.com
- Add .github/actions/setup-uv-python and route all five uv workflows
  through it, so one file holds the uv version instead of the three that
  were in effect: 0.10.4, 0.12.5, and unpinned
- Give the action a hardcoded --frozen and boolean flags rather than a
  caller-supplied argument string, so no call site can skip the lockfile
- Add tool_version_check to watch the pins dependabot cannot see, filing
  one tracking issue for versions in Actions inputs, Dockerfile ARGs and
  PEP 723 script headers
- Split github-actions majors into their own dependabot group, since one
  group is one pull request and a single breaking action upgrade would
  otherwise block every routine bump
- Set setup-uv's working-directory everywhere, so cache discovery finds
  openc3/python/uv.lock instead of a repository root without one

Co-Authored-By: Claude noreply@anthropic.com
Comment thread .github/scripts/check_tool_versions.py Fixed
mcosgriff and others added 8 commits August 21, 2026 10:24
…ring sanitization'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Accumulating it into a bash array left the lockfile guarantee invisible
to both readers and scanners, though the flag was always present. Only
the optional flags build up in a variable now; behavior is unchanged.

Co-Authored-By: Claude noreply@anthropic.com
v9 stopped pruning the cache by default and v10 disables caching for
pull_request_target, workflow_run and release when enable-cache is auto.
Neither applies here: every call site sets enable-cache explicitly and
no workflow triggers on those events.

Co-Authored-By: Claude noreply@anthropic.com
The job syncs with openc3 installed as an editable project, and uv
revalidates that install on every uv run, so --no-build fails with
"can't be installed because it is marked as --no-build but has no
binary distribution" and exits 2. It only works where the job also
passes --no-install-project.
ruff parses files and never imports them, so the lint job has no use
for the editable openc3 install. Skipping it is what allows --no-build,
which keeps any third-party build backend from executing in that job.
Code scanning renders the rule id in its Rule filter, so a bare
unresolved-attribute is indistinguishable from another tool's rules.
CodeQL namespaces the same way with rb/ and go/ prefixes. The docs
anchor still uses the bare name, so helpUri is unaffected.
- Fix the ruff job, which exited 2: it skips the editable openc3
  install, and uv run --frozen re-evaluates whether that skipped
  project could be installed, rejecting it under --no-build
- Apply the same pair to the unit test uv run calls, so no third-party
  build backend executes there either; that job keeps the project
  installed, which pytest needs to import openc3
Both test signatures fit on one line at the configured 120 columns. The
file landed unformatted because python_lint only format-checks openc3
and the script-runner scripts, never test/.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants