mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-08 02:53:25 -08:00
[CrashReporting] Log where crash reports go and warn when they cannot
The client resolved COCKATRICE_SENTRY_DSN (environment over the baked-in value) without ever saying which one won, and sentry-native refuses to build a request for a DSN it considers invalid without reporting anything, so a tester pointing the client at a scratch project had nothing to go on when a crash never appeared. Say which DSN source won, and log the destination (host and project id, never the key) once the SDK is armed. Warn instead of staying quiet when no DSN is configured at all, when a DSN is malformed - disabling reporting rather than silently falling back to the project baked into the build, which is the rule the installer already follows in cmake/CrashReporting.cmake - and when the build was compiled without Sentry support. A deliberate Never-send stays at info level: that is a choice, not a misconfiguration. Also warn when a pending crash envelope was captured for a different destination than the session that will upload it. sentry-native posts every envelope with the DSN held in the transport state of the session doing the sending, and envelopes restored from disk are raw, so the "dsn" header of a cached envelope is never read: a crash captured for one project can be uploaded to another with nothing in the log to show it. Tests cover the DSN shape check (same unanchored pattern the build matches, so a DSN this build accepted is never rejected here), destination description without the key, and the mismatch detection, which stays quiet for a different key on the same project, unreadable files, and headers without a dsn.
This commit is contained in:
parent
828e6cc1d0
commit
69b421f1c2
4 changed files with 197 additions and 1 deletions
|
|
@ -75,6 +75,68 @@ TEST(CrashReporterTest, ReportingEnabledGating)
|
|||
ASSERT_FALSE(CrashReporter::isReportingEnabled(dsn, Mode::NeverSend));
|
||||
}
|
||||
|
||||
TEST(CrashReporterTest, IsDsnWellFormedAcceptsWhatTheBuildAcceptsAndRejectsUiLinks)
|
||||
{
|
||||
ASSERT_TRUE(CrashReporter::isDsnWellFormed(QStringLiteral("https://abc123@o0.ingest.sentry.io/1234567")));
|
||||
ASSERT_TRUE(CrashReporter::isDsnWellFormed(QStringLiteral("http://key@localhost:9000/42")));
|
||||
// Unanchored like cmake/CrashReporting.cmake's MATCHES, so a DSN the build baked is never
|
||||
// rejected here: a trailing path still matches.
|
||||
ASSERT_TRUE(CrashReporter::isDsnWellFormed(QStringLiteral("https://key@host.example/7/extra")));
|
||||
// The project-settings URL is the mistake a tester actually makes.
|
||||
ASSERT_FALSE(CrashReporter::isDsnWellFormed(
|
||||
QStringLiteral("https://sentry.io/settings/cockatrice/projects/cockatrice-desktop/keys/")));
|
||||
ASSERT_FALSE(CrashReporter::isDsnWellFormed(QStringLiteral("https://key@host.example/not-a-number")));
|
||||
ASSERT_FALSE(CrashReporter::isDsnWellFormed(QStringLiteral("o0.ingest.sentry.io/1234567")));
|
||||
ASSERT_FALSE(CrashReporter::isDsnWellFormed(QString()));
|
||||
}
|
||||
|
||||
TEST(CrashReporterTest, DescribeDsnNamesHostAndProjectWithoutTheKey)
|
||||
{
|
||||
const QString described =
|
||||
CrashReporter::describeDsn(QStringLiteral("https://supersecretkey@o0.ingest.sentry.io/1234567"));
|
||||
ASSERT_EQ(described, QStringLiteral("o0.ingest.sentry.io (project 1234567)"));
|
||||
ASSERT_FALSE(described.contains(QStringLiteral("supersecretkey")));
|
||||
ASSERT_TRUE(CrashReporter::describeDsn(QStringLiteral("not a dsn")).isEmpty());
|
||||
ASSERT_TRUE(CrashReporter::describeDsn(QString()).isEmpty());
|
||||
}
|
||||
|
||||
TEST(CrashReporterTest, DescribeOriginMismatchReportsOnlyRealDestinationChanges)
|
||||
{
|
||||
const QTemporaryDir dir;
|
||||
ASSERT_TRUE(dir.isValid());
|
||||
const QString envelopePath = dir.filePath(QStringLiteral("crash.envelope"));
|
||||
QFile file(envelopePath);
|
||||
ASSERT_TRUE(file.open(QIODevice::WriteOnly));
|
||||
file.write(QByteArrayLiteral("{\"event_id\":\"x\",\"dsn\":\"https://keyA@hostA.example/111\"}\n"));
|
||||
file.write(QByteArrayLiteral("{\"type\":\"event\",\"length\":2}\n{}\n"));
|
||||
file.close();
|
||||
|
||||
const QString described =
|
||||
CrashReporter::describeOriginMismatch(envelopePath, QStringLiteral("https://keyB@hostB.example/222"));
|
||||
ASSERT_FALSE(described.isEmpty());
|
||||
ASSERT_TRUE(described.contains(QStringLiteral("hostA.example")));
|
||||
ASSERT_TRUE(described.contains(QStringLiteral("hostB.example")));
|
||||
ASSERT_FALSE(described.contains(QStringLiteral("keyA")));
|
||||
ASSERT_FALSE(described.contains(QStringLiteral("keyB")));
|
||||
|
||||
// A different key for the SAME host and project is not a routing change and must stay quiet.
|
||||
ASSERT_TRUE(
|
||||
CrashReporter::describeOriginMismatch(envelopePath, QStringLiteral("https://otherkey@hostA.example/111"))
|
||||
.isEmpty());
|
||||
// An unreadable envelope, a header without a dsn, or no current dsn are all silent.
|
||||
ASSERT_TRUE(CrashReporter::describeOriginMismatch(dir.filePath(QStringLiteral("absent.envelope")),
|
||||
QStringLiteral("https://keyB@hostB.example/222"))
|
||||
.isEmpty());
|
||||
ASSERT_TRUE(CrashReporter::describeOriginMismatch(envelopePath, QString()).isEmpty());
|
||||
const QString headerlessPath = dir.filePath(QStringLiteral("no-dsn.envelope"));
|
||||
QFile headerless(headerlessPath);
|
||||
ASSERT_TRUE(headerless.open(QIODevice::WriteOnly));
|
||||
headerless.write(QByteArrayLiteral("{\"event_id\":\"y\"}\n"));
|
||||
headerless.close();
|
||||
ASSERT_TRUE(CrashReporter::describeOriginMismatch(headerlessPath, QStringLiteral("https://keyB@hostB.example/222"))
|
||||
.isEmpty());
|
||||
}
|
||||
|
||||
TEST(CrashReporterTest, ShutdownWithoutInitIsSafe)
|
||||
{
|
||||
CrashReporter reporter;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue