Refactor test workflows to keep the same patterns as in other repos (terraform, operator)

This commit is contained in:
Volodymyr Zotov
2025-12-12 14:22:36 -06:00
parent e3aa72700f
commit df80909445
6 changed files with 268 additions and 327 deletions

View File

@@ -1,131 +0,0 @@
name: Acceptance test
on:
workflow_call:
inputs:
secret:
required: true
type: string
secret-in-section:
required: true
type: string
multiline-secret:
required: true
type: string
export-env:
required: true
type: boolean
version:
required: false
type: string
default: "latest"
os:
required: true
type: string
default: "ubuntu-latest"
auth:
required: true
type: string
jobs:
acceptance-test:
runs-on: ${{ inputs.os }}
steps:
- name: Base checkout
uses: actions/checkout@v4
if: |
github.event_name != 'repository_dispatch' &&
(
github.ref == 'refs/heads/main' ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
)
)
- name: Fork based /ok-to-test checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.client_payload.pull_request.head.sha }}
if: |
github.event_name == 'repository_dispatch' &&
github.event.client_payload.slash_command.args.named.sha != '' &&
contains(
github.event.client_payload.pull_request.head.sha,
github.event.client_payload.slash_command.args.named.sha
)
- name: Launch 1Password Connect instance
if: ${{ inputs.auth == 'connect' }}
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 && sleep 10
- name: Configure Service account
if: ${{ inputs.auth == 'service-account' }}
uses: ./configure
with:
service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
- name: Verify Service Account env var is set
if: ${{ inputs.auth == 'service-account' }}
shell: bash
run: |
if [ -z "${OP_SERVICE_ACCOUNT_TOKEN}" ]; then
echo "OP_SERVICE_ACCOUNT_TOKEN environment variable is not set" >&2
exit 1
fi
- name: Configure 1Password Connect
if: ${{ inputs.auth == 'connect' }}
uses: ./configure # 1password/load-secrets-action/configure@<version>
with:
connect-host: http://localhost:8080
connect-token: ${{ secrets.OP_CONNECT_TOKEN }}
- name: Verify Connect env vars are set
if: ${{ inputs.auth == 'connect' }}
run: |
if [ -z "$OP_CONNECT_HOST" ] || [ -z "$OP_CONNECT_TOKEN" ]; then
echo "OP_CONNECT_HOST or OP_CONNECT_TOKEN environment variables are not set" >&2
exit 1
fi
- name: Load secrets
id: load_secrets
uses: ./ # 1password/load-secrets-action@<version>
with:
version: ${{ inputs.version }}
export-env: ${{ inputs.export-env }}
env:
SECRET: ${{ inputs.secret }}
SECRET_IN_SECTION: ${{ inputs.secret-in-section }}
MULTILINE_SECRET: ${{ inputs.multiline-secret }}
OP_ENV_FILE: ./tests/.env.tpl
- name: Assert test secret values [step output]
if: ${{ !inputs.export-env }}
env:
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 }}
run: ./tests/assert-env-set.sh
- name: Assert test secret values [exported env]
if: ${{ inputs.export-env }}
run: ./tests/assert-env-set.sh
- name: Remove secrets [exported env]
if: ${{ inputs.export-env }}
uses: ./ # 1password/load-secrets-action@<version>
with:
unset-previous: true
- name: Assert removed secrets [exported env]
if: ${{ inputs.export-env }}
run: ./tests/assert-env-unset.sh

159
.github/workflows/e2e-tests.yml vendored Normal file
View File

@@ -0,0 +1,159 @@
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:
secrets:
OP_CONNECT_CREDENTIALS:
required: true
OP_CONNECT_TOKEN:
required: true
OP_SERVICE_ACCOUNT_TOKEN:
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 }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, 2.30.0]
export-env: [true, false]
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Generate .env.tpl
shell: bash
run: |
echo "FILE_SECRET=op://${{ secrets.VAULT }}/test-secret/password" > tests/.env.tpl
echo "FILE_SECRET_IN_SECTION=op://${{ secrets.VAULT }}/test-secret/test-section/password" >> tests/.env.tpl
echo "FILE_MULTILINE_SECRET=op://${{ secrets.VAULT }}/multiline-secret/notesPlain" >> tests/.env.tpl
- 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
OP_ENV_FILE: ./tests/.env.tpl
- name: Assert test secret values [step output]
if: ${{ !matrix.export-env }}
shell: bash
env:
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 }}
run: ./tests/assert-env-set.sh
- name: Assert test secret values [exported env]
if: ${{ matrix.export-env }}
shell: bash
run: ./tests/assert-env-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 }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version: [latest, 2.30.0]
export-env: [true, false]
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Generate .env.tpl
run: |
mkdir -p tests
echo "FILE_SECRET=op://${{ secrets.VAULT }}/test-secret/password" > tests/.env.tpl
echo "FILE_SECRET_IN_SECTION=op://${{ secrets.VAULT }}/test-secret/test-section/password" >> tests/.env.tpl
echo "FILE_MULTILINE_SECRET=op://${{ secrets.VAULT }}/multiline-secret/notesPlain" >> tests/.env.tpl
- 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 && sleep 10
- 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
OP_ENV_FILE: ./tests/.env.tpl
- name: Assert test secret values [step output]
if: ${{ !matrix.export-env }}
env:
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 }}
run: ./tests/assert-env-set.sh
- name: Assert test secret values [exported env]
if: ${{ matrix.export-env }}
run: ./tests/assert-env-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

View File

@@ -1,4 +1,4 @@
# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event
# Write comments "/ok-to-test sha=<hash>" on a pull request. This will emit a repository_dispatch event.
name: Ok To Test
on:
@@ -15,7 +15,7 @@ jobs:
if: ${{ github.event.issue.pull_request }}
steps:
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v3
uses: volodymyrZotov/slash-command-dispatch@7c1b623a2b0eba93f684c34f689a441f0be84cf1 # TODO: use peter-evans/slash-command-dispatch when fix for team permissions is released https://github.com/peter-evans/slash-command-dispatch/pull/424
with:
token: ${{ secrets.GITHUB_TOKEN }}
reaction-token: ${{ secrets.GITHUB_TOKEN }}

107
.github/workflows/test-e2e.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: E2E Tests
on:
push:
branches: [main]
pull_request:
repository_dispatch:
types: [ok-to-test-command]
concurrency:
group: >-
${{ github.event_name == 'pull_request' &&
format('e2e-{0}', github.event.pull_request.head.ref) ||
format('e2e-{0}', github.ref) }}
cancel-in-progress: true
jobs:
check-external-pr:
runs-on: ubuntu-latest
outputs:
condition: ${{ steps.check.outputs.condition }}
steps:
- name: Check if PR is from external contributor
id: check
run: |
echo "Event name: ${{ github.event_name }}"
echo "Repository: ${{ github.repository }}"
if [ "${{ github.event_name }}" == "pull_request" ]; then
# For pull_request events, check if PR is from external fork
echo "PR head repo: ${{ github.event.pull_request.head.repo.full_name }}"
if [ "${{ github.actor }}" == "dependabot[bot]" ]; then
echo "condition=skip" >> $GITHUB_OUTPUT
echo "Setting condition=skip (Dependabot PR)"
elif [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
echo "condition=skip" >> $GITHUB_OUTPUT
echo "Setting condition=skip (external fork PR creation)"
else
echo "condition=pr-creation-maintainer" >> $GITHUB_OUTPUT
echo "Setting condition=pr-creation-maintainer (internal PR creation)"
fi
elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then
# For repository_dispatch events (ok-to-test), check if sha matches
SHA_PARAM="${{ github.event.client_payload.slash_command.args.named.sha }}"
PR_HEAD_SHA="${{ github.event.client_payload.pull_request.head.sha }}"
echo "Checking dispatch event conditions..."
echo "SHA from command: $SHA_PARAM"
echo "PR head SHA: $PR_HEAD_SHA"
if [ -n "$SHA_PARAM" ] && [[ "$PR_HEAD_SHA" == *"$SHA_PARAM"* ]]; then
echo "condition=dispatch-event" >> $GITHUB_OUTPUT
echo "Setting condition=dispatch-event (sha matches)"
else
echo "condition=skip" >> $GITHUB_OUTPUT
echo "Setting condition=skip (sha does not match or empty)"
fi
elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref_name }}" == "main" ]; then
echo "condition=push-to-main" >> $GITHUB_OUTPUT
echo "Setting condition=push-to-main (push to main)"
else
# Unknown event type
echo "condition=skip" >> $GITHUB_OUTPUT
echo "Setting condition=skip (unknown event type: ${{ github.event_name }})"
fi
e2e:
needs: check-external-pr
if: |
(needs.check-external-pr.outputs.condition == 'pr-creation-maintainer')
||
(needs.check-external-pr.outputs.condition == 'dispatch-event')
||
needs.check-external-pr.outputs.condition == 'push-to-main'
uses: ./.github/workflows/e2e-tests.yml
secrets:
OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
VAULT: ${{ secrets.VAULT }}
# Post comment on fork PRs after /ok-to-test
comment-pr:
needs: [check-external-pr, e2e]
runs-on: ubuntu-latest
if: always() && needs.check-external-pr.outputs.condition == 'dispatch-event'
permissions:
pull-requests: write
steps:
- name: Create URL to the run output
id: vars
run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
- name: Create comment on PR
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.client_payload.pull_request.number }}
body: |
${{
needs.e2e.result == 'success' && '✅ E2E tests passed.' ||
needs.e2e.result == 'failure' && '❌ E2E tests failed.' ||
'⚠️ E2E tests completed.'
}}
[View test run output][1]
[1]: ${{ steps.vars.outputs.run-url }}

View File

@@ -1,92 +0,0 @@
on:
repository_dispatch:
types: [ok-to-test-command]
name: Run acceptance tests [fork]
jobs:
test-with-output-secrets:
if: |
github.event_name == 'repository_dispatch' &&
github.event.client_payload.slash_command.args.named.sha != '' &&
contains(
github.event.client_payload.pull_request.head.sha,
github.event.client_payload.slash_command.args.named.sha
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
with:
secret: op://acceptance-tests/test-secret/password
secret-in-section: op://acceptance-tests/test-secret/test-section/password
multiline-secret: op://acceptance-tests/multiline-secret/notesPlain
export-env: false
test-with-export-env:
if: |
github.event_name == 'repository_dispatch' &&
github.event.client_payload.slash_command.args.named.sha != '' &&
contains(
github.event.client_payload.pull_request.head.sha,
github.event.client_payload.slash_command.args.named.sha
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
with:
secret: op://acceptance-tests/test-secret/password
secret-in-section: op://acceptance-tests/test-secret/test-section/password
multiline-secret: op://acceptance-tests/multiline-secret/notesPlain
export-env: true
test-references-with-ids:
if: |
github.event_name == 'repository_dispatch' &&
github.event.client_payload.slash_command.args.named.sha != '' &&
contains(
github.event.client_payload.pull_request.head.sha,
github.event.client_payload.slash_command.args.named.sha
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
with:
secret: op://v5pz6venw4roosmkzdq2nhpv6u/hrgkzhrlvscomepxlgafb2m3ca/password
secret-in-section: op://v5pz6venw4roosmkzdq2nhpv6u/hrgkzhrlvscomepxlgafb2m3ca/Section_tco6nsqycj6jcbyx63h5isxcny/doxu3mhkozcznnk5vjrkpdqayy
multiline-secret: op://v5pz6venw4roosmkzdq2nhpv6u/ghtz3jvcc6dqmzc53d3r3eskge/notesPlain
export-env: false
update-checks:
# required permissions for updating the status of the pull request checks
permissions:
pull-requests: write
checks: write
runs-on: ubuntu-latest
if: ${{ always() }}
strategy:
matrix:
job-name:
[
test-with-output-secrets,
test-with-export-env,
test-references-with-ids,
]
needs:
[test-with-output-secrets, test-with-export-env, test-references-with-ids]
steps:
- uses: actions/github-script@v6
env:
job: ${{ matrix.job-name }}
ref: ${{ github.event.client_payload.pull_request.head.sha }}
conclusion: ${{ needs[format('{0}', matrix.job-name )].result }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: checks } = await github.rest.checks.listForRef({
...context.repo,
ref: process.env.ref
});
const check = checks.check_runs.filter(c => c.name === process.env.job);
const { data: result } = await github.rest.checks.update({
...context.repo,
check_run_id: check[0].id,
status: 'completed',
conclusion: process.env.conclusion
});
return result;

View File

@@ -1,102 +0,0 @@
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
branches: ["**"] # run for PRs targeting any branch (main and others)
name: Run acceptance tests
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- run: npm ci
- run: npm test
test-with-output-secrets:
if: |
github.ref == 'refs/heads/main' ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, latest-beta, 2.30.0, 2.30.0-beta.03]
auth: [connect, service-account]
exclude:
- os: macos-latest
auth: connect
- os: windows-latest
auth: connect
with:
os: ${{ matrix.os }}
version: ${{ matrix.version }}
auth: ${{ matrix.auth }}
secret: op://acceptance-tests/test-secret/password
secret-in-section: op://acceptance-tests/test-secret/test-section/password
multiline-secret: op://acceptance-tests/multiline-secret/notesPlain
export-env: false
test-with-export-env:
if: |
github.ref == 'refs/heads/main' ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, latest-beta, 2.30.0, 2.30.0-beta.03]
auth: [connect, service-account]
exclude:
- os: macos-latest
auth: connect
- os: windows-latest
auth: connect
with:
os: ${{ matrix.os }}
version: ${{ matrix.version }}
auth: ${{ matrix.auth }}
secret: op://acceptance-tests/test-secret/password
secret-in-section: op://acceptance-tests/test-secret/test-section/password
multiline-secret: op://acceptance-tests/multiline-secret/notesPlain
export-env: true
test-references-with-ids:
if: |
github.ref == 'refs/heads/main' ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
)
uses: 1password/load-secrets-action/.github/workflows/acceptance-test.yml@main
secrets: inherit
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, latest-beta, 2.30.0, 2.30.0-beta.03]
auth: [connect, service-account]
exclude:
- os: macos-latest
auth: connect
- os: windows-latest
auth: connect
with:
os: ${{ matrix.os }}
version: ${{ matrix.version }}
auth: ${{ matrix.auth }}
secret: op://v5pz6venw4roosmkzdq2nhpv6u/hrgkzhrlvscomepxlgafb2m3ca/password
secret-in-section: op://v5pz6venw4roosmkzdq2nhpv6u/hrgkzhrlvscomepxlgafb2m3ca/Section_tco6nsqycj6jcbyx63h5isxcny/doxu3mhkozcznnk5vjrkpdqayy
multiline-secret: op://v5pz6venw4roosmkzdq2nhpv6u/ghtz3jvcc6dqmzc53d3r3eskge/notesPlain
export-env: false