diff --git a/CHANGELOG.md b/CHANGELOG.md index 12afe1b..ffbf6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Changes yet to be released are documented here. +## v0.2.1 + +- Fix netrc parsing for one-line entries such as `machine ... login ... password ...` +- Always write netrc entries as one line with a non-empty login (`dummy`) +- Add regression tests for one-line netrc parsing and write format + ## v0.2.0 - Improve config discovery for server workflows: diff --git a/internal/netrc/netrc.go b/internal/netrc/netrc.go index 6eaae73..60eb1f5 100644 --- a/internal/netrc/netrc.go +++ b/internal/netrc/netrc.go @@ -93,23 +93,34 @@ func parse(path string) ([]entry, error) { } fields := strings.Fields(line) - if len(fields) < 2 { - continue - } - - switch fields[0] { - case "machine": - if current != nil { - entries = append(entries, *current) - } - current = &entry{machine: fields[1]} - case "login": - if current != nil { - current.login = fields[1] - } - case "password": - if current != nil { - current.password = fields[1] + for i := 0; i < len(fields); { + switch fields[i] { + case "machine": + if i+1 >= len(fields) { + i++ + continue + } + if current != nil { + entries = append(entries, *current) + } + current = &entry{machine: fields[i+1]} + i += 2 + case "login": + if current != nil && i+1 < len(fields) { + current.login = fields[i+1] + i += 2 + continue + } + i++ + case "password": + if current != nil && i+1 < len(fields) { + current.password = fields[i+1] + i += 2 + continue + } + i++ + default: + i++ } } } @@ -130,11 +141,12 @@ func write(path string, entries []entry) error { } var b strings.Builder - for i, e := range entries { - if i > 0 { - b.WriteString("\n") + for _, e := range entries { + login := e.login + if login == "" { + login = "dummy" } - fmt.Fprintf(&b, "machine %s\nlogin %s\npassword %s\n", e.machine, e.login, e.password) + fmt.Fprintf(&b, "machine %s login %s password %s\n", e.machine, login, e.password) } if err := os.WriteFile(path, []byte(b.String()), 0600); err != nil { diff --git a/internal/netrc/netrc_test.go b/internal/netrc/netrc_test.go index e8a0b51..ab8ded5 100644 --- a/internal/netrc/netrc_test.go +++ b/internal/netrc/netrc_test.go @@ -3,6 +3,7 @@ package netrc import ( "os" "path/filepath" + "strings" "testing" ) @@ -55,6 +56,28 @@ func TestUpsertUpdateExisting(t *testing.T) { } } +func TestUpsertUpdateExistingOneLineEntry(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "netrc") + + initial := "machine other.host login dummy password otherpass\nmachine cache.example.com login dummy password oldtoken\n" + if err := os.WriteFile(path, []byte(initial), 0600); err != nil { + t.Fatal(err) + } + + if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + pw, err := GetPassword(path, "cache.example.com") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if pw != "newtoken" { + t.Errorf("password = %q, want %q", pw, "newtoken") + } +} + func TestUpsertAppend(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "netrc") @@ -197,3 +220,29 @@ func TestFilePermissionsCorrected(t *testing.T) { t.Errorf("file permissions = %o, want 0600", perm) } } + +func TestWriteUsesOneLineFormatAndDummyLoginFallback(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "netrc") + + // Existing one-line entry with missing login should be normalized. + if err := os.WriteFile(path, []byte("machine cache.example.com password oldtoken\n"), 0600); err != nil { + t.Fatal(err) + } + + if err := Upsert(path, "cache.example.com", "newtoken"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + content, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read error: %v", err) + } + text := string(content) + if !strings.Contains(text, "machine cache.example.com login dummy password newtoken\n") { + t.Fatalf("unexpected netrc content: %q", text) + } + if strings.Contains(text, "\nlogin ") || strings.Contains(text, "\npassword ") { + t.Fatalf("netrc entry should be written on one line: %q", text) + } +} diff --git a/package.nix b/package.nix index 08c08bd..3187805 100644 --- a/package.nix +++ b/package.nix @@ -6,7 +6,7 @@ buildGoModule { pname = "nix-cache-login"; - version = "0.2.0"; + version = "0.2.1"; src = ./.; # src = fetchgit { # url = "https://guardianproject.dev/ops/nix-cache-login.git";