agenshield 0.11.0 → 0.11.2-beta.530
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/agenshield +88 -134
- package/bin/install.sh +557 -0
- package/package.json +10 -8
package/bin/agenshield
CHANGED
|
@@ -1,172 +1,126 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
|
-
# Launcher
|
|
3
|
-
# Resolves the correct platform-specific binary from optionalDependencies
|
|
4
|
-
# and executes it with all arguments forwarded.
|
|
2
|
+
# Launcher for the `agenshield` npm wrapper package.
|
|
5
3
|
#
|
|
6
|
-
#
|
|
4
|
+
# The wrapper is a thin BOOTSTRAP — it no longer bundles platform-specific
|
|
5
|
+
# binaries (those are too large for npm and now live on the agen-co/agenshield
|
|
6
|
+
# GitHub Release). On first use it runs the bundled `install.sh`, which
|
|
7
|
+
# downloads + verifies the signed artifact from GitHub Releases, then delegates
|
|
8
|
+
# to the installed `agenshield` binary. This keeps `npx agenshield …` working
|
|
9
|
+
# while the heavy signed artifacts ship via GitHub Releases instead of npm.
|
|
10
|
+
#
|
|
11
|
+
# Installed as `bin/agenshield` in the wrapper package (alongside `install.sh`).
|
|
7
12
|
|
|
8
13
|
set -e
|
|
9
14
|
|
|
10
|
-
#
|
|
15
|
+
# ── Platform / arch (validation + diagnostics) ──────────────────────────────
|
|
11
16
|
case "$(uname -s)" in
|
|
12
17
|
Darwin) OS="darwin" ;;
|
|
13
18
|
Linux) OS="linux" ;;
|
|
14
19
|
*) echo "Unsupported platform: $(uname -s)" >&2; exit 1 ;;
|
|
15
20
|
esac
|
|
16
|
-
|
|
17
21
|
case "$(uname -m)" in
|
|
18
22
|
x86_64|amd64) ARCH="x64" ;;
|
|
19
|
-
aarch64|arm64)
|
|
20
|
-
*)
|
|
23
|
+
aarch64|arm64) ARCH="arm64" ;;
|
|
24
|
+
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
|
|
21
25
|
esac
|
|
22
26
|
|
|
23
27
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
BIN=""
|
|
27
|
-
PKG_ROOT=""
|
|
28
|
+
INSTALLER="$SCRIPT_DIR/install.sh"
|
|
29
|
+
HOME_BIN="${HOME}/.agenshield/bin/agenshield"
|
|
28
30
|
|
|
29
|
-
# Wrapper version
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# resolved platform binary's embedded VERSION asset matches. Without this,
|
|
33
|
-
# `npx agenshield@<new> upgrade` could compare against a stale binary's
|
|
34
|
-
# baked-in version and silently no-op as "already at version <old>".
|
|
31
|
+
# ── Wrapper version → AGENSHIELD_NPX_PACKAGE_VERSION ─────────────────────────
|
|
32
|
+
# Forwarded to the binary so getVersion() reports what the user actually invoked
|
|
33
|
+
# (`npx agenshield@<v>`), and so `upgrade` targets <v>. Load-bearing — keep it.
|
|
35
34
|
WRAPPER_PKG_JSON="$SCRIPT_DIR/../package.json"
|
|
36
35
|
WRAPPER_VERSION=""
|
|
37
36
|
if [ -f "$WRAPPER_PKG_JSON" ]; then
|
|
38
|
-
# Prefer node — guaranteed present for npx and immune to minified JSON.
|
|
39
|
-
# The earlier awk-only parser silently returned the wrong field when
|
|
40
|
-
# the package.json was on a single line (npm/yarn sometimes reformat
|
|
41
|
-
# before publish), which let `npx agenshield@<v>` boot with an empty
|
|
42
|
-
# WRAPPER_VERSION and silently no-op `upgrade` as "already at <old>".
|
|
43
37
|
if command -v node >/dev/null 2>&1; then
|
|
44
38
|
WRAPPER_VERSION=$(node -e "try{process.stdout.write(String(JSON.parse(require('fs').readFileSync(process.argv[1],'utf8')).version||''))}catch(_){}" "$WRAPPER_PKG_JSON" 2>/dev/null || true)
|
|
45
39
|
fi
|
|
46
|
-
# awk fallback for non-node environments (direct shell invocation,
|
|
47
|
-
# `agenshield` symlink dragged outside npx, etc.). Multi-line JSON only.
|
|
48
40
|
if [ -z "$WRAPPER_VERSION" ]; then
|
|
41
|
+
# awk fallback for non-node environments (multi-line JSON only).
|
|
49
42
|
WRAPPER_VERSION=$(/usr/bin/awk -F'"' '/"version"/ { print $4; exit }' "$WRAPPER_PKG_JSON" 2>/dev/null || true)
|
|
50
43
|
fi
|
|
51
44
|
fi
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
DIST_DIR="$SCRIPT_DIR/../../${PLATFORM_DIR}"
|
|
55
|
-
if [ -x "$DIST_DIR/bin/agenshield" ]; then
|
|
56
|
-
BIN="$DIST_DIR/bin/agenshield"
|
|
57
|
-
PKG_ROOT="$DIST_DIR"
|
|
45
|
+
if [ -n "$WRAPPER_VERSION" ]; then
|
|
46
|
+
export AGENSHIELD_NPX_PACKAGE_VERSION="$WRAPPER_VERSION"
|
|
58
47
|
fi
|
|
59
48
|
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if [ -x "$
|
|
66
|
-
|
|
67
|
-
|
|
49
|
+
# ── Locate an already-installed agenshield binary ───────────────────────────
|
|
50
|
+
# Prefer ~/.agenshield/bin (tar install); then PATH (the .pkg symlinks
|
|
51
|
+
# /usr/local/bin/agenshield → /Library/AgenShield/bin). Skip this launcher's own
|
|
52
|
+
# directory so a globally-installed wrapper can't exec itself in a loop.
|
|
53
|
+
find_installed() {
|
|
54
|
+
if [ -x "$HOME_BIN" ]; then
|
|
55
|
+
echo "$HOME_BIN"
|
|
56
|
+
return 0
|
|
68
57
|
fi
|
|
69
|
-
|
|
58
|
+
me_dir=$(cd "$SCRIPT_DIR" 2>/dev/null && pwd || echo "$SCRIPT_DIR")
|
|
59
|
+
OLDIFS="$IFS"
|
|
60
|
+
IFS=:
|
|
61
|
+
for p in $PATH; do
|
|
62
|
+
[ -z "$p" ] && continue
|
|
63
|
+
cand="$p/agenshield"
|
|
64
|
+
[ -x "$cand" ] || continue
|
|
65
|
+
real=$(readlink -f "$cand" 2>/dev/null || echo "$cand")
|
|
66
|
+
cdir=$(cd "$(dirname "$real")" 2>/dev/null && pwd || echo "$p")
|
|
67
|
+
if [ "$cdir" = "$me_dir" ]; then
|
|
68
|
+
continue
|
|
69
|
+
fi
|
|
70
|
+
IFS="$OLDIFS"
|
|
71
|
+
echo "$real"
|
|
72
|
+
return 0
|
|
73
|
+
done
|
|
74
|
+
IFS="$OLDIFS"
|
|
75
|
+
return 1
|
|
76
|
+
}
|
|
70
77
|
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
# ── `install` → run the full installer with the user's args ─────────────────
|
|
79
|
+
# install.sh handles the macOS .pkg / Linux tarball download + checksum verify
|
|
80
|
+
# + enrollment (--token/--cloud-url/--org) + service setup.
|
|
81
|
+
if [ "${1:-}" = "install" ]; then
|
|
82
|
+
shift
|
|
83
|
+
if [ ! -f "$INSTALLER" ]; then
|
|
84
|
+
echo "agenshield: bundled installer missing ($INSTALLER)." >&2
|
|
85
|
+
echo " Install AgenShield from your workspace: https://portal.frontegg.com" >&2
|
|
86
|
+
exit 1
|
|
78
87
|
fi
|
|
88
|
+
# Pin the install to the wrapper's own version. `npx agenshield@<v> install`
|
|
89
|
+
# must install <v> — install.sh resolves GitHub `latest` ONLY when
|
|
90
|
+
# AGENSHIELD_VERSION is empty, so without this a pinned/prerelease invocation
|
|
91
|
+
# silently installed the latest STABLE instead. A user-supplied `--version`
|
|
92
|
+
# in "$@" still wins: install.sh's arg parser assigns AGENSHIELD_VERSION last.
|
|
93
|
+
# Empty WRAPPER_VERSION falls through to `latest` (unchanged behavior).
|
|
94
|
+
# Mirrors the bootstrap path below, which already pins via AGENSHIELD_VERSION.
|
|
95
|
+
exec env AGENSHIELD_VERSION="$WRAPPER_VERSION" sh "$INSTALLER" "$@"
|
|
79
96
|
fi
|
|
80
97
|
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
# `npx agenshield@<v>` always reports <v>, even when the resolved binary
|
|
84
|
-
# was hoisted/cached/symlinked from a different version.
|
|
85
|
-
if [ -n "$WRAPPER_VERSION" ]; then
|
|
86
|
-
export AGENSHIELD_NPX_PACKAGE_VERSION="$WRAPPER_VERSION"
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
if [ -n "$BIN" ]; then
|
|
90
|
-
exec "$BIN" "$@"
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
# 4. PATH fallback. Reached when optionalDeps silently failed to install
|
|
94
|
-
# (most common cause: root-owned files in ~/.npm cache from a prior
|
|
95
|
-
# `sudo npx`, so npm can't write the unpack and skips it without
|
|
96
|
-
# erroring). Without this fallback, npx exits 1, then npm-exec
|
|
97
|
-
# silently runs whatever `agenshield` is on PATH — typically a stale
|
|
98
|
-
# .pkg-installed binary that PRECEDES the env-var support, so
|
|
99
|
-
# `npx agenshield@<new>` reports the OLD installed version and the
|
|
100
|
-
# upgrade silently no-ops as "already at version <old>".
|
|
101
|
-
#
|
|
102
|
-
# By searching PATH ourselves, we control the env that the resolved
|
|
103
|
-
# binary inherits — AGENSHIELD_NPX_PACKAGE_VERSION is preserved
|
|
104
|
-
# through `exec`, so any `getVersion()`-aware build (>=.428) reports
|
|
105
|
-
# the wrapper version even when the cache is broken. Older builds
|
|
106
|
-
# still see only their own embedded VERSION; nothing we can do for
|
|
107
|
-
# those without reinstalling from the .pkg.
|
|
108
|
-
#
|
|
109
|
-
# Self-loop guard: skip any PATH entry that points back to this
|
|
110
|
-
# launcher's own directory (would cause infinite recursion).
|
|
111
|
-
ME_DIR="$SCRIPT_DIR"
|
|
112
|
-
ME_REAL=""
|
|
113
|
-
if command -v readlink >/dev/null 2>&1; then
|
|
114
|
-
ME_REAL=$(readlink -f "$0" 2>/dev/null || echo "$0")
|
|
115
|
-
else
|
|
116
|
-
ME_REAL="$0"
|
|
117
|
-
fi
|
|
118
|
-
ME_DIR_REAL=$(cd "$(dirname "$ME_REAL")" 2>/dev/null && pwd || echo "$ME_DIR")
|
|
98
|
+
# ── Every other subcommand: ensure installed, then delegate ─────────────────
|
|
99
|
+
BIN="$(find_installed || true)"
|
|
119
100
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
[ ! -x "$cand" ] && continue
|
|
126
|
-
# Resolve symlinks before comparing — the .pkg installs
|
|
127
|
-
# /usr/local/bin/agenshield as a symlink to /Library/AgenShield/bin/agenshield;
|
|
128
|
-
# we want to match that binary, not the symlink.
|
|
129
|
-
cand_real=$(readlink -f "$cand" 2>/dev/null || echo "$cand")
|
|
130
|
-
cand_dir=$(cd "$(dirname "$cand_real")" 2>/dev/null && pwd || echo "$p")
|
|
131
|
-
# Skip if the candidate is this same launcher (or in our own dir)
|
|
132
|
-
if [ "$cand_dir" = "$ME_DIR_REAL" ] || [ "$cand_dir" = "$ME_DIR" ]; then
|
|
133
|
-
continue
|
|
101
|
+
if [ -z "$BIN" ]; then
|
|
102
|
+
if [ ! -f "$INSTALLER" ]; then
|
|
103
|
+
echo "agenshield: not installed, and the bundled installer is missing." >&2
|
|
104
|
+
echo " Install AgenShield from your workspace: https://portal.frontegg.com" >&2
|
|
105
|
+
exit 1
|
|
134
106
|
fi
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
107
|
+
echo "agenshield: bootstrapping${WRAPPER_VERSION:+ v$WRAPPER_VERSION} from GitHub Releases…" >&2
|
|
108
|
+
# --skip-services lays the binary down quickly; `agenshield start` (or the
|
|
109
|
+
# .pkg postinstall) performs the privileged service setup. AGENSHIELD_VERSION
|
|
110
|
+
# pins the wrapper's version so npx version-pinning is honored.
|
|
111
|
+
if ! AGENSHIELD_VERSION="$WRAPPER_VERSION" sh "$INSTALLER" --skip-services >&2; then
|
|
112
|
+
echo "agenshield: bootstrap failed." >&2
|
|
113
|
+
echo " Get the install command from https://portal.frontegg.com" >&2
|
|
114
|
+
exit 1
|
|
139
115
|
fi
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
IFS="$OLDIFS"
|
|
116
|
+
BIN="$(find_installed || true)"
|
|
117
|
+
fi
|
|
143
118
|
|
|
144
|
-
|
|
145
|
-
echo "
|
|
146
|
-
echo "" >&2
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
echo " Expected: $PKG@${WRAPPER_VERSION}" >&2
|
|
150
|
-
echo "" >&2
|
|
119
|
+
if [ -z "$BIN" ]; then
|
|
120
|
+
echo "agenshield: install completed but no agenshield binary was found on PATH or in ~/.agenshield/bin." >&2
|
|
121
|
+
echo " Platform: ${OS}/${ARCH}" >&2
|
|
122
|
+
echo " Get the install command from https://portal.frontegg.com" >&2
|
|
123
|
+
exit 1
|
|
151
124
|
fi
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
echo "files root-owned). Recovery:" >&2
|
|
155
|
-
echo "" >&2
|
|
156
|
-
echo " sudo chown -R \"\$(id -u):\$(id -g)\" ~/.npm" >&2
|
|
157
|
-
echo " npm cache clean --force" >&2
|
|
158
|
-
echo " rm -rf ~/.npm/_npx" >&2
|
|
159
|
-
echo " npx --yes agenshield@<version> upgrade" >&2
|
|
160
|
-
echo "" >&2
|
|
161
|
-
echo "Or install the platform binary directly from npm and bypass npx:" >&2
|
|
162
|
-
echo "" >&2
|
|
163
|
-
echo " TARBALL=\$(npm view ${PKG}@<version> dist.tarball)" >&2
|
|
164
|
-
echo " curl -fSL -o /tmp/agenshield.tgz \"\$TARBALL\"" >&2
|
|
165
|
-
echo " tar -xzf /tmp/agenshield.tgz -C /tmp" >&2
|
|
166
|
-
echo " sudo installer -pkg /tmp/package/AgenShield.pkg -target /" >&2
|
|
167
|
-
echo "" >&2
|
|
168
|
-
echo "Supported platforms:" >&2
|
|
169
|
-
echo " - darwin/arm64 (Apple Silicon)" >&2
|
|
170
|
-
echo " - darwin/x64 (Intel Mac)" >&2
|
|
171
|
-
echo " - linux/x64 (Linux x86_64)" >&2
|
|
172
|
-
exit 1
|
|
125
|
+
|
|
126
|
+
exec "$BIN" "$@"
|
package/bin/install.sh
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# AgenShield Installer
|
|
3
|
+
#
|
|
4
|
+
# Downloads and installs the AgenShield SEA binaries for the current platform.
|
|
5
|
+
#
|
|
6
|
+
# Multi-binary layout:
|
|
7
|
+
# ~/.agenshield/bin/agenshield (CLI — on PATH)
|
|
8
|
+
# ~/.agenshield/libexec/agenshield-daemon (Daemon — internal)
|
|
9
|
+
# ~/.agenshield/libexec/agenshield-broker (Broker — internal)
|
|
10
|
+
# ~/.agenshield/lib/v{VERSION}/native/ (Native addons)
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# curl -fsSL https://get.agenshield.com/install.sh | sh
|
|
14
|
+
# curl -fsSL https://get.agenshield.com/install.sh | bash -s -- --cloud-url https://cloud.example.com --org my-org
|
|
15
|
+
#
|
|
16
|
+
# CLI arguments (override environment variables):
|
|
17
|
+
# --cloud-url <url> Cloud/policy server URL for automatic enrollment
|
|
18
|
+
# --org <id> Org client ID for MDM enrollment (device code flow on daemon start)
|
|
19
|
+
# --token <token> Enrollment token for automatic cloud setup (MDM)
|
|
20
|
+
# --version <ver> Install a specific version (default: latest)
|
|
21
|
+
# --skip-services Skip macOS LaunchDaemon/LaunchAgent install
|
|
22
|
+
# -h, --help Show usage and exit
|
|
23
|
+
#
|
|
24
|
+
# Environment variables:
|
|
25
|
+
# AGENSHIELD_VERSION - Install a specific version (default: latest)
|
|
26
|
+
# AGENSHIELD_GITHUB_REPO - GitHub repo for downloads (default: agen-co/agenshield)
|
|
27
|
+
# AGENSHIELD_TOKEN - Enrollment token for automatic cloud setup (MDM)
|
|
28
|
+
# AGENSHIELD_CLOUD_URL - Cloud API URL for automatic setup (requires AGENSHIELD_TOKEN or AGENSHIELD_ORG)
|
|
29
|
+
# AGENSHIELD_ORG - Org client ID for MDM enrollment (device code flow on daemon start)
|
|
30
|
+
# AGENSHIELD_BASE_URL - Base URL for downloading archive and checksums (overrides GitHub)
|
|
31
|
+
# AGENSHIELD_SKIP_SERVICES - Set to "1" to skip macOS LaunchDaemon/LaunchAgent install
|
|
32
|
+
#
|
|
33
|
+
set -e
|
|
34
|
+
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
# Configuration
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
GITHUB_REPO="${AGENSHIELD_GITHUB_REPO:-agen-co/agenshield}"
|
|
40
|
+
CLI_BINARY="agenshield"
|
|
41
|
+
|
|
42
|
+
# Colors (disabled if not a terminal or NO_COLOR is set)
|
|
43
|
+
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
44
|
+
RED='\033[0;31m'
|
|
45
|
+
GREEN='\033[0;32m'
|
|
46
|
+
YELLOW='\033[0;33m'
|
|
47
|
+
CYAN='\033[0;36m'
|
|
48
|
+
DIM='\033[2m'
|
|
49
|
+
BOLD='\033[1m'
|
|
50
|
+
RESET='\033[0m'
|
|
51
|
+
else
|
|
52
|
+
RED='' GREEN='' YELLOW='' CYAN='' DIM='' BOLD='' RESET=''
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Helpers
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
info() { printf "${CYAN}info${RESET} %s\n" "$1"; }
|
|
60
|
+
ok() { printf "${GREEN} ok${RESET} %s\n" "$1"; }
|
|
61
|
+
warn() { printf "${YELLOW}warn${RESET} %s\n" "$1"; }
|
|
62
|
+
error() { printf "${RED}error${RESET} %s\n" "$1" >&2; }
|
|
63
|
+
die() { error "$1"; exit 1; }
|
|
64
|
+
|
|
65
|
+
# Detect the platform
|
|
66
|
+
detect_platform() {
|
|
67
|
+
OS="$(uname -s)"
|
|
68
|
+
case "$OS" in
|
|
69
|
+
Darwin) PLATFORM="darwin" ;;
|
|
70
|
+
Linux) PLATFORM="linux" ;;
|
|
71
|
+
*) die "Unsupported operating system: $OS" ;;
|
|
72
|
+
esac
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Detect the architecture
|
|
76
|
+
detect_arch() {
|
|
77
|
+
ARCH="$(uname -m)"
|
|
78
|
+
case "$ARCH" in
|
|
79
|
+
x86_64|amd64) ARCH="x64" ;;
|
|
80
|
+
aarch64|arm64) ARCH="arm64" ;;
|
|
81
|
+
*) die "Unsupported architecture: $ARCH" ;;
|
|
82
|
+
esac
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Find a download utility
|
|
86
|
+
detect_downloader() {
|
|
87
|
+
if command -v curl >/dev/null 2>&1; then
|
|
88
|
+
DOWNLOAD_CMD="curl"
|
|
89
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
90
|
+
DOWNLOAD_CMD="wget"
|
|
91
|
+
else
|
|
92
|
+
die "Neither curl nor wget found. Please install one."
|
|
93
|
+
fi
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Download a URL to a file
|
|
97
|
+
download() {
|
|
98
|
+
url="$1"
|
|
99
|
+
dest="$2"
|
|
100
|
+
if [ "$DOWNLOAD_CMD" = "curl" ]; then
|
|
101
|
+
curl -fsSL -o "$dest" "$url"
|
|
102
|
+
else
|
|
103
|
+
wget -qO "$dest" "$url"
|
|
104
|
+
fi
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Download a URL and print to stdout
|
|
108
|
+
download_text() {
|
|
109
|
+
url="$1"
|
|
110
|
+
if [ "$DOWNLOAD_CMD" = "curl" ]; then
|
|
111
|
+
curl -fsSL "$url"
|
|
112
|
+
else
|
|
113
|
+
wget -qO- "$url"
|
|
114
|
+
fi
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Resolve the release channel: stable (default) | alpha | beta.
|
|
118
|
+
# Precedence mirrors the campaign install script + the CLI's resolveReleaseChannel:
|
|
119
|
+
# AGENSHIELD_CHANNEL wins, then AGENSHIELD_CLIENT_ALPHA/BETA=true.
|
|
120
|
+
resolve_channel() {
|
|
121
|
+
case "${AGENSHIELD_CHANNEL:-}" in
|
|
122
|
+
alpha) echo alpha; return ;;
|
|
123
|
+
beta) echo beta; return ;;
|
|
124
|
+
stable) echo stable; return ;;
|
|
125
|
+
esac
|
|
126
|
+
[ "${AGENSHIELD_CLIENT_ALPHA:-}" = "true" ] && { echo alpha; return; }
|
|
127
|
+
[ "${AGENSHIELD_CLIENT_BETA:-}" = "true" ] && { echo beta; return; }
|
|
128
|
+
echo stable
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Resolve the latest version for the channel from the GitHub Releases API.
|
|
132
|
+
# stable → /releases/latest (never a pre-release). alpha/beta → list recent
|
|
133
|
+
# releases (newest first) and take the first tag carrying the channel's
|
|
134
|
+
# pre-release identifier (-alpha / -beta), which release.yml only ever
|
|
135
|
+
# publishes as a pre-release. `/releases/latest` cannot see pre-releases, which
|
|
136
|
+
# is why alpha/beta were silently downgraded to stable before this fix.
|
|
137
|
+
resolve_latest_version() {
|
|
138
|
+
CHANNEL=$(resolve_channel)
|
|
139
|
+
|
|
140
|
+
if [ "$CHANNEL" = "stable" ]; then
|
|
141
|
+
info "Checking latest stable version..."
|
|
142
|
+
LATEST_JSON=$(download_text "https://api.github.com/repos/$GITHUB_REPO/releases/latest" 2>/dev/null || true)
|
|
143
|
+
[ -z "$LATEST_JSON" ] && die "Failed to query GitHub Releases API. Check your internet connection."
|
|
144
|
+
VERSION=$(echo "$LATEST_JSON" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\(v[^"]*\)".*/\1/' | sed 's/^v//')
|
|
145
|
+
else
|
|
146
|
+
info "Checking latest ${CHANNEL} pre-release..."
|
|
147
|
+
LIST_JSON=$(download_text "https://api.github.com/repos/$GITHUB_REPO/releases?per_page=30" 2>/dev/null || true)
|
|
148
|
+
[ -z "$LIST_JSON" ] && die "Failed to query GitHub Releases API. Check your internet connection."
|
|
149
|
+
# grep -o pulls every tag_name (newest-first, both compact + pretty JSON);
|
|
150
|
+
# filter to the channel marker and take the newest.
|
|
151
|
+
VERSION=$(echo "$LIST_JSON" \
|
|
152
|
+
| grep -oE '"tag_name"[[:space:]]*:[[:space:]]*"v[^"]*"' \
|
|
153
|
+
| sed -E 's/.*"(v[^"]*)".*/\1/' \
|
|
154
|
+
| grep -- "-${CHANNEL}" \
|
|
155
|
+
| head -1 | sed 's/^v//')
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
if [ -z "$VERSION" ]; then
|
|
159
|
+
die "Could not determine latest ${CHANNEL} version from GitHub."
|
|
160
|
+
fi
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# Verify SHA-256 checksum
|
|
164
|
+
verify_checksum() {
|
|
165
|
+
archive="$1"
|
|
166
|
+
expected_checksum="$2"
|
|
167
|
+
|
|
168
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
169
|
+
actual=$(shasum -a 256 "$archive" | awk '{print $1}')
|
|
170
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
171
|
+
actual=$(sha256sum "$archive" | awk '{print $1}')
|
|
172
|
+
else
|
|
173
|
+
warn "Neither shasum nor sha256sum found — skipping checksum verification"
|
|
174
|
+
return 0
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
if [ "$actual" != "$expected_checksum" ]; then
|
|
178
|
+
die "Checksum mismatch!\n Expected: $expected_checksum\n Actual: $actual"
|
|
179
|
+
fi
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# Main
|
|
184
|
+
# ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
main() {
|
|
187
|
+
# Parse CLI arguments (override environment variables)
|
|
188
|
+
while [ $# -gt 0 ]; do
|
|
189
|
+
case "$1" in
|
|
190
|
+
--cloud-url)
|
|
191
|
+
AGENSHIELD_CLOUD_URL="$2"; shift 2 ;;
|
|
192
|
+
--cloud-url=*)
|
|
193
|
+
AGENSHIELD_CLOUD_URL="${1#*=}"; shift ;;
|
|
194
|
+
--org)
|
|
195
|
+
AGENSHIELD_ORG="$2"; shift 2 ;;
|
|
196
|
+
--org=*)
|
|
197
|
+
AGENSHIELD_ORG="${1#*=}"; shift ;;
|
|
198
|
+
--token)
|
|
199
|
+
AGENSHIELD_TOKEN="$2"; shift 2 ;;
|
|
200
|
+
--token=*)
|
|
201
|
+
AGENSHIELD_TOKEN="${1#*=}"; shift ;;
|
|
202
|
+
--version)
|
|
203
|
+
AGENSHIELD_VERSION="$2"; shift 2 ;;
|
|
204
|
+
--version=*)
|
|
205
|
+
AGENSHIELD_VERSION="${1#*=}"; shift ;;
|
|
206
|
+
--skip-services)
|
|
207
|
+
AGENSHIELD_SKIP_SERVICES="1"; shift ;;
|
|
208
|
+
-h|--help)
|
|
209
|
+
printf "AgenShield Installer\n\n"
|
|
210
|
+
printf "Usage:\n"
|
|
211
|
+
printf " curl -fsSL https://get.agenshield.com/install.sh | sh\n"
|
|
212
|
+
printf " curl -fsSL https://get.agenshield.com/install.sh | bash -s -- [OPTIONS]\n\n"
|
|
213
|
+
printf "Options:\n"
|
|
214
|
+
printf " --cloud-url <url> Cloud/policy server URL for automatic enrollment\n"
|
|
215
|
+
printf " --org <id> Org client ID for MDM enrollment\n"
|
|
216
|
+
printf " --token <token> Enrollment token for automatic cloud setup\n"
|
|
217
|
+
printf " --version <ver> Install a specific version (default: latest)\n"
|
|
218
|
+
printf " --skip-services Skip macOS LaunchDaemon/LaunchAgent install\n"
|
|
219
|
+
printf " -h, --help Show this help message\n"
|
|
220
|
+
exit 0
|
|
221
|
+
;;
|
|
222
|
+
*)
|
|
223
|
+
warn "Unknown option: $1"; shift ;;
|
|
224
|
+
esac
|
|
225
|
+
done
|
|
226
|
+
|
|
227
|
+
# Validate: --org requires --cloud-url
|
|
228
|
+
if [ -n "${AGENSHIELD_ORG:-}" ] && [ -z "${AGENSHIELD_CLOUD_URL:-}" ]; then
|
|
229
|
+
die "--org requires --cloud-url to be specified"
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
printf "\n${BOLD}AgenShield Installer${RESET}\n\n"
|
|
233
|
+
|
|
234
|
+
detect_platform
|
|
235
|
+
detect_arch
|
|
236
|
+
detect_downloader
|
|
237
|
+
|
|
238
|
+
info "Platform: $PLATFORM/$ARCH"
|
|
239
|
+
|
|
240
|
+
# Determine version
|
|
241
|
+
VERSION="${AGENSHIELD_VERSION:-}"
|
|
242
|
+
if [ -z "$VERSION" ]; then
|
|
243
|
+
resolve_latest_version
|
|
244
|
+
fi
|
|
245
|
+
info "Version: $VERSION"
|
|
246
|
+
|
|
247
|
+
# ── macOS: use .pkg installer ────────────────────────────────────────────
|
|
248
|
+
if [ "$PLATFORM" = "darwin" ]; then
|
|
249
|
+
# AgenShield's macOS distribution is Apple Silicon (arm64) only — the
|
|
250
|
+
# release pipeline builds and publishes a single arm64 .pkg. On an
|
|
251
|
+
# Intel Mac, ARCH resolves to x64 and the .pkg URL would 404, then
|
|
252
|
+
# silently fall through to a (also-nonexistent) x64 .tar.gz — a
|
|
253
|
+
# confusing failure that looks like a broken release. Fail fast with a
|
|
254
|
+
# clear, actionable message instead.
|
|
255
|
+
if [ "$ARCH" != "arm64" ]; then
|
|
256
|
+
die "AgenShield for macOS currently supports Apple Silicon (arm64) only — detected '$ARCH'. Intel Macs are not yet supported."
|
|
257
|
+
fi
|
|
258
|
+
PKG_NAME="AgenShield-${VERSION}-${ARCH}.pkg"
|
|
259
|
+
BASE_URL="${AGENSHIELD_BASE_URL:-}"
|
|
260
|
+
if [ -n "$BASE_URL" ]; then
|
|
261
|
+
PKG_URL="${BASE_URL}/${PKG_NAME}"
|
|
262
|
+
else
|
|
263
|
+
PKG_URL="https://github.com/$GITHUB_REPO/releases/download/v${VERSION}/${PKG_NAME}"
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
TMPDIR_INSTALL="$(mktemp -d)"
|
|
267
|
+
trap 'rm -rf "$TMPDIR_INSTALL"' EXIT
|
|
268
|
+
|
|
269
|
+
info "Downloading macOS installer: $PKG_NAME..."
|
|
270
|
+
if download "$PKG_URL" "$TMPDIR_INSTALL/$PKG_NAME" 2>/dev/null; then
|
|
271
|
+
ok "Downloaded $PKG_NAME"
|
|
272
|
+
|
|
273
|
+
# Write enrollment tokens to a file for the .pkg postinstall to consume.
|
|
274
|
+
# macOS `installer` does NOT propagate env vars to pre/post install scripts,
|
|
275
|
+
# so we use a well-known file as the handoff mechanism.
|
|
276
|
+
ENROLL_HOME="${HOME}/.agenshield"
|
|
277
|
+
if [ -n "${AGENSHIELD_TOKEN:-}" ] && [ -n "${AGENSHIELD_CLOUD_URL:-}" ]; then
|
|
278
|
+
mkdir -p "$ENROLL_HOME"
|
|
279
|
+
cat > "$ENROLL_HOME/pending-enrollment.json" <<EEOF
|
|
280
|
+
{"token":"${AGENSHIELD_TOKEN}","cloudUrl":"${AGENSHIELD_CLOUD_URL}","org":"${AGENSHIELD_ORG:-}"}
|
|
281
|
+
EEOF
|
|
282
|
+
chmod 600 "$ENROLL_HOME/pending-enrollment.json"
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
if [ -t 0 ] && [ -t 1 ]; then
|
|
286
|
+
# Interactive: open the macOS Installer GUI
|
|
287
|
+
info "Opening installer..."
|
|
288
|
+
open "$TMPDIR_INSTALL/$PKG_NAME"
|
|
289
|
+
printf "\n${GREEN}${BOLD}macOS Installer opened.${RESET}\n"
|
|
290
|
+
printf " Follow the prompts to complete installation.\n"
|
|
291
|
+
printf " After installation completes, run: ${CYAN}agenshield start${RESET}\n\n"
|
|
292
|
+
exit 0
|
|
293
|
+
else
|
|
294
|
+
# Non-interactive (MDM/scripted): use command-line installer
|
|
295
|
+
info "Installing (headless mode)..."
|
|
296
|
+
|
|
297
|
+
# Show live postinstall progress by tailing the install log
|
|
298
|
+
sudo pkill -f "tail -F /var/log/agenshield-install.log" 2>/dev/null || true
|
|
299
|
+
sudo truncate -s 0 /var/log/agenshield-install.log 2>/dev/null || \
|
|
300
|
+
sudo sh -c 'echo -n "" > /var/log/agenshield-install.log' 2>/dev/null || true
|
|
301
|
+
sudo tail -F /var/log/agenshield-install.log 2>/dev/null | sed 's/^/ │ /' &
|
|
302
|
+
TAIL_PID=$!
|
|
303
|
+
_cleanup_tail() {
|
|
304
|
+
sudo pkill -P $$ 2>/dev/null || true
|
|
305
|
+
sudo pkill -f "tail -F /var/log/agenshield-install.log" 2>/dev/null || true
|
|
306
|
+
}
|
|
307
|
+
trap '_cleanup_tail; rm -rf "$TMPDIR_INSTALL"' EXIT INT TERM
|
|
308
|
+
|
|
309
|
+
sudo installer -pkg "$TMPDIR_INSTALL/$PKG_NAME" -target /
|
|
310
|
+
|
|
311
|
+
sleep 1
|
|
312
|
+
_cleanup_tail
|
|
313
|
+
ok "Package installed"
|
|
314
|
+
|
|
315
|
+
# The postinstall script reads pending-enrollment.json and enrolls.
|
|
316
|
+
# Wait for daemon to become ready (postinstall bootstraps LaunchDaemon).
|
|
317
|
+
if [ -n "${AGENSHIELD_TOKEN:-}" ] && [ -n "${AGENSHIELD_CLOUD_URL:-}" ]; then
|
|
318
|
+
info "Waiting for daemon to start..."
|
|
319
|
+
READY=0
|
|
320
|
+
for i in $(seq 1 20); do
|
|
321
|
+
if curl -sf http://127.0.0.1:5200/api/health >/dev/null 2>&1; then
|
|
322
|
+
READY=1
|
|
323
|
+
break
|
|
324
|
+
fi
|
|
325
|
+
sleep 1
|
|
326
|
+
done
|
|
327
|
+
|
|
328
|
+
if [ "$READY" = "1" ]; then
|
|
329
|
+
ok "Daemon is running"
|
|
330
|
+
# Login is NOT required to install or run AgenShield. The daemon is
|
|
331
|
+
# device-enrolled (campaign token) and enforces the synced policy
|
|
332
|
+
# bundle without a user session. The user signs in LATER from the
|
|
333
|
+
# AgenShield menubar to attach their account to this installation.
|
|
334
|
+
info "Sign in any time from the AgenShield menubar to link your account."
|
|
335
|
+
else
|
|
336
|
+
warn "Daemon did not become ready in 20s. Run: agenshield start"
|
|
337
|
+
fi
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
printf "\n${GREEN}${BOLD}AgenShield installed!${RESET}\n\n"
|
|
341
|
+
printf " Installation directory: ${DIM}/Library/AgenShield/${RESET}\n"
|
|
342
|
+
printf " Dashboard: ${CYAN}http://localhost:5200${RESET}\n"
|
|
343
|
+
printf " ${BOLD}Sign in${RESET} from the AgenShield menubar to link your account.\n\n"
|
|
344
|
+
exit 0
|
|
345
|
+
fi
|
|
346
|
+
else
|
|
347
|
+
warn "Could not download .pkg installer — falling back to tar.gz install"
|
|
348
|
+
fi
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
# ── Linux / fallback: tar.gz install ─────────────────────────────────────
|
|
352
|
+
|
|
353
|
+
# Construct download URL
|
|
354
|
+
ARCHIVE_NAME="agenshield-${VERSION}-${PLATFORM}-${ARCH}.tar.gz"
|
|
355
|
+
BASE_URL="${AGENSHIELD_BASE_URL:-}"
|
|
356
|
+
if [ -n "$BASE_URL" ]; then
|
|
357
|
+
DOWNLOAD_URL="${BASE_URL}/${ARCHIVE_NAME}"
|
|
358
|
+
CHECKSUM_URL="${BASE_URL}/checksums.sha256"
|
|
359
|
+
info "Using base URL: $BASE_URL"
|
|
360
|
+
else
|
|
361
|
+
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/v${VERSION}/${ARCHIVE_NAME}"
|
|
362
|
+
CHECKSUM_URL="https://github.com/$GITHUB_REPO/releases/download/v${VERSION}/checksums.sha256"
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
# Detect script directory for local archive mode
|
|
366
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
367
|
+
|
|
368
|
+
# Create temp directory
|
|
369
|
+
TMPDIR_INSTALL="$(mktemp -d)"
|
|
370
|
+
trap 'rm -rf "$TMPDIR_INSTALL"' EXIT
|
|
371
|
+
|
|
372
|
+
# Download or copy archive
|
|
373
|
+
if [ -f "$SCRIPT_DIR/$ARCHIVE_NAME" ]; then
|
|
374
|
+
info "Using local archive: $SCRIPT_DIR/$ARCHIVE_NAME"
|
|
375
|
+
cp "$SCRIPT_DIR/$ARCHIVE_NAME" "$TMPDIR_INSTALL/$ARCHIVE_NAME"
|
|
376
|
+
ok "Copied local $ARCHIVE_NAME"
|
|
377
|
+
else
|
|
378
|
+
info "Downloading $ARCHIVE_NAME..."
|
|
379
|
+
download "$DOWNLOAD_URL" "$TMPDIR_INSTALL/$ARCHIVE_NAME" || \
|
|
380
|
+
die "Failed to download $DOWNLOAD_URL"
|
|
381
|
+
ok "Downloaded $ARCHIVE_NAME"
|
|
382
|
+
fi
|
|
383
|
+
|
|
384
|
+
# Verify checksum
|
|
385
|
+
info "Verifying checksum..."
|
|
386
|
+
if [ -f "$SCRIPT_DIR/checksums.sha256" ]; then
|
|
387
|
+
CHECKSUMS=$(cat "$SCRIPT_DIR/checksums.sha256")
|
|
388
|
+
else
|
|
389
|
+
CHECKSUMS=$(download_text "$CHECKSUM_URL" 2>/dev/null || true)
|
|
390
|
+
fi
|
|
391
|
+
if [ -n "$CHECKSUMS" ]; then
|
|
392
|
+
EXPECTED=$(echo "$CHECKSUMS" | grep "$ARCHIVE_NAME" | awk '{print $1}')
|
|
393
|
+
if [ -n "$EXPECTED" ]; then
|
|
394
|
+
verify_checksum "$TMPDIR_INSTALL/$ARCHIVE_NAME" "$EXPECTED"
|
|
395
|
+
ok "Checksum verified"
|
|
396
|
+
else
|
|
397
|
+
warn "Archive not found in checksums file — skipping verification"
|
|
398
|
+
fi
|
|
399
|
+
else
|
|
400
|
+
warn "Could not download checksums — skipping verification"
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
# ── Installation directories ─────────────────────────────────────────────
|
|
404
|
+
INSTALL_DIR="${AGENSHIELD_INSTALL_DIR:-$HOME/.agenshield}"
|
|
405
|
+
BIN_DIR="$INSTALL_DIR/bin"
|
|
406
|
+
LIB_DIR="$INSTALL_DIR/lib/v${VERSION}"
|
|
407
|
+
|
|
408
|
+
mkdir -p "$BIN_DIR"
|
|
409
|
+
mkdir -p "$INSTALL_DIR/libexec"
|
|
410
|
+
mkdir -p "$INSTALL_DIR/logs"
|
|
411
|
+
|
|
412
|
+
# Extract archive to temp directory
|
|
413
|
+
EXTRACT_DIR="$TMPDIR_INSTALL/extract"
|
|
414
|
+
mkdir -p "$EXTRACT_DIR"
|
|
415
|
+
info "Extracting..."
|
|
416
|
+
tar -xzf "$TMPDIR_INSTALL/$ARCHIVE_NAME" -C "$EXTRACT_DIR"
|
|
417
|
+
|
|
418
|
+
# ── Copy binaries (no execution — avoids SentinelOne process-tree kill) ──
|
|
419
|
+
# CLI binary → bin/
|
|
420
|
+
if [ -f "$EXTRACT_DIR/$CLI_BINARY" ]; then
|
|
421
|
+
cp "$EXTRACT_DIR/$CLI_BINARY" "$BIN_DIR/$CLI_BINARY"
|
|
422
|
+
chmod 755 "$BIN_DIR/$CLI_BINARY"
|
|
423
|
+
ok "Installed $CLI_BINARY → $BIN_DIR/"
|
|
424
|
+
fi
|
|
425
|
+
|
|
426
|
+
# Daemon + broker → libexec/
|
|
427
|
+
for BINARY in agenshield-daemon agenshield-broker; do
|
|
428
|
+
if [ -f "$EXTRACT_DIR/$BINARY" ]; then
|
|
429
|
+
cp "$EXTRACT_DIR/$BINARY" "$INSTALL_DIR/libexec/$BINARY"
|
|
430
|
+
chmod 755 "$INSTALL_DIR/libexec/$BINARY"
|
|
431
|
+
ok "Installed $BINARY → libexec/"
|
|
432
|
+
fi
|
|
433
|
+
done
|
|
434
|
+
|
|
435
|
+
# Native modules
|
|
436
|
+
if [ -d "$EXTRACT_DIR/native" ]; then
|
|
437
|
+
mkdir -p "$LIB_DIR/native"
|
|
438
|
+
cp "$EXTRACT_DIR/native/"* "$LIB_DIR/native/" 2>/dev/null || true
|
|
439
|
+
ok "Installed native modules"
|
|
440
|
+
fi
|
|
441
|
+
|
|
442
|
+
# Worker scripts
|
|
443
|
+
if [ -d "$EXTRACT_DIR/workers" ]; then
|
|
444
|
+
mkdir -p "$LIB_DIR/workers"
|
|
445
|
+
cp "$EXTRACT_DIR/workers/"* "$LIB_DIR/workers/" 2>/dev/null || true
|
|
446
|
+
ok "Installed worker scripts"
|
|
447
|
+
fi
|
|
448
|
+
|
|
449
|
+
# Interceptor scripts
|
|
450
|
+
if [ -d "$EXTRACT_DIR/interceptor" ]; then
|
|
451
|
+
mkdir -p "$LIB_DIR/interceptor"
|
|
452
|
+
cp "$EXTRACT_DIR/interceptor/"* "$LIB_DIR/interceptor/" 2>/dev/null || true
|
|
453
|
+
ok "Installed interceptor scripts"
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
# Client scripts
|
|
457
|
+
if [ -d "$EXTRACT_DIR/client" ]; then
|
|
458
|
+
mkdir -p "$LIB_DIR/client"
|
|
459
|
+
cp "$EXTRACT_DIR/client/"* "$LIB_DIR/client/" 2>/dev/null || true
|
|
460
|
+
ok "Installed client scripts"
|
|
461
|
+
fi
|
|
462
|
+
|
|
463
|
+
# UI assets
|
|
464
|
+
if [ -d "$EXTRACT_DIR/ui-assets" ]; then
|
|
465
|
+
mkdir -p "$LIB_DIR/ui-assets"
|
|
466
|
+
cp -R "$EXTRACT_DIR/ui-assets/." "$LIB_DIR/ui-assets/" 2>/dev/null || true
|
|
467
|
+
ok "Installed UI assets"
|
|
468
|
+
fi
|
|
469
|
+
|
|
470
|
+
# macOS menu bar app
|
|
471
|
+
if [ -d "$EXTRACT_DIR/AgenShield.app" ]; then
|
|
472
|
+
APPS_DIR="$INSTALL_DIR/apps"
|
|
473
|
+
mkdir -p "$APPS_DIR"
|
|
474
|
+
rm -rf "$APPS_DIR/AgenShield.app" 2>/dev/null || true
|
|
475
|
+
cp -R "$EXTRACT_DIR/AgenShield.app" "$APPS_DIR/AgenShield.app"
|
|
476
|
+
ok "Installed AgenShield.app → apps/"
|
|
477
|
+
fi
|
|
478
|
+
|
|
479
|
+
# Write version stamp
|
|
480
|
+
mkdir -p "$LIB_DIR"
|
|
481
|
+
echo "${VERSION}:wius" > "$LIB_DIR/.extracted"
|
|
482
|
+
|
|
483
|
+
# ── macOS: remove quarantine from all installed files ───────────────────
|
|
484
|
+
if [ "$PLATFORM" = "darwin" ]; then
|
|
485
|
+
xattr -dr com.apple.quarantine "$INSTALL_DIR" 2>/dev/null || true
|
|
486
|
+
ok "Removed quarantine attributes"
|
|
487
|
+
fi
|
|
488
|
+
|
|
489
|
+
# ── Add to PATH ────────────────────────────────────────────────────────
|
|
490
|
+
SHELL_NAME="$(basename "${SHELL:-/bin/sh}")"
|
|
491
|
+
case "$SHELL_NAME" in
|
|
492
|
+
zsh) RC_FILE="$HOME/.zshrc" ;;
|
|
493
|
+
bash)
|
|
494
|
+
if [ -f "$HOME/.bash_profile" ]; then
|
|
495
|
+
RC_FILE="$HOME/.bash_profile"
|
|
496
|
+
else
|
|
497
|
+
RC_FILE="$HOME/.bashrc"
|
|
498
|
+
fi
|
|
499
|
+
;;
|
|
500
|
+
*) RC_FILE="$HOME/.profile" ;;
|
|
501
|
+
esac
|
|
502
|
+
|
|
503
|
+
if [ -f "$RC_FILE" ] && grep -q '.agenshield/bin' "$RC_FILE" 2>/dev/null; then
|
|
504
|
+
ok "PATH already configured in $RC_FILE"
|
|
505
|
+
else
|
|
506
|
+
printf '\n# AgenShield CLI\nexport PATH="%s:$PATH"\n' "$BIN_DIR" >> "$RC_FILE"
|
|
507
|
+
ok "Added PATH to $RC_FILE"
|
|
508
|
+
fi
|
|
509
|
+
|
|
510
|
+
# ── Complete installation (enrollment + service setup) ────────────────
|
|
511
|
+
export PATH="$BIN_DIR:$PATH"
|
|
512
|
+
|
|
513
|
+
# Enrollment only — binaries are already extracted above.
|
|
514
|
+
# Use --pkg-mode to skip binary re-installation and only do cloud enrollment.
|
|
515
|
+
if [ -n "${AGENSHIELD_TOKEN:-}" ] && [ -n "${AGENSHIELD_CLOUD_URL:-}" ]; then
|
|
516
|
+
INSTALL_CMD="\"$BIN_DIR/agenshield\" install --pkg-mode"
|
|
517
|
+
INSTALL_CMD="$INSTALL_CMD --cloud-url \"$AGENSHIELD_CLOUD_URL\""
|
|
518
|
+
INSTALL_CMD="$INSTALL_CMD --token \"$AGENSHIELD_TOKEN\""
|
|
519
|
+
if [ -n "${AGENSHIELD_ORG:-}" ]; then
|
|
520
|
+
INSTALL_CMD="$INSTALL_CMD --org \"$AGENSHIELD_ORG\""
|
|
521
|
+
fi
|
|
522
|
+
info "Running cloud enrollment..."
|
|
523
|
+
eval $INSTALL_CMD || warn "Cloud enrollment failed (you can retry with: agenshield install --pkg-mode --token ... --cloud-url ...)"
|
|
524
|
+
fi
|
|
525
|
+
|
|
526
|
+
# Re-ensure native modules are in place
|
|
527
|
+
if [ -d "$EXTRACT_DIR/native" ] && [ ! -d "$LIB_DIR/native" ]; then
|
|
528
|
+
mkdir -p "$LIB_DIR/native"
|
|
529
|
+
cp "$EXTRACT_DIR/native/"* "$LIB_DIR/native/" 2>/dev/null || true
|
|
530
|
+
ok "Re-installed native modules"
|
|
531
|
+
fi
|
|
532
|
+
|
|
533
|
+
# Start daemon — triggers /Applications copy + LaunchDaemon/Agent install.
|
|
534
|
+
# Installation must NOT require login: the daemon starts device-enrolled and
|
|
535
|
+
# enforces the synced policy bundle WITHOUT a user session. Setting
|
|
536
|
+
# AGENSHIELD_SKIP_LOGIN=1 (honored by libs/cli/src/utils/login.ts) suppresses
|
|
537
|
+
# the blocking browser-OAuth wait; the user signs in LATER from the AgenShield
|
|
538
|
+
# menubar. `agenshield start` still starts the daemon + installs services —
|
|
539
|
+
# only the trailing login step is skipped.
|
|
540
|
+
#
|
|
541
|
+
# Honor --skip-services / AGENSHIELD_SKIP_SERVICES: the .pkg postinstall has
|
|
542
|
+
# already installed + bootstrapped the LaunchDaemon, so skip the redundant
|
|
543
|
+
# in-pipe `agenshield start` when the operator opted out of service management.
|
|
544
|
+
if [ "${AGENSHIELD_SKIP_SERVICES:-0}" = "1" ]; then
|
|
545
|
+
info "Skipping 'agenshield start' (--skip-services); the LaunchDaemon manages the daemon."
|
|
546
|
+
else
|
|
547
|
+
info "Starting AgenShield daemon (login deferred to the menubar)..."
|
|
548
|
+
AGENSHIELD_SKIP_LOGIN=1 "$BIN_DIR/agenshield" start || warn "Daemon start failed (you can retry with: agenshield start)"
|
|
549
|
+
fi
|
|
550
|
+
|
|
551
|
+
printf "\n${GREEN}${BOLD}AgenShield installed and running!${RESET}\n\n"
|
|
552
|
+
printf " Installation directory: ${DIM}%s${RESET}\n" "$INSTALL_DIR"
|
|
553
|
+
printf " Dashboard: ${CYAN}http://localhost:5200${RESET}\n"
|
|
554
|
+
printf " ${BOLD}Sign in${RESET} from the AgenShield menubar to link your account.\n\n"
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
main "$@"
|
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenshield",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2-beta.530",
|
|
4
4
|
"description": "AgenShield — AI Agent Security Platform",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agenshield": "bin/agenshield"
|
|
7
7
|
},
|
|
8
|
-
"optionalDependencies": {
|
|
9
|
-
"@agenshield/cli-darwin-arm64": "0.11.0",
|
|
10
|
-
"@agenshield/cli-darwin-x64": "0.11.0",
|
|
11
|
-
"@agenshield/cli-linux-x64": "0.11.0"
|
|
12
|
-
},
|
|
13
8
|
"files": [
|
|
14
9
|
"bin/"
|
|
15
10
|
],
|
|
16
|
-
"license": "
|
|
11
|
+
"license": "Apache-2.0",
|
|
17
12
|
"repository": {
|
|
18
13
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/agen-co/
|
|
14
|
+
"url": "git+https://github.com/agen-co/agenshield.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://agen.co/shield",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/agen-co/agenshield/issues"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22.0.0"
|
|
20
22
|
}
|
|
21
23
|
}
|