name: E2E Tests

on:
  # For local testing with: act push -W .github/workflows/e2e-tests.yml
  push:
    branches-ignore:
      - "**" # Never runs on GitHub, only locally with act

  # For test.yml to call this workflow
  workflow_call:
    inputs:
      ref:
        description: "Git ref to checkout"
        required: true
        type: string
    secrets:
      OP_CONNECT_CREDENTIALS:
        required: true
      OP_CONNECT_TOKEN:
        required: true
      OP_SERVICE_ACCOUNT_TOKEN:
        required: true
      OP_WORKLOAD_ID:
        required: true
      OP_ENVIRONMENT_ID:
        required: true
      OP_INTEGRATION_KEY:
        required: true
      VAULT:
        description: "1Password vault name or UUID"
        required: true

jobs:
  test-service-account:
    name: Service Account (${{ matrix.os }}, ${{ matrix.version }}, export-env=${{ matrix.export-env }})
    if: false
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: true
      max-parallel: 4
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        version: [latest, 2.30.0]
        export-env: [true, false]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ inputs.ref }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Build actions
        run: npm run build:all

      - name: Generate .env.tpl
        shell: bash
        run: |
          echo "FILE_SECRET=op://${VAULT}/test-secret/password" > tests/.env.tpl
          echo "FILE_SECRET_IN_SECTION=op://${VAULT}/test-secret/test-section/password" >> tests/.env.tpl
          echo "FILE_MULTILINE_SECRET=op://${VAULT}/multiline-secret/notesPlain" >> tests/.env.tpl
          echo "FILE_WEBSITE=op://${VAULT}/test-secret/website" >> tests/.env.tpl
          echo "FILE_TEST_SSH_KEY=op://${VAULT}/test-ssh-key/private key" >> tests/.env.tpl
          echo "FILE_TEST_SSH_KEY_OPENSSH=op://${VAULT}/test-ssh-key/private key?ssh-format=openssh" >> tests/.env.tpl

        env:
          VAULT: ${{ secrets.VAULT }}
      - name: Configure Service account
        uses: ./configure
        with:
          service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}

      - name: Load secrets
        id: load_secrets
        uses: ./
        with:
          version: ${{ matrix.version }}
          export-env: ${{ matrix.export-env }}
        env:
          SECRET: op://${{ secrets.VAULT }}/test-secret/password
          SECRET_IN_SECTION: op://${{ secrets.VAULT }}/test-secret/test-section/password
          MULTILINE_SECRET: op://${{ secrets.VAULT }}/multiline-secret/notesPlain
          WEBSITE: op://${{ secrets.VAULT }}/test-secret/website
          TEST_SSH_KEY: op://${{ secrets.VAULT }}/test-ssh-key/private key
          TEST_SSH_KEY_OPENSSH: "op://${{ secrets.VAULT }}/test-ssh-key/private key?ssh-format=openssh"
          OP_ENV_FILE: ./tests/.env.tpl

      - name: Assert test secret values [step output]
        if: ${{ !matrix.export-env }}
        shell: bash
        env:
          ASSERT_WEBSITE: "true"
          SECRET: ${{ steps.load_secrets.outputs.SECRET }}
          SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.SECRET_IN_SECTION }}
          MULTILINE_SECRET: ${{ steps.load_secrets.outputs.MULTILINE_SECRET }}
          FILE_SECRET: ${{ steps.load_secrets.outputs.FILE_SECRET }}
          FILE_SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.FILE_SECRET_IN_SECTION }}
          FILE_MULTILINE_SECRET: ${{ steps.load_secrets.outputs.FILE_MULTILINE_SECRET }}
          WEBSITE: ${{ steps.load_secrets.outputs.WEBSITE }}
          FILE_WEBSITE: ${{ steps.load_secrets.outputs.FILE_WEBSITE }}
          TEST_SSH_KEY: ${{ steps.load_secrets.outputs.TEST_SSH_KEY }}
          FILE_TEST_SSH_KEY: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY }}
          TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.TEST_SSH_KEY_OPENSSH }}
          FILE_TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY_OPENSSH }}
        run: ./tests/assert-env-set.sh

      - name: Assert SSH key env vars [step output]
        if: ${{ !matrix.export-env }}
        shell: bash
        env:
          TEST_SSH_KEY: ${{ steps.load_secrets.outputs.TEST_SSH_KEY }}
          FILE_TEST_SSH_KEY: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY }}
          TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.TEST_SSH_KEY_OPENSSH }}
          FILE_TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY_OPENSSH }}
        run: ./tests/assert-ssh-keys-set.sh

      - name: Assert test secret values [exported env]
        if: ${{ matrix.export-env }}
        shell: bash
        env:
          ASSERT_WEBSITE: "true"
        run: ./tests/assert-env-set.sh

      - name: Assert SSH key env vars [exported env]
        if: ${{ matrix.export-env }}
        shell: bash
        run: ./tests/assert-ssh-keys-set.sh

      - name: Remove secrets [exported env]
        if: ${{ matrix.export-env }}
        uses: ./
        with:
          unset-previous: true

      - name: Assert removed secrets [exported env]
        if: ${{ matrix.export-env }}
        shell: bash
        run: ./tests/assert-env-unset.sh

  test-connect:
    name: Connect (ubuntu-latest, ${{ matrix.version }}, export-env=${{ matrix.export-env }})
    if: false
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        version: [latest, 2.30.0]
        export-env: [true, false]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ inputs.ref }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Build actions
        run: npm run build:all

      - name: Generate .env.tpl
        run: |
          mkdir -p tests
          echo "FILE_SECRET=op://${VAULT}/test-secret/password" > tests/.env.tpl
          echo "FILE_SECRET_IN_SECTION=op://${VAULT}/test-secret/test-section/password" >> tests/.env.tpl
          echo "FILE_MULTILINE_SECRET=op://${VAULT}/multiline-secret/notesPlain" >> tests/.env.tpl
          echo "FILE_TEST_SSH_KEY=op://${VAULT}/test-ssh-key/private key" >> tests/.env.tpl
          echo "FILE_TEST_SSH_KEY_OPENSSH=op://${VAULT}/test-ssh-key/private key?ssh-format=openssh" >> tests/.env.tpl

        env:
          VAULT: ${{ secrets.VAULT }}
      - name: Launch 1Password Connect instance
        env:
          OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
        run: |
          echo "$OP_CONNECT_CREDENTIALS" > 1password-credentials.json
          docker compose -f tests/fixtures/docker-compose.yml up -d
          timeout 60 bash -c 'until curl -sf http://localhost:8080/health >/dev/null 2>&1; do sleep 2; done'

      - name: Configure 1Password Connect
        uses: ./configure
        with:
          connect-host: http://localhost:8080
          connect-token: ${{ secrets.OP_CONNECT_TOKEN }}

      - name: Load secrets
        id: load_secrets
        uses: ./
        with:
          version: ${{ matrix.version }}
          export-env: ${{ matrix.export-env }}
        env:
          SECRET: op://${{ secrets.VAULT }}/test-secret/password
          SECRET_IN_SECTION: op://${{ secrets.VAULT }}/test-secret/test-section/password
          MULTILINE_SECRET: op://${{ secrets.VAULT }}/multiline-secret/notesPlain
          TEST_SSH_KEY: op://${{ secrets.VAULT }}/test-ssh-key/private key
          TEST_SSH_KEY_OPENSSH: "op://${{ secrets.VAULT }}/test-ssh-key/private key?ssh-format=openssh"
          OP_ENV_FILE: ./tests/.env.tpl

      - name: Assert test secret values [step output]
        if: ${{ !matrix.export-env }}
        env:
          ASSERT_WEBSITE: "false"
          SECRET: ${{ steps.load_secrets.outputs.SECRET }}
          SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.SECRET_IN_SECTION }}
          MULTILINE_SECRET: ${{ steps.load_secrets.outputs.MULTILINE_SECRET }}
          FILE_SECRET: ${{ steps.load_secrets.outputs.FILE_SECRET }}
          FILE_SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.FILE_SECRET_IN_SECTION }}
          FILE_MULTILINE_SECRET: ${{ steps.load_secrets.outputs.FILE_MULTILINE_SECRET }}
          TEST_SSH_KEY: ${{ steps.load_secrets.outputs.TEST_SSH_KEY }}
          FILE_TEST_SSH_KEY: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY }}
          TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.TEST_SSH_KEY_OPENSSH }}
          FILE_TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY_OPENSSH }}
        run: ./tests/assert-env-set.sh

      - name: Assert SSH key env vars [step output]
        if: ${{ !matrix.export-env }}
        env:
          TEST_SSH_KEY: ${{ steps.load_secrets.outputs.TEST_SSH_KEY }}
          FILE_TEST_SSH_KEY: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY }}
          TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.TEST_SSH_KEY_OPENSSH }}
          FILE_TEST_SSH_KEY_OPENSSH: ${{ steps.load_secrets.outputs.FILE_TEST_SSH_KEY_OPENSSH }}
        run: ./tests/assert-ssh-keys-set.sh

      - name: Assert test secret values [exported env]
        if: ${{ matrix.export-env }}
        env:
          ASSERT_WEBSITE: "false"
        run: ./tests/assert-env-set.sh

      - name: Assert SSH key env vars [exported env]
        if: ${{ matrix.export-env }}
        run: ./tests/assert-ssh-keys-set.sh

      - name: Remove secrets [exported env]
        if: ${{ matrix.export-env }}
        uses: ./
        with:
          unset-previous: true

      - name: Assert removed secrets [exported env]
        if: ${{ matrix.export-env }}
        run: ./tests/assert-env-unset.sh

  test-workload-identity:
    name: Workload Identity (ubuntu-latest, export-env=${{ matrix.export-env }})
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    strategy:
      fail-fast: true
      matrix:
        export-env: [true, false]
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ inputs.ref }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Build actions
        run: npm run build:all

      - name: Load secrets
        id: load_secrets
        uses: ./
        with:
          export-env: ${{ matrix.export-env }}
        env:
          OP_WORKLOAD_ID: ${{ secrets.OP_WORKLOAD_ID }}
          OP_ENVIRONMENT_ID: ${{ secrets.OP_ENVIRONMENT_ID }}
          OP_INTEGRATION_KEY: ${{ secrets.OP_INTEGRATION_KEY }}

      - name: Assert test secret values [step output]
        if: ${{ !matrix.export-env }}
        shell: bash
        env:
          ANOTHER_TEST: ${{ steps.load_secrets.outputs.ANOTHER_TEST }}
          SUPER_SECRET: ${{ steps.load_secrets.outputs.SUPER_SECRET }}
          TEST_SECRET: ${{ steps.load_secrets.outputs.TEST_SECRET }}
        run: ./tests/assert-workload-identity.sh

      - name: Assert test secret values [exported env]
        if: ${{ matrix.export-env }}
        shell: bash
        run: ./tests/assert-workload-identity.sh

      - name: Remove secrets [exported env]
        if: ${{ matrix.export-env }}
        uses: ./
        with:
          unset-previous: true

      - name: Assert removed secrets [exported env]
        if: ${{ matrix.export-env }}
        shell: bash
        run: |
          for var in ANOTHER_TEST SUPER_SECRET TEST_SECRET; do
            if [ -n "$(printenv "$var")" ]; then
              echo "Expected secret $var to be unset"
              exit 1
            fi
          done
