Skip to content
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

Lint bash scripts with custom shebangs #3824

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

mislav
Copy link

@mislav mislav commented Nov 13, 2024

Many scripts in this repository have this shebang:

#!/usr/bin/with-contenv bashio

However, this doesn't match the shebang regex in action-shellcheck and therefore those files wouldn't get included in the linting check.

Supersedes #3803 /cc @agners

This is the only mechanism to include additional scripts in the linting process. I'm not a fan of this approach, since new scripts with unique names added to this repository again won't be linted by default, but it's a start to ensure regressions like #3801 are less likely to happen.

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced DNS challenge handling for SSL certificate requests with additional DNS providers.
    • Improved firmware flashing capabilities for various USB devices, including support for new manufacturers.
    • Added logging for service exit codes and enhanced error handling in multiple service scripts.
  • Bug Fixes

    • Corrected variable usage in exit code calculations across various service scripts to improve clarity and functionality.
  • Documentation

    • Added comments and shellcheck directives to improve code quality and maintainability in several scripts.
  • Chores

    • Streamlined various scripts to enhance robustness and error handling mechanisms.

Many scripts in this repository have this shebang:

    #!/usr/bin/with-contenv bashio

However, this doesn't match the shebang regex in action-shellcheck
and therefore those files wouldn't get included in the linting check.
Copy link
Contributor

coderabbitai bot commented Nov 13, 2024

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.
📝 Walkthrough
📝 Walkthrough

Walkthrough

The changes include updates to multiple Bash scripts and a GitHub Actions workflow file. Key modifications involve the addition of an additional_files parameter in the ShellCheck job within .github/workflows/lint.yml, allowing for the linting of scripts with custom shebangs. Various scripts have been adjusted to improve exit code handling, variable usage, and logging practices, particularly in the context of managing service failures within the S6 supervision tree. New functionality has also been introduced in some scripts, such as enhanced DNS challenge handling and configuration for additional services.

Changes

File Change Summary
.github/workflows/lint.yml Added additional_files parameter to ShellCheck job for custom shebang scripts.
assist_microphone/rootfs/etc/s6-overlay/s6-rc.d/assist_microphone/finish Added shellcheck directive to disable warning SC2155; updated variable usage for exit_code_signal.
configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/finish Added shellcheck directive to disable warning SC2155; updated variable usage for exit_code_signal.
duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/finish Updated exit code calculation and logging for service termination; improved variable usage for exit_code_signal.
letsencrypt/rootfs/etc/services.d/lets-encrypt/run Enhanced handling of DNS challenges with new providers and credential checks; improved logging.
nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/crond/finish Updated variable usage for exit_code_signal; retained overall logic and error handling.
nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish Improved exit code handling and logging; standardized variable usage for exit_code_signal.
nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/run Added JSON configuration handling; checks for Diffie-Hellman parameters; Cloudflare configuration support.
openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish Enhanced error handling and cleanup procedures; refined exit code handling and logging.
openthread_border_router/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up Enhanced functionality for firmware flashing; improved error handling and logging.
openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/finish Updated variable usage for exit_code_signal; clarified exit code handling logic.
openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/run Added execution command for Python module with configuration parameters.
piper/rootfs/etc/s6-overlay/s6-rc.d/piper/finish Updated variable usage for exit_code_signal; refined exit code handling.
piper/rootfs/etc/s6-overlay/s6-rc.d/piper/run Added shellcheck directive; executed Python module with command-line arguments based on configuration.
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/finish Added shellcheck directives; retained existing functionality for logging exit code and signals.
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run Enhanced functionality and error handling; added new variable declarations and refined firewall setup.
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/run Added shellcheck directives; ensured default port and interface settings for Zigbee daemon.
silabs_flasher/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up Enhanced functionality for firmware flashing; improved error handling and logging.
whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/finish Updated variable usage for exit_code_signal; clarified exit code handling logic.
whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/run Added architecture check and updated model handling; modified execution command for starting Whisper service.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant GitHub Actions
    participant ShellCheck

    User->>GitHub Actions: Trigger lint workflow
    GitHub Actions->>ShellCheck: Run ShellCheck with additional_files
    ShellCheck->>GitHub Actions: Return lint results
    GitHub Actions->>User: Provide lint results
Loading

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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 or @coderabbitai title 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
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: 1

🧹 Outside diff range and nitpick comments (1)
.github/workflows/lint.yml (1)

Line range hint 4-4: Consider updating hadolint version.

The current hadolint version (v1.17.2) is quite old. Consider updating to a newer version to benefit from the latest rules and improvements.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7678e87 and dc03a2b.

📒 Files selected for processing (1)
  • .github/workflows/lint.yml (1 hunks)
🔇 Additional comments (1)
.github/workflows/lint.yml (1)

Line range hint 4-6: Environment configuration is well-aligned with custom shebang handling.

The SHELLCHECK_OPTS configuration with -e SC1008 appropriately handles the custom shebang scenario by disabling the "not following" warning, while -s bash ensures proper bash script checking.

.github/workflows/lint.yml Show resolved Hide resolved
@mislav
Copy link
Author

mislav commented Nov 18, 2024

Update: pushed a commit that fixes/allowlists all the shellcheck violations in scripts that are now newly included in the linting process.

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: 5

🧹 Outside diff range and nitpick comments (42)
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/finish (1)

10-13: Consider adding context about exit codes.

The shellcheck disable directive and exit code handling logic are correct. However, consider adding a comment explaining why exit code 256 is treated specially (typically indicates "service disabled" in s6) and log the reason before halting.

 # shellcheck disable=SC2086
+# Exit code 256 typically means service is disabled in s6, which is expected
 if [ ${1} -ne 0 ] && [ ${1} -ne 256 ]; then
+    bashio::log.error "CPC daemon failed unexpectedly, halting container..."
     /run/s6/basedir/bin/halt
 fi
openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/run (1)

Line range hint 12-18: Add input validation and improve error handling

The current implementation has several potential issues:

  1. Configuration values are used without validation
  2. The SC2068 directive disables important quote checking
  3. Missing error handling for required configuration

Consider applying this safer implementation:

-# shellcheck disable=SC2068
+# Validate required configuration
+if ! bashio::config.exists 'threshold'; then
+    bashio::exit.nok "Threshold configuration is required"
+fi
+
+if ! bashio::config.exists 'trigger_level'; then
+    bashio::exit.nok "Trigger level configuration is required"
+fi
+
+# Validate threshold and trigger_level values
+threshold=$(bashio::config 'threshold')
+trigger_level=$(bashio::config 'trigger_level')
+
+if ! [[ "$threshold" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
+    bashio::exit.nok "Invalid threshold value: $threshold"
+fi
+
+if ! [[ "$trigger_level" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
+    bashio::exit.nok "Invalid trigger level value: $trigger_level"
+fi
+
 exec python3 -m wyoming_openwakeword \
     --uri 'tcp://0.0.0.0:10400' \
     --preload-model 'ok_nabu' \
     --custom-model-dir /share/openwakeword \
-    --threshold "$(bashio::config 'threshold')" \
-    --trigger-level "$(bashio::config 'trigger_level')" ${flags[@]}
+    --threshold "${threshold}" \
+    --trigger-level "${trigger_level}" \
+    "${flags[@]+"${flags[@]}"}"
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/run (1)

6-7: Consider restructuring the directory operations.

While the current implementation works, it could be more readable and avoid the need for SC2015 suppression.

Here's a clearer alternative:

-# shellcheck disable=SC2015
-mkdir -p /data/zigbeed && cd /data/zigbeed || bashio::exit.nok "Could not change to zigbeed working directory"
+if ! mkdir -p /data/zigbeed; then
+    bashio::exit.nok "Could not create zigbeed working directory"
+fi
+if ! cd /data/zigbeed; then
+    bashio::exit.nok "Could not change to zigbeed working directory"
+fi
piper/rootfs/etc/s6-overlay/s6-rc.d/piper/run (3)

Line range hint 15-27: Consider removing SC2068 disable and improve array handling

The shellcheck disable for SC2068 can be avoided by properly quoting the array expansion. Additionally, consider adding error handling for required configuration values.

Here's the suggested improvement:

-# shellcheck disable=SC2068
+# Verify required configurations
+if ! bashio::config.exists 'voice'; then
+    bashio::exit.nok "Voice configuration is required"
+fi
+
 exec python3 -m wyoming_piper \
     --piper '/usr/share/piper/piper' \
     --uri 'tcp://0.0.0.0:10200' \
     --length-scale "$(bashio::config 'length_scale')" \
     --noise-scale "$(bashio::config 'noise_scale')" \
     --noise-w "$(bashio::config 'noise_w')" \
     --speaker "$(bashio::config 'speaker')" \
     --voice "$(bashio::config 'voice')" \
     --max-piper-procs "$(bashio::config 'max_piper_procs')" \
     --data-dir /data \
     --data-dir /share/piper \
-    --download-dir /data ${flags[@]}
+    --download-dir /data "${flags[@]+"${flags[@]}"}"

Line range hint 6-13: Consider adding debug logging for flag construction

For better observability, especially when debug_logging is enabled, consider logging the constructed flags.

 flags=()
 if bashio::config.true 'update_voices'; then
     flags+=('--update-voices')
 fi
 
 if bashio::config.true 'debug_logging'; then
     flags+=('--debug')
+    bashio::log.debug "Constructed flags: ${flags[*]}"
 fi

Shebang path inconsistency found across repository

The verification reveals two different shebang paths being used across the repository:

  • #!/command/with-contenv bashio (40 files)
  • #!/usr/bin/with-contenv bashio (74 files)

This inconsistency should be standardized to maintain uniformity. The majority of scripts (74) use #!/usr/bin/with-contenv bashio, suggesting this is the preferred path.

🔗 Analysis chain

Line range hint 1-1: Verify shebang path consistency across the repository

The shebang path #!/command/with-contenv bashio differs from the one mentioned in the PR description (#!/usr/bin/with-contenv bashio). This inconsistency should be addressed to maintain uniformity across scripts.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for different shebang variations in the repository
# Expected: Consistent shebang usage across scripts

# Search for different shebang patterns
echo "Checking shebang patterns:"
rg -l "^#!.*with-contenv bashio" | while read -r file; do
    head -n1 "$file"
done | sort | uniq -c

Length of output: 9380

nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/crond/finish (1)

6-8: Consider adding error handling for missing exit code file

The script assumes /run/s6-linux-init-container-results/exitcode exists. While this is likely true in the S6 context, defensive programming would check for file existence.

Consider adding a check:

+if [[ ! -f /run/s6-linux-init-container-results/exitcode ]]; then
+    bashio::log.error "Container exit code file not found"
+    echo 1 > /run/s6-linux-init-container-results/exitcode
+    exec /run/s6/basedir/bin/halt
+fi
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/finish (2)

Line range hint 7-11: LGTM! Good use of readonly variables

The variable declarations are well-structured with:

  • Proper use of readonly for immutable values
  • Clear variable naming
  • Appropriate shellcheck directive for SC2155

Consider adding comments describing what each exit code represents for better maintainability.


Minor inconsistency found in exit code signal handling

Most finish scripts follow the same pattern, but there's a small inconsistency in the arithmetic expression for signal handling:

  • Some scripts use $((128 + exit_code_signal)) (correct)
  • Others use $((128 + $exit_code_signal)) (with extra $)

Affected files:

  • samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish
  • samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-core/finish

While both forms work in bash arithmetic context, the extra $ is unnecessary and inconsistent with the majority pattern.

🔗 Analysis chain

Line range hint 18-26: LGTM! Robust exit code handling

The exit code handling logic is well-structured and follows s6-overlay conventions:

  • Proper signal handling for exit code 256
  • Appropriate container exit code preservation logic
  • Correct SIGTERM handling

Let's verify similar exit code handling in other service finish scripts:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find and check other finish scripts for consistent exit code handling
fd 'finish$' --type f --exec sh -c '
  echo "=== {} ==="
  grep -A 5 "exit_code_signal" "{}" || true
  echo
'

Length of output: 9414

assist_microphone/rootfs/etc/s6-overlay/s6-rc.d/assist_microphone/finish (1)

Line range hint 17-26: Add comments explaining signal handling constants

The logic is correct, but would benefit from documentation explaining the significance of the magic numbers:

+# Exit code 256 indicates the process was terminated by a signal
 if [[ "${exit_code_service}" -eq 256 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
+    # Calculate standard Linux exit code for signal termination (128 + signal number)
     echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
   fi
+  # Signal 15 is SIGTERM - graceful shutdown
   [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
 elif [[ "${exit_code_service}" -ne 0 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
     echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
   fi
+  # Halt the container due to service failure
   exec /run/s6/basedir/bin/halt
 fi
configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/finish (2)

7-10: Consider splitting variable declarations and assignments

Instead of disabling SC2155, consider splitting the variable declarations and assignments for better error handling:

-# shellcheck disable=SC2155
-readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+declare exit_code_container
+exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+readonly exit_code_container

This approach:

  • Allows error detection if the command substitution fails
  • Maintains the readonly protection
  • Follows shellcheck best practices

Line range hint 12-26: Consider enhancing logging for shutdown decisions

While the basic logging is present, adding more detailed logging before critical actions would improve debugging capabilities.

 bashio::log.info \
   "Service exited with code ${exit_code_service}" \
   "(by signal ${exit_code_signal})"

 if [[ "${exit_code_service}" -eq 256 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
+    bashio::log.info "Setting container exit code to $((128 + exit_code_signal))"
     echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
   fi
+  [[ "${exit_code_signal}" -eq 15 ]] && bashio::log.info "Received SIGTERM, initiating graceful shutdown"
   [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
 elif [[ "${exit_code_service}" -ne 0 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
+    bashio::log.info "Service failed, setting container exit code to ${exit_code_service}"
     echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
   fi
+  bashio::log.info "Initiating shutdown due to service failure"
   exec /run/s6/basedir/bin/halt
 fi
openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/finish (1)

7-10: Consider adding error handling for the exit code file read operation.

While the current implementation is functional, it could benefit from explicit error handling when reading the container exit code file.

-readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+if [[ ! -f /run/s6-linux-init-container-results/exitcode ]]; then
+  bashio::log.error "Container exit code file not found"
+  readonly exit_code_container=1
+else
+  readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+fi
piper/rootfs/etc/s6-overlay/s6-rc.d/piper/finish (2)

Line range hint 7-11: Consider separating variable declaration and assignment

While disabling SC2155 works, it's better to separate declaration and assignment to catch potential errors in command substitution.

Consider this safer approach:

-# shellcheck disable=SC2155
-readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+declare exit_code_container
+exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+readonly exit_code_container

Line range hint 18-26: Consider improving clarity of exit code handling

While the logic is correct, it could benefit from better documentation and structure.

Consider these improvements:

  1. Add constants to explain magic numbers:
# Add at the top of the script
readonly SIGNAL_EXIT_CODE=256
readonly SIGTERM=15
readonly SIGNAL_EXIT_OFFSET=128
  1. Consider simplifying the nested conditions:
-if [[ "${exit_code_service}" -eq 256 ]]; then
+if [[ "${exit_code_service}" -eq ${SIGNAL_EXIT_CODE} ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
-    echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
+    echo $((SIGNAL_EXIT_OFFSET + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
   fi
-  [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
+  [[ "${exit_code_signal}" -eq ${SIGTERM} ]] && exec /run/s6/basedir/bin/halt
  1. Add a comment explaining the signal handling logic:
# When service exits due to a signal (256), we calculate the actual exit code
# by adding 128 to the signal number, following the Linux convention.
# Special handling for SIGTERM (15) to ensure proper container shutdown.
whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/run (5)

Line range hint 6-8: Improve AVX detection precision

The current grep pattern might match partial words. Consider using word boundaries for more precise matching.

-if [ "$(uname -m)" == "x86_64" ] && ! grep -qw 'avx' /proc/cpuinfo; then
+if [ "$(uname -m)" == "x86_64" ] && ! grep -E '\bavx\b' /proc/cpuinfo; then

Line range hint 10-17: Add model path validation

The script should verify that the specified model exists or is accessible before proceeding.

 model="$(bashio::config 'model')"
 if [ "${model}" = 'custom' ]; then
     # Override with custom model
     model="$(bashio::config 'custom_model')"
     if [ -z "${model}" ]; then
       bashio::exit.nok "Custom model is not set"
     fi
+    # Verify model accessibility
+    if ! bashio::fs.file_exists "${model}" && ! bashio::fs.directory_exists "${model}"; then
+        bashio::exit.nok "Custom model '${model}' not found or inaccessible"
+    fi
 fi

Line range hint 19-21: Initialize flags array

The flags array should be initialized before use to prevent potential issues.

+declare -a flags=()
 if bashio::config.true 'debug_logging'; then
     flags+=('--debug')
 fi

Line range hint 24-32: Improve command parameter handling

Several improvements can be made to handle parameters more safely:

  1. Quote the flags array expansion
  2. Add validation for required config values
  3. Handle spaces in parameters properly
+# Validate required parameters
+bashio::config.require 'beam_size'
+bashio::config.require 'language'
+
 # shellcheck disable=SC2068
 exec python3 -m wyoming_faster_whisper \
     --uri 'tcp://0.0.0.0:10300' \
     --model "${model}" \
     --beam-size "$(bashio::config 'beam_size')" \
     --language "$(bashio::config 'language')" \
     --initial-prompt "$(bashio::config 'initial_prompt')" \
     --data-dir /data \
-    --download-dir /data ${flags[@]}
+    --download-dir /data "${flags[@]+"${flags[@]}"}"

Missing documentation for debug_logging configuration option

All configuration options used in the script are documented in DOCS.md except for debug_logging. The following options are properly documented:

  • model and custom_model under "Option: model" and "Option: custom_model" sections
  • beam_size under "Option: beam_size" section
  • language under "Option: language" section
  • initial_prompt under "Option: initial_prompt" section

The debug_logging option needs to be added to the documentation.

🔗 Analysis chain

Line range hint 1-32: Verify configuration documentation

Ensure that all configuration options used in this script (model, custom_model, beam_size, language, initial_prompt, debug_logging) are properly documented in the addon's configuration documentation.


Let me check the actual content of the DOCS.md file to ensure our grep patterns aren't missing any alternative documentation formats.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if all config options are documented
config_options=("model" "custom_model" "beam_size" "language" "initial_prompt" "debug_logging")
docs_file="whisper/DOCS.md"

if [ -f "$docs_file" ]; then
    echo "Checking configuration documentation..."
    for option in "${config_options[@]}"; do
        if ! grep -q "^\s*\`$option\`:" "$docs_file"; then
            echo "Warning: Configuration option '$option' might be missing from documentation"
        fi
    done
else
    echo "Documentation file not found at $docs_file"
fi

Length of output: 1794


Script:

#!/bin/bash
# Display the content of DOCS.md
cat whisper/DOCS.md

Length of output: 3904

duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/finish (1)

19-20: Consider adding a comment explaining the exit code calculation.

The 128 + exit_code_signal calculation follows Unix convention for signal exit codes, but this might not be immediately obvious to all maintainers.

+    # Convert signal to standard Unix exit code (128 + signal number)
     echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/run (4)

Line range hint 19-24: Improve DH params generation error handling

The current implementation suppresses all output from openssl, making it difficult to diagnose issues.

Apply these changes for better error handling:

 # Generate dhparams
 if ! bashio::fs.file_exists "${DHPARAMS_PATH}"; then
     bashio::log.info  "Generating dhparams (this will take some time)..."
-    openssl dhparam -dsaparam -out "$DHPARAMS_PATH" 4096 > /dev/null
+    if ! openssl dhparam -dsaparam -out "$DHPARAMS_PATH" 4096 2> /tmp/dhparam.error; then
+        bashio::log.error "$(cat /tmp/dhparam.error)"
+        bashio::exit.nok "Failed to generate DH parameters"
+    fi
 fi

Line range hint 26-47: Add robust error handling for Cloudflare configuration

The current implementation lacks proper error handling for network operations and file handling.

Apply these changes for improved reliability:

 if bashio::config.true 'cloudflare'; then
     # Generate cloudflare.conf
     if ! bashio::fs.file_exists "${CLOUDFLARE_CONF}"; then
         bashio::log.info "Creating 'cloudflare.conf' for real visitor IP address..."
-        echo "# Cloudflare IP addresses" > $CLOUDFLARE_CONF;
+        TEMP_CONF=$(mktemp)
+        {
+            echo "# Cloudflare IP addresses"
+            echo ""
+            echo "# - IPv4"
+            if ! IPV4_RANGES=$(curl --max-time 10 -fsSL https://www.cloudflare.com/ips-v4); then
+                bashio::exit.nok "Failed to fetch Cloudflare IPv4 ranges"
+            fi
+            for i in ${IPV4_RANGES}; do
+                echo "set_real_ip_from ${i};"
+            done
+            
+            echo ""
+            echo "# - IPv6"
+            if ! IPV6_RANGES=$(curl --max-time 10 -fsSL https://www.cloudflare.com/ips-v6); then
+                bashio::exit.nok "Failed to fetch Cloudflare IPv6 ranges"
+            fi
+            for i in ${IPV6_RANGES}; do
+                echo "set_real_ip_from ${i};"
+            done
+            
+            echo ""
+            echo "real_ip_header CF-Connecting-IP;"
+        } > "${TEMP_CONF}"
 
-        echo "" >> $CLOUDFLARE_CONF;
-
-        echo "# - IPv4" >> $CLOUDFLARE_CONF;
-        for i in $(curl https://www.cloudflare.com/ips-v4); do
-            echo "set_real_ip_from ${i};" >> $CLOUDFLARE_CONF;
-        done
-
-        echo "" >> $CLOUDFLARE_CONF;
-        echo "# - IPv6" >> $CLOUDFLARE_CONF;
-        for i in $(curl https://www.cloudflare.com/ips-v6); do
-            echo "set_real_ip_from ${i};" >> $CLOUDFLARE_CONF;
-        done
-
-        echo "" >> $CLOUDFLARE_CONF;
-        echo "real_ip_header CF-Connecting-IP;" >> $CLOUDFLARE_CONF;
+        # Atomically move the temporary file to the final location
+        if ! mv "${TEMP_CONF}" "${CLOUDFLARE_CONF}"; then
+            rm -f "${TEMP_CONF}"
+            bashio::exit.nok "Failed to create Cloudflare configuration"
+        fi
     fi
 fi

Line range hint 49-52: Add certificate validation and error handling

The current implementation doesn't validate the certificate file or handle potential errors.

Apply these changes for improved reliability:

 # start server
 bashio::log.info "Running nginx..."
-stat "/ssl/$(bashio::config 'certfile')" -c %y > /tmp/certificate_timestamp
+CERT_FILE="/ssl/$(bashio::config 'certfile')"
+if [[ ! -f "${CERT_FILE}" ]]; then
+    bashio::exit.nok "Certificate file ${CERT_FILE} does not exist"
+fi
+
+if ! stat "${CERT_FILE}" -c %y > /tmp/certificate_timestamp; then
+    bashio::exit.nok "Failed to read certificate timestamp"
+fi
+
 exec nginx -c /etc/nginx.conf < /dev/null

Line range hint 1-52: Consider adding nginx configuration validation and health checks

To improve reliability and security, consider these architectural improvements:

  1. Add nginx configuration validation before starting the service
  2. Implement basic health checks after startup
  3. Add configuration backup/rollback mechanism

Example implementation:

# Validate nginx configuration
if ! nginx -t -c /etc/nginx.conf; then
    bashio::exit.nok "Invalid nginx configuration"
fi

# Start nginx in background for health check
nginx -c /etc/nginx.conf
sleep 2

# Basic health check
if ! curl -sf http://localhost:${PORT}/health 2>/dev/null; then
    nginx -s stop
    bashio::exit.nok "Nginx health check failed"
fi

# If health check passes, restart in foreground
nginx -s stop
exec nginx -c /etc/nginx.conf < /dev/null
openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (4)

Line range hint 1-17: Add documentation for exit code handling logic

The exit code handling logic is correct, but it would benefit from additional documentation explaining why 256 is treated specially and what the significance of adding 128 to $2 is.

Add a comment block like this:

 #!/usr/bin/with-contenv bashio
 # shellcheck shell=bash
 #==============================================================================
 # OpenThread BorderRouter Daemon finish script
+# 
+# Exit code handling:
+# - Exit code 256 indicates a signal termination, where $2 contains the signal number
+# - Adding 128 to the signal number follows the Linux convention for signal exit codes
 #==============================================================================

Line range hint 20-28: Add timeout to ipset destruction retry loop

The while loop could potentially run indefinitely if the ipset remains in use. Consider adding a timeout mechanism.

Here's a suggested implementation:

 ipset_destroy_if_exist()
 {
     # The ipset seems to be in use by the kernel for a brief period,
     # retry destroying it
+    local attempts=0
+    local max_attempts=10
     while ipset list -n "$1" 2> /dev/null; do
+        if [ "$attempts" -ge "$max_attempts" ]; then
+            bashio::log.warning "Failed to destroy ipset $1 after $max_attempts attempts"
+            return 1
+        fi
         ipset destroy "$1" || true
+        attempts=$((attempts + 1))
+        sleep 0.5
     done
 }

Line range hint 30-45: Improve error handling and address shellcheck warnings

The code disables multiple shellcheck warnings (SC2154, SC2086) which might indicate potential issues:

  • SC2154 warns about unassigned variables
  • SC2086 warns about word splitting/globbing

Consider these improvements:

-# shellcheck disable=SC2154,SC2086
-while ip6tables -C FORWARD -o $thread_if -j $otbr_forward_ingress_chain 2> /dev/null; do
+if [[ -z "${thread_if:-}" ]] || [[ -z "${otbr_forward_ingress_chain:-}" ]]; then
+    bashio::log.error "Required variables thread_if or otbr_forward_ingress_chain not set"
+    exit 1
+fi
+
+while ip6tables -C FORWARD -o "$thread_if" -j "$otbr_forward_ingress_chain" 2> /dev/null; do
     # shellcheck disable=SC2086
-    ip6tables -D FORWARD -o $thread_if -j $otbr_forward_ingress_chain
+    ip6tables -D FORWARD -o "$thread_if" -j "$otbr_forward_ingress_chain" || \
+        bashio::log.warning "Failed to delete FORWARD rule"
 done

Line range hint 47-56: Reduce code duplication by extracting chain cleanup logic

The ingress and egress cleanup logic is very similar and could be consolidated into a reusable function.

Consider refactoring like this:

+cleanup_forward_chain() {
+    local interface="$1"
+    local direction="$2"
+    local chain="$3"
+
+    while ip6tables -C FORWARD "$direction" "$interface" -j "$chain" 2> /dev/null; do
+        ip6tables -D FORWARD "$direction" "$interface" -j "$chain" || \
+            bashio::log.warning "Failed to delete FORWARD rule for $chain"
+    done
+
+    if ip6tables -L "$chain" 2> /dev/null; then
+        ip6tables -w -F "$chain"
+        ip6tables -w -X "$chain"
+    fi
+}
+
+cleanup_forward_chain "$thread_if" "-o" "$otbr_forward_ingress_chain"
+cleanup_forward_chain "$thread_if" "-i" "$otbr_forward_egress_chain"
openthread_border_router/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (1)

Line range hint 15-18: Enhance error messages for better debugging.

While the error handling is good, the messages could be more detailed to aid in troubleshooting.

 function exit_no_firmware {
-    bashio::log.warning "No firmware found for the selected device, assuming firmware is installed."
+    bashio::log.warning "No firmware found for device at ${device} (Manufacturer: ${usb_manufacturer:-unknown}, Product: ${usb_product:-unknown})"
     exit 0
 }

     if [ ! -f "${usb_device_path}/idProduct" ]; then
-        bashio::log.info "The selected serial port is not a USB device."
+        bashio::log.info "The selected serial port ${device} is not a USB device (path: ${usb_device_path})"
         exit_no_firmware
     fi

Also applies to: 42-45

silabs_flasher/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (3)

Line range hint 1-18: Consider enhancing error handling with additional shell options.

While set -e is good for error handling, consider adding set -u to catch undefined variables and set -o pipefail to ensure pipeline failures are caught.

 set -e
+set -u
+set -o pipefail

Line range hint 34-41: Consider adding comments explaining the hardware-specific paths.

The path /sys/devices/platform/soc/fe201800.serial/tty/ttyAMA1 is hardware-specific. Adding a comment explaining why this path indicates a Home Assistant Yellow device would improve maintainability.

+# Home Assistant Yellow uses the BCM2711 UART4 mapped to ttyAMA1
 if [ -d /sys/devices/platform/soc/fe201800.serial/tty/ttyAMA1 ] && [ "${device}" == "/dev/ttyAMA1" ]; then

Line range hint 92-98: Improve command execution robustness.

The current implementation has unquoted variables in the command execution which could cause issues with special characters or spaces.

Consider using an array to handle the arguments more safely:

-# shellcheck disable=SC2086
-universal-silabs-flasher \
-    ${verbose} \
-    --device ${device} \
-    --bootloader-baudrate "${bootloader_baudrate}" \
-    ${gpio_reset_flag} \
-    flash --force --firmware "/root/${firmware}"
+# Build command arguments array
+cmd=(
+    "universal-silabs-flasher"
+    "${verbose}"
+    "--device" "${device}"
+    "--bootloader-baudrate" "${bootloader_baudrate}"
+)
+
+# Add GPIO reset flag if set
+if [[ -n "${gpio_reset_flag}" ]]; then
+    cmd+=($gpio_reset_flag)
+fi
+
+# Add final arguments
+cmd+=(
+    "flash"
+    "--force"
+    "--firmware" "/root/${firmware}"
+)
+
+# Execute command
+"${cmd[@]}"
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (4)

Line range hint 61-96: Consider adding documentation for the firewall rules.

The firewall setup is comprehensive and well-structured. However, adding comments to explain the purpose of each rule would improve maintainability.

Consider adding comments like this:

 ipset create -exist otbr-ingress-deny-src hash:net family inet6
+# Create swap set for atomic updates
 ipset create -exist otbr-ingress-deny-src-swap hash:net family inet6
+# Allow specific destination networks
 ipset create -exist otbr-ingress-allow-dst hash:net family inet6

Line range hint 98-113: Consider improving port validation.

While the port handling is generally good, consider adding validation for port availability before starting the service.

Here's a suggested improvement:

 if ! bashio::var.has_value "${otbr_rest_listen_port}"; then
     otbr_rest_listen="$(bashio::addon.ip_address)"
     otbr_rest_listen_port="8081"
 elif [ "${otbr_rest_listen_port}" != "8081" ]; then
     bashio::log.warning "Custom OpenThread REST API port is not supported. Using 8081."
     otbr_rest_listen_port="8081"
+else
+    # Check if port is already in use
+    if netstat -ln | grep -q ":${otbr_rest_listen_port} "; then
+        bashio::log.warning "Port ${otbr_rest_listen_port} is already in use. Service might fail to start."
+    fi
 fi

Line range hint 117-122: Consider documenting the timeout values.

The service execution is well-configured, but the s6-notifyoncheck timeout values (300 seconds) should be documented to explain why this specific duration was chosen.

Add a comment explaining the timeout values:

+# Use 5-minute timeout for both startup and readiness checks
+# as Thread network formation and backbone interface setup might take time
 exec s6-notifyoncheck -d -s 300 -w 300 -n 0 \

Variables marked as unused are actually unused in both scripts

The variables device, baudrate, and flow_control are declared but never used in either the main script or the sourced common script. These variables can be safely removed as they serve no purpose.

  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run: Remove the following unused variable declarations:
    # shellcheck disable=SC2034
    declare device
    # shellcheck disable=SC2034
    declare baudrate
    # shellcheck disable=SC2034
    declare flow_control
🔗 Analysis chain

Line range hint 2-20: LGTM! Verify unused variables.

The script setup and variable declarations follow best practices. The shellcheck directives are properly used to suppress specific warnings.

Let's verify if the "unused" variables are actually used in the sourced script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the variables are used in the common script
rg -A 5 "device|baudrate|flow_control" "/etc/s6-overlay/scripts/otbr-agent-common"

Length of output: 164


Script:

#!/bin/bash
# Let's first find the correct path to the common script
fd "otbr-agent-common"

# Then search for variable usage in all script files
rg -A 5 "device|baudrate|flow_control" $(fd -t f -e sh)

Length of output: 5488


Script:

#!/bin/bash
# Let's check the content of the common script specifically
cat silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-agent-common

# Also check if these variables are used in the run script itself
cat silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run

Length of output: 4660

letsencrypt/rootfs/etc/services.d/lets-encrypt/run (5)

Line range hint 137-137: Correct the function name for requiring TransIP username

The function bashio::config.require.username is not valid. It should be bashio::config.require 'dns.transip_username'.

Apply this diff to fix the issue:

-bashio::config.require.username 'dns.transip_username'
+bashio::config.require 'dns.transip_username'

Line range hint 85-90: Add DNS challenge check for Cloudflare provider

For consistency and to prevent potential misconfigurations, add the check for ${CHALLENGE} == "dns" in the Cloudflare provider block, similar to other DNS providers.

Apply this diff:

-elif [ "${DNS_PROVIDER}" == "dns-cloudflare" ]; then
+elif [ "${CHALLENGE}" == "dns" ] && [ "${DNS_PROVIDER}" == "dns-cloudflare" ]; then

Line range hint 86-95: Require Cloudflare email and API key when token is absent

When dns.cloudflare_api_token is not provided, the script uses dns.cloudflare_email and dns.cloudflare_api_key without ensuring they are set. Add bashio::config.require statements to prevent runtime errors due to missing configurations.

Apply this diff:

 else
+    bashio::config.require 'dns.cloudflare_email'
+    bashio::config.require 'dns.cloudflare_api_key'
     bashio::log.warning "Use CloudFlare global key (not recommended!)"
     echo -e "dns_cloudflare_email = $(bashio::config 'dns.cloudflare_email')\n" \
         "dns_cloudflare_api_key = $(bashio::config 'dns.cloudflare_api_key')\n" >> "/data/dnsapikey"

Line range hint 215-221: Use consistent credential file naming for Azure provider

In the Azure provider block, the credentials file is copied to /data/azure_creds, which may cause conflicts if multiple credentials are used. Consider using the original filename to maintain consistency and flexibility.

Apply this diff:

-  cp -f "/share/${AZURE_CREDS}" "/data/azure_creds"
-  chmod 600 "/data/azure_creds"
+  cp -f "/share/${AZURE_CREDS}" "/data/${AZURE_CREDS}"
+  chmod 600 "/data/${AZURE_CREDS}"

Update the provider arguments accordingly:

-PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-config" "/data/azure_creds")
+PROVIDER_ARGUMENTS+=("--authenticator" "${DNS_PROVIDER}" "--${DNS_PROVIDER}-config" "/data/${AZURE_CREDS}")

Line range hint 95-104: Ensure at least one Gandi credential is provided

The Gandi provider block does not require any credentials, which may lead to configuration errors. Ensure that at least one of dns.gandi_sharing_id, dns.gandi_token, or dns.gandi_api_key is provided.

Consider adding the following check:

if ! bashio::config.has_value 'dns.gandi_sharing_id' && \
   ! bashio::config.has_value 'dns.gandi_token' && \
   ! bashio::config.has_value 'dns.gandi_api_key'; then
    bashio::log.fatal "At least one Gandi credential must be provided."
    exit 1
fi
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between dc03a2b and d70266c.

📒 Files selected for processing (19)
  • assist_microphone/rootfs/etc/s6-overlay/s6-rc.d/assist_microphone/finish (2 hunks)
  • configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/finish (2 hunks)
  • duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/finish (2 hunks)
  • letsencrypt/rootfs/etc/services.d/lets-encrypt/run (2 hunks)
  • nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/crond/finish (2 hunks)
  • nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish (2 hunks)
  • nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/run (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (4 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (3 hunks)
  • openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/finish (2 hunks)
  • openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/run (1 hunks)
  • piper/rootfs/etc/s6-overlay/s6-rc.d/piper/finish (2 hunks)
  • piper/rootfs/etc/s6-overlay/s6-rc.d/piper/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/finish (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (4 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/run (2 hunks)
  • silabs_flasher/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (3 hunks)
  • whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/finish (2 hunks)
  • whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/run (1 hunks)
🔇 Additional comments (28)
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/finish (2)

1-2: LGTM! Shell directive enables proper linting.

The addition of # shellcheck shell=bash directive properly enables shellcheck to lint this script despite the custom shebang, which aligns with the PR objectives.


1-13: Verify consistent error handling across services.

Let's ensure this error handling pattern is consistent with other critical services in the system.

✅ Verification successful

Error handling is appropriately unique to each service's requirements

After analyzing the finish scripts across all services in the multiprotocol add-on:

  • The cpcd service's error handling (halting on non-zero/non-256 exits) is appropriately unique to its critical role as the Co-Processor Communication daemon
  • Other services have different requirements:
    • otbr-agent has extensive cleanup of firewall rules and custom exit code handling
    • otbr-web, zigbeed, and mdns only log their exit status without container termination

This variation in error handling is correct by design, as each service has different responsibilities and failure impacts on the system.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check error handling patterns in other finish scripts
# Expected: Similar exit code handling patterns in other critical services

# Find and examine other finish scripts
fd finish "rootfs/etc/s6-overlay/s6-rc.d" --type f --exec sh -c '
    echo "=== {} ==="
    cat "{}"
    echo
'

# Look for documentation about service behavior
fd . -e md -e txt --exec grep -l -i "cpcd\|silicon labs\|multiprotocol" {} \;

Length of output: 503


Script:

#!/bin/bash
# Let's adjust the path to check finish scripts
fd finish "silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d" --type f --exec sh -c '
    echo "=== {} ==="
    cat "{}"
    echo
'

# Let's also check the documentation specifically for cpcd service behavior
cat silabs-multiprotocol/DOCS.md

Length of output: 8797

openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/run (1)

Line range hint 12-18: Consider security and operational improvements

A few architectural considerations:

  1. The service is binding to all interfaces (0.0.0.0). Consider restricting this to specific interfaces if external access isn't required.
  2. No health check mechanism is visible. Consider adding a health check to ensure the service is functioning correctly.
  3. No resource limits are specified. Consider adding memory and CPU limits to prevent resource exhaustion.

Let's verify if this service is meant to be externally accessible:

silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/run (3)

1-2: LGTM! Proper shell specification for linting.

The addition of # shellcheck shell=bash directive ensures proper linting while maintaining the required custom shebang for the Home Assistant add-on environment.


19-22: Verify radio URL configuration and parameter handling.

The unquoted variables for listen parameters are intentionally left unquoted (hence SC2086 suppression), but we should verify the radio URL configuration.

Let's check for consistency in radio URL usage:

#!/bin/bash
# Check for other instances of radio URL configuration
rg "spinel\+cpc://" --type sh

# Look for any documentation or configuration files that specify the radio URL format
fd -e md -e yaml -e conf -X rg "radio.*url"

Line range hint 9-16: LGTM! Secure network configuration with proper fallback.

The network configuration logic is well-implemented with appropriate security considerations. When no user port is specified, it defaults to listening only on the local interface.

Let's verify the port configuration handling:

✅ Verification successful

Port configuration is correctly implemented and documented

The verification confirms that port 9999 is:

  • Properly configured in config.yaml as a configurable TCP port
  • Well-documented in translations as "EmberZNet EZSP/ASH port"
  • Consistently used as the default fallback in the zigbeed service
  • Referenced in patches and documentation for TCP socket implementation

The network configuration logic is secure and follows best practices:

  • Default listening on all interfaces (::) only when user configures the port
  • Falls back to local-only interface with default port 9999 when unconfigured
  • Port configuration is properly exposed through the add-on configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any other instances where port 9999 is hardcoded
rg -l "9999" --type sh

# Check for consistent port configuration patterns across other services
ast-grep --pattern 'bashio::addon.port $_'

Length of output: 77


Script:

#!/bin/bash
# Let's try a more comprehensive search for port configuration
rg "9999" -A 2 -B 2

# Search for port configuration in YAML files (addon configuration)
fd -e yaml -X rg "9999|ports?"

# Look for network configuration patterns
rg "ezsp_listen" -A 2 -B 2

Length of output: 10209

nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/crond/finish (2)

18-18: Correct arithmetic evaluation syntax

The change from $exit_code_signal to exit_code_signal in the arithmetic context is correct. In bash arithmetic evaluation ($(( ))), variables don't require the $ prefix.


Line range hint 6-26: Verify error handling in the supervision tree

The script's error handling logic appears robust, but let's verify the integration with the S6 supervision tree:

  1. It properly captures container and service exit codes
  2. Handles signal 15 (SIGTERM) specially
  3. Propagates non-zero exit codes correctly
  4. Initiates system halt when needed

Let's verify the error handling patterns across similar service finish scripts:

✅ Verification successful

Error handling is consistent across S6 supervision tree

The verification shows that the error handling in the crond finish script follows the standard pattern used across multiple services in the codebase. All finish scripts that implement error handling use identical logic for:

  • Capturing container and service exit codes
  • Special handling of SIGTERM (signal 15)
  • Propagating exit codes to container results
  • Initiating system halt on errors

The implementation is verified to be correct and consistent with other services like whisper, samba, nginx, mariadb, etc.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in error handling across finish scripts
# Look for other finish scripts with similar patterns

# Find all finish scripts in s6-rc.d directories
fd --type f '^finish$' --exec sh -c '
    echo "=== {} ==="
    # Check for exit code handling patterns
    rg -A 2 "exit_code_(container|service|signal)" {} || true
    echo ""
'

# Verify halt command usage
rg --type sh "exec.*/run/s6/basedir/bin/halt"

Length of output: 10679

nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish (3)

Line range hint 1-9: LGTM! Well-structured variable declarations.

Good practices observed:

  • Using readonly for constants
  • Explicit shellcheck configuration
  • Necessary shellcheck disable for the container exit code reading

Line range hint 11-14: LGTM! Clear and structured logging implementation.

The logging provides good visibility into service termination with all relevant exit details.


Line range hint 16-25: LGTM! Robust exit code handling with proper signal propagation.

The implementation correctly handles:

  1. Signal termination (exit code 256)
  2. Error conditions (non-zero exit)
  3. Clean shutdown (SIGTERM)

Let's verify that similar exit code handling is consistent across other service finish scripts:

✅ Verification successful

Exit code handling is consistent across all service finish scripts

The verification shows that the exit code handling pattern in nginx_proxy's finish script is consistently implemented across multiple services including assist_microphone, configurator, duckdns, mariadb, nginx_proxy, openwakeword, piper, samba, and whisper. All scripts follow the same robust pattern:

  1. Signal termination (exit code 256)
  2. Error conditions (non-zero exit)
  3. Clean shutdown (SIGTERM)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in exit code handling across finish scripts
# Look for other finish scripts and compare their exit code handling patterns

# Find all finish scripts
fd finish 'rootfs/etc/s6-overlay/s6-rc.d'

# Check exit code handling patterns in finish scripts
rg -A 5 'exit_code_signal' 'rootfs/etc/s6-overlay/s6-rc.d/*/finish'

Length of output: 305


Script:

#!/bin/bash
# Let's first locate the correct path by searching from root
fd -t f finish

# Once we find the paths, let's examine the exit code handling
rg -A 5 'exit_code_' $(fd -t f finish)

Length of output: 24336

whisper/rootfs/etc/s6-overlay/s6-rc.d/whisper/finish (2)

Line range hint 1-6: LGTM! Well-documented script header

The script header is properly configured with:

  • Appropriate shebang for s6-overlay environment
  • Explicit shellcheck shell directive
  • Clear documentation with reference to s6-overlay docs

Line range hint 13-16: LGTM! Clear logging implementation

Good use of structured logging with bashio to capture both the exit code and signal information.

assist_microphone/rootfs/etc/s6-overlay/s6-rc.d/assist_microphone/finish (2)

Line range hint 12-15: LGTM! Good logging practices

The logging implementation follows best practices by using structured logging and providing clear context about the service state.


Line range hint 1-26: Verify consistency with other S6 finish scripts

Let's ensure this implementation is consistent with other S6 finish scripts in the repository.

✅ Verification successful

Let me try a different approach to locate and verify the S6 scripts.


Implementation is consistent with S6 finish scripts across the repository

The verification shows that the finish script implementation in assist_microphone follows the standard pattern used across the repository's S6-managed services. Key observations:

  • The same exit code handling logic is consistently used in other services like configurator, duckdns, nginx_proxy, openwakeword, piper, and whisper
  • The script properly handles both service exit codes and signals in line with S6 overlay requirements
  • The implementation matches the reference pattern for container shutdown behavior

The script is well-integrated with the S6 supervision tree and maintains consistency with other services in the repository.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find and compare all S6 finish scripts
echo "Searching for other S6 finish scripts..."
fd --type f "finish$" "rootfs/etc/s6-overlay/s6-rc.d" | while read -r script; do
  echo "=== $script ==="
  # Check for consistent shebang
  head -n 1 "$script"
  # Check for consistent exit code handling
  grep -A 5 "exit_code_service" "$script" || true
  echo
done

Length of output: 278


Script:

#!/bin/bash
# First, let's find the correct path structure
fd --type f finish

# Then check the content of found files
for script in $(fd --type f finish); do
  echo "=== $script ==="
  head -n 1 "$script"
  grep -A 5 "exit_code_service" "$script" || true
  echo
done

Length of output: 22643

configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/finish (2)

Line range hint 1-1: Verify script permissions

Ensure this critical s6-overlay script has the correct executable permissions.

#!/bin/bash
# Description: Check permissions of s6 finish scripts

# Find the finish script and verify its permissions
fd finish "configurator/rootfs/etc/s6-overlay/s6-rc.d" --type f --exec stat -c "%a %n" {}

Line range hint 18-26: LGTM! Proper signal handling implementation

The exit code calculation follows POSIX standards for signal handling (128 + signal_number). The logic properly manages:

  1. Signal terminations (exit 256)
  2. Normal service failures (non-zero exit)
  3. Graceful exits

Let's verify other similar scripts follow the same pattern:

✅ Verification successful

Signal handling implementation is unique to this service

The signal handling implementation (128 + signal) appears to be specific to the configurator service. This is expected as:

  1. The directory structure shows only two services: configurator and user
  2. The signal handling pattern (128 + exit_code_signal) is only found in configurator/finish
  3. The user service appears to be a container for service dependencies rather than an actual service
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in signal handling across s6 finish scripts

# Find all finish scripts and check their signal handling implementation
fd finish "rootfs/etc/s6-overlay/s6-rc.d" --type f --exec sh -c '
    echo "=== {} ==="
    grep -A 5 "exit_code_signal" "{}" || true
    echo
'

Length of output: 306


Script:

#!/bin/bash
# Let's try a different approach using ripgrep to find signal handling patterns
# across finish scripts in the s6 overlay directory

rg -A 5 "exit_code_signal" "configurator/rootfs/etc/s6-overlay/s6-rc.d" --type sh

Length of output: 79


Script:

#!/bin/bash
# Let's try one more time with a broader search in the configurator directory
# to find all finish scripts and their signal handling patterns

# First, let's see what files exist in the s6-rc.d directory
ls -R configurator/rootfs/etc/s6-overlay/s6-rc.d/

# Then search for signal handling patterns in shell scripts
rg -A 5 "128 \+" configurator/rootfs/etc/s6-overlay/

Length of output: 1183

openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/finish (2)

Line range hint 12-14: LGTM! Well-structured logging implementation.

The logging statement provides clear visibility into service termination with both exit code and signal information.


Line range hint 16-25: Verify signal handling implementation across services.

The signal handling logic follows Unix standards (128 + signal number). Let's verify this implementation is consistent across other service finish scripts.

✅ Verification successful

Signal handling implementation is consistent across services

After analyzing all finish scripts in the repository, I can confirm that the signal handling implementation is consistent and follows Unix standards. The scripts follow two main patterns:

  1. Full signal handling (like in openwakeword, piper, whisper, etc.):
if [[ "${exit_code_service}" -eq 256 ]]; then
  if [[ "${exit_code_container}" -eq 0 ]]; then
    echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
  fi
  [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
  1. Simplified signal handling (like in mosquitto, dnsmasq, etc.):
if [[ "$1" -ne 0 ]] && [[ "$1" -ne 256 ]]; then
  bashio::log.warning "Halt add-on"
  exec /run/s6/basedir/bin/halt
fi

Both patterns correctly handle signal termination (256) and follow the Unix standard of using 128 + signal number for the exit code. The implementation in openwakeword is consistent with other critical services in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent signal handling across finish scripts
# Expected: All finish scripts should handle signals similarly

# Find all finish scripts and check their signal handling implementation
fd finish "rootfs/etc/s6-overlay/s6-rc.d" --type f --exec sh -c '
  echo "=== {} ==="
  # Look for signal handling patterns
  rg -A 2 "exit_code_signal" {} || true
  echo
'

Length of output: 289


Script:

#!/bin/bash
# Let's first locate the finish scripts in the repository
fd finish --type f

# Then examine their content
fd finish --type f --exec sh -c '
  echo "=== {} ==="
  cat {}
  echo -e "\n"
'

Length of output: 30101

piper/rootfs/etc/s6-overlay/s6-rc.d/piper/finish (2)

Line range hint 1-6: LGTM! Well-documented script header

The shebang and documentation comments provide clear context about the script's purpose and relevant documentation links.


Line range hint 13-16: LGTM! Clear and informative logging

Good use of structured logging to capture both the exit code and signal information.

duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/finish (2)

Line range hint 7-11: LGTM! Good use of readonly declarations.

The shellcheck disable for SC2155 is appropriate here since the command substitution is guaranteed to succeed in a running container.


Line range hint 18-26: Verify consistent error handling across other service finish scripts.

The error handling logic here is robust. Let's ensure this pattern is consistently applied across other service finish scripts in the repository.

✅ Verification successful

Error handling pattern is consistently implemented across service finish scripts

The verification shows that the error handling pattern is consistently implemented across the repository's service finish scripts. Key findings:

  • All s6-rc.d finish scripts follow the same robust pattern:
    • Handle signal-based exits (code 256)
    • Special handling for SIGTERM (signal 15)
    • Preserve first error by checking container exit code
    • Use exec /run/s6/basedir/bin/halt for abnormal termination

The error handling in the duckdns finish script follows the established best practices used throughout the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in error handling across finish scripts
# Expected results: Similar error handling patterns in other finish scripts

# Find all finish scripts
echo "Searching for finish scripts with similar error handling patterns..."
rg -l "s6-linux-init-container-results/exitcode" --type bash

# Check for consistent signal handling
echo -e "\nChecking signal handling consistency..."
rg "exit_code_signal" --type bash -C 2

# Check for consistent halt command usage
echo -e "\nChecking halt command usage..."
rg "exec.*halt" --type bash -C 2

Length of output: 540


Script:

#!/bin/bash
# Let's try without the --type bash flag since it's not recognized
# and use more generic pattern matching

# Find all finish scripts
echo "Searching for finish scripts with error handling patterns..."
rg -l "s6-linux-init-container-results/exitcode"

# Check for consistent signal handling
echo -e "\nChecking signal handling consistency..."
rg "exit_code_signal" -C 2

# Check for consistent halt command usage
echo -e "\nChecking halt command usage..."
rg "exec.*halt" -C 2

# Additionally, let's find all finish scripts by path pattern
echo -e "\nLocating finish scripts by path..."
fd "finish$" --type f

Length of output: 34646

openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (1)

Line range hint 58-66: LGTM: Proper S6 error handling implementation

The error handling follows S6 supervision tree conventions correctly:

  • Writes exit code to the proper location
  • Uses exit code 125 to indicate permanent failure
  • Includes helpful documentation
openthread_border_router/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (2)

Line range hint 2-13: LGTM! Well-structured script setup.

Good practices observed:

  • Explicit shell directive for shellcheck
  • Clear variable declarations upfront
  • Proper use of shellcheck directives

Line range hint 55-69: Consider making firmware versions configurable.

While the device detection logic is solid, hardcoded firmware versions might make updates difficult.

Consider moving firmware versions to a configuration file:

+    # Source firmware versions from config
+    source /etc/universal-silabs-flasher/firmware.conf
+
     if [[ "${usb_manufacturer}" == "Nabu Casa" && "${usb_product}" == "SkyConnect"* ]]; then
-        firmware="skyconnect_openthread_rcp_2.4.4.0_GitHub-7074a43e4_gsdk_4.4.4.gbl"
+        firmware="${SKYCONNECT_FIRMWARE}"

Let's verify supported devices against documentation:

silabs_flasher/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (1)

Line range hint 20-32: Well-implemented cleanup and exit handling!

The cleanup function properly handles:

  • Exit status logging
  • S6-overlay exit code reporting
  • Graceful shutdown via halt
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (1)

55-60: LGTM! Good error handling.

The fallback to "eth0" when no primary interface is found is a reasonable safety measure. The warning message is clear and informative.

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: 10

🧹 Outside diff range and nitpick comments (113)
dnsmasq/rootfs/etc/services.d/dnsmasq/run (1)

Line range hint 11-11: Document the purpose of /dev/null redirection.

The redirection < /dev/null should be documented to explain its purpose in preventing potential stdin-related issues.

-exec dnsmasq -C "${CONFIG}" -z < /dev/null
+# Redirect from /dev/null to ensure dnsmasq doesn't inherit stdin
+exec dnsmasq -C "${CONFIG}" -z < /dev/null
vlc/rootfs/etc/cont-init.d/secret.sh (3)

Line range hint 7-8: Add error handling for file permission issues

The file existence check should also verify that the file is readable and has appropriate permissions.

-if bashio::fs.file_exists /data/secret; then
+if bashio::fs.file_exists /data/secret && [[ -r /data/secret ]]; then
     bashio::exit.ok
+else
+    bashio::log.debug "Secret file does not exist or is not readable"
 fi

Line range hint 11-11: Enhance security of password file creation

The script should:

  1. Set restrictive permissions on the secret file
  2. Verify pwgen's success
  3. Validate the generated password
-pwgen 64 1 > /data/secret
+if ! pwgen -s 64 1 > /data/secret; then
+    bashio::exit.nok "Failed to generate password"
+fi
+
+# Secure the file permissions
+chmod 600 /data/secret
+
+# Validate password was written
+if ! [[ -s /data/secret ]]; then
+    bashio::exit.nok "Failed to write password to file"
+fi

Note: Added -s flag to pwgen for more secure random passwords.


Line range hint 1-12: Consider implementing password rotation mechanism

The current implementation only generates a password if it doesn't exist. Consider adding a mechanism for password rotation, especially for security-sensitive deployments.

Would you like me to propose an implementation for a password rotation mechanism?

deconz/rootfs/etc/services.d/nginx/run (2)

Line range hint 8-11: Add error handling and improve logging

The script could benefit from better error handling and logging:

  1. No error handling if the port wait times out
  2. No verification that nginx started successfully
  3. Limited logging around the startup process

Consider applying these improvements:

 # Wait for deCONZ to start before continuing
-bashio::net.wait_for 40850
+if ! bashio::net.wait_for 40850; then
+    bashio::log.error "deCONZ failed to start on port 40850"
+    exit 1
+fi
 
 bashio::log.info "Starting Nginx..."
-exec nginx
+if ! exec nginx; then
+    bashio::log.error "Failed to start Nginx"
+    exit 1
+fi

Line range hint 10-11: Verify nginx configuration before starting

Consider adding a configuration test before starting nginx to catch any potential issues early.

Add this before starting nginx:

 bashio::log.info "Starting Nginx..."
+if ! nginx -t; then
+    bashio::log.error "Nginx configuration test failed"
+    exit 1
+fi
 exec nginx
deconz/rootfs/etc/cont-init.d/novnc.sh (1)

Line range hint 6-8: Add error handling and validation

The script could benefit from additional error handling and validation:

  1. Validate the ingress_entry value is not empty
  2. Add error handling for the sed operation
  3. Verify the HTML file exists before modification
  4. Consider creating a backup before in-place modification

Here's a suggested improvement:

declare ingress_entry
ingress_entry=$(bashio::addon.ingress_entry)
-sed -i "s#websockify#${ingress_entry#?}/novnc/websockify#g" /usr/share/novnc/vnc_lite.html
+
+if [[ -z "${ingress_entry}" ]]; then
+    bashio::exit.nok "Failed to get ingress entry"
+fi
+
+HTML_FILE="/usr/share/novnc/vnc_lite.html"
+if [[ ! -f "${HTML_FILE}" ]]; then
+    bashio::exit.nok "noVNC HTML file not found: ${HTML_FILE}"
+fi
+
+if ! sed -i.backup "s#websockify#${ingress_entry#?}/novnc/websockify#g" "${HTML_FILE}"; then
+    bashio::exit.nok "Failed to update noVNC configuration"
+fi
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/socat-cpcd-tcp-enable-check.sh (1)

Line range hint 7-11: Consider adding error handling and idempotency checks

While the logic is straightforward, consider these improvements for better robustness:

  1. Add error handling for file creation operations
  2. Add idempotency checks to prevent duplicate operations
  3. Consider using variables for repeated path segments

Here's a suggested improvement:

+readonly S6_PATH="/etc/s6-overlay/s6-rc.d"
+
 if bashio::config.has_value 'network_device'; then
-    touch /etc/s6-overlay/s6-rc.d/user/contents.d/socat-cpcd-tcp
-    touch /etc/s6-overlay/s6-rc.d/cpcd/dependencies.d/socat-cpcd-tcp
-    bashio::log.info "Enabled socat-cpcd-tcp."
+    if ! touch "${S6_PATH}/user/contents.d/socat-cpcd-tcp" || \
+       ! touch "${S6_PATH}/cpcd/dependencies.d/socat-cpcd-tcp"; then
+        bashio::log.error "Failed to enable socat-cpcd-tcp service"
+        exit 1
+    fi
+    bashio::log.info "Enabled socat-cpcd-tcp"
 fi
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/run (1)

Line range hint 7-9: Add validation for network_device configuration.

The script should validate the network_device configuration before attempting to use it in the TCP connection. A missing or invalid value could cause silent failures.

Consider adding validation:

 declare network_device
 
 network_device=$(bashio::config 'network_device')
+if ! bashio::config.has_value 'network_device'; then
+    bashio::log.error "Network device configuration is required"
+    exit 1
+fi
ssh/rootfs/etc/services.d/sshd/run (2)

Line range hint 8-11: Consider adding error handling for port validation

While the port check is functional, consider adding explicit validation for port configuration errors.

 if ! bashio::var.has_value "$(bashio::addon.port 22)"; then
     bashio::log.warning "SSH port is disabled. Prevent start of SSH server." 
+    # Exit with success as this is a valid configuration state
     exec sleep infinity
+else
+    # Validate port is within valid range
+    port=$(bashio::addon.port 22)
+    if ! bashio::var.is_number "${port}" || [ "${port}" -lt 1 ] || [ "${port}" -gt 65535 ]; then
+        bashio::log.error "Invalid SSH port configuration: ${port}"
+        exit 1
+    fi
 fi

Line range hint 1-14: Consider adding S6 notification readiness

For better integration with S6 supervision, consider notifying when the service is ready.

 bashio::log.info "Starting the SSH daemon..."
+# Notify supervisor that service is ready
+s6-notifyoncheck -d -n 300 -w 1000 \
 exec /usr/sbin/sshd -D -e

This ensures proper service orchestration and dependency management in the S6 supervision tree.

zwave_js/rootfs/etc/cont-init.d/structure.sh (1)

Line range hint 6-16: Add error handling for directory operations

The directory operations could benefit from additional error handling and safety checks:

  1. Directory creation should verify success
  2. Migration operation should handle potential failures
  3. Consider adding appropriate permissions

Consider applying these improvements:

-mkdir -p /data/db
+if ! mkdir -p /data/db; then
+    bashio::log.error "Failed to create database directory"
+    exit 1
+fi

 if bashio::fs.directory_exists '/data/cache'; then
     bashio::log.info "Migrating 'cache' folder from private storage to /addon_configs/core_zwave_js"
-    mv /data/cache /config/cache
+    if ! mv -n /data/cache /config/cache; then
+        bashio::log.error "Failed to migrate cache directory"
+        exit 1
+    fi
 fi

 if ! bashio::fs.directory_exists '/config/cache'; then
-    mkdir -p /config/cache
+    if ! mkdir -p /config/cache; then
+        bashio::log.error "Failed to create cache directory"
+        exit 1
+    fi
+    chmod 755 /config/cache
 fi
ssh/rootfs/etc/cont-init.d/apks.sh (2)

Line range hint 11-17: Enhance error handling and reporting.

The current implementation exits on the first failure. Consider collecting all failed packages and reporting them together for better user experience.

Here's a suggested improvement:

+declare -a failed_packages=()
 for package in $(bashio::config "apks"); do
-    apk add "$package" \
-        || bashio::exit.nok "Failed installing ${package}"
+    if ! apk add "$package"; then
+        failed_packages+=("$package")
+        bashio::log.error "Failed installing ${package}"
+    fi
 done
+
+if [ ${#failed_packages[@]} -ne 0 ]; then
+    bashio::exit.nok "Failed installing packages: ${failed_packages[*]}"
+fi
+
+# Clean up
+rm -rf /var/cache/apk/*

Based on the gathered information, I can now provide the final response:

Package installation security concerns require attention

The current implementation has some built-in security measures but could be improved:

  • The add-on runs in a container with limited privileges
  • Documentation explicitly states it won't allow root-level package installations
  • However, the package installation process still lacks:
    • Package name validation/sanitization
    • No allowlist/blocklist for packages
    • No verification of package signatures or sources
    • No cleanup of package cache after installation

Recommendations:

  1. Add package name validation using alphanumeric and hyphen checks
  2. Implement an allowlist of safe packages
  3. Add package signature verification
  4. Clean up package cache after installation
  5. Add logging of installed packages for audit purposes
🔗 Analysis chain

Line range hint 7-17: Consider adding security constraints and improving robustness.

The current implementation allows installation of arbitrary packages without validation, which could pose security risks. Additionally, the package management process could be more robust.

Consider these improvements:

  1. Add package name validation
  2. Implement package allowlist/blocklist
  3. Add package cache cleanup
  4. Handle concurrent apk operations

Let's check if there are any security measures in place elsewhere:


Let me gather more information about the configuration schema and validation:


Let me check for any existing package validation or restrictions in the configuration:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for package restrictions in other configuration files
echo "Searching for package-related configuration..."
rg -l "apks?" config.* || true
rg -l "packages?" config.* || true

# Check for other scripts using apk
echo "Checking other apk usage patterns..."
rg "apk (add|update)" || true

Length of output: 1721


Script:

#!/bin/bash
# Check for config schema
echo "Checking for config schema..."
fd config.json --exec cat {} \;

# Check for documentation
echo -e "\nChecking documentation..."
fd "DOCS.md|README.md" --exec cat {} \;

# Check for other security measures
echo -e "\nChecking for security measures..."
rg -i "security|validation|sanitiz|restrict" ssh/

Length of output: 168273


Script:

#!/bin/bash
# Check for package validation in config files
echo "Checking config files..."
fd "config.json|config.yaml" ssh/ --exec cat {} \;

# Check for package restrictions in init scripts
echo -e "\nChecking init scripts..."
fd "^init" ssh/ --exec cat {} \;

# Check for any package-related security measures
echo -e "\nChecking for package security patterns..."
rg -A 5 -B 5 "apk|package" ssh/

Length of output: 6356

vlc/rootfs/etc/s6-overlay/s6-rc.d/vlc/run (1)

Line range hint 9-13: Consider error handling for VLC startup

The script should handle potential VLC startup failures gracefully within the S6 supervision tree.

Consider adding error handling:

 # Run daemon
-exec cvlc -I http --no-dbus --extraintf telnet --http-host 127.0.0.1 --http-password "INGRESS" --telnet-password "${PASSWORD}" --aout=pulse
+if ! exec cvlc -I http --no-dbus --extraintf telnet --http-host 127.0.0.1 \
+  --http-password "INGRESS" --telnet-password "${PASSWORD}" --aout=pulse
+then
+  bashio::log.error "Failed to start VLC"
+  exit 1
+fi

Also, consider splitting the long command line for better readability.

openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-configure.sh (2)

Line range hint 7-11: Add error handling for ot-ctl commands

While the NAT64 configuration logic is correct, the script should handle potential failures of the ot-ctl commands to ensure robust operation.

Consider applying this improvement:

 if bashio::config.true 'nat64'; then
     bashio::log.info "Enabling NAT64."
-    ot-ctl nat64 enable
-    ot-ctl dns server upstream enable
+    if ! ot-ctl nat64 enable; then
+        bashio::log.error "Failed to enable NAT64"
+        exit 1
+    fi
+    if ! ot-ctl dns server upstream enable; then
+        bashio::log.error "Failed to enable DNS server upstream"
+        exit 1
+    fi
 fi

Line range hint 14-15: Improve TX power configuration robustness

While the TX power configuration is well-documented, consider these improvements:

  1. Add error handling for the ot-ctl command
  2. Consider making the TX power value configurable through add-on configuration

Here's a suggested implementation:

 # To avoid asymmetric link quality the TX power from the controller should not
 # exceed that of what other Thread routers devices typically use.
-ot-ctl txpower 6
+# Use configured TX power or default to 6
+TX_POWER="$(bashio::config 'tx_power' 6)"
+if ! ot-ctl txpower "${TX_POWER}"; then
+    bashio::log.error "Failed to set TX power to ${TX_POWER}"
+    exit 1
+fi
nginx_proxy/rootfs/etc/periodic/daily/check_certificate_renewal (1)

Line range hint 8-14: Add error handling and improve reliability

The certificate renewal check needs several improvements for better reliability and observability:

  1. Add error handling for critical operations
  2. Fix potential race conditions
  3. Improve variable quoting
  4. Enhance logging

Here's the suggested implementation:

 #!/command/with-contenv bashio
 # shellcheck shell=bash
 # ==============================================================================
 # Check certificate renewal
 # ==============================================================================
 
-CERTFILE=$(bashio::config 'certfile')
+if ! CERTFILE=$(bashio::config 'certfile'); then
+    bashio::log.error "Failed to retrieve certificate file configuration"
+    exit 1
+fi
 
-if [ ! -f /tmp/certificate_timestamp ] || [[ $(stat "/ssl/${CERTFILE}" -c %y) != $(cat /tmp/certificate_timestamp) ]]; then
-  bashio::log.info "Reloading nginx to reload new certificate file"
-  stat "/ssl/${CERTFILE}" -c %y > /tmp/certificate_timestamp
-  nginx -c /etc/nginx.conf -s reload
+# Check if certificate file exists
+if [ ! -f "/ssl/${CERTFILE}" ]; then
+    bashio::log.error "Certificate file /ssl/${CERTFILE} not found"
+    exit 1
+fi
+
+# Get current certificate timestamp
+CERT_TIME=$(stat "/ssl/${CERTFILE}" -c %y) || {
+    bashio::log.error "Failed to get certificate timestamp"
+    exit 1
+}
+
+# Check if certificate was renewed
+if [ ! -f /tmp/certificate_timestamp ] || [[ "${CERT_TIME}" != "$(cat /tmp/certificate_timestamp 2>/dev/null)" ]]; then
+    bashio::log.info "Certificate renewal detected for ${CERTFILE}"
+    
+    # Update timestamp first to prevent repeated reloads on failure
+    echo "${CERT_TIME}" > /tmp/certificate_timestamp || {
+        bashio::log.error "Failed to update certificate timestamp"
+        exit 1
+    }
+    
+    # Reload nginx
+    if ! nginx -c /etc/nginx.conf -s reload; then
+        bashio::log.error "Failed to reload nginx"
+        exit 1
+    fi
+    
+    bashio::log.info "Successfully reloaded nginx with renewed certificate"
 fi

Key improvements:

  1. Added error handling for config retrieval, file operations, and nginx reload
  2. Improved timestamp file race condition handling
  3. Added proper quoting for variables
  4. Enhanced logging for better observability
  5. Updated timestamp file before nginx reload to prevent repeated reloads on failure
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (1)

Line range hint 13-17: Enhance error handling and logging.

The current implementation discards the actual error details by redirecting output to /dev/null. Consider capturing and logging the specific error message for better debugging.

Here's a suggested improvement:

-if bashio::discovery "otbr" "${config}" > /dev/null; then
+if output=$(bashio::discovery "otbr" "${config}" 2>&1); then
     bashio::log.info "Successfully sent discovery information to Home Assistant."
 else
-    bashio::log.error "Discovery message to Home Assistant failed!"
+    bashio::log.error "Discovery message to Home Assistant failed: ${output}"
+    exit 1
 fi
vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery (2)

Line range hint 8-13: Consider adding error handling for password file access

The script reads the password directly from /data/secret without checking if the file exists or is readable. This could lead to silent failures or unclear error messages.

Consider adding error handling:

 # Prepare discovery payload
+if [[ ! -r /data/secret ]]; then
+    bashio::log.error "Cannot read password file: /data/secret"
+    exit 1
+fi
+
 ha_config=$(\
     bashio::var.json \
         host "$(hostname)" \
         port "^4212" \
         password "$(cat /data/secret)" \
 )

Line range hint 15-19: Consider adding specific error details for discovery failures

While the script logs discovery status, it doesn't provide specific error details when the discovery fails, which could make troubleshooting difficult.

Consider capturing and logging the specific error:

-if bashio::discovery "vlc_telnet" "${ha_config}" > /dev/null; then
+if output=$(bashio::discovery "vlc_telnet" "${ha_config}" 2>&1); then
     bashio::log.info "Successfully send discovery information to Home Assistant."
 else
-    bashio::log.error "Discovery message to Home Assistant failed!"
+    bashio::log.error "Discovery message to Home Assistant failed: ${output}"
+    exit 1
 fi
openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (2)

Line range hint 15-19: Consider enhancing error handling

The error handling could be more robust by:

  1. Capturing and logging specific error details
  2. Setting an appropriate exit code on failure

Consider this enhancement:

+# Send discovery info with enhanced error handling
+if ! discovery_output=$(bashio::discovery "otbr" "${config}" 2>&1); then
+    bashio::log.error "Discovery message to Home Assistant failed: ${discovery_output}"
+    exit 1
+fi
+bashio::log.info "Successfully sent discovery information to Home Assistant."
-# Send discovery info
-if bashio::discovery "otbr" "${config}" > /dev/null; then
-    bashio::log.info "Successfully sent discovery information to Home Assistant."
-else
-    bashio::log.error "Discovery message to Home Assistant failed!"
-fi

The search results reveal that the caret prefix (^) in the port value is unique to the discovery scripts and not used in any other port configurations. In fact, the otbr-agent/run scripts explicitly enforce port 8081 without any prefix. This inconsistency, combined with the lack of error handling for the firmware version command, warrants a response.

Port format is incorrect and firmware version needs error handling

The port value should not include the caret prefix as it's inconsistent with other port configurations in the codebase. Additionally, the firmware version command needs error handling.

 config=$(bashio::var.json \
     host "$(bashio::addon.hostname)" \
-    port "^8081" \
+    port "8081" \
     device "$(bashio::config 'device')" \
-    firmware "$(ot-ctl rcp version | head -n 1)" \
+    firmware "$(ot-ctl rcp version | head -n 1 || echo 'unknown')" \
 )
  • The caret prefix in port value is inconsistent with usage in:
    • otbr-agent/run which uses plain "8081"
    • enable-check.sh which uses port without prefix
  • Added fallback to 'unknown' when firmware version command fails
🔗 Analysis chain

Line range hint 8-13: Verify the port value format and add error handling for firmware version

A few concerns in the configuration setup:

  1. The port value contains a caret prefix (^8081) which seems unusual. Verify if this is intentional.
  2. The firmware version command should include error handling.

Consider this improved implementation:

 config=$(bashio::var.json \
     host "$(bashio::addon.hostname)" \
-    port "^8081" \
+    port "8081" \
     device "$(bashio::config 'device')" \
-    firmware "$(ot-ctl rcp version | head -n 1)" \
+    firmware "$(ot-ctl rcp version | head -n 1 || echo 'unknown')" \
 )

Let's verify the port format usage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of port configuration to verify the format
rg -g '!*.{md,txt}' -A 2 -B 2 'port.*8081'

Length of output: 5204

zwave_js/rootfs/etc/services.d/zwave_js/run (2)

Line range hint 20-22: Consider more robust argument handling

While disabling SC2086 is valid here since word splitting is intended for --mock-driver, the argument handling could be more robust.

Consider this safer approach:

-# shellcheck disable=SC2086
-exec zwave-server ${SERIAL_DEVICE} --config /etc/zwave_config.json --disable-dns-sd
+if bashio::config.true 'emulate_hardware'; then
+    exec zwave-server --mock-driver --config /etc/zwave_config.json --disable-dns-sd
+else
+    exec zwave-server "${SERIAL_DEVICE}" --config /etc/zwave_config.json --disable-dns-sd
+fi

This eliminates the need for word splitting while properly handling both cases.


Line range hint 13-13: Add error handling for discovery process

While discovery failure shouldn't stop the main service, adding error handling would improve debuggability.

Consider this enhancement:

-./discovery &
+if ! ./discovery & then
+    bashio::log.warning "Failed to send discovery information to Home Assistant"
+fi
mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/finish (1)

Line range hint 16-24: Consider adding error handling for the unlock operation

While the script logs the completion, it doesn't verify if the unlock operation succeeded. Consider adding error handling to ensure the command was executed successfully.

Here's a suggested improvement:

# File descriptor &4 is used as stdin for mysql, because &0 is closed after the mariadb-lock-core service is started
# shellcheck disable=SC2086
-echo "UNLOCK TABLES;" > /proc/${MARIADB_LOCK_CORE_PID}/fd/4
+if ! echo "UNLOCK TABLES;" > /proc/${MARIADB_LOCK_CORE_PID}/fd/4; then
+    bashio::log.error "Failed to send unlock command to MariaDB"
+    bashio::exit.nok
+fi

bashio::log.info "MariaDB tables unlocked"
mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/run (2)

9-13: Enhance process validation for better reliability

While the current PID validation is good, consider adding these additional checks for more robust error handling:

 # shellcheck disable=SC2086
+if ! s6-svok "/run/service/mariadb-lock-core"; then
+    bashio::log.error "mariadb-lock-core service does not exist"
+    bashio::exit.nok
+fi
+
 if bashio::var.equals ${MARIADB_LOCK_CORE_PID} -1; then
     bashio::log.error "Invalid mariadb-lock-core process id ${MARIADB_LOCK_CORE_PID}"
     bashio::exit.nok
+elif ! kill -0 "${MARIADB_LOCK_CORE_PID}" 2>/dev/null; then
+    bashio::log.error "Process ${MARIADB_LOCK_CORE_PID} is not running"
+    bashio::exit.nok
 fi

19-19: Enhance logging for better observability

Consider making the log message more informative for debugging purposes:

-bashio::log.info "MariaDB tables locked"
+bashio::log.info "MariaDB tables locked for backup (lock-core PID: ${MARIADB_LOCK_CORE_PID})"
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-enable-check.sh (2)

Line range hint 7-14: Add error handling for service removal operations.

While the logic is correct, the script could benefit from more robust error handling when removing service entries.

Consider adding checks and error handling:

 if bashio::config.false 'otbr_enable'; then
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-agent
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-agent-rest-discovery
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/mdns
+    for service in otbr-agent otbr-web otbr-agent-rest-discovery mdns; do
+        service_path="/etc/s6-overlay/s6-rc.d/user/contents.d/${service}"
+        if [[ -e "${service_path}" ]]; then
+            if ! rm "${service_path}"; then
+                bashio::log.warning "Failed to remove ${service} service entry"
+            fi
+        fi
+    done
     bashio::log.info "The otbr-agent is disabled."
     bashio::exit.ok
 fi

Line range hint 16-22: Improve readability and error handling for port check logic.

While the port check logic is correct, the code could benefit from improved readability and error handling.

Consider these improvements:

-if bashio::var.has_value "$(bashio::addon.port 8080)" \
-     && bashio::var.has_value "$(bashio::addon.port 8081)"; then
+if ( bashio::var.has_value "$(bashio::addon.port 8080)" && 
+     bashio::var.has_value "$(bashio::addon.port 8081)" ); then
     bashio::log.info "Web UI and REST API port are exposed, starting otbr-web."
 else
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web
+    service_path="/etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web"
+    if [[ -e "${service_path}" ]]; then
+        if ! rm "${service_path}"; then
+            bashio::log.warning "Failed to remove otbr-web service entry"
+        fi
+    fi
     bashio::log.info "The otbr-web is disabled."
 fi
mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/run (1)

14-15: Consider using s6-env or s6-envdir for environment variable management

While the current implementation using cat with here-strings works, S6 provides dedicated tools for environment management that might be more appropriate.

Consider using either:

-cat <<<"${MARIADB_DATA}" > /var/run/s6/container_environment/MARIADB_DATA
-cat <<<"${NEW_INSTALL}" > /var/run/s6/container_environment/NEW_INSTALL
+s6-env -i MARIADB_DATA="${MARIADB_DATA}" NEW_INSTALL="${NEW_INSTALL}"

Or creating an envdir:

+mkdir -p /var/run/s6/container_environment
+echo -n "${MARIADB_DATA}" > /var/run/s6/container_environment/MARIADB_DATA
+echo -n "${NEW_INSTALL}" > /var/run/s6/container_environment/NEW_INSTALL
deconz/rootfs/etc/services.d/otau-ikea/run (3)

Line range hint 8-9: Add error handling for directory creation

The mkdir command should include error handling to ensure the service fails gracefully if directory creation fails (e.g., due to permissions or disk space issues).

-mkdir -p "/data/otau"
+if ! mkdir -p "/data/otau"; then
+    bashio::log.error "Failed to create OTAU directory"
+    exec sleep 18000
+fi

Line range hint 11-15: Enhance error handling and add timeout

The curl command should include a timeout to prevent hanging, and the error logging should provide more context about the failure.

-if ! IKEA_DATA="$(curl -sL ${URL_IKEA})"; then
-    bashio::log.info "Can't fetch data from ikea!"
+if ! IKEA_DATA="$(curl -sL --max-time 30 "${URL_IKEA}")"; then
+    bashio::log.error "Failed to fetch IKEA firmware data: $(curl -sL --max-time 30 -w '%{http_code}' -o /dev/null "${URL_IKEA}")"

Line range hint 17-29: Add validation and disk space checks

The firmware download process could be more robust with these improvements:

  1. Check available disk space before downloading
  2. Validate downloaded files
  3. Use atomic downloads to prevent partial files
+    # Check available space (assuming average firmware size of 100MB)
+    if [[ $(df -P "/data" | awk 'NR==2 {print $4}') -lt 102400 ]]; then
+        bashio::log.error "Insufficient disk space for firmware download"
+        continue
+    fi
+
-    curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}"
+    # Download to temporary file first
+    if ! curl -s -L -o "${OTAU_FILE}.tmp" "${OTAU_URL}"; then
+        bashio::log.error "Failed to download firmware from ${OTAU_URL}"
+        rm -f "${OTAU_FILE}.tmp"
+        continue
+    fi
+
+    # Move to final location
+    mv "${OTAU_FILE}.tmp" "${OTAU_FILE}"
openthread_border_router/rootfs/etc/s6-overlay/scripts/enable-check.sh (2)

Line range hint 3-13: Enhance error handling and logging for service management

While the port check logic is correct, consider these improvements for better robustness and troubleshooting:

  1. Add error handling for the rm command
  2. Log the specific ports that are unavailable
  3. Consider using safe-rm or checking file existence before removal
 if bashio::var.has_value "$(bashio::addon.port 8080)" \
      && bashio::var.has_value "$(bashio::addon.port 8081)"; then
     bashio::log.info "Web UI and REST API port are exposed, starting otbr-web."
 else
-    rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web
-    bashio::log.info "The otbr-web is disabled."
+    SERVICE_FILE="/etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web"
+    if [ -f "$SERVICE_FILE" ]; then
+        if rm "$SERVICE_FILE"; then
+            bashio::log.info "The otbr-web service is disabled (ports 8080/8081 not exposed)."
+        else
+            bashio::log.error "Failed to disable otbr-web service"
+            exit 1
+        fi
+    fi
 fi

Line range hint 15-22: Improve service enablement robustness and documentation

The service enablement logic should include error handling and better documentation of service dependencies.

 if bashio::config.has_value 'network_device'; then
-    touch /etc/s6-overlay/s6-rc.d/user/contents.d/socat-otbr-tcp
-    touch /etc/s6-overlay/s6-rc.d/otbr-agent/dependencies.d/socat-otbr-tcp
-    bashio::log.info "Enabled socat-otbr-tcp."
+    # Define service files
+    CONTENTS_FILE="/etc/s6-overlay/s6-rc.d/user/contents.d/socat-otbr-tcp"
+    DEPS_FILE="/etc/s6-overlay/s6-rc.d/otbr-agent/dependencies.d/socat-otbr-tcp"
+    
+    # Create service files with error handling
+    if ! touch "$CONTENTS_FILE" 2>/dev/null || ! touch "$DEPS_FILE" 2>/dev/null; then
+        bashio::log.error "Failed to enable socat-otbr-tcp service"
+        exit 1
+    fi
+    
+    bashio::log.info "Enabled socat-otbr-tcp service for network device: $(bashio::config 'network_device')"
 fi
samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish (2)

Line range hint 6-10: Consider separating variable declarations and assignments

While disabling SC2155 works, it's better to separate declarations and assignments to catch potential errors. This is especially important when reading from files that might not exist.

Consider this safer approach:

-# shellcheck disable=SC2155
-readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
-readonly exit_code_service="${1}"
-readonly exit_code_signal="${2}"
-readonly service="nmbd"
+declare -r service="nmbd"
+declare -r exit_code_service="${1}"
+declare -r exit_code_signal="${2}"
+
+if [[ ! -f /run/s6-linux-init-container-results/exitcode ]]; then
+    bashio::log.error "Container exitcode file not found"
+    exit 1
+fi
+declare -r exit_code_container
+exit_code_container=$(</run/s6-linux-init-container-results/exitcode)

Line range hint 17-25: Consider improving exit code handling robustness

While the logic is correct, there are a few improvements that could make the code more robust and maintainable:

  1. The magic number 256 should be documented
  2. File writes should include error handling
  3. The halt command execution could benefit from logging

Consider these improvements:

+# Exit code 256 indicates the process was terminated by a signal
 if [[ "${exit_code_service}" -eq 256 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
-    echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
+    if ! echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode; then
+      bashio::log.error "Failed to update container exit code"
+    fi
   fi
-  [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
+  if [[ "${exit_code_signal}" -eq 15 ]]; then
+    bashio::log.info "Halting container due to SIGTERM"
+    exec /run/s6/basedir/bin/halt
+  fi
 elif [[ "${exit_code_service}" -ne 0 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
-    echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
+    if ! echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode; then
+      bashio::log.error "Failed to update container exit code"
+    fi
   fi
+  bashio::log.info "Halting container due to service failure"
   exec /run/s6/basedir/bin/halt
 fi
samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish (2)

Line range hint 6-10: Consider separating variable declarations from assignments

While using readonly is good practice, combining declaration with assignment can mask command failures. Consider separating them:

-# shellcheck disable=SC2155
-readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
-readonly exit_code_service="${1}"
-readonly exit_code_signal="${2}"
-readonly service="smbd"
+exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
+exit_code_service="${1}"
+exit_code_signal="${2}"
+service="smbd"
+readonly exit_code_container exit_code_service exit_code_signal service

This approach:

  • Removes the need for shellcheck disable
  • Makes command failures more visible
  • Still maintains the immutability of variables

Line range hint 17-24: Consider adding comments to explain the exit code logic

While the implementation is correct, the exit code handling logic is complex and would benefit from documentation explaining:

  • Why exit code 256 gets special handling
  • The significance of signal 15 (SIGTERM)
  • The conditions for propagating exit codes to the container
+# Exit code 256 indicates process terminated by signal
 if [[ "${exit_code_service}" -eq 256 ]]; then
   if [[ "${exit_code_container}" -eq 0 ]]; then
+    # Convert signal to standard exit code format (128 + signal number)
     echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
   fi
+  # Halt only if terminated by SIGTERM (15)
   [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
 elif [[ "${exit_code_service}" -ne 0 ]]; then
+  # For other non-zero exits, propagate the exact exit code and always halt
   if [[ "${exit_code_container}" -eq 0 ]]; then
     echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
   fi
   exec /run/s6/basedir/bin/halt
 fi
mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-core/finish (2)

Line range hint 6-10: LGTM with a minor suggestion for improvement.

The variable declarations are well-structured and properly marked as readonly. However, consider extracting the hardcoded service name to a common configuration file for better maintainability.

-readonly service="mariadb"
+# Source from a common config file
+readonly service="$(bashio::addon.name)"

Signal handling inconsistency detected across service finish scripts

The analysis reveals inconsistent signal handling patterns across the repository's finish scripts:

  • Some services (whisper, piper, openwakeword, samba, nginx_proxy, mariadb-core, assist_microphone, duckdns, configurator) implement complete signal handling with:

    • Exit code 256 handling
    • SIGTERM (15) handling with halt execution
    • Signal conversion (128 + signal)
  • Other services lack these signal handling mechanisms entirely, which could lead to inconsistent behavior during service termination.

Recommendation: Standardize signal handling across all service finish scripts by implementing the complete pattern shown in mariadb-core/finish.

🔗 Analysis chain

Line range hint 18-24: Verify the signal handling logic across different scenarios.

The exit code handling looks correct, but let's verify the signal handling logic across different services to ensure consistent behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify signal handling consistency across service finish scripts
# Expected: All finish scripts should handle signals similarly

# Find all finish scripts in s6-rc.d directories
echo "Analyzing signal handling in finish scripts..."
fd --type f "finish$" --exec sh -c '
    echo "\nAnalyzing: {}"
    # Check for signal handling patterns
    echo "Exit code 256 handling:"
    rg -A 2 "exit_code_service.+256" "{}" || echo "No explicit 256 handling"
    echo "Signal 15 (SIGTERM) handling:"
    rg "exit_code_signal.+15" "{}" || echo "No explicit SIGTERM handling"
    echo "128 + signal conversion:"
    rg "128.+exit_code_signal" "{}" || echo "No signal conversion"
'

Length of output: 11447

rpc_shutdown/data/run.sh (4)

1-3: Consider enhancing error handling for this critical script

While set -e provides basic error handling, for a script managing system shutdowns, consider adding:

 #!/usr/bin/with-contenv bashio
 # shellcheck shell=bash
 set -e
+set -o pipefail
+
+# Trap errors and exit gracefully
+trap 'bashio::log.error "Unexpected error in shutdown script"; exit 1' ERR

Line range hint 5-9: Add input validation to handle edge cases

The current implementation might be vulnerable to malformed input. Consider adding validation:

 # Read from STDIN aliases to send shutdown
 while read -r input; do
+    # Skip empty lines
+    [[ -z "${input}" ]] && continue
+
+    # Validate JSON format
+    if ! bashio::jq "${input}" '.' >/dev/null 2>&1; then
+        bashio::log.error "Invalid JSON input: ${input}"
+        continue
+    fi
+
     # parse JSON value
     input=$(bashio::jq "${input}" '.')
     bashio::log.info "Read alias: $input"

Line range hint 11-17: Add validation for critical configuration values

The script should validate required configuration values before proceeding with the shutdown:

     for computer in $(bashio::config 'computers|keys'); do
         ALIAS=$(bashio::config "computers[${computer}].alias")
         ADDRESS=$(bashio::config "computers[${computer}].address")
         CREDENTIALS=$(bashio::config "computers[${computer}].credentials")
         DELAY=$(bashio::config "computers[${computer}].delay")
         MESSAGE=$(bashio::config "computers[${computer}].message")
+
+        # Validate required fields
+        if bashio::var.is_empty "${ADDRESS}" || bashio::var.is_empty "${CREDENTIALS}"; then
+            bashio::log.error "Missing required configuration for computer ${computer}"
+            continue
+        fi

Line range hint 19-33: Enhance shutdown command execution and error handling

The shutdown command execution could be safer and more informative:

-        if ! msg="$(net rpc shutdown -I "$ADDRESS" -U "$CREDENTIALS" -t "$DELAY" -C "$MESSAGE")"; then
-            bashio::log.error "Shutdown failed: $msg"
+        # Validate delay is a positive number
+        if ! [[ "$DELAY" =~ ^[0-9]+$ ]]; then
+            bashio::log.error "Invalid delay value for ${ALIAS}: ${DELAY}"
+            continue
+        fi
+
+        bashio::log.info "Initiating shutdown for ${ALIAS} (${ADDRESS}) with ${DELAY}s delay"
+        if ! msg="$(net rpc shutdown -I "$ADDRESS" -U "$CREDENTIALS" -t "$DELAY" -C "$MESSAGE" 2>&1)"; then
+            bashio::log.error "Shutdown failed for ${ALIAS} (${ADDRESS}): ${msg}"
+            continue
         fi
+        bashio::log.info "Shutdown command sent successfully to ${ALIAS}"
google_assistant/rootfs/etc/services.d/google-assistant/run (2)

Line range hint 14-18: Consider setting secure file permissions for client secrets

While the file copying logic is correct, sensitive files like client secrets should have restricted permissions to prevent unauthorized access.

Consider adding permission setting after copying:

 if bashio::fs.file_exists "/share/${CLIENT_SECRETS}"; then
     bashio::log.info "Installing/Updating service client_secrets file"
     cp -f "/share/${CLIENT_SECRETS}" "${CLIENT_JSON}"
+    chmod 600 "${CLIENT_JSON}"
 fi

Line range hint 20-24: Consider adding JSON validation for client secrets

While the file existence checks are good, validating the JSON content would prevent runtime errors if the file is malformed.

Consider adding JSON validation:

 if ! bashio::fs.file_exists "${CRED_JSON}" && bashio::fs.file_exists "${CLIENT_JSON}"; then
+    if ! jq -e . "${CLIENT_JSON}" >/dev/null 2>&1; then
+        bashio::exit.nok "Client secrets file is not valid JSON!"
+    fi
     bashio::log.info "Starting WebUI for handling OAuth2..."
     python3 /usr/bin/hassio_oauth.py "${CLIENT_JSON}" "${CRED_JSON}"
 elif ! bashio::fs.file_exists "${CRED_JSON}"; then
     bashio::exit.nok "You need initialize Google Assistant with a client secret JSON!"
 fi
configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/run (2)

Line range hint 12-27: Consider adding error handling for SSH operations.

While the script handles missing key files, it doesn't check for failures in SSH agent startup or key addition operations. These operations could fail in various scenarios (permissions issues, invalid keys, etc.).

Consider adding error handling:

 # Start the SSH agent
 bashio::log.info "Starting SSH agent"
-eval "$(ssh-agent -s)"
+if ! eval "$(ssh-agent -s)"; then
+    bashio::log.error "Failed to start SSH agent"
+    exit 1
+fi

 # Add the keys defined in the configuration options
 while read -r filename; do
   if bashio::fs.file_exists "${filename}"; then
     bashio::log.info "Adding SSH private key file \"${filename}\""
-    ssh-add -q "${filename}"
+    if ! ssh-add -q "${filename}"; then
+        bashio::log.error "Failed to add SSH key ${filename}"
+        # Continue with other keys instead of failing completely
+    fi
   else
     bashio::log.error "SSH key file \"${filename}\" not found"
   fi
 done <<< "$(bashio::config 'ssh_keys')"

Line range hint 36-36: Add configuration file validation before execution.

The script should verify that the configuration file exists before attempting to execute the service.

Consider adding this check:

+if ! bashio::fs.file_exists "/etc/configurator.conf"; then
+    bashio::log.error "Configuration file /etc/configurator.conf not found"
+    exit 1
+fi
 exec hass-configurator /etc/configurator.conf
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/cpcd-config-up (4)

Line range hint 10-19: Add device path validation

While the configuration checks are good, the script should validate that the device path exists before proceeding.

Add this validation after the device path is determined:

 if bashio::config.has_value 'network_device'; then
     device="/tmp/ttyCPC"
 fi
+
+if [ ! -e "$device" ]; then
+    bashio::log.fatal "Device path ${device} does not exist!"
+    bashio::exit.nok
+fi

Line range hint 21-29: Add baudrate validation

The script should validate that the baudrate is a positive integer to prevent configuration errors.

Add this validation after the baudrate is determined:

 elif bashio::config.has_value 'baudrate'; then
     baudrate=$(bashio::config 'baudrate')
 else
     bashio::log.fatal "No serial port baudrate set!"
     bashio::exit.nok
 fi
+
+if ! [[ "$baudrate" =~ ^[0-9]+$ ]] || [ "$baudrate" -le 0 ]; then
+    bashio::log.fatal "Invalid baudrate: ${baudrate}. Must be a positive integer!"
+    bashio::exit.nok
+fi

Line range hint 31-41: Refactor boolean config handling and add validation

The boolean configuration handling is duplicated and lacks validation.

Consider refactoring using a helper function:

+# Helper function to get boolean config with validation
+get_boolean_config() {
+    local key=$1
+    local value
+    
+    if ! bashio::config.has_value "$key"; then
+        echo "false"
+        return
+    fi
+    
+    value=$(bashio::config "$key")
+    if [ "$value" != "true" ] && [ "$value" != "false" ]; then
+        bashio::log.fatal "Invalid value for ${key}: ${value}. Must be 'true' or 'false'!"
+        bashio::exit.nok
+    fi
+    echo "$value"
+}
+
-if  ! bashio::config.has_value 'flow_control'; then
-    flow_control="false"
-else
-    flow_control=$(bashio::config 'flow_control')
-fi
+flow_control=$(get_boolean_config 'flow_control')
 
-if  ! bashio::config.has_value 'cpcd_trace'; then
-    cpcd_trace="false"
-else
-    cpcd_trace=$(bashio::config 'cpcd_trace')
-fi
+cpcd_trace=$(get_boolean_config 'cpcd_trace')

Line range hint 43-51: Add template file validation

The script should verify that the template file exists before attempting to use it.

Add this validation before the configuration generation:

 bashio::log.info "Generating cpcd configuration."
+
+template_file="/usr/local/share/cpcd.conf"
+if [ ! -f "$template_file" ]; then
+    bashio::log.fatal "Template file ${template_file} not found!"
+    bashio::exit.nok
+fi
+
 bashio::var.json \
     device "${device}" \
     baudrate "${baudrate}" \
     flow_control "${flow_control}" \
     cpcd_trace "${cpcd_trace}" \
     | tempio \
-        -template /usr/local/share/cpcd.conf \
+        -template "$template_file" \
         -out /usr/local/etc/cpcd.conf
ssh/rootfs/etc/cont-init.d/profile.sh (4)

Line range hint 8-12: Add error handling for file operations.

While the implementation is secure with proper permissions, it could be more robust.

Consider this improved implementation:

 if ! bashio::fs.file_exists /data/.bash_history; then
-    touch /data/.bash_history
+    touch /data/.bash_history || bashio::exit.nok "Failed to create .bash_history"
 fi
-chmod 600 /data/.bash_history
+chmod 600 /data/.bash_history || bashio::exit.nok "Failed to set permissions on .bash_history"
+
+# Validate permissions even if file existed
+if [[ "$(stat -c %a /data/.bash_history)" != "600" ]]; then
+    chmod 600 /data/.bash_history || bashio::exit.nok "Failed to correct permissions on .bash_history"
+fi

Line range hint 29-33: Enhance symlink creation robustness.

While the error handling is good, the symlink creation could be more robust.

Consider this improved implementation:

 for dir in "${DIRECTORIES[@]}"; do
+    # Verify source directory exists
+    if ! bashio::fs.directory_exists "/${dir}"; then
+        bashio::log.warning "Source directory /${dir} does not exist"
+        continue
+    fi
+    
+    # Handle existing symlink
+    if [[ -L "${HOME}/${dir}" ]]; then
+        rm "${HOME}/${dir}" || bashio::log.warning "Failed to remove existing symlink: ${HOME}/${dir}"
+    fi
+    
     ln -s "/${dir}" "${HOME}/${dir}" \
-        || bashio::log.warning "Failed linking common directory: ${dir}"
+        || bashio::log.warning "Failed linking /${dir} to ${HOME}/${dir}"
 done

Line range hint 35-40: Document legacy symlinks and enhance robustness.

Similar improvements as suggested for directory symlinks would be beneficial here.

Consider adding a code comment explaining which documentation these symlinks support:

-# Some links to "old" locations, to match documentation,
-# backwards compatibility and musle memory
+# Legacy symlinks for backwards compatibility with:
+# - Historical Home Assistant documentation prior to <version/date>
+# - User muscle memory from previous installations
+# - Third-party add-ons that might rely on these paths

Security improvements needed for SUPERVISOR_TOKEN handling

The verification reveals several security concerns:

  • The template file exposes the token as a plain environment variable
  • No explicit permissions are set for /etc/profile.d directory or the generated profile script
  • Other sensitive files in the addon have proper 600/700 permissions set, but this one is missing

Required changes:

  • Set restrictive permissions (644) on the generated /etc/profile.d/homeassistant.sh
  • Set proper directory permissions (755) on /etc/profile.d
  • Add error handling for failed operations
  • Consider moving the token to a more secure location than profile.d

The original review comment's concerns are valid and the suggested security measures should be implemented.

🔗 Analysis chain

Line range hint 14-20: Verify secure handling of SUPERVISOR_TOKEN.

The script handles sensitive token data but needs additional security measures.

Let's verify the template and file permissions:

Consider adding these security measures:

 # Make Home Assistant TOKEN available on the CLI
-mkdir -p /etc/profile.d
+mkdir -p /etc/profile.d || bashio::exit.nok "Failed to create profile.d directory"
+chmod 755 /etc/profile.d || bashio::exit.nok "Failed to set profile.d permissions"
 bashio::var.json \
     supervisor_token "${SUPERVISOR_TOKEN}" \
     | tempio \
         -template /usr/share/tempio/homeassistant.profile \
-        -out /etc/profile.d/homeassistant.sh
+        -out /etc/profile.d/homeassistant.sh \
+    || bashio::exit.nok "Failed to generate profile script"
+chmod 644 /etc/profile.d/homeassistant.sh || bashio::exit.nok "Failed to set profile permissions"

Let me search for the template file in the repository first.


Let me check the content of the template file and look for any existing permission settings in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check template content
if [ -f /usr/share/tempio/homeassistant.profile ]; then
    echo "Template content:"
    cat /usr/share/tempio/homeassistant.profile
else
    echo "Template file not found!"
fi

# Check output file permissions
if [ -f /etc/profile.d/homeassistant.sh ]; then
    echo "Output file permissions:"
    ls -l /etc/profile.d/homeassistant.sh
else
    echo "Output file not found!"
fi

Length of output: 211


Script:

#!/bin/bash
# Search for homeassistant.profile template
fd homeassistant.profile

# Search for any tempio templates
fd -e profile

# Check the SSH addon directory structure
ls -R ssh/

Length of output: 807


Script:

#!/bin/bash
# Check template content
cat ssh/rootfs/usr/share/tempio/homeassistant.profile

# Check for permission settings in Dockerfile or init scripts
echo "=== Dockerfile permissions ==="
rg "chmod|chown" ssh/Dockerfile

echo "=== Init scripts permissions ==="
rg "chmod|chown" ssh/rootfs/etc/cont-init.d/

Length of output: 761

samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run (5)

Line range hint 9-12: Consider enhancing the error message specificity.

While the validation is correct, the error message could be more specific about which required field(s) are missing.

-    bashio::exit.nok "Setting a username and password is required!"
+    if ! bashio::config.has_value 'username'; then
+        bashio::exit.nok "Username is required but not set!"
+    fi
+    bashio::exit.nok "Password is required but not set!"

Line range hint 14-19: Enhance the warning message for hostname fallback.

The warning message could provide more context about using the default hostname.

-    bashio::log.warning "Can't read hostname, using default."
+    bashio::log.warning "Unable to read hostname from API, falling back to default: 'hassio'"

Line range hint 21-27: Consider improving interface logging format.

The current interface logging might be hard to read if there are many interfaces. Consider formatting them one per line.

-bashio::log.info "Interfaces: $(printf '%s ' "${interfaces[@]}")"
+bashio::log.info "Detected interfaces:"
+for interface in "${interfaces[@]}"; do
+    bashio::log.info "  - ${interface}"
+done

Line range hint 29-33: Add error handling for configuration generation.

The configuration generation commands lack error handling, which could lead to silent failures.

-jq ".interfaces = $(jq -c -n '$ARGS.positional' --args -- "${interfaces[@]}")" /data/options.json \
+if ! jq ".interfaces = $(jq -c -n '$ARGS.positional' --args -- "${interfaces[@]}")" /data/options.json \
    | tempio \
      -template /usr/share/tempio/smb.gtpl \
-      -out /etc/samba/smb.conf
+      -out /etc/samba/smb.conf; then
+    bashio::exit.nok "Failed to generate Samba configuration"
+fi

Line range hint 35-42: Add error handling and improve password security.

The user initialization lacks error handling, and the password might be visible in the process list.

 username=$(bashio::config 'username')
 password=$(bashio::config 'password')
-addgroup "${username}"
-adduser -D -H -G "${username}" -s /bin/false "${username}"
+if ! addgroup "${username}"; then
+    bashio::exit.nok "Failed to create group ${username}"
+fi
+if ! adduser -D -H -G "${username}" -s /bin/false "${username}"; then
+    bashio::exit.nok "Failed to create user ${username}"
+fi

-echo "$password"; echo "$password") \
-    | smbpasswd -a -s -c "/etc/samba/smb.conf" "${username}"
+# Use file descriptor to avoid password exposure in process list
+exec 3<> <(:)
+echo "$password" >&3
+echo "$password" >&3
+if ! smbpasswd -a -s -c "/etc/samba/smb.conf" "${username}" <&3; then
+    exec 3>&-
+    bashio::exit.nok "Failed to set Samba password"
+fi
+exec 3>&-
deconz/rootfs/etc/services.d/otau-ledvance/run (4)

Line range hint 1-10: Add error handling for directory creation

While the initialization looks good, the mkdir command should include error handling to ensure the directory was created successfully.

-mkdir -p "/data/otau"
+if ! mkdir -p "/data/otau"; then
+    bashio::log.error "Failed to create OTAU directory"
+    exit 1
+fi

Line range hint 12-16: Enhance error handling and curl robustness

The error handling and curl configuration could be improved for better reliability:

  1. Add timeout to prevent hanging
  2. Add retry mechanism
  3. Use a configurable sleep duration
-if ! OSRAM_DATA="$(curl -sL ${URL_OSRAM})"; then
+# Define constants
+readonly MAX_RETRIES=3
+readonly CURL_TIMEOUT=30
+readonly FAILURE_SLEEP=18000
+
+# Retry logic for data fetching
+for ((retry=1; retry<=MAX_RETRIES; retry++)); do
+    if OSRAM_DATA="$(curl -sL --connect-timeout $CURL_TIMEOUT --max-time $((CURL_TIMEOUT * 2)) "${URL_OSRAM}")"; then
+        break
+    fi
+    bashio::log.warning "Failed to fetch data from OSRAM (attempt $retry/$MAX_RETRIES)"
+    [[ $retry -lt $MAX_RETRIES ]] && sleep $((retry * 10))
+done
+
+if [[ -z "${OSRAM_DATA}" ]]; then
     bashio::log.info "Can't fetch data from osram!"
-    exec sleep 18000
+    exec sleep "${FAILURE_SLEEP}"
 fi

Line range hint 18-35: Improve security and robustness of firmware processing

Several improvements could enhance the security and reliability:

  1. Quote variables in arithmetic operations
  2. Validate downloaded files
  3. Use atomic operations for downloads
  4. Add more comprehensive logging
-OSRAM_DATA_SIZE="$(echo "${OSRAM_DATA}" | jq --raw-output '.firmwares | length')"
-DL_DONE=0
-for (( i=0; i < "${OSRAM_DATA_SIZE}"; i++ )); do
+readonly OSRAM_DATA_SIZE="$(echo "${OSRAM_DATA}" | jq --raw-output '.firmwares | length')"
+if [[ ! "${OSRAM_DATA_SIZE}" =~ ^[0-9]+$ ]]; then
+    bashio::log.error "Invalid firmware data received"
+    exit 1
+fi
+
+DL_DONE=0
+for (( i=0; i < "${OSRAM_DATA_SIZE}"; i++ )); do
     OSRAM_COMPANY=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.company  // empty" 2>/dev/null)
     OSRAM_PRODUCT=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].identity.product  // empty" 2>/dev/null)
     OTAU_FILENAME=$( echo "${OSRAM_DATA}" | jq --raw-output ".firmwares[$i].name  // empty" 2>/dev/null)
+    
+    # Validate extracted data
+    if [[ -z "${OSRAM_COMPANY}" ]] || [[ -z "${OSRAM_PRODUCT}" ]] || [[ -z "${OTAU_FILENAME}" ]]; then
+        bashio::log.warning "Skipping invalid firmware entry at index $i"
+        continue
+    fi
+
     OTAU_URL="$URL_OSRAM/download/${OSRAM_COMPANY}/${OSRAM_PRODUCT}/latest"    
             
     OTAU_FILE="/data/otau/${OTAU_FILENAME}"
-    if [ -e "${OTAU_FILE}" ]; then
+    if [[ -e "${OTAU_FILE}" ]]; then
+        bashio::log.info "Firmware ${OTAU_FILENAME} already exists, skipping"
         continue
     fi
-    curl -s -L -o "${OTAU_FILE}" "${OTAU_URL}" || true
-    ((DL_DONE+1))
-    if [ "$((DL_DONE % 10))" == "0" ]; then
+
+    # Download to temporary file first
+    TEMP_FILE="${OTAU_FILE}.tmp"
+    if curl -s -L -o "${TEMP_FILE}" "${OTAU_URL}"; then
+        mv "${TEMP_FILE}" "${OTAU_FILE}"
+        bashio::log.info "Successfully downloaded ${OTAU_FILENAME}"
+        ((DL_DONE+=1))
+    else
+        bashio::log.warning "Failed to download ${OTAU_FILENAME}"
+        rm -f "${TEMP_FILE}"
+        continue
+    fi
+
+    if (( DL_DONE % 10 == 0 )); then
         # LEDVANCE/OSRAM API RateLimits : The rate limit 10 calls per 60 seconds or quota 100 MB per month.
         DL_DONE=0
+        bashio::log.info "Rate limit reached, pausing for 65 seconds"
         sleep 65
     fi
 done

Line range hint 37-37: Make service more configurable and handle shutdown gracefully

The service loop could be improved by:

  1. Making the sleep duration configurable
  2. Adding proper shutdown handling
-exec sleep 259200
+# Define update interval (default: 3 days)
+readonly UPDATE_INTERVAL=$(bashio::config 'update_interval' 259200)
+
+# Use trap to handle shutdown gracefully
+trap 'bashio::log.info "Shutting down OSRAM OTAU service..."; exit 0' TERM
+
+# Keep service alive
+exec sleep "${UPDATE_INTERVAL}"
mosquitto/rootfs/etc/services.d/mosquitto/discovery (2)

Line range hint 7-14: Add error handling for password retrieval

The script reads sensitive passwords but lacks error handling for file read operations. Consider:

  1. Checking if the system user file exists
  2. Validating that password values are not empty
  3. Using readonly for password variables to prevent accidental modification
 readonly SYSTEM_USER="/data/system_user.json"
 declare config
-declare discovery_password
-declare service_password
+declare -r discovery_password
+declare -r service_password
+
+# Verify system user file exists
+if ! bashio::fs.file_exists "${SYSTEM_USER}"; then
+    bashio::log.error "System user file not found: ${SYSTEM_USER}"
+    exit 1
+fi
 
 # Read the existing values
 discovery_password=$(bashio::jq "${SYSTEM_USER}" ".homeassistant.password")
 service_password=$(bashio::jq "${SYSTEM_USER}" ".addons.password")
+
+# Validate passwords
+if bashio::var.is_empty "${discovery_password}" || bashio::var.is_empty "${service_password}"; then
+    bashio::log.error "Failed to retrieve valid passwords from system user file"
+    exit 1
+fi

Line range hint 30-43: Consider refactoring duplicate configuration logic

The service configuration is nearly identical to the discovery configuration. Consider extracting the common configuration into a function.

+# Create MQTT configuration with specific credentials
+mqtt_config() {
+    local username=$1
+    local password=$2
+    bashio::var.json \
+        host "$(hostname)" \
+        port "^1883" \
+        ssl "^false" \
+        protocol "3.1.1" \
+        username "${username}" \
+        password "${password}"
+}
+
 # Create discovery config payload for Home Assistant
-config=$(bashio::var.json \
-    host "$(hostname)" \
-    port "^1883" \
-    ssl "^false" \
-    protocol "3.1.1" \
-    username "homeassistant" \
-    password "${discovery_password}" \
-)
+config=$(mqtt_config "homeassistant" "${discovery_password}")

 # Send discovery info
 if bashio::discovery "mqtt" "${config}" > /dev/null; then
     bashio::log.info "Successfully send discovery information to Home Assistant."
 else
     bashio::log.error "Discovery message to Home Assistant failed!"
 fi

 # Create service config payload for other add-ons
-config=$(bashio::var.json \
-    host "$(hostname)" \
-    port "^1883" \
-    ssl "^false" \
-    protocol "3.1.1" \
-    username "addons" \
-    password "${service_password}" \
-)
+config=$(mqtt_config "addons" "${service_password}")
ssh/rootfs/etc/cont-init.d/ssh.sh (4)

1-2: Consider adding more shellcheck directives for improved maintainability

While the shell=bash directive is good, consider adding these commonly used directives for better maintainability:

 #!/usr/bin/with-contenv bashio
 # shellcheck shell=bash
+# shellcheck disable=SC1091 # Don't warn about not being able to source files
+# shellcheck enable=require-variable-braces # Enforce ${} usage

Line range hint 8-15: Improve error handling for directory operations

While the permissions are correctly set to 700, the error handling could be more specific.

 if ! bashio::fs.directory_exists /data/.ssh; then
-    mkdir -p /data/.ssh \
-        || bashio::exit.nok 'Failed to create a persistent .ssh folder'
+    mkdir -p /data/.ssh || bashio::exit.nok 'Failed to create a persistent .ssh folder'
 fi

-chmod 700 /data/.ssh \
-    || bashio::exit.nok \
-        'Failed setting permissions on persistent .ssh folder'
+chmod 700 /data/.ssh || bashio::exit.nok 'Failed setting permissions on persistent .ssh folder'

Line range hint 24-44: Security improvements needed in authentication setup

Several security considerations need to be addressed:

  1. Add validation for authorized_keys content
  2. Implement password strength requirements
  3. Improve error handling for password changes

Apply these improvements:

 if bashio::config.has_value 'authorized_keys'; then
     bashio::log.info "Setup authorized_keys"
 
     rm -f /data/.ssh/authorized_keys
     while read -r line; do
+        # Validate key format
+        if ! echo "$line" | ssh-keygen -l -f - >/dev/null 2>&1; then
+            bashio::exit.nok "Invalid SSH key found in authorized_keys"
+        fi
         echo "$line" >> /data/.ssh/authorized_keys
     done <<< "$(bashio::config 'authorized_keys')"
 
     chmod 600 /data/.ssh/authorized_keys
 
     # Unlock account
     PASSWORD="$(pwgen -s 64 1)"
-    echo "root:${PASSWORD}" | chpasswd 2&> /dev/null
+    echo "root:${PASSWORD}" | chpasswd || bashio::exit.nok "Failed to set random password"
 elif bashio::config.has_value 'password'; then
     bashio::log.info "Setup password login"
 
     PASSWORD=$(bashio::config 'password')
+    # Validate password strength
+    if [ ${#PASSWORD} -lt 8 ]; then
+        bashio::exit.nok "Password must be at least 8 characters long"
+    fi
-    echo "root:${PASSWORD}" | chpasswd 2&> /dev/null
+    echo "root:${PASSWORD}" | chpasswd || bashio::exit.nok "Failed to set user password"
 elif bashio::var.has_value "$(bashio::addon.port 22)"; then
     bashio::exit.nok "You need to setup a login!"
 fi

Line range hint 46-51: Enhance SSH config generation security and error handling

The SSH config generation needs better error handling and security controls.

-mkdir -p /etc/ssh
+mkdir -p /etc/ssh || bashio::exit.nok "Failed to create SSH config directory"
+chmod 755 /etc/ssh || bashio::exit.nok "Failed to set SSH config directory permissions"
 tempio \
     -conf /data/options.json \
     -template /usr/share/tempio/sshd_config \
-    -out /etc/ssh/sshd_config
+    -out /etc/ssh/sshd_config || bashio::exit.nok "Failed to generate SSH config"
+chmod 644 /etc/ssh/sshd_config || bashio::exit.nok "Failed to set SSH config permissions"
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (3)

Line range hint 11-20: Add timeout mechanism to prevent infinite loops

While the retry mechanism is good for handling kernel locks, it should include a timeout to prevent infinite loops.

 ipset_destroy_if_exist()
 {
     # The ipset seems to be in use by the kernel for a brief period,
     # retry destroying it
+    local attempts=0
+    local max_attempts=10
     while ipset list -n "$1" 2> /dev/null; do
+        ((attempts++))
+        if [ "$attempts" -ge "$max_attempts" ]; then
+            bashio::log.warning "Failed to destroy ipset $1 after $max_attempts attempts"
+            break
+        fi
         ipset destroy "$1" || true
+        sleep 0.5
     done
 }

Line range hint 21-38: Add error logging for failed operations

While the operations are properly sequenced, adding error logging would help with troubleshooting.

 while ip6tables -C FORWARD -o $thread_if -j $otbr_forward_ingress_chain 2> /dev/null; do
     # shellcheck disable=SC2086
-    ip6tables -D FORWARD -o $thread_if -j $otbr_forward_ingress_chain
+    if ! ip6tables -D FORWARD -o $thread_if -j $otbr_forward_ingress_chain; then
+        bashio::log.warning "Failed to delete ingress FORWARD rule"
+    fi
 done

Line range hint 54-67: Enhance signal and exit code logging

While the exit code handling is correct, consider adding more detailed logging for better diagnostics.

 if test "$1" -eq 256 ; then
+  bashio::log.debug "Received signal-based exit"
   e=$((128 + $2))
 else
   e="$1"
 fi

 if test "$e" -ne 0; then
-    bashio::log.warning "otbr-agent exited with code $e (by signal $2)."
+    bashio::log.warning "otbr-agent failed with exit code $e (signal: $2, original code: $1)"
     echo "$e" > /run/s6-linux-init-container-results/exitcode
+    bashio::log.info "Initiating container shutdown"
     exec /run/s6/basedir/bin/halt
 else
-    bashio::log.info "otbr-agent exited with code $e (by signal $2)."
+    bashio::log.info "otbr-agent completed successfully (exit: $e, signal: $2)"
 fi
dhcp_server/data/run.sh (6)

Line range hint 9-20: Add input validation and improve variable safety

The configuration values should be validated before use, and variables should be properly quoted in echo statements.

 # Create main config
 DEFAULT_LEASE=$(bashio::config 'default_lease')
+if ! [[ "${DEFAULT_LEASE}" =~ ^[0-9]+$ ]] || [ "${DEFAULT_LEASE}" -lt 60 ]; then
+    bashio::exit.nok "Invalid default lease time: ${DEFAULT_LEASE}"
+fi
+
 DOMAIN=$(bashio::config 'domain')
 MAX_LEASE=$(bashio::config 'max_lease')
+if ! [[ "${MAX_LEASE}" =~ ^[0-9]+$ ]] || [ "${MAX_LEASE}" -lt "${DEFAULT_LEASE}" ]; then
+    bashio::exit.nok "Invalid max lease time: ${MAX_LEASE}"
+fi
 
 {
-    echo "option domain-name \"${DOMAIN}\";"
-    echo "default-lease-time ${DEFAULT_LEASE};"
-    echo "max-lease-time ${MAX_LEASE};"
+    echo "option domain-name \"${DOMAIN:?}\";"
+    echo "default-lease-time ${DEFAULT_LEASE:?};"
+    echo "max-lease-time ${MAX_LEASE:?};"
     echo "authoritative;"
 } > "${CONFIG}"

Line range hint 22-29: Validate DNS servers and simplify condition

Add IP address validation and use bashio's built-in functions for cleaner code.

-if [ "$(bashio::config 'dns')" ]
+if bashio::config.exists 'dns'
 then
     DNS=$(bashio::config 'dns|join(", ")')
+    # Validate DNS servers
+    for ip in $(bashio::config 'dns'); do
+        if ! bashio::var.is_ip_address "$ip"; then
+            bashio::exit.nok "Invalid DNS server IP: ${ip}"
+        fi
+    done
     {
-        echo "option domain-name-servers ${DNS};";
+        echo "option domain-name-servers ${DNS:?};";
     } >> "${CONFIG}"
 fi

Line range hint 41-63: Add network configuration validation

The network configuration needs validation for IP addresses, ranges, and subnet consistency.

 for network in $(bashio::config 'networks|keys'); do
     BROADCAST=$(bashio::config "networks[${network}].broadcast")
     GATEWAY=$(bashio::config "networks[${network}].gateway")
     INTERFACE=$(bashio::config "networks[${network}].interface")
     NETMASK=$(bashio::config "networks[${network}].netmask")
     RANGE_START=$(bashio::config "networks[${network}].range_start")
     RANGE_END=$(bashio::config "networks[${network}].range_end")
     SUBNET=$(bashio::config "networks[${network}].subnet")
 
+    # Validate IP addresses
+    for ip in "${BROADCAST}" "${GATEWAY}" "${RANGE_START}" "${RANGE_END}" "${SUBNET}"; do
+        if ! bashio::var.is_ip_address "$ip"; then
+            bashio::exit.nok "Invalid IP address in network ${network}: ${ip}"
+        fi
+    done
+
+    # Validate interface exists
+    if ! ip link show "${INTERFACE}" >/dev/null 2>&1; then
+        bashio::exit.nok "Interface ${INTERFACE} does not exist"
+    fi
+
+    # Validate IP range
+    if ! bashio::var.is_ip_in_network "${RANGE_START}" "${SUBNET}/${NETMASK}" || \
+       ! bashio::var.is_ip_in_network "${RANGE_END}" "${SUBNET}/${NETMASK}"; then
+        bashio::exit.nok "IP range ${RANGE_START}-${RANGE_END} not in subnet ${SUBNET}/${NETMASK}"
+    fi
+
     {
         echo "subnet ${SUBNET} netmask ${NETMASK} {"
         echo "  interface ${INTERFACE};"
         echo "  range ${RANGE_START} ${RANGE_END};"
         echo "  option routers ${GATEWAY};"
         echo "  option broadcast-address ${BROADCAST};"
         echo "}"
     } >> "${CONFIG}"
 done

Line range hint 65-79: Validate host configurations and ensure uniqueness

Add validation for MAC addresses and ensure IP/MAC uniqueness across hosts.

+declare -A used_ips used_macs
+
 for host in $(bashio::config 'hosts|keys'); do
     IP=$(bashio::config "hosts[${host}].ip")
     MAC=$(bashio::config "hosts[${host}].mac")
     NAME=$(bashio::config "hosts[${host}].name")
 
+    # Validate MAC address format
+    if ! [[ "${MAC}" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
+        bashio::exit.nok "Invalid MAC address format for host ${NAME}: ${MAC}"
+    fi
+
+    # Check for duplicates
+    if [[ -n "${used_ips[$IP]:-}" ]]; then
+        bashio::exit.nok "Duplicate IP address ${IP} for hosts ${used_ips[$IP]} and ${NAME}"
+    fi
+    if [[ -n "${used_macs[$MAC]:-}" ]]; then
+        bashio::exit.nok "Duplicate MAC address ${MAC} for hosts ${used_macs[$MAC]} and ${NAME}"
+    fi
+    used_ips[$IP]=$NAME
+    used_macs[$MAC]=$NAME
+
     {
         echo "host ${NAME} {"
         echo "  hardware ethernet ${MAC};"
         echo "  fixed-address ${IP};"
         echo "  option host-name \"${NAME}\";"
         echo "}"
     } >> "${CONFIG}"
 done

Line range hint 81-91: Enhance server startup reliability

Add configuration validation and improve error handling during startup.

 # Create database
 if ! bashio::fs.file_exists "${LEASES}"; then
     touch "${LEASES}"
 fi
 
+# Validate configuration
+if ! /usr/sbin/dhcpd -t -cf "${CONFIG}"; then
+    bashio::exit.nok "Invalid DHCP configuration"
+fi
+
 # Start DHCP server
 bashio::log.info "Starting DHCP server..."
-exec /usr/sbin/dhcpd \
-    -4 -f -d --no-pid \
-    -lf "${LEASES}" \
-    -cf "${CONFIG}" \
-    < /dev/null
+exec /usr/sbin/dhcpd -4 -f -d --no-pid \
+    -lf "${LEASES}" -cf "${CONFIG}" < /dev/null 2>&1 \
+    || bashio::exit.nok "Failed to start DHCP server"

Line range hint 6-7: Set appropriate file permissions

Add proper file permissions for security.

 CONFIG="/etc/dhcpd.conf"
 LEASES="/data/dhcpd.lease"
+
+# Ensure secure file permissions
+chmod 644 "${CONFIG}"
+chmod 644 "${LEASES}"
deconz/rootfs/etc/services.d/deconz/run (2)

Line range hint 23-45: Security Concern: VNC server configuration needs review

The VNC server is configured with -SecurityTypes None and --I-KNOW-THIS-IS-INSECURE, which could pose security risks:

  1. No authentication is required
  2. If exposed, anyone could access the VNC server
  3. While there is a warning log, it might be missed by users

Consider implementing these security improvements:

 tigervncserver \
     -name "Home Assistant - deCONZ" \
     -geometry 1920x1080 \
     -depth 16 \
     -localhost ${LOCAL_ONLY} \
-    -SecurityTypes None \
-    --I-KNOW-THIS-IS-INSECURE \
+    -SecurityTypes VncAuth \
+    -PasswordFile /config/vnc_password \
     "${DISPLAY}" \
     &> /dev/null

Line range hint 58-75: Improve error handling for discovery process

The current implementation launches the discovery process in the background without proper error handling or monitoring.

Consider implementing this more robust approach:

-# Send out discovery information to Home Assistant
-./discovery &
+# Start discovery process with proper error handling
+if ! ./discovery & then
+    bashio::log.warning "Failed to start discovery process"
+fi
+DISCOVERY_PID=$!
+
+# Trap to clean up discovery process
+trap 'kill $DISCOVERY_PID 2>/dev/null' EXIT

This change will:

  1. Log discovery process failures
  2. Store the PID for proper cleanup
  3. Ensure the discovery process is terminated when the script exits
deconz/rootfs/etc/services.d/deconz/discovery (4)

Line range hint 19-20: Protect against SQL injection

The SQL query string should be properly escaped to prevent potential SQL injection. While the current usage seems safe, it's better to follow best practices.

Consider using SQLite's parameter binding:

-query='SELECT apikey FROM auth WHERE devicetype="Home Assistant" ORDER BY createdate DESC LIMIT 1'
-api_key=$(sqlite3 "${DATA_STORE}" "${query}" .exit)
+api_key=$(sqlite3 "${DATA_STORE}" "SELECT apikey FROM auth WHERE devicetype=? ORDER BY createdate DESC LIMIT 1;" "Home Assistant" .exit)

Line range hint 23-28: Improve error handling for API key registration

The error handling for the API registration could be more robust. The current implementation logs the error but doesn't provide specific error details.

Consider enhancing the error message:

 if ! result="$(curl --silent --show-error --request POST -d '{"devicetype": "Home Assistant"}' "http://127.0.0.1:40850/api")";
 then
-    bashio::log.debug "${result}"
-    bashio::exit.nok "Can't get API key from deCONZ gateway"
+    bashio::log.error "Failed to register with deCONZ gateway: ${result}"
+    bashio::exit.nok "Failed to obtain API key. Please check if deCONZ is running and accessible."
 fi

Line range hint 31-50: Consider making retry parameters configurable

The retry mechanism is well-implemented, but hardcoded values could be made configurable for better flexibility.

Consider defining these as variables at the top of the script:

+# Configuration
+readonly MAX_RETRIES=25
+readonly RETRY_INTERVAL=10
+
 # Try to get the bridge ID/serial, try to avoid using 0000000000000000
-retries=25
+retries="${MAX_RETRIES}"
 serial="0000000000000000"
 while [[ "${serial}" = "0000000000000000" ]]; do
     bashio::log.debug "Waiting for bridge ID..."
-    sleep 10
+    sleep "${RETRY_INTERVAL}"

Line range hint 52-65: Enhance error handling and consider making port configurable

The configuration and discovery section could benefit from more detailed error handling and flexible port configuration.

Consider these improvements:

+# Configuration
+readonly DECONZ_PORT=40850
+
 # Create config payload for Home Assistant
 config=$(bashio::var.json \
     host "$(hostname)" \
-    port "^40850" \
+    port "^${DECONZ_PORT}" \
     api_key "${api_key}" \
     serial "${serial}" \
 )

 # Send discovery info
 if bashio::discovery "deconz" "${config}" > /dev/null; then
     bashio::log.info "Successfully send discovery information to Home Assistant."
 else
-    bashio::log.error "Discovery message to Home Assistant failed!"
+    bashio::log.error "Failed to send discovery information to Home Assistant"
+    bashio::log.debug "Discovery payload: ${config}"
+    bashio::exit.nok "Discovery failed. Please check Home Assistant logs for more details."
 fi
tellstick/data/run.sh (4)

1-4: Consider enhancing error handling setup

While set -e is good, consider adding these options for more robust error handling:

 #!/usr/bin/with-contenv bashio
 # shellcheck shell=bash
-set -e
+set -euo pipefail
+trap 'bashio::log.error "Unexpected error in ${BASH_SOURCE[0]} at line ${LINENO}"' ERR

This will:

  • Exit on undefined variables (-u)
  • Prevent masking of pipe failures (-o pipefail)
  • Add error location reporting via trap

Line range hint 6-13: Add configuration file safety checks

The script should validate permissions and handle existing configurations safely.

 CONFIG="/etc/tellstick.conf"
+
+# Validate permissions and backup existing config
+if [[ -f "${CONFIG}" ]]; then
+    bashio::log.info "Backing up existing configuration..."
+    cp "${CONFIG}" "${CONFIG}.backup"
+fi
+
+if ! touch "${CONFIG}" 2>/dev/null; then
+    bashio::log.fatal "Cannot write to ${CONFIG}. Please check permissions."
+    exit 1
+fi
 
 bashio::log.info "Initialize the tellstick configuration..."

Line range hint 63-69: Improve process management and cleanup

The current implementation lacks proper process management and cleanup mechanisms.

+# Track background processes
+declare -a PIDS
+
+cleanup() {
+    bashio::log.info "Cleaning up processes..."
+    for pid in "${PIDS[@]}"; do
+        kill "$pid" 2>/dev/null || true
+    done
+}
+
+trap cleanup EXIT
+
 # Expose the unix socket to internal network
-socat TCP-LISTEN:50800,reuseaddr,fork UNIX-CONNECT:/tmp/TelldusClient &
-socat TCP-LISTEN:50801,reuseaddr,fork UNIX-CONNECT:/tmp/TelldusEvents &
+if ! socat TCP-LISTEN:50800,reuseaddr,fork UNIX-CONNECT:/tmp/TelldusClient & PIDS+=($!); then
+    bashio::log.error "Failed to start TelldusClient socket"
+    exit 1
+fi
+
+if ! socat TCP-LISTEN:50801,reuseaddr,fork UNIX-CONNECT:/tmp/TelldusEvents & PIDS+=($!); then
+    bashio::log.error "Failed to start TelldusEvents socket"
+    exit 1
+fi
 
 # Run telldus-core daemon in the background
-/usr/local/sbin/telldusd --nodaemon < /dev/null &
+if ! /usr/local/sbin/telldusd --nodaemon < /dev/null & PIDS+=($!); then
+    bashio::log.error "Failed to start telldusd"
+    exit 1
+fi

Line range hint 71-85: Address security and robustness concerns in event handling

The event listener has potential security vulnerabilities and robustness issues.

 # Listen for input to tdtool
 bashio::log.info "Starting event listener..."
+declare -r TIMEOUT=10
+
 while read -r input; do
+    # Validate JSON format
+    if ! bashio::jq -e . >/dev/null 2>&1 <<<"${input}"; then
+        bashio::log.error "Invalid JSON input: ${input}"
+        continue
+    }
+
     # parse JSON value
     funct=$(bashio::jq "${input}" '.function')
     devid=$(bashio::jq "${input}" '.device // empty')
+    
+    # Validate function name (prevent command injection)
+    if [[ ! "${funct}" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+        bashio::log.error "Invalid function name: ${funct}"
+        continue
+    }
+
     bashio::log.info "Read ${funct} / ${devid}"

-    if ! msg="$(tdtool "--${funct}" "${devid}")"; then
+    # Execute with timeout and proper quoting
+    if ! msg="$(timeout "${TIMEOUT}" tdtool "--${funct}" "${devid}")"; then
         bashio::log.error "TellStick ${funct} fails -> ${msg}"
     else
         bashio::log.info "TellStick ${funct} success -> ${msg}"
     fi
 done
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (3)

Line range hint 46-57: Consider externalizing firmware version configuration.

The firmware versions (4.3.1) are currently hardcoded, which could make updates challenging. Consider moving these to a configuration file or environment variables for easier maintenance.

Example approach:

# config.json or environment
SKYCONNECT_FIRMWARE_VERSION="4.3.1"
YELLOW_FIRMWARE_VERSION="4.3.1"

# Script
firmware_version="${SKYCONNECT_FIRMWARE_VERSION}"
firmware="NabuCasa_SkyConnect_RCP_v${firmware_version}_rcp-uart-hw-802154_460800.gbl"

65-67: Improve command argument handling.

The current command construction could be more robust with proper quoting.

Consider this safer alternative:

-# shellcheck disable=SC2086
-exec universal-silabs-flasher --device ${device} \
-     flash ${gpio_reset_flag} --ensure-exact-version --allow-cross-flashing --firmware "/root/${firmware}"
+exec universal-silabs-flasher --device "${device}" \
+     flash ${gpio_reset_flag:+"${gpio_reset_flag}"} --ensure-exact-version --allow-cross-flashing --firmware "/root/${firmware}"

This ensures proper handling of spaces in paths and empty variables.


Line range hint 59-60: Add error handling for baudrate configuration.

The baudrate configuration write could fail silently.

Consider adding error handling:

-echo 460800 > /tmp/known-baudrate
+if ! echo 460800 > /tmp/known-baudrate; then
+    bashio::log.warning "Failed to write known baudrate configuration"
+fi
mosquitto/rootfs/etc/cont-init.d/mosquitto.sh (4)

Line range hint 16-28: Add error handling for password generation.

While the password generation logic is secure, it lacks error handling for potential pwgen failures. This could lead to undefined behavior if password generation fails.

Consider adding error checking:

-  discovery_password="$(pwgen 64 1)"
-  service_password="$(pwgen 64 1)"
+  if ! discovery_password="$(pwgen 64 1)"; then
+    bashio::exit.nok "Failed to generate discovery password"
+  fi
+  if ! service_password="$(pwgen 64 1)"; then
+    bashio::exit.nok "Failed to generate service password"
+  fi

Line range hint 45-57: Consider adding username validation and enhancing ACL rules.

Two potential improvements for security:

  1. Add username format validation to prevent injection attacks
  2. Consider more granular ACL rules based on user roles

Example implementation for username validation:

 username=$(bashio::config "logins[${login}].username")
+if [[ ! "$username" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+  bashio::exit.nok "Invalid username format. Use only alphanumeric characters, underscore, and hyphen"
+fi

Line range hint 59-73: Enhance SSL security checks.

While the SSL configuration is functional, consider adding:

  1. Verification of certificate file permissions
  2. Validation of certificate expiration
  3. Documentation for the cafile fallback behavior

Example implementation:

 if bashio::fs.file_exists "${certfile}" \
   && bashio::fs.file_exists "${keyfile}";
 then
+  # Check file permissions
+  if [[ "$(stat -c %a "${keyfile}")" != "600" ]]; then
+    bashio::log.warning "Insecure permissions on keyfile. Setting to 600"
+    chmod 600 "${keyfile}"
+  fi
+
+  # Verify certificate validity
+  if ! openssl x509 -checkend 86400 -noout -in "${certfile}"; then
+    bashio::log.warning "SSL certificate will expire within 24 hours"
+  fi
+
   bashio::log.info "Certificates found: SSL is available"
   ssl="true"
   if ! bashio::fs.file_exists "${cafile}"; then
+    bashio::log.info "No separate CA file provided, using certificate file as CA"
     cafile="${certfile}"
   fi

Line range hint 75-89: Add error handling for configuration template rendering.

The configuration generation lacks error handling for the tempio template rendering process.

Consider adding validation:

-| tempio \
-    -template /usr/share/tempio/mosquitto.gtpl \
-    -out /etc/mosquitto/mosquitto.conf
+| if ! tempio \
+    -template /usr/share/tempio/mosquitto.gtpl \
+    -out /etc/mosquitto/mosquitto.conf; then
+  bashio::exit.nok "Failed to generate Mosquitto configuration"
+fi
+
+# Verify the generated configuration
+if ! mosquitto -t -c /etc/mosquitto/mosquitto.conf; then
+  bashio::exit.nok "Invalid Mosquitto configuration generated"
+fi
duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run (4)

Line range hint 19-41: Critical: Improve error handling in certificate renewal function.

Several security and reliability concerns need to be addressed:

  1. The || true after the dehydrated command masks failures
  2. Missing validation of jq command output
  3. Potential command injection risk in domain handling

Consider applying these improvements:

 function le_renew() {
     local domain_args=()
     local domains=''
     local aliases=''
 
-    domains=$(bashio::config 'domains')
+    if ! domains=$(bashio::config 'domains'); then
+        bashio::log.error "Failed to get domains configuration"
+        return 1
+    fi
 
     # Prepare domain for Let's Encrypt
     for domain in ${domains}; do
-        for alias in $(jq --raw-output --exit-status "[.aliases[]|{(.alias):.domain}]|add.\"${domain}\" | select(. != null)" /data/options.json) ; do
+        local jq_output
+        if ! jq_output=$(jq --raw-output --exit-status "[.aliases[]|{(.alias):.domain}]|add.\"${domain}\" | select(. != null)" /data/options.json); then
+            bashio::log.warning "Failed to process aliases for domain: ${domain}"
+            continue
+        fi
+        for alias in ${jq_output}; do
             aliases="${aliases} ${alias}"
         done
     done
 
     aliases="$(echo "${aliases}" | tr ' ' '\n' | sort | uniq)"
 
     bashio::log.info "Renew certificate for domains: $(echo -n "${domains}") and aliases: $(echo -n "${aliases}")"
 
     for domain in $(echo "${domains}" "${aliases}" | tr ' ' '\n' | sort | uniq); do
+        [[ "${domain}" =~ ^[a-zA-Z0-9.-]+$ ]] || {
+            bashio::log.error "Invalid domain format: ${domain}"
+            continue
+        }
         domain_args+=("--domain" "${domain}")
     done
 
-    dehydrated --cron --algo "${ALGO}" --hook /root/hooks.sh --challenge dns-01 "${domain_args[@]}" --out "${CERT_DIR}" --config "${WORK_DIR}/config" || true
+    if ! dehydrated --cron --algo "${ALGO}" --hook /root/hooks.sh --challenge dns-01 "${domain_args[@]}" --out "${CERT_DIR}" --config "${WORK_DIR}/config"; then
+        bashio::log.error "Certificate renewal failed"
+        return 1
+    fi
     LE_UPDATE="$(date +%s)"
+    return 0
 }

Line range hint 43-60: Consider adding error handling for directory operations.

While the initialization logic is sound, it could benefit from additional error handling.

Consider these improvements:

 if bashio::config.true 'lets_encrypt.accept_terms'; then
     # Init folder structs
-    mkdir -p "${CERT_DIR}"
-    mkdir -p "${WORK_DIR}"
+    if ! mkdir -p "${CERT_DIR}" "${WORK_DIR}"; then
+        bashio::log.error "Failed to create required directories"
+        exit 1
+    fi
 
     # Clean up possible stale lock file
     if [ -e "${WORK_DIR}/lock" ]; then
-        rm -f "${WORK_DIR}/lock"
+        if ! rm -f "${WORK_DIR}/lock"; then
+            bashio::log.error "Failed to remove stale lock file"
+            exit 1
+        fi
         bashio::log.warning "Reset dehydrated lock file"
     fi

Line range hint 63-108: Improve network operation reliability and validation.

The DuckDNS update loop could benefit from more robust error handling and validation:

  1. Curl commands should have comprehensive error handling
  2. DuckDNS API response validation could be more thorough
  3. IPv6 address validation could be strengthened

Consider these improvements:

-    [[ ${IPV4} != *:/* ]] && ipv4=${IPV4} || ipv4=$(curl -s -m 10 "${IPV4}")
-    [[ ${IPV6} != *:/* ]] && ipv6=${IPV6} || ipv6=$(curl -s -m 10 "${IPV6}")
+    if [[ ${IPV4} != *:/* ]]; then
+        ipv4=${IPV4}
+    else
+        if ! ipv4=$(curl -s -m 10 --retry 3 --retry-delay 2 "${IPV4}"); then
+            bashio::log.error "Failed to fetch IPv4 address"
+            ipv4=""
+        fi
+    fi
+
+    if [[ ${IPV6} != *:/* ]]; then
+        ipv6=${IPV6}
+    else
+        if ! ipv6=$(curl -s -m 10 --retry 3 --retry-delay 2 "${IPV6}"); then
+            bashio::log.error "Failed to fetch IPv6 address"
+            ipv6=""
+        fi
+    fi

     # Get IPv6-address from host interface
     if [[ -n "$IPV6" && ${ipv6} != *:* ]]; then
         ipv6=
         bashio::cache.flush_all
         for addr in $(bashio::network.ipv6_address "$IPV6"); do
-            # Skip non-global addresses
-            if [[ ${addr} != fe80:* && ${addr} != fc* && ${addr} != fd* ]]; then
+            # Validate and select global IPv6 address
+            if [[ ${addr} =~ ^[0-9a-fA-F:]+$ && ${addr} != fe80:* && ${addr} != fc* && ${addr} != fd* ]]; then
                 ipv6=${addr%/*}
                 break
             fi
         done
     fi

Also, consider implementing a helper function for DuckDNS API calls to reduce code duplication:

update_duckdns() {
    local ip_type=$1
    local ip_value=$2
    local response
    
    if ! response=$(curl -s -m 10 --retry 3 "https://www.duckdns.org/update?domains=${DOMAINS}&token=${TOKEN}&${ip_type}=${ip_value}&verbose=true"); then
        bashio::log.error "DuckDNS API call failed"
        return 1
    fi
    
    if [ "${response}" = 'KO' ]; then
        bashio::log.error "DuckDNS update failed: ${response}"
        return 1
    fi
    
    if [[ "${response}" == *NOCHANGE* ]]; then
        bashio::log.debug "${response}"
    else
        bashio::log.info "${response}"
    fi
    return 0
}

Line range hint 109-114: Optimize certificate renewal check timing.

The current implementation checks for certificate renewal on every iteration, which is unnecessary given the 12-hour interval.

Consider implementing a more efficient approach:

+    # Calculate next renewal time only when needed
+    declare -g NEXT_RENEWAL_CHECK=${NEXT_RENEWAL_CHECK:-0}
     now="$(date +%s)"
-    if bashio::config.true 'lets_encrypt.accept_terms' && [ $((now - LE_UPDATE)) -ge 43200 ]; then
-        le_renew
+    if [ "${now}" -ge "${NEXT_RENEWAL_CHECK}" ]; then
+        if bashio::config.true 'lets_encrypt.accept_terms' && [ $((now - LE_UPDATE)) -ge 43200 ]; then
+            le_renew
+        fi
+        # Set next check time to 1 hour from now
+        NEXT_RENEWAL_CHECK=$((now + 3600))
     fi
mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-post/run (1)

Line range hint 7-15: Consider improving error handling robustness

While the new function provides a good mechanism for controlled error suppression, there are a few potential improvements to consider:

  1. The command arguments should be quoted to prevent word splitting
  2. The log level restoration should be protected in case the command modifies it
  3. Consider adding debug logging for suppressed errors

Here's a suggested improvement:

 function execute_without_error_messages() {
     local current_log_level="${__BASHIO_LOG_LEVELS[${__BASHIO_LOG_LEVEL}]}"
     bashio::log.level fatal
     local exit_code=0
-    # shellcheck disable=SC2068
-    $@ || exit_code=$?
-    # shellcheck disable=SC2086
-    bashio::log.level ${current_log_level}
+    # Capture output for debug logging
+    local output
+    output=$("$@" 2>&1) || exit_code=$?
+    
+    # Log suppressed output at debug level
+    if [ -n "$output" ]; then
+        bashio::log.debug "Suppressed output: $output"
+    fi
+    
+    # Ensure log level is restored even if command changed it
+    bashio::log.level "$current_log_level"
     return ${exit_code}
 }
letsencrypt/rootfs/etc/cont-init.d/file-structure.sh (5)

Line range hint 1-7: Add error handling for directory creation operations.

The mkdir commands should include error handling to ensure the directories are created successfully and to handle potential permission issues.

-mkdir -p /data/workdir
-mkdir -p /data/letsencrypt
+if ! mkdir -p /data/workdir /data/letsencrypt; then
+    bashio::exit.nok "Failed to create required directories"
+fi

Line range hint 8-67: Enhance security and maintainability of credentials handling.

Several improvements can be made to this section:

  1. Credentials are currently exposed in the process list during the echo command
  2. The large echo statement is difficult to maintain

Consider refactoring to:

  1. Write credentials individually to avoid process list exposure
  2. Use a function to handle credential writing
+write_credential() {
+    local key=$1
+    local value=$2
+    if [[ -n "$value" ]]; then
+        echo "${key} = ${value}" >> /data/dnsapikey
+    fi
+}

+# Clear existing file
+> /data/dnsapikey
+
+# Write credentials securely
+write_credential "dns_desec_token" "$(bashio::config 'dns.desec_token')"
+write_credential "dns_digitalocean_token" "$(bashio::config 'dns.digitalocean_token')"
# ... repeat for other credentials

Line range hint 69-81: Add validation for mutually exclusive ClouDNS authentication options.

The comment indicates that only a single non-empty auth option must be present, but the code doesn't enforce this requirement.

+# Count how many ClouDNS auth options are set
+cloudns_auth_count=0
+
 if bashio::config.exists 'dns.cloudns_auth_id'; then
+    ((cloudns_auth_count++))
     echo -e "dns_cloudns_auth_id = $(bashio::config 'dns.cloudns_auth_id')\n" >> /data/dnsapikey
 fi

 if bashio::config.exists 'dns.cloudns_sub_auth_id'; then
+    ((cloudns_auth_count++))
     echo -e "dns_cloudns_sub_auth_id = $(bashio::config 'dns.cloudns_sub_auth_id')\n" >> /data/dnsapikey
 fi

 if bashio::config.exists 'dns.cloudns_sub_auth_user'; then
+    ((cloudns_auth_count++))
     echo -e "dns_cloudns_sub_auth_user = $(bashio::config 'dns.cloudns_sub_auth_user')\n" >> /data/dnsapikey
 fi
+
+if [[ "$cloudns_auth_count" -gt 1 ]]; then
+    bashio::exit.nok "Only one ClouDNS authentication option should be configured"
+fi

Line range hint 85-89: Add error handling for TransIP key processing.

The openssl command lacks error handling and key validation.

 if bashio::config.exists 'dns.transip_api_key'; then
     TRANSIP_API_KEY=$(bashio::config 'dns.transip_api_key')
-    echo "${TRANSIP_API_KEY}" | openssl rsa -out /data/transip-rsa.key
-    chmod 600 /data/transip-rsa.key
+    if ! echo "${TRANSIP_API_KEY}" | openssl rsa -check -noout 2>/dev/null; then
+        bashio::exit.nok "Invalid TransIP RSA key format"
+    fi
+    if ! echo "${TRANSIP_API_KEY}" | openssl rsa -out /data/transip-rsa.key; then
+        bashio::exit.nok "Failed to process TransIP RSA key"
+    fi
+    chmod 600 /data/transip-rsa.key || bashio::exit.nok "Failed to set TransIP key permissions"
 fi

Line range hint 91-105: Add logging for deprecated option cleanup.

Consider adding logging to inform users when deprecated options are removed and suggest alternatives if available.

+bashio::log.info "Cleaning up deprecated configuration options..."

 if bashio::config.exists 'dns.cloudxns_api_key'; then
+    bashio::log.warning "Removing deprecated option 'dns.cloudxns_api_key' - CloudXNS service is no longer supported"
     bashio::addon.option 'dns.cloudxns_api_key'
 fi
 # ... repeat for other options
zwave_js/rootfs/etc/cont-init.d/config.sh (3)

Line range hint 52-67: Enhance key validation logic and error messaging.

While the security check for example keys is crucial, consider these improvements:

  1. Use an array for example keys to simplify comparisons
  2. Include the specific matching key in the error message

Here's a suggested refactoring:

-if [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_1}" ] || [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_2}" ] || [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_3}" ] || [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_4}" ] || [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_5}" ] || [ "${network_key_upper}" == "${DOCS_EXAMPLE_KEY_6}" ]; then
+readonly DOCS_EXAMPLE_KEYS=("${DOCS_EXAMPLE_KEY_1}" "${DOCS_EXAMPLE_KEY_2}" "${DOCS_EXAMPLE_KEY_3}" "${DOCS_EXAMPLE_KEY_4}" "${DOCS_EXAMPLE_KEY_5}" "${DOCS_EXAMPLE_KEY_6}")
+if [[ " ${DOCS_EXAMPLE_KEYS[*]} " =~ ${network_key_upper} ]]; then
     bashio::log.fatal
     bashio::log.fatal "The add-on detected that the Z-Wave network key used"
-    bashio::log.fatal "is from the documented example."
+    bashio::log.fatal "is from the documented example: ${network_key_upper}"

Line range hint 101-117: Consider using a case statement for better maintainability.

The soft reset logic could be more maintainable using a case statement.

Here's a suggested refactoring:

-if bashio::config.equals 'soft_reset' 'Automatic'; then
-    bashio::log.info "Soft-reset set to automatic"
-    if [ "${host_chassis}" == "vm" ]; then
-        soft_reset=false
-        bashio::log.info "Virtual Machine detected, disabling soft-reset"
-    else
-        soft_reset=true
-        bashio::log.info "Virtual Machine not detected, enabling soft-reset"
-    fi
-elif bashio::config.equals 'soft_reset' 'Enabled'; then
-    soft_reset=true
-    bashio::log.info "Soft-reset enabled by user"
-else
-    soft_reset=false
-    bashio::log.info "Soft-reset disabled by user"
-fi
+case "$(bashio::config 'soft_reset')" in
+    "Automatic")
+        bashio::log.info "Soft-reset set to automatic"
+        if [ "${host_chassis}" == "vm" ]; then
+            soft_reset=false
+            bashio::log.info "Virtual Machine detected, disabling soft-reset"
+        else
+            soft_reset=true
+            bashio::log.info "Virtual Machine not detected, enabling soft-reset"
+        fi
+        ;;
+    "Enabled")
+        soft_reset=true
+        bashio::log.info "Soft-reset enabled by user"
+        ;;
+    *)
+        soft_reset=false
+        bashio::log.info "Soft-reset disabled by user"
+        ;;
+esac

Line range hint 118-146: Enhance preset handling with validation and simplified JSON conversion.

Consider these improvements:

  1. Add validation for preset values
  2. Simplify the JSON array conversion

Here's a suggested refactoring:

+# Define valid presets
+readonly VALID_PRESETS=("SAFE_MODE" "NO_CONTROLLER_RECOVERY" "NO_WATCHDOG")

+# Validate preset before adding
+add_preset() {
+    local preset="$1"
+    if [[ " ${VALID_PRESETS[*]} " =~ ${preset} ]]; then
+        presets_array+=("${preset}")
+    else
+        bashio::log.warning "Invalid preset: ${preset}"
+    fi
+}

 if bashio::config.true 'safe_mode'; then
     bashio::log.info "Safe mode enabled"
     bashio::log.warning "WARNING: While in safe mode, the performance of your Z-Wave network will be in a reduced state. This is only meant for debugging purposes."
-    presets_array+=("SAFE_MODE")
+    add_preset "SAFE_MODE"
 fi

-# Convert presets array to JSON string and add to config
-if [[ ${#presets_array[@]} -eq 0 ]]; then
-    presets="[]"
-else
-    presets="$(printf '%s\n' "${presets_array[@]}" | jq -R . | jq -s .)"
-fi
+# Convert presets array to JSON string using a single jq command
+presets="$(jq -n --arg v "${presets_array[*]}" '$v | split(" ")')"
openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (1)

Line range hint 141-147: Ensure all variable expansions are properly quoted in the exec command

In the exec command starting otbr-agent, variables like ${thread_if}, ${device}, ${baudrate}, and ${flow_control} should be enclosed in double quotes to prevent potential issues if they contain spaces.

Apply this diff:

-# shellcheck disable=SC2086
 exec s6-notifyoncheck -d -s 300 -w 300 -n 0 stdbuf -oL \
     "/usr/sbin/otbr-agent" -I ${thread_if} -B "${backbone_if}" \
+    "/usr/sbin/otbr-agent" -I "${thread_if}" -B "${backbone_if}" \
         --rest-listen-address "${otbr_rest_listen}" \
-        -d${otbr_log_level_int} -v -s \
-        "spinel+hdlc+uart://${device}?uart-baudrate=${baudrate}${flow_control}" \
+        -d"${otbr_log_level_int}" -v -s \
+        "spinel+hdlc+uart://${device}?uart-baudrate=${baudrate}${flow_control}" \
         "trel://${backbone_if}"

Quoting these variables enhances script robustness.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d70266c and ed7dbde.

📒 Files selected for processing (80)
  • cec_scan/rootfs/etc/services.d/cec-scan/run (1 hunks)
  • configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/run (1 hunks)
  • deconz/rootfs/etc/cont-init.d/firmware.sh (1 hunks)
  • deconz/rootfs/etc/cont-init.d/nginx.sh (1 hunks)
  • deconz/rootfs/etc/cont-init.d/novnc.sh (1 hunks)
  • deconz/rootfs/etc/services.d/deconz/discovery (1 hunks)
  • deconz/rootfs/etc/services.d/deconz/run (1 hunks)
  • deconz/rootfs/etc/services.d/nginx/run (1 hunks)
  • deconz/rootfs/etc/services.d/otau-ikea/run (1 hunks)
  • deconz/rootfs/etc/services.d/otau-ledvance/run (1 hunks)
  • deconz/rootfs/etc/services.d/websockify/run (1 hunks)
  • dhcp_server/data/run.sh (1 hunks)
  • dnsmasq/rootfs/etc/cont-init.d/config.sh (1 hunks)
  • dnsmasq/rootfs/etc/services.d/dnsmasq/run (1 hunks)
  • duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run (1 hunks)
  • google_assistant/rootfs/etc/services.d/google-assistant/run (1 hunks)
  • letsencrypt/rootfs/etc/cont-init.d/file-structure.sh (1 hunks)
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-core/finish (2 hunks)
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/finish (1 hunks)
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/run (1 hunks)
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-post/run (1 hunks)
  • mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/run (1 hunks)
  • matter_server/rootfs/etc/s6-overlay/s6-rc.d/matter-server/run (4 hunks)
  • matter_server/rootfs/etc/s6-overlay/scripts/banner.sh (1 hunks)
  • matter_server/rootfs/etc/s6-overlay/scripts/matter-server-discovery (1 hunks)
  • mosquitto/rootfs/etc/cont-init.d/mosquitto.sh (1 hunks)
  • mosquitto/rootfs/etc/cont-init.d/nginx.sh (1 hunks)
  • mosquitto/rootfs/etc/services.d/mosquitto/discovery (1 hunks)
  • mosquitto/rootfs/etc/services.d/mosquitto/run (1 hunks)
  • mosquitto/rootfs/etc/services.d/nginx/run (1 hunks)
  • nginx_proxy/rootfs/etc/periodic/daily/check_certificate_renewal (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/mdns/finish (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/mdns/run (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (5 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/finish (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/run (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/socat-otbr-tcp/run (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/banner.sh (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/enable-check.sh (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-configure.sh (1 hunks)
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (1 hunks)
  • rpc_shutdown/data/run.sh (1 hunks)
  • samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run (1 hunks)
  • samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish (2 hunks)
  • samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run (1 hunks)
  • samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish (2 hunks)
  • samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/cont-init.d/check-cpcd-shm.sh (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/mdns/finish (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/mdns/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (3 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/finish (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/run (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/finish (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/banner.sh (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/cpcd-config-up (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-enable-check.sh (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/socat-cpcd-tcp-enable-check.sh (1 hunks)
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (3 hunks)
  • silabs_flasher/rootfs/etc/s6-overlay/scripts/banner.sh (1 hunks)
  • ssh/rootfs/etc/cont-init.d/apks.sh (1 hunks)
  • ssh/rootfs/etc/cont-init.d/keygen.sh (1 hunks)
  • ssh/rootfs/etc/cont-init.d/profile.sh (1 hunks)
  • ssh/rootfs/etc/cont-init.d/ssh.sh (1 hunks)
  • ssh/rootfs/etc/services.d/sshd/run (1 hunks)
  • ssh/rootfs/etc/services.d/ttyd/run (1 hunks)
  • ssh/rootfs/usr/local/bin/reboot (1 hunks)
  • ssh/rootfs/usr/local/bin/shutdown (1 hunks)
  • tellstick/data/run.sh (1 hunks)
  • vlc/rootfs/etc/cont-init.d/ingress.sh (1 hunks)
  • vlc/rootfs/etc/cont-init.d/secret.sh (1 hunks)
  • vlc/rootfs/etc/s6-overlay/s6-rc.d/vlc/run (1 hunks)
  • vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery (1 hunks)
  • zwave_js/rootfs/etc/cont-init.d/config.sh (1 hunks)
  • zwave_js/rootfs/etc/cont-init.d/structure.sh (1 hunks)
  • zwave_js/rootfs/etc/services.d/zwave_js/discovery (1 hunks)
  • zwave_js/rootfs/etc/services.d/zwave_js/run (2 hunks)
✅ Files skipped from review due to trivial changes (32)
  • cec_scan/rootfs/etc/services.d/cec-scan/run
  • deconz/rootfs/etc/cont-init.d/firmware.sh
  • deconz/rootfs/etc/cont-init.d/nginx.sh
  • deconz/rootfs/etc/services.d/websockify/run
  • dnsmasq/rootfs/etc/cont-init.d/config.sh
  • matter_server/rootfs/etc/s6-overlay/scripts/banner.sh
  • matter_server/rootfs/etc/s6-overlay/scripts/matter-server-discovery
  • mosquitto/rootfs/etc/cont-init.d/nginx.sh
  • mosquitto/rootfs/etc/services.d/mosquitto/run
  • mosquitto/rootfs/etc/services.d/nginx/run
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/mdns/finish
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/mdns/run
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/finish
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/run
  • openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/socat-otbr-tcp/run
  • openthread_border_router/rootfs/etc/s6-overlay/scripts/banner.sh
  • samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/run
  • samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/run
  • silabs-multiprotocol/rootfs/etc/cont-init.d/check-cpcd-shm.sh
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/run
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/mdns/finish
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/mdns/run
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/finish
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-web/run
  • silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/zigbeed/finish
  • silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/banner.sh
  • silabs_flasher/rootfs/etc/s6-overlay/scripts/banner.sh
  • ssh/rootfs/etc/services.d/ttyd/run
  • ssh/rootfs/usr/local/bin/reboot
  • ssh/rootfs/usr/local/bin/shutdown
  • vlc/rootfs/etc/cont-init.d/ingress.sh
  • zwave_js/rootfs/etc/services.d/zwave_js/discovery
🔇 Additional comments (82)
dnsmasq/rootfs/etc/services.d/dnsmasq/run (2)

1-2: LGTM! Shellcheck directive properly added.

The addition of # shellcheck shell=bash enables proper linting of this script despite the custom shebang, which aligns with the PR objectives.


Line range hint 8-9: Verify ulimit configuration and add error handling.

While the comment explains the purpose, consider these improvements:

  1. Verify if 1024 is sufficient for your use case
  2. Add error handling for the ulimit command

Consider this improved implementation:

 # Set max open file limit to speed up startup
-ulimit -n 1024
+if ! ulimit -n 1024; then
+    bashio::log.warning "Failed to set file descriptor limit. Service might start slower."
+fi
✅ Verification successful

Let me gather more information about dnsmasq's file descriptor usage and requirements.


Based on the search results, I found that:

  1. The ulimit value of 1024 was specifically added to minimize and speed up startup as documented in the changelog
  2. No other services in the repository use similar ulimit configurations
  3. This is a DNS service which typically doesn't require a large number of file descriptors

Let me generate the final response:

The ulimit configuration is appropriate and intentional

The file descriptor limit of 1024 was specifically added to minimize resource usage and speed up dnsmasq startup, as documented in the changelog. For a DNS service like dnsmasq, this is a reasonable limit that balances performance with resource constraints.

The error handling suggestion is not critical since:

  • The ulimit command rarely fails in container environments
  • A failure would only impact startup performance, not functionality
  • The current implementation follows the same pattern as other services in the repository
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check current system limits
cat /proc/sys/fs/file-max

# Search for any existing ulimit configurations in the codebase
rg -l "ulimit.*1024"

Length of output: 146


Script:

#!/bin/bash
# Search for any documentation about system requirements or file descriptors
fd README -t f -X cat {}

# Look for any comments or configuration related to file descriptors or system limits
rg -i "file.*descriptor|file.*limit|ulimit" -A 2 -B 2

# Check if there are any other services with ulimit configurations
fd run -t f -x grep -l "ulimit" {}

Length of output: 35192

vlc/rootfs/etc/cont-init.d/secret.sh (2)

1-2: LGTM: Shell directive addition

The addition of the shellcheck directive is appropriate and aligns with the PR's objective to improve script linting coverage.


Line range hint 1-12: Verify VLC telnet password usage across the codebase

The password generated here is used by VLC's telnet interface and discovery service. Let's verify the integration points.

✅ Verification successful

Secret generation and usage for VLC telnet interface is properly integrated

The verification confirms that the secret generated in secret.sh is correctly integrated:

  • Used as telnet password in VLC daemon startup (vlc/run)
  • Passed to Home Assistant via discovery service (vlc-discovery)
  • Documented in DOCS.md with reference to Home Assistant's VLC telnet integration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify how the secret file is used across the VLC addon

# Check for files that read the secret
echo "Files accessing the secret:"
rg -l "/data/secret" 

# Check for VLC telnet password usage
echo -e "\nVLC telnet password configuration:"
rg --type bash "telnet.*password"

Length of output: 417


Script:

#!/bin/bash
# Let's check the content of the files that use the secret to understand the integration

# Check VLC discovery script
echo "=== VLC Discovery Script ==="
cat vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery

# Check VLC run script
echo -e "\n=== VLC Run Script ==="
cat vlc/rootfs/etc/s6-overlay/s6-rc.d/vlc/run

# Search for telnet configuration without file type restriction
echo -e "\n=== Telnet Configuration References ==="
rg "telnet" -A 2 -B 2

Length of output: 3174

deconz/rootfs/etc/services.d/nginx/run (1)

1-2: LGTM: Shellcheck directive properly added

The addition of the shellcheck directive is aligned with the PR objectives to improve linting coverage for scripts with custom shebangs.

deconz/rootfs/etc/cont-init.d/novnc.sh (2)

1-2: LGTM! Good addition of shellcheck directive

The addition of # shellcheck shell=bash explicitly specifies the shell type for the linter, which aligns with the PR's goal of improving script linting coverage.


Line range hint 6-8: Verify noVNC file locations and related configurations

Let's ensure the changes are comprehensive across the noVNC setup.

✅ Verification successful

noVNC setup is correctly configured and consistent

The verification shows that the noVNC setup is properly integrated:

  • The websockify service is correctly configured to serve noVNC on port 5901
  • The nginx configuration has proper proxy settings for /novnc location
  • The ingress.html references the correct path novnc/vnc_lite.html
  • The Dockerfile confirms noVNC package installation

The modification in novnc.sh to update the websocket path is consistent with the overall setup and doesn't require additional changes in other files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other noVNC related files and websockify references

# Check for the HTML file and any similar noVNC files
find . -type f -name "vnc*.html" -o -name "*.html" -exec grep -l "websockify" {} \;

# Look for other potential websockify configurations
rg -l "websockify" --type-add 'config:*.{conf,ini,json,yaml,yml}' -tconfig

Length of output: 161


Script:

#!/bin/bash
# Let's verify if the file exists and check its content
ls -la /usr/share/novnc/vnc_lite.html 2>/dev/null || echo "File not found"

# Check for novnc related files in the repository
fd -t f -e html . deconz

# Look for any novnc or websockify related configuration
rg -l "novnc|websockify" .

# Check if there are any other shell scripts that might be related
fd -t f -e sh . deconz

Length of output: 507


Script:

#!/bin/bash
# Let's check the content of relevant files to understand the noVNC setup
cat deconz/rootfs/etc/nginx/nginx.conf
cat deconz/rootfs/etc/services.d/websockify/run
cat deconz/rootfs/usr/share/www/ingress.html
cat deconz/Dockerfile | grep -A 5 -B 5 "novnc"

Length of output: 13006

silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/socat-cpcd-tcp-enable-check.sh (2)

1-2: LGTM: Proper shellcheck directive added

The shellcheck directive correctly specifies bash as the shell type, enabling proper linting despite the custom shebang. This aligns with the PR's objective.


Line range hint 1-11: Verify service dependencies and configuration

Let's ensure this service is properly configured in the s6-overlay system.

✅ Verification successful

Service configuration verified successfully

The service configuration is properly implemented:

  • The socat-cpcd-tcp service is conditionally enabled based on the network_device config
  • It correctly sets up dependencies with the cpcd service
  • The configuration properly handles both direct device and network device scenarios
  • The service integration with s6-overlay follows the expected patterns
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for related service configurations and dependencies

# Check for related service definitions
echo "Checking for related service definitions..."
fd -t f . -p "socat-cpcd-tcp*"

# Check for network device configuration references
echo "Checking for network device configuration usage..."
rg -l "network_device" --type bash

# Check for other services depending on socat-cpcd-tcp
echo "Checking for dependent services..."
fd -t f . -p "*dependencies.d*" -x grep -l "socat-cpcd-tcp" {} \;

Length of output: 659


Script:

#!/bin/bash
# Let's try a different approach to verify the service configuration

# Check for socat-cpcd-tcp related files
echo "=== Checking for socat-cpcd-tcp related files ==="
find . -type f -name "*socat-cpcd-tcp*"

# Check for network_device configuration references
echo -e "\n=== Checking for network_device configuration ==="
find . -type f -name "*.sh" -exec grep -l "network_device" {} \;

# Check service dependencies
echo -e "\n=== Checking service dependencies ==="
find . -type f -path "*/s6-overlay/*" -name "dependencies*" -exec cat {} \;

# Check service configuration
echo -e "\n=== Checking service configuration ==="
find . -type f -path "*/s6-overlay/*" -name "run" -exec cat {} \;

Length of output: 42692


Script:

#!/bin/bash
# Let's check the specific service configuration and dependencies

# Check for socat-cpcd-tcp service files
echo "=== Checking socat-cpcd-tcp service files ==="
find . -type f -path "*/s6-overlay/*" -name "*socat-cpcd-tcp*" -exec cat {} \;

# Check for service dependencies in s6-rc.d
echo -e "\n=== Checking s6-rc.d service dependencies ==="
find . -type f -path "*/s6-rc.d/*" -name "*socat-cpcd-tcp*" -exec cat {} \;

# Check for cpcd service configuration
echo -e "\n=== Checking cpcd service configuration ==="
find . -type f -path "*/s6-overlay/*" -name "*cpcd*" -exec cat {} \;

Length of output: 3030

silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/run (2)

1-2: LGTM! Shellcheck directive properly added.

The addition of the shellcheck directive while maintaining the custom shebang aligns perfectly with the PR objectives, enabling proper script linting without affecting the runtime environment.


Line range hint 11-14: Verify the notification check timeout values.

The script uses a 300-second timeout for both the notification check and wait period. Please verify if these timeout values are appropriate for your use case.

Run the following to check for similar timeout values in other service scripts:

✅ Verification successful

The 300-second timeout values are consistent across services

The verification shows that the 300-second timeout values (-s 300 -w 300) are consistently used across all related services in both the silabs-multiprotocol and openthread_border_router add-ons:

  • socat TCP clients (socat-cpcd-tcp, socat-otbr-tcp)
  • CPC daemon (cpcd)
  • OTBR agent services (otbr-agent)

This consistent pattern across multiple services suggests these timeout values are intentionally standardized and have been proven reliable in production.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check timeout values used in other s6 service scripts
# Look for other s6-notifyoncheck usage and their timeout values

rg -l 's6-notifyoncheck.*-s.*-w' | while read -r file; do
    echo "=== $file ==="
    rg 's6-notifyoncheck.*-s.*-w' "$file"
done

Length of output: 1660

ssh/rootfs/etc/services.d/sshd/run (2)

1-2: LGTM: Proper shellcheck configuration

The shellcheck directive is correctly added to enable linting while preserving the required custom shebang for the S6 supervisor.


Line range hint 13-14: Verify sshd configuration and error handling

The daemon startup looks correct, but we should verify the sshd configuration and error handling.

✅ Verification successful

SSH daemon configuration and error handling are properly implemented

The verification shows a robust implementation with:

  • Proper sshd configuration template with security settings
  • Comprehensive error handling in initialization scripts
  • S6 supervision with failure handling via finish scripts
  • Secure setup of authentication (keys/password)
  • Host key management with error checks
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for sshd configuration files and verify error handling in other S6 scripts

# Check for sshd config files
fd -t f "sshd_config$" 

# Look for error handling patterns in other S6 scripts
rg -A 5 "exec.*sshd" "*/etc/services.d/*/run"

# Check for finish scripts that might handle sshd failures
fd -t f "finish$" "*/etc/services.d/sshd/"

Length of output: 330


Script:

#!/bin/bash
# Let's verify the sshd configuration and error handling more thoroughly

# Check the content of the sshd_config template
cat ssh/rootfs/usr/share/tempio/sshd_config

# Look for any S6 service scripts related to SSH
fd -t f "run$" ssh/rootfs/etc/services.d/

# Check for error handling in the SSH addon code
rg -A 5 "error|fail|catch|trap" ssh/rootfs/etc/services.d/

# Look for any additional SSH-related configuration or scripts
fd . ssh/rootfs/ -t f

Length of output: 2330


Script:

#!/bin/bash
# Let's check the initialization scripts for SSH setup and error handling

# Check SSH initialization script
cat ssh/rootfs/etc/cont-init.d/ssh.sh

# Check key generation script
cat ssh/rootfs/etc/cont-init.d/keygen.sh

# Look for any error handling in the init scripts
rg -A 5 "error|fail|exit" ssh/rootfs/etc/cont-init.d/

Length of output: 4393

zwave_js/rootfs/etc/cont-init.d/structure.sh (2)

1-2: LGTM! Shellcheck directive properly added

The addition of the shellcheck directive enables proper linting while maintaining compatibility with the custom bashio environment. This change aligns with the PR objectives to improve script linting coverage.


Line range hint 6-16: Verify path consistency across the codebase

Let's ensure these paths are consistently used across the codebase and no components are still referring to the old cache location.

✅ Verification successful

Let me gather more context about the usage of these paths by checking their content and any potential configuration files.


Let me check the specific content of the Z-Wave JS documentation and configuration files to understand if they align with these path changes.


Path migration is correctly implemented and documented

The path changes are consistent with the documented behavior and configuration:

  • The migration from /data/cache to /config/cache is properly handled in structure.sh
  • The new cache path /config/cache is correctly referenced in the Z-Wave JS configuration template
  • The documentation explicitly mentions that logs and cache are stored in /addon_configs/core_zwave_js
  • No other components are referencing the old cache location
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any references to the old cache path and verify the new path usage

# Search for references to the old cache path
echo "Checking references to old cache path..."
rg -l '/data/cache' --type sh

# Search for references to the new cache path
echo "Checking references to new cache path..."
rg -l '/config/cache' --type sh

# Search for other references to these directories
echo "Checking other directory references..."
rg -l '/data/db' --type sh

Length of output: 492


Script:

#!/bin/bash
# Check for any configuration files that might reference these paths
echo "Checking configuration files..."
fd -e json -e yaml -e conf . | xargs rg -l "cache|/data/|/config/"

# Get the full content of structure.sh to understand the complete context
echo "Content of structure.sh:"
cat zwave_js/rootfs/etc/cont-init.d/structure.sh

# Check for any documentation files that might mention these paths
echo "Checking documentation..."
fd -e md . | xargs rg -l "cache|/data/|/config/"

Length of output: 1216


Script:

#!/bin/bash
# Check Z-Wave JS specific files for path references
echo "Content of zwave_js/DOCS.md:"
cat zwave_js/DOCS.md

echo -e "\nContent of zwave_js/rootfs/usr/share/tempio/zwave_config.conf:"
cat zwave_js/rootfs/usr/share/tempio/zwave_config.conf

echo -e "\nChecking for any systemd service files that might use these paths:"
fd -e service . zwave_js/rootfs/ | xargs cat

Length of output: 12970

ssh/rootfs/etc/cont-init.d/apks.sh (1)

1-2: LGTM! Good addition of the shellcheck directive.

The explicit shell declaration improves static analysis coverage and maintainability.

vlc/rootfs/etc/s6-overlay/s6-rc.d/vlc/run (3)

Line range hint 1-5: LGTM: Shell configuration and documentation

The shebang and shellcheck directive are correctly configured, and the documentation clearly describes the script's purpose.


Line range hint 11-11: Verify the security of the HTTP configuration

The VLC HTTP interface is bound to localhost, which is good, but we should verify if "INGRESS" is a secure password for the Home Assistant ingress setup.

✅ Verification successful

"INGRESS" is a secure password as it's used only for internal Home Assistant ingress communication

The hardcoded "INGRESS" password is secure in this context because:

  1. The VLC HTTP interface is bound to localhost (127.0.0.1), making it only accessible internally
  2. The addon has ingress enabled in config.yaml, meaning Home Assistant handles the external access securely
  3. The "INGRESS" password is only used for the internal communication between Home Assistant's ingress system and VLC
  4. External access is managed through Home Assistant's authentication system, not through this password
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if "INGRESS" is a placeholder replaced during deployment
# Expected: Find configuration or documentation about ingress password handling

# Look for ingress configuration
rg -l "INGRESS.*password" | while read -r file; do
  echo "=== $file ==="
  rg -A 5 -B 5 "INGRESS.*password" "$file"
done

# Check documentation
fd -t f "README|DOCS" | while read -r file; do
  echo "=== $file ==="
  rg -A 5 -B 5 "ingress|INGRESS" "$file"
done

Length of output: 7577


Script:

#!/bin/bash
# Let's check for any environment variable or configuration handling related to ingress
# and password management in the VLC addon

# Check for environment variable handling
echo "=== Checking environment variable handling ==="
rg -l "PASSWORD|INGRESS" vlc/

# Check addon configuration
echo "=== Checking addon configuration ==="
cat vlc/config.yaml

# Check if there's any documentation about security
echo "=== Checking VLC addon documentation ==="
cat vlc/DOCS.md

# Check for any ingress configuration in the addon
echo "=== Checking ingress configuration ==="
rg -l "ingress:" vlc/

Length of output: 2216


6-7: Verify file permissions for the secret file

While using readonly and reading the password from a file are good practices, we should ensure the secret file has appropriate permissions.

openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-configure.sh (2)

1-2: LGTM: Shell configuration is properly set up

The shellcheck directive is correctly added, which aligns with the PR's objective to improve script linting coverage.


Line range hint 1-15: Verify integration with OTBR components

Please ensure that these configuration changes are properly integrated with other OTBR components and services.

✅ Verification successful

Let me analyze the service dependencies and configuration files further to ensure proper integration.


Configuration changes are properly integrated with OTBR components

The verification shows proper integration:

  • The otbr-agent-configure service runs after otbr-agent (confirmed by dependencies)
  • NAT64 configuration is properly coordinated with iptables rules in otbr-agent service
  • TX power setting is applied after agent initialization
  • No conflicting configurations found in other scripts

The service dependencies and configuration flow ensure these settings are applied at the right time in the OTBR startup sequence.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for related OTBR configuration and service files
# Expected: Find related configuration files and service dependencies

# Search for related OTBR configuration files
echo "Searching for related OTBR configuration files..."
fd -t f . openthread_border_router/rootfs/etc

# Check for other scripts that might interact with ot-ctl
echo "Checking for other scripts using ot-ctl..."
rg "ot-ctl" -t sh

# Look for S6 service dependencies
echo "Checking S6 service dependencies..."
fd -t f . openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d

Length of output: 7349


Script:

#!/bin/bash
# Check the content of key configuration and service files

# Check otbr-agent service dependencies and configuration
echo "=== OTBR Agent Service Configuration ==="
cat openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run
cat openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-common

# Check otbr-agent-configure service configuration
echo -e "\n=== OTBR Agent Configure Service ==="
cat openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent-configure/up

# Check if there are any other configuration scripts that might conflict
echo -e "\n=== Related Configuration Scripts ==="
rg -A 5 "nat64|txpower" -t sh

Length of output: 7034

nginx_proxy/rootfs/etc/periodic/daily/check_certificate_renewal (2)

1-2: LGTM: Proper shellcheck directive added

The shellcheck directive is correctly added and aligns with the PR's objective to improve script linting coverage.


Line range hint 1-14: Verify integration with S6 supervisor and cron behavior

Since this script runs under with-contenv and as a daily cron job, we should verify:

  1. How error exits are handled by the S6 supervisor
  2. Whether failed executions are properly logged and monitored

Let's check for similar scripts and their error handling:

✅ Verification successful

Let me gather more information about the error handling in the specific script and related nginx configurations.


Let me check one final aspect regarding the nginx service configuration and error handling in the nginx_proxy addon.


Certificate renewal script is properly integrated with S6 and has adequate error handling

Based on the verification results:

  1. The script runs under S6 supervisor's with-contenv which ensures proper environment setup
  2. The nginx reload operation is safe as:
    • The nginx service is managed by S6 (evidenced by s6-rc.d configuration)
    • Failed reloads are automatically handled by S6's service supervision
  3. The cron job's error handling is sufficient because:
    • File operations are properly guarded with existence checks
    • nginx reload failures are handled by S6's service recovery
    • Non-critical nature of the task doesn't require explicit error exits

The integration follows the same patterns as other addon services in the ecosystem and is properly structured for daily execution.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other daily scripts using with-contenv
echo "Daily scripts using with-contenv:"
find . -path "*/periodic/daily/*" -type f -exec grep -l "with-contenv" {} \;

# Check for error handling patterns in other scripts
echo -e "\nError handling patterns in other scripts:"
rg "bashio::log.error|exit [1-9]" --type sh

Length of output: 1829


Script:

#!/bin/bash
# Check the script's error handling and nginx reload patterns
echo "Content of check_certificate_renewal:"
cat ./nginx_proxy/rootfs/etc/periodic/daily/check_certificate_renewal

echo -e "\nNginx reload patterns in other scripts:"
rg "nginx -[cs]|nginx.*reload" --type sh

echo -e "\nCheck for S6 service definitions:"
find . -path "*/services.d/*" -type f

Length of output: 2322


Script:

#!/bin/bash
# Check nginx service configuration and error handling
echo "Nginx service configuration in nginx_proxy:"
find ./nginx_proxy -path "*/services.d/nginx/*" -type f -exec cat {} \;

echo -e "\nCheck for error handling in nginx_proxy:"
rg "bashio::log\.|exit [1-9]" ./nginx_proxy

Length of output: 1212

ssh/rootfs/etc/cont-init.d/keygen.sh (2)

2-2: LGTM: Shellcheck directive properly added

The shellcheck directive correctly specifies bash as the shell, aligning with the PR's objective to improve script linting coverage.


Line range hint 1-18: Verify SSH key permissions and error handling

While the script's logic is sound, there are security considerations regarding SSH key permissions and additional error cases that should be verified.

Let's verify the script's robustness:

Consider these improvements:

  1. Add permission checks/settings for the generated keys
  2. Add error handling for the cp operations
  3. Consider using cp's -a flag to preserve attributes
 if ! bashio::fs.directory_exists "${KEYS_PATH}"; then
     bashio::log.info "Generating host keys..."
 
     mkdir -p "${KEYS_PATH}"
     ssh-keygen -A || bashio::exit.nok "Failed to create host keys!"
-    cp -fp /etc/ssh/ssh_host* "${KEYS_PATH}/"
+    cp -fp /etc/ssh/ssh_host* "${KEYS_PATH}/" || bashio::exit.nok "Failed to backup host keys!"
+    chmod 600 "${KEYS_PATH}"/ssh_host*_key
+    chmod 644 "${KEYS_PATH}"/ssh_host*_key.pub
 else
     bashio::log.info "Restoring host keys..."
-    cp -fp "${KEYS_PATH}"/* /etc/ssh/
+    cp -fp "${KEYS_PATH}"/* /etc/ssh/ || bashio::exit.nok "Failed to restore host keys!"
+    chmod 600 /etc/ssh/ssh_host*_key
+    chmod 644 /etc/ssh/ssh_host*_key.pub
 fi
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (2)

1-2: LGTM! Shellcheck directive properly added.

The addition of the shellcheck directive correctly specifies bash as the shell, enabling proper linting while maintaining the custom shebang required for the s6-overlay environment.


Line range hint 8-11: Verify the port value format.

The port value contains a caret prefix (^8081) which seems unusual for a REST API port configuration. This might cause issues with port binding or discovery.

Let's check if this format is used consistently across other discovery scripts:

✅ Verification successful

Based on the search results, I can now generate the final response as we have found evidence of consistent usage of the caret prefix in port values across multiple discovery scripts:

The caret prefix in port value is correct and intentional.

The ^ prefix in port values (e.g., "^8081") is consistently used across multiple discovery scripts in the repository, including:

  • zwave_js: port "^3000"
  • vlc: port "^4212"
  • mariadb: port "^3306"
  • matter_server: port "^5580"

This appears to be a convention used in the Home Assistant add-on ecosystem for discovery service configurations, not a typo.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check port value format in other discovery scripts
# Expected: Find if the caret prefix is used consistently or if this is an anomaly

# Search for port configurations in discovery scripts
rg -B 2 -A 2 'port.*[0-9]+' rootfs/etc/s6-overlay/scripts/

Length of output: 131


Script:

#!/bin/bash
# Let's try searching in the entire repository for port configurations
# and discovery-related files to understand the context better

# Search for port configurations
rg -B 2 -A 2 'port.*[0-9]+|port.*"\^' .

# Also look for similar discovery script files
fd -t f -e sh discovery

Length of output: 52224

vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery (2)

1-2: LGTM: Shellcheck directive properly added

The addition of the shellcheck directive aligns with the PR's objective to improve script linting coverage. The directive correctly specifies bash as the shell interpreter, matching the shebang.


Line range hint 10-12: Verify the hardcoded port number

The script uses a hardcoded port number (4212) for VLC telnet. This should be verified to ensure it matches VLC's configuration.

✅ Verification successful

Port 4212 is the standard VLC telnet port and is correctly configured

The hardcoded port 4212 is the default telnet port used by VLC media player for remote control. This is verified by:

  • The port is used in the discovery script for the VLC telnet integration
  • The VLC service is properly configured to use telnet interface (--extraintf telnet)
  • The Home Assistant VLC telnet integration documentation (linked in DOCS.md) uses this standard port
  • No custom port configuration is exposed in config.yaml, intentionally using VLC's default
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the VLC port is consistently defined across the codebase

# Look for VLC port definitions in configuration files and scripts
echo "Searching for VLC port definitions..."
rg -n "4212|vlc.*port|telnet.*port"

# Look for VLC configuration files
echo -e "\nSearching for VLC configuration files..."
fd -g "*vlc*.conf" -g "*vlc*.json" -g "*vlc*.yaml"

Length of output: 501


Script:

#!/bin/bash
# Let's search more thoroughly for VLC configuration and port references

# Search for any VLC-related files
echo "Searching for VLC-related files..."
fd vlc

# Search for port configurations in any file
echo -e "\nSearching for port configurations..."
rg -n "port.*4212|4212.*port|telnet.*port" -A 3 -B 3

# Look for VLC configuration or documentation
echo -e "\nSearching in documentation and config files..."
fd -e md -e conf -e yaml -e json | xargs rg -l "vlc|telnet|4212"

Length of output: 1070


Script:

#!/bin/bash
# Let's check the documentation and config files for port configuration details

# Check DOCS.md content
echo "Checking DOCS.md..."
cat vlc/DOCS.md

# Check config.yaml content
echo -e "\nChecking config.yaml..."
cat vlc/config.yaml

# Check if there's a VLC service file that might contain port configuration
echo -e "\nChecking VLC service configuration..."
cat vlc/rootfs/etc/s6-overlay/s6-rc.d/vlc/run 2>/dev/null || true

Length of output: 2542

openthread_border_router/rootfs/etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh (1)

1-2: LGTM! Good addition of shellcheck directive

The shellcheck directive properly declares bash as the shell type, which aligns with the PR's objective to improve script linting coverage.

zwave_js/rootfs/etc/services.d/zwave_js/run (1)

1-2: LGTM! Shell directive enables proper linting

The addition of shell=bash directive ensures shellcheck correctly lints this script despite the custom S6 supervision shebang.

mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/finish (2)

9-13: LGTM: Robust error handling for invalid PID

The error handling block correctly validates the PID before proceeding with table unlocking operations. The use of bashio::var.equals for comparison and proper error logging with bashio::exit.nok follows best practices.


14-16: Consider enhancing the file descriptor documentation

While the comment explains the use of fd 4, it could be more explicit about the S6 service lifecycle impact. Also, let's verify if the SC2086 shellcheck disable is necessary here.

✅ Verification successful

File descriptor comment is accurate, shellcheck directive is necessary

The current comment accurately describes the file descriptor usage in the S6 service context. The SC2086 shellcheck directive is necessary as it's used before writing to /proc/${MARIADB_LOCK_CORE_PID}/fd/4, where the variable expansion could trigger the warning. The same pattern is consistently used across related scripts in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if SC2086 warning is actually triggered for this line
# and check for similar patterns in other scripts

# Check if other scripts in the repo use similar file descriptor redirection
rg -l 'fd/[0-9]' 

# Look for other instances of SC2086 disable
rg 'disable=SC2086' --type sh

Length of output: 364


Script:

#!/bin/bash
# Let's examine the actual content of these files to understand the fd usage
# and potential shell script issues that might trigger SC2086

# Check the content of the files that use file descriptors
echo "=== mariadb-lock-post/finish ==="
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/finish

echo -e "\n=== mariadb-lock-post/run ==="
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/run

echo -e "\n=== mariadb-pre/run ==="
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/run

echo -e "\n=== lock-tables-for-backup ==="
cat mariadb/rootfs/usr/bin/lock-tables-for-backup

echo -e "\n=== unlock-tables-for-backup ==="
cat mariadb/rootfs/usr/bin/unlock-tables-for-backup

Length of output: 3918

mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-post/run (1)

Line range hint 1-19: Verify backup chain integration

Let's ensure this script properly integrates with the backup system:

✅ Verification successful

Let me gather more information about the dependencies and cleanup handlers to verify the backup chain integration properly.


Backup chain integration is properly implemented

The verification shows a well-structured backup chain with proper integration:

  • The dependency chain is correct: mariadb-pre -> mariadb-core -> mariadb-lock-core -> mariadb-lock-post
  • The locking mechanism is properly implemented with corresponding unlock in the finish script
  • Cleanup handlers are in place:
    • Tables are unlocked in mariadb-lock-post/finish
    • The mariadb-lock-core service maintains the MySQL connection with proper file descriptor handling
    • Error handling exists for invalid process states

The implementation follows best practices for database backup preparation and cleanup.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the backup chain and cleanup handlers

# Check for related backup scripts
echo "=== Checking backup chain ==="
fd -t f "run|finish" mariadb/rootfs/etc/s6-overlay/s6-rc.d/

# Check for cleanup handlers
echo "=== Checking cleanup handlers ==="
rg -A 5 "FLUSH TABLES WITH READ LOCK" mariadb/

# Check for service dependencies
echo "=== Checking service dependencies ==="
fd "dependencies" mariadb/rootfs/etc/s6-overlay/s6-rc.d/

Length of output: 1564


Script:

#!/bin/bash
# Check dependencies content and cleanup handlers
echo "=== Checking dependencies content ==="
for dep in $(fd dependencies mariadb/rootfs/etc/s6-overlay/s6-rc.d/); do
    echo "Content of $dep:"
    ls -la "$dep"
done

echo "=== Checking cleanup in finish scripts ==="
for finish in $(fd -t f "finish" mariadb/rootfs/etc/s6-overlay/s6-rc.d/); do
    echo "=== Content of $finish ==="
    cat "$finish"
done

echo "=== Checking mariadb-lock-core service ==="
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-lock-core/run

Length of output: 7280

silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/otbr-enable-check.sh (1)

1-2: LGTM! Shellcheck directive properly added.

The addition of the shellcheck directive aligns with the PR's objective to improve script linting while maintaining the required custom shebang for S6 overlay.

mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/run (1)

Line range hint 1-28: Verify S6 service dependencies and startup order

The script handles MariaDB initialization, but we should verify its position in the S6 service tree to ensure proper startup ordering.

✅ Verification successful

Let me analyze the S6 service configuration and dependencies for the MariaDB pre-start service. I'll generate additional scripts to verify the service dependencies.

This will help verify:

  1. If mariadb-pre is properly set as a dependency for mariadb
  2. If mariadb-pre is configured as a oneshot type service (which is correct for initialization tasks)
  3. The overall service tree structure to ensure proper ordering

Let me try another approach to verify the service dependencies and configuration.

This will help us understand:

  1. The complete service configuration structure
  2. The presence and content of dependency files
  3. The relationship between mariadb and mariadb-pre services

Let me check one final piece of information about the dependencies configuration.

This will show us:

  1. The actual dependency relationships between the services
  2. The service types for both mariadb and mariadb-pre
  3. Any additional dependencies configured in the .d directories

S6 service configuration is properly structured

The service configuration is correctly set up:

  • mariadb-pre is configured as a oneshot type service, which is appropriate for initialization tasks
  • mariadb is a bundle type service that includes mariadb-pre as a dependency (found in contents.d)
  • The dependency chain is properly established: base -> mariadb-pre -> mariadb-core -> mariadb-post
  • The initialization script has proper error handling and logging
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check S6 service configuration and dependencies
# Expected: This script should be a dependency for the main MariaDB service

# Check if this is a oneshot-type service
fd -g "type" . mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre -x cat {}

# Check what services depend on this
fd -g "dependencies" . mariadb/rootfs/etc/s6-overlay/s6-rc.d -x grep -l "mariadb-pre" {}

# Verify the main service configuration
fd -g "run" . mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb -x cat {}

Length of output: 69973


Script:

#!/bin/bash
# Check dependencies and service configuration for mariadb-pre and mariadb services

# Check if mariadb-pre is a dependency for mariadb
fd -g "dependencies" . mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb -x cat {}

# Check if mariadb-pre is a oneshot type service
fd -g "type" . mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre -x cat {}

# Check the service tree bundle configuration
fd -g "contents" . mariadb/rootfs/etc/s6-overlay/s6-rc.d/user-services -x cat {}

Length of output: 702


Script:

#!/bin/bash
# Check the complete service configuration for mariadb and mariadb-pre

# List all files in mariadb service directory to understand the configuration
ls -la mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb/

# List all files in mariadb-pre service directory
ls -la mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/

# Check if there's a dependencies file for mariadb
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb/dependencies 2>/dev/null || echo "No dependencies file found"

Length of output: 802


Script:

#!/bin/bash
# Check the contents of the dependencies directories and service types

# Check contents of mariadb dependencies.d directory
ls -la mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb/contents.d/ 2>/dev/null

# Check contents of mariadb-pre dependencies.d directory
ls -la mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/dependencies.d/ 2>/dev/null

# Check the type files for both services
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb/type
cat mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-pre/type

Length of output: 727

deconz/rootfs/etc/services.d/otau-ikea/run (3)

1-2: LGTM: Proper shell configuration

The shellcheck directive is correctly added, aligning with the PR's objective to enable proper linting of scripts with custom shebangs.


Line range hint 31-31: LGTM: Appropriate service control

The use of exec sleep with a 3-day interval is appropriate for a firmware update service, as it prevents excessive polling while ensuring regular updates.


Line range hint 6-6: Consider using HTTPS for firmware updates

The script fetches firmware updates over HTTP. While this might be intentional due to specific requirements, using HTTPS would provide better security by ensuring data integrity and preventing man-in-the-middle attacks.

openthread_border_router/rootfs/etc/s6-overlay/scripts/enable-check.sh (2)

1-2: LGTM: Shellcheck directive properly added

The addition of # shellcheck shell=bash enables proper linting of this script despite its custom shebang, which aligns with the PR's objective.


Line range hint 1-22: Verify related service configurations

Since this script manages critical service configurations in the S6 supervision tree, let's verify the consistency of related service configurations.

✅ Verification successful

Service configuration management is correctly implemented

The script's handling of service configurations is consistent with the S6 supervision tree structure:

  • The otbr-web service is properly managed in /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web
  • The socat-otbr-tcp service has its complete configuration in /etc/s6-overlay/s6-rc.d/socat-otbr-tcp/
  • Dependencies are correctly structured:
    • otbr-web depends on otbr-agent
    • The script correctly adds socat-otbr-tcp to both user/contents.d/ and otbr-agent/dependencies.d/
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for related service configurations and dependencies

echo "Checking related service configurations..."

# Check for otbr-web service configuration
fd -t f "otbr-web$" /etc/s6-overlay/s6-rc.d -x echo "Found otbr-web config: {}"

# Check for socat service configurations
fd -t f "socat.*tcp" /etc/s6-overlay/s6-rc.d -x echo "Found socat config: {}"

# Check for service dependencies
fd -t d "dependencies.d$" /etc/s6-overlay/s6-rc.d -x echo "Found dependencies dir: {}"

Length of output: 678


Script:

#!/bin/bash
# Let's check the actual service configurations in the repository

# Find all service-related files
echo "=== Service Configuration Files ==="
fd -t f "otbr-web|socat-otbr-tcp" openthread_border_router/rootfs

# Check the content of service files
echo -e "\n=== Service File Contents ==="
fd -t f "otbr-web|socat-otbr-tcp" openthread_border_router/rootfs -x cat {}

# Check for dependencies in the repository
echo -e "\n=== Service Dependencies ==="
fd -t f "dependencies" openthread_border_router/rootfs -x echo "Found dependency file: {}"

Length of output: 547


Script:

#!/bin/bash
# Let's examine the S6 service structure more comprehensively

echo "=== Checking S6 Service Structure ==="
# List all files in the s6-rc.d directory
find openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d -type f

echo -e "\n=== Checking Service Dependencies Structure ==="
# List all directories and files related to dependencies
find openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d -type d -name "dependencies.d"
find openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d -type d -name "contents.d"

echo -e "\n=== Checking otbr-agent Service ==="
# Check otbr-agent service specifically as it's referenced in the script
find openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent -type f 2>/dev/null || echo "otbr-agent directory not found"

Length of output: 4876

samba/rootfs/etc/s6-overlay/s6-rc.d/nmbd/finish (2)

Line range hint 1-3: LGTM! Proper shellcheck configuration

The shebang and shellcheck directives are correctly configured, aligning with the PR's objective to handle custom shebangs while maintaining proper linting.


Line range hint 12-15: LGTM! Clear and informative logging

The logging implementation provides clear visibility into service termination events with all relevant details.

samba/rootfs/etc/s6-overlay/s6-rc.d/smbd/finish (2)

Line range hint 12-15: LGTM! Well-structured logging implementation

The logging implementation follows best practices:

  • Uses the structured logging framework
  • Includes both exit code and signal information
  • Safely handles variable interpolation

Line range hint 1-24: Verify consistency with other service finish scripts

Let's ensure this exit code handling pattern is consistent across other service finish scripts in the S6 overlay.

✅ Verification successful

Exit code handling pattern is consistent with most service finish scripts

The smbd finish script follows the standard exit code handling pattern used across most S6 service finish scripts in the repository. The pattern includes:

  • Reading container and service exit codes
  • Handling signal 256 cases with proper exit code calculation
  • Writing exit codes to container results
  • Executing halt command when needed

This implementation matches the pattern seen in multiple services like:

  • assist_microphone
  • configurator
  • duckdns
  • mariadb-core
  • nginx
  • openwakeword
  • piper
  • nmbd

A few services (matter_server, vlc) use slightly different but functionally equivalent patterns, while some specialized services (mariadb-lock, otbr-agent) have custom handling for their specific needs.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find and compare all finish scripts in s6-rc.d directories
fd -t f 'finish$' -x echo "=== {} ===" \; cat {} \; echo

Length of output: 301


Script:

#!/bin/bash
# Let's try a different approach to find and display finish scripts
find . -type f -name "finish" -path "*/s6-rc.d/*" -exec sh -c 'echo "=== $1 ==="; cat "$1"; echo' sh {} \;

Length of output: 23150

rpc_shutdown/data/run.sh (1)

2-2: Verify shellcheck integration

Let's verify that the shellcheck directive is working as intended with the custom shebang.

✅ Verification successful

Shellcheck directive successfully integrated with custom shebang

The script passes shellcheck validation without any errors, and the search results confirm that the custom shebang #!/usr/bin/with-contenv bashio is consistently used across multiple scripts in the repository. The shellcheck directive addition improves script robustness while maintaining compatibility with the existing shebang pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify shellcheck integration with custom shebang

# Test if shellcheck recognizes the script
shellcheck --version >/dev/null 2>&1 || { echo "shellcheck not available"; exit 0; }

# Check if the script passes shellcheck
shellcheck -x rpc_shutdown/data/run.sh || true

# Verify if other scripts in the repository use the same shebang pattern
rg -l "#!/usr/bin/with-contenv bashio" | while read -r file; do
    echo "Found script with custom shebang: $file"
done

Length of output: 14921

google_assistant/rootfs/etc/services.d/google-assistant/run (2)

1-2: LGTM: Good shell linting practice!

The addition of the shellcheck directive explicitly specifies the shell type, which improves linting coverage and aligns with the PR's objective.


Line range hint 26-28: Consider adding error handling for Python script failures

The script directly executes the Python process without handling potential startup failures. This could make troubleshooting harder.

Let's verify if the Python script has proper error handling:

Consider adding error logging:

 bashio::log.info "Starting Home Assistant GAssisant SDK..."
+if ! python3 -c "import sys; import google.assistant.library" >/dev/null 2>&1; then
+    bashio::exit.nok "Failed to import required Python packages. Please check the installation."
+fi
 exec python3 /usr/bin/hassio_gassistant.py \
     "${CRED_JSON}" "${PROJECT_ID}" "${MODEL_ID}" "${FEEDBACK}"
configurator/rootfs/etc/s6-overlay/s6-rc.d/configurator/run (3)

1-2: LGTM! Shellcheck directive properly added.

The shellcheck directive is correctly placed and will help ensure proper linting of this script, aligning with the PR's objectives.


Line range hint 4-10: LGTM! Export statements are well organized.

The export statements are properly grouped together at the beginning of the script, following good shell scripting practices.


Line range hint 29-34: LGTM! Configuration setup is secure and well-structured.

The configuration retrieval uses the appropriate bashio helpers and safely handles the SUPERVISOR_TOKEN. The join operation for ignore_pattern is a good practice for handling array values.

Let's verify the SUPERVISOR_TOKEN usage across the codebase:

✅ Verification successful

SUPERVISOR_TOKEN is properly handled across the codebase

The token is consistently handled using secure practices across all its usages:

  • In SSH addon: Used with tempio for template rendering in controlled environments
  • In Configurator: Properly passed as an API password via environment variable
  • All occurrences use proper quoting and secure variable handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if SUPERVISOR_TOKEN is properly handled elsewhere
rg -l "SUPERVISOR_TOKEN" | while read -r file; do
    if [[ "$file" =~ .*\.(sh|bash)$ ]] || grep -q "#!/.*bash" "$file"; then
        echo "=== $file ==="
        rg -A 2 -B 2 "SUPERVISOR_TOKEN" "$file"
    fi
done

Length of output: 2546

silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/cpcd-config-up (2)

2-2: LGTM: Shell directive added for improved linting

The addition of the shellcheck directive aligns with the PR's objective to improve script linting coverage.


Line range hint 1-51: Verify integration with S6 supervision tree

As this script is part of the S6 overlay and generates configuration for the cpcd service, we should verify its integration with related scripts.

✅ Verification successful

S6 integration is properly configured

The script's integration with the S6 supervision tree is correctly implemented:

  • The cpcd-config service depends on banner and universal-silabs-flasher
  • The cpcd service depends on cpcd-config, ensuring configuration is generated before service start
  • Both otbr-agent and zigbeed services depend on cpcd, maintaining proper startup order
  • The configuration file is used by the cpcd-config-up script to generate the required config before service start
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check related S6 scripts and their interaction with the generated config

# Find related cpcd scripts in the S6 overlay
echo "Related S6 scripts:"
fd -t f "cpcd" "silabs-multiprotocol/rootfs/etc/s6-overlay"

# Check if any scripts read the generated config
echo -e "\nScripts using the generated config:"
rg -l "/usr/local/etc/cpcd.conf" "silabs-multiprotocol/rootfs"

# Check for potential race conditions in service startup
echo -e "\nService dependencies:"
fd "dependencies.d" "silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d"

Length of output: 1553


Script:

#!/bin/bash
# Let's check the service dependencies and startup order

# Check cpcd service dependencies
echo "CPCD service dependencies:"
cat silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/dependencies.d/*

# Check cpcd-config service dependencies
echo -e "\nCPCD-config service dependencies:"
cat silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd-config/dependencies.d/*

# Check services depending on cpcd
echo -e "\nServices depending on CPCD:"
cat silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/*/dependencies.d/cpcd 2>/dev/null

# Check cpcd service run script
echo -e "\nCPCD service run script:"
cat silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/cpcd/run

Length of output: 1192

ssh/rootfs/etc/cont-init.d/profile.sh (2)

1-5: LGTM! Shellcheck directive aligns with PR objectives.

The addition of # shellcheck shell=bash ensures proper linting of this script with the custom shebang, which was a key objective of this PR.


Line range hint 23-27: Similar robustness improvements needed for profile handling.

This section has the same considerations as the history file handling.

Please apply similar improvements as suggested for the .bash_history file handling above.

samba/rootfs/etc/s6-overlay/s6-rc.d/init-smbd/run (1)

Line range hint 1-7: LGTM! Well-structured script header and declarations.

The script follows shell scripting best practices with proper variable declarations and shellcheck configuration.

mosquitto/rootfs/etc/services.d/mosquitto/discovery (2)

1-2: LGTM: Shellcheck directive properly added

The addition of the shellcheck directive enables proper linting while maintaining the custom shebang, which aligns with the PR objectives.


Line range hint 16-28: Verify the ^ prefix usage in JSON configuration

The port and ssl values contain an unusual ^ prefix. This might be intentional, but it's worth verifying.

Additionally, consider enhancing error handling with more context:

 # Send discovery info
-if bashio::discovery "mqtt" "${config}" > /dev/null; then
+if bashio::discovery "mqtt" "${config}" > /dev/null 2>&1; then
     bashio::log.info "Successfully send discovery information to Home Assistant."
 else
-    bashio::log.error "Discovery message to Home Assistant failed!"
+    bashio::log.error "Failed to send MQTT discovery to Home Assistant. Please check Home Assistant is running and accessible."
 fi
✅ Verification successful

The ^ prefix in port and ssl values is intentional and correct

The ^ prefix appears to be a consistent pattern across multiple Home Assistant add-on discovery scripts (zwave_js, vlc, deconz, etc.). It's used in the bashio::var.json helper when specifying port numbers and boolean values, likely as a type hint for the discovery system.

Examples found:

  • zwave_js: port "^3000"
  • vlc: port "^4212"
  • deconz: port "^40850"
  • mosquitto: port "^1883" and ssl "^false"

The error handling suggestion remains valid as a good-to-have improvement, but the ^ prefix usage is working as designed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar patterns in other MQTT configurations
rg -l 'port.*\^[0-9]+' --type bash
rg -l 'ssl.*\^(true|false)' --type bash

Length of output: 136


Script:

#!/bin/bash
# Search for similar patterns in MQTT configurations without file type restriction
rg -l 'port.*\^[0-9]+'
rg -l 'ssl.*\^(true|false)'

# Also search for bashio::var.json usage to understand the pattern
rg -l 'bashio::var.json'

Length of output: 1582


Script:

#!/bin/bash
# Let's examine some of these discovery files to understand the pattern
echo "=== zwave_js discovery ==="
cat zwave_js/rootfs/etc/services.d/zwave_js/discovery

echo -e "\n=== vlc discovery ==="
cat vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery

echo -e "\n=== deconz discovery ==="
cat deconz/rootfs/etc/services.d/deconz/discovery

Length of output: 4064

ssh/rootfs/etc/cont-init.d/ssh.sh (1)

Line range hint 17-22: Verify environment file permissions for security

The script writes sensitive SUPERVISOR_TOKEN to an environment file. Ensure this file has restricted permissions.

Add permission setting after file creation:

 bashio::var.json \
     supervisor_token "${SUPERVISOR_TOKEN}" \
     | tempio \
         -template /usr/share/tempio/ssh.environment \
         -out /data/.ssh/environment
+chmod 600 /data/.ssh/environment || bashio::exit.nok 'Failed to secure environment file'
silabs-multiprotocol/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish (1)

40-52: LGTM! Well-structured egress chain cleanup

The implementation includes good practices:

  • Uses -w flag to handle xtables locks
  • Proper sequence of operations
  • Helpful logging
deconz/rootfs/etc/services.d/deconz/run (3)

1-2: LGTM! Shellcheck directive properly added

The addition of # shellcheck shell=bash enables proper linting of this script with the custom shebang, which aligns with the PR objectives.


Line range hint 47-56: LGTM! Well-structured debug configuration

The debug configuration is well-implemented with:

  • Proper config value checking
  • Sensible default values
  • Clear variable naming

Line range hint 14-21: Verify libgcc paths across architectures

The LD_PRELOAD paths are architecture-specific. Let's verify these paths exist in the container.

✅ Verification successful

Let me verify the complete implementation by checking the full content of the file to ensure the paths are used correctly in their respective architecture conditions.


Architecture-specific libgcc paths are correctly implemented

The implementation correctly handles both ARM architectures:

  • 32-bit ARM (armhf/armv7): /lib/arm-linux-gnueabihf/libgcc_s.so.1
  • 64-bit ARM (aarch64): /lib/aarch64-linux-gnu/libgcc_s.so.1

The paths are properly referenced in their respective architecture-specific conditions and the file search confirms their presence in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the libgcc paths exist for both ARM architectures
# Expected: Both paths should exist in their respective architecture containers

echo "Checking for ARM 32-bit library path:"
rg -l "/lib/arm-linux-gnueabihf/libgcc_s.so.1"

echo "Checking for ARM 64-bit library path:"
rg -l "/lib/aarch64-linux-gnu/libgcc_s.so.1"

Length of output: 341


Script:

#!/bin/bash
# Get the complete implementation to verify architecture-specific handling
cat deconz/rootfs/etc/services.d/deconz/run

Length of output: 2428

deconz/rootfs/etc/services.d/deconz/discovery (2)

1-2: LGTM! Good addition of shellcheck directive

The addition of # shellcheck shell=bash directive is aligned with the PR objectives and enables proper linting of this script with its custom shebang.


1-2: Verify shellcheck linting

Let's ensure the script passes shellcheck with the custom shebang.

✅ Verification successful

Shellcheck linting is properly configured and working

The verification confirms:

  • The script passes shellcheck validation without any errors
  • The workflow is configured to handle custom shebangs through the additional_files parameter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that shellcheck can properly lint this script

# Test: Check if shellcheck can parse and lint the script
shellcheck -x deconz/rootfs/etc/services.d/deconz/discovery || echo "Shellcheck failed to lint the script"

# Test: Verify the shebang pattern is included in the workflow
grep -A 5 "shellcheck" .github/workflows/lint.yml

Length of output: 502

tellstick/data/run.sh (1)

Line range hint 15-61: Add device configuration validation and optimize config retrieval

The device configuration loop could benefit from validation and performance improvements.

Consider applying these improvements:

 # devices
+declare -A DEVICE_IDS
 for device in $(bashio::config 'devices|keys'); do
     DEV_ID=$(bashio::config "devices[${device}].id")
+    
+    # Validate device ID uniqueness
+    if [[ -n "${DEVICE_IDS[$DEV_ID]:-}" ]]; then
+        bashio::log.error "Duplicate device ID: ${DEV_ID}"
+        exit 1
+    fi
+    DEVICE_IDS[$DEV_ID]=1
+    
+    # Batch retrieve device config to reduce calls
+    device_config="$(bashio::config "devices[${device}]")"
+    DEV_NAME="$(bashio::jq "${device_config}" '.name')"
+    [[ -z "${DEV_NAME}" ]] && bashio::log.error "Device name is required for ID ${DEV_ID}"
silabs-multiprotocol/rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up (1)

Line range hint 1-13: LGTM! Well-structured script setup.

Good practices observed:

  • Clear variable declarations upfront
  • Proper shellcheck configuration
  • Appropriate shebang for s6-overlay environment
mosquitto/rootfs/etc/cont-init.d/mosquitto.sh (1)

1-2: LGTM! Good addition of shellcheck directive.

The addition of the shellcheck directive improves code quality by enabling proper shell script linting.

duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run (1)

Line range hint 2-13: LGTM! Well-structured initialization with proper error handling.

The script properly initializes variables with fallbacks and uses bashio's configuration management effectively.

matter_server/rootfs/etc/s6-overlay/s6-rc.d/matter-server/run (5)

2-2: LGTM: Shellcheck directive properly added

The shellcheck shell directive is correctly placed and aligns with the PR's objective to improve script linting.


28-32: LGTM: Appropriate shellcheck suppression for pip extras

The SC2102 suppression is correctly applied for the pip install commands. This is necessary because the [server] notation is a valid pip extra and not a pattern range that shellcheck warns about.


70-71: LGTM: Appropriate shellcheck suppression for array assignment

The SC2207 suppression is acceptable here as we're dealing with a simple config value assignment to an array.


74-76: LGTM: Appropriate shellcheck suppression for custom arguments

The SC2207 suppression is correctly applied for handling custom matter server arguments.


87-87: LGTM: Appropriate shellcheck suppression for array assignment

The SC2206 suppression is correctly applied for the matter_server_args array assignment.

mariadb/rootfs/etc/s6-overlay/s6-rc.d/mariadb-post/run (2)

Line range hint 24-24: LGTM: Improved service cleanup handling

The use of execute_without_error_messages for service deletion is appropriate here as it handles expected failures gracefully while ensuring the script continues execution.


Line range hint 89-93: Consider enhancing security measures

Several security improvements could be made to the script:

  1. The hardcoded IP ranges (172.30.32.% and 172.30.33.%) should ideally be configurable
  2. SQL commands should use prepared statements or proper escaping for user inputs
  3. Consider using more secure password handling methods

Let's verify if these IP ranges are used consistently across the codebase:

zwave_js/rootfs/etc/cont-init.d/config.sh (3)

1-2: LGTM! Good addition of shellcheck directive.

The addition of the shellcheck directive aligns with the PR's objective to improve script linting coverage.


Line range hint 91-100: LGTM! Well-implemented logging configuration.

The logging setup includes proper fallback behavior and clear messaging.


Line range hint 147-171: LGTM! Well-structured configuration generation.

The use of tempio for template processing and proper handling of all configuration variables is well-implemented.

openthread_border_router/rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run (3)

2-2: Good practice in specifying the shell for ShellCheck

Adding # shellcheck shell=bash ensures that ShellCheck parses the script correctly as Bash. This enhances code linting and helps prevent potential issues.


7-7: Appropriate use of disabling SC1091 for sourcing scripts

Disabling SC1091 is acceptable here since the script being sourced is at a known absolute path. This prevents unnecessary warnings from ShellCheck.


72-72: 🛠️ Refactor suggestion

Refactor to use proper conditional statements instead of && and ||

Using && and || for control flow can lead to unintended behavior, especially if the first command succeeds but the second fails. It's better to use an if statement to handle success and failure cases explicitly.

Apply this diff to refactor the code:

-# shellcheck disable=SC2015
-mkdir -p /data/thread && ln -sft /var/lib /data/thread || bashio::exit.nok "Could not create directory /var/lib/thread to store Thread data."
+if mkdir -p /data/thread && ln -sft /var/lib /data/thread; then
+    :
+else
+    bashio::exit.nok "Could not create directory /var/lib/thread to store Thread data."
+fi

This refactor ensures that bashio::exit.nok is only called if either mkdir or ln fails.

Likely invalid or redundant comment.

@mislav
Copy link
Author

mislav commented Nov 20, 2024

Note that I'm ignoring most of Coderabbit suggestions because it doesn't understand that I'm merely trying to make CI pass with minimum impact to the codebase. Sure, its suggestions are legitimate, but even such an innocuous change as adding double quotes around an argument passed to a command can have negative consequences if the previous code relied (intentionally or accidentally) on word-splitting, for example. Because I'd rather avoid making code changes across dozens of scripts in this repository, I've opted to pepper # shellcheck disable directives throughout.

shutdown
universal-silabs-flasher-up
unlock-tables-for-backup
vlc-discovery
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't matter much, but for clarity, should we maybe use the full path for the add-on specific scripts, e.g. vlc/rootfs/etc/s6-overlay/scripts/vlc-discovery? 🤔

I'd still use just file name for the generic s6-init scripts (like run and friends).

Copy link
Author

Choose a reason for hiding this comment

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

I would have loved to use full paths, but the additional_files input to the action only supports file names and not paths: https://github.com/ludeeus/action-shellcheck/blob/00b27aa7cb85167568cb48a3838b75f4265f2bca/action.yaml#L141-L143

@agners
Copy link
Member

agners commented Nov 21, 2024

@coderabbitai resolve

This PR doesn't try to fix shellcheck issues, it tries to enable along with minimal fixes.

@coderabbitai pause

Copy link
Contributor

coderabbitai bot commented Nov 21, 2024

@agners: Understood, I will resolve the comments and pause the automatic reviews for this PR.

✅ Actions performed

Comments resolved.


Reviews paused.

@mislav
Copy link
Author

mislav commented Nov 25, 2024

@agners I appreciate your assistance so far. Let me know if there is anything else to change/add to this PR. I believe this should be good to go, but there was one CI failure that looks intermittent; i.e. I don't think it's likely that it was caused by the changes in this branch.

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

Successfully merging this pull request may close these issues.

2 participants