fix(doctor): honest module count, temp-path audit warning, connection line
Some checks are pending
Security / Security check (push) Waiting to run

Three doctor-page findings from the usertest panel:

- Module tile no longer counts the hub's built-in 'system'
  pseudo-module — a fresh hub shows 0 modules, matching the
  welcome checklist's definition of an install. Counting is a
  top-level function with unit tests.
- When the audit DB lives in an OS-cleanable temp directory
  (/var/folders, /tmp, Windows Temp), the daemon-files panel
  says so instead of presenting the state as healthy. The
  classifier is a top-level function with unit tests.
- The daemon card states who-talks-to-whom-how in one line:
  endpoint, transport security (TLS / unencrypted-local /
  unencrypted), and whether a bearer token is attached (length
  only) — the auditor's baseline the green dot cannot answer.

Also syncs pubspec.yaml (0.70.0 -> 0.72.0) with kStudioVersion,
which had drifted to 0.71.0 while pubspec stayed behind.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-18 00:56:46 +02:00
parent afa3fa7eae
commit 703d961cec
10 changed files with 303 additions and 3 deletions

View file

@ -0,0 +1,78 @@
// Guards two doctor-page facts the usertest panel caught drifting:
//
// 1. The module count must exclude the hub's built-in `system`
// pseudo-module a fresh hub shows 0 modules, matching the
// welcome checklist's "system.* are built-ins, not installs".
// 2. The volatile-path classifier behind the audit-DB warning:
// an evidence log in an OS-cleanable temp directory must be
// flagged, real operator paths must not.
import 'package:chain_client_sdk/chain_client_sdk.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:chain_studio/data/hub.dart';
import 'package:chain_studio/pages/doctor.dart';
CapabilityEntry _cap(String capability, String moduleName) =>
CapabilityEntry(capability: capability, moduleName: moduleName);
void main() {
group('installedModuleNames', () {
test('a fresh hub (builtins only) counts zero modules', () {
final caps = [_cap('system.approval', 'system')];
expect(installedModuleNames(caps), isEmpty);
});
test('real modules count, builtins stay excluded', () {
final caps = [
_cap('system.approval', 'system'),
_cap('debug.echo', 'echo'),
_cap('text.extract', 'text-extract'),
_cap('text.diff', 'text-diff'),
];
expect(
installedModuleNames(caps),
{'echo', 'text-extract', 'text-diff'},
);
});
test('one module providing two capabilities counts once', () {
final caps = [
_cap('doc.hash', 'doc-tools'),
_cap('doc.validate', 'doc-tools'),
];
expect(installedModuleNames(caps), {'doc-tools'});
});
});
group('isVolatilePath', () {
test('flags OS temp locations on every platform', () {
const volatile = [
'/var/folders/8l/j_3vtbb579z/T/chain_studio_test_x/chain.db',
'/private/var/folders/8l/j_3vtbb579z/T/x/chain.db',
'/tmp/chain-test/.chain/chain.db',
'/private/tmp/chain-test/chain.db',
r'C:\Users\op\AppData\Local\Temp\chain\chain.db',
r'C:\Windows\Temp\chain.db',
];
for (final p in volatile) {
expect(isVolatilePath(p), isTrue, reason: p);
}
});
test('leaves real operator paths alone', () {
const durable = [
'/Users/op/.chain/chain.db',
'/home/op/.chain/chain.db',
r'C:\Users\op\.chain\chain.db',
'/var/lib/chain/chain.db',
// "tmp" as a name fragment is not a temp directory.
'/Users/op/tmpfiles/.chain/chain.db',
'',
];
for (final p in durable) {
expect(isVolatilePath(p), isFalse, reason: p);
}
});
});
}