Compare commits
No commits in common. "main" and "v0.2.0" have entirely different histories.
9 changed files with 28 additions and 188 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -4,22 +4,6 @@
|
||||||
|
|
||||||
Changes yet to be released are documented here.
|
Changes yet to be released are documented here.
|
||||||
|
|
||||||
## v0.3.0
|
|
||||||
|
|
||||||
- Stop setting `nix.settings.netrc-file` from the Home Manager module
|
|
||||||
- Document `netrc_path` in `config.toml` as the path operators should wire into their daemon configuration
|
|
||||||
- Add a module evaluation check to prevent the Home Manager module from reintroducing `nix.settings.netrc-file`
|
|
||||||
|
|
||||||
These changes are made to support both cppnix and detsysnix. The latter has [special requirements][additionalnetrcsources] around the `netrc` files.
|
|
||||||
|
|
||||||
[additionalnetrcsources]: https://docs.determinate.systems/determinate-nix/#additionalnetrcsources
|
|
||||||
|
|
||||||
## 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
|
## v0.2.0
|
||||||
|
|
||||||
- Improve config discovery for server workflows:
|
- Improve config discovery for server workflows:
|
||||||
|
|
|
||||||
18
README.md
18
README.md
|
|
@ -58,14 +58,6 @@ netrc_path = "$XDG_CONFIG_HOME/nix/netrc"
|
||||||
|
|
||||||
Path values support environment variable expansion (`$VAR` and `${VAR}`).
|
Path values support environment variable expansion (`$VAR` and `${VAR}`).
|
||||||
|
|
||||||
`netrc_path` is the path this tool writes tokens to.
|
|
||||||
|
|
||||||
Configure Nix to read that same path.
|
|
||||||
|
|
||||||
This supports both cppnix and detsysnix. The latter has [special
|
|
||||||
requirements][additionalnetrcsources] around `netrc` files, so set
|
|
||||||
`additionalNetrcSources` to include the configured `netrc_path`.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -86,15 +78,6 @@ Config path resolution order:
|
||||||
The NixOS server module exports `NIX_CACHE_LOGIN_CONFIG` and installs
|
The NixOS server module exports `NIX_CACHE_LOGIN_CONFIG` and installs
|
||||||
`/etc/nix-cache-login/config.toml` from `services.nix-cache-login-server.configFile`.
|
`/etc/nix-cache-login/config.toml` from `services.nix-cache-login-server.configFile`.
|
||||||
|
|
||||||
## Module Integration
|
|
||||||
|
|
||||||
The Home Manager and NixOS modules in this repo install the package and refresh
|
|
||||||
services.
|
|
||||||
|
|
||||||
Nix and detsysnix daemon configuration stays outside these modules.
|
|
||||||
|
|
||||||
Set your daemon to read the `netrc_path` configured in `config.toml`.
|
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
This tool is actively maintained by [Guardian Project](https://guardianproject.info).
|
This tool is actively maintained by [Guardian Project](https://guardianproject.info).
|
||||||
|
|
@ -109,7 +92,6 @@ For security-related issues, please contact us through our [security policy][sec
|
||||||
|
|
||||||
[issues]: https://guardianproject.dev/ops/nix-cache-login/issues
|
[issues]: https://guardianproject.dev/ops/nix-cache-login/issues
|
||||||
[sec]: https://guardianproject.info/contact/
|
[sec]: https://guardianproject.info/contact/
|
||||||
[additionalnetrcsources]: https://docs.determinate.systems/determinate-nix/#additionalnetrcsources
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
10
flake.lock
generated
10
flake.lock
generated
|
|
@ -2,12 +2,12 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775423009,
|
"lastModified": 1771848320,
|
||||||
"narHash": "sha256-vPKLpjhIVWdDrfiUM8atW6YkIggCEKdSAlJPzzhkQlw=",
|
"narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=",
|
||||||
"rev": "68d8aa3d661f0e6bd5862291b5bb263b2a6595c9",
|
"rev": "2fc6539b481e1d2569f25f8799236694180c0993",
|
||||||
"revCount": 975402,
|
"revCount": 953160,
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.975402%2Brev-68d8aa3d661f0e6bd5862291b5bb263b2a6595c9/019d657b-b3b7-7288-b3c0-42d420df206b/source.tar.gz"
|
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.953160%2Brev-2fc6539b481e1d2569f25f8799236694180c0993/019c8e05-d2f6-7c7e-9ead-612154b18bfb/source.tar.gz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
'';
|
'';
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
});
|
});
|
||||||
module-checks = import ./module-checks.nix { inherit self pkgs; };
|
|
||||||
devShell = self.devShells.${pkgs.stdenv.hostPlatform.system}.default;
|
devShell = self.devShells.${pkgs.stdenv.hostPlatform.system}.default;
|
||||||
}
|
}
|
||||||
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
nix.settings.netrc-file = "${config.xdg.configHome}/nix/netrc";
|
||||||
home.packages = [ cfg.package ];
|
home.packages = [ cfg.package ];
|
||||||
systemd.user.services.nix-cache-login = {
|
systemd.user.services.nix-cache-login = {
|
||||||
Unit.Description = "Nix cache login - refresh access token";
|
Unit.Description = "Nix cache login - refresh access token";
|
||||||
|
|
|
||||||
|
|
@ -93,34 +93,23 @@ func parse(path string) ([]entry, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
for i := 0; i < len(fields); {
|
if len(fields) < 2 {
|
||||||
switch fields[i] {
|
|
||||||
case "machine":
|
|
||||||
if i+1 >= len(fields) {
|
|
||||||
i++
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch fields[0] {
|
||||||
|
case "machine":
|
||||||
if current != nil {
|
if current != nil {
|
||||||
entries = append(entries, *current)
|
entries = append(entries, *current)
|
||||||
}
|
}
|
||||||
current = &entry{machine: fields[i+1]}
|
current = &entry{machine: fields[1]}
|
||||||
i += 2
|
|
||||||
case "login":
|
case "login":
|
||||||
if current != nil && i+1 < len(fields) {
|
if current != nil {
|
||||||
current.login = fields[i+1]
|
current.login = fields[1]
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
i++
|
|
||||||
case "password":
|
case "password":
|
||||||
if current != nil && i+1 < len(fields) {
|
if current != nil {
|
||||||
current.password = fields[i+1]
|
current.password = fields[1]
|
||||||
i += 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
default:
|
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,12 +130,11 @@ func write(path string, entries []entry) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, e := range entries {
|
for i, e := range entries {
|
||||||
login := e.login
|
if i > 0 {
|
||||||
if login == "" {
|
b.WriteString("\n")
|
||||||
login = "dummy"
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&b, "machine %s login %s password %s\n", e.machine, login, e.password)
|
fmt.Fprintf(&b, "machine %s\nlogin %s\npassword %s\n", e.machine, e.login, e.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(path, []byte(b.String()), 0600); err != nil {
|
if err := os.WriteFile(path, []byte(b.String()), 0600); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package netrc
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -56,28 +55,6 @@ 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) {
|
func TestUpsertAppend(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
path := filepath.Join(dir, "netrc")
|
path := filepath.Join(dir, "netrc")
|
||||||
|
|
@ -220,29 +197,3 @@ func TestFilePermissionsCorrected(t *testing.T) {
|
||||||
t.Errorf("file permissions = %o, want 0600", perm)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
{ self, pkgs }:
|
|
||||||
let
|
|
||||||
lib = pkgs.lib;
|
|
||||||
fakePackage = pkgs.runCommand "nix-cache-login-fake-package" { } ''
|
|
||||||
mkdir -p "$out/bin"
|
|
||||||
touch "$out/bin/nix-cache-login"
|
|
||||||
chmod +x "$out/bin/nix-cache-login"
|
|
||||||
'';
|
|
||||||
|
|
||||||
hmStubModule =
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
home.packages = lib.mkOption {
|
|
||||||
type = lib.types.listOf lib.types.package;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
home.homeDirectory = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "/home/tester";
|
|
||||||
};
|
|
||||||
xdg.configHome = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "/home/tester/.config";
|
|
||||||
};
|
|
||||||
nix.settings = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
systemd.user.services = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
systemd.user.timers = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
launchd.agents = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
evalHome =
|
|
||||||
extraConfig:
|
|
||||||
lib.evalModules {
|
|
||||||
modules = [
|
|
||||||
hmStubModule
|
|
||||||
./home-module.nix
|
|
||||||
{
|
|
||||||
services.nix-cache-login.enable = true;
|
|
||||||
services.nix-cache-login.package = fakePackage;
|
|
||||||
}
|
|
||||||
extraConfig
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
homeDefault = evalHome { };
|
|
||||||
in
|
|
||||||
pkgs.runCommand "nix-cache-login-module-checks" { } ''
|
|
||||||
test ${lib.escapeShellArg (builtins.toJSON (builtins.hasAttr "netrc-file" homeDefault.config.nix.settings))} = ${lib.escapeShellArg "false"}
|
|
||||||
test ${lib.escapeShellArg homeDefault.config.systemd.user.services.nix-cache-login.Service.ExecStart} = ${lib.escapeShellArg "${fakePackage}/bin/nix-cache-login refresh"}
|
|
||||||
touch "$out"
|
|
||||||
''
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
buildGoModule {
|
buildGoModule {
|
||||||
pname = "nix-cache-login";
|
pname = "nix-cache-login";
|
||||||
version = "0.3.0";
|
version = "0.2.0";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
# src = fetchgit {
|
# src = fetchgit {
|
||||||
# url = "https://guardianproject.dev/ops/nix-cache-login.git";
|
# url = "https://guardianproject.dev/ops/nix-cache-login.git";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue