@stsepelin/checktrail 0.1.0-alpha.1
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/CONTRIBUTING.md +42 -0
- package/LICENSE +21 -0
- package/README.md +355 -0
- package/SECURITY.md +46 -0
- package/dist/src/actionlint-evidence.d.ts +2 -0
- package/dist/src/actionlint-evidence.js +166 -0
- package/dist/src/actionlint-inputs.d.ts +5 -0
- package/dist/src/actionlint-inputs.js +123 -0
- package/dist/src/actionlint-runner.d.ts +1 -0
- package/dist/src/actionlint-runner.js +122 -0
- package/dist/src/actionlint.d.ts +19 -0
- package/dist/src/actionlint.js +80 -0
- package/dist/src/adapters.d.ts +49 -0
- package/dist/src/adapters.js +430 -0
- package/dist/src/architecture.d.ts +107 -0
- package/dist/src/architecture.js +230 -0
- package/dist/src/clang-evidence.d.ts +2 -0
- package/dist/src/clang-evidence.js +194 -0
- package/dist/src/clang-protocol.d.ts +3 -0
- package/dist/src/clang-protocol.js +25 -0
- package/dist/src/clang-runner.d.ts +1 -0
- package/dist/src/clang-runner.js +159 -0
- package/dist/src/clang.d.ts +44 -0
- package/dist/src/clang.js +197 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +338 -0
- package/dist/src/config.d.ts +33 -0
- package/dist/src/config.js +140 -0
- package/dist/src/contract-schema.d.ts +85 -0
- package/dist/src/contract-schema.js +56 -0
- package/dist/src/contract-worker.d.ts +1 -0
- package/dist/src/contract-worker.js +123 -0
- package/dist/src/contracts.d.ts +22 -0
- package/dist/src/contracts.js +123 -0
- package/dist/src/django-evidence.d.ts +2 -0
- package/dist/src/django-evidence.js +100 -0
- package/dist/src/django-runner.d.ts +1 -0
- package/dist/src/django-runner.js +80 -0
- package/dist/src/django.d.ts +9 -0
- package/dist/src/django.js +50 -0
- package/dist/src/dotnet-compiler.d.ts +1 -0
- package/dist/src/dotnet-compiler.js +87 -0
- package/dist/src/dotnet-evidence.d.ts +2 -0
- package/dist/src/dotnet-evidence.js +127 -0
- package/dist/src/dotnet-runner.d.ts +1 -0
- package/dist/src/dotnet-runner.js +167 -0
- package/dist/src/dotnet.d.ts +65 -0
- package/dist/src/dotnet.js +120 -0
- package/dist/src/engine.d.ts +19 -0
- package/dist/src/engine.js +239 -0
- package/dist/src/environment.d.ts +6 -0
- package/dist/src/environment.js +36 -0
- package/dist/src/eslint-evidence.d.ts +2 -0
- package/dist/src/eslint-evidence.js +98 -0
- package/dist/src/eslint-runner.d.ts +1 -0
- package/dist/src/eslint-runner.js +61 -0
- package/dist/src/eslint.d.ts +2 -0
- package/dist/src/eslint.js +40 -0
- package/dist/src/evidence.d.ts +2 -0
- package/dist/src/evidence.js +313 -0
- package/dist/src/external-adapter.d.ts +164 -0
- package/dist/src/external-adapter.js +265 -0
- package/dist/src/external-evidence.d.ts +2 -0
- package/dist/src/external-evidence.js +127 -0
- package/dist/src/external-runner.d.ts +1 -0
- package/dist/src/external-runner.js +122 -0
- package/dist/src/fastapi-evidence.d.ts +2 -0
- package/dist/src/fastapi-evidence.js +126 -0
- package/dist/src/fastapi-runner.d.ts +1 -0
- package/dist/src/fastapi-runner.js +84 -0
- package/dist/src/fastapi.d.ts +10 -0
- package/dist/src/fastapi.js +52 -0
- package/dist/src/fetch-pack.d.ts +16 -0
- package/dist/src/fetch-pack.js +154 -0
- package/dist/src/finding-policy-schema.d.ts +146 -0
- package/dist/src/finding-policy-schema.js +70 -0
- package/dist/src/finding-policy.d.ts +62 -0
- package/dist/src/finding-policy.js +206 -0
- package/dist/src/git-selection.d.ts +3 -0
- package/dist/src/git-selection.js +229 -0
- package/dist/src/go-directives.d.ts +1 -0
- package/dist/src/go-directives.js +32 -0
- package/dist/src/go-scope.d.ts +11 -0
- package/dist/src/go-scope.js +122 -0
- package/dist/src/golangci-evidence.d.ts +2 -0
- package/dist/src/golangci-evidence.js +92 -0
- package/dist/src/golangci-runner.d.ts +1 -0
- package/dist/src/golangci-runner.js +124 -0
- package/dist/src/golangci.d.ts +2 -0
- package/dist/src/golangci.js +35 -0
- package/dist/src/guidance.d.ts +98 -0
- package/dist/src/guidance.js +247 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.js +16 -0
- package/dist/src/inventory.d.ts +4 -0
- package/dist/src/inventory.js +94 -0
- package/dist/src/java-compiler.d.ts +1 -0
- package/dist/src/java-compiler.js +110 -0
- package/dist/src/java-evidence.d.ts +2 -0
- package/dist/src/java-evidence.js +114 -0
- package/dist/src/java-runner.d.ts +1 -0
- package/dist/src/java-runner.js +79 -0
- package/dist/src/java.d.ts +25 -0
- package/dist/src/java.js +102 -0
- package/dist/src/jest-evidence.d.ts +2 -0
- package/dist/src/jest-evidence.js +117 -0
- package/dist/src/jest-runner.d.ts +1 -0
- package/dist/src/jest-runner.js +46 -0
- package/dist/src/jest.d.ts +2 -0
- package/dist/src/jest.js +36 -0
- package/dist/src/junit.d.ts +18 -0
- package/dist/src/junit.js +157 -0
- package/dist/src/laravel-evidence.d.ts +2 -0
- package/dist/src/laravel-evidence.js +175 -0
- package/dist/src/laravel-runner.d.ts +1 -0
- package/dist/src/laravel-runner.js +168 -0
- package/dist/src/laravel.d.ts +8 -0
- package/dist/src/laravel.js +50 -0
- package/dist/src/local-tool.d.ts +1 -0
- package/dist/src/local-tool.js +19 -0
- package/dist/src/mcp.d.ts +14 -0
- package/dist/src/mcp.js +362 -0
- package/dist/src/mutation.d.ts +118 -0
- package/dist/src/mutation.js +370 -0
- package/dist/src/mypy-evidence.d.ts +2 -0
- package/dist/src/mypy-evidence.js +63 -0
- package/dist/src/mypy.d.ts +2 -0
- package/dist/src/mypy.js +59 -0
- package/dist/src/node-reporter.d.ts +1 -0
- package/dist/src/node-reporter.js +28 -0
- package/dist/src/nuxt-evidence.d.ts +2 -0
- package/dist/src/nuxt-evidence.js +160 -0
- package/dist/src/nuxt-protocol.d.ts +52 -0
- package/dist/src/nuxt-protocol.js +29 -0
- package/dist/src/nuxt-runner.d.ts +1 -0
- package/dist/src/nuxt-runner.js +165 -0
- package/dist/src/nuxt.d.ts +24 -0
- package/dist/src/nuxt.js +105 -0
- package/dist/src/output.d.ts +3 -0
- package/dist/src/output.js +48 -0
- package/dist/src/phpstan-evidence.d.ts +2 -0
- package/dist/src/phpstan-evidence.js +81 -0
- package/dist/src/phpstan.d.ts +2 -0
- package/dist/src/phpstan.js +51 -0
- package/dist/src/phpunit-evidence.d.ts +2 -0
- package/dist/src/phpunit-evidence.js +53 -0
- package/dist/src/phpunit.d.ts +2 -0
- package/dist/src/phpunit.js +58 -0
- package/dist/src/pint-evidence.d.ts +2 -0
- package/dist/src/pint-evidence.js +79 -0
- package/dist/src/pint-runner.d.ts +1 -0
- package/dist/src/pint-runner.js +53 -0
- package/dist/src/pint.d.ts +2 -0
- package/dist/src/pint.js +37 -0
- package/dist/src/playwright-evidence.d.ts +2 -0
- package/dist/src/playwright-evidence.js +127 -0
- package/dist/src/playwright-reporter.d.ts +10 -0
- package/dist/src/playwright-reporter.js +37 -0
- package/dist/src/playwright-runner.d.ts +1 -0
- package/dist/src/playwright-runner.js +61 -0
- package/dist/src/playwright.d.ts +2 -0
- package/dist/src/playwright.js +35 -0
- package/dist/src/policy-pack.d.ts +21 -0
- package/dist/src/policy-pack.js +41 -0
- package/dist/src/pytest-evidence.d.ts +2 -0
- package/dist/src/pytest-evidence.js +116 -0
- package/dist/src/pytest-runner.d.ts +1 -0
- package/dist/src/pytest-runner.js +48 -0
- package/dist/src/pytest.d.ts +2 -0
- package/dist/src/pytest.js +25 -0
- package/dist/src/report-validation.d.ts +129 -0
- package/dist/src/report-validation.js +27 -0
- package/dist/src/review.d.ts +270 -0
- package/dist/src/review.js +349 -0
- package/dist/src/ruby.d.ts +2 -0
- package/dist/src/ruby.js +25 -0
- package/dist/src/ruff-evidence.d.ts +2 -0
- package/dist/src/ruff-evidence.js +99 -0
- package/dist/src/ruff.d.ts +2 -0
- package/dist/src/ruff.js +40 -0
- package/dist/src/runner.d.ts +8 -0
- package/dist/src/runner.js +117 -0
- package/dist/src/runtime-inventory.d.ts +112 -0
- package/dist/src/runtime-inventory.js +200 -0
- package/dist/src/rust-dep-info.d.ts +1 -0
- package/dist/src/rust-dep-info.js +46 -0
- package/dist/src/rust-evidence.d.ts +2 -0
- package/dist/src/rust-evidence.js +157 -0
- package/dist/src/rust-runner.d.ts +1 -0
- package/dist/src/rust-runner.js +161 -0
- package/dist/src/rust.d.ts +7 -0
- package/dist/src/rust.js +39 -0
- package/dist/src/sarif.d.ts +86 -0
- package/dist/src/sarif.js +113 -0
- package/dist/src/schemas.d.ts +393 -0
- package/dist/src/schemas.js +222 -0
- package/dist/src/staticcheck-evidence.d.ts +2 -0
- package/dist/src/staticcheck-evidence.js +75 -0
- package/dist/src/swift.d.ts +2 -0
- package/dist/src/swift.js +20 -0
- package/dist/src/task-store.d.ts +37 -0
- package/dist/src/task-store.js +349 -0
- package/dist/src/tool-versions.d.ts +3 -0
- package/dist/src/tool-versions.js +260 -0
- package/dist/src/types.d.ts +157 -0
- package/dist/src/types.js +37 -0
- package/dist/src/typescript-build-evidence.d.ts +2 -0
- package/dist/src/typescript-build-evidence.js +86 -0
- package/dist/src/typescript-build-runner.d.ts +1 -0
- package/dist/src/typescript-build-runner.js +132 -0
- package/dist/src/typescript-build.d.ts +2 -0
- package/dist/src/typescript-build.js +41 -0
- package/dist/src/typescript.d.ts +2 -0
- package/dist/src/typescript.js +54 -0
- package/dist/src/validation-task-worker.d.ts +1 -0
- package/dist/src/validation-task-worker.js +205 -0
- package/dist/src/validation-tasks-protocol.d.ts +69 -0
- package/dist/src/validation-tasks-protocol.js +57 -0
- package/dist/src/validation-tasks.d.ts +11 -0
- package/dist/src/validation-tasks.js +144 -0
- package/dist/src/vitest-evidence.d.ts +2 -0
- package/dist/src/vitest-evidence.js +112 -0
- package/dist/src/vitest-runner.d.ts +1 -0
- package/dist/src/vitest-runner.js +48 -0
- package/dist/src/vitest.d.ts +2 -0
- package/dist/src/vitest.js +36 -0
- package/dist/src/vue-router-capture.d.ts +42 -0
- package/dist/src/vue-router-capture.js +87 -0
- package/dist/src/vue-router-evidence.d.ts +2 -0
- package/dist/src/vue-router-evidence.js +126 -0
- package/dist/src/vue-router-protocol.d.ts +63 -0
- package/dist/src/vue-router-protocol.js +44 -0
- package/dist/src/vue-router-runner.d.ts +1 -0
- package/dist/src/vue-router-runner.js +88 -0
- package/dist/src/vue-router.d.ts +23 -0
- package/dist/src/vue-router.js +108 -0
- package/dist/src/vue-tsc-runner.d.ts +1 -0
- package/dist/src/vue-tsc-runner.js +24 -0
- package/dist/src/workspace.d.ts +7 -0
- package/dist/src/workspace.js +53 -0
- package/docs/ACCEPTANCE.md +56 -0
- package/docs/ACTIONLINT.md +112 -0
- package/docs/ARCHITECTURE-POLICY.md +82 -0
- package/docs/ARCHITECTURE.md +122 -0
- package/docs/CLANG.md +113 -0
- package/docs/CLIENTS.md +109 -0
- package/docs/CONTRACTS.md +73 -0
- package/docs/DEPENDENCIES.md +42 -0
- package/docs/DJANGO.md +70 -0
- package/docs/DOTNET.md +114 -0
- package/docs/ENVIRONMENTS.md +52 -0
- package/docs/ESLINT.md +68 -0
- package/docs/EVALUATION.md +124 -0
- package/docs/EXECUTION.md +250 -0
- package/docs/EXTERNAL-ADAPTERS.md +170 -0
- package/docs/EXTERNAL-EVALUATION.md +155 -0
- package/docs/EXTERNAL-RUFF-EVALUATION.md +85 -0
- package/docs/FASTAPI.md +73 -0
- package/docs/FINDING-POLICY.md +67 -0
- package/docs/GO-RACE.md +19 -0
- package/docs/GO-SCOPE.md +63 -0
- package/docs/GOLANGCI-LINT.md +64 -0
- package/docs/GUIDANCE.md +46 -0
- package/docs/IMPACT-MEASUREMENT.md +97 -0
- package/docs/INSTALLATION.md +102 -0
- package/docs/JAVA.md +79 -0
- package/docs/JEST.md +36 -0
- package/docs/JUNIT.md +31 -0
- package/docs/LANGUAGES.md +113 -0
- package/docs/LARAVEL.md +111 -0
- package/docs/MCP-COMPATIBILITY.md +68 -0
- package/docs/MUTATIONS.md +93 -0
- package/docs/MYPY.md +37 -0
- package/docs/NATIVE-CI.md +96 -0
- package/docs/NUXT.md +123 -0
- package/docs/PACK-DISTRIBUTION.md +98 -0
- package/docs/PERFORMANCE.md +71 -0
- package/docs/PEST.md +36 -0
- package/docs/PHPSTAN.md +48 -0
- package/docs/PHPUNIT.md +32 -0
- package/docs/PINT.md +41 -0
- package/docs/PLAN.md +265 -0
- package/docs/PLAYWRIGHT.md +73 -0
- package/docs/POLICY-PACKS.md +106 -0
- package/docs/PRIOR-WORKFLOW-EVALUATION.md +116 -0
- package/docs/PUBLICATION.md +28 -0
- package/docs/PYTEST.md +51 -0
- package/docs/RELEASE.md +115 -0
- package/docs/RENAMING.md +55 -0
- package/docs/REVIEW-EXCHANGE.md +136 -0
- package/docs/RUBY.md +50 -0
- package/docs/RUFF.md +39 -0
- package/docs/RUNTIME-INVENTORY.md +56 -0
- package/docs/RUST.md +74 -0
- package/docs/SARIF.md +64 -0
- package/docs/STATUS.md +530 -0
- package/docs/SWIFT.md +48 -0
- package/docs/TASK-STORAGE.md +141 -0
- package/docs/TOOL-IDENTITY.md +30 -0
- package/docs/TYPESCRIPT-BUILD.md +55 -0
- package/docs/VALIDATION-TASKS.md +119 -0
- package/docs/VITEST.md +36 -0
- package/docs/VUE-ROUTER.md +130 -0
- package/docs/VUE-TSC.md +26 -0
- package/docs/WORKSPACES.md +81 -0
- package/docs/licenses/nodable-entities-3.0.0.txt +21 -0
- package/docs/measurements/client-claude-before-schema-fix-darwin-arm64-node26.json +60 -0
- package/docs/measurements/client-claude-darwin-arm64-node26.json +55 -0
- package/docs/measurements/client-codex-darwin-arm64-node26.json +175 -0
- package/docs/measurements/evaluation-corpus-repo-verifier.json +332 -0
- package/docs/measurements/evaluation-darwin-arm64-node26.json +1236 -0
- package/docs/measurements/evaluation-linux-arm64-node22.json +1236 -0
- package/docs/measurements/external-eslint-darwin-arm64-node26.json +11866 -0
- package/docs/measurements/external-eslint-linux-arm64-node22.json +11866 -0
- package/docs/measurements/external-eslint-preservation.json +1527 -0
- package/docs/measurements/external-ruff-darwin-arm64-node26.json +1031 -0
- package/docs/measurements/external-ruff-linux-arm64-node22.json +1031 -0
- package/docs/measurements/hosted-ci-52ba415.json +1005 -0
- package/docs/measurements/impact-darwin-arm64-node26.json +6685 -0
- package/docs/measurements/impact-linux-arm64-node22.json +6690 -0
- package/docs/measurements/performance-darwin-arm64-node26.json +845 -0
- package/docs/measurements/performance-linux-arm64-node22.json +845 -0
- package/docs/measurements/required-native-profiles.json +500 -0
- package/package.json +72 -0
- package/packs/actionlint.json +8 -0
- package/packs/cpp.json +8 -0
- package/packs/dotnet.json +8 -0
- package/packs/go.json +7 -0
- package/packs/java.json +8 -0
- package/packs/javascript-node.json +7 -0
- package/packs/nuxt.json +7 -0
- package/packs/php-pest.json +7 -0
- package/packs/php-phpunit.json +7 -0
- package/packs/python-pytest.json +7 -0
- package/packs/ruby.json +7 -0
- package/packs/rust.json +7 -0
- package/packs/swift.json +7 -0
- package/packs/vue-router.json +7 -0
- package/packs/vue.json +11 -0
- package/schemas/actionlint-config.schema.json +19 -0
- package/schemas/architecture-policy.schema.json +51 -0
- package/schemas/architecture-report.schema.json +123 -0
- package/schemas/architecture-summary.schema.json +82 -0
- package/schemas/clang-database.schema.json +23 -0
- package/schemas/config.schema.json +69 -0
- package/schemas/contract-bundle.schema.json +78 -0
- package/schemas/contract-report.schema.json +114 -0
- package/schemas/contract-summary.schema.json +72 -0
- package/schemas/dependency-graph.schema.json +65 -0
- package/schemas/django-config.schema.json +16 -0
- package/schemas/dotnet-config.schema.json +60 -0
- package/schemas/external-manifest.schema.json +97 -0
- package/schemas/external-reference.schema.json +10 -0
- package/schemas/external-request.schema.json +56 -0
- package/schemas/external-result.schema.json +111 -0
- package/schemas/fastapi-config.schema.json +27 -0
- package/schemas/finding-baseline.schema.json +92 -0
- package/schemas/finding-comparison-summary.schema.json +95 -0
- package/schemas/finding-comparison.schema.json +121 -0
- package/schemas/guidance-context.schema.json +34 -0
- package/schemas/guidance-report.schema.json +176 -0
- package/schemas/guidance-summary.schema.json +68 -0
- package/schemas/java-config.schema.json +24 -0
- package/schemas/junit.schema.json +69 -0
- package/schemas/laravel-config.schema.json +11 -0
- package/schemas/mutation-recipe.schema.json +31 -0
- package/schemas/mutation-report.schema.json +238 -0
- package/schemas/mutation-summary.schema.json +98 -0
- package/schemas/nuxt-config.schema.json +51 -0
- package/schemas/plan-summary.schema.json +63 -0
- package/schemas/plan.schema.json +244 -0
- package/schemas/policy-pack.schema.json +41 -0
- package/schemas/report-summary.schema.json +100 -0
- package/schemas/report.schema.json +463 -0
- package/schemas/review-assessment.schema.json +133 -0
- package/schemas/review-context-summary.schema.json +31 -0
- package/schemas/review-context.schema.json +254 -0
- package/schemas/review-receipt-summary.schema.json +104 -0
- package/schemas/review-receipt.schema.json +271 -0
- package/schemas/review-selection.schema.json +30 -0
- package/schemas/runtime-comparison-summary.schema.json +68 -0
- package/schemas/runtime-comparison.schema.json +127 -0
- package/schemas/runtime-inventory.schema.json +99 -0
- package/schemas/vue-router-config.schema.json +67 -0
- package/server.json +47 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export const djangoRunner = String.raw `
|
|
2
|
+
import contextlib, hashlib, json, sys
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
5
|
+
|
|
6
|
+
def identity(value):
|
|
7
|
+
module = getattr(value, '__module__', None)
|
|
8
|
+
name = getattr(value, '__qualname__', None)
|
|
9
|
+
if not isinstance(module, str) or not isinstance(name, str):
|
|
10
|
+
raise ValueError('Unsupported callable identity')
|
|
11
|
+
return module + '.' + name
|
|
12
|
+
|
|
13
|
+
def capture():
|
|
14
|
+
import django
|
|
15
|
+
django.setup()
|
|
16
|
+
from django.urls import get_resolver
|
|
17
|
+
from django.urls.resolvers import URLPattern, URLResolver, RoutePattern, RegexPattern
|
|
18
|
+
from django.urls.converters import IntConverter, StringConverter, UUIDConverter, SlugConverter, PathConverter
|
|
19
|
+
supported_converters = (IntConverter, StringConverter, UUIDConverter, SlugConverter, PathConverter)
|
|
20
|
+
entries = []
|
|
21
|
+
visited = 0
|
|
22
|
+
unsupported = 0
|
|
23
|
+
def walk(routes, patterns, namespaces, defaults, depth):
|
|
24
|
+
nonlocal visited, unsupported
|
|
25
|
+
if depth > 32:
|
|
26
|
+
raise ValueError('URL resolver depth limit exceeded')
|
|
27
|
+
for route in routes:
|
|
28
|
+
visited += 1
|
|
29
|
+
if visited > 20000:
|
|
30
|
+
raise ValueError('URL inventory entry limit exceeded')
|
|
31
|
+
if type(route) not in (URLPattern, URLResolver) or type(route.pattern) not in (RoutePattern, RegexPattern):
|
|
32
|
+
unsupported += 1
|
|
33
|
+
continue
|
|
34
|
+
pattern = route.pattern
|
|
35
|
+
if type(pattern) is RoutePattern and type(pattern._route) is not str:
|
|
36
|
+
unsupported += 1
|
|
37
|
+
continue
|
|
38
|
+
if any(type(converter) not in supported_converters for converter in pattern.converters.values()):
|
|
39
|
+
unsupported += 1
|
|
40
|
+
continue
|
|
41
|
+
signature = json.dumps([type(pattern).__name__, pattern.regex.pattern, pattern.regex.flags, pattern._is_endpoint], separators=(',', ':'), ensure_ascii=False)
|
|
42
|
+
fragments = patterns + [signature]
|
|
43
|
+
values = {**defaults, **(route.default_kwargs if type(route) is URLResolver else route.default_args)}
|
|
44
|
+
if type(route) is URLResolver:
|
|
45
|
+
walk(route.url_patterns, fragments, namespaces + ([route.namespace] if route.namespace else []), values, depth + 1)
|
|
46
|
+
else:
|
|
47
|
+
values_json = json.dumps(values, sort_keys=True, separators=(',', ':'), allow_nan=False)
|
|
48
|
+
handler = getattr(route.callback, 'view_class', route.callback)
|
|
49
|
+
entries.append({
|
|
50
|
+
'key': json.dumps(fragments, separators=(',', ':'), ensure_ascii=False),
|
|
51
|
+
'attributes': {'patterns': fragments, 'namespaces': namespaces, 'handler': identity(handler),
|
|
52
|
+
'name': route.name, 'defaultsHash': hashlib.sha256(values_json.encode()).hexdigest()}
|
|
53
|
+
})
|
|
54
|
+
walk(get_resolver().url_patterns, [], [], {}, 0)
|
|
55
|
+
return entries, visited, unsupported
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
try:
|
|
59
|
+
installed = version('Django')
|
|
60
|
+
except PackageNotFoundError:
|
|
61
|
+
json.dump({'unavailable': 'django-runtime', 'reason': 'missing-package'}, sys.stdout)
|
|
62
|
+
sys.exit(3)
|
|
63
|
+
if installed != '6.1.1':
|
|
64
|
+
json.dump({'unavailable': 'django-runtime', 'reason': 'unsupported-version'}, sys.stdout)
|
|
65
|
+
sys.exit(3)
|
|
66
|
+
config = json.loads(sys.argv[1])
|
|
67
|
+
with contextlib.redirect_stdout(sys.stderr):
|
|
68
|
+
entries, visited, unsupported = capture()
|
|
69
|
+
json.dump({
|
|
70
|
+
'version': 1, 'djangoVersion': installed, 'visitedNodes': visited, 'unsupportedNodes': unsupported,
|
|
71
|
+
'runtime': {'schemaVersion': 1, 'format': 'runtime-inventory',
|
|
72
|
+
'producer': {'name': 'checktrail.django-routes', 'version': '1.0.0'},
|
|
73
|
+
'assembly': {'name': config['assembly'], 'environment': config['environment']},
|
|
74
|
+
'sourceFingerprint': sys.argv[2], 'capturedAt': datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z'),
|
|
75
|
+
'collections': [{'kind': 'routes', 'complete': unsupported == 0, 'ordered': True, 'entries': entries}]}
|
|
76
|
+
}, sys.stdout)
|
|
77
|
+
except Exception as error:
|
|
78
|
+
print(type(error).__name__ + ': ' + str(error), file=sys.stderr)
|
|
79
|
+
sys.exit(2)
|
|
80
|
+
`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Check, Inventory, Project } from "./types.js";
|
|
3
|
+
export declare const djangoConfigSchema: z.ZodObject<{
|
|
4
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
5
|
+
settings: z.ZodString;
|
|
6
|
+
assembly: z.ZodString;
|
|
7
|
+
environment: z.ZodString;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
export declare function djangoCheck(source: Inventory, project: Project): Promise<Check>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { readProjectFile } from "./inventory.js";
|
|
4
|
+
import { djangoRunner } from "./django-runner.js";
|
|
5
|
+
export const djangoConfigSchema = z.strictObject({
|
|
6
|
+
schemaVersion: z.literal(1),
|
|
7
|
+
settings: z
|
|
8
|
+
.string()
|
|
9
|
+
.regex(/^[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*$/)
|
|
10
|
+
.max(256),
|
|
11
|
+
assembly: z.string().min(1).max(256),
|
|
12
|
+
environment: z.string().min(1).max(256),
|
|
13
|
+
});
|
|
14
|
+
export async function djangoCheck(source, project) {
|
|
15
|
+
const check = {
|
|
16
|
+
id: "python.django-routes",
|
|
17
|
+
adapter: project.adapter,
|
|
18
|
+
project: project.path,
|
|
19
|
+
scope: [],
|
|
20
|
+
commands: [],
|
|
21
|
+
kind: "analysis",
|
|
22
|
+
parser: "django-json",
|
|
23
|
+
reason: "Load explicit Django test settings, run native application setup, and inventory supported URL patterns including nested resolvers.",
|
|
24
|
+
};
|
|
25
|
+
if (!project.files.includes("checktrail.django.json")) {
|
|
26
|
+
check.unavailableReason =
|
|
27
|
+
"Django route validation requires an explicit checktrail.django.json profile.";
|
|
28
|
+
return check;
|
|
29
|
+
}
|
|
30
|
+
const config = djangoConfigSchema.parse(JSON.parse(await readProjectFile(source.root, path.posix.join(project.path, "checktrail.django.json"))));
|
|
31
|
+
const modulePath = config.settings.replaceAll(".", "/");
|
|
32
|
+
check.scope = [`${modulePath}.py`, `${modulePath}/__init__.py`].filter((file) => project.files.includes(file));
|
|
33
|
+
if (check.scope.length !== 1) {
|
|
34
|
+
check.unavailableReason =
|
|
35
|
+
"Django settings must resolve to one inventoried local Python module or package.";
|
|
36
|
+
return check;
|
|
37
|
+
}
|
|
38
|
+
check.commands = [
|
|
39
|
+
{
|
|
40
|
+
executable: "python3",
|
|
41
|
+
args: ["-c", djangoRunner, JSON.stringify(config), source.fingerprint],
|
|
42
|
+
cwd: project.path,
|
|
43
|
+
env: {
|
|
44
|
+
PYTHONDONTWRITEBYTECODE: "1",
|
|
45
|
+
DJANGO_SETTINGS_MODULE: config.settings,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
return check;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const dotnetCompilerSource: string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const dotnetCompilerSource = String.raw `
|
|
2
|
+
using System;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.IO;
|
|
5
|
+
using System.Linq;
|
|
6
|
+
using System.Reflection.Metadata;
|
|
7
|
+
using System.Reflection.PortableExecutable;
|
|
8
|
+
using System.Text;
|
|
9
|
+
using System.Text.Json;
|
|
10
|
+
using Microsoft.CodeAnalysis;
|
|
11
|
+
using Microsoft.CodeAnalysis.CSharp;
|
|
12
|
+
using Microsoft.CodeAnalysis.Text;
|
|
13
|
+
|
|
14
|
+
sealed class BoundedOutput : MemoryStream {
|
|
15
|
+
const int Limit = 32 * 1024 * 1024;
|
|
16
|
+
void Check(long length) { if (length > Limit) throw new IOException("Compiler output limit exceeded"); }
|
|
17
|
+
public override void Write(byte[] buffer, int offset, int count) { Check(Position + count); base.Write(buffer, offset, count); }
|
|
18
|
+
public override void Write(ReadOnlySpan<byte> buffer) { Check(Position + buffer.Length); base.Write(buffer); }
|
|
19
|
+
public override void WriteByte(byte value) { Check(Position + 1); base.WriteByte(value); }
|
|
20
|
+
public override void SetLength(long value) { Check(value); base.SetLength(value); }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class VerifierCompiler {
|
|
24
|
+
static void Main(string[] args) {
|
|
25
|
+
using var input = JsonDocument.Parse(File.ReadAllText(args[0], Encoding.UTF8));
|
|
26
|
+
var root = input.RootElement;
|
|
27
|
+
var config = root.GetProperty("config");
|
|
28
|
+
var language = config.GetProperty("languageVersion").GetString() switch {
|
|
29
|
+
"12" => LanguageVersion.CSharp12, "13" => LanguageVersion.CSharp13, "14" => LanguageVersion.CSharp14,
|
|
30
|
+
_ => throw new InvalidOperationException("Unsupported language version")
|
|
31
|
+
};
|
|
32
|
+
var nullable = config.GetProperty("nullable").GetString() switch {
|
|
33
|
+
"enable" => NullableContextOptions.Enable, "disable" => NullableContextOptions.Disable,
|
|
34
|
+
"warnings" => NullableContextOptions.Warnings, "annotations" => NullableContextOptions.Annotations,
|
|
35
|
+
_ => throw new InvalidOperationException("Unsupported nullable context")
|
|
36
|
+
};
|
|
37
|
+
var parseOptions = new CSharpParseOptions(language, DocumentationMode.Parse, SourceCodeKind.Regular,
|
|
38
|
+
config.GetProperty("defines").EnumerateArray().Select(item => item.GetString()!));
|
|
39
|
+
var trees = new List<SyntaxTree>();
|
|
40
|
+
foreach (var file in root.GetProperty("sources").EnumerateArray()) {
|
|
41
|
+
var name = file.GetString()!;
|
|
42
|
+
var text = File.ReadAllText(name, new UTF8Encoding(false, true));
|
|
43
|
+
trees.Add(CSharpSyntaxTree.ParseText(SourceText.From(text, Encoding.UTF8, SourceHashAlgorithm.Sha256), parseOptions, name));
|
|
44
|
+
}
|
|
45
|
+
var implicitUsings = config.GetProperty("implicitUsings").GetBoolean();
|
|
46
|
+
if (implicitUsings) trees.Add(CSharpSyntaxTree.ParseText("global using System; global using System.Collections.Generic; global using System.IO; global using System.Linq; global using System.Net.Http; global using System.Threading; global using System.Threading.Tasks;", parseOptions, "checktrail://implicit-usings", Encoding.UTF8));
|
|
47
|
+
var references = root.GetProperty("references").EnumerateArray().Select(item => {
|
|
48
|
+
var file = item.GetString()!;
|
|
49
|
+
using var stream = File.OpenRead(file);
|
|
50
|
+
using var image = new PEReader(stream);
|
|
51
|
+
if (!image.HasMetadata) throw new InvalidOperationException("Reference is not a managed assembly");
|
|
52
|
+
var metadata = image.GetMetadataReader();
|
|
53
|
+
if (!metadata.IsAssembly || metadata.AssemblyFiles.Count != 0)
|
|
54
|
+
throw new InvalidOperationException("Multi-file assembly references are unsupported");
|
|
55
|
+
return MetadataReference.CreateFromFile(file);
|
|
56
|
+
}).ToArray();
|
|
57
|
+
var options = new CSharpCompilationOptions(
|
|
58
|
+
config.GetProperty("outputKind").GetString() == "console" ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary,
|
|
59
|
+
optimizationLevel: OptimizationLevel.Release, checkOverflow: config.GetProperty("checkedArithmetic").GetBoolean(),
|
|
60
|
+
allowUnsafe: config.GetProperty("allowUnsafe").GetBoolean(), warningLevel: 9999,
|
|
61
|
+
generalDiagnosticOption: config.GetProperty("warningsAsErrors").GetBoolean() ? ReportDiagnostic.Error : ReportDiagnostic.Default,
|
|
62
|
+
concurrentBuild: false, deterministic: true, nullableContextOptions: nullable, reportSuppressedDiagnostics: true);
|
|
63
|
+
var compilation = CSharpCompilation.Create(config.GetProperty("assemblyName").GetString()!, trees, references, options);
|
|
64
|
+
var sources = new List<object>();
|
|
65
|
+
foreach (var tree in trees.Where(tree => tree.FilePath != "checktrail://implicit-usings")) {
|
|
66
|
+
var syntax = tree.GetRoot();
|
|
67
|
+
var model = compilation.GetSemanticModel(tree);
|
|
68
|
+
var diagnostics = model.GetDiagnostics();
|
|
69
|
+
if (diagnostics.Length > 2000) throw new InvalidOperationException("Diagnostic limit exceeded");
|
|
70
|
+
sources.Add(new {file = tree.FilePath, syntaxLength = syntax.FullSpan.Length, textLength = tree.GetText().Length,
|
|
71
|
+
semantic = model.SyntaxTree == tree, semanticDiagnosticCount = diagnostics.Length});
|
|
72
|
+
}
|
|
73
|
+
using var output = new BoundedOutput();
|
|
74
|
+
var result = compilation.Emit(output);
|
|
75
|
+
if (result.Diagnostics.Length > 2000) throw new InvalidOperationException("Diagnostic limit exceeded");
|
|
76
|
+
var messages = result.Diagnostics.Select(item => {
|
|
77
|
+
var line = item.Location.IsInSource ? item.Location.GetLineSpan() : default;
|
|
78
|
+
return new {code = item.Id, severity = item.Severity.ToString(), message = item.GetMessage(System.Globalization.CultureInfo.InvariantCulture),
|
|
79
|
+
suppressed = item.IsSuppressed, file = item.Location.IsInSource ? item.Location.SourceTree?.FilePath : null,
|
|
80
|
+
line = item.Location.IsInSource ? line.StartLinePosition.Line + 1 : 0};
|
|
81
|
+
}).ToArray();
|
|
82
|
+
Console.Write(JsonSerializer.Serialize(new {version = 1, compiler = typeof(CSharpCompilation).Assembly.GetName().Version!.ToString(),
|
|
83
|
+
runtime = Environment.Version.ToString(), success = result.Success, outputBytes = output.Length,
|
|
84
|
+
ownedTreeCount = implicitUsings ? 1 : 0, referenceCount = references.Length, settings = config, sources, diagnostics = messages}));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { dotnetConfigSchema, dotnetInvocationSchema } from "./dotnet.js";
|
|
4
|
+
const schema = z.strictObject({
|
|
5
|
+
sdkVersion: z.literal("10.0.401"),
|
|
6
|
+
runtimeReferenceVersion: z.literal("10.0.12"),
|
|
7
|
+
referenceFiles: z.number().int().min(2).max(509),
|
|
8
|
+
compilerAndReferencesSha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
9
|
+
compilation: z.strictObject({
|
|
10
|
+
version: z.literal(1),
|
|
11
|
+
compiler: z.literal("5.9.0.0"),
|
|
12
|
+
runtime: z.literal("10.0.12"),
|
|
13
|
+
success: z.boolean(),
|
|
14
|
+
outputBytes: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.nonnegative()
|
|
18
|
+
.max(32 * 1024 * 1024),
|
|
19
|
+
ownedTreeCount: z.number().int().min(0).max(1),
|
|
20
|
+
referenceCount: z.number().int().positive(),
|
|
21
|
+
settings: dotnetConfigSchema,
|
|
22
|
+
sources: z
|
|
23
|
+
.array(z.strictObject({
|
|
24
|
+
file: z.string(),
|
|
25
|
+
syntaxLength: z.number().int().nonnegative(),
|
|
26
|
+
textLength: z.number().int().nonnegative(),
|
|
27
|
+
semantic: z.boolean(),
|
|
28
|
+
semanticDiagnosticCount: z.number().int().nonnegative().max(2000),
|
|
29
|
+
}))
|
|
30
|
+
.max(20_000),
|
|
31
|
+
diagnostics: z
|
|
32
|
+
.array(z.strictObject({
|
|
33
|
+
code: z.string().regex(/^CS\d+$/),
|
|
34
|
+
severity: z.enum(["Error", "Warning", "Info", "Hidden"]),
|
|
35
|
+
message: z.string(),
|
|
36
|
+
suppressed: z.boolean(),
|
|
37
|
+
file: z.string().nullable(),
|
|
38
|
+
line: z.number().int().nonnegative(),
|
|
39
|
+
}))
|
|
40
|
+
.max(2000),
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
export function dotnetEvidence(check, processes, root) {
|
|
44
|
+
const incomplete = {
|
|
45
|
+
status: "inconclusive",
|
|
46
|
+
reason: ".NET evidence is malformed, suppressed or missing native compilation/source accounting",
|
|
47
|
+
findingsComplete: false,
|
|
48
|
+
};
|
|
49
|
+
if (!root || processes.length !== 1)
|
|
50
|
+
return incomplete;
|
|
51
|
+
const process = processes[0];
|
|
52
|
+
if (process.exitCode === 3) {
|
|
53
|
+
try {
|
|
54
|
+
z.strictObject({ unavailable: z.literal("dotnet-toolchain") }).parse(JSON.parse(process.stdout));
|
|
55
|
+
return {
|
|
56
|
+
status: "unavailable",
|
|
57
|
+
reason: "The verified .NET SDK and Roslyn compiler are unavailable",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return incomplete;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (process.exitCode !== 0)
|
|
65
|
+
return {
|
|
66
|
+
status: "error",
|
|
67
|
+
reason: ".NET evidence collection did not complete normally",
|
|
68
|
+
findingsComplete: false,
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
const data = schema.parse(JSON.parse(process.stdout));
|
|
72
|
+
const result = data.compilation;
|
|
73
|
+
const planned = dotnetInvocationSchema.parse(JSON.parse(check.commands[0].args[2]));
|
|
74
|
+
if (JSON.stringify(planned.scope) !== JSON.stringify(check.scope) ||
|
|
75
|
+
JSON.stringify(planned.config) !== JSON.stringify(result.settings) ||
|
|
76
|
+
result.ownedTreeCount !== Number(planned.config.implicitUsings) ||
|
|
77
|
+
result.referenceCount !==
|
|
78
|
+
data.referenceFiles + planned.config.references.length)
|
|
79
|
+
return incomplete;
|
|
80
|
+
const expected = new Set(check.scope.map((file) => path.resolve(root, check.project, file)));
|
|
81
|
+
const findings = result.diagnostics
|
|
82
|
+
.filter((item) => !item.suppressed)
|
|
83
|
+
.map((item) => ({
|
|
84
|
+
ruleId: `csharp/${item.code}`,
|
|
85
|
+
level: item.severity === "Error"
|
|
86
|
+
? "error"
|
|
87
|
+
: item.severity === "Warning"
|
|
88
|
+
? "warning"
|
|
89
|
+
: "note",
|
|
90
|
+
message: item.message,
|
|
91
|
+
...(item.file && expected.has(item.file) && item.line > 0
|
|
92
|
+
? {
|
|
93
|
+
file: path.relative(root, item.file).split(path.sep).join("/"),
|
|
94
|
+
line: item.line,
|
|
95
|
+
}
|
|
96
|
+
: {}),
|
|
97
|
+
}));
|
|
98
|
+
const errors = result.diagnostics.some((item) => item.severity === "Error" && !item.suppressed);
|
|
99
|
+
if (errors && !result.success)
|
|
100
|
+
return {
|
|
101
|
+
status: "failed",
|
|
102
|
+
reason: "Roslyn reported compiler errors; failed compilation does not establish complete analysis",
|
|
103
|
+
findings,
|
|
104
|
+
findingsComplete: false,
|
|
105
|
+
};
|
|
106
|
+
if (errors ||
|
|
107
|
+
!result.success ||
|
|
108
|
+
!result.outputBytes ||
|
|
109
|
+
result.diagnostics.some((item) => item.suppressed) ||
|
|
110
|
+
!expected.size ||
|
|
111
|
+
result.sources.length !== expected.size ||
|
|
112
|
+
new Set(result.sources.map((item) => item.file)).size !== expected.size ||
|
|
113
|
+
result.sources.some((item) => !expected.has(item.file) ||
|
|
114
|
+
!item.semantic ||
|
|
115
|
+
item.syntaxLength !== item.textLength))
|
|
116
|
+
return { ...incomplete, findings };
|
|
117
|
+
return {
|
|
118
|
+
status: "passed",
|
|
119
|
+
reason: "Configured C# sources compiled with native syntax and semantic accounting; no application code, build targets or tests were executed",
|
|
120
|
+
findings,
|
|
121
|
+
findingsComplete: true,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return incomplete;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { copyFile, mkdtemp, readFile, readdir, realpath, rm, stat, writeFile, } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { dotnetCompilerSource } from "./dotnet-compiler.js";
|
|
7
|
+
import { dotnetInvocationSchema, dotnetReferences } from "./dotnet.js";
|
|
8
|
+
import { withinRoot } from "./inventory.js";
|
|
9
|
+
const sdkVersion = "10.0.401";
|
|
10
|
+
const runtimeVersion = "10.0.12";
|
|
11
|
+
const compilerVersion = "5.9.0-1.26423.113 (e34a38d2ae1fc26406a317517196e55c68ff83ab)";
|
|
12
|
+
const env = {
|
|
13
|
+
PATH: process.env.PATH ?? "",
|
|
14
|
+
DOTNET_CLI_TELEMETRY_OPTOUT: "1",
|
|
15
|
+
DOTNET_NOLOGO: "1",
|
|
16
|
+
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1",
|
|
17
|
+
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "1",
|
|
18
|
+
DOTNET_EnableDiagnostics: "0",
|
|
19
|
+
DOTNET_GCHeapHardLimit: "10000000",
|
|
20
|
+
};
|
|
21
|
+
let nativeBytes = 0;
|
|
22
|
+
function invoke(args, cwd) {
|
|
23
|
+
const result = spawnSync("dotnet", args, {
|
|
24
|
+
cwd,
|
|
25
|
+
env,
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
maxBuffer: 1024 * 1024,
|
|
28
|
+
});
|
|
29
|
+
nativeBytes +=
|
|
30
|
+
Buffer.byteLength(result.stdout ?? "") +
|
|
31
|
+
Buffer.byteLength(result.stderr ?? "");
|
|
32
|
+
if (result.error ||
|
|
33
|
+
result.signal ||
|
|
34
|
+
result.status === null ||
|
|
35
|
+
nativeBytes > 4 * 1024 * 1024)
|
|
36
|
+
throw new Error(".NET invocation did not complete within evidence limits");
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
async function fingerprint(files) {
|
|
40
|
+
const hash = createHash("sha256");
|
|
41
|
+
let total = 0;
|
|
42
|
+
if (files.length > 512)
|
|
43
|
+
throw new Error(".NET reference pack exceeds file limits");
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
const info = await stat(file);
|
|
46
|
+
total += info.size;
|
|
47
|
+
if (!info.isFile() ||
|
|
48
|
+
info.size > 32 * 1024 * 1024 ||
|
|
49
|
+
total > 128 * 1024 * 1024)
|
|
50
|
+
throw new Error(".NET reference pack exceeds byte limits");
|
|
51
|
+
hash
|
|
52
|
+
.update(path.basename(file))
|
|
53
|
+
.update("\0")
|
|
54
|
+
.update(createHash("sha256")
|
|
55
|
+
.update(await readFile(file))
|
|
56
|
+
.digest("hex"))
|
|
57
|
+
.update("\0");
|
|
58
|
+
}
|
|
59
|
+
return hash.digest("hex");
|
|
60
|
+
}
|
|
61
|
+
async function main() {
|
|
62
|
+
const temporary = await mkdtemp(path.join(tmpdir(), "checktrail-dotnet-"));
|
|
63
|
+
try {
|
|
64
|
+
let sdk;
|
|
65
|
+
try {
|
|
66
|
+
const list = invoke(["--list-sdks"], temporary);
|
|
67
|
+
const matches = list.stdout
|
|
68
|
+
.split(/\r?\n/)
|
|
69
|
+
.flatMap((line) => /^10\.0\.401 \[([^\r\n]+)\]$/.exec(line)?.[1] ?? []);
|
|
70
|
+
if (list.status !== 0 || list.stderr || matches.length !== 1)
|
|
71
|
+
throw new Error("Missing verified SDK");
|
|
72
|
+
sdk = await realpath(path.join(matches[0], sdkVersion));
|
|
73
|
+
const version = invoke(["exec", path.join(sdk, "Roslyn/bincore/csc.dll"), "-version"], temporary);
|
|
74
|
+
if (version.status !== 0 ||
|
|
75
|
+
version.stderr ||
|
|
76
|
+
version.stdout.trim() !== compilerVersion)
|
|
77
|
+
throw new Error("Unverified Roslyn compiler");
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
process.stdout.write(JSON.stringify({ unavailable: "dotnet-toolchain" }));
|
|
81
|
+
process.exitCode = 3;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (process.argv[2] === "--version") {
|
|
85
|
+
process.stdout.write(`${sdkVersion}\n`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const installation = path.resolve(sdk, "../..");
|
|
89
|
+
const referencePack = path.join(installation, "packs/Microsoft.NETCore.App.Ref", runtimeVersion, "ref/net10.0");
|
|
90
|
+
const builtins = (await readdir(referencePack))
|
|
91
|
+
.filter((file) => file.endsWith(".dll"))
|
|
92
|
+
.sort()
|
|
93
|
+
.map((file) => path.join(referencePack, file));
|
|
94
|
+
if (!["System.Runtime.dll", "mscorlib.dll"].every((file) => builtins.includes(path.join(referencePack, file))))
|
|
95
|
+
throw new Error("Incomplete .NET reference pack");
|
|
96
|
+
const compiler = path.join(sdk, "Roslyn/bincore");
|
|
97
|
+
const compilerLibraries = [
|
|
98
|
+
"Microsoft.CodeAnalysis.dll",
|
|
99
|
+
"Microsoft.CodeAnalysis.CSharp.dll",
|
|
100
|
+
].map((file) => path.join(compiler, file));
|
|
101
|
+
const toolFiles = [
|
|
102
|
+
...builtins,
|
|
103
|
+
...compilerLibraries,
|
|
104
|
+
path.join(compiler, "csc.dll"),
|
|
105
|
+
];
|
|
106
|
+
const before = await fingerprint(toolFiles);
|
|
107
|
+
const root = await realpath(process.argv[2]);
|
|
108
|
+
const project = path.relative(root, await realpath(process.cwd())) || ".";
|
|
109
|
+
const invocation = dotnetInvocationSchema.parse(JSON.parse(process.argv[3]));
|
|
110
|
+
const references = await dotnetReferences(root, project, invocation.config);
|
|
111
|
+
const sources = await Promise.all(invocation.scope.map((file) => withinRoot(root, path.join(project, file))));
|
|
112
|
+
const helper = path.join(temporary, "VerifierCompiler.cs");
|
|
113
|
+
const output = path.join(temporary, "VerifierCompiler.dll");
|
|
114
|
+
await writeFile(helper, dotnetCompilerSource);
|
|
115
|
+
const bootstrap = invoke([
|
|
116
|
+
"exec",
|
|
117
|
+
path.join(compiler, "csc.dll"),
|
|
118
|
+
"-nologo",
|
|
119
|
+
"-noconfig",
|
|
120
|
+
"-nostdlib+",
|
|
121
|
+
"-langversion:14",
|
|
122
|
+
"-nullable:enable",
|
|
123
|
+
"-warnaserror+",
|
|
124
|
+
"-target:exe",
|
|
125
|
+
`-out:${output}`,
|
|
126
|
+
...[...builtins, ...compilerLibraries].map((file) => `-r:${file}`),
|
|
127
|
+
helper,
|
|
128
|
+
], temporary);
|
|
129
|
+
if (bootstrap.status !== 0 || bootstrap.stderr || bootstrap.stdout.trim())
|
|
130
|
+
throw new Error("Owned .NET compiler helper could not be prepared");
|
|
131
|
+
for (const file of compilerLibraries)
|
|
132
|
+
await copyFile(file, path.join(temporary, path.basename(file)));
|
|
133
|
+
await writeFile(path.join(temporary, "VerifierCompiler.runtimeconfig.json"), JSON.stringify({
|
|
134
|
+
runtimeOptions: {
|
|
135
|
+
tfm: "net10.0",
|
|
136
|
+
framework: { name: "Microsoft.NETCore.App", version: runtimeVersion },
|
|
137
|
+
rollForward: "Disable",
|
|
138
|
+
},
|
|
139
|
+
}));
|
|
140
|
+
const input = path.join(temporary, "invocation.json");
|
|
141
|
+
await writeFile(input, JSON.stringify({
|
|
142
|
+
config: invocation.config,
|
|
143
|
+
sources,
|
|
144
|
+
references: [...builtins, ...references],
|
|
145
|
+
}));
|
|
146
|
+
const result = invoke(["exec", output, input], temporary);
|
|
147
|
+
if (result.status !== 0 || result.stderr.trim())
|
|
148
|
+
throw new Error(".NET compiler did not complete evidence collection");
|
|
149
|
+
await dotnetReferences(root, project, invocation.config);
|
|
150
|
+
if ((await fingerprint(toolFiles)) !== before)
|
|
151
|
+
throw new Error(".NET reference pack or compiler changed during compilation");
|
|
152
|
+
process.stdout.write(JSON.stringify({
|
|
153
|
+
sdkVersion,
|
|
154
|
+
runtimeReferenceVersion: runtimeVersion,
|
|
155
|
+
referenceFiles: builtins.length,
|
|
156
|
+
compilerAndReferencesSha256: before,
|
|
157
|
+
compilation: JSON.parse(result.stdout),
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await rm(temporary, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
main().catch(() => {
|
|
165
|
+
process.stderr.write(".NET evidence collection could not complete\n");
|
|
166
|
+
process.exitCode = 2;
|
|
167
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Check, Inventory, Project } from "./types.js";
|
|
3
|
+
export declare const dotnetConfigSchema: z.ZodObject<{
|
|
4
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
5
|
+
targetFramework: z.ZodLiteral<"net10.0">;
|
|
6
|
+
assemblyName: z.ZodString;
|
|
7
|
+
languageVersion: z.ZodEnum<{
|
|
8
|
+
12: "12";
|
|
9
|
+
13: "13";
|
|
10
|
+
14: "14";
|
|
11
|
+
}>;
|
|
12
|
+
outputKind: z.ZodEnum<{
|
|
13
|
+
library: "library";
|
|
14
|
+
console: "console";
|
|
15
|
+
}>;
|
|
16
|
+
nullable: z.ZodEnum<{
|
|
17
|
+
enable: "enable";
|
|
18
|
+
disable: "disable";
|
|
19
|
+
warnings: "warnings";
|
|
20
|
+
annotations: "annotations";
|
|
21
|
+
}>;
|
|
22
|
+
warningsAsErrors: z.ZodBoolean;
|
|
23
|
+
allowUnsafe: z.ZodBoolean;
|
|
24
|
+
checkedArithmetic: z.ZodBoolean;
|
|
25
|
+
implicitUsings: z.ZodBoolean;
|
|
26
|
+
defines: z.ZodArray<z.ZodString>;
|
|
27
|
+
references: z.ZodArray<z.ZodObject<{
|
|
28
|
+
path: z.ZodString;
|
|
29
|
+
sha256: z.ZodString;
|
|
30
|
+
}, z.core.$strict>>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
export declare const dotnetInvocationSchema: z.ZodObject<{
|
|
33
|
+
config: z.ZodObject<{
|
|
34
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
35
|
+
targetFramework: z.ZodLiteral<"net10.0">;
|
|
36
|
+
assemblyName: z.ZodString;
|
|
37
|
+
languageVersion: z.ZodEnum<{
|
|
38
|
+
12: "12";
|
|
39
|
+
13: "13";
|
|
40
|
+
14: "14";
|
|
41
|
+
}>;
|
|
42
|
+
outputKind: z.ZodEnum<{
|
|
43
|
+
library: "library";
|
|
44
|
+
console: "console";
|
|
45
|
+
}>;
|
|
46
|
+
nullable: z.ZodEnum<{
|
|
47
|
+
enable: "enable";
|
|
48
|
+
disable: "disable";
|
|
49
|
+
warnings: "warnings";
|
|
50
|
+
annotations: "annotations";
|
|
51
|
+
}>;
|
|
52
|
+
warningsAsErrors: z.ZodBoolean;
|
|
53
|
+
allowUnsafe: z.ZodBoolean;
|
|
54
|
+
checkedArithmetic: z.ZodBoolean;
|
|
55
|
+
implicitUsings: z.ZodBoolean;
|
|
56
|
+
defines: z.ZodArray<z.ZodString>;
|
|
57
|
+
references: z.ZodArray<z.ZodObject<{
|
|
58
|
+
path: z.ZodString;
|
|
59
|
+
sha256: z.ZodString;
|
|
60
|
+
}, z.core.$strict>>;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
scope: z.ZodArray<z.ZodString>;
|
|
63
|
+
}, z.core.$strict>;
|
|
64
|
+
export declare function dotnetReferences(root: string, project: string, config: z.infer<typeof dotnetConfigSchema>): Promise<string[]>;
|
|
65
|
+
export declare function dotnetCheck(source: Inventory, project: Project): Promise<Check>;
|