Rewrite pack: conformance suite — keystone-tempest-plugin — branch master
Branch
master@41e16f7f319c— run against Keystonestable/2026.2@e6dc5ae079e6with Tempest 47.0.0 — analysed on 2026-10-28keystone:= Keystone repository (stable/2026.2)
This file turns keystone-tempest-plugin into a conformance suite for OpenKeel Keystone:
- what it checks;
- how to run it against any implementation;
- the reference results obtained with the Python Keystone;
- what it does not cover.
1. Reference results
| Measure | Value |
|---|---|
| Tests run | 1,980: 1,936 RBAC, 38 API, 6 scenario |
| Passed | 1,966 |
| Skipped | 14 by design (02 § 4); 0 failure, 0 error |
| HTTP exchanges | 17,873, each tagged with its test |
RBAC assertions (do_request) | 4,372, 0 differences between the expected and the actual status |
| Operations in the RBAC matrix | 187 |
| Keystone routes exercised | 196 of 259 (§ 5) |
| Response schemas inferred | 198 operations |
| Duration | about 12 minutes on a laptop, with the harness settings of § 2 |
A rewrite is conformant when it gives the same outcome for all 1,980 tests, with the same 14 skips. A stricter check also compares the 4,372 assertions one by one with _rewrite/rbac-assertions_master.json.
2. How to run it
Use the keystone_tempest_plugin.py adapter of the generate-reverse-spec skill. Install Keystone, Tempest and the plugin in the same venv:
conformance_capture.py scenarios <keystone-tempest-plugin> --branch master --adapter adapters/keystone_tempest_plugin.py \
--routes-json <reverse-spec-keystone>/_rewrite/routes_stable-2026.2.json --workdir <tmp> --out <tmp>/cc
- Restrict the run with
KTP_MODULES=keystone_tempest_plugin.tests.rbac.v3.test_project,…. One module takes under a minute. - Keystone settings that the suite needs:
[oslo_policy] enforce_scope = trueandenforce_new_defaults = true, otherwise the RBAC tests are skipped or test the old rules;[identity-feature-enabled]intempest.conf:access_rules,application_credentials,project_tags,trust= true;federation,external_idp= false.
- Two process constraints:
- Tempest and Keystone both use the global oslo.config object, so Tempest runs in a subprocess.
- Keystone is served on
127.0.0.1:<free port>. A runner addsX-Test-Idto every request, so that each exchange is tagged with its test.
- Speed of the harness, which does not change behaviour:
- oslo.db forces
NullPoolon SQLite files, so every session reconnects and re-reads the schema. The adapter switches toQueuePool; without it, the full run takes hours. - The adapter sets
[identity] password_hash_rounds = 4, the bcrypt minimum.
- oslo.db forces
- Against OpenKeel Keystone: keep the generated
tempest.conf, point[identity] uri_v3at the Go service, create the bootstrap admin (admin, projectadmin,Defaultdomain, system roleadmin), then run the runner alone, or the adapter with the service started outside.
3. What the RBAC matrix requires
_rewrite/rbac-matrix_master.md gives the expected result for each operation and each of the 11 personas: system_*, domain_* and project_*, with the roles admin, manager, member and reader. It is the executable form of Keystone's default policies. Key points for a rewrite:
- **An
adminrole on a project is a cloud administrator.**project_adminhas the same result assystem_adminon 179 of the 181 operations where both are tested: it can create domains, limits, roles, endpoints, identity providers, endpoint groups…- The cause is the rule
admin_required = role:admin or is_admin:1(keystone:keystone/common/policies/base.py:84). Many policies accept it withscope_types=['system', 'project'], for exampleidentity:create_domain(keystone:keystone/common/policies/domain.py:83-89). - The tests encode it:
ProjectAdminTestsinherits fromSystemAdminTests(keystone_tempest_plugin/tests/rbac/v3/test_project.py:580-582,keystone_tempest_plugin/tests/rbac/v3/test_user.py:492). - The 2 differences are trusts (
POST /v3/OS-TRUST/trusts, which needs a project-scoped token) and the access rules of another user.
- **
domain_adminis also a global administrator for users and projects** (DomainAdminTestsinherits fromSystemAdminTests,keystone_tempest_plugin/tests/rbac/v3/test_user.py:251). However, it is refused the operations whosescope_typesexcludedomain, such asPOST /v3/domains. - **
domain_managerandproject_manager** (themanagerrole) give✓/403cells: allowed in their own domain or project, refused elsewhere. Examples: create projects and users, and grant roles in their own domain. A rewrite must evaluate the target (target.domain.id,target.project.id), not just the role. - Readers and members get 403 on every write. Reads of other domains or projects give 403 too.
- Owner-filtered lists:
GET /v3/credentialsreturns 200 to all 11 personas, so the matrix shows✓everywhere. The filtering is checked by the test itself, withassertIn/assertNotInon the body:domain_*andproject_*see their own credentials and not those of other users (keystone_tempest_plugin/tests/rbac/v3/test_credential.py:381-397, inherited by every class fromDomainManagerTestsdown);- the system personas,
domain_adminandproject_adminsee all of them (keystone_tempest_plugin/tests/rbac/v3/test_credential.py:211-221).
- 403 or 404 for a target that does not exist: see 02 § 2.
4. A behaviour the suite no longer checks
Commit d5dcf00f4f69 of the plugin removed the tests of cross-domain grants of domain-specific roles (06):
- Keystone
stable/2026.2still acceptsPUT /v3/domains/{d}/users/{u}/roles/{r}with 204 whenrbelongs to another domain; - Keystone
masterrefuses it sincekeystone:fa43c4b3d.
Since the plugin tests neither behaviour, a rewrite must decide on its own. Recommendation: refuse the grant (403), like master, and add that test to the OpenKeel suite.
5. Coverage gaps
63 Keystone routes are not called by any test (_rewrite/keystone-operations-not-covered_master.json). They need their own tests in OpenKeel:
| Group | Routes | Notes |
|---|---|---|
Methods registered on collection URLs (DELETE /v3/policies, PATCH /v3/OS-OAUTH1/consumers, PUT /v3/OS-FEDERATION/mappings, GET /v3/ec2tokens…) | 16 | not used by any client; their actual behaviour was not checked here |
OS-INHERIT (inherited role assignments) | 14 | none tested: grant, check, list and revoke inherited roles |
Federated login (…/protocols/{p}/auth, WebSSO, SAML2, ECP, metadata, OS-FEDERATION/domains and projects) | 13 | needs an external IdP: the 6 federation scenarios are skipped |
/v3/auth/catalog, domains, projects, system, tokens/OS-PKI/revoked | 5 | token introspection, used by Horizon and the CLI |
OAuth1 delegation (request_token, authorize, access_token) and POST /v3/OS-OAUTH2/token | 4 | only the consumer CRUD is tested |
Discovery /, /v3, /static/{filename} | 3 | tested by keystoneauth's scenarios (reverse-spec-keystoneauth 07) |
| Other | 8 | POST /v3/users/{u}/password (change one's own password), DELETE /v3/users/{u}/tokens, GET /v3/OS-REVOKE/events, POST /v3/regions, POST /v3/ec2tokens, POST /v3/s3tokens, GET /v3/OS-SIMPLE-CERT/ca and certificates |
Keystone's own unit tests cover these routes (reverse-spec-keystone 07). Together, the two suites cover the API.
6. Files in _rewrite/
| File | Content |
|---|---|
tests_master.json | the 1,980 tests with outcome and skip reason |
rbac-assertions_master.json | the 4,372 assertions: test, persona, client method, expected status or exception, requests made with their status |
rbac-matrix_master.md / .json | operation × persona matrix, with the policy names |
exchanges_master.json.gz | the 17,873 exchanges (request, response, test id) |
response-schemas_master.md / .json | response schemas for 198 operations |
observed-errors_master.md | 271 (operation, status, message) combinations |
keystone-operations-not-covered_master.json | the 63 routes not exercised |
Source: reverse-spec-keystone-tempest-plugin/07-rewrite-pack_master.md. The _rewrite/ and _inventory/ files are not published on the site.