diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 80610141..bc67705f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -476,7 +476,7 @@ jobs: retention-days: 1 # --------------------------------------------------------------------------- - # cli-build — per-platform `akua` binary matrix. Downloads the wasm + # cli-build — per-platform `akuapkg` binary matrix. Downloads the wasm # bundle (same artefact native-build consumes), packages tarballs + # sha256 sidecars. # --------------------------------------------------------------------------- @@ -547,7 +547,7 @@ jobs: # Pull the wasm bundle the wasm-bundle job built. Bytes land at # their original paths under the workspace root — exactly where - # akua-cli/build.rs + helm-engine-wasm/build.rs + + # akuapkg-cli/build.rs + helm-engine-wasm/build.rs + # kustomize-engine-wasm/build.rs look for them. The matrix runner's # build.rs precompiles each .wasm into a target-arch cwasm via # wasmtime AOT. @@ -557,14 +557,14 @@ jobs: name: wasm-bundle path: . - - name: Build akua CLI + - name: Build Akuapkg CLI # `ci-release` profile: lto off, codegen-units=16, symbols # stripped, line-tables-only debug. Trades ~5-10% runtime perf # for ~25-40% compile-time reduction. See Cargo.toml. - run: mise exec -- cargo build -p akua-cli --profile ci-release --target ${{ matrix.target }} + run: mise exec -- cargo build -p akuapkg-cli --profile ci-release --target ${{ matrix.target }} - # Smoke-test the binary the way an end-user would: `akua init` + - # `akua render` against the scaffolded Package. Catches any future + # Smoke-test the binary the way an end-user would: `akuapkg init` + + # `akuapkg render` against the scaffolded Package. Catches any future # "binary ships without a worker" / wrong-arch cwasm regression # before users see it. Skipped on cross-compiled targets where the # runner can't execute the output. @@ -573,17 +573,17 @@ jobs: shell: bash run: | set -eu - bin="$PWD/target/${{ matrix.target }}/ci-release/akua" + bin="$PWD/target/${{ matrix.target }}/ci-release/akuapkg" # Guard: the binary must report the tag it ships under. Catches a # regression in the version-injection step before users see a - # release whose `akua -V` disagrees with its tag. + # release whose `akuapkg -V` disagrees with its tag. expected="${{ needs.detect-version.outputs.version }}" got="$("$bin" -V | awk '{print $NF}')" if [ "$got" != "$expected" ]; then echo "version mismatch: binary reports '$got', tag is '$expected'" >&2 exit 1 fi - echo "version ok: akua -V == $expected" + echo "version ok: akuapkg -V == $expected" tmp=$(mktemp -d) cd "$tmp" "$bin" init smoke @@ -597,29 +597,29 @@ jobs: if: matrix.archive == 'tar.gz' shell: bash run: | - name="akua-${{ needs.detect-version.outputs.tag }}-${{ matrix.target }}" + name="akuapkg-${{ needs.detect-version.outputs.tag }}-${{ matrix.target }}" mkdir -p dist - cp target/${{ matrix.target }}/ci-release/akua dist/ + cp target/${{ matrix.target }}/ci-release/akuapkg dist/ cp README.md SECURITY.md LICENSE dist/ 2>/dev/null || true - cd dist && tar -czf "${name}.tar.gz" akua README.md SECURITY.md LICENSE + cd dist && tar -czf "${name}.tar.gz" akuapkg README.md SECURITY.md LICENSE shasum -a 256 "${name}.tar.gz" > "${name}.tar.gz.sha256" - name: Package (windows) if: matrix.archive == 'zip' shell: pwsh run: | - $name = "akua-${{ needs.detect-version.outputs.tag }}-${{ matrix.target }}" + $name = "akuapkg-${{ needs.detect-version.outputs.tag }}-${{ matrix.target }}" New-Item -ItemType Directory -Force -Path dist | Out-Null - Copy-Item "target/${{ matrix.target }}/ci-release/akua.exe" -Destination dist/ + Copy-Item "target/${{ matrix.target }}/ci-release/akuapkg.exe" -Destination dist/ Copy-Item README.md,SECURITY.md,LICENSE -Destination dist/ -ErrorAction SilentlyContinue Push-Location dist - 7z a "$name.zip" akua.exe README.md SECURITY.md LICENSE + 7z a "$name.zip" akuapkg.exe README.md SECURITY.md LICENSE (Get-FileHash -Algorithm SHA256 "$name.zip").Hash.ToLower() + " $name.zip" | Out-File -Encoding ascii "$name.zip.sha256" Pop-Location - uses: actions/upload-artifact@v7 with: - name: akua-${{ matrix.target }} + name: akuapkg-${{ matrix.target }} path: | dist/*.tar.gz* dist/*.zip* @@ -641,15 +641,15 @@ jobs: - uses: actions/download-artifact@v8 with: # Filter to the cli-build artifacts this job consumes — - # `akua-` per-platform tarballs + sha256 sidecars - # (uploaded as `name: akua-${{ matrix.target }}` upstream). + # `akuapkg-` per-platform tarballs + sha256 sidecars + # (uploaded as `name: akuapkg-${{ matrix.target }}` upstream). # Without the pattern, download-artifact also pulls the # docker job's `akua-dev~akua~.dockerbuild` provenance # artifact whose `~`-containing name fails path validation # in v4 (and only silently slips by on v8 because the # merge-multiple flag tolerates it; defensive here so a # v8 → v4 downgrade doesn't bring back the bug). - pattern: 'akua-*' + pattern: 'akuapkg-*' path: dist merge-multiple: true - name: Create or verify immutable release @@ -676,14 +676,14 @@ jobs: --repo "${GH_REPO}" \ --verify-tag \ --target "${SOURCE_COMMIT}" \ - --title "akua ${VERSION}" \ + --title "Akuapkg ${VERSION}" \ --notes "${notes}" \ "${flags[@]}" \ dist/*.tar.gz dist/*.zip dist/*.sha256 # --------------------------------------------------------------------------- - # docker — multi-arch image at `ghcr.io/akua-dev/akua:`. Skips - # the `:latest` tag for prereleases so `docker pull akua:latest` + # docker — multi-arch image at `ghcr.io/akua-dev/akuapkg:`. Skips + # the `:latest` tag for prereleases so `docker pull akuapkg:latest` # stays on the most recent stable release. # --------------------------------------------------------------------------- docker: @@ -696,7 +696,7 @@ jobs: ref: ${{ needs.detect-version.outputs.source_commit }} - uses: actions/download-artifact@v8 with: - pattern: 'akua-*' + pattern: 'akuapkg-*' path: dist merge-multiple: true - uses: docker/setup-qemu-action@v4 @@ -714,18 +714,18 @@ jobs: set -eu mkdir -p image-context/amd64 image-context/arm64 tag="${{ needs.detect-version.outputs.tag }}" - tar -xzf "dist/akua-${tag}-x86_64-unknown-linux-gnu.tar.gz" -C image-context/amd64 akua - tar -xzf "dist/akua-${tag}-aarch64-unknown-linux-gnu.tar.gz" -C image-context/arm64 akua + tar -xzf "dist/akuapkg-${tag}-x86_64-unknown-linux-gnu.tar.gz" -C image-context/amd64 akuapkg + tar -xzf "dist/akuapkg-${tag}-aarch64-unknown-linux-gnu.tar.gz" -C image-context/arm64 akuapkg - name: Compute image tags id: tags run: | set -eu tag="${{ needs.detect-version.outputs.tag }}" # Versioned tag always; `:latest` only for stable releases. - tags="ghcr.io/akua-dev/akua:${tag}" + tags="ghcr.io/akua-dev/akuapkg:${tag}" if [ "${{ needs.detect-version.outputs.is_prerelease }}" = "false" ]; then tags="${tags} - ghcr.io/akua-dev/akua:latest" + ghcr.io/akua-dev/akuapkg:latest" fi { echo "tags<` for Akua/KCL packages, `charts..path` for Helm charts (where the resolver hands the engine a path it produced itself). User code never writes a literal path string, never concatenates path segments, never reaches across the filesystem. `akua.toml [dependencies]` is the single source of truth for what's reachable; the resolver materializes deps into the cache and the path-escape guard only has to validate paths the resolver itself produced. This shrinks the sandbox-escape attack surface to zero in user code: a malicious Package cannot construct a path-escape string because there are no path strings in the call surface to begin with. **`replace` and `path` deps are workspace-local; never cross Package boundaries.** Path-based escape hatches in `akua.toml` (`path = "..."`, `replace = { path = "..." }`) exist for fast local iteration — they must not become an attack surface when akua processes third-party Packages in production: - `replace.path` and bare `path = "..."` deps must canonicalize under the workspace root. Absolute paths and `..` escape are rejected at resolve time. -- `akua publish` strips every `replace` directive from the artifact's manifest before signing — consumers never inherit a publisher's replace. +- `akuapkg publish` strips every `replace` directive from the artifact's manifest before signing — consumers never inherit a publisher's replace. - Production deployments (`AKUA_REJECT_REPLACE=1`, auto in agent context) fail any render whose dep graph touches a replace directive. - `chart_resolver` runs on the host, outside the wasmtime sandbox; the path-safety + no-replace rules are the only thing standing between a malicious `akua.toml` and the host filesystem (service-account tokens, mounted secrets, in-cluster TLS material). -**`akua render` ≠ `akua export`.** `render` executes the Package's program (invokes engines, produces deploy-ready manifests). `export` converts a canonical artifact to a format view (JSON Schema, OpenAPI, YAML, Rego bundle). They are different verbs for different jobs. +**`akuapkg render` ≠ `akuapkg export`.** `render` executes the Package's program (invokes engines, produces deploy-ready manifests). `export` converts a canonical artifact to a format view (JSON Schema, OpenAPI, YAML, Rego bundle). They are different verbs for different jobs. ## Architecture discipline - **Substrate, not content.** We do not curate a package catalog. Upstream projects publish their own signed packages; akua provides signing + distribution + diff + audit infrastructure. Same logic for policy: Rego is a host, not a DSL we own. - **Typed deps surface as alias-method calls.** When a dep is registered in `akua.toml`, the synthesized stub owns the engine call: `webapp.template(webapp.TemplateOpts{values = webapp.Values{...}})` for Helm charts, `upstream.render(upstream.Input{...})` for Akua packages. The engine import (`akua.helm`, `akua.pkg`) is an implementation detail of the stub — user code reaches it via the alias, not directly. **Engine-direct callables (`akua.`) remain the surface for engines whose input is *not* a registered typed dep** — `kustomize.build({path = "./overlays"})` is the canonical case (kustomize bases are local-to-Package file organization, not external deps; the within-Package path is bounded by the workspace preopen + path-escape guard, not the cross-Package alias rule). Same logic for `kro.rgd`, `oci.fetch_manifests`. Kyverno / CEL / foreign Rego are `import data.…` in Rego, resolved via `akua.toml`. Never runtime string lookups like `kyverno.check({bundle: "oci://..."})`. -- **Embedded via wasmtime only.** KCL, Helm, OPA, Regal, Kustomize, kro offline instantiator, CEL, Kyverno-to-Rego converter all ship as wasip1 modules hosted inside akua's wasmtime. `$PATH` never required, never consulted. There is no shell-out fallback — "embedded by default" means "embedded only," because the sandbox invariant above forbids subprocess execution in the render path. +- **Embedded via wasmtime only.** KCL, Helm, OPA, Regal, Kustomize, kro offline instantiator, CEL, Kyverno-to-Rego converter all ship as wasip1 modules hosted inside Akuapkg's wasmtime. `$PATH` never required, never consulted. There is no shell-out fallback — "embedded by default" means "embedded only," because the sandbox invariant above forbids subprocess execution in the render path. - **Compose with the ecosystem, don't replace it.** ArgoCD, Flux, kro, Helm release lifecycle, kubectl, Crossplane are first-class consumers of akua output. We target their formats (`RawManifests`, `HelmChart`, `ResourceGraphDefinition`, `Crossplane`, `OCIBundle`). We don't ask customers to switch reconcilers. ## The one akua-specified shape @@ -93,15 +90,15 @@ That's it. akua does **not** specify `App`, `Environment`, `Cluster`, `Secret`, **New CLI verb — one PR moves all of these together** (binary/SDK/docs are one contract): -- `crates/akua-core/src/.rs` (logic) → `crates/akua-cli/src/verbs/.rs` (verb wrapper) → `main.rs` (clap dispatch) +- `crates/akua-core/src/.rs` (logic) → `crates/akuapkg-cli/src/verbs/.rs` (verb wrapper) → `main.rs` (clap dispatch) - `crates/akua-napi/src/lib.rs` (`#[napi]` wrapper calling `verbs::::run`) → `packages/sdk/src/mod.ts` (`Akua.()` method routes through `loadNapi()` + `callNapi`). The napi surface is declared in **three** hand-maintained places that must stay in sync: the `#[napi]` fn, `crates/akua-napi/index.d.ts` (committed despite its "auto-generated" header), and the `NapiAddon` interface in `packages/sdk/src/napi.ts` — a missing entry fails the release `sdk-build` (`tsc`), not local `cargo`. Don't rely on `process.env` reaching the addon (Bun doesn't `setenv` on assignment) — pass values through napi args. -- Tests at every layer; integration golden under `crates/akua-cli/tests/` if the verb operates on a Package +- Tests at every layer; integration golden under `crates/akuapkg-cli/tests/` if the verb operates on a Package - `docs/cli.md` section, verb-count bump (grep for the current count across docs/README), 🚧 → ✅ - `CHANGELOG.md` entry; `task release:validate` still green -**Touching `eval_kcl` or anything called from it:** `cargo build` doesn't rebuild `akua-render-worker.cwasm` (the worker is compiled separately to `wasm32-wasip1` by `task build:render-worker`). `crates/akua-cli/build.rs` watches `crates/akua-render-worker/src` and `crates/akua-core/src` and emits a `cargo:warning=` when sources are newer than the staged `.wasm` — heed it and run `task build:render-worker` before re-running `cargo build`. +**Touching `eval_kcl` or anything called from it:** `cargo build` doesn't rebuild `akua-render-worker.cwasm` (the worker is compiled separately to `wasm32-wasip1` by `task build:render-worker`). `crates/akuapkg-cli/build.rs` watches `crates/akua-render-worker/src` and `crates/akua-core/src` and emits a `cargo:warning=` when sources are newer than the staged `.wasm` — heed it and run `task build:render-worker` before re-running `cargo build`. -**Embedded-engine builds + feature wiring** (these cost real time when missed): the engine wasm assets (`crates/{helm,kustomize}-engine-wasm/assets/*.wasm`) are **gitignored** — a fresh clone or `git worktree` can't compile `akua-core` until `task build:engines` runs (or you copy the built assets in). The Go engine source (`crates/helm-engine-wasm/go-src/`) rebuilds via `task build:helm-engine-wasm` (Go→wasip1) — a *different* artifact from the Rust render-worker's `task build:render-worker`; when you change Go engine code, rebuild the engine, not the worker. And a new `akua-core` feature is **dead in the shipped binary/SDK** unless it's added to the `akua-core` dep `features = [...]` in **both** `crates/akua-cli/Cargo.toml` and `crates/akua-napi/Cargo.toml` — otherwise it silently compiles to its `#[cfg(not(feature))]` stub there even though `cargo test -p akua-core --features …` passes. +**Embedded-engine builds + feature wiring** (these cost real time when missed): the engine wasm assets (`crates/{helm,kustomize}-engine-wasm/assets/*.wasm`) are **gitignored** — a fresh clone or `git worktree` can't compile `akua-core` until `task build:engines` runs (or you copy the built assets in). The Go engine source (`crates/helm-engine-wasm/go-src/`) rebuilds via `task build:helm-engine-wasm` (Go→wasip1) — a *different* artifact from the Rust render-worker's `task build:render-worker`; when you change Go engine code, rebuild the engine, not the worker. And a new `akua-core` feature is **dead in the shipped binary/SDK** unless it's added to the `akua-core` dep `features = [...]` in **both** `crates/akuapkg-cli/Cargo.toml` and `crates/akua-napi/Cargo.toml` — otherwise it silently compiles to its `#[cfg(not(feature))]` stub there even though `cargo test -p akua-core --features …` passes. **Releases are tag-triggered and expensive — batch them.** A pushed `v*` tag fires the full build matrix (Windows + macOS jobs dominate at ~30min and can't be self-hosted), npm publishing, and container publishing. Accumulate fixes on `main` and cut **one** tag when a human explicitly asks — never tag per change/chunk. The release derives its version from the tag (`scripts/set-cargo-version.sh` + a smoke-test guard asserting `akua -V == tag`); the committed `Cargo.toml` version is a dev placeholder, so don't expect hand-bumping it to affect a release. Tags are immutable: never delete and re-push one. The `@akua-dev/native` publish must not use `--ignore-scripts`; see [docs/releasing.md](docs/releasing.md) for the release contract and fail-closed recovery procedure. @@ -124,12 +121,11 @@ That's it. akua does **not** specify `App`, `Environment`, `Cluster`, `Secret`, ## Quality gates ```sh -akua check # fast syntax / type / dep check, no execution -akua fmt --check # fail CI if any file needs formatting -akua lint # Regal + kcl lint + cross-engine -akua test # unit tests (*_test.rego, test_*.k) + golden -akua verify # akua.toml ↔ akua.lock integrity + cosign -akua policy check # when policy changed; verdict must be allow +akuapkg check # fast syntax / type / dep check, no execution +akuapkg fmt --check # fail CI if any file needs formatting +akuapkg lint # Regal + kcl lint + cross-engine +akuapkg test # unit tests (*_test.rego, test_*.k) + golden +akuapkg verify # akua.toml ↔ akua.lock integrity + cosign ``` All are embedded — no installation of `opa` / `kcl` / `regal` needed. diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b46dab6..bbd27717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,19 +29,19 @@ minor bump in the SDK. ### Added -- **Hosted API bridge in the single `akua` CLI** ([api.rs](crates/akua-cli/src/verbs/api.rs), [docs/cli.md](docs/cli.md)). `akua api` now calls the hosted Akua API with token auth, configurable base URL, workspace context, request field/body helpers, and Akua structured errors for auth, permission, rate-limit, transport, and timeout failures. `akua api spec` fetches the public OpenAPI document; elevated audiences return `E_UNSUPPORTED` until the server exposes authorized audience-specific specs. +- **Hosted API bridge in the single `akua` CLI** ([api.rs](crates/akuapkg-cli/src/verbs/api.rs), [docs/cli.md](docs/cli.md)). `akuapkg api` now calls the hosted Akua API with token auth, configurable base URL, workspace context, request field/body helpers, and Akua structured errors for auth, permission, rate-limit, transport, and timeout failures. `akuapkg api spec` fetches the public OpenAPI document; elevated audiences return `E_UNSUPPORTED` until the server exposes authorized audience-specific specs. ### Fixed - **SDK launch docs and generated site now describe the shipped Node/Bun NAPI surface** ([docs/sdk.md](docs/sdk.md), [site/concepts/sdk.html](site/concepts/sdk.html)). The public SDK page no longer advertises stale browser support, shell-out dispatch, or future Akua Cloud namespaces as part of `@akua-dev/sdk`; it documents the current package as a native-addon-backed Package SDK with render/export/check/lint/verify and vendor drift guards. -- **Large render/export regressions stay covered by launch-readiness tests** ([packages/sdk](packages/sdk), [crates/akua-cli](crates/akua-cli)). The SDK and CLI regression coverage now guards the large render-output path and export surface that previously drifted during launch hardening. -- **Helm `values.schema.json` defaults that contradict generated KCL types are omitted** ([values_schema.rs](crates/akua-core/src/values_schema.rs), [helm_union_schema.rs](crates/akua-cli/tests/helm_union_schema.rs)). Chart schemas that declare unsafe defaults such as `null` for non-null fields, numeric defaults for strings, or mismatched array items no longer emit invalid KCL defaults that abort the render worker. +- **Large render/export regressions stay covered by launch-readiness tests** ([packages/sdk](packages/sdk), [crates/akuapkg-cli](crates/akuapkg-cli)). The SDK and CLI regression coverage now guards the large render-output path and export surface that previously drifted during launch hardening. +- **Helm `values.schema.json` defaults that contradict generated KCL types are omitted** ([values_schema.rs](crates/akua-core/src/values_schema.rs), [helm_union_schema.rs](crates/akuapkg-cli/tests/helm_union_schema.rs)). Chart schemas that declare unsafe defaults such as `null` for non-null fields, numeric defaults for strings, or mismatched array items no longer emit invalid KCL defaults that abort the render worker. ## [0.8.20] — 2026-06-09 ### Fixed -- **Render budget handling is stable across persistent nested engine sessions** ([engine-host-wasm](crates/engine-host-wasm/src/lib.rs), [render.rs](crates/akua-cli/src/verbs/render.rs)). Helm/Kustomize sessions now refresh their Wasmtime epoch deadline before each call, so a reused session no longer inherits a stale expired deadline after idle time. Worker interrupt traps are also classified as `E_RENDER_BUDGET_DEADLINE` and return the timeout exit code instead of surfacing as generic KCL evaluation failures. +- **Render budget handling is stable across persistent nested engine sessions** ([engine-host-wasm](crates/engine-host-wasm/src/lib.rs), [render.rs](crates/akuapkg-cli/src/verbs/render.rs)). Helm/Kustomize sessions now refresh their Wasmtime epoch deadline before each call, so a reused session no longer inherits a stale expired deadline after idle time. Worker interrupt traps are also classified as `E_RENDER_BUDGET_DEADLINE` and return the timeout exit code instead of surfacing as generic KCL evaluation failures. ## [0.8.19] — 2026-06-01 @@ -53,7 +53,7 @@ minor bump in the SDK. ### Fixed -- **`akua cache` now inventories and clears the helm chart cache** (`$XDG_CACHE_HOME/akua/helm`) added with the helm-repo dep source. Previously the helm cache grew unmanaged: `akua cache list` did not show it and `akua cache clear` did not reclaim it. `--helm` scope flag added to `akua cache clear`; `akua cache path` and `akua cache list` now report the helm root alongside oci and git. The default clear (no scope flag) wipes all three caches. +- **`akuapkg cache` now inventories and clears the helm chart cache** (`$XDG_CACHE_HOME/akua/helm`) added with the helm-repo dep source. Previously the helm cache grew unmanaged: `akuapkg cache list` did not show it and `akuapkg cache clear` did not reclaim it. `--helm` scope flag added to `akuapkg cache clear`; `akuapkg cache path` and `akuapkg cache list` now report the helm root alongside oci and git. The default clear (no scope flag) wipes all three caches. ## [0.8.17] — 2026-05-29 @@ -70,7 +70,7 @@ integrity + DoS-resilience hardening). See ### Security -- **Hardening from the 2026-05-29 security audit** ([docs/security-audit-2026-05-29.md](docs/security-audit-2026-05-29.md)). `akua publish` now strips `replace` directives from the signed manifest (consumers never inherit a publisher's replace); untrusted chart `values.schema.json` property names + descriptions are validated/escaped before KCL codegen (no injection); helm/kustomize engine Stores get a memory cap + finite epoch (chart-DoS ceiling); HTTP fetch bodies + gzip→tar extraction are size-capped (OOM / decompression-bomb); `BasicAuth` redacts its password in `Debug` and no longer derives `Serialize`; the git transport forces TLS verification (ignores ambient `GIT_SSL_NO_VERIFY`); plus several lower-severity fixes (UTF-8 panic on registry error bodies, helm `http://` scheme-downgrade rejection, helm `chart`-name + OCI userinfo validation, git tree-entry name guard, `vendor add` URL canonicalization). `--timeout` now bounds the render worker's epoch deadline (previously the worker always used the 6s default). No sandbox-escape was found; these are integrity + DoS-resilience hardening. +- **Hardening from the 2026-05-29 security audit** ([docs/security-audit-2026-05-29.md](docs/security-audit-2026-05-29.md)). `akuapkg publish` now strips `replace` directives from the signed manifest (consumers never inherit a publisher's replace); untrusted chart `values.schema.json` property names + descriptions are validated/escaped before KCL codegen (no injection); helm/kustomize engine Stores get a memory cap + finite epoch (chart-DoS ceiling); HTTP fetch bodies + gzip→tar extraction are size-capped (OOM / decompression-bomb); `BasicAuth` redacts its password in `Debug` and no longer derives `Serialize`; the git transport forces TLS verification (ignores ambient `GIT_SSL_NO_VERIFY`); plus several lower-severity fixes (UTF-8 panic on registry error bodies, helm `http://` scheme-downgrade rejection, helm `chart`-name + OCI userinfo validation, git tree-entry name guard, `vendor add` URL canonicalization). `--timeout` now bounds the render worker's epoch deadline (previously the worker always used the 6s default). No sandbox-escape was found; these are integrity + DoS-resilience hardening. ### Changed @@ -98,7 +98,7 @@ programmatically instead of relying on env-var propagation Bun doesn't do. ## [0.8.14] — 2026-05-29 -Real-world Helm rendering. This release makes akua render the charts +Real-world Helm rendering. This release makes akuapkg render the charts people actually deploy — pulling from classic HTTPS Helm repositories, composing charts inside modular sub-packages, and surviving the schema shapes and output sizes of large upstream charts (temporal, argo-cd, @@ -107,7 +107,7 @@ pipeline's version-stamping. ### Added -- **HTTPS helm-repo dependency source** ([helm_repo_fetcher.rs](crates/akua-core/src/helm_repo_fetcher.rs)). `akua.toml` deps can now name a classic Helm repository — `repo` + `chart` + `version` (exact or semver range) — alongside `oci`/`git`/`path`. Resolved against the repo's `index.yaml` at add/lock time, content-pinned by `.tgz` sha256 in `akua.lock`, rendered deterministically from the cache offline. Private repos use the existing host-keyed `--auth`. The CLI gains `akua add --repo --chart --version `; the SDK's `add()` mirrors it. +- **HTTPS helm-repo dependency source** ([helm_repo_fetcher.rs](crates/akua-core/src/helm_repo_fetcher.rs)). `akua.toml` deps can now name a classic Helm repository — `repo` + `chart` + `version` (exact or semver range) — alongside `oci`/`git`/`path`. Resolved against the repo's `index.yaml` at add/lock time, content-pinned by `.tgz` sha256 in `akua.lock`, rendered deterministically from the cache offline. Private repos use the existing host-keyed `--auth`. The CLI gains `akuapkg add --repo --chart --version `; the SDK's `add()` mirrors it. - **`examples/13-subpackage-helm`** — a modular sub-package that itself composes a Helm chart, exercising the cross-package context fix below. - **`examples/14-helm-repo-dep`** — a chart pulled from an HTTPS Helm repository (network-gated e2e test, run pre-release like `examples_kcl_ecosystem`). @@ -117,7 +117,7 @@ pipeline's version-stamping. - **Helm `NOTES.txt` no longer breaks renders** ([helm.rs](crates/akua-core/src/helm.rs)). The engine returns `NOTES.txt` (top-level and per-subchart) among its files, but those are free-form prose, not manifests. akua parsed every file as YAML, so notes containing `kubectl …:` lines aborted the whole render with `could not find expected ':'`. `NOTES.txt` is now skipped before parsing. - **Union-typed chart values no longer crash the evaluator** ([values_schema.rs](crates/akua-core/src/values_schema.rs)). A `values.schema.json` field typed `["string","integer","null"]` was collapsed to its first member while its default was emitted verbatim (`port: str = 8080`), aborting the wasm KCL evaluator. akua now emits a real KCL union (`int | str`) and marks `null`-bearing unions optional. Unblocks charts like traefik. - **Hyphenated dependency names now import correctly** ([mod_file.rs](crates/akua-core/src/mod_file.rs)). A dep keyed `cnpg-operator` produced a `cnpg-operator.k` module that `import charts.cnpg_operator` couldn't see (`-` is not a KCL identifier). Dep names are sanitized to KCL identifiers at every materialization site, with collision detection and digit-leading handling. -- **Large renders no longer fail with an opaque I/O error** ([render_worker.rs](crates/akua-cli/src/render_worker.rs)). The worker's stdout pipe was capped at 1 MiB, so a chart rendering >1 MiB (e.g. argo-cd, ~1.36 MB) died with `os error 29`. The cap is raised to the worker's memory ceiling (256 MiB) and overflow now surfaces as a typed `E_RENDER_OUTPUT_TOO_LARGE`. +- **Large renders no longer fail with an opaque I/O error** ([render_worker.rs](crates/akuapkg-cli/src/render_worker.rs)). The worker's stdout pipe was capped at 1 MiB, so a chart rendering >1 MiB (e.g. argo-cd, ~1.36 MB) died with `os error 29`. The cap is raised to the worker's memory ceiling (256 MiB) and overflow now surfaces as a typed `E_RENDER_OUTPUT_TOO_LARGE`. - **Sub-package stubs no longer leak `charts.*` imports** ([pkg_stub.rs](crates/akua-core/src/pkg_stub.rs)). A sub-package's `import charts.` was carried into the synthesized stub compiled in the root context, where `charts` isn't registered. Chart imports are stripped from stubs (the schemas are what the stub needs). - **Release binaries report their tag version** ([release.yml](.github/workflows/release.yml)). The pipeline derives the workspace version from the pushed git tag (`scripts/set-cargo-version.sh`) and asserts `akua -V` matches the tag in the build smoke-test. Previously `CARGO_PKG_VERSION` was pinned to the committed `Cargo.toml`, so 0.8.9–0.8.13 binaries (and their SLSA provenance / OCI annotations) all reported `0.8.8`. @@ -141,8 +141,8 @@ rejected at parse time. ## [0.8.7] — 2026-05-07 -Workspace-vendor surfacing: the CLI now exposes `akua vendor add`, -`akua vendor check`, and `akua vendor list`; the SDK mirrors those +Workspace-vendor surfacing: the CLI now exposes `akuapkg vendor add`, +`akuapkg vendor check`, and `akuapkg vendor list`; the SDK mirrors those entry points. `vendor add` writes the lockfile pin alongside materializing the tree, vendor-first resolver lookup is universal across all dep kinds, and lockfile metadata clears on digest change @@ -154,11 +154,11 @@ GitHub Releases / Homebrew. ### Added -- `akua vendor` with `add`, `check`, and `list` subcommands. +- `akuapkg vendor` with `add`, `check`, and `list` subcommands. - `@akua-dev/sdk` vendor methods: `vendorAdd`, `vendorCheck`, and `vendorList`. - `vendor add` writes a `LockedPackage` pin into `akua.lock` alongside - materializing the tree, so `vendor check` and `akua verify` have a + materializing the tree, so `vendor check` and `akuapkg verify` have a stable digest to compare against — required for the offline-render contract once the canonical source is GC'd. - `examples/12-vendor-offline/` — end-to-end demonstration of the @@ -248,7 +248,7 @@ pull / fetch paths. ### Fixed - **Render-worker freshness guard for release profiles.** `cargo - build -p akua-cli --profile {release,ci-release}` now hard-fails + build -p akuapkg-cli --profile {release,ci-release}` now hard-fails when the embedded `akua-render-worker.wasm` was built from different source content than the akua-core code that's about to embed it. Previously the build emitted a `cargo:warning=` and @@ -260,7 +260,7 @@ pull / fetch paths. `crates/akua-render-worker/**` as `sources:`. Adds `crates/akua-core/**` to the dependency list so an akua-core edit re-triggers the worker build instead of leaving Taskfile reporting - "up to date" while the akua-cli build.rs flags drift. + "up to date" while the akuapkg-cli build.rs flags drift. - **`examples_kcl_ecosystem` integration test gated behind `#[ignore]`.** It pulls live from `oci://ghcr.io/kcl-lang/k8s` and occasionally trips the wasmtime epoch budget on cold caches. Now @@ -276,12 +276,12 @@ pull / fetch paths. | `crates/akua-core/src/oci_puller.rs` | 9.2 % | 87 % | | `crates/akua-core/src/oci_fetcher.rs` | 14.9 % | 80 % | | `crates/engine-host-wasm/src/lib.rs` | 56 % | 76 % | - | `crates/akua-cli/src/verbs/publish.rs` | 0 % | 87 % | - | `crates/akua-cli/src/verbs/pull.rs` | 0 % | 85 % | - | `crates/akua-cli/src/verbs/dev.rs` | 0 % | 85 % | - | `crates/akua-cli/src/verbs/sign.rs` | 84 % | 87 % | + | `crates/akuapkg-cli/src/verbs/publish.rs` | 0 % | 87 % | + | `crates/akuapkg-cli/src/verbs/pull.rs` | 0 % | 85 % | + | `crates/akuapkg-cli/src/verbs/dev.rs` | 0 % | 85 % | + | `crates/akuapkg-cli/src/verbs/sign.rs` | 84 % | 87 % | | `crates/akua-core/src/helm.rs` | 49 % | 68 % | - | `crates/akua-cli/src/observability.rs` | 31 % | 50 % | + | `crates/akuapkg-cli/src/observability.rs` | 31 % | 50 % | ~80 new tests, all running through `cargo nextest` in seconds. Branch coverage on the load-bearing security invariants: @@ -416,7 +416,7 @@ attempt actually executed the matrix end-to-end. - **Cross-compile cwasm architecture mismatch.** `macos-latest` runners are now aarch64 (M-series). When the matrix cross-compiled - `x86_64-apple-darwin`, `akua-cli/build.rs` precompiled the worker + `x86_64-apple-darwin`, `akuapkg-cli/build.rs` precompiled the worker cwasm on the aarch64 host and embedded it in the x86_64 binary; runtime `Module::deserialize` then trapped with `Module was compiled for architecture 'aarch64'`. Fixed by passing cargo's @@ -445,7 +445,7 @@ attempt actually executed the matrix end-to-end. ## [0.8.2] — 2026-04-29 Critical fix: every released CLI binary since 0.6.0 shipped without -the wasmtime render-worker embedded — `akua render` against any +the wasmtime render-worker embedded — `akuapkg render` against any package failed with `E_RENDER_KCL` "render sandbox unavailable — worker module wasn't compiled into this akua binary." The cli-release matrix runners never invoked `task build:render-worker`, so @@ -461,7 +461,7 @@ no such artefact and no test ever exercised the produced binary. - **cli-release matrix builds the worker + engines pre-`cargo build`.** Two new steps before `Build akua CLI`: `task build:engines` and - `task build:render-worker`. Without these, `akua-cli/build.rs` + `task build:render-worker`. Without these, `akuapkg-cli/build.rs` has nothing to embed. - **Smoke test on the produced binary.** New step runs ` init smoke && render` against the scaffolded @@ -558,7 +558,7 @@ guard that closes the host-side dep-resolution attack surface. agent context; CI / agent / container invocations no longer honor publisher-supplied replaces. Strict `"1"`-only (matches the `AKUA_BRIDGE_TRACE` convention). -- **`akua render --timeout=` / `--max-depth=`** — wires +- **`akuapkg render --timeout=` / `--max-depth=`** — wires the existing `BudgetSnapshot` to the CLI surface. Go-duration parser (`30s`, `5m`, `250ms`); typo'd values surface as `E_INVALID_FLAG`. New `akua_core::duration_parse` crate-public. @@ -636,12 +636,12 @@ example). - Render-worker rebuild trigger now watches `akua-render-worker/src` + `akua-core/src` and emits a `cargo:warning=` when the staged `.cwasm` is stale. -- `akua init .` derives the package name from `basename($PWD)` +- `akuapkg init .` derives the package name from `basename($PWD)` instead of writing `name = "."`. - `E_PATH_ESCAPE` errors now carry a `hint` field with both remediations (vendor under the Package or declare in `akua.toml`). -- `akua render --debug` (under `--json`) emits `evalResult` +- `akuapkg render --debug` (under `--json`) emits `evalResult` alongside the summary — the post-eval resources list before YAML normalization. @@ -764,7 +764,7 @@ shape. - **P0** Tar extraction — reject symlink + hard-link entries in Rust `unpack_chart_tgz`. Prevents arbitrary file read via - `akua inspect` on a malicious chart whose entry points at + `akuapkg inspect` on a malicious chart whose entry points at `/etc/passwd`. - **P0** `engine-helmfile` removed from default cargo features. Helmfile's Go-template `exec` / `readFile` / `requiredEnv` functions @@ -861,10 +861,10 @@ deterministically; 26 verbs implement the universal CLI contract. **Authoring + render** - KCL-typed Packages: `package.k` with `import` + `schema` + `resources` regions, published as signed OCI artifacts. -- `akua render` — wasmtime-sandboxed evaluation. Engines (Helm v4, +- `akuapkg render` — wasmtime-sandboxed evaluation. Engines (Helm v4, Kustomize) compiled to `wasm32-wasip1` and hosted inside akua's own wasmtime — no `$PATH`, no shell-out, no ambient filesystem. -- `akua export` — emit the Package's `Input` schema as JSON Schema +- `akuapkg export` — emit the Package's `Input` schema as JSON Schema 2020-12 or OpenAPI 3.1. Field docstrings become `description`; `@ui(...)` decorators become `x-ui` extensions for form renderers (rjsf, JSONForms) and admission-webhook validators. @@ -901,9 +901,9 @@ every verb supports `--json`, `--plan`, `--timeout`, Specification](https://agentskills.io). **Signing + attestation** -- `akua publish` emits cosign signatures (ECDSA P-256 keyed) and +- `akuapkg publish` emits cosign signatures (ECDSA P-256 keyed) and SLSA v1 predicates by default; consumers verify on pull. Air-gap - flow: `akua pack` → `akua sign` → `akua verify --tarball`. + flow: `akuapkg pack` → `akua sign` → `akuapkg verify --tarball`. **SDK** - `@akua/sdk` (`packages/sdk`) — in-process WASM via `akua-wasm` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 36aa1252..a2ee883c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ discuss direction. - **Issues** — bug reports, feature requests, design feedback - **Docs** — `docs/`, example READMEs, the top-level `README.md`; these drift fastest - **Test coverage** — especially for engines + CEL expression edge cases -- **Regression coverage on real charts** — `akua render` against popular Helm charts from ArtifactHub; file issues for any that mis-render +- **Regression coverage on real charts** — `akuapkg render` against popular Helm charts from ArtifactHub; file issues for any that mis-render ## Development setup @@ -40,8 +40,8 @@ Subsequent builds are fast. ## Running the examples ```bash -cargo run -p akua-cli -- tree --package examples/hello-package -cargo run -p akua-cli -- render --package examples/hello-package --out dist/chart --release demo +cargo run -p akuapkg-cli -- tree --package examples/hello-package +cargo run -p akuapkg-cli -- render --package examples/hello-package --out dist/chart --release demo ``` ## What's landed / what's next diff --git a/Cargo.lock b/Cargo.lock index 10214a4f..7e00bbd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,40 +49,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "akua-cli" -version = "0.8.20" -dependencies = [ - "akua-core", - "clap", - "ctrlc", - "engine-host-wasm", - "helm-engine-wasm", - "httpmock", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry_sdk", - "p256", - "pkcs8", - "rand 0.8.6", - "reqwest", - "schemars", - "serde", - "serde_json", - "serde_yml", - "source-hash", - "tempfile", - "thiserror 2.0.18", - "tokio", - "toml 1.1.2+spec-1.1.0", - "tracing", - "tracing-opentelemetry", - "tracing-subscriber", - "ts-rs", - "wasmtime", - "wasmtime-wasi", -] - [[package]] name = "akua-core" version = "0.8.20" @@ -123,8 +89,8 @@ dependencies = [ name = "akua-napi" version = "0.8.20" dependencies = [ - "akua-cli", "akua-core", + "akuapkg-cli", "napi", "napi-build", "napi-derive", @@ -146,6 +112,40 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "akuapkg-cli" +version = "0.8.20" +dependencies = [ + "akua-core", + "clap", + "ctrlc", + "engine-host-wasm", + "helm-engine-wasm", + "httpmock", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry_sdk", + "p256", + "pkcs8", + "rand 0.8.6", + "reqwest", + "schemars", + "serde", + "serde_json", + "serde_yml", + "source-hash", + "tempfile", + "thiserror 2.0.18", + "tokio", + "toml 1.1.2+spec-1.1.0", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", + "ts-rs", + "wasmtime", + "wasmtime-wasi", +] + [[package]] name = "allocator-api2" version = "0.2.21" diff --git a/Cargo.toml b/Cargo.toml index 162fa4d1..53e3c25b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ resolver = "2" members = [ "crates/akua-core", - "crates/akua-cli", + "crates/akuapkg-cli", "crates/akua-napi", "crates/akua-render-worker", "crates/engine-host-wasm", @@ -15,7 +15,7 @@ members = [ version = "0.8.20" edition = "2021" license = "Apache-2.0" -repository = "https://github.com/cnap-tech/akua" +repository = "https://github.com/akua-dev/akua" authors = ["CNAP Tech "] [workspace.dependencies] diff --git a/README.md b/README.md index d20389a8..ca541623 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ curl -fsSL https://cli.akua.dev/install | sh # render anywhere -akua render --inputs inputs.yaml --out ./deploy +akuapkg render --inputs inputs.yaml --out ./deploy ``` ## Quick start @@ -101,8 +101,8 @@ resources = [r | { ``` ```sh -akua render --inputs prod.yaml --out ./deploy # sandboxed render → raw manifests -akua publish . # cosign-signed OCI artifact + SLSA attestation +akuapkg render --inputs prod.yaml --out ./deploy # sandboxed render → raw manifests +akuapkg publish . # cosign-signed OCI artifact + SLSA attestation ``` For cross-Package composition (install one Akua package on top of another, with overlays / filters / extras), see [`examples/11-install-as-package/`](examples/11-install-as-package/). Twelve worked examples — Helm, Kustomize, multi-engine, package composition, KCL ecosystem, install-as-Package — each commit `rendered/` goldens byte-checked in CI. @@ -112,8 +112,8 @@ For cross-Package composition (install one Akua package on top of another, with - **Sandboxed by default.** Every render runs in a wasmtime WASI sandbox with memory / CPU / wall-clock caps. No shell-out, no `$PATH` lookup, no ambient filesystem. Untrusted Packages are safe to render on shared hosts. Adversarial test suite proves each invariant. See [`docs/security-model.md`](docs/security-model.md). - **Typed packages, not YAML templates.** KCL has real schemas, real types, real imports. Drift between the value the operator wrote and the value the chart consumed becomes a compile error, not a 3am incident. - **Embedded engines.** Helm v4 + Kustomize compiled to `wasm32-wasip1` and hosted inside akua. `helm.template(...)` works without a `helm` binary anywhere on your machine. See [`docs/embedded-engines.md`](docs/embedded-engines.md). -- **Signed + attested.** `akua publish` emits cosign signatures and SLSA v1 attestations by default. On pull, the `akua.lock` digest is always verified; cosign + SLSA verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. ECDSA P-256 keyed cosign today; keyless on the v0.3 roadmap. -- **Deterministic.** Same inputs + same lockfile + same akua version → byte-identical output. No `now()`, no `random()`, no env reads in the render pipeline. +- **Signed + attested.** `akuapkg publish` emits cosign signatures and SLSA v1 attestations by default. On pull, the `akua.lock` digest is always verified; cosign + SLSA verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. ECDSA P-256 keyed cosign today; keyless on the v0.3 roadmap. +- **Deterministic.** Same inputs + same lockfile + same akuapkg version → byte-identical output. No `now()`, no `random()`, no env reads in the render pipeline. - **Compose with the ecosystem.** kpm-published KCL packages (`oci://ghcr.io/kcl-lang/*`) drop straight into `[dependencies]` — `import k8s.api.apps.v1` resolves against the upstream schema bundle. See [`examples/10-kcl-ecosystem/`](examples/10-kcl-ecosystem/). - **Agent-first.** Auto-detects Claude Code, Cursor, Codex, Gemini CLI, Goose, Amp, OpenCode, Cline, and 25+ other agents. Every verb emits `--json`, uses typed exit codes, and ships skill manifests under [`skills/`](skills/) conforming to the [Agent Skills Specification](https://agentskills.io). See [`docs/agent-usage.md`](docs/agent-usage.md). @@ -127,7 +127,7 @@ curl -fsSL https://cli.akua.dev/install | sh irm https://cli.akua.dev/install.ps1 | iex # From source -cargo install --git https://github.com/akua-dev/akua akua-cli +cargo install --git https://github.com/akua-dev/akua akuapkg-cli ``` ```sh diff --git a/SECURITY.md b/SECURITY.md index 1f4ee5de..453b2ee9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ akua's threat model assumes the **package author is untrusted**. A worker process, CI runner, local developer, or agent sandbox should be -able to run `akua render` / `akua inspect` / `akua publish` / `akua +able to run `akuapkg render` / `akuapkg inspect` / `akuapkg publish` / `akua policy check` / `@akua-dev/sdk` calls against attacker-controlled `Package.k` + chart tarballs + Rego modules **without an OS-level sandbox** for the vast majority of workflows. @@ -23,7 +23,7 @@ entry — symlinks, hard links, device files, FIFOs all error out with Without this, a malicious `mychart.tgz` could ship `mychart/values.schema.json -> /etc/passwd` and a subsequent -`akua inspect` would read the symlink target and surface its contents +`akuapkg inspect` would read the symlink target and surface its contents in the JSON output. ### Decompression bombs + entry-count caps @@ -106,7 +106,7 @@ build time. Enable only if you trust every package you build: ```sh -cargo build -p akua-cli --features akua-core/engine-helmfile +cargo build -p akuapkg-cli --features akua-core/engine-helmfile ``` When on, akua still validates source paths but cannot constrain what diff --git a/Taskfile.yml b/Taskfile.yml index 3c629611..9bf69cab 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -9,7 +9,7 @@ vars: HELM_ENGINE_WASM: crates/helm-engine-wasm/assets/helm-engine.wasm KUSTOMIZE_ENGINE_WASM: crates/kustomize-engine-wasm/assets/kustomize-engine.wasm # Produced by `task build:render-worker`. Embedded in the CLI at - # build time via akua-cli's build.rs — AOT-compiled to a .cwasm + # build time via akuapkg-cli's build.rs — AOT-compiled to a .cwasm # matching the runtime wasmtime Config hash so per-render # Module::deserialize is a memcpy, not a Cranelift pass. RENDER_WORKER_WASM: target/wasm32-wasip1/release/akua-render-worker.wasm @@ -72,7 +72,7 @@ tasks: - cargo clippy --workspace --all-targets -- -D warnings # Rendering verbs (and clippy --all-targets, which compiles them) need - # the embedded wasmtime sandbox artifacts on disk: akua-cli's build.rs + # the embedded wasmtime sandbox artifacts on disk: akuapkg-cli's build.rs # precompiles them into the binary, and emits E_SANDBOX_UNAVAILABLE # when any is missing. Both lint + test depend on this. # @@ -80,7 +80,7 @@ tasks: # toolchains (Rust→wasip1 + Go→wasip1 × 2) so concurrency is a # straightforward win. sandbox-artifacts: - desc: Build every embedded wasm needed by akua-cli's build.rs + desc: Build every embedded wasm needed by akuapkg-cli's build.rs deps: - build:render-worker - build:helm-engine-wasm @@ -136,7 +136,7 @@ tasks: # `#[ignore]`-gated by default (live ghcr.io pull + wasmtime # epoch budget make it flaky in `cargo test --workspace`). # Pre-tag we WANT it to run. - - cargo test -p akua-cli --features cosign-verify,dev-watch + - cargo test -p akuapkg-cli --features cosign-verify,dev-watch --test examples_helm_hello --test examples_hello_webapp --test examples_pkg_compose @@ -158,17 +158,17 @@ tasks: release:local: desc: Build the release binary locally cmds: - - cargo build --release -p akua-cli - - ls -lh target/release/akua + - cargo build --release -p akuapkg-cli + - ls -lh target/release/akuapkg release:target: - desc: Build akua for a specific Rust target (used by the release workflow) + desc: Build Akuapkg for a specific Rust target (used by the release workflow) vars: TARGET: '{{.TARGET | default "x86_64-unknown-linux-gnu"}}' CARGO: '{{.CARGO | default "cargo"}}' cmds: - - '{{.CARGO}} build --release -p akua-cli --target {{.TARGET}}' - - ls -lh target/{{.TARGET}}/release/akua + - '{{.CARGO}} build --release -p akuapkg-cli --target {{.TARGET}}' + - ls -lh target/{{.TARGET}}/release/akuapkg # ---- Embedded engines (wasip1; built by Go toolchain, hosted by wasmtime) # Each engine is a Go program compiled to `wasm32-wasip1` and embedded in @@ -219,10 +219,10 @@ tasks: # ---- Render worker (Rust → wasip1; the Phase 4 sandbox) ------------------ build:render-worker: - desc: Build akua-render-worker for wasm32-wasip1 (embedded in akua-cli) + desc: Build akua-render-worker for wasm32-wasip1 (embedded in akuapkg-cli) # akua-core is linked into the worker, so akua-core edits change # the produced wasm. Without it in `sources:`, task's caching - # reports "up to date" while akua-cli's build.rs flags the worker + # reports "up to date" while akuapkg-cli's build.rs flags the worker # as stale — the contributor goes in circles. sources: - crates/akua-render-worker/**/*.rs @@ -243,7 +243,7 @@ tasks: --config 'profile.release.debug="line-tables-only"' - ls -lh {{.RENDER_WORKER_WASM}} # Record the content hash of the sources the .wasm was just built - # from. akua-cli's build.rs reads this on next consumer build — + # from. akuapkg-cli's build.rs reads this on next consumer build — # mismatch means host/worker drift (a release-quality bug). # Authoritative over mtime; not perturbed by `git checkout`. - >- @@ -263,16 +263,16 @@ tasks: # output dir via `TS_RS_EXPORT_DIR` since the macro leaves # `export_to` empty. Run the lib tests for every crate that # declares a `contract_type!` — akua-core owns the shared - # primitives, akua-cli owns per-verb response shapes. + # primitives, akuapkg-cli owns per-verb response shapes. - | TS_RS_EXPORT_DIR="$(pwd)/{{.SDK_TYPES_DIR}}" \ cargo test -p akua-core --features ts-export --lib export_bindings - | TS_RS_EXPORT_DIR="$(pwd)/{{.SDK_TYPES_DIR}}" \ - cargo test -p akua-cli --features schema-export,ts-export --lib export_bindings + cargo test -p akuapkg-cli --features schema-export,ts-export --lib export_bindings # schemars bundle — single `akua.json` with every type in # `$defs`. Triggered by the dedicated emission test. - - cargo test -p akua-cli --features schema-export,ts-export --test export_sdk_bundle + - cargo test -p akuapkg-cli --features schema-export,ts-export --test export_sdk_bundle sdk:check: desc: Fail if generated SDK artifacts drift from the Rust source @@ -319,7 +319,7 @@ tasks: desc: End-to-end — build akua, then run every SDK test with AKUA_E2E=1 (unlocks the gated e2e cases) deps: [sdk:install] cmds: - - cargo build -p akua-cli + - cargo build -p akuapkg-cli - cd packages/sdk && AKUA_E2E=1 bun test sdk:bench: @@ -500,7 +500,7 @@ tasks: - command -v cargo-nextest >/dev/null 2>&1 || cargo install cargo-nextest --locked --version 0.9.86 - cargo llvm-cov clean --workspace # Default features cover the cli + core + napi paths. Example - # golden tests live behind cosign-verify + dev-watch in akua-cli; + # golden tests live behind cosign-verify + dev-watch in akuapkg-cli; # run them in a second instrumented pass so their lines count. # Test failures don't abort report generation — coverage of a # partially-failing run is still informative, and the report @@ -508,7 +508,7 @@ tasks: # --workspace` separately to fail-the-build on real test breakage. - cmd: cargo llvm-cov nextest --no-report --workspace --no-fail-fast ignore_error: true - - cmd: cargo llvm-cov nextest --no-report -p akua-cli --features cosign-verify,dev-watch --no-fail-fast + - cmd: cargo llvm-cov nextest --no-report -p akuapkg-cli --features cosign-verify,dev-watch --no-fail-fast ignore_error: true # Doc tests aren't covered by nextest; bring them in via libtest. # Small impact (~32 fence blocks across the workspace) but counted. diff --git a/crates/akua-core/Cargo.toml b/crates/akua-core/Cargo.toml index 5e169285..e478c6d1 100644 --- a/crates/akua-core/Cargo.toml +++ b/crates/akua-core/Cargo.toml @@ -33,7 +33,7 @@ embed-engines = [ # sources for `@akua-dev/sdk`. `schema-export` does the same for # schemars (JSON Schema bundle). Both are build-time only; zero # cost in production builds. Triggered by the emission test in -# akua-cli (`cargo test -p akua-cli --features schema-export,ts-export`). +# akuapkg-cli (`cargo test -p akuapkg-cli --features schema-export,ts-export`). ts-export = ["dep:ts-rs"] schema-export = ["dep:schemars"] # KCL engine — native Rust via kcl-lang/lib (git dep). diff --git a/crates/akua-core/src/check.rs b/crates/akua-core/src/check.rs index 7925c898..a8617243 100644 --- a/crates/akua-core/src/check.rs +++ b/crates/akua-core/src/check.rs @@ -46,7 +46,7 @@ pub struct CheckResult { /// Run the three gates. Every source is `Option<&str>` because the /// CLI tolerates a workspace missing one or more: a fresh package /// may have no `akua.lock` yet; `akua check --package-only` won't -/// pass a manifest. The akua-cli verb decides when to read each +/// pass a manifest. The akuapkg-cli verb decides when to read each /// file and when to skip. /// /// `package_source` pairs a filename with a buffer; the filename diff --git a/crates/akua-core/src/lib.rs b/crates/akua-core/src/lib.rs index 0efa6e54..b6608d6a 100644 --- a/crates/akua-core/src/lib.rs +++ b/crates/akua-core/src/lib.rs @@ -26,7 +26,7 @@ /// } /// ``` /// -/// Workspace-internal by intent: `akua-cli` reuses it for verbs that +/// Workspace-internal by intent: `akuapkg-cli` reuses it for verbs that /// define their own response types (e.g. `VersionOutput`). External /// consumers don't need it — they're not writing to `sdk-types/` or /// the bundle. `#[macro_export]` is the mechanism that makes the diff --git a/crates/akua-core/src/package_k.rs b/crates/akua-core/src/package_k.rs index 4734f2e8..96691913 100644 --- a/crates/akua-core/src/package_k.rs +++ b/crates/akua-core/src/package_k.rs @@ -128,7 +128,7 @@ impl PackageK { /// typed resource list. /// /// **Private to akua-core.** Production render paths run inside - /// the wasmtime sandbox (see `akua_cli::verbs::render::render_in_worker`) + /// the wasmtime sandbox (see `akuapkg_cli::verbs::render::render_in_worker`) /// per CLAUDE.md's "Sandboxed by default. No shell-out, ever" /// invariant. This method stays crate-private for akua-core's /// own unit tests — it provides the same KCL + plugin-bridge @@ -222,7 +222,7 @@ impl PackageK { /// Parse a rendered Package's top-level YAML (the `yaml_result` KCL /// produced, or an equivalent string the sandboxed render worker /// returns) into a typed [`RenderedPackage`]. Exposed so the -/// wasmtime-hosted render path in `akua-cli` can share the same +/// wasmtime-hosted render path in `akuapkg-cli` can share the same /// parse + validation rules as the native in-process path. pub fn parse_rendered_yaml(yaml: &str) -> Result { parse_rendered(yaml) @@ -501,7 +501,7 @@ pub fn eval_source_with_inputs( /// KCL's import resolver sees the `charts` ExternalPkg and resolves /// `import charts.` to the files there. Plugin callouts from /// those imports still flow through the host-side plugin bridge -/// (helm / kustomize handlers live on akua-cli's side, not in the +/// (helm / kustomize handlers live on akuapkg-cli's side, not in the /// worker). /// /// `kcl_pkgs` is an alias→guest-path map of upstream KCL packages @@ -679,7 +679,7 @@ fn eval_kcl( // can't do that — `std::env::temp_dir()` + `std::fs::write` are // unconditional panics. The host instead preopens its own // materialized stdlib into the worker's WasiCtx at `/akua-stdlib` - // (see `akua_cli::render_worker::invoke_inner`), and we hand + // (see `akuapkg_cli::render_worker::invoke_inner`), and we hand // KCL that guest-visible path. Identical import shape on both // sides: `import akua.helm` resolves either way. let mut external_pkgs: Vec = Vec::new(); diff --git a/crates/akua-napi/Cargo.toml b/crates/akua-napi/Cargo.toml index 5ff87a1e..0b55b736 100644 --- a/crates/akua-napi/Cargo.toml +++ b/crates/akua-napi/Cargo.toml @@ -24,7 +24,7 @@ crate-type = ["cdylib"] [dependencies] # Reuse the CLI verb impls verbatim — every Akua.* method on the JS -# side maps 1:1 to a CLI verb, so depending on `akua-cli`'s lib gives +# side maps 1:1 to a CLI verb, so depending on `akuapkg-cli`'s lib gives # us identical envelopes + identical behavior, no logic at the napi # boundary. # @@ -34,7 +34,7 @@ crate-type = ["cdylib"] # wasmtime JIT-compiles on first render (~5–10 s cold). Shrinks the # published per-platform npm package by 3x; warm renders amortize # the JIT cost across the process lifetime. -akua-cli = { path = "../akua-cli", default-features = false, features = [ +akuapkg-cli = { path = "../akuapkg-cli", default-features = false, features = [ "oci-fetch", "cosign-verify", ] } diff --git a/crates/akua-napi/loader.js b/crates/akua-napi/loader.js index f77b004b..fb67afa4 100644 --- a/crates/akua-napi/loader.js +++ b/crates/akua-napi/loader.js @@ -14,7 +14,7 @@ // Why a separate file: index.js is regenerated on every `napi build`, // so any setup we'd inline there gets clobbered. Keeping the env-var // plumbing in loader.js makes it survive regen + leaves the auto-gen -// machinery untouched. See cnap-tech/akua#482. +// machinery untouched. See akua-dev/akua#482. 'use strict'; diff --git a/crates/akua-napi/src/lib.rs b/crates/akua-napi/src/lib.rs index de8e2028..c48818c7 100644 --- a/crates/akua-napi/src/lib.rs +++ b/crates/akua-napi/src/lib.rs @@ -4,7 +4,7 @@ //! unknown bundle stays for browsers + pure-KCL fast path. //! //! Scope: thin pass-through bindings. Every function delegates to the -//! matching `akua_cli::verbs::*::run` entry, capturing the `--json` +//! matching `akuapkg_cli::verbs::*::run` entry, capturing the `--json` //! envelope to stdout and parsing it back into a `serde_json::Value` //! for the JS caller. Zero envelope divergence from the CLI: same //! bytes, different transport. @@ -15,12 +15,12 @@ use std::collections::HashMap; use std::io::Cursor; use std::path::Path; -use akua_cli::contract::{emit_output, Context}; -use akua_cli::verbs; use akua_core::cli_contract::{ExitCode, StructuredError}; use akua_core::oci_puller::OciPullError; use akua_core::oci_transport::TransportError; use akua_core::vendor as core_vendor; +use akuapkg_cli::contract::{emit_output, Context}; +use akuapkg_cli::verbs; use napi::bindgen_prelude::*; use napi_derive::napi; diff --git a/crates/akua-render-worker/Cargo.toml b/crates/akua-render-worker/Cargo.toml index a07ba46d..79f26419 100644 --- a/crates/akua-render-worker/Cargo.toml +++ b/crates/akua-render-worker/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "akua-render-worker" -description = "Sandboxed render path — `akua render` target compiled to `wasm32-wasip1` and hosted inside the akua-cli wasmtime." +description = "Sandboxed render path — `akua render` target compiled to `wasm32-wasip1` and hosted inside the akuapkg-cli wasmtime." version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true authors.workspace = true -# Binary target — akua-cli instantiates this as a wasmtime module and +# Binary target — akuapkg-cli instantiates this as a wasmtime module and # invokes `_start`. Native builds compile + run the same path for # quick local iteration; wasip1 builds produce the shipping artifact. [[bin]] diff --git a/crates/akua-cli/Cargo.toml b/crates/akuapkg-cli/Cargo.toml similarity index 93% rename from crates/akua-cli/Cargo.toml rename to crates/akuapkg-cli/Cargo.toml index 2d4df0a3..97084054 100644 --- a/crates/akua-cli/Cargo.toml +++ b/crates/akuapkg-cli/Cargo.toml @@ -1,30 +1,29 @@ [package] -name = "akua-cli" -description = "Akua command-line tool" +name = "akuapkg-cli" +description = "Akua Package command-line tool" version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true authors.workspace = true +# Runs at build time to AOT-compile the render-worker .wasm into a +# platform-specific .cwasm. Module::deserialize at run time is a +# memcpy + fixup; Module::new would spend seconds in Cranelift per +# startup. +build = "build.rs" [lib] -name = "akua_cli" +name = "akuapkg_cli" path = "src/lib.rs" [[bin]] -name = "akua" +name = "akuapkg" path = "src/main.rs" -# Runs at build time to AOT-compile the render-worker .wasm into a -# platform-specific .cwasm. Module::deserialize at run time is a -# memcpy + fixup; Module::new would spend seconds in Cranelift per -# startup. -build = "build.rs" - [features] # Pass-through gates mirroring akua-core. Lets call-sites in the CLI # tree `#[cfg(feature = "cosign-verify")]` their own bits (e.g. the -# attestation chain walker in `akua verify`) rather than leaking the +# attestation chain walker in `akuapkg verify`) rather than leaking the # toggle through the core-only feature. default = ["oci-fetch", "cosign-verify", "dev-watch", "precompile-engines", "embed-engines", "otel"] oci-fetch = ["akua-core/oci-fetch"] @@ -38,7 +37,7 @@ precompile-engines = ["akua-core/precompile-engines"] # `embed-engines` (default on): include_bytes!() the helm + kustomize # engine wasm into the binary. Disable for the napi npm distribution # where the engines ship via `@akua-dev/native-engines` and the -# loader points at them via AKUA_NATIVE_ENGINES_DIR. See cnap-tech/akua#482. +# loader points at them via AKUA_NATIVE_ENGINES_DIR. See akua-dev/akua#482. embed-engines = ["akua-core/embed-engines"] # OpenTelemetry export. Default on; activates only when the runtime sees # OTEL_EXPORTER_OTLP_ENDPOINT (or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT). Off @@ -49,7 +48,7 @@ otel = ["dep:tracing-opentelemetry", "dep:opentelemetry", "dep:opentelemetry_sdk # as TypeScript sources. `schema-export` does the same for # schemars (JSON Schema). Both are build-time only; zero cost in # production builds. Trigger via the emission test at -# `cargo test -p akua-cli --features schema-export,ts-export`. +# `cargo test -p akuapkg-cli --features schema-export,ts-export`. ts-export = ["akua-core/ts-export", "dep:ts-rs"] schema-export = ["akua-core/schema-export", "dep:schemars"] @@ -62,7 +61,7 @@ serde_yaml = { workspace = true } thiserror = { workspace = true } toml = { workspace = true } reqwest = { workspace = true } -# `akua dev` SIGINT handler. Lightweight, zero transitive deps beyond +# `akuapkg dev` SIGINT handler. Lightweight, zero transitive deps beyond # libc. Feature-gated under `dev-watch` so headless builds don't # pull it. ctrlc = { version = "3", optional = true } diff --git a/crates/akua-cli/build.rs b/crates/akuapkg-cli/build.rs similarity index 95% rename from crates/akua-cli/build.rs rename to crates/akuapkg-cli/build.rs index 77033bce..63eef909 100644 --- a/crates/akua-cli/build.rs +++ b/crates/akuapkg-cli/build.rs @@ -6,7 +6,7 @@ //! (cargo build against `wasm32-wasip1` in `crates/akua-render-worker/`). //! This build.rs expects that artifact to already exist; it does NOT //! recurse into cargo to build the worker. That keeps the build -//! topology cycle-free — akua-cli depends on the precompiled .cwasm, +//! topology cycle-free — akuapkg-cli depends on the precompiled .cwasm, //! the worker is built with its own cargo invocation. //! //! If the worker .wasm isn't present we emit a sentinel empty `.cwasm` @@ -59,11 +59,11 @@ fn main() { // (empty sandbox + runtime E_SANDBOX_UNAVAILABLE) shipped // broken binaries through CI matrices that don't run // `task build:render-worker` — the symptom only surfaces on - // first `akua render` post-install. Better to fail the build. + // first `akuapkg render` post-install. Better to fail the build. // // dev / test profiles still get the empty-sandbox fallback // so contributors who haven't run `task build:render-worker` - // yet aren't blocked from compiling akua-cli for unit tests + // yet aren't blocked from compiling akuapkg-cli for unit tests // that don't exercise the worker. let profile = std::env::var("PROFILE").unwrap_or_default(); let release_like = profile == "release" @@ -73,7 +73,7 @@ fn main() { panic!( "akua-render-worker.wasm not found at {} — release profiles must ship a worker. \ Run `task build:render-worker` (or set AKUA_REQUIRE_WORKER=0 to override) before \ - `cargo build -p akua-cli --release`.", + `cargo build -p akuapkg-cli --release`.", worker_wasm.display() ); } @@ -87,7 +87,7 @@ fn main() { } // Freshness check: verify that the embedded worker .wasm was built - // from the same akua-core sources akua-cli is currently compiling + // from the same akua-core sources akuapkg-cli is currently compiling // against. Mismatch = host/worker drift = release-quality bug. // // Two signals, in order: @@ -244,13 +244,13 @@ fn walk_for_newer_source( None } -/// akua-cli's build.rs runs with CWD = crates/akua-cli. The workspace +/// akuapkg-cli's build.rs runs with CWD = crates/akuapkg-cli. The workspace /// root sits two parents up. fn workspace_root() -> PathBuf { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"); PathBuf::from(manifest_dir) .parent() .and_then(|p| p.parent()) - .expect("crates/akua-cli parent chain") + .expect("crates/akuapkg-cli parent chain") .to_path_buf() } diff --git a/crates/akua-cli/src/api_config.rs b/crates/akuapkg-cli/src/api_config.rs similarity index 100% rename from crates/akua-cli/src/api_config.rs rename to crates/akuapkg-cli/src/api_config.rs diff --git a/crates/akua-cli/src/auth_parse.rs b/crates/akuapkg-cli/src/auth_parse.rs similarity index 100% rename from crates/akua-cli/src/auth_parse.rs rename to crates/akuapkg-cli/src/auth_parse.rs diff --git a/crates/akua-cli/src/contract/args.rs b/crates/akuapkg-cli/src/contract/args.rs similarity index 100% rename from crates/akua-cli/src/contract/args.rs rename to crates/akuapkg-cli/src/contract/args.rs diff --git a/crates/akua-cli/src/contract/context.rs b/crates/akuapkg-cli/src/contract/context.rs similarity index 100% rename from crates/akua-cli/src/contract/context.rs rename to crates/akuapkg-cli/src/contract/context.rs diff --git a/crates/akua-cli/src/contract/emit.rs b/crates/akuapkg-cli/src/contract/emit.rs similarity index 99% rename from crates/akua-cli/src/contract/emit.rs rename to crates/akuapkg-cli/src/contract/emit.rs index bac78ed2..03ce2d21 100644 --- a/crates/akua-cli/src/contract/emit.rs +++ b/crates/akuapkg-cli/src/contract/emit.rs @@ -138,7 +138,7 @@ mod tests { .with_line(14) .with_suggestion("remove quotes around 3") .with_default_docs() - .with_next_action("edit apps/api/inputs.yaml and re-run akua lint"); + .with_next_action("edit apps/api/inputs.yaml and re-run akuapkg lint"); emit_error(&mut buf, &text_ctx(), &err).expect("write"); let out = String::from_utf8(buf).expect("utf-8"); assert!( diff --git a/crates/akua-cli/src/contract/mod.rs b/crates/akuapkg-cli/src/contract/mod.rs similarity index 100% rename from crates/akua-cli/src/contract/mod.rs rename to crates/akuapkg-cli/src/contract/mod.rs diff --git a/crates/akua-cli/src/lib.rs b/crates/akuapkg-cli/src/lib.rs similarity index 100% rename from crates/akua-cli/src/lib.rs rename to crates/akuapkg-cli/src/lib.rs diff --git a/crates/akua-cli/src/main.rs b/crates/akuapkg-cli/src/main.rs similarity index 98% rename from crates/akua-cli/src/main.rs rename to crates/akuapkg-cli/src/main.rs index cadc241f..7093d805 100644 --- a/crates/akua-cli/src/main.rs +++ b/crates/akuapkg-cli/src/main.rs @@ -1,4 +1,4 @@ -//! # akua +//! # akuapkg //! //! Cloud-native packaging CLI. One binary, one contract — every verb //! honours the CLI contract in [`docs/cli-contract.md`](../../../docs/cli-contract.md). @@ -9,10 +9,11 @@ use std::path::PathBuf; use clap::{ArgAction, ArgGroup, Args, Parser, Subcommand}; -use akua_cli::contract::{emit_error, Context, UniversalArgs}; +use akua_core::cli_contract::{AgentContext, ExitCode, StructuredError}; +use akuapkg_cli::contract::{emit_error, Context, UniversalArgs}; #[cfg(feature = "dev-watch")] -use akua_cli::verbs::dev as dev_verb; -use akua_cli::verbs::{ +use akuapkg_cli::verbs::dev as dev_verb; +use akuapkg_cli::verbs::{ add as add_verb, api as api_verb, auth as auth_verb, cache as cache_verb, check as check_verb, diff as diff_verb, export as export_verb, fmt as fmt_verb, init as init_verb, inspect as inspect_verb, lint as lint_verb, lock as lock_verb, pack as pack_verb, @@ -22,11 +23,10 @@ use akua_cli::verbs::{ whoami as whoami_verb, }; #[cfg(feature = "cosign-verify")] -use akua_cli::verbs::{sign as sign_verb, verify_tarball as verify_tarball_verb}; -use akua_core::cli_contract::{AgentContext, ExitCode, StructuredError}; +use akuapkg_cli::verbs::{sign as sign_verb, verify_tarball as verify_tarball_verb}; #[derive(Parser)] -#[command(name = "akua")] +#[command(name = "akuapkg")] #[command(about = "Cloud-native package build and transform toolkit", long_about = None)] #[command(version)] struct Cli { @@ -59,7 +59,7 @@ enum Commands { args: UniversalArgs, }, - /// Print `akua` binary version. + /// Print `akuapkg` binary version. Version { #[command(flatten)] args: UniversalArgs, @@ -309,7 +309,7 @@ enum Commands { /// Produce a cosign signature for a packed tarball. /// /// Writes an `.akuasig` sidecar next to the tarball for a later - /// `akua push --sig` to upload — does not touch a registry. + /// `akuapkg push --sig` to upload — does not touch a registry. /// Unlocks the air-gap flow: pack + sign here, transfer, push + /// upload-sig there. #[cfg(feature = "cosign-verify")] @@ -348,7 +348,7 @@ enum Commands { /// Bump `akua.lock` to whatever upstream now serves. /// - /// Distinct from `akua lock`: where `lock` rejects OCI digest + /// Distinct from `akuapkg lock`: where `lock` rejects OCI digest /// drift (security), `update` accepts it and records the new /// digest. `--dep ` scopes the refresh to one entry. /// Cargo analogue: `cargo update`. @@ -384,7 +384,7 @@ enum Commands { /// Upload a pre-packed `.tar.gz` to OCI. /// - /// The push half of `akua publish`, decomposed so air-gap flows + /// The push half of `akuapkg publish`, decomposed so air-gap flows /// work: pack on one host, transfer the tarball, push from /// another. Push { @@ -420,7 +420,7 @@ enum Commands { /// re-evaluates on each entry, prints the top-level bindings. /// Meta commands start with `.` (`.load `, `.reset`, /// `.show`, `.help`, `.exit`). No engine callables - /// (`helm.template`, `pkg.render`, etc.) — use `akua render` + /// (`helm.template`, `pkg.render`, etc.) — use `akuapkg render` /// against a workspace for those. Repl { #[command(flatten)] @@ -429,7 +429,7 @@ enum Commands { /// Pack the workspace into a local `.tar.gz`. /// - /// Same shape as the tarball `akua publish` uploads, but written + /// Same shape as the tarball `akuapkg publish` uploads, but written /// to disk instead of pushed. Use for air-gap transfers, offline /// signing, or archival diff. Pack { @@ -510,7 +510,7 @@ enum Commands { #[arg(long, default_value = "./package.k")] package: PathBuf, - /// Path to a packed `.tar.gz` (from `akua pack` / `akua pull`). + /// Path to a packed `.tar.gz` (from `akuapkg pack` / `akuapkg pull`). /// When set, overrides `--package`. #[arg(long)] tarball: Option, @@ -898,7 +898,7 @@ struct RenderCliArgs { /// Forbid network access during resolve. /// /// OCI deps must be fully satisfied from the local cache - /// (populated by a prior `akua add`). Path + replace deps are + /// (populated by a prior `akuapkg add`). Path + replace deps are /// unaffected. #[arg(long)] offline: bool, @@ -924,7 +924,7 @@ fn main() { let cli = Cli::parse(); let args = universal_args(&cli.command); let ctx = resolve_ctx(args); - let _observability = akua_cli::observability::init_subscriber(args, &ctx); + let _observability = akuapkg_cli::observability::init_subscriber(args, &ctx); let exit = dispatch(cli.command); std::process::exit(exit.code()); } @@ -1277,12 +1277,12 @@ fn run_vendor_add( fn resolve_auth( auth_pairs: &[String], auth_file: Option<&std::path::Path>, -) -> Result, akua_cli::auth_parse::AuthParseError> { +) -> Result, akuapkg_cli::auth_parse::AuthParseError> { let from_file = auth_file - .map(akua_cli::auth_parse::load_auth_file) + .map(akuapkg_cli::auth_parse::load_auth_file) .transpose()?; - let from_flags = akua_cli::auth_parse::parse_auth_pairs(auth_pairs.iter())?; - Ok(akua_cli::auth_parse::merge_auth(from_file, from_flags)) + let from_flags = akuapkg_cli::auth_parse::parse_auth_pairs(auth_pairs.iter())?; + Ok(akuapkg_cli::auth_parse::merge_auth(from_file, from_flags)) } fn run_api( @@ -1302,7 +1302,7 @@ fn run_api( &StructuredError::new( akua_core::cli_contract::codes::E_UNSUPPORTED, format!( - "`akua api spec --audience {audience}` is not supported until the hosted API serves authorized audience-specific OpenAPI documents" + "`akuapkg api spec --audience {audience}` is not supported until the hosted API serves authorized audience-specific OpenAPI documents" ), ) .with_default_docs(), @@ -1769,10 +1769,10 @@ fn resolve_ctx(args: &UniversalArgs) -> Context { Context::resolve(args, AgentContext::detect()) } -/// Decide where `akua init` writes and what `[package].name` it records. +/// Decide where `akuapkg init` writes and what `[package].name` it records. /// /// Four cases: -/// 1. No name → CWD + sanitized basename (`mkdir foo && cd foo && akua init`). +/// 1. No name → CWD + sanitized basename (`mkdir foo && cd foo && akuapkg init`). /// 2. `.` / `./` → CWD + sanitized basename (the broken case from #4). /// 3. Bare valid identifier → `.//` + name as-is. /// 4. Path-like or invalid identifier → use as path, sanitize basename @@ -1963,7 +1963,7 @@ mod tests { #[test] fn derive_init_with_path_arg_uses_path_target_and_sanitized_basename() { - // `akua init ./Some.Subdir` → target `./Some.Subdir`, name + // `akuapkg init ./Some.Subdir` → target `./Some.Subdir`, name // `some_subdir`. Path-like args are a separate case from `.`. let (target, name) = derive_init_target_and_name(Some("./Some.Subdir")); assert_eq!(target, std::path::PathBuf::from("./Some.Subdir")); diff --git a/crates/akua-cli/src/observability.rs b/crates/akuapkg-cli/src/observability.rs similarity index 97% rename from crates/akua-cli/src/observability.rs rename to crates/akuapkg-cli/src/observability.rs index da00c6c4..41c41cbc 100644 --- a/crates/akua-cli/src/observability.rs +++ b/crates/akuapkg-cli/src/observability.rs @@ -9,7 +9,7 @@ //! 1. `RUST_LOG` env var — escape hatch, full `EnvFilter` syntax. //! 2. `--log-level=…` //! 3. `-v` / `--verbose` (forces `debug`) -//! 4. Default: `warn,akua=info,akua_cli=info,akua_core=info,akua_render_worker=info` +//! 4. Default: `warn,akua=info,akuapkg_cli=info,akua_core=info,akua_render_worker=info` //! //! The legacy `AKUA_BRIDGE_TRACE=1` shortcut is honored by OR-ing //! `akua::bridge=debug` into the resolved filter. @@ -61,7 +61,7 @@ fn resolve_filter_with(args: &UniversalArgs, rust_log: Option<&str>) -> String { // salsa, kcl_*) quiet even at --log-level=debug; only akua* targets // honor the requested level. RUST_LOG remains the escape hatch for // anyone who needs to peek at internals. - format!("warn,akua={level},akua_cli={level},akua_core={level},akua_render_worker={level}") + format!("warn,akua={level},akuapkg_cli={level},akua_core={level},akua_render_worker={level}") } fn resolve_filter(args: &UniversalArgs) -> String { @@ -72,7 +72,7 @@ fn default_filter() -> String { // Leading `warn` silences transitive crates (wasmtime emits an // info span per syscall; kcl/rustc_span/salsa flood at debug); // only akua* targets stay at info. - "warn,akua=info,akua_cli=info,akua_core=info,akua_render_worker=info".to_string() + "warn,akua=info,akuapkg_cli=info,akua_core=info,akua_render_worker=info".to_string() } /// Pure version of [`apply_bridge_trace`]. `bridge_trace` is the value @@ -241,7 +241,7 @@ mod tests { let f = resolve_filter_with(&args, None); assert!(f.starts_with("warn,"), "got: {f}"); assert!(f.contains("akua=trace")); - assert!(f.contains("akua_cli=trace")); + assert!(f.contains("akuapkg_cli=trace")); assert!(f.contains("akua_core=trace")); assert!(f.contains("akua_render_worker=trace")); } diff --git a/crates/akua-cli/src/render_worker.rs b/crates/akuapkg-cli/src/render_worker.rs similarity index 99% rename from crates/akua-cli/src/render_worker.rs rename to crates/akuapkg-cli/src/render_worker.rs index 18691240..28f0854d 100644 --- a/crates/akua-cli/src/render_worker.rs +++ b/crates/akuapkg-cli/src/render_worker.rs @@ -201,7 +201,7 @@ pub enum WorkerError { /// need to run `task build:render-worker` before `cargo build`. #[error( "render sandbox unavailable — worker module wasn't compiled into this akua binary. \ - Run `task build:render-worker` and rebuild akua-cli." + Run `task build:render-worker` and rebuild akuapkg-cli." )] SandboxUnavailable, @@ -258,7 +258,7 @@ pub struct RenderHost { impl RenderHost { /// Process-wide cached host. `RenderHost::new` does a multi-MB /// `Module::deserialize` memcpy of the embedded cwasm — in - /// `akua dev`'s watch loop that adds up. Init once on first + /// `akuapkg dev`'s watch loop that adds up. Init once on first /// success, reuse forever. Init failures are not cached (they /// typically reflect a broken build and the caller may want /// to retry after rebuilding). @@ -657,7 +657,7 @@ struct HostState { /// pointer to KCL. /// /// The worker-side engine bridges (helm/kustomize) live as -/// host-registered plugin handlers in akua-cli; the render worker +/// host-registered plugin handlers in akuapkg-cli; the render worker /// itself stays engine-free. Invariants: /// /// - Guest never sees host addresses — every pointer is a guest @@ -860,7 +860,7 @@ mod tests { } /// Skips when the sandbox wasn't compiled in. Run - /// `task build:render-worker && cargo test -p akua-cli` to get + /// `task build:render-worker && cargo test -p akuapkg-cli` to get /// real coverage. fn host_or_skip() -> Option { match RenderHost::new() { diff --git a/crates/akua-cli/src/test_helpers.rs b/crates/akuapkg-cli/src/test_helpers.rs similarity index 100% rename from crates/akua-cli/src/test_helpers.rs rename to crates/akuapkg-cli/src/test_helpers.rs diff --git a/crates/akua-cli/src/verbs/add.rs b/crates/akuapkg-cli/src/verbs/add.rs similarity index 97% rename from crates/akua-cli/src/verbs/add.rs rename to crates/akuapkg-cli/src/verbs/add.rs index 35575588..3fd5f69f 100644 --- a/crates/akua-cli/src/verbs/add.rs +++ b/crates/akuapkg-cli/src/verbs/add.rs @@ -1,4 +1,4 @@ -//! `akua add` — insert a dependency into `akua.toml`. +//! `akuapkg add` — insert a dependency into `akua.toml`. //! //! Pure manifest-edit verb: parses the existing `akua.toml`, inserts a //! [`Dependency`] keyed by `name`, writes the canonical TOML back. No @@ -102,7 +102,7 @@ impl AddError { AddError::Load(e) => { let base = e.to_structured(); if matches!(e, ManifestLoadError::Missing { .. }) { - base.with_suggestion("run `akua init` first") + base.with_suggestion("run `akuapkg init` first") } else { base } @@ -190,7 +190,7 @@ pub fn run( source: e, })?; - // `akua add` is the verb where OCI pulls + lockfile updates are + // `akuapkg add` is the verb where OCI pulls + lockfile updates are // authorized — this is the Cargo/Go-modules "go get" semantic. // Path deps resolve locally, OCI deps pull over the network, // replace-overridden deps source from the local fork. Prior @@ -212,7 +212,7 @@ pub fn run( offline: false, cache_root: None, expected_digests, - cosign_public_key_pem: None, // akua add surfaces cosign via render / verify + cosign_public_key_pem: None, // akuapkg add surfaces cosign via render / verify reject_replace: akua_core::chart_resolver::replace_rejected_from_env(), auth: None, }; @@ -236,7 +236,7 @@ pub fn run( // Soft-fail: manifest edit above stands. A missing path, // a pre-existing chart dir, an OCI auth 403 for a chart // we can't reach — none of these should undo the user's - // declarative intent. `akua render` re-runs the resolver + // declarative intent. `akuapkg render` re-runs the resolver // strictly when output actually has to be produced. } } diff --git a/crates/akua-cli/src/verbs/api.rs b/crates/akuapkg-cli/src/verbs/api.rs similarity index 99% rename from crates/akua-cli/src/verbs/api.rs rename to crates/akuapkg-cli/src/verbs/api.rs index 7c7293f7..7ed4ae14 100644 --- a/crates/akua-cli/src/verbs/api.rs +++ b/crates/akuapkg-cli/src/verbs/api.rs @@ -341,7 +341,7 @@ fn reject_deferred_response_processing(args: &ApiArgs) -> Result<(), StructuredE if let Some(flag) = unsupported { return Err(StructuredError::new( codes::E_UNSUPPORTED, - format!("{flag} is not implemented for `akua api` yet"), + format!("{flag} is not implemented for `akuapkg api` yet"), ) .with_default_docs()); } diff --git a/crates/akua-cli/src/verbs/auth.rs b/crates/akuapkg-cli/src/verbs/auth.rs similarity index 95% rename from crates/akua-cli/src/verbs/auth.rs rename to crates/akuapkg-cli/src/verbs/auth.rs index 27f71c54..266b802a 100644 --- a/crates/akua-cli/src/verbs/auth.rs +++ b/crates/akuapkg-cli/src/verbs/auth.rs @@ -1,15 +1,15 @@ -//! `akua auth` — manage credentials in `$XDG_CONFIG_HOME/akua/auth.toml`. +//! `akuapkg auth` — manage credentials in `$XDG_CONFIG_HOME/akua/auth.toml`. //! //! Subverbs: -//! - `akua auth list` — enumerate every configured registry across +//! - `akuapkg auth list` — enumerate every configured registry across //! both akua/auth.toml and ~/.docker/config.json. Never prints the //! secret — only `{registry, source, auth_kind}`. -//! - `akua auth add --registry --username ` — reads the +//! - `akuapkg auth add --registry --username ` — reads the //! password from stdin (operator-safe; mirrors //! `docker login --password-stdin`). Writes to akua/auth.toml. -//! - `akua auth add --registry --token` — reads a bearer +//! - `akuapkg auth add --registry --token` — reads a bearer //! token from stdin. Used for GHCR classic PATs, DockerHub PATs. -//! - `akua auth remove --registry ` — drop the entry. +//! - `akuapkg auth remove --registry ` — drop the entry. //! //! Why not interactive prompt + password masking? Tested-code-only, //! scriptable, and matches the docker idiom. No TTY dependency. @@ -43,7 +43,7 @@ impl SecretReader for StdinReader { fn trim_secret(s: &str) -> String { // Strip a single trailing newline (\n or \r\n) — shells pipe - // `echo | akua auth add ...` commonly. Don't strip whitespace + // `echo | akuapkg auth add ...` commonly. Don't strip whitespace // that may be part of the token (tokens are typically // base64url and can't contain whitespace anyway). let trimmed = s.strip_suffix('\n').unwrap_or(s); @@ -99,7 +99,7 @@ pub struct AuthRemoveBody { #[derive(Debug, thiserror::Error)] pub enum AuthVerbError { - #[error("no akua auth config path — set $XDG_CONFIG_HOME or $HOME")] + #[error("no akuapkg auth config path — set $XDG_CONFIG_HOME or $HOME")] NoConfigPath, #[error(transparent)] @@ -108,7 +108,7 @@ pub enum AuthVerbError { #[error("reading secret from stdin: {0}")] SecretRead(#[source] std::io::Error), - #[error("empty secret — `akua auth add` requires a non-empty value on stdin")] + #[error("empty secret — `akuapkg auth add` requires a non-empty value on stdin")] EmptySecret, #[error("write to stdout failed: {0}")] diff --git a/crates/akua-cli/src/verbs/cache.rs b/crates/akuapkg-cli/src/verbs/cache.rs similarity index 97% rename from crates/akua-cli/src/verbs/cache.rs rename to crates/akuapkg-cli/src/verbs/cache.rs index 180ee42f..47d8e36b 100644 --- a/crates/akua-cli/src/verbs/cache.rs +++ b/crates/akuapkg-cli/src/verbs/cache.rs @@ -1,16 +1,16 @@ -//! `akua cache` — list, clear, or locate the content-addressed caches -//! that `akua add` + `akua render` populate on disk. +//! `akuapkg cache` — list, clear, or locate the content-addressed caches +//! that `akuapkg add` + `akuapkg render` populate on disk. //! //! Subverbs: -//! - `akua cache list` — enumerate OCI blobs + git repos/checkouts + +//! - `akuapkg cache list` — enumerate OCI blobs + git repos/checkouts + //! helm charts under `$XDG_CACHE_HOME/akua/{oci,git,helm}` with sizes. -//! - `akua cache clear [--oci | --git | --helm]` — reclaim disk. Default +//! - `akuapkg cache clear [--oci | --git | --helm]` — reclaim disk. Default //! wipes all three; flags narrow it. Safe on absent caches (no-op). -//! - `akua cache path` — print the resolved cache roots. Useful for +//! - `akuapkg cache path` — print the resolved cache roots. Useful for //! scripting `du -sh` / mount-point pinning on CI runners. //! //! Why this exists: ephemeral CI runners + self-hosted agents share -//! disk across tenants. "How big is the akua cache?" and "nuke the +//! disk across tenants. "How big is the akuapkg cache?" and "nuke the //! cache" need deterministic tooling — not `rm -rf` guessing at the //! layout. This verb is the tooling. diff --git a/crates/akua-cli/src/verbs/check.rs b/crates/akuapkg-cli/src/verbs/check.rs similarity index 98% rename from crates/akua-cli/src/verbs/check.rs rename to crates/akuapkg-cli/src/verbs/check.rs index fbe2f5b8..6576a335 100644 --- a/crates/akua-cli/src/verbs/check.rs +++ b/crates/akuapkg-cli/src/verbs/check.rs @@ -1,4 +1,4 @@ -//! `akua check` — fast workspace check: parse akua.toml + akua.lock, +//! `akuapkg check` — fast workspace check: parse akua.toml + akua.lock, //! lint the Package.k. No execution, no writes. //! //! Pure logic lives in `akua_core::check`; this verb is a thin CLI @@ -15,7 +15,7 @@ use akua_core::cli_contract::{codes, ExitCode, StructuredError}; use crate::contract::{emit_output, Context}; /// Re-export so external callers that were importing -/// `akua_cli::verbs::check::{CheckOutput, CheckResult}` (e.g. the +/// `akuapkg_cli::verbs::check::{CheckOutput, CheckResult}` (e.g. the /// SDK bundle export test) keep compiling. pub use akua_core::check::{CheckOutput, CheckResult}; diff --git a/crates/akua-cli/src/verbs/dev.rs b/crates/akuapkg-cli/src/verbs/dev.rs similarity index 97% rename from crates/akua-cli/src/verbs/dev.rs rename to crates/akuapkg-cli/src/verbs/dev.rs index 2436300c..88171ef0 100644 --- a/crates/akua-cli/src/verbs/dev.rs +++ b/crates/akuapkg-cli/src/verbs/dev.rs @@ -1,4 +1,4 @@ -//! `akua dev` — file-watch + hot re-render loop. +//! `akuapkg dev` — file-watch + hot re-render loop. //! //! Runs until Ctrl-C. Each debounced save batch triggers one //! re-render of the target Package; the verdict streams to stdout @@ -25,7 +25,7 @@ pub struct DevArgs<'a> { pub package_path: PathBuf, /// Inputs file. When absent the render uses schema defaults, - /// matching `akua render` auto-discovery. + /// matching `akuapkg render` auto-discovery. pub inputs_path: Option, /// Render output dir. `./deploy` by default. @@ -74,7 +74,7 @@ pub fn run( // Auto-enable the replace gate in agent context (CLAUDE.md: a // composed sub-package must not touch a `replace` directive in - // production), matching `akua render`. `dev` doesn't resolve root + // production), matching `akuapkg render`. `dev` doesn't resolve root // deps yet, but sub-packages it composes do. let reject_replace = ctx.agent.detected || akua_core::chart_resolver::replace_rejected_from_env(); @@ -106,7 +106,7 @@ where args.debounce, |changed| render(changed), |event| { - // Broken-pipe handling: if the user pipes `akua dev | + // Broken-pipe handling: if the user pipes `akuapkg dev | // head`, the first failed write must stop the loop — // otherwise we burn CPU re-rendering to a closed fd. // Setting `stop` here makes the next `should_stop` @@ -137,7 +137,7 @@ fn render_once( ) -> Result { let pkg = PackageK::load(&args.package_path).map_err(|e| e.to_string())?; let inputs = load_inputs(args)?; - // `akua dev` today doesn't resolve `[dependencies]` or expose + // `akuapkg dev` today doesn't resolve `[dependencies]` or expose // strict mode — defer both until the watch loop gets flags for // them. Rendering still runs in the sandbox. let charts = akua_core::chart_resolver::ResolvedCharts::default(); @@ -324,7 +324,7 @@ mod tests { } /// No `inputs_path` set + no auto-discovered file → empty mapping. - /// `akua render` and `akua dev` share this fallback behavior. + /// `akuapkg render` and `akuapkg dev` share this fallback behavior. #[test] fn load_inputs_returns_empty_mapping_when_no_inputs_resolved() { let ws = workspace_with(MINIMAL_PACKAGE_TOML); diff --git a/crates/akua-cli/src/verbs/diff.rs b/crates/akuapkg-cli/src/verbs/diff.rs similarity index 97% rename from crates/akua-cli/src/verbs/diff.rs rename to crates/akuapkg-cli/src/verbs/diff.rs index 43e61d13..659c7f1a 100644 --- a/crates/akua-cli/src/verbs/diff.rs +++ b/crates/akuapkg-cli/src/verbs/diff.rs @@ -1,7 +1,7 @@ -//! `akua diff` — structural diff between two rendered-output directories. +//! `akuapkg diff` — structural diff between two rendered-output directories. //! //! Compare two directories of rendered manifests (typically the output -//! of two `akua render` runs against different inputs or different +//! of two `akuapkg render` runs against different inputs or different //! Package versions). MVP: file-level diff via sha256; line-level YAML //! diff is a follow-up. diff --git a/crates/akua-cli/src/verbs/export.rs b/crates/akuapkg-cli/src/verbs/export.rs similarity index 98% rename from crates/akua-cli/src/verbs/export.rs rename to crates/akuapkg-cli/src/verbs/export.rs index 0f121ba5..4a7bf9fd 100644 --- a/crates/akua-cli/src/verbs/export.rs +++ b/crates/akuapkg-cli/src/verbs/export.rs @@ -1,7 +1,7 @@ -//! `akua export` — emit the Package's `Input` schema in a standard +//! `akuapkg export` — emit the Package's `Input` schema in a standard //! interchange format (JSON Schema 2020-12 or OpenAPI 3.1). //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua export` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg export` section. //! //! Backed by `akua_core::export::export_input_schema` / //! `export_input_openapi`. The verb reads the Package source from diff --git a/crates/akua-cli/src/verbs/fmt.rs b/crates/akuapkg-cli/src/verbs/fmt.rs similarity index 98% rename from crates/akua-cli/src/verbs/fmt.rs rename to crates/akuapkg-cli/src/verbs/fmt.rs index c15a1293..b4dc0cc2 100644 --- a/crates/akua-cli/src/verbs/fmt.rs +++ b/crates/akuapkg-cli/src/verbs/fmt.rs @@ -1,6 +1,6 @@ -//! `akua fmt` — format a Package.k via KCL's formatter. +//! `akuapkg fmt` — format a Package.k via KCL's formatter. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua fmt` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg fmt` section. //! //! KCL-only. Rego formatting not yet implemented. diff --git a/crates/akua-cli/src/verbs/init.rs b/crates/akuapkg-cli/src/verbs/init.rs similarity index 97% rename from crates/akua-cli/src/verbs/init.rs rename to crates/akuapkg-cli/src/verbs/init.rs index 5a73915c..93719c78 100644 --- a/crates/akua-cli/src/verbs/init.rs +++ b/crates/akuapkg-cli/src/verbs/init.rs @@ -1,6 +1,6 @@ -//! `akua init` — scaffold a new Package. +//! `akuapkg init` — scaffold a new Package. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua init` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg init` section. use std::io::Write; use std::path::{Path, PathBuf}; @@ -71,7 +71,7 @@ impl InitError { .with_default_docs(), InitError::EmptyName => { StructuredError::new(codes::E_INIT_EMPTY_NAME, self.to_string()) - .with_suggestion("pass `akua init ` or run from a named directory") + .with_suggestion("pass `akuapkg init ` or run from a named directory") .with_default_docs() } InitError::StdoutWrite(e) => { @@ -307,7 +307,7 @@ mod tests { let inputs = serde_yaml::from_str(&fs::read_to_string(pkg.join("inputs.example.yaml")).unwrap()) .expect("inputs.yaml parses"); - // Render through the wasmtime sandbox — same path `akua render` + // Render through the wasmtime sandbox — same path `akuapkg render` // uses in production. Scaffold must be valid all the way // through, not just parseable. let rendered = crate::verbs::render::render_in_worker( diff --git a/crates/akua-cli/src/verbs/inspect.rs b/crates/akuapkg-cli/src/verbs/inspect.rs similarity index 99% rename from crates/akua-cli/src/verbs/inspect.rs rename to crates/akuapkg-cli/src/verbs/inspect.rs index 5610ffc2..5b4daffe 100644 --- a/crates/akua-cli/src/verbs/inspect.rs +++ b/crates/akuapkg-cli/src/verbs/inspect.rs @@ -1,4 +1,4 @@ -//! `akua inspect` — report a Package's input surface OR a packed +//! `akuapkg inspect` — report a Package's input surface OR a packed //! tarball's metadata, without executing either. //! //! Two modes: @@ -8,8 +8,8 @@ //! discover what inputs the Package expects before invoking it. //! - **Tarball mode** (`--tarball`): read a packed `.tar.gz` in-memory //! without unpacking, report name/version/edition, layer digest, -//! file count, and vendored deps. Pair with `akua pack` + -//! `akua push` — operators triage an air-gap-transferred tarball +//! file count, and vendored deps. Pair with `akuapkg pack` + +//! `akuapkg push` — operators triage an air-gap-transferred tarball //! before pushing it. use std::io::Write; diff --git a/crates/akua-cli/src/verbs/lint.rs b/crates/akuapkg-cli/src/verbs/lint.rs similarity index 96% rename from crates/akua-cli/src/verbs/lint.rs rename to crates/akuapkg-cli/src/verbs/lint.rs index 52a5a358..01268c97 100644 --- a/crates/akua-cli/src/verbs/lint.rs +++ b/crates/akuapkg-cli/src/verbs/lint.rs @@ -1,10 +1,10 @@ -//! `akua lint` — KCL parse-only validation of a Package.k. +//! `akuapkg lint` — KCL parse-only validation of a Package.k. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua lint` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg lint` section. //! //! Parse-only: catches syntax errors and import resolution failures //! without executing the program. Execution errors (schema validation, -//! unresolved options) surface through `akua render --dry-run`. +//! unresolved options) surface through `akuapkg render --dry-run`. use std::io::Write; use std::path::{Path, PathBuf}; diff --git a/crates/akua-cli/src/verbs/lock.rs b/crates/akuapkg-cli/src/verbs/lock.rs similarity index 98% rename from crates/akua-cli/src/verbs/lock.rs rename to crates/akuapkg-cli/src/verbs/lock.rs index 6b22f3dd..ad53a46d 100644 --- a/crates/akua-cli/src/verbs/lock.rs +++ b/crates/akuapkg-cli/src/verbs/lock.rs @@ -1,4 +1,4 @@ -//! `akua lock` — regenerate `akua.lock` from `akua.toml`. +//! `akuapkg lock` — regenerate `akua.lock` from `akua.toml`. //! //! Cargo analogue: `cargo generate-lockfile`. Resolves every declared //! dep (online — path, OCI, git), merges the result into any existing @@ -60,14 +60,14 @@ pub enum LockError { Resolve(#[from] ChartResolveError), #[error( - "lockfile drift detected — on-disk akua.lock doesn't match what `akua lock` would write" + "lockfile drift detected — on-disk akua.lock doesn't match what `akuapkg lock` would write" )] Drift, /// A dep alias is referenced by `import ` (or /// `pkg.render({package = ""})`) but resolves to a Helm /// chart, not a KCL/Akua module. Surfaced at lock time so - /// the user gets a clear message before `akua check` fails + /// the user gets a clear message before `akuapkg check` fails /// with KCL's opaque CannotFindModule. #[error( "dep `{alias}` is referenced by `import {alias}` but resolves as a Helm chart — \ @@ -147,7 +147,7 @@ pub fn run( // via `helm.template(...)` not `import` — surface the mismatch // here, before writing the lockfile, so the user gets a clear // error pointing at the offending alias instead of `CannotFindModule` - // later from `akua check`. + // later from `akuapkg check`. let package_k = args.workspace.join("package.k"); if let Ok(source) = std::fs::read_to_string(&package_k) { if let Some(mismatch) = chart_resolver::validate_import_kinds(&source, &resolved) diff --git a/crates/akua-cli/src/verbs/mod.rs b/crates/akuapkg-cli/src/verbs/mod.rs similarity index 100% rename from crates/akua-cli/src/verbs/mod.rs rename to crates/akuapkg-cli/src/verbs/mod.rs diff --git a/crates/akua-cli/src/verbs/pack.rs b/crates/akuapkg-cli/src/verbs/pack.rs similarity index 97% rename from crates/akua-cli/src/verbs/pack.rs rename to crates/akuapkg-cli/src/verbs/pack.rs index 3ff72355..af8311e8 100644 --- a/crates/akua-cli/src/verbs/pack.rs +++ b/crates/akuapkg-cli/src/verbs/pack.rs @@ -1,4 +1,4 @@ -//! `akua pack` — build the same tarball `akua publish` uploads, but +//! `akuapkg pack` — build the same tarball `akuapkg publish` uploads, but //! to a local file instead of a registry. Use cases: //! //! - **Air-gap workflows**: pack in one environment, transfer the @@ -10,7 +10,7 @@ //! state; diff a later pack against it bit-for-bit. //! //! Output is byte-deterministic given identical inputs (same contract -//! as `akua publish`), so re-packing an unchanged workspace produces +//! as `akuapkg publish`), so re-packing an unchanged workspace produces //! an unchanged tarball digest — callers can pin the layer digest //! downstream. @@ -29,7 +29,7 @@ pub struct PackArgs<'a> { /// Target tarball. When `None`, defaults to /// `/dist/-.tar.gz`. The `dist/` - /// subdir is walker-skipped, so repeated `akua pack` runs + /// subdir is walker-skipped, so repeated `akuapkg pack` runs /// produce byte-identical tarballs. pub out: Option<&'a Path>, diff --git a/crates/akua-cli/src/verbs/publish.rs b/crates/akuapkg-cli/src/verbs/publish.rs similarity index 98% rename from crates/akua-cli/src/verbs/publish.rs rename to crates/akuapkg-cli/src/verbs/publish.rs index 53505241..baf82872 100644 --- a/crates/akua-cli/src/verbs/publish.rs +++ b/crates/akuapkg-cli/src/verbs/publish.rs @@ -1,10 +1,10 @@ -//! `akua publish` — tarball the workspace + push it to an OCI registry. +//! `akuapkg publish` — tarball the workspace + push it to an OCI registry. //! -//! The reciprocal of `akua add`: where add consumes a registry-hosted +//! The reciprocal of `akuapkg add`: where add consumes a registry-hosted //! chart, publish *produces* one. Shape: //! //! ```text -//! akua publish --ref oci://ghcr.io/acme/my-pkg [--tag 0.2.0] +//! akuapkg publish --ref oci://ghcr.io/acme/my-pkg [--tag 0.2.0] //! ``` //! //! Default tag is the `version` field of `[package]` in `akua.toml`, @@ -376,7 +376,7 @@ mod tests { dir } - /// Stand up a mock registry that accepts a full `akua publish`: + /// Stand up a mock registry that accepts a full `akuapkg publish`: /// the two-blob upload pair (layer + config) plus the manifest /// PUT. Returns `(server, oci_ref)`. fn mock_registry_accepting_publishes(repo: &str, tag: &str) -> (MockServer, String) { diff --git a/crates/akua-cli/src/verbs/pull.rs b/crates/akuapkg-cli/src/verbs/pull.rs similarity index 97% rename from crates/akua-cli/src/verbs/pull.rs rename to crates/akuapkg-cli/src/verbs/pull.rs index 3d22ea2a..bd0f199a 100644 --- a/crates/akua-cli/src/verbs/pull.rs +++ b/crates/akuapkg-cli/src/verbs/pull.rs @@ -1,7 +1,7 @@ -//! `akua pull` — retrieve a published akua Package from an OCI registry +//! `akuapkg pull` — retrieve a published akua Package from an OCI registry //! and extract it to a target directory. //! -//! Inverse of `akua publish`. The resolved manifest digest is emitted +//! Inverse of `akuapkg publish`. The resolved manifest digest is emitted //! to stdout so callers can pin it in downstream automation (CI //! scripts, `akua.lock` entries, etc). @@ -20,7 +20,7 @@ pub struct PullArgs<'a> { /// `oci:///` of the published akua Package. pub oci_ref: &'a str, - /// Tag to pull. Required — unlike `akua publish`, there's no + /// Tag to pull. Required — unlike `akuapkg publish`, there's no /// workspace-local default to fall back to. pub tag: &'a str, diff --git a/crates/akua-cli/src/verbs/push.rs b/crates/akuapkg-cli/src/verbs/push.rs similarity index 96% rename from crates/akua-cli/src/verbs/push.rs rename to crates/akuapkg-cli/src/verbs/push.rs index 9816c886..375a9d48 100644 --- a/crates/akua-cli/src/verbs/push.rs +++ b/crates/akuapkg-cli/src/verbs/push.rs @@ -1,19 +1,19 @@ -//! `akua push` — upload a pre-packed `.tar.gz` to an OCI registry. +//! `akuapkg push` — upload a pre-packed `.tar.gz` to an OCI registry. //! -//! The push half of `akua publish`. Pair with `akua pack` to get the +//! The push half of `akuapkg publish`. Pair with `akuapkg pack` to get the //! air-gap workflow: pack on one host, transfer the tarball across a //! boundary, push from another host. //! //! Deliberately minimal: no signing, no attestation, no workspace -//! read. `akua publish` is the all-in-one verb for the common case; -//! `akua push` is for operators who already have a tarball in hand. +//! read. `akuapkg publish` is the all-in-one verb for the common case; +//! `akuapkg push` is for operators who already have a tarball in hand. //! -//! Unlike `akua publish`, `--tag` is required — the tarball has no +//! Unlike `akuapkg publish`, `--tag` is required — the tarball has no //! workspace-local default to fall back to. (We could extract //! akua.toml from the archive to read the version, but that's a //! surprising bit of magic for a verb whose contract is "push this //! byte stream"; operators who want workspace-derived tags should -//! use `akua publish` directly.) +//! use `akuapkg publish` directly.) use std::io::Write; use std::path::{Path, PathBuf}; @@ -234,7 +234,7 @@ fn read_and_validate_sidecar( // Local digest from the same layer bytes we're about to push. // Any divergence here means the sidecar was signed against a - // different tarball (or an akua version whose config blob has + // different tarball (or an akuapkg version whose config blob has // moved). let expected = oci_pusher::compute_publish_digests(layer_bytes).manifest_digest; if s.manifest_digest != expected { diff --git a/crates/akua-cli/src/verbs/remove.rs b/crates/akuapkg-cli/src/verbs/remove.rs similarity index 97% rename from crates/akua-cli/src/verbs/remove.rs rename to crates/akuapkg-cli/src/verbs/remove.rs index e8f8bb37..f9265a34 100644 --- a/crates/akua-cli/src/verbs/remove.rs +++ b/crates/akuapkg-cli/src/verbs/remove.rs @@ -1,9 +1,9 @@ -//! `akua remove` — drop a dependency from `akua.toml` + `akua.lock`. +//! `akuapkg remove` — drop a dependency from `akua.toml` + `akua.lock`. //! //! Mirror of [`crate::verbs::add`]. Edits the manifest, prunes any //! matching `[[package]]` entry from the lockfile, and leaves OCI //! cache artifacts alone (they're content-addressed and cheap to -//! re-fetch — a separate `akua cache gc` verb can reap them later). +//! re-fetch — a separate `akuapkg cache gc` verb can reap them later). use std::io::Write; use std::path::{Path, PathBuf}; @@ -112,7 +112,7 @@ pub fn run( let path = args.workspace.join("akua.toml"); std::fs::write(&path, serialized).map_err(|e| RemoveError::Io { path, source: e })?; - // Prune matching lockfile entries too so `akua verify` stays + // Prune matching lockfile entries too so `akuapkg verify` stays // green after the edit. Skip when the lockfile doesn't exist // yet (a first-edit repo) — that's not an error. match AkuaLock::load(args.workspace) { diff --git a/crates/akua-cli/src/verbs/render.rs b/crates/akuapkg-cli/src/verbs/render.rs similarity index 99% rename from crates/akua-cli/src/verbs/render.rs rename to crates/akuapkg-cli/src/verbs/render.rs index 4e21ea8e..94c8f5f6 100644 --- a/crates/akua-cli/src/verbs/render.rs +++ b/crates/akuapkg-cli/src/verbs/render.rs @@ -1,6 +1,6 @@ -//! `akua render` — execute a Package against inputs and write raw YAML manifests. +//! `akuapkg render` — execute a Package against inputs and write raw YAML manifests. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua render` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg render` section. use std::io::Write; use std::path::{Path, PathBuf}; @@ -136,7 +136,7 @@ pub struct RenderArgs<'a> { /// missing cache entry fails the render with `E_DEP_RESOLVE` /// (distinct from a HTTP failure). Path + replace deps always /// resolve locally, so offline renders keep working for them. - /// Designed for air-gapped CI runners where the `akua add` step + /// Designed for air-gapped CI runners where the `akuapkg add` step /// happened elsewhere. pub offline: bool, @@ -402,7 +402,7 @@ struct DebugEnvelope<'a> { } /// Thin adapter around `akua_core::package_k::resolve_inputs_path` -/// so `akua render` + `akua dev` share the probe order. +/// so `akuapkg render` + `akuapkg dev` share the probe order. fn resolve_inputs_path(args: &RenderArgs<'_>) -> Option { akua_core::package_k::resolve_inputs_path(args.package_path, args.inputs_path) } @@ -458,7 +458,7 @@ fn resolve_package_charts( .map(|p| (p.name, p.digest)) .collect(), Err(LockLoadError::Missing { .. }) => Default::default(), - Err(_) => Default::default(), // lock corruption surfaces via `akua verify` + Err(_) => Default::default(), // lock corruption surfaces via `akuapkg verify` }; let cosign_public_key_pem = load_cosign_public_key(&manifest, workspace)?; @@ -472,10 +472,10 @@ fn resolve_package_charts( // { path = "..." }`); humans can also opt in via env var. See // CLAUDE.md "`replace` and `path` deps are workspace-local". reject_replace: ctx.agent.detected || chart_resolver::replace_rejected_from_env(), - // `akua render` operates on already-vendored deps — the + // `akuapkg render` operates on already-vendored deps — the // resolver hits the local vendor tree first and only falls // back to a network fetch on a cache miss. The vendor step - // (`akua vendor add`) is where credentials enter the + // (`akuapkg vendor add`) is where credentials enter the // pipeline; render doesn't expose `--auth` of its own. auth: None, }; diff --git a/crates/akua-cli/src/verbs/repl.rs b/crates/akuapkg-cli/src/verbs/repl.rs similarity index 95% rename from crates/akua-cli/src/verbs/repl.rs rename to crates/akuapkg-cli/src/verbs/repl.rs index db05bb37..9b3ad9c5 100644 --- a/crates/akua-cli/src/verbs/repl.rs +++ b/crates/akuapkg-cli/src/verbs/repl.rs @@ -1,4 +1,4 @@ -//! `akua repl` — interactive KCL shell. +//! `akuapkg repl` — interactive KCL shell. //! //! Accumulates every submitted line into a growing `.k` source //! buffer, re-evaluates on each submit via the wasmtime-hosted @@ -10,7 +10,7 @@ //! Deliberately minimal for this slice: //! //! - Plain-line editor — `std::io::stdin().read_line`. Users who want -//! history + arrow-keys can wrap with `rlwrap akua repl`. +//! history + arrow-keys can wrap with `rlwrap akuapkg repl`. //! - No Rego layer. Lands when the policy engine phase is designed. //! - No engine callables (`helm.template`, `pkg.render`, etc.) — //! those belong inside a workspace the repl doesn't materialize. @@ -23,8 +23,8 @@ //! //! JSON output is not meaningful for an interactive verb; `--json` //! falls back to a one-line "repl doesn't emit JSON" banner + text -//! mode. Agents invoking `akua repl` programmatically should use -//! `akua render` or `akua inspect` instead. +//! mode. Agents invoking `akuapkg repl` programmatically should use +//! `akuapkg render` or `akuapkg inspect` instead. //! //! ## KCL quirks //! @@ -74,13 +74,13 @@ pub fn run( if matches!(ctx.output, crate::contract::OutputMode::Json) { writeln!( stdout, - "{{\"note\":\"akua repl is interactive; JSON output is not supported — falling back to text\"}}" + "{{\"note\":\"akuapkg repl is interactive; JSON output is not supported — falling back to text\"}}" ) .map_err(ReplError::StdoutWrite)?; } else { writeln!( stdout, - "akua repl — KCL interactive (type `.exit` or Ctrl-D to quit, `.help` for commands)" + "akuapkg repl — KCL interactive (type `.exit` or Ctrl-D to quit, `.help` for commands)" ) .map_err(ReplError::StdoutWrite)?; } @@ -97,7 +97,7 @@ pub fn run( let n = stdin.read_line(&mut line).map_err(ReplError::StdinRead)?; if n == 0 { // EOF — exit cleanly so the repl composes with piped - // scripts (`echo "x = 42" | akua repl` → one eval + exit). + // scripts (`echo "x = 42" | akuapkg repl` → one eval + exit). writeln!(stdout).map_err(ReplError::StdoutWrite)?; return Ok(ExitCode::Success); } @@ -361,6 +361,6 @@ mod tests { run(&ctx_human(), &ReplArgs, &mut stdin, &mut stdout).unwrap(); // Quit writes the greeter + prompt, no render body. let text = String::from_utf8(stdout).unwrap(); - assert!(text.starts_with("akua repl"), "{text}"); + assert!(text.starts_with("akuapkg repl"), "{text}"); } } diff --git a/crates/akua-cli/src/verbs/sign.rs b/crates/akuapkg-cli/src/verbs/sign.rs similarity index 99% rename from crates/akua-cli/src/verbs/sign.rs rename to crates/akuapkg-cli/src/verbs/sign.rs index 1bfda28d..d2781246 100644 --- a/crates/akua-cli/src/verbs/sign.rs +++ b/crates/akuapkg-cli/src/verbs/sign.rs @@ -1,6 +1,6 @@ //! `akua sign` — produce a cosign signature for a packed tarball //! without touching a registry. Writes an `.akuasig` sidecar next to -//! the tarball for a later `akua push --sig` to upload. +//! the tarball for a later `akuapkg push --sig` to upload. //! //! Flow: //! 1. Read tarball bytes. diff --git a/crates/akua-cli/src/verbs/test.rs b/crates/akuapkg-cli/src/verbs/test.rs similarity index 98% rename from crates/akua-cli/src/verbs/test.rs rename to crates/akuapkg-cli/src/verbs/test.rs index 101f5d26..ecb67fdd 100644 --- a/crates/akua-cli/src/verbs/test.rs +++ b/crates/akuapkg-cli/src/verbs/test.rs @@ -1,4 +1,4 @@ -//! `akua test` — discover + run KCL test files in a workspace. +//! `akuapkg test` — discover + run KCL test files in a workspace. //! //! Convention: any file matching `test_*.k` or `*_test.k` is a test. //! Each is evaluated via the standard PackageK loader; KCL's @@ -83,7 +83,7 @@ pub fn run( let assertions = test_runner::run(args.workspace)?; // `--update-snapshots` implies `--golden`. We intentionally - // still run assertion tests so `akua test --update-snapshots` + // still run assertion tests so `akuapkg test --update-snapshots` // doesn't silently skip authoring-quality checks while ops // assume they passed. let want_golden = args.golden || args.update_snapshots; diff --git a/crates/akua-cli/src/verbs/tree.rs b/crates/akuapkg-cli/src/verbs/tree.rs similarity index 98% rename from crates/akua-cli/src/verbs/tree.rs rename to crates/akuapkg-cli/src/verbs/tree.rs index 42a06f62..e8c7a403 100644 --- a/crates/akua-cli/src/verbs/tree.rs +++ b/crates/akuapkg-cli/src/verbs/tree.rs @@ -1,4 +1,4 @@ -//! `akua tree` — print the manifest's declared deps + lockfile entries. +//! `akuapkg tree` — print the manifest's declared deps + lockfile entries. //! //! Pure walker logic lives in `akua_core::tree`; this verb reads //! files, delegates, renders the human-mode text on top of the @@ -14,7 +14,7 @@ use akua_core::{tree_from_sources, LockLoadError, ManifestLoadError, TreeSourceE use crate::contract::{emit_output, Context}; /// Re-exports so external callers importing -/// `akua_cli::verbs::tree::{TreeOutput, DepRow, …}` keep compiling. +/// `akuapkg_cli::verbs::tree::{TreeOutput, DepRow, …}` keep compiling. pub use akua_core::tree::{DepRow, LockedInfo, PackageInfo, TreeOutput}; #[derive(Debug, Clone)] diff --git a/crates/akua-cli/src/verbs/update.rs b/crates/akuapkg-cli/src/verbs/update.rs similarity index 98% rename from crates/akua-cli/src/verbs/update.rs rename to crates/akuapkg-cli/src/verbs/update.rs index 8a22eb1f..4534966f 100644 --- a/crates/akua-cli/src/verbs/update.rs +++ b/crates/akuapkg-cli/src/verbs/update.rs @@ -1,9 +1,9 @@ -//! `akua update` — intentionally bump `akua.lock` against whatever +//! `akuapkg update` — intentionally bump `akua.lock` against whatever //! upstream now serves. //! -//! Distinct from [`super::lock`]: where `akua lock` fails hard on +//! Distinct from [`super::lock`]: where `akuapkg lock` fails hard on //! OCI digest drift (security — registry served different bytes than -//! the last pinned digest), `akua update` accepts the drift and +//! the last pinned digest), `akuapkg update` accepts the drift and //! records the new digest. Operators invoke `update` when they //! *want* the refresh. //! diff --git a/crates/akua-cli/src/verbs/vendor.rs b/crates/akuapkg-cli/src/verbs/vendor.rs similarity index 95% rename from crates/akua-cli/src/verbs/vendor.rs rename to crates/akuapkg-cli/src/verbs/vendor.rs index 14fefb7d..0be51cf4 100644 --- a/crates/akua-cli/src/verbs/vendor.rs +++ b/crates/akuapkg-cli/src/verbs/vendor.rs @@ -1,13 +1,13 @@ -//! `akua vendor` — materialize, inspect, and drift-check the workspace +//! `akuapkg vendor` — materialize, inspect, and drift-check the workspace //! vendor tree at `.akua/vendor//`. //! //! Subcommands: -//! - `akua vendor add ` — copy the declared dep into the vendor tree. -//! - `akua vendor check` — compare the vendor tree against the manifest/lock. -//! - `akua vendor list` — inventory the on-disk vendor trees, including orphans. +//! - `akuapkg vendor add ` — copy the declared dep into the vendor tree. +//! - `akuapkg vendor check` — compare the vendor tree against the manifest/lock. +//! - `akuapkg vendor list` — inventory the on-disk vendor trees, including orphans. //! //! This module also keeps the shared `collect_vendor_pairs` helper used by -//! `akua pack` and `akua publish`. The helper lives here because it emits a +//! `akuapkg pack` and `akuapkg publish`. The helper lives here because it emits a //! stderr warning on resolver failure, which is CLI-layer behavior. use std::io::Write; diff --git a/crates/akua-cli/src/verbs/verify.rs b/crates/akuapkg-cli/src/verbs/verify.rs similarity index 98% rename from crates/akua-cli/src/verbs/verify.rs rename to crates/akuapkg-cli/src/verbs/verify.rs index ac2161d0..ebcd8268 100644 --- a/crates/akua-cli/src/verbs/verify.rs +++ b/crates/akuapkg-cli/src/verbs/verify.rs @@ -1,6 +1,6 @@ -//! `akua verify` — lockfile consistency check. +//! `akuapkg verify` — lockfile consistency check. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua verify` section. +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg verify` section. //! //! Enforces, against `akua.toml` + `akua.lock`: //! @@ -59,7 +59,7 @@ pub enum Violation { MissingSignature { name: String, version: String }, /// Path-dep on-disk content diverges from the digest `akua.lock` /// pinned. Someone mutated the vendored chart without re-running - /// `akua add` — either intentional (run add to refresh) or + /// `akuapkg add` — either intentional (run add to refresh) or /// accidental (revert the edit). PathDigestDrift { name: String, @@ -130,7 +130,7 @@ impl VerifyError { VerifyError::Manifest(e) => { let base = e.to_structured(); if matches!(e, ManifestLoadError::Missing { .. }) { - base.with_suggestion("run `akua init` or check the working directory") + base.with_suggestion("run `akuapkg init` or check the working directory") } else { base } @@ -139,7 +139,7 @@ impl VerifyError { let base = e.to_structured(); if matches!(e, LockLoadError::Missing { .. }) { base.with_suggestion( - "run `akua add` to resolve deps and generate the lockfile", + "run `akuapkg add` to resolve deps and generate the lockfile", ) } else { base @@ -222,9 +222,9 @@ pub fn check(workspace: &Path) -> Result { // Path-dep drift detection: re-hash the on-disk chart and compare // to the lockfile digest. A mismatch means someone mutated the - // vendored tree without re-running `akua add` — CI must fail. We + // vendored tree without re-running `akuapkg add` — CI must fail. We // run the resolver in offline mode so OCI/git deps don't touch - // the network from `akua verify`. + // the network from `akuapkg verify`. let drift_resolution = chart_resolver::resolve(&manifest, workspace); if let Ok(resolved) = drift_resolution { for pkg in &lock.packages { @@ -275,7 +275,7 @@ pub fn check(workspace: &Path) -> Result { // what akua.lock pinned. // // Missing sidecar + cryptographic failures + subject drift all - // surface as distinct violations so `akua verify --json` gives + // surface as distinct violations so `akuapkg verify --json` gives // the operator actionable signal. #[cfg(feature = "cosign-verify")] { @@ -478,7 +478,7 @@ fn write_text(stdout: &mut W, output: &VerifyOutput) -> std::io::Resul actual, } => writeln!( stdout, - " - path-digest-drift: {name}\n expected {expected}\n actual {actual}\n run `akua add --force {name} --path ` to refresh" + " - path-digest-drift: {name}\n expected {expected}\n actual {actual}\n run `akuapkg add --force {name} --path ` to refresh" )?, Violation::PathMissing { name, path } => writeln!( stdout, diff --git a/crates/akua-cli/src/verbs/verify_tarball.rs b/crates/akuapkg-cli/src/verbs/verify_tarball.rs similarity index 99% rename from crates/akua-cli/src/verbs/verify_tarball.rs rename to crates/akuapkg-cli/src/verbs/verify_tarball.rs index 217ba79a..b36bc0b6 100644 --- a/crates/akua-cli/src/verbs/verify_tarball.rs +++ b/crates/akuapkg-cli/src/verbs/verify_tarball.rs @@ -1,4 +1,4 @@ -//! `akua verify --tarball` — verify a local tarball + sidecars +//! `akuapkg verify --tarball` — verify a local tarball + sidecars //! against a cosign public key, no registry round-trip. //! //! Pair to `akua sign`: closes the offline loop so operators can diff --git a/crates/akua-cli/src/verbs/version.rs b/crates/akuapkg-cli/src/verbs/version.rs similarity index 97% rename from crates/akua-cli/src/verbs/version.rs rename to crates/akuapkg-cli/src/verbs/version.rs index 4da53483..2bb487e9 100644 --- a/crates/akua-cli/src/verbs/version.rs +++ b/crates/akuapkg-cli/src/verbs/version.rs @@ -1,4 +1,4 @@ -//! `akua version` — CLI version and build info. +//! `akuapkg version` — CLI version and build info. //! //! Exit code always `Success`. Output shape stable across versions; //! only field values differ. diff --git a/crates/akua-cli/src/verbs/whoami.rs b/crates/akuapkg-cli/src/verbs/whoami.rs similarity index 94% rename from crates/akua-cli/src/verbs/whoami.rs rename to crates/akuapkg-cli/src/verbs/whoami.rs index cc56d811..d09744ea 100644 --- a/crates/akua-cli/src/verbs/whoami.rs +++ b/crates/akuapkg-cli/src/verbs/whoami.rs @@ -1,6 +1,6 @@ -//! `akua whoami` — identity + agent context introspection. +//! `akuapkg whoami` — identity + agent context introspection. //! -//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akua whoami` section; +//! Spec: [`docs/cli.md`](../../../../docs/cli.md) `akuapkg whoami` section; //! [`cli-contract.md §1.5`](../../../../docs/cli-contract.md#15-agent-context-auto-detection). use std::io::Write; @@ -42,7 +42,7 @@ pub fn run(ctx: &Context, stdout: &mut W) -> std::io::Result fn write_text(stdout: &mut W, output: &WhoamiOutput) -> std::io::Result<()> { writeln!(stdout, "not logged in")?; - writeln!(stdout, "akua version: {}", output.version)?; + writeln!(stdout, "akuapkg version: {}", output.version)?; if output.agent_context.detected { if let (Some(src), Some(name)) = (output.agent_context.source, &output.agent_context.name) { writeln!( @@ -97,7 +97,7 @@ mod tests { run(&ctx, &mut buf).expect("run"); let out = String::from_utf8(buf).expect("utf-8"); assert!(out.contains("not logged in")); - assert!(out.contains("akua version:")); + assert!(out.contains("akuapkg version:")); assert!(!out.contains("agent context:")); } diff --git a/crates/akua-cli/tests/api_integration.rs b/crates/akuapkg-cli/tests/api_integration.rs similarity index 98% rename from crates/akua-cli/tests/api_integration.rs rename to crates/akuapkg-cli/tests/api_integration.rs index a0d5b357..5bba1159 100644 --- a/crates/akua-cli/tests/api_integration.rs +++ b/crates/akuapkg-cli/tests/api_integration.rs @@ -1,4 +1,4 @@ -//! End-to-end tests for `akua api`. +//! End-to-end tests for `akuapkg api`. //! //! These drive the compiled binary against a local mock server so the //! hosted API bridge never talks to the real Akua API during tests. @@ -11,10 +11,10 @@ use httpmock::prelude::*; use httpmock::Method::HEAD; use serde_json::json; -const AKUA_BIN: &str = env!("CARGO_BIN_EXE_akua"); +const AKUAPKG_BIN: &str = env!("CARGO_BIN_EXE_akuapkg"); fn run(cwd: &Path, args: &[&str]) -> Output { - Command::new(AKUA_BIN) + Command::new(AKUAPKG_BIN) .current_dir(cwd) .env("AKUA_NO_AGENT_DETECT", "1") .args(args) diff --git a/crates/akua-cli/tests/cli_integration.rs b/crates/akuapkg-cli/tests/cli_integration.rs similarity index 97% rename from crates/akua-cli/tests/cli_integration.rs rename to crates/akuapkg-cli/tests/cli_integration.rs index 1e7466f9..1a88ef1a 100644 --- a/crates/akua-cli/tests/cli_integration.rs +++ b/crates/akuapkg-cli/tests/cli_integration.rs @@ -1,6 +1,6 @@ //! End-to-end integration tests. //! -//! These drive the compiled `akua` binary (not the library surface), +//! These drive the compiled `akuapkg` binary (not the library surface), //! asserting exit codes, stdout JSON shapes, and stderr structured- //! error payloads. Catches regressions the per-verb unit tests miss — //! clap wiring, `main.rs` dispatch, exit-code propagation. @@ -8,23 +8,23 @@ use std::path::Path; use std::process::{Command, Output}; -/// Path to the compiled `akua` binary, injected by Cargo at build time +/// Path to the compiled `akuapkg` binary, injected by Cargo at build time /// for integration tests in `tests/`. -const AKUA_BIN: &str = env!("CARGO_BIN_EXE_akua"); +const AKUAPKG_BIN: &str = env!("CARGO_BIN_EXE_akuapkg"); -/// Run `akua ` in `cwd` and return (exit-code, stdout, stderr). +/// Run `akuapkg ` in `cwd` and return (exit-code, stdout, stderr). /// /// The binary is forced out of agent-detection mode via /// `AKUA_NO_AGENT_DETECT=1` so tests get deterministic text output — /// each test then opts into JSON with `--json` where it wants to /// assert the structured shape. fn run(cwd: &Path, args: &[&str]) -> Output { - Command::new(AKUA_BIN) + Command::new(AKUAPKG_BIN) .current_dir(cwd) .env("AKUA_NO_AGENT_DETECT", "1") .args(args) .output() - .expect("spawn akua binary") + .expect("spawn akuapkg binary") } fn assert_exit(output: &Output, expected: i32) { @@ -101,7 +101,7 @@ fn init_scaffolds_three_files_and_reports_them() { #[test] fn init_dot_uses_cwd_basename_not_literal_dot() { - // `akua init .` from a directory must record the directory's basename + // `akuapkg init .` from a directory must record the directory's basename // in [package].name, not the literal `.` — `.` isn't a valid KCL // identifier and the manifest parser rejects it. let dir = tempdir(); @@ -192,8 +192,8 @@ fn init_then_render_produces_deterministic_manifests() { #[test] fn init_then_render_without_inputs_flag_uses_scaffold_inputs_example() { - // After `akua init`, the scaffold drops `inputs.example.yaml` next - // to package.k. `akua render` without --inputs should auto-discover + // After `akuapkg init`, the scaffold drops `inputs.example.yaml` next + // to package.k. `akuapkg render` without --inputs should auto-discover // it so the scaffold workflow is a single command. let dir = tempdir(); run(dir.path(), &["init", "app"]); @@ -401,7 +401,7 @@ fn render_missing_package_surfaces_structured_error_on_stderr() { fn path_dep_to_akua_package_resolves_through_tree() { // A [dependencies] entry pointing to a sibling Akua Package // (akua.toml + package.k, no kcl.mod) must resolve through the - // dep system. `akua tree --json` reports resolved deps; without + // dep system. `akuapkg tree --json` reports resolved deps; without // detection of the Akua-package shape the resolver would // classify the dep as a Helm chart. let dir = tempdir(); @@ -458,7 +458,7 @@ fn lock_rejects_helm_dep_referenced_via_import() { // A [dependencies] entry that resolves as a Helm chart but // appears in `import ` must fail at lock time with // E_DEP_KIND_MISMATCH — without this guard the lockfile writes - // cleanly and the failure defers to `akua check`'s opaque + // cleanly and the failure defers to `akuapkg check`'s opaque // CannotFindModule. // // The chart is staged inside the install workspace so the @@ -876,7 +876,7 @@ fn agent_env_flips_output_mode_to_json_automatically() { // AKUA_NO_AGENT_DETECT set, Command would inherit it and silently // defeat this test. let dir = tempdir(); - let out = Command::new(AKUA_BIN) + let out = Command::new(AKUAPKG_BIN) .current_dir(dir.path()) .env_remove("AKUA_NO_AGENT_DETECT") .env("CLAUDECODE", "1") diff --git a/crates/akua-cli/tests/examples_export.rs b/crates/akuapkg-cli/tests/examples_export.rs similarity index 93% rename from crates/akua-cli/tests/examples_export.rs rename to crates/akuapkg-cli/tests/examples_export.rs index c11dd5b0..acf471c9 100644 --- a/crates/akua-cli/tests/examples_export.rs +++ b/crates/akuapkg-cli/tests/examples_export.rs @@ -1,4 +1,4 @@ -//! End-to-end check: `akua export` against the canonical +//! End-to-end check: `akuapkg export` against the canonical //! `examples/01-hello-webapp/package.k` produces JSON Schema 2020-12 //! that matches the committed golden at //! `examples/01-hello-webapp/exported/inputs.schema.json`. Catches @@ -9,9 +9,9 @@ use std::path::{Path, PathBuf}; -use akua_cli::contract::Context; -use akua_cli::verbs::export::{run, ExportArgs, ExportFormat}; use akua_core::cli_contract::ExitCode; +use akuapkg_cli::contract::Context; +use akuapkg_cli::verbs::export::{run, ExportArgs, ExportFormat}; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_hello_webapp.rs b/crates/akuapkg-cli/tests/examples_hello_webapp.rs similarity index 98% rename from crates/akua-cli/tests/examples_hello_webapp.rs rename to crates/akuapkg-cli/tests/examples_hello_webapp.rs index 1becd19b..9e991147 100644 --- a/crates/akua-cli/tests/examples_hello_webapp.rs +++ b/crates/akuapkg-cli/tests/examples_hello_webapp.rs @@ -12,8 +12,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_helm_hello.rs b/crates/akuapkg-cli/tests/examples_helm_hello.rs similarity index 97% rename from crates/akua-cli/tests/examples_helm_hello.rs rename to crates/akuapkg-cli/tests/examples_helm_hello.rs index fc3f7158..26ca253b 100644 --- a/crates/akua-cli/tests/examples_helm_hello.rs +++ b/crates/akuapkg-cli/tests/examples_helm_hello.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_helm_repo_dep.rs b/crates/akuapkg-cli/tests/examples_helm_repo_dep.rs similarity index 97% rename from crates/akua-cli/tests/examples_helm_repo_dep.rs rename to crates/akuapkg-cli/tests/examples_helm_repo_dep.rs index 370a1b12..54ad14a5 100644 --- a/crates/akua-cli/tests/examples_helm_repo_dep.rs +++ b/crates/akuapkg-cli/tests/examples_helm_repo_dep.rs @@ -17,10 +17,10 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::chart_resolver::ResolverOptions; use akua_core::lock_file::AkuaLock; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) @@ -46,7 +46,7 @@ fn renders_helm_repo_dep_podinfo() { "example 14 must declare the podinfo dep" ); - // Mirror the production `akua render` flow: load akua.lock for digest + // Mirror the production `akuapkg render` flow: load akua.lock for digest // pinning, run the resolver online so first-time fetches populate // `~/.cache/akua/helm//podinfo/` from the Helm repository. let lock = AkuaLock::load(&dir).expect("load akua.lock"); diff --git a/crates/akua-cli/tests/examples_install_as_package.rs b/crates/akuapkg-cli/tests/examples_install_as_package.rs similarity index 98% rename from crates/akua-cli/tests/examples_install_as_package.rs rename to crates/akuapkg-cli/tests/examples_install_as_package.rs index 14a69c74..ec1564f7 100644 --- a/crates/akua-cli/tests/examples_install_as_package.rs +++ b/crates/akuapkg-cli/tests/examples_install_as_package.rs @@ -7,8 +7,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_kcl_ecosystem.rs b/crates/akuapkg-cli/tests/examples_kcl_ecosystem.rs similarity index 97% rename from crates/akua-cli/tests/examples_kcl_ecosystem.rs rename to crates/akuapkg-cli/tests/examples_kcl_ecosystem.rs index fa7a9a91..9904419d 100644 --- a/crates/akua-cli/tests/examples_kcl_ecosystem.rs +++ b/crates/akuapkg-cli/tests/examples_kcl_ecosystem.rs @@ -15,10 +15,10 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::chart_resolver::ResolverOptions; use akua_core::lock_file::{AkuaLock, LockedPackage}; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) @@ -44,7 +44,7 @@ fn renders_kcl_ecosystem_dep_against_golden() { "example 10 must declare the k8s dep" ); - // Mirror the production `akua render` flow: load akua.lock for + // Mirror the production `akuapkg render` flow: load akua.lock for // digest pinning, run the resolver online so first-time pulls // populate `~/.cache/akua/oci/sha256//` from ghcr.io. let lock = AkuaLock::load(&dir).expect("load akua.lock"); diff --git a/crates/akua-cli/tests/examples_kustomize_hello.rs b/crates/akuapkg-cli/tests/examples_kustomize_hello.rs similarity index 97% rename from crates/akua-cli/tests/examples_kustomize_hello.rs rename to crates/akuapkg-cli/tests/examples_kustomize_hello.rs index b785b22d..b9e725eb 100644 --- a/crates/akua-cli/tests/examples_kustomize_hello.rs +++ b/crates/akuapkg-cli/tests/examples_kustomize_hello.rs @@ -9,8 +9,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_pkg_compose.rs b/crates/akuapkg-cli/tests/examples_pkg_compose.rs similarity index 98% rename from crates/akua-cli/tests/examples_pkg_compose.rs rename to crates/akuapkg-cli/tests/examples_pkg_compose.rs index a4113551..b7d5688f 100644 --- a/crates/akua-cli/tests/examples_pkg_compose.rs +++ b/crates/akuapkg-cli/tests/examples_pkg_compose.rs @@ -7,8 +7,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_subpackage_helm.rs b/crates/akuapkg-cli/tests/examples_subpackage_helm.rs similarity index 98% rename from crates/akua-cli/tests/examples_subpackage_helm.rs rename to crates/akuapkg-cli/tests/examples_subpackage_helm.rs index e48cce59..d132d677 100644 --- a/crates/akua-cli/tests/examples_subpackage_helm.rs +++ b/crates/akuapkg-cli/tests/examples_subpackage_helm.rs @@ -15,8 +15,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/examples_vendor_offline.rs b/crates/akuapkg-cli/tests/examples_vendor_offline.rs similarity index 98% rename from crates/akua-cli/tests/examples_vendor_offline.rs rename to crates/akuapkg-cli/tests/examples_vendor_offline.rs index 457b01e3..3315d079 100644 --- a/crates/akua-cli/tests/examples_vendor_offline.rs +++ b/crates/akuapkg-cli/tests/examples_vendor_offline.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK}; +use akuapkg_cli::verbs::render::render_in_worker; fn example_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")) diff --git a/crates/akua-cli/tests/export_sdk_bundle.rs b/crates/akuapkg-cli/tests/export_sdk_bundle.rs similarity index 83% rename from crates/akua-cli/tests/export_sdk_bundle.rs rename to crates/akuapkg-cli/tests/export_sdk_bundle.rs index f218b4d4..7ec7a96a 100644 --- a/crates/akua-cli/tests/export_sdk_bundle.rs +++ b/crates/akuapkg-cli/tests/export_sdk_bundle.rs @@ -1,7 +1,7 @@ //! Emit the single JSON Schema bundle for the whole akua CLI contract. //! -//! Lives in `akua-cli` (not `akua-core`) because the bundle needs to -//! register types from both crates — akua-cli depends on akua-core, +//! Lives in `akuapkg-cli` (not `akua-core`) because the bundle needs to +//! register types from both crates — akuapkg-cli depends on akua-core, //! so this is the only place that sees the full surface. //! //! ts-rs (feature = "ts-export") emits per-type `.ts` files because @@ -9,26 +9,26 @@ //! type in `$defs` — the standard JSON Schema bundle shape, matching //! how `schemas/v1/akua.json` will ship in the signed release artifact. //! -//! Trigger: `cargo test -p akua-cli --features schema-export --test export_sdk_bundle`. +//! Trigger: `cargo test -p akuapkg-cli --features schema-export --test export_sdk_bundle`. #![cfg(feature = "schema-export")] use std::path::Path; -use akua_cli::verbs::check::CheckOutput; -use akua_cli::verbs::fmt::FmtOutput; -use akua_cli::verbs::inspect::InspectOutput; -use akua_cli::verbs::lint::LintOutput; -use akua_cli::verbs::tree::TreeOutput; -use akua_cli::verbs::verify::VerifyOutput; -use akua_cli::verbs::version::VersionOutput; -use akua_cli::verbs::whoami::WhoamiOutput; use akua_core::cli_contract::error::Level; use akua_core::cli_contract::{AgentContext, AgentSource, ExitCode, StructuredError}; use akua_core::dir_diff::DirDiff; use akua_core::package_k::LintIssue; use akua_core::package_render::RenderSummary; use akua_core::vendor::{VendorAddOutput, VendorCheckOutput, VendorListOutput}; +use akuapkg_cli::verbs::check::CheckOutput; +use akuapkg_cli::verbs::fmt::FmtOutput; +use akuapkg_cli::verbs::inspect::InspectOutput; +use akuapkg_cli::verbs::lint::LintOutput; +use akuapkg_cli::verbs::tree::TreeOutput; +use akuapkg_cli::verbs::verify::VerifyOutput; +use akuapkg_cli::verbs::version::VersionOutput; +use akuapkg_cli::verbs::whoami::WhoamiOutput; use schemars::generate::SchemaSettings; #[test] diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/akua.toml b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/akua.toml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/akua.toml rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/akua.toml diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/Chart.yaml b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/Chart.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/Chart.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/Chart.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/templates/configmap.yaml b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/templates/configmap.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/templates/configmap.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/templates/configmap.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.schema.json b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.schema.json similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.schema.json rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.schema.json diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.yaml b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/chart/values.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/package.k b/crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/package.k similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-contradictory-schema-defaults/package.k rename to crates/akuapkg-cli/tests/fixtures/helm-contradictory-schema-defaults/package.k diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/akua.toml b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/akua.toml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/akua.toml rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/akua.toml diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/chart/Chart.yaml b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/Chart.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/chart/Chart.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/Chart.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/chart/templates/configmap.yaml b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/templates/configmap.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/chart/templates/configmap.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/templates/configmap.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/chart/values.schema.json b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/values.schema.json similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/chart/values.schema.json rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/values.schema.json diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/chart/values.yaml b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/values.yaml similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/chart/values.yaml rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/chart/values.yaml diff --git a/crates/akua-cli/tests/fixtures/helm-union-schema/package.k b/crates/akuapkg-cli/tests/fixtures/helm-union-schema/package.k similarity index 100% rename from crates/akua-cli/tests/fixtures/helm-union-schema/package.k rename to crates/akuapkg-cli/tests/fixtures/helm-union-schema/package.k diff --git a/crates/akua-cli/tests/helm_union_schema.rs b/crates/akuapkg-cli/tests/helm_union_schema.rs similarity index 98% rename from crates/akua-cli/tests/helm_union_schema.rs rename to crates/akuapkg-cli/tests/helm_union_schema.rs index d5362cad..3dccb531 100644 --- a/crates/akua-cli/tests/helm_union_schema.rs +++ b/crates/akuapkg-cli/tests/helm_union_schema.rs @@ -17,8 +17,8 @@ use std::path::{Path, PathBuf}; -use akua_cli::verbs::render::render_in_worker; use akua_core::{chart_resolver, AkuaManifest, PackageK, RenderedPackage}; +use akuapkg_cli::verbs::render::render_in_worker; fn fixture_dir(name: &str) -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join(format!("tests/fixtures/{name}")) diff --git a/crates/akua-cli/tests/sandbox_adversarial.rs b/crates/akuapkg-cli/tests/sandbox_adversarial.rs similarity index 99% rename from crates/akua-cli/tests/sandbox_adversarial.rs rename to crates/akuapkg-cli/tests/sandbox_adversarial.rs index c468bf8a..1efe375d 100644 --- a/crates/akua-cli/tests/sandbox_adversarial.rs +++ b/crates/akuapkg-cli/tests/sandbox_adversarial.rs @@ -29,7 +29,7 @@ use std::path::Path; -use akua_cli::render_worker::{ +use akuapkg_cli::render_worker::{ RenderHost, ResourceLimits, WorkerError, WorkerRequest, WorkerResponse, }; diff --git a/crates/akua-cli/tests/sandbox_nested_wasmtime.rs b/crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs similarity index 97% rename from crates/akua-cli/tests/sandbox_nested_wasmtime.rs rename to crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs index 5f773ea7..5f09c466 100644 --- a/crates/akua-cli/tests/sandbox_nested_wasmtime.rs +++ b/crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs @@ -18,13 +18,13 @@ //! //! task build:render-worker //! task build:helm-engine-wasm -//! cargo test -p akua-cli --test sandbox_nested_wasmtime -- --include-ignored +//! cargo test -p akuapkg-cli --test sandbox_nested_wasmtime -- --include-ignored #![cfg(all(feature = "cosign-verify", feature = "dev-watch"))] use std::path::PathBuf; -use akua_cli::render_worker::{RenderHost, ResourceLimits, WorkerRequest, WorkerResponse}; +use akuapkg_cli::render_worker::{RenderHost, ResourceLimits, WorkerRequest, WorkerResponse}; /// Chart dir path inside the repo — used as `helm.template` input. fn chart_dir() -> PathBuf { diff --git a/crates/helm-engine-wasm/Cargo.toml b/crates/helm-engine-wasm/Cargo.toml index 35089627..8d22e009 100644 --- a/crates/helm-engine-wasm/Cargo.toml +++ b/crates/helm-engine-wasm/Cargo.toml @@ -12,7 +12,7 @@ authors.workspace = true # binary size. With it OFF, the source `.wasm` is embedded and # wasmtime JIT-compiles at first call — meaningful binary-size win # at the cost of ~5–10 s first-render. Off for the `akua-napi` npm -# distribution; on for `akua-cli`'s single-binary release. +# distribution; on for `akuapkg-cli`'s single-binary release. # # `embed-engines` (default on): include_bytes!() the engine wasm # directly into the crate. With it OFF, the per-platform binary @@ -21,7 +21,7 @@ authors.workspace = true # helm-engine.{cwasm|wasm} file. Set OFF on the napi-rs build so the # 7 per-platform `@akua-dev/native-*` packages don't each duplicate # the 73 MB helm wasm; the bytes ship once via -# `@akua-dev/native-engines`. See cnap-tech/akua#482. +# `@akua-dev/native-engines`. See akua-dev/akua#482. [features] default = ["precompile", "embed-engines"] precompile = [] diff --git a/crates/kustomize-engine-wasm/Cargo.toml b/crates/kustomize-engine-wasm/Cargo.toml index 831fdce3..fc33f578 100644 --- a/crates/kustomize-engine-wasm/Cargo.toml +++ b/crates/kustomize-engine-wasm/Cargo.toml @@ -15,7 +15,7 @@ authors.workspace = true # directly. With OFF, the binary carries no bytes; consumer points # `AKUA_NATIVE_ENGINES_DIR` at a directory containing the # kustomize-engine.{cwasm|wasm} file. Mirrors helm-engine-wasm. -# See cnap-tech/akua#482. +# See akua-dev/akua#482. [features] default = ["precompile", "embed-engines"] precompile = [] diff --git a/crates/source-hash/Cargo.toml b/crates/source-hash/Cargo.toml index 57081b47..dad8e6fa 100644 --- a/crates/source-hash/Cargo.toml +++ b/crates/source-hash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "source-hash" -description = "Stable content hash of source trees. Used by `task build:render-worker` (producer) and akua-cli's build.rs (consumer) to verify host/worker lockstep." +description = "Stable content hash of source trees. Used by `task build:render-worker` (producer) and akuapkg-cli's build.rs (consumer) to verify host/worker lockstep." version.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/source-hash/src/lib.rs b/crates/source-hash/src/lib.rs index 92154094..d1fbd1bd 100644 --- a/crates/source-hash/src/lib.rs +++ b/crates/source-hash/src/lib.rs @@ -1,11 +1,11 @@ //! Stable content hash of source trees. //! //! Used to verify that the embedded `akua-render-worker.wasm` was built -//! from the same akua-core sources that `akua-cli` is currently being +//! from the same akua-core sources that `akuapkg-cli` is currently being //! compiled against. Mismatch = host/worker drift = release-quality bug. //! //! The producer (`task build:render-worker`) invokes the binary to write -//! the hash to a file alongside the .wasm. The consumer (akua-cli's +//! the hash to a file alongside the .wasm. The consumer (akuapkg-cli's //! build.rs) imports this lib and recomputes; mismatch flips //! `cargo:warning=` → `panic!` in release-like profiles. //! @@ -98,7 +98,7 @@ fn collect_files(dir: &Path, out: &mut Vec) { } /// Whether `path` is a source file the freshness protocol covers. -/// Shared with akua-cli's mtime fallback walker so a future addition +/// Shared with akuapkg-cli's mtime fallback walker so a future addition /// (e.g. `.kcl`) only has to land in one place. pub fn is_tracked_source(path: &Path) -> bool { matches!( diff --git a/docs/agent-usage.md b/docs/agent-usage.md index 51adc595..0f830dcf 100644 --- a/docs/agent-usage.md +++ b/docs/agent-usage.md @@ -41,7 +41,7 @@ At process start, akua checks environment variables in this order: If any matches, akua silently enables `--json`, `--log=json`, `--no-color`, `--no-progress`, `--no-interactive`. Explicit flags always win (user can force text output with `--no-json` or `--format=text`). -No stderr announcement. No prelude on stdout. Detection is observable via `akua whoami --json` (reveals the `agent_context` field) or at `--log-level=debug`. Otherwise invisible. +No stderr announcement. No prelude on stdout. Detection is observable via `akuapkg whoami --json` (reveals the `agent_context` field) or at `--log-level=debug`. Otherwise invisible. --- @@ -162,13 +162,13 @@ agent loads new-package SKILL.md fully: now has full procedure for scaffolding + adding sources agent executes: - $ akua add chart oci://ghcr.io/bitnami/charts/redis --version 21.0.0 + $ akuapkg add chart oci://ghcr.io/bitnami/charts/redis --version 21.0.0 $ edit package.k to wire redis values to existing schema - $ akua lint - $ akua render --inputs inputs.yaml --out ./rendered + $ akuapkg lint + $ akuapkg render --inputs inputs.yaml --out ./rendered agent verifies: - $ akua diff previous:v1.2 ./rendered --json + $ akuapkg diff previous:v1.2 ./rendered --json (structural diff shows: new source redis, new schema field redis.replicas) agent commits + opens PR: @@ -176,7 +176,7 @@ agent commits + opens PR: $ gh pr create CI runs: - akua lint + diff-gate + policy check → attached to PR as comments + akuapkg lint + diff-gate + policy check → attached to PR as comments human reviews + approves + merges diff --git a/docs/architecture.md b/docs/architecture.md index 505304e3..c476a0e1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -10,7 +10,7 @@ This document describes the **target architecture**. Implementation is tracked i author compile consume ────── ─────── ─────── - KCL Package ──▶ akua render ──▶ reconcilers: + KCL Package ──▶ akuapkg render ──▶ reconcilers: (*.k + akua.toml) │ ArgoCD / Flux / kro │ Helm release lifecycle Rego Policy ──▶ ├─ embedded kubectl / Crossplane @@ -24,7 +24,7 @@ This document describes the **target architecture**. Implementation is tracked i (human intent + │ Kustomize digest-pinned ledger) │ kro (offline) │ - └─ akua publish ──▶ OCI registry + └─ akuapkg publish ──▶ OCI registry (signed + SLSA) (cosign + SLSA v1) ``` @@ -36,9 +36,9 @@ Three stages, each independently pluggable. See [`docs/package-format.md`](./pac |---|---|---| | **CLI** — `akua` binary | 27 shipped verbs + ~10 planned (see [`cli.md`](./cli.md)) | developers, CI, agents in sandboxes | | **SDK** — `@akua-dev/sdk` | same capabilities, Node/Bun-native | backend services that embed akua in-process | -| **Browser** — playground at `akua.dev` + local `akua dev` UI | subset that compiles to WebAssembly | authoring, review, live-preview | +| **Browser** — playground at `akua.dev` + local `akuapkg dev` UI | subset that compiles to WebAssembly | authoring, review, live-preview | -**Trust contract:** the binary, the SDK, and the browser produce byte-identical output for the same inputs. No "the real thing is behind the paywall." A backend service calling `@akua-dev/sdk.render()` gets the same bytes a developer gets from `akua render` in their terminal. +**Trust contract:** the binary, the SDK, and the browser produce byte-identical output for the same inputs. No "the real thing is behind the paywall." A backend service calling `@akua-dev/sdk.render()` gets the same bytes a developer gets from `akuapkg render` in their terminal. See [`docs/cli-contract.md`](./cli-contract.md) for the universal contract every consumer honors. @@ -50,19 +50,19 @@ See [`docs/embedded-engines.md`](./embedded-engines.md) for the embedding contra ## Canonical form is typed code -- **Packages** — authored in **KCL** (`Package.k` with three regions: imports / schema / body). Published as signed OCI artifacts. `akua render` emits raw YAML, one file per resource. See [`docs/package-format.md`](./package-format.md). +- **Packages** — authored in **KCL** (`Package.k` with three regions: imports / schema / body). Published as signed OCI artifacts. `akuapkg render` emits raw YAML, one file per resource. See [`docs/package-format.md`](./package-format.md). - **Policies** — authored in **Rego**. Kyverno / CEL / foreign Rego modules are consumed as compile-resolved imports via `akua.toml`, not runtime string lookups. -- **Higher-level workspace concepts** (App, Environment, Cluster, Secret, Gateway, Workspace, PolicySet, …) — **user-defined KCL schemas** in the consumer's own workspace, shaped to their deployment reality. akua does not ship a KRM vocabulary. Reconcilers (ArgoCD / Flux / kro) consume the raw-Kubernetes output of `akua render`; they don't need akua-specific kinds. +- **Higher-level workspace concepts** (App, Environment, Cluster, Secret, Gateway, Workspace, PolicySet, …) — **user-defined KCL schemas** in the consumer's own workspace, shaped to their deployment reality. akua does not ship a KRM vocabulary. Reconcilers (ArgoCD / Flux / kro) consume the raw-Kubernetes output of `akuapkg render`; they don't need akua-specific kinds. ## Determinism -Same inputs + same `akua.lock` + same akua version → byte-identical output. No `now()`, no `random()`, no env reads, no filesystem reads, no cluster reads inside the render pipeline. +Same inputs + same `akua.lock` + same akuapkg version → byte-identical output. No `now()`, no `random()`, no env reads, no filesystem reads, no cluster reads inside the render pipeline. See [`design-notes.md §engine-determinism`](./design-notes.md#10-engine-determinism-reality-check) for the pragmatic trade-offs (why Helm stays non-pure even though pure-functional would be cleaner). ## Signing + attestation by default -`akua publish` emits a cosign signature plus a SLSA v1 predicate unless the caller explicitly opts out. On pull, the `akua.lock` digest is verified before any bytes touch disk (always — the universal integrity gate); cosign signature + SLSA attestation verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. See [`docs/lockfile-format.md`](./lockfile-format.md) and [`docs/cli.md`](./cli.md) `publish` / `verify`. +`akuapkg publish` emits a cosign signature plus a SLSA v1 predicate unless the caller explicitly opts out. On pull, the `akua.lock` digest is verified before any bytes touch disk (always — the universal integrity gate); cosign signature + SLSA attestation verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. See [`docs/lockfile-format.md`](./lockfile-format.md) and [`docs/cli.md`](./cli.md) `publish` / `verify`. ## What akua is not diff --git a/docs/cli-contract.md b/docs/cli-contract.md index 30535cd3..367a5c7d 100644 --- a/docs/cli-contract.md +++ b/docs/cli-contract.md @@ -13,8 +13,8 @@ This document specifies the universal invariants every `akua` subcommand must sa Every verb accepts `--json` and emits a single, parseable JSON document (or JSON-lines stream for long-running commands) to stdout. No exceptions. ```sh -akua render --json -akua diff a b --json +akuapkg render --json +akuapkg diff a b --json akua deploy status --handle=r-4f2 --json ``` @@ -81,11 +81,11 @@ If any of these are set, the invocation is considered to be running in an **agen | invocation | result | | ----------------------------------------------- | ----------------------------- | -| `akua render --json` in a human shell | JSON — flag wins | -| `akua render --no-json` in an agent context | text — explicit opt-out wins | -| `akua render --format=text` in an agent context | text — explicit override wins | -| `akua render` in a human shell | text — default | -| `akua render` in an agent context | JSON — auto-detected | +| `akuapkg render --json` in a human shell | JSON — flag wins | +| `akuapkg render --no-json` in an agent context | text — explicit opt-out wins | +| `akuapkg render --format=text` in an agent context | text — explicit override wins | +| `akuapkg render` in a human shell | text — default | +| `akuapkg render` in an agent context | JSON — auto-detected | **No signal, by design.** @@ -94,7 +94,7 @@ When detection activates, akua adapts behavior silently. No banner. No stderr an Detection is introspectable when needed: -- `akua whoami --json` includes an `agent_context` field with the detected agent name and source env var. +- `akuapkg whoami --json` includes an `agent_context` field with the detected agent name and source env var. - `--log-level=debug` emits a single `agent_context_detected` event in debug logs — useful for post-hoc diagnosis, silent in normal operation. Otherwise: invisible by default, discoverable on demand. That's the discipline. @@ -141,7 +141,7 @@ Any other exit code is a bug. Agents branch on these codes. Every verb that modifies state accepts `--idempotency-key=`. If the same key is seen twice on the same resource with the same intent, the second call is a no-op and returns the original result. - `akua deploy --idempotency-key=` — safe to retry -- `akua publish --idempotency-key=` — duplicate publish returns the original digest +- `akuapkg publish --idempotency-key=` — duplicate publish returns the original digest - `akua secret rotate --idempotency-key=` — rotating with the same key is idempotent Agents generate fresh UUIDs per logical operation and retry on network errors without risk. @@ -171,7 +171,7 @@ Every verb that blocks on network or reconciliation accepts `--timeout=` to cap the `pkg.render` composition chain (default 16). Hitting the cap fails with `E_RENDER_BUDGET_DEPTH`. Pair with `--timeout` for hardened CI / agent runs. +`akuapkg render` additionally honors `--max-depth=` to cap the `pkg.render` composition chain (default 16). Hitting the cap fails with `E_RENDER_BUDGET_DEPTH`. Pair with `--timeout` for hardened CI / agent runs. Async operations (`deploy`, `rollout`, long-running renders) return an opaque handle immediately; use `akua … wait --handle=` to block. @@ -215,7 +215,7 @@ Same data as `akua help --json` filtered to one verb. Useful for targeted intros - `akua login ` authenticates to an OCI registry. Credentials are stored in the system credential store (Keychain on macOS, libsecret on Linux, Credential Manager on Windows). - No plaintext credentials in config files. -- `akua whoami` returns the current identity, scopes, and registry logins. +- `akuapkg whoami` returns the current identity, scopes, and registry logins. - Tokens can be scoped per-registry; agents receive per-task scoped tokens that expire automatically. --- @@ -314,7 +314,7 @@ When `verdict=needs-approval`, the verb exits with code 5 and does not write; it Every PR adding a verb or flag is reviewed against this contract. The CI lint step includes: -- `akua lint-cli` — checks every verb emits `--json`, has typed exit codes, accepts `--timeout`, passes `--describe --json` round-trip. +- `akuapkg lint-cli` — checks every verb emits `--json`, has typed exit codes, accepts `--timeout`, passes `--describe --json` round-trip. - Contract violations block merge. - Contract amendments require RFC. diff --git a/docs/cli.md b/docs/cli.md index 090d35b0..685cd4e8 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -38,11 +38,11 @@ When `akua` is run inside an AI-agent session, it detects this from env vars and ```sh # Human shell — text output -$ akua render +$ akuapkg render [pretty text output] # Agent context — auto-JSON, no flag needed -$ CLAUDECODE=1 akua render +$ CLAUDECODE=1 akuapkg render {"format":"raw-manifests","target":"./deploy","manifests":3,"hash":"sha256:…"} ``` @@ -55,23 +55,23 @@ See [cli-contract.md §1.5](cli-contract.md#15-agent-context-auto-detection) for ``` AUTHOR PUBLISH DEPLOY OPERATE ------ ------- ------ ------- -akua init akua attest akua deploy akua secret -akua add akua publish akua rollout akua policy -akua vendor akua pull akua dev akua audit -akua render akua inspect akua query -akua diff akua export akua infra +akuapkg init akua attest akua deploy akua secret +akuapkg add akuapkg publish akua rollout akua policy +akuapkg vendor akuapkg pull akuapkg dev akua audit +akuapkg render akuapkg inspect akua query +akuapkg diff akuapkg export akua infra DEVELOP SESSION META ------- ------- ---- -akua test akua login akua help -akua fmt akua logout akua version -akua lint akua whoami akua telemetry -akua check akua api - akua lint-cli +akuapkg test akua login akua help +akuapkg fmt akua logout akuapkg version +akuapkg lint akuapkg whoami akua telemetry +akuapkg check akuapkg api + akuapkg lint-cli akua bench akua trace akua cov -akua repl +akuapkg repl akua eval ``` @@ -90,12 +90,12 @@ Thirty-five verbs. Grouped by purpose. Each covered below. --- -## `akua init` ✅ +## `akuapkg init` ✅ Scaffold a new package or workspace. ``` -akua init [name] [flags] +akuapkg init [name] [flags] ``` Creates a directory with: @@ -108,7 +108,7 @@ Creates a directory with: | flag | description | |---|---| -| `--template=` | use a template (see `akua init --list-templates`) | +| `--template=` | use a template (see `akuapkg init --list-templates`) | | `--package-name=` | name for the Package (defaults to directory name) | | `--no-git` | skip `git init` | | `--list-templates` | list available templates | @@ -138,12 +138,12 @@ Creates a directory with: --- -## `akua add` ✅ +## `akuapkg add` ✅ Insert a dependency into `akua.toml`. Pure manifest edit — the resolver best-effortly updates `akua.lock` immediately after. ``` -akua add (--oci= | --git= | --path= | --repo= --chart=) [flags] +akuapkg add (--oci= | --git= | --path= | --repo= --chart=) [flags] ``` Exactly one source flag is required. `--repo` requires `--chart`. @@ -161,19 +161,19 @@ Exactly one source flag is required. `--repo` requires `--chart`. ```sh # OCI dep -akua add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 +akuapkg add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 # Git dep pinned to a tag -akua add tooling --git https://github.com/acme/tools --tag v1.2.3 +akuapkg add tooling --git https://github.com/acme/tools --tag v1.2.3 # Local path dep -akua add shared --path ../shared +akuapkg add shared --path ../shared # HTTPS Helm-repo dep -akua add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0 +akuapkg add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0 # Replace an existing entry -akua add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.21.0 --force +akuapkg add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.21.0 --force ``` ### Flags @@ -209,16 +209,16 @@ akua add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.21.0 --- -## `akua vendor` ✅ +## `akuapkg vendor` ✅ Materialize and inspect the workspace vendor tree at `.akua/vendor/`. ``` -akua vendor [flags] +akuapkg vendor [flags] ``` Subcommands: -- `add ` — copy the declared dependency into `.akua/vendor//` and pin its digest in `akua.lock`. The dependency must already exist in `[dependencies]`; otherwise the command fails with a suggestion to declare it in `akua.toml`. Works for `path`, `oci`, `git`, and `helm` (repo) deps alike — the resolver's vendor-first lookup is universal across all four source kinds, so once added, the canonical source can be deleted and `akua render` still succeeds via the vendored bytes. +- `add ` — copy the declared dependency into `.akua/vendor//` and pin its digest in `akua.lock`. The dependency must already exist in `[dependencies]`; otherwise the command fails with a suggestion to declare it in `akua.toml`. Works for `path`, `oci`, `git`, and `helm` (repo) deps alike — the resolver's vendor-first lookup is universal across all four source kinds, so once added, the canonical source can be deleted and `akuapkg render` still succeeds via the vendored bytes. - `check` — compare the on-disk vendor trees against `akua.toml` + `akua.lock`. Drift exits with code `1`. - `list` — enumerate on-disk vendor trees, including orphaned entries. @@ -251,15 +251,15 @@ See `examples/12-vendor-offline/` for the end-to-end offline-render contract dem --- -## `akua lint` ✅ +## `akuapkg lint` ✅ Parse-only check of a `package.k` — catches syntax errors and import- resolution failures without executing the program. Runtime errors (schema validation, unresolved options, engine failures) surface -through `akua render --dry-run`. +through `akuapkg render --dry-run`. ``` -akua lint [flags] +akuapkg lint [flags] ``` ### Flags @@ -306,17 +306,17 @@ Or on parse failure: --- -## `akua render` ✅ +## `akuapkg render` ✅ **Run the Package's program.** Evaluate the KCL, invoke every source engine (Helm, kro, Kustomize), compose results, produce deploy-ready manifests. ``` -akua render [path] [flags] +akuapkg render [path] [flags] ``` **Discovery.** With no `path`, renders every user-authored document in the workspace whose schema declares render semantics — typically the workspace's App-shaped documents that reference a Package and carry inputs. With a `path`, renders only that file. Users author their own App / Environment / etc. schemas (akua does not specify them; see [package-format.md](package-format.md)); `render` processes whichever documents the workspace declares as renderable. -> **Not the same as `akua export`.** `render` executes the full pipeline against customer inputs and writes manifests a reconciler applies to a cluster. `export` converts a canonical artifact (schema, user-authored KCL document, policy bundle) into a format view (JSON Schema, YAML, OpenAPI, Rego bundle). Render needs inputs; export usually doesn't. Render invokes engines; export is format translation. See [`akua export`](#akua-export) below. +> **Not the same as `akuapkg export`.** `render` executes the full pipeline against customer inputs and writes manifests a reconciler applies to a cluster. `export` converts a canonical artifact (schema, user-authored KCL document, policy bundle) into a format view (JSON Schema, YAML, OpenAPI, Rego bundle). Render needs inputs; export usually doesn't. Render invokes engines; export is format translation. See [`akuapkg export`](#akuapkg-export) below. ### Flags @@ -330,7 +330,7 @@ akua render [path] [flags] > **Engines.** Helm and Akua-package composition reach the user via alias-method calls — `webapp.template(webapp.TemplateOpts{values = webapp.Values{...}})`, `upstream.render(upstream.Input{...})` — synthesized per dep from `akua.toml`. Kustomize stays engine-direct (`kustomize.build({path = "./overlays"})`) because its input is a within-Package directory, not a typed dep. All backends ship as embedded WASM modules; akua never shells out to `helm` or `kustomize` binaries — every engine runs inside the wasmtime sandbox alongside the render worker. See [`docs/security-model.md`](security-model.md) and [`docs/embedded-engines.md`](embedded-engines.md). > -> **One render output.** akua writes raw YAML manifests, one file per resource. Distribution shapes like Helm charts or OCI bundles are future `akua publish --as ` concerns — they wrap rendered manifests at distribution time, not as a Package-declared output. +> **One render output.** akua writes raw YAML manifests, one file per resource. Distribution shapes like Helm charts or OCI bundles are future `akuapkg publish --as ` concerns — they wrap rendered manifests at distribution time, not as a Package-declared output. ### Exit codes @@ -348,17 +348,17 @@ akua render [path] [flags] } ``` -`format` is always `"raw-manifests"` today. `target` is the resolved output directory. `hash` is `sha256:` of the concatenated `\n` blocks — stable across runs when inputs + lockfile + akua version match. +`format` is always `"raw-manifests"` today. `target` is the resolved output directory. `hash` is `sha256:` of the concatenated `\n` blocks — stable across runs when inputs + lockfile + akuapkg version match. --- -## `akua diff` ✅ +## `akuapkg diff` ✅ Structural diff between two package versions, or between a local package and a published version. ``` -akua diff [flags] -akua diff # diff local HEAD against published ref +akuapkg diff [flags] +akuapkg diff # diff local HEAD against published ref ``` ### Flags @@ -399,7 +399,7 @@ akua diff # diff local HEAD against published ref --- -## `akua attest` 🚧 +## `akuapkg attest` 🚧 Emit a SLSA v1 provenance predicate for the current package or a built artifact. @@ -433,12 +433,12 @@ akua attest [path] [flags] --- -## `akua publish` 🚧 +## `akuapkg publish` 🚧 Push a signed package to an OCI registry. ``` -akua publish [path] [flags] +akuapkg publish [path] [flags] ``` ### Flags @@ -471,12 +471,12 @@ akua publish [path] [flags] --- -## `akua pull` 🚧 +## `akuapkg pull` 🚧 Fetch a package from an OCI registry into the local cache. ``` -akua pull [flags] +akuapkg pull [flags] ``` ### Flags @@ -489,14 +489,14 @@ akua pull [flags] --- -## `akua inspect` ✅ +## `akuapkg inspect` ✅ Report a `package.k`'s input surface — every `option()` call-site with its name, declared type, required flag, default, and help text. Parse-only: the program is not executed. ``` -akua inspect [flags] +akuapkg inspect [flags] ``` ### Flags @@ -531,21 +531,21 @@ kcl_lang's `list_options` only reads a type arg passed directly to > **SDK-first OCI inspection.** Published Akua Package inspection is > available first through `@akua-dev/sdk` as `inspectOciPackage()`. -> The CLI target `akua inspect ` remains future work for +> The CLI target `akuapkg inspect ` remains future work for > full audit reports such as signatures, SLSA attestations, source > provenance, and rendered-manifest counts. --- -## `akua export` ✅ +## `akuapkg export` ✅ **Convert a Package's `Input` schema to a standard interchange format.** Emits JSON Schema 2020-12 (raw) or OpenAPI 3.1 (Input wrapped under `components.schemas`). Backed by KCL's resolver + AST walk; field docstrings become `description`, `@ui(...)` decorators become `x-ui` extensions. ``` -akua export --package [--format=] [--out=] +akuapkg export --package [--format=] [--out=] ``` -> **Not the same as `akua render`.** `export` is format translation — it doesn't invoke Helm / kro / Kustomize and doesn't need customer inputs. It answers *"how do I describe this Package's inputs in a format other tools understand?"* Use `render` when you want deploy-ready manifests; use `export` when you want a schema for a UI form renderer or API doc generator. See [`akua render`](#akua-render) above. +> **Not the same as `akuapkg render`.** `export` is format translation — it doesn't invoke Helm / kro / Kustomize and doesn't need customer inputs. It answers *"how do I describe this Package's inputs in a format other tools understand?"* Use `render` when you want deploy-ready manifests; use `export` when you want a schema for a UI form renderer or API doc generator. See [`akuapkg render`](#akuapkg-render) above. ### Supported formats @@ -596,13 +596,13 @@ schema Input: ```sh # JSON Schema for a web form -akua export --package package.k > inputs.schema.json +akuapkg export --package package.k > inputs.schema.json # OpenAPI 3.1 for API docs -akua export --package package.k --format=openapi > package.openapi.json +akuapkg export --package package.k --format=openapi > package.openapi.json # Write to file directly -akua export --package package.k --out=exported/inputs.schema.json +akuapkg export --package package.k --out=exported/inputs.schema.json ``` ### Exit codes @@ -611,13 +611,13 @@ akua export --package package.k --out=exported/inputs.schema.json --- -## `akua api` ✅ +## `akuapkg api` ✅ Call the hosted Akua API from the OSS CLI. This is an optional hosted extension: local package workflows such as `render`, `export`, `check`, `lint`, `test`, and `verify` do not require hosted API credentials or network access. ``` -akua api [flags] -akua api spec [--audience=] [flags] +akuapkg api [flags] +akuapkg api spec [--audience=] [flags] ``` `` can be a version-relative path such as `/workspaces` or an absolute URL on the configured API origin. Relative paths are resolved under the base URL. The default base URL is `https://api.akua.dev/v1/`. @@ -626,22 +626,22 @@ akua api spec [--audience=] [flags] ```sh # List workspaces -akua api /workspaces +akuapkg api /workspaces # Create a product from a JSON body -akua api /products -X POST --input product.json +akuapkg api /products -X POST --input product.json # Send typed fields as JSON -akua api /access_decisions -X POST -F permission=offers.create +akuapkg api /access_decisions -X POST -F permission=offers.create # Send a workspace context header -akua api /products --workspace ws_123 +akuapkg api /products --workspace ws_123 # Fetch the public OpenAPI document -akua api spec +akuapkg api spec # Use a non-default API origin -akua api /workspaces --base-url https://staging.example.dev/v1/ +akuapkg api /workspaces --base-url https://staging.example.dev/v1/ ``` ### Request flags @@ -677,18 +677,18 @@ Connection values resolve in this order: | bearer token | `--token`, then `AKUA_API_TOKEN` | | workspace context | `--workspace`, then `AKUA_WORKSPACE_ID` | -`akua api` uses hosted API bearer tokens only. `akua auth` remains registry auth for OCI operations and is not reused for hosted API requests. A missing hosted API token fails with `E_AUTH_REQUIRED`; pass `--token` or set `AKUA_API_TOKEN`. +`akuapkg api` uses hosted API bearer tokens only. `akuapkg auth` remains registry auth for OCI operations and is not reused for hosted API requests. A missing hosted API token fails with `E_AUTH_REQUIRED`; pass `--token` or set `AKUA_API_TOKEN`. -### `akua api spec` +### `akuapkg api spec` -`akua api spec` fetches the public OpenAPI document from `/openapi.json` on the configured base URL. `akua api spec --audience public` is equivalent. +`akuapkg api spec` fetches the public OpenAPI document from `/openapi.json` on the configured base URL. `akuapkg api spec --audience public` is equivalent. Elevated audiences are visible in the CLI contract but not served in this release: ```sh -akua api spec --audience partner -akua api spec --audience admin -akua api spec --audience internal +akuapkg api spec --audience partner +akuapkg api spec --audience admin +akuapkg api spec --audience internal ``` Each elevated audience exits with `E_UNSUPPORTED` until the hosted API serves authorized audience-specific OpenAPI documents. The CLI does not locally filter the public OpenAPI document to simulate elevated audiences. @@ -709,12 +709,12 @@ HTTP `401` maps to auth errors, `403` maps to forbidden user errors, `429` exits --- -## `akua dev` ✅ +## `akuapkg dev` ✅ Start the hot-reload development loop. ``` -akua dev [flags] +akuapkg dev [flags] ``` Single long-running process. Watches workspace for changes. Renders, validates policy, applies to local target. Serves a browser UI at `http://localhost:5173`. @@ -745,11 +745,11 @@ Streaming JSON-lines of pipeline events: {"t":1713636002,"stage":"reconcile","resource":"Deployment/api","status":"ready"} ``` -Useful for agents that want to drive `akua dev` programmatically. +Useful for agents that want to drive `akuapkg dev` programmatically. --- -## `akua deploy` 🚧 +## `akuapkg deploy` 🚧 Deploy rendered output to a reconciler target. @@ -805,7 +805,7 @@ akua deploy cancel --handle= --- -## `akua rollout` 🚧 +## `akuapkg rollout` 🚧 Cross-repo / cross-service staged rollout orchestration. @@ -836,7 +836,7 @@ akua rollout abort --handle= # triggers rollback --- -## `akua secret` 🚧 +## `akuapkg secret` 🚧 Typed secret operations. Secrets move as refs, never raw bytes. @@ -878,7 +878,7 @@ akua secret delete # soft delete; needs approval --- -## `akua policy` 🚧 +## `akuapkg policy` 🚧 Policy tier operations. @@ -924,7 +924,7 @@ akua policy publish # publish custom tier to O --- -## `akua audit` 🚧 +## `akuapkg audit` 🚧 Causality spine. Trace changes, explain incidents, query the audit trail. @@ -971,7 +971,7 @@ akua audit who # who has permission to mo --- -## `akua query` 🚧 +## `akuapkg query` 🚧 Structured queries against observability stores. @@ -1010,7 +1010,7 @@ akua query "error_rate p99 last 1h service=checkout" --json --- -## `akua infra` 🚧 +## `akuapkg infra` 🚧 Cluster, network, DNS, cert primitives. Wraps Crossplane or Terraform under the hood. @@ -1030,7 +1030,7 @@ akua infra import # bring external resource under management --- -## `akua login` 🚧 +## `akuapkg login` 🚧 Authenticate to OCI registries and signing providers. @@ -1050,7 +1050,7 @@ Credentials are stored in the system credential store (Keychain, libsecret, Cred --- -## `akua logout` 🚧 +## `akuapkg logout` 🚧 Remove stored credentials. @@ -1061,12 +1061,12 @@ akua logout --all --- -## `akua whoami` ✅ +## `akuapkg whoami` ✅ Display current identity, logged-in registries, and scopes. ``` -akua whoami [flags] +akuapkg whoami [flags] ``` ### JSON output @@ -1091,12 +1091,12 @@ akua whoami [flags] --- -## `akua test` 🚧 +## `akuapkg test` 🚧 Run unit tests for packages, policies, or both. Unified test runner across engines — detects target types by file extension. ``` -akua test [path] [flags] +akuapkg test [path] [flags] ``` Discovers and runs: @@ -1147,12 +1147,12 @@ Discovers and runs: --- -## `akua fmt` ✅ +## `akuapkg fmt` ✅ Format KCL and Rego sources in place. ``` -akua fmt [path] [flags] +akuapkg fmt [path] [flags] ``` Uses embedded `kcl fmt` for `.k` files and embedded `opa fmt` for `.rego` files. Idempotent; safe to run in CI. @@ -1170,15 +1170,15 @@ Uses embedded `kcl fmt` for `.k` files and embedded `opa fmt` for `.rego` files. --- -## `akua check` ✅ +## `akuapkg check` ✅ Syntax + type + dependency check. No execution, no rendering. Fast. ``` -akua check [path] [flags] +akuapkg check [path] [flags] ``` -Stricter than `akua lint` (actual compile errors, not style); cheaper than `akua render` (doesn't invoke engines). Good for IDE save hooks and pre-commit. +Stricter than `akuapkg lint` (actual compile errors, not style); cheaper than `akuapkg render` (doesn't invoke engines). Good for IDE save hooks and pre-commit. ### JSON output @@ -1208,7 +1208,7 @@ On error: --- -## `akua bench` 🚧 +## `akuapkg bench` 🚧 Benchmark policy evaluation and package render latency. @@ -1245,7 +1245,7 @@ Uses OPA partial evaluation for policy benchmarks; the KCL interpreter's own tim --- -## `akua trace` 🚧 +## `akuapkg trace` 🚧 Explain the evaluation path of a policy query. Useful for debugging "why did this rule deny?" or "why didn't this rule fire?" @@ -1279,7 +1279,7 @@ ALLOW deny[msg] evaluated to {"production Deployments must have a team label"} --- -## `akua cov` 🚧 +## `akuapkg cov` 🚧 Generate a test coverage report across rules (Rego) and schemas (KCL). @@ -1287,7 +1287,7 @@ Generate a test coverage report across rules (Rego) and schemas (KCL). akua cov [path] [flags] ``` -Equivalent to `akua test --coverage` but produces a standalone report. Useful for CI gates that enforce a minimum coverage percentage. +Equivalent to `akuapkg test --coverage` but produces a standalone report. Useful for CI gates that enforce a minimum coverage percentage. ### Flags @@ -1298,12 +1298,12 @@ Equivalent to `akua test --coverage` but produces a standalone report. Useful fo --- -## `akua repl` ✅ +## `akuapkg repl` ✅ Interactive REPL for exploring policies and packages. ``` -akua repl [flags] +akuapkg repl [flags] ``` Supports two modes (tab-switched): @@ -1315,7 +1315,7 @@ Useful for experimenting before committing to a rule or package change. --- -## `akua eval` 🚧 +## `akuapkg eval` 🚧 One-shot evaluator — cheap, scriptable. For Rego queries and KCL expressions without entering the REPL. @@ -1346,7 +1346,7 @@ akua eval --lang=kcl 'schema Input; input = Input {...}; input.replicas * 2' --- -## `akua help` 🚧 +## `akuapkg help` 🚧 ``` akua help # list all verbs @@ -1358,11 +1358,11 @@ The `--json` form is the agent-discovery surface. --- -## `akua version` ✅ +## `akuapkg version` ✅ ``` -akua version # print version + git SHA -akua version --json +akuapkg version # print version + git SHA +akuapkg version --json ``` ```json @@ -1378,7 +1378,7 @@ akua version --json --- -## `akua telemetry` 🚧 +## `akuapkg telemetry` 🚧 Opt-in, anonymized usage data. @@ -1393,12 +1393,12 @@ Default: disabled. Agents enable explicitly if desired. --- -## `akua lint-cli` (internal, advanced) 🚧 +## `akuapkg lint-cli` (internal, advanced) 🚧 Validate that the current binary honors the CLI contract. ``` -akua lint-cli +akuapkg lint-cli ``` Used in CI to catch contract violations before release. @@ -1418,9 +1418,9 @@ A minimal set. No hidden state. | `AKUA_LOG_LEVEL` | override `--log-level` | | `AKUA_NO_TELEMETRY` | force telemetry off (for CI) | | `AKUA_TOKEN_FILE` | path to a token file for non-interactive auth | -| `AKUA_API_TOKEN` | hosted API bearer token for `akua api` | -| `AKUA_API_BASE_URL` | hosted API base URL for `akua api` (default: `https://api.akua.dev/v1/`) | -| `AKUA_WORKSPACE_ID` | workspace context sent by `akua api` as `akua-context` | +| `AKUA_API_TOKEN` | hosted API bearer token for `akuapkg api` | +| `AKUA_API_BASE_URL` | hosted API base URL for `akuapkg api` (default: `https://api.akua.dev/v1/`) | +| `AKUA_WORKSPACE_ID` | workspace context sent by `akuapkg api` as `akua-context` | | `AKUA_AGENT` | signal an agent context explicitly (value is the agent name) | | `AKUA_NO_AGENT_DETECT` | disable agent-context auto-detection | diff --git a/docs/debugging.md b/docs/debugging.md index 60ef941f..804e55e9 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -7,7 +7,7 @@ should reach for it before guessing. ## TL;DR ```sh -akua render --package package.k --inputs ... --log=json --log-level=debug 2>&1 | head -20 +akuapkg render --package package.k --inputs ... --log=json --log-level=debug 2>&1 | head -20 ``` Three knobs cover almost every case: @@ -22,7 +22,7 @@ Three knobs cover almost every case: - **CLI contract §9** — [docs/cli-contract.md](cli-contract.md#9-logging) — flag semantics, JSON line shape, target taxonomy. - **CLI contract §9.1** — OpenTelemetry env-var surface. -- **`crates/akua-cli/src/observability.rs`** — host-side subscriber wiring. +- **`crates/akuapkg-cli/src/observability.rs`** — host-side subscriber wiring. - **`crates/akua-render-worker/src/observability.rs`** — worker-side subscriber. ## What you'll see @@ -62,7 +62,7 @@ Frame names + file:line resolve via: If a trap shows bare `wasm function NNNN`: 1. The worker `.wasm` is stale or stripped — run `task build:render-worker` and verify the file size grew. -2. The `.cwasm` AOT artifact may be cached — `cargo clean -p akua-cli && cargo build -p akua-cli` to force a re-bake against the current Config. +2. The `.cwasm` AOT artifact may be cached — `cargo clean -p akuapkg-cli && cargo build -p akuapkg-cli` to force a re-bake against the current Config. ## When a plugin handler fails @@ -94,7 +94,7 @@ If a render fails inside an example: ```sh cd examples/ -cargo run -q -p akua-cli -- render \ +cargo run -q -p akuapkg-cli -- render \ --package package.k \ --inputs inputs.example.yaml \ --log=json --log-level=debug 2>&1 | tail -30 @@ -104,10 +104,10 @@ Tail (not head) grabs the failing event + envelope; head grabs the warm-up traff ## When the worker is the wrong version -A persistent gotcha: `cargo build -p akua-cli` does **not** rebuild the render-worker `.wasm`. The build script emits a warning when sources are newer than the staged `.wasm`: +A persistent gotcha: `cargo build -p akuapkg-cli` does **not** rebuild the render-worker `.wasm`. The build script emits a warning when sources are newer than the staged `.wasm`: ``` -warning: akua-cli@0.7.0: akua-render-worker.wasm is older than crates/akua-core/... — run `task build:render-worker` +warning: akuapkg-cli@0.7.0: akua-render-worker.wasm is older than crates/akua-core/... — run `task build:render-worker` ``` Rebuild explicitly: @@ -145,7 +145,7 @@ For cross-render or production traces, set `OTEL_EXPORTER_OTLP_ENDPOINT`. Exampl docker run --rm -p 4317:4317 -p 16686:16686 jaegertracing/all-in-one OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \ OTEL_SERVICE_NAME=akua-dev \ - cargo run -q -p akua-cli -- render --package examples/00-helm-hello/package.k + cargo run -q -p akuapkg-cli -- render --package examples/00-helm-hello/package.k ``` The same trace tree (`worker.invoke → bridge.call → kcl eval`) shows up at `http://localhost:16686`. The OTel layer is gated on the `otel` cargo feature — on by default for the CLI binary, off for the napi distribution. cli-contract §9.1 lists every honored `OTEL_*` env var. diff --git a/docs/design-notes.md b/docs/design-notes.md index d9523b3b..9f91af73 100644 --- a/docs/design-notes.md +++ b/docs/design-notes.md @@ -19,9 +19,9 @@ ### What akua is - **A single binary and SDK** covering the whole packaging + platform lifecycle: author, render, test, lint, format, sign, publish, verify, diff, inspect, deploy, query, audit. Thirty verbs. One mental model. The bun/deno pattern applied to cloud-native. -- **Typed composition.** Packages authored in **KCL** with first-class schemas; policies authored in **Rego**. YAML is a derived view via `akua export`, never authoritative. -- **Deterministic transformation.** Same inputs + same lockfile + same akua version → byte-identical output. No non-determinism inside the render pipeline. -- **Signed + attested by default.** cosign signature + SLSA v1 predicate on every `akua publish`. On pull, the `akua.lock` digest is always verified (the universal gate); cosign + SLSA verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. +- **Typed composition.** Packages authored in **KCL** with first-class schemas; policies authored in **Rego**. YAML is a derived view via `akuapkg export`, never authoritative. +- **Deterministic transformation.** Same inputs + same lockfile + same akuapkg version → byte-identical output. No non-determinism inside the render pipeline. +- **Signed + attested by default.** cosign signature + SLSA v1 predicate on every `akuapkg publish`. On pull, the `akua.lock` digest is always verified (the universal gate); cosign + SLSA verification engages, fail-closed, when a `[signing] cosign_public_key` is configured. - **Agent-first.** The primary user is an AI agent operating in a Linux sandbox. Humans gate at policy checkpoints. See [`agent-usage.md`](./agent-usage.md). ### What akua is *not* @@ -68,7 +68,7 @@ KCL, Helm, OPA, Regal, Kustomize, kro offline instantiator, CEL, Kyverno-to-Rego Two consequences: (a) `akua` works in any sandbox without pre-provisioning, (b) version drift between engines is impossible — we ship a tested set together. -### 2.5 `akua render` ≠ `akua export` +### 2.5 `akuapkg render` ≠ `akuapkg export` `render` executes the Package's program (invokes engines, produces deploy-ready manifests). `export` converts a canonical artifact to a format view (JSON Schema, OpenAPI, YAML, Rego bundle). Different verbs for different jobs. Conflating them is the most common interface mistake; the CLI contract keeps them separate. @@ -90,13 +90,13 @@ Consequence: we inherit KCL's choices (including its not-quite-Python syntax) an Rego is awkward to learn but genuinely solves cross-resource reasoning and partial evaluation — jobs you cannot do cleanly in KCL. Kyverno is k8s-scoped; CEL can't express cross-resource rules; OPA with Rego is the mature choice. -We make Rego palatable through tooling (Regal linter, opa test runner, `akua repl`) and compile-resolved imports so custom rules stay small. +We make Rego palatable through tooling (Regal linter, opa test runner, `akuapkg repl`) and compile-resolved imports so custom rules stay small. ### 3.3 OCI registries, not a central catalog Centralized package curation is fragile (see Bitnami's deprecation and its fallout). First-party publishing is the durable pattern. We ship signing + distribution + diff + audit infrastructure so any maintainer can publish trustworthy packages themselves. -Consequence: no shelf to browse on day one. Mitigation: browser-based audit at `akua.dev` for any public artifact; `akua init` templates for common starts. +Consequence: no shelf to browse on day one. Mitigation: browser-based audit at `akua.dev` for any public artifact; `akuapkg init` templates for common starts. ### 3.4 Helm v4 still an engine diff --git a/docs/embedded-engines.md b/docs/embedded-engines.md index bba115b5..30db6c86 100644 --- a/docs/embedded-engines.md +++ b/docs/embedded-engines.md @@ -14,7 +14,7 @@ Three reasons, same as the helm-engine-wasm decision: 2. **Version determinism.** akua ships with a known-good engine version. No "works on my machine" where my `opa` is 0.55 and yours is 0.62 and we get different verdicts. 3. **Air-gap friendly.** Environments where customers can't install arbitrary binaries (FedRAMP, certain enterprise networks) still work because akua is self-contained. -Plus the agent case: agents can't install binaries. If `akua test` needs `opa` and there's no `opa` in the sandbox, the agent is stuck. Embedded means the agent gets the full toolkit from one install. +Plus the agent case: agents can't install binaries. If `akuapkg test` needs `opa` and there's no `opa` in the sandbox, the agent is stuck. Embedded means the agent gets the full toolkit from one install. --- @@ -58,7 +58,7 @@ Precompilation: each engine's `build.rs` calls `engine_host_wasm::precompile(... | **Helm v4 template engine** | Go → wasip1 | wasmtime-hosted | shipped (forked to strip client-go; ~20 MB WASM) | | **OPA** (Rego) | Go → wasip1 or OPA-native WASM | wasmtime-hosted | v0.2 | | **Regal** (Rego linter) | Go → wasip1 | wasmtime-hosted | v0.2 | -| **Kyverno-to-Rego converter** | Go → wasip1 | wasmtime-hosted; runs at `akua add` time | v0.3 | +| **Kyverno-to-Rego converter** | Go → wasip1 | wasmtime-hosted; runs at `akuapkg add` time | v0.3 | | **CEL** (`cel-go`) | Go → wasip1 | wasmtime-hosted | v0.3 | | **kustomize** | Go → wasip1 | wasmtime-hosted | v0.3 | | **kro RGD instantiator** | Go → wasip1 (offline path) | wasmtime-hosted | v0.2 | @@ -75,27 +75,27 @@ Each verb that invokes engines documents which ones. From [cli.md](cli.md): | verb | engines used | |---|---| -| `akua init` | KCL (scaffold) | -| `akua add` | (fetch/convert) Kyverno-to-Rego converter, KCL schema generator | -| `akua render` | KCL + Helm + kro offline instantiator + Kustomize + output emitters | -| `akua lint` | KCL + Regal | -| `akua fmt` | KCL + opa fmt | -| `akua check` | KCL + OPA (parse-only) | -| `akua test` | KCL + OPA | +| `akuapkg init` | KCL (scaffold) | +| `akuapkg add` | (fetch/convert) Kyverno-to-Rego converter, KCL schema generator | +| `akuapkg render` | KCL + Helm + kro offline instantiator + Kustomize + output emitters | +| `akuapkg lint` | KCL + Regal | +| `akuapkg fmt` | KCL + opa fmt | +| `akuapkg check` | KCL + OPA (parse-only) | +| `akuapkg test` | KCL + OPA | | `akua trace` | OPA (`--explain`) | | `akua bench` | OPA partial evaluation, KCL interpreter timing | | `akua policy check` | OPA + CEL (via Rego runtime) | -| `akua repl` | KCL + OPA | +| `akuapkg repl` | KCL + OPA | | `akua eval` | KCL or OPA per `--lang` | | `akua attest` | (no engines; just signing + SLSA predicate generation) | -| `akua diff` | KCL + OPA (for policy compat diff) | +| `akuapkg diff` | KCL + OPA (for policy compat diff) | --- ## Determinism guarantees -- Embedded engines are version-pinned to the akua release. Two runs of `akua render` at the same akua version produce byte-identical output (the [CLI contract §1.3](cli-contract.md#13-determinism)). -- An `akua bundle lock` manifest (forthcoming) will record the exact embedded engine versions for the workspace; `akua bundle verify` confirms a CI runner has the same akua version as the last known-good. +- Embedded engines are version-pinned to the akua release. Two runs of `akuapkg render` at the same akuapkg version produce byte-identical output (the [CLI contract §1.3](cli-contract.md#13-determinism)). +- An `akua bundle lock` manifest (forthcoming) will record the exact embedded engine versions for the workspace; `akua bundle verify` confirms a CI runner has the same akuapkg version as the last known-good. --- @@ -117,7 +117,7 @@ System integrations are a separate category from engines. `akua deploy` calls `k ## What's NOT embedded - **`kubectl`** — used only by `akua deploy --to=kubectl`. Too specific to a user's cluster context; we rely on the system version. -- **`git`** — used for `akua publish` and workspace operations. Extremely stable and universally available. +- **`git`** — used for `akuapkg publish` and workspace operations. Extremely stable and universally available. - **`cosign`** — used for signing. We embed the verification path (cryptographic primitives are in akua-core) but use `cosign` CLI for signing operations that need hardware keys. - **`docker` / `podman`** — used only if a user opts into a Dockerfile-based build. Rare for akua workflows. @@ -126,14 +126,14 @@ System integrations are a separate category from engines. `akua deploy` calls `k ## Performance notes - Cold-start overhead for a wasmtime-hosted engine: ~5-30 ms per engine, once per `akua` invocation. With precompile cache: ~2-5 ms. -- `akua dev` keeps engines warm for the session. Subsequent renders skip cold-start entirely. +- `akuapkg dev` keeps engines warm for the session. Subsequent renders skip cold-start entirely. - Benchmarks at [docs/bench/](bench/) (forthcoming) show akua's embedded OPA within 5% of native `opa eval` for realistic policy workloads. --- ## For agents -Agents get the full engine toolkit from one install with zero PATH management. When writing skills that invoke `akua test`, `akua fmt`, `akua bench`, they never need to check `which opa`. Skills remain portable across fresh sandboxes, CI runners, and developer laptops without setup instructions beyond `curl -fsSL https://cli.akua.dev/install | sh`. +Agents get the full engine toolkit from one install with zero PATH management. When writing skills that invoke `akuapkg test`, `akuapkg fmt`, `akua bench`, they never need to check `which opa`. Skills remain portable across fresh sandboxes, CI runners, and developer laptops without setup instructions beyond `curl -fsSL https://cli.akua.dev/install | sh`. --- diff --git a/docs/errors/E_AUTH_PARSE.md b/docs/errors/E_AUTH_PARSE.md index 7050a1f9..3c863cfc 100644 --- a/docs/errors/E_AUTH_PARSE.md +++ b/docs/errors/E_AUTH_PARSE.md @@ -11,7 +11,7 @@ This is distinct from [`E_INVALID_FLAG`](./E_INVALID_FLAG.md): that code covers ### `--auth` value missing the `=` separator ```sh -akua vendor add upstream --auth github.com:alice:ghp_xyz # no `=` +akuapkg vendor add upstream --auth github.com:alice:ghp_xyz # no `=` ``` The expected shape is `=:`. The split happens on the *first* `=` (so passwords containing `=` survive). @@ -19,7 +19,7 @@ The expected shape is `=:`. The split happens on the *fi ### `--auth` value missing the `:` separator inside credentials ```sh -akua vendor add upstream --auth github.com=alice # missing `:password` +akuapkg vendor add upstream --auth github.com=alice # missing `:password` ``` The credential portion (right of the first `=`) splits on the *first* `:`. @@ -27,8 +27,8 @@ The credential portion (right of the first `=`) splits on the *first* `:`. ### `--auth` value with an empty username or password ```sh -akua vendor add upstream --auth github.com=:ghp_xyz # empty username -akua vendor add upstream --auth github.com=alice: # empty password +akuapkg vendor add upstream --auth github.com=:ghp_xyz # empty username +akuapkg vendor add upstream --auth github.com=alice: # empty password ``` Both halves of the credential must be non-empty. @@ -59,7 +59,7 @@ The file is a single TOML document with a `[auth]` table. Each entry's value is ### Inline flag ```sh -akua vendor add upstream \ +akuapkg vendor add upstream \ --auth github.com/myco=alice:$GH_TOKEN \ --auth gitlab.example.com=ci-bot:$GL_TOKEN ``` @@ -76,7 +76,7 @@ Repeat `--auth` for multiple hosts. Each value is one prefix-keyed credential. ``` ```sh -akua vendor add upstream --auth-file ./auth.toml +akuapkg vendor add upstream --auth-file ./auth.toml ``` ### Combining file and flag @@ -84,14 +84,14 @@ akua vendor add upstream --auth-file ./auth.toml Both are accepted on the same invocation. If a prefix appears in both, the flag value wins — same precedence as environment overrides over config files. This lets CI inject one-off overrides without rewriting the file: ```sh -akua vendor add upstream \ +akuapkg vendor add upstream \ --auth-file ./auth.toml \ --auth github.com/myco=alice:$ROTATED_TOKEN # overrides the file entry ``` ## Why akua doesn't auto-load `~/.netrc` / `~/.docker/config.json` -See [`E_MANIFEST_GIT_USERINFO`](./E_MANIFEST_GIT_USERINFO.md#why-no-netrc--dockerconfigjson-fallback) for the rationale. Short version: multi-tenant SDK consumers can't safely inherit ambient credentials, and the same explicit-input stance that keeps `akua render` deterministic applies to credentials. +See [`E_MANIFEST_GIT_USERINFO`](./E_MANIFEST_GIT_USERINFO.md#why-no-netrc--dockerconfigjson-fallback) for the rationale. Short version: multi-tenant SDK consumers can't safely inherit ambient credentials, and the same explicit-input stance that keeps `akuapkg render` deterministic applies to credentials. ## Related diff --git a/docs/errors/E_MANIFEST_GIT_USERINFO.md b/docs/errors/E_MANIFEST_GIT_USERINFO.md index a3c1606c..0980f47f 100644 --- a/docs/errors/E_MANIFEST_GIT_USERINFO.md +++ b/docs/errors/E_MANIFEST_GIT_USERINFO.md @@ -45,7 +45,7 @@ The `auth` map is keyed by URL prefix (longest-prefix wins, same rule git's cred ### From the CLI ```sh -akua vendor add upstream --auth github.com/myco/private=alice:$GH_TOKEN +akuapkg vendor add upstream --auth github.com/myco/private=alice:$GH_TOKEN ``` Repeat `--auth` for multiple hosts. For environments where flags are awkward (CI, scripts), pass `--auth-file ` pointing at a TOML file you explicitly named: @@ -57,7 +57,7 @@ Repeat `--auth` for multiple hosts. For environments where flags are awkward (CI ``` ```sh -akua vendor add upstream --auth-file ./auth.toml +akuapkg vendor add upstream --auth-file ./auth.toml ``` ### Update your `akua.toml` @@ -73,17 +73,17 @@ upstream = { git = "https://alice:ghp_xyz@github.com/myco/private", tag = "v1" } upstream = { git = "https://github.com/myco/private", tag = "v1" } ``` -Then re-run `akua vendor add upstream` with the credential supplied via flag / SDK parameter. +Then re-run `akuapkg vendor add upstream` with the credential supplied via flag / SDK parameter. ## Why no `~/.netrc` / `~/.docker/config.json` fallback? Akua deliberately does not auto-load ambient credential files. Two reasons: - **Multi-tenant SDK consumers.** A server-side process embedding `@akua-dev/sdk` may handle requests from multiple tenants. Credentials that "happen to be on disk" can cross-contaminate between tenants. Explicit-only auth means each call carries exactly the credentials authorized for that call's principal. -- **Sandbox parity.** `akua render` runs Packages in a wasmtime sandbox with strict capability scoping. Extending the same "no implicit input" stance to credentials is a coherent invariant — the SDK and CLI surface are the only places credentials enter the system. +- **Sandbox parity.** `akuapkg render` runs Packages in a wasmtime sandbox with strict capability scoping. Extending the same "no implicit input" stance to credentials is a coherent invariant — the SDK and CLI surface are the only places credentials enter the system. ## Related - [docs/sdk.md → Credentials](../sdk.md#credentials---auth) — full SDK auth surface -- [docs/cli.md → akua vendor → Auth flags](../cli.md#auth-flags-private-git-remotes) — CLI flag surface +- [docs/cli.md → akuapkg vendor → Auth flags](../cli.md#auth-flags-private-git-remotes) — CLI flag surface - [docs/security-model.md](../security-model.md) — broader explicit-input stance diff --git a/docs/errors/E_PATH_ESCAPE.md b/docs/errors/E_PATH_ESCAPE.md index 9bd970f6..4113ee8b 100644 --- a/docs/errors/E_PATH_ESCAPE.md +++ b/docs/errors/E_PATH_ESCAPE.md @@ -13,7 +13,7 @@ which escapes the Package directory `/private/tmp/spike1/install` ## Why akua refuses -`akua render` runs each Package inside a wasmtime sandbox with read-only filesystem preopens scoped to the Package directory. A path that resolves outside that root is — by construction — unreachable through the sandbox's capabilities. We surface the error early instead of letting it manifest as a confusing wasmtime open-file failure deeper in the render. +`akuapkg render` runs each Package inside a wasmtime sandbox with read-only filesystem preopens scoped to the Package directory. A path that resolves outside that root is — by construction — unreachable through the sandbox's capabilities. We surface the error early instead of letting it manifest as a confusing wasmtime open-file failure deeper in the render. See [`docs/security-model.md`](../security-model.md) for the full threat model. @@ -77,7 +77,7 @@ import upstream resources = upstream.resources + extras ``` -`akua lock` records the resolved digest; `akua render` reads the dep from the local cache (under `~/.cache/akua/`), and the sandbox preopens that cache root in addition to the Package directory. +`akuapkg lock` records the resolved digest; `akuapkg render` reads the dep from the local cache (under `~/.cache/akua/`), and the sandbox preopens that cache root in addition to the Package directory. ## What NOT to do diff --git a/docs/hero-source/README.md b/docs/hero-source/README.md index d35b5908..de554d90 100644 --- a/docs/hero-source/README.md +++ b/docs/hero-source/README.md @@ -73,7 +73,7 @@ or `gifsicle --lossy=80`), it's a one-line change to the Taskfile. 3. Nine → one. Tri-color invariant stripe lands. 4. Live CLI — the embedded `hero-clip.mp4` plays inside a terminal frame. Longest scene, 30 s of the 58 s runtime. - 5. Compiled GitOps: KCL Package → akua render → signed OCI → + 5. Compiled GitOps: KCL Package → akuapkg render → signed OCI → PR diff → admission re-verify. 6. Agent-first: detected agents + `--json` / typed exit codes / 9 skills shipped. diff --git a/docs/hero-source/design/brief.md b/docs/hero-source/design/brief.md index c49d50be..7c306221 100644 --- a/docs/hero-source/design/brief.md +++ b/docs/hero-source/design/brief.md @@ -11,10 +11,10 @@ akua is the bun/deno collapse for cloud-native packaging. One Rust binary that c Three invariants are wired into the runtime, not bolted on: 1. **Typed.** Inputs are KCL schemas with compile-time constraints. A typo fails at parse time, not at `kubectl apply`. (KCL is a CNCF Sandbox project; we don't own it, we embed it.) -2. **Signed.** Every `akua publish` emits a cosign ECDSA P-256 signature plus a SLSA v1 attestation. Consumers verify on pull. Unsigned publishing is a flag, not a default. +2. **Signed.** Every `akuapkg publish` emits a cosign ECDSA P-256 signature plus a SLSA v1 attestation. Consumers verify on pull. Unsigned publishing is a flag, not a default. 3. **Sandboxed.** Every render runs inside a wasmtime WASI sandbox: no shell-out, no `$PATH` lookup, no ambient filesystem, no network. Untrusted Packages are safe to render on shared hosts. -Same inputs + same lockfile + same akua version → byte-identical output. That determinism is load-bearing for the audit story (Compiled GitOps: render at CI, diff in the deploy repo is exactly what hits the cluster). +Same inputs + same lockfile + same akuapkg version → byte-identical output. That determinism is load-bearing for the audit story (Compiled GitOps: render at CI, diff in the deploy repo is exactly what hits the cluster). ## Who this is for @@ -40,8 +40,8 @@ Convey, in 30 seconds, to a skeptical platform engineer scrolling past on github - The before state — the nine-tool pipeline they currently run (`helm template`, `kustomize build`, `kyverno test`, `syft`, `cosign sign`, `cosign attest`, `docker buildx`, `argocd sync`, `verifyImages` admission). Nine configs, nine failure modes. - The collapse — these become one binary. One signed artifact per version, one Rekor entry per publish, one git diff per deploy. -- The CLI as living thing — actual terminal output from `akua add` / `akua lock` / `akua tree`, showing Helm charts as typed deps with cosign-locked digests. (You'll get a real terminal recording to embed; design the frame around it.) -- The Compiled GitOps loop — Package authored in KCL → CI runs `akua render` + `akua publish` → signed OCI artifact lands in a deploy repo → ArgoCD / Flux syncs → admission re-verifies on apply. Render at CI, apply at the cluster. +- The CLI as living thing — actual terminal output from `akuapkg add` / `akuapkg lock` / `akuapkg tree`, showing Helm charts as typed deps with cosign-locked digests. (You'll get a real terminal recording to embed; design the frame around it.) +- The Compiled GitOps loop — Package authored in KCL → CI runs `akuapkg render` + `akuapkg publish` → signed OCI artifact lands in a deploy repo → ArgoCD / Flux syncs → admission re-verifies on apply. Render at CI, apply at the cluster. - The three invariants as the close — Typed, Signed, Sandboxed. The piece is the README hero on github.com. It autoplays muted, loops, and is the first thing anyone sees. It runs alongside a `` fallback for npm/crates.io readers who don't get `

a package manager surface, not a templating tool.⏵ recorded — replace with hero.gif
- akua add nginx@18.2.0 + akuapkg add nginx@18.2.0 resolving nginx@18.2.0 via oci://…/bitnamicharts/nginx verifying ✓ cosign · ECDSA P-256 · rekor#48291103 generating schema nginx.Values · 148 fields - akua lock + akuapkg lock cosign 1/1 verified · pinned by digest schemas 1/1 typed · 0 untyped values akua.lock sha256:c9a4…d3f1  diff --git a/docs/hero-source/vhs/hero-clip.tape b/docs/hero-source/vhs/hero-clip.tape index cdaee5a7..8173ebd1 100644 --- a/docs/hero-source/vhs/hero-clip.tape +++ b/docs/hero-source/vhs/hero-clip.tape @@ -26,7 +26,7 @@ Sleep 400ms Show # Beat 1 — add a real Helm chart from OCI as a typed dep. -Type "akua add --oci oci://ghcr.io/stefanprodan/charts/podinfo --version 6.7.1 podinfo" +Type "akuapkg add --oci oci://ghcr.io/stefanprodan/charts/podinfo --version 6.7.1 podinfo" Sleep 300ms Enter Sleep 3000ms @@ -37,7 +37,7 @@ Enter Sleep 150ms # Beat 2 — lockfile pinned by content-addressed digest. -Type "akua lock" +Type "akuapkg lock" Sleep 250ms Enter Sleep 3200ms @@ -48,7 +48,7 @@ Enter Sleep 150ms # Beat 3 — typed dep graph. -Type "akua tree" +Type "akuapkg tree" Sleep 250ms Enter Sleep 3500ms @@ -60,7 +60,7 @@ Sleep 150ms # Beat 4 — sandboxed deterministic render. Output: real K8s manifests # plus the deterministic sha256 of the rendered output. -Type "akua render --inputs inputs.yaml --out ./deploy" +Type "akuapkg render --inputs inputs.yaml --out ./deploy" Sleep 250ms Enter Sleep 4000ms @@ -73,7 +73,7 @@ Sleep 150ms # Beat 5 — materialize the typed OCI dep into the workspace's vendor tree. # Output shows the cosign-verified digest, on-disk path, and byte size — # proof the dep was fetched, content-addressed, and pinned without `helm`. -Type "akua vendor add podinfo" +Type "akuapkg vendor add podinfo" Sleep 300ms Enter Sleep 6000ms diff --git a/docs/impl-plan.md b/docs/impl-plan.md index ae21e55f..fd1d6d94 100644 --- a/docs/impl-plan.md +++ b/docs/impl-plan.md @@ -24,7 +24,7 @@ akua is a pre-alpha project; the pivot is a **surgical rewrite, not a greenfield | Component | What changes | |---|---| -| `crates/akua-cli/src/main.rs` | 30-verb surface replacing current ~10 verbs; honors [`cli-contract.md`](./cli-contract.md) universally | +| `crates/akuapkg-cli/src/main.rs` | 30-verb surface replacing current ~10 verbs; honors [`cli-contract.md`](./cli-contract.md) universally | | `crates/akua-core/src/schema.rs` | `x-user-input` / `x-install` vocabulary → `@ui` decorators on KCL schemas (see [`package-format.md`](./package-format.md)) | | `crates/akua-core/src/source.rs` | `package.yaml` + `engine:` field loader → `Package.k` KCL loader | | `crates/akua-core/src/engine/` | Engine trait kept; impls become **callables from KCL** (`helm.template()`, `kustomize.build()`, `rgd.instantiate()`) instead of `Engine::prepare()` invoked by umbrella assembler | @@ -56,7 +56,7 @@ The rewrite is designed for agent-driven execution. Every phase decomposes into ### Ground rules -1. **One task = one PR.** No mega-PRs. Each task passes `akua check && akua lint && akua test && akua fmt --check` on its own. +1. **One task = one PR.** No mega-PRs. Each task passes `akuapkg check && akuapkg lint && akuapkg test && akuapkg fmt --check` on its own. 2. **Every task has a reference spec.** The agent's first action on any task is to read the linked spec section. No guessing shape. 3. **Every task has a verification step.** A specific example, a specific assertion, a specific rendered-output comparison. No "looks good to me." 4. **Agents follow CLAUDE.md invariants mechanically.** Violations are architectural bugs, not style issues. @@ -75,7 +75,7 @@ New files: crates/.rs (empty; follow spec) Acceptance: - Unit tests for - Integration test: `akua examples/` produces -- `akua check && akua lint && akua test && akua fmt --check` passes +- `akuapkg check && akuapkg lint && akuapkg test && akuapkg fmt --check` passes - CLAUDE.md invariants respected: no non-determinism, no YAML-as-truth, typed-code-canonical Do not: @@ -99,9 +99,9 @@ Within each phase, tasks execute in a partially ordered DAG. Agents pick up any (--json, --plan, typed exits, idempotency, agent detection) - [A.5] akua render (KCL-only) ──┐ + [A.5] akuapkg render (KCL-only) ──┐ ├─▶ [A.8] @akua-dev/sdk render parity - [A.6] akua publish + verify ──┘ + [A.6] akuapkg publish + verify ──┘ ``` A.1, A.2, A.3 are independent — three agents can pick them up in parallel. A.4 depends on all three. A.5, A.6 branch from A.4. A.7, A.8 are the phase exit gate. @@ -128,21 +128,21 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor **A.3 — CLI contract primitives** - Spec: [`cli-contract.md`](./cli-contract.md) (§1 through §15) -- Deliverable: `crates/akua-cli/src/contract/` — `--json` / `--plan` / typed exit codes (0/1/2/3/4/5/6) / `--timeout` / `--idempotency-key` as a reusable argument-group + response-shaping layer. Agent context auto-detection per §1.5. Structured errors on stderr. -- Tests: every exit code reachable via a stub verb; `akua whoami --json` returns agent-context structure. +- Deliverable: `crates/akuapkg-cli/src/contract/` — `--json` / `--plan` / typed exit codes (0/1/2/3/4/5/6) / `--timeout` / `--idempotency-key` as a reusable argument-group + response-shaping layer. Agent context auto-detection per §1.5. Structured errors on stderr. +- Tests: every exit code reachable via a stub verb; `akuapkg whoami --json` returns agent-context structure. **A.4 — CLI skeleton wiring** - Deliverable: 30 verbs registered in clap with stubbed handlers returning `exit 2 system-error: not-implemented`. Each handler reads CLI contract primitives from A.3. - Tests: `akua help --json` returns the full verb tree; every verb accepts `--json` and `--plan`. -- Carry-forward: `crates/akua-cli/src/main.rs` structure. +- Carry-forward: `crates/akuapkg-cli/src/main.rs` structure. -**A.5 — `akua render` (KCL-only)** +**A.5 — `akuapkg render` (KCL-only)** - Spec: [`cli.md`](./cli.md) `render` section + [`package-format.md`](./package-format.md) output format - Deliverable: execute a `Package.k` with given inputs, produce `resources[]` per the KCL program's top-level binding. KCL-only (no Helm, no Kustomize yet). - Tests: `examples/01-hello-webapp` produces expected manifests; byte-identical across three runs. - Depends on: A.2, A.4. -**A.6 — `akua publish` + `akua verify`** +**A.6 — `akuapkg publish` + `akuapkg verify`** - Carry-forward: `crates/akua-core/src/publish.rs` + `attest.rs`. - Deliverable: wire existing OCI push + SLSA emission to the new verb surface. Consume `akua.lock` for reproducibility checks. - Tests: round-trip publish + verify against local OCI registry (zot). @@ -154,7 +154,7 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor **A.8 — `@akua-dev/sdk` render parity** - Spec: [`sdk.md`](./sdk.md) -- Deliverable: `packages/sdk/src/render.ts` produces byte-identical output to `akua render` for the same inputs. Same for `publish` and `verify`. +- Deliverable: `packages/sdk/src/render.ts` produces byte-identical output to `akuapkg render` for the same inputs. Same for `publish` and `verify`. - Tests: cross-consumer determinism test (CLI output hash == SDK output hash). - Depends on: A.5, A.6. @@ -179,11 +179,11 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor - Carry-forward: existing `cel-interpreter` integration. - KCL callable: `cel.eval(expr, ctx)`. -**B.5 — `akua diff`** +**B.5 — `akuapkg diff`** - Spec: [`cli.md`](./cli.md) `diff`. - Deliverable: structural diff between two rendered outputs; stable, readable, parseable with `--json`. -**B.6 — `akua inspect`** +**B.6 — `akuapkg inspect`** - Spec: [`cli.md`](./cli.md) `inspect`. - Deliverable: full-tree output (schema, deps, attestations, metadata) for any OCI-published artifact. @@ -205,7 +205,7 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor **C.3 — `akua policy check`** - Deliverable: verdict path returns `{allow | deny | needs-approval}` + structured reasons. -**C.4 — `akua test` (Rego + KCL)** +**C.4 — `akuapkg test` (Rego + KCL)** - Deliverable: run `*_test.rego` via embedded OPA test runner; run `test_*.k` via embedded KCL test harness. - Spec: [`cli.md`](./cli.md) `test`. @@ -226,16 +226,16 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor - Deliverable: `--to=argocd`, `--to=flux`, `--to=kro`, `--to=helm`, `--to=kubectl`, `--to=`. No non-K8s drivers. - Each driver: emit the reconciler's native consumable; apply or commit as appropriate. -**D.2 — `akua dev` build graph** +**D.2 — `akuapkg dev` build graph** - Deliverable: `crates/akua-dev/` — content-addressable build DAG, `notify-rs` watcher, change classifier, incremental rebuild. -**D.3 — `akua dev` browser UI** +**D.3 — `akuapkg dev` browser UI** - Deliverable: WebSocket-driven UI at `localhost:5173` showing pipeline stages, resource health, log tail, manifest diff. Terminal fallback via Ratatui. -**D.4 — `akua dev` local target** +**D.4 — `akuapkg dev` local target** - Deliverable: kind / k3d / minikube integration; server-side apply; persistence across restarts; `*.127.0.0.1.nip.io` default DNS. -**D.5 — `akua repl`** +**D.5 — `akuapkg repl`** - Deliverable: interactive Rego + KCL REPL. Command-history, tab-complete, `--json` out mode for agent consumption. **D.6 — `akua trace` + `akua cov`** @@ -244,7 +244,7 @@ Each task below is sized for a single agent session (~1–3 hours of focused wor **D.7 — `akua query`** - Deliverable: Loki / Prom queries dispatched from the CLI against configured cluster endpoints. No federation in v1. -**Phase D exit gate:** solo-developer journey completes on a fresh laptop in under 5 minutes; `akua dev` edit-to-applied loop under 500ms median. +**Phase D exit gate:** solo-developer journey completes on a fresh laptop in under 5 minutes; `akuapkg dev` edit-to-applied loop under 500ms median. ### Phase E — Browser playground + Studio @@ -269,7 +269,7 @@ The repository ships agent skills ([`skills/`](./skills/)) following the [Agent 2. Reads the phase-current task (see GitHub Issues with label `phase-A` / `phase-B` / ...). 3. Opens the linked spec section. 4. Writes code + tests matching the acceptance criteria. -5. Runs `akua check && akua lint && akua test && akua fmt --check`. +5. Runs `akuapkg check && akuapkg lint && akuapkg test && akuapkg fmt --check`. 6. Opens a PR with the task title. If the agent is blocked on a design decision, it opens an issue with label `design-question` rather than guessing. The masterplan (internal) decides; the answer lands as a spec update; the agent picks up the task again. @@ -284,9 +284,9 @@ Every phase's exit gate includes one of the existing examples in [`examples/`](. Additional cross-cutting checks: -- **Determinism.** `akua render` on any example, run three times, produces byte-identical output. Run in CI. +- **Determinism.** `akuapkg render` on any example, run three times, produces byte-identical output. Run in CI. - **CLI / SDK parity.** Every verb that produces output is called from both `akua ` and `@akua-dev/sdk.()`; outputs must match byte-for-byte. Run in CI. -- **Agent contract.** `akua whoami --json` exposes the agent context correctly under `CLAUDECODE=1` / `CURSOR_CLI=1` / `GEMINI_CLI=1` / `AGENT=foo`. CI matrix runs verbs under each. +- **Agent contract.** `akuapkg whoami --json` exposes the agent context correctly under `CLAUDECODE=1` / `CURSOR_CLI=1` / `GEMINI_CLI=1` / `AGENT=foo`. CI matrix runs verbs under each. - **Policy gate.** The rewrite branch maintains a passing `akua policy check` against `tier/production`. Merges to main require green. --- diff --git a/docs/lockfile-format.md b/docs/lockfile-format.md index a12024e0..ce511721 100644 --- a/docs/lockfile-format.md +++ b/docs/lockfile-format.md @@ -16,7 +16,7 @@ Clear separation of concerns: | | intent | evidence | |---|---|---| | file | `akua.toml` | `akua.lock` | -| edited by | human | `akua add` / `akua pull` / `akua publish` / `akua update` | +| edited by | human | `akuapkg add` / `akuapkg pull` / `akuapkg publish` / `akuapkg update` | | shape | small, stable | may be large; churns on every resolved-version change | | review focus | "do we want this dep?" | "is this the expected digest + signature?" | @@ -111,7 +111,7 @@ Cargo.lock-flavored TOML: one `[[package]]` entry per resolved artifact, alphabe ```toml # akua.lock — machine-maintained. Never hand-edit. -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. version = 1 # lockfile format version; bumped on incompatible changes @@ -148,7 +148,7 @@ signature = "cosign:sigstore:bitnamicharts" | `version` | yes | exact resolved semver (not a range) | | `source` | yes | full source ref: `oci://…`, `git+https://…`, `path+file://…`, or `helm+#` | | `digest` | yes | content-addressable source hash: `sha256:` for OCI/path/helm-repo deps; `git:` for git deps | -| `vendor_digest` | no | `sha256:` hash of the vendored on-disk tree when it differs from `digest`; used by `akua vendor check` for git deps without losing the commit pin | +| `vendor_digest` | no | `sha256:` hash of the vendored on-disk tree when it differs from `digest`; used by `akuapkg vendor check` for git deps without losing the commit pin | | `signature` | conditional | cosign signature. Keyless: `cosign:sigstore:`. Keyed: `cosign:key:`. Required unless `[package].strictSigning = false` in `akua.toml` | | `dependencies` | no | `["name@version", …]` — transitive edges for graph walks | | `attestation` | no | SLSA attestation digest; present when the dep's author publishes one alongside | @@ -179,7 +179,7 @@ digest = "sha256:" ### What `akua.lock` does NOT contain -- Source code (not a vendor directory — see `akua vendor` for that) +- Source code (not a vendor directory — see `akuapkg vendor` for that) - Version ranges (those live in `akua.toml`) - User-facing comments @@ -187,7 +187,7 @@ digest = "sha256:" ## Resolution workflow -### `akua add --version=` +### `akuapkg add --version=` 1. Reads current `akua.toml` 2. Adds the new entry to `[dependencies]` @@ -198,7 +198,7 @@ digest = "sha256:" Result: both `akua.toml` and `akua.lock` updated in one atomic operation. -### `akua verify` (CI gate) +### `akuapkg verify` (CI gate) 1. Reads `akua.toml` and `akua.lock` 2. Resolves every dep from `akua.toml` @@ -207,13 +207,13 @@ Result: both `akua.toml` and `akua.lock` updated in one atomic operation. Run in CI on every PR to catch lockfile tampering. -### `akua update [dep]` +### `akuapkg update [dep]` Updates to the highest allowed version per `akua.toml` constraints; rewrites the relevant `[[package]]` entries in `akua.lock`. Leaves other deps untouched unless their constraints also match a new version. -### `akua vendor` (optional) +### `akuapkg vendor` (optional) -Materializes a dependency's bytes into `.akua/vendor//` and pins the source digest in `akua.lock`. The resolver prefers the vendored copy across all dep kinds (`path` / `oci` / `git` / `helm`), so the canonical source can be deleted post-vendor and `akua render` still succeeds offline. For git deps, `digest` stays `git:` and `vendor_digest` stores the vendored tree hash for local drift checks. Required for air-gapped builds, optional otherwise. +Materializes a dependency's bytes into `.akua/vendor//` and pins the source digest in `akua.lock`. The resolver prefers the vendored copy across all dep kinds (`path` / `oci` / `git` / `helm`), so the canonical source can be deleted post-vendor and `akuapkg render` still succeeds offline. For git deps, `digest` stays `git:` and `vendor_digest` stores the vendored tree hash for local drift checks. Required for air-gapped builds, optional otherwise. **Bytes-tied lockfile metadata.** Cosign signatures, SLSA attestations, transitive dependency lists, `yanked`, and Kyverno-converter fields all bind to a specific digest. When a re-vendor or version bump produces a new digest, those fields are dropped on upsert rather than written as `(digest=B, sig=sig(A))` entries that no consumer can verify. The `source` / `version` / `digest` triple is always rewritten; everything else is conditional on `prior.digest == new.digest`. @@ -343,4 +343,4 @@ digest = "sha256:m3n4o5…" signature = "cosign:key:acme" ``` -CI runs `akua verify` on every PR; any digest mismatch or missing signature fails the build. +CI runs `akuapkg verify` on every PR; any digest mismatch or missing signature fails the build. diff --git a/docs/package-format.md b/docs/package-format.md index c4722e2c..f2051d28 100644 --- a/docs/package-format.md +++ b/docs/package-format.md @@ -34,11 +34,11 @@ _app = helm.template(helm.Template { chart = webapp.Chart, values = ... }) resources = _pg + _app ``` -That's it. `akua render` writes `resources` as raw YAML files under +That's it. `akuapkg render` writes `resources` as raw YAML files under `--out`. Other distribution shapes (Helm charts, OCI bundles, kro RGDs) come from either (a) **transformation** functions invoked in the body that produce more K8s resources (`kro.rgd(...)`, `crossplane.composition(...)`), -or (b) future `akua publish --as ` at distribution time. The +or (b) future `akuapkg publish --as ` at distribution time. The Package itself never pre-commits to an emit format — `resources` is the single canonical thing it produces. @@ -51,7 +51,7 @@ An import brings one of four things into scope: | import form | purpose | pinned by | |---|---|---| | `import akua.` | a source-engine callable (`helm`, `rgd`, `kustomize`, `oci`) | the akua CLI version | -| `import charts.` | a typed Helm chart dep previously added via `akua add` (synthetic wrapper that exposes the chart path + a pre-bound `template` callable) | `akua.toml` | +| `import charts.` | a typed Helm chart dep previously added via `akuapkg add` (synthetic wrapper that exposes the chart path + a pre-bound `template` callable) | `akua.toml` | | `import pkgs.` | a typed Akua-package dep (synthetic stub re-exporting the upstream's schemas + a pre-bound `render` lambda — `pkgs..render(pkgs..Input{...})`) | `akua.toml` | | `import ` | an upstream KCL ecosystem package (e.g. `import k8s.api.apps.v1` against `oci://ghcr.io/kcl-lang/k8s`) | `akua.toml` | | `import ` | a local KCL module within this package | the filesystem | @@ -67,10 +67,10 @@ Helm-chart deps and KCL-package deps both land in `[dependencies]`; akua tells t | Path | `{ path = "../shared" }` | workspace-local, dev-only | | Helm repo | `{ repo = "https://go.temporal.io/helm-charts", chart = "temporal", version = "0.62.0" }` | classic HTTPS Helm repository | -Helm-repo deps resolve against the repo's `index.yaml` at `akua add` / lock time, content-pinned by `.tgz` sha256 in `akua.lock`, and rendered deterministically offline. Add one with: +Helm-repo deps resolve against the repo's `index.yaml` at `akuapkg add` / lock time, content-pinned by `.tgz` sha256 in `akua.lock`, and rendered deterministically offline. Add one with: ```sh -akua add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0 +akuapkg add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0 ``` **For Helm charts and Akua-package deps, use the alias method on the import** — the synthesized stub owns the engine call so the consumer just states the typed args: @@ -118,7 +118,7 @@ Rules: - Fields use KCL's native type syntax: `str`, `int`, `float`, `bool`, `[T]`, `{str: T}`, unions (`"a" | "b" | "c"`), nested schemas. - Fields without defaults are required. Fields with defaults are optional. - Use KCL docstrings for field documentation — `akua` tooling surfaces them in autocomplete and generated docs. -- `check:` blocks can express cross-field constraints; they run during `akua render`. +- `check:` blocks can express cross-field constraints; they run during `akuapkg render`. - No runtime side effects (no env lookups, no filesystem, no network). KCL's sandbox enforces this. Example with all shapes: @@ -162,7 +162,7 @@ schema HostInput: ### UI hints (optional) ✅ -When a Package is consumed through a UI (merchant install form, Package Studio, generated Swagger form), renderers benefit from hints about field ordering, labels, placeholders, grouping. akua reads UI hints from two sources, both projected into the JSON Schema / OpenAPI output of [`akua export`](cli.md#akua-export). +When a Package is consumed through a UI (merchant install form, Package Studio, generated Swagger form), renderers benefit from hints about field ordering, labels, placeholders, grouping. akua reads UI hints from two sources, both projected into the JSON Schema / OpenAPI output of [`akuapkg export`](cli.md#akuapkg-export). **KCL docstrings** — the field's `"""…"""` docstring becomes the schema property's `description`: @@ -194,7 +194,7 @@ schema Input: replicas: int = 3 ``` -`@ui(...)` is an akua-specific authoring hint, not a registered KCL decorator — `akua render` strips it before handing the source to KCL's resolver, while `akua export` extracts it from the parsed AST. +`@ui(...)` is an akua-specific authoring hint, not a registered KCL decorator — `akuapkg render` strips it before handing the source to KCL's resolver, while `akuapkg export` extracts it from the parsed AST. ### Exporting a view vs rendering ✅ @@ -202,19 +202,19 @@ The canonical Package is KCL. akua ships two different verbs producing different | verb | purpose | needs inputs? | output | |---|---|---|---| -| `akua export` | convert the Package's `Input` schema to a standard interchange format | no | JSON Schema 2020-12 or OpenAPI 3.1 | -| `akua render` | execute the Package's full pipeline and produce deploy-ready Kubernetes manifests | yes | rendered YAML the reconciler applies | +| `akuapkg export` | convert the Package's `Input` schema to a standard interchange format | no | JSON Schema 2020-12 or OpenAPI 3.1 | +| `akuapkg render` | execute the Package's full pipeline and produce deploy-ready Kubernetes manifests | yes | rendered YAML the reconciler applies | -For install UIs, API docs, rjsf / JSONForms, admission webhook schemas, and client SDK generators — `akua export` skips engine invocation and customer inputs: +For install UIs, API docs, rjsf / JSONForms, admission webhook schemas, and client SDK generators — `akuapkg export` skips engine invocation and customer inputs: ```sh -akua export --package package.k > inputs.schema.json # JSON Schema 2020-12 -akua export --package package.k --format=openapi > package.openapi.json +akuapkg export --package package.k > inputs.schema.json # JSON Schema 2020-12 +akuapkg export --package package.k --format=openapi > package.openapi.json ``` -For actual deployment rendering — use `akua render` with customer inputs (covered in §9). +For actual deployment rendering — use `akuapkg render` with customer inputs (covered in §9). -`akua export` output is pure, spec-compliant JSON Schema 2020-12 / OpenAPI 3.1. Docstrings become `description`; `@ui(...)` decorators become `x-ui` metadata. Consumers that speak these standards — including every JSON Schema tool in the ecosystem — work unchanged. +`akuapkg export` output is pure, spec-compliant JSON Schema 2020-12 / OpenAPI 3.1. Docstrings become `description`; `@ui(...)` decorators become `x-ui` metadata. Consumers that speak these standards — including every JSON Schema tool in the ecosystem — work unchanged. **No `x-user-input` or `x-input` markers.** Previous versions of akua layered custom extensions on JSON Schema to mark user-configurable fields and embed transforms. With KCL as the authoring substrate, both are redundant: the `Input` schema IS the customer-configurable contract by definition, and transforms live as KCL code in the package body. The eventual exported JSON Schema is standards-pure; UI renderers in the broader ecosystem don't need to learn akua-specific vocabulary. @@ -285,7 +285,7 @@ KCL `check:` blocks evaluate at render time against each resource; failures surf ## 5. The render output -`akua render --out ./deploy` writes every entry in `resources` as its +`akuapkg render --out ./deploy` writes every entry in `resources` as its own YAML file in `./deploy/`. Filenames are deterministic (`--.yaml`), ordered by resource-list position. @@ -304,9 +304,9 @@ want a different shape use one of: `crossplane.composition(...)`, `kyverno.policy(...)` all fit this mould: they produce CRDs + composite resources that go into `resources` alongside everything else, and ship as plain YAML. -- **Future distribution verbs** — `akua publish --as helm-chart` +- **Future distribution verbs** — `akuapkg publish --as helm-chart` wraps rendered manifests into a Helm chart at distribution time; - `akua publish --as oci-bundle` signs and packages them. These are + `akuapkg publish --as oci-bundle` signs and packages them. These are distribution concerns, not render concerns — the Package's `resources` are the input, not a pre-declared output list. @@ -332,7 +332,7 @@ metadata = { # Machine-readable keyword list for catalog discovery keywords: ["postgres", "webapp", "payments"] - # Minimum akua version required to render this package + # Minimum akuapkg version required to render this package requires: { akua: ">=0.2.0" engines: { helm: ">=4.0", kcl: ">=0.12" } @@ -360,7 +360,7 @@ Violation of any of these is a compile error with a clear message. ## 8. Rendering model -`akua render`: +`akuapkg render`: 1. Parses `package.k` and type-checks the program. 2. Loads `input` from inputs file (YAML or KCL). Validates against the `Input` schema. @@ -405,7 +405,7 @@ See [examples/01-hello-webapp](../examples/01-hello-webapp/) for the fully runna ## 10. Testing Packages -Packages ship with tests. The test runner is built into `akua test`; no separate framework required. +Packages ship with tests. The test runner is built into `akuapkg test`; no separate framework required. ### Test file conventions @@ -464,17 +464,17 @@ tests/ ``` ```sh -akua test --golden # regenerate goldens if they drifted intentionally -akua test --golden=verify # fail CI if goldens don't match (default in CI) +akuapkg test --golden # regenerate goldens if they drifted intentionally +akuapkg test --golden=verify # fail CI if goldens don't match (default in CI) ``` ### Running ```sh -akua test # runs everything, including Rego tests -akua test --watch # re-runs on file change (ideal for TDD) -akua test --coverage # report per-schema / per-source coverage -akua test --filter=default # only tests matching 'default' +akuapkg test # runs everything, including Rego tests +akuapkg test --watch # re-runs on file change (ideal for TDD) +akuapkg test --coverage # report per-schema / per-source coverage +akuapkg test --filter=default # only tests matching 'default' ``` Tests run via the embedded KCL engine (see [embedded-engines.md](embedded-engines.md)) — fast, sandboxed, deterministic. @@ -492,7 +492,7 @@ Packages without tests ship with a lint warning; platform teams can enforce a po ## 11. Relationship to other docs -- **[cli.md — `akua init` / `akua add` / `akua render` / `akua export` / `akua test` / `akua publish`](cli.md)** — the verbs that operate on packages. `render` runs the program; `export` converts the canonical form to a view. +- **[cli.md — `akuapkg init` / `akuapkg add` / `akuapkg render` / `akuapkg export` / `akuapkg test` / `akuapkg publish`](cli.md)** — the verbs that operate on packages. `render` runs the program; `export` converts the canonical form to a view. - **[lockfile-format.md](lockfile-format.md)** — how `akua.toml` + `akua.lock` pin imports - **[policy-format.md](policy-format.md)** — how Rego policies evaluate against rendered resources (separate concern from `check:` blocks) - **[embedded-engines.md](embedded-engines.md)** — which engines run your tests diff --git a/docs/performance.md b/docs/performance.md index 3ee53527..1e924b81 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -7,7 +7,7 @@ Render-path benchmarks. Useful for: -- Sanity-checking that akua's pipeline is fast enough for the signature experience (`akua dev` sub-100ms edit-to-render loops). +- Sanity-checking that akua's pipeline is fast enough for the signature experience (`akuapkg dev` sub-100ms edit-to-render loops). - Understanding the cost of each engine callable (`helm.template`, `kustomize.build`, `pkg.render`) so Package authors can reason about their render budget. - Validating that the WASI WebAssembly target (for shipping-a-renderer / ArgoCD plugin use cases) is within an acceptable latency multiplier vs native. @@ -80,7 +80,7 @@ Native only (WASI plugins are stubbed — benchmarking stubs is meaningless). --- -## 3. End-to-end `akua render` CLI latency (embedded WASM engines) +## 3. End-to-end `akuapkg render` CLI latency (embedded WASM engines) What it measures: full user-visible time — binary startup + arg parse + Package load + KCL eval + any plugin work + WASM engine instantiation + render. Measured via [`hyperfine`](https://github.com/sharkdp/hyperfine) with 3 warmup runs and ≥10 timed runs, `--dry-run` so filesystem writes don't vary the sample. @@ -116,7 +116,7 @@ exactly once. Next wins along this axis (not shipped): -- **Persistent Engine across invocations in `akua dev` / `akua serve`** — single long-lived process. Today each `akua render` is a fresh process and pays the init once. A long-lived process pays it once total. +- **Persistent Engine across invocations in `akuapkg dev` / `akua serve`** — single long-lived process. Today each `akuapkg render` is a fresh process and pays the init once. A long-lived process pays it once total. ### 5.2 Pooling allocator @@ -130,7 +130,7 @@ Wasmtime's `Module::serialize` on a post-`_initialize` instance would let us ski ## Implications for the signature experience -`akua dev` (the masterplan-§12 hot-reload loop) wants sub-100ms edit-to-re-render. Current budget vs today's measured numbers: +`akuapkg dev` (the masterplan-§12 hot-reload loop) wants sub-100ms edit-to-re-render. Current budget vs today's measured numbers: | Package complexity | End-to-end render | Under 100ms budget? | |---|---:|:---:| @@ -146,7 +146,7 @@ render_work) instead of N × (init + render_work). Combined effect of Phase 1b (forked helm: 75 MB → 20 MB wasm, faster deserialize) + §5.1 session reuse cut the single-helm case from -~120 ms to **~57 ms** — inside the 100 ms budget. `akua dev` +~120 ms to **~57 ms** — inside the 100 ms budget. `akuapkg dev` persistent-process will drive it lower still. --- @@ -157,6 +157,6 @@ The harnesses live under `/tmp` in the dev environment; they're intentionally no 1. **Pure KCL benchmark** — 50 lines of Rust that calls `kcl_lang::API::exec_program` in a loop. Build `--release` natively and for `--target wasm32-wasip1`. Run the wasm binary under a minimal `wasmtime` Rust host that stubs the plugin import. 2. **Plugin dispatch benchmark** — same harness, adds `akua-core` as a dep, calls `install_builtin_plugins()` before the loop. -3. **End-to-end CLI benchmark** — `task build:helm-engine-wasm && task build:kustomize-engine-wasm && cargo build --release -p akua-cli`, then `hyperfine --warmup 3 --min-runs 10 'target/release/akua render --package ... --dry-run'`. +3. **End-to-end CLI benchmark** — `task build:helm-engine-wasm && task build:kustomize-engine-wasm && cargo build --release -p akuapkg-cli`, then `hyperfine --warmup 3 --min-runs 10 'target/release/akuapkg render --package ... --dry-run'`. If the benchmarks need to go into CI, the harnesses move into `crates/akua-bench/` with criterion and get versioned. Out of scope until we have a performance regression story. diff --git a/docs/policy-format.md b/docs/policy-format.md index 8ddfee39..9d395f27 100644 --- a/docs/policy-format.md +++ b/docs/policy-format.md @@ -115,7 +115,7 @@ deny[msg] { tier.production.deny[msg] } ### 4.2 Kyverno bundles (converted to Rego at build time) -Kyverno ships policies as Kubernetes CRDs with a native YAML DSL. akua's `akua add policy ` uses an embedded Kyverno→Rego converter to compile the bundle into Rego modules stored under `./.akua/policies/vendor/`. +Kyverno ships policies as Kubernetes CRDs with a native YAML DSL. akua's `akuapkg add policy ` uses an embedded Kyverno→Rego converter to compile the bundle into Rego modules stored under `./.akua/policies/vendor/`. ```toml # akua.toml @@ -128,11 +128,11 @@ import data.akua.policies.kyverno.security deny[msg] { kyverno.security.deny[msg] } # Kyverno rules, now evaluated as Rego ``` -The conversion is one-way and happens at `akua add` time; the original Kyverno source is preserved for audit but not consumed at eval time. Reproducibility: same Kyverno version + same converter version → same Rego output. +The conversion is one-way and happens at `akuapkg add` time; the original Kyverno source is preserved for audit but not consumed at eval time. Reproducibility: same Kyverno version + same converter version → same Rego output. ### 4.3 CEL expression libraries (compiled to Rego) -CEL (Google's Common Expression Language) is simple enough to compile directly to Rego primitives. `akua add policy ` runs the CEL→Rego compiler; imported the same way: +CEL (Google's Common Expression Language) is simple enough to compile directly to Rego primitives. `akuapkg add policy ` runs the CEL→Rego compiler; imported the same way: ```rego import data.akua.policies.cel.my_expressions @@ -247,7 +247,7 @@ Policy evaluates at multiple points; each runs the same Rego against different i | point | input | failure mode | |---|---|---| -| `akua render` / `akua dev` | rendered manifests + live context | lint error; render succeeds but marks the output as deny-policy | +| `akuapkg render` / `akuapkg dev` | rendered manifests + live context | lint error; render succeeds but marks the output as deny-policy | | `akua deploy` / CI gate | rendered manifests + target environment | exit 3 (policy deny) or exit 5 (needs approval) | | in-cluster admission (optional) | admission webhook payload | reject apply | | audit sweep (scheduled) | current cluster state | produce an Incident record | @@ -261,21 +261,21 @@ All four share the same Rego bundle. The host language guarantees uniform behavi ### New tier from scratch ```sh -akua init policy my-org-production +akuapkg init policy my-org-production # creates policies/my-org-production.rego with starter template ``` ### Import an existing tier ```sh -akua add policy oci://policies.akua.dev/tier/production --version 1.2.0 +akuapkg add policy oci://policies.akua.dev/tier/production --version 1.2.0 # adds to akua.toml + akua.lock; makes 'data.akua.policies.tier.production' importable ``` ### Import a Kyverno bundle ```sh -akua add policy oci://policies.akua.dev/kyverno/security --version 2.0.0 +akuapkg add policy oci://policies.akua.dev/kyverno/security --version 2.0.0 # fetches Kyverno YAML, converts to Rego, stores under .akua/policies/vendor/ ``` @@ -289,7 +289,7 @@ akua policy check --tier my-org-production --target ./deploy/production ### Publish a tier ```sh -akua publish --policy my-org-production --to oci://policies.acme.com/my-org-production --tag v1.0.0 +akuapkg publish --policy my-org-production --to oci://policies.acme.com/my-org-production --tag v1.0.0 # pushes the Rego bundle signed + SLSA-attested ``` @@ -340,9 +340,9 @@ test_allow_with_team_label { Run: ```sh -akua test # runs all Rego + KCL tests -akua test --coverage # includes per-rule coverage -akua test --watch # TDD mode +akuapkg test # runs all Rego + KCL tests +akuapkg test --coverage # includes per-rule coverage +akuapkg test --watch # TDD mode ``` Every test runs via the embedded OPA (see [embedded-engines.md](embedded-engines.md)). Output matches `opa test` structure; coverage format is compatible with standard OPA coverage tooling. @@ -374,7 +374,7 @@ No separate test framework. No mocking. The package gets rendered, the policy ru ### Linting ```sh -akua lint +akuapkg lint ``` Runs: @@ -388,9 +388,9 @@ Output is structured per [cli.md](cli.md#akua-lint). Severity levels: warn, erro ### Formatting ```sh -akua fmt # in-place -akua fmt --check # fail CI if formatting needed -akua fmt --diff # preview changes without applying +akuapkg fmt # in-place +akuapkg fmt --check # fail CI if formatting needed +akuapkg fmt --diff # preview changes without applying ``` Runs `opa fmt` (embedded) on `.rego` files and `kcl fmt` (embedded) on `.k` files. Both are idempotent. @@ -427,7 +427,7 @@ Embedded OPA's coverage report, rolled up across Rego files + imported tier bund ### REPL ```sh -akua repl +akuapkg repl > :mode rego rego> data.akua.policies.production.deny with input as { resource: { kind: "Deployment" } } [...] @@ -441,7 +441,7 @@ rego> :trace - **[package-format.md](package-format.md)** — how `check:` blocks in KCL complement Rego - **[lockfile-format.md](lockfile-format.md)** — how Rego imports are pinned -- **[cli.md — `akua policy` / `akua test` / `akua trace` / `akua bench`](cli.md)** — the verbs that operate on policy +- **[cli.md — `akua policy` / `akuapkg test` / `akua trace` / `akua bench`](cli.md)** — the verbs that operate on policy - **[embedded-engines.md](embedded-engines.md)** — OPA, Regal, Kyverno-to-Rego converter, CEL all embedded via wasmtime - **[skills/apply-policy-tier](../skills/apply-policy-tier/SKILL.md)** — agent workflow for subscribing to a tier - **[skills/test-and-lint](../skills/test-and-lint/SKILL.md)** — agent workflow for setting up tests + lint gates diff --git a/docs/roadmap.md b/docs/roadmap.md index 78192b80..0ec3af8c 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -18,7 +18,7 @@ The roadmap is ordered by implementation phase, but releases cut across phases. **Security invariant — v0.1.0 blocks until this holds end-to-end:** -- Phase 4 shipped — every `akua render` invocation (CLI or SDK) runs inside a wasmtime WASI sandbox with memory / fuel / epoch caps + capability-model filesystem preopens. No native render fallback. +- Phase 4 shipped — every `akuapkg render` invocation (CLI or SDK) runs inside a wasmtime WASI sandbox with memory / fuel / epoch caps + capability-model filesystem preopens. No native render fallback. - Phase 4B shipped — `@akua-dev/sdk` delivers the same render path via `wasm32-unknown-unknown` inside the host JS runtime's own sandbox. Identical guarantees for SDK consumers — same invariant, different sandbox. - Path-escape + symlink-escape rejected at the plugin boundary (shipped Phase 0 — guard existing tests). - No shell-out in any render path. No `--unsafe-host` flag. No feature gate that opens one (shipped Phase 0 — guard this at code review forever). @@ -33,12 +33,12 @@ The roadmap is ordered by implementation phase, but releases cut across phases. - Helm + Kustomize WASM engines - Typed `charts.*` deps over path / OCI / git with `replace` + lockfile digests - Cosign keyed verify + SLSA v1 attestation on publish -- Full air-gap crypto loop: `akua pack` → `akua sign` → transfer → `akua verify --tarball` → `akua push --sig` -- Operational verbs: `akua cache`, `akua auth`, `akua lock [--check]`, `akua update [--dep]` +- Full air-gap crypto loop: `akuapkg pack` → `akua sign` → transfer → `akuapkg verify --tarball` → `akuapkg push --sig` +- Operational verbs: `akuapkg cache`, `akuapkg auth`, `akuapkg lock [--check]`, `akuapkg update [--dep]` **Still to ship for v0.1.0 (ordered by blast radius if skipped):** -1. **Phase 4** — wasmtime-hosted `akua render`. Security invariant for the CLI. +1. **Phase 4** — wasmtime-hosted `akuapkg render`. Security invariant for the CLI. 2. **Phase 4B** — `akua-wasm` bundle via JSR. Security invariant for the SDK + full verb coverage. 3. Adversarial test suite targeting the sandbox (listed above). 4. Docs sweep — see [v0.1.0 release punch list](#v010-release-punch-list). Explicitly: the "this doesn't yet hold" caveats in security-model.md go. @@ -57,7 +57,7 @@ These are feature absences, not invariant violations. Users know exactly what th ### v0.2.0 — hosted multi-tenant - Phase 5 — `akua serve` (~2-3 weeks). Single process handles N concurrent renders with per-tenant isolation. v0.1.0 already delivers the per-render sandbox; v0.2.0 adds the concurrent-tenants HTTP surface on top. -- `akua attest` + `akua verify --att` — offline DSSE/SLSA alongside the existing signature flow. +- `akua attest` + `akuapkg verify --att` — offline DSSE/SLSA alongside the existing signature flow. ### v0.3.0 — supply-chain completeness @@ -69,7 +69,7 @@ These are feature absences, not invariant violations. Users know exactly what th - Policy engine phase (design open — regorus vs OPA→WASM). - Phase 8 — Rego test runner (depends on policy engine). -- Phase 8 — `akua repl` Rego half (depends on policy engine). +- Phase 8 — `akuapkg repl` Rego half (depends on policy engine). - Phase 9 — `akua deploy`, `akua query`, `akua trace`, `akua policy` ("ship when there's demand"). --- @@ -140,7 +140,7 @@ Spec-to-code convergence. [docs/package-format.md §2](package-format.md) and [d - [x] `chart_resolver` module: local-path deps → canonicalized path + sha256 digest - [x] Per-render `charts` KCL external pkg generated from resolved deps (`charts/.k` exposes `path` + `sha256` constants) - [x] `PackageK::render_with_charts` threads resolved chart paths as allowed absolute roots for the plugin path-escape guard — `helm.template(nginx.path, ...)` survives without an `--unsafe-host` escape hatch -- [x] `akua render` CLI verb auto-loads sibling `akua.toml`, resolves charts, passes them through +- [x] `akuapkg render` CLI verb auto-loads sibling `akua.toml`, resolves charts, passes them through - [x] `examples/01-hello-webapp` vendored nginx chart + rewritten Package renders end-to-end — verified via `examples_hello_webapp.rs` integration test ### Phase 2b slice A — replace directive + lockfile digests (SHIPPED — 2026-04-22) @@ -149,8 +149,8 @@ Spec-to-code convergence. [docs/package-format.md §2](package-format.md) and [d - [x] `ResolvedSource` enum (`Path` / `Oci` / `OciReplaced` / `GitReplaced`) drives the lockfile writer - [x] `chart_resolver::merge_into_lock` upserts path-dep + replace entries, preserving prior cosign / attestation metadata - [x] `AkuaLock::save` / `find` / `upsert` writer API -- [x] `akua add` best-effort updates the lockfile on every edit -- [x] `akua verify` exempts `path+file://` sources from strict_signing +- [x] `akuapkg add` best-effort updates the lockfile on every edit +- [x] `akuapkg verify` exempts `path+file://` sources from strict_signing ### Phase 2b slice B — OCI pull + digest verify (SHIPPED — 2026-04-22) @@ -158,20 +158,20 @@ Spec-to-code convergence. [docs/package-format.md §2](package-format.md) and [d - [x] Content-addressed cache at `$XDG_CACHE_HOME/akua/oci/sha256/` — second render reuses the unpacked tree - [x] Lockfile-pinned digest verify on pull — a drifted tag fails the render loudly with `LockDigestMismatch` - [x] `ResolverOptions { offline, cache_root, expected_digests }` gate — `resolve()` stays offline for tests; `resolve_with_options()` is the network path -- [x] `akua render` + `akua add` pass lockfile digests as `expected_digests` +- [x] `akuapkg render` + `akuapkg add` pass lockfile digests as `expected_digests` - [x] Integration test pulls `ghcr.io/stefanprodan/charts/podinfo:6.6.0`, caches, verifies digest-mismatch rejection ### Phase 2b slice C (SHIPPED — 2026-04-22) -- [x] `akua render --strict`: raw-string plugin paths rejected. Forces every chart to go through `akua.toml` + `import charts.`. Typed exit code `E_STRICT_UNTYPED_CHART`. -- [x] `akua render --offline`: OCI / git deps must cache-hit. Air-gapped CI path. -- [x] `akua verify` path-dep drift detection: re-hashes vendored charts on disk, emits `PathDigestDrift` / `PathMissing` violations when the tree diverged from `akua.lock` or was deleted. +- [x] `akuapkg render --strict`: raw-string plugin paths rejected. Forces every chart to go through `akua.toml` + `import charts.`. Typed exit code `E_STRICT_UNTYPED_CHART`. +- [x] `akuapkg render --offline`: OCI / git deps must cache-hit. Air-gapped CI path. +- [x] `akuapkg verify` path-dep drift detection: re-hashes vendored charts on disk, emits `PathDigestDrift` / `PathMissing` violations when the tree diverged from `akua.lock` or was deleted. - [x] Git deps via `gix` (pure Rust, no shell-out). Clones into `$XDG_CACHE_HOME/akua/git/repos/` + checkouts under `checkouts//`. Content-addressed, lockfile-pinned by commit SHA. - [x] Private-repo OCI auth via `~/.config/akua/auth.toml` (akua-native TOML) and `~/.docker/config.json` (standard docker login format). Basic auth + bearer PATs supported; docker credential helpers intentionally not (shell-out). - [x] Generated `charts.` module grows a `Values` schema (from `values.schema.json`) + a `TemplateOpts` wrapper + `template()` lambda pre-filled with `chart = path`. Authors call `nginx.template(nginx.TemplateOpts { values = {...} })` — the "chart: str | Chart" ergonomic win, via a callable on the module rather than a schema union. -- [x] `akua remove` prunes matching lockfile entries; `akua tree` shows `[replace -> ]` markers for fork overrides. +- [x] `akuapkg remove` prunes matching lockfile entries; `akuapkg tree` shows `[replace -> ]` markers for fork overrides. -**Exit gate:** ✅ all three slices shipped. OCI chart end-to-end via `akua render` (cache hit on second call). Git chart via `gix` (no shell-out). Private-repo auth for both. `--strict` / `--offline` / path-dep drift for CI-grade guarantees. `charts..template(...)` gives Package authors an autocomplete-driven authoring surface. +**Exit gate:** ✅ all three slices shipped. OCI chart end-to-end via `akuapkg render` (cache hit on second call). Git chart via `gix` (no shell-out). Private-repo auth for both. `--strict` / `--offline` / path-dep drift for CI-grade guarantees. `charts..template(...)` gives Package authors an autocomplete-driven authoring surface. --- @@ -193,20 +193,20 @@ are no host-side preopens to grant. --- -## Phase 4 — Wasmtime-hosted `akua render` (2-3 weeks) — **blocks v0.1.0** +## Phase 4 — Wasmtime-hosted `akuapkg render` (2-3 weeks) — **blocks v0.1.0** -Sandbox becomes the default execution path for akua itself. User-invoked `akua render` wraps a wasip1-compiled `akua-render-worker` inside wasmtime. Delivers CLAUDE.md's "sandboxed by default" invariant at the process level — **the precondition for cutting v0.1.0**. No release before this lands. +Sandbox becomes the default execution path for akua itself. User-invoked `akuapkg render` wraps a wasip1-compiled `akua-render-worker` inside wasmtime. Delivers CLAUDE.md's "sandboxed by default" invariant at the process level — **the precondition for cutting v0.1.0**. No release before this lands. - [x] **Spike complete 2026-04-24** ([docs/spikes/kcl-wasm-feasibility.md](spikes/kcl-wasm-feasibility.md)) — compile + runtime both green on `wasm32-wasip1`. Two runtime panics resolved same day: `kcl-driver::get_pkg_list` via [cnap-tech/kcl@akua-wasm32](https://github.com/cnap-tech/kcl/tree/akua-wasm32) fork + upstream PR [kcl-lang/kcl#2086](https://github.com/kcl-lang/kcl/pull/2086), `stdlib::stdlib_root` via cfg-guard in akua-core. - [x] `akua-render-worker` binary targeting `wasm32-wasip1` — Ping + Render requests both handled. akua-core + engine-kcl compiled into the worker via the `[patch]` pin. -- [x] Wasmtime host harness in `akua-cli`: per-render Store with `StoreLimits::memory_size(256 MiB)` + `epoch_interruption` + background epoch ticker. Single shared Engine for worker + engine plugins (helm, kustomize) per wasmtime's "one Engine, many Stores" pattern. Plugin bridge (`env::kcl_plugin_invoke_json_wasm`) ferries callouts across the Store boundary; plugin panics survive the wasip1 trap boundary via out-of-band capture on `HostState`. +- [x] Wasmtime host harness in `akuapkg-cli`: per-render Store with `StoreLimits::memory_size(256 MiB)` + `epoch_interruption` + background epoch ticker. Single shared Engine for worker + engine plugins (helm, kustomize) per wasmtime's "one Engine, many Stores" pattern. Plugin bridge (`env::kcl_plugin_invoke_json_wasm`) ferries callouts across the Store boundary; plugin panics survive the wasip1 trap boundary via out-of-band capture on `HostState`. - [x] AOT-compile `.cwasm` at akua's build time; embed in akua binary (`include_bytes!` wrapping `$OUT_DIR/akua-render-worker.cwasm`, Config-hash-matched to runtime). -- [x] `akua render`, `akua dev`, `akua repl` all dispatch through the worker — no native fallback. Plugin callouts (`helm.template`, `kustomize.build`) bridged to host handlers. +- [x] `akuapkg render`, `akuapkg dev`, `akuapkg repl` all dispatch through the worker — no native fallback. Plugin callouts (`helm.template`, `kustomize.build`) bridged to host handlers. - [x] CVE-2026-34988 mitigation: pinned `wasmtime = "43"` across workspace (43.0.1 min). - [ ] Benchmark regression suite: sub-100ms render budget still met (documented target, untested in the current sweep) - [ ] `InstanceAllocationStrategy::pooling(...)` + `Config::consume_fuel(true)` — deferred. Today's Store limits (memory + epoch) cover the invariant; fuel + pooling are optimization knobs, not correctness knobs. -**Exit gate:** every `akua render` runs inside wasmtime. Native code path no longer exists for render execution. **✅ Shipped 2026-04-24.** +**Exit gate:** every `akuapkg render` runs inside wasmtime. Native code path no longer exists for render execution. **✅ Shipped 2026-04-24.** --- @@ -253,17 +253,17 @@ HTTP front end for concurrent render requests. Per-request `Store` with preopens - [x] `cosign` module: ECDSA P-256 keyed verification of simple-signing payloads, digest correlation with the fetched manifest. - [x] `oci_fetcher::fetch_with_opts` pulls the `sha256-.sig` sidecar + payload blob when a public key is configured; surfaces `CosignVerify` / `CosignSignatureMissing` distinctly. -- [x] `akua.toml [signing] cosign_public_key = "./keys/cosign.pub"` config. `ResolverOptions.cosign_public_key_pem` threads through to the fetcher. `akua render` loads the key off disk. +- [x] `akua.toml [signing] cosign_public_key = "./keys/cosign.pub"` config. `ResolverOptions.cosign_public_key_pem` threads through to the fetcher. `akuapkg render` loads the key off disk. - [x] Typed CLI code `E_COSIGN_VERIFY` — agents branch on "bytes failed the supply-chain gate" separately from "couldn't resolve the chart." ### Phase 6 slice B — deferred — **targets v0.3.0** - [ ] Keyless verify via sigstore-rs (Fulcio cert chain + Rekor transparency log) -- [x] SLSA v1 predicate generation on `akua publish` (shipped Phase 7 B) -- [x] `akua verify` walks the attestation chain — Package → deps (direct only today; transitive deferred to Phase 7 C follow-up) +- [x] SLSA v1 predicate generation on `akuapkg publish` (shipped Phase 7 B) +- [x] `akuapkg verify` walks the attestation chain — Package → deps (direct only today; transitive deferred to Phase 7 C follow-up) - [ ] `akua.toml` `strictSigning: true` makes the signing block mandatory on every OCI dep -**Exit gate (full phase):** A published Package with a `charts.*` dep round-trips through `akua publish` → `akua pull` → `akua render` → `akua verify`, all signatures validated. Slice A lands keyed verify; slice B closes the loop with keyless + SLSA once `akua publish` exists. +**Exit gate (full phase):** A published Package with a `charts.*` dep round-trips through `akuapkg publish` → `akuapkg pull` → `akuapkg render` → `akuapkg verify`, all signatures validated. Slice A lands keyed verify; slice B closes the loop with keyless + SLSA once `akuapkg publish` exists. --- @@ -273,12 +273,12 @@ HTTP front end for concurrent render requests. Per-request `Store` with preopens - [x] `oci_transport` module: shared HTTP + bearer-challenge auth. Fetcher + puller + pusher all funnel through it. - [x] `oci_pusher` module: monolithic upload of blob + config + manifest under akua-specific media types (`application/vnd.akua.package.content.v1.tar+gzip`). -- [x] `akua publish --ref [--tag] [--no-sign]`: deterministic workspace tarball → OCI artifact. `package_tar::pack_workspace` excludes render outputs + hidden dirs + per-consumer `inputs.yaml`. +- [x] `akuapkg publish --ref [--tag] [--no-sign]`: deterministic workspace tarball → OCI artifact. `package_tar::pack_workspace` excludes render outputs + hidden dirs + per-consumer `inputs.yaml`. - [x] `oci_puller` module: inverse of pusher, enforces akua media type + manifest-declared digest. -- [x] `akua pull --ref --tag --out `: fetches + `package_tar::unpack_to` into a target directory. +- [x] `akuapkg pull --ref --tag --out `: fetches + `package_tar::unpack_to` into a target directory. - [x] Cosign signing primitive: `cosign::build_simple_signing_payload` + `sign_keyed` (P-256 ECDSA), round-trip proven against the verify primitive Phase 6 A shipped. - [x] `oci_pusher::push_cosign_signature`: pushes the `.sig` sidecar at `sha256-.sig` with `dev.cosignproject.cosign/signature` annotation. -- [x] `akua.toml [signing].cosign_private_key`: `akua publish` signs by default when set. `--no-sign` CLI override. +- [x] `akua.toml [signing].cosign_private_key`: `akuapkg publish` signs by default when set. `--no-sign` CLI override. - [x] Typed exit codes `E_PUBLISH_FAILED` / `E_PULL_FAILED`. ### Phase 7 slice B — SLSA attestation (SHIPPED — 2026-04-22) @@ -286,22 +286,22 @@ HTTP front end for concurrent render requests. Per-request `Store` with preopens - [x] `slsa` module: in-toto v1 statement + SLSA v1 provenance predicate builder. Materials pulled from `akua.lock`; `buildType = https://akua.dev/slsa/publish/v1`; builder id keyed to the akua release. - [x] `cosign::sign_dsse` / `verify_dsse`: DSSE v1 envelope sign + verify with PAE (Pre-Auth Encoding) binding `payloadType` into the signature so cross-envelope-type substitution is rejected. - [x] `oci_pusher::push_attestation`: pushes the DSSE envelope as a `.att` sidecar at `sha256-.att` with media type `application/vnd.dsse.envelope.v1+json`. -- [x] `akua publish` auto-attests when signing is active; `--no-attest` disables independently of `--no-sign`. `PublishOutput.attestation_tag` surfaces the sidecar ref. +- [x] `akuapkg publish` auto-attests when signing is active; `--no-attest` disables independently of `--no-sign`. `PublishOutput.attestation_tag` surfaces the sidecar ref. ### Phase 7 slice C (partial — SHIPPED 2026-04-22) - [x] `oci_puller::pull_attestation`: fetches the `.att` sidecar from a registry + returns the DSSE envelope bytes. 404 → Ok(None) so consumers can distinguish "publisher didn't attest" from transport errors. -- [x] `akua verify` attestation chain walk: for every OCI dep in `akua.lock`, when a cosign public key is configured, pulls + verifies the sidecar, asserts the SLSA subject digest matches the lockfile-pinned digest. Three new typed violations: `AttestationMissing`, `AttestationInvalid`, `AttestationSubjectMismatch`. +- [x] `akuapkg verify` attestation chain walk: for every OCI dep in `akua.lock`, when a cosign public key is configured, pulls + verifies the sidecar, asserts the SLSA subject digest matches the lockfile-pinned digest. Three new typed violations: `AttestationMissing`, `AttestationInvalid`, `AttestationSubjectMismatch`. ### Phase 7 slice C — encrypted keys (SHIPPED — 2026-04-22) - [x] `cosign::sign_keyed_with_passphrase` + `sign_dsse_with_passphrase`: encrypted PKCS#8 PEM (`-----BEGIN ENCRYPTED PRIVATE KEY-----`) supported. Unencrypted path unchanged. -- [x] `akua publish` reads `$AKUA_COSIGN_PASSPHRASE`. No `--passphrase` CLI flag — argv leaks to `ps`. +- [x] `akuapkg publish` reads `$AKUA_COSIGN_PASSPHRASE`. No `--passphrase` CLI flag — argv leaks to `ps`. - [x] Missing passphrase on encrypted key surfaces a clear error naming the env var. ### Phase 7 slice C — vendored deps (SHIPPED — 2026-04-22) -- [x] `akua publish` resolves non-path deps + embeds each chart tree at `.akua/vendor//` in the tarball. Resolver failures print a loud stderr warning — no silent un-vendored publishes. +- [x] `akuapkg publish` resolves non-path deps + embeds each chart tree at `.akua/vendor//` in the tarball. Resolver failures print a loud stderr warning — no silent un-vendored publishes. - [x] Resolver consults `/.akua/vendor//` before attempting network fetch. Offline-after-pull renders now succeed for a published Package with OCI or git deps. - [x] End-to-end round-trip integration test: pack-with-vendor → unpack → offline resolve → assert nginx resolved from `.akua/vendor/` with matching digest. @@ -310,20 +310,20 @@ HTTP front end for concurrent render requests. Per-request `Store` with preopens - [ ] Recursive attestation walk over transitive deps — a published Package's own deps must themselves be attested. Blocked on fixture Packages that attest their dep graph. - [ ] HSM / cosign-native key formats (PKCS#11 / cosign-cli key ref) — targets v0.3.0. -**Exit gate (full phase):** Published Package round-trips `akua publish` → `akua pull` → `akua render` with cosign signatures validated at each hop. ✅ slice A covers the core round-trip; slice B adds SLSA + offline-render-from-published-digests on top. +**Exit gate (full phase):** Published Package round-trips `akuapkg publish` → `akuapkg pull` → `akuapkg render` with cosign signatures validated at each hop. ✅ slice A covers the core round-trip; slice B adds SLSA + offline-render-from-published-digests on top. --- -## Phase 8 — Author surface (`akua test`, `akua dev`, `akua repl`) +## Phase 8 — Author surface (`akuapkg test`, `akuapkg dev`, `akuapkg repl`) -Shipping incrementally alongside the core. `akua test` is live; the +Shipping incrementally alongside the core. `akuapkg test` is live; the rest ship when demand justifies the surface. -- [x] `akua test` — `test_*.k` / `*_test.k` runner. Files are evaluated via the same `PackageK` loader `akua render` uses; KCL `assert` + `check:` failures surface as per-file test failures. Structured JSON verdict + exit code 1 on any fail. (2026-04-22) +- [x] `akuapkg test` — `test_*.k` / `*_test.k` runner. Files are evaluated via the same `PackageK` loader `akuapkg render` uses; KCL `assert` + `check:` failures surface as per-file test failures. Structured JSON verdict + exit code 1 on any fail. (2026-04-22) - [ ] Rego test runner (`*_test.rego`) — paired with the policy engine phase -- [x] Golden-file snapshot support for render-output tests — `akua test --golden` dir-diffs every `package.k`×`inputs*.yaml` combo against `snapshots///`; `--update-snapshots` regenerates. (2026-04-22) -- [x] `akua dev` — file-watch hot-reload. `notify` + `notify-debouncer-mini`; `Rendered`/`RenderError` events stream to stdout (JSONL in agent mode). Watches per kept subdir non-recursively so `target/`/`node_modules/` monorepos don't exhaust `fs.inotify.max_user_watches`. Broken-pipe-aware. (2026-04-22) — apply-to-cluster deferred (needs kind driver). -- [~] `akua repl` — KCL half shipped (2026-04-24): accumulates submitted lines into a growing `.k` source, re-evaluates via `eval_source`, prints top-level YAML. Meta commands `.load / .reset / .show / .help / .exit`. Plain-line I/O (users wanting history wrap via `rlwrap`). Rego half deferred until the policy engine phase is designed. +- [x] Golden-file snapshot support for render-output tests — `akuapkg test --golden` dir-diffs every `package.k`×`inputs*.yaml` combo against `snapshots///`; `--update-snapshots` regenerates. (2026-04-22) +- [x] `akuapkg dev` — file-watch hot-reload. `notify` + `notify-debouncer-mini`; `Rendered`/`RenderError` events stream to stdout (JSONL in agent mode). Watches per kept subdir non-recursively so `target/`/`node_modules/` monorepos don't exhaust `fs.inotify.max_user_watches`. Broken-pipe-aware. (2026-04-22) — apply-to-cluster deferred (needs kind driver). +- [~] `akuapkg repl` — KCL half shipped (2026-04-24): accumulates submitted lines into a growing `.k` source, re-evaluates via `eval_source`, prints top-level YAML. Meta commands `.load / .reset / .show / .help / .exit`. Plain-line I/O (users wanting history wrap via `rlwrap`). Rego half deferred until the policy engine phase is designed. --- @@ -332,20 +332,20 @@ rest ship when demand justifies the surface. Glue that ships alongside the author loop but targets operators rather than authors. Small, composable, agent-friendly. -- [x] `akua cache list | clear [--oci|--git|--helm] | path` — inventory + reclaim the content-addressed caches under `$XDG_CACHE_HOME/akua/{oci,git,helm}` that `akua add` + `akua render` populate. Discriminated JSON shape `{action: list|clear|path, …}`. Ephemeral CI runners and disk-pressure triage without `rm -rf` guessing. (2026-04-23) -- [x] `akua auth list | add | remove` — manage `$XDG_CONFIG_HOME/akua/auth.toml` without hand-editing TOML. `add --username`/`--token` reads the secret from stdin (mirrors `docker login --password-stdin` — no secret on argv, no TTY dependency). `list` tags each entry with source ("akua" / "docker" / "both") and auth_kind, never echoing secrets. (2026-04-23) -- [x] `akua pack` — local-file sibling of `akua publish`. Writes the same deterministic `.tar.gz` to disk instead of pushing. Unlocks air-gap transfers, offline signing, and bit-diff archival. Defaults to `/dist/-.tar.gz` (walker-skipped subdir so re-packing is idempotent); `--no-vendor` skips embedding deps. Emits `layer_digest` matching the OCI layer digest the registry would assign. (2026-04-23) -- [x] `akua push --tarball --ref --tag ` — upload a pre-packed tarball. The push half of `akua publish`, decomposed so air-gap flows complete: pack here, transfer, push there. No signing / attestation (publish remains the all-in-one). (2026-04-24) -- [x] `akua inspect --tarball ` — triage a packed `.tar.gz` in-memory without unpacking. Reports `{package_name, version, edition}` parsed from the embedded `akua.toml`, `layer_digest`, `{compressed,uncompressed}_size_bytes`, `file_count`, sorted `vendored_deps`. Completes the air-gap triad: pack → transfer → inspect → push. (2026-04-24) -- [x] `akua lock [--check]` — regenerate `akua.lock` from `akua.toml` (cargo `generate-lockfile` analogue). `--check` diffs without writing and exits `E_LOCK_DRIFT` on staleness — pre-commit / CI gate to catch "author edited akua.toml but forgot to re-lock." Preserves signatures on unchanged entries via `merge_into_lock`; canonical TOML byte-compare for drift detection. (2026-04-24) -- [x] `akua update [--dep ]` — intentionally bump the lock against whatever upstream now serves. Inverse stance to `akua lock`: where `lock` rejects OCI digest drift (security), `update` accepts it and records the new digest. `--dep` scopes the lockfile write to one entry (cargo `update -p foo` analogue). Output lists `{updated, unchanged, skipped}` so operators see exactly what moved. (2026-04-24) -- [x] `akua sign` + `akua push --sig` — offline signing pair that completes the air-gap flow. `akua sign --tarball --ref --tag [--key]` computes `oci_pusher::compute_publish_digests()` locally (pure function, matches registry-side math post-push) and writes a `.akuasig` sidecar (JSON; carries `{oci_ref, tag, manifest_digest, simple_signing_payload, signature_b64, akua_version}`). `akua push --sig ` validates ref/tag/digest against the push target pre-upload, then pushes the `.sig` tag via the existing cosign push path. Sign + push hosts must pin the same akua binary (config blob embeds `env!("CARGO_PKG_VERSION")`). (2026-04-24) -- [x] `akua verify --tarball [--sig ] [--public-key ]` — offline verify against a `.akuasig`, no registry round-trip. Three checks: sidecar readable, local manifest_digest matches sidecar's, ECDSA signature verifies (skipped when no public key). Falls back to `akua.toml [signing].cosign_public_key`. Closes the air-gap loop: pack → sign → transfer → verify → push. Full chain smoke-tested end-to-end. (2026-04-24) +- [x] `akuapkg cache list | clear [--oci|--git|--helm] | path` — inventory + reclaim the content-addressed caches under `$XDG_CACHE_HOME/akua/{oci,git,helm}` that `akuapkg add` + `akuapkg render` populate. Discriminated JSON shape `{action: list|clear|path, …}`. Ephemeral CI runners and disk-pressure triage without `rm -rf` guessing. (2026-04-23) +- [x] `akuapkg auth list | add | remove` — manage `$XDG_CONFIG_HOME/akua/auth.toml` without hand-editing TOML. `add --username`/`--token` reads the secret from stdin (mirrors `docker login --password-stdin` — no secret on argv, no TTY dependency). `list` tags each entry with source ("akua" / "docker" / "both") and auth_kind, never echoing secrets. (2026-04-23) +- [x] `akuapkg pack` — local-file sibling of `akuapkg publish`. Writes the same deterministic `.tar.gz` to disk instead of pushing. Unlocks air-gap transfers, offline signing, and bit-diff archival. Defaults to `/dist/-.tar.gz` (walker-skipped subdir so re-packing is idempotent); `--no-vendor` skips embedding deps. Emits `layer_digest` matching the OCI layer digest the registry would assign. (2026-04-23) +- [x] `akuapkg push --tarball --ref --tag ` — upload a pre-packed tarball. The push half of `akuapkg publish`, decomposed so air-gap flows complete: pack here, transfer, push there. No signing / attestation (publish remains the all-in-one). (2026-04-24) +- [x] `akuapkg inspect --tarball ` — triage a packed `.tar.gz` in-memory without unpacking. Reports `{package_name, version, edition}` parsed from the embedded `akua.toml`, `layer_digest`, `{compressed,uncompressed}_size_bytes`, `file_count`, sorted `vendored_deps`. Completes the air-gap triad: pack → transfer → inspect → push. (2026-04-24) +- [x] `akuapkg lock [--check]` — regenerate `akua.lock` from `akua.toml` (cargo `generate-lockfile` analogue). `--check` diffs without writing and exits `E_LOCK_DRIFT` on staleness — pre-commit / CI gate to catch "author edited akua.toml but forgot to re-lock." Preserves signatures on unchanged entries via `merge_into_lock`; canonical TOML byte-compare for drift detection. (2026-04-24) +- [x] `akuapkg update [--dep ]` — intentionally bump the lock against whatever upstream now serves. Inverse stance to `akuapkg lock`: where `lock` rejects OCI digest drift (security), `update` accepts it and records the new digest. `--dep` scopes the lockfile write to one entry (cargo `update -p foo` analogue). Output lists `{updated, unchanged, skipped}` so operators see exactly what moved. (2026-04-24) +- [x] `akua sign` + `akuapkg push --sig` — offline signing pair that completes the air-gap flow. `akua sign --tarball --ref --tag [--key]` computes `oci_pusher::compute_publish_digests()` locally (pure function, matches registry-side math post-push) and writes a `.akuasig` sidecar (JSON; carries `{oci_ref, tag, manifest_digest, simple_signing_payload, signature_b64, akua_version}`). `akuapkg push --sig ` validates ref/tag/digest against the push target pre-upload, then pushes the `.sig` tag via the existing cosign push path. Sign + push hosts must pin the same akua binary (config blob embeds `env!("CARGO_PKG_VERSION")`). (2026-04-24) +- [x] `akuapkg verify --tarball [--sig ] [--public-key ]` — offline verify against a `.akuasig`, no registry round-trip. Three checks: sidecar readable, local manifest_digest matches sidecar's, ECDSA signature verifies (skipped when no public key). Falls back to `akua.toml [signing].cosign_public_key`. Closes the air-gap loop: pack → sign → transfer → verify → push. Full chain smoke-tested end-to-end. (2026-04-24) ### Planned -- [ ] `akua attest` + `akua push --att` — offline attestation pair symmetric to `akua sign`. Signs an SLSA v1 DSSE envelope bound to the tarball's manifest digest; sidecar format `.akuaatt` mirrors `.akuasig`. Completes the air-gap crypto story alongside signing. -- [ ] Extend `akua verify --tarball` with `--att ` — DSSE attestation verify. Lands with `akua attest`. +- [ ] `akua attest` + `akuapkg push --att` — offline attestation pair symmetric to `akua sign`. Signs an SLSA v1 DSSE envelope bound to the tarball's manifest digest; sidecar format `.akuaatt` mirrors `.akuasig`. Completes the air-gap crypto story alongside signing. +- [ ] Extend `akuapkg verify --tarball` with `--att ` — DSSE attestation verify. Lands with `akua attest`. --- @@ -363,7 +363,7 @@ Concrete boxes to check before cutting the alpha tag. Everything under "core ver v0.1.0 doesn't cut until CLAUDE.md's promise holds end-to-end. No caveats in release notes say otherwise. -- [x] Phase 4 shipped — every `akua render` / `akua dev` / `akua repl` runs inside wasmtime. No native render path exists. +- [x] Phase 4 shipped — every `akuapkg render` / `akuapkg dev` / `akuapkg repl` runs inside wasmtime. No native render path exists. - [~] Phase 4B shipped — Node-side lands (`@akua-dev/sdk` loads `akua-wasm` lazily, first WASM-backed method green). Browser target + engine bundling outstanding. - [~] Fuel-exhaustion — fuel not wired for v0.1.0 (see Phase 4 notes above); epoch is the active CPU cap. Covered by `epoch_cap_traps_runaway_evaluation` in `tests/sandbox_adversarial.rs`. - [x] Adversarial test: memory-bomb allocation fails cleanly against the per-render `StoreLimitsBuilder::memory_size` cap. (`memory_cap_enforced_below_minimum_instance_size` + `memory_cap_traps_runtime_growth_past_limit`.) @@ -379,11 +379,11 @@ v0.1.0 doesn't cut until CLAUDE.md's promise holds end-to-end. No caveats in rel ### Build + test - [ ] Release notes draft — what's in (feature absences only, never invariant caveats), what comes in v0.2.0 (hosted multi-tenant via `akua serve`) -- [ ] `cargo test -p akua-core -p akua-cli` green on CI across Linux + macOS +- [ ] `cargo test -p akua-core -p akuapkg-cli` green on CI across Linux + macOS - [ ] `akua --version` matches the tag -- [ ] Every `examples//` renders through `akua render` without errors -- [ ] Every `examples//` passes `akua check && akua lint && akua test` -- [ ] One curated upstream Package published to a public OCI registry for `akua pull` smoke-testing +- [ ] Every `examples//` renders through `akuapkg render` without errors +- [ ] Every `examples//` passes `akuapkg check && akuapkg lint && akuapkg test` +- [ ] One curated upstream Package published to a public OCI registry for `akuapkg pull` smoke-testing ### Docs sweep — sharpen + remove outdated claims @@ -404,13 +404,13 @@ Many markdown files predate recent shipping and make claims that no longer match - [ ] **[docs/impl-plan.md](impl-plan.md)** — cross-check against roadmap.md; remove duplication, or collapse to a pointer if this file has drifted past usefulness. - [ ] **[docs/sdk.md](sdk.md)** — if the TypeScript SDK isn't shipped, mark as target-state or remove the reference from CLAUDE.md. - [ ] **`examples/*/README.md`** — every example's README describes what it actually does today. Remove "shell-out" references; point to Phase 1/3 WASM engines. -- [ ] **Package author's README template** — `akua init` scaffolds a README that compiles on first `akua render`. +- [ ] **Package author's README template** — `akuapkg init` scaffolds a README that compiles on first `akuapkg render`. ### Feature-docs for shipped surface -- [ ] Air-gap flow end-to-end: `akua pack` → `akua sign` → transfer → `akua verify --tarball` → `akua push --sig`, runnable snippet with a freshly-generated key. -- [ ] Publishing story: `akua publish` + `[signing]` config + what a consumer sees on `akua pull` + `akua verify`. -- [ ] Operational verbs crib sheet: `akua cache`, `akua auth`, `akua lock [--check]`, `akua update`. +- [ ] Air-gap flow end-to-end: `akuapkg pack` → `akua sign` → transfer → `akuapkg verify --tarball` → `akuapkg push --sig`, runnable snippet with a freshly-generated key. +- [ ] Publishing story: `akuapkg publish` + `[signing]` config + what a consumer sees on `akuapkg pull` + `akuapkg verify`. +- [ ] Operational verbs crib sheet: `akuapkg cache`, `akuapkg auth`, `akuapkg lock [--check]`, `akuapkg update`. ### @akua-dev/sdk — TypeScript SDK via WASM on JSR (blocks v0.1.0) diff --git a/docs/sdk.md b/docs/sdk.md index 4b3b75e5..4c899e0e 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -63,7 +63,7 @@ The package currently exports the `Akua` class, SDK error classes, validation he | Method | Returns | Notes | |---|---|---| | `version()` | `VersionOutput` | SDK and native version information. | -| `whoami()` | `WhoamiOutput` | Mirrors `akua whoami`. | +| `whoami()` | `WhoamiOutput` | Mirrors `akuapkg whoami`. | | `render(opts)` | `RenderSummary` | Executes an on-disk Package and writes rendered YAML files to `out`. | | `renderSource(opts)` | `string` | Executes Package source or a Package file and returns raw rendered YAML. | | `export(opts)` | `Record` | Returns the Package `Input` schema as JSON Schema or OpenAPI. | diff --git a/docs/security-audit-2026-05-29.md b/docs/security-audit-2026-05-29.md index 42a580f1..665f1047 100644 --- a/docs/security-audit-2026-05-29.md +++ b/docs/security-audit-2026-05-29.md @@ -26,7 +26,7 @@ fetch buffering, decompression bombs). | # | Severity | Finding | Area | Status | |---|---|---|---|---| -| 1 | HIGH | `akua publish` does not strip `replace` directives before packing+signing | supply-chain | ✅ fixed | +| 1 | HIGH | `akuapkg publish` does not strip `replace` directives before packing+signing | supply-chain | ✅ fixed | | 2 | HIGH | KCL injection via unsanitized `values.schema.json` property names | codegen | ✅ fixed | | 3 | HIGH | KCL docstring breakout via unescaped `"""` in schema descriptions | codegen | ✅ fixed | | 4 | MEDIUM | Native helm/kustomize engine Stores have no memory cap + infinite epoch → chart DoS | sandbox | ✅ fixed | @@ -54,15 +54,15 @@ is the universal verified-before-write gate and cosign signature verification en (fail-closed) when a `[signing].cosign_public_key` is configured — keeping signing opt-in rather than breaking every key-less workspace. **#16** (stale worker preopen comment) and **#17** (`--timeout` now derives the worker epoch deadline, with a unit -test) are fixed. All `akua-core` + `akua-cli` tests pass on the merged result; the CLI +test) are fixed. All `akua-core` + `akuapkg-cli` tests pass on the merged result; the CLI builds clean. Each "Fix:" note below describes the change that landed. ## Findings -### 1. [HIGH] `akua publish` does not strip `replace` before signing -`crates/akua-core/src/package_tar.rs:133-144`, `crates/akua-cli/src/verbs/publish.rs:183` +### 1. [HIGH] `akuapkg publish` does not strip `replace` before signing +`crates/akua-core/src/package_tar.rs:133-144`, `crates/akuapkg-cli/src/verbs/publish.rs:183` -CLAUDE.md: *"`akua publish` strips every `replace` directive from the artifact's +CLAUDE.md: *"`akuapkg publish` strips every `replace` directive from the artifact's manifest before signing — consumers never inherit a publisher's replace."* This is **not implemented.** `pack_workspace_with_vendored_deps` appends `akua.toml` byte-for-byte, so the manifest's `replace` directives survive into the digested, @@ -132,7 +132,7 @@ serde shape). The `blocking-http-transport-curl-rustls` gix feature applies Git-compatible TLS env settings, including `GIT_SSL_NO_VERIFY`. On a poisoned environment, an attacker can -disable TLS validation and MITM the *first* `akua add` of a git dep (TOFU window); +disable TLS validation and MITM the *first* `akuapkg add` of a git dep (TOFU window); subsequent fetches are protected by the lockfile commit pin. **Fix:** every initial clone and cached-repository refresh now forces `ssl_verify = true` before the TLS handshake, ignoring `GIT_SSL_NO_VERIFY` and `http.sslVerify=false`. The connection @@ -141,7 +141,7 @@ retains only `ssl_ca_info`, so custom trust configured through `GIT_SSL_CAINFO` credentials, or other Git transport options. ### 9. [MEDIUM] Cosign verification is opt-in, not "verify by default" -`crates/akua-cli/src/verbs/render.rs:482-498`, `verify.rs:280-285`, `oci_fetcher.rs:439-449` +`crates/akuapkg-cli/src/verbs/render.rs:482-498`, `verify.rs:280-285`, `oci_fetcher.rs:439-449` Signature/attestation verification only engages when `[signing].cosign_public_key` is configured; absent a key, the crypto verify is a silent no-op and only diff --git a/docs/security-model.md b/docs/security-model.md index 27b634eb..6cade24e 100644 --- a/docs/security-model.md +++ b/docs/security-model.md @@ -25,7 +25,7 @@ akua is a **sandboxed-by-default** render substrate. Every render runs inside a - **Declarative mischief** in the Package's rendered output. akua produces whatever YAML the author writes. Policy evaluation ([docs/policy-format.md](policy-format.md)) is the layer that catches "this Package declares a root-privileged Deployment." The renderer's job is faithful execution of the Package, not moral judgment. - **Side-channel leaks** (timing, memory-access patterns). wasmtime provides strong isolation but not constant-time; a sophisticated adversary could extract bits via timing. Not our bar. -- **Bugs in the dep supply chain beyond what the lockfile catches.** `akua.lock` pins OCI deps by sha256 of the chart blob; a drift between what the lockfile recorded and what the registry now serves is rejected (`LockDigestMismatch`). But if the *initial* `akua add` pulled from a compromised registry that served a malicious chart and recorded its digest, every subsequent render faithfully reproduces it. Phase 6 (cosign verification + SLSA attestation walk) closes this gap. +- **Bugs in the dep supply chain beyond what the lockfile catches.** `akua.lock` pins OCI deps by sha256 of the chart blob; a drift between what the lockfile recorded and what the registry now serves is rejected (`LockDigestMismatch`). But if the *initial* `akuapkg add` pulled from a compromised registry that served a malicious chart and recorded its digest, every subsequent render faithfully reproduces it. Phase 6 (cosign verification + SLSA attestation walk) closes this gap. --- @@ -48,7 +48,7 @@ akua follows wasmtime's documented pattern: **one process-global `Engine`, one ` When a Package calls `helm.template(...)` or `kustomize.build(...)` from inside the render worker: ``` -akua-cli (native Rust) +akuapkg-cli (native Rust) └ Engine (shared) ├ Store A — render worker, KCL evaluator paused in host import │ ⇣ kcl_plugin_invoke_json_wasm (wasm import) @@ -88,7 +88,7 @@ Even inside the sandbox, akua applies additional invariants on the Package's own - **Path-traversal guard** on every plugin callable's path argument. `kcl_plugin::resolve_in_package` canonicalizes + asserts-under-package-dir + resolves symlinks. A Package that passes `"../../etc/passwd"` to `pkg.render(...)` gets a typed error, not a render. Absolute paths are accepted only when they fall under an `allowed_roots` entry the renderer registered — today, that's exactly the set of resolved `charts.*` deps (path-based dep dir or OCI cache dir for the blob we just pulled). Nothing else. - **KCL language-level sandbox.** The KCL language itself has no `os.read`, `http.get`, env reads, or `time.now()`. A pure-KCL Package is deterministic by construction. This is upstream KCL's own invariant. - **Plugin registry is closed.** Only akua-core can register plugins (`kcl_plugin::register` is pub but only called at akua startup). Packages cannot invent their own. -- **Strict render mode** (`--strict`): reject raw-string paths in plugin callables. Forces typed `charts.*` imports resolved via `akua.toml`. Default for `akua publish` and `akua serve`; optional for interactive `akua render`. +- **Strict render mode** (`--strict`): reject raw-string paths in plugin callables. Forces typed `charts.*` imports resolved via `akua.toml`. Default for `akuapkg publish` and `akua serve`; optional for interactive `akuapkg render`. --- @@ -101,22 +101,22 @@ This is the current-state gap vs the target. See [docs/roadmap.md](roadmap.md) p | Path-traversal rejection in plugin handlers | Shipped — `resolve_in_package` + `allowed_roots` | ✅ Phase 0 | | `helm.template` / `kustomize.build` via WASM engines | Shipped — no shell-out, wasmtime-hosted | ✅ Phases 1 + 3 | | Typed `charts.*` imports + lockfile digests | Shipped — path + OCI, replace override | ✅ Phase 2a, 2b A+B | -| `akua render --strict` rejects raw chart paths | Shipped — `E_STRICT_UNTYPED_CHART` | ✅ Phase 2b C | -| `akua verify` path-dep digest drift detection | Shipped — `PathDigestDrift` / `PathMissing` | ✅ Phase 2b C | +| `akuapkg render --strict` rejects raw chart paths | Shipped — `E_STRICT_UNTYPED_CHART` | ✅ Phase 2b C | +| `akuapkg verify` path-dep digest drift detection | Shipped — `PathDigestDrift` / `PathMissing` | ✅ Phase 2b C | | Render worker wrapped in wasmtime | Shipped — every render runs inside a `Store` with memory/epoch caps + capability-model preopens | ✅ Phase 4 | | `akua serve` per-tenant isolation | Verb doesn't exist | Phase 5 | | cosign keyed verification on OCI deps | Shipped — `[signing] cosign_public_key`, ECDSA P-256 | ✅ Phase 6 A | -| `akua publish` with cosign sign-by-default | Shipped — P-256 PKCS#8 PEM private keys | ✅ Phase 7 A | -| `akua pull` with manifest digest verify | Shipped | ✅ Phase 7 A | +| `akuapkg publish` with cosign sign-by-default | Shipped — P-256 PKCS#8 PEM private keys | ✅ Phase 7 A | +| `akuapkg pull` with manifest digest verify | Shipped | ✅ Phase 7 A | | cosign keyless (fulcio + rekor) verification | Not implemented | Phase 6 B | | SLSA v1 attestation generation on publish | Shipped — DSSE envelope, in-toto v1 statement | ✅ Phase 7 B | -| `akua verify` attestation chain walk | Shipped — pulls `.att` sidecars + DSSE verify + subject-digest check for every OCI dep | ✅ Phase 7 C | +| `akuapkg verify` attestation chain walk | Shipped — pulls `.att` sidecars + DSSE verify + subject-digest check for every OCI dep | ✅ Phase 7 C | | Recursive attestation walk over transitive deps | Not implemented — needs published Package to attest its own deps | Phase 7 C (follow-up) | | Encrypted cosign private keys — PKCS#8 PBES2 | Shipped — `$AKUA_COSIGN_PASSPHRASE` env var | ✅ Phase 7 C | -| OCI-vendored deps → network-free `akua render` after pull | Shipped — `.akua/vendor//` convention | ✅ Phase 7 C | +| OCI-vendored deps → network-free `akuapkg render` after pull | Shipped — `.akua/vendor//` convention | ✅ Phase 7 C | | HSM / cosign-native key format | Not implemented | Phase 7 D | | Git dep checkout via `gix` | Shipped — pure Rust, no shell-out | ✅ Phase 2b C | -| Private-repo OCI auth (docker config / akua auth.toml) | Shipped — Basic + bearer PAT | ✅ Phase 2b C | +| Private-repo OCI auth (docker config / akuapkg auth.toml) | Shipped — Basic + bearer PAT | ✅ Phase 2b C | | Docker credential helpers | Not implemented — would require shell-out | Won't ship | --- diff --git a/docs/security.md b/docs/security.md index 2ad77528..402214d5 100644 --- a/docs/security.md +++ b/docs/security.md @@ -48,7 +48,7 @@ This is not a mitigation bolted onto `helm template` — it is a structural cons ArgoCD, by default, fetches Helm charts by tag at sync time. Tags are mutable: a supply chain attacker who controls the chart registry can replace `v1.2.3` with malicious content after your ArgoCD config points to it. -akua uses a content-addressed lockfile (`akua.lock`) that pins every chart dependency to a SHA-256 digest at `akua publish` time: +akua uses a content-addressed lockfile (`akua.lock`) that pins every chart dependency to a SHA-256 digest at `akuapkg publish` time: ```toml # akua.lock (committed to git) @@ -62,15 +62,15 @@ At render time, akua verifies the digest before invoking the Helm engine. If the ### 3. Cosign signatures + SLSA v1 attestations -Every `akua publish` emits: +Every `akuapkg publish` emits: - A **cosign signature** over the package OCI digest (keyless via Sigstore, or key-based). - A **SLSA v1 Build predicate** recording builder identity, source commit, and the set of input digests. -On `akua pull`, the `akua.lock` digest is always verified before bytes touch disk. Cosign signature + SLSA attestation verification additionally engages — fail-closed — when the consuming workspace configures a `[signing] cosign_public_key`: +On `akuapkg pull`, the `akua.lock` digest is always verified before bytes touch disk. Cosign signature + SLSA attestation verification additionally engages — fail-closed — when the consuming workspace configures a `[signing] cosign_public_key`: ```sh -akua pull oci://registry.example.com/my-app:1.0.0 +akuapkg pull oci://registry.example.com/my-app:1.0.0 # → always: verifies the pulled blob against the akua.lock pinned digest # → with [signing] cosign_public_key configured: # verifies the cosign signature + SLSA predicate digest chain, @@ -84,7 +84,7 @@ This gives you a cryptographic chain from source commit to deployed manifests. A The ArgoCD repo-server fetches chart dependencies at render time. This opens SSRF attack surfaces: a chart can declare a `repository:` pointing at an internal service, and the fetch happens with repo-server's network privileges. -akua separates **resolution** (happens at `akua publish` time, produces `akua.lock`) from **rendering** (happens offline, using only the already-fetched + digest-verified content). The Helm WASM engine receives charts as in-memory bytes with no ability to initiate network calls. There is no SSRF surface during rendering. +akua separates **resolution** (happens at `akuapkg publish` time, produces `akua.lock`) from **rendering** (happens offline, using only the already-fetched + digest-verified content). The Helm WASM engine receives charts as in-memory bytes with no ability to initiate network calls. There is no SSRF surface during rendering. --- diff --git a/docs/spikes/engines-on-wasm32-unknown-unknown.md b/docs/spikes/engines-on-wasm32-unknown-unknown.md index 081d9c66..f6129218 100644 --- a/docs/spikes/engines-on-wasm32-unknown-unknown.md +++ b/docs/spikes/engines-on-wasm32-unknown-unknown.md @@ -4,7 +4,7 @@ Phase 4 shipped `akua-wasm` compiling the KCL render path to `wasm32-unknown-unknown`. `@akua-dev/sdk` v0.0.0 consumes the Node build; `Akua.renderSource()` renders pure-KCL Packages in-process. -The remaining Phase 4B gap is **engine callouts from the browser**: `helm.template(...)` and `kustomize.build(...)` are implemented as Go engines compiled to `wasm32-wasip1`, hosted inside the CLI's wasmtime Engine via the `engine-host-wasm` crate. That shape works on the CLI (`akua render`) and on `@akua-dev/sdk` for Node (bundled CLI binary — though the SDK today wires only `renderSource`, not the helm/kustomize callouts). It does **not** work in the browser: there's no wasmtime, no WASI host, and the `env::kcl_plugin_invoke_json_wasm` bridge has no one to answer it. +The remaining Phase 4B gap is **engine callouts from the browser**: `helm.template(...)` and `kustomize.build(...)` are implemented as Go engines compiled to `wasm32-wasip1`, hosted inside the CLI's wasmtime Engine via the `engine-host-wasm` crate. That shape works on the CLI (`akuapkg render`) and on `@akua-dev/sdk` for Node (bundled CLI binary — though the SDK today wires only `renderSource`, not the helm/kustomize callouts). It does **not** work in the browser: there's no wasmtime, no WASI host, and the `env::kcl_plugin_invoke_json_wasm` bridge has no one to answer it. v0.1.0 blocks on deciding what to do. This doc enumerates the candidates and records the call. diff --git a/docs/spikes/kcl-wasm-feasibility.md b/docs/spikes/kcl-wasm-feasibility.md index 2a392fbb..b7828019 100644 --- a/docs/spikes/kcl-wasm-feasibility.md +++ b/docs/spikes/kcl-wasm-feasibility.md @@ -34,7 +34,7 @@ Produces a 145 MB wasip1 binary (unoptimized debug). Compile is clean. 2. **`akua_core::stdlib::stdlib_root`** calls `std::env::temp_dir()` — also an unconditional panic on wasip1 (`sys/pal/wasip1/os.rs:119:5`, same error message as the kcl issue but a different call site). Fixed in-tree: skip the "akua" stdlib `ExternalPkg` on wasm32 (pure-KCL Packages work; stdlib-requiring Packages will land later when the plugin bridge forwards `akua.*` callouts from worker to host). -**Go signal for Phase 4 — confirmed.** End-to-end test shipped: `render_pure_kcl_returns_yaml_end_to_end` evaluates `x = 42\ngreeting = "hello"\n` inside the per-render wasmtime sandbox and recovers the top-level YAML with correct values. Sandbox resources (fuel / epoch / 256 MiB memory) active throughout. Test runs on every `cargo test -p akua-cli` invocation. +**Go signal for Phase 4 — confirmed.** End-to-end test shipped: `render_pure_kcl_returns_yaml_end_to_end` evaluates `x = 42\ngreeting = "hello"\n` inside the per-render wasmtime sandbox and recovers the top-level YAML with correct values. Sandbox resources (fuel / epoch / 256 MiB memory) active throughout. Test runs on every `cargo test -p akuapkg-cli` invocation. ### wasm32-unknown-unknown — yellow, two fixable issues diff --git a/docs/spikes/pkg-render-import-method.md b/docs/spikes/pkg-render-import-method.md index 0fcd1033..51f2bf09 100644 --- a/docs/spikes/pkg-render-import-method.md +++ b/docs/spikes/pkg-render-import-method.md @@ -18,7 +18,7 @@ call site that reads naturally to a coding agent or human reviewer. ## Decision Each Akua Package's `package.k` declares two akua-managed lines at -the bottom (templated by `akua init`, validated by `akua lint`): +the bottom (templated by `akuapkg init`, validated by `akuapkg lint`): ```kcl __id = "upstream" # must equal [package].name in akua.toml @@ -77,7 +77,7 @@ rather than reading it from the call. `pkg.render({ package = "upstream", inputs = ... })` keeps the engine- plugin shape (visible call) but reintroduces a stringly-typed package -reference. KCL doesn't catch typos; only `akua check` does. Type- +reference. KCL doesn't catch typos; only `akuapkg check` does. Type- safety lives in the build tool, not the language. Worse ergonomics than method-on-import for no architectural gain. @@ -90,7 +90,7 @@ loads + renders the upstream package. The map is keyed by the upstream's canonical `[package].name` (from its `akua.toml`) — which is what `__id` captures in the lambda. -`akua lint` enforces `__id == [package].name`. `akua check` enforces +`akuapkg lint` enforces `__id == [package].name`. `akuapkg check` enforces that every dep referenced via `import + .render(...)` is declared in `[dependencies]`. @@ -137,9 +137,9 @@ Staged across PRs to keep each reviewable: ### Stage 3: Author tooling -- `akua init` template adds the two-line API surface at the bottom of +- `akuapkg init` template adds the two-line API surface at the bottom of the new `package.k`. -- `akua lint` rule: +- `akuapkg lint` rule: - `__id` declared and equals `[package].name` - `render` lambda declared with the canonical signature @@ -153,7 +153,7 @@ Staged across PRs to keep each reviewable: ### Stage 5: Documentation - `docs/package-format.md` documents the two-line API surface. -- `docs/cli.md` updates the `akua init` template. +- `docs/cli.md` updates the `akuapkg init` template. - This spike doc moves to "implemented". ## Hookable extension point @@ -190,7 +190,7 @@ time, the hook is there. - **`pkg.renderById` exposed via `akua.pkg`**: the consumer's `package.k` doesn't need to know about it (the lambda lives in upstream). But the upstream needs `import akua.pkg` to call it. - Templated by `akua init`. + Templated by `akuapkg init`. - **Backwards compatibility**: pre-alpha; we're free to drop the old `pkg.render({path})` plugin in one breaking change. Changelog entry + migration note. diff --git a/docs/spikes/pkg-render-nested-sandbox.md b/docs/spikes/pkg-render-nested-sandbox.md index 169ed2ff..7b9c72a9 100644 --- a/docs/spikes/pkg-render-nested-sandbox.md +++ b/docs/spikes/pkg-render-nested-sandbox.md @@ -27,7 +27,7 @@ budget. ### Topology - The outer render runs inside `RenderHost::shared().invoke_with_deps` - (`crates/akua-cli/src/render_worker.rs`) which builds a fresh + (`crates/akuapkg-cli/src/render_worker.rs`) which builds a fresh `Store`, instantiates the AOT-compiled worker, and pipes a JSON request through WASI stdin. - KCL plugin calls bridge back to the host via diff --git a/docs/spikes/wasmtime-multi-engine.md b/docs/spikes/wasmtime-multi-engine.md index cec61822..76bcbd41 100644 --- a/docs/spikes/wasmtime-multi-engine.md +++ b/docs/spikes/wasmtime-multi-engine.md @@ -11,7 +11,7 @@ The alternative: one `Engine`, one `Linker`, many `Store`s — the render worker ## Method 1. Delegated a research pass against wasmtime's docs + source + test suite + GitHub discussions. -2. Wrote a verification test (`crates/akua-cli/tests/sandbox_nested_wasmtime.rs`) exercising helm `render_dir` through the plugin bridge end-to-end. +2. Wrote a verification test (`crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs`) exercising helm `render_dir` through the plugin bridge end-to-end. ## Findings @@ -51,8 +51,8 @@ Without changes, the research-flagged failure mode fired: - New `engine_host_wasm::shared_config()` + `shared_engine()` (OnceLock singleton). One Config: `wasm_exceptions` + `epoch_interruption` (no fuel — would force every engine Store to `set_fuel` before every call). - `engine_host_wasm::Session::init` uses `shared_engine()` instead of constructing a fresh Engine. -- `akua_cli::render_worker::RenderHost` holds `&'static Engine` borrow into `shared_engine()`. -- `akua-cli`'s `build.rs` routes through `shared_config()` so the AOT `.cwasm` matches the runtime Config hash automatically. +- `akuapkg_cli::render_worker::RenderHost` holds `&'static Engine` borrow into `shared_engine()`. +- `akuapkg-cli`'s `build.rs` routes through `shared_config()` so the AOT `.cwasm` matches the runtime Config hash automatically. - Every engine-plugin Store opts out of the epoch ticker via `set_epoch_deadline(u64::MAX)` — the host-Rust caller above them owns whole-call timeouts. End-to-end verification test (`helm_template_through_plugin_bridge_across_engines`): @@ -85,5 +85,5 @@ Today, sharing an Engine means all plugins trust the same Cranelift settings, th ## Artefacts - [crates/engine-host-wasm/src/lib.rs](../../crates/engine-host-wasm/src/lib.rs): `shared_config`, `shared_engine`, the `epoch_deadline = u64::MAX` fix. -- [crates/akua-cli/src/render_worker.rs](../../crates/akua-cli/src/render_worker.rs): `RenderHost` + plugin bridge. -- [crates/akua-cli/tests/sandbox_nested_wasmtime.rs](../../crates/akua-cli/tests/sandbox_nested_wasmtime.rs): the verification test. `#[ignore]` by default; run with `cargo test -p akua-cli --test sandbox_nested_wasmtime -- --include-ignored`. +- [crates/akuapkg-cli/src/render_worker.rs](../../crates/akuapkg-cli/src/render_worker.rs): `RenderHost` + plugin bridge. +- [crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs](../../crates/akuapkg-cli/tests/sandbox_nested_wasmtime.rs): the verification test. `#[ignore]` by default; run with `cargo test -p akuapkg-cli --test sandbox_nested_wasmtime -- --include-ignored`. diff --git a/docs/superpowers/plans/2026-05-29-https-helm-repo-deps.md b/docs/superpowers/plans/2026-05-29-https-helm-repo-deps.md index f55b14fe..d3985b05 100644 --- a/docs/superpowers/plans/2026-05-29-https-helm-repo-deps.md +++ b/docs/superpowers/plans/2026-05-29-https-helm-repo-deps.md @@ -22,7 +22,7 @@ | `crates/akua-core/src/chart_resolver.rs` | Per-source resolution → `ResolvedChart` + lockfile fields | Modify: `ResolvedSource::Helm`, `resolve_helm`, `VendorKind::Helm` | | `crates/akua-core/Cargo.toml` | deps + feature flag | Modify: add `semver`, `helm-fetch` feature | | `crates/akua-core/src/lib.rs` | module registration | Modify: `mod helm_repo_fetcher;` | -| `crates/akua-cli/src/verbs/add.rs` | `akua add` helm form | Modify (Task 8) | +| `crates/akuapkg-cli/src/verbs/add.rs` | `akuapkg add` helm form | Modify (Task 8) | | `crates/akua-napi/src/lib.rs`, `packages/sdk/src/mod.ts` | SDK surface | Modify (Task 8) | | `docs/lockfile-format.md`, `docs/package-format.md`, `docs/cli.md` | docs | Modify (Task 9) | @@ -396,7 +396,7 @@ pub enum HelmRepoFetchError { Http { url: String, detail: String }, #[error("digest mismatch for `{chart}`: expected {expected}, got {actual}")] DigestMismatch { chart: String, expected: String, actual: String }, - #[error("offline and `{chart}` is not in the cache — run `akua add` online first")] + #[error("offline and `{chart}` is not in the cache — run `akuapkg add` online first")] OfflineCacheMiss { chart: String }, #[error("io error at {path}: {source}")] Io { path: std::path::PathBuf, #[source] source: std::io::Error }, @@ -964,13 +964,13 @@ fn resolve_helm( let digest = expected.ok_or_else(|| ChartResolveError::UnsupportedSource { name: name.to_string(), kind: DependencySource::Helm, - reason: "offline mode needs a lockfile-pinned digest — run `akua add` first", + reason: "offline mode needs a lockfile-pinned digest — run `akuapkg add` first", })?; crate::helm_repo_fetcher::fetch_from_cache(&cache_root, digest).ok_or_else(|| { ChartResolveError::UnsupportedSource { name: name.to_string(), kind: DependencySource::Helm, - reason: "offline and chart not cached — run `akua add` online first", + reason: "offline and chart not cached — run `akuapkg add` online first", } })? } else { @@ -1087,16 +1087,16 @@ git commit -m "test(lockfile): helm-repo source round-trip" --- -## Task 10: CLI `akua add` + SDK surface +## Task 10: CLI `akuapkg add` + SDK surface **Files:** -- Modify: `crates/akua-cli/src/verbs/add.rs` -- Modify: `crates/akua-cli/src/main.rs` (clap flags) +- Modify: `crates/akuapkg-cli/src/verbs/add.rs` +- Modify: `crates/akuapkg-cli/src/main.rs` (clap flags) - Modify: `crates/akua-napi/src/lib.rs`, `packages/sdk/src/mod.ts` - [ ] **Step 1: Inspect the existing `add` flag wiring** -Read `crates/akua-cli/src/verbs/add.rs` and the `Add` clap struct in `main.rs`. Note how `--oci`/`--git`/`--path`/`--version`/`--tag`/`--rev` map onto a `Dependency`. +Read `crates/akuapkg-cli/src/verbs/add.rs` and the `Add` clap struct in `main.rs`. Note how `--oci`/`--git`/`--path`/`--version`/`--tag`/`--rev` map onto a `Dependency`. - [ ] **Step 2: Write the failing CLI test** @@ -1113,16 +1113,16 @@ Fill the body by copying the OCI add test and swapping the asserted fields to `r - [ ] **Step 3: Run, verify fails** -Run: `cargo test -p akua-cli adds_helm_repo_dep` +Run: `cargo test -p akuapkg-cli adds_helm_repo_dep` Expected: FAIL/compile error — no `--repo`/`--chart` flags. - [ ] **Step 4: Add `--repo` + `--chart` clap flags and map them** -Add `repo: Option` and `chart: Option` to the `Add` args struct; in `add::run`, when `repo` is set, build a `Dependency { repo, chart, version, ..Default }` and run `akua lock` resolution to pin the digest (reuse the existing post-add lock path the OCI form uses). +Add `repo: Option` and `chart: Option` to the `Add` args struct; in `add::run`, when `repo` is set, build a `Dependency { repo, chart, version, ..Default }` and run `akuapkg lock` resolution to pin the digest (reuse the existing post-add lock path the OCI form uses). - [ ] **Step 5: Run, verify pass** -Run: `cargo test -p akua-cli adds_helm_repo_dep` +Run: `cargo test -p akuapkg-cli adds_helm_repo_dep` Expected: PASS. - [ ] **Step 6: Mirror in napi + SDK** @@ -1132,8 +1132,8 @@ Add `repo?`/`chart?` to the napi `add` shim and `Akua.add()` options in `package - [ ] **Step 7: Commit** ```bash -git add crates/akua-cli crates/akua-napi packages/sdk -git commit -m "feat(add): akua add --repo --chart helm-repo form + SDK" +git add crates/akuapkg-cli crates/akua-napi packages/sdk +git commit -m "feat(add): akuapkg add --repo --chart helm-repo form + SDK" ``` --- @@ -1141,8 +1141,8 @@ git commit -m "feat(add): akua add --repo --chart helm-repo form + SDK" ## Task 11: Integration golden + end-to-end render **Files:** -- Create: `crates/akua-cli/tests/fixtures/helm-repo/` (a fixture repo: `index.yaml` + a small `.tgz`) -- Create: `crates/akua-cli/tests/examples_helm_repo.rs` +- Create: `crates/akuapkg-cli/tests/fixtures/helm-repo/` (a fixture repo: `index.yaml` + a small `.tgz`) +- Create: `crates/akuapkg-cli/tests/examples_helm_repo.rs` - [ ] **Step 1: Build a fixture helm repo** @@ -1154,17 +1154,17 @@ A Package with `[dependencies.demo] repo/chart/version`, an `akua.lock` pinning - [ ] **Step 3: Run** -Run: `cargo test -p akua-cli --features helm-fetch,oci-fetch examples_helm_repo` +Run: `cargo test -p akuapkg-cli --features helm-fetch,oci-fetch examples_helm_repo` Expected: PASS, deterministic. - [ ] **Step 4: Real-world smoke (manual, documented in the test file as a comment)** -Build the binary (`task build:render-worker && task release:local`), point a throwaway Package at temporal's real repo (`repo = "https://go.temporal.io/helm-charts"`, `chart = "temporal"`, `version = ">=0.60,<0.63"`), `akua add` then `akua render`, confirm 55 manifests and a populated `akua.lock`. Delete the throwaway. (Not a CI test — network-dependent.) +Build the binary (`task build:render-worker && task release:local`), point a throwaway Package at temporal's real repo (`repo = "https://go.temporal.io/helm-charts"`, `chart = "temporal"`, `version = ">=0.60,<0.63"`), `akuapkg add` then `akuapkg render`, confirm 55 manifests and a populated `akua.lock`. Delete the throwaway. (Not a CI test — network-dependent.) - [ ] **Step 5: Commit** ```bash -git add crates/akua-cli/tests +git add crates/akuapkg-cli/tests git commit -m "test(helm-repo): integration golden for repo-sourced chart render" ``` @@ -1177,7 +1177,7 @@ git commit -m "test(helm-repo): integration golden for repo-sourced chart render - [ ] **Step 1: Document the `repo`/`chart` source** -In `docs/package-format.md` and `docs/cli.md`, add `repo` + `chart` to the dependency-source table with the temporal example. In `docs/lockfile-format.md`, document the `helm+#` source ref + `sha256:` digest. Add an `akua add --repo` example to the `add` section. +In `docs/package-format.md` and `docs/cli.md`, add `repo` + `chart` to the dependency-source table with the temporal example. In `docs/lockfile-format.md`, document the `helm+#` source ref + `sha256:` digest. Add an `akuapkg add --repo` example to the `add` section. - [ ] **Step 2: CHANGELOG entry** @@ -1215,7 +1215,7 @@ git commit -m "docs(helm-repo): document repo/chart dependency source" - Semver ranges → Task 5. ✓ - Docs → Task 12. ✓ -**Placeholder scan:** Tasks 10–11 leave two test bodies described rather than fully written (the `akua add` test and the integration fixture) because they must mirror existing CLI test scaffolding whose exact helpers aren't quoted here; each step names the existing test to copy and the exact fields to assert. All `akua-core` code steps contain complete code. +**Placeholder scan:** Tasks 10–11 leave two test bodies described rather than fully written (the `akuapkg add` test and the integration fixture) because they must mirror existing CLI test scaffolding whose exact helpers aren't quoted here; each step names the existing test to copy and the exact fields to assert. All `akua-core` code steps contain complete code. **Type consistency:** `Fetched{root_dir,digest,version}`, `FetchOpts{expected_digest,auth}`, `HelmRepoFetchError`, `ResolvedSource::Helm{repo,chart,version,digest}`, `DependencySpec::Helm{repo,chart,version}`, and `select_version → (String,String)` are used consistently across Tasks 4–9. Accessor/field names that must be confirmed against existing code are flagged inline (`BasicAuth` fields, `resolve_path` signature, `ResolverOptions.host_auth`, `ResolvedChart` accessor). diff --git a/docs/superpowers/specs/2026-05-29-https-helm-repo-deps-design.md b/docs/superpowers/specs/2026-05-29-https-helm-repo-deps-design.md index a59ccb0d..576ca789 100644 --- a/docs/superpowers/specs/2026-05-29-https-helm-repo-deps-design.md +++ b/docs/superpowers/specs/2026-05-29-https-helm-repo-deps-design.md @@ -49,7 +49,7 @@ invariant governs akua's **own `publish` output**, not third-party upstreams. HTTPS helm-repo charts adopt the identical pattern: -- `akua add` / `akua lock` resolve the version, download the `.tgz`, compute +- `akuapkg add` / `akuapkg lock` resolve the version, download the `.tgz`, compute its tree SHA256, and write `digest = "sha256:"` into `akua.lock`. - Every subsequent fetch verifies the downloaded tarball's tree hash against the pinned digest; a mismatch fails the resolve hard (same as OCI's @@ -100,11 +100,11 @@ A new `helm_repo_fetcher` module (modeled on `git_fetcher`): ## Determinism -- `index.yaml` is consulted **only** at `akua add` / `akua lock`. It writes the +- `index.yaml` is consulted **only** at `akuapkg add` / `akuapkg lock`. It writes the resolved exact version and the `.tgz` digest into `akua.lock`. -- `akua render` resolves from the pinned digest + cache; it never reads +- `akuapkg render` resolves from the pinned digest + cache; it never reads `index.yaml` and never hits the network. Same inputs + same lockfile + same - akua version → byte-identical output, satisfying the determinism invariant. + akuapkg version → byte-identical output, satisfying the determinism invariant. ## Data-model changes @@ -150,8 +150,8 @@ Re-pull verifies `digest`. `replace` provenance recorded as for oci/git. ## CLI / SDK surface (one contract) -- `akua add` gains a helm-repo form: - `akua add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version ">=0.60,<0.63"`. +- `akuapkg add` gains a helm-repo form: + `akuapkg add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version ">=0.60,<0.63"`. Resolves the range, writes `akua.toml` + `akua.lock`. - The napi shim + `packages/sdk` `Akua.add()` route the new fields through. - `docs/lockfile-format.md`, `docs/package-format.md`, and the dependency-source @@ -162,7 +162,7 @@ Re-pull verifies `digest`. `replace` provenance recorded as for oci/git. - `repo` URLs with embedded `user:pass@` rejected at parse (as for git). - Tarball extraction goes through the existing path-escape guard; a malicious `.tgz` with `../` members cannot escape the cache dir. -- `akua publish` strips `replace` for helm deps too (existing behavior is +- `akuapkg publish` strips `replace` for helm deps too (existing behavior is source-agnostic). - Credentials only ever come from the `host_auth` map; akua never reads `~/.netrc`, `helm`'s `repositories.yaml`, or ambient credential stores. diff --git a/docs/use-cases.md b/docs/use-cases.md index bf112337..2b5dba89 100644 --- a/docs/use-cases.md +++ b/docs/use-cases.md @@ -26,13 +26,13 @@ In a managed-SaaS model, operator and customer collapse into "the tenant," and t Package.k ───┐ (imports engines, │ - declares schema, │ akua check (syntax + types) - wires outputs) │ akua lint (Regal + kcl lint) - ├──▶ akua test (*_test.rego + test_*.k) - sources/ │ akua render --plan (dry run with sample inputs) - (helm / kcl / │ akua fmt --check + declares schema, │ akuapkg check (syntax + types) + wires outputs) │ akuapkg lint (Regal + kcl lint) + ├──▶ akuapkg test (*_test.rego + test_*.k) + sources/ │ akuapkg render --plan (dry run with sample inputs) + (helm / kcl / │ akuapkg fmt --check kustomize / ...) │ - │ akua publish ──────────────▶ signed + attested + │ akuapkg publish ──────────────▶ signed + attested akua.toml / .sum ─┘ (cosign + SLSA v1) OCI artifact ``` @@ -53,7 +53,7 @@ One OCI digest, many deploys, per-tenant values resolved at deploy-time. (releaseName + inputs differ) ``` -Consumers: ArgoCD Helm source, Flux `HelmRelease`, `helm install`. `akua render` executes on commit to produce per-tenant rendered manifests, committed to the deploy path (compiled GitOps); or the reconciler does the templating itself against the shared chart. +Consumers: ArgoCD Helm source, Flux `HelmRelease`, `helm install`. `akuapkg render` executes on commit to produce per-tenant rendered manifests, committed to the deploy path (compiled GitOps); or the reconciler does the templating itself against the shared chart. When Model A works: - ✅ Late-bindable engines (Helm templates, RGD with deploy-time CEL). @@ -66,10 +66,10 @@ When Model A breaks down: ### Model B — per-install chart, values baked in (escape hatch) -One OCI digest per install. `akua render` runs the full pipeline with that tenant's inputs and pushes a sealed artifact. +One OCI digest per install. `akuapkg render` runs the full pipeline with that tenant's inputs and pushes a sealed artifact. ``` - Package + tenant inputs ──▶ akua render + publish ──▶ tenant-specific OCI digest + Package + tenant inputs ──▶ akuapkg render + publish ──▶ tenant-specific OCI digest (chart@sha256:xxx) ``` @@ -137,9 +137,9 @@ Same Package, same `akua` binary, no install UI. ``` Developer: - akua dev # sub-second hot-reload against local cluster - akua render --inputs my.yaml # produce raw manifests - akua publish --to oci://myregistry/mychart (optional) + akuapkg dev # sub-second hot-reload against local cluster + akuapkg render --inputs my.yaml # produce raw manifests + akuapkg publish --to oci://myregistry/mychart (optional) Developer or ops: helm install mychart oci://myregistry/mychart --values my-inputs.yaml @@ -148,7 +148,7 @@ Or via reconciler: kubectl apply -f argocd-application.yaml ``` -`akua` is a build tool here. No hosting platform, no install UI. The output is raw manifests any OCI-aware consumer works with; future `akua publish --as helm-chart` / `--as oci-bundle` will wrap the render into other distribution shapes at publish time. +`akua` is a build tool here. No hosting platform, no install UI. The output is raw manifests any OCI-aware consumer works with; future `akuapkg publish --as helm-chart` / `--as oci-bundle` will wrap the render into other distribution shapes at publish time. --- diff --git a/examples/00-helm-hello/README.md b/examples/00-helm-hello/README.md index 7c45d45f..19cbf39e 100644 --- a/examples/00-helm-hello/README.md +++ b/examples/00-helm-hello/README.md @@ -15,7 +15,7 @@ callable end-to-end. |---|---| | `package.k` | KCL Package; imports `akua.helm`, calls `helm.template`, wires the result into `resources = …`. | | `akua.toml` | Manifest — no external deps. | -| `inputs.example.yaml` | Auto-discovered by `akua render` when `--inputs` is omitted. | +| `inputs.example.yaml` | Auto-discovered by `akuapkg render` when `--inputs` is omitted. | | `chart/` | A tiny in-tree Helm chart (one `ConfigMap` template). | ## Render @@ -23,14 +23,14 @@ callable end-to-end. `package.k` passes `"./chart"` to `helm.template`; akua resolves that against the Package.k's directory (via the path-traversal-guarded `resolve_in_package`) and hands the chart tarball to the embedded -WASM Helm engine. `akua render` works from any cwd — point +WASM Helm engine. `akuapkg render` works from any cwd — point `--package` at this directory: ```sh # Build the embedded helm engine once per machine: task build:helm-engine-wasm -akua render --package examples/00-helm-hello/package.k --out ./rendered +akuapkg render --package examples/00-helm-hello/package.k --out ./rendered ``` The rendered `ConfigMap` lands at `./rendered/000-configmap-hello-greeting.yaml` @@ -55,4 +55,4 @@ shell-out, ever." ## Spec See [`docs/package-format.md §5`](../../docs/package-format.md#5-outputs--what-akua-emits) -for the `outputs` shape and [`docs/cli.md` `akua render`](../../docs/cli.md#akua-render). +for the `outputs` shape and [`docs/cli.md` `akuapkg render`](../../docs/cli.md#akua-render). diff --git a/examples/00-helm-hello/package.k b/examples/00-helm-hello/package.k index 79793447..7cba92f5 100644 --- a/examples/00-helm-hello/package.k +++ b/examples/00-helm-hello/package.k @@ -7,11 +7,11 @@ # # Render: # -# akua render --out ./rendered +# akuapkg render --out ./rendered # # `./chart` is a raw-string path resolved under the Package dir — the # original simplest-possible shape. Example 01 shows the typed -# `import charts.` form that Phase 2a landed; `akua render +# `import charts.` form that Phase 2a landed; `akuapkg render # --strict` only accepts that form. # # Inputs flow through KCL's `option()` mechanism; `inputs.example.yaml` diff --git a/examples/01-hello-webapp/README.md b/examples/01-hello-webapp/README.md index 84d67c4e..a71545ea 100644 --- a/examples/01-hello-webapp/README.md +++ b/examples/01-hello-webapp/README.md @@ -39,8 +39,8 @@ this one. ## Run ```sh -akua add # resolve deps → writes akua.lock -akua render --inputs inputs.yaml # render to ./deploy/ +akuapkg add # resolve deps → writes akua.lock +akuapkg render --inputs inputs.yaml # render to ./deploy/ ls deploy/ # 000-deployment-hello.yaml, 001-service-hello.yaml ``` @@ -48,7 +48,7 @@ Under `--strict`, akua rejects raw-string chart paths — every chart must be declared in `akua.toml` and imported as `charts.`: ```sh -akua render --strict --inputs inputs.yaml +akuapkg render --strict --inputs inputs.yaml ``` ## Vendored chart vs OCI pull @@ -63,7 +63,7 @@ nginx = { oci = "oci://registry-1.docker.io/bitnamicharts/nginx", version = "18. ``` akua pulls the chart into `$XDG_CACHE_HOME/akua/oci/` on first -`akua add` / `akua render`, verifying the blob digest against +`akuapkg add` / `akuapkg render`, verifying the blob digest against `akua.lock` on subsequent renders. See Phase 2b in `docs/roadmap.md`. ## Local fork override diff --git a/examples/01-hello-webapp/akua.lock b/examples/01-hello-webapp/akua.lock index 79b356bf..bff28a59 100644 --- a/examples/01-hello-webapp/akua.lock +++ b/examples/01-hello-webapp/akua.lock @@ -1,5 +1,5 @@ # akua.lock — machine-maintained. Never hand-edit. -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. version = 1 diff --git a/examples/01-hello-webapp/package.k b/examples/01-hello-webapp/package.k index fef4eb32..bca7cd3d 100644 --- a/examples/01-hello-webapp/package.k +++ b/examples/01-hello-webapp/package.k @@ -4,7 +4,7 @@ # inputs, raw-manifest output. # # Render: -# akua render --inputs inputs.yaml # render to ./rendered by default +# akuapkg render --inputs inputs.yaml # render to ./rendered by default import akua.ctx import charts.nginx as nginx # Phase 2a: resolved from akua.toml diff --git a/examples/02-webapp-postgres/README.md b/examples/02-webapp-postgres/README.md index 83dfd379..1a32c87d 100644 --- a/examples/02-webapp-postgres/README.md +++ b/examples/02-webapp-postgres/README.md @@ -24,9 +24,9 @@ Two Helm charts composed into one Package. A webapp consumes a Postgres connecti ## Run ```sh -akua add # resolve cnpg + webapp charts -akua render --inputs inputs.yaml # render both into ./rendered/ -akua test # run test_package.k +akuapkg add # resolve cnpg + webapp charts +akuapkg render --inputs inputs.yaml # render both into ./rendered/ +akuapkg test # run test_package.k ``` ## The cross-source convention pattern diff --git a/examples/02-webapp-postgres/package.k b/examples/02-webapp-postgres/package.k index 06ea830d..d4830226 100644 --- a/examples/02-webapp-postgres/package.k +++ b/examples/02-webapp-postgres/package.k @@ -11,7 +11,7 @@ # - optional postRenderer for cross-cutting mutation (team label) # # Render: -# akua render --inputs inputs.yaml --out ./rendered +# akuapkg render --inputs inputs.yaml --out ./rendered import akua.ctx import charts.cnpg as cnpg diff --git a/examples/02-webapp-postgres/test_package.k b/examples/02-webapp-postgres/test_package.k index ddc28057..e6203c53 100644 --- a/examples/02-webapp-postgres/test_package.k +++ b/examples/02-webapp-postgres/test_package.k @@ -1,6 +1,6 @@ # test_package.k — unit tests for the 02-webapp-postgres Package. # -# Run with: akua test +# Run with: akuapkg test # # File naming per cli.md: `test_*.k`. Top-level assertions run; failures # surface with line + field context. diff --git a/examples/03-multi-env-app/README.md b/examples/03-multi-env-app/README.md index 3fedbbe8..b40f87ac 100644 --- a/examples/03-multi-env-app/README.md +++ b/examples/03-multi-env-app/README.md @@ -54,20 +54,20 @@ Same output. Pure KCL. No special akua flags, no akua-owned schema to obey. ## Render ```sh -akua add # resolve deps → writes akua.lock -akua render # renders every App document it finds -akua render --filter=env=production # narrow to one env using a general filter +akuapkg add # resolve deps → writes akua.lock +akuapkg render # renders every App document it finds +akuapkg render --filter=env=production # narrow to one env using a general filter ``` -There is no `--env` or `--all-envs` flag. `akua render` processes every document of a KCL-declared shape in the workspace. Filtering is a general-purpose concern expressed via `--filter` over any field, not an env-specific primitive. +There is no `--env` or `--all-envs` flag. `akuapkg render` processes every document of a KCL-declared shape in the workspace. Filtering is a general-purpose concern expressed via `--filter` over any field, not an env-specific primitive. ## Deriving YAML views Reconcilers consume YAML. The `.k` files are authoritative; the YAML view is derived on demand: ```sh -akua export apps/checkout/production.k --format=yaml > apps/checkout/production.yaml -akua export environments/production.k --format=yaml > environments/production.yaml +akuapkg export apps/checkout/production.k --format=yaml > apps/checkout/production.yaml +akuapkg export environments/production.k --format=yaml > environments/production.yaml ``` Check these YAML files in or don't — they regenerate deterministically. The **rule**: never hand-edit the YAML — edit the `.k` and re-export. @@ -75,7 +75,7 @@ Check these YAML files in or don't — they regenerate deterministically. The ** ## Flow for a change 1. Edit `apps/checkout/production.k` (e.g. bump `replicas` from 5 to 7). -2. CI runs `akua check && akua lint && akua test && akua render`. +2. CI runs `akuapkg check && akuapkg lint && akuapkg test && akuapkg render`. 3. `akua policy check --tier=tier/production` against the rendered manifests — returns `allow` / `deny` / `needs-approval`. 4. If `needs-approval`: the review surface notifies approvers; human approves. 5. PR merges; deploy repo gets updated YAML; Argo/Flux reconciles. diff --git a/examples/04-policy-tier/README.md b/examples/04-policy-tier/README.md index e3464a44..d5cf5805 100644 --- a/examples/04-policy-tier/README.md +++ b/examples/04-policy-tier/README.md @@ -36,7 +36,7 @@ tier-prod = { oci = "oci://policies.akua.dev/tier/production", version = "1.2.0" kyv-sec = { oci = "oci://policies.akua.dev/kyverno/security", version = "2.0.0" } ``` -Both deps are signed OCI artifacts. The first is akua's reference `tier/production` Rego bundle; the second is a Kyverno bundle that akua converts to Rego at `akua add` time (stored under `.akua/policies/vendor/`). The `akua.lock` ledger records the resolved digest and cosign signature for each. +Both deps are signed OCI artifacts. The first is akua's reference `tier/production` Rego bundle; the second is a Kyverno bundle that akua converts to Rego at `akuapkg add` time (stored under `.akua/policies/vendor/`). The `akua.lock` ledger records the resolved digest and cosign signature for each. No runtime lookups. Every import resolves at build time. @@ -52,7 +52,7 @@ There is no `PolicySet` resource to declare. `akua policy check --tier=./policie ```sh # 1. Resolve deps + write akua.lock -akua add +akuapkg add # 2. Evaluate the tier against a passing fixture → verdict: allow akua policy check --tier=./policies --input=fixtures/good.yaml @@ -61,7 +61,7 @@ akua policy check --tier=./policies --input=fixtures/good.yaml akua policy check --tier=./policies --input=fixtures/bad.yaml # 4. Run the test file -akua test policies/ +akuapkg test policies/ ``` Exit codes from `akua policy check`: diff --git a/examples/04-policy-tier/akua.lock b/examples/04-policy-tier/akua.lock index 3ca9d6e9..d86c9d51 100644 --- a/examples/04-policy-tier/akua.lock +++ b/examples/04-policy-tier/akua.lock @@ -1,6 +1,6 @@ # akua.lock — machine-maintained. Never hand-edit. # -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. # A change here without a corresponding change to akua.toml is a flag for CI # review — someone's "what you got" diverged from "what you asked for." diff --git a/examples/04-policy-tier/akua.toml b/examples/04-policy-tier/akua.toml index cee817d2..e6c94eca 100644 --- a/examples/04-policy-tier/akua.toml +++ b/examples/04-policy-tier/akua.toml @@ -10,7 +10,7 @@ edition = "akua.dev/v1alpha1" # akua's reference production tier (signed OCI artifact). tier-prod = { oci = "oci://policies.akua.dev/tier/production", version = "1.2.0" } -# A Kyverno bundle. akua's Kyverno→Rego converter runs at `akua add` time; +# A Kyverno bundle. akua's Kyverno→Rego converter runs at `akuapkg add` time; # the compiled Rego lands under .akua/policies/vendor/ and imports into # our local policies as `data.akua.policies.kyverno.security`. kyv-sec = { oci = "oci://policies.akua.dev/kyverno/security", version = "2.0.0" } diff --git a/examples/04-policy-tier/policies/production_test.rego b/examples/04-policy-tier/policies/production_test.rego index c4ff29b6..78512137 100644 --- a/examples/04-policy-tier/policies/production_test.rego +++ b/examples/04-policy-tier/policies/production_test.rego @@ -1,6 +1,6 @@ # production_test.rego — tests for the local rules in production.rego. # -# Run with: akua test policies/ +# Run with: akuapkg test policies/ # # File naming convention per cli.md: `*_test.rego`. Rules named `test_*` are # discovered and executed by the embedded OPA test runner. diff --git a/examples/05-tests-and-golden/README.md b/examples/05-tests-and-golden/README.md index 42bf1656..381e413a 100644 --- a/examples/05-tests-and-golden/README.md +++ b/examples/05-tests-and-golden/README.md @@ -4,14 +4,14 @@ Shows where tests live and what each kind looks like: - **`test_*.k`** — KCL unit tests. Exercise the Package's `Input` schema, defaults, and `check:` blocks. - **`*_test.rego`** — Rego policy tests. Feed fixtures to the policy package and assert verdicts. -- **`testdata/golden//`** — golden render output. `akua test --golden` renders the Package against each input under `testdata/inputs/` and diffs the result against the expected bytes. A drift is a test failure. +- **`testdata/golden//`** — golden render output. `akuapkg test --golden` renders the Package against each input under `testdata/inputs/` and diffs the result against the expected bytes. A drift is a test failure. All three kinds run under one verb: ```sh -akua test # runs *_test.rego, test_*.k, golden fixtures -akua test --golden # golden-only -akua test --update-golden # overwrite golden with current render (use carefully) +akuapkg test # runs *_test.rego, test_*.k, golden fixtures +akuapkg test --golden # golden-only +akuapkg test --update-golden # overwrite golden with current render (use carefully) ``` ## Layout @@ -82,9 +82,9 @@ test_denies_missing_label { ## Golden tests -For each fixture under `testdata/inputs/`, `akua test --golden`: +For each fixture under `testdata/inputs/`, `akuapkg test --golden`: -1. Runs `akua render --inputs=testdata/inputs/.yaml`. +1. Runs `akuapkg render --inputs=testdata/inputs/.yaml`. 2. Writes a temporary output. 3. Diffs against `testdata/golden//` byte-for-byte. 4. Fails the test on any drift, printing the diff. @@ -92,9 +92,9 @@ For each fixture under `testdata/inputs/`, `akua test --golden`: Updates go through the human: ```sh -akua render --inputs=testdata/inputs/minimal.yaml --out=/tmp/render +akuapkg render --inputs=testdata/inputs/minimal.yaml --out=/tmp/render diff -r /tmp/render testdata/golden/minimal/ # eyeball the drift -akua test --update-golden # commit the new expectation +akuapkg test --update-golden # commit the new expectation ``` Golden tests are the cheapest way to catch "I accidentally changed the output shape in a refactor" regressions. They're also the cheapest way to generate false positives when engine versions bump — the diff is the signal, not the test's opinion. @@ -104,7 +104,7 @@ Golden tests are the cheapest way to catch "I accidentally changed the output sh - Writing a Package for the first time → `test_*.k` for schema + defaults. - Landing non-trivial rendering logic → add a golden fixture. - Authoring a policy → always write `*_test.rego` alongside. -- Bumping an engine version (e.g. Helm v4 → v4.1) → run `akua test --golden` first; expect some drift, review it, update if sound. +- Bumping an engine version (e.g. Helm v4 → v4.1) → run `akuapkg test --golden` first; expect some drift, review it, update if sound. ## See also diff --git a/examples/05-tests-and-golden/test_package.k b/examples/05-tests-and-golden/test_package.k index 0353d7ef..2bc5f3e1 100644 --- a/examples/05-tests-and-golden/test_package.k +++ b/examples/05-tests-and-golden/test_package.k @@ -26,6 +26,6 @@ assert _full.tls == False, "tls override should take effect" # check: block enforces the invariant (we can't construct Input {replicas=0}). # The failing construction is commented out to keep the test file itself -# compilable; akua test runs a companion negative-test runner for check: +# compilable; akuapkg test runs a companion negative-test runner for check: # violations. # _invalid = pkg.Input { appName = "a", hostname = "h", replicas = 0 } diff --git a/examples/06-multi-engine/README.md b/examples/06-multi-engine/README.md index 082f8a68..f0d42796 100644 --- a/examples/06-multi-engine/README.md +++ b/examples/06-multi-engine/README.md @@ -62,8 +62,8 @@ controller sees the RGD and reconciles its instances. ## Render ```sh -akua add # resolve deps -akua render --inputs inputs.yaml --out ./deploy +akuapkg add # resolve deps +akuapkg render --inputs inputs.yaml --out ./deploy ``` Result: diff --git a/examples/06-multi-engine/package.k b/examples/06-multi-engine/package.k index dd1147b5..5c21fec2 100644 --- a/examples/06-multi-engine/package.k +++ b/examples/06-multi-engine/package.k @@ -7,8 +7,8 @@ # - Inline KCL (NetworkPolicy authored directly in KCL) # # Render: -# akua add -# akua render --inputs inputs.yaml --out ./deploy +# akuapkg add +# akuapkg render --inputs inputs.yaml --out ./deploy import akua.ctx import akua.kustomize diff --git a/examples/07-package-reuse/README.md b/examples/07-package-reuse/README.md index 84d2c558..05aeab36 100644 --- a/examples/07-package-reuse/README.md +++ b/examples/07-package-reuse/README.md @@ -77,15 +77,15 @@ resources = [*_base, _dashboard] Three things fall out of this shape: 1. **Type safety.** The base's `Input` is a nested schema; misspelling a field fails at compile time with a line + column pointer. No "I forgot the base needs `hostname`" at render time. -2. **Pinned by digest.** `akua.toml` + `akua.lock` pin the base to a specific OCI digest. Base publishes v1.1 → you don't pick it up until you `akua add` explicitly. No silent drift. -3. **Signed provenance.** `akua verify` on the consumer walks the attestation chain: the consumer's SLSA predicate includes the base's digest, which carries its own SLSA predicate, which carries the base's sources. Auditable back to the original chart authors. +2. **Pinned by digest.** `akua.toml` + `akua.lock` pin the base to a specific OCI digest. Base publishes v1.1 → you don't pick it up until you `akuapkg add` explicitly. No silent drift. +3. **Signed provenance.** `akuapkg verify` on the consumer walks the attestation chain: the consumer's SLSA predicate includes the base's digest, which carries its own SLSA predicate, which carries the base's sources. Auditable back to the original chart authors. ## Running it ```sh -akua add # resolves deps → writes akua.lock -akua render --inputs inputs.yaml # composes base + local additions -akua inspect oci://pkg.acme.corp/platform-base:1.0 # peek at what we're pinning +akuapkg add # resolves deps → writes akua.lock +akuapkg render --inputs inputs.yaml # composes base + local additions +akuapkg inspect oci://pkg.acme.corp/platform-base:1.0 # peek at what we're pinning ``` ## When to reuse vs fork diff --git a/examples/07-package-reuse/akua.lock b/examples/07-package-reuse/akua.lock index 7d039a87..37367ad8 100644 --- a/examples/07-package-reuse/akua.lock +++ b/examples/07-package-reuse/akua.lock @@ -8,6 +8,6 @@ version = "1.0.0" source = "oci://pkg.acme.corp/platform-base" digest = "sha256:c7e4b8a1f3d5e6a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2" signature = "cosign:key:platform-team-acme" -# The base Package's own SLSA predicate is referenced so `akua verify` can +# The base Package's own SLSA predicate is referenced so `akuapkg verify` can # walk the full provenance chain. attestation = "sha256:e9d2c7f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5d7" diff --git a/examples/07-package-reuse/package.k b/examples/07-package-reuse/package.k index 21a04671..80d62a94 100644 --- a/examples/07-package-reuse/package.k +++ b/examples/07-package-reuse/package.k @@ -5,8 +5,8 @@ # preserving end-to-end type safety. # # Render: -# akua add -# akua render --inputs inputs.yaml +# akuapkg add +# akuapkg render --inputs inputs.yaml import akua.ctx import akua.pkg # package-as-source engine callable @@ -92,14 +92,14 @@ _extra_ingresses = [ # owner references, not list position. resources = [*_base, _dashboard, *_extra_ingresses] -# Metadata for `akua inspect` and audit surfaces. +# Metadata for `akuapkg inspect` and audit surfaces. metadata = { name: "checkout-with-dashboard" version: "0.1.0" description: "platform-base + experimental dashboard + multi-host routing" publisher: "github.com/acme/checkout" - # The walk that `akua verify` follows: this Package's attestation + # The walk that `akuapkg verify` follows: this Package's attestation # references the base's attestation, which references its source charts. extends: ["oci://pkg.acme.corp/platform-base@sha256:c7e4b8a1..."] } diff --git a/examples/08-pkg-compose/README.md b/examples/08-pkg-compose/README.md index 051de20e..6d318dbd 100644 --- a/examples/08-pkg-compose/README.md +++ b/examples/08-pkg-compose/README.md @@ -12,18 +12,18 @@ the results. Renders end-to-end today (pure KCL; no helm needed). | `shared/package.k` | Inner Package; emits one ConfigMap parameterized by `name` + `payload`. | | `shared/akua.toml` | Inner manifest — marks `shared/` as an Akua package. | | `akua.toml` | Outer manifest — declares `shared` as a workspace-local path dep. | -| `inputs.example.yaml` | Per-component inputs, auto-discovered by `akua render`. | +| `inputs.example.yaml` | Per-component inputs, auto-discovered by `akuapkg render`. | ## Render ```sh -cargo run -q -p akua-cli -- render --package examples/08-pkg-compose/package.k --out ./rendered +cargo run -q -p akuapkg-cli -- render --package examples/08-pkg-compose/package.k --out ./rendered ``` Or, from the example directory: ```sh -akua render --out ./rendered +akuapkg render --out ./rendered ``` Two ConfigMaps land in `./rendered/` (checked in as reference output): diff --git a/examples/08-pkg-compose/package.k b/examples/08-pkg-compose/package.k index eb2e419a..e3b22357 100644 --- a/examples/08-pkg-compose/package.k +++ b/examples/08-pkg-compose/package.k @@ -5,7 +5,7 @@ # # Render: # -# akua render --package examples/08-pkg-compose/package.k --out ./rendered +# akuapkg render --package examples/08-pkg-compose/package.k --out ./rendered # # Produces two ConfigMaps: `config-frontend` and `config-backend`, # each with its own data payload from the outer's inputs. diff --git a/examples/09-kustomize-hello/README.md b/examples/09-kustomize-hello/README.md index 66d7b044..a06cf511 100644 --- a/examples/09-kustomize-hello/README.md +++ b/examples/09-kustomize-hello/README.md @@ -23,7 +23,7 @@ callable end-to-end. ```sh task build:kustomize-engine-wasm # once per machine -akua render --package examples/09-kustomize-hello/package.k --out ./rendered +akuapkg render --package examples/09-kustomize-hello/package.k --out ./rendered ``` The rendered `ConfigMap` lands at @@ -34,4 +34,4 @@ example so you can eyeball the output without running anything. ## Spec See [`docs/package-format.md`](../../docs/package-format.md) for the -Package shape and [`docs/cli.md` `akua render`](../../docs/cli.md#akua-render). +Package shape and [`docs/cli.md` `akuapkg render`](../../docs/cli.md#akua-render). diff --git a/examples/09-kustomize-hello/package.k b/examples/09-kustomize-hello/package.k index e1272aed..4a9160cd 100644 --- a/examples/09-kustomize-hello/package.k +++ b/examples/09-kustomize-hello/package.k @@ -7,7 +7,7 @@ # # Render: # -# akua render --package examples/09-kustomize-hello/package.k --out ./rendered +# akuapkg render --package examples/09-kustomize-hello/package.k --out ./rendered # # No inputs — the kustomization tree is fully declarative. diff --git a/examples/10-kcl-ecosystem/akua.lock b/examples/10-kcl-ecosystem/akua.lock index 4c528494..d8fc4588 100644 --- a/examples/10-kcl-ecosystem/akua.lock +++ b/examples/10-kcl-ecosystem/akua.lock @@ -1,5 +1,5 @@ # akua.lock — machine-maintained. Never hand-edit. -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. version = 1 diff --git a/examples/10-kcl-ecosystem/package.k b/examples/10-kcl-ecosystem/package.k index 7f0f4f02..1740c1b9 100644 --- a/examples/10-kcl-ecosystem/package.k +++ b/examples/10-kcl-ecosystem/package.k @@ -10,7 +10,7 @@ # # Render: # -# akua render --package examples/10-kcl-ecosystem/package.k --out ./rendered +# akuapkg render --package examples/10-kcl-ecosystem/package.k --out ./rendered # # Bigger pitch: any package on ghcr.io/kcl-lang/* (or any kpm-published # OCI ref) plugs in the same way. akua handles the digest pin, signature diff --git a/examples/11-install-as-package/README.md b/examples/11-install-as-package/README.md index 0a601110..92745056 100644 --- a/examples/11-install-as-package/README.md +++ b/examples/11-install-as-package/README.md @@ -11,7 +11,7 @@ call site, no path strings in user code. | file | purpose | |---|---| | `upstream/package.k` | Sibling Akua package — Deployment + Service + PodDisruptionBudget. Authored as a normal Package; nothing about it is install-aware. | -| `akua.toml` | Dep alias `upstream = { path = "./upstream" }` for `akua tree` + lock-time validation. | +| `akua.toml` | Dep alias `upstream = { path = "./upstream" }` for `akuapkg tree` + lock-time validation. | | `package.k` | The install: `upstream.render(...)`, overlay tenant label, drop PDB, append a ConfigMap. | | `inputs.example.yaml` | Per-install inputs (tenant, app, replicas). | | `rendered/` | Reference output (3 files: Deployment, Service, ConfigMap). | @@ -19,7 +19,7 @@ call site, no path strings in user code. ## Render ```sh -akua render --out ./rendered +akuapkg render --out ./rendered ``` ## The install pattern diff --git a/examples/11-install-as-package/akua.toml b/examples/11-install-as-package/akua.toml index 36bd7c9a..7069b80a 100644 --- a/examples/11-install-as-package/akua.toml +++ b/examples/11-install-as-package/akua.toml @@ -5,6 +5,6 @@ edition = "akua.dev/v1alpha1" [dependencies] # Path-dep on the upstream Akua package. Declares the composition -# relationship for `akua tree` + lock-time validation. `pkg.render` +# relationship for `akuapkg tree` + lock-time validation. `pkg.render` # accepts the same path inline below. upstream = { path = "./upstream" } diff --git a/examples/12-vendor-offline/README.md b/examples/12-vendor-offline/README.md index b8d02c94..b71424c7 100644 --- a/examples/12-vendor-offline/README.md +++ b/examples/12-vendor-offline/README.md @@ -3,7 +3,7 @@ > **Renders end-to-end** off the local vendor tree. No registry, no > network, no credentials needed at render time. The same Package > renders identically inside an air-gapped environment or behind a -> firewall once `akua vendor add` has staged the bytes. +> firewall once `akuapkg vendor add` has staged the bytes. A Package whose dep is materialized into `.akua/vendor//` so render works without re-fetching from the canonical source. This @@ -16,7 +16,7 @@ succeeds because the resolver finds the bytes under The resolver prefers `.akua/vendor//` when it exists for *every* dep kind — path, OCI, and git alike (see -`chart_resolver::resolve_with_options`). `akua vendor add` is the +`chart_resolver::resolve_with_options`). `akuapkg vendor add` is the public CLI verb that populates that path from a declared dep and pins the digest in `akua.lock`. The contract: @@ -52,21 +52,21 @@ ls upstream-chart/ # → No such file or directory ls .akua/vendor/upstream/ # → Chart.yaml templates/ # 3. Render — succeeds without network, auth, or canonical source: -akua render --out ./rendered +akuapkg render --out ./rendered -# 4. Verify integrity — `akua vendor check` re-hashes the vendor tree +# 4. Verify integrity — `akuapkg vendor check` re-hashes the vendor tree # and compares against akua.lock: -akua vendor check +akuapkg vendor check # → ok # 5. List what's vendored, including any orphan trees that no longer # correspond to a dep in akua.toml: -akua vendor list +akuapkg vendor list ``` To regenerate the vendor tree from a canonical source (e.g., during development before committing), restore `upstream-chart/` and run -`akua vendor add upstream`. +`akuapkg vendor add upstream`. ## When vendoring matters @@ -93,16 +93,16 @@ It earns its keep when: ## Out of scope (for now) -- **Recursive transitive vendoring.** `akua vendor add upstream` +- **Recursive transitive vendoring.** `akuapkg vendor add upstream` vendors `upstream` only. If `upstream` itself depends on a chart that needs network at render time, vendor that too — track CI - drift with `akua vendor check`. + drift with `akuapkg vendor check`. - **Workspace-wide `vendor add` (no name).** Currently `add` takes exactly one dep name. Looping is the caller's job. ## Path-escape safety -`akua vendor add` rejects: +`akuapkg vendor add` rejects: - Absolute paths in `path = "..."`. `path = "/etc"` → `E_PATH_ESCAPE`. - Relative paths that canonicalize outside the workspace. `path = diff --git a/examples/12-vendor-offline/akua.lock b/examples/12-vendor-offline/akua.lock index 6b3ee190..39b5b6b1 100644 --- a/examples/12-vendor-offline/akua.lock +++ b/examples/12-vendor-offline/akua.lock @@ -1,5 +1,5 @@ # akua.lock — machine-maintained. Never hand-edit. -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. version = 1 diff --git a/examples/12-vendor-offline/akua.toml b/examples/12-vendor-offline/akua.toml index d74df5a6..66e8d373 100644 --- a/examples/12-vendor-offline/akua.toml +++ b/examples/12-vendor-offline/akua.toml @@ -6,7 +6,7 @@ edition = "akua.dev/v1alpha1" [dependencies] # A path dep that points at a sibling chart in this workspace. # -# `akua vendor add upstream` copies the resolved tree into +# `akuapkg vendor add upstream` copies the resolved tree into # `.akua/vendor/upstream/` and pins its digest in `akua.lock`. # The resolver then prefers the vendored copy, so subsequent # renders work without re-reading the original source. diff --git a/examples/12-vendor-offline/package.k b/examples/12-vendor-offline/package.k index 7be31c95..c430f69b 100644 --- a/examples/12-vendor-offline/package.k +++ b/examples/12-vendor-offline/package.k @@ -1,5 +1,5 @@ # Renders a chart vendored into `.akua/vendor/upstream/` via -# `akua vendor add upstream`. The dep declaration in `akua.toml` +# `akuapkg vendor add upstream`. The dep declaration in `akua.toml` # stays canonical (`path = "./upstream-chart"`); the resolver # prefers the vendored copy when present, so render is offline- # safe once the vendor tree is committed alongside the Package. diff --git a/examples/13-subpackage-helm/README.md b/examples/13-subpackage-helm/README.md index 93488692..e8937696 100644 --- a/examples/13-subpackage-helm/README.md +++ b/examples/13-subpackage-helm/README.md @@ -24,7 +24,7 @@ sub-package implementation. ## Render ```sh -akua render --out ./rendered +akuapkg render --out ./rendered ``` The interesting part is the import boundary: root package inputs remain diff --git a/examples/13-subpackage-helm/package.k b/examples/13-subpackage-helm/package.k index 330e7e04..d89296cc 100644 --- a/examples/13-subpackage-helm/package.k +++ b/examples/13-subpackage-helm/package.k @@ -8,7 +8,7 @@ import pkgs.webserver as ws # # Render: # -# akua render --out ./rendered +# akuapkg render --out ./rendered schema Input: """Public inputs for the subpackage-helm root Package.""" namespace: str = "demo" diff --git a/examples/14-helm-repo-dep/README.md b/examples/14-helm-repo-dep/README.md index 82fd0067..79fe0f04 100644 --- a/examples/14-helm-repo-dep/README.md +++ b/examples/14-helm-repo-dep/README.md @@ -4,7 +4,7 @@ > `akua.lock` by chart version and tarball digest. This example covers `repo` dependencies: charts published through an -`index.yaml` rather than OCI or a local path. `akua add` resolves the +`index.yaml` rather than OCI or a local path. `akuapkg add` resolves the repository index, pins the selected chart archive digest in `akua.lock`, and registers the chart as `charts.podinfo` for KCL rendering. Render uses Akua's embedded Helm engine; no Helm binary or shell-out is needed. @@ -21,7 +21,7 @@ uses Akua's embedded Helm engine; no Helm binary or shell-out is needed. ## Render ```sh -akua render --out ./rendered +akuapkg render --out ./rendered ``` Classic Helm repositories are useful when an upstream chart has not diff --git a/examples/14-helm-repo-dep/akua.lock b/examples/14-helm-repo-dep/akua.lock index aac9f5c4..cd8a0840 100644 --- a/examples/14-helm-repo-dep/akua.lock +++ b/examples/14-helm-repo-dep/akua.lock @@ -1,5 +1,5 @@ # akua.lock — machine-maintained. Never hand-edit. -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`. +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`. version = 1 diff --git a/examples/14-helm-repo-dep/package.k b/examples/14-helm-repo-dep/package.k index ec0478d1..2ed59de4 100644 --- a/examples/14-helm-repo-dep/package.k +++ b/examples/14-helm-repo-dep/package.k @@ -6,9 +6,9 @@ # pins its sha256 in akua.lock, and registers the unpacked chart as the # `charts.podinfo` KCL module. No Helm binary required; no shell-out. # -# Render (requires `akua add` online first to populate the cache): +# Render (requires `akuapkg add` online first to populate the cache): # -# akua render --out ./rendered +# akuapkg render --out ./rendered # # The dep source is `repo`/`chart`/`version` rather than `oci` or `path` — # the same resolver machinery, a different transport. Compare with example 01 diff --git a/examples/README.md b/examples/README.md index 0d5e05f2..cd521d49 100644 --- a/examples/README.md +++ b/examples/README.md @@ -11,7 +11,7 @@ Every green row in the table below renders through the shipped `akua` binary and | 00 | [00-helm-hello/](00-helm-hello/) | simplest Package exercising `helm.template` against a bundled chart | ✅ renders | | 01 | [01-hello-webapp/](01-hello-webapp/) | typed `charts.*` dep from `akua.toml`, Helm template, Deployment + Service | ✅ renders | | 02 | [02-webapp-postgres/](02-webapp-postgres/) | cross-source wiring — a webapp consuming a CNPG-managed Postgres secret via convention; `test_package.k` | ⚠ target-state (OCI chart refs need refreshing) | -| 03 | [03-multi-env-app/](03-multi-env-app/) | Package + App + Environment as typed KCL — the full workspace authoring shape | 📘 pattern reference (no single `akua render` target) | +| 03 | [03-multi-env-app/](03-multi-env-app/) | Package + App + Environment as typed KCL — the full workspace authoring shape | 📘 pattern reference (no single `akuapkg render` target) | | 04 | [04-policy-tier/](04-policy-tier/) | Rego tier + Kyverno compile-resolved import, passing + failing fixtures | 📘 target-state (policy engine not shipped) | | 05 | [05-tests-and-golden/](05-tests-and-golden/) | `test_*.k` + `*_test.rego` + golden-fixture render snapshots | ⚠ target-state (lockfile pins OCI refs that need refreshing) | | 06 | [06-multi-engine/](06-multi-engine/) | Helm + Kustomize + kro RGD + inline KCL in one Package | ⚠ target-state (references `pkg.akua.dev` — not yet published) | @@ -25,7 +25,7 @@ Every green row in the table below renders through the shipped `akua` binary and **Legend:** -- ✅ **renders** — end-to-end through `akua render`, golden output committed, deterministic across machines. +- ✅ **renders** — end-to-end through `akuapkg render`, golden output committed, deterministic across machines. - 📘 **pattern reference** — illustrates an authoring shape; not a single-command render target (policy composition, multi-env workspace walks). - ⚠ **target-state** — references remote sources (OCI registries we don't yet publish to, or example corporate registries). The shape is current; the concrete refs will work once `pkg.akua.dev` is live or once the tagged chart versions are pinned against current registries. @@ -37,18 +37,18 @@ Prerequisite: build the embedded engines once. ```sh task build:engines # helm + kustomize wasip1 artifacts -cargo install --path crates/akua-cli +cargo install --path crates/akuapkg-cli ``` Render a green example: ```sh cd examples/00-helm-hello -akua render --out /tmp/hello +akuapkg render --out /tmp/hello diff -r /tmp/hello rendered/ # byte-identical to committed golden ``` -The other green examples (01, 08, 09, 10, 11, 13) follow the same pattern — `akua render --package ./package.k --inputs ./inputs.yaml --out /tmp/` and compare against `rendered/`. Example 14 requires `akua add` online first (to populate the cache) then renders identically to a local Helm dep. +The other green examples (01, 08, 09, 10, 11, 13) follow the same pattern — `akuapkg render --package ./package.k --inputs ./inputs.yaml --out /tmp/` and compare against `rendered/`. Example 14 requires `akuapkg add` online first (to populate the cache) then renders identically to a local Helm dep. --- diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 2d5d7b28..ae643b97 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -62,7 +62,7 @@ bun run packages/sdk/examples/06-diff-renders.ts ## Types + schema are derived, not hand-written -- `src/types/*.ts` — per-type TS from `ts-rs` derives on Rust serde types in `akua-core` + `akua-cli`. +- `src/types/*.ts` — per-type TS from `ts-rs` derives on Rust serde types in `akua-core` + `akuapkg-cli`. - `src/schemas/akua.json` — a single bundled JSON Schema from `schemars`. Polyglot consumers (Python, Go, agents) validate against the same shape. Drift is guarded by `task sdk:check` — regenerate + `git diff --exit-code`. diff --git a/packages/sdk/examples/04-check-workspace.ts b/packages/sdk/examples/04-check-workspace.ts index cf559e4c..77f7826e 100644 --- a/packages/sdk/examples/04-check-workspace.ts +++ b/packages/sdk/examples/04-check-workspace.ts @@ -1,6 +1,6 @@ -// Run the three structural gates `akua check` uses: parse the +// Run the three structural gates `akuapkg check` uses: parse the // manifest, parse the lockfile (if present), lint the Package.k. -// In-process via WASM; identical semantics to `akua check --json`. +// In-process via WASM; identical semantics to `akuapkg check --json`. import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; diff --git a/packages/sdk/examples/05-tree-deps.ts b/packages/sdk/examples/05-tree-deps.ts index 8e3e153e..5503130b 100644 --- a/packages/sdk/examples/05-tree-deps.ts +++ b/packages/sdk/examples/05-tree-deps.ts @@ -1,6 +1,6 @@ // Walk a workspace's declared deps + lockfile entries — what // charts are pinned, what digests, what (if any) fork-overrides. -// Mirrors `akua tree --json` exactly; runs in-process via WASM. +// Mirrors `akuapkg tree --json` exactly; runs in-process via WASM. import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; diff --git a/packages/sdk/examples/08-shell-out-render.ts b/packages/sdk/examples/08-shell-out-render.ts index 49c95f2c..da7d6222 100644 --- a/packages/sdk/examples/08-shell-out-render.ts +++ b/packages/sdk/examples/08-shell-out-render.ts @@ -4,7 +4,7 @@ // covers the pure-KCL cases where no binary is needed. // // Run with the CLI built: `task build:engines && cargo install -// --path crates/akua-cli`, or point at your local debug build: +// --path crates/akuapkg-cli`, or point at your local debug build: // `AKUA_BINARY=/path/to/target/debug/akua bun run 08-...ts`. import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; diff --git a/packages/sdk/src/coverage-fillers.test.ts b/packages/sdk/src/coverage-fillers.test.ts index 9548bc0a..ab58994b 100644 --- a/packages/sdk/src/coverage-fillers.test.ts +++ b/packages/sdk/src/coverage-fillers.test.ts @@ -122,7 +122,7 @@ describe('Akua.diff', () => { describe('Akua.verify', () => { test('workspace with akua.toml + akua.lock returns a verdict envelope', async () => { // Use an example workspace that already has a committed lockfile. - // A scratch workspace would 404 on akua.lock since `akua lock` + // A scratch workspace would 404 on akua.lock since `akuapkg lock` // hasn't been run. const ws = join(repoRoot, 'examples/01-hello-webapp'); const v = await akua.verify({ workspace: ws }); diff --git a/packages/sdk/src/mod.ts b/packages/sdk/src/mod.ts index ce2bafe8..f8c8491c 100644 --- a/packages/sdk/src/mod.ts +++ b/packages/sdk/src/mod.ts @@ -38,6 +38,8 @@ import { type SchemaName, validateAs } from './validate.ts'; // separate `@akua-dev/sdk-wasm` package, not as a side-channel here. export * from './errors.ts'; +export { configureNapi } from './napi.ts'; +export type { NapiAddon } from './napi.ts'; export { AkuaContractError, standardSchemaFor, validateAs } from './validate.ts'; export type { SchemaName } from './validate.ts'; export type { @@ -365,7 +367,7 @@ export class Akua { } const napi = loadNapi(); - // `napi.renderToYaml` mirrors `akua render --stdout` — emits + // `napi.renderToYaml` mirrors `akuapkg render --stdout` — emits // raw multi-doc YAML directly. When the caller hands us raw // source we materialize it into a scratch dir so KCL spans + // chart-path resolution work the same as a path-mode render. @@ -402,7 +404,7 @@ export class Akua { } /** - * Insert a dependency into `akua.toml`. Mirrors `akua add --`. + * Insert a dependency into `akua.toml`. Mirrors `akuapkg add --`. * Pass exactly one of `oci`, `git`, `path`, or `repo` (the latter * requires `chart` too). The manifest edit runs in-process via the * napi addon; the resolver best-effortly updates `akua.lock`. @@ -429,7 +431,7 @@ export class Akua { /** * Fast syntax / type / dep check over the workspace. Runs - * in-process via the napi addon. Mirrors `akua check`. + * in-process via the napi addon. Mirrors `akuapkg check`. */ async check(opts: CheckOptions = {}): Promise { const napi = loadNapi(); @@ -441,7 +443,7 @@ export class Akua { /** * Run the KCL linter against the Package. In-process via the - * napi addon. Mirrors `akua lint`. + * napi addon. Mirrors `akuapkg lint`. */ async lint(opts: LintOptions = {}): Promise { const napi = loadNapi(); @@ -481,7 +483,7 @@ export class Akua { * Format KCL sources. In-process via the napi addon. * With `check=true`, reports which files would change without * touching disk. Without `check`, the formatted text is written - * back to the file (mirroring `akua fmt`'s in-place behavior). + * back to the file (mirroring `akuapkg fmt`'s in-place behavior). * * `opts.stdout` is honored by reading the (now-formatted) file * and writing it to `process.stdout`. The file write happens @@ -505,7 +507,7 @@ export class Akua { * Introspect a Package or a packed tarball — surfaces the option * set, dependency tree, signing metadata. Pass `{ package }` for * an on-disk Package or `{ tarball }` for a `.tar.gz` artifact - * (e.g. from `akua pack`). + * (e.g. from `akuapkg pack`). */ async inspect(opts: InspectOptions = {}): Promise { if (opts.package && opts.tarball) { diff --git a/packages/sdk/src/napi-configure-child.ts b/packages/sdk/src/napi-configure-child.ts new file mode 100644 index 00000000..3b004279 --- /dev/null +++ b/packages/sdk/src/napi-configure-child.ts @@ -0,0 +1,9 @@ +import { configureNapi } from './mod.ts'; +import { loadNapi, type NapiAddon } from './napi.ts'; + +const addon = { + version: () => ({ version: 'embedded' }), +} as NapiAddon; + +configureNapi(addon); +console.log((loadNapi().version() as { version: string }).version); diff --git a/packages/sdk/src/napi.test.ts b/packages/sdk/src/napi.test.ts new file mode 100644 index 00000000..b6c2220c --- /dev/null +++ b/packages/sdk/src/napi.test.ts @@ -0,0 +1,20 @@ +import { expect, test } from 'bun:test'; + +import { resolve } from 'node:path'; + +test('uses an explicitly configured native addon before resolving packages', async () => { + const script = resolve(import.meta.dir, 'napi-configure-child.ts'); + const proc = Bun.spawn([process.execPath, script], { + stdout: 'pipe', + stderr: 'pipe', + }); + const [exitCode, stdout, stderr] = await Promise.all([ + proc.exited, + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + ]); + + expect(exitCode).toBe(0); + expect(stderr).toBe(''); + expect(stdout.trim()).toBe('embedded'); +}); diff --git a/packages/sdk/src/napi.ts b/packages/sdk/src/napi.ts index f233d53a..5ce5a4aa 100644 --- a/packages/sdk/src/napi.ts +++ b/packages/sdk/src/napi.ts @@ -95,6 +95,20 @@ export interface NapiAddon { let cached: NapiAddon | undefined; let cachedError: Error | undefined; +/** + * Configure the native addon before the first SDK call. + * + * This is for embedders that ship one known platform binding inside their + * executable. Normal SDK consumers should not call it: `loadNapi()` resolves + * `@akua-dev/native` and its platform package automatically. + */ +export function configureNapi(addon: NapiAddon): void { + if (cached || cachedError) { + throw new Error('The native addon has already been resolved; configure it before the first SDK call.'); + } + cached = addon; +} + /** * Lazy-load and cache the napi addon for the host platform. * Resolution order matches what `@napi-rs/cli`'s generated stub does diff --git a/packages/sdk/src/schemas/akua.json b/packages/sdk/src/schemas/akua.json index 72075b96..4defa0a6 100644 --- a/packages/sdk/src/schemas/akua.json +++ b/packages/sdk/src/schemas/akua.json @@ -36,7 +36,7 @@ "type": "object" }, "AgentSource": { - "description": "Which env var triggered agent detection. Recorded in `akua whoami`\noutput for introspection and in debug-level logs for post-hoc diagnosis.", + "description": "Which env var triggered agent detection. Recorded in `akuapkg whoami`\noutput for introspection and in debug-level logs for post-hoc diagnosis.", "oneOf": [ { "const": "agent", @@ -66,7 +66,7 @@ ] }, "CheckOutput": { - "description": "Output shape for `akua check --json`. The `status` field is\n`\"ok\"` iff every entry in `checks` has `ok == true`.", + "description": "Output shape for `akuapkg check --json`. The `status` field is\n`\"ok\"` iff every entry in `checks` has `ok == true`.", "properties": { "checks": { "items": { @@ -769,7 +769,7 @@ "type": "object" }, "TreeOutput": { - "description": "Output shape for `akua tree --json`.", + "description": "Output shape for `akuapkg tree --json`.", "properties": { "dependencies": { "items": { @@ -1054,7 +1054,7 @@ "type": "object" }, { - "description": "Path-dep on-disk content diverges from the digest `akua.lock`\npinned. Someone mutated the vendored chart without re-running\n`akua add` — either intentional (run add to refresh) or\naccidental (revert the edit).", + "description": "Path-dep on-disk content diverges from the digest `akua.lock`\npinned. Someone mutated the vendored chart without re-running\n`akuapkg add` — either intentional (run add to refresh) or\naccidental (revert the edit).", "properties": { "actual": { "type": "string" diff --git a/packages/sdk/src/types/AgentSource.ts b/packages/sdk/src/types/AgentSource.ts index a3dc722d..c1042f63 100644 --- a/packages/sdk/src/types/AgentSource.ts +++ b/packages/sdk/src/types/AgentSource.ts @@ -1,7 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. /** - * Which env var triggered agent detection. Recorded in `akua whoami` + * Which env var triggered agent detection. Recorded in `akuapkg whoami` * output for introspection and in debug-level logs for post-hoc diagnosis. */ export type AgentSource = "agent" | "claude_code" | "gemini_cli" | "cursor_cli" | "akua_agent"; diff --git a/packages/sdk/src/types/CheckOutput.ts b/packages/sdk/src/types/CheckOutput.ts index b5c77bb2..2e70bb25 100644 --- a/packages/sdk/src/types/CheckOutput.ts +++ b/packages/sdk/src/types/CheckOutput.ts @@ -2,7 +2,7 @@ import type { CheckResult } from "./CheckResult"; /** - * Output shape for `akua check --json`. The `status` field is + * Output shape for `akuapkg check --json`. The `status` field is * `"ok"` iff every entry in `checks` has `ok == true`. */ export type CheckOutput = { status: string, checks: Array, }; diff --git a/packages/sdk/src/types/TreeOutput.ts b/packages/sdk/src/types/TreeOutput.ts index d4caae1d..281f8fd1 100644 --- a/packages/sdk/src/types/TreeOutput.ts +++ b/packages/sdk/src/types/TreeOutput.ts @@ -3,6 +3,6 @@ import type { DepRow } from "./DepRow"; import type { PackageInfo } from "./PackageInfo"; /** - * Output shape for `akua tree --json`. + * Output shape for `akuapkg tree --json`. */ export type TreeOutput = { package: PackageInfo, dependencies: Array, }; diff --git a/scripts/Dockerfile b/scripts/Dockerfile index a09e9832..2ac751ab 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -1,4 +1,4 @@ -# Minimal akua container — just the static-ish CLI binary, no helm/kubectl. +# Minimal Akuapkg container — just the static-ish CLI binary, no helm/kubectl. # Consumers layer their own tooling on top (kubectl, helm, argocd CLI, etc). # Multi-arch: amd64 + arm64. Build context contains per-arch subdirs # populated by cli-release.yml; `$TARGETARCH` picks the right one. @@ -12,6 +12,6 @@ ARG TARGETARCH # The binary was stripped at build time (ci-release profile), so a # distroless runtime is enough. CC variant (not `static`) because # our rustls build dynamically links libc's unwinder on linux-gnu. -COPY --chmod=0755 ${TARGETARCH}/akua /usr/local/bin/akua +COPY --chmod=0755 ${TARGETARCH}/akuapkg /usr/local/bin/akuapkg -ENTRYPOINT ["/usr/local/bin/akua"] +ENTRYPOINT ["/usr/local/bin/akuapkg"] diff --git a/scripts/aur/akua-bin/PKGBUILD b/scripts/aur/akuapkg-bin/PKGBUILD similarity index 67% rename from scripts/aur/akua-bin/PKGBUILD rename to scripts/aur/akuapkg-bin/PKGBUILD index cdd56505..21286a62 100644 --- a/scripts/aur/akua-bin/PKGBUILD +++ b/scripts/aur/akuapkg-bin/PKGBUILD @@ -1,34 +1,34 @@ # Maintainer: CNAP Tech # -# PKGBUILD for the akua-bin AUR package — thin wrapper around the +# PKGBUILD for the akuapkg-bin AUR package — thin wrapper around the # prebuilt x86_64-unknown-linux-gnu tarball shipped from our GitHub # Release. No building from source on the user's machine; `makepkg` # just extracts + installs. # -# Submit by (from a checkout of ssh://aur@aur.archlinux.org/akua-bin.git): +# Submit by (from a checkout of ssh://aur@aur.archlinux.org/akuapkg-bin.git): # cp /path/to/PKGBUILD ./ # makepkg --printsrcinfo > .SRCINFO -# git add PKGBUILD .SRCINFO && git commit -m "akua-bin " +# git add PKGBUILD .SRCINFO && git commit -m "akuapkg-bin " # git push # # AUR version bumps are manual. Automation would require a dedicated # AUR-push lane and maintainer SSH key; the Akua core release does not # update external package-manager repositories. -pkgname=akua-bin -_pkgname=akua +pkgname=akuapkg-bin +_pkgname=akuapkg pkgver=0.1.0 pkgrel=1 pkgdesc="Cloud-native package build, transform, and preview toolkit" arch=('x86_64' 'aarch64') -url="https://github.com/cnap-tech/akua" +url="https://github.com/akua-dev/akua" license=('Apache-2.0') -provides=('akua') -conflicts=('akua') +provides=('akuapkg') +conflicts=('akuapkg') # Per-arch sources — each tag publishes both amd64 and arm64 tarballs. -source_x86_64=("https://github.com/cnap-tech/akua/releases/download/akua-v${pkgver}/${_pkgname}-v${pkgver}-x86_64-unknown-linux-gnu.tar.gz") -source_aarch64=("https://github.com/cnap-tech/akua/releases/download/akua-v${pkgver}/${_pkgname}-v${pkgver}-aarch64-unknown-linux-gnu.tar.gz") +source_x86_64=("https://github.com/akua-dev/akua/releases/download/v${pkgver}/${_pkgname}-v${pkgver}-x86_64-unknown-linux-gnu.tar.gz") +source_aarch64=("https://github.com/akua-dev/akua/releases/download/v${pkgver}/${_pkgname}-v${pkgver}-aarch64-unknown-linux-gnu.tar.gz") # SHA256 checksums — bump alongside pkgver. The release workflow # writes each tarball's sha256 next to it as `.tar.gz.sha256`; @@ -37,7 +37,7 @@ sha256sums_x86_64=('SKIP') sha256sums_aarch64=('SKIP') package() { - install -Dm755 "${srcdir}/akua" "${pkgdir}/usr/bin/akua" + install -Dm755 "${srcdir}/akuapkg" "${pkgdir}/usr/bin/akuapkg" install -Dm644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" install -Dm644 "${srcdir}/README.md" "${pkgdir}/usr/share/doc/${pkgname}/README.md" install -Dm644 "${srcdir}/SECURITY.md" "${pkgdir}/usr/share/doc/${pkgname}/SECURITY.md" diff --git a/scripts/check-release-workflows.sh b/scripts/check-release-workflows.sh index 8b8d290d..5ecc4dbb 100644 --- a/scripts/check-release-workflows.sh +++ b/scripts/check-release-workflows.sh @@ -169,7 +169,7 @@ assert_before ".github/workflows/release.yml" \ for workflow in .github/workflows/*.yml; do assert_file_excludes "$workflow" "cnap-tech" done -assert_file_contains ".github/workflows/release.yml" "ghcr.io/akua-dev/akua:\${tag}" +assert_file_contains ".github/workflows/release.yml" "ghcr.io/akua-dev/akuapkg:\${tag}" assert_file_excludes_pattern ".github/workflows/release.yml" 'gh[[:space:]]+release[[:space:]]+upload' assert_file_excludes ".github/workflows/release.yml" "--clobber" assert_file_excludes ".github/workflows/release-publish.yml" "gh release download" diff --git a/scripts/gen-cli-pages.ts b/scripts/gen-cli-pages.ts index 93ac9b76..de9f4495 100644 --- a/scripts/gen-cli-pages.ts +++ b/scripts/gen-cli-pages.ts @@ -2,7 +2,7 @@ //! Split `docs/cli.md` into one HTML page per verb at `/cli/` plus //! an index at `/cli/`. //! -//! Each verb section in `cli.md` starts with `## \`akua \` ` +//! Each verb section in `cli.md` starts with `## \`akuapkg \` ` //! (status is ✅ shipped or 🚧 planned) and runs until the next `## ` or //! the end of the file. The status emoji is preserved inline in the page //! header, and the index lists shipped verbs separately from planned ones. @@ -32,7 +32,7 @@ function parseVerbs(md: string): { intro: string; verbs: Verb[] } { let current: { name: string; status: Verb['status']; lines: string[] } | null = null; for (const line of lines) { - const header = line.match(/^##\s+`akua\s+(\S+)`\s*(✅|🚧)?/); + const header = line.match(/^##\s+`akuapkg\s+(\S+)`\s*(✅|🚧)?/); if (header) { if (current) { verbs.push(finishVerb(current)); @@ -96,25 +96,25 @@ function renderVerbPage(verb: Verb, allVerbs: Set, sidebar: SidebarSpec) const status = verb.status === 'shipped' ? 'Shipped' : 'Planned'; const linkOpts: LinkResolverOpts = { sourceMd: 'docs/cli.md', - // `cli.md` cross-references like `#akua-render` were anchors + // `cli.md` cross-references like `#akuapkg-render` were anchors // inside the monolithic doc; on the per-verb-page layout each // verb is its own page, so they need to retarget. anchorResolve: (anchor) => { - const m = anchor.match(/^akua-(\S+?)(?:-.*)?$/); + const m = anchor.match(/^akuapkg-(\S+?)(?:-.*)?$/); if (m && allVerbs.has(m[1])) return `/cli/${m[1]}`; return null; }, }; const inner = `
-

akua / cli / ${escape(verb.name)}

-

akua ${escape(verb.name)}

+

akuapkg / cli / ${escape(verb.name)}

+

akuapkg ${escape(verb.name)}

${renderMarkdown(verb.body, linkOpts)} `; return pageShell({ - title: `akua ${verb.name}`, + title: `akuapkg ${verb.name}`, description: verb.tagline, body: inner, currentSection: '/cli/', @@ -133,7 +133,7 @@ function renderIndexPage(intro: string, verbs: Verb[], sidebar: SidebarSpec): st const li = vs .map( (v) => `
  • - akua ${escape(v.name)} + akuapkg ${escape(v.name)}
    ${escape(v.tagline)}
  • `, ) @@ -143,7 +143,7 @@ function renderIndexPage(intro: string, verbs: Verb[], sidebar: SidebarSpec): st const inner = `
    -

    akua / cli

    +

    akuapkg / cli

    CLI reference

    Every akua verb. Shipped verbs are wired and tested; planned verbs have a stable surface but no backing implementation yet.

    diff --git a/scripts/gen-error-pages.ts b/scripts/gen-error-pages.ts index 00c254a7..8a6fe5fc 100755 --- a/scripts/gen-error-pages.ts +++ b/scripts/gen-error-pages.ts @@ -128,7 +128,7 @@ function renderCodePage( const bodyHtml = richMarkdown ? renderMarkdown(richMarkdown) - : `

    What happened

    ${summaryHtml}

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    `; + : `

    What happened

    ${summaryHtml}

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    `; const inner = `
    diff --git a/scripts/gen-example-pages.ts b/scripts/gen-example-pages.ts index cb0f0d44..7fa5bfed 100644 --- a/scripts/gen-example-pages.ts +++ b/scripts/gen-example-pages.ts @@ -124,7 +124,7 @@ ${readmeHtml} ${packageKBlock} ${renderedBlock}

    - Source: examples/${escape(example.slug)}/ + Source: examples/${escape(example.slug)}/

    `; diff --git a/scripts/gen-landing.ts b/scripts/gen-landing.ts index aaf77060..f137721b 100644 --- a/scripts/gen-landing.ts +++ b/scripts/gen-landing.ts @@ -33,7 +33,7 @@ const body = `
    > irm https://cli.akua.dev/install.ps1 | iex

    From source

    -
    $ cargo install --git https://github.com/cnap-tech/akua akua-cli
    +
    $ cargo install --git https://github.com/akua-dev/akua akuapkg-cli

    SDK

    $ npm install @akua-dev/sdk
    @@ -47,8 +47,8 @@ const body = `
  • Concepts
  • Examples
  • Errors
  • -
  • GitHub
  • -
  • Releases
  • +
  • GitHub
  • +
  • Releases
  • diff --git a/scripts/gen-start-page.ts b/scripts/gen-start-page.ts index f2208ec5..59f4fbd7 100644 --- a/scripts/gen-start-page.ts +++ b/scripts/gen-start-page.ts @@ -22,12 +22,12 @@ const md = ` $ curl -fsSL https://cli.akua.dev/install | sh \`\`\` -Or grab a pinned binary from [Releases](https://github.com/cnap-tech/akua/releases). Windows: \`irm https://cli.akua.dev/install.ps1 | iex\`. +Or grab a pinned binary from [Releases](https://github.com/akua-dev/akua/releases). Windows: \`irm https://cli.akua.dev/install.ps1 | iex\`. Verify the install: \`\`\` -$ akua version +$ akuapkg version akua 0.8.7 \`\`\` @@ -35,19 +35,19 @@ akua 0.8.7 \`\`\` $ mkdir hello-akua && cd hello-akua -$ akua init +$ akuapkg init \`\`\` This drops three files in your workspace: - \`akua.toml\` — manifest. Declares the package metadata + dependencies. - \`package.k\` — your Package, written in [KCL](https://www.kcl-lang.io/). One file, three regions: imports, schemas, body. -- \`inputs.example.yaml\` — example input values \`akua render\` reads when no \`--inputs\` is passed. +- \`inputs.example.yaml\` — example input values \`akuapkg render\` reads when no \`--inputs\` is passed. ## 3. Render \`\`\` -$ akua render +$ akuapkg render \`\`\` By default, output goes to \`./rendered/\`. Each top-level Kubernetes resource your Package emits becomes its own YAML file, prefixed with a stable index so the layout is deterministic. Same inputs + same lockfile → byte-identical output, every time. @@ -74,10 +74,10 @@ Branch on \`code\` from agent code; the \`docs\` URL is the human-friendly fallb ## 4. Add a dependency -Composing with an upstream Helm chart? \`akua add\` updates \`akua.toml\` and \`akua.lock\` in one step: +Composing with an upstream Helm chart? \`akuapkg add\` updates \`akua.toml\` and \`akua.lock\` in one step: \`\`\` -$ akua add nginx --oci oci://ghcr.io/nginxinc/charts/nginx --version 1.0.0 +$ akuapkg add nginx --oci oci://ghcr.io/nginxinc/charts/nginx --version 1.0.0 \`\`\` Then in \`package.k\`: @@ -93,9 +93,9 @@ The resolver writes a \`charts//\` mount so the engine plugin (helm.templ When you're ready to ship: \`\`\` -$ akua verify # akua.toml ↔ akua.lock integrity + cosign signatures +$ akuapkg verify # akua.toml ↔ akua.lock integrity + cosign signatures $ akua sign # cosign-sign the artifact -$ akua publish # push the signed OCI artifact + SLSA attestation +$ akuapkg publish # push the signed OCI artifact + SLSA attestation \`\`\` By default \`publish\` refuses unless the lockfile is clean and a cosign key is configured. See [Concepts → Security model](/concepts/security-model) for the threat model and what \`strict_signing\` enforces. diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 6d19f445..fc35e342 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -1,7 +1,7 @@ -# akua install script for Windows — `irm https://cli.akua.dev/install.ps1 | iex` +# Akuapkg install script for Windows. # -# Downloads a prebuilt akua.exe from GitHub Releases into -# $env:AKUA_INSTALL\bin (default: $env:USERPROFILE\.akua\bin) and prints +# Downloads a prebuilt akuapkg.exe from GitHub Releases into +# $env:AKUAPKG_INSTALL\bin (default: $env:USERPROFILE\.akuapkg\bin) and prints # the PATH line to paste. # # We don't mutate the user's PATH or Registry — printing the env var @@ -28,7 +28,7 @@ $triple = switch ($arch) { 'x86_64' { 'x86_64-pc-windows-msvc' } # aarch64-pc-windows-msvc builds aren't shipped yet. Users on ARM64 # Windows get a clear error rather than a silently-broken binary. - 'ARM64' { Die "ARM64 Windows not yet supported. File an issue at https://github.com/cnap-tech/akua/issues" } + 'ARM64' { Die "ARM64 Windows not yet supported. File an issue at https://github.com/akua-dev/akua/issues" } default { Die "unsupported Windows arch: $arch" } } @@ -37,12 +37,12 @@ $triple = switch ($arch) { # --------------------------------------------------------------------------- # First positional arg: optional version. `v0.1.0`, `0.1.0`, or -# `akua-v0.1.0` all accepted. +# `akuapkg-v0.1.0` all accepted. $requestedVersion = $args[0] function Resolve-Version($v) { if ($v) { - $v = $v -replace '^akua-','' + $v = $v -replace '^akuapkg-','' if ($v -notmatch '^v') { $v = "v$v" } return $v } @@ -50,15 +50,15 @@ function Resolve-Version($v) { # -MaximumRedirection 0 means: stop at the first redirect and read # its Location header, rather than actually following it. $resp = try { - Invoke-WebRequest -Uri 'https://github.com/cnap-tech/akua/releases/latest' ` + Invoke-WebRequest -Uri 'https://github.com/akua-dev/akua/releases/latest' ` -MaximumRedirection 0 -ErrorAction SilentlyContinue } catch { $_.Exception.Response } $loc = $resp.Headers.Location if (-not $loc) { Die "could not resolve latest version from GitHub" } - # URL ends with .../tag/akua-vX.Y.Z - ($loc -split '/tag/akua-')[-1] + # URL ends with .../tag/vX.Y.Z + ($loc -split '/tag/')[-1] } $version = Resolve-Version $requestedVersion @@ -67,38 +67,38 @@ $version = Resolve-Version $requestedVersion # Download + install # --------------------------------------------------------------------------- -$base = if ($env:AKUA_DOWNLOAD_BASE) { $env:AKUA_DOWNLOAD_BASE } else { 'https://github.com' } -$asset = "akua-$version-$triple.zip" -$url = "$base/cnap-tech/akua/releases/download/akua-$version/$asset" +$base = if ($env:AKUAPKG_DOWNLOAD_BASE) { $env:AKUAPKG_DOWNLOAD_BASE } else { 'https://github.com' } +$asset = "akuapkg-$version-$triple.zip" +$url = "$base/akua-dev/akua/releases/download/$version/$asset" -$installRoot = if ($env:AKUA_INSTALL) { $env:AKUA_INSTALL } else { Join-Path $env:USERPROFILE '.akua' } +$installRoot = if ($env:AKUAPKG_INSTALL) { $env:AKUAPKG_INSTALL } else { Join-Path $env:USERPROFILE '.akuapkg' } $binDir = Join-Path $installRoot 'bin' -Info "downloading akua $version ($triple)" +Info "downloading akuapkg $version ($triple)" Info " from $url" -Info " to $binDir\akua.exe" +Info " to $binDir\akuapkg.exe" New-Item -ItemType Directory -Force -Path $binDir | Out-Null -$tmp = Join-Path $env:TEMP ("akua-install-" + [guid]::NewGuid()) +$tmp = Join-Path $env:TEMP ("akuapkg-install-" + [guid]::NewGuid()) New-Item -ItemType Directory -Force -Path $tmp | Out-Null try { - $zipPath = Join-Path $tmp 'akua.zip' + $zipPath = Join-Path $tmp 'akuapkg.zip' Invoke-WebRequest -Uri $url -OutFile $zipPath -UseBasicParsing ` -ErrorAction Stop Expand-Archive -Path $zipPath -DestinationPath $tmp -Force - $exeSrc = Join-Path $tmp 'akua.exe' + $exeSrc = Join-Path $tmp 'akuapkg.exe' if (-not (Test-Path $exeSrc)) { - Die "archive did not contain akua.exe" + Die "archive did not contain akuapkg.exe" } - Move-Item -Path $exeSrc -Destination (Join-Path $binDir 'akua.exe') -Force + Move-Item -Path $exeSrc -Destination (Join-Path $binDir 'akuapkg.exe') -Force } finally { Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue } -Success "installed akua $version to $binDir\akua.exe" +Success "installed akuapkg $version to $binDir\akuapkg.exe" Write-Host "" # PATH check — case-insensitive, split on `;`. @@ -111,4 +111,4 @@ if ($pathParts -notcontains $binDir) { Write-Host "" } -Info "verify: $binDir\akua.exe --version" +Info "verify: $binDir\akuapkg.exe --version" diff --git a/scripts/install.sh b/scripts/install.sh index 5fe6ef48..122c43d0 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,10 +1,10 @@ #!/bin/sh # shellcheck shell=dash # -# akua install script — `curl -fsSL https://cli.akua.dev/install | sh` +# Akuapkg install script. # -# Downloads a prebuilt `akua` binary from GitHub Releases into -# $AKUA_INSTALL/bin (defaulting to $HOME/.akua/bin), and prints the +# Downloads a prebuilt `akuapkg` binary from GitHub Releases into +# $AKUAPKG_INSTALL/bin (defaulting to $HOME/.akuapkg/bin), and prints the # `export PATH=…` line to paste into your shell config. # # We deliberately don't edit ~/.bashrc / ~/.zshrc / ~/.config/fish / etc @@ -15,11 +15,11 @@ # $1 version tag (e.g. `v0.1.0`); defaults to latest via GitHub redirect. # # Optional env: -# AKUA_INSTALL install root (default: $HOME/.akua) -# AKUA_DOWNLOAD_BASE download host (default: github.com, for CDN mirrors) +# AKUAPKG_INSTALL install root (default: $HOME/.akuapkg) +# AKUAPKG_DOWNLOAD_BASE download host (default: github.com, for CDN mirrors) # # Keep this script simple and easily auditable. If something gets -# hairy, it probably belongs in `akua` itself, not here. +# hairy, it probably belongs in `akuapkg` itself, not here. set -eu @@ -37,34 +37,34 @@ main() { local resolved_version resolved_version="$(resolve_version "$version")" - local base="${AKUA_DOWNLOAD_BASE:-https://github.com}" - local asset="akua-${resolved_version}-${triple}.tar.gz" - local url="${base}/cnap-tech/akua/releases/download/akua-${resolved_version}/${asset}" + local base="${AKUAPKG_DOWNLOAD_BASE:-https://github.com}" + local asset="akuapkg-${resolved_version}-${triple}.tar.gz" + local url="${base}/akua-dev/akua/releases/download/${resolved_version}/${asset}" - local install_root="${AKUA_INSTALL:-$HOME/.akua}" + local install_root="${AKUAPKG_INSTALL:-$HOME/.akuapkg}" local bin_dir="${install_root}/bin" - info "downloading akua ${resolved_version} (${triple})" + info "downloading akuapkg ${resolved_version} (${triple})" info " from ${url}" - info " to ${bin_dir}/akua" + info " to ${bin_dir}/akuapkg" mkdir -p "$bin_dir" || error "cannot create ${bin_dir}" local tmpdir - tmpdir="$(mktemp -d 2>/dev/null || mktemp -d -t 'akua')" + tmpdir="$(mktemp -d 2>/dev/null || mktemp -d -t 'akuapkg')" trap 'rm -rf "$tmpdir"' EXIT - curl -fsSL "$url" -o "$tmpdir/akua.tar.gz" \ + curl -fsSL "$url" -o "$tmpdir/akuapkg.tar.gz" \ || error "download failed from ${url}" - tar -xzf "$tmpdir/akua.tar.gz" -C "$tmpdir" \ + tar -xzf "$tmpdir/akuapkg.tar.gz" -C "$tmpdir" \ || error "extract failed (corrupt archive?)" - [ -f "$tmpdir/akua" ] || error "archive did not contain the akua binary" + [ -f "$tmpdir/akuapkg" ] || error "archive did not contain the akuapkg binary" - mv "$tmpdir/akua" "$bin_dir/akua" - chmod +x "$bin_dir/akua" + mv "$tmpdir/akuapkg" "$bin_dir/akuapkg" + chmod +x "$bin_dir/akuapkg" - success "installed akua ${resolved_version} to ${bin_dir}/akua" + success "installed akuapkg ${resolved_version} to ${bin_dir}/akuapkg" printf '\n' if ! echo ":$PATH:" | grep -q ":${bin_dir}:"; then @@ -72,7 +72,7 @@ main() { printf '\n export PATH="%s:$PATH"\n\n' "$bin_dir" fi - info "verify: ${bin_dir}/akua --version" + info "verify: ${bin_dir}/akuapkg --version" } # --------------------------------------------------------------------------- @@ -90,7 +90,7 @@ detect_triple() { # bail rather than give them a broken glibc binary that fails # at runtime with a confusing dynamic-linker error. if [ -f /etc/alpine-release ]; then - error "Alpine/musl not yet supported. Build from source:\n\n cargo install --git https://github.com/cnap-tech/akua akua-cli\n" + error "Alpine/musl not yet supported. Build from source:\n\n cargo install --git https://github.com/akua-dev/akua akuapkg-cli\n" fi case "$machine" in x86_64|amd64) triple="x86_64-unknown-linux-gnu" ;; @@ -112,7 +112,7 @@ detect_triple() { esac ;; MINGW*|MSYS*|CYGWIN*) - error "for Windows use:\n\n powershell -c \"irm https://akua.cnap.tech/install.ps1 | iex\"\n" + error "for Windows use the GitHub Release archive.\n" ;; *) error "unsupported OS: $sysname" @@ -128,8 +128,8 @@ detect_triple() { resolve_version() { local input="$1" if [ -n "$input" ]; then - # Accept `v0.1.0`, `0.1.0`, or `akua-v0.1.0` — normalise to `v0.1.0`. - echo "$input" | sed -e 's|^akua-||' -e 's|^v\{0,1\}|v|' + # Accept `v0.1.0`, `0.1.0`, or `akuapkg-v0.1.0` — normalise to `v0.1.0`. + echo "$input" | sed -e 's|^akuapkg-||' -e 's|^v\{0,1\}|v|' return fi # `releases/latest/download/...` redirects per-asset; to reconstruct @@ -137,9 +137,9 @@ resolve_version() { # redirect on `/releases/latest` itself. local location location="$(curl -fsSLI -o /dev/null -w '%{url_effective}\n' \ - https://github.com/cnap-tech/akua/releases/latest)" - # URL ends with .../tag/akua-vX.Y.Z - echo "$location" | sed -e 's|.*/tag/akua-||' + https://github.com/akua-dev/akua/releases/latest)" + # URL ends with .../tag/vX.Y.Z. + echo "$location" | sed -e 's|.*/tag/||' } # --------------------------------------------------------------------------- diff --git a/scripts/site/layout.ts b/scripts/site/layout.ts index 7db9b123..29e50ee7 100644 --- a/scripts/site/layout.ts +++ b/scripts/site/layout.ts @@ -442,7 +442,7 @@ ${sidebarHtml} ${opts.body}

    diff --git a/scripts/site/markdown.ts b/scripts/site/markdown.ts index 3927a4e4..7c6da3a6 100644 --- a/scripts/site/markdown.ts +++ b/scripts/site/markdown.ts @@ -9,8 +9,8 @@ import { escape } from './layout.ts'; /** Github-blob base for rewriting `../foo.md` links found in `docs/`. */ -const GITHUB_BLOB = 'https://github.com/cnap-tech/akua/blob/main'; -const GITHUB_TREE = 'https://github.com/cnap-tech/akua/tree/main'; +const GITHUB_BLOB = 'https://github.com/akua-dev/akua/blob/main'; +const GITHUB_TREE = 'https://github.com/akua-dev/akua/tree/main'; /** * Rewrite source-tree links to URLs that resolve on the deployed @@ -35,7 +35,7 @@ export interface LinkResolverOpts { * `skills/new-package/`) to a site URL. Return null to fall back * to the GitHub tree/blob URL. */ repoResolve?: (repoPath: string) => string | null; - /** Rewrite a bare in-page anchor (e.g. `#akua-render`) to a + /** Rewrite a bare in-page anchor (e.g. `#akuapkg-render`) to a * full URL — used when the source markdown is one big doc that * the renderer split into per-page files. Return null to leave * the anchor untouched. */ diff --git a/site/cli/add.html b/site/cli/add.html index 2d4b6f62..84eaf700 100644 --- a/site/cli/add.html +++ b/site/cli/add.html @@ -3,12 +3,12 @@ -akua add — akua +akuapkg add — akua - + @@ -292,36 +292,36 @@
    -

    akua / cli / add

    -

    akua add

    +

    akuapkg / cli / add

    +

    akuapkg add

    Insert a dependency into akua.toml. Pure manifest edit — the resolver best-effortly updates akua.lock immediately after.

    -
    akua add <name> (--oci=<url> | --git=<url> | --path=<path> | --repo=<url> --chart=<chart>) [flags]
    +
    akuapkg add <name> (--oci=<url> | --git=<url> | --path=<path> | --repo=<url> --chart=<chart>) [flags]

    Exactly one source flag is required. --repo requires --chart.

    Dependency sources

    sourceflagsuse when
    OCI--oci=<url>published signed artifact (most common)
    Git--git=<url>non-OCI-distributed sources
    Path--path=<path>workspace-local, dev-only
    Helm repo--repo=<url> --chart=<chart>classic HTTPS Helm repository

    Examples

    # OCI dep
    -akua add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0
    +akuapkg add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0
     
     # Git dep pinned to a tag
    -akua add tooling --git https://github.com/acme/tools --tag v1.2.3
    +akuapkg add tooling --git https://github.com/acme/tools --tag v1.2.3
     
     # Local path dep
    -akua add shared --path ../shared
    +akuapkg add shared --path ../shared
     
     # HTTPS Helm-repo dep
    -akua add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0
    +akuapkg add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0
     
     # Replace an existing entry
    -akua add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.21.0 --force
    +akuapkg add cnpg --oci oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.21.0 --force

    Flags

    flagdescription
    --oci=<url>OCI source URL (oci://…)
    --git=<url>Git source URL
    --path=<path>local filesystem path
    --repo=<url>HTTPS Helm-repo URL (pairs with --chart)
    --chart=<name>chart name within the Helm repo (required with --repo)
    --version=<version>version constraint; required for OCI and Helm-repo deps
    --tag=<tag>git tag (alternative to --rev)
    --rev=<sha>git commit SHA (alternative to --tag)
    --forcereplace an existing entry under name
    --workspace=<path>workspace root containing akua.toml (default: .)

    Exit codes

    @@ -337,7 +337,7 @@

    JSON output

    diff --git a/site/cli/api.html b/site/cli/api.html new file mode 100644 index 00000000..49ecb869 --- /dev/null +++ b/site/cli/api.html @@ -0,0 +1,367 @@ + + + + + +akuapkg api — akua + + + + + + + + + + + + + +
    + +
    + +
    +

    akuapkg / cli / api

    +

    akuapkg api

    +
    + +

    Call the hosted Akua API from the OSS CLI. This is an optional hosted extension: local package workflows such as render, export, check, lint, test, and verify do not require hosted API credentials or network access.

    +
    akuapkg api <path-or-url> [flags]
    +akuapkg api spec [--audience=<public|partner|admin|internal>] [flags]
    +

    <path-or-url> can be a version-relative path such as /workspaces or an absolute URL on the configured API origin. Relative paths are resolved under the base URL. The default base URL is https://api.akua.dev/v1/.

    +

    Examples

    +
    # List workspaces
    +akuapkg api /workspaces
    +
    +# Create a product from a JSON body
    +akuapkg api /products -X POST --input product.json
    +
    +# Send typed fields as JSON
    +akuapkg api /access_decisions -X POST -F permission=offers.create
    +
    +# Send a workspace context header
    +akuapkg api /products --workspace ws_123
    +
    +# Fetch the public OpenAPI document
    +akuapkg api spec
    +
    +# Use a non-default API origin
    +akuapkg api /workspaces --base-url https://staging.example.dev/v1/
    +

    Request flags

    +
    flagdescription
    -X, --method=<method>HTTP method. Defaults to GET when no body or fields are present, otherwise POST
    -H, --header=<name:value>extra request header. name=value is also accepted
    -f, --raw-field=<key=value>string field. Sent as query params for read methods and JSON body fields for writes without --input; when --input is present, fields stay in the query string
    -F, --field=<key=value>typed field. Parses true, false, null, and integers before sending
    --input=<file>JSON file to use as the request body
    --jq=<expr>reserved for response filtering; currently returns E_UNSUPPORTED
    --includereserved for response-header output; currently returns E_UNSUPPORTED
    --silentsuppress a successful response body
    --paginatereserved for pagination; currently returns E_UNSUPPORTED
    --slurpreserved for paginated response aggregation; currently returns E_UNSUPPORTED
    +

    Connection flags

    +
    flagdescription
    --base-url=<url>hosted API base URL. Defaults to https://api.akua.dev/v1/
    --token=<token>bearer token for hosted API auth
    --workspace=<id>workspace context sent as the akua-context request header
    +

    Environment resolution

    +

    Connection values resolve in this order:

    +
    settingresolution
    base URL--base-url, then AKUA_API_BASE_URL, then https://api.akua.dev/v1/
    bearer token--token, then AKUA_API_TOKEN
    workspace context--workspace, then AKUA_WORKSPACE_ID
    +

    akuapkg api uses hosted API bearer tokens only. akuapkg auth remains registry auth for OCI operations and is not reused for hosted API requests. A missing hosted API token fails with E_AUTH_REQUIRED; pass --token or set AKUA_API_TOKEN.

    +

    akuapkg api spec

    +

    akuapkg api spec fetches the public OpenAPI document from /openapi.json on the configured base URL. akuapkg api spec --audience public is equivalent.

    +

    Elevated audiences are visible in the CLI contract but not served in this release:

    +
    akuapkg api spec --audience partner
    +akuapkg api spec --audience admin
    +akuapkg api spec --audience internal
    +

    Each elevated audience exits with E_UNSUPPORTED until the hosted API serves authorized audience-specific OpenAPI documents. The CLI does not locally filter the public OpenAPI document to simulate elevated audiences.

    +

    Structured errors

    +

    Failed hosted API calls emit Akua structured errors on stderr. Under --json or agent context, stderr is JSON-lines:

    +
    {"code":"E_AUTH_INVALID","message":"token is invalid or expired","docs":"https://cli.akua.dev/errors/E_AUTH_INVALID"}
    +

    HTTP 401 maps to auth errors, 403 maps to forbidden user errors, 429 exits with the rate-limited exit code, and transport/timeouts use the standard CLI contract exit codes.

    +

    Exit codes

    +

    0 success, 1 user error, 2 system error, 4 rate limited, 6 timeout.

    + + +
    +
    + + + diff --git a/site/cli/attest.html b/site/cli/attest.html index bc1d539f..28c95e84 100644 --- a/site/cli/attest.html +++ b/site/cli/attest.html @@ -3,12 +3,12 @@ -akua attest — akua +akuapkg attest — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / attest

    -

    akua attest

    +

    akuapkg / cli / attest

    +

    akuapkg attest

    Emit a SLSA v1 provenance predicate for the current package or a built artifact.

    @@ -320,7 +320,7 @@

    JSON output

    diff --git a/site/cli/audit.html b/site/cli/audit.html index 65474fc1..ed198df7 100644 --- a/site/cli/audit.html +++ b/site/cli/audit.html @@ -3,12 +3,12 @@ -akua audit — akua +akuapkg audit — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / audit

    -

    akua audit

    +

    akuapkg / cli / audit

    +

    akuapkg audit

    Causality spine. Trace changes, explain incidents, query the audit trail.

    @@ -336,7 +336,7 @@

    JSON output (explain)

    diff --git a/site/cli/bench.html b/site/cli/bench.html index 359da99d..26f3eb92 100644 --- a/site/cli/bench.html +++ b/site/cli/bench.html @@ -3,12 +3,12 @@ -akua bench — akua +akuapkg bench — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / bench

    -

    akua bench

    +

    akuapkg / cli / bench

    +

    akuapkg bench

    Benchmark policy evaluation and package render latency.

    @@ -323,7 +323,7 @@

    JSON output

    diff --git a/site/cli/check.html b/site/cli/check.html index f013e815..a0bc85db 100644 --- a/site/cli/check.html +++ b/site/cli/check.html @@ -3,12 +3,12 @@ -akua check — akua +akuapkg check — akua - + @@ -292,19 +292,19 @@
    -

    akua / cli / check

    -

    akua check

    +

    akuapkg / cli / check

    +

    akuapkg check

    Syntax + type + dependency check. No execution, no rendering. Fast.

    -
    akua check [path] [flags]
    -

    Stricter than akua lint (actual compile errors, not style); cheaper than akua render (doesn't invoke engines). Good for IDE save hooks and pre-commit.

    +
    akuapkg check [path] [flags]
    +

    Stricter than akuapkg lint (actual compile errors, not style); cheaper than akuapkg render (doesn't invoke engines). Good for IDE save hooks and pre-commit.

    JSON output

    {
       "valid": true,
    @@ -326,7 +326,7 @@ 

    JSON output

    diff --git a/site/cli/cov.html b/site/cli/cov.html index 9dcd08ae..bc77d040 100644 --- a/site/cli/cov.html +++ b/site/cli/cov.html @@ -3,12 +3,12 @@ -akua cov — akua +akuapkg cov — akua - + @@ -292,25 +292,25 @@
    -

    akua / cli / cov

    -

    akua cov

    +

    akuapkg / cli / cov

    +

    akuapkg cov

    Generate a test coverage report across rules (Rego) and schemas (KCL).

    akua cov [path] [flags]
    -

    Equivalent to akua test --coverage but produces a standalone report. Useful for CI gates that enforce a minimum coverage percentage.

    +

    Equivalent to akuapkg test --coverage but produces a standalone report. Useful for CI gates that enforce a minimum coverage percentage.

    Flags

    flagdescription
    --min=<percentage>fail if coverage is below threshold (e.g. --min=80)
    `--format=<json\html\lcov>`report format (default json)
    diff --git a/site/cli/deploy.html b/site/cli/deploy.html index 021c016e..3cd6f91a 100644 --- a/site/cli/deploy.html +++ b/site/cli/deploy.html @@ -3,12 +3,12 @@ -akua deploy — akua +akuapkg deploy — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / deploy

    -

    akua deploy

    +

    akuapkg / cli / deploy

    +

    akuapkg deploy

    Deploy rendered output to a reconciler target.

    @@ -334,7 +334,7 @@

    JSON output (status)

    diff --git a/site/cli/dev.html b/site/cli/dev.html index 8568d613..0ba5f5dd 100644 --- a/site/cli/dev.html +++ b/site/cli/dev.html @@ -3,12 +3,12 @@ -akua dev — akua +akuapkg dev — akua - + @@ -292,18 +292,18 @@
    -

    akua / cli / dev

    -

    akua dev

    +

    akuapkg / cli / dev

    +

    akuapkg dev

    Start the hot-reload development loop.

    -
    akua dev [flags]
    +
    akuapkg dev [flags]

    Single long-running process. Watches workspace for changes. Renders, validates policy, applies to local target. Serves a browser UI at http://localhost:5173.

    Flags

    flagdescription
    `--target=<local\dry-run\cluster:<name>>`apply target (default: local kind cluster)
    --port=<num>browser UI port (default: 5173)
    --policy=<tier>policy tier for live checks (default: tier/dev)
    --no-browserdon't open browser automatically
    --freshwipe persistent state before starting
    --inputs=<file>override inputs file
    @@ -315,11 +315,11 @@

    JSON output (when --json)

    {"t":1713636001,"stage":"policy","resource":"Deployment/api","verdict":"allow"} {"t":1713636001,"stage":"apply","resource":"Deployment/api","op":"patch","duration_ms":198} {"t":1713636002,"stage":"reconcile","resource":"Deployment/api","status":"ready"}
    -

    Useful for agents that want to drive akua dev programmatically.

    +

    Useful for agents that want to drive akuapkg dev programmatically.

    diff --git a/site/cli/diff.html b/site/cli/diff.html index 95d6e868..c3491189 100644 --- a/site/cli/diff.html +++ b/site/cli/diff.html @@ -3,12 +3,12 @@ -akua diff — akua +akuapkg diff — akua - + @@ -292,19 +292,19 @@
    -

    akua / cli / diff

    -

    akua diff

    +

    akuapkg / cli / diff

    +

    akuapkg diff

    Structural diff between two package versions, or between a local package and a published version.

    -
    akua diff <a> <b> [flags]
    -akua diff <ref>                    # diff local HEAD against published ref
    +
    akuapkg diff <a> <b> [flags]
    +akuapkg diff <ref>                    # diff local HEAD against published ref

    Flags

    flagdescription
    `--format=<structural\yaml\both>`diff level (default: structural)
    `--scope=<schema\sources\manifests\all>`what to compare (default: all)
    --filter=<pattern>only show diffs matching pattern

    Exit codes

    @@ -332,7 +332,7 @@

    JSON output

    diff --git a/site/cli/eval.html b/site/cli/eval.html index 0ee5fb1f..ce3a7554 100644 --- a/site/cli/eval.html +++ b/site/cli/eval.html @@ -3,12 +3,12 @@ -akua eval — akua +akuapkg eval — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / eval

    -

    akua eval

    +

    akuapkg / cli / eval

    +

    akuapkg eval

    One-shot evaluator — cheap, scriptable. For Rego queries and KCL expressions without entering the REPL.

    @@ -318,7 +318,7 @@

    JSON output

    diff --git a/site/cli/export.html b/site/cli/export.html index ad4d53af..e201f51b 100644 --- a/site/cli/export.html +++ b/site/cli/export.html @@ -3,12 +3,12 @@ -akua export — akua +akuapkg export — akua - + @@ -292,19 +292,19 @@
    -

    akua / cli / export

    -

    akua export

    +

    akuapkg / cli / export

    +

    akuapkg export

    Convert a Package's Input schema to a standard interchange format. Emits JSON Schema 2020-12 (raw) or OpenAPI 3.1 (Input wrapped under components.schemas). Backed by KCL's resolver + AST walk; field docstrings become description, @ui(...) decorators become x-ui extensions.

    -
    akua export --package <path> [--format=<json-schema|openapi>] [--out=<file>]
    -
    Not the same as akua render. export is format translation — it doesn't invoke Helm / kro / Kustomize and doesn't need customer inputs. It answers "how do I describe this Package's inputs in a format other tools understand?" Use render when you want deploy-ready manifests; use export when you want a schema for a UI form renderer or API doc generator. See akua render above.
    +
    akuapkg export --package <path> [--format=<json-schema|openapi>] [--out=<file>]
    +
    Not the same as akuapkg render. export is format translation — it doesn't invoke Helm / kro / Kustomize and doesn't need customer inputs. It answers "how do I describe this Package's inputs in a format other tools understand?" Use render when you want deploy-ready manifests; use export when you want a schema for a UI form renderer or API doc generator. See akuapkg render above.

    Supported formats

    formatoutputfor
    json-schema (default)JSON Schema Draft 2020-12 for the Input schemainstall UIs, form renderers (rjsf, JSONForms)
    openapiOpenAPI 3.1 with Input under components.schemasAPI docs (Swagger UI, Redoc), client SDK generation, admission-webhook validators

    Flags

    @@ -333,19 +333,19 @@

    @ui(...) decorators →

    Examples

    # JSON Schema for a web form
    -akua export --package package.k > inputs.schema.json
    +akuapkg export --package package.k > inputs.schema.json
     
     # OpenAPI 3.1 for API docs
    -akua export --package package.k --format=openapi > package.openapi.json
    +akuapkg export --package package.k --format=openapi > package.openapi.json
     
     # Write to file directly
    -akua export --package package.k --out=exported/inputs.schema.json
    +akuapkg export --package package.k --out=exported/inputs.schema.json

    Exit codes

    0 success; 1 if package.k lacks an Input schema or has KCL syntax errors; 5 on filesystem errors.

    diff --git a/site/cli/fmt.html b/site/cli/fmt.html index 16809eb3..e3c35f62 100644 --- a/site/cli/fmt.html +++ b/site/cli/fmt.html @@ -3,12 +3,12 @@ -akua fmt — akua +akuapkg fmt — akua - + @@ -292,18 +292,18 @@
    -

    akua / cli / fmt

    -

    akua fmt

    +

    akuapkg / cli / fmt

    +

    akuapkg fmt

    Format KCL and Rego sources in place.

    -
    akua fmt [path] [flags]
    +
    akuapkg fmt [path] [flags]

    Uses embedded kcl fmt for .k files and embedded opa fmt for .rego files. Idempotent; safe to run in CI.

    Flags

    flagdescription
    --checkexit 1 if anything would change (CI gate); do not modify files
    --diffprint unified diff of changes without applying
    @@ -312,7 +312,7 @@

    Exit codes

    diff --git a/site/cli/help.html b/site/cli/help.html index a81523b9..13e1a7a4 100644 --- a/site/cli/help.html +++ b/site/cli/help.html @@ -3,12 +3,12 @@ -akua help — akua +akuapkg help — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / help

    -

    akua help

    +

    akuapkg / cli / help

    +

    akuapkg help

    akua help                    # list all verbs
    @@ -309,7 +309,7 @@ 

    akua help

    diff --git a/site/cli/index.html b/site/cli/index.html index e5ac23b2..2ea71352 100644 --- a/site/cli/index.html +++ b/site/cli/index.html @@ -292,20 +292,20 @@
    -

    akua / cli

    +

    akuapkg / cli

    CLI reference

    Every akua verb. Shipped verbs are wired and tested; planned verbs have a stable surface but no backing implementation yet.

    akua CLI reference

    Complete reference for the akua binary. Every verb, every subcommand, every flag.

    -

    For the universal contract every verb honors (JSON output, exit codes, idempotency, plan mode, timeouts), see cli-contract.md.

    -
    Status marker. Sections marked ✅ describe verbs available in the shipping binary. Sections marked 🚧 describe verbs from the target surface that aren't wired yet. If a verb isn't marked, assume 🚧. Shipped today (27 verbs): init · whoami · version · verify · render · add · vendor · dev · test · tree · pull · publish · sign · update · lock · push · repl · pack · remove · diff · check · inspect · lint · fmt · cache · auth · export Run akua --help at the command line for the authoritative live list.
    +

    For the universal contract every verb honors (JSON output, exit codes, idempotency, plan mode, timeouts), see cli-contract.md.

    +
    Status marker. Sections marked ✅ describe verbs available in the shipping binary. Sections marked 🚧 describe verbs from the target surface that aren't wired yet. If a verb isn't marked, assume 🚧. Shipped today (28 verbs): init · whoami · version · verify · render · add · vendor · dev · test · tree · pull · publish · sign · update · lock · push · repl · pack · remove · diff · check · inspect · lint · fmt · cache · auth · export · api Run akua --help at the command line for the authoritative live list.

    Top-level flags

    These flags are accepted by every verb:

    @@ -313,177 +313,182 @@

    Top-level flags

    Agent-context auto-detection

    When akua is run inside an AI-agent session, it detects this from env vars and auto-enables --json, --log=json, --no-color, --no-progress, and --no-interactive. Detection is keyed off AGENT=<name> (standard), CLAUDECODE, GEMINI_CLI, CURSOR_CLI, or AKUA_AGENT. Explicit flags always override detection.

    # Human shell — text output
    -$ akua render
    +$ akuapkg render
     [pretty text output]
     
     # Agent context — auto-JSON, no flag needed
    -$ CLAUDECODE=1 akua render
    +$ CLAUDECODE=1 akuapkg render
     {"format":"raw-manifests","target":"./deploy","manifests":3,"hash":"sha256:…"}
    -

    See cli-contract.md §1.5 for the full detection rules, override semantics, and env-var reference.

    +

    See cli-contract.md §1.5 for the full detection rules, override semantics, and env-var reference.


    Verb index

    AUTHOR              PUBLISH             DEPLOY              OPERATE
     ------              -------             ------              -------
    -akua init           akua attest         akua deploy         akua secret
    -akua add            akua publish        akua rollout        akua policy
    -akua vendor         akua pull           akua dev            akua audit
    -akua render         akua inspect                            akua query
    -akua diff           akua export                              akua infra
    +akuapkg init           akua attest         akua deploy         akua secret
    +akuapkg add            akuapkg publish        akua rollout        akua policy
    +akuapkg vendor         akuapkg pull           akuapkg dev            akua audit
    +akuapkg render         akuapkg inspect                            akua query
    +akuapkg diff           akuapkg export                              akua infra
     
     DEVELOP             SESSION             META
     -------             -------             ----
    -akua test           akua login          akua help
    -akua fmt            akua logout         akua version
    -akua lint           akua whoami         akua telemetry
    -akua check                              akua lint-cli
    +akuapkg test           akua login          akua help
    +akuapkg fmt            akua logout         akuapkg version
    +akuapkg lint           akuapkg whoami         akua telemetry
    +akuapkg check                              akuapkg api
    +                                        akuapkg lint-cli
     akua bench
     akua trace
     akua cov
    -akua repl
    +akuapkg repl
     akua eval
    -

    Thirty-four verbs. Grouped by purpose. Each covered below.

    -
    Quick disambiguation — render vs export vs inspect vs diff: | verb | takes | produces | invokes engines? | |---|---|---|---| | render | Package + inputs | deploy-ready manifests | yes | | export | any canonical artifact | format view (JSON Schema, YAML, OpenAPI, Rego bundle) | no | | inspect | a published package ref | audit report (schema, sources, signatures, attestation) | no | | diff | two package refs | structural diff between them | no | When in doubt: render = "run the program"; export = "convert the format"; inspect = "audit what's there"; diff = "compare two versions."
    +

    Thirty-five verbs. Grouped by purpose. Each covered below.

    +
    Quick disambiguation — render vs export vs inspect vs diff: | verb | takes | produces | invokes engines? | |---|---|---|---| | render | Package + inputs | deploy-ready manifests | yes | | export | any canonical artifact | format view (JSON Schema, YAML, OpenAPI, Rego bundle) | no | | inspect | local package.k or package tarball | package metadata and input surface | no | | diff | two package refs | structural diff between them | no | When in doubt: render = "run the program"; export = "convert the format"; inspect = "audit what's there"; diff = "compare two versions."

    -

    Shipped (15)

    • - akua init +

      Shipped (16)

      • + akuapkg init
        Scaffold a new package or workspace.
      • - akua add + akuapkg add
        Insert a dependency into `akua.toml`. Pure manifest edit — the resolver best-effortly updates `akua.lock` immediately after.
      • - akua vendor + akuapkg vendor
        Materialize and inspect the workspace vendor tree at `.akua/vendor/`.
      • - akua lint -
        Parse-only check of a `package.k` — catches syntax errors and import- resolution failures without executing the program. Runtime errors (schema validation, unresolved options, engine failures) surface through `akua render --dry-run`.
        + akuapkg lint +
        Parse-only check of a `package.k` — catches syntax errors and import- resolution failures without executing the program. Runtime errors (schema validation, unresolved options, engine failures) surface through `akuapkg render --dry-run`.
      • - akua render + akuapkg render
        **Run the Package's program.** Evaluate the KCL, invoke every source engine (Helm, kro, Kustomize), compose results, produce deploy-ready manifests.
      • - akua diff + akuapkg diff
        Structural diff between two package versions, or between a local package and a published version.
      • - akua inspect + akuapkg inspect
        Report a `package.k`'s input surface — every `option()` call-site with its name, declared type, required flag, default, and help text. Parse-only: the program is not executed.
      • - akua export + akuapkg export
        **Convert a Package's `Input` schema to a standard interchange format.** Emits JSON Schema 2020-12 (raw) or OpenAPI 3.1 (Input wrapped under `components.schemas`). Backed by KCL's resolver + AST walk; field docstrings become `description`,
      • - akua dev + akuapkg api +
        Call the hosted Akua API from the OSS CLI. This is an optional hosted extension: local package workflows such as `render`, `export`, `check`, `lint`, `test`, and `verify` do not require hosted API credentials or network access.
        +
      • +
      • + akuapkg dev
        Start the hot-reload development loop.
      • - akua whoami + akuapkg whoami
        Display current identity, logged-in registries, and scopes.
      • - akua fmt + akuapkg fmt
        Format KCL and Rego sources in place.
      • - akua check + akuapkg check
        Syntax + type + dependency check. No execution, no rendering. Fast.
      • - akua repl + akuapkg repl
        Interactive REPL for exploring policies and packages.
      • - akua version -
        ``` akua version # print version + git SHA akua version --json ```
        + akuapkg version +
        ``` akuapkg version # print version + git SHA akuapkg version --json ```
      • - akua lint-cli + akuapkg lint-cli
        Validate that the current binary honors the CLI contract.

      Planned (19)

    diff --git a/site/cli/infra.html b/site/cli/infra.html index aca3369e..0f42d06e 100644 --- a/site/cli/infra.html +++ b/site/cli/infra.html @@ -3,12 +3,12 @@ -akua infra — akua +akuapkg infra — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / infra

    -

    akua infra

    +

    akuapkg / cli / infra

    +

    akuapkg infra

    Cluster, network, DNS, cert primitives. Wraps Crossplane or Terraform under the hood.

    @@ -313,7 +313,7 @@

    Subcommands

    diff --git a/site/cli/init.html b/site/cli/init.html index b9923de2..27a2ae15 100644 --- a/site/cli/init.html +++ b/site/cli/init.html @@ -3,12 +3,12 @@ -akua init — akua +akuapkg init — akua - + @@ -292,22 +292,22 @@
    -

    akua / cli / init

    -

    akua init

    +

    akuapkg / cli / init

    +

    akuapkg init

    Scaffold a new package or workspace.

    -
    akua init [name] [flags]
    +
    akuapkg init [name] [flags]

    Creates a directory with:

    • package.k — typed KCL Package definition
    • inputs.example.yaml — sample input
    • .akua/ — metadata + lockfile location
    • README.md — minimal docs stub

    Flags

    -
    flagdescription
    --template=<name>use a template (see akua init --list-templates)
    --package-name=<name>name for the Package (defaults to directory name)
    --no-gitskip git init
    --list-templateslist available templates
    +
    flagdescription
    --template=<name>use a template (see akuapkg init --list-templates)
    --package-name=<name>name for the Package (defaults to directory name)
    --no-gitskip git init
    --list-templateslist available templates

    Templates

    • app — single-service app (default)
    • app-with-db — app + managed Postgres
    • umbrella — multi-service composition
    • platform-std — platform-team-published reusable package
    • empty — bare package.k with a minimal schema

    Exit codes

    @@ -322,7 +322,7 @@

    JSON output

    diff --git a/site/cli/inspect.html b/site/cli/inspect.html index a690405e..7e54dfe0 100644 --- a/site/cli/inspect.html +++ b/site/cli/inspect.html @@ -3,12 +3,12 @@ -akua inspect — akua +akuapkg inspect — akua - + @@ -292,18 +292,18 @@
    -

    akua / cli / inspect

    -

    akua inspect

    +

    akuapkg / cli / inspect

    +

    akuapkg inspect

    Report a package.k's input surface — every option() call-site with its name, declared type, required flag, default, and help text. Parse-only: the program is not executed.

    -
    akua inspect [flags]
    +
    akuapkg inspect [flags]

    Flags

    flagdescription
    --package=<path>path to the package.k file (default ./package.k)

    Exit codes

    @@ -319,11 +319,11 @@

    JSON output

    ] }

    Each option carries name, required, and optionally type, default, help when the KCL source supplies them. type is currently empty for the canonical input: Input = ctx.input() form — kcl_lang's list_options only reads a type arg passed directly to option(); full binding-context recovery arrives with AST walking.

    -
    Planned expansion (🚧). The target surface also audits a published OCI package — signatures, SLSA attestation chain, chart sources, rendered-manifest counts — via akua inspect <oci://…>. That depends on the OCI fetch pipeline (Phase B/C).
    +
    SDK-first OCI inspection. Published Akua Package inspection is available first through @akua-dev/sdk as inspectOciPackage(). The CLI target akuapkg inspect <oci://...> remains future work for full audit reports such as signatures, SLSA attestations, source provenance, and rendered-manifest counts.
    diff --git a/site/cli/lint-cli.html b/site/cli/lint-cli.html index ebe498be..0c1f65fc 100644 --- a/site/cli/lint-cli.html +++ b/site/cli/lint-cli.html @@ -3,12 +3,12 @@ -akua lint-cli — akua +akuapkg lint-cli — akua - + @@ -292,41 +292,41 @@
    -

    akua / cli / lint-cli

    -

    akua lint-cli

    +

    akuapkg / cli / lint-cli

    +

    akuapkg lint-cli

    Validate that the current binary honors the CLI contract.

    -
    akua lint-cli
    +
    akuapkg lint-cli

    Used in CI to catch contract violations before release.

    Environment variables

    A minimal set. No hidden state.

    akua-specific

    -
    varpurpose
    AKUA_REGISTRYdefault OCI registry for publish/pull
    AKUA_CACHE_DIRoverride cache location (default: $XDG_CACHE_HOME/akua)
    AKUA_LOG_LEVELoverride --log-level
    AKUA_NO_TELEMETRYforce telemetry off (for CI)
    AKUA_TOKEN_FILEpath to a token file for non-interactive auth
    AKUA_AGENTsignal an agent context explicitly (value is the agent name)
    AKUA_NO_AGENT_DETECTdisable agent-context auto-detection
    -

    All of these can be overridden by flags where a flag exists. Humans typically set nothing; agents typically set nothing (their environment already identifies them).

    +
    varpurpose
    AKUA_REGISTRYdefault OCI registry for publish/pull
    AKUA_CACHE_DIRoverride cache location (default: $XDG_CACHE_HOME/akua)
    AKUA_LOG_LEVELoverride --log-level
    AKUA_NO_TELEMETRYforce telemetry off (for CI)
    AKUA_TOKEN_FILEpath to a token file for non-interactive auth
    AKUA_API_TOKENhosted API bearer token for akuapkg api
    AKUA_API_BASE_URLhosted API base URL for akuapkg api (default: https://api.akua.dev/v1/)
    AKUA_WORKSPACE_IDworkspace context sent by akuapkg api as akua-context
    AKUA_AGENTsignal an agent context explicitly (value is the agent name)
    AKUA_NO_AGENT_DETECTdisable agent-context auto-detection
    +

    All of these can be overridden by flags where a flag exists. Local package workflows typically need none of them. Hosted API calls need a bearer token from --token or AKUA_API_TOKEN.

    Agent-context env vars (detected, never written)

    These are set by agent runtimes, not by akua. akua reads them to determine whether it's running in an agent context.

    varset by
    AGENT=<name>Goose (goose), Amp (amp), Codex (codex), Cline (cline), OpenCode (opencode) — emerging standard
    CLAUDECODE=1Claude Code
    GEMINI_CLI=1Gemini CLI
    CURSOR_CLI=1Cursor CLI
    GOOSE_TERMINAL=1, AMP_THREAD_ID=<id>, CODEX_SANDBOX=<id>, CLINE_ACTIVE=truesecondary identifiers per agent — recorded as context
    -

    See cli-contract.md §1.5 for detection rules and precedence.

    +

    See cli-contract.md §1.5 for detection rules and precedence.

    Exit code reference (summary)

    -

    From cli-contract.md:

    +

    From cli-contract.md:

    codemeaning
    0success
    1user error
    2system error
    3policy deny
    4rate limited
    5needs approval
    6timeout

    Stability and versioning

    • Pre-v1.0: breaking changes require a minor version bump + changelog entry.
    • v1.0 onward: flag removal requires 6-month deprecation; exit code semantics never change.
    • JSON output keys are part of the stability contract.
    • New verbs can be added without bumping major.

    What's not in this reference

    - +

    Spec cross-references

    - +
    diff --git a/site/cli/lint.html b/site/cli/lint.html index 825e4fce..4b1843ab 100644 --- a/site/cli/lint.html +++ b/site/cli/lint.html @@ -3,13 +3,13 @@ -akua lint — akua - +akuapkg lint — akua + - - + + @@ -292,18 +292,18 @@
    -

    akua / cli / lint

    -

    akua lint

    +

    akuapkg / cli / lint

    +

    akuapkg lint

    -

    Parse-only check of a package.k — catches syntax errors and import- resolution failures without executing the program. Runtime errors (schema validation, unresolved options, engine failures) surface through akua render --dry-run.

    -
    akua lint [flags]
    +

    Parse-only check of a package.k — catches syntax errors and import- resolution failures without executing the program. Runtime errors (schema validation, unresolved options, engine failures) surface through akuapkg render --dry-run.

    +
    akuapkg lint [flags]

    Flags

    flagdescription
    --package=<path>path to the package.k file (default ./package.k)

    Exit codes

    @@ -331,7 +331,7 @@

    JSON output

    diff --git a/site/cli/login.html b/site/cli/login.html index 017cea80..341739e8 100644 --- a/site/cli/login.html +++ b/site/cli/login.html @@ -3,12 +3,12 @@ -akua login — akua +akuapkg login — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / login

    -

    akua login

    +

    akuapkg / cli / login

    +

    akuapkg login

    Authenticate to OCI registries and signing providers.

    @@ -312,7 +312,7 @@

    Examples

    diff --git a/site/cli/logout.html b/site/cli/logout.html index aefe4f41..d425aac0 100644 --- a/site/cli/logout.html +++ b/site/cli/logout.html @@ -3,12 +3,12 @@ -akua logout — akua +akuapkg logout — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / logout

    -

    akua logout

    +

    akuapkg / cli / logout

    +

    akuapkg logout

    Remove stored credentials.

    @@ -308,7 +308,7 @@

    akua logout

    diff --git a/site/cli/policy.html b/site/cli/policy.html index 8848d8cc..b17fc55f 100644 --- a/site/cli/policy.html +++ b/site/cli/policy.html @@ -3,12 +3,12 @@ -akua policy — akua +akuapkg policy — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / policy

    -

    akua policy

    +

    akuapkg / cli / policy

    +

    akuapkg policy

    Policy tier operations.

    @@ -335,7 +335,7 @@

    JSON output (check)

    diff --git a/site/cli/publish.html b/site/cli/publish.html index 37ac272f..9e73eaf4 100644 --- a/site/cli/publish.html +++ b/site/cli/publish.html @@ -3,12 +3,12 @@ -akua publish — akua +akuapkg publish — akua - + @@ -292,18 +292,18 @@
    -

    akua / cli / publish

    -

    akua publish

    +

    akuapkg / cli / publish

    +

    akuapkg publish

    Push a signed package to an OCI registry.

    -
    akua publish [path] [flags]
    +
    akuapkg publish [path] [flags]

    Flags

    flagdescription
    --to=<oci-ref>destination (default: [package].spec.publish.default)
    --tag=<tag>tag (default: [package].version)
    --signsign with configured cosign key (default: on if logged in)
    --attestemit and attach SLSA predicate (default: on)
    --publicmark as public (required for ghcr public visibility)

    Exit codes

    @@ -321,7 +321,7 @@

    JSON output

    diff --git a/site/cli/pull.html b/site/cli/pull.html index 6cb013b7..81e79735 100644 --- a/site/cli/pull.html +++ b/site/cli/pull.html @@ -3,12 +3,12 @@ -akua pull — akua +akuapkg pull — akua - + @@ -292,24 +292,24 @@
    -

    akua / cli / pull

    -

    akua pull

    +

    akuapkg / cli / pull

    +

    akuapkg pull

    Fetch a package from an OCI registry into the local cache.

    -
    akua pull <ref> [flags]
    +
    akuapkg pull <ref> [flags]

    Flags

    flagdescription
    --verifyverify cosign signature (default: on)
    --unpack=<dir>unpack to directory instead of caching
    --insecureallow unsigned / unverifiable (dangerous)
    diff --git a/site/cli/query.html b/site/cli/query.html index bb790cad..b278efa4 100644 --- a/site/cli/query.html +++ b/site/cli/query.html @@ -3,12 +3,12 @@ -akua query — akua +akuapkg query — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / query

    -

    akua query

    +

    akuapkg / cli / query

    +

    akuapkg query

    Structured queries against observability stores.

    @@ -322,7 +322,7 @@

    Example

    diff --git a/site/cli/render.html b/site/cli/render.html index 4a61e1d1..77872a96 100644 --- a/site/cli/render.html +++ b/site/cli/render.html @@ -3,12 +3,12 @@ -akua render — akua +akuapkg render — akua - + @@ -292,23 +292,23 @@
    -

    akua / cli / render

    -

    akua render

    +

    akuapkg / cli / render

    +

    akuapkg render

    Run the Package's program. Evaluate the KCL, invoke every source engine (Helm, kro, Kustomize), compose results, produce deploy-ready manifests.

    -
    akua render [path] [flags]
    -

    Discovery. With no path, renders every user-authored document in the workspace whose schema declares render semantics — typically the workspace's App-shaped documents that reference a Package and carry inputs. With a path, renders only that file. Users author their own App / Environment / etc. schemas (akua does not specify them; see package-format.md); render processes whichever documents the workspace declares as renderable.

    -
    Not the same as akua export. render executes the full pipeline against customer inputs and writes manifests a reconciler applies to a cluster. export converts a canonical artifact (schema, user-authored KCL document, policy bundle) into a format view (JSON Schema, YAML, OpenAPI, Rego bundle). Render needs inputs; export usually doesn't. Render invokes engines; export is format translation. See akua export below.
    +
    akuapkg render [path] [flags]
    +

    Discovery. With no path, renders every user-authored document in the workspace whose schema declares render semantics — typically the workspace's App-shaped documents that reference a Package and carry inputs. With a path, renders only that file. Users author their own App / Environment / etc. schemas (akua does not specify them; see package-format.md); render processes whichever documents the workspace declares as renderable.

    +
    Not the same as akuapkg export. render executes the full pipeline against customer inputs and writes manifests a reconciler applies to a cluster. export converts a canonical artifact (schema, user-authored KCL document, policy bundle) into a format view (JSON Schema, YAML, OpenAPI, Rego bundle). Render needs inputs; export usually doesn't. Render invokes engines; export is format translation. See akuapkg export below.

    Flags

    flagdescription
    --package=<path>path to the package.k file (default ./package.k)
    --inputs=<file>inputs file (JSON or YAML). When omitted, probes ./inputs.yaml then ./inputs.example.yaml next to the package; falls back to schema defaults if neither exists
    --out=<dir>write to directory (default: ./deploy/)
    --stdoutprint rendered manifests as multi-doc YAML to stdout instead of writing files
    --dry-runrender but don't write files
    -
    Engines. Helm and Akua-package composition reach the user via alias-method calls — webapp.template(webapp.TemplateOpts{values = webapp.Values{...}}), upstream.render(upstream.Input{...}) — synthesized per dep from akua.toml. Kustomize stays engine-direct (kustomize.build({path = "./overlays"})) because its input is a within-Package directory, not a typed dep. All backends ship as embedded WASM modules; akua never shells out to helm or kustomize binaries — every engine runs inside the wasmtime sandbox alongside the render worker. See docs/security-model.md and docs/embedded-engines.md. One render output. akua writes raw YAML manifests, one file per resource. Distribution shapes like Helm charts or OCI bundles are future akua publish --as <format> concerns — they wrap rendered manifests at distribution time, not as a Package-declared output.
    +
    Engines. Helm and Akua-package composition reach the user via alias-method calls — webapp.template(webapp.TemplateOpts{values = webapp.Values{...}}), upstream.render(upstream.Input{...}) — synthesized per dep from akua.toml. Kustomize stays engine-direct (kustomize.build({path = "./overlays"})) because its input is a within-Package directory, not a typed dep. All backends ship as embedded WASM modules; akua never shells out to helm or kustomize binaries — every engine runs inside the wasmtime sandbox alongside the render worker. See docs/security-model.md and docs/embedded-engines.md. One render output. akua writes raw YAML manifests, one file per resource. Distribution shapes like Helm charts or OCI bundles are future akuapkg publish --as <format> concerns — they wrap rendered manifests at distribution time, not as a Package-declared output.

    Exit codes

    0 success, 1 user error, 2 system error. (Phase B adds 3 for policy deny.)

    JSON output

    @@ -319,11 +319,11 @@

    JSON output

    "hash": "sha256:…", "files": ["000-configmap-hello.yaml"] } -

    format is always "raw-manifests" today. target is the resolved output directory. hash is sha256:<hex> of the concatenated <filename>\n<yaml> blocks — stable across runs when inputs + lockfile + akua version match.

    +

    format is always "raw-manifests" today. target is the resolved output directory. hash is sha256:<hex> of the concatenated <filename>\n<yaml> blocks — stable across runs when inputs + lockfile + akuapkg version match.

    diff --git a/site/cli/repl.html b/site/cli/repl.html index 045aa83c..e5f21bb7 100644 --- a/site/cli/repl.html +++ b/site/cli/repl.html @@ -3,12 +3,12 @@ -akua repl — akua +akuapkg repl — akua - + @@ -292,25 +292,25 @@
    -

    akua / cli / repl

    -

    akua repl

    +

    akuapkg / cli / repl

    +

    akuapkg repl

    Interactive REPL for exploring policies and packages.

    -
    akua repl [flags]
    +
    akuapkg repl [flags]

    Supports two modes (tab-switched):

    • Rego mode — runs against the current policy set; evaluates expressions, shows trace, imports any data.akua.policies.*
    • KCL mode — runs against the current package; evaluates expressions, shows schema types, hot-imports modules

    Useful for experimenting before committing to a rule or package change.

    diff --git a/site/cli/rollout.html b/site/cli/rollout.html index 2d12912e..53f6a3de 100644 --- a/site/cli/rollout.html +++ b/site/cli/rollout.html @@ -3,12 +3,12 @@ -akua rollout — akua +akuapkg rollout — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / rollout

    -

    akua rollout

    +

    akuapkg / cli / rollout

    +

    akuapkg rollout

    Cross-repo / cross-service staged rollout orchestration.

    @@ -317,7 +317,7 @@

    Flags

    diff --git a/site/cli/secret.html b/site/cli/secret.html index 2fa54351..814156d5 100644 --- a/site/cli/secret.html +++ b/site/cli/secret.html @@ -3,12 +3,12 @@ -akua secret — akua +akuapkg secret — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / secret

    -

    akua secret

    +

    akuapkg / cli / secret

    +

    akuapkg secret

    Typed secret operations. Secrets move as refs, never raw bytes.

    @@ -331,7 +331,7 @@

    JSON output (trace)

    diff --git a/site/cli/telemetry.html b/site/cli/telemetry.html index b6544e29..9ae3c341 100644 --- a/site/cli/telemetry.html +++ b/site/cli/telemetry.html @@ -3,12 +3,12 @@ -akua telemetry — akua +akuapkg telemetry — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / telemetry

    -

    akua telemetry

    +

    akuapkg / cli / telemetry

    +

    akuapkg telemetry

    Opt-in, anonymized usage data.

    @@ -311,7 +311,7 @@

    akua telemetry

    diff --git a/site/cli/test.html b/site/cli/test.html index d1116393..da1e3112 100644 --- a/site/cli/test.html +++ b/site/cli/test.html @@ -3,12 +3,12 @@ -akua test — akua +akuapkg test — akua - + @@ -292,22 +292,22 @@
    -

    akua / cli / test

    -

    akua test

    +

    akuapkg / cli / test

    +

    akuapkg test

    Run unit tests for packages, policies, or both. Unified test runner across engines — detects target types by file extension.

    -
    akua test [path] [flags]
    +
    akuapkg test [path] [flags]

    Discovers and runs:

    • **/*_test.rego — Rego policy tests via embedded OPA
    • **/_test.k / test_.k — KCL test files via embedded KCL
    • Kyverno test.yaml bundle tests (when the bundle is imported)
    • Golden-output tests (*.golden.yaml compared against current render)

    Flags

    -
    flagdescription
    --coverageemit per-rule / per-schema coverage report
    --watchre-run on file change
    --goldenenable / verify golden-output comparisons
    --filter=<regex>run only matching tests
    --timeout=<dur>per-test timeout (default 30s)
    `--engine=<auto\embedded\shell>`engine selection (see embedded-engines.md)
    +
    flagdescription
    --coverageemit per-rule / per-schema coverage report
    --watchre-run on file change
    --goldenenable / verify golden-output comparisons
    --filter=<regex>run only matching tests
    --timeout=<dur>per-test timeout (default 30s)
    `--engine=<auto\embedded\shell>`engine selection (see embedded-engines.md)

    Exit codes

    0 if all pass, 1 if any fail, 2 on infrastructure error.

    JSON output

    @@ -333,7 +333,7 @@

    JSON output

    diff --git a/site/cli/trace.html b/site/cli/trace.html index f8f22f60..930d6212 100644 --- a/site/cli/trace.html +++ b/site/cli/trace.html @@ -3,12 +3,12 @@ -akua trace — akua +akuapkg trace — akua - + @@ -292,14 +292,14 @@
    -

    akua / cli / trace

    -

    akua trace

    +

    akuapkg / cli / trace

    +

    akuapkg trace

    Explain the evaluation path of a policy query. Useful for debugging "why did this rule deny?" or "why didn't this rule fire?"

    @@ -317,7 +317,7 @@

    Example

    diff --git a/site/cli/vendor.html b/site/cli/vendor.html index f63ffc1a..d70512ad 100644 --- a/site/cli/vendor.html +++ b/site/cli/vendor.html @@ -3,12 +3,12 @@ -akua vendor — akua +akuapkg vendor — akua - + @@ -292,23 +292,23 @@
    -

    akua / cli / vendor

    -

    akua vendor

    +

    akuapkg / cli / vendor

    +

    akuapkg vendor

    Materialize and inspect the workspace vendor tree at .akua/vendor/.

    -
    akua vendor <subcommand> [flags]
    +
    akuapkg vendor <subcommand> [flags]

    Subcommands:

    -
    • add <name> — copy the declared dependency into .akua/vendor/<name>/ and pin its digest in akua.lock. The dependency must already exist in [dependencies]; otherwise the command fails with a suggestion to declare it in akua.toml. Works for path, oci, git, and helm (repo) deps alike — the resolver's vendor-first lookup is universal across all four source kinds, so once added, the canonical source can be deleted and akua render still succeeds via the vendored bytes.
    • check — compare the on-disk vendor trees against akua.toml + akua.lock. Drift exits with code 1.
    • list — enumerate on-disk vendor trees, including orphaned entries.
    +
    • add <name> — copy the declared dependency into .akua/vendor/<name>/ and pin its digest in akua.lock. The dependency must already exist in [dependencies]; otherwise the command fails with a suggestion to declare it in akua.toml. Works for path, oci, git, and helm (repo) deps alike — the resolver's vendor-first lookup is universal across all four source kinds, so once added, the canonical source can be deleted and akuapkg render still succeeds via the vendored bytes.
    • check — compare the on-disk vendor trees against akua.toml + akua.lock. Drift exits with code 1.
    • list — enumerate on-disk vendor trees, including orphaned entries.

    add honors the universal write-contract flags: --plan, --timeout, and --idempotency-key. check and list are read-only.

    Auth flags (private git remotes)

    -

    vendor add accepts credentials at the call site for fetching private git deps. Akua never reads ambient credential files (~/.netrc, ~/.docker/config.json, env vars) — the SDK and CLI surface are the only auth sources. See E_MANIFEST_GIT_USERINFO for why credentials in akua.toml URLs are rejected.

    +

    vendor add accepts credentials at the call site for fetching private git deps. Akua never reads ambient credential files (~/.netrc, ~/.docker/config.json, env vars) — the SDK and CLI surface are the only auth sources. See E_MANIFEST_GIT_USERINFO for why credentials in akua.toml URLs are rejected.

    flagdescription
    --auth <prefix>=<user>:<password>Repeatable. Credential for a private git remote, keyed by URL prefix. The prefix is matched longest-first against the dep's URL — same rule git's credential helper uses. Example: --auth akua-git.cnap.tech/org-A=org-A:token.
    --auth-file <path>TOML file with a [auth] table keyed by URL prefix. --auth flags override file entries on conflict. The path must be explicit; akua never auto-discovers credential files.

    --auth-file shape:

    [auth]
    @@ -321,7 +321,7 @@ 

    Git HTTPS trust

    diff --git a/site/cli/version.html b/site/cli/version.html index 7c5c2be5..a3b397f9 100644 --- a/site/cli/version.html +++ b/site/cli/version.html @@ -3,13 +3,13 @@ -akua version — akua - +akuapkg version — akua + - - + + @@ -292,18 +292,18 @@
    -

    akua / cli / version

    -

    akua version

    +

    akuapkg / cli / version

    +

    akuapkg version

    -
    akua version                 # print version + git SHA
    -akua version --json
    +
    akuapkg version                 # print version + git SHA
    +akuapkg version --json
    {
       "version": "0.1.0",
       "commit": "abc123",
    @@ -315,7 +315,7 @@ 

    akua version

    diff --git a/site/cli/whoami.html b/site/cli/whoami.html index d37aa247..9937ba8d 100644 --- a/site/cli/whoami.html +++ b/site/cli/whoami.html @@ -3,12 +3,12 @@ -akua whoami — akua +akuapkg whoami — akua - + @@ -292,18 +292,18 @@
    -

    akua / cli / whoami

    -

    akua whoami

    +

    akuapkg / cli / whoami

    +

    akuapkg whoami

    Display current identity, logged-in registries, and scopes.

    -
    akua whoami [flags]
    +
    akuapkg whoami [flags]

    JSON output

    {
       "identity": "user@example.com",
    @@ -318,11 +318,11 @@ 

    JSON output

    "source_env": "CLAUDECODE" } }
    -

    agent_context is present when akua auto-detected an agent session (see cli-contract.md §1.5). When no agent is detected, the field is {"detected": false}.

    +

    agent_context is present when akua auto-detected an agent session (see cli-contract.md §1.5). When no agent is detected, the field is {"detected": false}.

    diff --git a/site/concepts/agent-usage.html b/site/concepts/agent-usage.html index a7c46125..487bf3c2 100644 --- a/site/concepts/agent-usage.html +++ b/site/concepts/agent-usage.html @@ -304,7 +304,7 @@

    Agent usage

    akua is designed agent-first. This doc covers how agents discover akua's capabilities, what ships out of the box, and why the architecture is the way it is.


    The short version

    -
    • akua auto-detects agent sessions from standard env vars (AGENT=…, CLAUDECODE=1, etc.) and silently enables JSON output, structured errors, no-interactive, no-color. See cli-contract.md §1.5.
    • The akua CLI surface follows a strict contract (JSON-first, typed exit codes, idempotent writes, plan mode, time-bounded) — the CLI is the agent API. See cli-contract.md.
    • Agent-ready workflows ship as skills in skills/ following the open Agent Skills Specification. Install them into Claude Code, Cursor, Codex, Gemini CLI, Goose, Amp, OpenCode, or any of the 35+ supported agents.
    • No MCP server. Shell + skills is structurally more efficient than MCP for operational tools (token cost, composability).
    +
    • akua auto-detects agent sessions from standard env vars (AGENT=…, CLAUDECODE=1, etc.) and silently enables JSON output, structured errors, no-interactive, no-color. See cli-contract.md §1.5.
    • The akua CLI surface follows a strict contract (JSON-first, typed exit codes, idempotent writes, plan mode, time-bounded) — the CLI is the agent API. See cli-contract.md.
    • Agent-ready workflows ship as skills in skills/ following the open Agent Skills Specification. Install them into Claude Code, Cursor, Codex, Gemini CLI, Goose, Amp, OpenCode, or any of the 35+ supported agents.
    • No MCP server. Shell + skills is structurally more efficient than MCP for operational tools (token cost, composability).

    Why no MCP server?

    MCP tool definitions consume 30k–90k tokens of agent context per connection before any reasoning starts. For a CLI with 20 verbs and 100+ subcommands, that's catastrophic.

    @@ -316,7 +316,7 @@

    How akua auto-detects agent context

    At process start, akua checks environment variables in this order:

    env varagent
    AGENT=<name>Goose, Amp, Codex, Cline, OpenCode (standard)
    CLAUDECODE=1Claude Code
    GEMINI_CLI=1Gemini CLI
    CURSOR_CLI=1Cursor CLI
    AKUA_AGENT=<name>akua-specific fallback

    If any matches, akua silently enables --json, --log=json, --no-color, --no-progress, --no-interactive. Explicit flags always win (user can force text output with --no-json or --format=text).

    -

    No stderr announcement. No prelude on stdout. Detection is observable via akua whoami --json (reveals the agent_context field) or at --log-level=debug. Otherwise invisible.

    +

    No stderr announcement. No prelude on stdout. Detection is observable via akuapkg whoami --json (reveals the agent_context field) or at --log-level=debug. Otherwise invisible.


    How to install akua skills into your agent

    Claude Code

    @@ -324,7 +324,7 @@

    Claude Code

    cp -r path/to/akua/skills/* ~/.claude/skills/

    OpenAI Codex

    Install via the Codex skills manager:

    -
    codex skills install github:cnap-tech/akua/skills
    +
    codex skills install github:akua-dev/akua/skills

    Cursor

    Add skills/ to Cursor's skill paths in .cursor/config.json:

    { "skills": { "paths": ["./skills"] } }
    @@ -333,16 +333,16 @@

    Gemini CLI

    gemini extensions install @akua/skills

    Goose, Amp, OpenCode, Cline, Roo Code, Amp, Command Code, Kiro, Factory, and 25+ others

    All support the open Agent Skills Specification. Any of:

    -
    • Symlink skills/ into the agent's expected location
    • Use npx skills install github:cnap-tech/akua/skills
    • Follow each agent's skill-installation instructions (linked from agentskills.io/overview)
    +
    • Symlink skills/ into the agent's expected location
    • Use npx skills install github:akua-dev/akua/skills
    • Follow each agent's skill-installation instructions (linked from agentskills.io/overview)

    Universal: npx skills

    The Vercel Labs skills manager works across all Agent Skills compatible agents:

    -
    npx skills install github:cnap-tech/akua/skills
    +
    npx skills install github:akua-dev/akua/skills
     npx skills list
     npx skills remove akua-*

    Shipped skills

    -

    Eight initial skills covering the most common akua workflows. See skills/ for details.

    -
    skilluse when
    new-packageuser wants to start a new akua Package
    inspect-packageauditing a third-party Package before use
    diff-gatesetting up CI to block breaking upgrades
    dev-loopiterating on a Package with hot-reload
    migrate-helmfileconverting Helmfile to akua
    rotate-secretrotating a shared secret across installs
    publish-signedreleasing a signed + attested Package
    apply-policy-tiersubscribing to a compliance / production tier
    +

    Eight initial skills covering the most common akua workflows. See skills/ for details.

    +
    skilluse when
    new-packageuser wants to start a new akua Package
    inspect-packageauditing a third-party Package before use
    diff-gatesetting up CI to block breaking upgrades
    dev-loopiterating on a Package with hot-reload
    migrate-helmfileconverting Helmfile to akua
    rotate-secretrotating a shared secret across installs
    publish-signedreleasing a signed + attested Package
    apply-policy-tiersubscribing to a compliance / production tier

    Writing your own skill

    Follow the spec:

    @@ -362,7 +362,7 @@

    Writing your own skill

    Step-by-step instructions...

    Validation: npx skills-ref validate ./skills/my-skill

    Good descriptions include trigger keywords agents would recognize. Agents load metadata for all skills (~100 tokens each) at startup; they load the full body only when they decide a skill applies.

    -

    See the shipped skills for canonical examples.

    +

    See the shipped skills for canonical examples.


    Running agents against akua — example loop

    agent receives user intent:
    @@ -375,13 +375,13 @@ 

    Running agents against akua now has full procedure for scaffolding + adding sources agent executes: - $ akua add chart oci://ghcr.io/bitnami/charts/redis --version 21.0.0 + $ akuapkg add chart oci://ghcr.io/bitnami/charts/redis --version 21.0.0 $ edit package.k to wire redis values to existing schema - $ akua lint - $ akua render --inputs inputs.yaml --out ./rendered + $ akuapkg lint + $ akuapkg render --inputs inputs.yaml --out ./rendered agent verifies: - $ akua diff previous:v1.2 ./rendered --json + $ akuapkg diff previous:v1.2 ./rendered --json (structural diff shows: new source redis, new schema field redis.replicas) agent commits + opens PR: @@ -389,7 +389,7 @@

    Running agents against akua $ gh pr create CI runs: - akua lint + diff-gate + policy check → attached to PR as comments + akuapkg lint + diff-gate + policy check → attached to PR as comments human reviews + approves + merges @@ -397,11 +397,11 @@

    Running agents against akua

    The whole loop: ~300 tokens of agent context for metadata, ~1000-2000 for the activated skill, plus primary task context. No MCP, no separate protocol, no magic — shell + git + markdown.


    - + diff --git a/site/concepts/cli-contract.html b/site/concepts/cli-contract.html index eebc35e1..398483e7 100644 --- a/site/concepts/cli-contract.html +++ b/site/concepts/cli-contract.html @@ -307,8 +307,8 @@

    CLI contract

    1. Output

    1.1 --json is universal

    Every verb accepts --json and emits a single, parseable JSON document (or JSON-lines stream for long-running commands) to stdout. No exceptions.

    -
    akua render --json
    -akua diff a b --json
    +
    akuapkg render --json
    +akuapkg diff a b --json
     akua deploy status --handle=r-4f2 --json

    Without --json, verbs emit human-readable text to stdout. With --json, they emit structured data agents can parse.

    1.2 Structured errors on stderr

    @@ -329,11 +329,11 @@

    1.5 Agent context auto-detection

    What auto-enables when an agent is detected:

    • --json output (equivalent to passing the flag explicitly)
    • --log=json (structured logs to stderr)
    • --no-color (colors off; implicit under --json anyway)
    • --no-progress (no spinners, no animated output)
    • --no-interactive (prompts fail fast with exit code 1 and a clear error instead of blocking on stdin)

    Override semantics (explicit always wins):

    -
    invocationresult
    akua render --json in a human shellJSON — flag wins
    akua render --no-json in an agent contexttext — explicit opt-out wins
    akua render --format=text in an agent contexttext — explicit override wins
    akua render in a human shelltext — default
    akua render in an agent contextJSON — auto-detected
    +
    invocationresult
    akuapkg render --json in a human shellJSON — flag wins
    akuapkg render --no-json in an agent contexttext — explicit opt-out wins
    akuapkg render --format=text in an agent contexttext — explicit override wins
    akuapkg render in a human shelltext — default
    akuapkg render in an agent contextJSON — auto-detected

    No signal, by design.

    When detection activates, akua adapts behavior silently. No banner. No stderr announcement. No prelude on stdout. The behavior change is observable from the output itself (JSON vs text); agents that set CLAUDECODE=1 or AGENT=goose already know they're in an agent context — akua repeating it back is noise.

    Detection is introspectable when needed:

    -
    • akua whoami --json includes an agent_context field with the detected agent name and source env var.
    • --log-level=debug emits a single agent_context_detected event in debug logs — useful for post-hoc diagnosis, silent in normal operation.
    +
    • akuapkg whoami --json includes an agent_context field with the detected agent name and source env var.
    • --log-level=debug emits a single agent_context_detected event in debug logs — useful for post-hoc diagnosis, silent in normal operation.

    Otherwise: invisible by default, discoverable on demand. That's the discipline.

    Opt-out:

    • AKUA_NO_AGENT_DETECT=1 — disable detection globally (useful for testing human-like output in an agent context, or for CI systems that happen to set agent env vars).
    • --no-agent-mode — per-invocation override.
    @@ -350,7 +350,7 @@

    2. Exit codes


    3. Writes are idempotent

    Every verb that modifies state accepts --idempotency-key=<uuid>. If the same key is seen twice on the same resource with the same intent, the second call is a no-op and returns the original result.

    -
    • akua deploy --idempotency-key=<k> — safe to retry
    • akua publish --idempotency-key=<k> — duplicate publish returns the original digest
    • akua secret rotate --idempotency-key=<k> — rotating with the same key is idempotent
    +
    • akua deploy --idempotency-key=<k> — safe to retry
    • akuapkg publish --idempotency-key=<k> — duplicate publish returns the original digest
    • akua secret rotate --idempotency-key=<k> — rotating with the same key is idempotent

    Agents generate fresh UUIDs per logical operation and retry on network errors without risk.


    4. Plan mode

    @@ -363,7 +363,7 @@

    4. Plan mode

    5. Time bounds

    Every verb that blocks on network or reconciliation accepts --timeout=<duration> (Go duration format: 30s, 5m, 1h, 250ms). Verbs never hang indefinitely.

    • Default timeout is verb-specific but never more than 5 minutes.
    • --timeout=0 means "return immediately with current state" (for status-read ops).
    • Timeouts exit with code 6.
    • Invalid duration strings (5min, 2 hours, raw integers) fail at parse time with code=E_INVALID_FLAG. Accepted units: ns, us / µs, ms, s, m, h.
    -

    akua render additionally honors --max-depth=<N> to cap the pkg.render composition chain (default 16). Hitting the cap fails with E_RENDER_BUDGET_DEPTH. Pair with --timeout for hardened CI / agent runs.

    +

    akuapkg render additionally honors --max-depth=<N> to cap the pkg.render composition chain (default 16). Hitting the cap fails with E_RENDER_BUDGET_DEPTH. Pair with --timeout for hardened CI / agent runs.

    Async operations (deploy, rollout, long-running renders) return an opaque handle immediately; use akua … wait --handle=<h> to block.


    6. Stable identifiers

    @@ -383,7 +383,7 @@

    7.3 akua <verb> --describe -

    Same data as akua help --json filtered to one verb. Useful for targeted introspection.


    8. Authentication

    -
    • akua login <registry> authenticates to an OCI registry. Credentials are stored in the system credential store (Keychain on macOS, libsecret on Linux, Credential Manager on Windows).
    • No plaintext credentials in config files.
    • akua whoami returns the current identity, scopes, and registry logins.
    • Tokens can be scoped per-registry; agents receive per-task scoped tokens that expire automatically.
    +
    • akua login <registry> authenticates to an OCI registry. Credentials are stored in the system credential store (Keychain on macOS, libsecret on Linux, Credential Manager on Windows).
    • No plaintext credentials in config files.
    • akuapkg whoami returns the current identity, scopes, and registry logins.
    • Tokens can be scoped per-registry; agents receive per-task scoped tokens that expire automatically.

    9. Logging

    • Default: human-readable text to stderr.
    • --log=json — JSON-lines to stderr; auto-enabled in agent context.
    • --log-level=<debug|info|warn|error> — filter; only applies to akua targets, transitive crates stay at warn.
    • -v / --verbose — shorthand for --log-level=debug.
    • Logs are separate from output. Output is the return value of the command; logs are observability.
    @@ -424,14 +424,14 @@

    14. What the contract is NOT


    15. Enforcement

    Every PR adding a verb or flag is reviewed against this contract. The CI lint step includes:

    -
    • akua lint-cli — checks every verb emits --json, has typed exit codes, accepts --timeout, passes --describe --json round-trip.
    • Contract violations block merge.
    • Contract amendments require RFC.
    +
    • akuapkg lint-cli — checks every verb emits --json, has typed exit codes, accepts --timeout, passes --describe --json round-trip.
    • Contract violations block merge.
    • Contract amendments require RFC.

    This contract is the single thing that makes akua agent-friendly. The narrow verb surface, the typed exits, the structured JSON, the idempotency keys, the plan mode — each is a deliberate choice, each is load-bearing, each must hold for every verb.

    When in doubt: obey the contract first, add the feature second. A feature that requires violating the contract is either a missing primitive (add it generically to the contract) or not worth shipping.

    diff --git a/site/concepts/debugging.html b/site/concepts/debugging.html index 7e81ce71..919771ea 100644 --- a/site/concepts/debugging.html +++ b/site/concepts/debugging.html @@ -303,11 +303,11 @@

    Debugging the render pipeline

    How to make the render pipeline cough up useful diagnostics when something goes wrong. This is the playbook the maintainer uses; agents should reach for it before guessing.

    TL;DR

    -
    akua render --package package.k --inputs ... --log=json --log-level=debug 2>&1 | head -20
    +
    akuapkg render --package package.k --inputs ... --log=json --log-level=debug 2>&1 | head -20

    Three knobs cover almost every case:

    knobwhat it adds
    --log=jsonstructured stderr lines you can jq over
    --log-level=debughost + worker spans, every plugin-bridge call
    RUST_LOG=...full EnvFilter syntax, lights up transitive crates

    Sources of truth

    -
    • CLI contract §9docs/cli-contract.md — flag semantics, JSON line shape, target taxonomy.
    • CLI contract §9.1 — OpenTelemetry env-var surface.
    • crates/akua-cli/src/observability.rs — host-side subscriber wiring.
    • crates/akua-render-worker/src/observability.rs — worker-side subscriber.
    +
    • CLI contract §9docs/cli-contract.md — flag semantics, JSON line shape, target taxonomy.
    • CLI contract §9.1 — OpenTelemetry env-var surface.
    • crates/akuapkg-cli/src/observability.rs — host-side subscriber wiring.
    • crates/akua-render-worker/src/observability.rs — worker-side subscriber.

    What you'll see

    Successful render at --log-level=debug:

    {"level":"DEBUG","fields":{"message":"worker.invoke.start"},"target":"akua","span":{...,"name":"worker.invoke"}}
    @@ -326,7 +326,7 @@ 

    When wasmtime traps

    Frame names + file:line resolve via:

    • Config::wasm_backtrace_details(Enable) + Config::generate_address_map(true) in engine_host_wasm::shared_config. Backtrace capture itself is on by default in wasmtime 43.
    • The worker .wasm's name section preserved by overriding the workspace [profile.release] strip via the task build:render-worker --config flags (see Taskfile.yml).

    If a trap shows bare wasm function NNNN:

    -
    1. The worker .wasm is stale or stripped — run task build:render-worker and verify the file size grew.
    2. The .cwasm AOT artifact may be cached — cargo clean -p akua-cli && cargo build -p akua-cli to force a re-bake against the current Config.
    +
    1. The worker .wasm is stale or stripped — run task build:render-worker and verify the file size grew.
    2. The .cwasm AOT artifact may be cached — cargo clean -p akuapkg-cli && cargo build -p akuapkg-cli to force a re-bake against the current Config.

    When a plugin handler fails

    KCL plugin calls (pkg.render, helm.template, kustomize.build) cross from inside-the-sandbox guest code to host functions. Failures look like:

    {"code":"E_RENDER_KCL","message":"plugin panic: pkg.render: <details>"}
    @@ -338,14 +338,14 @@

    Distinguishing host vs worker fa

    Replicating a failing render minimally

    If a render fails inside an example:

    cd examples/<name>
    -cargo run -q -p akua-cli -- render \
    +cargo run -q -p akuapkg-cli -- render \
         --package package.k \
         --inputs inputs.example.yaml \
         --log=json --log-level=debug 2>&1 | tail -30

    Tail (not head) grabs the failing event + envelope; head grabs the warm-up traffic. Pipe through jq -c 'select(.level=="ERROR" or .target=="akua::bridge")' to narrow to the salient lines.

    When the worker is the wrong version

    -

    A persistent gotcha: cargo build -p akua-cli does not rebuild the render-worker .wasm. The build script emits a warning when sources are newer than the staged .wasm:

    -
    warning: akua-cli@0.7.0: akua-render-worker.wasm is older than crates/akua-core/... — run `task build:render-worker`
    +

    A persistent gotcha: cargo build -p akuapkg-cli does not rebuild the render-worker .wasm. The build script emits a warning when sources are newer than the staged .wasm:

    +
    warning: akuapkg-cli@0.7.0: akua-render-worker.wasm is older than crates/akua-core/... — run `task build:render-worker`

    Rebuild explicitly:

    task build:render-worker

    Worker-side changes that need this:

    @@ -360,7 +360,7 @@

    OpenTelemetry export

    docker run --rm -p 4317:4317 -p 16686:16686 jaegertracing/all-in-one
     OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
       OTEL_SERVICE_NAME=akua-dev \
    -  cargo run -q -p akua-cli -- render --package examples/00-helm-hello/package.k
    + cargo run -q -p akuapkg-cli -- render --package examples/00-helm-hello/package.k

    The same trace tree (worker.invoke → bridge.call → kcl eval) shows up at http://localhost:16686. The OTel layer is gated on the otel cargo feature — on by default for the CLI binary, off for the napi distribution. cli-contract §9.1 lists every honored OTEL_* env var.

    Anti-patterns

    Things that don't work and aren't worth trying:

    @@ -368,7 +368,7 @@

    Anti-patterns

    diff --git a/site/concepts/embedded-engines.html b/site/concepts/embedded-engines.html index 75278d28..d0f36f8b 100644 --- a/site/concepts/embedded-engines.html +++ b/site/concepts/embedded-engines.html @@ -302,12 +302,12 @@

    Embedded engines

    How KCL, Helm, OPA, Regal, Kustomize, kro, and the Kyverno→Rego converter ship as wasip1 modules inside akua.

    akua bundles every engine it dispatches to — KCL, OPA (Rego), Kyverno, CEL, Helm, kro, Kustomize, Regal — into the akua binary itself. No $PATH dependencies. No helm or opa or kcl required to be installed separately. One binary, everything works out of the box.

    -

    This doc covers the embedding strategy, per-engine status, and what it means for agents and CI. No shell-out escape hatch anywhere in the render pipeline — see CLAUDE.md's "No shell-out, ever" invariant and security-model.md for the threat model.

    +

    This doc covers the embedding strategy, per-engine status, and what it means for agents and CI. No shell-out escape hatch anywhere in the render pipeline — see CLAUDE.md's "No shell-out, ever" invariant and security-model.md for the threat model.


    Why embed

    Three reasons, same as the helm-engine-wasm decision:

    1. Single binary UX. curl -fsSL https://cli.akua.dev/install | sh gives you everything. No "now install helm 4.1.4" followed by "now install opa 0.60" followed by "now install KCL 0.12."
    2. Version determinism. akua ships with a known-good engine version. No "works on my machine" where my opa is 0.55 and yours is 0.62 and we get different verdicts.
    3. Air-gap friendly. Environments where customers can't install arbitrary binaries (FedRAMP, certain enterprise networks) still work because akua is self-contained.
    -

    Plus the agent case: agents can't install binaries. If akua test needs opa and there's no opa in the sandbox, the agent is stuck. Embedded means the agent gets the full toolkit from one install.

    +

    Plus the agent case: agents can't install binaries. If akuapkg test needs opa and there's no opa in the sandbox, the agent is stuck. Embedded means the agent gets the full toolkit from one install.


    Embedding strategy

    Every engine reaches akua through the same architecture as helm-engine-wasm:

    @@ -327,20 +327,20 @@

    Embedding strategy

    typed FFI: Rust host ↔ WASM guest

    Shared Engine, many Stores. akua follows wasmtime's canonical pattern. One engine_host_wasm::shared_engine() singleton hosts:

    • the akua-render-worker (per-render Store with the tenant's preopens + memory cap + epoch deadline);
    • every engine plugin (helm, kustomize, future kro/CEL/kyverno) — each call gets its own Store on the same Engine.
    -

    Plugin callouts from sandboxed KCL cross the boundary once — through a single host-function import, env::kcl_plugin_invoke_json_wasm, that reads arguments from guest memory and dispatches to handlers registered against akua-core's plugin registry. The handler's engine Store runs, produces bytes, the bridge writes them back into the worker's linear memory. See docs/security-model.md — one Engine, many Stores — with a plugin bridge for the full picture + docs/spikes/wasmtime-multi-engine.md for the architecture decision.

    +

    Plugin callouts from sandboxed KCL cross the boundary once — through a single host-function import, env::kcl_plugin_invoke_json_wasm, that reads arguments from guest memory and dispatches to handlers registered against akua-core's plugin registry. The handler's engine Store runs, produces bytes, the bridge writes them back into the worker's linear memory. See docs/security-model.md — one Engine, many Stores — with a plugin bridge for the full picture + docs/spikes/wasmtime-multi-engine.md for the architecture decision.

    Precompilation: each engine's build.rs calls engine_host_wasm::precompile(...) against shared_config() at akua build time, producing a .cwasm deserialized in ~microseconds on first use.


    Engine inventory

    -
    enginesource languageembedding methodv0 status
    KCL (package authoring)Rust (kclvm-rs)direct linkshipped
    Helm v4 template engineGo → wasip1wasmtime-hostedshipped (forked to strip client-go; ~20 MB WASM)
    OPA (Rego)Go → wasip1 or OPA-native WASMwasmtime-hostedv0.2
    Regal (Rego linter)Go → wasip1wasmtime-hostedv0.2
    Kyverno-to-Rego converterGo → wasip1wasmtime-hosted; runs at akua add timev0.3
    CEL (cel-go)Go → wasip1wasmtime-hostedv0.3
    kustomizeGo → wasip1wasmtime-hostedv0.3
    kro RGD instantiatorGo → wasip1 (offline path)wasmtime-hostedv0.2
    +
    enginesource languageembedding methodv0 status
    KCL (package authoring)Rust (kclvm-rs)direct linkshipped
    Helm v4 template engineGo → wasip1wasmtime-hostedshipped (forked to strip client-go; ~20 MB WASM)
    OPA (Rego)Go → wasip1 or OPA-native WASMwasmtime-hostedv0.2
    Regal (Rego linter)Go → wasip1wasmtime-hostedv0.2
    Kyverno-to-Rego converterGo → wasip1wasmtime-hosted; runs at akuapkg add timev0.3
    CEL (cel-go)Go → wasip1wasmtime-hostedv0.3
    kustomizeGo → wasip1wasmtime-hostedv0.3
    kro RGD instantiatorGo → wasip1 (offline path)wasmtime-hostedv0.2

    All compiled to wasip1 where practical. When upstream projects ship optimized WASM artifacts (OPA has opa build -t wasm), we use theirs; otherwise we compile from source in our CI and ship the artifact with akua.

    Binary size impact per engine: KCL ~8 MB, Helm (stripped fork) ~20 MB, OPA (with Regal) ~15 MB, Kyverno converter ~18 MB, CEL ~5 MB, Kustomize ~12 MB, kro instantiator ~6 MB. Total overhead versus a bare akua: ~85 MB. We consider this acceptable for "everything just works" — same order of magnitude as Bun (~45 MB) or Deno (~110 MB).


    Per-verb engine routing

    -

    Each verb that invokes engines documents which ones. From cli.md:

    -
    verbengines used
    akua initKCL (scaffold)
    akua add(fetch/convert) Kyverno-to-Rego converter, KCL schema generator
    akua renderKCL + Helm + kro offline instantiator + Kustomize + output emitters
    akua lintKCL + Regal
    akua fmtKCL + opa fmt
    akua checkKCL + OPA (parse-only)
    akua testKCL + OPA
    akua traceOPA (--explain)
    akua benchOPA partial evaluation, KCL interpreter timing
    akua policy checkOPA + CEL (via Rego runtime)
    akua replKCL + OPA
    akua evalKCL or OPA per --lang
    akua attest(no engines; just signing + SLSA predicate generation)
    akua diffKCL + OPA (for policy compat diff)
    +

    Each verb that invokes engines documents which ones. From cli.md:

    +
    verbengines used
    akuapkg initKCL (scaffold)
    akuapkg add(fetch/convert) Kyverno-to-Rego converter, KCL schema generator
    akuapkg renderKCL + Helm + kro offline instantiator + Kustomize + output emitters
    akuapkg lintKCL + Regal
    akuapkg fmtKCL + opa fmt
    akuapkg checkKCL + OPA (parse-only)
    akuapkg testKCL + OPA
    akua traceOPA (--explain)
    akua benchOPA partial evaluation, KCL interpreter timing
    akua policy checkOPA + CEL (via Rego runtime)
    akuapkg replKCL + OPA
    akua evalKCL or OPA per --lang
    akua attest(no engines; just signing + SLSA predicate generation)
    akuapkg diffKCL + OPA (for policy compat diff)

    Determinism guarantees

    -
    • Embedded engines are version-pinned to the akua release. Two runs of akua render at the same akua version produce byte-identical output (the CLI contract §1.3).
    • An akua bundle lock manifest (forthcoming) will record the exact embedded engine versions for the workspace; akua bundle verify confirms a CI runner has the same akua version as the last known-good.
    +
    • Embedded engines are version-pinned to the akua release. Two runs of akuapkg render at the same akuapkg version produce byte-identical output (the CLI contract §1.3).
    • An akua bundle lock manifest (forthcoming) will record the exact embedded engine versions for the workspace; akua bundle verify confirms a CI runner has the same akuapkg version as the last known-good.

    Security posture

    Every embedded engine runs inside the wasmtime WASI sandbox:

    @@ -349,20 +349,20 @@

    Security posture

    System integrations are a separate category from engines. akua deploy calls kubectl (or similar) because it genuinely does need cluster access; those verbs live outside the render pipeline, and the binaries they invoke are external tools the user already trusts on their path. The render pipeline itself — everything that transforms inputs into deploy-ready artifacts — never shells out.


    What's NOT embedded

    -
    • kubectl — used only by akua deploy --to=kubectl. Too specific to a user's cluster context; we rely on the system version.
    • git — used for akua publish and workspace operations. Extremely stable and universally available.
    • cosign — used for signing. We embed the verification path (cryptographic primitives are in akua-core) but use cosign CLI for signing operations that need hardware keys.
    • docker / podman — used only if a user opts into a Dockerfile-based build. Rare for akua workflows.
    +
    • kubectl — used only by akua deploy --to=kubectl. Too specific to a user's cluster context; we rely on the system version.
    • git — used for akuapkg publish and workspace operations. Extremely stable and universally available.
    • cosign — used for signing. We embed the verification path (cryptographic primitives are in akua-core) but use cosign CLI for signing operations that need hardware keys.
    • docker / podman — used only if a user opts into a Dockerfile-based build. Rare for akua workflows.

    Performance notes

    -
    • Cold-start overhead for a wasmtime-hosted engine: ~5-30 ms per engine, once per akua invocation. With precompile cache: ~2-5 ms.
    • akua dev keeps engines warm for the session. Subsequent renders skip cold-start entirely.
    • Benchmarks at docs/bench/ (forthcoming) show akua's embedded OPA within 5% of native opa eval for realistic policy workloads.
    +
    • Cold-start overhead for a wasmtime-hosted engine: ~5-30 ms per engine, once per akua invocation. With precompile cache: ~2-5 ms.
    • akuapkg dev keeps engines warm for the session. Subsequent renders skip cold-start entirely.
    • Benchmarks at docs/bench/ (forthcoming) show akua's embedded OPA within 5% of native opa eval for realistic policy workloads.

    For agents

    -

    Agents get the full engine toolkit from one install with zero PATH management. When writing skills that invoke akua test, akua fmt, akua bench, they never need to check which opa. Skills remain portable across fresh sandboxes, CI runners, and developer laptops without setup instructions beyond curl -fsSL https://cli.akua.dev/install | sh.

    +

    Agents get the full engine toolkit from one install with zero PATH management. When writing skills that invoke akuapkg test, akuapkg fmt, akua bench, they never need to check which opa. Skills remain portable across fresh sandboxes, CI runners, and developer laptops without setup instructions beyond curl -fsSL https://cli.akua.dev/install | sh.


    Relationship to other docs

    - + diff --git a/site/concepts/index.html b/site/concepts/index.html index 3556a268..3e3734ed 100644 --- a/site/concepts/index.html +++ b/site/concepts/index.html @@ -336,7 +336,7 @@

    Concepts

    diff --git a/site/concepts/lockfile-format.html b/site/concepts/lockfile-format.html index 3f71ed2a..e2cc7924 100644 --- a/site/concepts/lockfile-format.html +++ b/site/concepts/lockfile-format.html @@ -307,7 +307,7 @@

    akua.toml + akua.lock


    Why two files

    Clear separation of concerns:

    -
    intentevidence
    fileakua.tomlakua.lock
    edited byhumanakua add / akua pull / akua publish / akua update
    shapesmall, stablemay be large; churns on every resolved-version change
    review focus"do we want this dep?""is this the expected digest + signature?"
    +
    intentevidence
    fileakua.tomlakua.lock
    edited byhumanakuapkg add / akuapkg pull / akuapkg publish / akuapkg update
    shapesmall, stablemay be large; churns on every resolved-version change
    review focus"do we want this dep?""is this the expected digest + signature?"

    A PR that modifies akua.lock but not akua.toml is automatically suspicious (someone changed what they got without changing what they asked for). CI can lint for this.

    Merged-lockfile alternatives (npm's package-lock.json, Cargo's Cargo.lock with deps embedded in Cargo.toml) bundle both concerns differently; we take Go's split (intent vs evidence in separate files) and Cargo's structured-TOML lockfile (so we can express a richer dep graph than go.sum's line-per-hash format).

    Naming

    @@ -357,7 +357,7 @@

    akua.lock

    Cargo.lock-flavored TOML: one [[package]] entry per resolved artifact, alphabetically ordered, with optional dependencies for the transitive graph.

    Format

    # akua.lock — machine-maintained. Never hand-edit.
    -# Regenerated by `akua add`, `akua pull`, `akua publish`, `akua update`.
    +# Regenerated by `akuapkg add`, `akuapkg pull`, `akuapkg publish`, `akuapkg update`.
     
     version = 1   # lockfile format version; bumped on incompatible changes
     
    @@ -385,7 +385,7 @@ 

    Format

    digest = "sha256:f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0" signature = "cosign:sigstore:bitnamicharts"

    Fields per [[package]]

    -
    fieldrequirednotes
    nameyesmatches the [dependencies] key in akua.toml
    versionyesexact resolved semver (not a range)
    sourceyesfull source ref: oci://…, git+https://…, path+file://…, or helm+<repo-url>#<chart>
    digestyescontent-addressable source hash: sha256: for OCI/path/helm-repo deps; git:<commit-sha> for git deps
    vendor_digestnosha256: hash of the vendored on-disk tree when it differs from digest; used by akua vendor check for git deps without losing the commit pin
    signatureconditionalcosign signature. Keyless: cosign:sigstore:<issuer>. Keyed: cosign:key:<identity>. Required unless [package].strictSigning = false in akua.toml
    dependenciesno["name@version", …] — transitive edges for graph walks
    attestationnoSLSA attestation digest; present when the dep's author publishes one alongside
    replacedno{ path = "…" } when a local replace is active
    yankednotrue for retracted versions
    +
    fieldrequirednotes
    nameyesmatches the [dependencies] key in akua.toml
    versionyesexact resolved semver (not a range)
    sourceyesfull source ref: oci://…, git+https://…, path+file://…, or helm+<repo-url>#<chart>
    digestyescontent-addressable source hash: sha256: for OCI/path/helm-repo deps; git:<commit-sha> for git deps
    vendor_digestnosha256: hash of the vendored on-disk tree when it differs from digest; used by akuapkg vendor check for git deps without losing the commit pin
    signatureconditionalcosign signature. Keyless: cosign:sigstore:<issuer>. Keyed: cosign:key:<identity>. Required unless [package].strictSigning = false in akua.toml
    dependenciesno["name@version", …] — transitive edges for graph walks
    attestationnoSLSA attestation digest; present when the dep's author publishes one alongside
    replacedno{ path = "…" } when a local replace is active
    yankednotrue for retracted versions

    Rules

    • Alphabetical order by name. Stable diffs even across unrelated PRs.
    • One [[package]] per resolved (name, version). Two major versions of the same dep means two entries.
    • No mutable metadata. No timestamps, no resolver versions, no author info. Everything is deterministic.
    • No comments in generated content. The tool-written [[package]] entries are clean; put explanations in akua.toml.
    • Trailing newline. POSIX file discipline.

    Helm-repo lock entries

    @@ -397,19 +397,19 @@

    Helm-repo lock entries

    digest = "sha256:<tgz-sha256>"

    source format is helm+<repo-url>#<chart>. digest is the sha256: hash of the downloaded .tgz, content-pinned and verified on every subsequent pull. No cosign signature (signature field absent) — Helm repositories distribute plain tarballs without a signing layer. Private repos use the host-keyed --auth / auth: credential at fetch time; credentials never appear in akua.lock.

    What akua.lock does NOT contain

    -
    • Source code (not a vendor directory — see akua vendor for that)
    • Version ranges (those live in akua.toml)
    • User-facing comments
    +
    • Source code (not a vendor directory — see akuapkg vendor for that)
    • Version ranges (those live in akua.toml)
    • User-facing comments

    Resolution workflow

    -

    akua add <kind> <ref> --version=<v>

    +

    akuapkg add <kind> <ref> --version=<v>

    1. Reads current akua.toml
    2. Adds the new entry to [dependencies]
    3. Fetches the artifact; computes digest
    4. Verifies cosign signature
    5. Updates akua.lock — inserts/updates the [[package]] entry; adds transitive deps alphabetically
    6. If the new dep transitively pulls others, repeats for each

    Result: both akua.toml and akua.lock updated in one atomic operation.

    -

    akua verify (CI gate)

    +

    akuapkg verify (CI gate)

    1. Reads akua.toml and akua.lock
    2. Resolves every dep from akua.toml
    3. Compares expected (manifest) vs locked (lockfile) digest + signature
    4. Exits 0 if everything matches; non-zero otherwise

    Run in CI on every PR to catch lockfile tampering.

    -

    akua update [dep]

    +

    akuapkg update [dep]

    Updates to the highest allowed version per akua.toml constraints; rewrites the relevant [[package]] entries in akua.lock. Leaves other deps untouched unless their constraints also match a new version.

    -

    akua vendor (optional)

    -

    Materializes a dependency's bytes into .akua/vendor/<name>/ and pins the source digest in akua.lock. The resolver prefers the vendored copy across all dep kinds (path / oci / git / helm), so the canonical source can be deleted post-vendor and akua render still succeeds offline. For git deps, digest stays git:<commit-sha> and vendor_digest stores the vendored tree hash for local drift checks. Required for air-gapped builds, optional otherwise.

    +

    akuapkg vendor (optional)

    +

    Materializes a dependency's bytes into .akua/vendor/<name>/ and pins the source digest in akua.lock. The resolver prefers the vendored copy across all dep kinds (path / oci / git / helm), so the canonical source can be deleted post-vendor and akuapkg render still succeeds offline. For git deps, digest stays git:<commit-sha> and vendor_digest stores the vendored tree hash for local drift checks. Required for air-gapped builds, optional otherwise.

    Bytes-tied lockfile metadata. Cosign signatures, SLSA attestations, transitive dependency lists, yanked, and Kyverno-converter fields all bind to a specific digest. When a re-vendor or version bump produces a new digest, those fields are dropped on upsert rather than written as (digest=B, sig=sig(A)) entries that no consumer can verify. The source / version / digest triple is always rewritten; everything else is conditional on prior.digest == new.digest.


    Workspaces

    @@ -508,11 +508,11 @@

    Example: a real workspace

    source = "oci://ghcr.io/acme/charts/webapp" digest = "sha256:m3n4o5…" signature = "cosign:key:acme"
    -

    CI runs akua verify on every PR; any digest mismatch or missing signature fails the build.

    +

    CI runs akuapkg verify on every PR; any digest mismatch or missing signature fails the build.

    diff --git a/site/concepts/package-format.html b/site/concepts/package-format.html index 112a4646..434e0eba 100644 --- a/site/concepts/package-format.html +++ b/site/concepts/package-format.html @@ -302,7 +302,7 @@

    Package format

    Package.k authoring shape — imports, schemas, body, and the `resources` output.

    The canonical shape of an akua Package. A Package is a reusable definition authored in KCL and published as a signed OCI artifact. Package.k is the only shape akua itself specifies; higher-level workspace concepts (App / Environment / Cluster / PolicySet / etc.) are user-defined KCL schemas in the consumer's workspace, not akua-owned kinds.

    -

    This document specifies what a package.k file may contain. Companion references: lockfile-format.md for akua.toml / akua.lock, policy-format.md for Rego.

    +

    This document specifies what a package.k file may contain. Companion references: lockfile-format.md for akua.toml / akua.lock, policy-format.md for Rego.


    1. Anatomy

    Every Package is one KCL program with three typed regions:

    @@ -327,16 +327,16 @@

    1. Anatomy

    _app = helm.template(helm.Template { chart = webapp.Chart, values = ... }) resources = _pg + _app
    -

    That's it. akua render writes resources as raw YAML files under --out. Other distribution shapes (Helm charts, OCI bundles, kro RGDs) come from either (a) transformation functions invoked in the body that produce more K8s resources (kro.rgd(...), crossplane.composition(...)), or (b) future akua publish --as <format> at distribution time. The Package itself never pre-commits to an emit format — resources is the single canonical thing it produces.

    +

    That's it. akuapkg render writes resources as raw YAML files under --out. Other distribution shapes (Helm charts, OCI bundles, kro RGDs) come from either (a) transformation functions invoked in the body that produce more K8s resources (kro.rgd(...), crossplane.composition(...)), or (b) future akuapkg publish --as <format> at distribution time. The Package itself never pre-commits to an emit format — resources is the single canonical thing it produces.


    2. Imports

    An import brings one of four things into scope:

    -
    import formpurposepinned by
    import akua.<engine>a source-engine callable (helm, rgd, kustomize, oci)the akua CLI version
    import charts.<name>a typed Helm chart dep previously added via akua add (synthetic wrapper that exposes the chart path + a pre-bound template callable)akua.toml
    import pkgs.<name>a typed Akua-package dep (synthetic stub re-exporting the upstream's schemas + a pre-bound render lambda — pkgs.<name>.render(pkgs.<name>.Input{...}))akua.toml
    import <name>an upstream KCL ecosystem package (e.g. import k8s.api.apps.v1 against oci://ghcr.io/kcl-lang/k8s)akua.toml
    import <local/path>a local KCL module within this packagethe filesystem
    +
    import formpurposepinned by
    import akua.<engine>a source-engine callable (helm, rgd, kustomize, oci)the akua CLI version
    import charts.<name>a typed Helm chart dep previously added via akuapkg add (synthetic wrapper that exposes the chart path + a pre-bound template callable)akua.toml
    import pkgs.<name>a typed Akua-package dep (synthetic stub re-exporting the upstream's schemas + a pre-bound render lambda — pkgs.<name>.render(pkgs.<name>.Input{...}))akua.toml
    import <name>an upstream KCL ecosystem package (e.g. import k8s.api.apps.v1 against oci://ghcr.io/kcl-lang/k8s)akua.toml
    import <local/path>a local KCL module within this packagethe filesystem

    Imports are resolved at build time against akua.toml (declared deps) and verified against akua.lock (digest + signature). Failed verification is a compile error. A missing pin is a compile error.

    Helm-chart deps and KCL-package deps both land in [dependencies]; akua tells them apart from the manifest media type + org.kcllang.package. annotations and routes them to the right consumer (Helm via the synthetic charts. wrapper, KCL packages as direct ExternalPkg entries inside the render sandbox). Four dependency source forms are supported:

    sourceakua.toml shapeuse when
    OCI{ oci = "oci://ghcr.io/.../foo", version = "1.2.3" }published signed artifact (most common)
    Git{ git = "https://github.com/foo/bar", tag = "v1.2.3" }non-OCI-distributed sources
    Path{ path = "../shared" }workspace-local, dev-only
    Helm repo{ repo = "https://go.temporal.io/helm-charts", chart = "temporal", version = "0.62.0" }classic HTTPS Helm repository
    -

    Helm-repo deps resolve against the repo's index.yaml at akua add / lock time, content-pinned by .tgz sha256 in akua.lock, and rendered deterministically offline. Add one with:

    -
    akua add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0
    +

    Helm-repo deps resolve against the repo's index.yaml at akuapkg add / lock time, content-pinned by .tgz sha256 in akua.lock, and rendered deterministically offline. Add one with:

    +
    akuapkg add temporal --repo https://go.temporal.io/helm-charts --chart temporal --version 0.62.0

    For Helm charts and Akua-package deps, use the alias method on the import — the synthesized stub owns the engine call so the consumer just states the typed args:

    import charts.webapp as webapp
     import pkgs.upstream as upstream
    @@ -358,7 +358,7 @@ 

    3. Schema — the public input cont

    input: Input = ctx.input() ```

    ctx.input() is a thin wrapper around KCL's option("input") that hides the plumbing string — a typo becomes a parse error instead of a silent pass-through. input: Input = ... triggers KCL's structural coercion: the returned dict is validated against the Input schema at this binding site, defaults fill in, check: blocks run.

    Under the hood ctx.input() is just option("input") or {}, so the Package remains standalone-valid KCLkcl fmt / kcl lint / IDE LSPs all work once import akua.ctx resolves (akua materializes the stdlib at render time and exposes it to KCL via ExecProgramArgs.external_pkgs).

    -
    • Fields use KCL's native type syntax: str, int, float, bool, [T], {str: T}, unions ("a" | "b" | "c"), nested schemas.
    • Fields without defaults are required. Fields with defaults are optional.
    • Use KCL docstrings for field documentation — akua tooling surfaces them in autocomplete and generated docs.
    • check: blocks can express cross-field constraints; they run during akua render.
    • No runtime side effects (no env lookups, no filesystem, no network). KCL's sandbox enforces this.
    +
    • Fields use KCL's native type syntax: str, int, float, bool, [T], {str: T}, unions ("a" | "b" | "c"), nested schemas.
    • Fields without defaults are required. Fields with defaults are optional.
    • Use KCL docstrings for field documentation — akua tooling surfaces them in autocomplete and generated docs.
    • check: blocks can express cross-field constraints; they run during akuapkg render.
    • No runtime side effects (no env lookups, no filesystem, no network). KCL's sandbox enforces this.

    Example with all shapes:

    schema Input:
         """Public inputs for this package."""
    @@ -395,7 +395,7 @@ 

    3. Schema — the public input cont hostname: str priority: int = 0

    UI hints (optional) ✅

    -

    When a Package is consumed through a UI (merchant install form, Package Studio, generated Swagger form), renderers benefit from hints about field ordering, labels, placeholders, grouping. akua reads UI hints from two sources, both projected into the JSON Schema / OpenAPI output of akua export.

    +

    When a Package is consumed through a UI (merchant install form, Package Studio, generated Swagger form), renderers benefit from hints about field ordering, labels, placeholders, grouping. akua reads UI hints from two sources, both projected into the JSON Schema / OpenAPI output of akuapkg export.

    KCL docstrings — the field's """…""" docstring becomes the schema property's description:

    schema Input:
         """Public inputs for this package."""
    @@ -418,15 +418,15 @@ 

    UI hints (optional) ✅

    @ui(order=30, group="Capacity", widget="slider", min=1, max=20) replicas: int = 3
    -

    @ui(...) is an akua-specific authoring hint, not a registered KCL decorator — akua render strips it before handing the source to KCL's resolver, while akua export extracts it from the parsed AST.

    +

    @ui(...) is an akua-specific authoring hint, not a registered KCL decorator — akuapkg render strips it before handing the source to KCL's resolver, while akuapkg export extracts it from the parsed AST.

    Exporting a view vs rendering ✅

    The canonical Package is KCL. akua ships two different verbs producing different outputs from it:

    -
    verbpurposeneeds inputs?output
    akua exportconvert the Package's Input schema to a standard interchange formatnoJSON Schema 2020-12 or OpenAPI 3.1
    akua renderexecute the Package's full pipeline and produce deploy-ready Kubernetes manifestsyesrendered YAML the reconciler applies
    -

    For install UIs, API docs, rjsf / JSONForms, admission webhook schemas, and client SDK generators — akua export skips engine invocation and customer inputs:

    -
    akua export --package package.k > inputs.schema.json              # JSON Schema 2020-12
    -akua export --package package.k --format=openapi > package.openapi.json
    -

    For actual deployment rendering — use akua render with customer inputs (covered in §9).

    -

    akua export output is pure, spec-compliant JSON Schema 2020-12 / OpenAPI 3.1. Docstrings become description; @ui(...) decorators become x-ui metadata. Consumers that speak these standards — including every JSON Schema tool in the ecosystem — work unchanged.

    +
    verbpurposeneeds inputs?output
    akuapkg exportconvert the Package's Input schema to a standard interchange formatnoJSON Schema 2020-12 or OpenAPI 3.1
    akuapkg renderexecute the Package's full pipeline and produce deploy-ready Kubernetes manifestsyesrendered YAML the reconciler applies
    +

    For install UIs, API docs, rjsf / JSONForms, admission webhook schemas, and client SDK generators — akuapkg export skips engine invocation and customer inputs:

    +
    akuapkg export --package package.k > inputs.schema.json              # JSON Schema 2020-12
    +akuapkg export --package package.k --format=openapi > package.openapi.json
    +

    For actual deployment rendering — use akuapkg render with customer inputs (covered in §9).

    +

    akuapkg export output is pure, spec-compliant JSON Schema 2020-12 / OpenAPI 3.1. Docstrings become description; @ui(...) decorators become x-ui metadata. Consumers that speak these standards — including every JSON Schema tool in the ecosystem — work unchanged.

    No x-user-input or x-input markers. Previous versions of akua layered custom extensions on JSON Schema to mark user-configurable fields and embed transforms. With KCL as the authoring substrate, both are redundant: the Input schema IS the customer-configurable contract by definition, and transforms live as KCL code in the package body. The eventual exported JSON Schema is standards-pure; UI renderers in the broader ecosystem don't need to learn akua-specific vocabulary.


    4. Body — engine calls + transforms

    @@ -467,7 +467,7 @@

    4. Body — engine calls + transforms< } resources = [*_pg, *_app, *_glue, *_addons, _servicemonitor]

    -

    Schema-level validation via check: blocks — this is KCL's role in the two-layer validation model (schema → Rego for cross-resource policy, see policy-format.md):

    +

    Schema-level validation via check: blocks — this is KCL's role in the two-layer validation model (schema → Rego for cross-resource policy, see policy-format.md):

    schema Deployment:
         spec: DeploymentSpec
         check:
    @@ -477,7 +477,7 @@ 

    4. Body — engine calls + transforms<

    KCL check: blocks evaluate at render time against each resource; failures surface as lint errors with line + field context.


    5. The render output

    -

    akua render --out ./deploy writes every entry in resources as its own YAML file in ./deploy/. Filenames are deterministic (<NNN>-<kind>-<name>.yaml), ordered by resource-list position.

    +

    akuapkg render --out ./deploy writes every entry in resources as its own YAML file in ./deploy/. Filenames are deterministic (<NNN>-<kind>-<name>.yaml), ordered by resource-list position.

    deploy/
     ├── 000-configmap-hello.yaml
     ├── 001-service-hello.yaml
    @@ -485,8 +485,8 @@ 

    5. The render output

    Raw manifests are akua's single render shape. Downstream systems that want a different shape use one of:

    • In-body transformations — a KCL function (present or future) that

    consumes resources and returns more K8s resources. kro.rgd(...), crossplane.composition(...), kyverno.policy(...) all fit this mould: they produce CRDs + composite resources that go into resources alongside everything else, and ship as plain YAML.

    -
    • Future distribution verbsakua publish --as helm-chart
    -

    wraps rendered manifests into a Helm chart at distribution time; akua publish --as oci-bundle signs and packages them. These are distribution concerns, not render concerns — the Package's resources are the input, not a pre-declared output list.

    +
    • Future distribution verbsakuapkg publish --as helm-chart
    +

    wraps rendered manifests into a Helm chart at distribution time; akuapkg publish --as oci-bundle signs and packages them. These are distribution concerns, not render concerns — the Package's resources are the input, not a pre-declared output list.

    This keeps the Package shape trivially uniform: one resources list, one render target. Authors reason about what exists; the CLI decides how it ships.


    6. Metadata

    @@ -502,7 +502,7 @@

    6. Metadata

    # Machine-readable keyword list for catalog discovery keywords: ["postgres", "webapp", "payments"] - # Minimum akua version required to render this package + # Minimum akuapkg version required to render this package requires: { akua: ">=0.2.0" engines: { helm: ">=4.0", kcl: ">=0.12" } @@ -512,11 +512,11 @@

    6. Metadata


    7. What's disallowed

    Because determinism and the WASI sandbox are load-bearing:

    -
    • No runtime I/O. No os.read, http.get, file.exists, env-var lookups. KCL's sandbox enforces this.
    • No non-determinism. No random(), no now(), no uuid(). Results depend only on input and imports.
    • No cluster reads at render time. Use RGD output + kro for runtime late-binding; never a live query from KCL.
    • No input overwrite at runtime. Inputs are provided once at render start and treated as immutable through the body.
    • No cross-source value imports. Source A cannot reference Source B's output. Both derive from input. (Runtime cross-refs are the RGD case; see policy-format.md for the broader framing.)
    +
    • No runtime I/O. No os.read, http.get, file.exists, env-var lookups. KCL's sandbox enforces this.
    • No non-determinism. No random(), no now(), no uuid(). Results depend only on input and imports.
    • No cluster reads at render time. Use RGD output + kro for runtime late-binding; never a live query from KCL.
    • No input overwrite at runtime. Inputs are provided once at render start and treated as immutable through the body.
    • No cross-source value imports. Source A cannot reference Source B's output. Both derive from input. (Runtime cross-refs are the RGD case; see policy-format.md for the broader framing.)

    Violation of any of these is a compile error with a clear message.


    8. Rendering model

    -

    akua render:

    +

    akuapkg render:

    1. Parses package.k and type-checks the program.
    2. Loads input from inputs file (YAML or KCL). Validates against the Input schema.
    3. Resolves dependencies via akua.toml / akua.lock. Pulls and verifies signed artifacts.
    4. Evaluates the KCL program. Every engine call happens here (in-process, sandboxed).
    5. Collects the resources list — pkg.render calls have already resolved inline.
    6. Writes each resource as its own YAML file under --out.
    7. (Future) Writes attestation.json (SLSA v1 predicate) alongside the manifests.

    Every step is deterministic: same inputs + same akua.lock + same akua version → byte-identical output.


    @@ -543,7 +543,7 @@

    9. Minimal example

    See examples/01-hello-webapp for the fully runnable version.


    10. Testing Packages

    -

    Packages ship with tests. The test runner is built into akua test; no separate framework required.

    +

    Packages ship with tests. The test runner is built into akuapkg test; no separate framework required.

    Test file conventions

    • test_*.k or *_test.k files anywhere under the package directory are discovered automatically.
    • A test file is a KCL program that uses assert or check: blocks to express expectations against the package's render output or schema.

    Example — schema defaults

    @@ -584,24 +584,24 @@

    Golden-output tests

    └── production/ ├── inputs.yaml └── expected.golden.yaml
    -
    akua test --golden              # regenerate goldens if they drifted intentionally
    -akua test --golden=verify       # fail CI if goldens don't match (default in CI)
    +
    akuapkg test --golden              # regenerate goldens if they drifted intentionally
    +akuapkg test --golden=verify       # fail CI if goldens don't match (default in CI)

    Running

    -
    akua test                       # runs everything, including Rego tests
    -akua test --watch               # re-runs on file change (ideal for TDD)
    -akua test --coverage            # report per-schema / per-source coverage
    -akua test --filter=default      # only tests matching 'default'
    +
    akuapkg test                       # runs everything, including Rego tests
    +akuapkg test --watch               # re-runs on file change (ideal for TDD)
    +akuapkg test --coverage            # report per-schema / per-source coverage
    +akuapkg test --filter=default      # only tests matching 'default'

    Tests run via the embedded KCL engine (see embedded-engines.md) — fast, sandboxed, deterministic.

    What to test

    -
    • Schema defaults and constraints — does input.replicas = 0 correctly fail the check: block?
    • Rendered-output shape — does the Deployment have the right labels, the right replicaCount?
    • Policy compat — does rendering with a specific tier succeed? (Integration test; see policy-format.md §9)
    • Upgrade compatibility — golden tests catch "dep bump accidentally changed the rendered manifest."
    +
    • Schema defaults and constraints — does input.replicas = 0 correctly fail the check: block?
    • Rendered-output shape — does the Deployment have the right labels, the right replicaCount?
    • Policy compat — does rendering with a specific tier succeed? (Integration test; see policy-format.md §9)
    • Upgrade compatibility — golden tests catch "dep bump accidentally changed the rendered manifest."

    Packages without tests ship with a lint warning; platform teams can enforce a policy rule requiring tests for production-tier packages.


    11. Relationship to other docs

    - + diff --git a/site/concepts/sdk.html b/site/concepts/sdk.html index 0a33c271..ab8bf4f5 100644 --- a/site/concepts/sdk.html +++ b/site/concepts/sdk.html @@ -337,7 +337,7 @@

    Runtime Contract


    Shipped API

    The package currently exports the Akua class, SDK error classes, validation helpers, and generated TypeScript types. Higher-level namespace clients for deploy, policy, audit, hosted documents, or Akua Cloud REST APIs are not part of @akua-dev/sdk.

    -
    MethodReturnsNotes
    version()VersionOutputSDK and native version information.
    whoami()WhoamiOutputMirrors akua whoami.
    render(opts)RenderSummaryExecutes an on-disk Package and writes rendered YAML files to out.
    renderSource(opts)stringExecutes Package source or a Package file and returns raw rendered YAML.
    export(opts)Record<string, unknown>Returns the Package Input schema as JSON Schema or OpenAPI.
    check(opts)CheckOutputSyntax, type, dependency, and lockfile checks.
    lint(opts)LintOutputKCL and package linting.
    fmt(opts)FmtOutputFormats KCL sources, or reports changes with check: true.
    inspect(opts)InspectOutputPackage metadata and option information.
    inspectOciPackage(opts)OciPackageInspectOutputPulls a published Akua Package through the native addon and returns verified digests, package metadata, and input schema without extracting to disk.
    tree(opts)TreeOutputDependency tree from akua.toml and akua.lock.
    diff(before, after)DirDiffStructural diff between two rendered manifest directories.
    add(name, opts)AddOutputAdds a dependency to akua.toml.
    vendorAdd(name, opts)VendorAddOutputMaterializes a declared dependency into .akua/vendor/<name>.
    vendorCheck(opts)VendorCheckOutputChecks vendor-tree drift.
    vendorList(opts)VendorListOutputLists vendored dependencies and orphaned entries.
    verify(opts)VerifyOutputVerifies workspace lockfile integrity and configured signing metadata.
    +
    MethodReturnsNotes
    version()VersionOutputSDK and native version information.
    whoami()WhoamiOutputMirrors akuapkg whoami.
    render(opts)RenderSummaryExecutes an on-disk Package and writes rendered YAML files to out.
    renderSource(opts)stringExecutes Package source or a Package file and returns raw rendered YAML.
    export(opts)Record<string, unknown>Returns the Package Input schema as JSON Schema or OpenAPI.
    check(opts)CheckOutputSyntax, type, dependency, and lockfile checks.
    lint(opts)LintOutputKCL and package linting.
    fmt(opts)FmtOutputFormats KCL sources, or reports changes with check: true.
    inspect(opts)InspectOutputPackage metadata and option information.
    inspectOciPackage(opts)OciPackageInspectOutputPulls a published Akua Package through the native addon and returns verified digests, package metadata, and input schema without extracting to disk.
    tree(opts)TreeOutputDependency tree from akua.toml and akua.lock.
    diff(before, after)DirDiffStructural diff between two rendered manifest directories.
    add(name, opts)AddOutputAdds a dependency to akua.toml.
    vendorAdd(name, opts)VendorAddOutputMaterializes a declared dependency into .akua/vendor/<name>.
    vendorCheck(opts)VendorCheckOutputChecks vendor-tree drift.
    vendorList(opts)VendorListOutputLists vendored dependencies and orphaned entries.
    verify(opts)VerifyOutputVerifies workspace lockfile integrity and configured signing metadata.

    Verbs that do not have SDK methods yet remain CLI-only. Use the akua binary directly for those workflows until NAPI bindings and SDK methods ship.


    Render And Export

    @@ -425,11 +425,11 @@

    Errors

    }

    - + diff --git a/site/concepts/security-model.html b/site/concepts/security-model.html index 71b5388b..f556351f 100644 --- a/site/concepts/security-model.html +++ b/site/concepts/security-model.html @@ -301,7 +301,7 @@

    Security model

    Wasmtime sandbox, capability-model preopens, replace-rejection in production, and the cosign + SLSA chain.

    -

    akua is a sandboxed-by-default render substrate. Every render runs inside a wasmtime WASI sandbox with memory / CPU / wall-clock caps and capability-model filesystem preopens. The invariant lives in CLAUDE.md; this document records what that actually means, what's guaranteed, and what's not.

    +

    akua is a sandboxed-by-default render substrate. Every render runs inside a wasmtime WASI sandbox with memory / CPU / wall-clock caps and capability-model filesystem preopens. The invariant lives in CLAUDE.md; this document records what that actually means, what's guaranteed, and what's not.


    Threat model

    Who is the adversary? The Package itself — author of the KCL program + the charts, overlays, policies it depends on.

    @@ -309,7 +309,7 @@

    Threat model

    What must we prevent?

    1. Reading files outside the Package directory and its explicit dep scope
    2. Writing files outside the designated output directory
    3. Making network requests
    4. Spawning subprocesses
    5. Exhausting host memory
    6. Exhausting host CPU (runaway loops, pathological schema evaluation)
    7. Exceeding a wall-clock deadline
    8. Escaping the sandbox to compromise the host process

    What are we NOT trying to prevent?

    -
    • Declarative mischief in the Package's rendered output. akua produces whatever YAML the author writes. Policy evaluation (docs/policy-format.md) is the layer that catches "this Package declares a root-privileged Deployment." The renderer's job is faithful execution of the Package, not moral judgment.
    • Side-channel leaks (timing, memory-access patterns). wasmtime provides strong isolation but not constant-time; a sophisticated adversary could extract bits via timing. Not our bar.
    • Bugs in the dep supply chain beyond what the lockfile catches. akua.lock pins OCI deps by sha256 of the chart blob; a drift between what the lockfile recorded and what the registry now serves is rejected (LockDigestMismatch). But if the initial akua add pulled from a compromised registry that served a malicious chart and recorded its digest, every subsequent render faithfully reproduces it. Phase 6 (cosign verification + SLSA attestation walk) closes this gap.
    +
    • Declarative mischief in the Package's rendered output. akua produces whatever YAML the author writes. Policy evaluation (docs/policy-format.md) is the layer that catches "this Package declares a root-privileged Deployment." The renderer's job is faithful execution of the Package, not moral judgment.
    • Side-channel leaks (timing, memory-access patterns). wasmtime provides strong isolation but not constant-time; a sophisticated adversary could extract bits via timing. Not our bar.
    • Bugs in the dep supply chain beyond what the lockfile catches. akua.lock pins OCI deps by sha256 of the chart blob; a drift between what the lockfile recorded and what the registry now serves is rejected (LockDigestMismatch). But if the initial akuapkg add pulled from a compromised registry that served a malicious chart and recorded its digest, every subsequent render faithfully reproduces it. Phase 6 (cosign verification + SLSA attestation walk) closes this gap.

    Execution model

    The render path runs in a wasmtime WASI sandbox. Concretely:

    @@ -318,7 +318,7 @@

    One Engine, many Stores

    akua follows wasmtime's documented pattern: one process-global Engine, one Linker of host imports, many per-invocation Stores. The render worker and every engine plugin (helm, kustomize, future kro/CEL) share the same Engine so that:

    • JIT-compiled code is compiled once and reused across all Stores.
    • Type interning, compat-hash checks, and trap dispatch live in one place — no duplication, no inter-Engine TLS races.
    • Per-invocation isolation still holds: each render gets its own Store, and plugin calls execute in their own separate Store too.

    When a Package calls helm.template(...) or kustomize.build(...) from inside the render worker:

    -
    akua-cli (native Rust)
    +
    akuapkg-cli (native Rust)
       └ Engine (shared)
           ├ Store A — render worker, KCL evaluator paused in host import
           │     ⇣ kcl_plugin_invoke_json_wasm (wasm import)
    @@ -328,7 +328,7 @@ 

    One Engine, many Stores ⇡ manifests bytes ⇡ host writes response into Store A's guest memory, returns ptr ⇡ KCL continues in Store A

    -

    Both Stores live on the same Engine and the same OS thread. Wasmtime's TLS tracks which Store is currently active; the paused Store resumes correctly when the plugin callout returns. Nested Engines were explicitly ruled out — they share process-global signal handlers in an untested way and duplicate the JIT cache. See docs/spikes/wasmtime-multi-engine.md for the research + verification.

    +

    Both Stores live on the same Engine and the same OS thread. Wasmtime's TLS tracks which Store is currently active; the paused Store resumes correctly when the plugin callout returns. Nested Engines were explicitly ruled out — they share process-global signal handlers in an untested way and duplicate the JIT cache. See docs/spikes/wasmtime-multi-engine.md for the research + verification.

    Plugin bridge boundary

    The env::kcl_plugin_invoke_json_wasm import is the one hole in the worker's sandbox — the only place untrusted KCL can call out to host code. It has exactly one job: read three JSON-string arguments from the guest's linear memory, dispatch to akua-core's plugin registry on the host, allocate response bytes in the guest via the worker's exported akua_bridge_alloc, and hand back a pointer. The host never runs arbitrary guest-supplied code; only the dispatcher and its registered handlers. Plugin handlers themselves run in their own Store, not on the host — so even a compromised helm engine can't escape to the native process.

    The bridge emits a one-line trace per call under AKUA_BRIDGE_TRACE=1 (stderr), useful for debugging misrouted plugin invocations.

    @@ -336,23 +336,23 @@

    What's guaranteed

    ThreatDefense
    Read files outside scopePreopened dirs only. WASI is a capability model: WasiCtxBuilder::preopened_dir(host_path, guest_path, DirPerms::READ, FilePerms::READ) hands exactly one directory to the guest. /etc, /proc, $HOME, /var/run/secrets — all unreachable because they're not mounted. There is no ambient filesystem; nothing to escape to.
    Write files outside scopeSame mechanism. Output dir preopened with DirPerms::MUTATE + FilePerms::WRITE; nothing else writable.
    Networkwasip1 has no socket syscalls, period. Not "denied by default" — denied by construction. No connect(), no DNS, no TLS initiation. The guest cannot fabricate a socket.
    SubprocessNo fork/exec in wasip1. Shell-out is unavailable at the host-ABI level.
    MemoryStoreLimitsBuilder::memory_size(256 << 20) caps each render Store at 256 MiB (tunable). memory.grow fails beyond the cap; wasm traps. Default: 256 MiB per render.
    CPU (wall-clock)Config::epoch_interruption(true) + background thread calling engine.increment_epoch() on a fixed tick. store.set_epoch_deadline(K) traps when the current epoch exceeds deadline. Cheap to check (compiled into every loop backedge). Default: 30 ticks × 100 ms/tick = 3 s wall-clock deadline per render. Engine-plugin Stores (helm, kustomize) opt out with deadline = u64::MAX — the host-Rust caller above them owns whole-call timeouts. Per-invocation fuel-based instruction counting is not enabled today; can return later without ABI impact.
    Stack overflowConfig::max_wasm_stack(bytes) caps the wasm-side stack. Default 512 KiB; lower for defense-in-depth.
    Instance count / table bloatStoreLimitsBuilder::instances(N), tables(N). Prevents wasm from inflating host memory via many small allocations.

    What's enforced in Package code itself (belt and suspenders)

    Even inside the sandbox, akua applies additional invariants on the Package's own code:

    -
    • Path-traversal guard on every plugin callable's path argument. kcl_plugin::resolve_in_package canonicalizes + asserts-under-package-dir + resolves symlinks. A Package that passes "../../etc/passwd" to pkg.render(...) gets a typed error, not a render. Absolute paths are accepted only when they fall under an allowed_roots entry the renderer registered — today, that's exactly the set of resolved charts.* deps (path-based dep dir or OCI cache dir for the blob we just pulled). Nothing else.
    • KCL language-level sandbox. The KCL language itself has no os.read, http.get, env reads, or time.now(). A pure-KCL Package is deterministic by construction. This is upstream KCL's own invariant.
    • Plugin registry is closed. Only akua-core can register plugins (kcl_plugin::register is pub but only called at akua startup). Packages cannot invent their own.
    • Strict render mode (--strict): reject raw-string paths in plugin callables. Forces typed charts.* imports resolved via akua.toml. Default for akua publish and akua serve; optional for interactive akua render.
    +
    • Path-traversal guard on every plugin callable's path argument. kcl_plugin::resolve_in_package canonicalizes + asserts-under-package-dir + resolves symlinks. A Package that passes "../../etc/passwd" to pkg.render(...) gets a typed error, not a render. Absolute paths are accepted only when they fall under an allowed_roots entry the renderer registered — today, that's exactly the set of resolved charts.* deps (path-based dep dir or OCI cache dir for the blob we just pulled). Nothing else.
    • KCL language-level sandbox. The KCL language itself has no os.read, http.get, env reads, or time.now(). A pure-KCL Package is deterministic by construction. This is upstream KCL's own invariant.
    • Plugin registry is closed. Only akua-core can register plugins (kcl_plugin::register is pub but only called at akua startup). Packages cannot invent their own.
    • Strict render mode (--strict): reject raw-string paths in plugin callables. Forces typed charts.* imports resolved via akua.toml. Default for akuapkg publish and akua serve; optional for interactive akuapkg render.

    What's NOT shipped yet

    -

    This is the current-state gap vs the target. See docs/roadmap.md phases for timing.

    -
    GuaranteeState todayPhase
    Path-traversal rejection in plugin handlersShipped — resolve_in_package + allowed_roots✅ Phase 0
    helm.template / kustomize.build via WASM enginesShipped — no shell-out, wasmtime-hosted✅ Phases 1 + 3
    Typed charts.* imports + lockfile digestsShipped — path + OCI, replace override✅ Phase 2a, 2b A+B
    akua render --strict rejects raw chart pathsShipped — E_STRICT_UNTYPED_CHART✅ Phase 2b C
    akua verify path-dep digest drift detectionShipped — PathDigestDrift / PathMissing✅ Phase 2b C
    Render worker wrapped in wasmtimeShipped — every render runs inside a Store with memory/epoch caps + capability-model preopens✅ Phase 4
    akua serve per-tenant isolationVerb doesn't existPhase 5
    cosign keyed verification on OCI depsShipped — [signing] cosign_public_key, ECDSA P-256✅ Phase 6 A
    akua publish with cosign sign-by-defaultShipped — P-256 PKCS#8 PEM private keys✅ Phase 7 A
    akua pull with manifest digest verifyShipped✅ Phase 7 A
    cosign keyless (fulcio + rekor) verificationNot implementedPhase 6 B
    SLSA v1 attestation generation on publishShipped — DSSE envelope, in-toto v1 statement✅ Phase 7 B
    akua verify attestation chain walkShipped — pulls .att sidecars + DSSE verify + subject-digest check for every OCI dep✅ Phase 7 C
    Recursive attestation walk over transitive depsNot implemented — needs published Package to attest its own depsPhase 7 C (follow-up)
    Encrypted cosign private keys — PKCS#8 PBES2Shipped — $AKUA_COSIGN_PASSPHRASE env var✅ Phase 7 C
    OCI-vendored deps → network-free akua render after pullShipped — .akua/vendor/<name>/ convention✅ Phase 7 C
    HSM / cosign-native key formatNot implementedPhase 7 D
    Git dep checkout via gixShipped — pure Rust, no shell-out✅ Phase 2b C
    Private-repo OCI auth (docker config / akua auth.toml)Shipped — Basic + bearer PAT✅ Phase 2b C
    Docker credential helpersNot implemented — would require shell-outWon't ship
    +

    This is the current-state gap vs the target. See docs/roadmap.md phases for timing.

    +
    GuaranteeState todayPhase
    Path-traversal rejection in plugin handlersShipped — resolve_in_package + allowed_roots✅ Phase 0
    helm.template / kustomize.build via WASM enginesShipped — no shell-out, wasmtime-hosted✅ Phases 1 + 3
    Typed charts.* imports + lockfile digestsShipped — path + OCI, replace override✅ Phase 2a, 2b A+B
    akuapkg render --strict rejects raw chart pathsShipped — E_STRICT_UNTYPED_CHART✅ Phase 2b C
    akuapkg verify path-dep digest drift detectionShipped — PathDigestDrift / PathMissing✅ Phase 2b C
    Render worker wrapped in wasmtimeShipped — every render runs inside a Store with memory/epoch caps + capability-model preopens✅ Phase 4
    akua serve per-tenant isolationVerb doesn't existPhase 5
    cosign keyed verification on OCI depsShipped — [signing] cosign_public_key, ECDSA P-256✅ Phase 6 A
    akuapkg publish with cosign sign-by-defaultShipped — P-256 PKCS#8 PEM private keys✅ Phase 7 A
    akuapkg pull with manifest digest verifyShipped✅ Phase 7 A
    cosign keyless (fulcio + rekor) verificationNot implementedPhase 6 B
    SLSA v1 attestation generation on publishShipped — DSSE envelope, in-toto v1 statement✅ Phase 7 B
    akuapkg verify attestation chain walkShipped — pulls .att sidecars + DSSE verify + subject-digest check for every OCI dep✅ Phase 7 C
    Recursive attestation walk over transitive depsNot implemented — needs published Package to attest its own depsPhase 7 C (follow-up)
    Encrypted cosign private keys — PKCS#8 PBES2Shipped — $AKUA_COSIGN_PASSPHRASE env var✅ Phase 7 C
    OCI-vendored deps → network-free akuapkg render after pullShipped — .akua/vendor/<name>/ convention✅ Phase 7 C
    HSM / cosign-native key formatNot implementedPhase 7 D
    Git dep checkout via gixShipped — pure Rust, no shell-out✅ Phase 2b C
    Private-repo OCI auth (docker config / akuapkg auth.toml)Shipped — Basic + bearer PAT✅ Phase 2b C
    Docker credential helpersNot implemented — would require shell-outWon't ship

    Why no shell-out, ever

    A prior design considered keeping helm.template as shell-out for convenience, with a feature flag and clear "trusted input only" warnings. That design is rejected. Reasons:

    -
    1. Opt-in security is not security. If the flag defaults to safe but can be flipped by a single command, every hosted service will eventually flip it for a one-off, forget, and get hit. "Secure by default" means the unsafe path doesn't exist, not that it's one flag away.
    2. Shell-out inherits host privileges. helm runs as the akua process's user with full PATH, env, cwd, network. Sandboxing individual subprocess invocations (seccomp, unshared namespaces) is possible but fragile, platform-specific, and hard to verify.
    3. WASM engines are the viable alternative. Benchmarks at docs/performance.md show KCL under wasmtime/WASI runs at ~2× native — comfortably inside the sub-100ms render budget. helm-engine-wasm prior work hit 20 MB WASM + 2.3s cold render. These are fine numbers.
    4. Removing shell-out forces the right engineering. As long as shell-out is "available as an escape hatch," investment flows there instead of toward the WASM engines. Cutting it is what unblocks Phases 1 + 3.
    +
    1. Opt-in security is not security. If the flag defaults to safe but can be flipped by a single command, every hosted service will eventually flip it for a one-off, forget, and get hit. "Secure by default" means the unsafe path doesn't exist, not that it's one flag away.
    2. Shell-out inherits host privileges. helm runs as the akua process's user with full PATH, env, cwd, network. Sandboxing individual subprocess invocations (seccomp, unshared namespaces) is possible but fragile, platform-specific, and hard to verify.
    3. WASM engines are the viable alternative. Benchmarks at docs/performance.md show KCL under wasmtime/WASI runs at ~2× native — comfortably inside the sub-100ms render budget. helm-engine-wasm prior work hit 20 MB WASM + 2.3s cold render. These are fine numbers.
    4. Removing shell-out forces the right engineering. As long as shell-out is "available as an escape hatch," investment flows there instead of toward the WASM engines. Cutting it is what unblocks Phases 1 + 3.

    The alternative — keep shell-out with lots of warnings — would ship a sandbox that has a hole in it. That's worse than shipping no sandbox; users would assume protection that doesn't exist.


    - + diff --git a/site/errors/E_ADD_DEP_EXISTS.html b/site/errors/E_ADD_DEP_EXISTS.html index 5633e529..9f8b7bbc 100644 --- a/site/errors/E_ADD_DEP_EXISTS.html +++ b/site/errors/E_ADD_DEP_EXISTS.html @@ -315,11 +315,11 @@

    General

    E_ADD_DEP_EXISTS

    -

    What happened

    Error code emitted by the akua CLI: E_ADD_DEP_EXISTS.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_ADD_DEP_EXISTS.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_ADD_INVALID_DEP.html b/site/errors/E_ADD_INVALID_DEP.html index d4f842aa..1f5c3e71 100644 --- a/site/errors/E_ADD_INVALID_DEP.html +++ b/site/errors/E_ADD_INVALID_DEP.html @@ -315,11 +315,11 @@

    General

    E_ADD_INVALID_DEP

    -

    What happened

    Error code emitted by the akua CLI: E_ADD_INVALID_DEP.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_ADD_INVALID_DEP.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_API_REQUEST.html b/site/errors/E_API_REQUEST.html index 28162149..f39ba6a8 100644 --- a/site/errors/E_API_REQUEST.html +++ b/site/errors/E_API_REQUEST.html @@ -315,11 +315,11 @@

    General

    E_API_REQUEST

    -

    What happened

    Hosted Akua API request failed before a structured response was available.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Hosted Akua API request failed before a structured response was available.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_AUTH_INVALID.html b/site/errors/E_AUTH_INVALID.html index be4fe1d8..f8da4747 100644 --- a/site/errors/E_AUTH_INVALID.html +++ b/site/errors/E_AUTH_INVALID.html @@ -315,11 +315,11 @@

    General

    E_AUTH_INVALID

    -

    What happened

    Hosted Akua API token was rejected as invalid or expired.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Hosted Akua API token was rejected as invalid or expired.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_AUTH_PARSE.html b/site/errors/E_AUTH_PARSE.html index 145af1e7..808ffb67 100644 --- a/site/errors/E_AUTH_PARSE.html +++ b/site/errors/E_AUTH_PARSE.html @@ -318,17 +318,17 @@

    E_AUTH_PARSE

    E_AUTH_PARSE — credential input is malformed

    What happened

    A CLI --auth flag value, or the contents of an --auth-file TOML payload, didn't parse into a (prefix, username, password) triple. Akua rejects the input before it reaches the resolver — credentials that round-trip through a malformed parser are a class of bug we don't want to ship into the lockfile or HTTP transport.

    -

    This is distinct from E_INVALID_FLAG: that code covers structural CLI errors (--timeout=5min); E_AUTH_PARSE is specifically for credential-shape errors so agents can branch on it.

    +

    This is distinct from E_INVALID_FLAG: that code covers structural CLI errors (--timeout=5min); E_AUTH_PARSE is specifically for credential-shape errors so agents can branch on it.

    Common causes

    --auth value missing the = separator

    -
    akua vendor add upstream --auth github.com:alice:ghp_xyz   # no `=`
    +
    akuapkg vendor add upstream --auth github.com:alice:ghp_xyz   # no `=`

    The expected shape is <prefix>=<user>:<password>. The split happens on the first = (so passwords containing = survive).

    --auth value missing the : separator inside credentials

    -
    akua vendor add upstream --auth github.com=alice            # missing `:password`
    +
    akuapkg vendor add upstream --auth github.com=alice            # missing `:password`

    The credential portion (right of the first =) splits on the first :.

    --auth value with an empty username or password

    -
    akua vendor add upstream --auth github.com=:ghp_xyz         # empty username
    -akua vendor add upstream --auth github.com=alice:           # empty password
    +
    akuapkg vendor add upstream --auth github.com=:ghp_xyz         # empty username
    +akuapkg vendor add upstream --auth github.com=alice:           # empty password

    Both halves of the credential must be non-empty.

    --auth-file points at a missing or unreadable path

    --auth-file: ./missing.toml: No such file or directory
    @@ -343,7 +343,7 @@

    --auth-f

    The file is a single TOML document with a [auth] table. Each entry's value is a table with exactly two string fields, username and password.

    How to fix it

    Inline flag

    -
    akua vendor add upstream \
    +
    akuapkg vendor add upstream \
       --auth github.com/myco=alice:$GH_TOKEN \
       --auth gitlab.example.com=ci-bot:$GL_TOKEN

    Repeat --auth for multiple hosts. Each value is one prefix-keyed credential.

    @@ -352,20 +352,20 @@

    Auth file (TOML)

    [auth] "github.com/myco" = { username = "alice", password = "ghp_xyz..." } "gitlab.example.com" = { username = "ci-bot", password = "glpat-..." }
    -
    akua vendor add upstream --auth-file ./auth.toml
    +
    akuapkg vendor add upstream --auth-file ./auth.toml

    Combining file and flag

    Both are accepted on the same invocation. If a prefix appears in both, the flag value wins — same precedence as environment overrides over config files. This lets CI inject one-off overrides without rewriting the file:

    -
    akua vendor add upstream \
    +
    akuapkg vendor add upstream \
       --auth-file ./auth.toml \
       --auth github.com/myco=alice:$ROTATED_TOKEN   # overrides the file entry

    Why akua doesn't auto-load ~/.netrc / ~/.docker/config.json

    -

    See E_MANIFEST_GIT_USERINFO for the rationale. Short version: multi-tenant SDK consumers can't safely inherit ambient credentials, and the same explicit-input stance that keeps akua render deterministic applies to credentials.

    +

    See E_MANIFEST_GIT_USERINFO for the rationale. Short version: multi-tenant SDK consumers can't safely inherit ambient credentials, and the same explicit-input stance that keeps akuapkg render deterministic applies to credentials.

    - + diff --git a/site/errors/E_AUTH_REQUIRED.html b/site/errors/E_AUTH_REQUIRED.html index a6fac598..44fb33f9 100644 --- a/site/errors/E_AUTH_REQUIRED.html +++ b/site/errors/E_AUTH_REQUIRED.html @@ -315,11 +315,11 @@

    General

    E_AUTH_REQUIRED

    -

    What happened

    Hosted Akua API auth token is required but was not provided.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Hosted Akua API auth token is required but was not provided.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_CHECK_FAIL.html b/site/errors/E_CHECK_FAIL.html index 1546bcfa..d844aba9 100644 --- a/site/errors/E_CHECK_FAIL.html +++ b/site/errors/E_CHECK_FAIL.html @@ -315,11 +315,11 @@

    General

    E_CHECK_FAIL

    -

    What happened

    Error code emitted by the akua CLI: E_CHECK_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_CHECK_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_COSIGN_SIG_MISSING.html b/site/errors/E_COSIGN_SIG_MISSING.html index f7e927e3..3176de4b 100644 --- a/site/errors/E_COSIGN_SIG_MISSING.html +++ b/site/errors/E_COSIGN_SIG_MISSING.html @@ -315,11 +315,11 @@

    General

    E_COSIGN_SIG_MISSING

    -

    What happened

    A cosign public key was configured but the registry has no .sig sidecar (or it's malformed). Publisher-side signal — actionable by the artifact's author, not the consumer.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    A cosign public key was configured but the registry has no .sig sidecar (or it's malformed). Publisher-side signal — actionable by the artifact's author, not the consumer.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_COSIGN_VERIFY.html b/site/errors/E_COSIGN_VERIFY.html index 639a4934..f7260617 100644 --- a/site/errors/E_COSIGN_VERIFY.html +++ b/site/errors/E_COSIGN_VERIFY.html @@ -315,11 +315,11 @@

    General

    E_COSIGN_VERIFY

    -

    What happened

    Cosign signature failed cryptographic verification, or the payload disagrees with the fetched digest. Attacker-side signal — someone served bytes the configured key didn't approve.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Cosign signature failed cryptographic verification, or the payload disagrees with the fetched digest. Attacker-side signal — someone served bytes the configured key didn't approve.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_DEP_KIND_MISMATCH.html b/site/errors/E_DEP_KIND_MISMATCH.html index 757d42f0..e977563d 100644 --- a/site/errors/E_DEP_KIND_MISMATCH.html +++ b/site/errors/E_DEP_KIND_MISMATCH.html @@ -315,11 +315,11 @@

    General

    E_DEP_KIND_MISMATCH

    -

    What happened

    A dep alias referenced by import <alias> (or pkg.render({package = "<alias>"})) in package.k resolves to a kind that's unreachable from KCL. Most common case: an Akua/KCL-module dep was misclassified as a Helm chart by the resolver, or the user declared a Helm chart alias they then tried to import. akua lock catches this before akua check later fails with the opaque CannotFindModule from KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    A dep alias referenced by import <alias> (or pkg.render({package = "<alias>"})) in package.k resolves to a kind that's unreachable from KCL. Most common case: an Akua/KCL-module dep was misclassified as a Helm chart by the resolver, or the user declared a Helm chart alias they then tried to import. akua lock catches this before akua check later fails with the opaque CannotFindModule from KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_DEP_RESOLVE.html b/site/errors/E_DEP_RESOLVE.html index 4190a5b8..917a5760 100644 --- a/site/errors/E_DEP_RESOLVE.html +++ b/site/errors/E_DEP_RESOLVE.html @@ -315,11 +315,11 @@

    General

    E_DEP_RESOLVE

    -

    What happened

    A dep in akua.toml failed to resolve (missing path, not-a-directory, OCI/git fetch failure, lockfile mismatch). Covers all dep kinds — path / oci / git / vendor — not chart-specific. See chart_resolver and vendor.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    A dep in akua.toml failed to resolve (missing path, not-a-directory, OCI/git fetch failure, lockfile mismatch). Covers all dep kinds — path / oci / git / vendor — not chart-specific. See chart_resolver and vendor.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_DIFF_FOUND.html b/site/errors/E_DIFF_FOUND.html index c6416ff4..bfaa4f81 100644 --- a/site/errors/E_DIFF_FOUND.html +++ b/site/errors/E_DIFF_FOUND.html @@ -315,11 +315,11 @@

    General

    E_DIFF_FOUND

    -

    What happened

    Error code emitted by the akua CLI: E_DIFF_FOUND.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_DIFF_FOUND.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_DIFF_NOT_DIR.html b/site/errors/E_DIFF_NOT_DIR.html index 6ffee26c..a91a3859 100644 --- a/site/errors/E_DIFF_NOT_DIR.html +++ b/site/errors/E_DIFF_NOT_DIR.html @@ -315,11 +315,11 @@

    General

    E_DIFF_NOT_DIR

    -

    What happened

    Error code emitted by the akua CLI: E_DIFF_NOT_DIR.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_DIFF_NOT_DIR.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_ENGINE_NOT_AVAILABLE.html b/site/errors/E_ENGINE_NOT_AVAILABLE.html index bfcdb8ee..7149eaa0 100644 --- a/site/errors/E_ENGINE_NOT_AVAILABLE.html +++ b/site/errors/E_ENGINE_NOT_AVAILABLE.html @@ -315,11 +315,11 @@

    General

    E_ENGINE_NOT_AVAILABLE

    -

    What happened

    Package called an engine plugin whose WASM backend hasn't shipped yet (docs/roadmap.md tracks the blocked features). Shell-out is not an option — see CLAUDE.md "No shell-out, ever."

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Package called an engine plugin whose WASM backend hasn't shipped yet (docs/roadmap.md tracks the blocked features). Shell-out is not an option — see CLAUDE.md "No shell-out, ever."

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_FMT_CHANGED.html b/site/errors/E_FMT_CHANGED.html index 462457bc..0e58aa93 100644 --- a/site/errors/E_FMT_CHANGED.html +++ b/site/errors/E_FMT_CHANGED.html @@ -315,11 +315,11 @@

    General

    E_FMT_CHANGED

    -

    What happened

    Error code emitted by the akua CLI: E_FMT_CHANGED.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_FMT_CHANGED.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_FMT_KCL.html b/site/errors/E_FMT_KCL.html index 582145e1..d0a79b2d 100644 --- a/site/errors/E_FMT_KCL.html +++ b/site/errors/E_FMT_KCL.html @@ -315,11 +315,11 @@

    General

    E_FMT_KCL

    -

    What happened

    Error code emitted by the akua CLI: E_FMT_KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_FMT_KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_FORBIDDEN.html b/site/errors/E_FORBIDDEN.html index 656b8d86..6bab3a49 100644 --- a/site/errors/E_FORBIDDEN.html +++ b/site/errors/E_FORBIDDEN.html @@ -315,11 +315,11 @@

    General

    E_FORBIDDEN

    -

    What happened

    Hosted Akua API token is valid but lacks permission for the request.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Hosted Akua API token is valid but lacks permission for the request.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INIT_EMPTY_NAME.html b/site/errors/E_INIT_EMPTY_NAME.html index 3ecbf9c0..5b94742a 100644 --- a/site/errors/E_INIT_EMPTY_NAME.html +++ b/site/errors/E_INIT_EMPTY_NAME.html @@ -315,11 +315,11 @@

    General

    E_INIT_EMPTY_NAME

    -

    What happened

    Error code emitted by the akua CLI: E_INIT_EMPTY_NAME.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_INIT_EMPTY_NAME.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INIT_EXISTS.html b/site/errors/E_INIT_EXISTS.html index 56a33149..ffaf4f2e 100644 --- a/site/errors/E_INIT_EXISTS.html +++ b/site/errors/E_INIT_EXISTS.html @@ -315,11 +315,11 @@

    General

    E_INIT_EXISTS

    -

    What happened

    Error code emitted by the akua CLI: E_INIT_EXISTS.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_INIT_EXISTS.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INPUTS_MISSING.html b/site/errors/E_INPUTS_MISSING.html index 80fa425d..a57969a9 100644 --- a/site/errors/E_INPUTS_MISSING.html +++ b/site/errors/E_INPUTS_MISSING.html @@ -315,11 +315,11 @@

    General

    E_INPUTS_MISSING

    -

    What happened

    Error code emitted by the akua CLI: E_INPUTS_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_INPUTS_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INPUTS_PARSE.html b/site/errors/E_INPUTS_PARSE.html index 51ece838..e27ac7a1 100644 --- a/site/errors/E_INPUTS_PARSE.html +++ b/site/errors/E_INPUTS_PARSE.html @@ -315,11 +315,11 @@

    General

    E_INPUTS_PARSE

    -

    What happened

    Error code emitted by the akua CLI: E_INPUTS_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_INPUTS_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INSPECT_FAIL.html b/site/errors/E_INSPECT_FAIL.html index 53b125c9..7e768401 100644 --- a/site/errors/E_INSPECT_FAIL.html +++ b/site/errors/E_INSPECT_FAIL.html @@ -315,11 +315,11 @@

    General

    E_INSPECT_FAIL

    -

    What happened

    Error code emitted by the akua CLI: E_INSPECT_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_INSPECT_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_INVALID_FLAG.html b/site/errors/E_INVALID_FLAG.html index 5c432e3b..2a816d33 100644 --- a/site/errors/E_INVALID_FLAG.html +++ b/site/errors/E_INVALID_FLAG.html @@ -315,11 +315,11 @@

    General

    E_INVALID_FLAG

    -

    What happened

    CLI-level flag value didn't parse — --timeout=5min, --max-depth=foo, etc. Distinct from E_INPUTS_PARSE (which covers inputs.yaml content) so agents can branch on the right thing.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    CLI-level flag value didn't parse — --timeout=5min, --max-depth=foo, etc. Distinct from E_INPUTS_PARSE (which covers inputs.yaml content) so agents can branch on the right thing.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_IO.html b/site/errors/E_IO.html index c828ccb9..03e24076 100644 --- a/site/errors/E_IO.html +++ b/site/errors/E_IO.html @@ -315,11 +315,11 @@

    General

    E_IO

    -

    What happened

    Error code emitted by the akua CLI: E_IO.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_IO.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_LINT_FAIL.html b/site/errors/E_LINT_FAIL.html index 24ebe770..264fc5ee 100644 --- a/site/errors/E_LINT_FAIL.html +++ b/site/errors/E_LINT_FAIL.html @@ -315,11 +315,11 @@

    General

    E_LINT_FAIL

    -

    What happened

    Error code emitted by the akua CLI: E_LINT_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_LINT_FAIL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_LOCK_DRIFT.html b/site/errors/E_LOCK_DRIFT.html index b4a3ba7d..e7aed076 100644 --- a/site/errors/E_LOCK_DRIFT.html +++ b/site/errors/E_LOCK_DRIFT.html @@ -315,11 +315,11 @@

    General

    E_LOCK_DRIFT

    -

    What happened

    akua.lock is out of sync with akua.tomlakua lock --check found drift. Re-run akua lock without --check to refresh.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.lock is out of sync with akua.tomlakua lock --check found drift. Re-run akua lock without --check to refresh.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_LOCK_MISSING.html b/site/errors/E_LOCK_MISSING.html index 281190c6..3fcfe7de 100644 --- a/site/errors/E_LOCK_MISSING.html +++ b/site/errors/E_LOCK_MISSING.html @@ -315,11 +315,11 @@

    General

    E_LOCK_MISSING

    -

    What happened

    Error code emitted by the akua CLI: E_LOCK_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_LOCK_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_LOCK_PARSE.html b/site/errors/E_LOCK_PARSE.html index 268e6e49..d38b1b37 100644 --- a/site/errors/E_LOCK_PARSE.html +++ b/site/errors/E_LOCK_PARSE.html @@ -315,11 +315,11 @@

    General

    E_LOCK_PARSE

    -

    What happened

    Error code emitted by the akua CLI: E_LOCK_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_LOCK_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_GIT_USERINFO.html b/site/errors/E_MANIFEST_GIT_USERINFO.html index 7cb04349..cd929e69 100644 --- a/site/errors/E_MANIFEST_GIT_USERINFO.html +++ b/site/errors/E_MANIFEST_GIT_USERINFO.html @@ -327,7 +327,7 @@

    What happened

    Why akua refuses

    akua.toml lives in version control. So does akua.lock, which records the canonical source URL of every resolved dep. If the manifest URL contained credentials, those credentials would be persisted into the lockfile, the git history of the project, and any artifact akua publishes — for the lifetime of the repository. Even rotating the token after the fact doesn't fully undo the leak (commit history, mirror clones, attacker forks).

    Akua's rule: credentials never appear in any file akua writes or reads as input. The same principle that bans secrets in kubectl apply -f'd manifests applies to akua's dependency declarations.

    -

    The lockfile field source (see lockfile-format.md) canonicalizes URLs by stripping userinfo, default ports, and .git suffix — so even if a malformed call ever reached the lockfile-write path, the credential would not survive. This validation is the first line of defense; the canonicalization is the second.

    +

    The lockfile field source (see lockfile-format.md) canonicalizes URLs by stripping userinfo, default ports, and .git suffix — so even if a malformed call ever reached the lockfile-write path, the credential would not survive. This validation is the first line of defense; the canonicalization is the second.

    How to fix it

    Pass credentials at the call site, never in akua.toml.

    From the SDK

    @@ -336,14 +336,14 @@

    From the SDK

    'github.com/myco/private': { username: 'alice', password: process.env.GH_TOKEN! } } });
    -

    The auth map is keyed by URL prefix (longest-prefix wins, same rule git's credential helper / .npmrc URL keys use). See sdk.md → Credentials for the full resolution rules.

    +

    The auth map is keyed by URL prefix (longest-prefix wins, same rule git's credential helper / .npmrc URL keys use). See sdk.md → Credentials for the full resolution rules.

    From the CLI

    -
    akua vendor add upstream --auth github.com/myco/private=alice:$GH_TOKEN
    +
    akuapkg vendor add upstream --auth github.com/myco/private=alice:$GH_TOKEN

    Repeat --auth for multiple hosts. For environments where flags are awkward (CI, scripts), pass --auth-file <path> pointing at a TOML file you explicitly named:

    # auth.toml
     [auth]
     "github.com/myco/private" = { username = "alice", password = "ghp_xyz..." }
    -
    akua vendor add upstream --auth-file ./auth.toml
    +
    akuapkg vendor add upstream --auth-file ./auth.toml

    Update your akua.toml

    Strip the userinfo from the URL itself:

    [dependencies]
    @@ -352,16 +352,16 @@ 

    Update your akua.toml

    # After: upstream = { git = "https://github.com/myco/private", tag = "v1" }
    -

    Then re-run akua vendor add upstream with the credential supplied via flag / SDK parameter.

    +

    Then re-run akuapkg vendor add upstream with the credential supplied via flag / SDK parameter.

    Why no ~/.netrc / ~/.docker/config.json fallback?

    Akua deliberately does not auto-load ambient credential files. Two reasons:

    -
    • Multi-tenant SDK consumers. A server-side process embedding @akua-dev/sdk may handle requests from multiple tenants. Credentials that "happen to be on disk" can cross-contaminate between tenants. Explicit-only auth means each call carries exactly the credentials authorized for that call's principal.
    • Sandbox parity. akua render runs Packages in a wasmtime sandbox with strict capability scoping. Extending the same "no implicit input" stance to credentials is a coherent invariant — the SDK and CLI surface are the only places credentials enter the system.
    +
    • Multi-tenant SDK consumers. A server-side process embedding @akua-dev/sdk may handle requests from multiple tenants. Credentials that "happen to be on disk" can cross-contaminate between tenants. Explicit-only auth means each call carries exactly the credentials authorized for that call's principal.
    • Sandbox parity. akuapkg render runs Packages in a wasmtime sandbox with strict capability scoping. Extending the same "no implicit input" stance to credentials is a coherent invariant — the SDK and CLI surface are the only places credentials enter the system.
    - + diff --git a/site/errors/E_MANIFEST_HELM_CHART_INVALID.html b/site/errors/E_MANIFEST_HELM_CHART_INVALID.html index dc8b2394..6aaacf4a 100644 --- a/site/errors/E_MANIFEST_HELM_CHART_INVALID.html +++ b/site/errors/E_MANIFEST_HELM_CHART_INVALID.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_HELM_CHART_INVALID

    -

    What happened

    akua.toml declares a repo dep whose chart value contains path separators (/, \) or .. — a chart name must be a plain single-component name. Rejected at parse time to prevent path confusion in the chart cache.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.toml declares a repo dep whose chart value contains path separators (/, \) or .. — a chart name must be a plain single-component name. Rejected at parse time to prevent path confusion in the chart cache.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_HELM_MISSING_CHART.html b/site/errors/E_MANIFEST_HELM_MISSING_CHART.html index cbfb881b..9554ff7d 100644 --- a/site/errors/E_MANIFEST_HELM_MISSING_CHART.html +++ b/site/errors/E_MANIFEST_HELM_MISSING_CHART.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_HELM_MISSING_CHART

    -

    What happened

    akua.toml declares a repo (HTTPS Helm repository) dep that is missing the required chart field.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.toml declares a repo (HTTPS Helm repository) dep that is missing the required chart field.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_HELM_MISSING_VERSION.html b/site/errors/E_MANIFEST_HELM_MISSING_VERSION.html index 6eca5ce5..3607dd9e 100644 --- a/site/errors/E_MANIFEST_HELM_MISSING_VERSION.html +++ b/site/errors/E_MANIFEST_HELM_MISSING_VERSION.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_HELM_MISSING_VERSION

    -

    What happened

    akua.toml declares a repo dep that is missing the required version field (a semver constraint is mandatory for reproducibility).

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.toml declares a repo dep that is missing the required version field (a semver constraint is mandatory for reproducibility).

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_HELM_USERINFO.html b/site/errors/E_MANIFEST_HELM_USERINFO.html index f5d614dd..004712b4 100644 --- a/site/errors/E_MANIFEST_HELM_USERINFO.html +++ b/site/errors/E_MANIFEST_HELM_USERINFO.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_HELM_USERINFO

    -

    What happened

    akua.toml declares a repo dep whose URL contains embedded credentials (https://user:pass@host/...). Rejected at parse time so the credential never reaches the lockfile or git history. Pass credentials via the SDK auth parameter or --auth instead.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.toml declares a repo dep whose URL contains embedded credentials (https://user:pass@host/...). Rejected at parse time so the credential never reaches the lockfile or git history. Pass credentials via the SDK auth parameter or --auth instead.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_MISSING.html b/site/errors/E_MANIFEST_MISSING.html index ea16d4e5..7af4fecf 100644 --- a/site/errors/E_MANIFEST_MISSING.html +++ b/site/errors/E_MANIFEST_MISSING.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_MISSING

    -

    What happened

    Error code emitted by the akua CLI: E_MANIFEST_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_MANIFEST_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_OCI_USERINFO.html b/site/errors/E_MANIFEST_OCI_USERINFO.html index 807ce699..174034cb 100644 --- a/site/errors/E_MANIFEST_OCI_USERINFO.html +++ b/site/errors/E_MANIFEST_OCI_USERINFO.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_OCI_USERINFO

    -

    What happened

    akua.toml declares an oci dep whose URL contains embedded credentials (oci://user:pass@host/...). Rejected at parse time so the credential never reaches the lockfile or git history. Pass credentials via the SDK auth parameter or --auth instead.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua.toml declares an oci dep whose URL contains embedded credentials (oci://user:pass@host/...). Rejected at parse time so the credential never reaches the lockfile or git history. Pass credentials via the SDK auth parameter or --auth instead.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_MANIFEST_PARSE.html b/site/errors/E_MANIFEST_PARSE.html index b615279e..3998ab21 100644 --- a/site/errors/E_MANIFEST_PARSE.html +++ b/site/errors/E_MANIFEST_PARSE.html @@ -315,11 +315,11 @@

    General

    E_MANIFEST_PARSE

    -

    What happened

    Error code emitted by the akua CLI: E_MANIFEST_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_MANIFEST_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_PACKAGE_MISSING.html b/site/errors/E_PACKAGE_MISSING.html index 29ada1be..758a5a52 100644 --- a/site/errors/E_PACKAGE_MISSING.html +++ b/site/errors/E_PACKAGE_MISSING.html @@ -315,11 +315,11 @@

    General

    E_PACKAGE_MISSING

    -

    What happened

    Error code emitted by the akua CLI: E_PACKAGE_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_PACKAGE_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_PACKAGE_PARSE.html b/site/errors/E_PACKAGE_PARSE.html index 3f078e7f..913978ca 100644 --- a/site/errors/E_PACKAGE_PARSE.html +++ b/site/errors/E_PACKAGE_PARSE.html @@ -315,11 +315,11 @@

    General

    E_PACKAGE_PARSE

    -

    What happened

    Error code emitted by the akua CLI: E_PACKAGE_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_PACKAGE_PARSE.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_PATH_ESCAPE.html b/site/errors/E_PATH_ESCAPE.html index ba4c1c83..8e8e0fb7 100644 --- a/site/errors/E_PATH_ESCAPE.html +++ b/site/errors/E_PATH_ESCAPE.html @@ -322,8 +322,8 @@

    What happened

    plugin path `../upstream` resolved to `/private/tmp/spike1/upstream`,
     which escapes the Package directory `/private/tmp/spike1/install`

    Why akua refuses

    -

    akua render runs each Package inside a wasmtime sandbox with read-only filesystem preopens scoped to the Package directory. A path that resolves outside that root is — by construction — unreachable through the sandbox's capabilities. We surface the error early instead of letting it manifest as a confusing wasmtime open-file failure deeper in the render.

    -

    See docs/security-model.md for the full threat model.

    +

    akuapkg render runs each Package inside a wasmtime sandbox with read-only filesystem preopens scoped to the Package directory. A path that resolves outside that root is — by construction — unreachable through the sandbox's capabilities. We surface the error early instead of letting it manifest as a confusing wasmtime open-file failure deeper in the render.

    +

    See docs/security-model.md for the full threat model.

    How to fix it

    Both correct paths declare the dependency in akua.toml and compose it by its typed alias — user code never writes a filesystem path. pkg.render accepts package = "<alias>" only; there is no path = "..." form.

    1. Vendor the dependency as a subdirectory

    @@ -360,15 +360,15 @@

    2. Declare a separatel # directly (the resolver mounts it as a KCL ExternalPkg): import upstream resources = upstream.resources + extras

    -

    akua lock records the resolved digest; akua render reads the dep from the local cache (under ~/.cache/akua/), and the sandbox preopens that cache root in addition to the Package directory.

    +

    akuapkg lock records the resolved digest; akuapkg render reads the dep from the local cache (under ~/.cache/akua/), and the sandbox preopens that cache root in addition to the Package directory.

    What NOT to do

    • Don't pass absolute paths to plugins (/var/cache/...). The sandbox refuses anything outside its preopened roots, even if you chmod your way to readability.
    • Don't symlink your way around it. Akua canonicalizes plugin paths before the under-Package check; a ./link → ../upstream symlink resolves the same as ../upstream and gets rejected the same way.

    See also

    - + diff --git a/site/errors/E_PUBLISH_FAILED.html b/site/errors/E_PUBLISH_FAILED.html index dcd10f35..ccbe6f50 100644 --- a/site/errors/E_PUBLISH_FAILED.html +++ b/site/errors/E_PUBLISH_FAILED.html @@ -315,11 +315,11 @@

    General

    E_PUBLISH_FAILED

    -

    What happened

    akua publish failed to upload the artifact. Wraps every registry- side failure (auth rejected, upload PUT non-2xx, manifest malformed).

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua publish failed to upload the artifact. Wraps every registry- side failure (auth rejected, upload PUT non-2xx, manifest malformed).

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_PULL_FAILED.html b/site/errors/E_PULL_FAILED.html index 4008f5b9..7bd935ab 100644 --- a/site/errors/E_PULL_FAILED.html +++ b/site/errors/E_PULL_FAILED.html @@ -315,11 +315,11 @@

    General

    E_PULL_FAILED

    -

    What happened

    akua pull couldn't retrieve / extract the requested artifact.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua pull couldn't retrieve / extract the requested artifact.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_REMOVE_NOT_FOUND.html b/site/errors/E_REMOVE_NOT_FOUND.html index 3c1b9187..a4b0589d 100644 --- a/site/errors/E_REMOVE_NOT_FOUND.html +++ b/site/errors/E_REMOVE_NOT_FOUND.html @@ -315,11 +315,11 @@

    General

    E_REMOVE_NOT_FOUND

    -

    What happened

    Error code emitted by the akua CLI: E_REMOVE_NOT_FOUND.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_REMOVE_NOT_FOUND.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_BUDGET_DEADLINE.html b/site/errors/E_RENDER_BUDGET_DEADLINE.html index c8b73dc6..5259ce53 100644 --- a/site/errors/E_RENDER_BUDGET_DEADLINE.html +++ b/site/errors/E_RENDER_BUDGET_DEADLINE.html @@ -315,11 +315,11 @@

    General

    E_RENDER_BUDGET_DEADLINE

    -

    What happened

    pkg.render was called after the wall-clock deadline the outer caller installed for the render had already expired.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    pkg.render was called after the wall-clock deadline the outer caller installed for the render had already expired.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_BUDGET_DEPTH.html b/site/errors/E_RENDER_BUDGET_DEPTH.html index 16021b32..c859b57f 100644 --- a/site/errors/E_RENDER_BUDGET_DEPTH.html +++ b/site/errors/E_RENDER_BUDGET_DEPTH.html @@ -315,11 +315,11 @@

    General

    E_RENDER_BUDGET_DEPTH

    -

    What happened

    pkg.render exceeded the render-stack depth cap. Default is generous (16); hitting it usually means runaway composition through fresh Packages, which cycle detection alone can't catch.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    pkg.render exceeded the render-stack depth cap. Default is generous (16); hitting it usually means runaway composition through fresh Packages, which cycle detection alone can't catch.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_CYCLE.html b/site/errors/E_RENDER_CYCLE.html index f941eea0..fc4bd53d 100644 --- a/site/errors/E_RENDER_CYCLE.html +++ b/site/errors/E_RENDER_CYCLE.html @@ -315,11 +315,11 @@

    General

    E_RENDER_CYCLE

    -

    What happened

    pkg.render re-entered a Package already on the render stack — composition cycle. Caught before the inner load to bound recursion; covers both direct and transitive cycles.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    pkg.render re-entered a Package already on the render stack — composition cycle. Caught before the inner load to bound recursion; covers both direct and transitive cycles.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_KCL.html b/site/errors/E_RENDER_KCL.html index 1d68d91d..bafc3986 100644 --- a/site/errors/E_RENDER_KCL.html +++ b/site/errors/E_RENDER_KCL.html @@ -315,11 +315,11 @@

    General

    E_RENDER_KCL

    -

    What happened

    Error code emitted by the akua CLI: E_RENDER_KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_RENDER_KCL.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_OUTPUT_TOO_LARGE.html b/site/errors/E_RENDER_OUTPUT_TOO_LARGE.html index 17b1e01a..bdcc0a59 100644 --- a/site/errors/E_RENDER_OUTPUT_TOO_LARGE.html +++ b/site/errors/E_RENDER_OUTPUT_TOO_LARGE.html @@ -315,11 +315,11 @@

    General

    E_RENDER_OUTPUT_TOO_LARGE

    -

    What happened

    A render produced more output than the host is willing to buffer from the sandboxed worker (the per-render stdout ceiling — a DoS bound on shared hosts). The Package renders, but its manifest set is too large to deliver. Distinct from E_RENDER_KCL so agents don't mistake an over-large-but-valid render for a program error.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    A render produced more output than the host is willing to buffer from the sandboxed worker (the per-render stdout ceiling — a DoS bound on shared hosts). The Package renders, but its manifest set is too large to deliver. Distinct from E_RENDER_KCL so agents don't mistake an over-large-but-valid render for a program error.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_RENDER_YAML.html b/site/errors/E_RENDER_YAML.html index c7a54e96..e068a55e 100644 --- a/site/errors/E_RENDER_YAML.html +++ b/site/errors/E_RENDER_YAML.html @@ -315,11 +315,11 @@

    General

    E_RENDER_YAML

    -

    What happened

    Error code emitted by the akua CLI: E_RENDER_YAML.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_RENDER_YAML.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_STRICT_UNTYPED_CHART.html b/site/errors/E_STRICT_UNTYPED_CHART.html index 80dbcee8..455f0518 100644 --- a/site/errors/E_STRICT_UNTYPED_CHART.html +++ b/site/errors/E_STRICT_UNTYPED_CHART.html @@ -315,11 +315,11 @@

    General

    E_STRICT_UNTYPED_CHART

    -

    What happened

    akua render --strict: a plugin was handed a raw-string chart path instead of a typed charts.* import. Surfaces the Package authoring site that needs to migrate.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    akua render --strict: a plugin was handed a raw-string chart path instead of a typed charts.* import. Surfaces the Package authoring site that needs to migrate.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_UNSUPPORTED.html b/site/errors/E_UNSUPPORTED.html index a0a6e2db..d7b9b4e8 100644 --- a/site/errors/E_UNSUPPORTED.html +++ b/site/errors/E_UNSUPPORTED.html @@ -315,11 +315,11 @@

    General

    E_UNSUPPORTED

    -

    What happened

    Requested CLI option or hosted API bridge feature is not implemented.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Requested CLI option or hosted API bridge feature is not implemented.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_VENDOR_DEP_MISSING.html b/site/errors/E_VENDOR_DEP_MISSING.html index aba49306..f894f6d1 100644 --- a/site/errors/E_VENDOR_DEP_MISSING.html +++ b/site/errors/E_VENDOR_DEP_MISSING.html @@ -315,11 +315,11 @@

    General

    E_VENDOR_DEP_MISSING

    -

    What happened

    Error code emitted by the akua CLI: E_VENDOR_DEP_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_VENDOR_DEP_MISSING.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/E_VENDOR_DRIFT.html b/site/errors/E_VENDOR_DRIFT.html index b8b5615c..efa6e982 100644 --- a/site/errors/E_VENDOR_DRIFT.html +++ b/site/errors/E_VENDOR_DRIFT.html @@ -315,11 +315,11 @@

    General

    E_VENDOR_DRIFT

    -

    What happened

    Error code emitted by the akua CLI: E_VENDOR_DRIFT.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    +

    What happened

    Error code emitted by the akua CLI: E_VENDOR_DRIFT.

    How to fix it

    This error doesn't have an extended remediation guide yet — track issues on GitHub or open one with your --json output if the message above wasn't enough.

    diff --git a/site/errors/index.html b/site/errors/index.html index 26e6ad33..068bd00e 100644 --- a/site/errors/index.html +++ b/site/errors/index.html @@ -501,7 +501,7 @@

    Error codes

    diff --git a/site/examples/00-helm-hello.html b/site/examples/00-helm-hello.html index ae81f637..02230547 100644 --- a/site/examples/00-helm-hello.html +++ b/site/examples/00-helm-hello.html @@ -301,22 +301,22 @@

    00-helm-hello

    The smallest Package that exercises akua's `helm.template` engine callable end-to-end.

    -
    Renders end-to-end via the embedded helm-engine-wasm. No helm binary on $PATH needed or consulted. All template rendering happens inside a wasmtime WASI sandbox. See docs/security-model.md + docs/roadmap.md Phase 1.
    +
    Renders end-to-end via the embedded helm-engine-wasm. No helm binary on $PATH needed or consulted. All template rendering happens inside a wasmtime WASI sandbox. See docs/security-model.md + docs/roadmap.md Phase 1.

    The smallest Package that exercises akua's helm.template engine callable end-to-end.

    What's here

    -
    filepurpose
    package.kKCL Package; imports akua.helm, calls helm.template, wires the result into resources = ….
    akua.tomlManifest — no external deps.
    inputs.example.yamlAuto-discovered by akua render when --inputs is omitted.
    chart/A tiny in-tree Helm chart (one ConfigMap template).
    +
    filepurpose
    package.kKCL Package; imports akua.helm, calls helm.template, wires the result into resources = ….
    akua.tomlManifest — no external deps.
    inputs.example.yamlAuto-discovered by akuapkg render when --inputs is omitted.
    chart/A tiny in-tree Helm chart (one ConfigMap template).

    Render

    -

    package.k passes "./chart" to helm.template; akua resolves that against the Package.k's directory (via the path-traversal-guarded resolve_in_package) and hands the chart tarball to the embedded WASM Helm engine. akua render works from any cwd — point --package at this directory:

    +

    package.k passes "./chart" to helm.template; akua resolves that against the Package.k's directory (via the path-traversal-guarded resolve_in_package) and hands the chart tarball to the embedded WASM Helm engine. akuapkg render works from any cwd — point --package at this directory:

    # Build the embedded helm engine once per machine:
     task build:helm-engine-wasm
     
    -akua render --package examples/00-helm-hello/package.k --out ./rendered
    +akuapkg render --package examples/00-helm-hello/package.k --out ./rendered

    The rendered ConfigMap lands at ./rendered/000-configmap-hello-greeting.yaml — already checked in alongside the example so you can eyeball the output without running anything.

    What's happening

    -

    package.k imports akua.helm — the bundled akua KCL stdlib, a thin typed wrapper over kcl_plugin.helm — and calls helm.template(helm.Template { ... }). Under the hood, akua's plugin dispatcher routes the call to a Rust handler that tars the chart directory, hands it to a Go program compiled to wasm32-wasip1 hosted via wasmtime (see crates/helm-engine-wasm/), parses the multi-document YAML output back into resources, and splats them into resources.

    +

    package.k imports akua.helm — the bundled akua KCL stdlib, a thin typed wrapper over kcl_plugin.helm — and calls helm.template(helm.Template { ... }). Under the hood, akua's plugin dispatcher routes the call to a Rust handler that tars the chart directory, hands it to a Go program compiled to wasm32-wasip1 hosted via wasmtime (see crates/helm-engine-wasm/), parses the multi-document YAML output back into resources, and splats them into resources.

    No helm binary touched. No subprocess. No $PATH. The entire render path lives inside a WASI sandbox. Per CLAUDE.md: "No shell-out, ever."

    Spec

    -

    See docs/package-format.md §5 for the outputs shape and docs/cli.md akua render.

    +

    See docs/package-format.md §5 for the outputs shape and docs/cli.md akuapkg render.

    package.k

    # Minimal Package that exercises the `helm.template` plugin callable.
     #
     # Renders the adjacent `./chart/` (a tiny ConfigMap template) through
    @@ -326,11 +326,11 @@ 

    package.k

    # Minimal Package that exercises t
     #
     # Render:
     #
    -#   akua render --out ./rendered
    +#   akuapkg render --out ./rendered
     #
     # `./chart` is a raw-string path resolved under the Package dir — the
     # original simplest-possible shape. Example 01 shows the typed
    -# `import charts.<name>` form that Phase 2a landed; `akua render
    +# `import charts.<name>` form that Phase 2a landed; `akuapkg render
     # --strict` only accepts that form.
     #
     # Inputs flow through KCL's `option()` mechanism; `inputs.example.yaml`
    @@ -377,12 +377,12 @@ 

    Rendered output

    000-configmap-hello-greeting.yaml

    - Source: examples/00-helm-hello/ + Source: examples/00-helm-hello/

    diff --git a/site/examples/01-hello-webapp.html b/site/examples/01-hello-webapp.html index 963413dc..a05e7216 100644 --- a/site/examples/01-hello-webapp.html +++ b/site/examples/01-hello-webapp.html @@ -322,29 +322,29 @@

    The three regions in package.k
  • Body — one call to nginx.template(nginx.TemplateOpts{...})
  • wiring public schema into chart values. Resources are aggregated into top-level resources. akua writes one YAML file per resource under --out.

    Run

    -
    akua add                                 # resolve deps → writes akua.lock
    -akua render --inputs inputs.yaml         # render to ./deploy/
    +
    akuapkg add                                 # resolve deps → writes akua.lock
    +akuapkg render --inputs inputs.yaml         # render to ./deploy/
     ls deploy/                               # 000-deployment-hello.yaml, 001-service-hello.yaml

    Under --strict, akua rejects raw-string chart paths — every chart must be declared in akua.toml and imported as charts.<name>:

    -
    akua render --strict --inputs inputs.yaml
    +
    akuapkg render --strict --inputs inputs.yaml

    Vendored chart vs OCI pull

    This example vendors nginx into vendor/nginx/ so the Package is self-contained and rendering works offline. To point at a registry instead, swap the akua.toml dep for:

    [dependencies]
     nginx = { oci = "oci://registry-1.docker.io/bitnamicharts/nginx", version = "18.2.0" }
    -

    akua pulls the chart into $XDG_CACHE_HOME/akua/oci/ on first akua add / akua render, verifying the blob digest against akua.lock on subsequent renders. See Phase 2b in docs/roadmap.md.

    +

    akua pulls the chart into $XDG_CACHE_HOME/akua/oci/ on first akuapkg add / akuapkg render, verifying the blob digest against akua.lock on subsequent renders. See Phase 2b in docs/roadmap.md.

    Local fork override

    While iterating on a chart, point a real oci:// dep at a local clone without losing the canonical source-of-record:

    nginx = { oci = "oci://registry-1.docker.io/bitnamicharts/nginx", version = "18.2.0", replace = { path = "../nginx-fork" } }

    akua.lock still records the oci:// digest; files resolve from ../nginx-fork. Drop the replace clause to switch back.

    See also

    - +

    package.k

    # Example 01 — hello-webapp
     #
     # Smallest useful akua Package. One local-path chart dep, a few public
     # inputs, raw-manifest output.
     #
     # Render:
    -#   akua render --inputs inputs.yaml      # render to ./rendered by default
    +#   akuapkg render --inputs inputs.yaml      # render to ./rendered by default
     
     import akua.ctx
     import charts.nginx as nginx    # Phase 2a: resolved from akua.toml
    @@ -425,12 +425,12 @@ 

    001-service-hello.yaml

    apiVersion: v1
       type: ClusterIP
     

    - Source: examples/01-hello-webapp/ + Source: examples/01-hello-webapp/

    diff --git a/site/examples/02-webapp-postgres.html b/site/examples/02-webapp-postgres.html index 11b717d5..be55199a 100644 --- a/site/examples/02-webapp-postgres.html +++ b/site/examples/02-webapp-postgres.html @@ -313,9 +313,9 @@

    Layout

    What's new vs 01

    • Two sources in one Package. Both are <chart>.template(...) calls (alias-method form, dispatched via the synthesized charts.<name> stub) returning resource lists; resources = [*_pg, *_labeled] aggregates them.
    • Cross-source wiring by convention. The webapp references the Postgres Secret by its predictable CloudNativePG name (${appName}-pg-app). No value needs to flow between the two source calls — both derive their values from input.
    • List-comprehension overlay. [r | {metadata.labels |= {"team": ...}} for r in _app] stamps a team label onto everything the app chart emits — same effect a Helm post-renderer would have, expressed in plain KCL after the typed list returns.
    • Unit tests. test_package.k asserts schema defaults and validates that check: blocks catch the invariant violations.

    Run

    -
    akua add                                 # resolve cnpg + webapp charts
    -akua render --inputs inputs.yaml         # render both into ./rendered/
    -akua test                                # run test_package.k
    +
    akuapkg add                                 # resolve cnpg + webapp charts
    +akuapkg render --inputs inputs.yaml         # render both into ./rendered/
    +akuapkg test                                # run test_package.k

    The cross-source convention pattern

    CloudNativePG (and most mature Kubernetes operators) publishes contracts on resource naming — cluster foo creates Secret foo-app with key uri. That's a runtime contract. The webapp references it by the same convention at render time:

    env = [{
    @@ -327,9 +327,9 @@ 

    The cross-source convention pattern }]

    If CNPG ever changed its naming convention, this is the one place we'd update — still at CI time, still deterministic. No cluster.get() runtime call ever needed.

    What's disallowed

    -
    • Source A cannot reference Source B's output. Both derive from input; cross-source late-binding is the RGD case. If you genuinely need it, route that source to a ResourceGraphDefinition output and let kro reconcile. See 06-multi-engine/ for the pattern.
    • No runtime cluster reads from KCL. Determinism is load-bearing (design-notes.md §2.2).
    +
    • Source A cannot reference Source B's output. Both derive from input; cross-source late-binding is the RGD case. If you genuinely need it, route that source to a ResourceGraphDefinition output and let kro reconcile. See 06-multi-engine/ for the pattern.
    • No runtime cluster reads from KCL. Determinism is load-bearing (design-notes.md §2.2).

    See also

    - +

    package.k

    # Example 02 — webapp-postgres
     #
     # Cross-source wiring. A webapp consumes a Postgres connection URL from a
    @@ -343,7 +343,7 @@ 

    package.k

    # Example 02 — webapp-postgres
     #   - optional postRenderer for cross-cutting mutation (team label)
     #
     # Render:
    -#   akua render --inputs inputs.yaml --out ./rendered
    +#   akuapkg render --inputs inputs.yaml --out ./rendered
     
     import akua.ctx
     import charts.cnpg    as cnpg
    @@ -409,12 +409,12 @@ 

    package.k

    # Example 02 — webapp-postgres
     

    - Source: examples/02-webapp-postgres/ + Source: examples/02-webapp-postgres/

    diff --git a/site/examples/03-multi-env-app.html b/site/examples/03-multi-env-app.html index bae3eec7..43731201 100644 --- a/site/examples/03-multi-env-app.html +++ b/site/examples/03-multi-env-app.html @@ -340,30 +340,30 @@

    Why one App p for e, v in envs ]

    Same output. Pure KCL. No special akua flags, no akua-owned schema to obey.

    Render

    -
    akua add                            # resolve deps → writes akua.lock
    -akua render                         # renders every App document it finds
    -akua render --filter=env=production # narrow to one env using a general filter
    -

    There is no --env or --all-envs flag. akua render processes every document of a KCL-declared shape in the workspace. Filtering is a general-purpose concern expressed via --filter over any field, not an env-specific primitive.

    +
    akuapkg add                            # resolve deps → writes akua.lock
    +akuapkg render                         # renders every App document it finds
    +akuapkg render --filter=env=production # narrow to one env using a general filter
    +

    There is no --env or --all-envs flag. akuapkg render processes every document of a KCL-declared shape in the workspace. Filtering is a general-purpose concern expressed via --filter over any field, not an env-specific primitive.

    Deriving YAML views

    Reconcilers consume YAML. The .k files are authoritative; the YAML view is derived on demand:

    -
    akua export apps/checkout/production.k --format=yaml > apps/checkout/production.yaml
    -akua export environments/production.k  --format=yaml > environments/production.yaml
    +
    akuapkg export apps/checkout/production.k --format=yaml > apps/checkout/production.yaml
    +akuapkg export environments/production.k  --format=yaml > environments/production.yaml

    Check these YAML files in or don't — they regenerate deterministically. The rule: never hand-edit the YAML — edit the .k and re-export.

    Flow for a change

    -
    1. Edit apps/checkout/production.k (e.g. bump replicas from 5 to 7).
    2. CI runs akua check && akua lint && akua test && akua render.
    3. akua policy check --tier=tier/production against the rendered manifests — returns allow / deny / needs-approval.
    4. If needs-approval: the review surface notifies approvers; human approves.
    5. PR merges; deploy repo gets updated YAML; Argo/Flux reconciles.
    +
    1. Edit apps/checkout/production.k (e.g. bump replicas from 5 to 7).
    2. CI runs akuapkg check && akuapkg lint && akuapkg test && akuapkg render.
    3. akua policy check --tier=tier/production against the rendered manifests — returns allow / deny / needs-approval.
    4. If needs-approval: the review surface notifies approvers; human approves.
    5. PR merges; deploy repo gets updated YAML; Argo/Flux reconciles.

    Why this design

    • "Substrate, not content." akua provides the typed authoring language (KCL), the signed distribution (Package + OCI), the deterministic pipeline, the policy host. Workspace concepts (App, Environment, whatever else) are workspace territory. That's what the CLAUDE.md invariant means in practice.
    • Enterprise reality. Every org's deployment shape is subtly different — additional approver rules, per-env secret stores, SLO targets, blue/green weights, regulatory fields. A ship-your-own-Environment-kind approach would pick one shape and lose the rest. Letting users define their own schemas means nobody is forced through a shape that misses a field they need.
    • akua Cloud carries its own concepts. If the commercial Cloud offering needs "Workspace", "Tenant", cross-workspace "Environment" — those are Convex schemas in the Cloud backend, not OSS KRMs. Keep the OSS surface small.

    See also

    - +

    - Source: examples/03-multi-env-app/ + Source: examples/03-multi-env-app/

    diff --git a/site/examples/04-policy-tier.html b/site/examples/04-policy-tier.html index 7637afd3..e7bcc8d5 100644 --- a/site/examples/04-policy-tier.html +++ b/site/examples/04-policy-tier.html @@ -303,7 +303,7 @@

    Example 04 — policy tier

    A workspace policy gate. Shows the policy stack end-to-end:

    • Authoring a Rego policy on top of an imported signed tier
    • Bringing in Kyverno rules via compile-resolved import (not runtime string lookup)
    • Running akua policy check against passing + failing fixtures
    • A *_test.rego file showing the test shape
    -

    This is the smallest example that exercises every part of the policy architecture described in policy-format.md.

    +

    This is the smallest example that exercises every part of the policy architecture described in policy-format.md.

    akua does not ship a PolicySet kind. Composition happens as plain Rego file layout: local .rego files import tiers as compile-resolved data.* via akua.toml. The workspace's policy layout is the workspace's concern.

    Layout

    04-policy-tier/
    @@ -321,7 +321,7 @@ 

    1. Declared deps — akua.toml[dependencies] tier-prod = { oci = "oci://policies.akua.dev/tier/production", version = "1.2.0" } kyv-sec = { oci = "oci://policies.akua.dev/kyverno/security", version = "2.0.0" }

    -

    Both deps are signed OCI artifacts. The first is akua's reference tier/production Rego bundle; the second is a Kyverno bundle that akua converts to Rego at akua add time (stored under .akua/policies/vendor/). The akua.lock ledger records the resolved digest and cosign signature for each.

    +

    Both deps are signed OCI artifacts. The first is akua's reference tier/production Rego bundle; the second is a Kyverno bundle that akua converts to Rego at akuapkg add time (stored under .akua/policies/vendor/). The akua.lock ledger records the resolved digest and cosign signature for each.

    No runtime lookups. Every import resolves at build time.

    2. Local rules — policies/production.rego

    Inherits rules from the two imports and adds a cross-resource aggregation rule specific to this workspace (per-env CPU budget, team-label requirement).

    @@ -329,7 +329,7 @@

    3. Composition is just Rego

    There is no PolicySet resource to declare. akua policy check --tier=./policies evaluates the Rego package under ./policies/ with the imports resolved from akua.toml. If you want to compose multiple local policy packages, lay them out under ./policies/<name>/ — Rego's own import + rule-merging is the composition mechanism.

    Running it

    # 1. Resolve deps + write akua.lock
    -akua add
    +akuapkg add
     
     # 2. Evaluate the tier against a passing fixture → verdict: allow
     akua policy check --tier=./policies --input=fixtures/good.yaml
    @@ -338,7 +338,7 @@ 

    Running it

    akua policy check --tier=./policies --input=fixtures/bad.yaml # 4. Run the test file -akua test policies/
    +akuapkg test policies/

    Exit codes from akua policy check:

    • 0 — allow
    • 3 — policy deny (the verdict was deny; rule violations printed to stdout as JSON when --json is passed)
    • 5 — needs-approval (the verdict was needs-approval; human review required before the change proceeds)

    The shape of a deny response

    @@ -357,16 +357,16 @@

    The shape of a deny response

    }

    Line + field precision. Agent-parseable. No stderr surprises.

    See also

    - +

    - Source: examples/04-policy-tier/ + Source: examples/04-policy-tier/

    diff --git a/site/examples/05-tests-and-golden.html b/site/examples/05-tests-and-golden.html index 87b38263..226c45d2 100644 --- a/site/examples/05-tests-and-golden.html +++ b/site/examples/05-tests-and-golden.html @@ -302,11 +302,11 @@

    Example 05 — tests and golden fixtures

    Shows where tests live and what each kind looks like:

    Shows where tests live and what each kind looks like:

    -
    • **test_*.k** — KCL unit tests. Exercise the Package's Input schema, defaults, and check: blocks.
    • **_test.rego* — Rego policy tests. Feed fixtures to the policy package and assert verdicts.
    • testdata/golden/<fixture>/ — golden render output. akua test --golden renders the Package against each input under testdata/inputs/ and diffs the result against the expected bytes. A drift is a test failure.
    +
    • **test_*.k** — KCL unit tests. Exercise the Package's Input schema, defaults, and check: blocks.
    • **_test.rego* — Rego policy tests. Feed fixtures to the policy package and assert verdicts.
    • testdata/golden/<fixture>/ — golden render output. akuapkg test --golden renders the Package against each input under testdata/inputs/ and diffs the result against the expected bytes. A drift is a test failure.

    All three kinds run under one verb:

    -
    akua test                   # runs *_test.rego, test_*.k, golden fixtures
    -akua test --golden          # golden-only
    -akua test --update-golden   # overwrite golden with current render (use carefully)
    +
    akuapkg test                   # runs *_test.rego, test_*.k, golden fixtures
    +akuapkg test --golden          # golden-only
    +akuapkg test --update-golden   # overwrite golden with current render (use carefully)

    Layout

    05-tests-and-golden/
     ├── akua.toml
    @@ -352,17 +352,17 @@ 

    Rego policy tests (po contains(msg, "must have a team label") }

    Golden tests

    -

    For each fixture under testdata/inputs/, akua test --golden:

    -
    1. Runs akua render --inputs=testdata/inputs/<name>.yaml.
    2. Writes a temporary output.
    3. Diffs against testdata/golden/<name>/ byte-for-byte.
    4. Fails the test on any drift, printing the diff.
    +

    For each fixture under testdata/inputs/, akuapkg test --golden:

    +
    1. Runs akuapkg render --inputs=testdata/inputs/<name>.yaml.
    2. Writes a temporary output.
    3. Diffs against testdata/golden/<name>/ byte-for-byte.
    4. Fails the test on any drift, printing the diff.

    Updates go through the human:

    -
    akua render --inputs=testdata/inputs/minimal.yaml --out=/tmp/render
    +
    akuapkg render --inputs=testdata/inputs/minimal.yaml --out=/tmp/render
     diff -r /tmp/render testdata/golden/minimal/    # eyeball the drift
    -akua test --update-golden                        # commit the new expectation
    +akuapkg test --update-golden # commit the new expectation

    Golden tests are the cheapest way to catch "I accidentally changed the output shape in a refactor" regressions. They're also the cheapest way to generate false positives when engine versions bump — the diff is the signal, not the test's opinion.

    When to add what

    -
    • Writing a Package for the first time → test_*.k for schema + defaults.
    • Landing non-trivial rendering logic → add a golden fixture.
    • Authoring a policy → always write *_test.rego alongside.
    • Bumping an engine version (e.g. Helm v4 → v4.1) → run akua test --golden first; expect some drift, review it, update if sound.
    +
    • Writing a Package for the first time → test_*.k for schema + defaults.
    • Landing non-trivial rendering logic → add a golden fixture.
    • Authoring a policy → always write *_test.rego alongside.
    • Bumping an engine version (e.g. Helm v4 → v4.1) → run akuapkg test --golden first; expect some drift, review it, update if sound.

    See also

    - +

    package.k

    import akua.ctx
     import charts.nginx as nginx
     
    @@ -393,12 +393,12 @@ 

    package.k

    import akua.ctx
     

    - Source: examples/05-tests-and-golden/ + Source: examples/05-tests-and-golden/

    diff --git a/site/examples/06-multi-engine.html b/site/examples/06-multi-engine.html index c609bbf0..de284668 100644 --- a/site/examples/06-multi-engine.html +++ b/site/examples/06-multi-engine.html @@ -332,8 +332,8 @@

    Aggregation

    resources = [*_app, *_monitor, _netpol, _glue]

    One Package, one flat resource list, one render output. ArgoCD/Flux applies the rendered YAML as it would any other manifest set; kro's controller sees the RGD and reconciles its instances.

    Render

    -
    akua add                         # resolve deps
    -akua render --inputs inputs.yaml --out ./deploy
    +
    akuapkg add                         # resolve deps
    +akuapkg render --inputs inputs.yaml --out ./deploy

    Result:

    deploy/
     ├── 000-deployment-webapp.yaml          # from helm
    @@ -344,7 +344,7 @@ 

    Render

    ├── 005-networkpolicy-webapp.yaml # from inline KCL └── 006-resourcegraphdefinition-glue.yaml # from kro.rgd — kro reconciles it

    See also

    - +

    package.k

    # Example 06 — multi-engine
     #
     # One Package, four sources, one render output (raw YAML):
    @@ -354,8 +354,8 @@ 

    package.k

    # Example 06 — multi-engine
     #   - Inline KCL  (NetworkPolicy authored directly in KCL)
     #
     # Render:
    -#   akua add
    -#   akua render --inputs inputs.yaml --out ./deploy
    +#   akuapkg add
    +#   akuapkg render --inputs inputs.yaml --out ./deploy
     
     import akua.ctx
     import akua.kustomize
    @@ -440,12 +440,12 @@ 

    package.k

    # Example 06 — multi-engine
     

    - Source: examples/06-multi-engine/ + Source: examples/06-multi-engine/

    diff --git a/site/examples/07-package-reuse.html b/site/examples/07-package-reuse.html index 7d2a6710..16f6dea7 100644 --- a/site/examples/07-package-reuse.html +++ b/site/examples/07-package-reuse.html @@ -302,7 +302,7 @@

    Example 07 — package reuse (cross-package composition)

    One akua Package composing another. The reuser pins the base Package by OCI digest in `akua.toml`, imports its `Input` schema into its own schema (as a nested field), and renders the base's...

    One akua Package composing another. The reuser pins the base Package by OCI digest in akua.toml, imports its Input schema into its own schema (as a nested field), and renders the base's resources inline alongside its own additions.

    -

    This is what cross-package composition looks like when the full spec lands — the shape this axis is settling into. Masterplan §18 and design-notes.md §6 still list this as an open question for the final API surface. Use this example as the north-star shape; expect minor signature tweaks as the spec locks in.

    +

    This is what cross-package composition looks like when the full spec lands — the shape this axis is settling into. Masterplan §18 and design-notes.md §6 still list this as an open question for the final API surface. Use this example as the north-star shape; expect minor signature tweaks as the spec locks in.

    The pattern

    ┌──────────────────────────────────────────────────────────────┐
     │ platform-base                                                 │  (separate repo, OCI-published)
    @@ -360,19 +360,19 @@ 

    The mechanism

    # Aggregate. resources = [*_base, _dashboard]

    Three things fall out of this shape:

    -
    1. Type safety. The base's Input is a nested schema; misspelling a field fails at compile time with a line + column pointer. No "I forgot the base needs hostname" at render time.
    2. Pinned by digest. akua.toml + akua.lock pin the base to a specific OCI digest. Base publishes v1.1 → you don't pick it up until you akua add explicitly. No silent drift.
    3. Signed provenance. akua verify on the consumer walks the attestation chain: the consumer's SLSA predicate includes the base's digest, which carries its own SLSA predicate, which carries the base's sources. Auditable back to the original chart authors.
    +
    1. Type safety. The base's Input is a nested schema; misspelling a field fails at compile time with a line + column pointer. No "I forgot the base needs hostname" at render time.
    2. Pinned by digest. akua.toml + akua.lock pin the base to a specific OCI digest. Base publishes v1.1 → you don't pick it up until you akuapkg add explicitly. No silent drift.
    3. Signed provenance. akuapkg verify on the consumer walks the attestation chain: the consumer's SLSA predicate includes the base's digest, which carries its own SLSA predicate, which carries the base's sources. Auditable back to the original chart authors.

    Running it

    -
    akua add                                 # resolves deps → writes akua.lock
    -akua render --inputs inputs.yaml         # composes base + local additions
    -akua inspect oci://pkg.acme.corp/platform-base:1.0   # peek at what we're pinning
    +
    akuapkg add                                 # resolves deps → writes akua.lock
    +akuapkg render --inputs inputs.yaml         # composes base + local additions
    +akuapkg inspect oci://pkg.acme.corp/platform-base:1.0   # peek at what we're pinning

    When to reuse vs fork

    Reuse when the base captures a genuine shared convention: your org's production-ready webapp shape, a standard observability stack, a licensed vendor package you subscribe to.

    Fork when you need base-level invariants that don't exist yet. Forking means copying the base's Package.k into your workspace and editing it. You lose the upgrade path; you own the full surface.

    Don't reuse to avoid learning KCL. If the base's author didn't anticipate your override, reuse leads to a pile of postRenderer hacks that are harder to maintain than a fork.

    Open-question addendum

    -

    This axis is specced to the shape shown above but the exact signature of pkg.render(Package, inputs) vs alternatives (base.render(input.base), auto-unwrapping imports, etc.) may iterate before the spec locks in. See masterplan §18 open question 6 and design-notes.md §6. Consumers of this example: don't hard-code the exact callable name in skills or training material yet.

    +

    This axis is specced to the shape shown above but the exact signature of pkg.render(Package, inputs) vs alternatives (base.render(input.base), auto-unwrapping imports, etc.) may iterate before the spec locks in. See masterplan §18 open question 6 and design-notes.md §6. Consumers of this example: don't hard-code the exact callable name in skills or training material yet.

    See also

    - +

    package.k

    # Example 07 — package reuse
     #
     # Composes a base Package (pinned by OCI digest in akua.toml) and adds local
    @@ -380,8 +380,8 @@ 

    package.k

    # Example 07 — package reuse
     # preserving end-to-end type safety.
     #
     # Render:
    -#   akua add
    -#   akua render --inputs inputs.yaml
    +#   akuapkg add
    +#   akuapkg render --inputs inputs.yaml
     
     import akua.ctx
     import akua.pkg                            # package-as-source engine callable
    @@ -467,26 +467,26 @@ 

    package.k

    # Example 07 — package reuse
     # owner references, not list position.
     resources = [*_base, _dashboard, *_extra_ingresses]
     
    -# Metadata for `akua inspect` and audit surfaces.
    +# Metadata for `akuapkg inspect` and audit surfaces.
     metadata = {
         name:        "checkout-with-dashboard"
         version:     "0.1.0"
         description: "platform-base + experimental dashboard + multi-host routing"
         publisher:   "github.com/acme/checkout"
     
    -    # The walk that `akua verify` follows: this Package's attestation
    +    # The walk that `akuapkg verify` follows: this Package's attestation
         # references the base's attestation, which references its source charts.
         extends: ["oci://pkg.acme.corp/platform-base@sha256:c7e4b8a1..."]
     }
     

    - Source: examples/07-package-reuse/ + Source: examples/07-package-reuse/

    diff --git a/site/examples/08-pkg-compose.html b/site/examples/08-pkg-compose.html index b533a7d8..9dc45636 100644 --- a/site/examples/08-pkg-compose.html +++ b/site/examples/08-pkg-compose.html @@ -303,11 +303,11 @@

    08-pkg-compose

    Package composition via pkg.render — an outer Package calls a reusable inner Package twice with different inputs and concatenates the results. Renders end-to-end today (pure KCL; no helm needed).

    What's here

    -
    filepurpose
    package.kOuter Package; calls pkg.render(pkg.Render { package = "shared", ... }) twice with distinct inputs.
    shared/package.kInner Package; emits one ConfigMap parameterized by name + payload.
    shared/akua.tomlInner manifest — marks shared/ as an Akua package.
    akua.tomlOuter manifest — declares shared as a workspace-local path dep.
    inputs.example.yamlPer-component inputs, auto-discovered by akua render.
    +
    filepurpose
    package.kOuter Package; calls pkg.render(pkg.Render { package = "shared", ... }) twice with distinct inputs.
    shared/package.kInner Package; emits one ConfigMap parameterized by name + payload.
    shared/akua.tomlInner manifest — marks shared/ as an Akua package.
    akua.tomlOuter manifest — declares shared as a workspace-local path dep.
    inputs.example.yamlPer-component inputs, auto-discovered by akuapkg render.

    Render

    -
    cargo run -q -p akua-cli -- render --package examples/08-pkg-compose/package.k --out ./rendered
    +
    cargo run -q -p akuapkg-cli -- render --package examples/08-pkg-compose/package.k --out ./rendered

    Or, from the example directory:

    -
    akua render --out ./rendered
    +
    akuapkg render --out ./rendered

    Two ConfigMaps land in ./rendered/ (checked in as reference output):

    rendered/
     ├── 000-configmap-frontend.yaml
    @@ -323,7 +323,7 @@ 

    package.k

    # Outer Package: composes two Conf
     #
     # Render:
     #
    -#   akua render --package examples/08-pkg-compose/package.k --out ./rendered
    +#   akuapkg render --package examples/08-pkg-compose/package.k --out ./rendered
     #
     # Produces two ConfigMaps: `config-frontend` and `config-backend`,
     # each with its own data payload from the outer's inputs.
    @@ -388,12 +388,12 @@ 

    001-configmap-backend.yaml

    apiVersion: v1
       LOG_LEVEL: info
     

    - Source: examples/08-pkg-compose/ + Source: examples/08-pkg-compose/

    diff --git a/site/examples/09-kustomize-hello.html b/site/examples/09-kustomize-hello.html index 38ec97cb..268660fa 100644 --- a/site/examples/09-kustomize-hello.html +++ b/site/examples/09-kustomize-hello.html @@ -301,16 +301,16 @@

    09-kustomize-hello

    Smallest Package that exercises akua's `kustomize.build` engine callable end-to-end.

    -
    Renders end-to-end via the embedded kustomize-engine-wasm. No kustomize binary on $PATH needed or consulted. Kustomize runs inside a wasmtime WASI sandbox against an in-memory filesystem unpacked from a tar.gz sent over the WASM ABI. See docs/security-model.md + docs/roadmap.md Phase 3.
    +
    Renders end-to-end via the embedded kustomize-engine-wasm. No kustomize binary on $PATH needed or consulted. Kustomize runs inside a wasmtime WASI sandbox against an in-memory filesystem unpacked from a tar.gz sent over the WASM ABI. See docs/security-model.md + docs/roadmap.md Phase 3.

    Smallest Package that exercises akua's kustomize.build engine callable end-to-end.

    What's here

    filepurpose
    package.kKCL Package; imports akua.kustomize, calls kustomize.build("./overlay"), wires the result into resources.
    akua.tomlManifest — no external deps.
    base/Base layer — a single ConfigMap.
    overlay/Overlay — adds a namePrefix + commonLabels.

    Render

    task build:kustomize-engine-wasm          # once per machine
    -akua render --package examples/09-kustomize-hello/package.k --out ./rendered
    +akuapkg render --package examples/09-kustomize-hello/package.k --out ./rendered

    The rendered ConfigMap lands at ./rendered/000-configmap-prod-hello.yaml — named prod-hello with the overlay's env: prod label applied. Checked in alongside the example so you can eyeball the output without running anything.

    Spec

    -

    See docs/package-format.md for the Package shape and docs/cli.md akua render.

    +

    See docs/package-format.md for the Package shape and docs/cli.md akuapkg render.

    package.k

    # Minimal Package that exercises the `kustomize.build` plugin callable.
     #
     # Wraps the adjacent `./overlay/` (which layers a namePrefix + labels
    @@ -320,7 +320,7 @@ 

    package.k

    # Minimal Package that exercises t
     #
     # Render:
     #
    -#   akua render --package examples/09-kustomize-hello/package.k --out ./rendered
    +#   akuapkg render --package examples/09-kustomize-hello/package.k --out ./rendered
     #
     # No inputs — the kustomization tree is fully declarative.
     
    @@ -342,12 +342,12 @@ 

    Rendered output

    000-configmap-prod-hello.yaml

    
    -  Source: examples/09-kustomize-hello/
    +  Source: examples/09-kustomize-hello/
     

    diff --git a/site/examples/10-kcl-ecosystem.html b/site/examples/10-kcl-ecosystem.html index e93f291d..078dce1f 100644 --- a/site/examples/10-kcl-ecosystem.html +++ b/site/examples/10-kcl-ecosystem.html @@ -314,7 +314,7 @@

    package.k

    # Package that consumes the upstre
     #
     # Render:
     #
    -#   akua render --package examples/10-kcl-ecosystem/package.k --out ./rendered
    +#   akuapkg render --package examples/10-kcl-ecosystem/package.k --out ./rendered
     #
     # Bigger pitch: any package on ghcr.io/kcl-lang/* (or any kpm-published
     # OCI ref) plugs in the same way. akua handles the digest pin, signature
    @@ -376,12 +376,12 @@ 

    Rendered output

    000-deployment-hello.yaml

    
    -  Source: examples/10-kcl-ecosystem/
    +  Source: examples/10-kcl-ecosystem/
     

    diff --git a/site/examples/11-install-as-package.html b/site/examples/11-install-as-package.html index 7d65b8ad..f9d9b38f 100644 --- a/site/examples/11-install-as-package.html +++ b/site/examples/11-install-as-package.html @@ -303,9 +303,9 @@

    11-install-as-package

    Composes a third-party Akua package (./upstream/) and applies a tenant overlay, drops a kind, and appends extras — the install-as-Package shape. Demonstrates the natural call form upstream.render(upstream.Input{...}): typed inputs at the consumer call site, no path strings in user code.

    Layout

    -
    filepurpose
    upstream/package.kSibling Akua package — Deployment + Service + PodDisruptionBudget. Authored as a normal Package; nothing about it is install-aware.
    akua.tomlDep alias upstream = { path = "./upstream" } for akua tree + lock-time validation.
    package.kThe install: upstream.render(...), overlay tenant label, drop PDB, append a ConfigMap.
    inputs.example.yamlPer-install inputs (tenant, app, replicas).
    rendered/Reference output (3 files: Deployment, Service, ConfigMap).
    +
    filepurpose
    upstream/package.kSibling Akua package — Deployment + Service + PodDisruptionBudget. Authored as a normal Package; nothing about it is install-aware.
    akua.tomlDep alias upstream = { path = "./upstream" } for akuapkg tree + lock-time validation.
    package.kThe install: upstream.render(...), overlay tenant label, drop PDB, append a ConfigMap.
    inputs.example.yamlPer-install inputs (tenant, app, replicas).
    rendered/Reference output (3 files: Deployment, Service, ConfigMap).

    Render

    -
    akua render --out ./rendered
    +
    akuapkg render --out ./rendered

    The install pattern

    import pkgs.upstream as upstream
     
    @@ -321,7 +321,7 @@ 

    The install pattern

    _extras = [{apiVersion = "v1", kind = "ConfigMap", ...}] resources = _filtered + _extras
    -

    The import lands a synthesized stub that owns a render lambda and re-exports upstream's schemas — KCL type-checks upstream.Input{...} at the call site (typos surface as compile errors, not as runtime worker traps). The mechanism mirrors import charts.<name> for Helm charts; see docs/package-format.md for the full shape.

    +

    The import lands a synthesized stub that owns a render lambda and re-exports upstream's schemas — KCL type-checks upstream.Input{...} at the call site (typos surface as compile errors, not as runtime worker traps). The mechanism mirrors import charts.<name> for Helm charts; see docs/package-format.md for the full shape.

    package.k

    import akua.ctx
     import pkgs.upstream as upstream
     
    @@ -415,12 +415,12 @@ 

    002-configmap-webapp-install-meta.yaml

    apiV
       upstreamApp: webapp
     

    - Source: examples/11-install-as-package/ + Source: examples/11-install-as-package/

    diff --git a/site/examples/12-vendor-offline.html b/site/examples/12-vendor-offline.html index 3d7f1ad7..8b519f93 100644 --- a/site/examples/12-vendor-offline.html +++ b/site/examples/12-vendor-offline.html @@ -301,10 +301,10 @@

    example 12 — vendor-offline (render without network or auth)

    A Package whose dep is materialized into `.akua/vendor//` so render works without re-fetching from the canonical source. This example takes the offline guarantee literally — the canonical...

    -
    Renders end-to-end off the local vendor tree. No registry, no network, no credentials needed at render time. The same Package renders identically inside an air-gapped environment or behind a firewall once akua vendor add has staged the bytes.
    +
    Renders end-to-end off the local vendor tree. No registry, no network, no credentials needed at render time. The same Package renders identically inside an air-gapped environment or behind a firewall once akuapkg vendor add has staged the bytes.

    A Package whose dep is materialized into .akua/vendor/<name>/ so render works without re-fetching from the canonical source. This example takes the offline guarantee literally — the canonical upstream-chart/ source is not present in the checkout. Render succeeds because the resolver finds the bytes under .akua/vendor/upstream/.

    Why vendor

    -

    The resolver prefers .akua/vendor/<name>/ when it exists for every dep kind — path, OCI, and git alike (see chart_resolver::resolve_with_options). akua vendor add is the public CLI verb that populates that path from a declared dep and pins the digest in akua.lock. The contract:

    +

    The resolver prefers .akua/vendor/<name>/ when it exists for every dep kind — path, OCI, and git alike (see chart_resolver::resolve_with_options). akuapkg vendor add is the public CLI verb that populates that path from a declared dep and pins the digest in akua.lock. The contract:

    • The dep declaration in akua.toml stays canonical (path / oci

    / git). It records what the dep is.

    • .akua/vendor/<name>/ records the bytes you want render to use.
    @@ -322,17 +322,17 @@

    Try it

    ls .akua/vendor/upstream/ # → Chart.yaml templates/ # 3. Render — succeeds without network, auth, or canonical source: -akua render --out ./rendered +akuapkg render --out ./rendered -# 4. Verify integrity — `akua vendor check` re-hashes the vendor tree +# 4. Verify integrity — `akuapkg vendor check` re-hashes the vendor tree # and compares against akua.lock: -akua vendor check +akuapkg vendor check # → ok # 5. List what's vendored, including any orphan trees that no longer # correspond to a dep in akua.toml: -akua vendor list
    -

    To regenerate the vendor tree from a canonical source (e.g., during development before committing), restore upstream-chart/ and run akua vendor add upstream.

    +akuapkg vendor list
    +

    To regenerate the vendor tree from a canonical source (e.g., during development before committing), restore upstream-chart/ and run akuapkg vendor add upstream.

    When vendoring matters

    For interactive Package authoring, vendoring is overkill — let the resolver fetch from OCI or git on every render.

    It earns its keep when:

    @@ -345,17 +345,17 @@

    When vendoring matters

    • Per-customer install repos (the cnap install-as-Package use

    case). The install pipeline mints a per-install token, vendors the composed Package's bytes once at bootstrap, and commits the result. Subsequent renders need neither the token nor network access.

    Out of scope (for now)

    -
    • Recursive transitive vendoring. akua vendor add upstream
    -

    vendors upstream only. If upstream itself depends on a chart that needs network at render time, vendor that too — track CI drift with akua vendor check.

    +
    • Recursive transitive vendoring. akuapkg vendor add upstream
    +

    vendors upstream only. If upstream itself depends on a chart that needs network at render time, vendor that too — track CI drift with akuapkg vendor check.

    • Workspace-wide vendor add (no name). Currently add takes

    exactly one dep name. Looping is the caller's job.

    Path-escape safety

    -

    akua vendor add rejects:

    +

    akuapkg vendor add rejects:

    • Absolute paths in path = "...". path = "/etc"E_PATH_ESCAPE.
    • Relative paths that canonicalize outside the workspace. `path =

    "../sibling"E_PATH_ESCAPE`.

    Same workspace-local invariant the resolver enforces for path deps — vendor cannot be used as a side-channel to copy arbitrary host bytes into an install repo.

    package.k

    # Renders a chart vendored into `.akua/vendor/upstream/` via
    -# `akua vendor add upstream`. The dep declaration in `akua.toml`
    +# `akuapkg vendor add upstream`. The dep declaration in `akua.toml`
     # stays canonical (`path = "./upstream-chart"`); the resolver
     # prefers the vendored copy when present, so render is offline-
     # safe once the vendor tree is committed alongside the Package.
    @@ -395,12 +395,12 @@ 

    Rendered output

    000-configmap-vendored-vendored.yaml

    - Source: examples/12-vendor-offline/ + Source: examples/12-vendor-offline/

    diff --git a/site/examples/13-subpackage-helm.html b/site/examples/13-subpackage-helm.html index 933cb501..182cd570 100644 --- a/site/examples/13-subpackage-helm.html +++ b/site/examples/13-subpackage-helm.html @@ -306,7 +306,7 @@

    13-subpackage-helm

    What's here

    filepurpose
    package.kRoot package that delegates rendering to pkgs.webserver.
    akua.tomlDeclares webserver = { path = "./deps/webserver" }.
    deps/webserver/Sub-package with its own Helm chart dependency.
    inputs.example.yamlNamespace input passed from the root to the sub-package.
    rendered/Reference output committed for integration tests.

    Render

    -
    akua render --out ./rendered
    +
    akuapkg render --out ./rendered

    The interesting part is the import boundary: root package inputs remain typed at the call site, and chart resolution stays local to the sub-package that declared the chart.

    package.k

    import akua.ctx
     import pkgs.webserver as ws
    @@ -318,7 +318,7 @@ 

    package.k

    import akua.ctx
     #
     # Render:
     #
    -#   akua render --out ./rendered
    +#   akuapkg render --out ./rendered
     schema Input:
         """Public inputs for the subpackage-helm root Package."""
         namespace: str = "demo"
    @@ -357,12 +357,12 @@ 

    Rendered output

    000-deployment-web-nginx.yaml

    
    -  Source: examples/13-subpackage-helm/
    +  Source: examples/13-subpackage-helm/
     

    diff --git a/site/examples/14-helm-repo-dep.html b/site/examples/14-helm-repo-dep.html index a277cf46..03f8da0c 100644 --- a/site/examples/14-helm-repo-dep.html +++ b/site/examples/14-helm-repo-dep.html @@ -4,12 +4,12 @@ 14-helm-repo-dep — akua - + - + @@ -299,14 +299,14 @@

    akua / examples / 14-helm-repo-dep

    14-helm-repo-dep

    -

    This example covers `repo` dependencies: charts published through an `index.yaml` rather than OCI or a local path. `akua add` resolves the repository index, pins the selected chart archive digest in...

    +

    This example covers `repo` dependencies: charts published through an `index.yaml` rather than OCI or a local path. `akuapkg add` resolves the repository index, pins the selected chart archive digest...

    Renders a Helm chart from a classic HTTPS Helm repository, pinned in akua.lock by chart version and tarball digest.
    -

    This example covers repo dependencies: charts published through an index.yaml rather than OCI or a local path. akua add resolves the repository index, pins the selected chart archive digest in akua.lock, and registers the chart as charts.podinfo for KCL rendering. Render uses Akua's embedded Helm engine; no Helm binary or shell-out is needed.

    +

    This example covers repo dependencies: charts published through an index.yaml rather than OCI or a local path. akuapkg add resolves the repository index, pins the selected chart archive digest in akua.lock, and registers the chart as charts.podinfo for KCL rendering. Render uses Akua's embedded Helm engine; no Helm binary or shell-out is needed.

    What's here

    filepurpose
    package.kImports charts.podinfo and renders it with typed values.
    akua.tomlDeclares the podinfo chart from https://stefanprodan.github.io/podinfo.
    akua.lockPins chart version 6.12.0 and the fetched archive digest.
    rendered/Reference output committed for integration tests.

    Render

    -
    akua render --out ./rendered
    +
    akuapkg render --out ./rendered

    Classic Helm repositories are useful when an upstream chart has not moved to OCI yet. The lockfile still gives the same reproducibility contract: exact chart version, exact digest, repeatable render.

    package.k

    # Package that pulls podinfo from the classic HTTPS Helm repository at
     # stefanprodan.github.io/podinfo and renders it with a typed values shape.
    @@ -316,9 +316,9 @@ 

    package.k

    # Package that pulls podinfo from
     # pins its sha256 in akua.lock, and registers the unpacked chart as the
     # `charts.podinfo` KCL module. No Helm binary required; no shell-out.
     #
    -# Render (requires `akua add` online first to populate the cache):
    +# Render (requires `akuapkg add` online first to populate the cache):
     #
    -#   akua render --out ./rendered
    +#   akuapkg render --out ./rendered
     #
     # The dep source is `repo`/`chart`/`version` rather than `oci` or `path` —
     # the same resolver machinery, a different transport. Compare with example 01
    @@ -334,12 +334,12 @@ 

    package.k

    # Package that pulls podinfo from
     

    - Source: examples/14-helm-repo-dep/ + Source: examples/14-helm-repo-dep/

    diff --git a/site/examples/index.html b/site/examples/index.html index 86f5d0cf..8230a5e1 100644 --- a/site/examples/index.html +++ b/site/examples/index.html @@ -358,12 +358,12 @@

    Examples

  • 14-helm-repo-dep — 14-helm-repo-dep -
    This example covers `repo` dependencies: charts published through an `index.yaml` rather than OCI or a local path. `akua add` resolves the repository index, pins the selected chart archive digest in...
    +
    This example covers `repo` dependencies: charts published through an `index.yaml` rather than OCI or a local path. `akuapkg add` resolves the repository index, pins the selected chart archive digest...
  • diff --git a/site/index.html b/site/index.html index 3ce2bc21..3670bba9 100644 --- a/site/index.html +++ b/site/index.html @@ -309,7 +309,7 @@

    Install (Windows)

    > irm https://cli.akua.dev/install.ps1 | iex

    From source

    -
    $ cargo install --git https://github.com/cnap-tech/akua akua-cli
    +
    $ cargo install --git https://github.com/akua-dev/akua akuapkg-cli

    SDK

    $ npm install @akua-dev/sdk
    @@ -323,8 +323,8 @@

    Docs

  • Concepts
  • Examples
  • Errors
  • -
  • GitHub
  • -
  • Releases
  • +
  • GitHub
  • +
  • Releases
  • @@ -332,7 +332,7 @@

    Docs

    diff --git a/site/start/index.html b/site/start/index.html index 14900ac0..c476e749 100644 --- a/site/start/index.html +++ b/site/start/index.html @@ -297,20 +297,20 @@

    Get started

    Install akua, render your first Package, and ship a signed artifact — in five minutes.

    -
    Pre-alpha. The path below works end-to-end on macOS / Linux. If you hit a wall, the error code reference and the verb's CLI page are the next stops.
    +
    Pre-alpha. The path below works end-to-end on macOS / Linux. If you hit a wall, the error code reference and the verb's CLI page are the next stops.

    1. Install

    $ curl -fsSL https://cli.akua.dev/install | sh
    -

    Or grab a pinned binary from Releases. Windows: irm https://cli.akua.dev/install.ps1 | iex.

    +

    Or grab a pinned binary from Releases. Windows: irm https://cli.akua.dev/install.ps1 | iex.

    Verify the install:

    -
    $ akua version
    +
    $ akuapkg version
     akua 0.8.7

    2. Initialize a workspace

    $ mkdir hello-akua && cd hello-akua
    -$ akua init
    +$ akuapkg init

    This drops three files in your workspace:

    -
    • akua.toml — manifest. Declares the package metadata + dependencies.
    • package.k — your Package, written in KCL. One file, three regions: imports, schemas, body.
    • inputs.example.yaml — example input values akua render reads when no --inputs is passed.
    +
    • akua.toml — manifest. Declares the package metadata + dependencies.
    • package.k — your Package, written in KCL. One file, three regions: imports, schemas, body.
    • inputs.example.yaml — example input values akuapkg render reads when no --inputs is passed.

    3. Render

    -
    $ akua render
    +
    $ akuapkg render

    By default, output goes to ./rendered/. Each top-level Kubernetes resource your Package emits becomes its own YAML file, prefixed with a stable index so the layout is deterministic. Same inputs + same lockfile → byte-identical output, every time.

    rendered/
     ├── 000-deployment-app.yaml
    @@ -325,23 +325,23 @@ 

    3. Render

    }

    Branch on code from agent code; the docs URL is the human-friendly fallback.

    4. Add a dependency

    -

    Composing with an upstream Helm chart? akua add updates akua.toml and akua.lock in one step:

    -
    $ akua add nginx --oci oci://ghcr.io/nginxinc/charts/nginx --version 1.0.0
    +

    Composing with an upstream Helm chart? akuapkg add updates akua.toml and akua.lock in one step:

    +
    $ akuapkg add nginx --oci oci://ghcr.io/nginxinc/charts/nginx --version 1.0.0

    Then in package.k:

    import charts.nginx as nginx

    The resolver writes a charts/<alias>/ mount so the engine plugin (helm.template, kustomize.build, …) gets a path it produced itself — no path strings in your KCL.

    5. Verify + sign + publish

    When you're ready to ship:

    -
    $ akua verify         # akua.toml ↔ akua.lock integrity + cosign signatures
    +
    $ akuapkg verify         # akua.toml ↔ akua.lock integrity + cosign signatures
     $ akua sign           # cosign-sign the artifact
    -$ akua publish        # push the signed OCI artifact + SLSA attestation
    -

    By default publish refuses unless the lockfile is clean and a cosign key is configured. See Concepts → Security model for the threat model and what strict_signing enforces.

    +$ akuapkg publish # push the signed OCI artifact + SLSA attestation
    +

    By default publish refuses unless the lockfile is clean and a cosign key is configured. See Concepts → Security model for the threat model and what strict_signing enforces.

    What's next

    -
    • Walk through the runnable examples — every one has package.k, inputs, and the rendered output side-by-side.
    • Read Concepts → Package format for the authoring shape.
    • Skim the CLI reference to see every verb at a glance — twenty-seven shipped, more in flight.
    • The SDK wraps the same surface for TypeScript / Bun / Deno consumers.
    +
    • Walk through the runnable examples — every one has package.k, inputs, and the rendered output side-by-side.
    • Read Concepts → Package format for the authoring shape.
    • Skim the CLI reference to see every verb at a glance — twenty-seven shipped, more in flight.
    • The SDK wraps the same surface for TypeScript / Bun / Deno consumers.
    diff --git a/skills/apply-policy-tier/SKILL.md b/skills/apply-policy-tier/SKILL.md index 7e361223..92ca1cb9 100644 --- a/skills/apply-policy-tier/SKILL.md +++ b/skills/apply-policy-tier/SKILL.md @@ -114,11 +114,11 @@ Commit + PR. CI runs `akua policy check` on the PR against the rendered output; ### 6. Monitor ongoing policy checks -Once the tier is assigned, every `akua deploy` and `akua dev` session checks against it: +Once the tier is assigned, every `akua deploy` and `akuapkg dev` session checks against it: ```sh akua deploy --to=argo # policy check runs automatically -akua dev --policy=tier/production # live re-check in the dev loop +akuapkg dev --policy=tier/production # live re-check in the dev loop ``` ## Compliance tiers (SOC2, HIPAA, FedRAMP) diff --git a/skills/dev-loop/SKILL.md b/skills/dev-loop/SKILL.md index 6ab9f85b..ad150513 100644 --- a/skills/dev-loop/SKILL.md +++ b/skills/dev-loop/SKILL.md @@ -1,13 +1,13 @@ --- name: dev-loop -description: Run a sub-second hot-reload development loop against a local Kubernetes cluster using `akua dev`. Use when iterating on a Package, debugging rendering, seeing a live diff of manifests as schema or inputs change, demoing an infra change, or when a user asks to preview how a change will affect deployed resources. +description: Run a sub-second hot-reload development loop against a local Kubernetes cluster using `akuapkg dev`. Use when iterating on a Package, debugging rendering, seeing a live diff of manifests as schema or inputs change, demoing an infra change, or when a user asks to preview how a change will affect deployed resources. license: Apache-2.0 compatibility: Requires Docker (for kind/k3d), or an existing k8s cluster context. Port 5173 available for the browser UI. --- -# Hot-reload development with `akua dev` +# Hot-reload development with `akuapkg dev` -`akua dev` is the signature akua experience. Watches the workspace; renders on every file save; applies to a local cluster in under 500ms; surfaces pipeline events in a browser UI at `http://localhost:5173`. +`akuapkg dev` is the signature akua experience. Watches the workspace; renders on every file save; applies to a local cluster in under 500ms; surfaces pipeline events in a browser UI at `http://localhost:5173`. ## When to use @@ -24,7 +24,7 @@ compatibility: Requires Docker (for kind/k3d), or an existing k8s cluster contex From the workspace root: ```sh -akua dev +akuapkg dev ``` On first run: creates a kind cluster named `akua-dev`, installs Traefik ingress, sets up `*.127.0.0.1.nip.io` DNS. Browser opens `http://localhost:5173`. @@ -60,7 +60,7 @@ The pipeline fires: parse → validate → render → policy check → diff → If an agent is driving the dev loop, use `--json` (auto-enabled when agent context detected — see [CLI contract §1.5](../../docs/cli-contract.md#15-agent-context-auto-detection)): ```sh -akua dev --json +akuapkg dev --json ``` Each line is a JSON event: @@ -84,13 +84,13 @@ Each line is a JSON event: Ctrl-C. The process: - Drains in-flight reconciliations gracefully (up to `--shutdown-timeout`, default 10s) -- Preserves the kind cluster + persistent data (next `akua dev` resumes where you left off) +- Preserves the kind cluster + persistent data (next `akuapkg dev` resumes where you left off) - Closes the browser UI To fully reset: ```sh -akua dev --fresh +akuapkg dev --fresh # OR kind delete cluster --name akua-dev ``` @@ -100,16 +100,16 @@ kind delete cluster --name akua-dev - **`render` slow (>500ms)** — workspace too large, or a source engine is misbehaving. Profile with `--log-level=debug`. - **`policy` denies** — UI shows the failing rule and the field/resource at fault. Fix the input and save; re-check is automatic. - **`reconcile` stuck** — pod crashlooping or health-check failing. UI surfaces last log lines; follow links to `kubectl describe`. -- **`drift detected`** — someone ran `kubectl apply` outside `akua dev`. Options: `adopt` (accept cluster state as new desired) or `revert` (snap cluster back to desired). +- **`drift detected`** — someone ran `kubectl apply` outside `akuapkg dev`. Options: `adopt` (accept cluster state as new desired) or `revert` (snap cluster back to desired). ## Failure modes -- **Docker not running** — `akua dev` needs Docker for kind. Start Docker Desktop / colima / podman. -- **Port 5173 in use** — `akua dev --ui-port 5174` +- **Docker not running** — `akuapkg dev` needs Docker for kind. Start Docker Desktop / colima / podman. +- **Port 5173 in use** — `akuapkg dev --ui-port 5174` - **kubeconfig not found** — set `$KUBECONFIG` or use `--target=cluster:` -- **Persistent data corrupt after abrupt shutdown** — `akua dev --fresh` wipes and restarts +- **Persistent data corrupt after abrupt shutdown** — `akuapkg dev --fresh` wipes and restarts ## Reference -- [cli.md — akua dev](../../docs/cli.md#akua-dev) +- [cli.md — akuapkg dev](../../docs/cli.md#akua-dev) - [Masterplan §11 — the signature experience](https://github.com/cnap-tech/cortex/blob/docs/cnap-masterplan/workspaces/robin/akua-masterplan.md) diff --git a/skills/diff-gate/SKILL.md b/skills/diff-gate/SKILL.md index 047c1322..c9c649ec 100644 --- a/skills/diff-gate/SKILL.md +++ b/skills/diff-gate/SKILL.md @@ -1,12 +1,12 @@ --- name: diff-gate -description: Set up a CI gate that runs akua diff on package upgrades and blocks merges that break schema compatibility or violate policy. Use when configuring CI for a platform repo, preventing breaking Helm-chart upgrades, gating Renovate or Dependabot PRs, or enforcing structural-compatibility checks before deployment. +description: Set up a CI gate that runs akuapkg diff on package upgrades and blocks merges that break schema compatibility or violate policy. Use when configuring CI for a platform repo, preventing breaking Helm-chart upgrades, gating Renovate or Dependabot PRs, or enforcing structural-compatibility checks before deployment. license: Apache-2.0 --- -# CI gate using `akua diff` +# CI gate using `akuapkg diff` -Dependency bumps (Renovate, Dependabot, or a human edit) can silently break production. `akua diff` returns a structural diff between two package versions and exits non-zero if schema fields change incompatibly. Wire it into CI to block bad merges. +Dependency bumps (Renovate, Dependabot, or a human edit) can silently break production. `akuapkg diff` returns a structural diff between two package versions and exits non-zero if schema fields change incompatibly. Wire it into CI to block bad merges. ## When to use @@ -15,7 +15,7 @@ Dependency bumps (Renovate, Dependabot, or a human edit) can silently break prod - As a policy requirement for production-tier deploys - Before adopting a new version of a third-party package -## What `akua diff` compares +## What `akuapkg diff` compares | category | blocks merge? | example | |---|---|---| @@ -36,7 +36,7 @@ Non-zero exit on any "yes"; warnings surface as PR comments without blocking. Create `.github/workflows/akua-diff.yml`: ```yaml -name: akua diff +name: akuapkg diff on: pull_request: @@ -63,8 +63,8 @@ jobs: if [ "$base_ref" != "$head_ref" ]; then echo "::group::Diff for ${app} ($base_ref → $head_ref)" - akua diff "$base_ref" "$head_ref" --json > diff.json || EXIT=$? - akua diff "$base_ref" "$head_ref" # human-readable for logs + akuapkg diff "$base_ref" "$head_ref" --json > diff.json || EXIT=$? + akuapkg diff "$base_ref" "$head_ref" # human-readable for logs echo "::endgroup::" fi done @@ -103,7 +103,7 @@ Enable policy-tier checking in the same workflow: ```yaml - name: Policy check run: | - akua render --filter=spec.env=production --out ./rendered + akuapkg render --filter=spec.env=production --out ./rendered akua policy check --tier tier/production --target ./rendered --json > verdict.json verdict=$(jq -r '.verdict' verdict.json) @@ -125,14 +125,14 @@ Exit code 3 (policy deny) is a distinct failure mode from exit 1 (schema breakin ## Renovate integration -Renovate can be configured to run `akua diff` as a post-upgrade task: +Renovate can be configured to run `akuapkg diff` as a post-upgrade task: ```json // renovate.json { "postUpgradeTasks": { "commands": [ - "akua diff {{baseBranch}}@{{package}} HEAD@{{package}} --json > diff.json" + "akuapkg diff {{baseBranch}}@{{package}} HEAD@{{package}} --json > diff.json" ], "fileFilters": ["diff.json"] } @@ -149,6 +149,6 @@ The diff attaches to the Renovate PR body automatically. ## Reference -- [cli.md — akua diff](../../docs/cli.md#akua-diff) +- [cli.md — akuapkg diff](../../docs/cli.md#akua-diff) - [cli.md — akua policy](../../docs/cli.md#akua-policy) - [cli-contract.md — typed exit codes](../../docs/cli-contract.md#2-exit-codes) diff --git a/skills/inspect-package/SKILL.md b/skills/inspect-package/SKILL.md index 2a82a0fa..06b7c384 100644 --- a/skills/inspect-package/SKILL.md +++ b/skills/inspect-package/SKILL.md @@ -21,7 +21,7 @@ Before consuming any package — first-party, community, or vendor — know what ### 1. Basic inspection ```sh -akua inspect oci://pkg.example.com/webapp:3.2 --json +akuapkg inspect oci://pkg.example.com/webapp:3.2 --json ``` Returns: @@ -37,7 +37,7 @@ Look at the `signer` field — it should match an identity you trust (a GitHub A ### 2. Show rendered output with sample inputs ```sh -akua inspect oci://pkg.example.com/webapp:3.2 \ +akuapkg inspect oci://pkg.example.com/webapp:3.2 \ --inputs '{"appName":"demo","hostname":"demo.example.com"}' \ --show=manifests ``` @@ -47,7 +47,7 @@ Renders the package with your inputs and prints the resulting Kubernetes YAML. T ### 3. Verify signatures directly ```sh -akua verify oci://pkg.example.com/webapp:3.2 +akuapkg verify oci://pkg.example.com/webapp:3.2 ``` Output includes: @@ -70,14 +70,14 @@ The playground renders in the browser using WASM — zero install, zero cluster, ### 5. Diff against another version ```sh -akua diff oci://pkg.example.com/webapp:3.1 oci://pkg.example.com/webapp:3.2 --json +akuapkg diff oci://pkg.example.com/webapp:3.1 oci://pkg.example.com/webapp:3.2 --json ``` Shows structural changes: schema fields added/removed/type-changed, source version bumps, policy-compatibility verdict. Non-zero exit if any structural change present. ## Expected output -On `akua inspect --json`: +On `akuapkg inspect --json`: ```json { @@ -111,11 +111,11 @@ On `akua inspect --json`: ## Failure modes - **`E_SIG_VERIFY_FAILED`** — signature does not verify. Either the artifact is tampered with, or the verification key is wrong. Do not proceed. -- **`E_FETCH_FAILED`** — cannot fetch the artifact. Check the OCI ref, check `akua whoami` for registry auth. +- **`E_FETCH_FAILED`** — cannot fetch the artifact. Check the OCI ref, check `akuapkg whoami` for registry auth. - **`E_ATTESTATION_MISSING`** — no SLSA predicate attached. Rendered output is unverifiable against a build pipeline. May be acceptable for community packages but is a red flag for production dependencies. ## Reference -- [cli.md — akua inspect](../../docs/cli.md#akua-inspect) -- [cli.md — akua verify](../../docs/cli.md#akua-verify) -- [cli.md — akua diff](../../docs/cli.md#akua-diff) +- [cli.md — akuapkg inspect](../../docs/cli.md#akua-inspect) +- [cli.md — akuapkg verify](../../docs/cli.md#akuapkg-verify) +- [cli.md — akuapkg diff](../../docs/cli.md#akua-diff) diff --git a/skills/migrate-helmfile/SKILL.md b/skills/migrate-helmfile/SKILL.md index f6aea6bf..16a0c32f 100644 --- a/skills/migrate-helmfile/SKILL.md +++ b/skills/migrate-helmfile/SKILL.md @@ -19,7 +19,7 @@ Helmfile orchestrates multiple Helm releases with templated values. akua replace ### 1. Scaffold a new akua Package ```sh -akua init +akuapkg init cd ``` @@ -72,8 +72,8 @@ Defaults that were in Helmfile's `| default 3` move into the schema's `int = 3`. For each release: ```sh -akua add chart oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 -akua add chart ./charts/webapp +akuapkg add chart oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 +akuapkg add chart ./charts/webapp ``` This generates typed `Chart` and `Values` subpackages, so you get autocomplete on chart values. @@ -119,14 +119,14 @@ _app = helm.template(webapp.Chart { ### 7. Render and verify ```sh -akua render --inputs inputs.yaml --out ./rendered +akuapkg render --inputs inputs.yaml --out ./rendered ``` Diff the output against the original Helmfile's `helmfile template` output: ```sh helmfile template > /tmp/before.yaml -akua render --inputs inputs.yaml --stdout > /tmp/after.yaml +akuapkg render --inputs inputs.yaml --stdout > /tmp/after.yaml diff /tmp/before.yaml /tmp/after.yaml ``` @@ -137,7 +137,7 @@ Expected: semantic equivalence. Cosmetic differences (whitespace, key ordering) Helmfile was reconciling via `helmfile apply`. With akua, render at CI and commit raw YAML; let ArgoCD/Flux reconcile. Update your deploy pipeline: - Remove `helmfile apply` from CI -- Add `akua render --out deploy/` to CI; commit the deploy/ directory +- Add `akuapkg render --out deploy/` to CI; commit the deploy/ directory - Configure Argo/Flux to sync from the deploy/ path ### 9. Decommission Helmfile @@ -158,6 +158,6 @@ Once the akua Package renders identically and a production run has succeeded, de ## Reference -- [cli.md — akua add](../../docs/cli.md#akua-add) +- [cli.md — akuapkg add](../../docs/cli.md#akua-add) - [examples/02-webapp-postgres](../../examples/02-webapp-postgres/) — canonical multi-source example - [new-package](../new-package/SKILL.md) — if starting fresh instead of migrating diff --git a/skills/new-package/SKILL.md b/skills/new-package/SKILL.md index 4569f665..9de470a0 100644 --- a/skills/new-package/SKILL.md +++ b/skills/new-package/SKILL.md @@ -19,7 +19,7 @@ An akua Package is a typed, reusable definition authored in KCL. One Package is ### 1. Scaffold ```sh -akua init +akuapkg init cd ``` @@ -32,30 +32,30 @@ This creates: ### 2. Add source engines -For each external source, use `akua add`. This generates a typed KCL subpackage under `./sources/` so you get autocomplete + validation on the source's native values. +For each external source, use `akuapkg add`. This generates a typed KCL subpackage under `./sources/` so you get autocomplete + validation on the source's native values. Helm chart: ```sh -akua add chart oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 +akuapkg add chart oci://ghcr.io/cloudnative-pg/charts/cluster --version 0.20.0 ``` kro RGD: ```sh -akua add rgd oci://pkg.example.com/glue-rgd:1.0 +akuapkg add rgd oci://pkg.example.com/glue-rgd:1.0 ``` Kustomize base: ```sh -akua add kustomize ./local/overlay +akuapkg add kustomize ./local/overlay ``` Another KCL package: ```sh -akua add kcl oci://ghcr.io/kcl-lang/k8s --version 1.31.2 +akuapkg add kcl oci://ghcr.io/kcl-lang/k8s --version 1.31.2 ``` ### 3. Edit the schema @@ -103,17 +103,17 @@ Each call returns a list of typed Kubernetes resources. Concatenate them with `[ ### 5. Render output -`akua render --out ./deploy` writes every entry in `resources` as its own +`akuapkg render --out ./deploy` writes every entry in `resources` as its own YAML file under `./deploy/`. No output-kind declaration — raw manifests is the single render shape. Ecosystem-specific shapes come either from in-body transformation functions (`kro.rgd(...)`, `crossplane.composition(...)` that produce K8s manifests joined into `resources`) or from future -distribution verbs like `akua publish --as `. See [docs/cli.md — akua render](../../docs/cli.md#akua-render). +distribution verbs like `akuapkg publish --as `. See [docs/cli.md — akuapkg render](../../docs/cli.md#akua-render). ### 6. Validate ```sh -akua lint +akuapkg lint ``` Catches: schema errors, unresolved source references, policy violations (if `--policy` is set). @@ -121,7 +121,7 @@ Catches: schema errors, unresolved source references, policy violations (if `--p ### 7. Render with sample inputs ```sh -akua render --inputs inputs.example.yaml --out ./rendered +akuapkg render --inputs inputs.example.yaml --out ./rendered ``` Inspect `./rendered/` — this is the exact YAML that would deploy. Committable to git. @@ -131,19 +131,19 @@ Inspect `./rendered/` — this is the exact YAML that would deploy. Committable If you have a local Kubernetes available: ```sh -akua dev +akuapkg dev ``` Opens `http://localhost:5173`, applies rendered manifests to a kind cluster, hot-reloads on every edit. ## Expected output -After `akua render`, `./rendered/` contains well-formed Kubernetes YAML, one file per resource, sorted by `kind/name`. The output is byte-deterministic: the same inputs always produce identical bytes. +After `akuapkg render`, `./rendered/` contains well-formed Kubernetes YAML, one file per resource, sorted by `kind/name`. The output is byte-deterministic: the same inputs always produce identical bytes. ## Failure modes - **`E_SCHEMA_INVALID`** — schema definition has invalid KCL. The error includes line and field; fix the schema. -- **`E_SOURCE_UNRESOLVED`** — a source reference in `akua add` failed to fetch. Check the OCI ref; verify credentials with `akua whoami`. +- **`E_SOURCE_UNRESOLVED`** — a source reference in `akuapkg add` failed to fetch. Check the OCI ref; verify credentials with `akuapkg whoami`. - **`E_POLICY_DENY`** (exit 3) — rendered manifests violate the configured policy tier. The error lists the failing rule and a suggested fix. - **`E_RENDER_FAILED`** — an engine function (helm.template, rgd.instantiate) raised an error. Usually a values-validation failure; check the source engine's own schema. diff --git a/skills/publish-signed/SKILL.md b/skills/publish-signed/SKILL.md index 348d2a0f..939a1473 100644 --- a/skills/publish-signed/SKILL.md +++ b/skills/publish-signed/SKILL.md @@ -7,7 +7,7 @@ compatibility: Requires a cosign-compatible signing key (keyless via Sigstore is # Publish a signed + attested Package -Default akua publish behavior signs the package with cosign and generates a SLSA v1 provenance predicate. No extra flags needed. This skill walks through the path, the verification, and the CI integration. +Default akuapkg publish behavior signs the package with cosign and generates a SLSA v1 provenance predicate. No extra flags needed. This skill walks through the path, the verification, and the CI integration. ## When to use @@ -40,7 +40,7 @@ Keyless Sigstore (no key material to manage): ### 2. Dry-run the publish ```sh -akua publish --to oci://ghcr.io/you/my-app --tag v1.0.0 --plan +akuapkg publish --to oci://ghcr.io/you/my-app --tag v1.0.0 --plan ``` Plan output: target ref, tag, digest (predicted), size, whether signing and attestation will apply, policy verdict. @@ -48,12 +48,12 @@ Plan output: target ref, tag, digest (predicted), size, whether signing and atte ### 3. Publish ```sh -akua publish --to oci://ghcr.io/you/my-app --tag v1.0.0 +akuapkg publish --to oci://ghcr.io/you/my-app --tag v1.0.0 ``` This: -- Builds the package (runs `akua render` internally against the declared default inputs; rejects if the package fails to render) +- Builds the package (runs `akuapkg render` internally against the declared default inputs; rejects if the package fails to render) - Computes content-addressable digest - Pushes to the target OCI registry - Generates SLSA v1 predicate from build environment @@ -77,7 +77,7 @@ Output: ### 4. Verify after publish ```sh -akua verify oci://ghcr.io/you/my-app:v1.0.0 +akuapkg verify oci://ghcr.io/you/my-app:v1.0.0 ``` Confirms: signature valid, signer identity matches expected, SLSA predicate present and valid, chain terminates at a trusted root. @@ -112,11 +112,11 @@ jobs: - name: Publish run: | akua login ghcr.io --token=${{ secrets.GITHUB_TOKEN }} - akua publish --to oci://ghcr.io/${{ github.repository }} --tag ${{ github.ref_name }} + akuapkg publish --to oci://ghcr.io/${{ github.repository }} --tag ${{ github.ref_name }} - name: Verify run: | - akua verify oci://ghcr.io/${{ github.repository }}:${{ github.ref_name }} + akuapkg verify oci://ghcr.io/${{ github.repository }}:${{ github.ref_name }} ``` The `id-token: write` permission is what enables keyless signing — GitHub Actions OIDC → Sigstore Fulcio → signing certificate embedded in the signature. No key material to manage or rotate. @@ -131,9 +131,9 @@ An agent releasing a package should always: ```sh IDEMP=$(uuidgen) -akua publish --to oci://ghcr.io/you/my-app --tag v1.0.0 \ +akuapkg publish --to oci://ghcr.io/you/my-app --tag v1.0.0 \ --idempotency-key=$IDEMP --json | tee publish.json -akua verify oci://ghcr.io/you/my-app:v1.0.0 --json | tee verify.json +akuapkg verify oci://ghcr.io/you/my-app:v1.0.0 --json | tee verify.json ``` If `verify.json.signed` is not `true` or the signer identity doesn't match expected, the release is not complete; surface to a human. @@ -148,7 +148,7 @@ Policy tiers can require: - Approvers (two-person review before production publish) ```sh -akua publish ... --plan --policy=tier/production --json +akuapkg publish ... --plan --policy=tier/production --json ``` Non-zero exit (code 3) if policy denies. Code 5 if needs approval; the output includes an approval URL agents/humans can follow. @@ -156,13 +156,13 @@ Non-zero exit (code 3) if policy denies. Code 5 if needs approval; the output in ## Failure modes - **`E_SIGN_FAILED`** — cosign can't acquire a signing certificate. Check OIDC setup (GitHub Actions `id-token: write`) or `cosign login`. -- **`E_PUSH_FAILED`** — registry rejected the push. Auth (`akua whoami`), registry quota, or network. +- **`E_PUSH_FAILED`** — registry rejected the push. Auth (`akuapkg whoami`), registry quota, or network. - **`E_ATTESTATION_FAILED`** — SLSA predicate generation failed. Usually a missing build-environment field; error message specifies which. -- **Tag already exists** — `akua publish` refuses to overwrite by default. Use `--overwrite` only if you're intentionally republishing a fixed version (and update the policy to allow it). +- **Tag already exists** — `akuapkg publish` refuses to overwrite by default. Use `--overwrite` only if you're intentionally republishing a fixed version (and update the policy to allow it). ## Reference -- [cli.md — akua publish](../../docs/cli.md#akua-publish) +- [cli.md — akuapkg publish](../../docs/cli.md#akua-publish) - [cli.md — akua attest](../../docs/cli.md#akua-attest) -- [cli.md — akua verify](../../docs/cli.md#akua-verify) +- [cli.md — akuapkg verify](../../docs/cli.md#akuapkg-verify) - [SLSA Level 3 requirements](https://slsa.dev/spec/v1.0/levels#build-l3) diff --git a/skills/test-and-lint/SKILL.md b/skills/test-and-lint/SKILL.md index 8e156592..e76120a9 100644 --- a/skills/test-and-lint/SKILL.md +++ b/skills/test-and-lint/SKILL.md @@ -20,7 +20,7 @@ akua embeds the full testing and debugging surface from its host engines (KCL, O ### 1. Add test files -Test naming conventions (discovered automatically by `akua test`): +Test naming conventions (discovered automatically by `akuapkg test`): - **KCL**: `test_*.k` or `*_test.k` anywhere under a Package - **Rego**: `*_test.rego` next to the policy files @@ -66,10 +66,10 @@ assert _default_sample.replicas == 3, "default replicas should be 3" ### 2. Run tests locally ```sh -akua test # runs everything -akua test --coverage # with coverage report -akua test --watch # TDD; re-runs on file change -akua test --filter= # only matching tests +akuapkg test # runs everything +akuapkg test --coverage # with coverage report +akuapkg test --watch # TDD; re-runs on file change +akuapkg test --filter= # only matching tests ``` Confirm all tests pass before committing. Coverage below 80% on policies is a smell. @@ -77,12 +77,12 @@ Confirm all tests pass before committing. Coverage below 80% on policies is a sm ### 3. Format + lint ```sh -akua fmt # in-place format -akua lint # style + correctness -akua check # syntax/type-only, fastest gate +akuapkg fmt # in-place format +akuapkg lint # style + correctness +akuapkg check # syntax/type-only, fastest gate ``` -Expected output on a clean workspace: zero issues. Any lint warnings include the `rule` name and usually a `fix` suggestion; apply with `akua lint --fix` where auto-fixable. +Expected output on a clean workspace: zero issues. Any lint warnings include the `rule` name and usually a `fix` suggestion; apply with `akuapkg lint --fix` where auto-fixable. ### 4. Wire pre-commit hooks @@ -93,30 +93,30 @@ repos: - repo: local hooks: - id: akua-fmt - name: akua fmt - entry: akua fmt --check + name: akuapkg fmt + entry: akuapkg fmt --check language: system pass_filenames: false - id: akua-lint - name: akua lint - entry: akua lint --severity=error + name: akuapkg lint + entry: akuapkg lint --severity=error language: system pass_filenames: false - id: akua-check - name: akua check - entry: akua check + name: akuapkg check + entry: akuapkg check language: system pass_filenames: false ``` -Fast feedback at commit time. `akua check` is the cheapest syntax/type pass; runs in under 100 ms for typical workspaces. +Fast feedback at commit time. `akuapkg check` is the cheapest syntax/type pass; runs in under 100 ms for typical workspaces. ### 5. Wire CI gates `.github/workflows/akua-test.yml`: ```yaml -name: akua test +name: akuapkg test on: [pull_request] jobs: test: @@ -127,16 +127,16 @@ jobs: run: curl -fsSL https://cli.akua.dev/install | sh - name: Check + lint run: | - akua check - akua lint --severity=error - akua fmt --check + akuapkg check + akuapkg lint --severity=error + akuapkg fmt --check - name: Test with coverage - run: akua test --coverage --min=80 + run: akuapkg test --coverage --min=80 - name: Verify lockfile - run: akua verify + run: akuapkg verify - name: Integration test — render + policy run: | - akua render --filter=spec.env=production --out ./rendered + akuapkg render --filter=spec.env=production --out ./rendered akua policy check --tier tier/production --target ./rendered ``` @@ -156,7 +156,7 @@ Common patterns: - "Expected rule to fire but didn't" — check that every condition in the rule body is `TRUE` in the trace; any `FALSE` short-circuits the rule. - "Unexpected denial" — find the rule that fired (marked `ALLOW` / result-producing); work through its conditions. -- "Different verdict in CI than local" — check `akua version --json` on both; embedded engine version mismatch is a common cause. +- "Different verdict in CI than local" — check `akuapkg version --json` on both; embedded engine version mismatch is a common cause. ### 7. Benchmark if latency matters @@ -178,30 +178,30 @@ Set minimum thresholds for policy quality: - name: Benchmark gate run: akua bench --policy=tier/production --p99-max-ms=10 - name: Ratio of tests-to-rules - run: akua lint --severity=error # fails if any rule has no test coverage + run: akuapkg lint --severity=error # fails if any rule has no test coverage ``` ## Agent-specific guidance When an agent is asked to fix a failing policy or add tests: -1. **Always `akua test --json` first** to see the failure shape in structured form. +1. **Always `akuapkg test --json` first** to see the failure shape in structured form. 2. **Use `akua trace --json`** for any unexplained denial before proposing a fix; don't guess. -3. **Add a regression test** before fixing — the test should fail in the current state and pass after the fix. This is verifiable by running `akua test` before and after. -4. **Prefer `akua lint --fix`** for auto-fixable style issues rather than editing manually. -5. **Update `akua.lock`** via `akua verify --update` if signatures or digests drifted after a dep bump. +3. **Add a regression test** before fixing — the test should fail in the current state and pass after the fix. This is verifiable by running `akuapkg test` before and after. +4. **Prefer `akuapkg lint --fix`** for auto-fixable style issues rather than editing manually. +5. **Update `akua.lock`** via `akuapkg verify --update` if signatures or digests drifted after a dep bump. ## Failure modes - **`E_TEST_FILE_NOT_FOUND`** — pattern `*_test.rego` or `test_*.k` matched nothing. Probably misnamed files. - **`E_COVERAGE_BELOW_MIN`** (exit 1) — CI gate failed. Add tests for uncovered rules; re-run with `--coverage` to see which. -- **`E_FMT_NEEDED`** (exit 1 under `--check`) — run `akua fmt` to auto-apply. +- **`E_FMT_NEEDED`** (exit 1 under `--check`) — run `akuapkg fmt` to auto-apply. - **`E_LINT_ERROR`** — severity:error issues. Not auto-fixable; author must address. - **`E_BENCH_REGRESSION`** — p99 exceeded threshold. Policy added a slow rule; profile and optimize. ## Reference -- [cli.md — akua test / fmt / lint / check / bench / trace / cov / repl / eval](../../docs/cli.md) +- [cli.md — akuapkg test / fmt / lint / check / bench / trace / cov / repl / eval](../../docs/cli.md) - [package-format.md §11 — Testing Packages](../../docs/package-format.md) - [policy-format.md §11 — Testing, linting, tracing](../../docs/policy-format.md) - [embedded-engines.md](../../docs/embedded-engines.md) — which engines drive which verbs