Skip to content

docs: add configuration guide with example and field descriptions#146

Open
WNN6231 wants to merge 10 commits into
dnstapir:mainfrom
WNN6231:main
Open

docs: add configuration guide with example and field descriptions#146
WNN6231 wants to merge 10 commits into
dnstapir:mainfrom
WNN6231:main

Conversation

@WNN6231
Copy link
Copy Markdown

@WNN6231 WNN6231 commented May 13, 2026

Closes #145

Added docs/configuration.md with:

  • Complete configuration example with all fields
  • Field descriptions and required/optional annotations
  • Reference table for all configuration sections

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive POP configuration guide with full YAML examples and per-file field reference tables covering startup configuration, logging, services, servers, keystore, sources, outputs, and policy rules.
    • Documented policy behavior with valid RPZ action values, note on partial redirect support, and three end-to-end examples (Strict, Permissive, Silent drop).
    • Described supported source file formats (domains, CSV, DAWG), CSV parsing rules, and DAWG limitations (allowlist-only, built from a sorted domain list, loaded at startup).

Review Change Stack

@WNN6231 WNN6231 requested a review from a team as a code owner May 13, 2026 10:08
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 328c0e37-69f8-4511-a71a-5125f3ead7ac

📥 Commits

Reviewing files that changed from the base of the PR and between 39e0678 and bbbe6a8.

📒 Files selected for processing (1)
  • docs/configuration.md

📝 Walkthrough

Walkthrough

Adds docs/configuration.md: a comprehensive POP configuration guide with four example YAML files (dnstapir-pop.yaml, pop-sources.yaml, pop-outputs.yaml, pop-policy.yaml), per-field reference tables, RPZ action mappings and examples, and supported file-format details for file-based sources.

Changes

Configuration Documentation

Layer / File(s) Summary
Primary POP config (dnstapir-pop.yaml)
docs/configuration.md
Provides a full dnstapir-pop.yaml example (logging, services, API/DNS/bootstrap servers, keystore) and a field-reference table for that file.
Sources configuration (pop-sources.yaml)
docs/configuration.md
Adds pop-sources.yaml example with MQTT feed, local DAWG allowlist, and xfr RPZ sources, plus a fields reference and note that DAWG is supported only for type: allowlist.
Outputs configuration (pop-outputs.yaml)
docs/configuration.md
Adds pop-outputs.yaml example defining downstream outputs and a field-reference table for output settings.
Policy configuration (pop-policy.yaml)
docs/configuration.md
Adds pop-policy.yaml example with allow/deny/doubt lists, a field-reference table, and a table enumerating valid RPZ action values and their RPZ effects plus multiple policy examples (Strict, Permissive, Silent drop); notes redirect is only partially implemented.
List file formats
docs/configuration.md
Documents supported file formats for source: file (domains, csv, dawg), CSV column expectations (header skipped; domain from second column), and DAWG constraints/behavior (allowlist-only, built via tapir, loaded at startup).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • jschlyter

Poem

🐰 I hopped through YAML, tidy and spry,
Lines aligned like stars in the sky,
Examples snug, tables neat,
Now docs and configs finally meet,
🥕📜

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a comprehensive configuration guide with example YAML files and detailed field descriptions.
Linked Issues check ✅ Passed The PR directly addresses issue #145 by providing comprehensive configuration documentation with example YAML files and per-field descriptions for all four configuration files.
Out of Scope Changes check ✅ Passed The changes are entirely scoped to documentation expansion in docs/configuration.md, directly fulfilling the requirement to provide configuration examples and documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@docs/configuration.md`:
- Line 3: The sentence "POP uses a YAML configuration file. Below is a complete
example with explanations for each field." overstates coverage; either replace
"with explanations for each field" with a softer phrase such as "with
explanations for the key fields" or "with explanations for most fields", or add
explicit per-field descriptions for every entry in the YAML example so the claim
is accurate; update the sentence text and/or expand the YAML block's inline
comments or an accompanying list so every YAML field has a matching explanation.
- Around line 93-122: Update the "Required Fields" table to include the missing
sections and fields shown in the example: add rows for bootstrapserver.* (e.g.,
bootstrapserver.active, bootstrapserver.addresses), policy.logfile,
policy.doubtlist.* (e.g., policy.doubtlist.action, policy.doubtlist.entries) and
any source-type-specific fields under sources.* (e.g., sources.*.mqtt_topic,
sources.*.file_pattern) and explicitly mark optional entries; ensure entries
reference the exact keys used elsewhere (bootstrapserver, policy.logfile,
policy.doubtlist.*, sources.*) so the table matches the documented configuration
schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9a18af4-7b39-4126-bfad-2ebc73d11191

📥 Commits

Reviewing files that changed from the base of the PR and between c114078 and b8b5abf.

📒 Files selected for processing (1)
  • docs/configuration.md

Comment thread docs/configuration.md Outdated
Comment thread docs/configuration.md Outdated
Copy link
Copy Markdown

@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

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

Inline comments:
In `@docs/configuration.md`:
- Around line 134-149: Update the table so that fields which depend on the
chosen source are marked as conditionally required rather than simply "no":
change the entries for topic, validatorkey, bootstrap, bootstrapurl,
bootstrapkey to indicate "required when source: mqtt", filename to "required
when source: file", and upstream and zone to "required when source: xfr" (you
can use phrasing like "required when `source: mqtt`" etc.) and ensure the
`format` entry still documents per-source allowed formats; keep the rest of the
table unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e8727ae1-6de6-4f26-8eda-8fb837280af0

📥 Commits

Reviewing files that changed from the base of the PR and between b8b5abf and de7718e.

📒 Files selected for processing (1)
  • docs/configuration.md

Comment thread docs/configuration.md
Copy link
Copy Markdown
Member

@oej oej left a comment

Choose a reason for hiding this comment

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

Good work. Just have a few minor comments. Will ask the team to review too.

Comment thread docs/configuration.md Outdated
| `name` | yes | Output identifier |
| `description` | yes | Human-readable description |
| `type` | yes | Source list type this output is derived from |
| `format` | yes | Output format (`rpz`) |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What are the options? Only "rpz" ?

Comment thread docs/configuration.md Outdated

## pop-outputs.yaml

Outputs define downstream DNS resolvers that receive RPZ NOTIFY and can perform AXFR/IXFR.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Clarify that these operations are over DNS

Comment thread docs/configuration.md Outdated
outputs:
downstream-resolver:
active: true
name: "downstream-resolver"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Using the same name as the config option is not clever. Set the name to something different

Comment thread docs/configuration.md
| Field | Required | Description |
|-------|----------|-------------|
| `policy.logfile` | no | Policy decision log file path |
| `policy.allowlist.action` | yes | Action for allowlisted names |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Document possible actions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, it's below. Sorry.

Copy link
Copy Markdown

@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

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

Inline comments:
In `@docs/configuration.md`:
- Around line 306-310: Add explicit language identifiers to the two fenced code
blocks: for the block containing the domain list (the fence that includes
"example.com\nmalicious.example.org\nblocked.test.") add the "text" language
(i.e., change ``` to ```text), and for the block containing the CSV sample (the
fence that starts with "id,domain,category") add the "csv" language (i.e.,
change ``` to ```csv) so markdownlint MD040 is satisfied.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0c89d14e-828d-4623-8f3e-80038d91b2cb

📥 Commits

Reviewing files that changed from the base of the PR and between de7718e and 1450124.

📒 Files selected for processing (1)
  • docs/configuration.md

Comment thread docs/configuration.md Outdated
@WNN6231
Copy link
Copy Markdown
Author

WNN6231 commented May 19, 2026

Hi @oej! Thanks for the review 🙏 I've addressed all the comments — let me know if anything else needs adjustment!

@jschlyter
Copy link
Copy Markdown
Member

@WNN6231 Can you sign your commits and push again?

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new documentation page describing POP’s YAML configuration files, including example configs and field-by-field reference tables, addressing the lack of config documentation raised in #145.

Changes:

  • Added docs/configuration.md with example YAML for the 4 config files POP loads at startup.
  • Added field reference tables for main config, sources, outputs, and policy.
  • Documented supported list file formats and provided policy examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/configuration.md
Comment on lines +17 to +21
log:
file: "/var/log/dnstapir/pop.log"
verbose: false
debug: false

Comment thread docs/configuration.md
Comment on lines +22 to +28
services:
rpz:
zonename: "rpz.example.com."
serialcache: "/var/cache/dnstapir/pop-serial.yaml"
reaper:
interval: 3600

Comment thread docs/configuration.md
Comment on lines +112 to +117
type: "allowlist"
format: "domains" # File format: domains, csv, or dawg
source: "file"
filename: "/etc/dnstapir/allowlist.txt"
immutable: false # If true, the list is never updated at runtime

Comment thread docs/configuration.md Outdated
| `nxdomain` | `.` — return NXDOMAIN |
| `nodata` | `*.` — return NODATA |
| `drop` | `rpz-drop.` — silently drop the query |
| `redirect` | redirect (target TBD in upstream config) |
Comment thread docs/configuration.md Outdated
Comment on lines +7 to +14
| `dnstapir-pop.yaml` | Main config: logging, services, API/DNS/bootstrap servers, keystore |
| `pop-sources.yaml` | Intelligence sources (MQTT, file, RPZ zone transfer) |
| `pop-outputs.yaml` | RPZ downstream outputs |
| `pop-policy.yaml` | Policy rules for allow/deny/doubtlist decisions |

---

## dnstapir-pop.yaml
WNN6231 added 9 commits May 23, 2026 18:47
- Split examples across all four config files (dnstapir-pop.yaml,
  pop-sources.yaml, pop-outputs.yaml, pop-policy.yaml)
- Fix source field values: mqtt/file/xfr (not URLs)
- Fix type field: allowlist/denylist/doubtlist (not protocol)
- Fix file source formats: domains/csv/dawg
- Fix valid policy actions per StringToAction in tapir package
- Add missing outputs section
- Clarify that rpz is currently the only supported output format
- Specify that NOTIFY and AXFR/IXFR are DNS operations
- Use a distinct example name (primary-resolver) instead of downstream-resolver
- Add 'text' identifier to domains example block
- Add 'csv' identifier to CSV example block
- Fixes markdownlint MD040 rule
@WNN6231
Copy link
Copy Markdown
Author

WNN6231 commented May 23, 2026

Hi @jschlyter, all commits are now signed and verified. Ready for another look.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/configuration.md (1)

138-138: 💤 Low value

Consider rewording to reduce repetition.

The description uses "For" three times in succession, which slightly impacts readability.

Suggested alternative phrasing
-| `format` | yes | Data format. For `source: mqtt`: `json`. For `source: file`: `domains`, `csv`, or `dawg`. For `source: xfr`: `rpz` |
+| `format` | yes | Data format: `json` for MQTT sources, `domains`/`csv`/`dawg` for file sources, `rpz` for zone transfers |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/configuration.md` at line 138, The `format` field description is
repetitive; rewrite the sentence for clarity by consolidating the examples and
avoiding repeated "For". Update the table entry for `format` to something like:
state that it specifies the data format and list per-source allowed values
(e.g., `source: mqtt` -> `json`; `source: file` -> `domains`, `csv`, `dawg`;
`source: xfr` -> `rpz`) so the `format` row (symbol: `format`) reads as a
single, concise phrase referencing each source and its valid formats.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/configuration.md`:
- Around line 221-229: The docs note that the "redirect" action is a
placeholder; update the policy and AXFR code so REDIRECT is implemented
end-to-end: change the hardcoded CNAME target "what-to-do-about-this" to use a
configurable redirect target (add a config field and read it where the
action-to-RPZ mapping is performed), ensure the action-to-RPZ mapping routine
(the mapping function in the policy engine) emits the proper CNAME target for
REDIRECT, and modify ApplyDoubtPolicy to handle the REDIRECT enum/value and
include the redirect CNAME in doubtlist AXFR generation so redirect records are
present in AXFR output; also update the docs text to describe the final redirect
semantics and config key.
- Line 229: Update the docs entry for `redirect` to point to the actual
upstream/tapir config fields that supply the redirect target instead of "TBD":
mention that RPZ CNAME local-data targets are generated from
tapir.ActionToCNAMETarget and specify which tapir/upstream config keys populate
ActionToCNAMETarget, and clarify that the AXFR doubtlist path (ApplyDoubtPolicy)
only supports NXDOMAIN, NODATA, and DROP so `redirect` is not wired there; also
state whether redirect is available for denylist vs doubtlist (and if only
denylist supports redirect via tapir). Use the symbols ApplyDoubtPolicy and
tapir.ActionToCNAMETarget in the text so readers can locate the implementation.

---

Nitpick comments:
In `@docs/configuration.md`:
- Line 138: The `format` field description is repetitive; rewrite the sentence
for clarity by consolidating the examples and avoiding repeated "For". Update
the table entry for `format` to something like: state that it specifies the data
format and list per-source allowed values (e.g., `source: mqtt` -> `json`;
`source: file` -> `domains`, `csv`, `dawg`; `source: xfr` -> `rpz`) so the
`format` row (symbol: `format`) reads as a single, concise phrase referencing
each source and its valid formats.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4607112-122b-4861-93b2-8652d48a1d7a

📥 Commits

Reviewing files that changed from the base of the PR and between 1450124 and 39e0678.

📒 Files selected for processing (1)
  • docs/configuration.md

Comment thread docs/configuration.md Outdated
Comment on lines +221 to +229
### Valid action values

| Value | RPZ effect |
|-------|-----------|
| `allowlist` or `passthru` | `rpz-passthru.` — allow the name through |
| `nxdomain` | `.` — return NXDOMAIN |
| `nodata` | `*.` — return NODATA |
| `drop` | `rpz-drop.` — silently drop the query |
| `redirect` | redirect (target TBD in upstream config) |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for action validation/processing in policy-related code

rg -n -C5 'action.*allowlist|action.*passthru|action.*nxdomain|action.*nodata|action.*drop|action.*redirect' --type go -g '!vendor/**'

Repository: dnstapir/pop

Length of output: 1461


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate where RPZ "action" strings are parsed/validated into tapir action tags.
rg -n --hidden -S \
  'allowlist|passthru|nxdomain|nodata|rpz-passthru|rpz-drop|redirect|NXDOMAIN|NODATA|DROP' \
  --type go -g '!vendor/**' .

# Show the policy action mapping code and nearby parser logic (small windows only).
rg -n -S 'func \(.*\)\s*HasAction|HasAction\(' --type go -g '!vendor/**' .
rg -n -S 'type .*Action|const .*NXDOMAIN|const .*NODATA|const .*DROP|redirect' --type go -g '!vendor/**' .

# Print the relevant policy.go sections around the first match we saw.
sed -n '120,210p' policy.go 2>/dev/null || true
ls -1

Repository: dnstapir/pop

Length of output: 4100


🏁 Script executed:

#!/bin/bash
set -u

# 1) Search for redirect/passthru/nxdomain/nodata/drop string handling in Go code
rg -n --hidden -S 'redirect|passthru|allowlist|nxdomain|nodata|rpz-passthru\.|rpz-drop\.' --type go -g '!vendor/**' .

# 2) Open the relevant action-parsing blocks we saw in sources.go and policy.go
echo "---- sources.go (around first action switch) ----"
sed -n '360,470p' sources.go

echo "---- policy.go (around rpzaction mapping) ----"
sed -n '120,210p' policy.go

# 3) Find how policy.allowlist.action is parsed
echo "---- Search for StringToAction usage ----"
rg -n --hidden -S 'StringToAction\(' --type go -g '!vendor/**' .

# 4) Find what tapir action constants exist in-repo (if any)
echo "---- Search for const/enum for actions ----"
rg -n --hidden -S 'type .*Action|const .*NXDOMAIN|const .*NODATA|const .*DROP|rpz-passthru|rpz-drop' --type go -g '!vendor/**' .

# 5) Confirm docs table and what it claims
echo "---- docs/configuration.md (action values table area) ----"
sed -n '200,260p' docs/configuration.md

Repository: dnstapir/pop

Length of output: 14389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for redirect/RPZ redirect support in this repo's Go code.
rg -n --hidden -S 'redirect|rpz-redirect|rpz.*redirect' --type go -g '!vendor/**' .

# Search for RPZ action CNAME targets handled (confirm supported set).
rg -n --hidden -S 'rpz-[a-z\-]+\.' --type go -g '!vendor/**' .

# Find where tapir.Action parsing is defined/used; look for StringToAction definition in-repo.
rg -n --hidden -S 'func\s+.*StringToAction|StringToAction\s*[:=]' --type go -g '!vendor/**' .

# Inspect structs.go where AllowlistAction / types are declared to see allowed actions.
sed -n '1,140p' structs.go 2>/dev/null || true

# Show go.mod for tapir dependency provenance.
ls -1
cat go.mod 2>/dev/null || true

Repository: dnstapir/pop

Length of output: 38


🏁 Script executed:

#!/bin/bash
set +euo pipefail

echo "== go.mod =="
cat go.mod 2>/dev/null || true

echo "== Search for redirect in repo (Go/docs/config) =="
rg -n --hidden -S 'redirect' -g '!*vendor/**' .

echo "== Search for rpz-redirect or rpz redirect targets =="
rg -n --hidden -S 'rpz-.*redirect|rpz.*redirect' -g '!*vendor/**' .

echo "== Search for rpzaction mapping =="
rg -n --hidden -S 'rpzaction' -g '!*vendor/**' .

echo "== Search for CNAME RPZ target literals =="
rg -n --hidden -S 'case "\."|case "\*\."|rpz-passthru\.|rpz-drop\.' -g '!*vendor/**' .

echo "== Search for tapir.ActionToString keys incl redirect/passthru =="
rg -n --hidden -S 'ActionToString\[[' -g '!*vendor/**' .

echo "== Inspect policy.go further where rpz actions are computed =="
sed -n '1,240p' policy.go

Repository: dnstapir/pop

Length of output: 10703


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate tapir module source in GOPATH module cache and search for action parsing.
GOPATH="$(go env GOPATH)"
MODCACHE="$GOPATH/pkg/mod"

echo "GOPATH=$GOPATH"
echo "MODCACHE=$MODCACHE"

# Find tapir module directory matching required version
echo "== tapir module dirs =="
ls -1 "$MODCACHE/github.com/dnstapir" 2>/dev/null | head -n 50 || true

echo "== Search tapir for StringToAction / Action parsing =="
rg -n -S 'func\s+StringToAction|type\s+Action|ActionToString|redirect|rpz-redirect|rpz-passthru|rpz-drop|ALLOWLIST|NXDOMAIN|NODATA|DROP' \
  "$MODCACHE/github.com/dnstapir" -g '*tapir*' --no-mmap 2>/dev/null | head -n 200

# Specifically try to print the StringToAction function body if found.
echo "== Attempt to print StringToAction definition context =="
rg -n -S 'func\s+StringToAction\(' "$MODCACHE/github.com/dnstapir" -g '*tapir*' --no-mmap 2>/dev/null | head -n 20

# Open rpz.go around where rpzaction is assigned into CNAME target.
echo "== rpz.go: around CNAME target assignment =="
sed -n '1,260p' rpz.go | sed -n '1,200p' # keep output small

echo "== Search rpz.go for redirect emission =="
rg -n -S 'redirect|rpz-redirect' rpz.go || true

Repository: dnstapir/pop

Length of output: 236


🏁 Script executed:

#!/bin/bash
set +euo pipefail

GOPATH="$(go env GOPATH)"
MODCACHE="$GOPATH/pkg/mod"
TPIR_DIR="$(ls -1 "$MODCACHE/github.com/dnstapir" | head -n 1)"
echo "tapir module dir: $MODCACHE/github.com/dnstapir/$TPIR_DIR"

TAPIR_PATH="$MODCACHE/github.com/dnstapir/$TPIR_DIR"
echo "== tapir go files (top-level scan) =="
find "$TAPIR_PATH" -maxdepth 2 -name '*.go' | head -n 50

echo "== rg: StringToAction =="
rg -n -S 'StringToAction' "$TAPIR_PATH" -g '*.go' --no-mmap || true

echo "== rg: ActionToString =="
rg -n -S 'ActionToString' "$TAPIR_PATH" -g '*.go' --no-mmap || true

echo "== rg: redirect =="
rg -n -S 'redirect' "$TAPIR_PATH" -g '*.go' --no-mmap || true

echo "== rg: rpz-passthru / rpz-drop literals in tapir =="
rg -n -S 'rpz-passthru\.|rpz-drop\.' "$TAPIR_PATH" -g '*.go' --no-mmap || true

echo "== rg: NXDOMAIN / NODATA / DROP / passthru =="
rg -n -S 'NXDOMAIN|NODATA|DROP|passthru|ALLOWLIST' "$TAPIR_PATH" -g '*.go' --no-mmap || true

Repository: dnstapir/pop

Length of output: 7072


🏁 Script executed:

#!/bin/bash
set +euo pipefail

# Inspect tapir action parsing/mapping (bitmask.go)
TAPIR_PATH="/home/jailuser/go/pkg/mod/github.com/dnstapir/tapir@v0.0.0-20251117100352-b3b797ea3b38"

echo "== tapir/bitmask.go: StringToAction and ActionToString =="
sed -n '80,170p' "$TAPIR_PATH/bitmask.go" 2>/dev/null || true

echo "== tapir/bitmask.go: search for REDIRECT handling further =="
rg -n -S 'REDIRECT|redirect' "$TAPIR_PATH/bitmask.go" || true

echo "== tapir/cmd/rpz.go: redirect / rpz output =="
rg -n -S 'redirect|rpz-.*redirect|CNAME' "$TAPIR_PATH/cmd/rpz.go" || true
sed -n '1,120p' "$TAPIR_PATH/cmd/rpz.go" 2>/dev/null || true

# Inspect tapir structs.go for action bitfield and any redirect fields
echo "== tapir/structs.go: REDIRECT fields =="
rg -n -S 'REDIRECT|redirect' "$TAPIR_PATH/structs.go" || true
sed -n '250,430p' "$TAPIR_PATH/structs.go" 2>/dev/null || true

# Inspect pop's rpz.go around where it sets CNAME target and applies actions
echo "== pop/rpz.go: where rpzaction used in CNAME =="
sed -n '1,220p' rpz.go
sed -n '220,320p' rpz.go

# Search for ActionToString usage in pop and rpz CNAME target mapping.
echo "== pop: search ActionToString usage =="
rg -n -S 'ActionToString\[' . -g '!vendor/**'

Repository: dnstapir/pop

Length of output: 21842


🏁 Script executed:

#!/bin/bash
set +euo pipefail

TAPIR_PATH="/home/jailuser/go/pkg/mod/github.com/dnstapir/tapir@v0.0.0-20251117100352-b3b797ea3b38"

echo "== tapir: search for placeholder text =="
rg -n -S 'what-to-do-about-this' "$TAPIR_PATH" -g '*.go' || true

echo "== tapir: search for CheckRedirect / redirect policy =="
rg -n -S 'CheckRedirect|redirectPolicy|REDIRECT' "$TAPIR_PATH" -g '*.go' || true

echo "== pop: search for REDIRECT handling in doubt policy =="
rg -n -S 'ApplyDoubtPolicy|REDIRECT|redirect' rpz.go policy.go sources.go -g '*.go' || true

# show ApplyDoubtPolicy for context
rg -n -S 'func ApplyDoubtPolicy' -n policy.go
sed -n '130,190p' policy.go

Repository: dnstapir/pop

Length of output: 3617


Fix documented redirect action semantics (currently placeholder/partial).

allowlist/passthru, nxdomain, nodata, and drop are accepted by the policy engine and map to RPZ CNAME targets rpz-passthru., ., *., and rpz-drop. respectively. redirect is also accepted, but it currently maps to the hardcoded placeholder CNAME target what-to-do-about-this (so the redirect target is not actually implemented). Additionally, doubtlist AXFR generation uses ApplyDoubtPolicy, which does not handle REDIRECT, so redirect may be missing from AXFR output for doubtlist-derived records.

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

In `@docs/configuration.md` around lines 221 - 229, The docs note that the
"redirect" action is a placeholder; update the policy and AXFR code so REDIRECT
is implemented end-to-end: change the hardcoded CNAME target
"what-to-do-about-this" to use a configurable redirect target (add a config
field and read it where the action-to-RPZ mapping is performed), ensure the
action-to-RPZ mapping routine (the mapping function in the policy engine) emits
the proper CNAME target for REDIRECT, and modify ApplyDoubtPolicy to handle the
REDIRECT enum/value and include the redirect CNAME in doubtlist AXFR generation
so redirect records are present in AXFR output; also update the docs text to
describe the final redirect semantics and config key.

Comment thread docs/configuration.md Outdated
| `nxdomain` | `.` — return NXDOMAIN |
| `nodata` | `*.` — return NODATA |
| `drop` | `rpz-drop.` — silently drop the query |
| `redirect` | redirect (target TBD in upstream config) |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for redirect action implementation

rg -n -C5 'redirect' --type go -g '*policy*.go' -g '!vendor/**'

Repository: dnstapir/pop

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Inspect docs context around the redirect row
sed -n '210,245p' docs/configuration.md

# Broader search for redirect handling across the repo (excluding vendor)
rg -n -C3 'redirect' -S -g'!vendor/**'

Repository: dnstapir/pop

Length of output: 1922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find redirect handling in Go across the whole repo (excluding vendor)
rg -n -S --type go 'case\s+"redirect"|case\s+`redirect`|"redirect"' -g '!vendor/**'

# 2) Locate the action mapping by searching for other known action strings
rg -n -S --type go '(allowlist|passthru|nxdomain|nodata|rpz-drop)' -g '!vendor/**'

Repository: dnstapir/pop

Length of output: 38


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for any RPZ redirect RHS emission (often uses rpz- prefix)
rg -n -S --type go 'rpz-redirect|rpz.*redirect|redirect\.' -g '!vendor/**'

# Find where RPZ action strings are generated/emitted (look for rpz- constants broadly)
rg -n -S --type go 'rpz-[a-z0-9-]+' -g '!vendor/**' --no-messages | head -n 50

# Show full docs context around the redirect row
sed -n '215,240p' docs/configuration.md

Repository: dnstapir/pop

Length of output: 38


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find how other documented actions are implemented in Go
rg -n -S --type go 'allowlist|passthru|nxdomain|nodata|rpz-drop|drop' -g '!vendor/**'

# Locate the policy/action dispatch area by looking for comparisons/switches (heuristic)
rg -n -S --type go '(switch|case|if)\s*.*(allowlist|passthru|nxdomain|nodata|drop)' -g '!vendor/**'

# Confirm there are no other docs mentions of redirect/target nearby
sed -n '220,238p' docs/configuration.md

Repository: dnstapir/pop

Length of output: 7394


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where tapir.Action parsing/string mapping is implemented (may include redirect support)
rg -n -S --type go 'StringToAction|ActionToString|type Action|const .*Action|REDIRECT' -g '!vendor/**'

# Specifically look for any redirect-like action identifiers in this repo (often tapir.REDIRECT)
rg -n -S --type go 'tapir\.(REDIRECT|Redirect|RPZREDIRECT|RPZ_REDIRECT)' -g '!vendor/**'

# Show the redirect row docs context around line 229
sed -n '220,236p' docs/configuration.md

Repository: dnstapir/pop

Length of output: 1370


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Repo-wide occurrences of the word redirect (excluding vendor/node_modules)
rg -n -S 'redirect' -g '!vendor/**' -g '!node_modules/**'

# Inspect how RPZ responses are computed (policy.go)
sed -n '1,240p' policy.go

# Inspect RPZ generation logic (rpz.go) around where actions are mapped/combined
sed -n '1,220p' rpz.go

Repository: dnstapir/pop

Length of output: 13963


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat go.mod
rg -n "dnstapir/tapir" go.sum | head -n 20

Repository: dnstapir/pop

Length of output: 2528


🌐 Web query:

dnstapir tapir redirect ActionToCNAMETarget StringToAction

💡 Result:

The terms “dnstapir tapir redirect ActionToCNAMETarget StringToAction” do not map to a single, clearly documented technical feature in the authoritative sources I located. From the sources I found: 1) DNS TAPIR (dnstapir.se) DNS TAPIR’s architecture describes DNS query logging/analysis components (Resolver → Minimise → Core) and that Core analyzes aggregated DNSTAP data and reports anomalies as “observations”. The pages I found do not mention symbols like ActionToCNAMETarget or StringToAction, nor a “redirect” action mapping [1][2]. 2) Tapir (softwaremill/tapir) Tapir’s official docs explain EndpointInput/endpoint inputs and how to capture query parameters via queryT (single parameter by name) and queryParams (all query parameters). The docs I found do not mention ActionToCNAMETarget or StringToAction [3][4]. 3) “redirect” actions exist in other products, but don’t match your provided identifiers For example, redirection.io documents a “Redirection” action that takes a target URL and status code [5], and ngrok documents a “Redirect Action” that transforms URLs via regex/CEL interpolation. These are different configuration models and do not define the exact symbols you provided [6]. What I need to answer precisely: please share the repository/link or a snippet where “ActionToCNAMETarget” and “StringToAction” appear (or confirm the exact project name and language/runtime). With that, I can do targeted follow-up searches and provide a fully source-cited explanation.

Citations:


🌐 Web query:

rpz redirect target TBD upstream config dnstapir tapir

💡 Result:

The RPZ “redirect target” is the CNAME “local data” value placed in the RPZ zone (i.e., the CNAME RDATA that the policy returns for a matching trigger). For example, the DROP action is encoded by a CNAME whose target is rpz-drop., which results in the query being discarded (no response sent to the client) [1]. Redirects to a “walled garden” are implemented by using a CNAME whose target is the walled-garden name (commonly written as a CNAME to the desired garden hostname, and optionally using wildcard forms for logging / templating) [1][2]. How that relates to “upstream config dnstapir tapir”: DNS TAPIR’s TAPIR Edge/Policy Processor can manipulate resolver responses (including redirecting users) and is connected to policy generation and response handling via RPZ, while DNSTAP is used for logging/observation of DNS traffic flowing through the system [3][4]. In other words, “dnstapir/tapir” provides/produces policy inputs (an RPZ feed/config) based on observations, but the actual “redirect target” that the resolver returns is still the RPZ CNAME local-data target contained in that RPZ policy feed [1][4]. If you tell me which resolver you’re configuring (Unbound/BIND/PowerDNS/other) and the RPZ zone/trigger name you’re using, I can map the exact config field that corresponds to the CNAME local-data “target” for “TBD”.

Citations:


Clarify redirect action support and where the redirect target is configured.

docs/configuration.md lists redirect (target TBD in upstream config) as a valid action, but this repo doesn’t provide any redirect-specific mapping: the AXFR doubtlist path (ApplyDoubtPolicy) only handles NXDOMAIN, NODATA, and DROP, so redirect isn’t wired there. RPZ CNAME “local data” targets are generated via tapir.ActionToCNAMETarget[...], so “TBD” should explicitly point to the upstream/tapir config field(s) that define the redirect target and note whether redirect works for denylist vs doubtlist.

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

In `@docs/configuration.md` at line 229, Update the docs entry for `redirect` to
point to the actual upstream/tapir config fields that supply the redirect target
instead of "TBD": mention that RPZ CNAME local-data targets are generated from
tapir.ActionToCNAMETarget and specify which tapir/upstream config keys populate
ActionToCNAMETarget, and clarify that the AXFR doubtlist path (ApplyDoubtPolicy)
only supports NXDOMAIN, NODATA, and DROP so `redirect` is not wired there; also
state whether redirect is available for denylist vs doubtlist (and if only
denylist supports redirect via tapir). Use the symbols ApplyDoubtPolicy and
tapir.ActionToCNAMETarget in the text so readers can locate the implementation.

@jschlyter jschlyter requested a review from morkrost May 23, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Community: Write configuration documentation

4 participants