From e298159aa8a7d99ccde718949332d1efe5633696 Mon Sep 17 00:00:00 2001 From: Dan Fiedler Date: Wed, 7 Oct 2026 15:23:36 -0400 Subject: [PATCH 1/7] Pin GitHub Actions to full-length commit SHAs --- .github/actions/marketplace-login/action.yml | 2 +- .github/code-quality-py.instructions.md | 206 +++++++++---------- .github/dependabot.yml | 2 + .github/workflows/_build.yml | 6 +- .github/workflows/agentops-watchdog.yml | 12 +- .github/workflows/ci.yml | 34 +-- .github/workflows/cut-release.yml | 2 +- .github/workflows/deploy-docs.yml | 4 +- .github/workflows/e2e.yml | 60 +++--- .github/workflows/marketplace-preflight.yml | 6 +- .github/workflows/release.yml | 28 +-- .github/workflows/staging.yml | 14 +- .pre-commit-config.yaml | 14 +- 13 files changed, 196 insertions(+), 194 deletions(-) diff --git a/.github/actions/marketplace-login/action.yml b/.github/actions/marketplace-login/action.yml index e3c2c4bb..42a3a14b 100644 --- a/.github/actions/marketplace-login/action.yml +++ b/.github/actions/marketplace-login/action.yml @@ -42,7 +42,7 @@ runs: done - name: Sign in with Marketplace workload identity - uses: azure/login@v3 + uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 with: client-id: ${{ inputs.client-id }} tenant-id: ${{ inputs.tenant-id }} diff --git a/.github/code-quality-py.instructions.md b/.github/code-quality-py.instructions.md index d55e997d..f05d5c34 100644 --- a/.github/code-quality-py.instructions.md +++ b/.github/code-quality-py.instructions.md @@ -1,103 +1,103 @@ ---- -applyTo: '**/*.py' ---- -# Systematic Code-Quality Pass Instructions for Python Codebase - -> Should check copilot-instructions.md for general guidelines first, but these are specific to Python files and should be applied in addition to any general instructions. - -You are performing a systematic code-quality pass on a Python codebase. Work through every folder one at a time. For each Python file, apply ALL of the following rules, then compile-check every edited file before moving to the next folder. - -## 1. Copyright & Module Docstring -- Every `.py` file (except empty `__init__.py`) must start with: - ``` - # Copyright (c) Microsoft Corporation. - # Licensed under the MIT License. - ``` -- Immediately after, add or replace the module-level docstring. It must: - - Describe what the module does in 1-2 sentences. - - Mention its role in the broader system (e.g., which pipeline stage, what it depends on). - - NOT contain generic filler like "This module provides utilities for…" - -## 2. Package `__init__.py` -- If empty, add the copyright header and a package docstring listing sub-modules with one-line descriptions. - -## 3. Class Docstrings -- Replace generic class docstrings with structured ones: - ``` - """One-line summary. - - Responsibilities: - 1. First responsibility. - 2. Second responsibility. - - Attributes: - attr_name: Description. - """ - ``` -- For dataclasses / Pydantic models, list all fields under "Attributes:". - -## 4. Method / Function Docstrings -- Every public and non-trivial private method must have a docstring. -- Use this structure: - ``` - """One-line summary. - - Steps: ← only for complex multi-step methods - 1. First step. - 2. Second step. - - Args: - param: Description. - - Returns: - Description. - - Raises: - ExceptionType: When condition. - """ - ``` -- Simple one-line methods (getters, delegates) get a single-line docstring. - -## 5. Comment Cleanup - REMOVE These -- **Redundant inline comments** that just restate the code: - `# Create Claim_Process entry in Cosmos DB` above `new_claim_process = Claim_Process(...)` -- **Banner comments** / section dividers: - `############################################################` - `## Initialize AgentFrameworkHelper and add it to the app ##` - `############################################################` -- **Commented-out code** (dead imports, print statements, old logic). -- **Heritage/provenance comments** referencing deleted files: - `Replaces create_quiet_logger() from quiet_logging.py` -- **Placeholder comments** that describe unimplemented intent: - `# Placeholder for document processing logic` -- **"For demonstration" / "Here you would typically"** comments. - -## 6. Comment Cleanup - KEEP These -- **Actionable TODOs** with clear intent: `# TODO: Make configurable if needed` -- **Non-obvious "why" comments** that explain a design decision: - `# Avoid unbounded growth on very chatty endpoints.` -- **Contract/protocol comments** that document external API behavior: - `# Image files bypass the 'extract' step.` - -## 7. Fix Stale References -- Search for outdated terminology (old project names, old class names, old pipeline descriptions) and correct them to match the current code. - -## 8. Remove Dead Code -- Delete unused imports. -- Delete `pass` in `else` blocks that only existed to hold a now-deleted comment. -- Delete redundant assignments like `claim_id = claim_id`. -- Delete duplicate imports (e.g., `import os` at module level AND inside a function). - -## 9. Compile-Check -- After finishing each folder, run `python -m py_compile ` on every edited file. -- Fix any errors before proceeding to the next folder. - -## Working Process -1. List the directory tree of the target folder. -2. Read all Python files in the folder. -3. Create a TODO list for the folder (one item per file + one for compile-check). -4. Edit files, marking each TODO as you go. -5. Compile-check all edited files. -6. Move to the next folder. - -Start with the folder I specify and work through it completely before asking what to do next. +--- +applyTo: '**/*.py' +--- +# Systematic Code-Quality Pass Instructions for Python Codebase + +> Should check copilot-instructions.md for general guidelines first, but these are specific to Python files and should be applied in addition to any general instructions. + +You are performing a systematic code-quality pass on a Python codebase. Work through every folder one at a time. For each Python file, apply ALL of the following rules, then compile-check every edited file before moving to the next folder. + +## 1. Copyright & Module Docstring +- Every `.py` file (except empty `__init__.py`) must start with: + ``` + # Copyright (c) Microsoft Corporation. + # Licensed under the MIT License. + ``` +- Immediately after, add or replace the module-level docstring. It must: + - Describe what the module does in 1-2 sentences. + - Mention its role in the broader system (e.g., which pipeline stage, what it depends on). + - NOT contain generic filler like "This module provides utilities for…" + +## 2. Package `__init__.py` +- If empty, add the copyright header and a package docstring listing sub-modules with one-line descriptions. + +## 3. Class Docstrings +- Replace generic class docstrings with structured ones: + ``` + """One-line summary. + + Responsibilities: + 1. First responsibility. + 2. Second responsibility. + + Attributes: + attr_name: Description. + """ + ``` +- For dataclasses / Pydantic models, list all fields under "Attributes:". + +## 4. Method / Function Docstrings +- Every public and non-trivial private method must have a docstring. +- Use this structure: + ``` + """One-line summary. + + Steps: ← only for complex multi-step methods + 1. First step. + 2. Second step. + + Args: + param: Description. + + Returns: + Description. + + Raises: + ExceptionType: When condition. + """ + ``` +- Simple one-line methods (getters, delegates) get a single-line docstring. + +## 5. Comment Cleanup - REMOVE These +- **Redundant inline comments** that just restate the code: + `# Create Claim_Process entry in Cosmos DB` above `new_claim_process = Claim_Process(...)` +- **Banner comments** / section dividers: + `############################################################` + `## Initialize AgentFrameworkHelper and add it to the app ##` + `############################################################` +- **Commented-out code** (dead imports, print statements, old logic). +- **Heritage/provenance comments** referencing deleted files: + `Replaces create_quiet_logger() from quiet_logging.py` +- **Placeholder comments** that describe unimplemented intent: + `# Placeholder for document processing logic` +- **"For demonstration" / "Here you would typically"** comments. + +## 6. Comment Cleanup - KEEP These +- **Actionable TODOs** with clear intent: `# TODO: Make configurable if needed` +- **Non-obvious "why" comments** that explain a design decision: + `# Avoid unbounded growth on very chatty endpoints.` +- **Contract/protocol comments** that document external API behavior: + `# Image files bypass the 'extract' step.` + +## 7. Fix Stale References +- Search for outdated terminology (old project names, old class names, old pipeline descriptions) and correct them to match the current code. + +## 8. Remove Dead Code +- Delete unused imports. +- Delete `pass` in `else` blocks that only existed to hold a now-deleted comment. +- Delete redundant assignments like `claim_id = claim_id`. +- Delete duplicate imports (e.g., `import os` at module level AND inside a function). + +## 9. Compile-Check +- After finishing each folder, run `python -m py_compile ` on every edited file. +- Fix any errors before proceeding to the next folder. + +## Working Process +1. List the directory tree of the target folder. +2. Read all Python files in the folder. +3. Create a TODO list for the folder (one item per file + one for compile-check). +4. Edit files, marking each TODO as you go. +5. Compile-check all edited files. +6. Move to the next folder. + +Start with the folder I specify and work through it completely before asking what to do next. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 962eed03..bab63982 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,6 +17,8 @@ updates: labels: - "dependencies" - "github-actions" + cooldown: + default-days: 7 - package-ecosystem: "npm" directory: "/plugins/agentops" schedule: diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml index 7b3846d5..7b08349d 100644 --- a/.github/workflows/_build.yml +++ b/.github/workflows/_build.yml @@ -39,7 +39,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ inputs.checkout_ref || github.ref }} fetch-depth: 0 # Full history required for setuptools-scm @@ -59,7 +59,7 @@ jobs: echo "Release package version pinned to $VERSION from $TAG" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" @@ -111,7 +111,7 @@ jobs: uv run python -c "from importlib.metadata import version; print(f'Version: {version(\"agentops-accelerator\")}')" - name: Upload build artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: dist path: dist/ diff --git a/.github/workflows/agentops-watchdog.yml b/.github/workflows/agentops-watchdog.yml index 2f2168ca..b166ca89 100644 --- a/.github/workflows/agentops-watchdog.yml +++ b/.github/workflows/agentops-watchdog.yml @@ -44,22 +44,22 @@ jobs: timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Azure login (OIDC) - uses: azure/login@v3 + uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906 # v3.1.0 with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.11" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 - name: Install AgentOps Toolkit (this branch) run: | @@ -72,7 +72,7 @@ jobs: # downloads when the artifact does not exist yet, instead of # surfacing a red error annotation on every first run. - name: Restore watchdog history (if any) - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: agentops-watchdog-history path: .agentops/agent/ @@ -97,7 +97,7 @@ jobs: - name: Upload watchdog artifacts if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: agentops-watchdog-history path: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 237252ff..c0059028 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,10 +38,10 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" enable-cache: false # test matrix saves this cache key @@ -67,12 +67,12 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # need the merge base to diff against develop - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -93,10 +93,10 @@ jobs: os: [ubuntu-latest, windows-latest] python-version: ["3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" @@ -111,7 +111,7 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: test-results-${{ matrix.os }}-py${{ matrix.python-version }} path: test-results.xml @@ -120,10 +120,10 @@ jobs: runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" enable-cache: false # test matrix saves this cache key @@ -138,7 +138,7 @@ jobs: run: uv run pytest tests/ --cov=agentops --cov-report=xml --cov-report=term-missing - name: Upload coverage - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-report path: coverage.xml @@ -154,12 +154,12 @@ jobs: permissions: id-token: write # Required for PyPI Trusted Publishing (OIDC) steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # Full history for setuptools-scm - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" enable-cache: false # test matrix saves this cache key @@ -213,7 +213,7 @@ jobs: echo "Dev version: ${{ steps.package-version.outputs.version }}" - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: repository-url: https://test.pypi.org/legacy/ verbose: true @@ -226,7 +226,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -278,13 +278,13 @@ jobs: build-vsix: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # CI uses the committed package.json version as-is (no publish, dry-run only). # The version in package.json is synced by cut-release.yml when a release branch is created. - name: Set up Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" @@ -306,7 +306,7 @@ jobs: echo "✅ VSIX packaging validated" - name: Upload VSIX artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: vsix path: plugins/agentops/*.vsix diff --git a/.github/workflows/cut-release.yml b/.github/workflows/cut-release.yml index 999ab1a8..fbd3e724 100644 --- a/.github/workflows/cut-release.yml +++ b/.github/workflows/cut-release.yml @@ -53,7 +53,7 @@ jobs: echo "version=$VERSION" >> "$GITHUB_ENV" - name: Checkout develop - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: develop fetch-depth: 0 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 36b71cd5..015c4861 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -60,13 +60,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 ref: develop - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: 3.11 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a2247308..bfeb8132 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -36,15 +36,15 @@ jobs: offline-smoke: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" @@ -59,7 +59,7 @@ jobs: - name: Upload evidence artifact if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: offline-smoke path: evidence/ @@ -69,15 +69,15 @@ jobs: unit-tests-with-coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" @@ -98,7 +98,7 @@ jobs: - name: Upload coverage + JUnit if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: unit-tests-with-coverage path: | @@ -127,7 +127,7 @@ jobs: hosted_agent_name: ${{ steps.create_hosted_agent.outputs.agent_name }} suffix: ${{ steps.suffix.outputs.value }} steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - id: suffix name: Compute per-run suffix @@ -229,7 +229,7 @@ jobs: - name: Set up Python (for hosted agent provisioning) if: ${{ github.event.inputs.scenarios == 'all' || github.event.inputs.scenarios == 'foundry-hosted' }} - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -256,11 +256,11 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" - name: Azure login (OIDC) @@ -286,7 +286,7 @@ jobs: - name: Render transcript if: always() run: uv run python scripts/e2e_make_transcript.py e2e-runs/foundry-prompt - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: always() with: name: live-foundry-prompt @@ -307,11 +307,11 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" - name: Azure login (OIDC) @@ -337,7 +337,7 @@ jobs: - name: Render transcript if: always() run: uv run python scripts/e2e_make_transcript.py e2e-runs/foundry-hosted - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: always() with: name: live-foundry-hosted @@ -359,11 +359,11 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" - name: Azure login (OIDC) @@ -388,7 +388,7 @@ jobs: - name: Render transcript if: always() run: uv run python scripts/e2e_make_transcript.py e2e-runs/http-aca - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: always() with: name: live-http-aca @@ -409,11 +409,11 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: version: ">=0.9.0" - name: Azure login (OIDC) @@ -438,7 +438,7 @@ jobs: - name: Render transcript if: always() run: uv run python scripts/e2e_make_transcript.py e2e-runs/model-direct - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: always() with: name: live-model-direct @@ -464,7 +464,7 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Azure login (OIDC) uses: ./.github/actions/azure-oidc-login with: @@ -481,7 +481,7 @@ jobs: --yes || true - name: Set up Python (for hosted agent teardown) if: needs.bootstrap-live.outputs.hosted_agent_name != '' - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" - name: Install azure-ai-projects (for hosted agent teardown) @@ -529,9 +529,9 @@ jobs: if: always() runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Download all artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts - name: Render consolidated summary diff --git a/.github/workflows/marketplace-preflight.yml b/.github/workflows/marketplace-preflight.yml index c18801a4..e2407472 100644 --- a/.github/workflows/marketplace-preflight.yml +++ b/.github/workflows/marketplace-preflight.yml @@ -51,11 +51,11 @@ jobs: *) echo "::error::Invalid Marketplace environment"; exit 1 ;; esac - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -77,7 +77,7 @@ jobs: - name: Save non-secret profile IDs if: inputs.mode == 'discover' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: marketplace-profile path: marketplace-profile.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4216c79d..c46a30e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,13 +96,13 @@ jobs: id-token: write # Required for PyPI Trusted Publishing (OIDC) steps: - name: Download build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: dist path: dist/ - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: repository-url: https://test.pypi.org/legacy/ verbose: true @@ -113,12 +113,12 @@ jobs: needs: publish-testpypi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -185,13 +185,13 @@ jobs: id-token: write # Required for PyPI trusted publishing (OIDC) steps: - name: Download build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: dist path: dist/ - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: verbose: true skip-existing: true @@ -226,12 +226,12 @@ jobs: fi - name: Check out trusted publishing tooling - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.workflow_sha }} - name: Check out release sources - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # Full history for version derivation ref: refs/tags/${{ inputs.tag || github.ref_name }} @@ -250,7 +250,7 @@ jobs: echo "VSIX version set to $VERSION (from tag $RELEASE_TAG)" - name: Set up Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" @@ -258,7 +258,7 @@ jobs: run: npm install -g @vscode/vsce@3.9.2 - name: Set up Python for Marketplace preflight - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -287,7 +287,7 @@ jobs: --package-path "release-source/plugins/agentops/${VSIX_FILE}" --allow-already-exists - name: Upload VSIX artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: vsix path: release-source/plugins/agentops/${{ env.VSIX_FILE }} @@ -301,16 +301,16 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Download Python dist artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: dist path: dist/ - name: Download VSIX artifact - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: vsix path: vsix/ diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index ed9c23cc..189cc595 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -59,13 +59,13 @@ jobs: id-token: write # Required for PyPI Trusted Publishing (OIDC) steps: - name: Download build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: dist path: dist/ - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: repository-url: https://test.pypi.org/legacy/ verbose: true @@ -76,12 +76,12 @@ jobs: needs: publish-testpypi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" @@ -138,7 +138,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Sync VSIX version from branch name run: | @@ -156,7 +156,7 @@ jobs: echo "VSIX version set to $VERSION (from branch $BRANCH)" - name: Set up Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" @@ -179,7 +179,7 @@ jobs: echo "VSIX candidate packaged only; Marketplace publication is reserved for the stable release." - name: Upload VSIX artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: vsix path: plugins/agentops/agentops-skills.vsix diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7a5b564..d4de6b03 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ -repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.10 - hooks: - - id: ruff - args: [--fix] - - id: ruff-format +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.10 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format From 6eb84766cbac2cf5fc695ddb38897cb94dfd76ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:18:46 -0300 Subject: [PATCH 2/7] chore(deps): bump virtualenv from 21.2.0 to 21.7.13 (#504) Bumps [virtualenv](https://github.com/pypa/virtualenv) from 21.2.0 to 21.7.13. - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/virtualenv/compare/21.2.0...21.7.13) --- updated-dependencies: - dependency-name: virtualenv dependency-version: 21.7.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/uv.lock b/uv.lock index cd062457..d1333056 100644 --- a/uv.lock +++ b/uv.lock @@ -2547,15 +2547,14 @@ wheels = [ [[package]] name = "python-discovery" -version = "1.2.0" +version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, - { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/90/bcce6b46823c9bec1757c964dc37ed332579be512e17a30e9698095dcae4/python_discovery-1.2.0.tar.gz", hash = "sha256:7d33e350704818b09e3da2bd419d37e21e7c30db6e0977bb438916e06b41b5b1", size = 58055, upload-time = "2026-03-19T01:43:08.248Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/57/250bd238b966cece44328235eb85290045d059265fdaf7527a3a958123db/python_discovery-1.6.1.tar.gz", hash = "sha256:cf87d3627dfb4412437fdd5b13eae402607722998d21567993aedbc59b23c15e", size = 84338, upload-time = "2026-09-18T01:31:53.971Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/3c/2005227cb951df502412de2fa781f800663cccbef8d90ec6f1b371ac2c0d/python_discovery-1.2.0-py3-none-any.whl", hash = "sha256:1e108f1bbe2ed0ef089823d28805d5ad32be8e734b86a5f212bf89b71c266e4a", size = 31524, upload-time = "2026-03-19T01:43:07.045Z" }, + { url = "https://files.pythonhosted.org/packages/16/7d/e9ffbadfbf89c93848412d04594135c4ae8c1d37d9e053b9c3ed718fabc4/python_discovery-1.6.1-py3-none-any.whl", hash = "sha256:d43fcdef879fe795352bd13ccf8d185ba5a9f86f36cfcd00529f596e737442b3", size = 38664, upload-time = "2026-09-18T01:31:52.448Z" }, ] [[package]] @@ -3226,7 +3225,7 @@ wheels = [ [[package]] name = "virtualenv" -version = "21.2.0" +version = "21.7.13" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, @@ -3234,9 +3233,9 @@ dependencies = [ { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/50/c9b84eb106d0db420b9878dac0a386c5791726f127ce20b06897f6e3a1e9/virtualenv-21.7.13.tar.gz", hash = "sha256:0355558b6f33619aab31347e43643b0ebc97f61ea3acf617b2b69e1f8a843d11", size = 5360306, upload-time = "2026-09-18T04:35:49.354Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ce/e74453531b0c49a58d0e8a4f9bab4495705859fee4a4f7de27d58f4a791a/virtualenv-21.7.13-py3-none-any.whl", hash = "sha256:1bea5af7463f59c4719db48fe739579a2a4f569c96f26c086edda85c96da9f59", size = 5328680, upload-time = "2026-09-18T04:35:47.194Z" }, ] [[package]] From 7bcd434973df04f934f9b04f587546ddca2dca6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:18:55 -0300 Subject: [PATCH 3/7] chore(deps): bump urllib3 from 2.7.0 to 2.8.0 (#503) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.7.0...2.8.0) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.8.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index d1333056..89320f4e 100644 --- a/uv.lock +++ b/uv.lock @@ -3154,11 +3154,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, + { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, ] [[package]] From bbccb303174c6a2c55c75d21be027a3762095b0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:19:04 -0300 Subject: [PATCH 4/7] chore(deps): bump pyjwt from 2.13.0 to 2.15.0 (#501) Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.13.0 to 2.15.0. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jpadilla/pyjwt/compare/2.13.0...2.15.0) --- updated-dependencies: - dependency-name: pyjwt dependency-version: 2.15.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 89320f4e..47494378 100644 --- a/uv.lock +++ b/uv.lock @@ -2478,11 +2478,11 @@ wheels = [ [[package]] name = "pyjwt" -version = "2.13.0" +version = "2.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/a5/5197bfd06417837ac079921c66fa6393f1dea3557272a263cebfef69e432/pyjwt-2.15.0.tar.gz", hash = "sha256:b11c5f9791d7bf51c2b39a81ed669f6b2dbbd669df2942f6c60167e9e3d1abe4", size = 120513, upload-time = "2026-09-23T16:56:00.689Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, + { url = "https://files.pythonhosted.org/packages/e8/55/40e45bf052ee8ee12a4dfd785519660f8effa7b065442b91646ec6828619/pyjwt-2.15.0-py3-none-any.whl", hash = "sha256:7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8", size = 33680, upload-time = "2026-09-23T16:55:59.241Z" }, ] [package.optional-dependencies] From bad7bf0f3735d4510d58406634d1996243eb8822 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:19:12 -0300 Subject: [PATCH 5/7] chore(deps): bump anyio from 4.12.1 to 4.14.2 (#498) Bumps [anyio](https://github.com/agronholm/anyio) from 4.12.1 to 4.14.2. - [Release notes](https://github.com/agronholm/anyio/releases) - [Commits](https://github.com/agronholm/anyio/compare/4.12.1...4.14.2) --- updated-dependencies: - dependency-name: anyio dependency-version: 4.14.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 47494378..69b65ba1 100644 --- a/uv.lock +++ b/uv.lock @@ -257,15 +257,15 @@ wheels = [ [[package]] name = "anyio" -version = "4.12.1" +version = "4.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, ] [[package]] From a842e4df8b0540fc81285b58acec3ace169eca1b Mon Sep 17 00:00:00 2001 From: Paulo Lacerda Date: Wed, 14 Oct 2026 20:29:48 -0300 Subject: [PATCH 6/7] test: accept SHA-pinned actions in marketplace workflow contracts Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- tests/unit/test_marketplace_publishing.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_marketplace_publishing.py b/tests/unit/test_marketplace_publishing.py index f598182b..0a1a10fe 100644 --- a/tests/unit/test_marketplace_publishing.py +++ b/tests/unit/test_marketplace_publishing.py @@ -23,6 +23,10 @@ TOKEN = "dummy-access-token" +def _is_action(step, name): + return str(step.get("uses", "")).startswith(name + "@") + + @pytest.fixture def marketplace(monkeypatch): spec = importlib.util.spec_from_file_location("marketplace", ROOT / "scripts" / "marketplace.py") @@ -327,7 +331,7 @@ def test_staging_only_packages_candidate_without_marketplace_credentials(): assert forbidden not in serialized steps = job["steps"] assert any(step.get("run") == "vsce package --pre-release -o agentops-skills.vsix" for step in steps) - artifact = next(step for step in steps if step.get("uses") == "actions/upload-artifact@v7") + artifact = next(step for step in steps if _is_action(step, "actions/upload-artifact")) assert artifact["with"]["name"] == "vsix" @@ -338,14 +342,14 @@ def test_login_does_not_require_subscription_or_shared_e2e_identity(): steps = action["runs"]["steps"] assert "PROFILE_ID" in steps[0]["run"] login = steps[1] - assert login["uses"] == "azure/login@v3" + assert login["uses"].startswith("azure/login@") assert login["with"]["allow-no-subscriptions"] is True assert "subscription-id" not in login["with"] def test_release_retry_keeps_tooling_separate_from_older_release_sources(): steps = load_workflow("release.yml")["jobs"]["publish-vsix"]["steps"] - checkouts = [step for step in steps if step.get("uses") == "actions/checkout@v7"] + checkouts = [step for step in steps if _is_action(step, "actions/checkout")] assert checkouts[0]["with"] == {"ref": "${{ github.workflow_sha }}"} assert checkouts[1]["with"]["ref"] == "refs/tags/${{ inputs.tag || github.ref_name }}" assert checkouts[1]["with"]["path"] == "release-source" @@ -353,7 +357,7 @@ def test_release_retry_keeps_tooling_separate_from_older_release_sources(): assert next(step for step in steps if step.get("name") == name)["working-directory"] == "release-source" package = next(step for step in steps if step.get("name") == "Package VSIX") assert package["working-directory"] == "release-source/plugins/agentops" - artifact = next(step for step in steps if step.get("uses") == "actions/upload-artifact@v7") + artifact = next(step for step in steps if _is_action(step, "actions/upload-artifact")) assert artifact["with"]["path"] == "release-source/plugins/agentops/${{ env.VSIX_FILE }}" @@ -366,7 +370,7 @@ def test_python_publishing_and_github_release_contracts_stay_intact(): ]: assert job["environment"] == environment assert job["permissions"]["id-token"] == "write" - assert any(step.get("uses") == "pypa/gh-action-pypi-publish@release/v1" for step in job["steps"]) + assert any(_is_action(step, "pypa/gh-action-pypi-publish") for step in job["steps"]) assert release["publish-vsix"]["needs"] == ["build", "publish-pypi"] assert release["github-release"]["needs"] == ["publish-pypi", "publish-vsix"] cut_release = (ROOT / ".github" / "workflows" / "cut-release.yml").read_text(encoding="utf-8") @@ -495,7 +499,7 @@ def test_preflight_workflow_has_no_upload_or_mutation_commands(): assert forbidden not in runs assert "python scripts/marketplace.py discover --out marketplace-profile.json" in runs assert "python scripts/marketplace.py check" in runs - artifact = next(step for step in steps if step.get("uses") == "actions/upload-artifact@v7") + artifact = next(step for step in steps if _is_action(step, "actions/upload-artifact")) assert artifact["with"]["path"] == "marketplace-profile.json" assert artifact["if"] == "inputs.mode == 'discover'" login = next(step for step in steps if step.get("uses") == "./.github/actions/marketplace-login") From 7dc0a1dc0cc7ae7159e5a7cd2c7736bf02afedc8 Mon Sep 17 00:00:00 2001 From: Paulo Lacerda Date: Wed, 14 Oct 2026 20:31:22 -0300 Subject: [PATCH 7/7] test: require full-SHA pins for actions in marketplace workflow contracts Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- tests/unit/test_marketplace_publishing.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_marketplace_publishing.py b/tests/unit/test_marketplace_publishing.py index 0a1a10fe..3cafbcd1 100644 --- a/tests/unit/test_marketplace_publishing.py +++ b/tests/unit/test_marketplace_publishing.py @@ -7,6 +7,7 @@ import io import json import os +import re import shutil import subprocess from pathlib import Path @@ -24,7 +25,7 @@ def _is_action(step, name): - return str(step.get("uses", "")).startswith(name + "@") + return re.fullmatch(re.escape(name) + r"@[0-9a-f]{40}", str(step.get("uses", "")).split(" ")[0]) is not None @pytest.fixture @@ -342,7 +343,7 @@ def test_login_does_not_require_subscription_or_shared_e2e_identity(): steps = action["runs"]["steps"] assert "PROFILE_ID" in steps[0]["run"] login = steps[1] - assert login["uses"].startswith("azure/login@") + assert _is_action(login, "azure/login") assert login["with"]["allow-no-subscriptions"] is True assert "subscription-id" not in login["with"]