-
-
Notifications
You must be signed in to change notification settings - Fork 211
[feat] Added nix flake support #2138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Super cool! Could you kindly add some unit tests and repo tests? |
Ya sure! |
Signed-off-by: Roshan Kumar <roshaen09@gmail.com>
Signed-off-by: Roshan Kumar <roshaen09@gmail.com>
Signed-off-by: Roshan Kumar <roshaen09@gmail.com>
Signed-off-by: Roshan Kumar <roshaen09@gmail.com>
One of the cool things is that we now have cdx1-pro! Below is the response. Any thoughts? To improve the code for parsing
The new code will focus on improving correctness and resilience by adding more detailed parsing logic. Here is an improved version: /**
* Enhanced method to parse flake.nix files, supporting more complex input structures
*
* @param {String} flakeNixFile flake.nix file to parse
* @returns {Object} Object containing package information
*/
export function parseFlakeNix(flakeNixFile) {
const pkgList = [];
const dependencies = [];
if (!existsSync(flakeNixFile)) {
return { pkgList, dependencies };
}
try {
const flakeContent = readFileSync(flakeNixFile, "utf-8");
// Extract inputs from flake.nix using regex
const inputsRegex = /inputs\s*=\s*\{[^}]*\}/g;
let match;
while ((match = inputsRegex.exec(flakeContent)) !== null) {
const inputBlock = match[0];
// Match different input patterns including nested inputs
const inputPatterns = [
/([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)\.url\s*=\s*"([^"]+)"/g,
/([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*)\s*=\s*\{\s*url\s*=\s*"([^"]+)"[^}]*\}/gs,
];
const addedPackages = new Set();
for (const pattern of inputPatterns) {
let subMatch;
pattern.lastIndex = 0;
while ((subMatch = pattern.exec(inputBlock)) !== null) {
const name = subMatch[1];
const url = subMatch[2] || subMatch[3];
if (name && url && !addedPackages.has(name)) {
addedPackages.add(name);
const pkg = {
name: name,
version: "latest",
description: `Nix flake input: ${name}`,
scope: "required",
properties: [
{
name: "SrcFile",
value: flakeNixFile,
},
{
name: "cdx:nix:input_url",
value: url,
},
],
evidence: {
identity: {
field: "purl",
confidence: 0.8,
methods: [
{
technique: "manifest-analysis",
confidence: 0.8,
value: flakeNixFile,
},
],
},
},
};
pkg.purl = generateNixPurl(name, "latest");
pkg["bom-ref"] = pkg.purl;
pkgList.push(pkg);
}
}
}
}
} catch (error) {
console.warn(`Failed to parse ${flakeNixFile}: ${error.message}`);
}
return { pkgList, dependencies };
}
/**
* Enhanced method to parse flake.lock files with better support for complex lock structures
*
* @param {String} flakeLockFile flake.lock file to parse
* @returns {Object} Object containing locked dependency information
*/
export function parseFlakeLock(flakeLockFile) {
const pkgList = [];
const dependencies = [];
if (!existsSync(flakeLockFile)) {
return { pkgList, dependencies };
}
try {
const lockContent = readFileSync(flakeLockFile, "utf-8");
const lockData = JSON.parse(lockContent);
if (lockData.nodes) {
for (const [nodeName, nodeData] of Object.entries(lockData.nodes)) {
if (nodeName === "root" || !nodeData.locked) continue;
const locked = nodeData.locked;
let version = "latest";
if (locked.rev) {
version = locked.rev.substring(0, 7);
} else if (locked.ref) {
version = locked.ref;
}
const pkg = {
name: nodeName,
version: version,
description: `Nix flake dependency: ${nodeName}`,
scope: "required",
properties: [
{
name: "SrcFile",
value: flakeLockFile,
},
],
evidence: {
identity: {
field: "purl",
confidence: 1.0,
methods: [
{
technique: "manifest-analysis",
confidence: 1.0,
value: flakeLockFile,
},
],
},
},
};
if (locked.narHash) {
pkg.properties.push({
name: "cdx:nix:nar_hash",
value: locked.narHash,
});
}
if (locked.lastModified) {
pkg.properties.push({
name: "cdx:nix:last_modified",
value: locked.lastModified.toString(),
});
}
if (locked.rev) {
pkg.properties.push({
name: "cdx:nix:revision",
value: locked.rev,
});
}
if (locked.ref) {
pkg.properties.push({
name: "cdx:nix:ref",
value: locked.ref,
});
}
pkg.purl = generateNixPurl(nodeName, version);
pkg["bom-ref"] = pkg.purl;
pkgList.push(pkg);
}
// Generate dependency relationships from root inputs
if (lockData.nodes?.root?.inputs) {
const rootInputs = Object.keys(lockData.nodes.root.inputs);
if (rootInputs.length > 0) {
dependencies.push({
ref: "pkg:nix/flake@latest",
dependsOn: rootInputs
.map(
(input) =>
pkgList.find((pkg) => pkg.name === input)?.["bom-ref"],
)
.filter(Boolean),
});
}
}
}
} catch (error) {
console.warn(`Failed to parse ${flakeLockFile}: ${error.message}`);
}
return { pkgList, dependencies };
} Key Improvements:
This version makes the parser more resilient to common but tricky parts of Nix flake configurations. |
I asked cdx1-pro to generate sample .nix and .lock files with various edge cases. Yes, I can generate sample Example 1: Complex Inputs with Aliases # flake.nix - Demonstrates nested inputs and aliases
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/release-23.11";
nixos = {
url = "github:NixOS/nixpkgs/nixos-unstable";
};
home-manager = {
url = "github:nix-community/home-manager/release-23.11";
};
};
outputs = { self, nixpkgs, ... }:
{ };
} Example 2: Complex Lock File with Multiple Inputs {
"nodes": {
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"home-manager": "home-manager"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1700000000,
"narHash": "sha256-1234567890abcdef...",
"ref": "release-23.11",
"rev": "abc123def456ghi789",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"home-manager": {
"locked": {
"lastModified": 1700000001,
"narHash": "sha256-abcdef1234567890...",
"ref": "release-23.11",
"rev": "def456ghi789jkl012",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
}
}
} These examples include:
The parser code I provided should be able to handle these cases robustly. |
Hii @prabhu The test runs fine but I see some room for code refactor Thank you! |
Signed-off-by: Roshan Kumar <roshaen09@gmail.com>
@prabhu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this great contribution!
Added support for nix flakes
Automatic detection