@westbayberry/dg 2.0.11 → 2.2.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/README.md +216 -226
- package/dist/agents/claude-code.js +113 -0
- package/dist/agents/codex.js +65 -0
- package/dist/agents/copilot-cli.js +115 -0
- package/dist/agents/cursor.js +113 -0
- package/dist/agents/gemini.js +107 -0
- package/dist/agents/persistence.js +285 -0
- package/dist/agents/registry.js +127 -0
- package/dist/agents/types.js +1 -0
- package/dist/agents/windsurf.js +93 -0
- package/dist/api/analyze.js +6 -4
- package/dist/audit/detectors.js +0 -11
- package/dist/audit/events.js +5 -21
- package/dist/audit-ui/AuditApp.js +2 -0
- package/dist/audit-ui/components/AuditResultsView.js +55 -92
- package/dist/audit-ui/export.js +0 -4
- package/dist/audit-ui/format.js +0 -3
- package/dist/audit-ui/launch.js +10 -1
- package/dist/auth/device-login.js +4 -5
- package/dist/auth/login-app.js +7 -7
- package/dist/auth/store.js +8 -3
- package/dist/bin/dg.js +59 -52
- package/dist/commands/agents.js +231 -0
- package/dist/commands/audit.js +22 -3
- package/dist/commands/config.js +26 -10
- package/dist/commands/cooldown.js +389 -0
- package/dist/commands/decisions.js +169 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/help.js +1 -1
- package/dist/commands/licenses.js +10 -22
- package/dist/commands/logout.js +4 -11
- package/dist/commands/router.js +8 -4
- package/dist/commands/sbom.js +206 -0
- package/dist/commands/scan.js +3 -2
- package/dist/commands/service.js +32 -13
- package/dist/commands/setup.js +197 -27
- package/dist/commands/status.js +5 -2
- package/dist/commands/types.js +1 -0
- package/dist/commands/update.js +17 -8
- package/dist/commands/verify.js +8 -5
- package/dist/config/settings.js +154 -65
- package/dist/decisions/apply.js +128 -0
- package/dist/decisions/remember-prompt.js +92 -0
- package/dist/export-ui/ExportDialog.js +198 -0
- package/dist/install-ui/LiveInstall.js +2 -2
- package/dist/install-ui/block-render.js +21 -4
- package/dist/install-ui/prep-spinner.js +32 -0
- package/dist/install-ui/prompt.js +14 -0
- package/dist/launcher/agent-check.js +466 -0
- package/dist/launcher/agent-hook-exec.js +70 -0
- package/dist/launcher/agent-hook-io.js +31 -0
- package/dist/launcher/cargo-cache.js +40 -0
- package/dist/launcher/classify.js +17 -6
- package/dist/launcher/env.js +71 -24
- package/dist/launcher/install-preflight.js +167 -17
- package/dist/launcher/live-install.js +25 -5
- package/dist/launcher/output-redaction.js +7 -4
- package/dist/launcher/preflight-prompt.js +43 -3
- package/dist/launcher/run.js +100 -86
- package/dist/launcher/spawn-invocation.js +21 -0
- package/dist/policy/cooldown.js +117 -0
- package/dist/policy/evaluate.js +5 -21
- package/dist/policy/pypi-name.js +17 -0
- package/dist/presentation/mode.js +3 -2
- package/dist/presentation/package-page.js +9 -0
- package/dist/presentation/provenance.js +23 -0
- package/dist/presentation/theme.js +7 -7
- package/dist/project/dgfile.js +446 -0
- package/dist/proxy/auth.js +42 -0
- package/dist/proxy/ca.js +29 -9
- package/dist/proxy/cooldown-exemptions-file.js +33 -0
- package/dist/proxy/enforcement.js +57 -17
- package/dist/proxy/metadata-map.js +66 -4
- package/dist/proxy/preverified.js +55 -0
- package/dist/proxy/server.js +473 -45
- package/dist/proxy/worker.js +16 -1
- package/dist/publish-set/collect.js +1 -4
- package/dist/publish-set/npm.js +8 -5
- package/dist/publish-set/pack.js +9 -3
- package/dist/runtime/cli.js +0 -4
- package/dist/runtime/fatal.js +31 -0
- package/dist/runtime/first-run.js +12 -11
- package/dist/runtime/node-version.js +43 -6
- package/dist/runtime/nudges.js +35 -2
- package/dist/sbom/cyclonedx.js +211 -0
- package/dist/sbom-ui/SbomApp.js +158 -0
- package/dist/sbom-ui/components/SbomHeader.js +32 -0
- package/dist/sbom-ui/components/SbomList.js +52 -0
- package/dist/sbom-ui/inventory.js +128 -0
- package/dist/sbom-ui/launch.js +51 -0
- package/dist/sbom-ui/run.js +55 -0
- package/dist/sbom-ui/store.js +26 -0
- package/dist/scan/collect.js +10 -6
- package/dist/scan/command.js +51 -17
- package/dist/scan/discovery.js +11 -2
- package/dist/scan/render.js +63 -8
- package/dist/scan/scanner-report.js +42 -9
- package/dist/scan/staged.js +71 -11
- package/dist/scan-ui/LegacyApp.js +12 -16
- package/dist/scan-ui/alt-screen.js +5 -8
- package/dist/scan-ui/components/InteractiveResultsView.js +193 -123
- package/dist/scan-ui/components/ProgressBar.js +3 -14
- package/dist/scan-ui/components/ProjectSelector.js +1 -1
- package/dist/scan-ui/components/ScoreHeader.js +2 -3
- package/dist/scan-ui/components/SetupBanner.js +0 -6
- package/dist/scan-ui/format-helpers.js +61 -5
- package/dist/scan-ui/hooks/useResizeRepaint.js +25 -0
- package/dist/scan-ui/hooks/useScan.js +46 -4
- package/dist/scan-ui/launch.js +7 -4
- package/dist/scan-ui/shims.js +14 -4
- package/dist/scripts/detect.js +158 -0
- package/dist/scripts/gate.js +170 -0
- package/dist/service/state.js +27 -8
- package/dist/service/trust-refresh.js +92 -0
- package/dist/service/worker.js +23 -1
- package/dist/setup/activate-shell.js +28 -0
- package/dist/setup/git-hook.js +49 -4
- package/dist/setup/plan.js +98 -29
- package/dist/setup-ui/gate.js +39 -0
- package/dist/setup-ui/offer.js +42 -0
- package/dist/setup-ui/selector.js +27 -0
- package/dist/setup-ui/tasks.js +56 -0
- package/dist/setup-ui/wizard.js +225 -0
- package/dist/state/cooldown-held.js +66 -0
- package/dist/state/index.js +1 -0
- package/dist/state/locks.js +4 -2
- package/dist/state/store.js +2 -1
- package/dist/util/external-tool.js +25 -0
- package/dist/util/git.js +10 -3
- package/dist/util/json-file.js +24 -0
- package/dist/util/report-writer.js +57 -0
- package/dist/util/tty-prompt.js +13 -6
- package/dist/verify/local.js +240 -42
- package/dist/verify/package-check.js +86 -18
- package/dist/verify/preflight.js +242 -49
- package/dist/verify/render.js +15 -1
- package/npm-shrinkwrap.json +2383 -0
- package/package.json +14 -8
- package/NOTICE +0 -5
- package/dist/commands/completion.js +0 -116
- package/dist/commands/explain.js +0 -232
- package/dist/commands/unavailable.js +0 -11
- package/dist/telemetry/events.js +0 -40
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@westbayberry/dg",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Dependency Guardian supply-chain firewall CLI",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/WestBayBerry/DG_CLI.git"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/WestBayBerry/DG_CLI/issues"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/WestBayBerry/DG_CLI#readme",
|
|
5
13
|
"type": "module",
|
|
6
14
|
"bin": {
|
|
7
15
|
"dg": "./dist/bin/dg.js"
|
|
@@ -9,14 +17,16 @@
|
|
|
9
17
|
"files": [
|
|
10
18
|
"dist",
|
|
11
19
|
"LICENSE",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
20
|
+
"package.json",
|
|
21
|
+
"npm-shrinkwrap.json"
|
|
14
22
|
],
|
|
15
23
|
"engines": {
|
|
16
24
|
"node": ">=22.14.0"
|
|
17
25
|
},
|
|
18
26
|
"scripts": {
|
|
19
27
|
"build": "node build.mjs",
|
|
28
|
+
"prepack": "node scripts/sync-shrinkwrap.mjs",
|
|
29
|
+
"postpack": "node scripts/sync-shrinkwrap.mjs restore",
|
|
20
30
|
"test": "vitest run",
|
|
21
31
|
"test:unit": "vitest run test/unit",
|
|
22
32
|
"test:integration": "vitest run test/integration",
|
|
@@ -26,11 +36,7 @@
|
|
|
26
36
|
"check:package": "node scripts/check-package-contract.mjs",
|
|
27
37
|
"check:tarball": "node scripts/check-tarball.mjs",
|
|
28
38
|
"check:legacy": "node scripts/check-legacy-absence.mjs",
|
|
29
|
-
"check
|
|
30
|
-
"check:release-docs": "node scripts/check-release-docs.mjs",
|
|
31
|
-
"check:plan-coverage": "node scripts/validate-plan-coverage.mjs",
|
|
32
|
-
"check:adversarial-plan": "node scripts/validate-adversarial-validation-plan.mjs",
|
|
33
|
-
"check": "npm run typecheck && npm run lint && npm run format:check && npm run check:package && npm run check:legacy && npm run check:release-docs && npm run check:plan-coverage && npm run check:adversarial-plan && npm run build && npm run test && npm run check:tarball && npm run check:architecture-cracks"
|
|
39
|
+
"check": "npm run typecheck && npm run lint && npm run format:check && npm run check:package && npm run check:legacy && npm run build && npm run test && npm run check:tarball"
|
|
34
40
|
},
|
|
35
41
|
"devDependencies": {
|
|
36
42
|
"@types/node": "22.15.30",
|
package/NOTICE
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { commandCatalog } from "./router.js";
|
|
2
|
-
import { packageManagerCommandNames } from "./wrap.js";
|
|
3
|
-
import { EXIT_USAGE } from "./types.js";
|
|
4
|
-
const SHELLS = ["bash", "zsh", "fish"];
|
|
5
|
-
const COMMON_FLAGS = ["--help", "--version", "--json", "--sarif", "--output", "--yes", "--check", "--staged", "--dg-force-install"];
|
|
6
|
-
const FISH_FLAG_DESCRIPTIONS = {
|
|
7
|
-
"--help": "Show help",
|
|
8
|
-
"--version": "Show version",
|
|
9
|
-
"--json": "Write JSON output",
|
|
10
|
-
"--sarif": "Write SARIF output",
|
|
11
|
-
"--output": "Write report to file",
|
|
12
|
-
"--yes": "Apply a confirmed mutation",
|
|
13
|
-
"--check": "Report without mutating",
|
|
14
|
-
"--staged": "Limit to staged files",
|
|
15
|
-
"--dg-force-install": "Install despite a block, where policy allows"
|
|
16
|
-
};
|
|
17
|
-
function completionCommands() {
|
|
18
|
-
const names = new Set(packageManagerCommandNames);
|
|
19
|
-
for (const command of commandCatalog) {
|
|
20
|
-
names.add(command.name);
|
|
21
|
-
for (const alias of command.aliases ?? []) {
|
|
22
|
-
names.add(alias);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return [...names];
|
|
26
|
-
}
|
|
27
|
-
export const completionCommand = {
|
|
28
|
-
name: "completion",
|
|
29
|
-
summary: "Print shell completion for bash, zsh, or fish.",
|
|
30
|
-
usage: "dg completion <bash|zsh|fish>",
|
|
31
|
-
args: [{ name: "<shell>", summary: "bash, zsh, or fish." }],
|
|
32
|
-
examples: [
|
|
33
|
-
"dg completion bash > ~/.local/share/bash-completion/completions/dg",
|
|
34
|
-
"dg completion zsh > ~/.zfunc/_dg",
|
|
35
|
-
"dg completion fish > ~/.config/fish/completions/dg.fish"
|
|
36
|
-
],
|
|
37
|
-
details: ["Prints a completion script to stdout without changing shell files."],
|
|
38
|
-
handler: (context) => completionHandler(context.args)
|
|
39
|
-
};
|
|
40
|
-
function completionHandler(args) {
|
|
41
|
-
const [shell, ...rest] = args;
|
|
42
|
-
if (!shell || rest.length > 0 || !isSupportedShell(shell)) {
|
|
43
|
-
return {
|
|
44
|
-
exitCode: EXIT_USAGE,
|
|
45
|
-
stdout: "",
|
|
46
|
-
stderr: "dg completion: expected one shell: bash, zsh, or fish.\n"
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
return {
|
|
50
|
-
exitCode: 0,
|
|
51
|
-
stdout: renderCompletion(shell),
|
|
52
|
-
stderr: ""
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function isSupportedShell(value) {
|
|
56
|
-
return SHELLS.includes(value);
|
|
57
|
-
}
|
|
58
|
-
function renderCompletion(shell) {
|
|
59
|
-
const commandList = completionCommands();
|
|
60
|
-
const commands = commandList.join(" ");
|
|
61
|
-
const flags = COMMON_FLAGS.join(" ");
|
|
62
|
-
if (shell === "bash") {
|
|
63
|
-
return `# dg bash completion
|
|
64
|
-
_dg_completion() {
|
|
65
|
-
local cur prev
|
|
66
|
-
COMPREPLY=()
|
|
67
|
-
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
68
|
-
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
69
|
-
if [ "$prev" = "completion" ]; then
|
|
70
|
-
COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") )
|
|
71
|
-
return 0
|
|
72
|
-
fi
|
|
73
|
-
if [ "$COMP_CWORD" -eq 1 ]; then
|
|
74
|
-
COMPREPLY=( $(compgen -W "${commands}" -- "$cur") )
|
|
75
|
-
return 0
|
|
76
|
-
fi
|
|
77
|
-
COMPREPLY=( $(compgen -W "${flags}" -- "$cur") )
|
|
78
|
-
}
|
|
79
|
-
complete -F _dg_completion dg
|
|
80
|
-
`;
|
|
81
|
-
}
|
|
82
|
-
if (shell === "zsh") {
|
|
83
|
-
return `#compdef dg
|
|
84
|
-
_dg() {
|
|
85
|
-
local -a commands flags shells
|
|
86
|
-
commands=(${commandList.map((command) => escapeZsh(command)).join(" ")})
|
|
87
|
-
flags=(${COMMON_FLAGS.map((flag) => escapeZsh(flag)).join(" ")})
|
|
88
|
-
shells=(bash zsh fish)
|
|
89
|
-
if [[ "$words[2]" == "completion" ]]; then
|
|
90
|
-
compadd "$@" -- "$shells[@]"
|
|
91
|
-
return
|
|
92
|
-
fi
|
|
93
|
-
if [[ "$CURRENT" -eq 2 ]]; then
|
|
94
|
-
compadd "$@" -- "$commands[@]"
|
|
95
|
-
return
|
|
96
|
-
fi
|
|
97
|
-
compadd "$@" -- "$flags[@]"
|
|
98
|
-
}
|
|
99
|
-
_dg "$@"
|
|
100
|
-
`;
|
|
101
|
-
}
|
|
102
|
-
const fishFlagLines = COMMON_FLAGS.map((flag) => {
|
|
103
|
-
const option = flag.replace(/^--/u, "");
|
|
104
|
-
const requiresArg = flag === "--output" ? " -r" : "";
|
|
105
|
-
const description = FISH_FLAG_DESCRIPTIONS[flag] ?? option;
|
|
106
|
-
return `complete -c dg -f -l ${option}${requiresArg} -d '${description}'`;
|
|
107
|
-
}).join("\n");
|
|
108
|
-
return `# dg fish completion
|
|
109
|
-
complete -c dg -f -n '__fish_is_first_arg' -a '${commands}' -d 'Dependency Guardian command'
|
|
110
|
-
complete -c dg -f -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish' -d 'Shell'
|
|
111
|
-
${fishFlagLines}
|
|
112
|
-
`;
|
|
113
|
-
}
|
|
114
|
-
function escapeZsh(value) {
|
|
115
|
-
return value.replace(/([\\[\]{}()$`"'\s])/gu, "\\$1");
|
|
116
|
-
}
|
package/dist/commands/explain.js
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import { EXIT_USAGE } from "./types.js";
|
|
2
|
-
import { closestCommand } from "./suggest.js";
|
|
3
|
-
export const EXPLANATIONS = {
|
|
4
|
-
"npm-lifecycle-script": {
|
|
5
|
-
what: "The package declares an install lifecycle script (preinstall/install/postinstall/prepare) that runs arbitrary code on your machine during 'npm install'.",
|
|
6
|
-
next: "Review the script in the package source. Prefer a version without install scripts, or install with --ignore-scripts."
|
|
7
|
-
},
|
|
8
|
-
"unverified-network-dependency": {
|
|
9
|
-
what: "A dependency is fetched from a raw URL (http/git) instead of the registry, so it has no registry identity or integrity to verify.",
|
|
10
|
-
next: "Pin the dependency to a registry version, or run 'dg verify <url>' before installing."
|
|
11
|
-
},
|
|
12
|
-
"local-artifact-dependency": {
|
|
13
|
-
what: "A dependency points at a local file path; its contents are whatever is on disk and are not registry-verified.",
|
|
14
|
-
next: "Run 'dg verify <path>' on the artifact, or replace it with a registry version."
|
|
15
|
-
},
|
|
16
|
-
malware: {
|
|
17
|
-
what: "The scanner confirmed this package version contains malicious code (for example credential theft or a backdoor).",
|
|
18
|
-
next: "Do not install it. Remove the dependency or pin a known-safe version; the dashboard link in the block shows the evidence."
|
|
19
|
-
},
|
|
20
|
-
policy: {
|
|
21
|
-
what: "Your organization or local policy denies this package, independent of a malware verdict.",
|
|
22
|
-
next: "Pick a compliant alternative, or ask your policy admin to allow it."
|
|
23
|
-
},
|
|
24
|
-
license: {
|
|
25
|
-
what: "The package license violates your license policy (for example a copyleft license your policy denies).",
|
|
26
|
-
next: "Replace the dependency, or update the license policy if the obligation is acceptable."
|
|
27
|
-
},
|
|
28
|
-
"hash-mismatch": {
|
|
29
|
-
what: "The downloaded artifact's hash does not match the artifact the scanner verified, which can indicate a tampered mirror or cache.",
|
|
30
|
-
next: "Clear your package cache and retry. If it persists, do not install and report it."
|
|
31
|
-
},
|
|
32
|
-
"private-upload-disabled": {
|
|
33
|
-
what: "The artifact comes from a private registry and private-artifact scanning is disabled, so the scanner never saw its contents.",
|
|
34
|
-
next: "Enable private artifact scanning (DG_SCAN_TARBALL_UPLOAD) or verify the artifact out of band."
|
|
35
|
-
},
|
|
36
|
-
"api-unavailable": {
|
|
37
|
-
what: "The scanner could not be reached, so no verdict exists for this install; policy decided fail-open or fail-closed.",
|
|
38
|
-
next: "Run 'dg doctor' and 'dg login' to check connectivity, then retry or re-check with 'dg verify'."
|
|
39
|
-
},
|
|
40
|
-
"quota-exceeded": {
|
|
41
|
-
what: "You've used your plan's monthly scan allowance, so this install could not be verified — it was blocked rather than installed unverified.",
|
|
42
|
-
next: "Upgrade your plan at westbayberry.com/pricing, or wait for your monthly limit to reset."
|
|
43
|
-
},
|
|
44
|
-
"api-timeout": {
|
|
45
|
-
what: "The scanner did not answer within the verdict timeout, so no verdict exists for this install.",
|
|
46
|
-
next: "Retry; if it persists, run 'dg doctor' to check connectivity."
|
|
47
|
-
},
|
|
48
|
-
"registry-timeout": {
|
|
49
|
-
what: "The upstream package registry did not respond, so the artifact was never fetched or verified.",
|
|
50
|
-
next: "Check the registry status and retry."
|
|
51
|
-
},
|
|
52
|
-
"analysis-incomplete": {
|
|
53
|
-
what: "The scanner analyzed only part of this package; the unanalyzed remainder is unverified, not safe.",
|
|
54
|
-
next: "Retry later, or override with --dg-force-install only if you accept the risk."
|
|
55
|
-
},
|
|
56
|
-
"unsupported-manager": {
|
|
57
|
-
what: "This package manager is gated in this dg build, so installs through it are not protected.",
|
|
58
|
-
next: "Use a supported manager through dg (npm, pnpm, yarn, pip, pipx, uv, uvx, cargo)."
|
|
59
|
-
},
|
|
60
|
-
"proxy-setup-failure": {
|
|
61
|
-
what: "dg's per-install enforcement proxy could not start, so protected installs fail closed rather than run unverified.",
|
|
62
|
-
next: "Run 'dg doctor' for the failing check, then retry."
|
|
63
|
-
},
|
|
64
|
-
"needs-login": {
|
|
65
|
-
what: "This install needed a verdict that requires an authenticated account, so it was blocked rather than installed unverified.",
|
|
66
|
-
next: "Run 'dg login', then retry the install."
|
|
67
|
-
},
|
|
68
|
-
lifecycle: {
|
|
69
|
-
what: "The scanner flagged an install lifecycle script (preinstall/install/postinstall) that runs arbitrary code during install.",
|
|
70
|
-
next: "Review the script in the package source, or install with --ignore-scripts."
|
|
71
|
-
},
|
|
72
|
-
"install-script": {
|
|
73
|
-
what: "The scanner found an install-time script in this package that executes code on your machine during install.",
|
|
74
|
-
next: "Review the script before installing; prefer a version without install scripts."
|
|
75
|
-
},
|
|
76
|
-
"archive-path-traversal": {
|
|
77
|
-
what: "The package archive contains an entry whose path escapes the extraction directory, a classic overwrite attack.",
|
|
78
|
-
next: "Do not install it; report the package and pin a known-safe version."
|
|
79
|
-
},
|
|
80
|
-
"archive-path-too-long": {
|
|
81
|
-
what: "The package archive contains an entry path long enough to break extraction or smuggle content past tooling.",
|
|
82
|
-
next: "Treat the artifact as untrusted and verify it out of band."
|
|
83
|
-
},
|
|
84
|
-
"archive-size-limit": {
|
|
85
|
-
what: "The package archive expands past dg's size limit, so its contents were not fully verified (possible zip bomb).",
|
|
86
|
-
next: "Verify the artifact out of band before trusting it."
|
|
87
|
-
},
|
|
88
|
-
"encrypted-archive-entry": {
|
|
89
|
-
what: "The package archive contains an encrypted entry dg cannot inspect, so part of the package is unverified.",
|
|
90
|
-
next: "Treat it as unverified; ask the publisher why the archive is encrypted."
|
|
91
|
-
},
|
|
92
|
-
"zip-data-descriptor": {
|
|
93
|
-
what: "The package archive uses zip data descriptors that can make different tools see different contents.",
|
|
94
|
-
next: "Verify the artifact out of band before trusting it."
|
|
95
|
-
},
|
|
96
|
-
"license-policy-denied": {
|
|
97
|
-
what: "The dependency's license is denied by your license policy.",
|
|
98
|
-
next: "Replace the dependency, or update the policy if the obligation is acceptable."
|
|
99
|
-
},
|
|
100
|
-
"lockfile-url-fallback": {
|
|
101
|
-
what: "A lockfile entry resolves to a raw URL instead of a registry version, so it has no registry identity to verify.",
|
|
102
|
-
next: "Re-pin the dependency to a registry version and regenerate the lockfile."
|
|
103
|
-
},
|
|
104
|
-
"unverified-lockfile-url": {
|
|
105
|
-
what: "A lockfile entry downloads from a URL the scanner could not verify against a registry artifact.",
|
|
106
|
-
next: "Pin a registry version, or run 'dg verify <url>' before installing."
|
|
107
|
-
},
|
|
108
|
-
"unverified-network-spec": {
|
|
109
|
-
what: "A dependency spec points at a raw http/git source instead of the registry, so its contents are unverified.",
|
|
110
|
-
next: "Pin the dependency to a registry version, or run 'dg verify <url>' first."
|
|
111
|
-
},
|
|
112
|
-
"unpinned-package-spec": {
|
|
113
|
-
what: "A dependency spec has no pinned version, so installs can silently pull a different artifact than was reviewed.",
|
|
114
|
-
next: "Pin an exact version (or use a lockfile) and re-run the scan."
|
|
115
|
-
},
|
|
116
|
-
"unsupported-package-spec": {
|
|
117
|
-
what: "A dependency spec uses a form dg cannot resolve to a registry artifact, so it was not verified.",
|
|
118
|
-
next: "Rewrite the spec as a registry name@version, or verify the artifact out of band."
|
|
119
|
-
},
|
|
120
|
-
"malformed-lockfile": {
|
|
121
|
-
what: "A lockfile could not be parsed, so the packages it pins were not verified.",
|
|
122
|
-
next: "Regenerate the lockfile with your package manager and re-run the scan."
|
|
123
|
-
},
|
|
124
|
-
"malformed-package-manifest": {
|
|
125
|
-
what: "A package manifest could not be parsed, so its dependencies were not verified.",
|
|
126
|
-
next: "Fix the manifest syntax and re-run the scan."
|
|
127
|
-
},
|
|
128
|
-
"missing-artifact-integrity": {
|
|
129
|
-
what: "A lockfile entry has no integrity hash, so the downloaded artifact cannot be checked against what was reviewed.",
|
|
130
|
-
next: "Regenerate the lockfile so every entry carries an integrity hash."
|
|
131
|
-
},
|
|
132
|
-
"credential-file": {
|
|
133
|
-
what: "Your publish set includes a credentials file (for example .npmrc, .netrc, or cloud keys) that would ship to the registry.",
|
|
134
|
-
next: "Remove the file from the publish set and rotate any leaked credential."
|
|
135
|
-
},
|
|
136
|
-
"private-key": {
|
|
137
|
-
what: "Your publish set includes a private key file that would become public on publish.",
|
|
138
|
-
next: "Remove it from the publish set and rotate the key."
|
|
139
|
-
},
|
|
140
|
-
"bundled-secret": {
|
|
141
|
-
what: "A file in your publish set contains what looks like a live secret (API key, token, or password).",
|
|
142
|
-
next: "Remove or redact the secret, rotate it, and re-run 'dg audit'."
|
|
143
|
-
},
|
|
144
|
-
"scm-leakage": {
|
|
145
|
-
what: "Your publish set includes version-control internals (for example a .git directory) that leak history and remotes.",
|
|
146
|
-
next: "Exclude the directory via the files allowlist or an ignore file."
|
|
147
|
-
},
|
|
148
|
-
"ci-config": {
|
|
149
|
-
what: "Your publish set includes CI configuration that often references internal infrastructure and secrets.",
|
|
150
|
-
next: "Exclude it from the publish set unless consumers need it."
|
|
151
|
-
},
|
|
152
|
-
"iac-secret": {
|
|
153
|
-
what: "Your publish set includes infrastructure-as-code state or vaults (for example tfstate) that commonly embed secrets.",
|
|
154
|
-
next: "Remove the file and rotate anything it contains."
|
|
155
|
-
},
|
|
156
|
-
"source-map": {
|
|
157
|
-
what: "Your publish set includes source maps that expose your original source to every consumer.",
|
|
158
|
-
next: "Exclude .map files from the publish set unless that is intended."
|
|
159
|
-
},
|
|
160
|
-
"build-artifact": {
|
|
161
|
-
what: "Your publish set includes build or coverage output that bloats the package and can leak internal paths.",
|
|
162
|
-
next: "Exclude the directory via the files allowlist."
|
|
163
|
-
},
|
|
164
|
-
"editor-os-junk": {
|
|
165
|
-
what: "Your publish set includes editor or OS junk files (for example .DS_Store or editor swap files).",
|
|
166
|
-
next: "Exclude them; they add noise and can leak local paths."
|
|
167
|
-
},
|
|
168
|
-
"data-dump": {
|
|
169
|
-
what: "Your publish set includes database dumps, logs, or captures that frequently contain real user data.",
|
|
170
|
-
next: "Remove the file and check whether the data requires disclosure."
|
|
171
|
-
},
|
|
172
|
-
"internal-leak": {
|
|
173
|
-
what: "Your publish set includes files that look internal-only (for example memory dumps or HAR captures).",
|
|
174
|
-
next: "Remove them from the publish set before publishing."
|
|
175
|
-
},
|
|
176
|
-
"lifecycle-risk": {
|
|
177
|
-
what: "Your package declares install lifecycle scripts that will run arbitrary code on every consumer's machine.",
|
|
178
|
-
next: "Drop the script if possible; consumers increasingly refuse install scripts."
|
|
179
|
-
},
|
|
180
|
-
structural: {
|
|
181
|
-
what: "The publish set has a structural problem (for example no files allowlist or a symlink escaping the package root).",
|
|
182
|
-
next: "Fix the structure so the publish set is exactly what you reviewed."
|
|
183
|
-
},
|
|
184
|
-
"pem-private-key": {
|
|
185
|
-
what: "A PEM-encoded private key is inside your publish set and would become public on publish.",
|
|
186
|
-
next: "Remove it from the publish set and rotate the key."
|
|
187
|
-
},
|
|
188
|
-
"no-files-allowlist": {
|
|
189
|
-
what: "package.json has no files allowlist, so npm publishes nearly everything in the directory by default.",
|
|
190
|
-
next: "Add a files allowlist so the publish set is explicit."
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
export const explainCommand = {
|
|
194
|
-
name: "explain",
|
|
195
|
-
summary: "Explain a dg finding or block cause and what to do about it.",
|
|
196
|
-
usage: "dg explain <finding-or-cause-id>",
|
|
197
|
-
args: [{ name: "<id>", summary: "A finding id or block cause (see the list below)." }],
|
|
198
|
-
examples: ["dg explain malware", "dg explain quota-exceeded"],
|
|
199
|
-
details: [
|
|
200
|
-
`Known ids: ${Object.keys(EXPLANATIONS).sort().join(", ")}`
|
|
201
|
-
],
|
|
202
|
-
handler: (context) => runExplain(context.args)
|
|
203
|
-
};
|
|
204
|
-
function runExplain(args) {
|
|
205
|
-
const id = args[0];
|
|
206
|
-
if (!id || args.length > 1) {
|
|
207
|
-
return {
|
|
208
|
-
exitCode: EXIT_USAGE,
|
|
209
|
-
stdout: "",
|
|
210
|
-
stderr: "dg explain: expected exactly one finding or cause id. Run 'dg explain --help'.\n"
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
const normalized = id.toLowerCase().replaceAll("_", "-");
|
|
214
|
-
const explanation = EXPLANATIONS[id] ?? EXPLANATIONS[normalized];
|
|
215
|
-
if (!explanation) {
|
|
216
|
-
const suggestion = closestCommand(normalized, Object.keys(EXPLANATIONS));
|
|
217
|
-
const hint = suggestion ? `Did you mean '${suggestion}'? ` : "";
|
|
218
|
-
return {
|
|
219
|
-
exitCode: 0,
|
|
220
|
-
stdout: `${id}\n\n` +
|
|
221
|
-
`dg has no local entry for '${id}'. ${hint}` +
|
|
222
|
-
"Scanner finding ids evolve faster than this glossary, so the id may still be real.\n\n" +
|
|
223
|
-
`Next: open the affected package's page on westbayberry.com — its findings list shows the evidence and remediation for '${id}'.\n`,
|
|
224
|
-
stderr: ""
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
return {
|
|
228
|
-
exitCode: 0,
|
|
229
|
-
stdout: `${id}\n\n${explanation.what}\n\nNext: ${explanation.next}\n`,
|
|
230
|
-
stderr: ""
|
|
231
|
-
};
|
|
232
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { EXIT_UNAVAILABLE } from "./types.js";
|
|
2
|
-
export function unavailableCommand(feature, nextStep) {
|
|
3
|
-
return (context) => {
|
|
4
|
-
const invoked = ["dg", ...context.commandPath, ...context.args].join(" ");
|
|
5
|
-
return {
|
|
6
|
-
exitCode: EXIT_UNAVAILABLE,
|
|
7
|
-
stdout: "",
|
|
8
|
-
stderr: `${invoked} is not available in this CLI build. ${feature}. ${nextStep}\n`
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
}
|
package/dist/telemetry/events.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { loadUserConfig } from "../config/settings.js";
|
|
4
|
-
import { resolveDgPaths } from "../state/index.js";
|
|
5
|
-
const ALLOWED_ATTRIBUTE_KEYS = new Set(["command", "exitCode", "policyMode", "decision", "packageCount", "authenticated"]);
|
|
6
|
-
export function telemetryLogPath(paths) {
|
|
7
|
-
return join(paths.stateDir, "telemetry.jsonl");
|
|
8
|
-
}
|
|
9
|
-
export function buildTelemetryEvent(type, attributes, now = new Date()) {
|
|
10
|
-
return {
|
|
11
|
-
type,
|
|
12
|
-
createdAt: now.toISOString(),
|
|
13
|
-
attributes: sanitizeTelemetryAttributes(attributes)
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export function recordTelemetryEvent(event, env = process.env) {
|
|
17
|
-
const config = loadUserConfig(env);
|
|
18
|
-
if (!config.telemetry.enabled) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
const path = telemetryLogPath(resolveDgPaths(env));
|
|
22
|
-
mkdirSync(dirname(path), {
|
|
23
|
-
recursive: true,
|
|
24
|
-
mode: 0o700
|
|
25
|
-
});
|
|
26
|
-
appendFileSync(path, `${JSON.stringify(event)}\n`, {
|
|
27
|
-
encoding: "utf8",
|
|
28
|
-
mode: 0o600
|
|
29
|
-
});
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
function sanitizeTelemetryAttributes(attributes) {
|
|
33
|
-
const sanitized = {};
|
|
34
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
35
|
-
if (ALLOWED_ATTRIBUTE_KEYS.has(key)) {
|
|
36
|
-
sanitized[key] = value;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return sanitized;
|
|
40
|
-
}
|