Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
51b39d8
Initial plan
Copilot Jul 16, 2026
f31fa15
Initial plan for rootless Copilot CLI installation
Copilot Jul 16, 2026
350faef
feat: add --rootless flag to install_copilot_cli.sh for ARC/DinD runners
Copilot Jul 16, 2026
757f19a
fix review feedback for rootless installer PR
Copilot Jul 16, 2026
a69b40d
Merge branch 'main' into copilot/explore-rootless-cli-installation
github-actions[bot] Jul 16, 2026
7b7a5e3
feat: add --rootless support to antigravity and threat-detect installers
lpcox Jul 16, 2026
69a1dc5
fix: don't pass --rootless to engine install scripts when AWF is enabled
lpcox Jul 16, 2026
3c97ecc
fix: pass --rootless to copilot installer only on ARC/DinD topology
lpcox Jul 17, 2026
eeef28f
Merge branch 'main' into copilot/explore-rootless-cli-installation
pelikhan Jul 17, 2026
a0923ef
fix: restore umask after writing Copilot engine command script
Copilot Jul 17, 2026
b09d463
chore: start pr-finisher pass
Copilot Jul 17, 2026
8d9bfbf
fix: restore auto-upgrade workflow schedule
Copilot Jul 17, 2026
d548f70
chore: start merge-conflict resolution pass
Copilot Jul 18, 2026
7ae0cb7
Merge origin/main into copilot/explore-rootless-cli-installation
Copilot Jul 18, 2026
9e6635a
chore: restore auto-upgrade schedule after validation drift
Copilot Jul 18, 2026
47f8c20
chore: plan refreshed pr-finisher pass
Copilot Jul 19, 2026
45c52c7
Merge remote-tracking branch 'origin/main' into copilot/explore-rootl…
Copilot Jul 19, 2026
8079243
Merge remote-tracking branch 'origin/main' into copilot/explore-rootl…
Copilot Jul 19, 2026
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: 2 additions & 0 deletions .github/workflows/smoke-ci.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 56 additions & 4 deletions actions/setup/sh/install_antigravity_cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
set +o histexpand

# Install Antigravity CLI (agy) from Google Cloud Storage
# Usage: install_antigravity_cli.sh VERSION
# Usage: install_antigravity_cli.sh VERSION [--rootless]
#
# This script downloads and installs the Antigravity CLI binary directly from
# Google Cloud Storage (https://storage.googleapis.com/antigravity-public/).
#
# Arguments:
# VERSION - Antigravity CLI version to install (required)
# VERSION - Antigravity CLI version to install (required)
# --rootless - Install to ~/.local/bin without sudo; appends that directory to
# $GITHUB_PATH so subsequent steps find the binary. Use this on
# ARC/DinD runners that enforce allowPrivilegeEscalation: false.
#
# Security features:
# - Downloads binary directly from Google Cloud Storage over HTTPS
Expand All @@ -20,16 +23,55 @@ set +o histexpand
set -euo pipefail

# Configuration
VERSION="${1:-}"
GCS_BASE_URL="https://storage.googleapis.com/antigravity-public/antigravity-cli"
INSTALL_DIR="/usr/local/bin"
BINARY_NAME="agy"

# Parse arguments: treat the first non-flag argument as VERSION, all --<flag> arguments as flags.
VERSION=""
ROOTLESS=false
for arg in "$@"; do
case "$arg" in
--rootless) ROOTLESS=true ;;
--*) echo "WARNING: Unknown flag: $arg" >&2 ;;
*)
if [ -z "$VERSION" ]; then
VERSION="$arg"
fi
;;
esac
done

if [ -z "$VERSION" ]; then
echo "ERROR: Version argument is required"
echo "Usage: $0 VERSION [--rootless]"
exit 1
fi

# In rootless mode, install into the user's home directory instead of /usr/local/bin
# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo.
if [ "$ROOTLESS" = "true" ]; then
INSTALL_DIR="${HOME}/.local/bin"
fi

# maybe_sudo runs a command with sudo unless --rootless was specified.
# In rootless mode, sudo is not available or needed.
maybe_sudo() {
if [ "$ROOTLESS" = "true" ]; then
"$@"
else
sudo "$@"
fi
}

# Rootless mode preflight: create and verify write access to the install directory.
if [ "$ROOTLESS" = "true" ]; then
if ! { mkdir -p "${INSTALL_DIR}" && [ -w "${INSTALL_DIR}" ]; }; then
echo "ERROR: --rootless could not create a writable install directory at ${INSTALL_DIR}" >&2
exit 1
fi
fi

# Detect OS and architecture
OS="$(uname -s)"
ARCH="$(uname -m)"
Expand Down Expand Up @@ -131,7 +173,17 @@ if [ ! -f "${TEMP_DIR}/antigravity" ]; then
echo "ERROR: Expected binary 'antigravity' not found in the extracted archive"
exit 1
fi
sudo install -m 755 "${TEMP_DIR}/antigravity" "${INSTALL_DIR}/${BINARY_NAME}"
maybe_sudo install -m 755 "${TEMP_DIR}/antigravity" "${INSTALL_DIR}/${BINARY_NAME}"

# In rootless mode, add the install dir to PATH for subsequent steps.
if [ "$ROOTLESS" = "true" ]; then
if [ -n "${GITHUB_PATH:-}" ]; then
echo "${INSTALL_DIR}" >> "${GITHUB_PATH}"
echo " Exported ${INSTALL_DIR} to GITHUB_PATH"
else
echo " GITHUB_PATH not set — binary installed at ${INSTALL_DIR}/${BINARY_NAME}"
fi
fi

# Verify installation
echo "Verifying Antigravity CLI installation..."
Expand Down
80 changes: 70 additions & 10 deletions actions/setup/sh/install_copilot_cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
set +o histexpand

# Install GitHub Copilot CLI with SHA256 checksum verification
# Usage: install_copilot_cli.sh [VERSION]
# Usage: install_copilot_cli.sh [VERSION] [--rootless]
#
# This script downloads and installs the GitHub Copilot CLI directly from GitHub
# releases with SHA256 checksum verification, following the secure pattern from
# install_awf_binary.sh to avoid executing unverified downloaded scripts.
#
# Arguments:
# VERSION - Optional Copilot CLI version to install (default: latest release)
# VERSION - Optional Copilot CLI version to install (default: latest release)
# --rootless - Install to ~/.local/bin without sudo; appends that directory to
# $GITHUB_PATH so subsequent steps find the binary. Use this on
# ARC/DinD runners that enforce allowPrivilegeEscalation: false.
#
# Security features:
# - Downloads binary directly from GitHub releases (no installer script execution)
Expand All @@ -20,7 +23,6 @@ set -euo pipefail

# Configuration
SECONDS_PER_DAY=86400
VERSION="${1:-}"
COPILOT_REPO="github/copilot-cli"
INSTALL_DIR="/usr/local/bin"
COPILOT_DIR="${HOME}/.copilot"
Expand All @@ -34,14 +36,53 @@ COMPAT_MATCHED_MIN_AGENT=""
COMPAT_MATCHED_MAX_AGENT=""
COMPAT_CACHE_TTL_DAYS=""

# Parse arguments: treat the first non-flag argument as VERSION, all --<flag> arguments as flags.
VERSION=""
ROOTLESS=false
for arg in "$@"; do
case "$arg" in
--rootless) ROOTLESS=true ;;
--*) echo "WARNING: Unknown flag: $arg" >&2 ;;
*)
if [ -z "$VERSION" ]; then
VERSION="$arg"
fi
;;
esac
done

# In rootless mode, install into the user's home directory instead of /usr/local/bin
# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo.
if [ "$ROOTLESS" = "true" ]; then
INSTALL_DIR="${HOME}/.local/bin"
fi

# maybe_sudo runs a command with sudo unless --rootless was specified.
# In rootless mode, sudo is not available or needed.
maybe_sudo() {
if [ "$ROOTLESS" = "true" ]; then
"$@"
else
sudo "$@"
fi
}

# Rootless mode preflight: create and verify write access to the install directory.
if [ "$ROOTLESS" = "true" ]; then
if ! { mkdir -p "${INSTALL_DIR}" && [ -w "${INSTALL_DIR}" ]; }; then
echo "ERROR: --rootless could not create a writable install directory at ${INSTALL_DIR}" >&2
exit 1
fi
fi

# Fix directory ownership before installation
# This is needed because a previous AWF run on the same runner may have used
# `sudo -E awf --enable-chroot ...`, which creates the .copilot directory with
# root ownership. The Copilot CLI (running as the runner user) then fails when
# trying to create subdirectories. See: https://github.com/github/gh-aw/issues/12066
echo "Ensuring correct ownership of $COPILOT_DIR..."
mkdir -p "$COPILOT_DIR"
sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR"
maybe_sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR"

# Clean up any stale AWF chroot directories left by previous runs.
# When AWF ran with `sudo -E awf --enable-host-access`, it created
Expand All @@ -51,8 +92,8 @@ sudo chown -R "$(id -u):$(id -g)" "$COPILOT_DIR"
# reports as "engine terminated unexpectedly" or fatal EACCES errors.
# Remove them here before the agent starts so the runner is in a clean state.
echo "Cleaning up stale AWF chroot directories..."
sudo find /tmp -maxdepth 1 -name 'awf-*-chroot-home' -type d -exec rm -rf -- {} + 2>/dev/null || true
sudo find /tmp -maxdepth 1 -name 'awf-chroot-*' -type d -exec rm -rf -- {} + 2>/dev/null || true
maybe_sudo find /tmp -maxdepth 1 -name 'awf-*-chroot-home' -type d -exec rm -rf -- {} + 2>/dev/null || true
maybe_sudo find /tmp -maxdepth 1 -name 'awf-chroot-*' -type d -exec rm -rf -- {} + 2>/dev/null || true

# Detect OS and architecture
OS="$(uname -s)"
Expand Down Expand Up @@ -454,7 +495,7 @@ activate_cached_copilot_bin() {
#!/usr/bin/env bash
exec "$cached_copilot_bin" "\$@"
EOF
sudo install -m 0755 "$wrapper_path" "${INSTALL_DIR}/copilot"
maybe_sudo install -m 0755 "$wrapper_path" "${INSTALL_DIR}/copilot"
echo " Wrapper installed at ${INSTALL_DIR}/copilot"
}

Expand Down Expand Up @@ -546,12 +587,31 @@ echo "✓ Checksum verification passed for ${TARBALL_NAME}"

# Extract and install binary
echo "Installing binary to ${INSTALL_DIR}..."
sudo tar -xz -C "${INSTALL_DIR}" -f "${TEMP_DIR}/${TARBALL_NAME}"
sudo chmod +x "${INSTALL_DIR}/copilot"
maybe_sudo tar -xz -C "${INSTALL_DIR}" -f "${TEMP_DIR}/${TARBALL_NAME}"
maybe_sudo chmod +x "${INSTALL_DIR}/copilot"

# In rootless mode, add the install dir to PATH for subsequent steps.
# $GITHUB_PATH is the mechanism for persisting PATH additions across steps in GitHub Actions.
if [ "$ROOTLESS" = "true" ]; then
if [ -n "${GITHUB_PATH:-}" ]; then
echo "${INSTALL_DIR}" >> "${GITHUB_PATH}"
echo " Exported ${INSTALL_DIR} to GITHUB_PATH"
else
echo "WARNING: --rootless install complete but \$GITHUB_PATH is unset; add ${INSTALL_DIR} to PATH manually" >&2
fi
fi

# Verify installation
echo "Verifying Copilot CLI installation..."
if command -v copilot >/dev/null 2>&1; then
if [ "$ROOTLESS" = "true" ]; then
if [ -x "${INSTALL_DIR}/copilot" ]; then
"${INSTALL_DIR}/copilot" --version
echo "✓ Copilot CLI installation complete"
else
echo "ERROR: Copilot CLI installation failed - binary not found at ${INSTALL_DIR}/copilot"
exit 1
fi
elif command -v copilot >/dev/null 2>&1; then
copilot --version
echo "✓ Copilot CLI installation complete"
else
Expand Down
63 changes: 57 additions & 6 deletions actions/setup/sh/install_threat_detect_binary.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ set +o histexpand
# Used when `features: gh-aw-detection: true` is set in the workflow frontmatter to enable
# the external threat-detect binary detection path instead of inline engine execution.
#
# Usage: install_threat_detect_binary.sh VERSION
# Usage: install_threat_detect_binary.sh VERSION [--rootless]
#
# Arguments:
# VERSION - threat-detect version to install (e.g., v0.2.2)
# VERSION - threat-detect version to install (e.g., v0.2.2)
# --rootless - Install to ~/.local/bin without sudo; appends that directory to
# $GITHUB_PATH so subsequent steps find the binary. Use this on
# ARC/DinD runners that enforce allowPrivilegeEscalation: false.
#
# Platform support:
# - Linux (x64, arm64): Downloads pre-built binary
Expand All @@ -21,17 +24,55 @@ set +o histexpand
set -euo pipefail

# Configuration
THREAT_DETECT_VERSION="${1:-}"
THREAT_DETECT_REPO="github/gh-aw-threat-detection"
THREAT_DETECT_INSTALL_DIR="/usr/local/bin"
THREAT_DETECT_INSTALL_NAME="threat-detect"

# Parse arguments: treat the first non-flag argument as VERSION, all --<flag> arguments as flags.
THREAT_DETECT_VERSION=""
ROOTLESS=false
for arg in "$@"; do
case "$arg" in
--rootless) ROOTLESS=true ;;
--*) echo "WARNING: Unknown flag: $arg" >&2 ;;
*)
if [ -z "$THREAT_DETECT_VERSION" ]; then
THREAT_DETECT_VERSION="$arg"
fi
;;
esac
done

if [ -z "$THREAT_DETECT_VERSION" ]; then
echo "ERROR: threat-detect version is required"
echo "Usage: $0 VERSION"
echo "Usage: $0 VERSION [--rootless]"
exit 1
fi

# In rootless mode, install into the user's home directory instead of /usr/local/bin
# so that ARC/DinD runners with allowPrivilegeEscalation: false can run without sudo.
if [ "$ROOTLESS" = "true" ]; then
THREAT_DETECT_INSTALL_DIR="${HOME}/.local/bin"
fi

# maybe_sudo runs a command with sudo unless --rootless was specified.
# In rootless mode, sudo is not available or needed.
maybe_sudo() {
if [ "$ROOTLESS" = "true" ]; then
"$@"
else
sudo "$@"
fi
}

# Rootless mode preflight: create and verify write access to the install directory.
if [ "$ROOTLESS" = "true" ]; then
if ! { mkdir -p "${THREAT_DETECT_INSTALL_DIR}" && [ -w "${THREAT_DETECT_INSTALL_DIR}" ]; }; then
echo "ERROR: --rootless could not create a writable install directory at ${THREAT_DETECT_INSTALL_DIR}" >&2
exit 1
fi
fi

# Detect OS and architecture
OS="$(uname -s)"
ARCH="$(uname -m)"
Expand Down Expand Up @@ -106,7 +147,7 @@ install_linux_binary() {

# Make binary executable and install
chmod +x "${TEMP_DIR}/${binary_name}"
sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}"
maybe_sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}"
}

install_darwin_binary() {
Expand All @@ -127,7 +168,7 @@ install_darwin_binary() {

# Make binary executable and install
chmod +x "${TEMP_DIR}/${binary_name}"
sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}"
maybe_sudo mv "${TEMP_DIR}/${binary_name}" "${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}"
}

case "$OS" in
Expand All @@ -143,6 +184,16 @@ case "$OS" in
;;
esac

# In rootless mode, add the install dir to PATH for subsequent steps.
if [ "$ROOTLESS" = "true" ]; then
if [ -n "${GITHUB_PATH:-}" ]; then
echo "${THREAT_DETECT_INSTALL_DIR}" >> "${GITHUB_PATH}"
echo " Exported ${THREAT_DETECT_INSTALL_DIR} to GITHUB_PATH"
else
echo " GITHUB_PATH not set — binary installed at ${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}"
fi
fi

# Verify installation
"${THREAT_DETECT_INSTALL_DIR}/${THREAT_DETECT_INSTALL_NAME}" --version

Expand Down
Loading
Loading