tap: attesto 0.5.0 + attesto-local-vault 2.0.1
Mirrored from attesto-v1 ops/get-host/homebrew/ (commit f21339ce); hashes from the KMS-signed channel manifests on get.attesto.eu. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,178 @@
|
|||||||
|
# Attesto Local Vault — container-wrapper formula.
|
||||||
|
#
|
||||||
|
# The Local Vault ships ONLY as a container image, pinned by digest. This
|
||||||
|
# formula does not install a native vault; it installs a small POSIX-sh
|
||||||
|
# wrapper that runs every CLI subcommand inside that image via Docker.
|
||||||
|
#
|
||||||
|
# PROVENANCE OF THE sha256 VALUE: the url below is the signed installer copy
|
||||||
|
# from the versioned channel, and its hash is copied verbatim from the SIGNED
|
||||||
|
# manifest https://get.attesto.eu/local-vault/2.0.1/SHA256SUMS after
|
||||||
|
# verifying its cosign signature:
|
||||||
|
#
|
||||||
|
# curl -fsSLO https://get.attesto.eu/cosign.pub
|
||||||
|
# curl -fsSLO https://get.attesto.eu/local-vault/2.0.1/SHA256SUMS
|
||||||
|
# curl -fsSLO https://get.attesto.eu/local-vault/2.0.1/SHA256SUMS.sig
|
||||||
|
# cosign verify-blob --key cosign.pub --insecure-ignore-tlog \
|
||||||
|
# --signature SHA256SUMS.sig SHA256SUMS
|
||||||
|
#
|
||||||
|
# (--insecure-ignore-tlog: KMS release key, no Rekor entry — the project's
|
||||||
|
# documented verification flow.)
|
||||||
|
#
|
||||||
|
# SYNC CONTRACT: the wrapper heredoc below must stay behaviorally identical
|
||||||
|
# (same docker argv) to the wrapper embedded in the channel installer
|
||||||
|
# (ops/get-host/local-vault/install.sh in the main repo, served as
|
||||||
|
# https://get.attesto.eu/local-vault/install.sh). The check
|
||||||
|
# tests/wrapper_sync_check.sh in the tap source tree runs both against a
|
||||||
|
# stub docker and diffs the argv; it extracts the heredoc textually, so keep
|
||||||
|
# the <<~'WRAPPER' markers and the 6-space body indentation.
|
||||||
|
class AttestoLocalVault < Formula
|
||||||
|
desc "Container wrapper for the Attesto Local Vault (digest-pinned image)"
|
||||||
|
homepage "https://attesto.eu"
|
||||||
|
url "https://get.attesto.eu/local-vault/2.0.1/install.sh"
|
||||||
|
sha256 "35770b22886f04a7021d6b854d21f1208092fa02eca5d9c8762218ced4861ae5"
|
||||||
|
license "Apache-2.0"
|
||||||
|
|
||||||
|
def install
|
||||||
|
# The staged download is the signed channel installer. It is kept for
|
||||||
|
# reference/out-of-band verification only — never executed; the wrapper
|
||||||
|
# written below is the Homebrew-native equivalent of the wrapper that
|
||||||
|
# installer would write.
|
||||||
|
pkgshare.install "install.sh"
|
||||||
|
|
||||||
|
(bin/"attesto-local-vault").write wrapper_script
|
||||||
|
chmod 0755, bin/"attesto-local-vault"
|
||||||
|
end
|
||||||
|
|
||||||
|
def caveats
|
||||||
|
<<~EOS
|
||||||
|
attesto-local-vault is a container wrapper: it needs a working Docker
|
||||||
|
engine at runtime (Docker Desktop on macOS, Docker Engine on Linux).
|
||||||
|
Homebrew does not and cannot install Docker for you.
|
||||||
|
|
||||||
|
Honesty note for macOS: the Local Vault and its Linux-only provider
|
||||||
|
sandbox run inside Docker Desktop's Linux VM. Attesto's isolation
|
||||||
|
claims apply within that VM — a native macOS process would not carry
|
||||||
|
them, which is exactly why this install is a container wrapper and
|
||||||
|
never claims native isolation.
|
||||||
|
|
||||||
|
The first run pulls the digest-pinned image and prepares the state and
|
||||||
|
config directories under
|
||||||
|
${XDG_DATA_HOME:-~/.local/share}/attesto-local-vault
|
||||||
|
(override the root with ATTESTO_LOCAL_VAULT_HOME). The state directory
|
||||||
|
holds the vault's keys, spool, and provenance capsules — deleting it
|
||||||
|
destroys evidence that may exist nowhere else.
|
||||||
|
|
||||||
|
Get started (mint a single-use enrollment token in the console):
|
||||||
|
attesto-local-vault init --base-url https://verify.attesto.eu --enrollment-token lvet_...
|
||||||
|
attesto-local-vault doctor
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
|
test do
|
||||||
|
# The wrapper must at least parse.
|
||||||
|
system "sh", "-n", bin/"attesto-local-vault"
|
||||||
|
|
||||||
|
# Run it against a stub docker and inspect the argv it produces: the
|
||||||
|
# digest-pinned image, the state/config mounts, and our arguments must
|
||||||
|
# all be there.
|
||||||
|
(testpath/"stub").mkpath
|
||||||
|
(testpath/"stub/docker").write <<~STUB
|
||||||
|
#!/bin/sh
|
||||||
|
printf '%s\\n' "$@" >> "#{testpath}/docker-argv.log"
|
||||||
|
exit 0
|
||||||
|
STUB
|
||||||
|
chmod 0755, testpath/"stub/docker"
|
||||||
|
ENV.prepend_path "PATH", testpath/"stub"
|
||||||
|
ENV["ATTESTO_LOCAL_VAULT_HOME"] = (testpath/"vault-home").to_s
|
||||||
|
|
||||||
|
system bin/"attesto-local-vault", "--help"
|
||||||
|
|
||||||
|
log = (testpath/"docker-argv.log").read
|
||||||
|
assert_match "git.attesto.eu/attesto/local-vault@sha256:" \
|
||||||
|
"5799e7f0669c9b42a55a338f4233cfa5afb5aa6a2627c2c50f7545a41bff1551", log
|
||||||
|
assert_match "--help", log
|
||||||
|
assert_match "/var/lib/attesto", log
|
||||||
|
assert_match "/etc/attesto/local-vault", log
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Kept in sync with the wrapper written by install.sh — see the SYNC
|
||||||
|
# CONTRACT comment at the top of this file. The single-quoted chown script
|
||||||
|
# inside the bootstrap block must stay byte-identical to install.sh's
|
||||||
|
# (including its 4-space continuation line): it is a single docker argv
|
||||||
|
# element and the sync check compares argv exactly.
|
||||||
|
def wrapper_script
|
||||||
|
<<~'WRAPPER'
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
# attesto-local-vault — container wrapper installed by Homebrew
|
||||||
|
# (attesto/attesto tap). Every argument is passed to the CLI inside the
|
||||||
|
# image; stdin/stdout and the exit code pass through.
|
||||||
|
# ATTESTO_LOCAL_VAULT_IMAGE overrides the image for one invocation; all
|
||||||
|
# other ATTESTO_LOCAL_VAULT_* environment variables are forwarded into
|
||||||
|
# the container. Kept behaviorally identical (same docker argv) to the
|
||||||
|
# wrapper written by https://get.attesto.eu/local-vault/install.sh.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
IMAGE="${ATTESTO_LOCAL_VAULT_IMAGE:-git.attesto.eu/attesto/local-vault@sha256:5799e7f0669c9b42a55a338f4233cfa5afb5aa6a2627c2c50f7545a41bff1551}"
|
||||||
|
ROOT_DIR="${ATTESTO_LOCAL_VAULT_HOME:-${XDG_DATA_HOME:-$HOME/.local/share}/attesto-local-vault}"
|
||||||
|
STATE_DIR="$ROOT_DIR/data" # mounted at /var/lib/attesto
|
||||||
|
CONFIG_DIR="$ROOT_DIR/config" # mounted at /etc/attesto/local-vault
|
||||||
|
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "attesto-local-vault: docker is required but was not found on PATH." >&2
|
||||||
|
echo "Install Docker Desktop (macOS) or Docker Engine (Linux) and retry." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# First run: create the state+config dirs and hand them to the image's
|
||||||
|
# unprivileged user, exactly as the channel installer does at install
|
||||||
|
# time. On Docker Desktop (macOS) the chown is a harmless no-op. The
|
||||||
|
# quoted -c script must stay byte-identical to install.sh's.
|
||||||
|
if [ ! -d "$STATE_DIR" ] || [ ! -d "$CONFIG_DIR" ]; then
|
||||||
|
mkdir -p "$STATE_DIR" "$CONFIG_DIR"
|
||||||
|
docker run --rm --user root --entrypoint /bin/sh \
|
||||||
|
-v "$STATE_DIR:/var/lib/attesto" \
|
||||||
|
-v "$CONFIG_DIR:/etc/attesto/local-vault" \
|
||||||
|
"$IMAGE" -c 'chown attesto:attesto-provider /var/lib/attesto /etc/attesto/local-vault \
|
||||||
|
&& install -d -o attesto -g attesto-provider -m 2770 /var/lib/attesto/provider-work /var/lib/attesto/run'
|
||||||
|
fi
|
||||||
|
|
||||||
|
tty_flags=""
|
||||||
|
if [ -t 0 ] && [ -t 1 ]; then tty_flags="-t"; fi
|
||||||
|
|
||||||
|
# Forward ATTESTO_LOCAL_VAULT_* env vars (after the wrapper defaults, so an
|
||||||
|
# explicit host value wins). The wrapper's own image knob stays on the host,
|
||||||
|
# and the container config dir is always the mounted path.
|
||||||
|
env_flags=""
|
||||||
|
for name in $(env | sed -n 's/^\(ATTESTO_LOCAL_VAULT_[A-Za-z0-9_]*\)=.*/\1/p'); do
|
||||||
|
case "$name" in
|
||||||
|
ATTESTO_LOCAL_VAULT_IMAGE|ATTESTO_LOCAL_VAULT_CONFIG_DIR) continue ;;
|
||||||
|
esac
|
||||||
|
env_flags="$env_flags -e $name"
|
||||||
|
done
|
||||||
|
|
||||||
|
run() {
|
||||||
|
# shellcheck disable=SC2086 # tty_flags/env_flags are token-safe
|
||||||
|
exec docker run --rm -i $tty_flags \
|
||||||
|
-v "$STATE_DIR:/var/lib/attesto" \
|
||||||
|
-v "$CONFIG_DIR:/etc/attesto/local-vault" \
|
||||||
|
-e ATTESTO_LOCAL_VAULT_CONFIG_DIR=/etc/attesto/local-vault \
|
||||||
|
-e ATTESTO_LOCAL_VAULT_SPOOL_DB=/var/lib/attesto/spool.sqlite3 \
|
||||||
|
-e ATTESTO_LOCAL_VAULT_FINALIZED_QUEUE_DB=/var/lib/attesto/finalized-evidence.sqlite3 \
|
||||||
|
-e ATTESTO_LOCAL_VAULT_CAPSULE_STORE_DB=/var/lib/attesto/provenance-capsules.sqlite3 \
|
||||||
|
-e ATTESTO_LOCAL_VAULT_WITNESS_DB=/var/lib/attesto/witness.sqlite3 \
|
||||||
|
$env_flags \
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mount the caller's working directory so file arguments (attestation
|
||||||
|
# files, JSON payloads) resolve transparently. Skipped for / and for
|
||||||
|
# paths a -v flag cannot express.
|
||||||
|
case "$PWD" in
|
||||||
|
/|*:*) run "$IMAGE" "$@" ;;
|
||||||
|
*) run -v "$PWD:/workdir" -w /workdir "$IMAGE" "$@" ;;
|
||||||
|
esac
|
||||||
|
WRAPPER
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Attesto CLI — offline verifier for Attesto evidence.
|
||||||
|
#
|
||||||
|
# PROVENANCE OF THE sha256 VALUES: every hash below is copied verbatim from
|
||||||
|
# the SIGNED channel manifest https://get.attesto.eu/0.5.0/SHA256SUMS after
|
||||||
|
# verifying its cosign signature:
|
||||||
|
#
|
||||||
|
# curl -fsSLO https://get.attesto.eu/cosign.pub
|
||||||
|
# curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS
|
||||||
|
# curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS.sig
|
||||||
|
# cosign verify-blob --key cosign.pub --insecure-ignore-tlog \
|
||||||
|
# --signature SHA256SUMS.sig SHA256SUMS
|
||||||
|
#
|
||||||
|
# (--insecure-ignore-tlog: the release key is a KMS key and signatures are
|
||||||
|
# not uploaded to Rekor; this matches the project's documented verification
|
||||||
|
# flow.) Do not replace these hashes with locally computed ones.
|
||||||
|
class Attesto < Formula
|
||||||
|
desc "Offline verifier CLI for Attesto evidence (receipts, bundles, anchors)"
|
||||||
|
homepage "https://attesto.eu"
|
||||||
|
version "0.5.0"
|
||||||
|
license "Apache-2.0"
|
||||||
|
|
||||||
|
# KNOWN AUDIT WAIVER: `brew audit --strict` reports "Use `url :stable`" for
|
||||||
|
# the livecheck url below. That is a false positive in the
|
||||||
|
# FormulaAudit/LivecheckUrlSymbol cop: with every stable `url` inside
|
||||||
|
# on_macos/on_linux blocks, the cop takes the FIRST `url` call in the class
|
||||||
|
# body as the stable URL — which is this livecheck url itself, so it always
|
||||||
|
# self-matches, whatever string it holds. Following the suggestion would be
|
||||||
|
# wrong (livecheck would scan a binary download instead of the version
|
||||||
|
# feed), and moving `livecheck` after the on_* blocks trips ComponentsOrder
|
||||||
|
# instead. Canonical order is kept; the finding is waived.
|
||||||
|
livecheck do
|
||||||
|
url "https://get.attesto.eu/latest-version.txt"
|
||||||
|
regex(/^v?(\d+(?:\.\d+)+)$/i)
|
||||||
|
end
|
||||||
|
|
||||||
|
on_macos do
|
||||||
|
on_arm do
|
||||||
|
url "https://get.attesto.eu/0.5.0/attesto_0.5.0_darwin_arm64"
|
||||||
|
sha256 "8fd7a0044d5d042cd63f7972d80c78a099f5880050933a718bcdae9429e76815"
|
||||||
|
end
|
||||||
|
on_intel do
|
||||||
|
url "https://get.attesto.eu/0.5.0/attesto_0.5.0_darwin_amd64"
|
||||||
|
sha256 "ddc4d82ac9ecf8c85abee0f6300e305288d590f5b76723445ca76137a6d17dbf"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_linux do
|
||||||
|
on_arm do
|
||||||
|
url "https://get.attesto.eu/0.5.0/attesto_0.5.0_linux_arm64"
|
||||||
|
sha256 "bce90fd4714e61fc2b95813b6935cceadf8b5346764c5ab4c3c968aab511d5c6"
|
||||||
|
end
|
||||||
|
on_intel do
|
||||||
|
url "https://get.attesto.eu/0.5.0/attesto_0.5.0_linux_amd64"
|
||||||
|
sha256 "65ec45c16096556eea86604ba61a15f5934874e5f92dc24de194657609e45bc8"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def install
|
||||||
|
os = OS.mac? ? "darwin" : "linux"
|
||||||
|
arch = Hardware::CPU.arm? ? "arm64" : "amd64"
|
||||||
|
bin.install "attesto_#{version}_#{os}_#{arch}" => "attesto"
|
||||||
|
chmod 0755, bin/"attesto"
|
||||||
|
end
|
||||||
|
|
||||||
|
test do
|
||||||
|
assert_match version.to_s, shell_output("#{bin}/attesto version")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# attesto/attesto — Homebrew tap
|
||||||
|
|
||||||
|
Homebrew tap for [Attesto](https://attesto.eu): the `attesto` verifier CLI and
|
||||||
|
the `attesto-local-vault` container wrapper. Artifacts are served from the
|
||||||
|
signed download host [get.attesto.eu](https://get.attesto.eu).
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew tap attesto/attesto https://git.rotz.ai/attesto/homebrew-attesto.git
|
||||||
|
brew install attesto # the CLI (offline verifier)
|
||||||
|
brew install attesto-local-vault # the Local Vault container wrapper
|
||||||
|
```
|
||||||
|
|
||||||
|
## What is signed, and how to verify independently
|
||||||
|
|
||||||
|
Every release channel on get.attesto.eu carries a `SHA256SUMS` manifest and a
|
||||||
|
cosign signature over it (`SHA256SUMS.sig`). The `sha256` stanzas in the
|
||||||
|
formulas of this tap are copied verbatim from those **signed** manifests —
|
||||||
|
never computed locally. Homebrew then enforces the same hashes on every
|
||||||
|
install.
|
||||||
|
|
||||||
|
You do not have to trust this tap. Verify the manifests yourself:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -fsSLO https://get.attesto.eu/cosign.pub
|
||||||
|
|
||||||
|
# CLI channel
|
||||||
|
curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS
|
||||||
|
curl -fsSLO https://get.attesto.eu/0.5.0/SHA256SUMS.sig
|
||||||
|
cosign verify-blob --key cosign.pub --insecure-ignore-tlog \
|
||||||
|
--signature SHA256SUMS.sig SHA256SUMS
|
||||||
|
|
||||||
|
# Local Vault channel
|
||||||
|
curl -fsSLO https://get.attesto.eu/local-vault/2.0.1/SHA256SUMS
|
||||||
|
curl -fsSLO https://get.attesto.eu/local-vault/2.0.1/SHA256SUMS.sig
|
||||||
|
cosign verify-blob --key cosign.pub --insecure-ignore-tlog \
|
||||||
|
--signature SHA256SUMS.sig SHA256SUMS
|
||||||
|
```
|
||||||
|
|
||||||
|
then compare the listed hashes with the `sha256` values in `Formula/*.rb`.
|
||||||
|
(`--insecure-ignore-tlog` is required because the release key is a KMS key
|
||||||
|
and signatures are not uploaded to the Rekor transparency log.)
|
||||||
|
|
||||||
|
The Local Vault container image itself is referenced **by digest**, not by a
|
||||||
|
tag, so the wrapper can only ever run the exact image
|
||||||
|
`git.attesto.eu/attesto/local-vault@sha256:5799e7f0669c9b42a55a338f4233cfa5afb5aa6a2627c2c50f7545a41bff1551`.
|
||||||
|
|
||||||
|
## macOS honesty note
|
||||||
|
|
||||||
|
`attesto-local-vault` requires Docker (Docker Desktop on macOS) at runtime —
|
||||||
|
Homebrew does not install it for you. On macOS the vault and its Linux-only
|
||||||
|
provider sandbox run **inside Docker Desktop's Linux VM**. Attesto's
|
||||||
|
isolation claims apply within that VM; a native macOS process would not carry
|
||||||
|
them, which is exactly why the macOS install is a container wrapper and never
|
||||||
|
claims native isolation.
|
||||||
|
|
||||||
|
## Where this tap comes from
|
||||||
|
|
||||||
|
The contents of this repository are mirrored from `ops/get-host/homebrew/` in
|
||||||
|
the main Attesto repository — that directory is the source of truth; changes
|
||||||
|
land there first and are synced here at publish time (`sync_tap.sh`). The
|
||||||
|
behavioral parity between the brew wrapper and the `install.sh` wrapper is
|
||||||
|
enforced there by `tests/wrapper_sync_check.sh`.
|
||||||
Reference in New Issue
Block a user