Skip to content

fix(integrations): honor shared refresh for installed targets #10457

fix(integrations): honor shared refresh for installed targets

fix(integrations): honor shared refresh for installed targets #10457

Workflow file for this run

name: Lint & Security
permissions:
contents: read
on:
push:
branches: ["main"]
pull_request:
schedule:
- cron: "17 4 * * 1"
workflow_dispatch:
jobs:
checks:
name: Lint & dependency audit
if: ${{ github.event_name != 'schedule' }}
runs-on: ubuntu-latest
env:
DOC_GLOBS: |
docs/**/*.md
README.md
README.zh-CN.md
README.ja.md
README.ko.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
DEVELOPMENT.md
SECURITY.md
SUPPORT.md
spec-driven.md
presets/*.md
workflows/*.md
steps:
- name: Checkout
id: checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Install uv
id: uv
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
- name: Set up Python
id: python
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
# Explicit prerequisites let independent checks finish after a failure
# without masking that failure or continuing after cancellation.
# Audit committed inputs before Markdownlint can execute repository
# JavaScript configuration in this shared workspace.
- name: Check committed audit requirements are current
if: ${{ !cancelled() && steps.checkout.outcome == 'success' && steps.uv.outcome == 'success' && steps.python.outcome == 'success' }}
env:
DEPENDENCY_DIFF_BASE: ${{ github.event.pull_request.base.sha || github.event.before || '' }}
DEPENDENCY_DIFF_HEAD: ${{ github.event.pull_request.head.sha || github.sha }}
GENERATED_REQUIREMENTS: ${{ runner.temp }}/security-audit-requirements.txt
run: python .github/scripts/check_security_requirements.py
- name: Run pip-audit (committed requirements)
if: ${{ !cancelled() && steps.checkout.outcome == 'success' && steps.uv.outcome == 'success' && steps.python.outcome == 'success' }}
run: uvx --from pip-audit==2.10.0 pip-audit --disable-pip --require-hashes -r .github/security-audit-requirements.txt --progress-spinner off
- name: Run ruff check
if: ${{ !cancelled() && steps.checkout.outcome == 'success' && steps.uv.outcome == 'success' && steps.python.outcome == 'success' }}
run: uvx ruff@0.15.0 check src tests
- name: Run git diff --check
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
GITHUB_SHA: ${{ github.sha }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "pull_request" ]; then
git fetch --no-tags origin "+${PR_BASE_SHA}:refs/checks/pr-base"
git diff --check refs/checks/pr-base HEAD
elif [ "$EVENT_NAME" = "workflow_dispatch" ]; then
git diff-tree --check --no-commit-id --root --diff-merges=first-parent -r "$GITHUB_SHA"
elif [ "$PUSH_BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
git diff-tree --check --no-commit-id --root -r "$GITHUB_SHA"
else
git fetch --no-tags origin "+${PUSH_BEFORE_SHA}:refs/checks/push-before"
git diff --check refs/checks/push-before HEAD
fi
# Documentation only. Commands, skills, prompt templates, agent
# instructions (AGENTS.md) and .github/ content are inputs to coding
# agents rather than prose, and are deliberately left unlinted so a
# documentation pass never reformats them. Add new documentation
# paths to the DOC_GLOBS list above.
- name: Verify the documentation globs match files
id: documentation-globs
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
shell: bash
run: |
set -euo pipefail
shopt -s globstar nullglob
# Checked per glob, not on the total: one stale entry among several
# still leaves that part of the documentation unlinted, which is the
# failure #4526 was about.
count=0
empty=()
while IFS= read -r glob; do
[ -z "$glob" ] && continue
matched=0
for path in $glob; do
[ -f "$path" ] && matched=$((matched + 1))
done
# An array, not a string: nullglob is on, so re-expanding an
# unquoted list of unmatched globs would erase it.
[ "$matched" -eq 0 ] && empty+=("$glob")
count=$((count + matched))
done <<< "$DOC_GLOBS"
echo "documentation files matched: $count"
if [ ${#empty[@]} -gt 0 ]; then
for glob in "${empty[@]}"; do
echo "::error::markdownlint glob matches no files: $glob (see #4526)"
done
exit 1
fi
- name: Run markdownlint-cli2
if: ${{ !cancelled() && steps.checkout.outcome == 'success' && steps.documentation-globs.outcome == 'success' }}
uses: DavidAnson/markdownlint-cli2-action@696eb3f2509270d7b882d2aa68347bc676e7af34 # v25.0.0
with:
globs: ${{ env.DOC_GLOBS }}
# shellcheck is preinstalled on ubuntu-latest runners.
# Start at --severity=error to block real bugs without flagging style
# (notably SC2155). Tighten in a follow-up after cleanup.
- name: Run shellcheck on shell scripts
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
run: git ls-files -z -- '*.sh' | xargs -0 shellcheck --severity=error
# macOS ships bash 3.2, where bash 4+ case-modification parameter
# expansions error with "bad substitution". shellcheck assumes bash 4+
# from the shebang and cannot flag these, so guard explicitly; use tr
# for portable case conversion.
- name: Reject bash 4+ case-modification expansions
if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}
run: |
matches=$(git ls-files -z -- '*.sh' | xargs -0 grep -nE '\$\{[A-Za-z_][A-Za-z0-9_]*(\[[^]]*\])?(\^\^?|,,?|~~?|@[UuLl])[^}]*\}' || true)
if [ -n "$matches" ]; then
echo "Found bash 4+ case-modification expansion(s); use tr for portability (macOS ships bash 3.2):"
echo "$matches"
exit 1
fi
dependency-audit-scheduled:
name: Dependency audit scheduled (${{ matrix.os }}, Python ${{ matrix.python-version }})
if: ${{ github.event_name == 'schedule' }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
# Keep live per-platform resolution separate from the deterministic
# committed snapshot used by push, pull request, and manual runs.
- name: Compile scheduled audit requirements
run: |
uv pip compile pyproject.toml --extra test --python-version "${{ matrix.python-version }}" --upgrade --generate-hashes --quiet --output-file "${{ runner.temp }}/spec-kit-audit-requirements.txt"
- name: Run pip-audit (scheduled live resolution)
run: uvx --from pip-audit==2.10.0 pip-audit --disable-pip --require-hashes -r "${{ runner.temp }}/spec-kit-audit-requirements.txt" --progress-spinner off