Skip to content

epic: CLI provenance, safe updates, and project state #248

Closed
5 of 5 issues completed
Closed

Description

@Oaklight

Context

zerodep is a code-distribution CLI: modules are copied into a project as
single files. That makes provenance and safe updates the product, not
extras. Today:

  • update / update --all overwrite every file with force=True, yes=True.
    _scan_outdated() marks a file outdated whenever its hash differs from
    upstream, so a local edit is indistinguishable from an upstream change and is
    silently destroyed on the next update.
  • Installs fetch manifest.json and module files from the mutable master
    branch (BRANCH = "master") and never verify the fetched bytes against the
    manifest's content_hash. The same CLI version can install different code on
    different days, and a compromised mirror/CDN cannot be detected.
  • Nothing records what was installed. outdated has to guess by scanning a
    directory; --nested, custom vendor dirs, and renamed files confuse it.
    There is no status, no remove, and no way to tell "locally modified" from
    "upstream updated".

Downstream projects (toolregistry, toolregistry-server, toolregistry-hub)
already vendor modules under [tool.zerodep] vendor-dir and run an automated
zerodep-update.yml that calls outdated --json and update --all. They
inherit every one of these problems.

Workstreams

  • State: record installs in <vendor-dir>/zerodep.lock.json
    (version, upstream hash, installed file hashes, requested vs dependency)
    and add zerodep status.
  • Safe update: three-state comparison (up-to-date / upstream-updated /
    locally-modified), refuse to clobber modified files without --force,
    add --diff and --check.
  • Trust: pin installs to a release ref (v<CLI version> by default for
    installed CLIs) and verify every fetched file against the manifest's
    content_hash.
  • Lifecycle: zerodep remove, --dry-run, JSON output for status.
  • Downstream CI: update the zerodep-update workflows to commit the
    lock and handle skipped (locally modified) modules instead of forcing.
  • Release checks: extend zerodep release-check with the checks that
    only exist as conventions today (stdlib-only imports, declared
    dependencies, bench-* coverage, Makefile wiring) plus --with-lint /
    --with-tests (feat(cli): add --with-lint/--with-tests and repo consistency checks to release-check #258).
  • Release checks in PR CI: run the same command on every PR so those
    rules fail before merge instead of at tag time (ci: run zerodep release-check on every PR #259).

Acceptance criteria

  • A project that edited a vendored file can run zerodep update --all without
    losing the edit; the file is reported and skipped.
  • zerodep status distinguishes up-to-date, upstream-updated,
    locally-modified, missing, and missing-dependency, with --json and
    --exit-code.
  • An installed CLI fetches from the release tag that matches its version by
    default; a file whose bytes do not match the manifest hash aborts the install.
  • zerodep update --diff shows what would change without writing.
  • toolregistry's vendored modules can be inventoried and updated with a lock,
    and its update workflow no longer force-overwrites local patches.

Non-goals

  • A runtime package manager, dependency resolver for third-party packages, or
    importing modules instead of copying them.
  • Replacing [tool.zerodep] vendor-dir; the lock lives inside that directory.

Activity

  1. Oaklight commented on Oct 23, 2026

    @Oaklight
    OwnerAuthor

    Workstream 1 landed in #254 (merge commits 5540a7e, 83532fe): zerodep.lock.json provenance, release pinning + integrity verification, safe add/update, status, and a lock-aware outdated. This closes #249, #250 and #251. Docs and changelog are updated in both worktrees.

    Remaining: #252 (remove/dry-run/search) and #253 (downstream CI). #253 needs a release that includes the new CLI — downstream installs zerodep from PyPI, and the PyPI publisher is still bound to pypi.yml (#247), so publishing from release.yml fails until that is resolved.

  2. Oaklight commented on Oct 23, 2026

    @Oaklight
    OwnerAuthor

    #253 is done (three downstream repos adopted locks and the new update workflow). Remaining from the epic: #252 (remove / dry-run / search). The CLI workstream (#249–#251) shipped in 2026.10.23.1 on PyPI; the release plumbing is now single-publisher (#247) with a verified re-publish path.

  3. Oaklight commented on Oct 23, 2026

    @Oaklight
    OwnerAuthor

    All five workstreams plus the release-check follow-ups are done: #249–#253 and #252/#258/#259 are closed, the CLI shipped in 2026.10.23.1/.2, the three downstream repos carry locks and the new update workflow, and PR CI now runs zerodep release-check. Remaining CLI ideas (if any) belong in new issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions