Prepare explicit bb-block staging prototype environment

Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
Tom Brow
2026-10-20 15:29:43 -07:00
parent 115ee178dc
commit 91d7d325d4
5 changed files with 74 additions and 2 deletions

View File

@@ -116,3 +116,24 @@ complete sign-in/current-community readiness, scan the hand-authored demo QR wit
Camera, verify no automatic creation, edit/submit, and verify avatar persistence
and a real agent response. Source/widget tests and QR image decoding do not prove
these physical-device steps. No production or conference-release inclusion.
## bb-block staging preparation
The explicit internal staging build target is
`BUZZ_BUILDERLAB_URL=https://test.blockstaging.build`, with
`BUZZ_AUTH_DOMAINS=buzz.test.blockstaging.build,communities.test.blockstaging.build`.
Only the existing `buzz.test.blockstaging.build` relay and community subdomains
map to that account origin. The login origin, push host and arbitrary sibling
hosts are not accepted as community relays. Public staging sessions and
account-scoped identities remain separate; do not transfer tokens across realms.
This configuration is prepared, not physically validated or installed. The
bb-block edge is WARP-only. Historical BYOD access evidence covers the exact
relay and push hosts, not the login origin. Native OAuth eligibility and the
owner's `ENABLE_BEEKEEPER_AGENT_REGISTRY` flag still need verification. Switching
build targets does not bypass network policy or recover an existing identity.
The prototype's owned-community listing also does not replace normal onboarding's
joined-community discovery and identity recovery.
For standalone physical testing, use Xcode's **Profile** configuration. Debug
Flutter builds require a debugger and cannot validate normal Home/Camera launch.

View File

@@ -9,7 +9,10 @@ import '../shared/hosted/hosted_environment.dart';
Future<List<AddCommunityDeepLink>> loadPrototypeOwnedCommunities(
BuilderlabAccountClient account,
) async {
if (HostedEnvironment.origin.host != 'app.builderlabstaging.xyz') {
if (!{
'app.builderlabstaging.xyz',
'test.blockstaging.build',
}.contains(HostedEnvironment.origin.host)) {
throw StateError('Owned-community prototype requires staging.');
}
final response = await account.post('/v1/buzz/communities/list', {});

View File

@@ -171,7 +171,10 @@ class RemoteAgentController extends ChangeNotifier {
Future<void> initialize() => _initialization ??= _initialize();
Future<void> _initialize() async {
if (HostedEnvironment.origin.host != 'app.builderlabstaging.xyz') {
if (!{
'app.builderlabstaging.xyz',
'test.blockstaging.build',
}.contains(HostedEnvironment.origin.host)) {
throw StateError(
'This prototype requires the staging build configuration.',
);

View File

@@ -8,6 +8,7 @@ abstract final class HostedEnvironment {
'communities.buzz.xyz': 'https://app.builderlab.xyz',
'communities.public.builderlabstaging.xyz':
'https://app.builderlabstaging.xyz',
'communities.test.blockstaging.build': 'https://test.blockstaging.build',
};
/// Creation and admission use the same trusted build-specific host mapping.
@@ -57,6 +58,10 @@ abstract final class HostedEnvironment {
return null;
}
final host = relay.host.toLowerCase();
// The existing bb-block staging community predates community subdomains.
if (host == 'buzz.test.blockstaging.build') {
return Uri.parse('https://test.blockstaging.build');
}
for (final entry in _communityAccounts.entries) {
if (host.endsWith('.${entry.key}')) return Uri.parse(entry.value);
}
@@ -75,6 +80,7 @@ abstract final class HostedEnvironment {
if (!{
'https://app.builderlab.xyz',
'https://app.builderlabstaging.xyz',
'https://test.blockstaging.build',
}.contains(configured)) {
throw StateError('Unsupported hosted account environment');
}

View File

@@ -15,7 +15,26 @@ void main() {
),
Uri.parse('https://app.builderlabstaging.xyz'),
);
for (final host in [
'team.communities.test.blockstaging.build',
'buzz.test.blockstaging.build',
]) {
expect(
HostedEnvironment.accountOriginFor(Uri.parse('wss://$host')),
Uri.parse('https://test.blockstaging.build'),
);
}
for (final value in [
'wss://test.blockstaging.build',
'wss://buzz-push.test.blockstaging.build',
'wss://other.test.blockstaging.build',
'wss://buzz.test.blockstaging.build.attacker.test',
'wss://buzz.test.blockstaging.build.',
'wss://buzz.test.blockstaging.build:8443',
'wss://user@buzz.test.blockstaging.build',
'wss://buzz.test.blockstaging.build/path',
'wss://buzz.test.blockstaging.build?account=other',
'wss://communities.test.blockstaging.build',
'wss://team.communities.public.builderlabstaging.xyz.attacker.test',
'wss://communities.public.builderlabstaging.xyz',
'wss://team.communities.public.builderlabstaging.xyz.',
@@ -35,6 +54,26 @@ void main() {
}
});
test('selected build never accepts another account realm', () {
for (final (relay, account) in [
('wss://a.communities.buzz.xyz', 'https://app.builderlab.xyz'),
(
'wss://a.communities.public.builderlabstaging.xyz',
'https://app.builderlabstaging.xyz',
),
(
'wss://a.communities.test.blockstaging.build',
'https://test.blockstaging.build',
),
('wss://buzz.test.blockstaging.build', 'https://test.blockstaging.build'),
]) {
expect(
HostedEnvironment.supportsRelay(Uri.parse(relay)),
HostedEnvironment.origin == Uri.parse(account),
);
}
});
test('authentication follows only configured DNS domain boundaries', () {
expect(HostedEnvironment.enabled, HostedEnvironment.authDomains.isNotEmpty);
for (final domain in HostedEnvironment.authDomains) {