mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
PDS 0.4.0 (@atproto/pds 0.4.0-beta.7) signs the service-auth JWT it
attaches to proxied app.bsky.* calls with iss, aud and exp only
(createServiceJwt in dist/index.js of the image). The AppView requires
the lxm claim and rejects every such call with 401
BadJwtLexiconMethod, so social-app shows errorMessageView on Following
and Notifications. 0.4.66 passes the called method as lxm into every
service JWT it signs and sends every proxied call through the
SSRF-guarded proxy agent.
0.4.66 also replaces the whole-handle limit of 0.4.0 (30 characters
for the entire handle) with a limit of 18 on the part in front of the
service domain, so kc-administrator.<domain> passes for any domain
length, including kc-administrator.infinito.nexus (31).
- meta/services.yml: pin ghcr.io/bluesky-social/pds to 0.4.66.
- vars/main.yml: the public AppView URL is always https. Onion-primary
deployments took the protocol from the local TLS setting and sent the
service JWT to api.bsky.app over plain http. services.view.enabled is
evaluated as a bool.
- templates/env.j2: drop PDS_ADMIN_EMAIL, which neither 0.4.0 nor
0.4.66 reads. PDS_CONTACT_EMAIL_ADDRESS stays unset on purpose:
describeServer would publish the administrator's address.
- Administration.md: the account database only migrates forward; a
rollback restores the bluesky_pds_data backup together with the old
pin.
- Playwright: the broker login moves into _shared.js and waits for a
landing outside /oauth2/, because the bare base URL also matches the
intermediate /oauth2/callback hop. New scenarios check that the PDS
proxies getTimeline and listNotifications to the AppView with a JWT
it accepts, for the broker session (OIDC) and for a native session
(oauth2 disabled), and that social-app renders Following and
Notifications without errorMessageView or lxm page errors. The
rendering scenario is clearnet only: social-app boots only after
loading its age-assurance config from public.api.bsky.app.
Merge note for feature/store-i18n: 19b491b014 raises the pin to 0.4.21
and renames the contact-mail line to PDS_CONTACT_EMAIL_ADDRESS. Resolve
the pin to 0.4.66 (0.4.21 still signs without lxm, and the account
database cannot migrate back) and keep the line deleted. Take the union
of both sides in _shared.js and playwright.spec.js.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
76 lines
2.6 KiB
JavaScript
76 lines
2.6 KiB
JavaScript
const { expect } = require("@playwright/test");
|
|
const { skipUnlessServiceEnabled } = require("./service-gating");
|
|
const { resolveTimeout } = require("./timeouts");
|
|
const {
|
|
decodeDotenvQuotedValue,
|
|
gotoOnion,
|
|
normalizeBaseUrl,
|
|
performKeycloakLoginForm,
|
|
runAdminFlow,
|
|
runBiberFlow,
|
|
runGuestFlow,
|
|
} = require("./personas");
|
|
|
|
const baseUrl = normalizeBaseUrl(process.env.BLUESKY_BASE_URL || "");
|
|
const oidcIssuerUrl = normalizeBaseUrl(process.env.OIDC_ISSUER_URL || "");
|
|
const canonicalDomain = decodeDotenvQuotedValue(process.env.CANONICAL_DOMAIN || "");
|
|
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME);
|
|
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD);
|
|
const adminHandle = decodeDotenvQuotedValue(process.env.ADMIN_HANDLE || "");
|
|
const pdsBaseUrl = decodeDotenvQuotedValue(process.env.PDS_BASE_URL || "");
|
|
|
|
async function beforeEach({ page }) {
|
|
expect(baseUrl, "BLUESKY_BASE_URL must be set").toBeTruthy();
|
|
expect(canonicalDomain, "CANONICAL_DOMAIN must be set").toBeTruthy();
|
|
await page.context().clearCookies();
|
|
}
|
|
|
|
async function loginThroughBroker(page) {
|
|
expect(adminUsername, "ADMIN_USERNAME must be set when OIDC is enabled").toBeTruthy();
|
|
expect(adminPassword, "ADMIN_PASSWORD must be set when OIDC is enabled").toBeTruthy();
|
|
expect(oidcIssuerUrl, "OIDC_ISSUER_URL must be set when OIDC is enabled").toBeTruthy();
|
|
|
|
const expectedOidcAuthUrl = `${oidcIssuerUrl}/protocol/openid-connect/auth`;
|
|
const expectedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
|
|
await gotoOnion(page, `${expectedBaseUrl}/`);
|
|
|
|
await expect
|
|
.poll(() => page.url(), {
|
|
timeout: resolveTimeout(60_000),
|
|
message: `expected redirect to Keycloak OIDC auth (${expectedOidcAuthUrl})`,
|
|
})
|
|
.toContain(expectedOidcAuthUrl);
|
|
|
|
await performKeycloakLoginForm(page, adminUsername, adminPassword);
|
|
|
|
await expect
|
|
.poll(() => page.url(), {
|
|
timeout: resolveTimeout(90_000),
|
|
message: `expected post-OIDC URL to land on Bluesky outside /oauth2/* (got: ${page.url()})`,
|
|
})
|
|
.toMatch(new RegExp(`^${expectedBaseUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/(?!oauth2/)`));
|
|
|
|
await page.waitForLoadState("networkidle", { timeout: resolveTimeout(30_000) }).catch(() => {});
|
|
await expect(page.locator("body")).toBeVisible({ timeout: resolveTimeout(60_000) });
|
|
}
|
|
|
|
module.exports = {
|
|
env: {
|
|
baseUrl,
|
|
oidcIssuerUrl,
|
|
canonicalDomain,
|
|
adminUsername,
|
|
adminPassword,
|
|
adminHandle,
|
|
pdsBaseUrl,
|
|
},
|
|
skipUnlessServiceEnabled,
|
|
loginThroughBroker,
|
|
performKeycloakLoginForm,
|
|
runAdminFlow,
|
|
runBiberFlow,
|
|
runGuestFlow,
|
|
beforeEach,
|
|
};
|