From 8683efadcf5fcb7247c66ae5fe57ae569dd620af Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Sat, 17 Oct 2026 10:52:00 +0300 Subject: [PATCH] fix: cache JSON/XML detection in the cell inspector, check chmod of the TLS key file, log audit write failures --- .../security/ssl_certificate_support.dart | 16 +++++++- lib/core/storage/local_db.dart | 9 +++-- .../grid_cell_popover_inspector.dart | 37 +++++++++++++------ 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/lib/core/security/ssl_certificate_support.dart b/lib/core/security/ssl_certificate_support.dart index ae6e3852..aa4f46d9 100644 --- a/lib/core/security/ssl_certificate_support.dart +++ b/lib/core/security/ssl_certificate_support.dart @@ -174,9 +174,21 @@ Future resolveMongoTlsCertificateKeyFile({ final merged = File('${dir.path}/client.pem'); await merged.writeAsString('$certBytes\n$keyBytes\n', flush: true); if (!Platform.isWindows) { + // `Process.run` does not throw on a non-zero exit, so check it: a key + // file that stayed at the default mode must not be handed out silently. try { - await Process.run('chmod', ['600', merged.path]); - } catch (_) {} + final result = await Process.run('chmod', ['600', merged.path]); + if (result.exitCode != 0) { + throw FileSystemException( + 'Could not restrict permissions of the TLS client key file: ' + '${result.stderr}'.trim(), + merged.path, + ); + } + } catch (_) { + await cleanupMongoTlsTempFile(merged.path); + rethrow; + } } return merged.path; } diff --git a/lib/core/storage/local_db.dart b/lib/core/storage/local_db.dart index ffae4447..109548cf 100644 --- a/lib/core/storage/local_db.dart +++ b/lib/core/storage/local_db.dart @@ -583,8 +583,9 @@ class LocalDb { [kMutationAuditCap], ); } - } catch (_) { - // Best effort. + } catch (e) { + // Best effort, but a missing audit trail should not be invisible. + debugPrint('LocalDb: could not record a mutation audit entry: $e'); } } @@ -624,8 +625,8 @@ class LocalDb { 'SELECT id FROM mcp_activity ORDER BY id DESC LIMIT 1 OFFSET ?)', [kMcpActivityCap], ); - } catch (_) { - // Best effort. + } catch (e) { + debugPrint('LocalDb: could not record MCP activity: $e'); } } diff --git a/lib/features/workspace/grid_cell_popover_inspector.dart b/lib/features/workspace/grid_cell_popover_inspector.dart index 6ff292b9..845f9c68 100644 --- a/lib/features/workspace/grid_cell_popover_inspector.dart +++ b/lib/features/workspace/grid_cell_popover_inspector.dart @@ -169,26 +169,39 @@ class _GridCellInspectorDialogState }); } - bool _isJson() { - final text = _controller.text.trim(); + // build() asks for both on every rebuild. Parsing a large cell each time + // janks, so the answer is kept for the text it was computed for (the + // controller hands out the same String until the text changes). + String? _kindText; + var _kindIsJson = false; + var _kindIsXml = false; + + void _refreshKind() { + final raw = _controller.text; + if (identical(raw, _kindText)) return; + _kindText = raw; + final text = raw.trim(); + _kindIsJson = false; + _kindIsXml = false; if ((text.startsWith('{') && text.endsWith('}')) || (text.startsWith('[') && text.endsWith(']'))) { try { jsonDecode(text); - return true; - } catch (_) { - return false; - } + _kindIsJson = true; + } catch (_) {} + } else if (text.startsWith('<') && text.endsWith('>')) { + _kindIsXml = XmlHtmlFormatter.validate(text) == null; } - return false; + } + + bool _isJson() { + _refreshKind(); + return _kindIsJson; } bool _isXml() { - final text = _controller.text.trim(); - if (text.startsWith('<') && text.endsWith('>')) { - return XmlHtmlFormatter.validate(text) == null; - } - return false; + _refreshKind(); + return _kindIsXml; } bool _isHex() {