Skip to content

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 07:06
· 115 commits to main since this release
1cb4a76

Track T Phase 1: for PyPI and npm, MCP answers now carry checks on whether a dependency can be trusted, so an AI coding agent sees them before it adds or changes one.

  • Registry digests: locked digests are compared with what the registry publishes.
  • PyPI provenance: attestations are verified with the new optional [provenance] extra.
  • Lookalike names: names that resemble popular packages are flagged as indicators.
  • Added dependencies: a file check against an earlier copy checks only what was added or changed, and openpulse trust does the same from the CLI.
  • Untrusted text: text from files and upstreams never reaches an agent unvalidated.

Every check uses the closed T-F1 status vocabulary and is never part of a verdict. Verdicts, contracts and the frozen evaluation are unchanged. No upgrade steps are needed. The new trust, provenance, lookalike and digest_integrity fields are additive.

Added

  • Trust checks on added dependencies (track T, v0.12.0 item U5). check_dependency_file takes an earlier copy of the file as base_path; the PyPI and npm dependencies added or changed since then get registry existence, provenance (PyPI) and lookalike indicators in a new trust block. It holds counts per check and status, and lists every CONFIRMED_MALICIOUS, VERIFIED_FAILURE or SUSPICIOUS_INCONCLUSIVE record under attention.

    • trust_all checks every dependency instead. With neither, trust is null and nothing extra is fetched.
    • Budget: trust checks run before the file-wide lookups, so the additions get the session budget first. The live checks are capped at 40 packages per file (the W4 bound), and the rest are counted as capped. Lookalike is local data, so every package gets it.
    • MCP: base_path is confined to the project root like path.
    • CLI: openpulse trust FILE [--base EARLIER] [--offline] [--json] prints the same block. It is report-only and never exits non-zero.
    • Never part of a verdict (tested). PyPI spelling variants (Zope_Interface, zope.interface) are the same dependency, not an addition.
    • Not yet: the GitHub Action on pull requests. It needs the base file from git, and gating on trust statuses is T-E1 (track T Phase 4).
  • Lookalike-name indicators in dependency_status (track T, T-A2, v0.12.0 item U4). A PyPI or npm name is compared with the curated catalog and a pinned popular-name list. Every rule that fires is named, with the reference it matched:

    • separator: equal once -, _ and . are removed;
    • edit_distance: within 1 edit, or 2 for names of 10+ characters, where a swap counts as one;
    • confusable: equal under the UTS #39 skeleton restricted to ASCII;
    • scope: npm @x/name where name is a reference.
    • Outcomes: SUSPICIOUS_INCONCLUSIVE is an indicator, never a typosquat verdict. A reference name is VERIFIED_RELATIONSHIP. Nothing firing is MISSING_EVIDENCE, not evidence of authenticity. Local data only: no network, no budget, never part of a verdict.
    • Reference data (owner-approved sources), each built and pinned by the new scripts/refresh_reference_names.py and listed in the new NOTICE:
      • npm-high-impact 1.13.0 (MIT, 17,335 names), checked against npm's sha512 integrity and read as text, never executed;
      • the ASCII mappings of UTS #39 confusables.txt 18.0.0 (Unicode License v3), pinned by sha256.
    • PyPI's popular list: a dated BigQuery query over the CC BY 4.0 download dataset, printed by the tool for a maintainer with a Google Cloud account to run. Until then, PyPI names are compared with the curated catalog only, and answers show the empty list.
  • PyPI provenance in dependency_status (track T, T-B1, v0.12.0 item U3). For a PyPI package with a version, the new provenance field verifies the release's PEP 740 attestations from PyPI's Integrity API, for up to 4 files (wheels first), each against the file's sha256. Verification uses pypi-attestations (Sigstore), never cryptography of our own.

    • Repository cross-check: for curated packages, the attestation's publisher is compared with the catalog's GitHub repository; a different repository is VERIFIED_FAILURE (starjacking).
    • Other outcomes: an attestation that doesn't verify is VERIFIED_FAILURE. No published provenance is MISSING_EVIDENCE, never a failure, because most packages publish none. VERIFIED_RELATIONSHIP says where and how the files were built, never that they are benign (Ultralytics' first malicious releases carried valid provenance).
    • Untrusted text: publisher fields and file names are validated before they appear or reach a URL.
    • New optional extra [provenance] (owner-approved, Phase 0 decision 5), Python 3.11+: pypi-attestations and its ~24 dependencies, hash-locked in the new requirements-provenance.lock, which scripts/compile_locks.py generates, constrained to the core, mcp and audit-tool pins. Without the extra, the field is NOT_PERFORMED with how to enable it. A new CI provenance job installs it from the lock, checks drift, audits it and runs its tests.
    • Lock checker fixes: scripts/check_lock.py now reads the provenance lock and parses >= floors that carry an environment marker.
    • Unchanged: verdicts.
  • Digest integrity for lockfiles (track T, T-B4, v0.12.0 item U2). check_dependency_file (MCP) compares each digest a package-lock.json (integrity) or poetry.lock (files[].hash) pins with what npm (dist.integrity, or dist.shasum for old sha1 locks) or PyPI (urls[].digests.sha256) publishes for that version. A locked digest the registry doesn't publish is VERIFIED_FAILURE, listed under digest_integrity.failures: the locked artifact is not the one the registry serves (substituted, re-uploaded or tampered).

    • Other outcomes: no usable locked digest is MISSING_EVIDENCE, and no usable registry answer is NOT_PERFORMED, never a failure.
    • Safety: lockfile digests are validated before use, and names before any URL. Each check spends one lookup from the session budget, under the 40-per-file cap.
    • Reader output unchanged: core.lockfile_reader.lockfile_digests reads the digests separately, so the dependency entries the verdict engine, contracts and ledger use are untouched.
    • Unchanged: verdicts. No new dependency; hashing only.

Security

  • Reader skip messages never carry file text to an agent (track T, T-F3, v0.12.0 item U1). check_dependency_file (MCP) passed the readers' skip messages through as written. Those messages quote the file's own lines, and the agent writes the files it asks about. A quoted value is now shown only when it has a requirement shape (requests>=2.31.0, junit:junit, ^4.2: no whitespace, no Markdown link). Any other value becomes <not shown>, and messages are stripped of control, bidi and zero-width characters and capped at 240 characters. The CLI keeps the full messages for humans, stripped of control and bidi characters.