deer-flow/docker/lark-cli-init/build-runtime.sh
Ryker_Feng 7aa314b4c1
feat: add Lark CLI integration (#3971)
* feat: add lark cli integration

* fix: polish lark integration actions

* feat: support lark incremental permissions

* fix: detect lark authorization completion

* fix: harden lark integration install

* feat: expand lark auth scopes and reuse host auth in sandbox

Default lark auth to least-privilege (recommend=false, base sign-in only)
and expose the full set of lark-cli --domain business domains as native
--domain grants instead of a 4-domain read-only mapping. Resolve the
skill pack from the latest larksuite/cli GitHub release at install time
with content-hash integrity, and surface version/runtime drift in status.

Share the per-user lark-cli config/data profile between the Gateway
Settings auth flow and agent conversations by mounting the integration
dirs into the AIO sandbox and injecting the matching env for lark-cli
commands, with an allowlisted extra_mounts path in the provisioner/K8s
backend and traversal guards on integration paths.

* style: fix lint issues from ruff and prettier

Sort imports in the provisioner PVC test and re-wrap two long i18n
description strings to satisfy backend ruff and frontend prettier CI.

* fix(lark): address managed integration review feedback

* fix(frontend): stabilize integrations settings e2e

* test(sandbox): isolate remote backend legacy visibility check

* test: fix backend unit failures after merge

* Harden Lark integration review fixes

* Format Lark integration E2E test

* fix(lark): harden sandbox credential exposure and status disclosure

Address willem_bd's security review on PR #3971:

- Mount the per-user lark-cli config dir (long-lived appSecret) read-only
  into the AIO sandbox; only the refreshable-token data dir stays writable.
- Redact host filesystem paths (install_path, cli.path) from
  GET /lark/status and the config/auth complete responses for non-admin
  callers, fail-closed on any auth error.
- Document the npm postinstall trade-off (--ignore-scripts is not viable
  because @larksuite/cli fetches its platform binary in postinstall).
- Document the sandbox credential trust boundary in AGENTS.md and README,
  pointing at the sidecar-broker follow-up (#4338).

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-07-26 08:09:17 +08:00

88 lines
2.8 KiB
Bash

#!/bin/sh
# Stage the DeerFlow sandbox lark-cli runtime layout from official release
# binaries. Runs at image BUILD time (network available).
#
# Usage: LARK_CLI_VERSION=v1.0.65 build-runtime.sh /opt/lark-cli
#
# Produces:
# <dest>/bin/lark-cli arch-dispatch launcher (uname -m)
# <dest>/linux-amd64/lark-cli
# <dest>/linux-arm64/lark-cli
# <dest>/.deerflow-lark-cli-runtime.json {"version": "vX.Y.Z"}
#
# The layout mirrors the Gateway writer (_write_lark_cli_sandbox_launcher) and
# satisfies _validate_lark_cli_sandbox_runtime, so the sandbox PATH contract is
# unchanged.
set -eu
DEST="${1:?destination directory required}"
VERSION="${LARK_CLI_VERSION:?LARK_CLI_VERSION required}"
REPO="larksuite/cli"
ARCHES="amd64 arm64"
# Normalize to a leading-v tag and a bare version.
case "$VERSION" in
v*) TAG="$VERSION" ;;
*) TAG="v$VERSION" ;;
esac
BARE="${TAG#v}"
BASE_URL="https://github.com/${REPO}/releases/download/${TAG}"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
echo "Downloading lark-cli ${TAG} release checksums..."
curl -fsSL "${BASE_URL}/checksums.txt" -o "${WORK}/checksums.txt"
mkdir -p "${DEST}/bin"
for arch in $ARCHES; do
asset="lark-cli-${BARE}-linux-${arch}.tar.gz"
echo "Downloading ${asset}..."
curl -fsSL "${BASE_URL}/${asset}" -o "${WORK}/${asset}"
expected="$(awk -v f="${asset}" '$2 == f || $2 == "*"f {print $1}' "${WORK}/checksums.txt" | head -n1)"
if [ -z "$expected" ]; then
echo "ERROR: no checksum for ${asset} in checksums.txt" >&2
exit 1
fi
actual="$(sha256sum "${WORK}/${asset}" | awk '{print $1}')"
if [ "$expected" != "$actual" ]; then
echo "ERROR: checksum mismatch for ${asset} (expected ${expected}, got ${actual})" >&2
exit 1
fi
mkdir -p "${DEST}/linux-${arch}"
# Extract only the single lark-cli executable from the archive.
tar -xzf "${WORK}/${asset}" -C "${WORK}"
found="$(find "${WORK}" -type f -name lark-cli ! -path "${DEST}/*" | head -n1)"
if [ -z "$found" ]; then
echo "ERROR: lark-cli executable not found in ${asset}" >&2
exit 1
fi
install -m 0755 "$found" "${DEST}/linux-${arch}/lark-cli"
rm -f "$found"
done
# Arch-dispatch launcher. Kept byte-identical to
# LARK_CLI_SANDBOX_LAUNCHER_SCRIPT in
# backend/packages/harness/deerflow/integrations/lark_cli.py
# (a unit test asserts the two never drift).
cat > "${DEST}/bin/lark-cli" <<'LAUNCHER'
#!/bin/sh
set -eu
case "$(uname -m)" in
x86_64|amd64) arch=amd64 ;;
aarch64|arm64) arch=arm64 ;;
*) echo "Unsupported sandbox architecture: $(uname -m)" >&2; exit 126 ;;
esac
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
exec "$script_dir/../linux-$arch/lark-cli" "$@"
LAUNCHER
chmod 0755 "${DEST}/bin/lark-cli"
printf '{\n "version": "%s"\n}\n' "$TAG" > "${DEST}/.deerflow-lark-cli-runtime.json"
echo "Staged lark-cli ${TAG} runtime at ${DEST}:"
ls -R "${DEST}"