Skip to content

add channel connectivity and command - #562

Merged
AbdulmalikAlayande merged 1 commit into
TegoLabs:mainfrom
codefather2026:main
Jul 31, 2026
Merged

AbdulmalikAlayande merged 1 commit into
TegoLabs:mainfrom
codefather2026:main

Conversation

@codefather2026

Copy link
Copy Markdown

Summary

Closes #320
Closes #317

Adds two new alerts subcommands:

  • sorokeep alerts test-all --contract <id> to send a synthetic connectivity check to every configured alert channel for a contract
  • sorokeep alerts channels to list all registered alert channel plugins, including dynamically registered ones

What Changed

  • added alerts test-all in src/commands/alerts.ts
  • reused the exact synthetic alert event construction already used by alerts test
  • added a pass/fail summary table for test-all
  • made test-all exit non-zero when any channel delivery fails
  • added alerts channels in src/commands/alerts.ts
  • listed each registered channel’s name, targetOption, and signing support

Tests

  • added coverage that alerts test-all sends a test event to every configured channel for a contract
  • added coverage that alerts test-all exits non-zero if any delivery fails
  • added coverage that alerts channels prints all five built-in channels
  • added coverage that dynamically registered plugin channels appear in the alerts channels output

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@codefather2026 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added an alerts channels command to list available alert channels and their configuration details.
    • Added an alerts test-all command to send test alerts across every configured channel and provide an overall delivery summary.
    • Test alerts now use a consistent event format across supported testing workflows.

Walkthrough

The alerts CLI now reuses a shared synthetic event builder, lists registered channel plugins, and tests delivery across all configured channels for a contract with summarized results and failure exit status.

Changes

Alert CLI expansion

Layer / File(s) Summary
Shared test-event flow
src/commands/alerts.ts
A shared helper builds threshold_crossed test events, and alerts test uses it.
Channel listing
src/commands/alerts.ts, tests/commands/alerts.test.ts
alerts channels lists built-in and dynamically registered channels with target and signing metadata.
Multi-channel connectivity testing
src/commands/alerts.ts, tests/commands/alerts.test.ts
alerts test-all delivers test events to every configured channel, prints results, and exits with status 1 when delivery fails.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: abdulmalikalayande

Poem

I’m a rabbit with channels to hop,
Testing each trail till the failures all stop.
Events bloom bright, targets reply,
Plugins join under one clear sky.
Passes are printed; failures say why.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related, but it is too vague to clearly identify the alerts test-all and channels additions. Use a more specific title that mentions the alerts subcommands, such as alerts test-all and alerts channels.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description matches the implemented alerts test-all and alerts channels changes.
Linked Issues check ✅ Passed The changes satisfy both linked issues by adding test-all and channels commands with tests for delivery, listing, and failure handling.
Out of Scope Changes check ✅ Passed The diff appears confined to the alerts command and its tests, with no obvious unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands/alerts.ts`:
- Around line 305-321: Update the channel-test loop around deliverSingleAlert to
start all channel checks concurrently rather than awaiting each one
sequentially, then await the combined results before populating results.
Preserve each result’s channelType, target, and success mapping, and avoid
introducing timeout behavior outside the scope of this change.

In `@tests/commands/alerts.test.ts`:
- Around line 839-854: Update the test containing registerAlertChannel and the
alerts channels output assertions to call _resetRegistryForTesting() during
cleanup after verifying the output, ensuring the dynamically registered
"matrix-listing-test" channel is removed before subsequent tests run.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 01ed2d23-2066-4bca-9bba-7e659bc55e43

📥 Commits

Reviewing files that changed from the base of the PR and between 35d9237 and 8c84e75.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • src/commands/alerts.ts
  • tests/commands/alerts.test.ts
📜 Review details
🔇 Additional comments (6)
src/commands/alerts.ts (4)

202-226: LGTM!


263-263: LGTM!


386-386: LGTM!


22-36: 🎯 Functional Correctness

No change needed.

buildTestEvent only receives rows from alert_configs, which are TTL-based and enforce threshold_ledgers INTEGER NOT NULL; resource alert configs are stored in the separate resource_alert_configs table.

			> Likely an incorrect or invalid review comment.
tests/commands/alerts.test.ts (2)

6-6: LGTM!


765-825: LGTM!

Comment thread src/commands/alerts.ts
Comment on lines +305 to +321
for (const config of configs) {
const testEvent = buildTestEvent(config.contract_id, config.threshold_ledgers);
console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);

const success = await deliverSingleAlert(
config.channel_type,
config.channel_target,
testEvent,
config.webhook_secret,
);

results.push({
channelType: config.channel_type,
target: config.channel_target,
success,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider parallelizing channel tests and guarding against a hanging channel.

Channels are tested one at a time with a blocking await inside the loop. deliverSingleAlert/the underlying channel.send() don't appear to enforce a timeout, so one slow or unresponsive channel delays reporting the status of every subsequent channel — for a contract with several channels this can make test-all hang far longer than necessary, undermining the "quick connectivity check" purpose of the command.

♻️ Suggested parallelization
-            const results: Array<{ channelType: string; target: string; success: boolean; }> = [];
-
-            for (const config of configs) {
-                const testEvent = buildTestEvent(config.contract_id, config.threshold_ledgers);
-                console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);
-
-                const success = await deliverSingleAlert(
-                    config.channel_type,
-                    config.channel_target,
-                    testEvent,
-                    config.webhook_secret,
-                );
-
-                results.push({
-                    channelType: config.channel_type,
-                    target: config.channel_target,
-                    success,
-                });
-            }
+            const results = await Promise.all(configs.map(async (config) => {
+                const testEvent = buildTestEvent(config.contract_id, config.threshold_ledgers);
+                console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);
+
+                const success = await deliverSingleAlert(
+                    config.channel_type,
+                    config.channel_target,
+                    testEvent,
+                    config.webhook_secret,
+                );
+
+                return { channelType: config.channel_type, target: config.channel_target, success };
+            }));

This still doesn't cap the worst-case wall-clock time if a channel truly hangs — pairing it with a per-call timeout would fully close the gap, but that likely needs a change in deliverSingleAlert/channel implementations outside this file.

📝 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
for (const config of configs) {
const testEvent = buildTestEvent(config.contract_id, config.threshold_ledgers);
console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);
const success = await deliverSingleAlert(
config.channel_type,
config.channel_target,
testEvent,
config.webhook_secret,
);
results.push({
channelType: config.channel_type,
target: config.channel_target,
success,
});
}
const results = await Promise.all(configs.map(async (config) => {
const testEvent = buildTestEvent(config.contract_id, config.threshold_ledgers);
console.log(`Sending test alert to ${config.channel_type}:${config.channel_target}...`);
const success = await deliverSingleAlert(
config.channel_type,
config.channel_target,
testEvent,
config.webhook_secret,
);
return { channelType: config.channel_type, target: config.channel_target, success };
}));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/alerts.ts` around lines 305 - 321, Update the channel-test loop
around deliverSingleAlert to start all channel checks concurrently rather than
awaiting each one sequentially, then await the combined results before
populating results. Preserve each result’s channelType, target, and success
mapping, and avoid introducing timeout behavior outside the scope of this
change.

Comment on lines +839 to +854
it("includes dynamically registered plugin channels in the output", () => {
registerAlertChannel({
name: "matrix-listing-test",
channel: { send: vi.fn().mockResolvedValue(undefined) },
targetOption: "url",
missingTargetError: "Error: --url is required when --type is matrix-listing-test.",
supportsSigning: false,
});

parse(["alerts", "channels"]);

const output = consoleLogSpy.mock.calls.flat().join("\n");
expect(output).toContain("matrix-listing-test");
expect(output).toContain("url");
expect(output).toContain("no");
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether the registry exposes any reset/unregister capability for tests.
rg -n 'export function' src/alerts/registry.ts

Repository: AbdulmalikAlayande/sorokeep

Length of output: 442


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== registry.ts =="
sed -n '1,90p' src/alerts/registry.ts

echo
echo "== imports and setup in alerts.test.ts around registry/cleanup =="
rg -n 'registerAlertChannel|_resetRegistryForTesting|afterEach|afterAll|beforeEach|beforeAll|alerts channels|consoleLogSpy' tests/commands/alerts.test.ts

echo
echo "== lines 800-870 =="
sed -n '800,870p' tests/commands/alerts.test.ts

Repository: AbdulmalikAlayande/sorokeep

Length of output: 5577


Reset the alert channel registry after registering the plugin channel.

registerAlertChannel adds "matrix-listing-test" to the module-level registry and alerts channels reads from that same registry, so this expectation can leak into later tests in the same test worker. Use _resetRegistryForTesting() in this test’s cleanup after verifying output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/commands/alerts.test.ts` around lines 839 - 854, Update the test
containing registerAlertChannel and the alerts channels output assertions to
call _resetRegistryForTesting() during cleanup after verifying the output,
ensuring the dynamically registered "matrix-listing-test" channel is removed
before subsequent tests run.

@gitguardian

gitguardian Bot commented Jul 29, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - Generic High Entropy Secret ded54f4 tests/commands/guard-cli-export-import.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@AbdulmalikAlayande
AbdulmalikAlayande merged commit 61ea4ea into TegoLabs:main Jul 31, 2026
3 of 4 checks passed
@AbdulmalikAlayande

Copy link
Copy Markdown
Collaborator

Verified locally (tsc, lint, full test suite 1178/1178, npm audit, build, manual CLI smoke test of both new commands) and merged into main — GitHub auto-marked this PR merged since the branch was fast-forwarded rather than squash-merged (a package-lock.json conflict needed manual resolution first). Clean, well-scoped PR — thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants