Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 114 additions & 9 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,57 @@ on:
- "test/testdata/**"

jobs:
# New Job: Checks permissions for PRs and outputs the result.
check-permissions:
name: Check PR author permissions
# This job only runs for pull_request_target events.
if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
outputs:
granted: ${{ steps.permission_check.outputs.result }}
steps:
- name: Check user permissions
id: permission_check
uses: actions/github-script@v7
with:
result-encoding: string # Capture the script's return value as an output
script: |
const actor = context.payload.pull_request.user.login;

// Allow dependabot and other bots unconditionally.
if (actor.endsWith('[bot]')) {
core.info(`User @${actor} is a bot, allowing.`);
return 'true';
}

try {
const response = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: actor,
});

const permission = response.data.permission;
if (permission === 'admin' || permission === 'write') {
core.info(`βœ… User @${actor} has '${permission}' permission. Proceeding.`);
return 'true';
} else {
core.warning(`User @${actor} has '${permission}' permission. 'write' or 'admin' is required. Skipping E2E tests.`);
return 'false';
}
} catch (error) {
core.warning(`Could not verify permission for @${actor}. They might not be a collaborator. Error: ${error.message}`);
return 'false';
}

# Modified Job: Now depends on the check-permissions job.
e2e-tests:
# Run on schedule, unconditional workflow_dispatch,
# or pull_request_target if the actor has write/admin permissions.
needs: [check-permissions] # It depends on the result of the check.
# The job runs on schedule/dispatch, or on PRs if the check-permissions job granted access.
if: >
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request_target' && contains(fromJSON('["zakisk", "infernus01", "savitaashture", "chmouel", "vdemeester", "enarha", "aThorp96", "waveywaves", "mathur07", "dependabot[bot]"]'), github.event.pull_request.user.login))
github.event_name == 'pull_request_target'
concurrency:
group: ${{ github.workflow }}-${{ matrix.provider }}-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true
Expand Down Expand Up @@ -68,10 +112,74 @@ jobs:
TEST_BITBUCKET_SERVER_USER: pipelines
TEST_BITBUCKET_SERVER_E2E_REPOSITORY: PAC/pac-e2e-tests
steps:
- name: Check user permissions (detailed)
id: check_perms
uses: actions/github-script@v7
with:
script: |
const actor = context.actor;
const { owner, repo } = context.repo;

try {
const response = await github.rest.repos.getCollaboratorPermissionLevel({
owner,
repo,
username: actor,
});

const userPermission = response.data.permission;

if (userPermission === 'admin') {
core.info(`βœ… Permission check successful. User @${actor} is an ADMIN.`);
} else if (userPermission === 'write') {
core.info(`βœ… Permission check successful. User @${actor} has WRITE permission.`);
} else {
core.setFailed(`❌ Permission check failed. User @${actor} has '${userPermission}' permission, but 'write' or 'admin' is required to proceed.`);
}

} catch (error) {
core.setFailed(`Could not verify permission for @${actor}. They might not be a collaborator. Error: ${error.message}`);
}

- uses: actions/checkout@v5
with:
ref: ${{ inputs.target_ref || github.event.pull_request.head.sha || github.sha }}

# Step to check PR author's org membership and repo permissions.
# This step will fail the job if checks do not pass, skipping subsequent steps.
- name: Check user permissions on PRs
if: github.event_name == 'pull_request_target'
uses: actions/github-script@v7
with:
script: |
const actor = context.payload.pull_request.user.login;
const org = context.repo.owner;

// Allow dependabot and other bots unconditionally.
if (actor.endsWith('[bot]')) {
core.info(`User @${actor} is a bot, allowing.`);
return;
}

try {
// Directly check the user's permission level on the repository.
// This covers both org members and external collaborators with sufficient access.
const response = await github.rest.repos.getCollaboratorPermissionLevel({
owner: org,
repo: context.repo.repo,
username: actor,
});

const permission = response.data.permission;
if (permission !== 'admin' && permission !== 'write') {
core.setFailed(`❌ User @${actor} has only '${permission}' repository permission. 'write' or 'admin' is required.`);
} else {
core.info(`βœ… User @${actor} has '${permission}' repository permission. Proceeding.`);
}
} catch (error) {
core.setFailed(`Permission check failed for @${actor}. They are likely not a collaborator on the repository. Error: ${error.message}`);
}

- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
Expand All @@ -93,8 +201,8 @@ jobs:
nohup gosmee client --saveDir /tmp/gosmee-replay ${{ secrets.PYSMEE_URL }} "http://${CONTROLLER_DOMAIN_URL}" &

- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
uses: mxschmitt/action-tmate@v3
with:
detached: true
limit-access-to-actor: true
Expand All @@ -121,11 +229,8 @@ jobs:
run: |
./hack/gh-workflow-ci.sh create_second_github_app_controller_on_ghe

# Adjusted step-level conditions based on the new job-level logic
- name: Run E2E Tests
# This step runs for schedule, PR target (if job started), or workflow_dispatch (if job started)
# Remove the old label check which is no longer relevant for triggering.
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request_target' }}
# The job-level `if` condition already handles this, so the step can run unconditionally
env:
TEST_PROVIDER: ${{ matrix.provider }}
TEST_BITBUCKET_CLOUD_TOKEN: ${{ secrets.BITBUCKET_CLOUD_TOKEN }}
Expand All @@ -142,7 +247,6 @@ jobs:
./hack/gh-workflow-ci.sh run_e2e_tests

- name: Run E2E Tests on nightly
# This step still runs specifically for schedule or workflow_dispatch
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
env:
NIGHTLY_E2E_TEST: "true"
Expand Down Expand Up @@ -188,3 +292,4 @@ jobs:
notify_when: "failure"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

8 changes: 8 additions & 0 deletions pkg/pipelineascode/pipelineascode.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ func (p *PacRun) Run(ctx context.Context) error {
return nil
}

// startPR creates and initializes a Tekton PipelineRun for the given match.
// It may auto-create a basic auth Secret for git access (and set its ownerRef),
// adds Pipelines-as-Code labels/annotations, optionally marks the PipelineRun
// as pending when repository concurrency is enabled, creates the PipelineRun in
// the target namespace, reports an initial status with a console URL to the SCM
// provider, and patches state/logURL metadata used by the PAC watcher. On
// partial failures after creation, it returns the created PipelineRun along
// with the error so callers can decide how to proceed.
func (p *PacRun) startPR(ctx context.Context, match matcher.Match) (*tektonv1.PipelineRun, error) {
var gitAuthSecretName string

Expand Down
Loading