mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 08:02:40 +00:00
test: a guest JWT is capped by the instance allowance; pin ee-repo-ref
The guest policy moved (parent merge): guests are free up to the instance allowance, then metered on Enterprise and hard-capped elsewhere. The JWT arm now calls guest_admission inside the transaction that records guest_activity (the advisory lock spans the count check and the row), and the door re-reads guest_session_stands (switch, instance switch, no account) for every guest request, so the JWT arm needs nothing extra for those. The plan gate on the key config is gone (guests are free on any plan). Adds an allowance test: with the window full on a capped instance, a stranger's JWT is refused (401) and a returning guest's is admitted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF3v6LA9399gNphmZaHYG3
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
60ae85419c
commit
2907a531b2
@@ -1 +1 @@
|
||||
a7dbde8c0df6da63dfa389c14c08bf4fd3169d5e
|
||||
b01177583aa21be2086b124025313967c6357879
|
||||
@@ -145,3 +145,101 @@ async fn the_allowance_caps_strangers_and_meters_an_enterprise_plan(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- The same allowance, reached through a guest JWT (`jwt_guest_`) ---
|
||||
|
||||
const JWT_PUB: &str = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzAfqyCh34iYOCW0vg4ejq/zzJlzL\nSZScjnVyPjLGTapEwo4gc6/y1Yudd/v54wKh0OdfTfzAKMPWx/2NWx/ugg==\n-----END PUBLIC KEY-----\n";
|
||||
const JWT_PRIV: &str = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgu27S2DbSwUh8BmQb\n/i4/VhNdoXV7PJekhnoceMULYLihRANCAATMB+rIKHfiJg4JbS+Dh6Or/PMmXMtJ\nlJyOdXI+MsZNqkTCjiBzr/LVi513+/njAqHQ519N/MAow9bH/Y1bH+6C\n-----END PRIVATE KEY-----\n";
|
||||
|
||||
fn guest_jwt(email: &str) -> String {
|
||||
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
|
||||
let exp = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
+ 3600;
|
||||
let claims = json!({
|
||||
"email": email,
|
||||
"workspace_id": "test-workspace",
|
||||
"app_path": APP_PATH,
|
||||
"exp": exp,
|
||||
});
|
||||
let jwt = encode(
|
||||
&Header::new(Algorithm::ES256),
|
||||
&claims,
|
||||
&EncodingKey::from_ec_pem(JWT_PRIV.as_bytes()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
format!("jwt_guest_{jwt}")
|
||||
}
|
||||
|
||||
/// A JWT guest is subject to the same allowance as a signed-in one. Past the cap on a
|
||||
/// capped instance, a stranger's JWT is refused (the auth arm returns 401; the visitor
|
||||
/// message is only logged, since the arm cannot carry it), while a guest already in the
|
||||
/// window is let back in.
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn a_guest_jwt_is_capped_like_a_signed_in_guest(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
let port = server.addr.port();
|
||||
let ws = format!("http://localhost:{port}/api/w/test-workspace");
|
||||
|
||||
authed(
|
||||
client().post(format!("{ws}/workspaces/edit_guest_access")),
|
||||
ADMIN_TOKEN,
|
||||
)
|
||||
.json(&json!({ "guest_access_enabled": true }))
|
||||
.send()
|
||||
.await?;
|
||||
let resp = authed(
|
||||
client().post(format!("{ws}/workspaces/edit_guest_jwt_key")),
|
||||
ADMIN_TOKEN,
|
||||
)
|
||||
.json(&json!({ "public_key": JWT_PUB }))
|
||||
.send()
|
||||
.await?;
|
||||
assert_eq!(resp.status(), 200, "{}", resp.text().await?);
|
||||
let resp = authed(client().post(format!("{ws}/apps/create")), ADMIN_TOKEN)
|
||||
.json(&json!({
|
||||
"path": APP_PATH,
|
||||
"summary": "Guest app",
|
||||
"value": {},
|
||||
"policy": { "execution_mode": "guest", "triggerables_v2": {} }
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
assert_eq!(resp.status(), 201, "{}", resp.text().await?);
|
||||
// The whole allowance, used today (g1..gN).
|
||||
sqlx::query(
|
||||
"INSERT INTO guest_activity (email, workspace_id, day)
|
||||
SELECT 'g' || i || '@example.com', 'test-workspace', CURRENT_DATE
|
||||
FROM generate_series(1, $1) AS i",
|
||||
)
|
||||
.bind(FREE_GUESTS_PER_WINDOW)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
set_plan(true);
|
||||
|
||||
let resp = authed(
|
||||
client().get(format!("{ws}/users/whoami")),
|
||||
&guest_jwt("stranger@example.com"),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
assert_eq!(resp.status(), 401, "a stranger's JWT is refused past the cap");
|
||||
|
||||
let resp = authed(
|
||||
client().get(format!("{ws}/users/whoami")),
|
||||
&guest_jwt("g1@example.com"),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
assert_eq!(
|
||||
resp.status(),
|
||||
200,
|
||||
"a returning guest's JWT is admitted: {}",
|
||||
resp.text().await?
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user