Skip to content

bedrock aws option - #9

Open
brunobuzzi wants to merge 1 commit into
GemTalk:mainfrom
lifeware-sa:main
Open

brunobuzzi wants to merge 1 commit into
GemTalk:mainfrom
lifeware-sa:main

Conversation

@brunobuzzi

@brunobuzzi brunobuzzi commented Oct 5, 2026 •

Copy link
Copy Markdown

Add an additional pane to configure connection to Claude through AWS Bedrock with SSO

RetriggerConfidence Score: 1/5

The PR does not appear safe to merge until Bedrock signing and the provider-selection and SSO-configuration failures are addressed.

Findings

  1. P1 Encoded model paths are mis-signed ▶
  2. P1 SSO credentials outlive their configuration ▶
  3. P1 Old sign-in overrides provider choice ▶
  4. P1 Default model assumes EU region ▶
  5. P2 Role denial clears valid session ▶
  6. P2 Security SSO secrets stored unencrypted ▶

Summary

The PR adds AWS Bedrock access through an in-app SSO device flow while retaining API-key access.

  • It adds provider selection, persisted AWS settings, credential retrieval, SigV4 signing, and event-stream conversion.
  • It also changes assistant service ownership and adds setup, signing, and stream-framing tests.
  • The review found request-signing, configuration-isolation, setup-race, and regional-default failures, plus credential-storage and error-handling concerns.

Reviews (1) · Last reviewed commit: "bedrock aws option"


final canonicalRequest = [
method,
uri.path,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Encoded model paths are mis-signed

When a Bedrock model ID contains a character such as :, the request URL contains its encoded form (%3A), but uri.path supplies the decoded character to the signer. Bedrock therefore receives a request whose path differs from the signed path and rejects it with a signature error. Sign the encoded path that is sent.

Comment on lines +266 to +271
Future<(String, String)> _registerClient() async {
final stored = await _store.read();
final clientId = stored?['clientId'] as String?;
final clientSecret = stored?['clientSecret'] as String?;
if (clientId != null && clientId.isNotEmpty && clientSecret != null && clientSecret.isNotEmpty) {
return (clientId, clientSecret);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 SSO credentials outlive their configuration

After a user changes the SSO region or start URL, this method can reuse the client registration from the previous configuration for the new device-authorization request, causing sign-in to fail. The stored access token is likewise checked without reference to the current configuration, so reopening the panel can skip sign-in with an unrelated token. Scope or invalidate stored credentials when the Identity Center configuration changes.

Comment on lines +227 to +231
if (!mounted) {
return;
}
setState(() => _pendingAuth = null);
await _startServices(BedrockAiBackend(config: config, session: session));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Old sign-in overrides provider choice

The provider picker remains available while beginLogin() is running, but changing providers does not cancel that sign-in. If the user switches to and saves an API key during this interval, the old sign-in can later install a Bedrock service anyway. This replaces the selected key-backed service without disposing it. Check that the sign-in is still current before starting Bedrock.

/// Bedrock serves Claude under an `anthropic.` provider prefix, and newer
/// models are reachable only through a cross-region inference profile — the
/// leading `eu.` here. Change the prefix if [bedrockRegion] leaves the EU.
static const String defaultModelId = 'eu.anthropic.claude-sonnet-5-5';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Default model assumes EU region

The model field defaults to an EU-prefixed inference-profile ID even when the user selects a non-EU Bedrock region. Accepting the prefilled model sends that EU ID to the selected regional endpoint, where the default configuration cannot serve requests. Choose a region-compatible default or require an explicit model choice.

Comment on lines +215 to +218
if (response.statusCode == 401 || response.statusCode == 403) {
// The access token has been revoked or has aged out server-side.
await _store.clear();
throw const AwsSsoLoginRequired('AWS SSO session expired. Please sign in again.');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Role denial clears valid session

If the configured account or role returns 403 because access is denied, this branch clears the SSO token and reports an expired session. Signing in again will not fix the role configuration, and the user must repeat authorization without seeing the useful role-access error. Distinguish a rejected token from denied access to the requested role.

Comment on lines +40 to +41
Future<void> write(Map<String, dynamic> value) async {
final prefs = await SharedPreferences.getInstance();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security SSO secrets stored unencrypted

The new preference entry contains the SSO bearer token and client secret. If someone can read the app's preference storage, they can obtain a still-valid token and use it to request AWS role credentials. Token expiry limits the exposure window but does not remove it; use platform-protected secret storage instead.

How this was verified: The approval flow stores the token and client secret in unencrypted preferences, and the credentials flow uses the stored token to request role credentials.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant