Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .conformance-catalog-ref
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b4c758a7dac698d7fcacd32dafcd4bb2f5dbddaf
15 changes: 14 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,20 @@ jobs:
- name: Clone shared conformance catalog (out of tree)
if: matrix.package == 'root'
run: |
git clone --depth 1 https://github.com/AuthPlane/conformance.git "$RUNNER_TEMP/conformance"
# Conformance catalog pinned by SHA, single-sourced from the tracked
# .conformance-catalog-ref at the repo root (read from the checked-out
# workspace, so the Checkout step above must precede this one). Bump
# that file when adopting new catalog cases, together with the SDK-side
# conformance coverage, so a catalog change can never break CI on its
# own. Source: github.com/AuthPlane/conformance.
CONFORMANCE_CATALOG_REF="$(cat "$GITHUB_WORKSPACE/.conformance-catalog-ref")"
grep -Eq '^[0-9a-f]{40}$' <<<"$CONFORMANCE_CATALOG_REF" \
|| { echo "::error::.conformance-catalog-ref must be a 40-hex commit SHA"; exit 1; }
git init -q "$RUNNER_TEMP/conformance"
git -C "$RUNNER_TEMP/conformance" \
fetch --depth=1 https://github.com/AuthPlane/conformance.git "$CONFORMANCE_CATALOG_REF" \
|| { echo "::error::Pinned conformance catalog ref $CONFORMANCE_CATALOG_REF is unreachable"; exit 1; }
git -C "$RUNNER_TEMP/conformance" checkout -q FETCH_HEAD

- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/conformance-catalog-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Conformance catalog drift

# Weekly (plus on-demand) check that the SDK's @pytest.mark.conformance markers
# still cover the LATEST conformance catalog default branch, independent of the
# pinned SHA that gates PR CI (.conformance-catalog-ref). A newly added,
# uncovered catalog case FAILS this scheduled job so the drift is visible on the
# Actions dashboard; it never breaks PR CI, which has no pull_request trigger and
# runs against the pinned .conformance-catalog-ref.

on:
schedule:
# Mondays 06:00 UTC
- cron: "0 6 * * 1"
workflow_dispatch:

# Least-privilege default; this workflow only reads the repo.
permissions:
contents: read

jobs:
drift:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python 3.11
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"

- name: Install package dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

# Intentionally UNPINNED: track the catalog's default branch so newly
# added cases surface here. PR CI stays on the pinned .conformance-catalog-ref.
- name: Clone latest conformance catalog default branch (out of tree)
run: |
git clone --depth 1 https://github.com/AuthPlane/conformance.git "$RUNNER_TEMP/conformance"

- name: Check catalog alignment against the latest catalog
id: align
env:
AUTHPLANE_CONFORMANCE_CATALOG: ${{ runner.temp }}/conformance/oauth-sdk-conformance-catalog.yaml
run: |
pytest conformance-tests/test_catalog_alignment.py -v

- name: Report drift
if: always()
run: |
if [ "${{ steps.align.outcome }}" = "success" ]; then
echo "Conformance markers cover the latest catalog default branch." >> "$GITHUB_STEP_SUMMARY"
else
echo "::warning::Conformance catalog drift detected: the SDK's @pytest.mark.conformance markers do not cover every case in the latest catalog default branch. Extend coverage in conformance-tests/, then bump .conformance-catalog-ref to adopt the new cases."
{
echo "## Conformance catalog drift detected"
echo ""
echo "The SDK's \`@pytest.mark.conformance\` markers do not cover every case in the **latest** conformance catalog default branch."
echo "PR CI is unaffected — it runs against the pinned \`.conformance-catalog-ref\`."
echo "Extend coverage in \`conformance-tests/\`, then bump \`.conformance-catalog-ref\` to adopt the new cases."
} >> "$GITHUB_STEP_SUMMARY"
fi
15 changes: 14 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,20 @@ jobs:
# need its auth/persist-credentials features for a public read-only repo.
- name: Clone shared conformance catalog (out of tree)
run: |
git clone --depth 1 https://github.com/AuthPlane/conformance.git "$RUNNER_TEMP/conformance"
# Conformance catalog pinned by SHA, single-sourced from the tracked
# .conformance-catalog-ref at the repo root (read from the checked-out
# workspace, so the Checkout step above must precede this one). Bump
# that file when adopting new catalog cases, together with the SDK-side
# conformance coverage, so a catalog change can never break CI on its
# own. Source: github.com/AuthPlane/conformance.
CONFORMANCE_CATALOG_REF="$(cat "$GITHUB_WORKSPACE/.conformance-catalog-ref")"
grep -Eq '^[0-9a-f]{40}$' <<<"$CONFORMANCE_CATALOG_REF" \
|| { echo "::error::.conformance-catalog-ref must be a 40-hex commit SHA"; exit 1; }
git init -q "$RUNNER_TEMP/conformance"
git -C "$RUNNER_TEMP/conformance" \
fetch --depth=1 https://github.com/AuthPlane/conformance.git "$CONFORMANCE_CATALOG_REF" \
|| { echo "::error::Pinned conformance catalog ref $CONFORMANCE_CATALOG_REF is unreachable"; exit 1; }
git -C "$RUNNER_TEMP/conformance" checkout -q FETCH_HEAD

- name: Set up Python 3.11
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
Expand Down
10 changes: 0 additions & 10 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,6 @@ jobs:
# latest released version, so `pip install --upgrade pip` can't pull
# a patched build. Drop this ignore once pip >= 26.1 is on PyPI.
# See https://github.com/pypa/pip/pull/13870.
#
# PYSEC-2026-3483: affects mcp <= 1.27.2 (fixed in 1.28.1). The
# authplane-mcp adapter pins mcp <1.28.0 because 1.28 renamed the
# elicitation field elicitationId -> elicitation_id (snake_case),
# which breaks url_elicitation.py's ElicitRequestURLParams wire
# handling (every consent-driven exchange would raise a pydantic
# ValidationError). Accepted risk until the adapter is migrated to
# the 1.28 field name and the floor is raised to 1.28.1; drop this
# ignore then.
run: >-
pip-audit --skip-editable --progress-spinner off
--ignore-vuln CVE-2026-3219
--ignore-vuln PYSEC-2026-3483
50 changes: 43 additions & 7 deletions .github/workflows/workflows-lint.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
name: Lint workflows
name: Release tooling

# Catches workflow YAML / shell-in-`run:` regressions at PR time so a
# typo can't reach a release tag and surface only when a publish run
# fails. Scoped to changes under `.github/workflows/**` to keep CI
# overhead off unrelated PRs.
# fails. The shell scripts under scripts/ are in the same category — a
# break in them surfaces only when someone reaches for them after a
# release, which is the worst moment to discover it — so they are linted
# and tested here too. Scoped to those two paths to keep CI overhead off
# unrelated PRs.
#
# The scripts trigger is `scripts/**`, not `scripts/*.sh`: a single-level
# glob would leave a future scripts/lib/*.sh both untriggered here and
# unlinted below, in each case silently.

on:
pull_request:
paths:
- ".github/workflows/**"
- "scripts/**"
push:
branches:
- main
paths:
- ".github/workflows/**"
- "scripts/**"

permissions:
contents: read
Expand Down Expand Up @@ -56,9 +65,36 @@ jobs:
echo "${ACTIONLINT_INSTALL_DIR}" >> "${GITHUB_PATH}"
"${ACTIONLINT_INSTALL_DIR}/actionlint" -version

# `-shellcheck=shellcheck` makes the shellcheck dependency explicit
# rather than relying on actionlint's implicit lookup against the
# runner image's $PATH; if the Ubuntu image ever drops shellcheck the
# job fails loudly instead of silently degrading.
# Both steps below resolve `shellcheck` off the runner image's $PATH —
# actionlint via `-shellcheck=shellcheck`, the script lint directly.
# Asserting it once, up front, is what makes that dependency explicit:
# naming the binary in actionlint's flag only changes which lookup
# fails, and neither step announces the version it linted with. If the
# Ubuntu image ever drops shellcheck, this fails first and says so,
# rather than actionlint quietly degrading to no shell analysis.
- name: Check shellcheck is available
run: shellcheck --version

- name: Run actionlint
run: actionlint -color -shellcheck=shellcheck

- name: Shellcheck the release scripts
# find, not `scripts/*.sh`: the single-level glob would silently skip
# a future scripts/lib/*.sh, the same blind spot the path trigger had.
# An empty result is an error rather than a green no-op, so a moved or
# renamed directory cannot pass as a clean lint.
run: |
mapfile -d '' -t sh_files < <(find scripts -type f -name '*.sh' -print0)
if [[ ${#sh_files[@]} -eq 0 ]]; then
echo "error: no shell scripts found under scripts/" >&2
exit 1
fi
printf 'shellcheck: %s\n' "${sh_files[@]}"
shellcheck "${sh_files[@]}"

# backport-fixes.sh accepts a branch or a tag as --from, and only the
# branch form has a remote-tracking ref. The tag form is what the release
# flow tells you to use once release.yml has deleted the branch, so it is
# the form least likely to be exercised before it is needed.
- name: Test backport-fixes.sh
run: scripts/backport-fixes.test.sh
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ wheels/
.installed.cfg
*.egg

# uv lockfiles. Not tracked on main and nothing consumes them — no workflow
# installs with uv — so they are local resolution artifacts. Three of them were
# swept into a merge commit as untracked files and accounted for 94% of a PR's
# diff; ignoring them is what stops that recurring. Tracking them for
# reproducible installs is a real decision, and it belongs in its own PR
# alongside the CI change that would make them load-bearing.
uv.lock

# Testing
.pytest_cache/
.coverage
Expand Down
Loading
Loading