Skip to content
VediramVediramSupport

Packages

Allow only approved Python (pip) and JavaScript (npm) packages into the sandbox, from your own registry

Preview. This capability is not included in current Levee releases. This page describes how it works so you can plan for it; contact Vediram to join the preview.

When the agent writes a script in Python or JavaScript, it often needs add-on libraries called packages, downloaded with the pip or npm command. The package gate lets you decide which packages may be installed: some are allowed, some are refused, and some ask the user first. Packages come from your organization's own package server (or the public one), and every decision is recorded in the audit trail.

Why do packages need their own control?

Packages are code written by third parties, and a package manager is the easiest way for unwanted code to enter the sandbox. A misspelled package name, a compromised publisher account, or a document that tells the agent to "install this helpful tool" all end the same way.

Blocking the public package sites in web access stops installs outright. The package gate lets you say yes to some packages and no to the rest, and enforces that answer.

How does it work?

The agent runs ordinary install commands, and Levee answers them with only the packages you approved. Package installs pass through two layers:

LayerControlEffect
Web accessPublic registries (registry.npmjs.org, pypi.org, files.pythonhosted.org) stay denied in web-access policy.The agent cannot go around the gate by calling the registry directly.
Package gateEach package request is identified (manager, name, scope or namespace, version) and checked against your package rules.Only approved packages are served.

Inside the sandbox, npm and pip are pointed at the Levee package gate automatically. The agent runs ordinary commands (pip install requests, npm install lodash) and does not need to know the gate exists. The gate fetches approved packages from your registry, so the real registry address and its credentials never appear inside the sandbox.

Supported package managers:

ManagerWhat is served
npmPackage metadata and .tgz tarballs, scoped (@company/pkg) and unscoped packages. Works with npm, and with clients that use the npm registry protocol.
pipThe PEP 503 simple index and .whl, .tar.gz, .tar.bz2 and .zip distributions.

The gate is retrieval only. Publishing (npm publish, twine upload) is always refused, whatever the policy says.

Bring your own registry

The gate fetches approved packages from one package server (registry) per package manager. This is typically your organization's mirror or proxy repository:

  • JFrog Artifactory (npm and PyPI remote or virtual repositories)
  • Sonatype Nexus Repository
  • Pulp, or any registry that speaks the npm registry or PEP 503 protocol
  • The public registries themselves, if you do not run a mirror

Using your own registry means packages are still subject to the scanning, quarantine and license rules you already apply there. Levee adds the per-project, per-package decision and the audit trail on top.

Policy reference: proxies.pkg

One entry per package manager, each with its registry, a default decision and an ordered list of rules.

{
  "proxies": {
    "pkg": {
      "approvalPersistence": "session",
      "managers": {
        "npm": {
          "registry": "https://artifactory.contoso.com/api/npm/npm-virtual/",
          "default": "deny",
          "rules": [
            { "scope": "@contoso", "action": "allow" },
            { "package": "lodash", "version": "^4.17.0", "action": "allow" },
            { "package": "express", "version": ">=4.18.0 <5.0.0", "action": "allow" },
            { "package": "event-stream", "action": "deny" },
            { "package": "*", "action": "prompt" }
          ]
        },
        "pip": {
          "registry": "https://artifactory.contoso.com/api/pypi/pypi-virtual/",
          "default": "deny",
          "rules": [
            { "namespace": "contoso-*", "action": "allow" },
            { "package": "requests", "version": ">=2.28.0", "action": "allow" },
            { "package": "*", "action": "prompt" }
          ]
        }
      }
    }
  }
}

Top-level keys

KeyDefaultMeaning
approvalPersistencesessionWhat happens when a user approves a prompt: session remembers it until the project stops; policy writes it back into policy as a rule pinned to the exact version approved, which an admin can relax later.
managersnoneOne entry per package manager: npm, pip. A manager with no entry is refused entirely.

Manager keys

KeyDefaultMeaning
registryrequiredThe root URL of the upstream registry. For pip, give the repository root, not the simple/ index URL: a registry that ends in simple/ makes every package appear to be missing.
defaultdenyWhat to do when no rule matches: allow, deny or prompt.
rules[]Evaluated top to bottom; the first matching rule wins.

Unknown keys in a manager section are rejected, so a typo cannot silently weaken the policy.

Registry credentials are never written in policy. See Registry credentials.

Rule keys

Each rule has one matcher and an action:

KeyManagerMatches
packagenpm, pipThe exact package name, or * for any package.
scopenpmEvery package in an npm scope, for example @contoso.
namespacepipEvery package whose name starts with a prefix. Only a trailing * is supported: contoso-*.
versionnpm, pipOptional version constraint. npm uses semver ranges (^4.17.0, >=4.18.0 <5.0.0); pip uses PEP 440 specifiers (>=2.28.0, ==1.4.2, ~=3.1). Omit to match any version.
actionnpm, pipallow, deny or prompt.

About versions:

  • When the package manager only asks for metadata (before it has chosen a version), rules match on the name alone. The version constraint is enforced when the actual package file is downloaded.
  • If a rule has a version constraint and the requested version cannot be parsed, the rule does not match.
  • For pip, epochs (1!2.0), post-releases (.post1), development releases (.dev1) and local versions (+local) are not matched by version constraints. Use a name-only rule, or pin with == to a plain release, for packages that publish such versions.

Prompts

A prompt action holds the download and asks the user in the Levee app. The prompt shows the package manager, the package name, the scope or namespace, and the version when known. If the user approves, the download continues; if the user declines or does not answer in time, it is refused. See Approvals.

Registry credentials

The registry's credential is stored encrypted on each computer, never in policy, and never reaches the sandbox. If your registry requires authentication, store the credential on the machine with the Levee CLI from an elevated PowerShell prompt. The secret is read from a hidden prompt (or standard input), never from the command line, so it does not appear in process-creation logs:

# Basic authentication (username + password or API key)
levee upstream-auth set --manager npm --scheme basic --username svc-levee

# Bearer token
levee upstream-auth set --manager pip --scheme bearer

# List configured managers (secrets are never shown)
levee upstream-auth list

# Remove
levee upstream-auth clear --manager npm

The credential is stored encrypted on the machine in a location standard users cannot read, and is only ever sent to the configured registry host. It is never exposed inside the sandbox. If a stored credential is unusable, requests are refused rather than retried anonymously.

What does the agent see when a package is refused?

A "package not found" answer, whatever the reason. Every negative outcome returns the same response:

HTTP 404
{"error":"not_found"}

That covers a policy denial, a declined prompt, an unknown package manager, a package that does not exist upstream, and an upstream failure. To the package manager it looks like the package does not exist, so npm reports E404 and pip reports that no matching distribution was found. The agent cannot tell a denied package from a missing one; the reason is in the audit trail.

If a transfer fails after the download has already started, the connection is reset and the package manager reports a network error.

Things to know about your registry

Your registry must serve package files itself, respond quickly, and do its own caching. In detail:

  • Redirects must stay on the registry. The gate follows up to five redirects, and only while they stay under the registry base URL. Registries that redirect package downloads to a separate CDN or storage host appear as 404. Configure your repository to serve content directly (for example, disable redirect-to-storage for the repository used by Levee).
  • Timeouts. The upstream must start responding within 30 seconds, and must not stall for more than 30 seconds during a transfer.
  • No caching. The gate does not cache packages; your registry does that.

Audit

EventRecorded when
package.allowedA package was approved and served. The package is not served unless this record is stored.
package.deniedA package was refused. The detail explains why (for example no-policy-for-manager, method-not-allowed, upstream-unreachable, invalid-upstream-auth).
package.stream_interruptedAn approved download was interrupted (client-aborted, idle-read-timeout, transport-error).
package.prompted / package.prompt_approved / package.prompt_deniedA prompt was shown and answered.
package.rule_persistedAn approval was written back to policy (approvalPersistence: "policy").

package.denied with detail decision-aborted-by-client is benign: it usually means the user pressed Ctrl+C during an install. Exclude it from denial-rate alerts.

Credentials and package contents are never written to logs.