Skip to content

Develop#71

Merged
kweonminsung merged 46 commits intomainfrom
develop
Mar 23, 2026
Merged

Develop#71
kweonminsung merged 46 commits intomainfrom
develop

Conversation

@kweonminsung
Copy link
Copy Markdown
Owner

No description provided.

renovate bot and others added 30 commits November 20, 2025 16:44
chore(deps): update actions/checkout action to v6
fix(deps): update rust crate axum to 0.8.8
chore(deps): update rust crate tempfile to 3.24.0
fix(deps): update rust crate config to 0.15.19
fix(deps): update rust crate clap to 4.5.54
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
fix(deps): update rust crate tower-http to 0.6.8
…rification

56 feature add dns 01 tls verification
Copilot AI review requested due to automatic review settings March 23, 2026 19:32
@kweonminsung kweonminsung merged commit 848224f into main Mar 23, 2026
2 of 3 checks passed
Copy link
Copy Markdown
Contributor

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

This PR evolves Bindizr from an RNDC/zonefile-based workflow to a built-in DNS transfer (AXFR/IXFR) control plane with catalog zone support, while updating the HTTP API, socket daemon commands, and CLI to operate on zone/record names and support new operational flows.

Changes:

  • Introduces a new xfr module (AXFR/IXFR server, NOTIFY, catalog zone generation) and updates configuration keys to listen_addr + per-service *.listen_port.
  • Reworks API + tests to use zone name (and record name/type) as identifiers and removes rendered-zone/history endpoints.
  • Refactors CLI/socket commands away from DNS/RNDC operations toward CRUD + NOTIFY, plus adds table/json/yaml output support.

Reviewed changes

Copilot reviewed 106 out of 112 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/fixture/bindizr.conf.toml Updates test config to new listen_addr/listen_port + XFR section.
tests/common/mod.rs Updates test context imports/init; adjusts zone insert fields.
tests/api/zone.rs Updates zone API tests to use name-based routes and new validation expectations.
tests/api/record.rs Updates record API tests to use zone_name and name/type routes.
tests/api/mod.rs Updates error-handling tests for 404 and new request shape.
tests/api/dns.rs Removes DNS API tests.
src/xfr/server.rs Adds TCP XFR listener with ACL enforcement and query dispatch.
src/xfr/notify.rs Adds UDP NOTIFY sender to configured secondary servers.
src/xfr/mod.rs Adds XFR initialization + catalog-zone readiness hook.
src/xfr/ixfr.rs Implements IXFR response building using change history + SOA snapshots.
src/xfr/error.rs Introduces XfrError error type.
src/xfr/delta.rs Adds DB-to-XFR adapters for zone changes and SOA snapshots.
src/xfr/catalog.rs Implements catalog zone generation and AXFR/SOA handling for it.
src/xfr/axfr.rs Implements AXFR + SOA handlers (including catalog zone special-case).
src/socket/server/zone.rs Adds daemon socket handlers for zone CRUD.
src/socket/server/record.rs Adds daemon socket handlers for record CRUD/listing.
src/socket/server/notify.rs Adds daemon socket handler for NOTIFY command.
src/socket/server/mod.rs Routes new daemon commands (zone/record/notify) and removes DNS commands.
src/socket/server/dns.rs Removes daemon DNS/RNDC command handlers.
src/socket/dto.rs Replaces DNS command kinds with zone/record/notify kinds.
src/serializer/utils.rs Removes serializer helpers.
src/serializer/mod.rs Removes zonefile serializer.
src/rndc/mod.rs Removes RNDC client module.
src/main.rs Wires in xfr module and removes RNDC/serializer modules.
src/logger/mod.rs Switches logging output to stderr.
src/lib.rs Exposes new error and xfr modules; removes serializer/rndc exports.
src/error/mod.rs Adds top-level BindizrError and Result<T> alias.
src/database/schema.rs Updates schema: removes NS IP fields, replaces history tables with zone_changes + zone_soa_history.
src/database/repository/sqlite/zone_snapshot_repository_impl.rs Adds SQLite SOA snapshot repository implementation.
src/database/repository/sqlite/zone_repository_impl.rs Updates SQLite zone repo for new schema + DatabaseError.
src/database/repository/sqlite/zone_history_repository_impl.rs Removes SQLite zone history repository.
src/database/repository/sqlite/zone_change_repository_impl.rs Adds SQLite zone change repository implementation.
src/database/repository/sqlite/record_repository_impl.rs Updates SQLite record repo to return DatabaseError.
src/database/repository/sqlite/record_history_repository_impl.rs Removes SQLite record history repository.
src/database/repository/sqlite/mod.rs Exposes new SQLite change/snapshot repos; removes history repos.
src/database/repository/sqlite/api_token_repository_impl.rs Updates SQLite API token repo to return DatabaseError.
src/database/repository/postgres/zone_snapshot_repository_impl.rs Adds Postgres SOA snapshot repository implementation.
src/database/repository/postgres/zone_repository_impl.rs Updates Postgres zone repo for new schema + DatabaseError.
src/database/repository/postgres/zone_history_repository_impl.rs Removes Postgres zone history repository.
src/database/repository/postgres/zone_change_repository_impl.rs Adds Postgres zone change repository implementation.
src/database/repository/postgres/record_repository_impl.rs Updates Postgres record repo to return DatabaseError.
src/database/repository/postgres/record_history_repository_impl.rs Removes Postgres record history repository.
src/database/repository/postgres/mod.rs Exposes new Postgres change/snapshot repos; removes history repos.
src/database/repository/postgres/api_token_repository_impl.rs Updates Postgres API token repo to return DatabaseError.
src/database/repository/mysql/zone_snapshot_repository_impl.rs Adds MySQL SOA snapshot repository implementation.
src/database/repository/mysql/zone_repository_impl.rs Updates MySQL zone repo for new schema + DatabaseError.
src/database/repository/mysql/zone_history_repository_impl.rs Removes MySQL zone history repository.
src/database/repository/mysql/zone_change_repository_impl.rs Adds MySQL zone change repository implementation.
src/database/repository/mysql/record_repository_impl.rs Updates MySQL record repo to return DatabaseError.
src/database/repository/mysql/record_history_repository_impl.rs Removes MySQL record history repository.
src/database/repository/mysql/mod.rs Exposes new MySQL change/snapshot repos; removes history repos.
src/database/repository/mysql/api_token_repository_impl.rs Updates MySQL API token repo to return DatabaseError.
src/database/repository/mod.rs Replaces history traits with change/snapshot traits; standardizes on DatabaseError.
src/database/model/zone_snapshot.rs Adds SOA snapshot model.
src/database/model/zone_history.rs Removes zone history model.
src/database/model/zone_change.rs Adds zone change model.
src/database/model/zone.rs Removes primary NS IP fields from zone model.
src/database/model/record_history.rs Removes record history model.
src/database/model/record.rs Minor formatting cleanup around RecordType impls.
src/database/model/mod.rs Exposes new models (zone_change, zone_snapshot); removes history models.
src/database/model/api_token.rs Adds inline field comments for API token fields.
src/database/mod.rs Adds database::error; replaces history repo getters with change/snapshot getters.
src/database/error.rs Introduces DatabaseError and From<sqlx::Error> mapping.
src/config/tests.rs Adjusts float test value and comparisons.
src/config/mod.rs Adds config::error and get_config_optional.
src/config/error.rs Introduces ConfigError.
src/cli/output/table.rs Adds table row types for zone/record output.
src/cli/output/mod.rs Adds CLI output module exports.
src/cli/output/format.rs Adds json/yaml/table output selection and rendering.
src/cli/mod.rs Refactors CLI into command modules; adds CRUD + notify; starts XFR on bootstrap and waits for Ctrl+C.
src/cli/dns.rs Removes CLI DNS/RNDC commands.
src/cli/commands/token.rs Moves token command implementation under commands/.
src/cli/commands/status.rs Minor cleanup of status command request call.
src/cli/commands/start.rs Adds start command handler wrapper.
src/cli/commands/notify.rs Adds CLI NOTIFY command.
src/cli/commands/mod.rs Adds command module index.
src/cli/commands/get.rs Adds get zones/records CLI with output formatting.
src/cli/commands/delete.rs Adds delete zone/record CLI commands.
src/cli/commands/create.rs Adds create zone/record CLI commands.
src/api/validation.rs Introduces ValidationError.
src/api/service/zone_history.rs Removes zone history service.
src/api/service/record_history.rs Removes record history service.
src/api/service/mod.rs Removes dns/history services; keeps auth/record/zone.
src/api/service/dns.rs Removes DNS/RNDC service.
src/api/service/auth.rs Switches token validation to return ApiError and uses better status mapping.
src/api/mod.rs Updates binding config keys; spawns API server instead of awaiting it; updates log line.
src/api/error.rs Adds ApiError implementing IntoResponse.
src/api/dto.rs Removes zone NS IP fields and history DTOs; changes CreateZoneRequest.serial to optional; adds record zone_name.
src/api/controller/zone_history.rs Removes zone history controller/routes.
src/api/controller/zone.rs Switches zone routes to name-based paths; removes rendered endpoint; uses ApiError responses.
src/api/controller/record_history.rs Removes record history controller/routes.
src/api/controller/record.rs Switches record routes to name/type path and zone_name filtering; uses ApiError responses.
src/api/controller/mod.rs Removes DNS + history controller merges; keeps zone/record routes.
src/api/controller/middleware/body_parser.rs Updates comments and keeps custom JSON body extractor/rejection type.
src/api/controller/dns.rs Rewrites DNS controller (currently no longer merged into API router).
scripts/setup_bind_rndc.sh Removes RNDC-oriented setup script.
scripts/setup_bind.sh Adds new BIND secondary + catalog-zone setup script.
renovate.json Formatting-only change.
bindizr.conf.toml Updates default config to new listen keys and XFR settings; removes RNDC config.
README.md Updates documentation to describe XFR/catalog-zone architecture and new setup/CLI usage.
Cargo.toml Bumps version, updates dependencies, removes rndc, adds domain/thiserror/CLI output deps.
.github/workflows/update-openapi-docs.yml Updates checkout action major version.
.github/workflows/release.yml Updates checkout action major version.
.github/workflows/manual-release.yml Updates checkout action major version.
.github/workflows/ci.yml Updates checkout action major version.

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

Comment on lines +14 to +18
let response = GetZoneResponse::from_zone(&zone);
Ok(DaemonResponse {
message: "Zone retrieved successfully".to_string(),
data: serde_json::to_value(response).unwrap(),
})
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

These handlers use serde_json::to_value(...).unwrap(). If serialization fails for any reason, the daemon will panic and potentially crash the socket server. Prefer mapping serialization errors into the Result (return an Err or a structured DaemonResponse error) instead of unwrapping.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +65
} else {
vec![
ZoneRow::from_json(data).unwrap_or_else(|_| panic!("Failed to parse zone")),
]
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The CLI path uses unwrap_or_else(|_| panic!(...)) when parsing server responses into table rows. This can crash the CLI on unexpected/partial responses (or when the server returns an error payload). Prefer returning a Result with a helpful error message so the CLI fails gracefully instead of panicking.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +21
[xfr]
listen_port = 53
secondary_addrs = "127.0.0.1"
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The test fixture sets xfr.secondary_addrs = "127.0.0.1" (no port). If the runtime config contract expects ip:port entries (as implied by config docs / NOTIFY parsing), this value will be invalid for NOTIFY and can cause NOTIFY to skip all targets. Consider updating the fixture to include an explicit port (e.g., 127.0.0.1:53) or aligning the implementation to accept bare IPs consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +66 to +80
// Parse secondary servers list (format: "ip:port,ip:port,...")
let server_addresses: Vec<SocketAddr> = secondary_servers_str
.split(',')
.filter_map(|s| {
let trimmed = s.trim();
if trimmed.is_empty() {
return None;
}
match trimmed.parse::<SocketAddr>() {
Ok(addr) => Some(addr),
Err(e) => {
log_error!("Invalid server address '{}': {}", trimmed, e);
None
}
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

xfr.secondary_addrs parsing here only accepts SocketAddr (ip:port). However other code paths (e.g., XFR ACL parsing) accept bare IPs, and the test fixture config sets secondary_addrs = "127.0.0.1". With the current logic this will be treated as invalid and NOTIFY will silently skip all servers (server list becomes empty). Consider also accepting bare IpAddr values and defaulting the port (typically 53) or updating the config contract/docs + fixtures to always include a port.

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +100
// Check if client is in secondary servers list
if !secondary_servers.is_empty() && !secondary_servers.contains(&client_ip) {
log_warn!(
"XFR request denied from {} (not a configured secondary server)",
client_ip
);
return Err(XfrError::AccessDenied(format!(
"IP {} not allowed",
client_ip
)));
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

If xfr.secondary_addrs is empty, this ACL check allows XFR from any client IP. Since AXFR/IXFR exposes full zone contents, this is a risky default (especially because the sample config defaults secondary_addrs to empty). Consider default-denying when the allowlist is empty (or requiring an explicit config flag like xfr.allow_any = true), and log a clear warning/error when starting with an open ACL.

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +68
let zone_repository = get_zone_repository();
let mut response: Vec<GetRecordResponse> = Vec::new();

for record in records.iter() {
let zone_name = zone_repository
.get_by_id(record.zone_id)
.await
.ok()
.flatten()
.map(|z| z.name)
.unwrap_or_default();

let mut rec_response = GetRecordResponse::from_record(record);
rec_response.zone_name = Some(zone_name);
response.push(rec_response);
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

list_records does a separate zone_repository.get_by_id(...) query for each record to populate zone_name, which will become an N+1 query pattern as record counts grow. Consider fetching zone names in one query (e.g., preload all needed zone IDs into a map) or adjusting RecordService::get_records/DTOs to include the zone name via a join.

Copilot uses AI. Check for mistakes.
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.

2 participants