forge: core token gets admin scope so PATCH /admin/users/* works (#646)
This commit is contained in:
parent
e0070417fb
commit
745d95d2f5
1 changed files with 18 additions and 5 deletions
|
|
@ -78,6 +78,16 @@ const SEEDED_ORGS: &[&str] = &[CONFIG_ORG];
|
|||
const TOKEN_SCOPES: &str =
|
||||
"read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
||||
|
||||
/// Scopes for the bootstrap `core` token used by hive-c0re itself.
|
||||
/// Adds `read:admin,write:admin` on top of `TOKEN_SCOPES` so the host
|
||||
/// daemon can drive `/api/v1/admin/*` endpoints (PATCH user email on
|
||||
/// agent provision, future webhook + org admin work). Site-admin
|
||||
/// membership alone isn't enough — the token's own scope gate runs
|
||||
/// before the user-permission check, so `403 Forbidden` comes back
|
||||
/// for any `/admin/users/*` call from a non-admin-scoped token
|
||||
/// even if the bearer is an admin user (#646).
|
||||
const CORE_TOKEN_SCOPES: &str = "read:admin,write:admin,read:user,write:user,read:notification,write:notification,write:repository,write:issue,write:organization,write:misc";
|
||||
|
||||
/// Token file inside the agent's bind-mounted state dir (visible as
|
||||
/// `/state/forge-token` from inside the container).
|
||||
fn token_path(name: &str) -> PathBuf {
|
||||
|
|
@ -257,8 +267,11 @@ async fn ensure_user_email(name: &str) {
|
|||
/// Mint a fresh access token for `name` and persist it to
|
||||
/// `<state>/forge-token` (0600). Token name is suffixed with a
|
||||
/// monotonic clock so re-issuing doesn't collide with an existing
|
||||
/// token of the same name in the DB.
|
||||
async fn mint_and_persist_token(name: &str, path: &Path) -> Result<()> {
|
||||
/// token of the same name in the DB. `scopes` is the scope string
|
||||
/// passed to `forgejo admin user generate-access-token --scopes`;
|
||||
/// use `TOKEN_SCOPES` for agents, `CORE_TOKEN_SCOPES` for the
|
||||
/// bootstrap `core` user.
|
||||
async fn mint_and_persist_token(name: &str, path: &Path, scopes: &str) -> Result<()> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let token_name = format!(
|
||||
"{TOKEN_NAME_PREFIX}-{}",
|
||||
|
|
@ -275,7 +288,7 @@ async fn mint_and_persist_token(name: &str, path: &Path) -> Result<()> {
|
|||
"--token-name",
|
||||
&token_name,
|
||||
"--scopes",
|
||||
TOKEN_SCOPES,
|
||||
scopes,
|
||||
])
|
||||
.await?;
|
||||
let token = extract_token(&stdout)
|
||||
|
|
@ -299,7 +312,7 @@ pub async fn ensure_user_for(name: &str) -> Result<()> {
|
|||
}
|
||||
ensure_user_exists(name, false).await?;
|
||||
ensure_user_email(name).await;
|
||||
mint_and_persist_token(name, &token_path(name)).await
|
||||
mint_and_persist_token(name, &token_path(name), TOKEN_SCOPES).await
|
||||
}
|
||||
|
||||
/// Set `core`'s Forgejo avatar to the hyperhive logo once, then
|
||||
|
|
@ -377,7 +390,7 @@ async fn ensure_core_user_and_token() -> Result<String> {
|
|||
}
|
||||
}
|
||||
ensure_user_exists("core", true).await?;
|
||||
mint_and_persist_token("core", path).await?;
|
||||
mint_and_persist_token("core", path, CORE_TOKEN_SCOPES).await?;
|
||||
let raw = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("read {CORE_TOKEN_PATH} after mint"))?;
|
||||
Ok(raw.trim().to_owned())
|
||||
|
|
|
|||
Loading…
Reference in a new issue