Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jobs:
api/package-lock.json
worker/package-lock.json

- uses: subosito/flutter-action@v2
with:
channel: 'stable'

- run: ./scripts/lint.sh

build:
Expand Down Expand Up @@ -62,6 +66,10 @@ jobs:
api/package-lock.json
worker/package-lock.json

- uses: subosito/flutter-action@v2
with:
channel: 'stable'

- run: ./scripts/test.sh

release-scripts:
Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
- **Worker Install**: `cd worker && npm install`
- **Worker Dev**: `cd worker && npm run dev`
- **Worker Test**: `cd worker && npm run test:unit`
- **Worker Flutter Lint**: `cd worker_flutter && flutter analyze --no-fatal-infos`
- **Worker Flutter Test**: `cd worker_flutter && flutter test`

## Deployment
- **CI**: `.github/workflows/ci.yml` (Runs on PR)
Expand Down
4 changes: 4 additions & 0 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ cd frontend && npm ci && npm run lint && cd ..
# API
echo "=== API lint ==="
cd api && npm ci && npm run lint && cd ..

# Worker Flutter
echo "=== Worker Flutter lint ==="
cd worker_flutter && flutter analyze --no-fatal-infos && cd ..
4 changes: 4 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ npm run test:ingestion && cd ..
# Worker tests
echo "=== Worker unit tests ==="
cd worker && npm ci && npm run test:unit && cd ..

# Worker Flutter tests
echo "=== Worker Flutter tests ==="
cd worker_flutter && flutter test && cd ..
1 change: 0 additions & 1 deletion worker_flutter/lib/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:io';

import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:worker_flutter/main.dart';

Expand Down
2 changes: 1 addition & 1 deletion worker_flutter/lib/offline/db/app_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class AppDb extends _$AppDb {
/// test suite with `NativeDatabase.memory()` for hermetic, fast
/// integration tests that exercise the same SQL the app does at
/// runtime — but without touching disk.
AppDb.forTesting(QueryExecutor e) : super(e);
AppDb.forTesting(super.e);

@override
int get schemaVersion => 2;
Expand Down
4 changes: 2 additions & 2 deletions worker_flutter/lib/offline/deck_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:path/path.dart' as p;
/// One bundled-precon deck. The `.dck` content lives either in the
/// Flutter asset bundle (preferred — ships inside the app, available
/// instantly on first launch) or, for users with a separately-
/// installed Forge tree, in `<forgePath>/res/Decks/Commander/*.dck`.
/// installed Forge tree, in `[forgePath]/res/Decks/Commander/*.dck`.
class PreconDeck {
PreconDeck({
required this.displayName,
Expand Down Expand Up @@ -38,7 +38,7 @@ class PreconDeck {
}

/// Loads precons from the Flutter asset bundle PLUS any extra .dck
/// files the user may have dropped into `<forgePath>/res/Decks/
/// files the user may have dropped into `[forgePath]/res/Decks/
/// Commander/`. The bundled set is the floor — offline mode works
/// from a fresh install without a Forge download.
Future<List<PreconDeck>> loadBundledPrecons(String forgePath) async {
Expand Down
4 changes: 2 additions & 2 deletions worker_flutter/lib/sims/deck_picker_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ class DeckPickerSection extends StatefulWidget {
}

class _DeckPickerSectionState extends State<DeckPickerSection> {
late final ExpansionTileController _ctrl;
late final ExpansibleController _ctrl;

@override
void initState() {
super.initState();
_ctrl = ExpansionTileController();
_ctrl = ExpansibleController();
}

@override
Expand Down
20 changes: 10 additions & 10 deletions worker_flutter/lib/telemetry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ class Telemetry {
tags.forEach(scope.setTag);
}
if (extra != null) {
// ignore: deprecated_member_use — `setExtra` is the documented
// 8.x API. Sentry's 9.x release moves to structured contexts.
extra.forEach(scope.setExtra);
scope.setContexts('extra', extra);
}
},
);
Expand Down Expand Up @@ -111,19 +109,21 @@ SentryEvent? scrubPii(SentryEvent event, {Hint? hint}) {
? event
: event.copyWith(user: SentryUser(id: '[redacted]'));

// ignore: deprecated_member_use — see comment in Telemetry.captureError.
final extra = cleaned.extra;
if (extra != null) {
for (final key in extra.keys.toList()) {
final contexts = cleaned.contexts;
final extra = contexts['extra'];
if (extra is Map<String, dynamic>) {
final newExtra = Map<String, dynamic>.from(extra);
for (final key in newExtra.keys.toList()) {
if (_piiKeys.contains(key)) {
extra[key] = '[redacted]';
newExtra[key] = '[redacted]';
continue;
}
final value = extra[key];
final value = newExtra[key];
if (value is String && _emailRegex.hasMatch(value)) {
extra[key] = value.replaceAll(_emailRegex, '[redacted-email]');
newExtra[key] = value.replaceAll(_emailRegex, '[redacted-email]');
}
}
contexts['extra'] = newExtra;
}

final breadcrumbs = cleaned.breadcrumbs;
Expand Down
10 changes: 5 additions & 5 deletions worker_flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -692,10 +692,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -1193,10 +1193,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.9"
tray_manager:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1374,5 +1374,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.11.5 <4.0.0"
dart: ">=3.11.0 <4.0.0"
flutter: ">=3.38.4"
2 changes: 1 addition & 1 deletion worker_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ publish_to: 'none'
version: 0.2.0+1

environment:
sdk: ^3.11.5
sdk: ">=3.11.0 <4.0.0"

dependencies:
flutter:
Expand Down
1 change: 0 additions & 1 deletion worker_flutter/test/offline/resume_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';

import 'package:drift/drift.dart' show Value;
Expand Down
22 changes: 12 additions & 10 deletions worker_flutter/test/telemetry_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void main() {
group('scrubPii', () {
test('redacts email-shaped values in event extras', () {
final event = SentryEvent(message: const SentryMessage('hi')).copyWith(
extra: <String, dynamic>{
contexts: Contexts()..['extra'] = <String, dynamic>{
'note': 'user contacted me at someone@example.com about it',
'okField': 'no pii here',
},
Expand All @@ -28,14 +28,15 @@ void main() {
final scrubbed = scrubPii(event);

expect(scrubbed, isNotNull);
expect(scrubbed!.extra!['note'], contains('[redacted-email]'));
expect(scrubbed.extra!['note'], isNot(contains('someone@example.com')));
expect(scrubbed.extra!['okField'], 'no pii here');
final scrubbedExtra = scrubbed!.contexts['extra'] as Map<String, dynamic>;
expect(scrubbedExtra['note'], contains('[redacted-email]'));
expect(scrubbedExtra['note'], isNot(contains('someone@example.com')));
expect(scrubbedExtra['okField'], 'no pii here');
});

test('redacts known PII keys', () {
final event = SentryEvent(message: const SentryMessage('hi')).copyWith(
extra: <String, dynamic>{
contexts: Contexts()..['extra'] = <String, dynamic>{
'email': 'a@b.com',
'uid': 'xyz',
'displayName': 'Tyler',
Expand All @@ -46,11 +47,12 @@ void main() {

final scrubbed = scrubPii(event);

expect(scrubbed!.extra!['email'], '[redacted]');
expect(scrubbed.extra!['uid'], '[redacted]');
expect(scrubbed.extra!['displayName'], '[redacted]');
expect(scrubbed.extra!['user_id'], '[redacted]');
expect(scrubbed.extra!['safe'], 'keep me');
final scrubbedExtra = scrubbed!.contexts['extra'] as Map<String, dynamic>;
expect(scrubbedExtra['email'], '[redacted]');
expect(scrubbedExtra['uid'], '[redacted]');
expect(scrubbedExtra['displayName'], '[redacted]');
expect(scrubbedExtra['user_id'], '[redacted]');
expect(scrubbedExtra['safe'], 'keep me');
});

test('replaces user with redacted placeholder', () {
Expand Down
5 changes: 1 addition & 4 deletions worker_flutter/test/worker/log_uploader_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
Expand Down Expand Up @@ -116,9 +115,7 @@ void main() {
client: client,
);
await expectLater(
uploader
.upload(jobId: 'j', simIndex: 0, logText: 'x')
.timeout(const Duration(seconds: 35)),
uploader.upload(jobId: 'j', simIndex: 0, logText: 'x'),
completes,
);
},
Expand Down
Loading