Readable by people and pipelines.
Choose text for local review, JSON for automation, or SARIF for code-scanning systems. Output format never changes the analysis or exit-code contract.
Generate reports
# Human-readable terminal output
package-medic doctor . --format text
# Deterministic JSON written atomically
package-medic doctor . --format json --output artifacts/medic.json
# SARIF 2.1.0 as the primary format
package-medic doctor . --format sarif --output artifacts/medic.sarif
# JSON and SARIF from one analysis
package-medic doctor . --format json --output artifacts/medic.json --sarif-output artifacts/medic.sarifProgress is written to standard error, so redirected standard output remains valid JSON or SARIF. Destination directories are created and file output is replaced atomically.
JSON schema version 1
The stable camel-cased document contains version, target, scansummary, diagnostics, and analysisErrors. PackageMedic 0.6 also provides resolved packages, projectSettings,dependencyPaths, vulnerabilities,deprecatedPackages, policy metadata, suppressed and resolved diagnostics, and a structured schema-v3 diff object in Git mode.
{
"schemaVersion": 1,
"version": "0.6.0",
"target": "./MySolution.sln",
"summary": { "errors": 0, "warnings": 1, "information": 0 },
"analysisErrors": [],
"packages": [],
"projectSettings": [],
"dependencyPaths": [],
"vulnerabilities": [],
"deprecatedPackages": [],
"diagnostics": []
}Dependency impact in JSON
In Git mode, diff.impact contains gatePassed, a directionalsummary, changed packages with causal paths and provenance, policy violations, and the effective policy. The summary includes maximum blast radius, direct/transitive growth, source changes, and same-identitycontentChanges, while package violations include the responsible direct root and suggested action.
{
"diff": {
"schemaVersion": 3,
"impact": {
"gatePassed": false,
"summary": {
"addedDirectPackages": 1,
"addedTransitivePackages": 7,
"maximumBlastRadius": 7,
"contentChanges": 0,
"violations": 1
},
"violations": [
{
"code": "PMI004",
"kind": "addedTransitiveBudgetExceeded",
"message": "The dependency change adds 7 transitive packages; the configured limit is 5."
}
]
}
}
}Dependency impact remains in text and JSON rather than SARIF because PMI codes describe graph policy, not current source-code findings.
Dependency Time Machine JSON
simulate uses a separate schema version 2 so hypothetical evidence cannot be confused with an observed scan. It separates repository, request, mutation, verification, comparison, rejection reasons, and operational errors.
{
"schemaVersion": 2,
"kind": "dependencySimulation",
"toolVersion": "0.6.0",
"repository": {
"headCommit": "0000000000000000000000000000000000000000",
"analysisTarget": "MySolution.sln",
"workingTreeRequiredClean": true
},
"request": { "packageId": "Example.Package", "candidateVersion": "2.0.0" },
"mutation": {
"packageId": "Example.Package",
"file": "Directory.Packages.props",
"line": 18,
"kind": "centralPackageVersion",
"beforeVersion": "1.5.0",
"candidateVersion": "2.0.0",
"affectedProjects": ["src/App/App.csproj"],
"noChange": false,
"sourceSha256Before": "1111111111111111111111111111111111111111111111111111111111111111",
"sourceSha256After": "2222222222222222222222222222222222222222222222222222222222222222"
},
"verification": {
"restore": "passed",
"build": "notRun",
"tests": "notRun",
"runtimeCompatibility": "notVerified",
"evidenceLevel": "restoreOnly",
"auditedVulnerabilities": false,
"auditedDeprecations": false,
"lockedMode": "notEnabled"
},
"comparison": {
"diagnosticSummary": { "added": 0, "resolved": 0, "severityChanged": 0 },
"diagnosticChanges": [],
"packageSummary": {
"added": 0, "removed": 0, "upgraded": 0, "downgraded": 0,
"uncomparableVersionChanges": 0, "directToTransitive": 0,
"transitiveToDirect": 0, "otherModified": 0
},
"packageChanges": [],
"riskSummary": {
"vulnerabilitiesIntroduced": 0, "vulnerabilitiesResolved": 0,
"deprecationsIntroduced": 0, "deprecationsResolved": 0,
"vulnerabilitiesPersistent": 0, "deprecationsPersistent": 0
},
"projectSettingsChanges": [],
"isComplete": true
},
"isComplete": true,
"verdict": "pass",
"rejectionReasons": [],
"errors": []
}Verified evidence contracts
In PackageMedic 0.6, verified diff uses diff schema version 3 and adds a structured verification comparison. Verified simulate uses simulation schema version 2 and records its executed verification alongside the existing restore and graph comparison. The report carries stage status, bounded counts, failed-test identities, evidence level, blocking stage, and verdict; raw TRX files are not exported.
CycloneDX and unsigned in-toto evidence are separate output contracts rather than fields pasted into the main scan report. See Verified experiments for supported commands, completeness rules, and the limits of each format.
SARIF 2.1.0
PM001–PM008 are declared as stable rules with help text and links. Results can include a repository-relative location, portable fingerprint, project, evidence, action, confidence, original NuGet code, advisory context, and baseline state.
| PackageMedic | SARIF level |
|---|---|
| information | note |
| warning | warning |
| error | error |
Determinism
Given the same PackageMedic version, repository root, analysis result, and baseline, JSON and SARIF preserve the same rule, result, path, fingerprint, state, and property ordering. A diff SARIF includes current added or worsened findings only; resolved findings, semantic package direction, risk deltas, and CPM changes remain available in text and JSON.
Reports do not hide failures
Exit code 0 means the selected threshold was not reached, 1 means it was reached, and 2 means the analysis was operationally incomplete. A failed Impact Gate also returns 1. A simulation uses 0 forpass/noChange, 1 for a complete rejection, and2 when the conclusion is incomplete. --fail-on none disables only the PM diagnostic threshold; it never disables impact policy or converts an operational failure into success.