swarm-controller: make an existing forge user a site admin
POST /api/forge/users/{name}/admin reads the account and, when it is not
already a site admin, sets `admin` with admin_edit_user. It never
creates one: a human's account is made by their first authelia login,
so a missing one answers 404, saying the user has not logged in via SSO
yet. An existing admin is a success with nothing sent.
The edit carries `admin` alone. repo_creation_lockdown's login_name +
source_id = 0 would turn an SSO-made account into a local one: in
Forgejo 16 a source_id sets the login type.
An agent's name is refused, and so is any name when the roster can't be
read: a site admin ignores max_repo_creation, the lockdown that keeps an
agent's token from creating a repo and self-merging in it.
Refs #3782
This commit is contained in:
parent
ef494af188
commit
f1f59ea165
4 changed files with 407 additions and 5 deletions
|
|
@ -34,6 +34,7 @@ use utoipa::ToSchema;
|
|||
use crate::webhook::DeliveryKind;
|
||||
|
||||
pub mod agent_token;
|
||||
pub mod site_admin;
|
||||
|
||||
/// An agent's open config-PR, as [`Client::list_open_config_prs`] reports it
|
||||
/// and `GET /api/agents/{name}/config-pr` serves it.
|
||||
|
|
@ -1659,4 +1660,78 @@ mod tests {
|
|||
let body = lockdown_patch(&seen, "alice").expect("no lockdown PATCH sent");
|
||||
assert_eq!(body["max_repo_creation"], 0);
|
||||
}
|
||||
|
||||
/// Every `PATCH` body the stub saw.
|
||||
fn patches(seen: &Seen) -> Vec<serde_json::Value> {
|
||||
seen.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|(method, _, _)| method == "PATCH")
|
||||
.map(|(_, _, body)| body.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Only `admin` goes out: a `source_id` would reset an SSO-made
|
||||
/// account's login type, and the other fields would overwrite the user's
|
||||
/// own settings.
|
||||
#[tokio::test]
|
||||
async fn make_site_admin_sets_admin_and_nothing_else() {
|
||||
let (client, seen) = stub_forge(
|
||||
(404, "{}"),
|
||||
(200, r#"{"login":"mara","is_admin":false}"#),
|
||||
(200, "{}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
let plan = client.make_site_admin("mara").await.unwrap();
|
||||
|
||||
assert_eq!(plan, site_admin::Plan::Promote);
|
||||
let bodies = patches(&seen);
|
||||
assert_eq!(bodies.len(), 1, "{bodies:?}");
|
||||
let set: Vec<(&String, &serde_json::Value)> = bodies[0]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|(_, v)| !v.is_null())
|
||||
.collect();
|
||||
assert_eq!(set, [(&"admin".to_owned(), &serde_json::Value::Bool(true))]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn make_site_admin_leaves_an_admin_alone() {
|
||||
let (client, seen) = stub_forge(
|
||||
(404, "{}"),
|
||||
(200, r#"{"login":"mara","is_admin":true}"#),
|
||||
(200, "{}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
let plan = client.make_site_admin("mara").await.unwrap();
|
||||
|
||||
assert_eq!(plan, site_admin::Plan::AlreadyAdmin);
|
||||
assert!(patches(&seen).is_empty());
|
||||
}
|
||||
|
||||
/// A user who has not logged in yet is reported, not created: nothing is
|
||||
/// sent but the read.
|
||||
#[tokio::test]
|
||||
async fn make_site_admin_does_not_create_a_missing_user() {
|
||||
let (client, seen) = stub_forge(
|
||||
(201, "{}"),
|
||||
(404, r#"{"message":"user does not exist"}"#),
|
||||
(200, "{}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
let plan = client.make_site_admin("mara").await.unwrap();
|
||||
|
||||
assert_eq!(plan, site_admin::Plan::NoSuchUser);
|
||||
let methods: Vec<String> = seen
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(m, _, _)| m.clone())
|
||||
.collect();
|
||||
assert_eq!(methods, ["GET"]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue