Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
7d1c214
Fix dependency CVEs and gate PRs, releases and a weekly scan
zeevmoney Sep 21, 2026
e5a88c1
Move httpserver_listen_address to conftest so the port is order-indep…
zeevmoney Sep 21, 2026
160f129
TEMP: revert permit/ to origin/main to isolate test_bulk_operations
zeevmoney Sep 21, 2026
f9b4857
Revert "TEMP: revert permit/ to origin/main to isolate test_bulk_oper…
zeevmoney Sep 21, 2026
95a1860
Document the resource instance ident format correctly
zeevmoney Sep 22, 2026
1e6b9e6
Fix the major correctness bugs and enable the xfail tests for 3.0.0
zeevmoney Sep 22, 2026
199c4be
Isolate the end-to-end tests and start the PDP with the env's own key
zeevmoney Sep 22, 2026
3d11c3a
Give the PDP time to warm up and ABAC policy time to propagate
zeevmoney Sep 22, 2026
e7ce61d
Remove dead code and dead dependencies for 3.0.0
zeevmoney Sep 22, 2026
c439afb
Skip only the ABAC decision assertions, with the evidence
zeevmoney Sep 22, 2026
98ea10a
Fix resource_relations.list() and document two backend contracts
zeevmoney Sep 22, 2026
e86f630
Tolerate rate limiting during test teardown
zeevmoney Sep 22, 2026
0865f96
Retry rate-limited requests instead of tolerating them
zeevmoney Sep 22, 2026
0146bb8
Make the rate-limit retry more patient
zeevmoney Sep 22, 2026
e33c160
Point the ABAC skip at PER-16209
zeevmoney Sep 22, 2026
5391be2
Make CheckQuery.context optional for type checkers
zeevmoney Sep 22, 2026
afc16f4
Migrate packaging, dependencies and CI to uv
zeevmoney Sep 23, 2026
1d3b5de
Adopt strict ruff and mypy, reformat and fix the codebase
zeevmoney Sep 23, 2026
cc3253f
Merge main into the strict-tooling branch
zeevmoney Sep 29, 2026
42edcca
Adopt strict ruff, mypy and typos configuration
zeevmoney Sep 29, 2026
d0c46d4
Find the facade test's call sites without assuming layout
zeevmoney Sep 29, 2026
c3a754d
Reformat with ruff format at line length 100
zeevmoney Sep 29, 2026
afcce88
Let the sync stub generator copy whole-module imports
zeevmoney Sep 29, 2026
c62102a
Apply ruff's safe fixes
zeevmoney Sep 29, 2026
ca29753
Keep IncEx a typing generic
zeevmoney Sep 29, 2026
a812b48
Type and document the SDK for strict ruff and mypy
zeevmoney Sep 29, 2026
5d65977
Create test_envs' environments in the project it checks
zeevmoney Sep 29, 2026
00eba47
Stop test_envs' cleanup from hiding the real failure
zeevmoney Sep 29, 2026
1dbf931
Type the tests for strict ruff and mypy
zeevmoney Sep 29, 2026
e03f03d
Type and document the repository scripts
zeevmoney Sep 29, 2026
ba73988
Type and document the migration skill
zeevmoney Sep 29, 2026
01e4ca4
Fail clearly on non-finite Decimals in request bodies
zeevmoney Sep 29, 2026
a14ae11
Import the SDK without a DeprecationWarning
zeevmoney Sep 29, 2026
961b457
Fail the tests on any warning
zeevmoney Sep 29, 2026
ab998d0
Wait up to 300s for the PDP and keep its startup in the failure log
zeevmoney Sep 30, 2026
4cb0f35
Publish to PyPI by trusted publishing instead of a token
zeevmoney Oct 1, 2026
b68b88b
Turn off the Trivy action's cache in the release scan
zeevmoney Oct 1, 2026
4db824c
Pin the PDP image of the required e2e jobs by version and digest
zeevmoney Oct 1, 2026
7fb2b77
Set timeouts on the pytest and compatibility jobs
zeevmoney Oct 1, 2026
dd82004
Fail a release whose wheel or sdist ships more than permit
zeevmoney Oct 1, 2026
a170bb9
Give each release job a timeout
zeevmoney Oct 1, 2026
16fe8a1
Run the e2e tests on the latest PDP image and on the cloud PDP
zeevmoney Oct 1, 2026
e8eb692
Merge the release publishing changes for PER-16676
zeevmoney Oct 1, 2026
6ff940e
Merge the CI PDP pin and PDP legs for PER-16676
zeevmoney Oct 1, 2026
23a20d4
Check the CI-built wheel and sdist for extra packages too
zeevmoney Oct 1, 2026
d1f8455
Say why PyPI accepts the release upload without a token
zeevmoney Oct 1, 2026
e77f4a4
Describe the release workflow's jobs and trusted publishing
zeevmoney Oct 1, 2026
0d48ed7
Describe the pinned, latest and cloud PDP e2e jobs
zeevmoney Oct 1, 2026
f3e7221
Name the CI job that runs the cloud PDP tests
zeevmoney Oct 1, 2026
3552bd7
Require the cloud PDP's 501 in the cloud PDP tests
zeevmoney Oct 1, 2026
3764512
Count the four e2e jobs in CONTRIBUTING.md
zeevmoney Oct 1, 2026
2f68a35
Say that the pypi environment limits uploads to release tags
zeevmoney Oct 1, 2026
fb8f928
Run the Test and Security workflows on every PR, whatever its base
zeevmoney Oct 1, 2026
f8192ab
Test offline that a PDP's 501 makes the SDK raise
zeevmoney Oct 1, 2026
22d3c8e
Test real decisions on the cloud PDP instead of a 501
zeevmoney Oct 1, 2026
c241a0a
Expect the cloud PDP's tenant-association role in user permissions
zeevmoney Oct 1, 2026
2595538
Invite with a role of the invited resource in the invites e2e test
zeevmoney Oct 1, 2026
8cbc891
Poll for the PDP's role assignment list in the RBAC e2e tests
zeevmoney Oct 1, 2026
ced83e0
Poll for the PDP's authorized users in the RBAC e2e test
zeevmoney Oct 2, 2026
d4495ec
Keep ModelListInput's runtime annotation as typing.List
zeevmoney Oct 2, 2026
be78b11
Bound each PDP health probe to 5s and keep the first horizon failure
zeevmoney Oct 2, 2026
bad0b36
Bound the PDP wait by elapsed time rather than by tries
zeevmoney Oct 2, 2026
52303b4
Merge the strict-tooling review fixes from the base branch
zeevmoney Oct 2, 2026
5e219ea
Apply the bounded PDP wait and log filter to the latest-PDP job
zeevmoney Oct 2, 2026
3e9a388
Invite with a role of the invited resource in the invites e2e test
zeevmoney Oct 1, 2026
2513e53
Regenerate ApproveMessage, whose field the API renamed to detail
zeevmoney Oct 1, 2026
e48adf6
Merge the base branch's backported e2e and schema fixes
zeevmoney Oct 2, 2026
5977518
Merge main after #128's squash merge
zeevmoney Oct 2, 2026
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
80 changes: 56 additions & 24 deletions .github/workflows/python-sdk-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
build:
name: Build distribution
runs-on: ubuntu-24.04
# Each job here usually takes under a minute. The timeouts end a hung
# step long before GitHub's default of six hours.
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -77,7 +80,14 @@ jobs:
# published: the wheel, and the sdist, since a wheel built from the sdist
# (pip install --no-binary, a distribution's packager) holds only what
# the sdist does.
- name: Check the wheel and sdist ship their type information
#
# Nor may either one ship a package other than permit: permit 2.8.3's
# wheel installed a top-level `tests` package, which shadowed the
# consumer's own `tests` module. [tool.uv.build-backend] in
# pyproject.toml keeps it out now; this check fails the release if it
# comes back. test.yml's compatibility job runs the same check on pull
# requests to main; keep the two identical.
- name: Check the wheel and sdist contents
run: |
set -euo pipefail
uv run --no-project python - dist <<'PY'
Expand All @@ -86,22 +96,39 @@ jobs:
import zipfile
from pathlib import Path

REQUIRED = ["permit/py.typed", "permit/_sync_types.pyi"]


def check(artifact: Path, names: set[str], found: set[str], allowed: set[str]) -> None:
missing = [path for path in REQUIRED if path not in names]
if missing:
sys.exit(f"{artifact.name} is missing {missing}")
unexpected = sorted(found - allowed)
if unexpected:
sys.exit(f"{artifact.name} holds {unexpected}; only {sorted(allowed)} may ship")
print(f"{artifact.name} ships {' and '.join(REQUIRED)} and no package beside permit")


dist = Path(sys.argv[1])
wheels = sorted(dist.glob("*.whl"))
sdists = sorted(dist.glob("*.tar.gz"))
if len(wheels) != 1 or len(sdists) != 1:
found = [path.name for path in wheels + sdists]
sys.exit(f"expected one wheel and one sdist in {dist}, found {found}")
required = ["permit/py.typed", "permit/_sync_types.pyi"]
contents = {wheels[0]: set(zipfile.ZipFile(wheels[0]).namelist())}
# Every sdist path starts with its top-level permit-<version>/ directory.
with tarfile.open(sdists[0]) as sdist:
contents[sdists[0]] = {name.partition("/")[2] for name in sdist.getnames()}
for artifact, names in contents.items():
missing = [path for path in required if path not in names]
if missing:
sys.exit(f"{artifact.name} is missing {missing}")
print(f"{artifact.name} ships {' and '.join(required)}")
wheel, sdist = wheels[0], sdists[0]

# A wheel's top level is what lands in site-packages: permit/ and its
# permit-<version>.dist-info, named after permit-<version>-<tags>.whl.
with zipfile.ZipFile(wheel) as wheel_file:
names = set(wheel_file.namelist())
dist_info = "-".join(wheel.name.split("-")[:2]) + ".dist-info"
check(wheel, names, {name.split("/")[0] for name in names}, {"permit", dist_info})

# Every sdist path starts with its permit-<version>/ directory. Below
# it, the files are metadata and docs, and the only directory is permit/.
with tarfile.open(sdist) as sdist_file:
names = {name.partition("/")[2] for name in sdist_file.getnames()}
check(sdist, names, {name.split("/")[0] for name in names if "/" in name}, {"permit"})
PY

- name: Upload distribution
Expand All @@ -114,6 +141,7 @@ jobs:
scan:
name: Security Gate
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: [build]
steps:
- name: Checkout code
Expand Down Expand Up @@ -150,6 +178,12 @@ jobs:
# See the same step in security.yml: this only installs Trivy, and
# hide-progress keeps its empty scan from logging a warning.
hide-progress: true
# The action's cache is on by default and restores the Trivy binary
# itself from the Actions cache, with no checksum check, so a cache
# entry would decide which scanner the release gate runs. Off: every
# release downloads the binary and checks it against the checksums
# of its Trivy release.
cache: false
# The migration skill's sample apps pin vulnerable versions on
# purpose and are never installed (skills/tests/README.md).
skip-dirs: skills/tests/fixtures
Expand Down Expand Up @@ -209,15 +243,21 @@ jobs:
publish:
name: Publish to PyPI
runs-on: ubuntu-24.04
timeout-minutes: 10
needs: [scan]
# PyPI trusted publishing: this job holds no PyPI token. PyPI accepts its
# upload because this repository, this workflow file and this environment
# are registered as a trusted publisher of the permit project on pypi.org.
# Renaming any of the three stops releases until that registration is
# changed to match. PyPI does not check which branch or tag the job ran
# from, so a branch that edits this file to run on push could upload too.
# What limits uploads to release tags is the pypi environment's deployment
# rules, a repository setting, not anything in this file.
environment:
name: pypi
url: https://pypi.org/p/permit
permissions:
# id-token is what lets gh-action-pypi-publish attach PEP 740 build
# attestations. contents/pull-requests write were previously granted and
# never used -- nothing in this workflow commits or opens a PR.
id-token: write
id-token: write # OIDC token PyPI exchanges for an upload token; also signs attestations
steps:
# NODE_OPTIONS: the unzip library download-artifact v8.0.1 bundles still
# calls the deprecated Buffer() constructor, so every download prints
Expand All @@ -231,14 +271,6 @@ jobs:
name: dist
path: dist/

# No password: with no token given, the action authenticates by OIDC.
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
# zizmor: ignore[use-trusted-publishing]
# TODO: migrate to PyPI Trusted Publishing (OIDC) and drop this
# secret. That cannot be done from this repo alone -- it requires
# registering permitio/permit-python + this workflow filename +
# the "pypi" environment as a trusted publisher on PyPI first.
# Flipping the workflow before that is configured would break the
# next release, so it is deliberately left as a follow-up.
password: ${{ secrets.PYPI_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ on:
# a required check that never runs as perpetually pending rather than
# passing, so a path filter here would block every PR that happens not to
# touch a dependency file. The audit takes under two minutes, which is
# cheaper than that failure mode.
# cheaper than that failure mode. Not base-filtered either: a stacked PR,
# whose base is another PR's branch, gets the same checks before it merges.
pull_request:
branches: [main, master]
# Run on every merge to main too, so a regression is surfaced immediately
# (failed run on main) rather than waiting for the next PR to trip over it.
# No PR comment is posted on push; the job summary carries the detail.
Expand Down
Loading
Loading