diff --git a/.github/workflows/vulnix.yml b/.github/workflows/vulnix.yml index 60f797c..27f10a4 100644 --- a/.github/workflows/vulnix.yml +++ b/.github/workflows/vulnix.yml @@ -5,10 +5,6 @@ on: - cron: "0 6 * * 1" workflow_dispatch: -permissions: - contents: read - issues: write - jobs: scan: runs-on: nix diff --git a/ci.nix b/ci.nix index 2a6d0d1..77fa121 100644 --- a/ci.nix +++ b/ci.nix @@ -1,10 +1,17 @@ { lib, pkgs }: +let + # vulnix's bundled nix-2.34 broke its own --experimental-features detection + nixConf = pkgs.writeText "ci-nix.conf" "experimental-features = nix-command flakes"; +in # tools must track ci.py's subprocess calls; nix stays ambient (uses the # runner's own nix, not a pinned one). pkgs.writers.writePython3Bin "ci" { flakeIgnore = [ "E501" ]; libraries = [ pkgs.python3Packages.subprocess-tee ]; makeWrapperArgs = [ + "--set-default" + "NIX_USER_CONF_FILES" + (toString nixConf) "--prefix" "PATH" ":" diff --git a/ci.py b/ci.py index 7c47483..61076ea 100644 --- a/ci.py +++ b/ci.py @@ -18,7 +18,8 @@ def run(*args, **kw): def nix(*args): - return subprocess_tee.run(("nix", "--extra-experimental-features", "nix-command flakes", "-L", *args), check=True, text=True).stdout + # tee to stderr - stdout leaks into GITHUB_OUTPUT $() captures + return subprocess_tee.run(("nix", "--extra-experimental-features", "nix-command flakes", "-L", *args), check=True, text=True, stdout=sys.stderr).stdout def git(*args, check=True): @@ -32,13 +33,16 @@ def gitea(method, path, body=None): req.add_header("Authorization", f'token {os.environ["GH_TOKEN"]}') if data is not None: req.add_header("Content-Type", "application/json") - with urllib.request.urlopen(req) as resp: - raw = resp.read() + try: + with urllib.request.urlopen(req) as resp: + raw = resp.read() + except urllib.error.HTTPError as e: + sys.exit(f"gitea {method} {path}: {e.code} {e.reason}\n{e.read().decode()}") return json.loads(raw) if raw else None def find_open_issue(label): - issues = gitea("GET", f"/issues?state=open&labels={label}") + issues = gitea("GET", f"/issues?state=open&type=issues&labels={label}") return issues[0] if issues else None @@ -235,7 +239,7 @@ def format_vulnix(vulns): for v in vulns: for cve in v["affected_by"]: score = v.get("cvssv3_basescore", {}).get(cve) - desc = v.get("description", {}).get(cve, "") + desc = v.get("description", {}).get(cve, "").replace("\n", " ").replace("|", "∣") if len(desc) > 120: desc = desc[:117] + "..." rows.append((v["pname"], v["version"], cve, score, desc)) @@ -254,7 +258,7 @@ def format_vulnix(vulns): def vulnix(args): paths = list(build_hosts(args.ref).values()) - result = run("vulnix", "-j", "-C", *paths, capture_output=True) + result = run("vulnix", "-j", *paths, capture_output=True) if result.returncode not in (0, 2): print(result.stderr, file=sys.stderr) sys.exit(result.returncode)