Skip to content

Added testing for tracing #1068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open

Added testing for tracing #1068

wants to merge 29 commits into from

Conversation

allouis
Copy link
Collaborator

@allouis allouis commented Jul 17, 2025

No description provided.

Copy link

coderabbitai bot commented Jul 17, 2025

Walkthrough

A new asynchronous GET endpoint at /.ghost/activitypub/trace-testing was introduced in the Hono app. This endpoint extracts OpenTelemetry trace context from incoming traceparent and tracestate headers to continue or start a trace, enriches the logging context with Google Cloud trace metadata if available, and creates nested spans named "first" and "second." Within these spans, it logs trace and span IDs, captures a test error exception in Sentry, and records the exception on the active span. The endpoint returns a JSON response with trace and span IDs and the original traceparent header, handling errors with a 400 response.

The test script in package.json was simplified to a no-op command that echoes "skip tests," disabling the previous multi-step test execution. Several OpenTelemetry and Sentry dependencies were upgraded to newer major versions, and new packages @opentelemetry/sdk-node, @opentelemetry/auto-instrumentations-node, and @sentry/opentelemetry were added.

The OpenTelemetry and Sentry instrumentation setup in src/instrumentation.ts was refactored. Sentry initialization now disables automatic OpenTelemetry setup and HTTP span creation. The OpenTelemetry NodeSDK was introduced to configure trace exporters and span processors, with conditional setup for Google Cloud Trace and OTLP exporters. The global propagator setting to Sentry's propagator was commented out. Diagnostic logging was adjusted to use the otelApi namespace explicitly.

The CI/CD workflow .github/workflows/cicd.yml was modified to remove all steps related to building, testing, and pushing the "Migrations" Docker image for both private and public registries, while leaving other workflow steps unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 237f225 and ba38c18.

📒 Files selected for processing (1)
  • src/app.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build, Test and Push
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch negative-post-count-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bb0b99 and f9ca72c.

📒 Files selected for processing (2)
  • package.json (1 hunks)
  • src/app.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app.ts
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: allouis
PR: TryGhost/ActivityPub#593
File: src/http/api/reply.ts:48-59
Timestamp: 2025-04-30T11:39:20.993Z
Learning: In the TryGhost/ActivityPub repository, when working with URL IDs in API handlers, the codebase uses a pattern where the raw ID parameter is passed to `lookupObject` even when a decoded version has been created with `decodeURIComponent`. This pattern is consistent with existing functionality in `handlers.ts`.
Learnt from: allouis
PR: TryGhost/ActivityPub#1021
File: src/post/post.entity.ts:327-329
Timestamp: 2025-07-10T08:39:14.900Z
Learning: In the TryGhost/ActivityPub repository, when parsing data from Ghost CMS (such as post excerpts) using branded types with validation (like PostSummary.parse()), allouis prefers to let the parsing throw errors if Ghost sends incompatible data rather than adding defensive handling like truncation. This approach helps detect incompatibilities between the ActivityPub system and Ghost CMS early, ensuring issues are addressed at the source rather than silently ignored.
Learnt from: vershwal
PR: TryGhost/ActivityPub#1033
File: src/http/api/webhook.controller.ts:103-107
Timestamp: 2025-07-14T11:41:50.880Z
Learning: In src/http/api/webhook.controller.ts, the handlePostUnpublished, handlePostUpdated, and handlePostDeleted methods in PR #1033 are intentionally implemented as dummy APIs that return 200 status with null body. These are placeholder implementations to prevent URL errors while the actual backend logic will be built in upcoming PRs, following the incremental development approach used in this codebase.
Learnt from: mike182uk
PR: TryGhost/ActivityPub#1043
File: src/account/account.service.ts:759-794
Timestamp: 2025-07-15T13:07:04.697Z
Learning: In the TryGhost/ActivityPub repository, the exponential backoff for delivery failures in src/account/account.service.ts is intentionally designed without a maximum cap. This unbounded growth is by design - longer delivery failure periods give more confidence that an account is truly broken rather than temporarily unavailable, while still giving receivers a fair chance to recover from temporary issues.
Learnt from: mike182uk
PR: TryGhost/ActivityPub#1043
File: src/account/account.service.ts:54-55
Timestamp: 2025-07-15T13:05:42.512Z
Learning: In the TryGhost/ActivityPub repository, mike182uk designed the delivery failure backoff mechanism in src/account/account.service.ts to intentionally use unbounded exponential backoff without a maximum cap. This design serves as a confidence mechanism where the longer delivery attempts fail, the more confident the system becomes that the account is truly broken rather than experiencing temporary issues. The backoff gives receivers a "fair chance" of receiving future activities if they're having temporary issues that later get resolved.
Learnt from: allouis
PR: TryGhost/ActivityPub#858
File: features/support/content.js:15-22
Timestamp: 2025-06-16T15:43:23.967Z
Learning: allouis prefers to keep refactoring PRs focused on code restructuring only, without adding new functionality or changing behavior. Functional improvements like error handling should be suggested for separate PRs.

@@ -19,7 +19,7 @@
"migration": "docker compose run migrate create",
"migrate": "docker compose up migrate",
"test:cucumber": "./dev/docker/cucumber-tests",
"test": "docker compose run --rm migrate-testing up && docker compose run --rm -v \"$(pwd)/dist:/opt/activitypub/dist\" activitypub-testing yarn _test:all && yarn test:cucumber",
"test": "echo 'skip tests'",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Disabling the test script silently removes a key safety net

"test": "echo 'skip tests'" prevents any unit/integration/type tests from running locally or in CI, masking regressions and security issues.
If the intent is only to speed up development, prefer pointing test at the existing aggregated script (test:all) or gating the skip behind an env-flag so CI still exercises the suite.

-    "test": "echo 'skip tests'",
+    "test": "yarn test:all",

If you truly need to skip tests in some contexts, add a dedicated "test:skip" script and leave the canonical test hook intact.


To verify whether there’s an existing test:all (or similar) script to point the canonical test at, let’s inspect the scripts section:


🏁 Script executed:

#!/bin/bash
# List all scripts defined in package.json
echo "⮕ Scripts in package.json:"
jq '.scripts' package.json || true

# Check explicitly for test:all
echo
echo "⮕ Looking for a test:all script:"
rg -n '"test:all"' package.json || echo "No test:all script found"

Length of output: 2365


Restore the canonical test script to run the full suite

The repo already defines a test:all script that runs types and code checks inside Docker. Overriding test to echo 'skip tests' silences all tests and risks undetected regressions. Update test to point at test:all, and if you need skips, introduce a separate test:skip hook.

• File: package.json (around line 22)
• Replace the existing "test" line with:

-    "test": "echo 'skip tests'",
+    "test": "yarn test:all",

• (Optional) Add a dedicated skip script:

+    "test:skip": "echo 'skip tests'",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"test": "echo 'skip tests'",
"test": "yarn test:all",
"test:skip": "echo 'skip tests'",
🤖 Prompt for AI Agents
In package.json around line 22, the current "test" script is set to "echo 'skip
tests'", which disables all tests and risks missing regressions. Change the
"test" script to run the full test suite by setting it to "npm run test:all".
Optionally, add a new script "test:skip" with the value "echo 'skip tests'" if
you want a dedicated command to skip tests without affecting the main test
script.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/instrumentation.ts (2)

117-125: Consider refactoring duplicate Google Cloud Trace exporter setup.

The Google Cloud Trace exporter setup is duplicated between Sentry (lines 84-91) and OpenTelemetry configurations. Consider extracting the exporter creation into a shared function to improve maintainability.

+async function createGoogleCloudTraceExporter() {
+    const { TraceExporter } = await import(
+        '@google-cloud/opentelemetry-cloud-trace-exporter'
+    );
+    return new TraceExporter({});
+}

 // In Sentry setup (line 88-90)
-            const { TraceExporter } = await import(
-                '@google-cloud/opentelemetry-cloud-trace-exporter'
-            );
             sentryClient?.traceProvider?.addSpanProcessor(
-                new BatchSpanProcessor(new TraceExporter({})),
+                new BatchSpanProcessor(await createGoogleCloudTraceExporter()),
             );

 // In OpenTelemetry setup (line 119-124)
-        const { TraceExporter } = await import(
-            '@google-cloud/opentelemetry-cloud-trace-exporter'
-        );
         provider.addSpanProcessor(
-            new BatchSpanProcessor(new TraceExporter({})),
+            new BatchSpanProcessor(await createGoogleCloudTraceExporter()),
         );

127-139: Consider refactoring duplicate OTLP exporter setup.

Similar to the Google Cloud Trace exporter, the OTLP exporter setup is duplicated between Sentry (lines 93-104) and OpenTelemetry configurations.

+async function createOTLPTraceExporter() {
+    const { OTLPTraceExporter } = await import(
+        '@opentelemetry/exporter-trace-otlp-proto'
+    );
+    return new OTLPTraceExporter({
+        url: 'http://jaeger:4318/v1/traces',
+    });
+}

 // In Sentry setup (line 94-103)
-            const { OTLPTraceExporter } = await import(
-                '@opentelemetry/exporter-trace-otlp-proto'
-            );
             sentryClient?.traceProvider?.addSpanProcessor(
                 new SimpleSpanProcessor(
-                    new OTLPTraceExporter({
-                        url: 'http://jaeger:4318/v1/traces',
-                    }),
+                    await createOTLPTraceExporter(),
                 ),
             );

 // In OpenTelemetry setup (line 129-138)
-        const { OTLPTraceExporter } = await import(
-            '@opentelemetry/exporter-trace-otlp-proto'
-        );
         provider.addSpanProcessor(
             new SimpleSpanProcessor(
-                new OTLPTraceExporter({
-                    url: 'http://jaeger:4318/v1/traces',
-                }),
+                await createOTLPTraceExporter(),
             ),
         );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02c5910 and 710a662.

📒 Files selected for processing (2)
  • src/app.ts (2 hunks)
  • src/instrumentation.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app.ts
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: allouis
PR: TryGhost/ActivityPub#593
File: src/http/api/reply.ts:48-59
Timestamp: 2025-04-30T11:39:20.993Z
Learning: In the TryGhost/ActivityPub repository, when working with URL IDs in API handlers, the codebase uses a pattern where the raw ID parameter is passed to `lookupObject` even when a decoded version has been created with `decodeURIComponent`. This pattern is consistent with existing functionality in `handlers.ts`.
Learnt from: mike182uk
PR: TryGhost/ActivityPub#1043
File: src/account/account.service.ts:759-794
Timestamp: 2025-07-15T13:07:04.697Z
Learning: In the TryGhost/ActivityPub repository, the exponential backoff for delivery failures in src/account/account.service.ts is intentionally designed without a maximum cap. This unbounded growth is by design - longer delivery failure periods give more confidence that an account is truly broken rather than temporarily unavailable, while still giving receivers a fair chance to recover from temporary issues.
Learnt from: allouis
PR: TryGhost/ActivityPub#1021
File: src/post/post.entity.ts:327-329
Timestamp: 2025-07-10T08:39:14.900Z
Learning: In the TryGhost/ActivityPub repository, when parsing data from Ghost CMS (such as post excerpts) using branded types with validation (like PostSummary.parse()), allouis prefers to let the parsing throw errors if Ghost sends incompatible data rather than adding defensive handling like truncation. This approach helps detect incompatibilities between the ActivityPub system and Ghost CMS early, ensuring issues are addressed at the source rather than silently ignored.
Learnt from: mike182uk
PR: TryGhost/ActivityPub#1043
File: src/account/account.service.ts:54-55
Timestamp: 2025-07-15T13:05:42.512Z
Learning: In the TryGhost/ActivityPub repository, mike182uk designed the delivery failure backoff mechanism in src/account/account.service.ts to intentionally use unbounded exponential backoff without a maximum cap. This design serves as a confidence mechanism where the longer delivery attempts fail, the more confident the system becomes that the account is truly broken rather than experiencing temporary issues. The backoff gives receivers a "fair chance" of receiving future activities if they're having temporary issues that later get resolved.
Learnt from: vershwal
PR: TryGhost/ActivityPub#1033
File: src/http/api/webhook.controller.ts:103-107
Timestamp: 2025-07-14T11:41:50.880Z
Learning: In src/http/api/webhook.controller.ts, the handlePostUnpublished, handlePostUpdated, and handlePostDeleted methods in PR #1033 are intentionally implemented as dummy APIs that return 200 status with null body. These are placeholder implementations to prevent URL errors while the actual backend logic will be built in upcoming PRs, following the incremental development approach used in this codebase.
Learnt from: allouis
PR: TryGhost/ActivityPub#858
File: features/support/content.js:15-22
Timestamp: 2025-06-16T15:43:23.967Z
Learning: allouis prefers to keep refactoring PRs focused on code restructuring only, without adding new functionality or changing behavior. Functional improvements like error handling should be suggested for separate PRs.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build, Test and Push
🔇 Additional comments (2)
src/instrumentation.ts (2)

2-14: LGTM! Comprehensive OpenTelemetry imports.

The import statements correctly include all necessary OpenTelemetry modules for tracing setup, and the switch to sdk-trace-node is appropriate for Node.js applications.


33-40: Missing global provider registration for OpenTelemetry.

The NodeTracerProvider is created and configured but never registered globally. Without calling provider.register() after all span processors are added, the OpenTelemetry instrumentation won't work as expected.

Add this after all span processors are configured (after line 139):

+    // Register the provider globally
+    provider.register();

Likely an incorrect or invalid review comment.

export function otelSpanWrapper<TArgs extends unknown[], TReturn>(
fn: (...args: TArgs) => TReturn,
) {
const tracer = trace.getTracer('activitypub', '1.0.0');
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use consistent service version for tracer.

The tracer is using a hardcoded version '1.0.0' while the Resource configuration uses process.env.K_REVISION || '1.0.0'. Consider using the same version for consistency.

-    const tracer = trace.getTracer('activitypub', '1.0.0');
+    const tracer = trace.getTracer('activitypub', process.env.K_REVISION || '1.0.0');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const tracer = trace.getTracer('activitypub', '1.0.0');
const tracer = trace.getTracer('activitypub', process.env.K_REVISION || '1.0.0');
🤖 Prompt for AI Agents
In src/instrumentation.ts at line 159, the tracer version is hardcoded as
'1.0.0' which is inconsistent with the Resource configuration that uses
process.env.K_REVISION || '1.0.0'. Update the tracer initialization to use the
same version value by replacing the hardcoded string with process.env.K_REVISION
|| '1.0.0' to maintain consistency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apdevstaging.ghost.is do-not-merge Not intended for merge, e.g. testing on staging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant