diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index fe180b3..a372e1e 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -11,23 +11,38 @@ permissions: jobs: set-version: + name: Set version number runs-on: ubuntu-latest outputs: version: ${{ steps.get_version.outputs.tag }} + is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }} steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Set version number id: get_version run: | version="${{ github.ref_name }}" echo "tag=$version" >> $GITHUB_OUTPUT + - name: Check if pre-release + id: check_prerelease + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + IS_PRERELEASE=$(gh release view ${{ steps.get_version.outputs.tag }} --json isPrerelease --jq '.isPrerelease') + echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT + echo "Release ${{ steps.get_version.outputs.tag }} is pre-release: $IS_PRERELEASE" + create-binaries: needs: set-version uses: ./.github/workflows/create-artifact.yml with: version: ${{ needs.set-version.outputs.version }} - build: + publish-binaries: + name: Publish to GitHub release needs: [set-version, create-binaries] runs-on: ubuntu-latest @@ -35,37 +50,6 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: "lts/*" - registry-url: "https://registry.npmjs.org/" - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} - - - name: Setup safe-chain - run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/0.0.1-docker-linux-exec-beta/install-safe-chain.sh | sh -s -- --ci - - - name: Set the version in safe-chain package - run: npm --no-git-tag-version version ${{ needs.set-version.outputs.version }} --workspace=packages/safe-chain - - - name: Install dependencies - run: npm ci - - - name: Run tests - run: npm run test - - - name: Copy documentation files to package - run: | - cp README.md packages/safe-chain/ - cp LICENSE packages/safe-chain/ - cp -r docs packages/safe-chain/ - - - name: Publish to npm - run: | - echo "Publishing version ${{ needs.set-version.outputs.version }} to NPM" - npm publish --workspace=packages/safe-chain --access public --provenance - - name: Download all binary artifacts uses: actions/download-artifact@v4 with: @@ -107,3 +91,44 @@ jobs: release-artifacts/install-safe-chain.ps1 \ release-artifacts/uninstall-safe-chain.sh \ release-artifacts/uninstall-safe-chain.ps1 + + publish-npm: + name: Publish to npm + needs: [set-version, create-binaries] + if: needs.set-version.outputs.is_prerelease != 'true' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + registry-url: "https://registry.npmjs.org/" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} + + - name: Setup safe-chain + run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/latest/download/install-safe-chain.sh | sh -s -- --ci + + - name: Set the version in safe-chain package + run: npm --no-git-tag-version version ${{ needs.set-version.outputs.version }} --workspace=packages/safe-chain + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm run test + + - name: Copy documentation files to package + run: | + cp README.md packages/safe-chain/ + cp LICENSE packages/safe-chain/ + cp -r docs packages/safe-chain/ + + - name: Publish to npm + run: | + echo "Publishing version ${{ needs.set-version.outputs.version }} to NPM" + npm publish --workspace=packages/safe-chain --access public --provenance diff --git a/README.md b/README.md index a13395c..14dc26c 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ Aikido Safe Chain supports the following package managers: Installing the Aikido Safe Chain is easy with our one-line installer. -> ⚠️ **Already installed via npm?** See the [migration guide](https://github.com/AikidoSec/safe-chain/blob/main/docs/npm-to-binary-migration.md) to switch to the binary version. - ### Unix/Linux/macOS ```shell @@ -206,6 +204,7 @@ You can set the minimum package age through multiple sources (in order of priori Configure Safe Chain to scan packages from custom or private registries. Supported ecosystems: + - Node.js - Python @@ -348,5 +347,8 @@ pipeline { } ``` - After setup, all subsequent package manager commands in your CI pipeline will automatically be protected by Aikido Safe Chain's malware detection. + +# Troubleshooting + +Having issues? See the [Troubleshooting Guide](https://github.com/AikidoSec/safe-chain/blob/main/docs/troubleshooting.md) for help with common problems. diff --git a/docs/npm-to-binary-migration.md b/docs/npm-to-binary-migration.md deleted file mode 100644 index c29a044..0000000 --- a/docs/npm-to-binary-migration.md +++ /dev/null @@ -1,89 +0,0 @@ -# Migrating from npm global tool to binary installation - -If you previously installed safe-chain as an npm global package, you need to migrate to the binary installation. - -Depending on the version manager you're using, the uninstall process differs: - -### Standard npm (no version manager) - -1. **Clean up shell aliases:** - - ```bash - safe-chain teardown - ``` - -2. **Restart your terminal** - -3. **Uninstall the npm package:** - - ```bash - npm uninstall -g @aikidosec/safe-chain - ``` - -4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) - -### nvm (Node Version Manager) - -**Important:** nvm installs global packages separately for each Node version, so safe-chain must be uninstalled from each version where it was installed. - -1. **Clean up shell aliases:** - - ```bash - safe-chain teardown - ``` - -2. **Restart your terminal** - -3. **Uninstall from all Node versions:** - - **Option A** - Automated script (recommended): - - ```bash - for version in $(nvm list | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+'); do nvm use $version && npm uninstall -g @aikidosec/safe-chain; done - ``` - - **Option B** - Manual per version: - - ```bash - nvm use - npm uninstall -g @aikidosec/safe-chain - ``` - - Repeat for each Node version where safe-chain was installed. - -4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) - -### Volta - -1. **Clean up shell aliases:** - - ```bash - safe-chain teardown - ``` - -2. **Restart your terminal** - -3. **Uninstall the Volta package:** - - ```bash - volta uninstall @aikidosec/safe-chain - ``` - -4. **Install the binary version** (see [Installation](https://github.com/AikidoSec/safe-chain/blob/main/README.md#installation)) - -## Troubleshooting - -### Shell aliases still present after migration - -1. Run `safe-chain teardown` (if the binary is installed) -2. Manually remove any safe-chain entries from your shell config files: - - Bash: `~/.bashrc` - - Zsh: `~/.zshrc` - - Fish: `~/.config/fish/config.fish` - - PowerShell: `$PROFILE` -3. Restart your terminal -4. Re-run the install script - -### "command not found: safe-chain" after migration - -The binary installation directory (`~/.safe-chain/bin`) may not be in your PATH. Restart your terminal. If the problem persists: re-run the installation of safe-chain. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..398ef4a --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,249 @@ +# Troubleshooting + +This guide helps you diagnose and resolve common issues with Aikido Safe Chain. + +## Verification & Diagnostics + +### Check Installation + +```bash +# Check version +safe-chain --version +``` + +### Verify Shell Integration + +Run the verification command for your package manager: + +```bash +npm safe-chain-verify +pnpm safe-chain-verify +pip safe-chain-verify +uv safe-chain-verify + +# Any other supported package manager: {packagemanager} safe-chain-verify +``` + +Expected output: `OK: Safe-chain works!` + +### Test Malware Blocking + +Verify that malware detection is working: + +**For JavaScript/Node.js:** + +```bash +npm install safe-chain-test +``` + +**For Python:** + +```bash +pip3 install safe-chain-pi-test +``` + +These test packages are flagged as malware and should be blocked by Safe Chain. + +### Logging Options + +Use logging flags to get more information: + +```bash +# Verbose mode - detailed diagnostic output for troubleshooting +npm install express --safe-chain-logging=verbose + +# Silent mode - suppress all output except malware blocking +npm install express --safe-chain-logging=silent +``` + +## Common Issues + +### Shell Aliases Not Working After Installation + +**Symptom:** Running `npm` shows regular npm instead of safe-chain wrapped version + +**First step:** Restart your terminal (most common fix) + +**Verify it's working:** + +```bash +type npm +``` + +Should show: `npm is a function` + +**If still not working:** + +Check that your startup file sources safe-chain scripts from `~/.safe-chain/scripts/`: + +- Bash: `~/.bashrc` +- Zsh: `~/.zshrc` +- Fish: `~/.config/fish/config.fish` +- PowerShell: `$PROFILE` + +### "Command Not Found: safe-chain" + +**Symptom:** Binary not found in PATH + +**First step:** Restart your terminal + +**Check PATH:** + +```bash +echo $PATH +``` + +Should include `~/.safe-chain/bin` + +**If persists:** Re-run the installation script + +### Shell Aliases Persist After Uninstallation + +**Symptom:** safe-chain commands still active after running uninstall script + +**Steps:** + +1. Run `safe-chain teardown` (if binary still exists) +2. Restart your terminal +3. If still present, manually edit shell config files: + - Bash: `~/.bashrc` + - Zsh: `~/.zshrc` + - Fish: `~/.config/fish/config.fish` + - PowerShell: `$PROFILE` +4. Remove lines that source scripts from `~/.safe-chain/scripts/` +5. Restart terminal again + +## Manual Verification Steps + +### Check Installation Status + +```bash +# Check installation location (helps identify if installed via npm or as standalone binary) +which safe-chain + +# Verify binary exists +ls ~/.safe-chain/bin/safe-chain + +# Check version +safe-chain --version + +# Test shell integration +type npm +type pip +``` + +**Expected `which` output:** + +- Standalone binary (correct): `~/.safe-chain/bin/safe-chain` or `/Users//.safe-chain/bin/safe-chain` +- npm global (outdated): path containing `node_modules` or nvm version paths + +If `which` shows an npm installation, see [Check for Conflicting Installations](#check-for-conflicting-installations). + +### Check Shell Integration + +```bash +# Which shell you're using +echo $SHELL + +# Check if startup file sources safe-chain +# For Bash: +grep safe-chain ~/.bashrc + +# For Zsh: +grep safe-chain ~/.zshrc + +# For Fish: +grep safe-chain ~/.config/fish/config.fish + +# Verify scripts exist +ls ~/.safe-chain/scripts/ +``` + +### Check for Conflicting Installations + +> **Note:** The install/uninstall scripts automatically detect and remove conflicting installations, but you can manually check: + +```bash +# Check npm global +npm list -g @aikidosec/safe-chain + +# Check Volta +volta list safe-chain + +# Check nvm (all versions) +for version in $(nvm list | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+'); do + nvm exec "$version" npm list -g @aikidosec/safe-chain 2>/dev/null && echo "Found in $version" +done +``` + +## Manual Cleanup + +> **Note:** The install and uninstall scripts automatically handle these cleanup steps. Use these manual commands only if automatic cleanup fails. + +### Remove npm Global Installation + +```bash +npm uninstall -g @aikidosec/safe-chain +``` + +### Remove Volta Installation + +```bash +volta uninstall @aikidosec/safe-chain +``` + +### Remove nvm Installations (All Versions) + +```bash +# Automated approach +for version in $(nvm list | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+'); do + nvm exec "$version" npm uninstall -g @aikidosec/safe-chain +done + +# Or manual per version +nvm use +npm uninstall -g @aikidosec/safe-chain +``` + +### Clean Shell Configuration Files + +Manually remove safe-chain entries from: + +- Bash: `~/.bashrc` +- Zsh: `~/.zshrc` +- Fish: `~/.config/fish/config.fish` +- PowerShell: `$PROFILE` + +Look for and remove: + +- Lines sourcing from `~/.safe-chain/scripts/` +- Any safe-chain related function definitions + +### Remove Installation Directory + +```bash +rm -rf ~/.safe-chain +``` + +## Getting More Information + +### Enable Verbose Logging + +Get detailed diagnostic output: + +```bash +npm install express --safe-chain-logging=verbose +pip install requests --safe-chain-logging=verbose +``` + +### Report Issues + +If you encounter problems: + +1. Visit [GitHub Issues](https://github.com/AikidoSec/safe-chain/issues) +2. Include: + - Operating system and version + - Shell type and version + - `safe-chain --version` output + - Output from verification commands + - Verbose logs of the failing command diff --git a/install-scripts/install-safe-chain.sh b/install-scripts/install-safe-chain.sh index 1de2d23..88cabe7 100755 --- a/install-scripts/install-safe-chain.sh +++ b/install-scripts/install-safe-chain.sh @@ -159,6 +159,66 @@ remove_volta_installation() { fi } +# Check and uninstall nvm-managed package if present across all Node versions +remove_nvm_installation() { + # This script is run in sh shell for greatest compatibility. + # Because nvm is usually setup in bash/zsh/fish startup scripts, we need to source it. + # Otherwise it won't be available in sh. + if [ -s "$HOME/.nvm/nvm.sh" ]; then + # Source nvm to make it available in this script + . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1 + elif [ -s "$NVM_DIR/nvm.sh" ]; then + . "$NVM_DIR/nvm.sh" >/dev/null 2>&1 + fi + + # Check if nvm is now available + if ! command_exists nvm; then + return + fi + + nvm_versions=$(nvm list 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "") + + if [ -z "$nvm_versions" ]; then + return + fi + + # Track if we found any installations + found_installation=false + uninstall_failed=false + current_version=$(nvm current 2>/dev/null || echo "") + + # Check each version for safe-chain installation + for version in $nvm_versions; do + # Check if this version has safe-chain installed + # Use nvm exec to run npm list in the context of that Node version + if nvm exec "$version" npm list -g @aikidosec/safe-chain >/dev/null 2>&1; then + if [ "$found_installation" = false ]; then + info "Detected nvm installation(s) of @aikidosec/safe-chain" + info "Uninstalling from all Node versions..." + found_installation=true + fi + + info " Removing from Node $version..." + if nvm exec "$version" npm uninstall -g @aikidosec/safe-chain >/dev/null 2>&1; then + info " Successfully uninstalled from Node $version" + else + warn " Failed to uninstall from Node $version" + uninstall_failed=true + fi + fi + done + + # Restore original Node version if it was set + if [ -n "$current_version" ] && [ "$current_version" != "none" ] && [ "$current_version" != "system" ]; then + nvm use "$current_version" >/dev/null 2>&1 || true + fi + + # If any uninstall failed, error out instead of continuing + if [ "$uninstall_failed" = true ]; then + error "Failed to uninstall @aikidosec/safe-chain from all nvm Node versions. Please uninstall manually and try again." + fi +} + # Parse command-line arguments parse_arguments() { for arg in "$@"; do @@ -204,9 +264,10 @@ main() { info "$INSTALL_MSG" - # Check for existing safe-chain installation through npm or volta + # Check for existing safe-chain installation through nvm, volta, or npm remove_npm_installation remove_volta_installation + remove_nvm_installation # Detect platform OS=$(detect_os) diff --git a/install-scripts/uninstall-safe-chain.sh b/install-scripts/uninstall-safe-chain.sh index 4b2d7ec..e208319 100755 --- a/install-scripts/uninstall-safe-chain.sh +++ b/install-scripts/uninstall-safe-chain.sh @@ -75,6 +75,68 @@ remove_volta_installation() { fi } +# Check and uninstall nvm-managed package if present across all Node versions +remove_nvm_installation() { + # This script is run in sh shell for greatest compatibility. + # Because nvm is usually setup in bash/zsh/fish startup scripts, we need to source it. + # Otherwise it won't be available in sh. + if [ -s "$HOME/.nvm/nvm.sh" ]; then + # Source nvm to make it available in this script + . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1 + elif [ -s "$NVM_DIR/nvm.sh" ]; then + . "$NVM_DIR/nvm.sh" >/dev/null 2>&1 + fi + + # Check if nvm is now available + if ! command_exists nvm; then + return + fi + + # Get list of installed Node versions + nvm_versions=$(nvm list 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "") + + if [ -z "$nvm_versions" ]; then + return + fi + + # Track if we found any installations + found_installation=false + uninstall_failed=false + current_version=$(nvm current 2>/dev/null || echo "") + + # Check each version for safe-chain installation + for version in $nvm_versions; do + # Check if this version has safe-chain installed + # Use nvm exec to run npm list in the context of that Node version + if nvm exec "$version" npm list -g @aikidosec/safe-chain >/dev/null 2>&1; then + if [ "$found_installation" = false ]; then + info "Detected nvm installation(s) of @aikidosec/safe-chain" + info "Uninstalling from all Node versions..." + found_installation=true + fi + + info " Removing from Node $version..." + if nvm exec "$version" npm uninstall -g @aikidosec/safe-chain >/dev/null 2>&1; then + info " Successfully uninstalled from Node $version" + else + warn " Failed to uninstall from Node $version" + uninstall_failed=true + fi + fi + done + + # Restore original Node version if it was set + if [ -n "$current_version" ] && [ "$current_version" != "none" ] && [ "$current_version" != "system" ]; then + nvm use "$current_version" >/dev/null 2>&1 || true + fi + + # Show warning if any uninstall failed (but don't error out during uninstall) + if [ "$uninstall_failed" = true ]; then + warn "Failed to uninstall @aikidosec/safe-chain from some nvm Node versions" + warn "You may need to manually run: nvm exec npm uninstall -g @aikidosec/safe-chain" + fi +} + # Main uninstallation main() { SAFE_CHAIN_LOCATION="$INSTALL_DIR/safe-chain" @@ -89,8 +151,10 @@ main() { warn "safe-chain command not found. Proceeding with uninstallation." fi + # Check for existing safe-chain installation through nvm, volta, or npm remove_npm_installation remove_volta_installation + remove_nvm_installation # Remove install dir recursively if it exists if [ -d "$INSTALL_DIR" ]; then