From 9a4f7a19e46a99d2a35c28ba3b929e4d7d03f3e1 Mon Sep 17 00:00:00 2001 From: Yifei Sun Date: Mon, 27 Oct 2025 10:22:05 +0100 Subject: [PATCH 1/3] go-csp-collector: init at 0.0.16-unstable-2025-10-10 --- pkgs/by-name/go/go-csp-collector/package.nix | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 pkgs/by-name/go/go-csp-collector/package.nix diff --git a/pkgs/by-name/go/go-csp-collector/package.nix b/pkgs/by-name/go/go-csp-collector/package.nix new file mode 100644 index 000000000000..73046b614b05 --- /dev/null +++ b/pkgs/by-name/go/go-csp-collector/package.nix @@ -0,0 +1,49 @@ +{ + lib, + buildGoModule, + fetchFromGitHub, + versionCheckHook, + nix-update-script, +}: + +buildGoModule (finalAttrs: { + pname = "go-csp-collector"; + version = "0.0.16-unstable-2025-10-10"; + + src = fetchFromGitHub { + owner = "jacobbednarz"; + repo = "go-csp-collector"; + rev = "a0cf22ac6d1f5c8972bf53671ba174767d2adcd5"; + hash = "sha256-xFvO8ZuJQ5luCDOTPHtVeb1+3VvIKSwjt2TqkxBIY58="; + }; + + vendorHash = "sha256-SrQahSHO5ZIkcLR3BR5CR5BTStW1pH1Ij1Eql0b3tuU="; + + ldflags = [ + "-s" + "-w" + "-X main.Rev=${finalAttrs.version}" + ]; + + postInstall = '' + install -Dm644 init/go-csp-collector.service $out/lib/systemd/system/go-csp-collector.service + + substituteInPlace $out/lib/systemd/system/go-csp-collector.service \ + --replace-fail "/usr/local/bin/go-csp-collector" "$out/bin/go-csp-collector" + ''; + + doInstallCheck = true; + nativeInstallCheckInputs = [ versionCheckHook ]; + versionCheckProgramArg = "-version"; + + passthru.updateScript = nix-update-script { }; + + meta = { + description = "A content security policy violation collector written in Golang"; + homepage = "https://github.com/jacobbednarz/go-csp-collector"; + changelog = "https://github.com/jacobbednarz/go-csp-collector/blob/${finalAttrs.src.rev}/CHANGELOG.md"; + license = lib.licenses.mit; + mainProgram = "go-csp-collector"; + maintainers = with lib.maintainers; [ stepbrobd ]; + }; +}) From e30ee35619434c64c699a5732589e141afebb8a8 Mon Sep 17 00:00:00 2001 From: Yifei Sun Date: Mon, 27 Oct 2025 10:37:24 +0100 Subject: [PATCH 2/3] nixos/go-csp-collector: init module --- nixos/modules/module-list.nix | 1 + .../services/monitoring/go-csp-collector.nix | 106 ++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 nixos/modules/services/monitoring/go-csp-collector.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 36ccab4792b2..5a1d97e6d296 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -990,6 +990,7 @@ ./services/monitoring/gitwatch.nix ./services/monitoring/glances.nix ./services/monitoring/glpi-agent.nix + ./services/monitoring/go-csp-collector.nix ./services/monitoring/goss.nix ./services/monitoring/grafana-image-renderer.nix ./services/monitoring/grafana-reporter.nix diff --git a/nixos/modules/services/monitoring/go-csp-collector.nix b/nixos/modules/services/monitoring/go-csp-collector.nix new file mode 100644 index 000000000000..6fafbb840740 --- /dev/null +++ b/nixos/modules/services/monitoring/go-csp-collector.nix @@ -0,0 +1,106 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.go-csp-collector; + + inherit (lib) + boolToString + concatStringsSep + getExe + isBool + literalExpression + maintainers + mapAttrsToList + mkEnableOption + mkIf + mkOption + mkPackageOption + types + ; + + settingsToArgs = + settings: + concatStringsSep " " ( + mapAttrsToList ( + name: value: + let + flag = "-${name}"; + in + if isBool value then "${flag}=${boolToString value}" else "${flag} ${toString value}" + ) settings + ); +in +{ + meta.maintainers = with maintainers; [ stepbrobd ]; + + options.services.go-csp-collector = { + enable = mkEnableOption "go-csp-collector, a content security policy violation collector"; + + package = mkPackageOption pkgs "go-csp-collector" { }; + + settings = mkOption { + type = types.submodule { + freeformType = + with types; + attrsOf (oneOf [ + bool + path + str + ]); + + options = { + port = mkOption { + type = types.port; + description = "The port to listen on."; + default = 8080; + example = 8080; + }; + + output-format = mkOption { + type = types.enum [ + "text" + "json" + ]; + description = "Define how the violation reports are formatted for output."; + default = "text"; + example = "text"; + }; + }; + }; + + description = '' + Settings for go-csp-collector. See + for supported options. + ''; + + default = { }; + + example = literalExpression '' + { + debug = true; + health-check-path = "/health"; + } + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.packages = [ cfg.package ]; + systemd.services.go-csp-collector = { + description = "CSP violation collector"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ReadOnlyPaths = cfg.settings.filter-file or ""; + ExecStart = [ + "" + "${getExe cfg.package} ${settingsToArgs cfg.settings}" + ]; + }; + }; + }; +} From 53b7bada953d64829e4c75fc3ebd3ffdad58ae74 Mon Sep 17 00:00:00 2001 From: Yifei Sun Date: Sun, 26 Oct 2025 17:16:54 +0100 Subject: [PATCH 3/3] nixos/go-csp-collector: init test --- nixos/tests/all-tests.nix | 1 + nixos/tests/go-csp-collector.nix | 66 ++++++++++++++++++++ pkgs/by-name/go/go-csp-collector/package.nix | 6 +- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 nixos/tests/go-csp-collector.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 025c628344d8..099c37d27839 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -639,6 +639,7 @@ in gns3-server = runTest ./gns3-server.nix; gnupg = runTest ./gnupg.nix; go-camo = runTest ./go-camo.nix; + go-csp-collector = runTest ./go-csp-collector.nix; go-httpbin = runTest ./go-httpbin.nix; go-neb = runTest ./go-neb.nix; goatcounter = runTest ./goatcounter.nix; diff --git a/nixos/tests/go-csp-collector.nix b/nixos/tests/go-csp-collector.nix new file mode 100644 index 000000000000..ec75b51506ff --- /dev/null +++ b/nixos/tests/go-csp-collector.nix @@ -0,0 +1,66 @@ +{ lib, ... }: + +{ + name = "go-csp-collector"; + meta.maintainers = with lib.maintainers; [ stepbrobd ]; + + nodes.machine = + { pkgs, ... }: + { + services.go-csp-collector = { + enable = true; + settings = { + debug = true; + port = 9999; + health-check-path = "/health"; + filter-file = pkgs.writeText "filter" "chrome-extension://"; + }; + }; + }; + + testScript = '' + import json + + # health check + machine.wait_for_unit("go-csp-collector.service") + machine.wait_for_open_port(9999) + machine.succeed("curl -f http://localhost:9999/health") + + # send valid csp report + machine.succeed( + "curl -f -X POST http://127.0.0.1:9999/ " + "-H 'Content-Type: application/csp-report' " + "-d '" + json.dumps({ + "csp-report": { + "document-uri": "https://example.com/", + "referrer": "https://example.com/", + "violated-directive": "script-src", + "effective-directive": "script-src", + "original-policy": "script-src 'self'", + "blocked-uri": "https://example.org/malicious.js", + "status-code": 200 + } + }) + "'" + ) + logs = machine.succeed("journalctl -u go-csp-collector.service") + assert "level=debug" in logs, "debug mode not enabled" + assert "blocked_uri" in logs, "csp report not logged" + assert "https://example.org/malicious.js" in logs, "blocked uri not in logs" + + # check rejection + machine.fail( + "curl -f -X POST http://[::1]:9999/ " + "-H 'Content-Type: application/csp-report' " + "-d '" + json.dumps({ + "csp-report": { + "document-uri": "https://example.com/", + "blocked-uri": "chrome-extension://something", + "violated-directive": "script-src" + } + }) + "'" + ) + logs = machine.succeed("journalctl -u go-csp-collector.service") + assert "invalid resource" in logs, "filter rejection not logged" + assert "chrome-extension://" in logs, "filtered uri pattern not in logs" + ''; +} diff --git a/pkgs/by-name/go/go-csp-collector/package.nix b/pkgs/by-name/go/go-csp-collector/package.nix index 73046b614b05..c8437b2b122b 100644 --- a/pkgs/by-name/go/go-csp-collector/package.nix +++ b/pkgs/by-name/go/go-csp-collector/package.nix @@ -4,6 +4,7 @@ fetchFromGitHub, versionCheckHook, nix-update-script, + nixosTests, }: buildGoModule (finalAttrs: { @@ -36,7 +37,10 @@ buildGoModule (finalAttrs: { nativeInstallCheckInputs = [ versionCheckHook ]; versionCheckProgramArg = "-version"; - passthru.updateScript = nix-update-script { }; + passthru = { + updateScript = nix-update-script { }; + tests.service = nixosTests.go-csp-collector; + }; meta = { description = "A content security policy violation collector written in Golang";