Repository navigation
v0.18.0
Pre-release
Pre-release
·
116 commits
to dev
since this release
Immutable
release. Only release title and notes can be modified.
FOCA 0.18.0 adds a plugin engine for gateway apps such as proTES (plugins installed and pinned by operators, per-request pipelines, failover routing, provenance and a plugin test kit), an HTTP client for untrusted URLs guarded against SSRF, opt-in roles (e.g., for an admin mode), settings per trusted issuer and Python 3.15 support, and keeps one cached Casbin enforcer per app instance, so that requests cost about the same with many policy rules as with few. It contains breaking changes: please read Migrating to 0.18.0 before upgrading.
Breaking changes
- Access control: each app instance keeps one shared, cached Casbin enforcer, kept up to date via a record of changes (
<collection_name>_changes); rules changed in the database directly (e.g., withmongosh) no longer apply from the next request, but only aftermark_changed()or a restart; enforcer methods that FOCA's adapter can't store (update_policy(),remove_policies()) raiseNotImplementedError; during a rolling update from 0.17, upgrade all instances before changing rules (#450, #454). - Access control:
get_enforcer()is removed; use the context managerlocked_enforcer()(#468, #477). - Access control and errors: apps refuse to start if
group_mappingmaps groups but no group claim is set, or ifclaim_groupshas surrounding whitespace;exceptions.validation_detailsnow defaults totrue, so responses to invalid requests carry the validation reason asdetail(#467, #475). - Auth: with several trusted issuers, subjects are namespaced by issuer (
<namespace>|<subject>, by default the issuer URL), also in policies, resource roles, owners and on-behalf-of users; rules and grants stored for bare subjects no longer apply unless the issuer'snamespaceis set to""(#509, #512). - Auth: trusted issuers can be listed with settings of their own (
namespace,audience,claim_groups,userinfo_claims), which replace the global settings for their tokens;security.auth.issuersis typedSequence[str | IssuerConfig](useissuer_urlsfor the URLs) (#503, #510, #514). - Configuration: the top-level
pluginssection is now validated as FOCA's gateway plugin configuration, with unknown keys refused, also in apps that are no gateways; gateway apps refuse the keys of earlier middleware stacks (middlewares,custom.middlewares) (#486, #496).
Features
- Gateway plugins: a framework-free plugin engine (
foca.plugins) for gateway apps, declared withFoca(gateway=GatewayApp(...)): plugins from the entry point groupfoca.plugins, allowlisted and pinned inplugins.available, run in the phasesrequest,route,forwardandresponse, in steps with fallback alternatives, timeouts andon_failure(#486, #496). - Gateway plugins: clients choose presets, own pipelines (off by default) and backends per request in the reserved tags
gateway.pipelineandgateway.backends, within limits, roles and an admin frame (prepend,append); experimental (#487, #498). - Gateway plugins: provenance records of each run, with hashes of each plugin's changes and no secrets; optional records of failed runs with a TTL (#488, #499).
- Gateway plugins: typed backend lists for gateway apps (#493, #501), a default failover router
foca.routing.ordered(#491, #504), gateway tags that record the pipeline, plugins and backend of each task or run (#494, #505), a plugin listing API for clients (GET /plugins,GET /plugins/{plugin_id}) (#489, #506) and a plugin test kit (foca.plugins.testing) with contract checks and fakes (#492, #507). - Utilities:
GuardedClient(foca.utils.http) sends requests to untrusted URLs with SSRF guards (public addresses only, also after DNS resolution and on connect; redirects not followed; time and size limits); new dependenciesurllib3>=2.6,<3andpackaging>=23(#490, #500). - Access control: opt-in roles (
opt_in_roles, headeropt_in_header, defaultX-Request-Roles) that apply only to requests that ask for them, e.g., for an admin mode, withget_available_opt_in_roles()andget_active_opt_in_roles()(#502, #508). - Access control: ownership by document field (
set_owner_field(),owner_filter()) for resources that are never shared (#455, #456). - Configuration: startup checks that warn about settings that likely don't work as intended (e.g., no admins; placeholder service info), and
security.access_control.require_admin(#459, #466). - Configuration: public URLs behind proxies (
server.public_url,get_public_url()) and the typed custom configuration (get_custom_config()) (#460, #465). - Errors: request-specific details of validation errors (
exceptions.validation_details) (#461, #464). - Deployment: default Gunicorn settings for apps in containers (
foca.gunicorn_config) (#458, #463). - Python 3.15 is supported, with images tagged
-py3.15; the unsuffixed tags stay on Python 3.13 (#448, #457).
Security
- Gateway plugins: client pipelines are off by default and only accepted from authenticated callers, and the app warns on startup about policy steps of the default pipeline that client pipelines could skip (#518, #526).
- Gateway plugins: the caller (
Principal) passed to plugins is identified as by access control: on-behalf-of users, the roles of service clients and role rules (#519, #527). - The SSRF guard rejects IPv6 site-local addresses (
fec0::/10); the build context of the base image is an allowlist, so local files (e.g.,.env) can't end up in published images; the petstore-access-control example adds admins via the permissions API (#516, #522). - The
.dockerignorefiles of the examples are allowlists, so that local files stay out of example images (#511, #513).
Fixes
- Gateway plugins: the plugin listing API works in apps that set a controller for all operations (
add_operation_fieldswithx-openapi-router-controller) (#515, #521). - Gateway plugins: gateway settings are bound to their app: a later
Foca(...)withoutgateway=(e.g., in a Celery worker module) no longer clears them (#517, #525). - Access control: opt-in roles need no group mapping to them, so that an app's base config can make a role opt-in before its deployments map groups to it; apps warn of opt-in roles that no group is mapped to on startup, and opt-in roles must not be resource roles or start with a subject prefix (#530, #533).
- Releases are published only after their assets are uploaded (#451, #452).
- The petstore chart and the docs use a keep-alive of 100 s, longer than the idle timeouts of common proxies (#469, #478).
Documentation
- Migration guide for 0.18, linked from the README and the docs index; the README lists gateway plugins and the guarded HTTP client (#523, #531, #534, #535).
- Gateway plugins: the client-facing tags
gateway.pipelineandgateway.backendsand the settingsclient_pipelinesandclient_backendsare marked as experimental, as they may change with federated backend selection (#528) (#529, #532). - The version is taken from one source (#453, #462), and the chart version in the docs from
Chart.yaml(#472, #481). - Zenodo DOI and badge (#412, #476); the docs badge uses Shields.io (#473, #474, #479).
Maintenance
- CI workflow and job names are aligned with the other repositories, with a single required gate
CI passed(#480, #482). - Releases of the library chart need approval (#449, #520).
- Sourcery skips rule-test fixtures (#470, #471).
- Dependency updates (#484, #497).
- Citation metadata for 0.18.0 (#524, #536).
- A flaky timing test of the registry backend cache is fixed (#537, #538).
Commits
- fix: publish releases after uploading assets by @uniqueg in #452
- perf(access-control): cache the policy enforcer by @uniqueg in #454
- feat(access-control): add field-based ownership by @uniqueg in #456
- build: support Python 3.15 by @uniqueg in #457
- docs: take the version from one source by @uniqueg in #462
- feat(config): add default Gunicorn settings by @uniqueg in #463
- feat(errors): serve validation error details by @uniqueg in #464
- feat: add public URLs and typed custom config by @uniqueg in #465
- feat: add startup checks of the config by @uniqueg in #466
- ci: let Sourcery skip rule-test fixtures by @uniqueg in #471
- docs: fix the docs badge URL by @uniqueg in #474
- docs: add the Zenodo DOI and badge by @uniqueg in #476
- feat!: tighten group checks and error details by @uniqueg in #475
- refactor!: remove get_enforcer() by @uniqueg in #477
- fix(chart): use a keep-alive of 100 s by @uniqueg in #478
- docs: use Shields.io for the docs badge by @uniqueg in #479
- docs: take the chart version from Chart.yaml by @uniqueg in #481
- ci: align workflow and job names by @uniqueg in #482
- feat(plugins): add plugin engine by @uniqueg in #496
- feat(plugins): resolve per-request pipelines by @uniqueg in #498
- feat(plugins): record provenance by @uniqueg in #499
- feat(utils): add a guarded HTTP client by @uniqueg in #500
- feat(plugins): add typed backend lists by @uniqueg in #501
- feat(plugins): add default failover router by @uniqueg in #504
- feat(plugins): write gateway tags by @uniqueg in #505
- feat(plugins): list plugins for clients by @uniqueg in #506
- feat(plugins): add plugin test kit by @uniqueg in #507
- feat(access-control): add opt-in roles by @uniqueg in #508
- fix(auth): namespace subjects of several issuers by @uniqueg in #512
- fix: keep local files out of example images by @uniqueg in #513
- feat(auth): add per-issuer settings by @uniqueg in #514
- build(deps): Bump semgrep from 1.181.0 to 1.182.1 in the semgrep group across 1 directory by @dependabot[bot] in #497
- fix: close small pre-release review gaps by @uniqueg in #522
- fix(plugins): set controller of listing operations by @uniqueg in #521
- build(deps): Bump the github-actions group across 3 directories with 4 updates by @dependabot[bot] in #484
- ci: approve library chart releases by @uniqueg in #520
- fix(plugins): bind gateway settings to their app by @uniqueg in #525
- fix(plugins): fail closed on client pipelines by @uniqueg in #526
- fix(plugins): align Principal with access control by @uniqueg in #527
- docs: mark client gateway tags as experimental by @uniqueg in #532
- docs: complete the 0.18 migration guide by @uniqueg in #531
- fix: allow opt-in roles without group mapping by @uniqueg in #533
- docs: align the 0.18 guide on opt-in roles by @uniqueg in #535
- chore: set citation metadata to 0.18.0 by @uniqueg in #536
- test: fix flaky backend cache timing by @uniqueg in #538
Full Changelog: v0.17.0...v0.18.0