name: Action E2E

on:
  pull_request:
    branches: [main]
    paths:
      - action.yml
      - docs/github-action.md
      - .github/workflows/action-e2e.yml
  push:
    branches: [main]
    paths:
      - action.yml
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.ref) || github.run_id }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
  contents: read

jobs:
  default-config:
    name: Default config installs and protects
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 24
      - uses: ./
      - name: PATH wiring
        run: |
          set -e
          which pmg
          which npm
          test "$(command -v npm)" = "$HOME/.pmg/bin/npm"
      - name: Install a benign package
        run: |
          mkdir t && cd t
          npm init -y
          npm install express@5.2.1
          test -d node_modules/express
      - name: Block a known-malicious package
        shell: bash
        run: |
          set -eo pipefail
          mkdir m && cd m
          npm init -y
          set +e
          npm --prefer-online --no-cache i safedep-test-pkg@0.1.3 >out.log 2>&1
          code=$?
          set -e
          cat out.log
          if [ "$code" -eq 0 ]; then
            echo "::error::Expected install to fail (malicious package), but it succeeded." >&2
            exit 1
          fi
          grep -qi "Malicious package blocked" out.log

  custom-config-file:
    name: config-file input overrides defaults
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 24
      - name: Write custom PMG config
        run: |
          cat > pmg.yml <<'YAML'
          paranoid: true
          dependency_cooldown:
            enabled: true
            days: 365
          YAML
      - uses: ./
        with:
          config-file: pmg.yml
      - name: Verify config staged into PMG config dir
        run: |
          set -e
          dest="${XDG_CONFIG_HOME:-$HOME/.config}/safedep/pmg/config.yml"
          test -f "$dest"
          grep -q "^paranoid: true" "$dest"
          grep -q "days: 365" "$dest"
      - name: Verify env doesn't shadow file-based tuning
        shell: bash
        run: |
          # With no explicit "paranoid" input, the action must not export
          # PMG_PARANOID — otherwise it would override the staged config.
          if [ -n "${PMG_PARANOID:-}" ]; then
            echo "::error::PMG_PARANOID leaked into env ($PMG_PARANOID); would shadow config-file" >&2
            exit 1
          fi

  sandbox-setup:
    name: Sandbox setup (${{ matrix.driver }})
    runs-on: ubuntu-latest
    timeout-minutes: 10
    strategy:
      fail-fast: false
      matrix:
        driver: [landlock, bubblewrap]
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: 24
      - uses: ./
        with:
          sandbox: "true"
          sandbox-driver: ${{ matrix.driver }}
      - name: Sandbox env vars propagated
        shell: bash
        run: |
          set -e
          test "$PMG_SANDBOX_ENABLED" = "true"
          test "$PMG_SANDBOX_DRIVER" = "${{ matrix.driver }}"
          pmg version
      - name: Bubblewrap binary installed when driver=bubblewrap
        if: matrix.driver == 'bubblewrap'
        run: bwrap --version
      - name: AppArmor user-ns restriction relaxed
        shell: bash
        run: |
          # systemctl-stop is best-effort; just confirm the sysctl is now 0
          # so unprivileged user namespaces work for either driver.
          v=$(cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns 2>/dev/null || echo "missing")
          echo "apparmor_restrict_unprivileged_userns=$v"
          test "$v" = "0" -o "$v" = "missing"

  non-linux-fail-fast:
    name: Action fails fast on non-Linux runners
    strategy:
      fail-fast: false
      matrix:
        os: [macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Action must exit non-zero
        id: run
        continue-on-error: true
        uses: ./
      - name: Verify it failed
        shell: bash
        run: |
          test "${{ steps.run.outcome }}" = "failure"
