Skip to content

feat(tools): add macOS support to bm-dns-setup script - #347

Merged
myakove merged 8 commits into
RedHatQE:mainfrom
MiriSafra:feat/bm-dns-macos-support
Mar 17, 2026
Merged

myakove merged 8 commits into
RedHatQE:mainfrom
MiriSafra:feat/bm-dns-macos-support

Conversation

@MiriSafra

@MiriSafra MiriSafra commented Mar 17, 2026 •

Copy link
Copy Markdown
Member

Add macOS support to the bare-metal DNS setup script.
The script auto-detects the OS (uname -s) and uses /etc/resolver on macOS.
Linux behavior is unchanged.
Tested on macOS

Summary by CodeRabbit

  • New Features

    • Optional domain parameter for customizable DNS enable/disable flows
    • Input validation for IPs and domains to prevent misconfiguration
    • Platform-specific handling for Linux and macOS with OS-aware dispatch and clear unsupported-OS messaging
    • Improved interface detection by domain for accurate network targeting
    • Centralized command flow for consistent enable/disable handling
  • Documentation

    • Updated help/usage to include the new domain option and related error guidance

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add macOS support to bm-dns-setup script

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add macOS support via /etc/resolver configuration
• Auto-detect OS and route to platform-specific implementations
• Refactor Linux logic into dedicated enable/disable functions
• Update usage documentation for cross-platform clarity
Diagram
flowchart LR
  A["bm-dns-setup.sh"] --> B["OS Detection<br/>uname -s"]
  B --> C["Linux Path"]
  B --> D["macOS Path"]
  C --> E["enable_linux/<br/>disable_linux<br/>resolvectl"]
  D --> F["enable_macos/<br/>disable_macos<br/>/etc/resolver"]
Loading

Grey Divider

File Changes

1. tools/bm-dns-setup.sh ✨ Enhancement +64/-16

Add macOS DNS support with OS-specific implementations

• Add OS auto-detection using uname -s to route to Linux or macOS implementations
• Extract Linux DNS logic into enable_linux() and disable_linux() functions using resolvectl
• Implement macOS DNS setup via enable_macos() and disable_macos() functions using /etc/resolver
• Update usage documentation to reflect cross-platform support and clarify command behavior

tools/bm-dns-setup.sh


Grey Divider

Qodo Logo

@redhat-qe-bot2

Copy link
Copy Markdown

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: Disabled for this repository
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: All label categories are enabled (default configuration)

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. Status Checks: All required status checks must pass
  3. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  4. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • solenoci

Reviewers:

  • krcmarik
  • myakove
  • solenoci
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (9) 📘 Rule violations (4) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Trailing-dot domain accepted 🐞 Bug ✓ Correctness
Description
validate_domain() does not reject domains that end with a dot (e.g., "example.com."), so that value
can be used verbatim for resolvectl routing domains and as the macOS resolver filename under
/etc/resolver. This can produce unexpected/mismatching configuration because the script will
configure a different string than the typical domain form without the trailing dot.
Code

tools/bm-dns-setup.sh[R35-46]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" != *..* ]] || die "Invalid domain: $domain"
+
+    local label
+    local -a labels
+    IFS='.' read -r -a labels <<< "$domain"
+    for label in "${labels[@]}"; do
+        [[ ${#label} -le 63 ]] || die "Invalid domain: $domain"
+        [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || die "Invalid domain: $domain"
+    done
+}
Evidence
validate_domain() only checks for ".." and validates per-label syntax, but has no guard against a
trailing '.'; the validated domain is then passed through to OS-specific configuration, including
direct use as a macOS resolver file path.

tools/bm-dns-setup.sh[35-46]
tools/bm-dns-setup.sh[82-91]
tools/bm-dns-setup.sh[108-117]
tools/bm-dns-setup.sh[160-187]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` does not explicitly reject domains ending with a dot (e.g. `example.com.`). The script then uses the domain verbatim in OS-specific configuration (Linux routing domain `~$domain` and macOS resolver file `/etc/resolver/$domain`).
### Issue Context
Domain validation is intended to prevent misconfiguration introduced by the new `--domain` option.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-46]
- tools/bm-dns-setup.sh[82-91]
- tools/bm-dns-setup.sh[108-117]
- tools/bm-dns-setup.sh[160-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Disable clears interface DNS 🐞 Bug ✓ Correctness
Description
disable_linux() resets the entire interface DNS configuration by calling `resolvectl domain "$iface"
"" and resolvectl dns "$iface" ""`, which removes all domains and all DNS servers on that
interface. This can break unrelated DNS configuration that existed before running the script.
Code

tools/bm-dns-setup.sh[R92-95]

+    echo "Removing $domain DNS domain from $iface"
+    sudo resolvectl domain "$iface" ""
+    echo "Removing DNS server from $iface"
+    sudo resolvectl dns "$iface" ""
Evidence
The Linux disable path unconditionally clears the interface’s domain list and DNS server list by
passing empty strings to resolvectl, which is not scoped to only the domain/server this script
configured.

tools/bm-dns-setup.sh[87-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On Linux, `disable_linux()` clears *all* DNS servers and *all* DNS domains for the matched interface by setting them to empty strings. This is destructive if the interface had any pre-existing DNS settings.
## Issue Context
The script currently does not track prior per-link DNS configuration, so it cannot safely restore or selectively remove the entries it added.
## Fix Focus Areas
- tools/bm-dns-setup.sh[75-97]
- tools/bm-dns-setup.sh[153-181]
## Suggested direction
Choose one safe behavior:
1) **Stateful restore (preferred):**
- During `enable_linux`, read the current per-link DNS servers/domains and save them (plus iface, domain, and IP) into a state file (e.g., under `${XDG_STATE_HOME:-$HOME/.local/state}/bm-dns-setup/` or similar).
- During `disable_linux`, restore the saved values instead of wiping.
2) **Guarded destructive revert:**
- Before clearing anything, verify the current per-link DNS server list and domain list match exactly what the script would have set (e.g., contains only `$ip` and `~$domain`).
- If not an exact match, refuse to disable and instruct the user to revert manually.
Either approach prevents accidentally breaking unrelated DNS configuration on that interface.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. --domain arg not validated 📘 Rule violation ⛯ Reliability
Description
When --domain is provided without a value, the script references $2 under set -u and will exit
with an unhelpful shell error instead of a clear die message. This violates the fail-fast
requirement by not validating option content at the point of use.
Code

tools/bm-dns-setup.sh[R151-154]

+        while [[ $# -gt 0 ]]; do
+            case "$1" in
+                --domain) DOMAIN="$2"; shift 2 ;;
+                *) die "Unknown option: $1" ;;
Evidence
Compliance requires validating required content early and raising clear errors; the new option
parsing assigns DOMAIN from $2 without checking that it exists/non-empty, which can cause an
abrupt failure rather than a controlled error.

CLAUDE.md
tools/bm-dns-setup.sh[151-156]
tools/bm-dns-setup.sh[161-166]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CLI option parser uses `DOMAIN=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$2&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;` for `--domain` without ensuring a value exists. With `set -u`, `--domain` at the end (or followed by another flag) can crash the script with an unhelpful unbound-variable error instead of a clear validation error.
## Issue Context
This script is intended to be user-facing and should fail fast with actionable error messages for invalid CLI input.
## Fix Focus Areas
- tools/bm-dns-setup.sh[151-166]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (3)
4. Unescaped domain regex 🐞 Bug ✓ Correctness
Description
get_domain_interface interpolates the user-provided domain directly into a Bash [[ =~ ]]
regex, so characters like . or [ change matching semantics or can make the conditional error
out. This can cause disable_linux to select the wrong interface or fail to disable DNS for certain
domains.
Code

tools/bm-dns-setup.sh[R49-65]

+get_domain_interface() {
+    local domain="$1"
local current_iface=""
local found_iface=""
local link_re='^Link [0-9]+ \(([^)]+)\)'
while IFS= read -r line; do
if [[ "$line" =~ $link_re ]]; then
current_iface="${BASH_REMATCH[1]}"
-        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*mtv\.local ]]; then
+        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*${domain} ]]; then
found_iface="$current_iface"
break
fi
done < <(resolvectl status 2>/dev/null)
-    [[ -n "$found_iface" ]] || die "No interface found with mtv.local DNS domain configured"
+    [[ -n "$found_iface" ]] || die "No interface found with $domain DNS domain configured"
echo "$found_iface"
Evidence
The script uses [[ string =~ regex ]] with ${domain} unescaped, meaning regex metacharacters in
a normal domain (notably .) are treated as regex operators; this directly affects which interface
is selected for disabling.

tools/bm-dns-setup.sh[49-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`get_domain_interface` embeds the user-provided domain directly into a Bash regex (`[[ ... =~ ... ]]`). Regular domain characters like `.` are regex metacharacters, which can cause incorrect interface matches or regex parse errors.
### Issue Context
This affects Linux `disable` by potentially choosing the wrong interface (or failing) when locating the interface that has the domain configured.
### Fix Focus Areas
- tools/bm-dns-setup.sh[49-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Domain path traversal sudo 🐞 Bug ⛨ Security
Description
On macOS, the script writes and deletes /etc/resolver/$domain via sudo without validating
domain, allowing values containing / or .. to target arbitrary filesystem paths. This enables
unintended root-owned file overwrite/delete when the script is run and sudo is granted.
Code

tools/bm-dns-setup.sh[R94-110]

+enable_macos() {
+    local ip="$1"
+    local domain="$2"
+    echo "Setting up DNS resolver for $domain -> $ip"
+    sudo mkdir -p /etc/resolver
+    printf 'nameserver %s\n' "$ip" | sudo tee "/etc/resolver/$domain" >/dev/null
+    echo "DNS setup enabled. Verifying..."
+    sleep 1
+    scutil --dns | grep -A5 "$domain" || echo "Resolver added (may take a moment to activate)"
+}
+
+disable_macos() {
+    local domain="$1"
+    if [[ -f "/etc/resolver/$domain" ]]; then
+        echo "Removing $domain DNS resolver"
+        sudo rm "/etc/resolver/$domain"
+        echo "DNS setup disabled"
Evidence
$domain is directly concatenated into a sudo-privileged path for both creation (tee) and deletion
(rm). Without constraining domain to a safe filename-like domain, a caller can provide traversal
sequences containing / to escape /etc/resolver.

tools/bm-dns-setup.sh[94-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On macOS, `--domain` is used in a sudo-privileged path `/etc/resolver/$domain` for both file creation and deletion. Without validation, this enables path traversal (e.g., including `/` and `..`) to overwrite/delete arbitrary files as root.
### Issue Context
The script explicitly uses `sudo tee` and `sudo rm` on paths derived from `$domain`.
### Fix Focus Areas
- tools/bm-dns-setup.sh[94-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Unvalidated macOS DNS IP 🐞 Bug ✓ Correctness
Description
enable_macos writes the provided "IP" directly into /etc/resolver/mtv.local without validation, so a
malformed/whitespace/newline-containing value can be persisted and break mtv.local resolution until
manually removed. This is a new macOS-specific misconfiguration path because the Linux flow fails
fast during route/interface detection before applying DNS changes.
Code

tools/bm-dns-setup.sh[R79-83]

+enable_macos() {
+    local ip="$1"
+    echo "Setting up DNS resolver for mtv.local -> $ip"
+    sudo mkdir -p /etc/resolver
+    echo "nameserver $ip" | sudo tee /etc/resolver/mtv.local
Evidence
On macOS, the script persists the user-provided value into the resolver file unconditionally. On
Linux, the enable path calls get_interface(), which runs "ip route get" and dies on failure,
preventing configuration changes when the input is invalid/unroutable; that protective behavior is
absent on macOS.

tools/bm-dns-setup.sh[79-83]
tools/bm-dns-setup.sh[55-63]
tools/bm-dns-setup.sh[25-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`enable_macos()` writes the user-supplied `IP` directly to `/etc/resolver/mtv.local` without validation. This can persist malformed values (including whitespace/newlines) and break `mtv.local` resolution until the user manually removes the resolver file.
### Issue Context
Linux currently fails fast before applying DNS changes because `enable_linux()` calls `get_interface()` which fails if `ip route get` cannot resolve the route. The macOS path has no equivalent guard.
### Fix Focus Areas
- tools/bm-dns-setup.sh[79-88]
- tools/bm-dns-setup.sh[109-118]
- tools/bm-dns-setup.sh[25-35]
### Implementation notes
- Add a `validate_ip()` helper (at minimum: reject any whitespace/newlines, and enforce an IPv4 pattern; optionally validate each octet is 0-255).
- Call validation in the main `enable)` block before the OS `case`.
- In macOS file writing, use `printf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;nameserver %s\n&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27; &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$IP&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; | sudo tee /etc/resolver/mtv.local &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;/dev/null` to avoid `echo` option/escape edge cases.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

7. Duplicate uname dispatch blocks 📘 Rule violation ✓ Correctness ⭐ New
Description
The OS dispatch case "$(uname -s)" logic is duplicated in both run_enable() and run_disable(),
increasing maintenance risk if supported OS logic or messages change. This violates the
no-duplicate-code requirement to extract identical logic into a shared helper.
Code

tools/bm-dns-setup.sh[R132-149]

+run_enable() {
+    local ip="$1"
+    local domain="$2"
+    case "$(uname -s)" in
+        Linux)  enable_linux "$ip" "$domain" ;;
+        Darwin) enable_macos "$ip" "$domain" ;;
+        *)      die "Unsupported OS: $(uname -s). Supported: Linux, macOS." ;;
+    esac
+}
+
+run_disable() {
+    local domain="$1"
+    case "$(uname -s)" in
+        Linux)  disable_linux "$domain" ;;
+        Darwin) disable_macos "$domain" ;;
+        *)      die "Unsupported OS: $(uname -s). Supported: Linux, macOS." ;;
+    esac
+}
Evidence
PR Compliance ID 9 requires extracting identical logic repeated 2+ times into a helper. The PR
introduces two near-identical case "$(uname -s)" dispatch blocks (one in run_enable, one in
run_disable) with the same OS branches and unsupported-OS error handling.

CLAUDE.md
tools/bm-dns-setup.sh[132-140]
tools/bm-dns-setup.sh[142-149]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The OS dispatch logic (`case &quot;$(uname -s)&quot;`) is duplicated in both `run_enable()` and `run_disable()`, which violates the repository rule to extract identical logic repeated 2+ times into a helper.

## Issue Context
If OS support or messaging changes, both blocks must be updated consistently; duplication increases drift risk.

## Fix Focus Areas
- tools/bm-dns-setup.sh[132-149]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Domain length not validated 🐞 Bug ⛯ Reliability
Description
validate_domain() validates each label but never checks total domain length, allowing a very long
yet label-valid domain to pass. On macOS, enable_macos() uses the domain as a filename
(/etc/resolver/$domain), which can fail at runtime due to filesystem name/path length limits.
Code

tools/bm-dns-setup.sh[R35-46]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" != *..* && "$domain" != *. ]] || die "Invalid domain: $domain"
+
+    local label
+    local -a labels
+    IFS='.' read -r -a labels <<< "$domain"
+    for label in "${labels[@]}"; do
+        [[ ${#label} -le 63 ]] || die "Invalid domain: $domain"
+        [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || die "Invalid domain: $domain"
+    done
+}
Evidence
The validator only enforces per-label rules, while the macOS implementation directly uses the domain
string as a filesystem path component under /etc/resolver, creating a runtime failure mode for
long domains.

tools/bm-dns-setup.sh[35-46]
tools/bm-dns-setup.sh[108-117]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` does not check the total domain length, but on macOS the domain is used as a filename (`/etc/resolver/$domain`). Very long domains can therefore pass validation and then fail during file creation.
### Issue Context
Per-label validation exists (&amp;amp;lt;=63 chars each) but no overall limit is enforced.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-46]
- tools/bm-dns-setup.sh[108-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Dead regex anchor branch 🐞 Bug ✓ Correctness
Description
get_domain_interface() uses a regex fragment .*(^|[[:space:]]) where the ^ alternative is
logically dead due to the preceding .*, making the boundary intent misleading. This increases
maintenance risk for the Linux disable path that depends on this parsing.
Code

tools/bm-dns-setup.sh[72]

+        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*(^|[[:space:]])~?${escaped_domain}([[:space:]]|$) ]]; then
Evidence
The new domain-detection logic relies on a single complex regex; as written, it includes an
unreachable ^ branch, which obscures what boundary behavior is actually intended. disable_linux()
depends on get_domain_interface() to find the interface to modify.

tools/bm-dns-setup.sh[62-80]
tools/bm-dns-setup.sh[94-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The regex used to detect a configured routing domain includes a logically-dead `^` alternative (`.*(^|[[:space:]])`), which makes the matching intent unclear and riskier to change.
### Issue Context
This parsing is used by `disable_linux()` to find which interface to reset.
### Fix Focus Areas
- tools/bm-dns-setup.sh[62-80]
- tools/bm-dns-setup.sh[94-103]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (4)
10. Domain validation misses labels 🐞 Bug ✓ Correctness
Description
validate_domain() does not validate each DNS label, so it accepts domains with labels that start/end
with '-' (e.g., "example-.local"), potentially writing an unusable /etc/resolver entry on macOS or
passing an invalid routing domain to resolvectl on Linux.
Code

tools/bm-dns-setup.sh[R35-39]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9.-]*[a-zA-Z0-9])?$ ]] || die "Invalid domain: $domain"
+    [[ "$domain" != *..* ]] || die "Invalid domain: $domain"
+}
Evidence
The current regex only enforces that the overall string starts/ends with an alphanumeric and
contains only alphanumerics/dots/hyphens in between; it does not ensure each dot-separated label
starts/ends with an alphanumeric, so label-boundary hyphens can slip through.

tools/bm-dns-setup.sh[35-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` currently validates the domain as a whole string but does not validate each dot-separated label. This allows domains with invalid labels (e.g., labels that start/end with `-`) to pass and then be applied to OS DNS configuration.
### Issue Context
The script uses the validated domain to configure Linux routing domains (`resolvectl domain ... &amp;amp;amp;amp;amp;amp;amp;amp;quot;~$domain&amp;amp;amp;amp;amp;amp;amp;amp;quot;`) and to create macOS resolver files (`/etc/resolver/$domain`). If invalid domains pass validation, configuration may silently not work as intended.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Regex grep misleads 🐞 Bug ✓ Correctness
Description
On macOS, enable_macos() verifies the resolver using grep regex matching, so a domain containing
. is treated as a wildcard and the verification output can be misleading.
Code

tools/bm-dns-setup.sh[R104-110]

+    echo "Setting up DNS resolver for $domain -> $ip"
+    sudo mkdir -p /etc/resolver
+    printf 'nameserver %s\n' "$ip" | sudo tee "/etc/resolver/$domain" >/dev/null
+    echo "DNS setup enabled. Verifying..."
+    sleep 1  # Allow macOS resolver cache to refresh
+    scutil --dns | grep -A5 "$domain" || echo "Resolver added (may take a moment to activate)"
+}
Evidence
The verification step passes the domain directly to grep (regex mode by default). Since
validate_domain() allows dots, the pattern will treat . as “any character”, which can produce
false matches in the verification output (this does not affect the actual resolver file creation).

tools/bm-dns-setup.sh[101-110]
tools/bm-dns-setup.sh[35-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
macOS verification uses regex `grep`, so dotted domains are treated as regex patterns and may match unrelated output, misleading the user.
### Issue Context
This only affects the verification message printed after writing `/etc/resolver/&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;domain&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;`.
### Fix Focus Areas
- tools/bm-dns-setup.sh[101-110]
### Implementation sketch
- Change:
- `scutil --dns | grep -A5 &amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$domain&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; ...`
- To:
- `scutil --dns | grep -F -A5 -- &amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$domain&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; ...`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. Duplicate --domain parsing 📘 Rule violation ⛯ Reliability
Description
The --domain option parsing loop is duplicated in both the enable and disable branches. This
increases maintenance risk because future changes to option handling must be made in multiple
places.
Code

tools/bm-dns-setup.sh[R151-166]

+        while [[ $# -gt 0 ]]; do
+            case "$1" in
+                --domain) DOMAIN="$2"; shift 2 ;;
+                *) die "Unknown option: $1" ;;
+            esac
+        done
+        validate_ip "$IP"
+        run_enable "$IP" "$DOMAIN"
;;
disable)
-        [[ $# -eq 1 ]] || { echo "$USAGE" >&2; exit 1; }
-        IFACE="$(get_mtv_interface)"
-        echo "Detected interface: $IFACE"
-        echo "Removing mtv.local DNS domain from $IFACE"
-        sudo resolvectl domain "$IFACE" ""
-        echo "Removing BM DNS server from $IFACE"
-        sudo resolvectl dns "$IFACE" ""
-        echo "DNS setup disabled on $IFACE"
+        while [[ $# -gt 0 ]]; do
+            case "$1" in
+                --domain) DOMAIN="$2"; shift 2 ;;
+                *) die "Unknown option: $1" ;;
+            esac
+        done
Evidence
The compliance checklist requires extracting identical logic used 2+ times into helpers; the PR
introduces two identical while/case blocks for parsing --domain.

CLAUDE.md
tools/bm-dns-setup.sh[151-156]
tools/bm-dns-setup.sh[161-166]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The script duplicates identical option parsing logic for `--domain` in both `enable` and `disable`, which violates the no-duplicate-code requirement and makes future updates error-prone.
## Issue Context
Both action branches accept the same `--domain` flag and should share a single parsing implementation.
## Fix Focus Areas
- tools/bm-dns-setup.sh[151-166]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. README missing macOS DNS notes 📘 Rule violation ✓ Correctness
Description
The PR changes the bare-metal DNS setup workflow by adding macOS behavior (/etc/resolver) and
updating the script’s usage text, but no corresponding README update is present. Users relying on
README guidance may miss the new OS-specific setup and verification steps.
Code

tools/bm-dns-setup.sh[R7-12]

+Configure DNS resolution for bare-metal host.
+Auto-detects OS (Linux uses resolvectl, macOS uses /etc/resolver).
Commands:
-  enable <ip>  Set the BM host IP as DNS server for the detected interface
-  disable      Revert DNS settings on the interface that has mtv.local configured
+  enable <ip>  Set the BM host IP as DNS server for mtv.local domain
+  disable      Revert DNS settings
Evidence
Compliance requires README updates when changes affect usage/configuration. The updated
tools/bm-dns-setup.sh usage text explicitly adds macOS behavior and changes enable/disable
semantics, indicating a user-facing change that should be documented in README.md.

CLAUDE.md
tools/bm-dns-setup.sh[7-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR updates `tools/bm-dns-setup.sh` to support macOS using `/etc/resolver`, which changes usage/configuration behavior, but README.md does not document these OS-specific steps.
## Issue Context
The script now auto-detects OS and uses different mechanisms on Linux vs macOS, including writing `/etc/resolver/mtv.local` and suggesting verification via `scutil --dns`.
## Fix Focus Areas
- tools/bm-dns-setup.sh[7-12]
- tools/bm-dns-setup.sh[77-88]
- tools/bm-dns-setup.sh[105-125]
- README.md[8-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Grey Divider

Previous review results

Review updated until commit b2376af

Results up to commit b2376af


🐞 Bugs (9) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider
Action required
1. Trailing-dot domain accepted 🐞 Bug ✓ Correctness
Description
validate_domain() does not reject domains that end with a dot (e.g., "example.com."), so that value
can be used verbatim for resolvectl routing domains and as the macOS resolver filename under
/etc/resolver. This can produce unexpected/mismatching configuration because the script will
configure a different string than the typical domain form without the trailing dot.
Code

tools/bm-dns-setup.sh[R35-46]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" != *..* ]] || die "Invalid domain: $domain"
+
+    local label
+    local -a labels
+    IFS='.' read -r -a labels <<< "$domain"
+    for label in "${labels[@]}"; do
+        [[ ${#label} -le 63 ]] || die "Invalid domain: $domain"
+        [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || die "Invalid domain: $domain"
+    done
+}
Evidence
validate_domain() only checks for ".." and validates per-label syntax, but has no guard against a
trailing '.'; the validated domain is then passed through to OS-specific configuration, including
direct use as a macOS resolver file path.

tools/bm-dns-setup.sh[35-46]
tools/bm-dns-setup.sh[82-91]
tools/bm-dns-setup.sh[108-117]
tools/bm-dns-setup.sh[160-187]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` does not explicitly reject domains ending with a dot (e.g. `example.com.`). The script then uses the domain verbatim in OS-specific configuration (Linux routing domain `~$domain` and macOS resolver file `/etc/resolver/$domain`).
### Issue Context
Domain validation is intended to prevent misconfiguration introduced by the new `--domain` option.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-46]
- tools/bm-dns-setup.sh[82-91]
- tools/bm-dns-setup.sh[108-117]
- tools/bm-dns-setup.sh[160-187]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Disable clears interface DNS 🐞 Bug ✓ Correctness
Description
disable_linux() resets the entire interface DNS configuration by calling `resolvectl domain "$iface"
"" and resolvectl dns "$iface" ""`, which removes all domains and all DNS servers on that
interface. This can break unrelated DNS configuration that existed before running the script.
Code

tools/bm-dns-setup.sh[R92-95]

+    echo "Removing $domain DNS domain from $iface"
+    sudo resolvectl domain "$iface" ""
+    echo "Removing DNS server from $iface"
+    sudo resolvectl dns "$iface" ""
Evidence
The Linux disable path unconditionally clears the interface’s domain list and DNS server list by
passing empty strings to resolvectl, which is not scoped to only the domain/server this script
configured.

tools/bm-dns-setup.sh[87-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On Linux, `disable_linux()` clears *all* DNS servers and *all* DNS domains for the matched interface by setting them to empty strings. This is destructive if the interface had any pre-existing DNS settings.
## Issue Context
The script currently does not track prior per-link DNS configuration, so it cannot safely restore or selectively remove the entries it added.
## Fix Focus Areas
- tools/bm-dns-setup.sh[75-97]
- tools/bm-dns-setup.sh[153-181]
## Suggested direction
Choose one safe behavior:
1) **Stateful restore (preferred):**
- During `enable_linux`, read the current per-link DNS servers/domains and save them (plus iface, domain, and IP) into a state file (e.g., under `${XDG_STATE_HOME:-$HOME/.local/state}/bm-dns-setup/` or similar).
- During `disable_linux`, restore the saved values instead of wiping.
2) **Guarded destructive revert:**
- Before clearing anything, verify the current per-link DNS server list and domain list match exactly what the script would have set (e.g., contains only `$ip` and `~$domain`).
- If not an exact match, refuse to disable and instruct the user to revert manually.
Either approach prevents accidentally breaking unrelated DNS configuration on that interface.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. --domain arg not validated 📘 Rule violation ⛯ Reliability
Description
When --domain is provided without a value, the script references $2 under set -u and will exit
with an unhelpful shell error instead of a clear die message. This violates the fail-fast
requirement by not validating option content at the point of use.
Code

tools/bm-dns-setup.sh[R151-154]

+        while [[ $# -gt 0 ]]; do
+            case "$1" in
+                --domain) DOMAIN="$2"; shift 2 ;;
+                *) die "Unknown option: $1" ;;
Evidence
Compliance requires validating required content early and raising clear errors; the new option
parsing assigns DOMAIN from $2 without checking that it exists/non-empty, which can cause an
abrupt failure rather than a controlled error.

CLAUDE.md
tools/bm-dns-setup.sh[151-156]
tools/bm-dns-setup.sh[161-166]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The CLI option parser uses `DOMAIN=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$2&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;` for `--domain` without ensuring a value exists. With `set -u`, `--domain` at the end (or followed by another flag) can crash the script with an unhelpful unbound-variable error instead of a clear validation error.
## Issue Context
This script is intended to be user-facing and should fail fast with actionable error messages for invalid CLI input.
## Fix Focus Areas
- tools/bm-dns-setup.sh[151-166]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (3)
4. Unescaped domain regex 🐞 Bug ✓ Correctness
Description
get_domain_interface interpolates the user-provided domain directly into a Bash [[ =~ ]]
regex, so characters like . or [ change matching semantics or can make the conditional error
out. This can cause disable_linux to select the wrong interface or fail to disable DNS for certain
domains.
Code

tools/bm-dns-setup.sh[R49-65]

+get_domain_interface() {
+    local domain="$1"
local current_iface=""
local found_iface=""
local link_re='^Link [0-9]+ \(([^)]+)\)'
while IFS= read -r line; do
if [[ "$line" =~ $link_re ]]; then
 current_iface="${BASH_REMATCH[1]}"
-        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*mtv\.local ]]; then
+        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*${domain} ]]; then
 found_iface="$current_iface"
 break
fi
done < <(resolvectl status 2>/dev/null)
-    [[ -n "$found_iface" ]] || die "No interface found with mtv.local DNS domain configured"
+    [[ -n "$found_iface" ]] || die "No interface found with $domain DNS domain configured"
echo "$found_iface"
Evidence
The script uses [[ string =~ regex ]] with ${domain} unescaped, meaning regex metacharacters in
a normal domain (notably .) are treated as regex operators; this directly affects which interface
is selected for disabling.

tools/bm-dns-setup.sh[49-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`get_domain_interface` embeds the user-provided domain directly into a Bash regex (`[[ ... =~ ... ]]`). Regular domain characters like `.` are regex metacharacters, which can cause incorrect interface matches or regex parse errors.
### Issue Context
This affects Linux `disable` by potentially choosing the wrong interface (or failing) when locating the interface that has the domain configured.
### Fix Focus Areas
- tools/bm-dns-setup.sh[49-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Domain path traversal sudo 🐞 Bug ⛨ Security
Description
On macOS, the script writes and deletes /etc/resolver/$domain via sudo without validating
domain, allowing values containing / or .. to target arbitrary filesystem paths. This enables
unintended root-owned file overwrite/delete when the script is run and sudo is granted.
Code

tools/bm-dns-setup.sh[R94-110]

+enable_macos() {
+    local ip="$1"
+    local domain="$2"
+    echo "Setting up DNS resolver for $domain -> $ip"
+    sudo mkdir -p /etc/resolver
+    printf 'nameserver %s\n' "$ip" | sudo tee "/etc/resolver/$domain" >/dev/null
+    echo "DNS setup enabled. Verifying..."
+    sleep 1
+    scutil --dns | grep -A5 "$domain" || echo "Resolver added (may take a moment to activate)"
+}
+
+disable_macos() {
+    local domain="$1"
+    if [[ -f "/etc/resolver/$domain" ]]; then
+        echo "Removing $domain DNS resolver"
+        sudo rm "/etc/resolver/$domain"
+        echo "DNS setup disabled"
Evidence
$domain is directly concatenated into a sudo-privileged path for both creation (tee) and deletion
(rm). Without constraining domain to a safe filename-like domain, a caller can provide traversal
sequences containing / to escape /etc/resolver.

tools/bm-dns-setup.sh[94-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On macOS, `--domain` is used in a sudo-privileged path `/etc/resolver/$domain` for both file creation and deletion. Without validation, this enables path traversal (e.g., including `/` and `..`) to overwrite/delete arbitrary files as root.
### Issue Context
The script explicitly uses `sudo tee` and `sudo rm` on paths derived from `$domain`.
### Fix Focus Areas
- tools/bm-dns-setup.sh[94-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Unvalidated macOS DNS IP 🐞 Bug ✓ Correctness
Description
enable_macos writes the provided "IP" directly into /etc/resolver/mtv.local without validation, so a
malformed/whitespace/newline-containing value can be persisted and break mtv.local resolution until
manually removed. This is a new macOS-specific misconfiguration path because the Linux flow fails
fast during route/interface detection before applying DNS changes.
Code

tools/bm-dns-setup.sh[R79-83]

+enable_macos() {
+    local ip="$1"
+    echo "Setting up DNS resolver for mtv.local -> $ip"
+    sudo mkdir -p /etc/resolver
+    echo "nameserver $ip" | sudo tee /etc/resolver/mtv.local
Evidence
On macOS, the script persists the user-provided value into the resolver file unconditionally. On
Linux, the enable path calls get_interface(), which runs "ip route get" and dies on failure,
preventing configuration changes when the input is invalid/unroutable; that protective behavior is
absent on macOS.

tools/bm-dns-setup.sh[79-83]
tools/bm-dns-setup.sh[55-63]
tools/bm-dns-setup.sh[25-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`enable_macos()` writes the user-supplied `IP` directly to `/etc/resolver/mtv.local` without validation. This can persist malformed values (including whitespace/newlines) and break `mtv.local` resolution until the user manually removes the resolver file.
### Issue Context
Linux currently fails fast before applying DNS changes because `enable_linux()` calls `get_interface()` which fails if `ip route get` cannot resolve the route. The macOS path has no equivalent guard.
### Fix Focus Areas
- tools/bm-dns-setup.sh[79-88]
- tools/bm-dns-setup.sh[109-118]
- tools/bm-dns-setup.sh[25-35]
### Implementation notes
- Add a `validate_ip()` helper (at minimum: reject any whitespace/newlines, and enforce an IPv4 pattern; optionally validate each octet is 0-255).
- Call validation in the main `enable)` block before the OS `case`.
- In macOS file writing, use `printf &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;nameserver %s\n&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27; &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;$IP&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; | sudo tee /etc/resolver/mtv.local &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;/dev/null` to avoid `echo` option/escape edge cases.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
7. Domain length not validated 🐞 Bug ⛯ Reliability
Description
validate_domain() validates each label but never checks total domain length, allowing a very long
yet label-valid domain to pass. On macOS, enable_macos() uses the domain as a filename
(/etc/resolver/$domain), which can fail at runtime due to filesystem name/path length limits.
Code

tools/bm-dns-setup.sh[R35-46]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" != *..* && "$domain" != *. ]] || die "Invalid domain: $domain"
+
+    local label
+    local -a labels
+    IFS='.' read -r -a labels <<< "$domain"
+    for label in "${labels[@]}"; do
+        [[ ${#label} -le 63 ]] || die "Invalid domain: $domain"
+        [[ "$label" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]] || die "Invalid domain: $domain"
+    done
+}
Evidence
The validator only enforces per-label rules, while the macOS implementation directly uses the domain
string as a filesystem path component under /etc/resolver, creating a runtime failure mode for
long domains.

tools/bm-dns-setup.sh[35-46]
tools/bm-dns-setup.sh[108-117]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` does not check the total domain length, but on macOS the domain is used as a filename (`/etc/resolver/$domain`). Very long domains can therefore pass validation and then fail during file creation.
### Issue Context
Per-label validation exists (&amp;lt;=63 chars each) but no overall limit is enforced.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-46]
- tools/bm-dns-setup.sh[108-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Dead regex anchor branch 🐞 Bug ✓ Correctness
Description
get_domain_interface() uses a regex fragment .*(^|[[:space:]]) where the ^ alternative is
logically dead due to the preceding .*, making the boundary intent misleading. This increases
maintenance risk for the Linux disable path that depends on this parsing.
Code

tools/bm-dns-setup.sh[72]

+        elif [[ -n "$current_iface" && "$line" =~ DNS\ Domain:.*(^|[[:space:]])~?${escaped_domain}([[:space:]]|$) ]]; then
Evidence
The new domain-detection logic relies on a single complex regex; as written, it includes an
unreachable ^ branch, which obscures what boundary behavior is actually intended. disable_linux()
depends on get_domain_interface() to find the interface to modify.

tools/bm-dns-setup.sh[62-80]
tools/bm-dns-setup.sh[94-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The regex used to detect a configured routing domain includes a logically-dead `^` alternative (`.*(^|[[:space:]])`), which makes the matching intent unclear and riskier to change.
### Issue Context
This parsing is used by `disable_linux()` to find which interface to reset.
### Fix Focus Areas
- tools/bm-dns-setup.sh[62-80]
- tools/bm-dns-setup.sh[94-103]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Domain validation misses labels 🐞 Bug ✓ Correctness
Description
validate_domain() does not validate each DNS label, so it accepts domains with labels that start/end
with '-' (e.g., "example-.local"), potentially writing an unusable /etc/resolver entry on macOS or
passing an invalid routing domain to resolvectl on Linux.
Code

tools/bm-dns-setup.sh[R35-39]

+validate_domain() {
+    local domain="$1"
+    [[ "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9.-]*[a-zA-Z0-9])?$ ]] || die "Invalid domain: $domain"
+    [[ "$domain" != *..* ]] || die "Invalid domain: $domain"
+}
Evidence
The current regex only enforces that the overall string starts/ends with an alphanumeric and
contains only alphanumerics/dots/hyphens in between; it does not ensure each dot-separated label
starts/ends with an alphanumeric, so label-boundary hyphens can slip through.

tools/bm-dns-setup.sh[35-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`validate_domain()` currently validates the domain as a whole string but does not validate each dot-separated label. This allows domains with invalid labels (e.g., labels that start/end with `-`) to pass and then be applied to OS DNS configuration.
### Issue Context
The script uses the validated domain to configure Linux routing domains (`resolvectl domain ... &amp;amp;amp;amp;amp;amp;amp;quot;~$domain&amp;amp;amp;amp;amp;amp;amp;quot;`) and to create macOS resolver files (`/etc/resolver/$domain`). If invalid domains pass validation, configuration may silently not work as intended.
### Fix Focus Areas
- tools/bm-dns-setup.sh[35-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (3)
10. Regex grep misleads 🐞 Bug ✓ Correctness
Description
On macOS, enable_macos() verifies the resolver using grep regex matching, so a domain containing
. is treated as a wildcard and the verification output can be misleading.
Code

tools/bm-dns-setup.sh[R104-110]

+    echo "Setting up DNS resolver for $domain -> $ip"
+    sudo mkdir -p /etc/resolver
+    printf 'nameserver %s\n' "$ip" | sudo tee "/etc/resolver/$domain" >/dev/null
+    echo "DNS setup enabled. Verifying..."
+    sleep 1  # Allow macOS resolver cache to refresh
+    scutil --dns | grep -A5 "$domain" || echo "Resolver added (may take a moment to activate)"
+}
Evidence
The verification step passes...

Comment thread tools/bm-dns-setup.sh Resolved
Comment thread tools/bm-dns-setup.sh Resolved
Comment thread tools/bm-dns-setup.sh Resolved
- Auto-detect OS via uname -s (Linux: resolvectl, macOS: /etc/resolver)
- Add --domain flag (default: mtv.local)
- Add IP validation
- Extract OS dispatch to functions (no duplicate code)
@MiriSafra
MiriSafra force-pushed the feat/bm-dns-macos-support branch from de1e5a2 to c531a0d Compare March 17, 2026 13:22
@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit c531a0d

@coderabbitai

coderabbitai Bot commented Mar 17, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Refactors tools/bm-dns-setup.sh to add an optional --domain parameter, input validators (validate_ip, validate_domain), domain-aware interface detection (get_domain_interface(domain)), OS-specific enable/disable implementations for Linux and macOS, and centralized OS dispatch (run_enable, run_disable). (32 words)

Changes

Cohort / File(s) Summary
DNS Setup Script
tools/bm-dns-setup.sh
Adds --domain parsing (default mtv.local), validate_ip() and validate_domain(); renames get_mtv_interface() → get_domain_interface(domain); introduces enable_linux(ip, domain), disable_linux(domain), enable_macos(ip, domain), disable_macos(domain); adds dispatchers run_enable(ip, domain) and run_disable(domain); centralizes main flow and improves OS-specific error handling.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Script as bm-dns-setup.sh
    participant OS as OS (systemd-resolved / macOS)
    participant Net as Network Interface

    User->>Script: run enable/disable --domain [--ip]
    Script->>Script: validate_domain(domain)\nvalidate_ip(ip)?
    alt validation fails
        Script-->>User: error and exit
    else validation passes
        Script->>Script: get_domain_interface(domain)
        Script->>OS: run_enable/run_disable -> enable_* / disable_*(domain, ip)
        OS->>Net: apply DNS config for domain (resolvectl or /etc/resolver)
        OS-->>Script: success/failure
        Script-->>User: success or error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding macOS support to the bm-dns-setup script, which is the primary objective and the most significant enhancement in this changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

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

myakove
myakove previously approved these changes Mar 17, 2026
@myakove

myakove commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator

/approve

Comment thread tools/bm-dns-setup.sh Resolved
Comment thread tools/bm-dns-setup.sh Resolved
Comment thread tools/bm-dns-setup.sh Resolved
@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit c531a0d

@MiriSafra

Copy link
Copy Markdown
Member Author

/verified

@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit 9bfd911

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
tools/bm-dns-setup.sh (1)

165-184: 🛠️ Refactor suggestion | 🟠 Major

MEDIUM: Extract duplicate option-parsing logic into a helper function.

The while loops at lines 165-172 and 178-184 are identical. This violates DRY and makes future changes error-prone (e.g., adding a new option requires updating two places).

♻️ Proposed refactor
+parse_options() {
+    while [[ $# -gt 0 ]]; do
+        case "$1" in
+            --domain)
+                [[ -n "${2:-}" ]] || die "--domain requires a value"
+                DOMAIN="$2"; shift 2 ;;
+            *) die "Unknown option: $1" ;;
+        esac
+    done
+}
+
 case "$ACTION" in
     enable)
         [[ $# -ge 1 ]] || { echo "$USAGE" >&2; exit 1; }
         IP="$1"
         shift
-        while [[ $# -gt 0 ]]; do
-            case "$1" in
-                --domain)
-                    [[ -n "${2:-}" ]] || die "--domain requires a value"
-                    DOMAIN="$2"; shift 2 ;;
-                *) die "Unknown option: $1" ;;
-            esac
-        done
+        parse_options "$@"
         validate_ip "$IP"
         validate_domain "$DOMAIN"
         run_enable "$IP" "$DOMAIN"
         ;;
     disable)
-        while [[ $# -gt 0 ]]; do
-            case "$1" in
-                --domain)
-                    [[ -n "${2:-}" ]] || die "--domain requires a value"
-                    DOMAIN="$2"; shift 2 ;;
-                *) die "Unknown option: $1" ;;
-            esac
-        done
+        parse_options "$@"
         validate_domain "$DOMAIN"
         run_disable "$DOMAIN"
         ;;
 esac
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/bm-dns-setup.sh` around lines 165 - 184, Extract the duplicated
option-parsing while-loop into a helper function (e.g., parse_domain_option)
that reads "--domain" into the global DOMAIN variable, performs the same
validation and shifting, and calls die for unknown options; then replace the two
identical while loops in the "enable" and "disable" case branches with a single
call to parse_domain_option and leave the subsequent validate_domain and
run_enable (and the corresponding run_disable) calls in place so behavior is
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tools/bm-dns-setup.sh`:
- Around line 165-184: Extract the duplicated option-parsing while-loop into a
helper function (e.g., parse_domain_option) that reads "--domain" into the
global DOMAIN variable, performs the same validation and shifting, and calls die
for unknown options; then replace the two identical while loops in the "enable"
and "disable" case branches with a single call to parse_domain_option and leave
the subsequent validate_domain and run_enable (and the corresponding
run_disable) calls in place so behavior is unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e1325eac-9014-447d-bda1-9b03c4538278

📥 Commits

Reviewing files that changed from the base of the PR and between 3fde01e and 9bfd911.

📒 Files selected for processing (1)
  • tools/bm-dns-setup.sh

coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 17, 2026
Comment thread tools/bm-dns-setup.sh Resolved
@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit b2376af

@MiriSafra

Copy link
Copy Markdown
Member Author

/verified

@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Persistent review updated to latest commit b2376af

@myakove

myakove commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator

/approve

Please check the unresolved comment

@MiriSafra

Copy link
Copy Markdown
Member Author

Opened #348 for the disable_linux() DNS wipe issue. @myakove

@myakove

myakove commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator

/check-can-merge

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.

6 participants