diff --git a/.github/actions/reaction/action.yml b/.github/actions/reaction/action.yml deleted file mode 100644 index 9858b7290c..0000000000 --- a/.github/actions/reaction/action.yml +++ /dev/null @@ -1,130 +0,0 @@ -name: "Add/Remove reaction on triggering item" -description: "Adds or removes a reaction on the issue/PR/comment that triggered the workflow" -inputs: - github-token: - description: "Token with issues/pull-requests write (GITHUB_TOKEN is fine)" - required: true - mode: - description: "'add' or 'remove'" - required: true - reaction: - description: "One of +1, -1, laugh, confused, heart, hooray, rocket, eyes" - required: false - default: "eyes" - reaction-id: - description: "Optional reaction id to remove (if known)" - required: false -outputs: - reaction-id: - description: "ID of the reaction that was added (for later removal)" -runs: - using: "composite" - steps: - - name: Compute reactions API endpoint for the triggering payload - id: ctx - shell: bash - env: - GITHUB_EVENT_NAME: ${{ github.event_name }} - GITHUB_EVENT_PATH: ${{ github.event_path }} - GITHUB_REPOSITORY: ${{ github.repository }} - run: | - set -euo pipefail - owner="${GITHUB_REPOSITORY%%/*}" - repo="${GITHUB_REPOSITORY##*/}" - ev="$GITHUB_EVENT_PATH" - - case "$GITHUB_EVENT_NAME" in - issues) - number=$(jq -r '.issue.number' "$ev") - endpoint="/repos/$owner/$repo/issues/$number/reactions" - ;; - issue_comment) - cid=$(jq -r '.comment.id' "$ev") - endpoint="/repos/$owner/$repo/issues/comments/$cid/reactions" - ;; - pull_request|pull_request_target) - number=$(jq -r '.pull_request.number' "$ev") - # PRs are "issues" for the reactions endpoint - endpoint="/repos/$owner/$repo/issues/$number/reactions" - ;; - pull_request_review_comment) - cid=$(jq -r '.comment.id' "$ev") - endpoint="/repos/$owner/$repo/pulls/comments/$cid/reactions" - ;; - *) - echo "Unsupported event: $GITHUB_EVENT_NAME" >&2 - exit 1 - ;; - esac - - echo "endpoint=$endpoint" >> "$GITHUB_OUTPUT" - - - name: Add reaction - if: ${{ inputs.mode == 'add' }} - shell: bash - env: - GH_TOKEN: ${{ inputs.github-token }} - ENDPOINT: ${{ steps.ctx.outputs.endpoint }} - REACTION: ${{ inputs.reaction }} - run: | - set -euo pipefail - # Create (or fetch existing) reaction - # The API returns the reaction object (201 on create, 200 if it already existed) - resp=$(gh api \ - -H "Accept: application/vnd.github+json" \ - -X POST "$ENDPOINT" \ - -f content="$REACTION" \ - || true) - - # If a concurrent create happened, fall back to listing to find our reaction - if [ -z "${resp:-}" ] || [ "$resp" = "null" ]; then - resp=$(gh api -H "Accept: application/vnd.github+json" "$ENDPOINT") - rid=$(echo "$resp" | jq -r --arg r "$REACTION" \ - '.[] | select(.content==$r and .user.login=="github-actions[bot]") | .id' | head -n1) - else - rid=$(echo "$resp" | jq -r '.id') - if [ "$rid" = "null" ] || [ -z "$rid" ]; then - # fallback to list, just in case - list=$(gh api -H "Accept: application/vnd.github+json" "$ENDPOINT") - rid=$(echo "$list" | jq -r --arg r "$REACTION" \ - '.[] | select(.content==$r and .user.login=="github-actions[bot]") | .id' | head -n1) - fi - fi - - if [ -z "${rid:-}" ]; then - echo "Warning: could not determine reaction id; cleanup will list/filter." >&2 - fi - - echo "reaction-id=${rid:-}" >> "$GITHUB_OUTPUT" - - - name: Remove reaction - if: ${{ inputs.mode == 'remove' }} - shell: bash - env: - GH_TOKEN: ${{ inputs.github-token }} - ENDPOINT: ${{ steps.ctx.outputs.endpoint }} - REACTION: ${{ inputs.reaction }} - REACTION_ID_IN: ${{ inputs.reaction-id }} - run: | - set -euo pipefail - - delete_by_id () { - local rid="$1" - if [ -n "$rid" ] && [ "$rid" != "null" ]; then - gh api -H "Accept: application/vnd.github+json" -X DELETE "/reactions/$rid" || true - fi - } - - if [ -n "$REACTION_ID_IN" ]; then - # Fast path: we were given the id from the add step - delete_by_id "$REACTION_ID_IN" - exit 0 - fi - - # Fallback: list reactions on the same subject, and delete the bot's matching reaction(s) - list=$(gh api -H "Accept: application/vnd.github+json" "$ENDPOINT" || echo "[]") - echo "$list" | jq -r --arg r "$REACTION" ' - .[] | select(.content==$r and .user.login=="github-actions[bot]") | .id - ' | while read -r rid; do - delete_by_id "$rid" - done \ No newline at end of file diff --git a/DEVGUIDE.md b/DEVGUIDE.md index 015e28e2ac..afd784ac8f 100644 --- a/DEVGUIDE.md +++ b/DEVGUIDE.md @@ -1,6 +1,6 @@ # Developer Guide -> [!WARNING] +> [!CAUTION] > This extension is a research demonstrator. It is in early development and may change significantly. It has not been thoroughly tested. Using agentic workflows in your repository requires careful supervision, and even then things can still go wrong. Use it with caution, and at your own risk. This guide provides comprehensive information for developers working on gh-aw, including setup, development workflow, testing, and contribution guidelines. diff --git a/README.md b/README.md index f4a7e37d0b..27dd7f88e8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Write agentic workflows in natural language markdown, and run them in GitHub Actions. From [GitHub Next](https://githubnext.com/). -> [!WARNING] +> [!CAUTION] > This extension is a research demonstrator. It is in early development and may change significantly. It has not been thoroughly tested. Using agentic workflows in your repository requires careful supervision, and even then things can still go wrong. Use it with caution, and at your own risk. ## ⚡ Quick Start (30 seconds) diff --git a/docs/index.md b/docs/index.md index ba45de5eac..43f773fb5a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # 📖 GitHub Agentic Workflows Documentation -> [!WARNING] +> [!CAUTION] > This extension is a research demonstrator. It is in early development and may change significantly. It has not been thoroughly tested. Using agentic workflows in your repository requires careful supervision, and even then things can still go wrong. Use it with caution, and at your own risk. Complete documentation for creating and managing agentic workflows with GitHub Actions. diff --git a/pkg/workflow/templates/check_team_member.yaml b/pkg/workflow/templates/check_team_member.yaml index 23d982eb1b..6fe7c681d5 100644 --- a/pkg/workflow/templates/check_team_member.yaml +++ b/pkg/workflow/templates/check_team_member.yaml @@ -13,49 +13,27 @@ runs: const actor = context.actor; const { owner, repo } = context.repo; - console.log(`Checking if user '${actor}' is a member of organization '${owner}'`); - + // Check if the actor has repository access (admin, maintain permissions) try { - // First, check if the actor has repository access (admin, write, maintain permissions) - try { - const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ - owner: owner, - repo: repo, - username: actor - }); - - const permission = repoPermission.data.permission; - console.log(`Repository permission level: ${permission}`); - - if (permission === 'admin' || permission === 'write' || permission === 'maintain') { - console.log(`User has ${permission} access to repository`); - core.setOutput('is_team_member', 'true'); - return; - } - } catch (repoError) { - console.log(`Repository permission check failed: ${repoError.message}`); - // Continue to org membership check - } + console.log(`Checking if user '${actor}' is admin or maintainer of ${owner}/${repo}`); + + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor + }); - // Fallback: check organization membership - try { - await github.rest.orgs.getMembershipForUser({ - org: owner, - username: actor - }); - console.log(`User is a member of organization ${owner}`); + const permission = repoPermission.data.permission; + console.log(`Repository permission level: ${permission}`); + + if (permission === 'admin' || permission === 'maintain') { + console.log(`User has ${permission} access to repository`); core.setOutput('is_team_member', 'true'); return; - } catch (orgError) { - console.log(`Organization membership check failed: ${orgError.message}`); } + } catch (repoError) { + console.log(`Repository permission check failed: ${repoError.message}`); + } + + core.setOutput('is_team_member', 'false'); - // If both checks failed, user is not a team member - console.log('User is not a team member (no repository access and not org member)'); - core.setOutput('is_team_member', 'false'); - - } catch (error) { - console.error(`Error checking team membership: ${error.message}`); - // Default to false on error for security - core.setOutput('is_team_member', 'false'); - } \ No newline at end of file diff --git a/pkg/workflow/templates/compute_text_action.yaml b/pkg/workflow/templates/compute_text_action.yaml index 7c32af2634..5e0f3f14ea 100644 --- a/pkg/workflow/templates/compute_text_action.yaml +++ b/pkg/workflow/templates/compute_text_action.yaml @@ -12,6 +12,29 @@ runs: with: script: | let text = ''; + + const actor = context.actor; + const { owner, repo } = context.repo; + + // Check if the actor has repository access (admin, maintain permissions) + try { + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor + }); + + const permission = repoPermission.data.permission; + console.log(`Repository permission level: ${permission}`); + + if (permission !== 'admin' && permission !== 'maintain') { + return; + } + } catch (repoError) { + console.log(`Repository permission check failed: ${repoError.message}`); + core.setOutput('text', ''); + return; + } // Determine current body text based on event context switch (context.eventName) {