Last active
August 13, 2026 18:31
-
-
Save lpenguin/8372ed4fca659007a07a2184b20b1ef3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -Eeuo pipefail | |
| # Prevent credentials and expanded commands from appearing in setup logs. | |
| set +x | |
| # ============================================================================= | |
| # Configuration | |
| # ============================================================================= | |
| readonly AUTH_DIR="$HOME/.config/codex-cloud-auth" | |
| readonly ENV_FILE="$AUTH_DIR/env.sh" | |
| readonly GH_TOKEN_FILE="$AUTH_DIR/github-token" | |
| readonly NOTION_TOKEN_FILE="$AUTH_DIR/notion-token" | |
| readonly BIN_DIR="$HOME/.local/bin" | |
| readonly PLAYWRIGHT_BROWSER_DIR="$HOME/.cache/ms-playwright" | |
| # Override through an ordinary Cloud environment variable if needed. | |
| readonly NOTION_CLI_VERSION="${NOTION_CLI_VERSION:-0.7.0}" | |
| # ============================================================================= | |
| # Helpers | |
| # ============================================================================= | |
| require_secret() { | |
| local name="$1" | |
| if [[ -z "${!name:-}" ]]; then | |
| echo "ERROR: Cloud secret '$name' is missing or empty." >&2 | |
| exit 1 | |
| fi | |
| } | |
| append_line_once() { | |
| local line="$1" | |
| local file="$2" | |
| touch "$file" | |
| if ! grep -Fqx "$line" "$file"; then | |
| printf '\n%s\n' "$line" >> "$file" | |
| fi | |
| } | |
| # ============================================================================= | |
| # Credentials | |
| # | |
| # Codex Cloud Secrets are removed before the agent phase. The credentials are | |
| # copied into protected files because gh and notion need live API access later. | |
| # Use narrowly scoped, short-lived tokens. | |
| # ============================================================================= | |
| require_secret CODEX_GITHUB_TOKEN | |
| require_secret CODEX_NOTION_TOKEN | |
| install -d -m 700 "$AUTH_DIR" | |
| install -d -m 755 "$BIN_DIR" | |
| install -d -m 755 "$PLAYWRIGHT_BROWSER_DIR" | |
| install -m 600 /dev/null "$GH_TOKEN_FILE" | |
| install -m 600 /dev/null "$NOTION_TOKEN_FILE" | |
| printf '%s' "$CODEX_GITHUB_TOKEN" > "$GH_TOKEN_FILE" | |
| printf '%s' "$CODEX_NOTION_TOKEN" > "$NOTION_TOKEN_FILE" | |
| { | |
| printf '%s\n' '# Generated by codex-cloud-tools-setup.sh' | |
| printf '%s\n' 'export PATH="$HOME/.local/bin:$PATH"' | |
| printf '%s\n' 'export GH_TOKEN="$(<"$HOME/.config/codex-cloud-auth/github-token")"' | |
| printf '%s\n' 'export NOTION_TOKEN="$(<"$HOME/.config/codex-cloud-auth/notion-token")"' | |
| printf '%s\n' 'export PLAYWRIGHT_BROWSERS_PATH="$HOME/.cache/ms-playwright"' | |
| printf '%s\n' 'export PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT="120000"' | |
| } > "$ENV_FILE" | |
| chmod 600 "$ENV_FILE" | |
| readonly SOURCE_LINE='. "$HOME/.config/codex-cloud-auth/env.sh"' | |
| append_line_once "$SOURCE_LINE" "$HOME/.bashrc" | |
| append_line_once "$SOURCE_LINE" "$HOME/.profile" | |
| # Make the configuration available to the rest of this setup run. | |
| # shellcheck disable=SC1090 | |
| . "$ENV_FILE" | |
| # Remove the original Cloud Secret variables from this process. | |
| unset CODEX_GITHUB_TOKEN | |
| unset CODEX_NOTION_TOKEN | |
| # ============================================================================= | |
| # GitHub CLI | |
| # ============================================================================= | |
| echo | |
| echo "Configuring GitHub CLI..." | |
| if ! command -v gh >/dev/null 2>&1; then | |
| echo "ERROR: GitHub CLI (gh) is not installed in this Cloud image." >&2 | |
| exit 1 | |
| fi | |
| echo "GitHub CLI: $(gh --version | head -n 1)" | |
| gh auth status --hostname github.com | |
| # Configure HTTPS git operations such as `git push` to retrieve credentials | |
| # through gh, which in turn uses GH_TOKEN. | |
| gh auth setup-git --hostname github.com | |
| printf 'GitHub account: ' | |
| gh api user --jq '.login' | |
| # ============================================================================= | |
| # 4ier/notion-cli | |
| # | |
| # Install the binary from GitHub Releases. The npm package's Node downloader | |
| # may bypass the Codex Cloud HTTP proxy. | |
| # ============================================================================= | |
| echo | |
| echo "Configuring notion-cli..." | |
| case "$NOTION_CLI_VERSION" in | |
| v*) | |
| readonly NOTION_TAG="$NOTION_CLI_VERSION" | |
| ;; | |
| *) | |
| readonly NOTION_TAG="v$NOTION_CLI_VERSION" | |
| ;; | |
| esac | |
| readonly NOTION_VERSION="${NOTION_TAG#v}" | |
| case "$(uname -m)" in | |
| x86_64|amd64) | |
| readonly NOTION_ARCH="amd64" | |
| ;; | |
| aarch64|arm64) | |
| readonly NOTION_ARCH="arm64" | |
| ;; | |
| *) | |
| echo "ERROR: Unsupported architecture: $(uname -m)" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| readonly NOTION_ASSET="notion-cli_${NOTION_VERSION}_linux_${NOTION_ARCH}.tar.gz" | |
| notion_tmp_dir="$(mktemp -d)" | |
| cleanup() { | |
| if [[ -n "${notion_tmp_dir:-}" && -d "$notion_tmp_dir" ]]; then | |
| rm -rf -- "$notion_tmp_dir" | |
| fi | |
| } | |
| trap cleanup EXIT | |
| echo "Downloading notion-cli $NOTION_TAG ($NOTION_ARCH)..." | |
| gh release download "$NOTION_TAG" \ | |
| --repo 4ier/notion-cli \ | |
| --pattern "$NOTION_ASSET" \ | |
| --pattern "checksums.txt" \ | |
| --dir "$notion_tmp_dir" | |
| expected_checksum="$( | |
| awk -v asset="$NOTION_ASSET" \ | |
| '$2 == asset || $2 == "*" asset { print $1; exit }' \ | |
| "$notion_tmp_dir/checksums.txt" | |
| )" | |
| if [[ -z "$expected_checksum" ]]; then | |
| echo "ERROR: No checksum found for $NOTION_ASSET." >&2 | |
| exit 1 | |
| fi | |
| actual_checksum="$( | |
| sha256sum "$notion_tmp_dir/$NOTION_ASSET" | | |
| awk '{ print $1 }' | |
| )" | |
| if [[ "$actual_checksum" != "$expected_checksum" ]]; then | |
| echo "ERROR: notion-cli checksum verification failed." >&2 | |
| echo "Expected: $expected_checksum" >&2 | |
| echo "Actual: $actual_checksum" >&2 | |
| exit 1 | |
| fi | |
| tar -xzf "$notion_tmp_dir/$NOTION_ASSET" \ | |
| -C "$notion_tmp_dir" | |
| if [[ ! -f "$notion_tmp_dir/notion" ]]; then | |
| echo "ERROR: notion binary was not found in the release archive." >&2 | |
| exit 1 | |
| fi | |
| install -m 0755 \ | |
| "$notion_tmp_dir/notion" \ | |
| "$BIN_DIR/notion" | |
| echo "Notion CLI: $(notion --version 2>/dev/null || echo "$NOTION_TAG")" | |
| notion auth status | |
| notion user me >/dev/null | |
| echo "Notion API authentication verified." | |
| # ============================================================================= | |
| # Project dependencies | |
| # ============================================================================= | |
| echo | |
| echo "Installing project dependencies..." | |
| if [[ -f pnpm-lock.yaml ]]; then | |
| corepack enable | |
| pnpm install --frozen-lockfile | |
| elif [[ -f yarn.lock ]]; then | |
| corepack enable | |
| if yarn --version | grep -qE '^[23-9]\.'; then | |
| yarn install --immutable | |
| else | |
| yarn install --frozen-lockfile | |
| fi | |
| elif [[ -f package-lock.json ]]; then | |
| npm ci | |
| elif [[ -f package.json ]]; then | |
| echo "WARNING: package.json exists without a recognized lockfile." | |
| echo "Running npm install." | |
| npm install | |
| else | |
| echo "No Node.js project detected; skipping dependency installation." | |
| fi | |
| # ============================================================================= | |
| # Playwright Chromium | |
| # | |
| # Browser installation happens during setup, when Codex Cloud setup networking | |
| # is available. The agent should not need to download Chromium later. | |
| # ============================================================================= | |
| echo | |
| echo "Configuring Playwright Chromium..." | |
| PLAYWRIGHT_BIN="" | |
| if [[ -x "$PWD/node_modules/.bin/playwright" ]]; then | |
| PLAYWRIGHT_BIN="$PWD/node_modules/.bin/playwright" | |
| elif command -v playwright >/dev/null 2>&1; then | |
| PLAYWRIGHT_BIN="$(command -v playwright)" | |
| fi | |
| if [[ -n "$PLAYWRIGHT_BIN" ]]; then | |
| echo "Playwright CLI: $PLAYWRIGHT_BIN" | |
| echo "Browser directory: $PLAYWRIGHT_BROWSERS_PATH" | |
| # --only-shell is sufficient for ordinary headless tests and screenshots | |
| # and downloads less data than the full browser. | |
| "$PLAYWRIGHT_BIN" install chromium --only-shell | |
| echo | |
| echo "Installed Playwright browsers:" | |
| "$PLAYWRIGHT_BIN" install --list | |
| else | |
| echo "WARNING: Playwright is not installed in this repository." | |
| echo "Add @playwright/test or playwright to devDependencies." | |
| echo "Chromium installation was skipped." | |
| fi | |
| # ============================================================================= | |
| # Summary | |
| # ============================================================================= | |
| echo | |
| echo "============================================================" | |
| echo "Codex Cloud tools configured successfully" | |
| echo "============================================================" | |
| echo | |
| echo "GitHub:" | |
| echo " gh auth status" | |
| echo " gh issue list --repo OWNER/REPO" | |
| echo | |
| echo "Notion:" | |
| echo " notion auth status" | |
| echo " notion search \"query\"" | |
| echo | |
| echo "Playwright:" | |
| echo " ./node_modules/.bin/playwright install --list" | |
| echo " npm test" | |
| echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment