Lockfile & integrity

ecko get writes three things: the package into vendor/, its source and version into the lockfile ecko.lock, and a hash into ecko.sum.

ecko get github.com/ecko-lang/url

What is pinned

ecko.lock records, per dependency, where it came from and the resolved version. ecko.sum records a SHA-256 over the fetched file tree for each package and version - it is the only place integrity lives. ecko install rebuilds vendor/ from those pins and fails if what it fetches does not match. A dependency cannot change under you without the lockfile changing, and a change to ecko.lock or ecko.sum is a diff in a review.

Commit vendor/

The recommended default, and the reason the design vendors rather than installs: a project with vendor/ committed builds with no network, no registry, and no resolution step, indefinitely. There is no service whose outage stops your build and no version that can be yanked out from under you.

The cost is repository size. For pure-Ecko packages, which is what these are, that cost is small - they are source files.

If you would rather not commit it, commit the lockfile and ecko.sum, then run ecko install. You then depend on the forge being reachable at build time. Without ecko.sum there is nothing to verify the fetched bytes against, and ecko install refuses rather than installing unverified.

Commands

commandeffect
ecko get <path>[@version]Fetch, vendor, pin
ecko installRebuild vendor/ from the lockfile, verifying hashes against ecko.sum
ecko update [name...]Not implemented. Refuses and points at ecko get
ecko remove <name>Unvendor and unpin

update is the only one that would change what a pin means, which is why it is separate from install. There is no dependency graph to re-resolve - a fetched package bundles its own vendor/ - so change one package's version explicitly with ecko get <path>@<version>, which re-fetches and re-pins just that package. The command exists and says so rather than doing something surprising; see Package commands.

Fetch safety

Fetching is where a program first trusts something it did not write, so the defaults are conservative:

  • https only. A plain-http source from a non-loopback host is refused. ECKO_NET_ALLOW_HTTP=1 opts out, and exists for a local registry.
  • Size caps before unpacking: 50 MiB downloaded, 200 MiB unpacked (ECKO_PKG_MAX_BYTES, ECKO_PKG_MAX_UNPACKED). An archive that expands without bound is refused rather than filling the disk.
  • Hash before use. The tree is verified against the pin before anything is imported.
  • Private sources via ECKO_PKG_TOKEN for the bearer token and ECKO_PKG_GIT_BASE to point at a mirror. The token is sent only to the host ECKO_PKG_GIT_BASE names - or github.com when it is unset, or whatever ECKO_PKG_TOKEN_HOSTS lists. A lockfile naming some other host is still fetched, without the credential: the operator chooses who receives it, not a file that arrived by cloning a repository.

What a lockfile does not do

It pins bytes, not behaviour. A package that has permission to reach the network can behave differently on different days regardless of its hash, which is what capabilities are for. Pinning and granting answer different questions, and you want both.