OXYGENHUB

Tokens page lists every scope the hub checks, each with what it grants b45384c909c1

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-27 22:52 UTC
Signature
✔ signed by Andy McCall
Hash
b45384c909c19ecb69915e69e0395441aaf509e1156dd94d0f38794449ec26b1
Depends on
19bb31ff1f5c 3f4b0ea6eabf d23464c0ac60
Depended on by
00ef7b83b340 101740454617
In bookmarks
api-unknown-fields cancel-landed-runs clear-waiting close-proposal-140 diffusion-pin-bookmark draft-ready image-check job-waits main oh-comment-body-file proposal-list-fast run-one-job wiki-says-so
In tags
v0.1.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.5.0 v0.5.1 v0.5.2 v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
Edits
8 atoms, 0 tree operations, 3 files

Browse the tree at this change

modified crates/hub/src/web/settings.rs +12 −5
…
349 unchanged lines
350 350
#[template(path = "settings_tokens.html")]
351 351
pub struct TokensPage {
352 352
    shell: Shell,
353 +
    scopes: &'static [(&'static str, &'static str)],
353 354
    me: accounts::Account,
354 355
    tokens: Vec<accounts::Token>,
355 356
    /// A freshly created token, shown once.
…
11 unchanged lines
367 368
    error: Option<String>,
368 369
) -> Result<Page<TokensPage>, Error> {
369 370
    let tokens = accounts::tokens_of(&app.db, me.id).await.map_err(|e| Error::from_db(shell.clone(), e))?;
370 -
    Ok(Page(TokensPage { shell, me, tokens, fresh, notice, error }))
371 +
    Ok(Page(TokensPage { shell, scopes: SCOPES, me, tokens, fresh, notice, error }))
371 372
}
372 373
373 374
pub async fn tokens(State(app): State<Shared>, viewer: Viewer) -> Result<Page<TokensPage>, Error> {
…
15 unchanged lines
389 390
    expires_days: String,
390 391
}
391 392
393 +
/// Every scope the hub checks, with what it grants. The tokens page lists
394 +
/// exactly these, so a scope cannot exist without a checkbox.
392 395
pub const SCOPES: &[(&str, &str)] = &[
393 -
    ("repo:read", "read repositories you can see (clone, fetch, pull)"),
394 -
    ("repo:write", "push to repositories you can write to"),
395 -
    ("repo:admin", "change repository settings through the API"),
396 -
    ("user:read", "read your profile through the API"),
396 +
    ("repo:read", "read repositories you can see: clone, fetch, pull, and the read API"),
397 +
    ("repo:write", "push to repositories you can write to; also covers proposals, issues and checks"),
398 +
    ("repo:admin", "create repositories and change settings through the API"),
399 +
    ("proposals:write", "open, comment on and review proposals, without push access"),
400 +
    ("issues:write", "open, comment on and close issues, without push access"),
401 +
    ("checks:write", "report checks on states, for CI systems, without push access"),
402 +
    ("hooks:admin", "manage webhooks through the API"),
403 +
    ("user:read", "read your own profile through the API"),
397 404
];
398 405
399 406
pub async fn tokens_create(
…
38 unchanged lines
modified templates/settings_tokens.html +2 −5
…
26 unchanged lines
27 27
  <h2>New token</h2>
28 28
  <label for="name">Name</label><input type="text" id="name" name="name" required placeholder="laptop, CI, …">
29 29
  <label>Scopes</label>
30 -
  <div class="choice">
31 -
    <label><input type="checkbox" name="scopes" value="repo:read" checked> repo:read</label>
32 -
    <label><input type="checkbox" name="scopes" value="repo:write" checked> repo:write</label>
33 -
    <label><input type="checkbox" name="scopes" value="repo:admin"> repo:admin</label>
34 -
    <label><input type="checkbox" name="scopes" value="user:read"> user:read</label>
30 +
  <div class="scopes">
31 +
    {% for (name, what) in scopes %}<label><input type="checkbox" name="scopes" value="{{ name }}"{% if *name == "repo:read" || *name == "repo:write" %} checked{% endif %}> <code>{{ name }}</code> <span class="small mute">{{ what }}</span></label>{% endfor %}
35 32
  </div>
36 33
  <label for="repos">Only these repositories (comma-separated owner/name; empty for all)</label><input type="text" id="repos" name="repos">
37 34
  <label for="expires_days">Expires after (days; empty for never)</label><input type="number" id="expires_days" name="expires_days" min="1">
…
3 unchanged lines
modified templates/style.css +2 −0
…
300 unchanged lines
301 301
.inline-find { flex: 0 1 220px; }
302 302
.hits .hit { margin: 0; padding: 4px 8px; border-bottom: 1px solid var(--line); background: var(--panel); font-size: 13px; overflow-x: auto; white-space: nowrap; }
303 303
.hits .hit code { background: none; }
304 +
305 +
.scopes label { display: block; text-transform: none; letter-spacing: 0; font-size: 14px; color: var(--ink); margin: 4px 0; }