Skip to content

ci: add reusable Pysa workflow#87

Merged
haasonsaas merged 2 commits into
mainfrom
codex/shared-pysa-ci-20260516
May 16, 2026
Merged

ci: add reusable Pysa workflow#87
haasonsaas merged 2 commits into
mainfrom
codex/shared-pysa-ci-20260516

Conversation

@haasonsaas
Copy link
Copy Markdown
Contributor

Summary

  • add a reusable Pyre/Pysa workflow for Python repositories
  • add a workflow-picker template and metadata for downstream adoption
  • document source directories, taint model paths, dependency setup, and generated Pyre config behavior

Test plan

  • ruby -e 'require "yaml"; ARGV.each { |f| YAML.load_file(f); puts "ok #{f}" }' .github/workflows/pysa.yml .github/workflow-templates/pysa.yml\n- ruby -e 'require "json"; ARGV.each { |f| JSON.parse(File.read(f)); puts "ok #{f}" }' .github/workflow-templates/pysa.properties.json\n- ruby -Itest -e 'ARGV.each { |path| require "./#{path}" }' test/*_test.rb\n- git diff --check

@cursor
Copy link
Copy Markdown

cursor Bot commented May 16, 2026

PR Summary

Low Risk
Low risk: adds new GitHub Actions workflows/templates and documentation only, with no production code changes; main impact is potential CI noise or runtime from newly adopted Pysa analysis.

Overview
Adds a reusable GitHub Actions workflow, .github/workflows/pysa.yml, to run Pyre/Pysa taint analysis with configurable Python version/runner/working directory, optional dependency bootstrap (requirements_file/setup_command), optional taint models path, and automatic generation of a minimal .pyre_configuration when missing.

Introduces a workflow-picker template (.github/workflow-templates/pysa.yml + pysa.properties.json) for downstream repos and updates README.md with adoption and configuration guidance, including PR path filters and artifact upload of analysis outputs.

Reviewed by Cursor Bugbot for commit de1e065. Bugbot is set up for automated code reviews on this repo. Configure here.

@haasonsaas haasonsaas changed the title Add reusable Pysa workflow ci: add reusable Pysa workflow May 16, 2026
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Config skip on .pyre_configuration.local alone causes failure
    • The workflow now only skips config generation when the base .pyre_configuration exists, so repos with only .pyre_configuration.local still get a generated base config.
Preview (c3b79ce308)
diff --git a/.github/workflow-templates/pysa.properties.json b/.github/workflow-templates/pysa.properties.json
new file mode 100644
--- /dev/null
+++ b/.github/workflow-templates/pysa.properties.json
@@ -1,0 +1,9 @@
+{
+  "name": "Pysa static analysis",
+  "description": "Run Pyre/Pysa taint analysis for Python repositories.",
+  "iconName": "octicon shield-check",
+  "categories": [
+    "Security",
+    "Continuous integration"
+  ]
+}

diff --git a/.github/workflow-templates/pysa.yml b/.github/workflow-templates/pysa.yml
new file mode 100644
--- /dev/null
+++ b/.github/workflow-templates/pysa.yml
@@ -1,0 +1,19 @@
+name: Pysa static analysis
+
+on:
+  pull_request:
+    paths:
+      - "**/*.py"
+      - "pyproject.toml"
+      - "requirements*.txt"
+      - ".pyre_configuration*"
+      - ".pysa/**"
+      - ".github/workflows/pysa.yml"
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+jobs:
+  pysa:
+    uses: evalops/.github/.github/workflows/pysa.yml@main

diff --git a/.github/workflows/pysa.yml b/.github/workflows/pysa.yml
new file mode 100644
--- /dev/null
+++ b/.github/workflows/pysa.yml
@@ -1,0 +1,130 @@
+name: pysa
+
+on:
+  workflow_call:
+    inputs:
+      python_version:
+        description: "Python version used to install and run Pyre/Pysa"
+        required: false
+        type: string
+        default: "3.12"
+      runner_label:
+        description: "Runner label used for Pysa"
+        required: false
+        type: string
+        default: blacksmith-4vcpu-ubuntu-2404
+      working_directory:
+        description: "Repository-relative directory to analyze"
+        required: false
+        type: string
+        default: "."
+      source_directories:
+        description: "Comma-separated Python source directories for generated Pyre config"
+        required: false
+        type: string
+        default: "."
+      taint_models_path:
+        description: "Optional Pysa taint-model directory"
+        required: false
+        type: string
+        default: ".pysa"
+      requirements_file:
+        description: "Optional requirements file to install before analysis"
+        required: false
+        type: string
+        default: ""
+      setup_command:
+        description: "Optional shell command to install repo-specific dependencies"
+        required: false
+        type: string
+        default: ""
+      pyre_package:
+        description: "pip package spec for Pyre/Pysa"
+        required: false
+        type: string
+        default: "pyre-check"
+
+permissions:
+  contents: read
+
+jobs:
+  analyze:
+    runs-on: ${{ inputs.runner_label }}
+    timeout-minutes: 25
+    defaults:
+      run:
+        working-directory: ${{ inputs.working_directory }}
+    env:
+      PYRE_PACKAGE: ${{ inputs.pyre_package }}
+      REQUIREMENTS_FILE: ${{ inputs.requirements_file }}
+      SETUP_COMMAND: ${{ inputs.setup_command }}
+      SOURCE_DIRECTORIES: ${{ inputs.source_directories }}
+      TAINT_MODELS_PATH: ${{ inputs.taint_models_path }}
+    steps:
+      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
+
+      - uses: actions/setup-python@v5
+        with:
+          python-version: ${{ inputs.python_version }}
+
+      - name: Install dependencies
+        shell: bash
+        run: |
+          set -euo pipefail
+          python -m pip install --upgrade pip
+          if [ -n "${REQUIREMENTS_FILE}" ]; then
+            python -m pip install -r "${REQUIREMENTS_FILE}"
+          fi
+          if [ -n "${SETUP_COMMAND}" ]; then
+            bash -lc "${SETUP_COMMAND}"
+          fi
+          python -m pip install "${PYRE_PACKAGE}"
+
+      - name: Ensure Pyre configuration
+        shell: bash
+        run: |
+          set -euo pipefail
+          if [ -f ".pyre_configuration" ]; then
+            echo "using repository Pyre configuration"
+            exit 0
+          fi
+          python - <<'PY'
+          import json
+          import os
+
+          sources = [
+              item.strip()
+              for item in os.environ["SOURCE_DIRECTORIES"].split(",")
+              if item.strip()
+          ]
+          if not sources:
+              sources = ["."]
+          with open(".pyre_configuration", "w", encoding="utf-8") as fh:
+              json.dump({"source_directories": sources}, fh, indent=2)
+              fh.write("\n")
+          PY
+
+      - name: Run Pysa
+        shell: bash
+        run: |
+          set -euo pipefail
+          mkdir -p pysa-results
+          args=(analyze --save-results-to pysa-results)
+          if [ -n "${TAINT_MODELS_PATH}" ]; then
+            if [ -d "${TAINT_MODELS_PATH}" ]; then
+              args+=(--taint-models-path "${TAINT_MODELS_PATH}")
+            else
+              echo "::warning::Pysa taint model path '${TAINT_MODELS_PATH}' does not exist; running with bundled models only."
+            fi
+          fi
+          pyre "${args[@]}" | tee pysa-output.txt
+
+      - name: Upload Pysa output
+        if: ${{ always() }}
+        uses: actions/upload-artifact@v4
+        with:
+          name: pysa-output
+          path: |
+            ${{ inputs.working_directory }}/pysa-output.txt
+            ${{ inputs.working_directory }}/pysa-results/**
+          if-no-files-found: ignore

diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@
 - `codex-ci-triage.yml` triages a specific failed Actions run.
 - `codex-post-merge-verify.yml` checks default-branch health after merges.
 - `codex-label-churn-audit.yml` audits PR label mutation loops.
+- `pysa.yml` runs Pyre/Pysa taint analysis for Python repos.
 
 Each template expects an `OPENAI_API_KEY` repository secret. Repositories that
 need stronger, repo-specific behavior should copy the matching prompt from
@@ -147,6 +148,40 @@
       require_agents: true

+### Pysa Static Analysis
+
+Use .github/workflows/pysa.yml to add Pyre/Pysa taint analysis to Python
+repositories. Downstream repos can adopt it from the workflow template picker or
+with:
+
+```yaml
+name: Pysa static analysis
+
+on:

  • pull_request:
  • paths:
  •  - "**/*.py"
    
  •  - "pyproject.toml"
    
  •  - "requirements*.txt"
    
  •  - ".pyre_configuration*"
    
  •  - ".pysa/**"
    
  • workflow_dispatch:

+permissions:

  • contents: read

+jobs:

  • pysa:
  • uses: evalops/.github/.github/workflows/pysa.yml@main
  • with:
  •  source_directories: "."
    
  •  taint_models_path: ".pysa"
    

+```
+
+Repos with custom dependency bootstrapping can pass requirements_file or
+`setup_command`. Repos without committed Pyre configuration get a minimal
+generated `.pyre_configuration` from `source_directories`.
+

Service Catalog

services.yaml is intentionally lightweight. It should answer:


</details>


<sub>You can send follow-ups to the cloud agent <a href="https://cursor.com/agents/bc-20c898b8-375e-474c-bbf5-e196ad91820a">here</a>.</sub>
<!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END -->

<sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit de1e065aa9d9bb35a88f0dfb2fe8a7c793dbc31e. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>

Comment thread .github/workflows/pysa.yml
@haasonsaas haasonsaas merged commit c8d83e4 into main May 16, 2026
3 checks passed
@haasonsaas haasonsaas deleted the codex/shared-pysa-ci-20260516 branch May 16, 2026 15:01
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