Skip to content

Conversation

@apocaliss92
Copy link

@apocaliss92 apocaliss92 commented Dec 19, 2025

This PR adds support to a new notification platform under development

https://notifier-docs.zentik.app/

Summary by CodeRabbit

  • New Features
    • Added Zentik notification integration to send alerts with configurable server endpoint, authentication token, bucket ID, delivery priority mapping, title, subtitle, message, and targeted recipients. Supports optional insecure TLS, multi-recipient expansion, basic input validation, error logging, and HTTP response handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

Walkthrough

Adds a new Unraid Dynamix agent manifest (ZentikNotifier.xml) that defines configuration variables and embeds a Bash script to validate curl/jq, normalize inputs, map Unraid IMPORTANCE to Zentik DELIVERY_TYPE, assemble a JSON payload (optionally userIds), and POST it to a Zentik endpoint with Bearer auth and optional insecure TLS.

Changes

Cohort / File(s) Summary
New Zentik Agent Manifest
emhttp/plugins/dynamix/agents/ZentikNotifier.xml
New agent manifest defining variables (SERVER_URL, ALLOW_INSECURE, BUCKET_ID, ACCESS_TOKEN, USER_IDS, TITLE, SUBTITLE, MESSAGE) and embedding a Bash script that: checks for curl and jq; initializes and normalizes inputs (expands multi-select); maps Unraid IMPORTANCE → Zentik DELIVERY_TYPE; builds JSON payload (optional userIds as null when empty); constructs ENDPOINT as SERVER_URL/message; supports --insecure; and performs an HTTP POST with Bearer token, returning non-zero on failures and logging basic errors.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify dependency presence checks for curl and jq
  • Confirm IMPORTANCEDELIVERY_TYPE mapping logic
  • Review jq usage for payload assembly and handling of empty userIds
  • Validate endpoint construction, Authorization header, and --insecure handling
  • Check error handling and exit codes for missing/invalid inputs and non-2xx responses

Poem

🐰 I hopped a script from den to tray,
Server URL and token tucked away,
With curl and jq I stitch the note,
Payload sent on a tiny trot,
Zentik pings — hop! — and away I sway ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'New notification agent: Zentik notifier agent' directly and clearly describes the main change: adding a new notification agent for Zentik.
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
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 910580b and 53c32a6.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml

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 and usage tips.

Copy link
Contributor

@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: 2

🧹 Nitpick comments (2)
emhttp/plugins/dynamix/agents/ZentikNotifier.xml (2)

31-32: Consider expanding logging for better observability.

The LOG variable is defined but only used for error messages (lines 74, 78, 102). For better troubleshooting, consider logging successful operations or key steps (e.g., "Sending notification to $ENDPOINT", "Notification sent successfully").


49-52: Optional: Simplify whitespace normalization.

The sed pipeline for TITLE and SUBTITLE works correctly but could be slightly more concise:

TITLE=$(echo -e "$TITLE" | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $//')
SUBTITLE=$(echo -e "$SUBTITLE" | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $//')

Or using xargs which naturally trims and normalizes whitespace:

TITLE=$(echo -e "$TITLE" | xargs)
SUBTITLE=$(echo -e "$SUBTITLE" | xargs)
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 987fa42 and 2f98210.

⛔ Files ignored due to path filters (1)
  • emhttp/plugins/dynamix/icons/zentiknotifier.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ljm42
Repo: unraid/webgui PR: 2364
File: emhttp/plugins/dynamix/agents/Discord.xml:63-66
Timestamp: 2025-09-15T16:59:48.473Z
Learning: In Unraid systems, NGINX_DEFAULTURL configuration only produces servername or servername.localTLD formats, never IPv4/IPv6 addresses. The dot-checking logic in Discord notification agent is specifically designed to filter out bare hostnames that Discord API won't accept.
📚 Learning: 2025-09-05T16:33:12.970Z
Learnt from: Squidly271
Repo: unraid/webgui PR: 2353
File: emhttp/plugins/dynamix/DashStats.page:2257-2257
Timestamp: 2025-09-05T16:33:12.970Z
Learning: In the Unraid webGUI Nchan system, publisher scripts (like "update_1") publish to normalized endpoint names (like "update1"). The Nchan header lists the script names to start, while JavaScript subscribes to the published endpoints. For example: Nchan="update_1" starts the script which calls publish_noDupe('update1', data), and JavaScript subscribes to '/sub/update1'. This is the intended design, not a mismatch.

Applied to files:

  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml
🔇 Additional comments (5)
emhttp/plugins/dynamix/agents/ZentikNotifier.xml (5)

1-12: LGTM! Well-structured agent manifest.

The variable declarations follow Unraid agent conventions with appropriate help text, descriptions, and sensible defaults.


27-29: LGTM! Proper dependency validation.

The upfront dependency check for curl and jq prevents runtime failures with a clear error message.


54-65: LGTM! Sensible importance mapping.

The mapping from Unraid importance levels to Zentik delivery types is logical, and the default case provides a safe fallback for unexpected values.


82-88: LGTM! Robust user IDs processing.

The pipeline correctly handles comma-separated user IDs, trims whitespace, filters empty entries, and converts to a JSON array or null if empty.


90-104: LGTM! Proper JSON payload construction with error handling.

Using jq to build the payload ensures proper JSON escaping, and the exit status check catches any construction errors.

ServerUrl building reordered
Copy link
Contributor

@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: 2

🧹 Nitpick comments (2)
emhttp/plugins/dynamix/agents/ZentikNotifier.xml (2)

51-53: Consider edge cases with echo -e interpretation.

The echo -e command interprets escape sequences in TITLE, SUBTITLE, and MESSAGE. While this may be intentional to support formatted input, it could cause unexpected behavior if notification fields contain literal backslashes or escape sequences like \n, \t, etc.

If this interpretation is intentional, consider documenting it. Otherwise, use echo "$VAR" without -e to avoid interpretation.


84-90: Consider documenting the complex USER_IDS parsing pipeline.

The pipeline at line 88 correctly parses comma-separated user IDs into a JSON array, but it's fairly complex. Consider adding a brief comment explaining the transformation steps for future maintainability.

Example documentation
# userIds: optional comma-separated list
USER_IDS_JSON="null"
if [[ -n "$USER_IDS" && "$USER_IDS" != "none" ]]; then
  # Parse comma-separated list into JSON array:
  # 1. Split by comma, 2. Trim whitespace, 3. Drop empties, 4. Quote as JSON strings, 5. Collect into array
  USER_IDS_JSON=$(printf '%s\n' "$USER_IDS" | tr ',' '\n' | sed 's/^ *//; s/ *$//' | awk 'NF' | jq -R . | jq -s .)
  [[ "$USER_IDS_JSON" == "[]" ]] && USER_IDS_JSON="null"
fi
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f98210 and 910580b.

📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-05T16:33:12.970Z
Learnt from: Squidly271
Repo: unraid/webgui PR: 2353
File: emhttp/plugins/dynamix/DashStats.page:2257-2257
Timestamp: 2025-09-05T16:33:12.970Z
Learning: In the Unraid webGUI Nchan system, publisher scripts (like "update_1") publish to normalized endpoint names (like "update1"). The Nchan header lists the script names to start, while JavaScript subscribes to the published endpoints. For example: Nchan="update_1" starts the script which calls publish_noDupe('update1', data), and JavaScript subscribes to '/sub/update1'. This is the intended design, not a mismatch.

Applied to files:

  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml
📚 Learning: 2025-09-15T16:59:48.473Z
Learnt from: ljm42
Repo: unraid/webgui PR: 2364
File: emhttp/plugins/dynamix/agents/Discord.xml:63-66
Timestamp: 2025-09-15T16:59:48.473Z
Learning: In Unraid systems, NGINX_DEFAULTURL configuration only produces servername or servername.localTLD formats, never IPv4/IPv6 addresses. The dot-checking logic in Discord notification agent is specifically designed to filter out bare hostnames that Discord API won't accept.

Applied to files:

  • emhttp/plugins/dynamix/agents/ZentikNotifier.xml
🔇 Additional comments (9)
emhttp/plugins/dynamix/agents/ZentikNotifier.xml (9)

1-13: LGTM: Well-structured manifest with good security defaults.

The XML manifest structure follows Dynamix agent conventions. Security defaults are appropriate with ALLOW_INSECURE="no", and required credentials have no defaults, forcing explicit configuration.


32-48: LGTM: Good initialization with test-friendly defaults.

The script properly initializes logging and provides sensible defaults for standalone testing. The fallback assignments for TITLE/SUBTITLE/MESSAGE handle edge cases gracefully.


56-66: LGTM: Clean importance-to-delivery-type mapping.

The case statement properly maps Unraid importance levels to Zentik delivery types with a sensible default fallback.


71-78: LGTM: Proper validation order.

Required variables are validated before use. This correctly addresses the previous review comment about validation ordering.


80-82: LGTM: Clean endpoint construction.

The endpoint is constructed after validation, correctly stripping trailing slashes before appending the path.


92-106: LGTM: Secure JSON payload construction with proper error handling.

The jq command properly uses --arg and --argjson flags to safely construct the JSON payload, preventing injection issues. Error handling is appropriate.


118-118: Good: Conditional insecure SSL flag.

The -k flag is now properly gated behind the ALLOW_INSECURE configuration variable, addressing the security concern from the previous review. This allows users to opt-in to insecure connections only when necessary.


120-127: Good: HTTP response validation added.

The script now captures the HTTP response and validates the status code is in the 2xx range, properly addressing the previous review comment about response validation.


18-18: Verify the {0} placeholder usage.

The {0} placeholder appears to be a template variable. Ensure this is the correct placeholder format for Dynamix agent scripts and that the notification system properly substitutes common code here.

#!/bin/bash
# Description: Check other Dynamix agents for similar placeholder patterns

# Search for {0} or similar placeholder patterns in other agent XML files
fd -e xml . emhttp/plugins/dynamix/agents/ --exec grep -l '{[0-9]}' {}

Comment on lines 108 to 127
# POST
args=(
-s -X POST
-m 10
-w "\n%{http_code}"
-H "Authorization: Bearer ${ACCESS_TOKEN}"
-H 'Content-Type: application/json'
--data-binary "$PAYLOAD"
"$ENDPOINT"
)
[[ "${ALLOW_INSECURE}" == "yes" ]] && args+=( -k )

RESPONSE=$(curl "${args[@]}" 2>&1)
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)

# Check if HTTP status indicates success (2xx)
if [[ ! "$HTTP_CODE" =~ ^2[0-9]{2}$ ]]; then
echo "HTTP request failed with status $HTTP_CODE" >>"$LOG"
exit 1
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add curl exit code validation before parsing HTTP response.

The script captures the curl response but doesn't check curl's exit code. If curl fails due to network errors, DNS resolution failure, or timeout, the script won't properly detect it before attempting to parse the HTTP status code.

🔎 Proposed fix
 [[ "${ALLOW_INSECURE}" == "yes" ]] && args+=( -k )
 
 RESPONSE=$(curl "${args[@]}" 2>&1)
+CURL_EXIT=$?
+
+if [[ $CURL_EXIT -ne 0 ]]; then
+  echo "curl failed with exit code $CURL_EXIT" >>"$LOG"
+  exit 1
+fi
+
 HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
 
 # Check if HTTP status indicates success (2xx)
🤖 Prompt for AI Agents
In emhttp/plugins/dynamix/agents/ZentikNotifier.xml around lines 108 to 127, the
script runs curl and immediately parses the last line as HTTP status without
checking curl's exit code; capture curl's exit status (e.g., CURL_EXIT=$?)
immediately after the curl invocation and, if non-zero, write an error to the
log including the curl exit code and the raw curl output, then exit before
attempting to parse HTTP_CODE; only proceed to extract and validate HTTP_CODE
when curl succeeded.

Curl exit checked first
@github-actions
Copy link

🔧 PR Test Plugin Available

A test plugin has been generated for this PR that includes the modified files.

Version: 2025.12.22.1810
Build: View Workflow Run

📥 Installation Instructions:

Install via Unraid Web UI:

  1. Go to Plugins → Install Plugin
  2. Copy and paste this URL:
https://preview.dl.unraid.net/pr-plugins/pr-2490/webgui-pr-2490.plg
  1. Click Install

Alternative: Direct Download

⚠️ Important Notes:

  • Testing only: This plugin is for testing PR changes
  • Backup included: Original files are automatically backed up
  • Easy removal: Files are restored when plugin is removed
  • Conflicts: Remove this plugin before installing production updates

📝 Modified Files:

Click to expand file list
emhttp/plugins/dynamix/agents/ZentikNotifier.xml
emhttp/plugins/dynamix/icons/zentiknotifier.png

🔄 To Remove:

Navigate to Plugins → Installed Plugins and remove webgui-pr-2490, or run:

plugin remove webgui-pr-2490

🤖 This comment is automatically generated and will be updated with each new push to this PR.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant