From 141ae2c2fd7f444b44afb6df1c8f6d0039592e64 Mon Sep 17 00:00:00 2001 From: cvince Date: Sun, 7 Jun 2026 17:58:17 -0700 Subject: [PATCH 1/3] feat(capy): add capy secrets-manager package Installs the Capy CLI (@capysc/cli@0.6.1) into a Minimal environment and pinholes the developer's ~/.capy session into the box, so in-box `capy run -- ` injects branch-scoped secrets without transporting any key material (shared-session model). - build.ncl: @capysc/cli install, runtime deps (node-lts, git, ca-certificates, coreutils, glibc, base), node_modules output, and a ~/.capy Credential pinhole (read-write; trusted dev shells only). - build.sh: npm global install into the output prefix. - self-test: capy --version runs in a clean room and matches the pin. Verified: minimal package capy + minimal check capy pass; capy runs in a box. --- packages/capy/build.ncl | 60 +++++++++++++++++++++++++++++++++++++++++ packages/capy/build.sh | 16 +++++++++++ 2 files changed, 76 insertions(+) create mode 100644 packages/capy/build.ncl create mode 100755 packages/capy/build.sh diff --git a/packages/capy/build.ncl b/packages/capy/build.ncl new file mode 100644 index 0000000..77b21af --- /dev/null +++ b/packages/capy/build.ncl @@ -0,0 +1,60 @@ +let { Attrs, BuildSpec, Local, OutputBin, OutputData, Test, .. } = import "minimal.ncl" in +let base = import "../base/build.ncl" in +let coreutils = import "../coreutils/build.ncl" in +let glibc = import "../glibc/build.ncl" in +let ca-certificates = import "../ca-certificates/build.ncl" in +let git = import "../git/build.ncl" in +let node-lts = import "../node-lts/build.ncl" in + +let version = "0.6.1" in +{ + name = "capy", + build_deps = [ + { file = "build.sh" } | Local, + node-lts, # node + npm to install the package + ], + runtime_deps = [ + base, + glibc, + coreutils, # `capy` shebang resolves node via /usr/bin/env + ca-certificates, # HTTPS to the Capy API (sync / co-decrypt) + git, # capy shells out to git for repo/branch detection + node-lts, # capy is a Node CLI (#!/usr/bin/env node) + ], + + cmd = "./build.sh", + build_args = { + include version, + }, + + # npm fetches @capysc/cli + its deps from the registry during the build. + # Follow-up: vendor the tarball + transitive deps as hash-pinned Sources for a + # fully hermetic / SLSA build. + needs = { dns = {}, internet = {} }, + + outputs = { + capy = { glob = "usr/bin/capy" } | OutputBin, + node_modules = { glob = "usr/lib/node_modules/**" } | OutputData, + }, + attrs = + { + upstream_version = version, + # 1a shared-session model: pinhole the host ~/.capy into the box so in-box + # capy reuses the developer's existing login (no key transport). rw because + # capy refreshes its session and writes caches. Exposes the full host + # session to the box: trusted dev shells only, never untrusted agent tasks. + env_dir_mappings = [{ read_only = false, path = "~/.capy", class = 'Credential }], + } | Attrs, + + tests = { + runs = + { + class = 'Standalone, + test_deps = [base, node-lts], + cmds = [ + # capy must run and report its version with no auth/network/config. + ["/bin/bash", "-c", "capy --version | grep -q '%{version}'"], + ], + } | Test, + }, +} | BuildSpec diff --git a/packages/capy/build.sh b/packages/capy/build.sh new file mode 100755 index 0000000..8f9d625 --- /dev/null +++ b/packages/capy/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +# Install @capysc/cli (the `capy` CLI) into the package output prefix. +# Outputs are harvested from $OUTPUT_DIR (see build.ncl `outputs`). +PREFIX="$OUTPUT_DIR/usr" +mkdir -p "$PREFIX" + +# Keep npm's cache inside the build sandbox (no writable $HOME). +export npm_config_cache="$(pwd)/.npm-cache" + +npm install \ + --global \ + --prefix "$PREFIX" \ + --no-audit --no-fund \ + "@capysc/cli@${MINIMAL_ARG_VERSION}" From e4d361063fb450af3eae45381975e1004ff71da9 Mon Sep 17 00:00:00 2001 From: cvince Date: Sun, 7 Jun 2026 18:22:20 -0700 Subject: [PATCH 2/3] review: drop hand-rolled npm cache, rely on toolchain env_state_wiring The previous `export npm_config_cache="$(pwd)/.npm-cache"` was redundant and non-deterministic: node/node-lts already wire NPM_CONFIG_CACHE to a Minimal- managed state dir via env_state_wiring. Simplify build.sh to match the other npm-CLI packages (pyright, typescript-language-server, mermaid-cli). Verified: minimal package capy + minimal check capy still pass (incl. self-test). --- packages/capy/build.sh | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/capy/build.sh b/packages/capy/build.sh index 8f9d625..ac2d134 100755 --- a/packages/capy/build.sh +++ b/packages/capy/build.sh @@ -1,16 +1,4 @@ #!/bin/sh -set -e +set -ex -# Install @capysc/cli (the `capy` CLI) into the package output prefix. -# Outputs are harvested from $OUTPUT_DIR (see build.ncl `outputs`). -PREFIX="$OUTPUT_DIR/usr" -mkdir -p "$PREFIX" - -# Keep npm's cache inside the build sandbox (no writable $HOME). -export npm_config_cache="$(pwd)/.npm-cache" - -npm install \ - --global \ - --prefix "$PREFIX" \ - --no-audit --no-fund \ - "@capysc/cli@${MINIMAL_ARG_VERSION}" +npm install -g --prefix=$OUTPUT_DIR/usr @capysc/cli@$MINIMAL_ARG_VERSION From 264c05c523aafb0e52dd44dfef7506a60d2961fe Mon Sep 17 00:00:00 2001 From: cvince Date: Sun, 7 Jun 2026 20:22:14 -0700 Subject: [PATCH 3/3] feat(capy): add source_provenance for the canonical upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declares capysc/capy-cli as the source of record per the new-package checklist. (Building from source vs the npm prebuilt is deferred — still npm-install for now.) --- packages/capy/build.ncl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/capy/build.ncl b/packages/capy/build.ncl index 77b21af..f84bb73 100644 --- a/packages/capy/build.ncl +++ b/packages/capy/build.ncl @@ -39,6 +39,11 @@ let version = "0.6.1" in attrs = { upstream_version = version, + source_provenance = { + category = 'GithubRepo, + owner = "capysc", + repo = "capy-cli", + }, # 1a shared-session model: pinhole the host ~/.capy into the box so in-box # capy reuses the developer's existing login (no key transport). rw because # capy refreshes its session and writes caches. Exposes the full host