# How the GitHub‑Asana Action Handles Bot Users as Pull‑Request Authors

> Learn how the GitHub Asana action handles bot users as pull request authors, assigning tasks to human users for accurate attribution.

- Repository: [Keita Kitamura/github-asana-request-review-action](https://github.com/keitap/github-asana-request-review-action)
- Tags: internals
- Published: 2026-03-05

---

**When a GitHub bot authors a pull request, the action automatically substitutes the bot's identity with the human assignee to ensure Asana tasks and comments are attributed to a real user account.**

The `keitap/github-asana-request-review-action` bridges GitHub code reviews with Asana task management, but automated pull requests from services like Dependabot present a unique challenge: bots lack Asana accounts. To handle bot users as pull request authors effectively, the action implements a fallback mechanism that delegates accountability to the assigned human reviewer.

## Bot Detection Logic in handler.go

The action identifies automated authors in [`handler.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/handler.go) through the `getAssigneeOrRequester` method. This function inspects the `User.Type` field of the GitHub API response to distinguish between human and machine accounts.

```go
// https://github.com/keitap/github-asana-request-review-action/blob/main/handler.go#L69-L90
func (h *Handler) getAssigneeOrRequester(pr *github.PullRequestReviewEvent) (requester *Account, err error) {
    // 1️⃣ Detect a bot author and a non‑nil assignee.
    if pr.PullRequest.User.GetType() == "Bot" && pr.PullRequest.Assignee != nil {
        log.Printf("pull request user is a bot: %s", pr.PullRequest.User.GetLogin())

        // 2️⃣ Fetch the Asana account for the assignee instead of the bot.
        requester, err = h.fetchAccount(pr.PullRequest.Assignee.GetLogin())
        if err != nil {
            return nil, fmt.Errorf(": %w", err)
        }
        return requester, nil
    }

    // 3️⃣ Normal case – the author is a human; fetch their account directly.
    requester, err = h.fetchAccount(pr.PullRequest.User.GetLogin())
    if err != nil {
        return nil, fmt.Errorf(": %w", err)
    }
    return requester, nil
}

```

### Identifying GitHub Bot Accounts

The condition `pr.PullRequest.User.GetType() == "Bot"` targets the **User.Type** property returned by GitHub's REST API. Automated accounts—including Dependabot, GitHub Actions, and third-party integration bots—return the literal string `"Bot"` in this field, while human users return `"User"`.

### The Assignee Fallback Strategy

When the bot detection condition succeeds, the action verifies that `pr.PullRequest.Assignee != nil`. If a human assignee exists, the system logs the bot detection via `log.Printf` and immediately pivots to `h.fetchAccount(pr.PullRequest.Assignee.GetLogin())`. This ensures the subsequent Asana sub-tasks and review comments are linked to the assignee's Asana identity rather than the bot's unmapped login.

## Account Resolution Through fetchAccount

After determining the effective requester, the action resolves the GitHub username to an Asana GID through the `fetchAccount` helper. This method queries the `Config.Accounts` map defined in [`config.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/config.go), which stores the deliberate mapping between GitHub logins and Asana user identifiers.

If the login—whether the original author or the fallback assignee—lacks a configured mapping, `fetchAccount` returns a `NoAsanaAccount` placeholder. This graceful degradation prevents the action from failing while clearly flagging unmapped users in the workflow logs.

## Practical Implementation Example

The following Go example demonstrates how the action processes a `PullRequestReviewEvent` where Dependabot is the PR author:

```go
package main

import (
	"log"

	"github.com/google/go-github/v74/github"
	"github.com/keitap/github-asana-request-review-action"
)

func main() {
	// Mock a PullRequestReviewEvent where the PR author is a bot.
	pr := &github.PullRequest{
		User: &github.User{
			Login: github.String("dependabot[bot]"),
			Type:  github.String("Bot"),
		},
		Assignee: &github.User{
			Login: github.String("alice"),
		},
		// body would contain the Asana task link in a real PR.
	}
	event := &github.PullRequestReviewEvent{
		PullRequest: pr,
		Repo:        &github.Repository{}, // omitted for brevity
	}

	// Assume we have already built a Handler with config, Asana, and GitHub clients.
	h := githubasana.NewHandler(config, asanaClient, githubClient)

	// The handler automatically resolves the requester (alice) instead of the bot.
	if err := h.handlePullRequestReviewEvent(event); err != nil {
		log.Fatalf("failed: %v", err)
	}
}

```

When executed with proper client configuration, this workflow attributes all generated Asana actions to **alice** while logging the detection of `dependabot[bot]` in the runner logs.

## Summary

- The action detects bot authors by checking if `User.Type == "Bot"` in the GitHub API response.
- When a bot is detected and an assignee exists, the system automatically substitutes the assignee's identity for the bot's login.
- The `fetchAccount` method in [`handler.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/handler.go) resolves the effective username to an Asana GID using the repository's configuration mapping.
- Unmapped users receive a `NoAsanaAccount` placeholder, ensuring the workflow continues without failure.
- This logic is implemented in the `getAssigneeOrRequester` method within [`handler.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/handler.go), with supporting configuration in [`config.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/config.go) and [`account.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/account.go).

## Frequently Asked Questions

### What happens if a bot authors a PR but no assignee is set?

If `pr.PullRequest.Assignee` is nil when a bot is detected, the action falls through to the default path and attempts to fetch the account for the bot's login directly. Since bots lack Asana mappings, this typically returns a `NoAsanaAccount` placeholder, and the Asana task creation proceeds without a specific requester attribution.

### Does the action support all GitHub bot types?

Yes. The implementation relies on the GitHub API's `User.Type` field rather than hardcoded bot names. Any automated account—whether Dependabot, GitHub Actions, or third-party integration bots—that returns `"Bot"` in the type field triggers the fallback logic automatically.

### Where is the GitHub-to-Asana user mapping configured?

The mapping is defined in [`config.go`](https://github.com/keitap/github-asana-request-review-action/blob/main/config.go) within the `Config.Accounts` structure. Repository maintainers must explicitly configure which GitHub usernames correspond to which Asana GIDs; the `fetchAccount` method references this configuration when resolving requesters and reviewers.

### How does the action log bot detection events?

When the `getAssigneeOrRequester` method detects a bot author, it emits a log message via `log.Printf` stating `"pull request user is a bot: %s"` followed by the bot's login. This appears in the GitHub Actions workflow logs, providing transparency about when the assignee fallback mechanism activates.