From b22ffee1bb8eb74b4725b061eb176ff07f428f7e Mon Sep 17 00:00:00 2001 From: abrown38 Date: Fri, 9 Oct 2026 09:05:59 +0000 Subject: [PATCH] Fix the import warning for allow-update { none; }; document CLI config paths jarld import warned that zones with allow-update { none; } use dynamic updates, though that turns them off (validation already allowed it). docs/cli.md now gives the CLI configuration file's location on macOS and Windows, not only ~/.config/jarl/config.yaml. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 9 +++++++++ docs/cli.md | 15 +++++++++++++-- docs/install.md | 3 ++- internal/importer/importer.go | 17 ++++++++++++++++- internal/importer/importer_test.go | 19 +++++++++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c7653..dd760af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,15 @@ All notable changes to Jarl are documented here. The format follows and prints the steps to install Jarl and adopt the configuration (docs/development.md). +### Fixed + +- `jarld import` no longer warns that a zone with `allow-update { none; }` + uses dynamic updates (validation already allowed it). +- docs/cli.md gives the CLI configuration file's location on macOS + (`~/Library/Application Support/jarl/config.yaml`) and Windows + (`%AppData%\jarl\config.yaml`). It was documented only as + `~/.config/jarl/config.yaml`. + ## [0.1.0] - 2026-10-09 The first version. diff --git a/docs/cli.md b/docs/cli.md index 1860b20..cf06023 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -44,8 +44,19 @@ jarl whoami | Changeset to stage into | `-C/--changeset` | `JARL_CHANGESET` | | Flags win over the environment, and the environment wins over the file. The -file is `~/.config/jarl/config.yaml` (mode 0600), or `--config` / -`JARL_CLI_CONFIG`. `jarl config show` prints it with the token masked. +file is `jarl/config.yaml` in the user's configuration directory, or +`--config` / `JARL_CLI_CONFIG`: + +| System | File | +|--------|------| +| Linux and other Unix | `~/.config/jarl/config.yaml` (`$XDG_CONFIG_HOME/jarl/config.yaml` if set) | +| macOS | `~/Library/Application Support/jarl/config.yaml` | +| Windows | `%AppData%\jarl\config.yaml` (`C:\Users\\AppData\Roaming\jarl\config.yaml`) | + +It is written with mode 0600 (on Windows, the AppData folder is already +private to the user). `jarl config show` prints its path and the settings, +with the token masked. On Windows and macOS there is no local jarld, so +always set a server. Get tokens from the web UI (Account → API tokens), from `jarl token create`, or from `jarld init --token` on the server. diff --git a/docs/install.md b/docs/install.md index 1881caf..0a2239b 100644 --- a/docs/install.md +++ b/docs/install.md @@ -322,7 +322,8 @@ jarl status jarl zone list ``` -The CLI's settings are stored in `~/.config/jarl/config.yaml` (mode 0600). +The CLI's settings are stored in `~/.config/jarl/config.yaml` (mode 0600; +macOS and Windows use their own folders, see [cli.md](cli.md#setup)). `JARL_SERVER` and `JARL_TOKEN` override them, which is handy in scripts. Create more tokens in the web UI (Account → API tokens) or with `jarl token create NAME`. See [cli.md](cli.md). diff --git a/internal/importer/importer.go b/internal/importer/importer.go index 5c9d554..1183746 100644 --- a/internal/importer/importer.go +++ b/internal/importer/importer.go @@ -477,7 +477,7 @@ func (im *importer) zone(s *namedconf.Stmt, v *model.View) error { } report.Records, report.Skipped = n, skipped for _, o := range opts { - if kw := o.Keyword(); kw == "allow-update" || kw == "update-policy" { + if kw := o.Keyword(); kw == "update-policy" || kw == "allow-update" && !allowsNone(o) { im.warn("zone %s uses %s (dynamic updates); Jarl rewrites zone files and won't apply such zones until %s is removed", dnsname.Display(z.Name), kw, kw) } } @@ -735,3 +735,18 @@ func ParseZoneText(zone, text string) (*ParsedZone, error) { } return pz, nil } + +// allowsNone says whether an address match list option is { none; } +// (allow-update { none; } turns dynamic updates off). +func allowsNone(o *namedconf.Stmt) bool { + b := o.FirstBlock() + if b == nil { + return false + } + for _, s := range b.Stmts { + if namedconf.Compact(s.Items) != "none" { + return false + } + } + return true +} diff --git a/internal/importer/importer_test.go b/internal/importer/importer_test.go index cabdf9d..3c523d6 100644 --- a/internal/importer/importer_test.go +++ b/internal/importer/importer_test.go @@ -146,3 +146,22 @@ func TestParseTTL(t *testing.T) { } } } + +func TestImportAllowUpdateWarning(t *testing.T) { + dir := t.TempDir() + os.WriteFile(filepath.Join(dir, "x.db"), []byte("$TTL 300\n@ IN SOA ns1.x.test. h.x.test. 1 2 3 4 5\n@ IN NS ns1\nns1 IN A 192.0.2.1\n"), 0o644) + for conf, want := range map[string]bool{ + `allow-update { none; };`: false, + `allow-update { 127.0.0.1; };`: true, + `update-policy local;`: true, + } { + os.WriteFile(filepath.Join(dir, "named.conf"), []byte(`zone "x.test" { type primary; file "`+dir+`/x.db"; `+conf+` };`), 0o644) + _, rep, err := Import(context.Background(), filepath.Join(dir, "named.conf"), Options{Alloc: seqAlloc()}) + if err != nil { + t.Fatal(err) + } + if got := len(rep.Warnings) > 0; got != want { + t.Errorf("%s: warnings = %v", conf, rep.Warnings) + } + } +}