@nathapp/nax-agent 0.1.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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/coding-tools/coding-tool-bash.d.ts +46 -0
- package/dist/coding-tools/coding-tool-bash.js +44 -0
- package/dist/coding-tools/coding-tool-extras.d.ts +35 -0
- package/dist/coding-tools/coding-tool-extras.js +56 -0
- package/dist/coding-tools/coding-tool-sandbox.d.ts +74 -0
- package/dist/coding-tools/coding-tool-sandbox.js +215 -0
- package/dist/coding-tools/coding-tool-support.d.ts +132 -0
- package/dist/coding-tools/coding-tool-support.js +159 -0
- package/dist/coding-tools/universal-coding-tools.d.ts +11 -0
- package/dist/coding-tools/universal-coding-tools.js +5 -0
- package/dist/command-interceptor/index.d.ts +55 -0
- package/dist/command-interceptor/index.js +60 -0
- package/dist/command-interceptor/shell.d.ts +36 -0
- package/dist/command-interceptor/shell.js +137 -0
- package/dist/command-safety/build.d.ts +19 -0
- package/dist/command-safety/build.js +47 -0
- package/dist/command-safety/guard.d.ts +32 -0
- package/dist/command-safety/guard.js +179 -0
- package/dist/command-safety/identifiers.d.ts +24 -0
- package/dist/command-safety/identifiers.js +20 -0
- package/dist/command-safety/index.d.ts +17 -0
- package/dist/command-safety/index.js +11 -0
- package/dist/command-safety/questions.d.ts +19 -0
- package/dist/command-safety/questions.js +60 -0
- package/dist/command-safety/row.d.ts +2 -0
- package/dist/command-safety/row.js +14 -0
- package/dist/command-safety/rule-scorer.d.ts +9 -0
- package/dist/command-safety/rule-scorer.js +391 -0
- package/dist/command-safety/shadow.d.ts +33 -0
- package/dist/command-safety/shadow.js +188 -0
- package/dist/command-safety/systemone-client.d.ts +16 -0
- package/dist/command-safety/systemone-client.js +92 -0
- package/dist/command-safety/tap.d.ts +37 -0
- package/dist/command-safety/tap.js +77 -0
- package/dist/command-safety/temp-only.d.ts +6 -0
- package/dist/command-safety/temp-only.js +215 -0
- package/dist/command-safety/tmp-write.d.ts +2 -0
- package/dist/command-safety/tmp-write.js +112 -0
- package/dist/command-safety/types.d.ts +185 -0
- package/dist/command-safety/types.js +21 -0
- package/dist/config/bash-approval.d.ts +33 -0
- package/dist/config/bash-approval.js +30 -0
- package/dist/config/catalog-overrides.d.ts +94 -0
- package/dist/config/catalog-overrides.js +7 -0
- package/dist/config/native-agent/index.d.ts +8 -0
- package/dist/config/native-agent/index.js +8 -0
- package/dist/config/schemas-sandbox.d.ts +31 -0
- package/dist/config/schemas-sandbox.js +45 -0
- package/dist/cost/core/index.d.ts +8 -0
- package/dist/cost/core/index.js +7 -0
- package/dist/cost/estimate.d.ts +34 -0
- package/dist/cost/estimate.js +65 -0
- package/dist/cost/model-spec.d.ts +28 -0
- package/dist/cost/model-spec.js +29 -0
- package/dist/cost/standard-types.d.ts +9 -0
- package/dist/cost/standard-types.js +1 -0
- package/dist/cost/usage-math.d.ts +18 -0
- package/dist/cost/usage-math.js +46 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +21 -0
- package/dist/infra/agent-logger.d.ts +22 -0
- package/dist/infra/agent-logger.js +19 -0
- package/dist/infra/credentials-config.d.ts +20 -0
- package/dist/infra/credentials-config.js +15 -0
- package/dist/infra/errors.d.ts +9 -0
- package/dist/infra/errors.js +11 -0
- package/dist/infra/index.d.ts +7 -0
- package/dist/infra/index.js +7 -0
- package/dist/infra/nax-error.d.ts +10 -0
- package/dist/infra/nax-error.js +16 -0
- package/dist/infra/spin-breaker/hash.d.ts +2 -0
- package/dist/infra/spin-breaker/hash.js +5 -0
- package/dist/infra/spin-breaker/index.d.ts +120 -0
- package/dist/infra/spin-breaker/index.js +340 -0
- package/dist/internal/agent-output-env.d.ts +44 -0
- package/dist/internal/agent-output-env.js +57 -0
- package/dist/internal/argv-exec.d.ts +58 -0
- package/dist/internal/argv-exec.js +224 -0
- package/dist/internal/bounded-io.d.ts +24 -0
- package/dist/internal/bounded-io.js +51 -0
- package/dist/internal/command-spec/index.d.ts +29 -0
- package/dist/internal/command-spec/index.js +36 -0
- package/dist/internal/describe-value-type.d.ts +8 -0
- package/dist/internal/describe-value-type.js +14 -0
- package/dist/internal/exec-framing.d.ts +18 -0
- package/dist/internal/exec-framing.js +22 -0
- package/dist/internal/file-lock.d.ts +91 -0
- package/dist/internal/file-lock.js +212 -0
- package/dist/internal/file-size.d.ts +2 -0
- package/dist/internal/file-size.js +12 -0
- package/dist/internal/git-add.d.ts +43 -0
- package/dist/internal/git-add.js +59 -0
- package/dist/internal/git-env.d.ts +59 -0
- package/dist/internal/git-env.js +93 -0
- package/dist/internal/git-exec.d.ts +58 -0
- package/dist/internal/git-exec.js +115 -0
- package/dist/internal/path-file-lock.d.ts +23 -0
- package/dist/internal/path-file-lock.js +25 -0
- package/dist/internal/process-alive.d.ts +42 -0
- package/dist/internal/process-alive.js +56 -0
- package/dist/internal/process-kill.d.ts +27 -0
- package/dist/internal/process-kill.js +54 -0
- package/dist/internal/realpath.d.ts +29 -0
- package/dist/internal/realpath.js +52 -0
- package/dist/internal/redact.d.ts +40 -0
- package/dist/internal/redact.js +161 -0
- package/dist/internal/shell-quote.d.ts +2 -0
- package/dist/internal/shell-quote.js +4 -0
- package/dist/internal/sort.d.ts +20 -0
- package/dist/internal/sort.js +20 -0
- package/dist/internal/strip-control-chars.d.ts +19 -0
- package/dist/internal/strip-control-chars.js +38 -0
- package/dist/internal/thenable.d.ts +10 -0
- package/dist/internal/thenable.js +15 -0
- package/dist/internal.d.ts +91 -0
- package/dist/internal.js +91 -0
- package/dist/native/adapter-deps.d.ts +46 -0
- package/dist/native/adapter-deps.js +43 -0
- package/dist/native/auth-types.d.ts +70 -0
- package/dist/native/auth-types.js +13 -0
- package/dist/native/auth.d.ts +133 -0
- package/dist/native/auth.js +362 -0
- package/dist/native/client.d.ts +50 -0
- package/dist/native/client.js +174 -0
- package/dist/native/complete.d.ts +33 -0
- package/dist/native/complete.js +88 -0
- package/dist/native/credentials/chained-store.d.ts +30 -0
- package/dist/native/credentials/chained-store.js +68 -0
- package/dist/native/credentials/change-guard.d.ts +51 -0
- package/dist/native/credentials/change-guard.js +136 -0
- package/dist/native/credentials/exec-source.d.ts +50 -0
- package/dist/native/credentials/exec-source.js +222 -0
- package/dist/native/credentials/fingerprint.d.ts +26 -0
- package/dist/native/credentials/fingerprint.js +174 -0
- package/dist/native/credentials/helper-process.d.ts +79 -0
- package/dist/native/credentials/helper-process.js +259 -0
- package/dist/native/credentials/helper-protocol.d.ts +36 -0
- package/dist/native/credentials/helper-protocol.js +79 -0
- package/dist/native/credentials/index.d.ts +60 -0
- package/dist/native/credentials/index.js +184 -0
- package/dist/native/errors.d.ts +34 -0
- package/dist/native/errors.js +109 -0
- package/dist/native/index.d.ts +25 -0
- package/dist/native/index.js +23 -0
- package/dist/native/model-resolver.d.ts +57 -0
- package/dist/native/model-resolver.js +73 -0
- package/dist/native/models.d.ts +116 -0
- package/dist/native/models.js +183 -0
- package/dist/native/session/ask-human.d.ts +15 -0
- package/dist/native/session/ask-human.js +22 -0
- package/dist/native/session/compaction.d.ts +94 -0
- package/dist/native/session/compaction.js +170 -0
- package/dist/native/session/handle-invalid-tool-call.d.ts +111 -0
- package/dist/native/session/handle-invalid-tool-call.js +159 -0
- package/dist/native/session/loop-events/cache-boundary.d.ts +11 -0
- package/dist/native/session/loop-events/cache-boundary.js +29 -0
- package/dist/native/session/loop-events/external-handler.d.ts +38 -0
- package/dist/native/session/loop-events/external-handler.js +193 -0
- package/dist/native/session/loop-events/index.d.ts +16 -0
- package/dist/native/session/loop-events/index.js +15 -0
- package/dist/native/session/loop-events/payload-guard.d.ts +9 -0
- package/dist/native/session/loop-events/payload-guard.js +31 -0
- package/dist/native/session/loop-events/registry.d.ts +84 -0
- package/dist/native/session/loop-events/registry.js +305 -0
- package/dist/native/session/loop-events/types.d.ts +251 -0
- package/dist/native/session/loop-events/types.js +14 -0
- package/dist/native/session/loop-handlers.d.ts +73 -0
- package/dist/native/session/loop-handlers.js +137 -0
- package/dist/native/session/nudge.d.ts +29 -0
- package/dist/native/session/nudge.js +35 -0
- package/dist/native/session/rate-provenance.d.ts +17 -0
- package/dist/native/session/rate-provenance.js +39 -0
- package/dist/native/session/session.d.ts +139 -0
- package/dist/native/session/session.js +208 -0
- package/dist/native/session/tool-input-exemplar.d.ts +2 -0
- package/dist/native/session/tool-input-exemplar.js +66 -0
- package/dist/native/session/tool-input-validation.d.ts +15 -0
- package/dist/native/session/tool-input-validation.js +146 -0
- package/dist/native/session/tool-mapping.d.ts +18 -0
- package/dist/native/session/tool-mapping.js +27 -0
- package/dist/native/session/tool-result.d.ts +37 -0
- package/dist/native/session/tool-result.js +25 -0
- package/dist/native/session/transcript-store.d.ts +77 -0
- package/dist/native/session/transcript-store.js +200 -0
- package/dist/native/session/truncation-handler.d.ts +47 -0
- package/dist/native/session/truncation-handler.js +83 -0
- package/dist/native/session/turn-accumulator.d.ts +45 -0
- package/dist/native/session/turn-accumulator.js +67 -0
- package/dist/native/session/turn-ask-human.d.ts +23 -0
- package/dist/native/session/turn-ask-human.js +41 -0
- package/dist/native/session/turn-compaction-step.d.ts +74 -0
- package/dist/native/session/turn-compaction-step.js +128 -0
- package/dist/native/session/turn-complete-step.d.ts +77 -0
- package/dist/native/session/turn-complete-step.js +159 -0
- package/dist/native/session/turn-end-event.d.ts +3 -0
- package/dist/native/session/turn-end-event.js +17 -0
- package/dist/native/session/turn-events.d.ts +63 -0
- package/dist/native/session/turn-events.js +48 -0
- package/dist/native/session/turn-loop-round-trip.d.ts +116 -0
- package/dist/native/session/turn-loop-round-trip.js +318 -0
- package/dist/native/session/turn-loop.d.ts +23 -0
- package/dist/native/session/turn-loop.js +250 -0
- package/dist/native/session/turn-result.d.ts +39 -0
- package/dist/native/session/turn-result.js +64 -0
- package/dist/native/session/turn-retry.d.ts +120 -0
- package/dist/native/session/turn-retry.js +182 -0
- package/dist/native/session/turn-tool-batch.d.ts +61 -0
- package/dist/native/session/turn-tool-batch.js +259 -0
- package/dist/native/session/turn-types.d.ts +164 -0
- package/dist/native/session/turn-types.js +36 -0
- package/dist/native/session-adapter.d.ts +56 -0
- package/dist/native/session-adapter.js +369 -0
- package/dist/native/session-affinity.d.ts +36 -0
- package/dist/native/session-affinity.js +43 -0
- package/dist/native/tier-providers.d.ts +18 -0
- package/dist/native/tier-providers.js +20 -0
- package/dist/permissions/approval-audit.d.ts +10 -0
- package/dist/permissions/approval-audit.js +22 -0
- package/dist/permissions/approvals-link.d.ts +20 -0
- package/dist/permissions/approvals-link.js +62 -0
- package/dist/permissions/approvals-store.d.ts +168 -0
- package/dist/permissions/approvals-store.js +259 -0
- package/dist/permissions/approvals-taint.d.ts +33 -0
- package/dist/permissions/approvals-taint.js +138 -0
- package/dist/permissions/ask-chain.d.ts +69 -0
- package/dist/permissions/ask-chain.js +32 -0
- package/dist/permissions/ask.d.ts +23 -0
- package/dist/permissions/ask.js +25 -0
- package/dist/permissions/bash-lex.d.ts +59 -0
- package/dist/permissions/bash-lex.js +279 -0
- package/dist/permissions/grammar.d.ts +12 -0
- package/dist/permissions/grammar.js +24 -0
- package/dist/permissions/index.d.ts +11 -0
- package/dist/permissions/index.js +9 -0
- package/dist/permissions/secret-spans.d.ts +19 -0
- package/dist/permissions/secret-spans.js +88 -0
- package/dist/permissions/types.d.ts +85 -0
- package/dist/permissions/types.js +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/node-glob.d.ts +3 -0
- package/dist/runtime/node-glob.js +83 -0
- package/dist/runtime/node-runtime.d.ts +3 -0
- package/dist/runtime/node-runtime.js +126 -0
- package/dist/runtime/slot.d.ts +11 -0
- package/dist/runtime/slot.js +17 -0
- package/dist/runtime/types.d.ts +51 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/which.d.ts +8 -0
- package/dist/runtime/which.js +32 -0
- package/dist/sandbox/argv-quote.d.ts +11 -0
- package/dist/sandbox/argv-quote.js +13 -0
- package/dist/sandbox/defaults.d.ts +27 -0
- package/dist/sandbox/defaults.js +47 -0
- package/dist/sandbox/git-guards.d.ts +64 -0
- package/dist/sandbox/git-guards.js +161 -0
- package/dist/sandbox/index.d.ts +11 -0
- package/dist/sandbox/index.js +10 -0
- package/dist/sandbox/launcher.d.ts +37 -0
- package/dist/sandbox/launcher.js +160 -0
- package/dist/sandbox/messages.d.ts +17 -0
- package/dist/sandbox/messages.js +46 -0
- package/dist/sandbox/policy-builder.d.ts +44 -0
- package/dist/sandbox/policy-builder.js +149 -0
- package/dist/sandbox/policy-inputs.d.ts +53 -0
- package/dist/sandbox/policy-inputs.js +76 -0
- package/dist/sandbox/probe.d.ts +8 -0
- package/dist/sandbox/probe.js +66 -0
- package/dist/sandbox/registry.d.ts +17 -0
- package/dist/sandbox/registry.js +57 -0
- package/dist/sandbox/session-tmp.d.ts +20 -0
- package/dist/sandbox/session-tmp.js +95 -0
- package/dist/sandbox/srt-backend.d.ts +21 -0
- package/dist/sandbox/srt-backend.js +99 -0
- package/dist/sandbox/types.d.ts +102 -0
- package/dist/sandbox/types.js +1 -0
- package/dist/session/adapter-failure.d.ts +60 -0
- package/dist/session/adapter-failure.js +11 -0
- package/dist/session/agent-stream-events.d.ts +103 -0
- package/dist/session/agent-stream-events.js +6 -0
- package/dist/session/interaction-handler.d.ts +53 -0
- package/dist/session/interaction-handler.js +2 -0
- package/dist/session/no-op-interaction-handler.d.ts +9 -0
- package/dist/session/no-op-interaction-handler.js +11 -0
- package/dist/session/protocol-types.d.ts +12 -0
- package/dist/session/protocol-types.js +1 -0
- package/dist/session/session-types.d.ts +456 -0
- package/dist/session/session-types.js +64 -0
- package/dist/session/tool-descriptor.d.ts +23 -0
- package/dist/session/tool-descriptor.js +5 -0
- package/dist/session/turn-deadline.d.ts +17 -0
- package/dist/session/turn-deadline.js +23 -0
- package/dist/tools/ask-request.d.ts +35 -0
- package/dist/tools/ask-request.js +57 -0
- package/dist/tools/bash-cwd.d.ts +82 -0
- package/dist/tools/bash-cwd.js +55 -0
- package/dist/tools/bash.d.ts +69 -0
- package/dist/tools/bash.js +283 -0
- package/dist/tools/delete.d.ts +57 -0
- package/dist/tools/delete.js +154 -0
- package/dist/tools/denial-redirect.d.ts +42 -0
- package/dist/tools/denial-redirect.js +266 -0
- package/dist/tools/deny-paths.d.ts +35 -0
- package/dist/tools/deny-paths.js +76 -0
- package/dist/tools/edit-region.d.ts +50 -0
- package/dist/tools/edit-region.js +90 -0
- package/dist/tools/edit.d.ts +25 -0
- package/dist/tools/edit.js +114 -0
- package/dist/tools/exec-allowlist-text.d.ts +18 -0
- package/dist/tools/exec-allowlist-text.js +24 -0
- package/dist/tools/exec-guard.d.ts +69 -0
- package/dist/tools/exec-guard.js +151 -0
- package/dist/tools/git-commit.d.ts +59 -0
- package/dist/tools/git-commit.js +220 -0
- package/dist/tools/git-flags/index.d.ts +10 -0
- package/dist/tools/git-flags/index.js +10 -0
- package/dist/tools/git.d.ts +88 -0
- package/dist/tools/git.js +397 -0
- package/dist/tools/glob.d.ts +29 -0
- package/dist/tools/glob.js +153 -0
- package/dist/tools/grep.d.ts +21 -0
- package/dist/tools/grep.js +162 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.js +28 -0
- package/dist/tools/narrow-grants.d.ts +19 -0
- package/dist/tools/narrow-grants.js +54 -0
- package/dist/tools/nax-owned-writes.d.ts +135 -0
- package/dist/tools/nax-owned-writes.js +259 -0
- package/dist/tools/package-managers-table.d.ts +146 -0
- package/dist/tools/package-managers-table.js +325 -0
- package/dist/tools/package-managers-types.d.ts +36 -0
- package/dist/tools/package-managers-types.js +6 -0
- package/dist/tools/package-managers.d.ts +85 -0
- package/dist/tools/package-managers.js +391 -0
- package/dist/tools/path-list.d.ts +38 -0
- package/dist/tools/path-list.js +62 -0
- package/dist/tools/policy-bash-raw.d.ts +19 -0
- package/dist/tools/policy-bash-raw.js +210 -0
- package/dist/tools/policy-bash.d.ts +64 -0
- package/dist/tools/policy-bash.js +232 -0
- package/dist/tools/policy-command-branch.d.ts +32 -0
- package/dist/tools/policy-command-branch.js +63 -0
- package/dist/tools/policy-input.d.ts +2 -0
- package/dist/tools/policy-input.js +10 -0
- package/dist/tools/policy-match.d.ts +75 -0
- package/dist/tools/policy-match.js +117 -0
- package/dist/tools/policy-paths-branch.d.ts +97 -0
- package/dist/tools/policy-paths-branch.js +314 -0
- package/dist/tools/policy.d.ts +65 -0
- package/dist/tools/policy.js +232 -0
- package/dist/tools/protected-paths.d.ts +26 -0
- package/dist/tools/protected-paths.js +8 -0
- package/dist/tools/provider-adapt.d.ts +4 -0
- package/dist/tools/provider-adapt.js +32 -0
- package/dist/tools/provider-advertise.d.ts +39 -0
- package/dist/tools/provider-advertise.js +50 -0
- package/dist/tools/provider-grants.d.ts +36 -0
- package/dist/tools/provider-grants.js +72 -0
- package/dist/tools/provider-sanitize.d.ts +19 -0
- package/dist/tools/provider-sanitize.js +53 -0
- package/dist/tools/provider-types.d.ts +41 -0
- package/dist/tools/provider-types.js +26 -0
- package/dist/tools/read-continuation.d.ts +147 -0
- package/dist/tools/read-continuation.js +176 -0
- package/dist/tools/read-file.d.ts +32 -0
- package/dist/tools/read-file.js +85 -0
- package/dist/tools/read.d.ts +25 -0
- package/dist/tools/read.js +182 -0
- package/dist/tools/registry.d.ts +125 -0
- package/dist/tools/registry.js +67 -0
- package/dist/tools/request-capability.d.ts +13 -0
- package/dist/tools/request-capability.js +23 -0
- package/dist/tools/run-command-exec.d.ts +14 -0
- package/dist/tools/run-command-exec.js +161 -0
- package/dist/tools/run-command.d.ts +107 -0
- package/dist/tools/run-command.js +398 -0
- package/dist/tools/runtime-calltool.d.ts +146 -0
- package/dist/tools/runtime-calltool.js +223 -0
- package/dist/tools/runtime.d.ts +149 -0
- package/dist/tools/runtime.js +345 -0
- package/dist/tools/scratchpad.d.ts +20 -0
- package/dist/tools/scratchpad.js +197 -0
- package/dist/tools/spill.d.ts +81 -0
- package/dist/tools/spill.js +251 -0
- package/dist/tools/tool-audit.d.ts +171 -0
- package/dist/tools/tool-audit.js +183 -0
- package/dist/tools/truncate.d.ts +98 -0
- package/dist/tools/truncate.js +297 -0
- package/dist/tools/types.d.ts +145 -0
- package/dist/tools/types.js +24 -0
- package/dist/tools/verb-denial-argv-hint.d.ts +35 -0
- package/dist/tools/verb-denial-argv-hint.js +40 -0
- package/dist/tools/write.d.ts +9 -0
- package/dist/tools/write.js +45 -0
- package/package.json +54 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package-manager knowledge table for the install-shaped exec branch.
|
|
3
|
+
*
|
|
4
|
+
* Each entry is DATA — a description of one manager's install verbs (and
|
|
5
|
+
* their aliases), its no-scripts mechanism, how to rewrite argv for a
|
|
6
|
+
* package-scoped versus repo-root-scoped call, and which incoming flags
|
|
7
|
+
* would smuggle in a second workspace member if we spliced our own scoping
|
|
8
|
+
* flag in beside them. No branching policy lives here; `normalizeExec` in
|
|
9
|
+
* `package-managers.ts` is the only place that interprets these fields.
|
|
10
|
+
*
|
|
11
|
+
* Facts this table encodes, verified against each tool's own documentation
|
|
12
|
+
* (see task-4 brief, 2026-09-06) plus two review-driven fix rounds:
|
|
13
|
+
*
|
|
14
|
+
* - Yarn 2+ ("Berry") has no `--ignore-scripts` flag; it honours the
|
|
15
|
+
* `enableScripts` setting, overridable per-invocation via the
|
|
16
|
+
* `YARN_ENABLE_SCRIPTS` environment variable. Yarn 1 ("Classic") takes
|
|
17
|
+
* `--ignore-scripts`. Passing `--ignore-scripts` to Yarn 2+ is a hard
|
|
18
|
+
* error, so version detection that is inconclusive must default to the
|
|
19
|
+
* Yarn 2+ branch — the env var is inert on Yarn 1, the flag is fatal on
|
|
20
|
+
* Yarn 2+, and failing toward the inert option is the safe direction.
|
|
21
|
+
* - pnpm's `--filter` requires the `./` prefix to select by path
|
|
22
|
+
* (`--filter ./packages/foo`); the bare form (`packages/foo`) is parsed as
|
|
23
|
+
* a package NAME and silently selects nothing.
|
|
24
|
+
* - `yarn workspace <name>` and `cargo add -p <name>` take the manifest
|
|
25
|
+
* NAME, not a path.
|
|
26
|
+
*
|
|
27
|
+
* pip and uv no-scripts mechanisms: I could not confirm a mechanism from
|
|
28
|
+
* either tool's own documentation that actually suppresses arbitrary code
|
|
29
|
+
* execution during an install the way `--ignore-scripts` does for npm/bun/
|
|
30
|
+
* yarn-classic:
|
|
31
|
+
*
|
|
32
|
+
* - pip has no `--ignore-scripts` equivalent at all. `--only-binary :all:`
|
|
33
|
+
* forces wheel-only resolution (no sdist, so no `setup.py` executes for
|
|
34
|
+
* any package pip resolves), but it is a resolution-strategy flag, not a
|
|
35
|
+
* scripts switch — it errors the whole install if a required dependency
|
|
36
|
+
* ships no wheel, rather than degrading gracefully. Wiring it in as if it
|
|
37
|
+
* were "the no-scripts flag" would look like protection where none was
|
|
38
|
+
* verified, and I have not confirmed it is safe as a blanket default
|
|
39
|
+
* here. Left as `{ none: true }`.
|
|
40
|
+
* - uv installs prebuilt wheels by default and only builds from source
|
|
41
|
+
* (running a build backend, e.g. `setup.py`/PEP 517 hooks) when a
|
|
42
|
+
* dependency has no wheel for the target platform, same as pip. There is
|
|
43
|
+
* no uv flag documented as suppressing that fallback build step itself —
|
|
44
|
+
* `--no-build-isolation` changes how a source build is isolated, it does
|
|
45
|
+
* not prevent one from happening, so it is not a substitute either. Left
|
|
46
|
+
* as `{ none: true }` per the brief's instruction not to invent a switch.
|
|
47
|
+
*
|
|
48
|
+
* Both gaps mean pip/uv installs get cwd/scoping normalization but no
|
|
49
|
+
* scripts-suppression hardening. This should be tracked as a follow-up
|
|
50
|
+
* rather than silently accepted.
|
|
51
|
+
*
|
|
52
|
+
* Install-verb ALIASES (fix round 1, Critical finding A): each manager's
|
|
53
|
+
* install verb has common short aliases the model can reach for just as
|
|
54
|
+
* easily as the canonical spelling (`npm i` is as ordinary an invocation as
|
|
55
|
+
* `npm install`). They are listed here as additional single-token verb
|
|
56
|
+
* sequences, matched by `classifyExec` exactly like the canonical verb in
|
|
57
|
+
* both its position-anchored match and its fail-closed scan — never as a
|
|
58
|
+
* special case in the matcher itself. Sources: npm's own `install` command
|
|
59
|
+
* aliases (`i`, `in`, `ins`, `inst`, `insta`, `instal`, `install`, `add`) and
|
|
60
|
+
* its `install-test`/`it` alias pair; pnpm's `i`/`install-test` aliases of
|
|
61
|
+
* `install`; bun's `i`/`a` aliases of `install`/`add`. Yarn Classic and
|
|
62
|
+
* Berry do not document a short alias for `install`/`add`, so none is
|
|
63
|
+
* added — checked and confirmed empty, not merely unresearched.
|
|
64
|
+
*
|
|
65
|
+
* Workspace-scoping SMUGGLING (fix round 1, Critical finding 2 + addendum
|
|
66
|
+
* A/C): before this table splices in its own scoping flag or no-scripts
|
|
67
|
+
* flag, `normalizeExec` screens the incoming argv for tokens that would
|
|
68
|
+
* change what gets targeted if left in place — a second `-w`/`--filter`
|
|
69
|
+
* naming another member, or a `--ignore-scripts`/`--no-ignore-scripts` the
|
|
70
|
+
* model added itself. `scopingConflict` is each entry's screen for the
|
|
71
|
+
* first kind; the second kind (`SCRIPTS_CONTROL_FLAG`) is universal and
|
|
72
|
+
* lives in `package-managers.ts` since it isn't manager-specific data. Both
|
|
73
|
+
* DENY rather than strip: dropping a flag the model wrote changes the
|
|
74
|
+
* request while reporting success, which is worse than a visible refusal.
|
|
75
|
+
* Coverage: npm `-w`/`--workspace`/`--workspaces`/`--workspace-root`/
|
|
76
|
+
* `--include-workspace-root`; pnpm `--filter`/`-f`/`-w`/`--workspace-root`/
|
|
77
|
+
* `--filter-prod`/`--include-workspace-root`; cargo `-p`/`--package`; uv
|
|
78
|
+
* `--package`/`--all-packages`. Yarn's `workspace`/`workspaces` leading
|
|
79
|
+
* subcommand is not screened here — see the comment on yarn's
|
|
80
|
+
* `scopingConflict` for why that path is already unreachable by
|
|
81
|
+
* construction.
|
|
82
|
+
*
|
|
83
|
+
* Directory-redirect CONTAINMENT (fix round 2): `target` is a closed enum
|
|
84
|
+
* precisely so no path can arrive from the model — `normalizeExec` computes
|
|
85
|
+
* cwd, the model never supplies one. A directory-redirect flag inside argv
|
|
86
|
+
* (`bun add --cwd /elsewhere x`) hands that choice straight back, ignoring
|
|
87
|
+
* whatever cwd this table computed. This is the containment property
|
|
88
|
+
* itself, not a scoping nicety, so it is screened for EVERY manager entry
|
|
89
|
+
* via `globalDirectoryFlags`/`installDirectoryFlags`, denied on the same
|
|
90
|
+
* deny-never-strip basis as scoping/scripts-control flags.
|
|
91
|
+
*
|
|
92
|
+
* A flag global to the manager (works with any subcommand, not just an
|
|
93
|
+
* install verb) is screened for BOTH install-shaped and generic calls —
|
|
94
|
+
* `normalizeExec` checks it before branching on classification kind at all,
|
|
95
|
+
* because a generic call (`bun x tsc --cwd /elsewhere`) escapes the same
|
|
96
|
+
* containment otherwise. An install-specific flag is screened only when the
|
|
97
|
+
* call is already install-shaped, since it has no effect (or no meaning) on
|
|
98
|
+
* a generic invocation of that manager.
|
|
99
|
+
*
|
|
100
|
+
* | manager | global (`globalDirectoryFlags`) | install-only (`installDirectoryFlags`) |
|
|
101
|
+
* |---|---|---|
|
|
102
|
+
* | bun | `--cwd` | — |
|
|
103
|
+
* | yarn | `--cwd`, `-C` (fix round 3 — `-C` is added for symmetry with pnpm; not confirmed as a documented yarn alias, but an over-denial here is the safe direction) | — |
|
|
104
|
+
* | pnpm | `--dir`, `-C` | — |
|
|
105
|
+
* | npm | — | — (`--prefix` changes npm's effective directory; already denied by `DENIED_FLAGS` in `exec-guard.ts` regardless of manager — not duplicated here) |
|
|
106
|
+
* | cargo | `--manifest-path` (accepted by nearly every cargo subcommand, `add`/`fetch` included) | — |
|
|
107
|
+
* | pip | `--python` (a general pip option, valid before or after the subcommand, that redirects which interpreter/environment gets installed into) | `--target`, `-t` (documented short alias, fix round 3), `--root` (install-destination overrides, meaningful only for `pip install`; `--prefix` is likewise install-scoped but already covered by the same shared `DENIED_FLAGS` entry as npm's, so also not duplicated) |
|
|
108
|
+
* | uv | `--directory`, `--project` (both are documented as general uv options, accepted ahead of the subcommand, that change what "the project" means for the whole invocation) | — |
|
|
109
|
+
* | go | `-C` (a general go flag: "change to dir before running the command") | — |
|
|
110
|
+
*
|
|
111
|
+
* `uv pip <anything>` (fix round 3, finding 3) is denied at classification
|
|
112
|
+
* time, not treated as a directory-redirect flag gap — see the comment on
|
|
113
|
+
* `isNestedPipInvocation` in `package-managers.ts` for why nesting one
|
|
114
|
+
* manager's semantics inside another's entry was rejected in favor of a
|
|
115
|
+
* flat denial.
|
|
116
|
+
*/
|
|
117
|
+
import { normalizeFlagToken } from "./exec-guard.js";
|
|
118
|
+
const IGNORE_SCRIPTS_FLAG = { flag: "--ignore-scripts" };
|
|
119
|
+
const NO_MECHANISM = { none: true };
|
|
120
|
+
/** Shared by every `packageForm` that needs the member's manifest NAME (yarn, cargo, uv).
|
|
121
|
+
* `normalizeExec` already denies before calling `packageForm` when
|
|
122
|
+
* `entry.needsPackageName` is true and `input.packageName` is undefined —
|
|
123
|
+
* this exists so each `packageForm` can narrow `ctx.packageName` from
|
|
124
|
+
* `string | undefined` to `string` without a postfix `!` (banned in this
|
|
125
|
+
* repo), and as a second, independent guard rather than only a comment. */
|
|
126
|
+
function packageNameOrError(ctx, manager) {
|
|
127
|
+
if (ctx.packageName === undefined) {
|
|
128
|
+
return { error: `${manager} workspace scoping requires the member package's manifest name` };
|
|
129
|
+
}
|
|
130
|
+
return { name: ctx.packageName };
|
|
131
|
+
}
|
|
132
|
+
/** A token anywhere in argv (after the binary) that case/`=`-normalizes to one of `flags`. */
|
|
133
|
+
function flagConflict(argv, flags) {
|
|
134
|
+
const lowered = new Set(flags.map((flag) => normalizeFlagToken(flag)));
|
|
135
|
+
for (let i = 1; i < argv.length; i++) {
|
|
136
|
+
const token = argv[i];
|
|
137
|
+
const normalized = normalizeFlagToken(token);
|
|
138
|
+
if (lowered.has(normalized))
|
|
139
|
+
return token;
|
|
140
|
+
for (const flag of lowered) {
|
|
141
|
+
if (flag.length === 2 && normalized.startsWith(flag) && normalized.length > flag.length)
|
|
142
|
+
return token;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
export const MANAGER_TABLE = {
|
|
148
|
+
bun: {
|
|
149
|
+
installVerbs: [["install"], ["i"], ["add"], ["a"]],
|
|
150
|
+
noScripts: () => IGNORE_SCRIPTS_FLAG,
|
|
151
|
+
needsPackageName: false,
|
|
152
|
+
// bun has no workspace-scoping flag in this table's model — nothing to smuggle.
|
|
153
|
+
scopingConflict: () => undefined,
|
|
154
|
+
// `--cwd` is global to bun (any subcommand), so it must be screened
|
|
155
|
+
// regardless of classification — see the file header table.
|
|
156
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--cwd"]),
|
|
157
|
+
installDirectoryConflict: () => undefined,
|
|
158
|
+
// bun resolves the workspace member purely from cwd — no scoping flag needed.
|
|
159
|
+
packageForm: (argv, ctx) => ({ argv, cwd: ctx.packageWorkdir }),
|
|
160
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
161
|
+
},
|
|
162
|
+
npm: {
|
|
163
|
+
installVerbs: [
|
|
164
|
+
["install"],
|
|
165
|
+
["i"],
|
|
166
|
+
["in"],
|
|
167
|
+
["ins"],
|
|
168
|
+
["inst"],
|
|
169
|
+
["insta"],
|
|
170
|
+
["instal"],
|
|
171
|
+
["install-test"],
|
|
172
|
+
["it"],
|
|
173
|
+
["add"],
|
|
174
|
+
["ci"],
|
|
175
|
+
],
|
|
176
|
+
noScripts: () => IGNORE_SCRIPTS_FLAG,
|
|
177
|
+
needsPackageName: false,
|
|
178
|
+
scopingConflict: (argv) => flagConflict(argv, ["-w", "--workspace", "--workspaces", "--workspace-root", "--include-workspace-root"]),
|
|
179
|
+
// npm's directory-redirect flag is `--prefix`, already denied by the
|
|
180
|
+
// shared, manager-agnostic `DENIED_FLAGS` in `exec-guard.ts` — not
|
|
181
|
+
// duplicated here (see the file header table).
|
|
182
|
+
globalDirectoryConflict: () => undefined,
|
|
183
|
+
installDirectoryConflict: () => undefined,
|
|
184
|
+
// `npm -w <relPath> <verb> ...` runs from the repo root; `-w` accepts a
|
|
185
|
+
// relative path.
|
|
186
|
+
packageForm: (argv, ctx) => ({
|
|
187
|
+
argv: [argv[0], "-w", ctx.packageRelPath, ...argv.slice(1)],
|
|
188
|
+
cwd: ctx.repoRoot,
|
|
189
|
+
}),
|
|
190
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
191
|
+
},
|
|
192
|
+
pnpm: {
|
|
193
|
+
installVerbs: [["install"], ["i"], ["install-test"], ["add"]],
|
|
194
|
+
noScripts: () => IGNORE_SCRIPTS_FLAG,
|
|
195
|
+
needsPackageName: false,
|
|
196
|
+
scopingConflict: (argv) => flagConflict(argv, ["--filter", "-f", "-w", "--workspace-root", "--filter-prod", "--include-workspace-root"]),
|
|
197
|
+
// `--dir`/`-C` are global to pnpm (any subcommand) — screened
|
|
198
|
+
// regardless of classification.
|
|
199
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--dir", "-C"]),
|
|
200
|
+
installDirectoryConflict: () => undefined,
|
|
201
|
+
// The `./` prefix is mandatory: pnpm parses a bare "packages/foo" as a
|
|
202
|
+
// package NAME, which silently selects nothing.
|
|
203
|
+
packageForm: (argv, ctx) => ({
|
|
204
|
+
argv: [argv[0], "--filter", `./${ctx.packageRelPath}`, ...argv.slice(1)],
|
|
205
|
+
cwd: ctx.repoRoot,
|
|
206
|
+
}),
|
|
207
|
+
// `pnpm add -w ...` targets the workspace root package explicitly.
|
|
208
|
+
rootForm: (argv, ctx) => ({
|
|
209
|
+
argv: [argv[0], argv[1], "-w", ...argv.slice(2)],
|
|
210
|
+
cwd: ctx.repoRoot,
|
|
211
|
+
}),
|
|
212
|
+
},
|
|
213
|
+
yarn: {
|
|
214
|
+
installVerbs: [["install"], ["add"]],
|
|
215
|
+
noScripts: (ctx) => (ctx.yarnMajor === 1 ? IGNORE_SCRIPTS_FLAG : { env: { YARN_ENABLE_SCRIPTS: "false" } }),
|
|
216
|
+
needsPackageName: true,
|
|
217
|
+
// `yarn workspace <name> ...`/`yarn workspaces ...` as a LEADING
|
|
218
|
+
// subcommand would be the smuggling vector here, but it is already
|
|
219
|
+
// unreachable: `classifyExec`'s position-anchored match only ever
|
|
220
|
+
// classifies a call as install-shaped when the very first non-flag
|
|
221
|
+
// token IS an install verb. A leading "workspace"/"workspaces" token
|
|
222
|
+
// fails that match, and the real verb further along the argv is then
|
|
223
|
+
// caught by the fail-closed scan instead (denied, not silently made
|
|
224
|
+
// generic) before this function is ever reached. No independent screen
|
|
225
|
+
// is needed on top of that.
|
|
226
|
+
scopingConflict: () => undefined,
|
|
227
|
+
// `--cwd` is global to yarn (any subcommand) — screened regardless of
|
|
228
|
+
// classification. `-C` is added for symmetry with pnpm's entry (fix
|
|
229
|
+
// round 3, finding 2) — yarn's own docs do not document a `-C` short
|
|
230
|
+
// alias, so this is an over-denial rather than a confirmed fact; that
|
|
231
|
+
// is the safe direction here, so it stays.
|
|
232
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--cwd", "-C"]),
|
|
233
|
+
installDirectoryConflict: () => undefined,
|
|
234
|
+
// `yarn workspace <name> ...` takes the manifest NAME, not a path.
|
|
235
|
+
packageForm: (argv, ctx) => {
|
|
236
|
+
const resolved = packageNameOrError(ctx, "yarn");
|
|
237
|
+
if ("error" in resolved)
|
|
238
|
+
return resolved;
|
|
239
|
+
return { argv: [argv[0], "workspace", resolved.name, ...argv.slice(1)], cwd: ctx.repoRoot };
|
|
240
|
+
},
|
|
241
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
242
|
+
},
|
|
243
|
+
pip: {
|
|
244
|
+
installVerbs: [["install"]],
|
|
245
|
+
// See file header: no confirmed ignore-scripts equivalent for pip.
|
|
246
|
+
noScripts: () => NO_MECHANISM,
|
|
247
|
+
needsPackageName: false,
|
|
248
|
+
// pip has no workspace concept in this table's model — nothing to smuggle.
|
|
249
|
+
scopingConflict: () => undefined,
|
|
250
|
+
// `--python` is a general pip option (valid before or after the
|
|
251
|
+
// subcommand) that redirects which interpreter/environment gets
|
|
252
|
+
// installed into — screened regardless of classification. `--prefix`
|
|
253
|
+
// would be the other general redirect, but it is already covered by
|
|
254
|
+
// the same shared `DENIED_FLAGS` entry as npm's, so not duplicated.
|
|
255
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--python"]),
|
|
256
|
+
// `--target`/`--root` only mean anything for `pip install`. `-t` is
|
|
257
|
+
// pip's own documented short alias for `--target` (fix round 3,
|
|
258
|
+
// finding 1) — checked pip's docs for a short alias of `--root` and
|
|
259
|
+
// `--python` too; neither documents one, so only `-t` is added here.
|
|
260
|
+
installDirectoryConflict: (argv) => flagConflict(argv, ["--target", "-t", "--root"]),
|
|
261
|
+
packageForm: (argv, ctx) => ({ argv, cwd: ctx.packageWorkdir }),
|
|
262
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
263
|
+
},
|
|
264
|
+
uv: {
|
|
265
|
+
installVerbs: [["sync"], ["add"]],
|
|
266
|
+
// See file header: no confirmed ignore-scripts equivalent for uv.
|
|
267
|
+
noScripts: () => NO_MECHANISM,
|
|
268
|
+
needsPackageName: true,
|
|
269
|
+
scopingConflict: (argv) => flagConflict(argv, ["--package", "--all-packages"]),
|
|
270
|
+
// `--directory`/`--project` are general uv options (accepted ahead of
|
|
271
|
+
// the subcommand) that change what "the project" means for the whole
|
|
272
|
+
// invocation — screened regardless of classification.
|
|
273
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--directory", "--project"]),
|
|
274
|
+
installDirectoryConflict: () => undefined,
|
|
275
|
+
// `uv <verb> --package <name> ...` restricts the operation to one
|
|
276
|
+
// workspace member; runs from the repo root.
|
|
277
|
+
packageForm: (argv, ctx) => {
|
|
278
|
+
const resolved = packageNameOrError(ctx, "uv");
|
|
279
|
+
if ("error" in resolved)
|
|
280
|
+
return resolved;
|
|
281
|
+
return {
|
|
282
|
+
argv: [argv[0], argv[1], "--package", resolved.name, ...argv.slice(2)],
|
|
283
|
+
cwd: ctx.repoRoot,
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
287
|
+
},
|
|
288
|
+
go: {
|
|
289
|
+
installVerbs: [["get"], ["mod", "download"]],
|
|
290
|
+
// Downloads only; runs nothing.
|
|
291
|
+
noScripts: () => NO_MECHANISM,
|
|
292
|
+
needsPackageName: false,
|
|
293
|
+
// go has no workspace-scoping flag in this table's model — nothing to smuggle.
|
|
294
|
+
scopingConflict: () => undefined,
|
|
295
|
+
// `-C dir` is a general go flag ("change to dir before running the
|
|
296
|
+
// command") — screened regardless of classification.
|
|
297
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["-C"]),
|
|
298
|
+
installDirectoryConflict: () => undefined,
|
|
299
|
+
packageForm: (argv, ctx) => ({ argv, cwd: ctx.packageWorkdir }),
|
|
300
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
301
|
+
},
|
|
302
|
+
cargo: {
|
|
303
|
+
installVerbs: [["add"], ["fetch"]],
|
|
304
|
+
// `cargo add` edits a manifest, `cargo fetch` downloads; neither runs a
|
|
305
|
+
// build script during the command itself.
|
|
306
|
+
noScripts: () => NO_MECHANISM,
|
|
307
|
+
needsPackageName: true,
|
|
308
|
+
scopingConflict: (argv) => flagConflict(argv, ["-p", "--package"]),
|
|
309
|
+
// `--manifest-path` is accepted by nearly every cargo subcommand,
|
|
310
|
+
// `add`/`fetch` included — screened regardless of classification.
|
|
311
|
+
globalDirectoryConflict: (argv) => flagConflict(argv, ["--manifest-path"]),
|
|
312
|
+
installDirectoryConflict: () => undefined,
|
|
313
|
+
// `cargo add -p <name> ...` takes the manifest NAME, not a path.
|
|
314
|
+
packageForm: (argv, ctx) => {
|
|
315
|
+
const resolved = packageNameOrError(ctx, "cargo");
|
|
316
|
+
if ("error" in resolved)
|
|
317
|
+
return resolved;
|
|
318
|
+
return {
|
|
319
|
+
argv: [argv[0], argv[1], "-p", resolved.name, ...argv.slice(2)],
|
|
320
|
+
cwd: ctx.repoRoot,
|
|
321
|
+
};
|
|
322
|
+
},
|
|
323
|
+
rootForm: (argv, ctx) => ({ argv, cwd: ctx.repoRoot }),
|
|
324
|
+
},
|
|
325
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types between `package-managers.ts` (the public surface) and
|
|
3
|
+
* `package-managers-table.ts` (the per-manager data). Split out so the table
|
|
4
|
+
* does not need to import the module that imports it.
|
|
5
|
+
*/
|
|
6
|
+
export type ExecTarget = "package" | "repoRoot";
|
|
7
|
+
/**
|
|
8
|
+
* The subset of `NormalizeInput` a manager entry's functions need, minus the
|
|
9
|
+
* argv/target already threaded explicitly through the call.
|
|
10
|
+
*/
|
|
11
|
+
export interface WorkspaceContext {
|
|
12
|
+
readonly repoRoot: string;
|
|
13
|
+
readonly packageWorkdir: string;
|
|
14
|
+
readonly packageRelPath: string;
|
|
15
|
+
readonly packageName?: string;
|
|
16
|
+
readonly allowScripts: boolean;
|
|
17
|
+
/** Yarn major version, when known. Undefined means "inconclusive" — the
|
|
18
|
+
* Yarn entry's `noScripts` must default to the Yarn 2+ (env-var) branch,
|
|
19
|
+
* since the flag branch is a hard error on Yarn 2+ and the env var is
|
|
20
|
+
* merely inert on Yarn 1. */
|
|
21
|
+
readonly yarnMajor?: number;
|
|
22
|
+
}
|
|
23
|
+
export type NoScripts = {
|
|
24
|
+
readonly flag: string;
|
|
25
|
+
} | {
|
|
26
|
+
readonly env: Readonly<Record<string, string>>;
|
|
27
|
+
} | {
|
|
28
|
+
readonly none: true;
|
|
29
|
+
};
|
|
30
|
+
export type NormalizeResult = {
|
|
31
|
+
readonly argv: readonly string[];
|
|
32
|
+
readonly cwd: string;
|
|
33
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
34
|
+
} | {
|
|
35
|
+
readonly error: string;
|
|
36
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classification and normalization for the install-shaped exec branch.
|
|
3
|
+
*
|
|
4
|
+
* A call is install-shaped only when `argv[0]` is a known manager AND the
|
|
5
|
+
* verb is one of that manager's install verbs; such calls are hardened (a
|
|
6
|
+
* no-scripts mechanism, when one is known) and normalized (scoped to the
|
|
7
|
+
* story's own workspace member) by `normalizeExec`. Everything else is
|
|
8
|
+
* generic: it runs exactly as given, at the target cwd, with no rewriting
|
|
9
|
+
* and no mechanism — reachable only through an explicit `Exec(...)` grant
|
|
10
|
+
* elsewhere in the policy.
|
|
11
|
+
*
|
|
12
|
+
* Both directions matter. Without the generic class, something like
|
|
13
|
+
* `bun x tsc --noEmit` could never be permitted by any grant. Without the
|
|
14
|
+
* "known manager plus install verb" test, a loosely classified `bun add`
|
|
15
|
+
* could reach the generic path and skip its no-scripts mechanism entirely.
|
|
16
|
+
* Neither class may borrow the other's treatment — this module is pure
|
|
17
|
+
* classification/data lookup, no spawning, no policy, no I/O.
|
|
18
|
+
*
|
|
19
|
+
* Classification is FAIL-CLOSED (fix round 1, Critical finding 1). A global
|
|
20
|
+
* flag ahead of the verb (`npm --loglevel=silent install x`) must not push
|
|
21
|
+
* a real install onto the unhardened generic path, but a flag's own VALUE
|
|
22
|
+
* token must not be mistaken for the verb either. Three branches, in order:
|
|
23
|
+
*
|
|
24
|
+
* 1. Find the first token after argv[0] that does not start with "-". If
|
|
25
|
+
* it (or the token sequence starting there, for multi-token verbs
|
|
26
|
+
* like `go mod download`) matches one of this manager's install verbs
|
|
27
|
+
* (aliases included), the call is install-shaped.
|
|
28
|
+
* 2. Otherwise, if ANY token anywhere in argv equals one of this
|
|
29
|
+
* manager's install verb tokens, DENY, naming the token. This is the
|
|
30
|
+
* fail-closed branch: `npm --loglevel silent install x` has "silent"
|
|
31
|
+
* as its first non-flag token (branch 1 misses, because a flag's
|
|
32
|
+
* value is not the verb), so the "install" token later in argv trips
|
|
33
|
+
* this branch instead. That is deliberate — a visible refusal the
|
|
34
|
+
* model can retry without the global flag beats a silent unhardened
|
|
35
|
+
* install. Do not "improve" this into a fall-through to generic.
|
|
36
|
+
* 3. Otherwise the call is generic.
|
|
37
|
+
*
|
|
38
|
+
* A manager invocation can also be DISGUISED rather than merely flag-led
|
|
39
|
+
* (addendum finding B): `npx`/`bunx`/`pnpx` run an arbitrary package outside
|
|
40
|
+
* this table's model entirely, and `pnpm dlx npm install x` / `yarn dlx bun
|
|
41
|
+
* add x` launder a real manager invocation through a dlx-style verb. Both
|
|
42
|
+
* shapes are denied before verb classification even runs — there is no
|
|
43
|
+
* argv shape here this table can normalize safely, so neither may fall
|
|
44
|
+
* through to generic. `argv[0]` is also case- and executable-suffix-
|
|
45
|
+
* normalized (`NPM`, `npm.cmd`, `npm.exe` all resolve to the `npm` entry)
|
|
46
|
+
* before every manager lookup; the path-separator form (`./npm`) is already
|
|
47
|
+
* refused upstream by `validateArgv` in `exec-guard.ts` and is not
|
|
48
|
+
* duplicated here.
|
|
49
|
+
*
|
|
50
|
+
* A directory-redirect flag (`--cwd`, `--dir`, `--manifest-path`, ...) is
|
|
51
|
+
* denied on the same basis (fix round 2): `target` is a closed enum
|
|
52
|
+
* precisely so no path can arrive from the model, and a flag like this
|
|
53
|
+
* hands that choice straight back. Manager-global redirect flags are
|
|
54
|
+
* screened for install-shaped AND generic calls alike — see
|
|
55
|
+
* `package-managers-table.ts`'s file header for the full per-manager table
|
|
56
|
+
* of which flags are global versus install-only.
|
|
57
|
+
*
|
|
58
|
+
* `uv pip <anything>` is also denied at classification time (fix round 3,
|
|
59
|
+
* finding 3) — see `isNestedPipInvocation` for why nesting is rejected in
|
|
60
|
+
* favor of a flat denial.
|
|
61
|
+
*
|
|
62
|
+
* None of the fix-round-3 gaps (pip's `-t` alias, yarn's `-C`, `uv pip`
|
|
63
|
+
* nesting) is reachable under the built-in default allowlist, which is
|
|
64
|
+
* install-only and contains neither `uv pip *`, a bare `pip install`, nor
|
|
65
|
+
* a yarn form with `-C`. They become reachable only when a project writes
|
|
66
|
+
* a widening `Exec(...)` grant by hand — defense-in-depth, not a live hole
|
|
67
|
+
* under the shipped default.
|
|
68
|
+
*/
|
|
69
|
+
import type { NormalizeResult, WorkspaceContext } from "./package-managers-types.ts";
|
|
70
|
+
export type { ExecTarget, NormalizeResult } from "./package-managers-types.ts";
|
|
71
|
+
import type { ExecTarget } from "./package-managers-types.ts";
|
|
72
|
+
export interface NormalizeInput extends WorkspaceContext {
|
|
73
|
+
readonly argv: readonly string[];
|
|
74
|
+
readonly target: ExecTarget;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Lowercases and strips a trailing executable suffix so `NPM`, `npm.cmd`
|
|
78
|
+
* and `npm.exe` all resolve to the same `MANAGER_TABLE` entry as `npm`.
|
|
79
|
+
* Path-separator forms (`./npm`, `..\npm.exe`) are refused upstream by
|
|
80
|
+
* `validateArgv` in `exec-guard.ts` and are not re-checked here.
|
|
81
|
+
*/
|
|
82
|
+
export declare function normalizeManagerBinary(token: string): string;
|
|
83
|
+
export declare function isKnownManager(binary: string): boolean;
|
|
84
|
+
export declare function classifyExec(argv: readonly string[]): "install" | "generic" | "deny";
|
|
85
|
+
export declare function normalizeExec(input: NormalizeInput): NormalizeResult;
|