DOC_INDEX
THEME
DOCS/Modules/Lockfile & Supply Chain

Lockfile & Supply Chain

How orchstep.lock pins modules to an immutable commit and content hash for reproducible, tamper-evident builds

Git tags are mutable - @company/deploy/v1.2.0 can be force-moved to different bytes tomorrow. Every ecosystem that ships executable units solves this with a lockfile (go.sum, package-lock.json, .terraform.lock.hcl, Cargo.lock). OrchStep's is orchstep.lock.

What gets pinned

When OrchStep resolves a remote module, it records three things in orchstep.lock:

modules:
    deploy:
        source: "@company/deploy"
        version: 1.2.0                                   # resolved semver
        tag: deploy/v1.2.0                               # the git tag matched
        commit: 8af4687c67c62d834860013a1004232509cd17ce # immutable commit SHA
        hash: sha256:b50fe37b6526eb19283ecab0d59d96af... # content hash of the module
  • commit binds the module to an exact commit, not a movable tag.
  • hash is a sha256 over the module's files (excluding .git), so even a re-pointed commit or a tampered cache is detected.

How it behaves

  • First resolve writes the lock. Run a workflow with an unlocked remote module and OrchStep resolves the newest version your constraint allows, then writes orchstep.lock next to your orchstep.yml. Commit this file.

  • Later runs are pinned and verified. With a lock present, OrchStep fetches the pinned commit (ignoring the tag entirely) and recomputes the content hash. A mismatch - the tag was force-moved, or the cache was tampered with - fails the run:

    module 'deploy' failed integrity check: orchstep.lock expects sha256:b50f...
    but resolved content is sha256:1c9d... (the tag may have been force-moved or
    the cache tampered; run 'orchstep module update' if this change is intended)

Local-path modules (./mod, ../shared) are never locked - there's nothing remote to pin.

Commands

CommandWhat it does
orchstep module lockWrite orchstep.lock for the workflow's modules. Keeps versions already pinned; fills in any missing ones.
orchstep module update [name...]Re-resolve modules to the newest version their constraint allows and re-pin commit + hash. Bumps everything, or just the named modules.
orchstep module verifyRe-fetch every locked module at its pinned commit, recompute the hash, and exit non-zero on any drift.

In CI

Treat orchstep.lock like any other lockfile: commit it, and gate builds with module verify so a moved tag or tampered module fails the pipeline instead of silently changing what runs.

steps:
  - uses: orchstep/setup-orchstep@v1
  - run: orchstep module verify        # fails the build on supply-chain drift
  - run: orchstep run deploy

To forbid implicit lock writes in automation entirely, set ORCHSTEP_LOCK_AUTOWRITE=false - resolves then require an up-to-date committed lock instead of writing one.

Updating a module on purpose

orchstep module update deploy   # bump 'deploy' to newest allowed, re-pin
git add orchstep.lock           # review the commit/hash change in the diff

Because the change shows up as a commit + hash diff in orchstep.lock, a reviewer can see exactly which bytes changed - the property a platform/security team asks for.