Compare commits

...

10 commits

Author SHA1 Message Date
Kévin Commaille 1e8cecb601
Merge f95dcfb0e7 into 43c65786eb 2026-01-06 12:52:16 -05:00
Tulir Asokan 43c65786eb
Specify that the /openid/userinfo return value must be validated (#2288) 2026-01-06 12:23:19 -05:00
Richard van der Hoff f2b68c7163
Updates to release process (#2289)
Some clarifications to the release process doc, particularly in view of #2275.
2026-01-06 17:05:59 +00:00
Richard van der Hoff fb2221aad7
Include spec release in filenames in built tarball (#2276)
It's slightly confusing that everything just ends up under `spec/`, so let's
put the version number in there
2026-01-06 16:19:57 +00:00
Kévin Commaille f95dcfb0e7
Fix changelog (again)
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 13:09:53 +01:00
Kévin Commaille c98c03b32c
Fix changelogs
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 13:06:50 +01:00
Kévin Commaille 19bf443d0e
Fix examples
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 13:03:03 +01:00
Kévin Commaille 147f8703d4
Fix fragments
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 12:59:01 +01:00
Kévin Commaille bcd5f6bcfb
Add changelog
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 12:54:20 +01:00
Kévin Commaille 05b0d0602d
Spec User suspension & locking endpoints
As per MSC4323.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-12-19 12:46:54 +01:00
15 changed files with 481 additions and 43 deletions

View file

@ -195,6 +195,8 @@ jobs:
needs: [calculate-baseurl, build-openapi, generate-changelog] needs: [calculate-baseurl, build-openapi, generate-changelog]
# run even if generate-changelog was skipped # run even if generate-changelog was skipped
if: ${{ always() }} if: ${{ always() }}
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
steps: steps:
- name: " Setup Node" - name: " Setup Node"
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -217,8 +219,10 @@ jobs:
with: with:
name: changelog-artifact name: changelog-artifact
path: content/changelog path: content/changelog
- name: "⚙️ hugo" - name: "⚙️ hugo"
run: hugo --baseURL "${{ needs.calculate-baseurl.outputs.baseURL }}" -d "spec" run: hugo --baseURL "${baseURL}" -d "spec${baseURL}"
# We manually unpack the spec OpenAPI definition JSON to the website tree # We manually unpack the spec OpenAPI definition JSON to the website tree
# to make it available to the world in a canonical place: # to make it available to the world in a canonical place:
# https://spec.matrix.org/latest/client-server-api/api.json # https://spec.matrix.org/latest/client-server-api/api.json
@ -229,10 +233,13 @@ jobs:
name: openapi-artifact name: openapi-artifact
- name: "📝 Unpack the OpenAPI definitions in the right location" - name: "📝 Unpack the OpenAPI definitions in the right location"
run: | run: |
tar -xzf openapi.tar.gz tar -C "spec${baseURL}" --strip-components=1 -xzf openapi.tar.gz
- name: "📦 Tarball creation" - name: "📦 Tarball creation"
run: tar -czf spec.tar.gz spec run: |
cd spec
tar -czf ../spec.tar.gz *
- name: "📤 Artifact upload" - name: "📤 Artifact upload"
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
@ -261,14 +268,9 @@ jobs:
name: spec-artifact name: spec-artifact
- name: "📝 Unpack the spec" - name: "📝 Unpack the spec"
# we have to unpack it into the right path given the baseurl, so that the
# links are correct.
# eg if baseurl is `/unstable`, we want to put the site in `spec/unstable`.
run: | run: |
mkdir -p "spec${baseURL}" mkdir spec
tar -C "spec${baseURL}" --strip-components=1 -xvzf spec.tar.gz tar -C spec -xvzf spec.tar.gz
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
- name: "Run htmltest" - name: "Run htmltest"
uses: wjdp/htmltest-action@master uses: wjdp/htmltest-action@master
@ -278,8 +280,10 @@ jobs:
build-historical-spec: build-historical-spec:
name: "📖 Build the historical backup spec" name: "📖 Build the historical backup spec"
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-openapi] needs: [calculate-baseurl, build-openapi]
if: ${{ startsWith(github.ref, 'refs/tags/') }} if: ${{ startsWith(github.ref, 'refs/tags/') }}
env:
baseURL: "${{ needs.calculate-baseurl.outputs.baseURL }}"
steps: steps:
- name: " Setup Node" - name: " Setup Node"
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -299,9 +303,8 @@ jobs:
- name: "⚙️ hugo" - name: "⚙️ hugo"
env: env:
HUGO_PARAMS_VERSION_STATUS: "historical" HUGO_PARAMS_VERSION_STATUS: "historical"
# Create a baseURL like `/v1.2` out of the `v1.2` tag
run: | run: |
hugo --baseURL "/${GITHUB_REF/refs\/tags\//}" -d "spec" hugo --baseURL "${baseURL}" -d "spec${baseURL}"
- name: "📥 Spec definition download" - name: "📥 Spec definition download"
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@ -309,10 +312,12 @@ jobs:
name: openapi-artifact name: openapi-artifact
- name: "📝 Unpack the OpenAPI definitions in the right location" - name: "📝 Unpack the OpenAPI definitions in the right location"
run: | run: |
tar -xzf openapi.tar.gz tar -C "spec${baseURL}" --strip-components=1 -xzf openapi.tar.gz
- name: "📦 Tarball creation" - name: "📦 Tarball creation"
run: tar -czf spec-historical.tar.gz spec run: |
cd spec
tar -czf ../spec-historical.tar.gz *
- name: "📤 Artifact upload" - name: "📤 Artifact upload"
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4

View file

@ -45,7 +45,9 @@ jobs:
name: spec-artifact name: spec-artifact
- name: "📦 Extract Artifacts" - name: "📦 Extract Artifacts"
run: tar -xzvf spec.tar.gz && rm spec.tar.gz run: |
mkdir spec
tar -C spec -xzvf spec.tar.gz && rm spec.tar.gz
- name: "📤 Deploy to Netlify" - name: "📤 Deploy to Netlify"
id: netlify id: netlify

View file

@ -0,0 +1 @@
Add endpoints to lock and suspend server-local users for administrations and add the `m.account_management` capability, as per [MSC4323](https://github.com/matrix-org/matrix-spec-proposals/pull/4323).

View file

@ -0,0 +1 @@
Add `GET /_matrix/client/v1/admin/suspend/{userId}`, as per [MSC4323](https://github.com/matrix-org/matrix-spec-proposals/pull/4323).

View file

@ -0,0 +1 @@
Add `PUT /_matrix/client/v1/admin/suspend/{userId}`, as per [MSC4323](https://github.com/matrix-org/matrix-spec-proposals/pull/4323).

View file

@ -0,0 +1 @@
Add `GET /_matrix/client/v1/admin/lock/{userId}`, as per [MSC4323](https://github.com/matrix-org/matrix-spec-proposals/pull/4323).

View file

@ -0,0 +1 @@
Add `PUT /_matrix/client/v1/admin/lock/{userId}`, as per [MSC4323](https://github.com/matrix-org/matrix-spec-proposals/pull/4323).

View file

@ -0,0 +1 @@
Include the spec release version in the filenames in the tarballs generated by CI.

View file

@ -0,0 +1 @@
Updates to the release documentation.

View file

@ -0,0 +1 @@
Specify that callers of `/_matrix/federation/v1/openid/userinfo` must validate the returned user ID.

View file

@ -2280,9 +2280,12 @@ The server SHOULD return one of the following responses:
Server administrators may apply locks to prevent users from usefully Server administrators may apply locks to prevent users from usefully
using their accounts, for instance, due to safety or security concerns. using their accounts, for instance, due to safety or security concerns.
In contrast to account deactivation, locking is a non-destructive action In contrast to account deactivation, locking is a non-destructive action
that can be reversed. This specification describes the behaviour of clients that can be reversed.
and servers when an account is locked. It deliberately leaves the methods
for locking and unlocking accounts as a server implementation detail. {{% added-in v="1.18" %}} To lock or unlock an account, the administrators
SHOULD use the [`PUT /admin/lock/{userId}`](#put_matrixclientv1adminlockuserid)
endpoint. They MAY also use [`GET /admin/lock/{userId}`](#get_matrixclientv1adminlockuserid)
to check whether a user's account is locked.
When an account is locked, servers MUST return a `401 Unauthorized` error When an account is locked, servers MUST return a `401 Unauthorized` error
response with an `M_USER_LOCKED` error code and [`soft_logout`](#soft-logout) response with an `M_USER_LOCKED` error code and [`soft_logout`](#soft-logout)
@ -2331,6 +2334,11 @@ from that account. The effect is similar to [locking](#account-locking), though
without risk of the client losing state from a logout. Suspensions are reversible, without risk of the client losing state from a logout. Suspensions are reversible,
like locks and unlike deactivations. like locks and unlike deactivations.
{{% added-in v="1.18" %}} To suspend or unsuspend an account, the administrators
SHOULD use the [`PUT /admin/suspend/{userId}`](#put_matrixclientv1adminsuspenduserid)
endpoint. They MAY also use [`GET /admin/suspend/{userId}`](#get_matrixclientv1adminsuspenduserid)
to check whether a user's account is suspended.
The actions a user can perform while suspended is deliberately left as an The actions a user can perform while suspended is deliberately left as an
implementation detail. Servers SHOULD permit the user to perform at least the implementation detail. Servers SHOULD permit the user to perform at least the
following, however: following, however:
@ -2386,9 +2394,6 @@ Content-Type: application/json
} }
``` ```
APIs for initiating suspension or unsuspension are not included in this version
of the specification, and left as an implementation detail.
### Adding Account Administrative Contact Information ### Adding Account Administrative Contact Information
A homeserver may keep some contact information for administrative use. A homeserver may keep some contact information for administrative use.

View file

@ -16,7 +16,7 @@ info:
title: Matrix Client-Server Administration API title: Matrix Client-Server Administration API
version: 1.0.0 version: 1.0.0
paths: paths:
"/admin/whois/{userId}": "/v3/admin/whois/{userId}":
get: get:
summary: Gets information about a particular user. summary: Gets information about a particular user.
description: |- description: |-
@ -107,6 +107,391 @@ paths:
} }
tags: tags:
- Server administration - Server administration
"/v1/admin/suspend/{userId}":
get:
summary: Gets information about the suspended status of a particular user.
x-addedInMatrixVersion: "1.18"
description: |-
Gets information about the suspended status of a particular server-local user.
The user calling this endpoint MUST be a server admin.
In order to prevent user enumeration, servers MUST ensure that authorization is checked
prior to trying to do account lookups.
operationId: getAdminSuspendUser
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user to look up.
required: true
example: "@peter:rabbit.rocks"
schema:
type: string
format: mx-user-id
pattern: "^@"
responses:
"200":
description: The lookup was successful.
content:
application/json:
schema:
type: object
properties:
suspended:
type: boolean
description: Whether the target account is suspended.
example: true
required:
- suspended
examples:
response:
value: {
"suspended": true,
}
"400":
description: |-
The user ID does not belong to the local server. The errcode is `M_INVALID_PARAM`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_INVALID_PARAM",
"error": "User does not belong to the local server."
}
"403":
description: |-
The requesting user is not a server administrator, or the target user is another
administrator. The errcode is `M_FORBIDDEN`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Requesting user is not a server administrator."
}
"404":
description: |-
The user ID is not found, or is deactivated. The errcode is `M_NOT_FOUND`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "User not found."
}
tags:
- Server administration
put:
summary: Set the suspended status of a particular user.
x-addedInMatrixVersion: "1.18"
description: |-
Sets the suspended status of a particular server-local user.
The user calling this endpoint MUST be a server admin. The client SHOULD check that the user
is allowed to suspend other users at the [`GET /capabilities`](/client-server-api/#get_matrixclientv3capabilities)
endpoint prior to using this endpoint.
In order to prevent user enumeration, servers MUST ensure that authorization is checked
prior to trying to do account lookups.
operationId: setAdminSuspendUser
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user to change the suspended status of.
required: true
example: "@peter:rabbit.rocks"
schema:
type: string
format: mx-user-id
pattern: "^@"
requestBody:
content:
application/json:
schema:
type: object
properties:
suspended:
type: boolean
description: Whether to suspend the target account.
example: true
required:
- suspended
examples:
request:
value: {
"suspended": true,
}
required: true
responses:
"200":
description: The action was successful.
content:
application/json:
schema:
type: object
properties:
suspended:
type: boolean
description: Whether the target account is suspended.
example: true
required:
- suspended
examples:
response:
value: {
"suspended": true,
}
"400":
description: |-
The user ID does not belong to the local server. The errcode is `M_INVALID_PARAM`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_INVALID_PARAM",
"error": "User does not belong to the local server."
}
"403":
description: |-
The requesting user is not a server administrator, is trying to suspend their own
account, or the target user is another administrator. The errcode is `M_FORBIDDEN`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Requesting user is not a server administrator."
}
"404":
description: |-
The user ID is not found, or is deactivated. The errcode is `M_NOT_FOUND`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "User not found."
}
tags:
- Server administration
"/v1/admin/lock/{userId}":
get:
summary: Gets information about the locked status of a particular user.
x-addedInMatrixVersion: "1.18"
description: |-
Gets information about the locked status of a particular server-local user.
The user calling this endpoint MUST be a server admin.
In order to prevent user enumeration, servers MUST ensure that authorization is checked
prior to trying to do account lookups.
operationId: getAdminLockUser
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user to look up.
required: true
example: "@peter:rabbit.rocks"
schema:
type: string
format: mx-user-id
pattern: "^@"
responses:
"200":
description: The lookup was successful.
content:
application/json:
schema:
type: object
properties:
locked:
type: boolean
description: Whether the target account is locked.
required:
- locked
examples:
response:
value: {
"locked": true,
}
"400":
description: |-
The user ID does not belong to the local server. The errcode is `M_INVALID_PARAM`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_INVALID_PARAM",
"error": "User does not belong to the local server."
}
"403":
description: |-
The requesting user is not a server administrator, or the target user is another
administrator. The errcode is `M_FORBIDDEN`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Requesting user is not a server administrator."
}
"404":
description: |-
The user ID is not found, or is deactivated. The errcode is `M_NOT_FOUND`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "User not found."
}
tags:
- Server administration
put:
summary: Set the locked status of a particular user.
x-addedInMatrixVersion: "1.18"
description: |-
Sets the locked status of a particular server-local user.
The user calling this endpoint MUST be a server admin. The client SHOULD check that the user
is allowed to lock other users at the [`GET /capabilities`](/client-server-api/#get_matrixclientv3capabilities)
endpoint prior to using this endpoint.
In order to prevent user enumeration, servers MUST ensure that authorization is checked
prior to trying to do account lookups.
operationId: setAdminLockUser
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user to change the locked status of.
required: true
example: "@peter:rabbit.rocks"
schema:
type: string
format: mx-user-id
pattern: "^@"
requestBody:
content:
application/json:
schema:
type: object
properties:
locked:
type: boolean
description: Whether to lock the target account.
example: true
required:
- locked
examples:
request:
value: {
"locked": true,
}
required: true
responses:
"200":
description: The action was successful.
content:
application/json:
schema:
type: object
properties:
locked:
type: boolean
description: Whether the target account is locked.
example: true
required:
- locked
examples:
response:
value: {
"locked": true,
}
"400":
description: |-
The user ID does not belong to the local server. The errcode is `M_INVALID_PARAM`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_INVALID_PARAM",
"error": "User does not belong to the local server."
}
"403":
description: |-
The requesting user is not a server administrator, is trying to lock their own
account, or the target user is another administrator. The errcode is `M_FORBIDDEN`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Requesting user is not a server administrator."
}
"404":
description: |-
The user ID is not found, or is deactivated. The errcode is `M_NOT_FOUND`.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "User not found."
}
tags:
- Server administration
servers: servers:
- url: "{protocol}://{hostname}{basePath}" - url: "{protocol}://{hostname}{basePath}"
variables: variables:
@ -118,7 +503,7 @@ servers:
hostname: hostname:
default: localhost:8008 default: localhost:8008
basePath: basePath:
default: /_matrix/client/v3 default: /_matrix/client
components: components:
securitySchemes: securitySchemes:
accessTokenQuery: accessTokenQuery:

View file

@ -141,6 +141,34 @@ paths:
example: true example: true
required: required:
- enabled - enabled
m.account_moderation:
x-addedInMatrixVersion: "1.18"
type: object
title: AccountModerationCapability
description: |-
Capability to indicate if the user can perform account moderation actions
via [server administration](/client-server-api/#server-administration)
endpoints.
This property should be omitted altogether if `suspend` and `lock` would
be `false`.
properties:
suspend:
type: boolean
description: |-
`true` if the user can suspend a user via [`PUT /admin/suspend/{userId}`](/client-server-api/#put_matrixclientv1adminsuspenduserid),
`false` otherwise.
Defaults to `false`.
example: true
lock:
type: boolean
description: |-
`true` if the user can lock a user via [`PUT /admin/lock/{userId}`](/client-server-api/#put_matrixclientv1adminlockuserid),
`false` otherwise.
Defaults to `false`.
example: true
examples: examples:
response: response:
value: { value: {

View file

@ -43,7 +43,12 @@ paths:
properties: properties:
sub: sub:
type: string type: string
description: The Matrix User ID who generated the token. description: |
The Matrix User ID who generated the token.
The caller MUST validate that the returned user ID is on the server they
called (i.e. if you make a request to example.com and it returns
`@alice:matrix.org`, the result is invalid).
example: "@alice:example.com" example: "@alice:example.com"
required: required:
- sub - sub

View file

@ -50,11 +50,6 @@ First, can we even release the spec? This stage is mostly preparation work neede
to ensure a consistent and reliable specification. to ensure a consistent and reliable specification.
1. Ensure `main` is committed with all the spec changes you expect to be there. 1. Ensure `main` is committed with all the spec changes you expect to be there.
2. Review the changelog to look for typos, wording inconsistencies, or lines which
can be merged. For example, "Fix typos" and "Fix spelling" can be condensed to
"Fix various typos throughout the specification".
3. Do a quick skim to ensure changelogs reference the MSCs which brought the changes
in. They should be linked to the GitHub MSC PR (not the markdown document).
## The release ## The release
@ -79,20 +74,24 @@ release.
2. Run `./scripts/generate-changelog.sh v1.2` (using the correct version number). 2. Run `./scripts/generate-changelog.sh v1.2` (using the correct version number).
The script will use the current date. If that date is wrong, correct the document The script will use the current date. If that date is wrong, correct the document
by using the same `YYYY-MM-DD` date format. by using the same `YYYY-MM-DD` date format.
3. Commit the result. 3. Review the changelog to look for typos, wording inconsistencies, or lines which
can be merged. For example, "Fix typos" and "Fix spelling" can be condensed to
"Fix various typos throughout the specification".
4. Do a quick skim to ensure changelogs reference the MSCs which brought the changes
in. They should be linked to the GitHub MSC PR (not the markdown document).
5. Commit the result.
6. Now is a good time to have someone else review the changelog.
5. Tag the branch with the spec release with a format of `v1.2` (if releasing Matrix 1.2). 5. Tag the branch with the spec release with a format of `v1.2` (if releasing Matrix 1.2).
6. Push the release branch and the tag. 6. Push the release branch and the tag.
7. GitHub Actions will run its build steps. Wait until these are successful. If fixes 7. GitHub Actions will run its build steps. Wait until these are successful. If fixes
need to be made to repair the pipeline or spec build, delete and re-tag the release. need to be made to repair the pipeline or spec build, delete and re-tag the release.
You may need to fix up the changelog file by hand in this case. You may need to fix up the changelog file by hand in this case.
8. Check out and fast-forward `main` to the release branch. 8. GitHub Actions should have drafted a release based on the new tag. Find it
9. Create a new release on GitHub from the newly created tag. at https://github.com/matrix-org/matrix-spec/releases.
* The title should be just "v1.2" (for example). 1. Double-check the generated release notes, and check that `spec-artifact.zip` and
* The description should be a copy/paste of the changelog. The generated changelog `spec-historical-artifact.zip` are both attached to the draft release.
will be at `content/changelog/v1.2.md` - copy/paste verbatim. 2. Publish the draft release.
* Upload the artifacts of the GitHub Actions build for the release to the GitHub 9. Check out and fast-forward `main` to the release branch.
release as artifacts themselves. This should be the tarball that will be deployed
to spec.matrix.org.
10. Commit a reversion to `params.version` of `./config/_default/hugo.toml` on `main`: 10. Commit a reversion to `params.version` of `./config/_default/hugo.toml` on `main`:
```toml ```toml
[params.version] [params.version]
@ -103,7 +102,8 @@ release.
``` ```
11. Push pending commits and ensure the unstable spec updates accordingly from the 11. Push pending commits and ensure the unstable spec updates accordingly from the
GitHub Actions pipeline. GitHub Actions pipeline.
12. Deploy the release on the webserver. See internal wiki. 12. Deploy the release on the webserver. See "Spec release process" in the
internal handbook.
## Patching a release ## Patching a release