Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Security-sensitive areas — the actual installer surface customers run,
# plus the served landing page and CI. Same owner today; placeholder for
# when more reviewers join.
/cloudanix-guard @taurusismysign
/cdxai @taurusismysign
/lib/ @taurusismysign
/index.html @taurusismysign
/CNAME @taurusismysign
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Deploy this repo's content to GitHub Pages on every push to main.
# The repo root is published as-is:
# ./cloudanix-guard → install.cloudanix.com/cloudanix-guard
# ./cdxai → install.cloudanix.com/cdxai
# ./lib/common → install.cloudanix.com/lib/common
# ./index.html → install.cloudanix.com/

Expand Down Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Sanity-check the install scripts are executable
run: |
set -euo pipefail
for f in cloudanix-guard; do
for f in cdxai; do
[ -x "$f" ] || { echo "$f is not executable"; exit 1; }
done

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/shellcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
with:
severity: warning
# Scan everything that looks like a bash script. The product
# installers (cloudanix-guard, etc.) have no extension and
# installers (cdxai, etc.) have no extension and
# are at the repo root; the lib lives under _lib/.
scandir: '.'
additional_files: 'cloudanix-guard'
additional_files: 'cdxai'
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ One-line installers for Cloudanix products. Served at
**[install.cloudanix.com](https://install.cloudanix.com)**.

```bash
curl -fsSL https://install.cloudanix.com/cloudanix-guard | bash
curl -fsSL https://install.cloudanix.com/cdxai | bash
```

> **Env vars go on the `bash` side of the pipe**, not on `curl`. Vars
Expand Down Expand Up @@ -36,28 +36,28 @@ live in their own repositories and carry their own licenses.

| Product | URL |
|--------------------|----------------------------------------------|
| Cloudanix Guard | `install.cloudanix.com/cloudanix-guard` |
| Cloudanix Guard | `install.cloudanix.com/cdxai` |

---

## How a customer installs Cloudanix Guard

```bash
curl -fsSL https://install.cloudanix.com/cloudanix-guard | bash
curl -fsSL https://install.cloudanix.com/cdxai | bash
```

What that does (paraphrased from the [script itself](./cloudanix-guard)):
What that does (paraphrased from the [script itself](./cdxai)):

1. Verifies `curl` and `tar` are available and detects your OS/arch.
2. Downloads the matching release archive
(`cloudanix-guard_<version>_<os>_<arch>.tar.gz`) + its SHA256
(`cdxai_<version>_<os>_<arch>.tar.gz`) + its SHA256
sidecar from
`github.com/Cloudanix/artifacts/raw/main/coding-agent-guard/`.
3. Verifies the archive against its SHA256 — aborts on mismatch.
4. Extracts the self-contained `cloudanix-guard` binary — no Python,
4. Extracts the self-contained `cdxai` binary — no Python,
no runtime to manage.
5. Installs it at the stable path
`~/.cloudanix-guard/bin/cloudanix-guard`, so upgrades replace the
`~/.cdxai/bin/cdxai`, so upgrades replace the
binary in place and never invalidate paths other tools have
registered (e.g. Codex's hook trust-hash).
6. Prints next-step instructions, including how to wire the guard
Expand All @@ -66,12 +66,12 @@ What that does (paraphrased from the [script itself](./cloudanix-guard)):
### Pin a version

```bash
curl -fsSL https://install.cloudanix.com/cloudanix-guard \
| CLOUDANIX_VERSION="0.1.1" bash
curl -fsSL https://install.cloudanix.com/cdxai \
| CDXAI_VERSION="0.1.1" bash
```

The named version must exist in `Cloudanix/artifacts/coding-agent-guard/`
as `cloudanix-guard_<version>_<os>_<arch>.tar.gz` (with a matching
as `cdxai_<version>_<os>_<arch>.tar.gz` (with a matching
`.sha256` sidecar) for your platform. Otherwise the installer aborts
with a 404 from the artifact CDN.

Expand All @@ -92,12 +92,12 @@ with a 404 from the artifact CDN.
- **Strict mode + ShellCheck on CI** — `set -euo pipefail`; no
unguarded `command-not-found`; no implicit word-split bugs.
- **Dev-only env-var overrides are gated** behind
`CLOUDANIX_INSTALL_DEV=1`. Without that flag, the overrides
(`CLOUDANIX_LOCAL_LIB`, `CLOUDANIX_LOCAL_BINARY`,
`CLOUDANIX_LOCAL_TARBALL`, `CLOUDANIX_INSTALL_BASE`,
`CLOUDANIX_ARTIFACTS_URL`) refuse to apply — closes a phishing path
`CDXAI_INSTALL_DEV=1`. Without that flag, the overrides
(`CDXAI_LOCAL_LIB`, `CDXAI_LOCAL_BINARY`,
`CDXAI_LOCAL_TARBALL`, `CDXAI_INSTALL_BASE`,
`CDXAI_ARTIFACTS_URL`) refuse to apply — closes a phishing path
where someone tricks a developer into pasting
`CLOUDANIX_LOCAL_BINARY=/tmp/evil curl … | bash`.
`CDXAI_LOCAL_BINARY=/tmp/evil curl … | bash`.

Found a bug? Open an issue on this repo. For sensitive disclosures
contact `security@cloudanix.com`.
Expand Down
113 changes: 57 additions & 56 deletions cloudanix-guard → cdxai
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
#!/usr/bin/env bash
# Cloudanix Guard — one-line installer.
#
# curl -fsSL https://install.cloudanix.com/cloudanix-guard | bash
# curl -fsSL https://install.cloudanix.com/cdxai | bash
#
# Installs the Cloudanix Guard binary — a single, self-contained
# executable (no Python, no runtime to manage). The binary is published
# to a public Cloudanix-controlled mirror (Cloudanix/artifacts) and
# verified locally against a SHA256 sidecar before it is installed.
#
# Optional env:
# CLOUDANIX_VERSION Pin a specific version, e.g. "1.0.0".
# CDXAI_VERSION Pin a specific version, e.g. "1.0.0".
# Defaults to "latest" (the alias updated on
# every release).
# CLOUDANIX_INSTALL_DIR Base install dir. Defaults to
# ~/.cloudanix-guard . The binary lands at
# <dir>/bin/cloudanix-guard .
# CLOUDANIX_NO_MODIFY_PATH Set to "1" to skip adding the install dir to
# CDXAI_INSTALL_DIR Base install dir. Defaults to
# ~/.cdxai . The binary lands at
# <dir>/bin/cdxai .
# CDXAI_NO_MODIFY_PATH Set to "1" to skip adding the install dir to
# your shell PATH; the installer then just prints
# the line to add manually.
# NO_COLOR Disable colour output.
#
# Dev-only overrides (require CLOUDANIX_INSTALL_DEV=1):
# CLOUDANIX_INSTALL_DEV Set to "1" to enable any of:
# CLOUDANIX_LOCAL_LIB Path to a local lib/common
# CLOUDANIX_LOCAL_BINARY Path to a prebuilt binary (skips download)
# CLOUDANIX_LOCAL_TARBALL Path to a local release tarball (skips download)
# CLOUDANIX_INSTALL_BASE Override install.cloudanix.com URL
# CLOUDANIX_ARTIFACTS_URL Override the artifacts CDN URL
# Dev-only overrides (require CDXAI_INSTALL_DEV=1):
# CDXAI_INSTALL_DEV Set to "1" to enable any of:
# CDXAI_LOCAL_LIB Path to a local lib/common
# CDXAI_LOCAL_BINARY Path to a prebuilt binary (skips download)
# CDXAI_LOCAL_TARBALL Path to a local release tarball (skips download)
# CDXAI_INSTALL_BASE Override install.cloudanix.com URL
# CDXAI_ARTIFACTS_URL Override the artifacts CDN URL
#
# Exit codes:
# 0 success
# 1 user-facing error (unsupported OS, missing tools, dev override
# used without CLOUDANIX_INSTALL_DEV=1, etc.)
# used without CDXAI_INSTALL_DEV=1, etc.)
# 2 network / artifact integrity error (download failed or SHA256
# mismatch)
#
# This installer is open source (MIT). Audit at:
# https://github.com/Cloudanix/install-scripts/blob/main/cloudanix-guard
# https://github.com/Cloudanix/install-scripts/blob/main/cdxai

set -euo pipefail

# ─── dev-only override gating ───────────────────────────────────────
#
# Phishing defence: a customer can be tricked into pasting
# CLOUDANIX_LOCAL_BINARY=/tmp/evil curl ... | bash
# into their terminal. Requiring CLOUDANIX_INSTALL_DEV=1 makes it
# CDXAI_LOCAL_BINARY=/tmp/evil curl ... | bash
# into their terminal. Requiring CDXAI_INSTALL_DEV=1 makes it
# obvious that something dev-only is happening.

if [ -z "${CLOUDANIX_INSTALL_DEV:-}" ]; then
for _v in CLOUDANIX_LOCAL_LIB CLOUDANIX_LOCAL_BINARY CLOUDANIX_LOCAL_TARBALL CLOUDANIX_INSTALL_BASE CLOUDANIX_ARTIFACTS_URL; do
if [ -z "${CDXAI_INSTALL_DEV:-}" ]; then
for _v in CDXAI_LOCAL_LIB CDXAI_LOCAL_BINARY CDXAI_LOCAL_TARBALL CDXAI_INSTALL_BASE CDXAI_ARTIFACTS_URL; do
eval _val="\${${_v}:-}"
if [ -n "${_val:-}" ]; then
echo "error: ${_v} is a development-only override." >&2
echo " Set CLOUDANIX_INSTALL_DEV=1 to enable it." >&2
echo " Set CDXAI_INSTALL_DEV=1 to enable it." >&2
exit 1
fi
done
fi

# ─── source the shared helpers ──────────────────────────────────────

INSTALL_BASE="${CLOUDANIX_INSTALL_BASE:-https://install.cloudanix.com}"
INSTALL_BASE="${CDXAI_INSTALL_BASE:-https://install.cloudanix.com}"

if [ -n "${CLOUDANIX_LOCAL_LIB:-}" ] && [ -f "${CLOUDANIX_LOCAL_LIB}" ]; then
if [ -n "${CDXAI_LOCAL_LIB:-}" ] && [ -f "${CDXAI_LOCAL_LIB}" ]; then
# shellcheck source=lib/common
source "${CLOUDANIX_LOCAL_LIB}"
source "${CDXAI_LOCAL_LIB}"
else
# Fetch common to a real temp file so we can:
# 1. Check the HTTP fetch succeeded.
Expand Down Expand Up @@ -96,17 +96,17 @@ cdx::init_strict

# ─── product-specific config ────────────────────────────────────────

readonly PRODUCT="cloudanix-guard"
INSTALL_DIR="${CLOUDANIX_INSTALL_DIR:-${HOME}/.cloudanix-guard}"
readonly PRODUCT="cdxai"
INSTALL_DIR="${CDXAI_INSTALL_DIR:-${HOME}/.cdxai}"
readonly INSTALL_DIR
readonly BIN_DIR="${INSTALL_DIR}/bin"
readonly LAUNCHER_PATH="${BIN_DIR}/${PRODUCT}"

# Public CDN that holds the release binaries. Override only via the
# dev-gated CLOUDANIX_ARTIFACTS_URL above.
readonly ARTIFACTS_URL="${CLOUDANIX_ARTIFACTS_URL:-https://github.com/Cloudanix/artifacts/raw/main/coding-agent-guard}"
# dev-gated CDXAI_ARTIFACTS_URL above.
readonly ARTIFACTS_URL="${CDXAI_ARTIFACTS_URL:-https://github.com/Cloudanix/artifacts/raw/main/coding-agent-guard}"

VERSION="${CLOUDANIX_VERSION:-latest}"
VERSION="${CDXAI_VERSION:-latest}"

# Set by the resolve step (download+extract, or a dev-provided local
# binary/tarball). Always ends up pointing at the executable to install.
Expand Down Expand Up @@ -144,7 +144,7 @@ main() {
cdx::step "Installing"
install_binary "${BINARY_PATH}" "${LAUNCHER_PATH}"
cdx::ok "installed: ${LAUNCHER_PATH}"
note_legacy_venv
note_legacy_install

cdx::step "Configuring PATH"
ensure_on_path
Expand All @@ -158,20 +158,20 @@ main() {
resolve_binary() {
local version="$1"

if [ -n "${CLOUDANIX_LOCAL_BINARY:-}" ]; then
[ -f "${CLOUDANIX_LOCAL_BINARY}" ] \
|| cdx::die "CLOUDANIX_LOCAL_BINARY=${CLOUDANIX_LOCAL_BINARY} is not a file"
cdx::warn "using local binary (skipping download + checksum): ${CLOUDANIX_LOCAL_BINARY}"
BINARY_PATH="${CLOUDANIX_LOCAL_BINARY}"
if [ -n "${CDXAI_LOCAL_BINARY:-}" ]; then
[ -f "${CDXAI_LOCAL_BINARY}" ] \
|| cdx::die "CDXAI_LOCAL_BINARY=${CDXAI_LOCAL_BINARY} is not a file"
cdx::warn "using local binary (skipping download + checksum): ${CDXAI_LOCAL_BINARY}"
BINARY_PATH="${CDXAI_LOCAL_BINARY}"
return 0
fi

local tarball
if [ -n "${CLOUDANIX_LOCAL_TARBALL:-}" ]; then
[ -f "${CLOUDANIX_LOCAL_TARBALL}" ] \
|| cdx::die "CLOUDANIX_LOCAL_TARBALL=${CLOUDANIX_LOCAL_TARBALL} is not a file"
cdx::warn "using local tarball (skipping download + checksum): ${CLOUDANIX_LOCAL_TARBALL}"
tarball="${CLOUDANIX_LOCAL_TARBALL}"
if [ -n "${CDXAI_LOCAL_TARBALL:-}" ]; then
[ -f "${CDXAI_LOCAL_TARBALL}" ] \
|| cdx::die "CDXAI_LOCAL_TARBALL=${CDXAI_LOCAL_TARBALL} is not a file"
cdx::warn "using local tarball (skipping download + checksum): ${CDXAI_LOCAL_TARBALL}"
tarball="${CDXAI_LOCAL_TARBALL}"
else
download_tarball "${version}" # sets TARBALL_PATH
tarball="${TARBALL_PATH}"
Expand All @@ -195,7 +195,7 @@ _goarch() {
# see the cdx::ensure_tmpdir comment on why the tmpdir trap must stay in
# main()'s shell.
#
# Archives are named cloudanix-guard_<version>_<os>_<arch>.tar.gz (the
# Archives are named cdxai_<version>_<os>_<arch>.tar.gz (the
# goreleaser convention) with a sibling .sha256 sidecar in coreutils
# format ("<hex> <name>"). We download both and verify locally — if the
# public mirror is ever tampered with and a malicious archive is pushed
Expand Down Expand Up @@ -228,7 +228,7 @@ download_tarball() {
cdx::info "fetching ${url}"
curl -fsSL -o "${tmp}/${fn}" "${url}" || {
cdx::err "binary download failed: ${url}"
cdx::err " (Is CLOUDANIX_VERSION=${tag} published for ${CDX_OS}/${arch}?"
cdx::err " (Is CDXAI_VERSION=${tag} published for ${CDX_OS}/${arch}?"
cdx::err " Check https://github.com/Cloudanix/artifacts/tree/main/coding-agent-guard )"
exit 2
}
Expand Down Expand Up @@ -267,7 +267,7 @@ sha256_verify() {
fi
}

# Extract the tarball into CDX_TMPDIR and locate the cloudanix-guard
# Extract the tarball into CDX_TMPDIR and locate the cdxai
# binary. Sets the global BINARY_PATH.
extract_binary() {
local tarball="$1"
Expand All @@ -288,7 +288,7 @@ extract_binary() {

# ─── install the binary at the stable launcher path ─────────────────
#
# The binary lives at ~/.cloudanix-guard/bin/cloudanix-guard for the
# The binary lives at ~/.cdxai/bin/cdxai for the
# life of the install. Coding agents (especially Codex, which
# trust-hashes the exact path of every hook command) record THIS path,
# so keeping it stable across upgrades means replacing the binary in
Expand All @@ -314,8 +314,8 @@ install_binary() {

# ─── PATH wiring (multi-shell) ──────────────────────────────────────
#
# The binary installs to ~/.cloudanix-guard/bin, which is almost never on a
# fresh machine's PATH — so a bare `cloudanix-guard` returns "command not
# The binary installs to ~/.cdxai/bin, which is almost never on a
# fresh machine's PATH — so a bare `cdxai` returns "command not
# found" even though the install succeeded (the agent hooks are unaffected:
# they invoke the binary by absolute path). Append the right line, with the
# right syntax, to the rc the user's shell actually reads:
Expand All @@ -326,7 +326,7 @@ install_binary() {
# else → ~/.profile (POSIX login fallback) export PATH=...
#
# Idempotent (skips if BIN_DIR is already referenced). Opt out with
# CLOUDANIX_NO_MODIFY_PATH=1; falls back to printing the line if it can't
# CDXAI_NO_MODIFY_PATH=1; falls back to printing the line if it can't
# determine the shell or write the file.
ensure_on_path() {
# Already resolvable in this process → future shells inherit it; done.
Expand All @@ -335,8 +335,8 @@ ensure_on_path() {
return 0
fi

if [ -n "${CLOUDANIX_NO_MODIFY_PATH:-}" ]; then
cdx::info "CLOUDANIX_NO_MODIFY_PATH set — not editing your shell profile."
if [ -n "${CDXAI_NO_MODIFY_PATH:-}" ]; then
cdx::info "CDXAI_NO_MODIFY_PATH set — not editing your shell profile."
_print_path_instructions
return 0
fi
Expand Down Expand Up @@ -368,7 +368,7 @@ ensure_on_path() {
# present afterwards (added or already there), 1 if the file couldn't be written.
_append_path_line() {
local rc="$1" line="$2"
local marker="# added by cloudanix-guard installer"
local marker="# added by cdxai installer"

mkdir -p "$(dirname "${rc}")" 2>/dev/null || true

Expand All @@ -394,13 +394,14 @@ _print_path_instructions() {
cdx::warn " fish: fish_add_path \"${BIN_DIR}\""
}

# Older Python installs left a venv at ~/.cloudanix-guard/venv. The Go
# binary doesn't use it; mention it but don't delete it — that's the
# user's call.
note_legacy_venv() {
local venv="${INSTALL_DIR}/venv"
if [ -d "${venv}" ]; then
cdx::info "note: a previous Python install's venv at ${venv} is no longer used (safe to delete)."
# A prior install lived at ~/.cloudanix-guard (the binary was renamed
# cloudanix-guard -> cdxai and the install dir moved to ~/.cdxai). Note any
# leftover old install dir — and the even-older Python venv inside it — but
# don't delete it; that's the user's call (re-run `cdxai configure` first).
note_legacy_install() {
local legacy="${HOME}/.cloudanix-guard"
if [ -d "${legacy}" ]; then
cdx::info "note: a previous install at ${legacy} is superseded by ${INSTALL_DIR} (safe to delete after you re-run 'cdxai configure')."
fi
}

Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ <h2>Cloudanix Guard</h2>
— inspects prompts and tool calls for secrets, PII, and sensitive
files before they reach the LLM.
</p>
<pre>curl -fsSL https://install.cloudanix.com/cloudanix-guard | bash</pre>
<pre>curl -fsSL https://install.cloudanix.com/cdxai | bash</pre>
<details>
<summary>Options</summary>
<p style="margin: 12px 0 4px;">
Pin a specific version:
</p>
<pre>curl -fsSL https://install.cloudanix.com/cloudanix-guard \
| CLOUDANIX_VERSION="0.1.1" bash</pre>
<pre>curl -fsSL https://install.cloudanix.com/cdxai \
| CDXAI_VERSION="0.1.1" bash</pre>
<p style="margin: 14px 0 4px;">
<strong>Env vars go on the <code class="inline">bash</code>
side of the pipe</strong>, not on
Expand Down
Loading
Loading