~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A space a session's grant leaves out is not asked again for an hour

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/space-reader-retry

What changes

When spaces::discover checks the spaces an owner may be a member of, it skips any space their session was refused for want of scope in the last hour (InvalidToken's "Scope does not permit", or ScopeMissingError, as oauth::out_of_scope reads them). That refusal logs space reader out of scope at info. It used to log space reader not checked at warn. docs/design/access.md says so.

Why

Discovery runs every minute while an owner browses. On prod, one account's session was refused an organization's space each time ("Scope does not permit reading at://…/space/dev.knotless.org/self"). That logged a warning a minute, and each try cost a getDelegationToken call to the account's PDS, some taking 2–9s. The grant doesn't change until the account logs in again, so asking every minute can't succeed.

How it was checked

A unit test in spaces.rs shows that a refusal for scope is kept, and that the space isn't asked again until an hour has passed. Other errors and other accounts aren't kept. reader_checks covers the new log line. The rest is left to CI.

Shortcomings

The hour is kept in memory, so a deploy asks once more. Logging in again with a wider grant waits out the rest of the hour before that space is asked.

🤖 Generated with Claude Code

Asked for changes

This keeps a per-account, per-space record of scope refusals in memory. discover skips a refused space for an hour, and the log line for it drops from warn to info. The approach is sound and the docs are updated.

The change as pushed does not compile. The use std::time::{Duration, Instant}; line now appears twice, because the old line was left in place. That is a duplicate import error (E0252). Remove one of them. The check and test runs were still queued when I looked, so the build error has not shown up there yet.

Smaller point: OUT_OF_SCOPE is a process-wide static and is never pruned, so entries stay until restart. At one entry per refused (account, space) pair that is probably fine.

crates/knotless-serve/src/spaces.rsline 42Outdated
use std::collections::{BTreeSet, HashMap, HashSet};
use std::sync::atomic::Ordering;
use std::sync::{Arc, LazyLock, Mutex};
use std::time::{Duration, Instant};
review.knotless.dev

Duplicate of the use std::time::{Duration, Instant}; on line 41, which fails to compile. Drop one.

Approved

The duplicate Duration, Instant import I flagged is gone, so the build error is fixed. The imports now merge cleanly.

The pull remembers each (account, space) scope refusal for an hour and skips that space in discover. The refusal logs at info as space reader out of scope, and docs/design/access.md says so. oauth::out_of_scope exists and is public, and its &impl Display signature accepts the &anyhow::Error both call sites pass. The unit test covers storing a refusal, not storing other errors, not storing other accounts, and expiry. reader_checked covers the new log line.

The check and test runs were still queued when I looked, so I haven't seen them pass. Watch those before merging. I can't see any reason they'd fail.

The in-memory map is never pruned. That is fine at one entry per refused pair. The PR body already states the shortcomings.

Merged as 390a487