kirograph 0.16.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +103 -1605
- package/dist/architecture/layers/dart.js +112 -0
- package/dist/architecture/layers/dart.js.map +7 -0
- package/dist/architecture/layers/index.js +3 -1
- package/dist/architecture/layers/index.js.map +2 -2
- package/dist/bin/banner.js +74 -6
- package/dist/bin/banner.js.map +2 -2
- package/dist/bin/commands/affected.js +40 -5
- package/dist/bin/commands/affected.js.map +2 -2
- package/dist/bin/commands/attack-surface.js +157 -0
- package/dist/bin/commands/attack-surface.js.map +7 -0
- package/dist/bin/commands/benchmark.js +206 -0
- package/dist/bin/commands/benchmark.js.map +7 -0
- package/dist/bin/commands/budget.js +70 -0
- package/dist/bin/commands/budget.js.map +7 -0
- package/dist/bin/commands/communities.js +77 -0
- package/dist/bin/commands/communities.js.map +7 -0
- package/dist/bin/commands/data.js +665 -0
- package/dist/bin/commands/data.js.map +7 -0
- package/dist/bin/commands/dep-confusion.js +119 -0
- package/dist/bin/commands/dep-confusion.js.map +7 -0
- package/dist/bin/commands/export.js +304 -10
- package/dist/bin/commands/export.js.map +2 -2
- package/dist/bin/commands/flows.js +97 -0
- package/dist/bin/commands/flows.js.map +7 -0
- package/dist/bin/commands/help.js +386 -100
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/install.js +90 -8
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/licenses.js +201 -0
- package/dist/bin/commands/licenses.js.map +7 -0
- package/dist/bin/commands/reachability.js +160 -0
- package/dist/bin/commands/reachability.js.map +7 -0
- package/dist/bin/commands/read.js +100 -0
- package/dist/bin/commands/read.js.map +7 -0
- package/dist/bin/commands/refactor.js +116 -0
- package/dist/bin/commands/refactor.js.map +7 -0
- package/dist/bin/commands/remediation.js +133 -0
- package/dist/bin/commands/remediation.js.map +7 -0
- package/dist/bin/commands/sbom.js +76 -0
- package/dist/bin/commands/sbom.js.map +7 -0
- package/dist/bin/commands/security-ci-report.js +267 -0
- package/dist/bin/commands/security-ci-report.js.map +7 -0
- package/dist/bin/commands/security-export.js +1349 -0
- package/dist/bin/commands/security-export.js.map +7 -0
- package/dist/bin/commands/security-flows.js +126 -0
- package/dist/bin/commands/security-flows.js.map +7 -0
- package/dist/bin/commands/security-secrets.js +170 -0
- package/dist/bin/commands/security-secrets.js.map +7 -0
- package/dist/bin/commands/security.js +193 -0
- package/dist/bin/commands/security.js.map +7 -0
- package/dist/bin/commands/staleness.js +144 -0
- package/dist/bin/commands/staleness.js.map +7 -0
- package/dist/bin/commands/status.js +102 -2
- package/dist/bin/commands/status.js.map +2 -2
- package/dist/bin/commands/supply-chain.js +138 -0
- package/dist/bin/commands/supply-chain.js.map +7 -0
- package/dist/bin/commands/uninit.js +109 -60
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/commands/vex.js +76 -0
- package/dist/bin/commands/vex.js.map +7 -0
- package/dist/bin/commands/vuln-suppress.js +95 -0
- package/dist/bin/commands/vuln-suppress.js.map +7 -0
- package/dist/bin/commands/vulns.js +382 -0
- package/dist/bin/commands/vulns.js.map +7 -0
- package/dist/bin/installer/auto-detect.js +125 -0
- package/dist/bin/installer/auto-detect.js.map +7 -0
- package/dist/bin/installer/cli-agent.js +28 -5
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.js +47 -0
- package/dist/bin/installer/common.js.map +2 -2
- package/dist/bin/installer/config-prompt.js +39 -1
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/detect.js +309 -0
- package/dist/bin/installer/detect.js.map +7 -0
- package/dist/bin/installer/index.js +36 -1
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.js +195 -3
- package/dist/bin/installer/instructions.js.map +2 -2
- package/dist/bin/installer/steering.js +440 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/aider.js +3 -3
- package/dist/bin/installer/targets/aider.js.map +2 -2
- package/dist/bin/installer/targets/amp.js +3 -3
- package/dist/bin/installer/targets/amp.js.map +2 -2
- package/dist/bin/installer/targets/antigravity.js +35 -6
- package/dist/bin/installer/targets/antigravity.js.map +2 -2
- package/dist/bin/installer/targets/augment.js +3 -3
- package/dist/bin/installer/targets/augment.js.map +2 -2
- package/dist/bin/installer/targets/claude.js +49 -5
- package/dist/bin/installer/targets/claude.js.map +2 -2
- package/dist/bin/installer/targets/cline.js +32 -6
- package/dist/bin/installer/targets/cline.js.map +2 -2
- package/dist/bin/installer/targets/codex.js +64 -12
- package/dist/bin/installer/targets/codex.js.map +2 -2
- package/dist/bin/installer/targets/continue.js +2 -2
- package/dist/bin/installer/targets/continue.js.map +2 -2
- package/dist/bin/installer/targets/copilot-cli.js +101 -0
- package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
- package/dist/bin/installer/targets/copilot.js +31 -5
- package/dist/bin/installer/targets/copilot.js.map +2 -2
- package/dist/bin/installer/targets/cursor.js +4 -4
- package/dist/bin/installer/targets/cursor.js.map +2 -2
- package/dist/bin/installer/targets/devin.js +2 -2
- package/dist/bin/installer/targets/devin.js.map +2 -2
- package/dist/bin/installer/targets/gemini-cli.js +2 -2
- package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
- package/dist/bin/installer/targets/generic.js +2 -14
- package/dist/bin/installer/targets/generic.js.map +2 -2
- package/dist/bin/installer/targets/goose.js +3 -3
- package/dist/bin/installer/targets/goose.js.map +2 -2
- package/dist/bin/installer/targets/index.js +250 -0
- package/dist/bin/installer/targets/index.js.map +2 -2
- package/dist/bin/installer/targets/junie.js +2 -2
- package/dist/bin/installer/targets/junie.js.map +2 -2
- package/dist/bin/installer/targets/kilo.js +2 -2
- package/dist/bin/installer/targets/kilo.js.map +2 -2
- package/dist/bin/installer/targets/kiro.js +3 -3
- package/dist/bin/installer/targets/kiro.js.map +2 -2
- package/dist/bin/installer/targets/opencode.js +2 -2
- package/dist/bin/installer/targets/opencode.js.map +2 -2
- package/dist/bin/installer/targets/openhands.js +3 -3
- package/dist/bin/installer/targets/openhands.js.map +2 -2
- package/dist/bin/installer/targets/qoder.js +91 -0
- package/dist/bin/installer/targets/qoder.js.map +7 -0
- package/dist/bin/installer/targets/qwen.js +96 -0
- package/dist/bin/installer/targets/qwen.js.map +7 -0
- package/dist/bin/installer/targets/replit.js +3 -3
- package/dist/bin/installer/targets/replit.js.map +2 -2
- package/dist/bin/installer/targets/roo.js +2 -2
- package/dist/bin/installer/targets/roo.js.map +2 -2
- package/dist/bin/installer/targets/tabnine.js +3 -3
- package/dist/bin/installer/targets/tabnine.js.map +2 -2
- package/dist/bin/installer/targets/trae.js +5 -5
- package/dist/bin/installer/targets/trae.js.map +2 -2
- package/dist/bin/installer/targets/warp.js +2 -2
- package/dist/bin/installer/targets/warp.js.map +2 -2
- package/dist/bin/installer/targets/windsurf.js +35 -6
- package/dist/bin/installer/targets/windsurf.js.map +2 -2
- package/dist/bin/kirograph.js +74 -6
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/bin/progress.js +30 -0
- package/dist/bin/progress.js.map +2 -2
- package/dist/compression/naive-cost.js +25 -0
- package/dist/compression/naive-cost.js.map +2 -2
- package/dist/compression/tracker.js +91 -2
- package/dist/compression/tracker.js.map +2 -2
- package/dist/compression/types.js.map +1 -1
- package/dist/config.js +126 -3
- package/dist/config.js.map +2 -2
- package/dist/core/pipeline.js +92 -4
- package/dist/core/pipeline.js.map +2 -2
- package/dist/data/filters.js +105 -0
- package/dist/data/filters.js.map +7 -0
- package/dist/data/indexer.js +225 -0
- package/dist/data/indexer.js.map +7 -0
- package/dist/data/linker.js +150 -0
- package/dist/data/linker.js.map +7 -0
- package/dist/data/lint.js +109 -0
- package/dist/data/lint.js.map +7 -0
- package/dist/data/parsers/csv.js +132 -0
- package/dist/data/parsers/csv.js.map +7 -0
- package/dist/data/parsers/excel.js +88 -0
- package/dist/data/parsers/excel.js.map +7 -0
- package/dist/data/parsers/index.js +79 -0
- package/dist/data/parsers/index.js.map +7 -0
- package/dist/data/parsers/json-array.js +89 -0
- package/dist/data/parsers/json-array.js.map +7 -0
- package/dist/data/parsers/jsonl.js +84 -0
- package/dist/data/parsers/jsonl.js.map +7 -0
- package/dist/data/parsers/parquet.js +95 -0
- package/dist/data/parsers/parquet.js.map +7 -0
- package/dist/data/profiler.js +182 -0
- package/dist/data/profiler.js.map +7 -0
- package/dist/data/queries.js +512 -0
- package/dist/data/queries.js.map +7 -0
- package/dist/data/types.js +17 -0
- package/dist/data/types.js.map +7 -0
- package/dist/db/data-schema.sql +61 -0
- package/dist/db/database.js +67 -5
- package/dist/db/database.js.map +2 -2
- package/dist/db/memory-schema.sql +5 -1
- package/dist/db/schema.sql +3 -1
- package/dist/db/security-schema.sql +72 -0
- package/dist/extraction/extractor.js +81 -0
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/grammars.js +32 -8
- package/dist/extraction/grammars.js.map +2 -2
- package/dist/extraction/languages.js +43 -1
- package/dist/extraction/languages.js.map +2 -2
- package/dist/extraction/notebook.js +300 -0
- package/dist/extraction/notebook.js.map +7 -0
- package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
- package/dist/frameworks/flutter.js +130 -0
- package/dist/frameworks/flutter.js.map +7 -0
- package/dist/frameworks/index.js +7 -1
- package/dist/frameworks/index.js.map +3 -3
- package/dist/graph/communities.js +317 -0
- package/dist/graph/communities.js.map +7 -0
- package/dist/graph/flows.js +138 -0
- package/dist/graph/flows.js.map +7 -0
- package/dist/graph/refactor.js +155 -0
- package/dist/graph/refactor.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/mcp/cache.js +172 -0
- package/dist/mcp/cache.js.map +7 -0
- package/dist/mcp/read-modes.js +295 -0
- package/dist/mcp/read-modes.js.map +7 -0
- package/dist/mcp/server.js +2 -1
- package/dist/mcp/server.js.map +2 -2
- package/dist/mcp/tool-names.js +29 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.js +1588 -6
- package/dist/mcp/tools.js.map +3 -3
- package/dist/memory/database.js +32 -2
- package/dist/memory/database.js.map +2 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/resolution/bridges/android-rn.js +298 -0
- package/dist/resolution/bridges/android-rn.js.map +7 -0
- package/dist/resolution/bridges/expo-modules.js +155 -0
- package/dist/resolution/bridges/expo-modules.js.map +7 -0
- package/dist/resolution/bridges/flutter-channel.js +385 -0
- package/dist/resolution/bridges/flutter-channel.js.map +7 -0
- package/dist/resolution/bridges/index.js +80 -0
- package/dist/resolution/bridges/index.js.map +7 -0
- package/dist/resolution/bridges/native-events.js +188 -0
- package/dist/resolution/bridges/native-events.js.map +7 -0
- package/dist/resolution/bridges/native-views.js +244 -0
- package/dist/resolution/bridges/native-views.js.map +7 -0
- package/dist/resolution/bridges/react-native.js +161 -0
- package/dist/resolution/bridges/react-native.js.map +7 -0
- package/dist/resolution/bridges/swift-objc.js +227 -0
- package/dist/resolution/bridges/swift-objc.js.map +7 -0
- package/dist/resolution/bridges/turbomodules.js +216 -0
- package/dist/resolution/bridges/turbomodules.js.map +7 -0
- package/dist/resolution/index.js +61 -2
- package/dist/resolution/index.js.map +2 -2
- package/dist/security/attack-surface.js +164 -0
- package/dist/security/attack-surface.js.map +7 -0
- package/dist/security/context-warnings.js +123 -0
- package/dist/security/context-warnings.js.map +7 -0
- package/dist/security/context-warnings.test.js +300 -0
- package/dist/security/context-warnings.test.js.map +7 -0
- package/dist/security/data-flows.js +228 -0
- package/dist/security/data-flows.js.map +7 -0
- package/dist/security/dep-confusion.js +255 -0
- package/dist/security/dep-confusion.js.map +7 -0
- package/dist/security/errors.js +51 -0
- package/dist/security/errors.js.map +7 -0
- package/dist/security/export/fix-suggestions.js +58 -0
- package/dist/security/export/fix-suggestions.js.map +7 -0
- package/dist/security/export/fix-suggestions.test.js +74 -0
- package/dist/security/export/fix-suggestions.test.js.map +7 -0
- package/dist/security/export/sbom.js +230 -0
- package/dist/security/export/sbom.js.map +7 -0
- package/dist/security/export/sbom.test.js +288 -0
- package/dist/security/export/sbom.test.js.map +7 -0
- package/dist/security/export/serialization.js +142 -0
- package/dist/security/export/serialization.js.map +7 -0
- package/dist/security/export/serialization.test.js +310 -0
- package/dist/security/export/serialization.test.js.map +7 -0
- package/dist/security/export/vex.js +220 -0
- package/dist/security/export/vex.js.map +7 -0
- package/dist/security/export/vex.test.js +278 -0
- package/dist/security/export/vex.test.js.map +7 -0
- package/dist/security/index.js +67 -0
- package/dist/security/index.js.map +7 -0
- package/dist/security/integrator-transitives.test.js +359 -0
- package/dist/security/integrator-transitives.test.js.map +7 -0
- package/dist/security/integrator.js +491 -0
- package/dist/security/integrator.js.map +7 -0
- package/dist/security/integrator.test.js +237 -0
- package/dist/security/integrator.test.js.map +7 -0
- package/dist/security/license.js +70 -0
- package/dist/security/license.js.map +7 -0
- package/dist/security/manifest/adapter.js +243 -0
- package/dist/security/manifest/adapter.js.map +7 -0
- package/dist/security/manifest/adapter.test.js +272 -0
- package/dist/security/manifest/adapter.test.js.map +7 -0
- package/dist/security/manifest/parser.js +376 -0
- package/dist/security/manifest/parser.js.map +7 -0
- package/dist/security/manifest/parser.test.js +110 -0
- package/dist/security/manifest/parser.test.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.js +233 -0
- package/dist/security/manifest/plugins/cargo.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.test.js +304 -0
- package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
- package/dist/security/manifest/plugins/composer.js +152 -0
- package/dist/security/manifest/plugins/composer.js.map +7 -0
- package/dist/security/manifest/plugins/go.js +146 -0
- package/dist/security/manifest/plugins/go.js.map +7 -0
- package/dist/security/manifest/plugins/go.test.js +341 -0
- package/dist/security/manifest/plugins/go.test.js.map +7 -0
- package/dist/security/manifest/plugins/gradle.js +159 -0
- package/dist/security/manifest/plugins/gradle.js.map +7 -0
- package/dist/security/manifest/plugins/hex.js +159 -0
- package/dist/security/manifest/plugins/hex.js.map +7 -0
- package/dist/security/manifest/plugins/maven.js +128 -0
- package/dist/security/manifest/plugins/maven.js.map +7 -0
- package/dist/security/manifest/plugins/maven.test.js +389 -0
- package/dist/security/manifest/plugins/maven.test.js.map +7 -0
- package/dist/security/manifest/plugins/npm.js +284 -0
- package/dist/security/manifest/plugins/npm.js.map +7 -0
- package/dist/security/manifest/plugins/npm.test.js +298 -0
- package/dist/security/manifest/plugins/npm.test.js.map +7 -0
- package/dist/security/manifest/plugins/nuget.js +186 -0
- package/dist/security/manifest/plugins/nuget.js.map +7 -0
- package/dist/security/manifest/plugins/pip.js +123 -0
- package/dist/security/manifest/plugins/pip.js.map +7 -0
- package/dist/security/manifest/plugins/pip.test.js +208 -0
- package/dist/security/manifest/plugins/pip.test.js.map +7 -0
- package/dist/security/manifest/plugins/pubspec.js +212 -0
- package/dist/security/manifest/plugins/pubspec.js.map +7 -0
- package/dist/security/manifest/plugins/pyproject.js +261 -0
- package/dist/security/manifest/plugins/pyproject.js.map +7 -0
- package/dist/security/manifest/plugins/rubygems.js +185 -0
- package/dist/security/manifest/plugins/rubygems.js.map +7 -0
- package/dist/security/manifest/plugins/swift.js +200 -0
- package/dist/security/manifest/plugins/swift.js.map +7 -0
- package/dist/security/owasp.js +104 -0
- package/dist/security/owasp.js.map +7 -0
- package/dist/security/pipeline.js +125 -0
- package/dist/security/pipeline.js.map +7 -0
- package/dist/security/reachability.js +276 -0
- package/dist/security/reachability.js.map +7 -0
- package/dist/security/reachability.test.js +394 -0
- package/dist/security/reachability.test.js.map +7 -0
- package/dist/security/remediation.js +126 -0
- package/dist/security/remediation.js.map +7 -0
- package/dist/security/secrets.js +176 -0
- package/dist/security/secrets.js.map +7 -0
- package/dist/security/staleness.js +231 -0
- package/dist/security/staleness.js.map +7 -0
- package/dist/security/supply-chain.js +301 -0
- package/dist/security/supply-chain.js.map +7 -0
- package/dist/security/suppressions.js +106 -0
- package/dist/security/suppressions.js.map +7 -0
- package/dist/security/types.js +17 -0
- package/dist/security/types.js.map +7 -0
- package/dist/security/vuln/client.js +355 -0
- package/dist/security/vuln/client.js.map +7 -0
- package/dist/security/vuln/client.test.js +288 -0
- package/dist/security/vuln/client.test.js.map +7 -0
- package/dist/security/vuln/epss-client.js +95 -0
- package/dist/security/vuln/epss-client.js.map +7 -0
- package/dist/security/vuln/index.js +29 -0
- package/dist/security/vuln/index.js.map +7 -0
- package/dist/security/vuln/osv-adapter.js +321 -0
- package/dist/security/vuln/osv-adapter.js.map +7 -0
- package/dist/security/vuln/osv-adapter.test.js +391 -0
- package/dist/security/vuln/osv-adapter.test.js.map +7 -0
- package/dist/security/vuln/types.js +17 -0
- package/dist/security/vuln/types.js.map +7 -0
- package/dist/types.js.map +2 -2
- package/package.json +5 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/security/manifest/plugins/npm.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Unit tests for the npm security manifest plugin.\n */\nimport { describe, it, expect, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { parseNpmManifest } from './npm';\n\ndescribe('parseNpmManifest', () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kirograph-npm-test-'));\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n function writePackageJson(content: Record<string, unknown>, dir?: string): string {\n const targetDir = dir ?? tmpDir;\n const filePath = path.join(targetDir, 'package.json');\n fs.mkdirSync(targetDir, { recursive: true });\n fs.writeFileSync(filePath, JSON.stringify(content, null, 2));\n return filePath;\n }\n\n it('extracts production dependencies with correct scope', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n version: '1.0.0',\n dependencies: {\n express: '^4.18.2',\n lodash: '~4.17.21',\n },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n const express = deps.find(d => d.name === 'express');\n expect(express).toBeDefined();\n expect(express!.declaredConstraint).toBe('^4.18.2');\n expect(express!.scope).toBe('production');\n expect(express!.ecosystem).toBe('npm');\n\n const lodash = deps.find(d => d.name === 'lodash');\n expect(lodash).toBeDefined();\n expect(lodash!.declaredConstraint).toBe('~4.17.21');\n expect(lodash!.scope).toBe('production');\n });\n\n it('extracts devDependencies with development scope', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n devDependencies: {\n vitest: '^1.0.0',\n typescript: '^5.0.0',\n },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(2);\n expect(deps.every(d => d.scope === 'development')).toBe(true);\n });\n\n it('extracts optionalDependencies with optional scope', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n optionalDependencies: {\n 'better-sqlite3': '^11.0.0',\n },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].scope).toBe('optional');\n expect(deps[0].name).toBe('better-sqlite3');\n });\n\n it('handles all scope fields together', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n dependencies: { express: '^4.18.0' },\n devDependencies: { vitest: '^1.0.0' },\n optionalDependencies: { sqlite3: '^5.0.0' },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(3);\n expect(deps.find(d => d.name === 'express')!.scope).toBe('production');\n expect(deps.find(d => d.name === 'vitest')!.scope).toBe('development');\n expect(deps.find(d => d.name === 'sqlite3')!.scope).toBe('optional');\n });\n\n it('resolves versions from package-lock.json (v2/v3 format)', async () => {\n writePackageJson({\n name: 'test-project',\n dependencies: { express: '^4.18.0' },\n });\n\n // Write a package-lock.json with resolved versions\n const lockContent = {\n lockfileVersion: 3,\n packages: {\n '': { name: 'test-project', version: '1.0.0' },\n 'node_modules/express': { version: '4.18.2' },\n },\n };\n fs.writeFileSync(\n path.join(tmpDir, 'package-lock.json'),\n JSON.stringify(lockContent),\n );\n\n const manifestPath = path.join(tmpDir, 'package.json');\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].resolvedVersion).toBe('4.18.2');\n expect(deps[0].declaredConstraint).toBe('^4.18.0');\n });\n\n it('resolves versions from package-lock.json (v1 format)', async () => {\n writePackageJson({\n name: 'test-project',\n dependencies: { lodash: '^4.17.0' },\n });\n\n const lockContent = {\n lockfileVersion: 1,\n dependencies: {\n lodash: { version: '4.17.21' },\n },\n };\n fs.writeFileSync(\n path.join(tmpDir, 'package-lock.json'),\n JSON.stringify(lockContent),\n );\n\n const manifestPath = path.join(tmpDir, 'package.json');\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].resolvedVersion).toBe('4.17.21');\n });\n\n it('resolves versions from yarn.lock', async () => {\n writePackageJson({\n name: 'test-project',\n dependencies: { react: '^18.0.0' },\n });\n\n const yarnLock = `# yarn lockfile v1\n\nreact@^18.0.0:\n version \"18.2.0\"\n resolved \"https://registry.yarnpkg.com/react/-/react-18.2.0.tgz\"\n integrity sha512-abc123\n`;\n fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), yarnLock);\n\n const manifestPath = path.join(tmpDir, 'package.json');\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].resolvedVersion).toBe('18.2.0');\n });\n\n it('handles scoped packages in yarn.lock', async () => {\n writePackageJson({\n name: 'test-project',\n dependencies: { '@types/node': '^20.0.0' },\n });\n\n const yarnLock = `# yarn lockfile v1\n\n\"@types/node@^20.0.0\":\n version \"20.11.5\"\n resolved \"https://registry.yarnpkg.com/@types/node/-/node-20.11.5.tgz\"\n`;\n fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), yarnLock);\n\n const manifestPath = path.join(tmpDir, 'package.json');\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].name).toBe('@types/node');\n expect(deps[0].resolvedVersion).toBe('20.11.5');\n });\n\n it('skips invalid dependency entries gracefully', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n dependencies: {\n express: '^4.18.0',\n '': '^1.0.0', // invalid: empty name\n '.hidden': '^1.0.0', // invalid: starts with dot\n validPkg: '', // invalid: empty constraint\n anotherValid: '^2.0.0', // valid\n badConstraint: 123, // invalid: non-string constraint\n },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n // Should only extract valid entries\n const names = deps.map(d => d.name);\n expect(names).toContain('express');\n expect(names).toContain('anotherValid');\n expect(names).not.toContain('');\n expect(names).not.toContain('.hidden');\n expect(names).not.toContain('validPkg');\n expect(names).not.toContain('badConstraint');\n });\n\n it('returns empty array for invalid JSON', async () => {\n const filePath = path.join(tmpDir, 'package.json');\n fs.writeFileSync(filePath, 'not valid json {{{');\n\n const deps = await parseNpmManifest(filePath, tmpDir);\n expect(deps).toEqual([]);\n });\n\n it('returns empty array for non-object JSON', async () => {\n const filePath = path.join(tmpDir, 'package.json');\n fs.writeFileSync(filePath, '\"just a string\"');\n\n const deps = await parseNpmManifest(filePath, tmpDir);\n expect(deps).toEqual([]);\n });\n\n it('returns empty array for array JSON', async () => {\n const filePath = path.join(tmpDir, 'package.json');\n fs.writeFileSync(filePath, '[1, 2, 3]');\n\n const deps = await parseNpmManifest(filePath, tmpDir);\n expect(deps).toEqual([]);\n });\n\n it('handles package.json with no dependency fields', async () => {\n const manifestPath = writePackageJson({\n name: 'empty-project',\n version: '1.0.0',\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n expect(deps).toEqual([]);\n });\n\n it('sets sourceManifest as relative path', async () => {\n const subDir = path.join(tmpDir, 'packages', 'sub');\n const manifestPath = writePackageJson(\n { name: 'sub', dependencies: { foo: '^1.0.0' } },\n subDir,\n );\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].sourceManifest).toBe('packages/sub/package.json');\n });\n\n it('handles peerDependencies with production scope', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n peerDependencies: { react: '>=16.0.0' },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].name).toBe('react');\n expect(deps[0].scope).toBe('production');\n expect(deps[0].declaredConstraint).toBe('>=16.0.0');\n });\n\n it('does not duplicate peerDependencies already in dependencies', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n dependencies: { react: '^18.0.0' },\n peerDependencies: { react: '>=16.0.0' },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n const reactDeps = deps.filter(d => d.name === 'react');\n expect(reactDeps).toHaveLength(1);\n expect(reactDeps[0].scope).toBe('production');\n expect(reactDeps[0].declaredConstraint).toBe('^18.0.0');\n });\n\n it('prefers package-lock.json over yarn.lock', async () => {\n writePackageJson({\n name: 'test-project',\n dependencies: { express: '^4.0.0' },\n });\n\n // Both lock files present\n const lockContent = {\n lockfileVersion: 3,\n packages: {\n '': { name: 'test-project' },\n 'node_modules/express': { version: '4.18.2' },\n },\n };\n fs.writeFileSync(path.join(tmpDir, 'package-lock.json'), JSON.stringify(lockContent));\n\n const yarnLock = `# yarn lockfile v1\n\nexpress@^4.0.0:\n version \"4.17.0\"\n`;\n fs.writeFileSync(path.join(tmpDir, 'yarn.lock'), yarnLock);\n\n const manifestPath = path.join(tmpDir, 'package.json');\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n // Should use package-lock.json version\n expect(deps[0].resolvedVersion).toBe('4.18.2');\n });\n\n it('leaves resolvedVersion undefined when no lock file exists', async () => {\n const manifestPath = writePackageJson({\n name: 'test-project',\n dependencies: { express: '^4.18.0' },\n });\n\n const deps = await parseNpmManifest(manifestPath, tmpDir);\n\n expect(deps).toHaveLength(1);\n expect(deps[0].resolvedVersion).toBeUndefined();\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var nuget_exports = {};
|
|
30
|
+
__export(nuget_exports, {
|
|
31
|
+
parseNugetManifest: () => parseNugetManifest
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(nuget_exports);
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var import_errors = require("../../../errors");
|
|
37
|
+
async function parseNugetManifest(manifestPath, projectRoot) {
|
|
38
|
+
const manifestDir = path.dirname(manifestPath);
|
|
39
|
+
const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
|
|
40
|
+
let content;
|
|
41
|
+
try {
|
|
42
|
+
content = fs.readFileSync(manifestPath, "utf8");
|
|
43
|
+
} catch (err) {
|
|
44
|
+
(0, import_errors.logWarn)(`[sec:nuget] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const resolvedVersions = loadResolvedVersions(manifestDir);
|
|
48
|
+
const license = extractNugetLicense(content);
|
|
49
|
+
const dependencies = [];
|
|
50
|
+
const csprojDeps = extractPackageReferences(content, relativeManifest);
|
|
51
|
+
for (const dep of csprojDeps) {
|
|
52
|
+
const resolvedVersion = resolvedVersions.get(dep.name.toLowerCase());
|
|
53
|
+
dependencies.push({
|
|
54
|
+
name: dep.name,
|
|
55
|
+
declaredConstraint: dep.constraint,
|
|
56
|
+
resolvedVersion,
|
|
57
|
+
scope: dep.scope,
|
|
58
|
+
ecosystem: "nuget",
|
|
59
|
+
sourceManifest: relativeManifest,
|
|
60
|
+
...license !== void 0 ? { license } : {}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const packagesConfigPath = path.join(manifestDir, "packages.config");
|
|
64
|
+
if (fs.existsSync(packagesConfigPath)) {
|
|
65
|
+
const relativePackagesConfig = path.relative(projectRoot, packagesConfigPath).replace(/\\/g, "/");
|
|
66
|
+
try {
|
|
67
|
+
const packagesConfigContent = fs.readFileSync(packagesConfigPath, "utf8");
|
|
68
|
+
const legacyDeps = extractPackagesConfig(packagesConfigContent, relativePackagesConfig);
|
|
69
|
+
for (const dep of legacyDeps) {
|
|
70
|
+
const resolvedVersion = resolvedVersions.get(dep.name.toLowerCase());
|
|
71
|
+
dependencies.push({
|
|
72
|
+
name: dep.name,
|
|
73
|
+
declaredConstraint: dep.constraint,
|
|
74
|
+
resolvedVersion,
|
|
75
|
+
scope: dep.scope,
|
|
76
|
+
ecosystem: "nuget",
|
|
77
|
+
sourceManifest: relativePackagesConfig,
|
|
78
|
+
...license !== void 0 ? { license } : {}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
(0, import_errors.logWarn)(`[sec:nuget] Failed to read ${relativePackagesConfig}: ${err instanceof Error ? err.message : String(err)}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return dependencies;
|
|
86
|
+
}
|
|
87
|
+
function extractPackageReferences(content, relativeManifest) {
|
|
88
|
+
const deps = [];
|
|
89
|
+
const elementRegex = /<PackageReference\b([^>]*?)(?:\/>|>([\s\S]*?)<\/PackageReference>)/gi;
|
|
90
|
+
let match;
|
|
91
|
+
while ((match = elementRegex.exec(content)) !== null) {
|
|
92
|
+
const attributes = match[1] ?? "";
|
|
93
|
+
const innerContent = match[2] ?? "";
|
|
94
|
+
const includeMatch = attributes.match(/\bInclude\s*=\s*"([^"]+)"/i);
|
|
95
|
+
if (!includeMatch) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const name = includeMatch[1].trim();
|
|
99
|
+
if (!name) {
|
|
100
|
+
(0, import_errors.logWarn)(`[sec:nuget] Empty Include attribute in PackageReference at ${relativeManifest} \u2014 skipping`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const privateAssetsMatch = attributes.match(/\bPrivateAssets\s*=\s*"([^"]*)"/i);
|
|
104
|
+
const scope = privateAssetsMatch && privateAssetsMatch[1].toLowerCase() === "all" ? "development" : "production";
|
|
105
|
+
let constraint = null;
|
|
106
|
+
const versionAttrMatch = attributes.match(/\bVersion\s*=\s*"([^"]+)"/i);
|
|
107
|
+
if (versionAttrMatch && versionAttrMatch[1].trim() !== "") {
|
|
108
|
+
constraint = versionAttrMatch[1].trim();
|
|
109
|
+
}
|
|
110
|
+
if (!constraint && innerContent) {
|
|
111
|
+
const versionElemMatch = innerContent.match(/<Version\s*>\s*([^<]+)\s*<\/Version>/i);
|
|
112
|
+
if (versionElemMatch && versionElemMatch[1].trim() !== "") {
|
|
113
|
+
constraint = versionElemMatch[1].trim();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!constraint) {
|
|
117
|
+
constraint = "*";
|
|
118
|
+
}
|
|
119
|
+
deps.push({ name, constraint, scope });
|
|
120
|
+
}
|
|
121
|
+
return deps;
|
|
122
|
+
}
|
|
123
|
+
function extractPackagesConfig(content, relativeManifest) {
|
|
124
|
+
const deps = [];
|
|
125
|
+
const packageRegex = /<package\b([^>]*?)\/>/gi;
|
|
126
|
+
let match;
|
|
127
|
+
while ((match = packageRegex.exec(content)) !== null) {
|
|
128
|
+
const attributes = match[1] ?? "";
|
|
129
|
+
const idMatch = attributes.match(/\bid\s*=\s*"([^"]+)"/i);
|
|
130
|
+
if (!idMatch) continue;
|
|
131
|
+
const name = idMatch[1].trim();
|
|
132
|
+
if (!name) {
|
|
133
|
+
(0, import_errors.logWarn)(`[sec:nuget] Empty id attribute in packages.config at ${relativeManifest} \u2014 skipping`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const versionMatch = attributes.match(/\bversion\s*=\s*"([^"]+)"/i);
|
|
137
|
+
const constraint = versionMatch && versionMatch[1].trim() !== "" ? versionMatch[1].trim() : "*";
|
|
138
|
+
deps.push({ name, constraint, scope: "production" });
|
|
139
|
+
}
|
|
140
|
+
return deps;
|
|
141
|
+
}
|
|
142
|
+
function loadResolvedVersions(manifestDir) {
|
|
143
|
+
const map = /* @__PURE__ */ new Map();
|
|
144
|
+
const lockPath = path.join(manifestDir, "packages.lock.json");
|
|
145
|
+
if (!fs.existsSync(lockPath)) {
|
|
146
|
+
return map;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const raw = fs.readFileSync(lockPath, "utf8");
|
|
150
|
+
const parsed = JSON.parse(raw);
|
|
151
|
+
extractFromPackagesLock(parsed, map);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
(0, import_errors.logWarn)(`[sec:nuget] Failed to parse packages.lock.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
154
|
+
}
|
|
155
|
+
return map;
|
|
156
|
+
}
|
|
157
|
+
function extractFromPackagesLock(parsed, map) {
|
|
158
|
+
if (typeof parsed !== "object" || parsed === null) return;
|
|
159
|
+
const root = parsed;
|
|
160
|
+
const dependencies = root["dependencies"];
|
|
161
|
+
if (typeof dependencies !== "object" || dependencies === null) return;
|
|
162
|
+
for (const framework of Object.values(dependencies)) {
|
|
163
|
+
if (typeof framework !== "object" || framework === null) continue;
|
|
164
|
+
for (const [packageName, packageInfo] of Object.entries(framework)) {
|
|
165
|
+
if (map.has(packageName.toLowerCase())) continue;
|
|
166
|
+
if (typeof packageInfo !== "object" || packageInfo === null) continue;
|
|
167
|
+
const info = packageInfo;
|
|
168
|
+
const resolved = info["resolved"];
|
|
169
|
+
if (typeof resolved === "string" && resolved.trim() !== "") {
|
|
170
|
+
map.set(packageName.toLowerCase(), resolved.trim());
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function extractNugetLicense(content) {
|
|
176
|
+
const match = content.match(/<PackageLicenseExpression\s*>\s*([^<]+)\s*<\/PackageLicenseExpression>/i);
|
|
177
|
+
if (match && match[1].trim() !== "") {
|
|
178
|
+
return match[1].trim();
|
|
179
|
+
}
|
|
180
|
+
return void 0;
|
|
181
|
+
}
|
|
182
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
183
|
+
0 && (module.exports = {
|
|
184
|
+
parseNugetManifest
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=nuget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/security/manifest/plugins/nuget.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * NuGet Version Extraction Plugin for KiroGraph-Sec\n *\n * Extends the existing architecture csproj parser to extract version constraints,\n * resolved versions (from packages.lock.json), and dependency scopes for security analysis.\n *\n * Reuses `csprojParser` from `src/architecture/manifest/csproj.ts` for discovery and\n * basic parsing, then layers on version/scope extraction.\n *\n * Handles:\n * - Inline attribute format: `<PackageReference Include=\"Name\" Version=\"1.0.0\"/>`\n * - Multi-line child element format: `<PackageReference Include=\"Name\"><Version>1.0.0</Version></PackageReference>`\n * - Legacy packages.config: `<package id=\"Name\" version=\"1.0.0\" targetFramework=\"...\"/>`\n * - Lock file packages.lock.json for resolved versions\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\n/**\n * Resolved version map: package name (lower-cased) \u2192 resolved version string.\n * Built from packages.lock.json.\n */\ntype ResolvedVersionMap = Map<string, string>;\n\n/**\n * Parse a .csproj manifest and extract NuGet dependency declarations\n * with version constraints, scopes, and resolved versions from packages.lock.json.\n * Also parses a packages.config in the same directory if present.\n *\n * @param manifestPath - Absolute path to the .csproj file\n * @param projectRoot - Absolute path to the project root directory\n * @returns Array of parsed dependencies with version and scope information\n */\nexport async function parseNugetManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const manifestDir = path.dirname(manifestPath);\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n // Read the .csproj content\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:nuget] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n // Attempt to load resolved versions from packages.lock.json\n const resolvedVersions = loadResolvedVersions(manifestDir);\n\n // Extract project-level license from .csproj\n const license = extractNugetLicense(content);\n\n const dependencies: ParsedDependency[] = [];\n\n // Extract from .csproj PackageReference elements\n const csprojDeps = extractPackageReferences(content, relativeManifest);\n for (const dep of csprojDeps) {\n const resolvedVersion = resolvedVersions.get(dep.name.toLowerCase());\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion,\n scope: dep.scope,\n ecosystem: 'nuget',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n\n // Also parse packages.config in the same directory (legacy NuGet)\n const packagesConfigPath = path.join(manifestDir, 'packages.config');\n if (fs.existsSync(packagesConfigPath)) {\n const relativePackagesConfig = path.relative(projectRoot, packagesConfigPath).replace(/\\\\/g, '/');\n try {\n const packagesConfigContent = fs.readFileSync(packagesConfigPath, 'utf8');\n const legacyDeps = extractPackagesConfig(packagesConfigContent, relativePackagesConfig);\n for (const dep of legacyDeps) {\n const resolvedVersion = resolvedVersions.get(dep.name.toLowerCase());\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion,\n scope: dep.scope,\n ecosystem: 'nuget',\n sourceManifest: relativePackagesConfig,\n ...(license !== undefined ? { license } : {}),\n });\n }\n } catch (err) {\n logWarn(`[sec:nuget] Failed to read ${relativePackagesConfig}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return dependencies;\n}\n\n/**\n * A raw dependency entry extracted from a .csproj or packages.config file.\n */\ninterface RawDependency {\n name: string;\n constraint: string;\n scope: ParsedDependency['scope'];\n}\n\n/**\n * Extract PackageReference entries from .csproj XML content.\n *\n * Handles:\n * - Inline: `<PackageReference Include=\"Newtonsoft.Json\" Version=\"13.0.1\" />`\n * - With PrivateAssets=\"all\": `<PackageReference Include=\"MSTest.TestFramework\" Version=\"3.1.1\" PrivateAssets=\"all\" />`\n * - Multi-line child: `<PackageReference Include=\"Name\"><Version>1.0.0</Version></PackageReference>`\n */\nfunction extractPackageReferences(content: string, relativeManifest: string): RawDependency[] {\n const deps: RawDependency[] = [];\n\n // Match single-line <PackageReference ... /> and multi-line <PackageReference ...>...</PackageReference>\n // The regex captures the full element including potential child content\n const elementRegex = /<PackageReference\\b([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/PackageReference>)/gi;\n let match: RegExpExecArray | null;\n\n while ((match = elementRegex.exec(content)) !== null) {\n const attributes = match[1] ?? '';\n const innerContent = match[2] ?? '';\n\n // Extract the Include attribute (package name)\n const includeMatch = attributes.match(/\\bInclude\\s*=\\s*\"([^\"]+)\"/i);\n if (!includeMatch) {\n continue;\n }\n const name = includeMatch[1].trim();\n if (!name) {\n logWarn(`[sec:nuget] Empty Include attribute in PackageReference at ${relativeManifest} \u2014 skipping`);\n continue;\n }\n\n // Determine scope: PrivateAssets=\"all\" indicates a development/build-only dependency\n const privateAssetsMatch = attributes.match(/\\bPrivateAssets\\s*=\\s*\"([^\"]*)\"/i);\n const scope: ParsedDependency['scope'] =\n privateAssetsMatch && privateAssetsMatch[1].toLowerCase() === 'all'\n ? 'development'\n : 'production';\n\n // Extract version from Version attribute (inline format)\n let constraint: string | null = null;\n const versionAttrMatch = attributes.match(/\\bVersion\\s*=\\s*\"([^\"]+)\"/i);\n if (versionAttrMatch && versionAttrMatch[1].trim() !== '') {\n constraint = versionAttrMatch[1].trim();\n }\n\n // If no inline version, check for <Version> child element (multi-line format)\n if (!constraint && innerContent) {\n const versionElemMatch = innerContent.match(/<Version\\s*>\\s*([^<]+)\\s*<\\/Version>/i);\n if (versionElemMatch && versionElemMatch[1].trim() !== '') {\n constraint = versionElemMatch[1].trim();\n }\n }\n\n if (!constraint) {\n // Version may be managed centrally (Directory.Packages.props) \u2014 use \"*\"\n constraint = '*';\n }\n\n deps.push({ name, constraint, scope });\n }\n\n return deps;\n}\n\n/**\n * Extract package entries from a legacy packages.config XML file.\n *\n * Format: `<package id=\"Newtonsoft.Json\" version=\"13.0.1\" targetFramework=\"net48\" />`\n * All packages from packages.config are treated as production scope.\n */\nfunction extractPackagesConfig(content: string, relativeManifest: string): RawDependency[] {\n const deps: RawDependency[] = [];\n\n const packageRegex = /<package\\b([^>]*?)\\/>/gi;\n let match: RegExpExecArray | null;\n\n while ((match = packageRegex.exec(content)) !== null) {\n const attributes = match[1] ?? '';\n\n const idMatch = attributes.match(/\\bid\\s*=\\s*\"([^\"]+)\"/i);\n if (!idMatch) continue;\n const name = idMatch[1].trim();\n if (!name) {\n logWarn(`[sec:nuget] Empty id attribute in packages.config at ${relativeManifest} \u2014 skipping`);\n continue;\n }\n\n const versionMatch = attributes.match(/\\bversion\\s*=\\s*\"([^\"]+)\"/i);\n const constraint = versionMatch && versionMatch[1].trim() !== '' ? versionMatch[1].trim() : '*';\n\n deps.push({ name, constraint, scope: 'production' });\n }\n\n return deps;\n}\n\n/**\n * Attempt to load resolved versions from packages.lock.json in the given directory.\n * Returns an empty map if the lock file is not available.\n *\n * packages.lock.json format:\n * ```json\n * {\n * \"version\": 1,\n * \"dependencies\": {\n * \"net8.0\": {\n * \"Newtonsoft.Json\": {\n * \"type\": \"Direct\",\n * \"resolved\": \"13.0.3\",\n * ...\n * }\n * }\n * }\n * }\n * ```\n */\nfunction loadResolvedVersions(manifestDir: string): ResolvedVersionMap {\n const map: ResolvedVersionMap = new Map();\n\n const lockPath = path.join(manifestDir, 'packages.lock.json');\n if (!fs.existsSync(lockPath)) {\n return map;\n }\n\n try {\n const raw = fs.readFileSync(lockPath, 'utf8');\n const parsed = JSON.parse(raw);\n extractFromPackagesLock(parsed, map);\n } catch (err) {\n logWarn(`[sec:nuget] Failed to parse packages.lock.json: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return map;\n}\n\n/**\n * Extract resolved versions from a parsed packages.lock.json object.\n *\n * Iterates over all target frameworks and their packages, storing\n * the `resolved` version for each package (keyed by lower-cased name).\n */\nfunction extractFromPackagesLock(\n parsed: unknown,\n map: ResolvedVersionMap,\n): void {\n if (typeof parsed !== 'object' || parsed === null) return;\n\n const root = parsed as Record<string, unknown>;\n const dependencies = root['dependencies'];\n if (typeof dependencies !== 'object' || dependencies === null) return;\n\n // Iterate over target frameworks (e.g. \"net8.0\", \"net48\")\n for (const framework of Object.values(dependencies as Record<string, unknown>)) {\n if (typeof framework !== 'object' || framework === null) continue;\n\n // Iterate over packages within the framework\n for (const [packageName, packageInfo] of Object.entries(framework as Record<string, unknown>)) {\n if (map.has(packageName.toLowerCase())) continue; // first occurrence wins\n if (typeof packageInfo !== 'object' || packageInfo === null) continue;\n\n const info = packageInfo as Record<string, unknown>;\n const resolved = info['resolved'];\n if (typeof resolved === 'string' && resolved.trim() !== '') {\n map.set(packageName.toLowerCase(), resolved.trim());\n }\n }\n }\n}\n\n/**\n * Extract the PackageLicenseExpression from a .csproj file.\n * Handles: <PackageLicenseExpression>MIT</PackageLicenseExpression>\n */\nfunction extractNugetLicense(content: string): string | undefined {\n const match = content.match(/<PackageLicenseExpression\\s*>\\s*([^<]+)\\s*<\\/PackageLicenseExpression>/i);\n if (match && match[1].trim() !== '') {\n return match[1].trim();\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,SAAoB;AACpB,WAAsB;AAEtB,oBAAwB;AAiBxB,eAAsB,mBACpB,cACA,aAC6B;AAC7B,QAAM,cAAc,KAAK,QAAQ,YAAY;AAC7C,QAAM,mBAAmB,KAAK,SAAS,aAAa,YAAY,EAAE,QAAQ,OAAO,GAAG;AAGpF,MAAI;AACJ,MAAI;AACF,cAAU,GAAG,aAAa,cAAc,MAAM;AAAA,EAChD,SAAS,KAAK;AACZ,+BAAQ,8BAA8B,gBAAgB,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC7G,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,mBAAmB,qBAAqB,WAAW;AAGzD,QAAM,UAAU,oBAAoB,OAAO;AAE3C,QAAM,eAAmC,CAAC;AAG1C,QAAM,aAAa,yBAAyB,SAAS,gBAAgB;AACrE,aAAW,OAAO,YAAY;AAC5B,UAAM,kBAAkB,iBAAiB,IAAI,IAAI,KAAK,YAAY,CAAC;AACnE,iBAAa,KAAK;AAAA,MAChB,MAAM,IAAI;AAAA,MACV,oBAAoB,IAAI;AAAA,MACxB;AAAA,MACA,OAAO,IAAI;AAAA,MACX,WAAW;AAAA,MACX,gBAAgB;AAAA,MAChB,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH;AAGA,QAAM,qBAAqB,KAAK,KAAK,aAAa,iBAAiB;AACnE,MAAI,GAAG,WAAW,kBAAkB,GAAG;AACrC,UAAM,yBAAyB,KAAK,SAAS,aAAa,kBAAkB,EAAE,QAAQ,OAAO,GAAG;AAChG,QAAI;AACF,YAAM,wBAAwB,GAAG,aAAa,oBAAoB,MAAM;AACxE,YAAM,aAAa,sBAAsB,uBAAuB,sBAAsB;AACtF,iBAAW,OAAO,YAAY;AAC5B,cAAM,kBAAkB,iBAAiB,IAAI,IAAI,KAAK,YAAY,CAAC;AACnE,qBAAa,KAAK;AAAA,UAChB,MAAM,IAAI;AAAA,UACV,oBAAoB,IAAI;AAAA,UACxB;AAAA,UACA,OAAO,IAAI;AAAA,UACX,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC7C,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,iCAAQ,8BAA8B,sBAAsB,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IACrH;AAAA,EACF;AAEA,SAAO;AACT;AAmBA,SAAS,yBAAyB,SAAiB,kBAA2C;AAC5F,QAAM,OAAwB,CAAC;AAI/B,QAAM,eAAe;AACrB,MAAI;AAEJ,UAAQ,QAAQ,aAAa,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,aAAa,MAAM,CAAC,KAAK;AAC/B,UAAM,eAAe,MAAM,CAAC,KAAK;AAGjC,UAAM,eAAe,WAAW,MAAM,4BAA4B;AAClE,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AACA,UAAM,OAAO,aAAa,CAAC,EAAE,KAAK;AAClC,QAAI,CAAC,MAAM;AACT,iCAAQ,8DAA8D,gBAAgB,kBAAa;AACnG;AAAA,IACF;AAGA,UAAM,qBAAqB,WAAW,MAAM,kCAAkC;AAC9E,UAAM,QACJ,sBAAsB,mBAAmB,CAAC,EAAE,YAAY,MAAM,QAC1D,gBACA;AAGN,QAAI,aAA4B;AAChC,UAAM,mBAAmB,WAAW,MAAM,4BAA4B;AACtE,QAAI,oBAAoB,iBAAiB,CAAC,EAAE,KAAK,MAAM,IAAI;AACzD,mBAAa,iBAAiB,CAAC,EAAE,KAAK;AAAA,IACxC;AAGA,QAAI,CAAC,cAAc,cAAc;AAC/B,YAAM,mBAAmB,aAAa,MAAM,uCAAuC;AACnF,UAAI,oBAAoB,iBAAiB,CAAC,EAAE,KAAK,MAAM,IAAI;AACzD,qBAAa,iBAAiB,CAAC,EAAE,KAAK;AAAA,MACxC;AAAA,IACF;AAEA,QAAI,CAAC,YAAY;AAEf,mBAAa;AAAA,IACf;AAEA,SAAK,KAAK,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EACvC;AAEA,SAAO;AACT;AAQA,SAAS,sBAAsB,SAAiB,kBAA2C;AACzF,QAAM,OAAwB,CAAC;AAE/B,QAAM,eAAe;AACrB,MAAI;AAEJ,UAAQ,QAAQ,aAAa,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,aAAa,MAAM,CAAC,KAAK;AAE/B,UAAM,UAAU,WAAW,MAAM,uBAAuB;AACxD,QAAI,CAAC,QAAS;AACd,UAAM,OAAO,QAAQ,CAAC,EAAE,KAAK;AAC7B,QAAI,CAAC,MAAM;AACT,iCAAQ,wDAAwD,gBAAgB,kBAAa;AAC7F;AAAA,IACF;AAEA,UAAM,eAAe,WAAW,MAAM,4BAA4B;AAClE,UAAM,aAAa,gBAAgB,aAAa,CAAC,EAAE,KAAK,MAAM,KAAK,aAAa,CAAC,EAAE,KAAK,IAAI;AAE5F,SAAK,KAAK,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC;AAAA,EACrD;AAEA,SAAO;AACT;AAsBA,SAAS,qBAAqB,aAAyC;AACrE,QAAM,MAA0B,oBAAI,IAAI;AAExC,QAAM,WAAW,KAAK,KAAK,aAAa,oBAAoB;AAC5D,MAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,MAAM,GAAG,aAAa,UAAU,MAAM;AAC5C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,4BAAwB,QAAQ,GAAG;AAAA,EACrC,SAAS,KAAK;AACZ,+BAAQ,mDAAmD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,EAC/G;AAEA,SAAO;AACT;AAQA,SAAS,wBACP,QACA,KACM;AACN,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM;AAEnD,QAAM,OAAO;AACb,QAAM,eAAe,KAAK,cAAc;AACxC,MAAI,OAAO,iBAAiB,YAAY,iBAAiB,KAAM;AAG/D,aAAW,aAAa,OAAO,OAAO,YAAuC,GAAG;AAC9E,QAAI,OAAO,cAAc,YAAY,cAAc,KAAM;AAGzD,eAAW,CAAC,aAAa,WAAW,KAAK,OAAO,QAAQ,SAAoC,GAAG;AAC7F,UAAI,IAAI,IAAI,YAAY,YAAY,CAAC,EAAG;AACxC,UAAI,OAAO,gBAAgB,YAAY,gBAAgB,KAAM;AAE7D,YAAM,OAAO;AACb,YAAM,WAAW,KAAK,UAAU;AAChC,UAAI,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,IAAI;AAC1D,YAAI,IAAI,YAAY,YAAY,GAAG,SAAS,KAAK,CAAC;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AACF;AAMA,SAAS,oBAAoB,SAAqC;AAChE,QAAM,QAAQ,QAAQ,MAAM,yEAAyE;AACrG,MAAI,SAAS,MAAM,CAAC,EAAE,KAAK,MAAM,IAAI;AACnC,WAAO,MAAM,CAAC,EAAE,KAAK;AAAA,EACvB;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var pip_exports = {};
|
|
30
|
+
__export(pip_exports, {
|
|
31
|
+
parsePipManifest: () => parsePipManifest
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(pip_exports);
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var import_errors = require("../../../errors");
|
|
37
|
+
const PIP_OPTION_PREFIXES = ["-r", "-c", "-e", "--index-url", "--extra-index-url"];
|
|
38
|
+
const REQUIREMENT_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)(\[.*?\])?\s*(.*)/;
|
|
39
|
+
const VERSION_OPERATOR_REGEX = /^(~=|===|==|!=|>=|<=|>|<)/;
|
|
40
|
+
async function parsePipManifest(manifestPath, projectRoot) {
|
|
41
|
+
const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
|
|
42
|
+
let content;
|
|
43
|
+
try {
|
|
44
|
+
content = fs.readFileSync(manifestPath, "utf8");
|
|
45
|
+
} catch (err) {
|
|
46
|
+
(0, import_errors.logWarn)(`[sec:pip] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const dependencies = [];
|
|
50
|
+
const lines = content.split("\n");
|
|
51
|
+
for (let i = 0; i < lines.length; i++) {
|
|
52
|
+
const rawLine = lines[i];
|
|
53
|
+
const line = stripInlineComment(rawLine).trim();
|
|
54
|
+
if (line === "") continue;
|
|
55
|
+
if (line.startsWith("#")) continue;
|
|
56
|
+
if (isPipOption(line)) continue;
|
|
57
|
+
const withoutMarker = stripEnvironmentMarker(line);
|
|
58
|
+
const parsed = parseRequirementLine(withoutMarker, i + 1, relativeManifest);
|
|
59
|
+
if (parsed) {
|
|
60
|
+
dependencies.push(parsed);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return dependencies;
|
|
64
|
+
}
|
|
65
|
+
function stripInlineComment(line) {
|
|
66
|
+
const commentIndex = line.search(/\s#/);
|
|
67
|
+
if (commentIndex !== -1) {
|
|
68
|
+
return line.slice(0, commentIndex);
|
|
69
|
+
}
|
|
70
|
+
return line;
|
|
71
|
+
}
|
|
72
|
+
function isPipOption(line) {
|
|
73
|
+
for (const prefix of PIP_OPTION_PREFIXES) {
|
|
74
|
+
if (line.startsWith(prefix)) return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function stripEnvironmentMarker(line) {
|
|
79
|
+
const semicolonIndex = line.indexOf(";");
|
|
80
|
+
if (semicolonIndex !== -1) {
|
|
81
|
+
return line.slice(0, semicolonIndex).trim();
|
|
82
|
+
}
|
|
83
|
+
return line;
|
|
84
|
+
}
|
|
85
|
+
function parseRequirementLine(line, lineNumber, relativeManifest) {
|
|
86
|
+
const match = line.match(REQUIREMENT_REGEX);
|
|
87
|
+
if (!match) {
|
|
88
|
+
(0, import_errors.logWarn)(`[sec:pip] Could not parse line ${lineNumber} in ${relativeManifest}: "${line}"`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const name = match[1];
|
|
92
|
+
const constraintPart = (match[4] ?? "").trim();
|
|
93
|
+
let declaredConstraint = "";
|
|
94
|
+
let resolvedVersion;
|
|
95
|
+
if (constraintPart !== "") {
|
|
96
|
+
if (!VERSION_OPERATOR_REGEX.test(constraintPart)) {
|
|
97
|
+
(0, import_errors.logWarn)(`[sec:pip] Invalid version constraint for "${name}" at line ${lineNumber} in ${relativeManifest}: "${constraintPart}"`);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
declaredConstraint = constraintPart;
|
|
101
|
+
const exactMatch = constraintPart.match(/^==\s*([^\s,]+)/);
|
|
102
|
+
if (exactMatch) {
|
|
103
|
+
resolvedVersion = exactMatch[1];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
name: normalizePackageName(name),
|
|
108
|
+
declaredConstraint,
|
|
109
|
+
resolvedVersion,
|
|
110
|
+
scope: "production",
|
|
111
|
+
// requirements.txt doesn't distinguish scopes
|
|
112
|
+
ecosystem: "pypi",
|
|
113
|
+
sourceManifest: relativeManifest
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function normalizePackageName(name) {
|
|
117
|
+
return name.toLowerCase().replace(/[-_.]+/g, "-");
|
|
118
|
+
}
|
|
119
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
120
|
+
0 && (module.exports = {
|
|
121
|
+
parsePipManifest
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=pip.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/security/manifest/plugins/pip.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Pip Version Extraction Plugin for KiroGraph-Sec\n *\n * Extends the existing architecture python parser to extract version constraints\n * and resolved versions from requirements.txt files for security analysis.\n *\n * Reuses `pythonParser` from `src/architecture/manifest/python.ts` for discovery.\n * Parses requirements.txt line by line to extract package names and version constraints.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\n/**\n * Lines starting with these prefixes are pip options, not package declarations.\n */\nconst PIP_OPTION_PREFIXES = ['-r', '-c', '-e', '--index-url', '--extra-index-url'];\n\n/**\n * Regex to parse a pip requirement line.\n * Captures: package name, optional version constraint (operator + version).\n * Examples:\n * flask==2.3.0 \u2192 name=\"flask\", constraint=\"==2.3.0\"\n * requests>=2.28 \u2192 name=\"requests\", constraint=\">=2.28\"\n * django~=4.2 \u2192 name=\"django\", constraint=\"~=4.2\"\n * numpy \u2192 name=\"numpy\", constraint=\"\"\n * package[extra]>=1 \u2192 name=\"package\", constraint=\">=1\"\n */\nconst REQUIREMENT_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?)(\\[.*?\\])?\\s*(.*)/;\n\n/**\n * Regex to match a version constraint operator at the start of a string.\n */\nconst VERSION_OPERATOR_REGEX = /^(~=|===|==|!=|>=|<=|>|<)/;\n\n/**\n * Parse a pip requirements.txt manifest and extract dependency declarations\n * with version constraints.\n *\n * @param manifestPath - Absolute path to the requirements.txt file\n * @param projectRoot - Absolute path to the project root directory\n * @returns Array of parsed dependencies with version and scope information\n */\nexport async function parsePipManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n // Read the requirements.txt file\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:pip] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n const dependencies: ParsedDependency[] = [];\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const rawLine = lines[i];\n // Strip inline comments and trim whitespace\n const line = stripInlineComment(rawLine).trim();\n\n // Skip empty lines\n if (line === '') continue;\n\n // Skip comment lines\n if (line.startsWith('#')) continue;\n\n // Skip pip option lines\n if (isPipOption(line)) continue;\n\n // Strip environment markers (e.g. \"; sys_platform == 'win32'\")\n const withoutMarker = stripEnvironmentMarker(line);\n\n // Parse the requirement\n const parsed = parseRequirementLine(withoutMarker, i + 1, relativeManifest);\n if (parsed) {\n dependencies.push(parsed);\n }\n }\n\n return dependencies;\n}\n\n/**\n * Strip inline comments from a line.\n * Inline comments in requirements.txt start with # preceded by whitespace.\n */\nfunction stripInlineComment(line: string): string {\n // Match # that is preceded by whitespace (not part of a URL or version)\n const commentIndex = line.search(/\\s#/);\n if (commentIndex !== -1) {\n return line.slice(0, commentIndex);\n }\n return line;\n}\n\n/**\n * Check if a line is a pip option (not a package declaration).\n */\nfunction isPipOption(line: string): boolean {\n for (const prefix of PIP_OPTION_PREFIXES) {\n if (line.startsWith(prefix)) return true;\n }\n return false;\n}\n\n/**\n * Strip environment markers from a requirement line.\n * Environment markers follow a semicolon, e.g.:\n * pywin32; sys_platform == \"win32\"\n * colorama>=0.4; os_name == \"nt\"\n */\nfunction stripEnvironmentMarker(line: string): string {\n const semicolonIndex = line.indexOf(';');\n if (semicolonIndex !== -1) {\n return line.slice(0, semicolonIndex).trim();\n }\n return line;\n}\n\n/**\n * Parse a single requirement line into a ParsedDependency.\n * Returns null if the line cannot be parsed (logs a warning).\n */\nfunction parseRequirementLine(\n line: string,\n lineNumber: number,\n relativeManifest: string,\n): ParsedDependency | null {\n const match = line.match(REQUIREMENT_REGEX);\n if (!match) {\n logWarn(`[sec:pip] Could not parse line ${lineNumber} in ${relativeManifest}: \"${line}\"`);\n return null;\n }\n\n const name = match[1];\n const constraintPart = (match[4] ?? '').trim();\n\n // Validate that the constraint part, if present, starts with a valid operator\n let declaredConstraint = '';\n let resolvedVersion: string | undefined;\n\n if (constraintPart !== '') {\n if (!VERSION_OPERATOR_REGEX.test(constraintPart)) {\n logWarn(`[sec:pip] Invalid version constraint for \"${name}\" at line ${lineNumber} in ${relativeManifest}: \"${constraintPart}\"`);\n return null;\n }\n declaredConstraint = constraintPart;\n\n // If the constraint uses ==, the resolved version is the exact version\n const exactMatch = constraintPart.match(/^==\\s*([^\\s,]+)/);\n if (exactMatch) {\n resolvedVersion = exactMatch[1];\n }\n }\n\n return {\n name: normalizePackageName(name),\n declaredConstraint,\n resolvedVersion,\n scope: 'production', // requirements.txt doesn't distinguish scopes\n ecosystem: 'pypi',\n sourceManifest: relativeManifest,\n };\n}\n\n/**\n * Normalize a Python package name following PEP 503:\n * lowercase and replace any run of underscores, hyphens, or periods with a single hyphen.\n */\nfunction normalizePackageName(name: string): string {\n return name.toLowerCase().replace(/[-_.]+/g, '-');\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,SAAoB;AACpB,WAAsB;AAEtB,oBAAwB;AAKxB,MAAM,sBAAsB,CAAC,MAAM,MAAM,MAAM,eAAe,mBAAmB;AAYjF,MAAM,oBAAoB;AAK1B,MAAM,yBAAyB;AAU/B,eAAsB,iBACpB,cACA,aAC6B;AAC7B,QAAM,mBAAmB,KAAK,SAAS,aAAa,YAAY,EAAE,QAAQ,OAAO,GAAG;AAGpF,MAAI;AACJ,MAAI;AACF,cAAU,GAAG,aAAa,cAAc,MAAM;AAAA,EAChD,SAAS,KAAK;AACZ,+BAAQ,4BAA4B,gBAAgB,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC3G,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,eAAmC,CAAC;AAC1C,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAEhC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,UAAU,MAAM,CAAC;AAEvB,UAAM,OAAO,mBAAmB,OAAO,EAAE,KAAK;AAG9C,QAAI,SAAS,GAAI;AAGjB,QAAI,KAAK,WAAW,GAAG,EAAG;AAG1B,QAAI,YAAY,IAAI,EAAG;AAGvB,UAAM,gBAAgB,uBAAuB,IAAI;AAGjD,UAAM,SAAS,qBAAqB,eAAe,IAAI,GAAG,gBAAgB;AAC1E,QAAI,QAAQ;AACV,mBAAa,KAAK,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,mBAAmB,MAAsB;AAEhD,QAAM,eAAe,KAAK,OAAO,KAAK;AACtC,MAAI,iBAAiB,IAAI;AACvB,WAAO,KAAK,MAAM,GAAG,YAAY;AAAA,EACnC;AACA,SAAO;AACT;AAKA,SAAS,YAAY,MAAuB;AAC1C,aAAW,UAAU,qBAAqB;AACxC,QAAI,KAAK,WAAW,MAAM,EAAG,QAAO;AAAA,EACtC;AACA,SAAO;AACT;AAQA,SAAS,uBAAuB,MAAsB;AACpD,QAAM,iBAAiB,KAAK,QAAQ,GAAG;AACvC,MAAI,mBAAmB,IAAI;AACzB,WAAO,KAAK,MAAM,GAAG,cAAc,EAAE,KAAK;AAAA,EAC5C;AACA,SAAO;AACT;AAMA,SAAS,qBACP,MACA,YACA,kBACyB;AACzB,QAAM,QAAQ,KAAK,MAAM,iBAAiB;AAC1C,MAAI,CAAC,OAAO;AACV,+BAAQ,kCAAkC,UAAU,OAAO,gBAAgB,MAAM,IAAI,GAAG;AACxF,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,CAAC;AACpB,QAAM,kBAAkB,MAAM,CAAC,KAAK,IAAI,KAAK;AAG7C,MAAI,qBAAqB;AACzB,MAAI;AAEJ,MAAI,mBAAmB,IAAI;AACzB,QAAI,CAAC,uBAAuB,KAAK,cAAc,GAAG;AAChD,iCAAQ,6CAA6C,IAAI,aAAa,UAAU,OAAO,gBAAgB,MAAM,cAAc,GAAG;AAC9H,aAAO;AAAA,IACT;AACA,yBAAqB;AAGrB,UAAM,aAAa,eAAe,MAAM,iBAAiB;AACzD,QAAI,YAAY;AACd,wBAAkB,WAAW,CAAC;AAAA,IAChC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,qBAAqB,IAAI;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,OAAO;AAAA;AAAA,IACP,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB;AACF;AAMA,SAAS,qBAAqB,MAAsB;AAClD,SAAO,KAAK,YAAY,EAAE,QAAQ,WAAW,GAAG;AAClD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_vitest = require("vitest");
|
|
25
|
+
var fs = __toESM(require("fs"));
|
|
26
|
+
var path = __toESM(require("path"));
|
|
27
|
+
var os = __toESM(require("os"));
|
|
28
|
+
var import_pip = require("./pip");
|
|
29
|
+
(0, import_vitest.describe)("parsePipManifest", () => {
|
|
30
|
+
let tmpDir;
|
|
31
|
+
(0, import_vitest.beforeEach)(() => {
|
|
32
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kirograph-pip-test-"));
|
|
33
|
+
});
|
|
34
|
+
(0, import_vitest.afterEach)(() => {
|
|
35
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
36
|
+
});
|
|
37
|
+
function writeRequirements(content, filename = "requirements.txt") {
|
|
38
|
+
const filePath = path.join(tmpDir, filename);
|
|
39
|
+
fs.writeFileSync(filePath, content);
|
|
40
|
+
return filePath;
|
|
41
|
+
}
|
|
42
|
+
(0, import_vitest.it)("extracts packages with == constraint and resolves exact version", async () => {
|
|
43
|
+
const manifestPath = writeRequirements("flask==2.3.0\nrequests==2.28.1\n");
|
|
44
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
45
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
46
|
+
const flask = deps.find((d) => d.name === "flask");
|
|
47
|
+
(0, import_vitest.expect)(flask).toBeDefined();
|
|
48
|
+
(0, import_vitest.expect)(flask.declaredConstraint).toBe("==2.3.0");
|
|
49
|
+
(0, import_vitest.expect)(flask.resolvedVersion).toBe("2.3.0");
|
|
50
|
+
(0, import_vitest.expect)(flask.scope).toBe("production");
|
|
51
|
+
(0, import_vitest.expect)(flask.ecosystem).toBe("pypi");
|
|
52
|
+
const requests = deps.find((d) => d.name === "requests");
|
|
53
|
+
(0, import_vitest.expect)(requests).toBeDefined();
|
|
54
|
+
(0, import_vitest.expect)(requests.declaredConstraint).toBe("==2.28.1");
|
|
55
|
+
(0, import_vitest.expect)(requests.resolvedVersion).toBe("2.28.1");
|
|
56
|
+
});
|
|
57
|
+
(0, import_vitest.it)("extracts packages with >= constraint (no resolved version)", async () => {
|
|
58
|
+
const manifestPath = writeRequirements("requests>=2.28\n");
|
|
59
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
60
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
61
|
+
(0, import_vitest.expect)(deps[0].name).toBe("requests");
|
|
62
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe(">=2.28");
|
|
63
|
+
(0, import_vitest.expect)(deps[0].resolvedVersion).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
(0, import_vitest.it)("extracts packages with ~= constraint", async () => {
|
|
66
|
+
const manifestPath = writeRequirements("django~=4.2\n");
|
|
67
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
68
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
69
|
+
(0, import_vitest.expect)(deps[0].name).toBe("django");
|
|
70
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe("~=4.2");
|
|
71
|
+
(0, import_vitest.expect)(deps[0].resolvedVersion).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
(0, import_vitest.it)("extracts packages with no version constraint", async () => {
|
|
74
|
+
const manifestPath = writeRequirements("numpy\nscipy\n");
|
|
75
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
76
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
77
|
+
(0, import_vitest.expect)(deps[0].name).toBe("numpy");
|
|
78
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe("");
|
|
79
|
+
(0, import_vitest.expect)(deps[0].resolvedVersion).toBeUndefined();
|
|
80
|
+
(0, import_vitest.expect)(deps[1].name).toBe("scipy");
|
|
81
|
+
});
|
|
82
|
+
(0, import_vitest.it)("skips comment lines", async () => {
|
|
83
|
+
const manifestPath = writeRequirements(
|
|
84
|
+
"# This is a comment\nflask==2.3.0\n# Another comment\nrequests>=2.28\n"
|
|
85
|
+
);
|
|
86
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
87
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
88
|
+
(0, import_vitest.expect)(deps.map((d) => d.name)).toEqual(["flask", "requests"]);
|
|
89
|
+
});
|
|
90
|
+
(0, import_vitest.it)("skips empty lines", async () => {
|
|
91
|
+
const manifestPath = writeRequirements("flask==2.3.0\n\n\nrequests>=2.28\n\n");
|
|
92
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
93
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
94
|
+
});
|
|
95
|
+
(0, import_vitest.it)("skips pip option lines (-r, -c, -e, --index-url, --extra-index-url)", async () => {
|
|
96
|
+
const manifestPath = writeRequirements(
|
|
97
|
+
"-r base.txt\n-c constraints.txt\n-e git+https://github.com/user/repo.git\n--index-url https://pypi.org/simple\n--extra-index-url https://private.pypi.org/simple\nflask==2.3.0\n"
|
|
98
|
+
);
|
|
99
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
100
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
101
|
+
(0, import_vitest.expect)(deps[0].name).toBe("flask");
|
|
102
|
+
});
|
|
103
|
+
(0, import_vitest.it)("strips environment markers", async () => {
|
|
104
|
+
const manifestPath = writeRequirements(
|
|
105
|
+
'pywin32>=300; sys_platform == "win32"\ncolorama>=0.4; os_name == "nt"\nflask==2.3.0\n'
|
|
106
|
+
);
|
|
107
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
108
|
+
(0, import_vitest.expect)(deps).toHaveLength(3);
|
|
109
|
+
const pywin32 = deps.find((d) => d.name === "pywin32");
|
|
110
|
+
(0, import_vitest.expect)(pywin32).toBeDefined();
|
|
111
|
+
(0, import_vitest.expect)(pywin32.declaredConstraint).toBe(">=300");
|
|
112
|
+
const colorama = deps.find((d) => d.name === "colorama");
|
|
113
|
+
(0, import_vitest.expect)(colorama).toBeDefined();
|
|
114
|
+
(0, import_vitest.expect)(colorama.declaredConstraint).toBe(">=0.4");
|
|
115
|
+
});
|
|
116
|
+
(0, import_vitest.it)("handles packages with extras (e.g. package[extra]>=1.0)", async () => {
|
|
117
|
+
const manifestPath = writeRequirements("requests[security]>=2.28.0\ncelery[redis]==5.3.0\n");
|
|
118
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
119
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
120
|
+
const requests = deps.find((d) => d.name === "requests");
|
|
121
|
+
(0, import_vitest.expect)(requests).toBeDefined();
|
|
122
|
+
(0, import_vitest.expect)(requests.declaredConstraint).toBe(">=2.28.0");
|
|
123
|
+
const celery = deps.find((d) => d.name === "celery");
|
|
124
|
+
(0, import_vitest.expect)(celery).toBeDefined();
|
|
125
|
+
(0, import_vitest.expect)(celery.declaredConstraint).toBe("==5.3.0");
|
|
126
|
+
(0, import_vitest.expect)(celery.resolvedVersion).toBe("5.3.0");
|
|
127
|
+
});
|
|
128
|
+
(0, import_vitest.it)("normalizes package names (PEP 503)", async () => {
|
|
129
|
+
const manifestPath = writeRequirements(
|
|
130
|
+
"Flask==2.3.0\nPyYAML>=6.0\nmy_package==1.0.0\nAnother.Package>=2.0\n"
|
|
131
|
+
);
|
|
132
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
133
|
+
(0, import_vitest.expect)(deps).toHaveLength(4);
|
|
134
|
+
(0, import_vitest.expect)(deps.map((d) => d.name)).toEqual([
|
|
135
|
+
"flask",
|
|
136
|
+
"pyyaml",
|
|
137
|
+
"my-package",
|
|
138
|
+
"another-package"
|
|
139
|
+
]);
|
|
140
|
+
});
|
|
141
|
+
(0, import_vitest.it)("all dependencies have production scope", async () => {
|
|
142
|
+
const manifestPath = writeRequirements("flask==2.3.0\npytest==7.0.0\nmypy>=1.0\n");
|
|
143
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
144
|
+
(0, import_vitest.expect)(deps).toHaveLength(3);
|
|
145
|
+
(0, import_vitest.expect)(deps.every((d) => d.scope === "production")).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
(0, import_vitest.it)("all dependencies have pypi ecosystem", async () => {
|
|
148
|
+
const manifestPath = writeRequirements("flask==2.3.0\ndjango~=4.2\n");
|
|
149
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
150
|
+
(0, import_vitest.expect)(deps.every((d) => d.ecosystem === "pypi")).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
(0, import_vitest.it)("sets sourceManifest as relative path", async () => {
|
|
153
|
+
const subDir = path.join(tmpDir, "services", "api");
|
|
154
|
+
fs.mkdirSync(subDir, { recursive: true });
|
|
155
|
+
const filePath = path.join(subDir, "requirements.txt");
|
|
156
|
+
fs.writeFileSync(filePath, "flask==2.3.0\n");
|
|
157
|
+
const deps = await (0, import_pip.parsePipManifest)(filePath, tmpDir);
|
|
158
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
159
|
+
(0, import_vitest.expect)(deps[0].sourceManifest).toBe("services/api/requirements.txt");
|
|
160
|
+
});
|
|
161
|
+
(0, import_vitest.it)("returns empty array for non-existent file", async () => {
|
|
162
|
+
const deps = await (0, import_pip.parsePipManifest)(
|
|
163
|
+
path.join(tmpDir, "nonexistent.txt"),
|
|
164
|
+
tmpDir
|
|
165
|
+
);
|
|
166
|
+
(0, import_vitest.expect)(deps).toEqual([]);
|
|
167
|
+
});
|
|
168
|
+
(0, import_vitest.it)("handles inline comments", async () => {
|
|
169
|
+
const manifestPath = writeRequirements(
|
|
170
|
+
"flask==2.3.0 # web framework\nrequests>=2.28 # HTTP library\n"
|
|
171
|
+
);
|
|
172
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
173
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
174
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe("==2.3.0");
|
|
175
|
+
(0, import_vitest.expect)(deps[1].declaredConstraint).toBe(">=2.28");
|
|
176
|
+
});
|
|
177
|
+
(0, import_vitest.it)("handles compound version constraints (e.g. >=1.0,<2.0)", async () => {
|
|
178
|
+
const manifestPath = writeRequirements("flask>=2.0,<3.0\nrequests>=2.28,!=2.29.0\n");
|
|
179
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
180
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
181
|
+
(0, import_vitest.expect)(deps[0].name).toBe("flask");
|
|
182
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe(">=2.0,<3.0");
|
|
183
|
+
(0, import_vitest.expect)(deps[0].resolvedVersion).toBeUndefined();
|
|
184
|
+
(0, import_vitest.expect)(deps[1].name).toBe("requests");
|
|
185
|
+
(0, import_vitest.expect)(deps[1].declaredConstraint).toBe(">=2.28,!=2.29.0");
|
|
186
|
+
});
|
|
187
|
+
(0, import_vitest.it)("handles != constraint", async () => {
|
|
188
|
+
const manifestPath = writeRequirements("flask!=2.2.0\n");
|
|
189
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
190
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
191
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe("!=2.2.0");
|
|
192
|
+
(0, import_vitest.expect)(deps[0].resolvedVersion).toBeUndefined();
|
|
193
|
+
});
|
|
194
|
+
(0, import_vitest.it)("handles < and > constraints", async () => {
|
|
195
|
+
const manifestPath = writeRequirements("flask>2.0\ndjango<5.0\n");
|
|
196
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
197
|
+
(0, import_vitest.expect)(deps).toHaveLength(2);
|
|
198
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe(">2.0");
|
|
199
|
+
(0, import_vitest.expect)(deps[1].declaredConstraint).toBe("<5.0");
|
|
200
|
+
});
|
|
201
|
+
(0, import_vitest.it)("handles <= constraint", async () => {
|
|
202
|
+
const manifestPath = writeRequirements("flask<=2.3.0\n");
|
|
203
|
+
const deps = await (0, import_pip.parsePipManifest)(manifestPath, tmpDir);
|
|
204
|
+
(0, import_vitest.expect)(deps).toHaveLength(1);
|
|
205
|
+
(0, import_vitest.expect)(deps[0].declaredConstraint).toBe("<=2.3.0");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
//# sourceMappingURL=pip.test.js.map
|